Date: Tue, 12 Jul 2016 08:38:03 +0000 (UTC) From: Sepherosa Ziehau <sephe@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r302634 - in head/sys/dev/hyperv: include netvsc vmbus Message-ID: <201607120838.u6C8c3iV029550@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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_ */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201607120838.u6C8c3iV029550>