Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 19 Jan 2015 21:40:14 +0000 (UTC)
From:      Gleb Smirnoff <glebius@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r277399 - in projects/ifnet/sys: conf dev/bge dev/xl kern net
Message-ID:  <201501192140.t0JLeEDg063481@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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.
  */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201501192140.t0JLeEDg063481>