svn commit: r302634 - in head/sys/dev/hyperv: include netvsc vmbus
Sepherosa Ziehau
sephe at FreeBSD.org
Tue Jul 12 08:38:04 UTC 2016
Author: sephe
Date: Tue Jul 12 08:38:03 2016
New Revision: 302634
URL: https://svnweb.freebsd.org/changeset/base/302634
Log:
hyperv/vmbus: Fix sub-channel re-open support.
For multi-channel devices, once the primary channel is closed,
a set of 'rescind' messages for sub-channels will be delivered
by Hypervisor. Sub-channel MUST be freed according to these
'rescind' messages; directly re-openning sub-channels in the
same fashion as the primary channel's re-opening does NOT work
at all.
After the primary channel is re-opened, requested # of sub-
channels will be delivered though 'channel offer' messages, and
this set of newly offered channels can be opened along side with
the primary channel.
This unbreaks the MTU setting for hn(4), which requires re-
openning all existsing channels upon MTU change.
MFC after: 1 week
Sponsored by: Microsoft OSTC
Differential Revision: https://reviews.freebsd.org/D6978
Modified:
head/sys/dev/hyperv/include/hyperv.h
head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
head/sys/dev/hyperv/vmbus/vmbus_reg.h
Modified: head/sys/dev/hyperv/include/hyperv.h
==============================================================================
--- head/sys/dev/hyperv/include/hyperv.h Tue Jul 12 08:28:51 2016 (r302633)
+++ head/sys/dev/hyperv/include/hyperv.h Tue Jul 12 08:38:03 2016 (r302634)
@@ -717,6 +717,7 @@ void vmbus_channel_cpu_rr(struct hv_vmb
struct hv_vmbus_channel **
vmbus_get_subchan(struct hv_vmbus_channel *pri_chan, int subchan_cnt);
void vmbus_rel_subchan(struct hv_vmbus_channel **subchan, int subchan_cnt);
+void vmbus_drain_subchan(struct hv_vmbus_channel *pri_chan);
/**
* @brief Get physical address from virtual
Modified: head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
==============================================================================
--- head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c Tue Jul 12 08:28:51 2016 (r302633)
+++ head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c Tue Jul 12 08:38:03 2016 (r302634)
@@ -345,6 +345,7 @@ static void hn_destroy_rx_data(struct hn
static void hn_set_tx_chimney_size(struct hn_softc *, int);
static void hn_channel_attach(struct hn_softc *, struct hv_vmbus_channel *);
static void hn_subchan_attach(struct hn_softc *, struct hv_vmbus_channel *);
+static void hn_subchan_setup(struct hn_softc *);
static int hn_transmit(struct ifnet *, struct mbuf *);
static void hn_xmit_qflush(struct ifnet *);
@@ -575,25 +576,8 @@ netvsc_attach(device_t dev)
device_printf(dev, "%d TX ring, %d RX ring\n",
sc->hn_tx_ring_inuse, sc->hn_rx_ring_inuse);
- if (sc->net_dev->num_channel > 1) {
- struct hv_vmbus_channel **subchan;
- int subchan_cnt = sc->net_dev->num_channel - 1;
- int i;
-
- /* Wait for sub-channels setup to complete. */
- subchan = vmbus_get_subchan(pri_chan, subchan_cnt);
-
- /* Attach the sub-channels. */
- for (i = 0; i < subchan_cnt; ++i) {
- /* NOTE: Calling order is critical. */
- hn_subchan_attach(sc, subchan[i]);
- hv_nv_subchan_attach(subchan[i]);
- }
-
- /* Release the sub-channels */
- vmbus_rel_subchan(subchan, subchan_cnt);
- device_printf(dev, "%d sub-channels setup done\n", subchan_cnt);
- }
+ if (sc->net_dev->num_channel > 1)
+ hn_subchan_setup(sc);
#if __FreeBSD_version >= 1100099
if (sc->hn_rx_ring_inuse > 1) {
@@ -1620,6 +1604,10 @@ hn_ioctl(struct ifnet *ifp, u_long cmd,
NV_UNLOCK(sc);
break;
}
+
+ /* Wait for subchannels to be destroyed */
+ vmbus_drain_subchan(hn_dev->channel);
+
error = hv_rf_on_device_add(hn_dev, &device_info,
sc->hn_rx_ring_inuse);
if (error) {
@@ -1628,6 +1616,26 @@ hn_ioctl(struct ifnet *ifp, u_long cmd,
NV_UNLOCK(sc);
break;
}
+ KASSERT(sc->hn_rx_ring_cnt == sc->net_dev->num_channel,
+ ("RX ring count %d and channel count %u mismatch",
+ sc->hn_rx_ring_cnt, sc->net_dev->num_channel));
+ if (sc->net_dev->num_channel > 1) {
+ int r;
+
+ /*
+ * Skip the rings on primary channel; they are
+ * handled by the hv_rf_on_device_add() above.
+ */
+ for (r = 1; r < sc->hn_rx_ring_cnt; ++r) {
+ sc->hn_rx_ring[r].hn_rx_flags &=
+ ~HN_RX_FLAG_ATTACHED;
+ }
+ for (r = 1; r < sc->hn_tx_ring_cnt; ++r) {
+ sc->hn_tx_ring[r].hn_tx_flags &=
+ ~HN_TX_FLAG_ATTACHED;
+ }
+ hn_subchan_setup(sc);
+ }
sc->hn_tx_chimney_max = sc->net_dev->send_section_size;
if (sc->hn_tx_ring[0].hn_tx_chimney_size >
@@ -2980,6 +2988,29 @@ hn_subchan_attach(struct hn_softc *sc, s
}
static void
+hn_subchan_setup(struct hn_softc *sc)
+{
+ struct hv_device *device_ctx = vmbus_get_devctx(sc->hn_dev);
+ struct hv_vmbus_channel **subchan;
+ int subchan_cnt = sc->net_dev->num_channel - 1;
+ int i;
+
+ /* Wait for sub-channels setup to complete. */
+ subchan = vmbus_get_subchan(device_ctx->channel, subchan_cnt);
+
+ /* Attach the sub-channels. */
+ for (i = 0; i < subchan_cnt; ++i) {
+ /* NOTE: Calling order is critical. */
+ hn_subchan_attach(sc, subchan[i]);
+ hv_nv_subchan_attach(subchan[i]);
+ }
+
+ /* Release the sub-channels */
+ vmbus_rel_subchan(subchan, subchan_cnt);
+ if_printf(sc->hn_ifp, "%d sub-channels setup done\n", subchan_cnt);
+}
+
+static void
hn_tx_taskq_create(void *arg __unused)
{
if (!hn_share_tx_taskq)
Modified: head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c
==============================================================================
--- head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c Tue Jul 12 08:28:51 2016 (r302633)
+++ head/sys/dev/hyperv/vmbus/hv_channel_mgmt.c Tue Jul 12 08:38:03 2016 (r302634)
@@ -367,6 +367,54 @@ vmbus_chan_detach_task(void *xchan, int
if (HV_VMBUS_CHAN_ISPRIMARY(chan)) {
/* Only primary channel owns the hv_device */
hv_vmbus_child_device_unregister(chan->device);
+ /* NOTE: DO NOT free primary channel for now */
+ } else {
+ struct vmbus_softc *sc = chan->vmbus_sc;
+ struct hv_vmbus_channel *pri_chan = chan->primary_channel;
+ struct vmbus_chanmsg_chfree *req;
+ struct vmbus_msghc *mh;
+ int error;
+
+ mh = vmbus_msghc_get(sc, sizeof(*req));
+ if (mh == NULL) {
+ device_printf(sc->vmbus_dev,
+ "can not get msg hypercall for chfree(chan%u)\n",
+ chan->offer_msg.child_rel_id);
+ goto remove;
+ }
+
+ req = vmbus_msghc_dataptr(mh);
+ req->chm_hdr.chm_type = VMBUS_CHANMSG_TYPE_CHFREE;
+ req->chm_chanid = chan->offer_msg.child_rel_id;
+
+ error = vmbus_msghc_exec_noresult(mh);
+ vmbus_msghc_put(sc, mh);
+
+ if (error) {
+ device_printf(sc->vmbus_dev,
+ "chfree(chan%u) failed: %d",
+ chan->offer_msg.child_rel_id, error);
+ /* NOTE: Move on! */
+ } else {
+ if (bootverbose) {
+ device_printf(sc->vmbus_dev, "chan%u freed\n",
+ chan->offer_msg.child_rel_id);
+ }
+ }
+remove:
+ mtx_lock(&sc->vmbus_chlist_lock);
+ TAILQ_REMOVE(&sc->vmbus_chlist, chan, ch_link);
+ mtx_unlock(&sc->vmbus_chlist_lock);
+
+ mtx_lock(&pri_chan->sc_lock);
+ TAILQ_REMOVE(&pri_chan->sc_list_anchor, chan, sc_list_entry);
+ KASSERT(pri_chan->subchan_cnt > 0,
+ ("invalid subchan_cnt %d", pri_chan->subchan_cnt));
+ pri_chan->subchan_cnt--;
+ mtx_unlock(&pri_chan->sc_lock);
+ wakeup(pri_chan);
+
+ hv_vmbus_free_vmbus_channel(chan);
}
}
@@ -504,6 +552,15 @@ vmbus_rel_subchan(struct hv_vmbus_channe
}
void
+vmbus_drain_subchan(struct hv_vmbus_channel *pri_chan)
+{
+ mtx_lock(&pri_chan->sc_lock);
+ while (pri_chan->subchan_cnt > 0)
+ mtx_sleep(pri_chan, &pri_chan->sc_lock, 0, "dsubch", 0);
+ mtx_unlock(&pri_chan->sc_lock);
+}
+
+void
vmbus_chan_msgproc(struct vmbus_softc *sc, const struct vmbus_message *msg)
{
vmbus_chanmsg_proc_t msg_proc;
Modified: head/sys/dev/hyperv/vmbus/vmbus_reg.h
==============================================================================
--- head/sys/dev/hyperv/vmbus/vmbus_reg.h Tue Jul 12 08:28:51 2016 (r302633)
+++ head/sys/dev/hyperv/vmbus/vmbus_reg.h Tue Jul 12 08:38:03 2016 (r302634)
@@ -102,6 +102,7 @@ struct vmbus_gpa_range {
#define VMBUS_CHANMSG_TYPE_GPADL_CONNRESP 10 /* RESP */
#define VMBUS_CHANMSG_TYPE_GPADL_DISCONN 11 /* REQ */
#define VMBUS_CHANMSG_TYPE_GPADL_DISCONNRESP 12 /* RESP */
+#define VMBUS_CHANMSG_TYPE_CHFREE 13 /* REQ */
#define VMBUS_CHANMSG_TYPE_CONNECT 14 /* REQ */
#define VMBUS_CHANMSG_TYPE_CONNECT_RESP 15 /* RESP */
#define VMBUS_CHANMSG_TYPE_DISCONNECT 16 /* REQ */
@@ -206,4 +207,10 @@ struct vmbus_chanmsg_gpadl_disconn {
uint32_t chm_gpadl;
} __packed;
+/* VMBUS_CHANMSG_TYPE_CHFREE */
+struct vmbus_chanmsg_chfree {
+ struct vmbus_chanmsg_hdr chm_hdr;
+ uint32_t chm_chanid;
+} __packed;
+
#endif /* !_VMBUS_REG_H_ */
More information about the svn-src-all
mailing list