svn commit: r277399 - in projects/ifnet/sys: conf dev/bge dev/xl kern net
Gleb Smirnoff
glebius at FreeBSD.org
Mon Jan 19 21:40:16 UTC 2015
Author: glebius
Date: Mon Jan 19 21:40:13 2015
New Revision: 277399
URL: https://svnweb.freebsd.org/changeset/base/277399
Log:
Bring polling(4) to new ifnet world order.
o Since polling(4) is so much ifnet-oriented 'svn move' it:
kern/kern_poll.c -> net/if_polling.c
o Make the polling table not static, but dynamic and growing,
taking idea from the ifindex table. Now registering an interface
for polling can not fail.
o Create if_poll_t method in the if_ops. Drivers that support polling
should declare IFCAP_POLLING in their capabilities and impment
ifop_poll.
o Rename:
ether_poll_register -> if_poll_register
ether_poll_deregister -> if_poll_deregister
And make these functions private to the stack. Note that they are
voids now, due to not failing.
o The stack calls if_poll_register/if_poll_deregister on SIOCSIFCAP
and passes it down to driver. A driver needs to do only hardware
specific things to turn polling on or off.
Sponsored by: Netflix
Sponsored by: Nginx, Inc.
Added:
projects/ifnet/sys/net/if_polling.c
- copied, changed from r277397, projects/ifnet/sys/kern/kern_poll.c
Deleted:
projects/ifnet/sys/kern/kern_poll.c
Modified:
projects/ifnet/sys/conf/files
projects/ifnet/sys/dev/bge/if_bge.c
projects/ifnet/sys/dev/xl/if_xl.c
projects/ifnet/sys/net/if.c
projects/ifnet/sys/net/if.h
projects/ifnet/sys/net/if_var.h
Modified: projects/ifnet/sys/conf/files
==============================================================================
--- projects/ifnet/sys/conf/files Mon Jan 19 21:30:40 2015 (r277398)
+++ projects/ifnet/sys/conf/files Mon Jan 19 21:40:13 2015 (r277399)
@@ -2981,7 +2981,6 @@ kern/kern_ntptime.c standard
kern/kern_osd.c standard
kern/kern_physio.c standard
kern/kern_pmc.c standard
-kern/kern_poll.c optional device_polling
kern/kern_priv.c standard
kern/kern_proc.c standard
kern/kern_procctl.c standard
@@ -3253,6 +3252,7 @@ net/if_llatbl.c standard
net/if_me.c optional me inet
net/if_media.c standard
net/if_mib.c standard
+net/if_polling.c optional device_polling
net/if_spppfr.c optional sppp | netgraph_sppp
net/if_spppsubr.c optional sppp | netgraph_sppp
net/if_stf.c optional stf inet inet6
Modified: projects/ifnet/sys/dev/bge/if_bge.c
==============================================================================
--- projects/ifnet/sys/dev/bge/if_bge.c Mon Jan 19 21:30:40 2015 (r277398)
+++ projects/ifnet/sys/dev/bge/if_bge.c Mon Jan 19 21:40:13 2015 (r277399)
@@ -539,6 +539,9 @@ static struct ifdriver bge_ifdrv = {
.ifop_init = bge_init,
.ifop_transmit = bge_transmit,
.ifop_get_counter = bge_get_counter,
+#ifdef DEVICE_POLLING
+ .ifop_poll = bge_poll,
+#endif
},
.ifdrv_name = "bge",
.ifdrv_type = IFT_ETHER,
@@ -3334,6 +3337,9 @@ bge_attach(device_t dev)
.ifat_drv = &bge_ifdrv,
.ifat_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST,
.ifat_capabilities = IFCAP_HWCSUM | IFCAP_VLAN_HWTAGGING |
+#ifdef DEVICE_POLLING
+ IFCAP_POLLING |
+#endif
IFCAP_VLAN_MTU | IFCAP_VLAN_HWCSUM,
};
struct bge_softc *sc;
@@ -3927,9 +3933,6 @@ again:
ifat.ifat_capabilities |= IFCAP_TSO4 | IFCAP_VLAN_HWTSO;
}
ifat.ifat_capenable = ifat.ifat_capabilities;
-#ifdef DEVICE_POLLING
- ifat.ifat_capabilities |= IFCAP_POLLING;
-#endif
/*
* 5700 B0 chips do not support checksumming correctly due
* to hardware bugs.
@@ -3959,11 +3962,6 @@ bge_detach(device_t dev)
sc = device_get_softc(dev);
ifp = sc->bge_ifp;
-#ifdef DEVICE_POLLING
- if (sc->bge_capenable & IFCAP_POLLING)
- ether_poll_deregister(ifp);
-#endif
-
if (device_is_attached(dev)) {
if_detach(ifp);
BGE_LOCK(sc);
@@ -4804,7 +4802,7 @@ bge_tick(void *xsc)
*/
#ifdef DEVICE_POLLING
/* In polling mode we poll link state in bge_poll(). */
- if (!(if_getcapenable(sc->bge_ifp) & IFCAP_POLLING))
+ if (!(sc->bge_capenable & IFCAP_POLLING))
#endif
{
sc->bge_link_evt++;
@@ -5819,26 +5817,17 @@ bge_ioctl(if_t ifp, u_long command, void
mask = ifr->ifr_reqcap ^ ifr->ifr_curcap;
#ifdef DEVICE_POLLING
if (mask & IFCAP_POLLING) {
+ BGE_LOCK(sc);
if (ifr->ifr_reqcap & IFCAP_POLLING) {
- error = ether_poll_register(bge_poll, ifp);
- if (error)
- return (error);
- BGE_LOCK(sc);
BGE_SETBIT(sc, BGE_PCI_MISC_CTL,
BGE_PCIMISCCTL_MASK_PCI_INTR);
bge_writembx(sc, BGE_MBX_IRQ0_LO, 1);
- BGE_UNLOCK(sc);
} else {
- error = ether_poll_deregister(ifp);
- /* Enable interrupt even in error case */
- BGE_LOCK(sc);
BGE_CLRBIT(sc, BGE_PCI_MISC_CTL,
BGE_PCIMISCCTL_MASK_PCI_INTR);
bge_writembx(sc, BGE_MBX_IRQ0_LO, 0);
- BGE_UNLOCK(sc);
- if (error)
- return (error);
}
+ BGE_UNLOCK(sc);
}
#endif
sc->bge_capenable = ifr->ifr_reqcap;
Modified: projects/ifnet/sys/dev/xl/if_xl.c
==============================================================================
--- projects/ifnet/sys/dev/xl/if_xl.c Mon Jan 19 21:30:40 2015 (r277398)
+++ projects/ifnet/sys/dev/xl/if_xl.c Mon Jan 19 21:40:13 2015 (r277399)
@@ -249,7 +249,6 @@ static void xl_setwol(struct xl_softc *)
#ifdef DEVICE_POLLING
static int xl_poll(if_t, enum poll_cmd cmd, int count);
-static int xl_poll_locked(if_t, enum poll_cmd cmd, int count);
#endif
static int xl_ifmedia_upd(if_t);
@@ -335,6 +334,9 @@ static struct ifdriver xl_ifdrv = {
.ifop_ioctl = xl_ioctl,
.ifop_transmit = xl_transmit,
.ifop_init = xl_init,
+#ifdef DEVICE_POLLING
+ .ifop_poll = xl_poll,
+#endif
},
.ifdrv_name = "xl",
.ifdrv_type = IFT_ETHER,
@@ -1571,11 +1573,6 @@ xl_detach(device_t dev)
KASSERT(mtx_initialized(&sc->xl_mtx), ("xl mutex not initialized"));
-#ifdef DEVICE_POLLING
- if (ifp && ifp->if_capenable & IFCAP_POLLING)
- ether_poll_deregister(ifp);
-#endif
-
if (sc->xl_flags & XL_FLAG_USE_MMIO) {
rid = XL_PCI_LOMEM;
res = SYS_RES_MEMORY;
@@ -1846,7 +1843,7 @@ again:
BUS_DMASYNC_POSTREAD);
while ((rxstat = le32toh(sc->xl_cdata.xl_rx_head->xl_ptr->xl_status))) {
#ifdef DEVICE_POLLING
- if (ifp->if_capenable & IFCAP_POLLING) {
+ if (sc->xl_capenable & IFCAP_POLLING) {
if (sc->rxcycles <= 0)
break;
sc->rxcycles--;
@@ -2154,7 +2151,7 @@ xl_intr(void *arg)
XL_LOCK(sc);
#ifdef DEVICE_POLLING
- if (ifp->if_capenable & IFCAP_POLLING) {
+ if (sc->xl_capenable & IFCAP_POLLING) {
XL_UNLOCK(sc);
return;
}
@@ -2212,23 +2209,15 @@ xl_intr(void *arg)
static int
xl_poll(if_t ifp, enum poll_cmd cmd, int count)
{
- struct xl_softc *sc = ifp->if_softc;
+ struct xl_softc *sc;
int rx_npkts = 0;
+ sc = if_getsoftc(ifp, IF_DRIVER_SOFTC);
XL_LOCK(sc);
- if (sc->xl_flags & XL_FLAG_RUNNING)
- rx_npkts = xl_poll_locked(ifp, cmd, count);
- XL_UNLOCK(sc);
- return (rx_npkts);
-}
-
-static int
-xl_poll_locked(if_t ifp, enum poll_cmd cmd, int count)
-{
- struct xl_softc *sc = ifp->if_softc;
- int rx_npkts;
-
- XL_LOCK_ASSERT(sc);
+ if (sc->xl_flags & XL_FLAG_RUNNING) {
+ XL_UNLOCK(sc);
+ return (0);
+ }
sc->rxcycles = count;
rx_npkts = xl_rxeof(sc);
@@ -2239,9 +2228,9 @@ xl_poll_locked(if_t ifp, enum poll_cmd c
if (if_snd_len(ifp)) {
if (sc->xl_type == XL_TYPE_905B)
- xl_start_90xB_locked(ifp);
+ xl_start_90xB_locked(sc);
else
- xl_start_locked(ifp);
+ xl_start_locked(sc);
}
if (cmd == POLL_AND_CHECK_STATUS) {
@@ -2266,6 +2255,8 @@ xl_poll_locked(if_t ifp, enum poll_cmd c
xl_stats_update(sc);
}
}
+ XL_UNLOCK(sc);
+
return (rx_npkts);
}
#endif /* DEVICE_POLLING */
@@ -2826,7 +2817,7 @@ xl_init_locked(struct xl_softc *sc)
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_STAT_ENB|XL_INTRS);
#ifdef DEVICE_POLLING
/* Disable interrupts if we are polling. */
- if (ifp->if_capenable & IFCAP_POLLING)
+ if (sc->xl_capenable & IFCAP_POLLING)
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|0);
else
#endif
@@ -3028,16 +3019,11 @@ xl_ioctl(if_t ifp, u_long command, void
case SIOCSIFCAP:
#ifdef DEVICE_POLLING
if (((ifr->ifr_reqcap ^ ifr->ifr_curcap) & IFCAP_POLLING)) {
+ XL_LOCK(sc);
if ((ifr->ifr_reqcap & IFCAP_POLLING) != 0) {
- error = ether_poll_register(xl_poll, ifp);
- if (error)
- break;
- XL_LOCK(sc);
/* Disable interrupts */
CSR_WRITE_2(sc, XL_COMMAND, XL_CMD_INTR_ENB|0);
- XL_UNLOCK(sc);
} else {
- error = ether_poll_deregister(ifp);
/* Enable interrupts. */
XL_LOCK(sc);
CSR_WRITE_2(sc, XL_COMMAND,
@@ -3047,10 +3033,8 @@ xl_ioctl(if_t ifp, u_long command, void
if (sc->xl_flags & XL_FLAG_FUNCREG)
bus_space_write_4(sc->xl_ftag,
sc->xl_fhandle, 4, 0x8000);
- XL_UNLOCK(sc);
- if (error)
- break;
}
+ XL_UNLOCK(sc);
}
#endif /* DEVICE_POLLING */
sc->xl_capenable = ifr->ifr_reqcap;
Modified: projects/ifnet/sys/net/if.c
==============================================================================
--- projects/ifnet/sys/net/if.c Mon Jan 19 21:30:40 2015 (r277398)
+++ projects/ifnet/sys/net/if.c Mon Jan 19 21:40:13 2015 (r277399)
@@ -918,7 +918,10 @@ if_detach(if_t ifp)
ifp->if_flags |= IFF_DYING; /* XXX: Locking */
bpfdetach(ifp);
-
+#ifdef DEVICE_POLLING
+ if (ifp->if_capenable & IFCAP_POLLING)
+ if_poll_deregister(ifp);
+#endif
CURVNET_SET_QUIET(ifp->if_vnet);
if_detach_internal(ifp, 0);
@@ -2521,13 +2524,21 @@ if_drvioctl(u_long cmd, struct ifnet *if
return (0);
ifr->ifr_curcap = ifp->if_capenable;
error = if_ioctl(ifp, cmd, data, td);
- if (error == 0) {
- ifp->if_capenable = ifr->ifr_reqcap;
- ifp->if_hwassist = ifr->ifr_hwassist;
- getmicrotime(&ifp->if_lastchange);
- if (ifp->if_vlantrunk != NULL)
- (*vlan_trunk_cap_p)(ifp);
+ if (error != 0)
+ break;
+#ifdef DEVICE_POLLING
+ if ((ifr->ifr_reqcap ^ ifr->ifr_curcap) & IFCAP_POLLING) {
+ if (ifr->ifr_reqcap & IFCAP_POLLING)
+ if_poll_register(ifp);
+ else
+ if_poll_deregister(ifp);
}
+#endif
+ ifp->if_capenable = ifr->ifr_reqcap;
+ ifp->if_hwassist = ifr->ifr_hwassist;
+ getmicrotime(&ifp->if_lastchange);
+ if (ifp->if_vlantrunk != NULL)
+ (*vlan_trunk_cap_p)(ifp);
break;
#ifdef MAC
case SIOCSIFMAC:
Modified: projects/ifnet/sys/net/if.h
==============================================================================
--- projects/ifnet/sys/net/if.h Mon Jan 19 21:30:40 2015 (r277398)
+++ projects/ifnet/sys/net/if.h Mon Jan 19 21:40:13 2015 (r277399)
@@ -597,6 +597,10 @@ typedef void (*if_qflush_t)(if_t);
typedef int (*if_resolvemulti_t)(if_t, struct sockaddr **,
struct sockaddr *);
typedef void (*if_reassign_t)(if_t, struct vnet *);
+#ifdef DEVICE_POLLING
+enum poll_cmd { POLL_ONLY, POLL_AND_CHECK_STATUS };
+typedef int (*if_poll_t)(if_t ifp, enum poll_cmd cmd, int count);
+#endif
/*
* Interface methods. Usually stored in ifdriver definition, however
@@ -607,6 +611,9 @@ struct ifops {
if_input_t ifop_input; /* input routine (from h/w driver) */
if_transmit_t ifop_transmit; /* initiate output routine */
if_output_t ifop_output;
+#ifdef DEVICE_POLLING
+ if_poll_t ifop_poll;
+#endif
if_ioctl_t ifop_ioctl; /* ioctl routine */
if_get_counter_t ifop_get_counter; /* get counter values */
if_init_t ifop_init; /* init routine */
Copied and modified: projects/ifnet/sys/net/if_polling.c (from r277397, projects/ifnet/sys/kern/kern_poll.c)
==============================================================================
--- projects/ifnet/sys/kern/kern_poll.c Mon Jan 19 21:27:34 2015 (r277397, copy source)
+++ projects/ifnet/sys/net/if_polling.c Mon Jan 19 21:40:13 2015 (r277399)
@@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$");
void hardclock_device_poll(void); /* hook from hardclock */
static struct mtx poll_mtx;
+static MALLOC_DEFINE(M_IFPOLLING, "ifpoll", "interface polling table");
/*
* Polling support for [network] device drivers.
@@ -244,14 +245,33 @@ static uint32_t idlepoll_sleeping; /* id
SYSCTL_UINT(_kern_polling, OID_AUTO, idlepoll_sleeping, CTLFLAG_RD,
&idlepoll_sleeping, 0, "idlepoll is sleeping");
+static struct ifnet **poll_table;
+static u_int poll_indexlim;
-#define POLL_LIST_LEN 128
-struct pollrec {
- poll_handler_t *handler;
- struct ifnet *ifp;
-};
+static void
+poll_grow(void)
+{
+ int oldlim;
+ u_int n;
+ struct ifnet **e;
-static struct pollrec pr[POLL_LIST_LEN];
+ mtx_assert(&poll_mtx, MA_OWNED);
+ oldlim = poll_indexlim;
+ mtx_unlock(&poll_mtx);
+ n = (oldlim << 1) * sizeof(*e);
+ e = malloc(n, M_IFPOLLING, M_WAITOK | M_ZERO);
+ mtx_lock(&poll_mtx);
+ if (poll_indexlim != oldlim) {
+ free(e, M_IFPOLLING);
+ return;
+ }
+ if (poll_table != NULL) {
+ memcpy(e, poll_table, n/2);
+ free(poll_table, M_IFPOLLING);
+ }
+ poll_indexlim <<= 1;
+ poll_table = e;
+}
static void
poll_shutdown(void *arg, int howto)
@@ -338,7 +358,7 @@ ether_poll(int count)
count = poll_each_burst;
for (i = 0 ; i < poll_handlers ; i++)
- pr[i].handler(pr[i].ifp, POLL_ONLY, count);
+ if_poll(poll_table[i], POLL_ONLY, count);
mtx_unlock(&poll_mtx);
}
@@ -445,91 +465,45 @@ netisr_poll(void)
residual_burst -= cycles;
for (i = 0 ; i < poll_handlers ; i++)
- pr[i].handler(pr[i].ifp, arg, cycles);
+ if_poll(poll_table[i], POLL_ONLY, cycles);
phase = 4;
mtx_unlock(&poll_mtx);
}
/*
- * Try to register routine for polling. Returns 0 if successful
- * (and polling should be enabled), error code otherwise.
- * A device is not supposed to register itself multiple times.
- *
- * This is called from within the *_ioctl() functions.
+ * Register routine for polling. Called in context of ioctl(2).
*/
-int
-ether_poll_register(poll_handler_t *h, if_t ifp)
+void
+if_poll_register(struct ifnet *ifp)
{
- int i;
-
- KASSERT(h != NULL, ("%s: handler is NULL", __func__));
- KASSERT(ifp != NULL, ("%s: ifp is NULL", __func__));
mtx_lock(&poll_mtx);
- if (poll_handlers >= POLL_LIST_LEN) {
- /*
- * List full, cannot register more entries.
- * This should never happen; if it does, it is probably a
- * broken driver trying to register multiple times. Checking
- * this at runtime is expensive, and won't solve the problem
- * anyways, so just report a few times and then give up.
- */
- static int verbose = 10 ;
- if (verbose >0) {
- log(LOG_ERR, "poll handlers list full, "
- "maybe a broken driver ?\n");
- verbose--;
- }
- mtx_unlock(&poll_mtx);
- return (ENOMEM); /* no polling for you */
- }
-
- for (i = 0 ; i < poll_handlers ; i++)
- if (pr[i].ifp == ifp && pr[i].handler != NULL) {
- mtx_unlock(&poll_mtx);
- log(LOG_DEBUG, "ether_poll_register: %s: handler"
- " already registered\n", ifp->if_xname);
- return (EEXIST);
- }
-
- pr[poll_handlers].handler = h;
- pr[poll_handlers].ifp = ifp;
- poll_handlers++;
+ if (poll_handlers >= poll_indexlim)
+ poll_grow();
+ poll_table[poll_handlers++] = ifp;
mtx_unlock(&poll_mtx);
if (idlepoll_sleeping)
wakeup(&idlepoll_sleeping);
- return (0);
}
/*
- * Remove interface from the polling list. Called from *_ioctl(), too.
+ * Remove interface from the polling list. Called from ioctl(2), too.
*/
-int
-ether_poll_deregister(if_t ifp)
+void
+if_poll_deregister(struct ifnet *ifp)
{
int i;
- KASSERT(ifp != NULL, ("%s: ifp is NULL", __func__));
-
mtx_lock(&poll_mtx);
-
for (i = 0 ; i < poll_handlers ; i++)
- if (pr[i].ifp == ifp) /* found it */
+ if (poll_table[i] == ifp) /* found it */
break;
- if (i == poll_handlers) {
- log(LOG_DEBUG, "ether_poll_deregister: %s: not found!\n",
- ifp->if_xname);
- mtx_unlock(&poll_mtx);
- return (ENOENT);
- }
+ KASSERT(i < poll_handlers, ("%s: can't find %p", __func__, ifp));
poll_handlers--;
- if (i < poll_handlers) { /* Last entry replaces this one. */
- pr[i].handler = pr[poll_handlers].handler;
- pr[i].ifp = pr[poll_handlers].ifp;
- }
+ if (i < poll_handlers) /* Last entry replaces this one. */
+ poll_table[i] = poll_table[poll_handlers];
mtx_unlock(&poll_mtx);
- return (0);
}
static void
Modified: projects/ifnet/sys/net/if_var.h
==============================================================================
--- projects/ifnet/sys/net/if_var.h Mon Jan 19 21:30:40 2015 (r277398)
+++ projects/ifnet/sys/net/if_var.h Mon Jan 19 21:40:13 2015 (r277399)
@@ -424,12 +424,9 @@ void if_tsomax_common(const struct iftso
int if_tsomax_update(if_t ifp, const struct iftsomax *);
#ifdef DEVICE_POLLING
-enum poll_cmd { POLL_ONLY, POLL_AND_CHECK_STATUS };
-
-typedef int poll_handler_t(if_t ifp, enum poll_cmd cmd, int count);
-int ether_poll_register(poll_handler_t *h, if_t ifp);
-int ether_poll_deregister(if_t ifp);
-#endif /* DEVICE_POLLING */
+void if_poll_register(struct ifnet *ifp);
+void if_poll_deregister(struct ifnet *ifp);
+#endif
/*
* Wrappers around ifops. Some ops are optional and can be NULL,
@@ -515,6 +512,15 @@ if_reassign(if_t ifp, struct vnet *new)
return (ifp->if_ops->ifop_reassign(ifp, new));
}
+#ifdef DEVICE_POLLING
+static inline int
+if_poll(if_t ifp, enum poll_cmd cmd, int count)
+{
+
+ return (ifp->if_ops->ifop_poll(ifp, cmd, count));
+}
+#endif
+
/*
* Inliners to shorten code, and make protocols more ifnet-agnostic.
*/
More information about the svn-src-projects
mailing list