svn commit: r307621 - in stable/10/sys/dev/hyperv: include netvsc vmbus
Sepherosa Ziehau
sephe at FreeBSD.org
Wed Oct 19 08:40:26 UTC 2016
Author: sephe
Date: Wed Oct 19 08:40:24 2016
New Revision: 307621
URL: https://svnweb.freebsd.org/changeset/base/307621
Log:
MFC 307012,307013,307262
307012
hyperv/vmbus: Allow driver to inject synchronous task into channel taskq.
Sponsored by: Microsoft
Differential Revision: https://reviews.freebsd.org/D8208
307013
hyperv/hn: Rework link status support.
This is the preamble for network device SR-IOV and
NDIS_STATUS_NETWORK_CHANGE handling.
Sponsored by: Microsoft
Differential Revision: https://reviews.freebsd.org/D8209
307262
hyperv/hn: Management parts always need suspend and resume.
Sponsored by: Microsoft
Modified:
stable/10/sys/dev/hyperv/include/vmbus.h
stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h
stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c
stable/10/sys/dev/hyperv/netvsc/if_hnvar.h
stable/10/sys/dev/hyperv/vmbus/vmbus_chan.c
Directory Properties:
stable/10/ (props changed)
Modified: stable/10/sys/dev/hyperv/include/vmbus.h
==============================================================================
--- stable/10/sys/dev/hyperv/include/vmbus.h Wed Oct 19 08:32:24 2016 (r307620)
+++ stable/10/sys/dev/hyperv/include/vmbus.h Wed Oct 19 08:40:24 2016 (r307621)
@@ -118,6 +118,7 @@ struct vmbus_chan_br {
struct vmbus_channel;
struct hyperv_guid;
+struct task;
typedef void (*vmbus_chan_callback_t)(struct vmbus_channel *, void *);
@@ -135,6 +136,8 @@ int vmbus_chan_open_br(struct vmbus_cha
int udlen, vmbus_chan_callback_t cb, void *cbarg);
void vmbus_chan_close(struct vmbus_channel *chan);
void vmbus_chan_intr_drain(struct vmbus_channel *chan);
+void vmbus_chan_run_task(struct vmbus_channel *chan,
+ struct task *task);
int vmbus_chan_gpadl_connect(struct vmbus_channel *chan,
bus_addr_t paddr, int size, uint32_t *gpadl);
Modified: stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h Wed Oct 19 08:32:24 2016 (r307620)
+++ stable/10/sys/dev/hyperv/netvsc/hv_net_vsc.h Wed Oct 19 08:40:24 2016 (r307621)
@@ -234,6 +234,10 @@ struct hn_softc {
struct vmbus_xact_ctx *hn_xact;
uint32_t hn_nvs_ver;
+ struct taskqueue *hn_mgmt_taskq;
+ struct taskqueue *hn_mgmt_taskq0;
+ struct task hn_link_task;
+
uint32_t hn_caps; /* HN_CAP_ */
uint32_t hn_flags; /* HN_FLAG_ */
void *hn_rxbuf;
@@ -272,7 +276,6 @@ struct hn_softc {
*/
struct hn_send_ctx;
-void netvsc_linkstatus_callback(struct hn_softc *sc, uint32_t status);
int hv_nv_on_send(struct vmbus_channel *chan, uint32_t rndis_mtype,
struct hn_send_ctx *sndc, struct vmbus_gpa *gpa, int gpa_cnt);
Modified: stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c Wed Oct 19 08:32:24 2016 (r307620)
+++ stable/10/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c Wed Oct 19 08:40:24 2016 (r307621)
@@ -336,6 +336,8 @@ static void hn_fixup_tx_data(struct hn_s
static void hn_destroy_tx_data(struct hn_softc *);
static void hn_start_taskfunc(void *, int);
static void hn_start_txeof_taskfunc(void *, int);
+static void hn_link_taskfunc(void *, int);
+static void hn_suspend_mgmt_taskfunc(void *, int);
static int hn_encap(struct hn_tx_ring *, struct hn_txdesc *, struct mbuf **);
static int hn_create_rx_data(struct hn_softc *sc, int);
static void hn_destroy_rx_data(struct hn_softc *sc);
@@ -351,7 +353,11 @@ static int hn_synth_attach(struct hn_sof
static void hn_synth_detach(struct hn_softc *);
static bool hn_tx_ring_pending(struct hn_tx_ring *);
static void hn_suspend(struct hn_softc *);
+static void hn_suspend_data(struct hn_softc *);
+static void hn_suspend_mgmt(struct hn_softc *);
static void hn_resume(struct hn_softc *);
+static void hn_resume_data(struct hn_softc *);
+static void hn_resume_mgmt(struct hn_softc *);
static void hn_rx_drain(struct vmbus_channel *);
static void hn_tx_resume(struct hn_softc *, int);
static void hn_tx_ring_qflush(struct hn_tx_ring *);
@@ -533,7 +539,6 @@ netvsc_attach(device_t dev)
struct sysctl_oid_list *child;
struct sysctl_ctx_list *ctx;
uint8_t eaddr[ETHER_ADDR_LEN];
- uint32_t link_status;
struct ifnet *ifp = NULL;
int error, ring_cnt, tx_ring_cnt;
@@ -567,6 +572,15 @@ netvsc_attach(device_t dev)
}
/*
+ * Setup taskqueue for mangement tasks, e.g. link status.
+ */
+ sc->hn_mgmt_taskq0 = taskqueue_create("hn_mgmt", M_WAITOK,
+ taskqueue_thread_enqueue, &sc->hn_mgmt_taskq0);
+ taskqueue_start_threads(&sc->hn_mgmt_taskq0, 1, PI_NET, "%s mgmt",
+ device_get_nameunit(dev));
+ TASK_INIT(&sc->hn_link_task, 0, hn_link_taskfunc, sc);
+
+ /*
* Allocate ifnet and setup its name earlier, so that if_printf
* can be used by functions, which will be called after
* ether_ifattach().
@@ -637,12 +651,6 @@ netvsc_attach(device_t dev)
if (error)
goto failed;
- error = hn_rndis_get_linkstatus(sc, &link_status);
- if (error)
- goto failed;
- if (link_status == NDIS_MEDIA_STATE_CONNECTED)
- sc->hn_carrier = 1;
-
error = hn_rndis_get_eaddr(sc, eaddr);
if (error)
goto failed;
@@ -752,6 +760,12 @@ netvsc_attach(device_t dev)
/* Inform the upper layer about the long frame support. */
ifp->if_hdrlen = sizeof(struct ether_vlan_header);
+ /*
+ * Kick off link status check.
+ */
+ sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
+ hn_link_status_update(sc);
+
return (0);
failed:
if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED)
@@ -771,6 +785,12 @@ netvsc_detach(device_t dev)
if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
if (ifp->if_drv_flags & IFF_DRV_RUNNING)
hn_stop(sc);
+ /*
+ * NOTE:
+ * hn_stop() only suspends data, so managment
+ * stuffs have to be suspended manually here.
+ */
+ hn_suspend_mgmt(sc);
hn_synth_detach(sc);
}
HN_UNLOCK(sc);
@@ -783,6 +803,7 @@ netvsc_detach(device_t dev)
if (sc->hn_tx_taskq != hn_tx_taskq)
taskqueue_free(sc->hn_tx_taskq);
+ taskqueue_free(sc->hn_mgmt_taskq0);
if (sc->hn_xact != NULL)
vmbus_xact_ctx_destroy(sc->hn_xact);
@@ -802,6 +823,36 @@ netvsc_shutdown(device_t dev)
return (0);
}
+static void
+hn_link_taskfunc(void *xsc, int pending __unused)
+{
+ struct hn_softc *sc = xsc;
+ struct ifnet *ifp = sc->hn_ifp;
+ uint32_t link_status;
+ int error;
+
+ error = hn_rndis_get_linkstatus(sc, &link_status);
+ if (error) {
+ /* XXX what to do? */
+ return;
+ }
+
+ if (link_status == NDIS_MEDIA_STATE_CONNECTED)
+ sc->hn_carrier = 1;
+ else
+ sc->hn_carrier = 0;
+ if_link_state_change(ifp,
+ sc->hn_carrier ? LINK_STATE_UP : LINK_STATE_DOWN);
+}
+
+void
+hn_link_status_update(struct hn_softc *sc)
+{
+
+ if (sc->hn_mgmt_taskq != NULL)
+ taskqueue_enqueue(sc->hn_mgmt_taskq, &sc->hn_link_task);
+}
+
static __inline int
hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
@@ -1333,19 +1384,6 @@ hn_start_locked(struct hn_tx_ring *txr,
}
/*
- * Link up/down notification
- */
-void
-netvsc_linkstatus_callback(struct hn_softc *sc, uint32_t status)
-{
- if (status == 1) {
- sc->hn_carrier = 1;
- } else {
- sc->hn_carrier = 0;
- }
-}
-
-/*
* Append the specified data to the indicated mbuf chain,
* Extend the mbuf chain if the new data does not fit in
* existing space.
@@ -1673,8 +1711,11 @@ hn_ioctl(struct ifnet *ifp, u_long cmd,
hn_set_lro_lenlim(sc, HN_LRO_LENLIM_MIN(ifp));
#endif
- if (ifp->if_drv_flags & IFF_DRV_RUNNING)
- hn_suspend(sc);
+ /*
+ * Suspend this interface before the synthetic parts
+ * are ripped.
+ */
+ hn_suspend(sc);
/*
* Detach the synthetics parts, i.e. NVS and RNDIS.
@@ -1692,9 +1733,10 @@ hn_ioctl(struct ifnet *ifp, u_long cmd,
hn_set_chim_size(sc, sc->hn_chim_szmax);
hn_set_tso_maxsize(sc, hn_tso_maxlen, ifr->ifr_mtu);
- /* All done! Resume now. */
- if (ifp->if_drv_flags & IFF_DRV_RUNNING)
- hn_resume(sc);
+ /*
+ * All done! Resume the interface now.
+ */
+ hn_resume(sc);
HN_UNLOCK(sc);
break;
@@ -1821,9 +1863,9 @@ hn_stop(struct hn_softc *sc)
KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
("synthetic parts were not attached"));
- /* Clear RUNNING bit _before_ hn_suspend() */
+ /* Clear RUNNING bit _before_ hn_suspend_data() */
atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
- hn_suspend(sc);
+ hn_suspend_data(sc);
/* Clear OACTIVE bit. */
atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE);
@@ -1916,9 +1958,6 @@ hn_init_locked(struct hn_softc *sc)
/* Everything is ready; unleash! */
atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
-
- /* TODO: check RNDIS link status. */
- if_link_state_change(ifp, LINK_STATE_UP);
}
static void
@@ -3620,7 +3659,7 @@ hn_rx_drain(struct vmbus_channel *chan)
}
static void
-hn_suspend(struct hn_softc *sc)
+hn_suspend_data(struct hn_softc *sc)
{
struct vmbus_channel **subch = NULL;
int i, nsubch;
@@ -3674,6 +3713,42 @@ hn_suspend(struct hn_softc *sc)
}
static void
+hn_suspend_mgmt_taskfunc(void *xsc, int pending __unused)
+{
+
+ ((struct hn_softc *)xsc)->hn_mgmt_taskq = NULL;
+}
+
+static void
+hn_suspend_mgmt(struct hn_softc *sc)
+{
+ struct task task;
+
+ HN_LOCK_ASSERT(sc);
+
+ /*
+ * Make sure that hn_mgmt_taskq0 can nolonger be accessed
+ * through hn_mgmt_taskq.
+ */
+ TASK_INIT(&task, 0, hn_suspend_mgmt_taskfunc, sc);
+ vmbus_chan_run_task(sc->hn_prichan, &task);
+
+ /*
+ * Make sure that all pending management tasks are completed.
+ */
+ taskqueue_drain_all(sc->hn_mgmt_taskq0);
+}
+
+static void
+hn_suspend(struct hn_softc *sc)
+{
+
+ if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
+ hn_suspend_data(sc);
+ hn_suspend_mgmt(sc);
+}
+
+static void
hn_tx_resume(struct hn_softc *sc, int tx_ring_cnt)
{
int i;
@@ -3691,7 +3766,7 @@ hn_tx_resume(struct hn_softc *sc, int tx
}
static void
-hn_resume(struct hn_softc *sc)
+hn_resume_data(struct hn_softc *sc)
{
int i;
@@ -3705,7 +3780,8 @@ hn_resume(struct hn_softc *sc)
/*
* Make sure to clear suspend status on "all" TX rings,
- * since hn_tx_ring_inuse can be changed after hn_suspend().
+ * since hn_tx_ring_inuse can be changed after
+ * hn_suspend_data().
*/
hn_tx_resume(sc, sc->hn_tx_ring_cnt);
@@ -3733,6 +3809,26 @@ hn_resume(struct hn_softc *sc)
}
static void
+hn_resume_mgmt(struct hn_softc *sc)
+{
+
+ /*
+ * Kick off link status check.
+ */
+ sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
+ hn_link_status_update(sc);
+}
+
+static void
+hn_resume(struct hn_softc *sc)
+{
+
+ if (sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING)
+ hn_resume_data(sc);
+ hn_resume_mgmt(sc);
+}
+
+static void
hn_nvs_handle_notify(struct hn_softc *sc, const struct vmbus_chanpkt_hdr *pkt)
{
const struct hn_nvs_hdr *hdr;
Modified: stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c Wed Oct 19 08:32:24 2016 (r307620)
+++ stable/10/sys/dev/hyperv/netvsc/hv_rndis_filter.c Wed Oct 19 08:40:24 2016 (r307621)
@@ -168,11 +168,8 @@ hv_rf_receive_indicate_status(struct hn_
switch (msg->rm_status) {
case RNDIS_STATUS_MEDIA_CONNECT:
- netvsc_linkstatus_callback(sc, 1);
- break;
-
case RNDIS_STATUS_MEDIA_DISCONNECT:
- netvsc_linkstatus_callback(sc, 0);
+ hn_link_status_update(sc);
break;
case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:
Modified: stable/10/sys/dev/hyperv/netvsc/if_hnvar.h
==============================================================================
--- stable/10/sys/dev/hyperv/netvsc/if_hnvar.h Wed Oct 19 08:32:24 2016 (r307620)
+++ stable/10/sys/dev/hyperv/netvsc/if_hnvar.h Wed Oct 19 08:40:24 2016 (r307621)
@@ -138,6 +138,7 @@ void hn_nvs_sent_xact(struct hn_send_ct
int hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
const struct hn_recvinfo *info);
void hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr);
+void hn_link_status_update(struct hn_softc *sc);
extern struct hn_send_ctx hn_send_ctx_none;
Modified: stable/10/sys/dev/hyperv/vmbus/vmbus_chan.c
==============================================================================
--- stable/10/sys/dev/hyperv/vmbus/vmbus_chan.c Wed Oct 19 08:32:24 2016 (r307620)
+++ stable/10/sys/dev/hyperv/vmbus/vmbus_chan.c Wed Oct 19 08:40:24 2016 (r307621)
@@ -1713,3 +1713,11 @@ vmbus_chan_rx_empty(const struct vmbus_c
return (vmbus_rxbr_empty(&chan->ch_rxbr));
}
+
+void
+vmbus_chan_run_task(struct vmbus_channel *chan, struct task *task)
+{
+
+ taskqueue_enqueue(chan->ch_tq, task);
+ taskqueue_drain(chan->ch_tq, task);
+}
More information about the svn-src-all
mailing list