aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/hyperv/netvsc
diff options
context:
space:
mode:
authorSepherosa Ziehau <sephe@FreeBSD.org>2016-12-12 05:18:03 +0000
committerSepherosa Ziehau <sephe@FreeBSD.org>2016-12-12 05:18:03 +0000
commit6c1204df36ac61e01a12c770d46a0acbd905e502 (patch)
tree6b9a5445562bdd61e56c55c5630312648fee41a0 /sys/dev/hyperv/netvsc
parentb99113a1c114534f665834e4aae824cfdaadacf7 (diff)
downloadsrc-6c1204df36ac61e01a12c770d46a0acbd905e502.tar.gz
src-6c1204df36ac61e01a12c770d46a0acbd905e502.zip
hyperv/hn: Add polling support
MFC after: 1 week Sponsored by: Microsoft Differential Revision: https://reviews.freebsd.org/D8739
Notes
Notes: svn path=/head/; revision=309875
Diffstat (limited to 'sys/dev/hyperv/netvsc')
-rw-r--r--sys/dev/hyperv/netvsc/if_hn.c79
-rw-r--r--sys/dev/hyperv/netvsc/if_hnvar.h2
2 files changed, 81 insertions, 0 deletions
diff --git a/sys/dev/hyperv/netvsc/if_hn.c b/sys/dev/hyperv/netvsc/if_hn.c
index 983fdc384567..90b5a852b7c0 100644
--- a/sys/dev/hyperv/netvsc/if_hn.c
+++ b/sys/dev/hyperv/netvsc/if_hn.c
@@ -293,6 +293,7 @@ static int hn_txagg_size_sysctl(SYSCTL_HANDLER_ARGS);
static int hn_txagg_pkts_sysctl(SYSCTL_HANDLER_ARGS);
static int hn_txagg_pktmax_sysctl(SYSCTL_HANDLER_ARGS);
static int hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS);
+static int hn_polling_sysctl(SYSCTL_HANDLER_ARGS);
static void hn_stop(struct hn_softc *);
static void hn_init_locked(struct hn_softc *);
@@ -319,6 +320,8 @@ static void hn_resume_mgmt(struct hn_softc *);
static void hn_suspend_mgmt_taskfunc(void *, int);
static void hn_chan_drain(struct hn_softc *,
struct vmbus_channel *);
+static void hn_polling(struct hn_softc *, u_int);
+static void hn_chan_polling(struct vmbus_channel *, u_int);
static void hn_update_link_status(struct hn_softc *);
static void hn_change_network(struct hn_softc *);
@@ -1117,6 +1120,10 @@ hn_attach(device_t dev)
hn_txagg_pkts_sysctl, "I",
"Packet transmission aggregation packets, "
"0 -- disable, -1 -- auto");
+ SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "polling",
+ CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, sc, 0,
+ hn_polling_sysctl, "I",
+ "Polling frequency: [100,1000000], 0 disable polling");
/*
* Setup the ifmedia, which has been initialized earlier.
@@ -2360,6 +2367,9 @@ hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
break;
}
+ /* Disable polling. */
+ hn_polling(sc, 0);
+
/*
* Suspend this interface before the synthetic parts
* are ripped.
@@ -2405,6 +2415,13 @@ hn_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
*/
hn_resume(sc);
+ /*
+ * Re-enable polling if this interface is running and
+ * the polling is requested.
+ */
+ if ((ifp->if_drv_flags & IFF_DRV_RUNNING) && sc->hn_pollhz > 0)
+ hn_polling(sc, sc->hn_pollhz);
+
HN_UNLOCK(sc);
break;
@@ -2531,6 +2548,9 @@ hn_stop(struct hn_softc *sc)
KASSERT(sc->hn_flags & HN_FLAG_SYNTH_ATTACHED,
("synthetic parts were not attached"));
+ /* Disable polling. */
+ hn_polling(sc, 0);
+
/* Clear RUNNING bit _before_ hn_suspend_data() */
atomic_clear_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
hn_suspend_data(sc);
@@ -2568,6 +2588,10 @@ hn_init_locked(struct hn_softc *sc)
/* Everything is ready; unleash! */
atomic_set_int(&ifp->if_drv_flags, IFF_DRV_RUNNING);
+
+ /* Re-enable polling if requested. */
+ if (sc->hn_pollhz > 0)
+ hn_polling(sc, sc->hn_pollhz);
}
static void
@@ -2875,6 +2899,61 @@ hn_txagg_align_sysctl(SYSCTL_HANDLER_ARGS)
return (sysctl_handle_int(oidp, &align, 0, req));
}
+static void
+hn_chan_polling(struct vmbus_channel *chan, u_int pollhz)
+{
+ if (pollhz == 0)
+ vmbus_chan_poll_disable(chan);
+ else
+ vmbus_chan_poll_enable(chan, pollhz);
+}
+
+static void
+hn_polling(struct hn_softc *sc, u_int pollhz)
+{
+ int nsubch = sc->hn_rx_ring_inuse - 1;
+
+ HN_LOCK_ASSERT(sc);
+
+ if (nsubch > 0) {
+ struct vmbus_channel **subch;
+ int i;
+
+ subch = vmbus_subchan_get(sc->hn_prichan, nsubch);
+ for (i = 0; i < nsubch; ++i)
+ hn_chan_polling(subch[i], pollhz);
+ vmbus_subchan_rel(subch, nsubch);
+ }
+ hn_chan_polling(sc->hn_prichan, pollhz);
+}
+
+static int
+hn_polling_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ struct hn_softc *sc = arg1;
+ int pollhz, error;
+
+ pollhz = sc->hn_pollhz;
+ error = sysctl_handle_int(oidp, &pollhz, 0, req);
+ if (error || req->newptr == NULL)
+ return (error);
+
+ if (pollhz != 0 &&
+ (pollhz < VMBUS_CHAN_POLLHZ_MIN || pollhz > VMBUS_CHAN_POLLHZ_MAX))
+ return (EINVAL);
+
+ HN_LOCK(sc);
+ if (sc->hn_pollhz != pollhz) {
+ sc->hn_pollhz = pollhz;
+ if ((sc->hn_ifp->if_drv_flags & IFF_DRV_RUNNING) &&
+ (sc->hn_flags & HN_FLAG_SYNTH_ATTACHED))
+ hn_polling(sc, sc->hn_pollhz);
+ }
+ HN_UNLOCK(sc);
+
+ return (0);
+}
+
static int
hn_ndis_version_sysctl(SYSCTL_HANDLER_ARGS)
{
diff --git a/sys/dev/hyperv/netvsc/if_hnvar.h b/sys/dev/hyperv/netvsc/if_hnvar.h
index 198d0d83e94d..38d7b6f7040b 100644
--- a/sys/dev/hyperv/netvsc/if_hnvar.h
+++ b/sys/dev/hyperv/netvsc/if_hnvar.h
@@ -212,6 +212,8 @@ struct hn_softc {
uint32_t hn_caps; /* HN_CAP_ */
uint32_t hn_flags; /* HN_FLAG_ */
+ u_int hn_pollhz;
+
void *hn_rxbuf;
uint32_t hn_rxbuf_gpadl;
struct hyperv_dma hn_rxbuf_dma;