Author: sephe
Date: Tue Oct 11 02:54:56 2016
New Revision: 307013
URL: https://svnweb.freebsd.org/changeset/base/307013

Log:
  hyperv/hn: Rework link status support.
  
  This is the preamble for network device SR-IOV and
  NDIS_STATUS_NETWORK_CHANGE handling.
  
  MFC after:    1 week
  Sponsored by: Microsoft
  Differential Revision:        https://reviews.freebsd.org/D8209

Modified:
  head/sys/dev/hyperv/netvsc/hv_net_vsc.h
  head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
  head/sys/dev/hyperv/netvsc/hv_rndis_filter.c
  head/sys/dev/hyperv/netvsc/if_hnvar.h

Modified: head/sys/dev/hyperv/netvsc/hv_net_vsc.h
==============================================================================
--- head/sys/dev/hyperv/netvsc/hv_net_vsc.h     Tue Oct 11 02:43:23 2016        
(r307012)
+++ head/sys/dev/hyperv/netvsc/hv_net_vsc.h     Tue Oct 11 02:54:56 2016        
(r307013)
@@ -233,6 +233,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;
@@ -271,7 +275,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: head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c
==============================================================================
--- head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c  Tue Oct 11 02:43:23 
2016        (r307012)
+++ head/sys/dev/hyperv/netvsc/hv_netvsc_drv_freebsd.c  Tue Oct 11 02:54:56 
2016        (r307013)
@@ -334,6 +334,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);
@@ -349,6 +351,8 @@ 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_rx_drain(struct vmbus_channel *);
 static void hn_tx_resume(struct hn_softc *, int);
@@ -518,7 +522,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;
 
@@ -551,6 +554,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().
@@ -621,12 +633,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;
@@ -736,6 +742,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)
@@ -755,6 +767,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);
@@ -767,6 +785,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);
@@ -786,6 +805,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)
@@ -1311,19 +1360,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.
@@ -1801,9 +1837,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);
@@ -1896,9 +1932,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
@@ -3600,7 +3633,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;
@@ -3654,6 +3687,41 @@ 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)
+{
+
+       hn_suspend_data(sc);
+       hn_suspend_mgmt(sc);
+}
+
+static void
 hn_tx_resume(struct hn_softc *sc, int tx_ring_cnt)
 {
        int i;
@@ -3685,7 +3753,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);
 
@@ -3710,6 +3779,12 @@ hn_resume(struct hn_softc *sc)
                 */
                taskqueue_enqueue(txr->hn_tx_taskq, &txr->hn_txeof_task);
        }
+
+       /*
+        * Kick off link status check.
+        */
+       sc->hn_mgmt_taskq = sc->hn_mgmt_taskq0;
+       hn_link_status_update(sc);
 }
 
 static void

Modified: head/sys/dev/hyperv/netvsc/hv_rndis_filter.c
==============================================================================
--- head/sys/dev/hyperv/netvsc/hv_rndis_filter.c        Tue Oct 11 02:43:23 
2016        (r307012)
+++ head/sys/dev/hyperv/netvsc/hv_rndis_filter.c        Tue Oct 11 02:54:56 
2016        (r307013)
@@ -167,11 +167,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: head/sys/dev/hyperv/netvsc/if_hnvar.h
==============================================================================
--- head/sys/dev/hyperv/netvsc/if_hnvar.h       Tue Oct 11 02:43:23 2016        
(r307012)
+++ head/sys/dev/hyperv/netvsc/if_hnvar.h       Tue Oct 11 02:54:56 2016        
(r307013)
@@ -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;
 
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to