Per-interface polling(4) status

Ruslan Ermilov ru at FreeBSD.org
Sat Apr 10 15:21:17 PDT 2004


Dear networkers,

Like I mumbled in another email, I've started working on a small
project that (when done) will allow for a per-interface polling(4)
status to be changed in run-time.  Attached is a proof of the
concept patch, that currently has support for the dc(4) driver
only (basically because I have this card plugged into my notebook).

That's how it looks like in the real life.

+ Turning individual polling status off/on:

: # sysctl -n kern.polling.enable
: 1
: # sysctl -n kern.polling.handlers
: 1
: # ifconfig dc0 -polling
: # ifconfig dc0 ether
: dc0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 1500
: 	ether 00:10:a4:c0:c0:45
: # sysctl -n kern.polling.handlers
: 0
: # ifconfig dc0 polling
: # ifconfig dc0 ether
: dc0: flags=18843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,POLLING> mtu 1500
: 	ether 00:10:a4:c0:c0:45
: # sysctl -n kern.polling.handlers
: 1

+ Suspending all polling activity:

: # sysctl -n kern.polling.handlers
: 1
: # sysctl kern.polling.enable=0
: kern.polling.enable: 1 -> 0
: # sysctl -n kern.polling.handlers
: 0
: # ifconfig dc0 ether
: dc0: flags=18843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,POLLING> mtu 1500
: 	ether 00:10:a4:c0:c0:45

(Note that the IFF_POLLING flag on the interface was not flipped,
please seek below for an explanation.)

+ Resuming all polling activity:

: # sysctl kern.polling.enable=1
: kern.polling.enable: 0 -> 1
: # sysctl -n kern.polling.handlers
: 1
: # ifconfig dc0 ether
: dc0: flags=18843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,POLLING> mtu 1500
: 	ether 00:10:a4:c0:c0:45

The patch changes the current meaning of the IFF_POLLING flag
indicating the polling status of this interface to a per-interface
option indicating the willingness of the given interface to
participate in the polling(4).  It's completely under a control of
the configuration software, normally ifconfig(8).

All polling(4) activity can still be suspended by setting the sysctl
kern.polling.enable to zero, and resumed by setting it to non-zero.

Driver notes.  The changes to drivers to catch up with this change
are minimal and consist in:

- Adding the "polling" boolean member to the softc structure,
  indicating if polling is active on this interface (the old
  meaning of the IFF_POLLING flag);

- Replacing the (ifp->if_flags & IFF_POLLING) conditionals with
  (sc->polling);

- Adding a few lines of code to support switching the polling
  status of the interface in the intr() and poll() functions.

Points I'm not sure about, and would like to hear the comments on:

- Should the initial polling status be on or off, on interfaces
  that support it?  The current version of the patch makes it
  off by default.

- Should I add the code to ether_poll_register() to sanity check
  that the interface doesn't attempt to register itself more
  than once?

(As an aside, the patch for kern_poll.c also fixes a minor bug
to ensure that ``poll_burst <= poll_burst_max'' is always true.)


Cheers,
-- 
Ruslan Ermilov
ru at FreeBSD.org
FreeBSD committer
-------------- next part --------------
Index: sbin/ifconfig/ifconfig.c
===================================================================
RCS file: /home/ncvs/src/sbin/ifconfig/ifconfig.c,v
retrieving revision 1.99
diff -u -p -r1.99 ifconfig.c
--- sbin/ifconfig/ifconfig.c	12 Mar 2004 23:52:32 -0000	1.99
+++ sbin/ifconfig/ifconfig.c	9 Apr 2004 20:00:14 -0000
@@ -195,6 +195,8 @@ struct	cmd {
 	{ "-arp",	IFF_NOARP,	setifflags },
 	{ "debug",	IFF_DEBUG,	setifflags },
 	{ "-debug",	-IFF_DEBUG,	setifflags },
+	{ "polling",	IFF_POLLING,	setifflags },
+	{ "-polling",	-IFF_POLLING,	setifflags },
 	{ "promisc",	IFF_PPROMISC,	setifflags },
 	{ "-promisc",	-IFF_PPROMISC,	setifflags },
 	{ "add",	IFF_UP,		notealias },
Index: sys/net/if.h
===================================================================
RCS file: /home/ncvs/src/sys/net/if.h,v
retrieving revision 1.83
diff -u -p -r1.83 if.h
--- sys/net/if.h	31 Oct 2003 18:32:08 -0000	1.83
+++ sys/net/if.h	9 Apr 2004 19:55:15 -0000
@@ -155,8 +155,7 @@ struct if_data {
 /* flags set internally only: */
 #define	IFF_CANTCHANGE \
 	(IFF_BROADCAST|IFF_POINTOPOINT|IFF_RUNNING|IFF_OACTIVE|\
-	    IFF_SIMPLEX|IFF_MULTICAST|IFF_ALLMULTI|IFF_SMART|IFF_PROMISC|\
-	    IFF_POLLING)
+	    IFF_SIMPLEX|IFF_MULTICAST|IFF_ALLMULTI|IFF_SMART|IFF_PROMISC)
 
 /*
  * Some convenience macros used for setting ifi_baudrate.
Index: sys/kern/kern_poll.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_poll.c,v
retrieving revision 1.16
diff -u -p -r1.16 kern_poll.c
--- sys/kern/kern_poll.c	25 Jan 2004 03:54:52 -0000	1.16
+++ sys/kern/kern_poll.c	10 Apr 2004 21:10:12 -0000
@@ -363,6 +363,8 @@ netisr_poll(void)
 			poll_burst_max = MIN_POLL_BURST_MAX;
 		else if (poll_burst_max > MAX_POLL_BURST_MAX)
 			poll_burst_max = MAX_POLL_BURST_MAX;
+		if (poll_burst > poll_burst_max)
+			poll_burst = poll_burst_max;
 
 		if (poll_each_burst < 1)
 			poll_each_burst = 1;
@@ -384,7 +386,6 @@ netisr_poll(void)
 		for (i = 0 ; i < poll_handlers ; i++) {
 			if (pr[i].handler &&
 			    pr[i].ifp->if_flags & IFF_RUNNING) {
-				pr[i].ifp->if_flags &= ~IFF_POLLING;
 				pr[i].handler(pr[i].ifp, POLL_DEREGISTER, 1);
 			}
 			pr[i].handler=NULL;
@@ -416,8 +417,6 @@ ether_poll_register(poll_handler_t *h, s
 		return 0;
 	if ( !(ifp->if_flags & IFF_UP) )	/* must be up		*/
 		return 0;
-	if (ifp->if_flags & IFF_POLLING)	/* already polling	*/
-		return 0;
 
 	s = splhigh();
 	if (poll_handlers >= POLL_LIST_LEN) {
@@ -441,7 +440,6 @@ ether_poll_register(poll_handler_t *h, s
 	pr[poll_handlers].handler = h;
 	pr[poll_handlers].ifp = ifp;
 	poll_handlers++;
-	ifp->if_flags |= IFF_POLLING;
 	splx(s);
 	if (idlepoll_sleeping)
 		wakeup(&idlepoll_sleeping);
@@ -450,9 +448,6 @@ ether_poll_register(poll_handler_t *h, s
 
 /*
  * Remove interface from the polling list. Normally called by *_stop().
- * It is not an error to call it with IFF_POLLING clear, the call is
- * sufficiently rare to be preferable to save the space for the extra
- * test in each driver in exchange of one additional function call.
  */
 int
 ether_poll_deregister(struct ifnet *ifp)
@@ -460,14 +455,13 @@ ether_poll_deregister(struct ifnet *ifp)
 	int i;
 
 	mtx_lock(&Giant);
-	if ( !ifp || !(ifp->if_flags & IFF_POLLING) ) {
+	if (!ifp) {
 		mtx_unlock(&Giant);
 		return 0;
 	}
 	for (i = 0 ; i < poll_handlers ; i++)
 		if (pr[i].ifp == ifp) /* found it */
 			break;
-	ifp->if_flags &= ~IFF_POLLING; /* found or not... */
 	if (i == poll_handlers) {
 		mtx_unlock(&Giant);
 		printf("ether_poll_deregister: ifp not found!!!\n");
Index: sys/pci/if_dc.c
===================================================================
RCS file: /home/ncvs/src/sys/pci/if_dc.c,v
retrieving revision 1.141
diff -u -p -r1.141 if_dc.c
--- sys/pci/if_dc.c	17 Mar 2004 17:50:53 -0000	1.141
+++ sys/pci/if_dc.c	10 Apr 2004 21:12:01 -0000
@@ -2747,7 +2747,7 @@ dc_rxeof(struct dc_softc *sc)
 	while (!(le32toh(sc->dc_ldata->dc_rx_list[i].dc_status) &
 	    DC_RXSTAT_OWN)) {
 #ifdef DEVICE_POLLING
-		if (ifp->if_flags & IFF_POLLING) {
+		if (sc->polling) {
 			if (sc->rxcycles <= 0)
 				break;
 			sc->rxcycles--;
@@ -3083,7 +3083,12 @@ dc_poll(struct ifnet *ifp, enum poll_cmd
 {
 	struct dc_softc *sc = ifp->if_softc;
 
+	if (!(ifp->if_flags & IFF_POLLING)) {
+		ether_poll_deregister(ifp);
+		cmd = POLL_DEREGISTER;
+	}
 	if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */
+		sc->polling = 0;
 		/* Re-enable interrupts. */
 		CSR_WRITE_4(sc, DC_IMR, DC_INTRS);
 		return;
@@ -3151,9 +3156,12 @@ dc_intr(void *arg)
 	DC_LOCK(sc);
 	ifp = &sc->arpcom.ac_if;
 #ifdef DEVICE_POLLING
-	if (ifp->if_flags & IFF_POLLING)
+	if (sc->polling)
 		goto done;
-	if (ether_poll_register(dc_poll, ifp)) { /* ok, disable interrupts */
+	if ((ifp->if_flags & IFF_POLLING) &&
+	    ether_poll_register(dc_poll, ifp)) {
+		/* ok, disable interrupts */
+		sc->polling = 1;
 		CSR_WRITE_4(sc, DC_IMR, 0x00000000);
 		goto done;
 	}
@@ -3544,7 +3552,7 @@ dc_init(void *xsc)
 	 * the case of polling. Some cards (e.g. fxp) turn interrupts on
 	 * after a reset.
 	 */
-	if (ifp->if_flags & IFF_POLLING)
+	if (sc->polling)
 		CSR_WRITE_4(sc, DC_IMR, 0x00000000);
 	else
 #endif
@@ -3754,7 +3762,10 @@ dc_stop(struct dc_softc *sc)
 
 	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
 #ifdef DEVICE_POLLING
-	ether_poll_deregister(ifp);
+	if (sc->polling) {
+		ether_poll_deregister(ifp);
+		sc->polling = 0;
+	}
 #endif
 
 	DC_CLRBIT(sc, DC_NETCFG, (DC_NETCFG_RX_ON | DC_NETCFG_TX_ON));
Index: sys/pci/if_dcreg.h
===================================================================
RCS file: /home/ncvs/src/sys/pci/if_dcreg.h,v
retrieving revision 1.41
diff -u -p -r1.41 if_dcreg.h
--- sys/pci/if_dcreg.h	8 Jan 2004 06:22:15 -0000	1.41
+++ sys/pci/if_dcreg.h	10 Apr 2004 07:53:23 -0000
@@ -754,6 +754,7 @@ struct dc_softc {
 #endif
 	struct mtx		dc_mtx;
 #ifdef DEVICE_POLLING
+	int			polling;
 	int			rxcycles;	/* ... when polling */
 #endif
 	int			suspended;	/* 0 = normal  1 = suspended */
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 187 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-net/attachments/20040411/d8a36a3f/attachment.bin


More information about the freebsd-net mailing list