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
This commit is contained in:
Sepherosa Ziehau 2016-10-11 02:54:56 +00:00
parent cca23e7c3c
commit 4afe249835
4 changed files with 108 additions and 32 deletions

View File

@ -233,6 +233,10 @@ struct hn_softc {
struct vmbus_xact_ctx *hn_xact; struct vmbus_xact_ctx *hn_xact;
uint32_t hn_nvs_ver; 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_caps; /* HN_CAP_ */
uint32_t hn_flags; /* HN_FLAG_ */ uint32_t hn_flags; /* HN_FLAG_ */
void *hn_rxbuf; void *hn_rxbuf;
@ -271,7 +275,6 @@ struct hn_softc {
*/ */
struct hn_send_ctx; 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, 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); struct hn_send_ctx *sndc, struct vmbus_gpa *gpa, int gpa_cnt);

View File

@ -334,6 +334,8 @@ static void hn_fixup_tx_data(struct hn_softc *);
static void hn_destroy_tx_data(struct hn_softc *); static void hn_destroy_tx_data(struct hn_softc *);
static void hn_start_taskfunc(void *, int); static void hn_start_taskfunc(void *, int);
static void hn_start_txeof_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_encap(struct hn_tx_ring *, struct hn_txdesc *, struct mbuf **);
static int hn_create_rx_data(struct hn_softc *sc, int); static int hn_create_rx_data(struct hn_softc *sc, int);
static void hn_destroy_rx_data(struct hn_softc *sc); static void hn_destroy_rx_data(struct hn_softc *sc);
@ -349,6 +351,8 @@ static int hn_synth_attach(struct hn_softc *, int);
static void hn_synth_detach(struct hn_softc *); static void hn_synth_detach(struct hn_softc *);
static bool hn_tx_ring_pending(struct hn_tx_ring *); static bool hn_tx_ring_pending(struct hn_tx_ring *);
static void hn_suspend(struct hn_softc *); 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(struct hn_softc *);
static void hn_rx_drain(struct vmbus_channel *); static void hn_rx_drain(struct vmbus_channel *);
static void hn_tx_resume(struct hn_softc *, int); 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_oid_list *child;
struct sysctl_ctx_list *ctx; struct sysctl_ctx_list *ctx;
uint8_t eaddr[ETHER_ADDR_LEN]; uint8_t eaddr[ETHER_ADDR_LEN];
uint32_t link_status;
struct ifnet *ifp = NULL; struct ifnet *ifp = NULL;
int error, ring_cnt, tx_ring_cnt; int error, ring_cnt, tx_ring_cnt;
@ -550,6 +553,15 @@ netvsc_attach(device_t dev)
sc->hn_tx_taskq = hn_tx_taskq; sc->hn_tx_taskq = hn_tx_taskq;
} }
/*
* 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 * Allocate ifnet and setup its name earlier, so that if_printf
* can be used by functions, which will be called after * can be used by functions, which will be called after
@ -621,12 +633,6 @@ netvsc_attach(device_t dev)
if (error) if (error)
goto failed; 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); error = hn_rndis_get_eaddr(sc, eaddr);
if (error) if (error)
goto failed; goto failed;
@ -736,6 +742,12 @@ netvsc_attach(device_t dev)
/* Inform the upper layer about the long frame support. */ /* Inform the upper layer about the long frame support. */
ifp->if_hdrlen = sizeof(struct ether_vlan_header); 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); return (0);
failed: failed:
if (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) 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 (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED) {
if (ifp->if_drv_flags & IFF_DRV_RUNNING) if (ifp->if_drv_flags & IFF_DRV_RUNNING)
hn_stop(sc); 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_synth_detach(sc);
} }
HN_UNLOCK(sc); HN_UNLOCK(sc);
@ -767,6 +785,7 @@ netvsc_detach(device_t dev)
if (sc->hn_tx_taskq != hn_tx_taskq) if (sc->hn_tx_taskq != hn_tx_taskq)
taskqueue_free(sc->hn_tx_taskq); taskqueue_free(sc->hn_tx_taskq);
taskqueue_free(sc->hn_mgmt_taskq0);
if (sc->hn_xact != NULL) if (sc->hn_xact != NULL)
vmbus_xact_ctx_destroy(sc->hn_xact); vmbus_xact_ctx_destroy(sc->hn_xact);
@ -786,6 +805,36 @@ netvsc_shutdown(device_t dev)
return (0); 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 static __inline int
hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd, hn_txdesc_dmamap_load(struct hn_tx_ring *txr, struct hn_txdesc *txd,
struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs) struct mbuf **m_head, bus_dma_segment_t *segs, int *nsegs)
@ -1310,19 +1359,6 @@ hn_start_locked(struct hn_tx_ring *txr, int len)
return 0; return 0;
} }
/*
* 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, * Append the specified data to the indicated mbuf chain,
* Extend the mbuf chain if the new data does not fit in * Extend the mbuf chain if the new data does not fit in
@ -1801,9 +1837,9 @@ hn_stop(struct hn_softc *sc)
KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED, KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
("synthetic parts were not 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); atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
hn_suspend(sc); hn_suspend_data(sc);
/* Clear OACTIVE bit. */ /* Clear OACTIVE bit. */
atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_OACTIVE); 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! */ /* Everything is ready; unleash! */
atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING); 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 static void
@ -3600,7 +3633,7 @@ hn_rx_drain(struct vmbus_channel *chan)
} }
static void static void
hn_suspend(struct hn_softc *sc) hn_suspend_data(struct hn_softc *sc)
{ {
struct vmbus_channel **subch = NULL; struct vmbus_channel **subch = NULL;
int i, nsubch; int i, nsubch;
@ -3653,6 +3686,41 @@ hn_suspend(struct hn_softc *sc)
vmbus_subchan_rel(subch, nsubch); vmbus_subchan_rel(subch, nsubch);
} }
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 static void
hn_tx_resume(struct hn_softc *sc, int tx_ring_cnt) hn_tx_resume(struct hn_softc *sc, int tx_ring_cnt)
{ {
@ -3685,7 +3753,8 @@ hn_resume(struct hn_softc *sc)
/* /*
* Make sure to clear suspend status on "all" TX rings, * 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); 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); 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 static void

View File

@ -167,11 +167,8 @@ hv_rf_receive_indicate_status(struct hn_softc *sc, const void *data, int dlen)
switch (msg->rm_status) { switch (msg->rm_status) {
case RNDIS_STATUS_MEDIA_CONNECT: case RNDIS_STATUS_MEDIA_CONNECT:
netvsc_linkstatus_callback(sc, 1);
break;
case RNDIS_STATUS_MEDIA_DISCONNECT: case RNDIS_STATUS_MEDIA_DISCONNECT:
netvsc_linkstatus_callback(sc, 0); hn_link_status_update(sc);
break; break;
case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG: case RNDIS_STATUS_TASK_OFFLOAD_CURRENT_CONFIG:

View File

@ -138,6 +138,7 @@ void hn_nvs_sent_xact(struct hn_send_ctx *sndc, struct hn_softc *sc,
int hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen, int hn_rxpkt(struct hn_rx_ring *rxr, const void *data, int dlen,
const struct hn_recvinfo *info); const struct hn_recvinfo *info);
void hn_chan_rollup(struct hn_rx_ring *rxr, struct hn_tx_ring *txr); 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; extern struct hn_send_ctx hn_send_ctx_none;