[REVIEW/TEST] polling(4) changes

Gleb Smirnoff glebius at FreeBSD.org
Fri Sep 30 09:03:06 PDT 2005


On Fri, Sep 30, 2005 at 04:40:00PM +0400, Gleb Smirnoff wrote:
T>   [please, follow-up on net@ only]
T> 
T>   Colleagues,
T> 
T>   here are some patches for review.

I have some changes to patch after last compile, and haven't tested them 
befire sending patch. Here is an updated one.

-- 
Totus tuus, Glebius.
GLEBIUS-RIPN GLEB-RIPE
-------------- next part --------------
Index: amd64/amd64/trap.c
===================================================================
RCS file: /home/ncvs/src/sys/amd64/amd64/trap.c,v
retrieving revision 1.293
diff -u -r1.293 trap.c
--- amd64/amd64/trap.c	28 Sep 2005 07:03:02 -0000	1.293
+++ amd64/amd64/trap.c	29 Sep 2005 09:41:32 -0000
@@ -146,11 +146,6 @@
 extern char *syscallnames[];
 #endif
 
-#ifdef DEVICE_POLLING
-extern u_int32_t poll_in_trap;
-extern int ether_poll(int count);
-#endif /* DEVICE_POLLING */
-
 /*
  * Exception, fault, and trap interface to the FreeBSD kernel.
  * This common code is called from assembly language IDT gate entry
@@ -241,11 +236,6 @@
 			trap_fatal(&frame, frame.tf_addr);
 	}
 
-#ifdef	DEVICE_POLLING
-	if (poll_in_trap)
-		ether_poll(poll_in_trap);
-#endif	/* DEVICE_POLLING */
-
         if (ISPL(frame.tf_cs) == SEL_UPL) {
 		/* user trap */
 
Index: dev/em/if_em.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/em/if_em.c,v
retrieving revision 1.73
diff -u -r1.73 if_em.c
--- dev/em/if_em.c	29 Sep 2005 13:23:34 -0000	1.73
+++ dev/em/if_em.c	30 Sep 2005 15:17:05 -0000
@@ -197,6 +197,9 @@
 static void em_add_int_delay_sysctl(struct adapter *, const char *,
 				    const char *, struct em_int_delay_info *,
 				    int, int);
+#ifdef DEVICE_POLLING
+static poll_handler_t em_poll;
+#endif
 
 /*********************************************************************
  *  FreeBSD Device Interface Entry Points                    
@@ -526,6 +529,11 @@
 
 	INIT_DEBUGOUT("em_detach: begin");
 
+#ifdef DEVICE_POLLING
+	if (ifp->if_capenable & IFCAP_POLLING)
+		ether_poll_deregister(ifp);
+#endif
+
 	EM_LOCK(adapter);
 	adapter->in_detach = 1;
 	em_stop(adapter);
@@ -717,7 +725,7 @@
 				em_initialize_receive_unit(adapter);
 			}
 #ifdef DEVICE_POLLING
-                        if (!(ifp->if_flags & IFF_POLLING))
+                        if (!(ifp->if_capenable & IFCAP_POLLING))
 #endif
 				em_enable_intr(adapter);
 			EM_UNLOCK(adapter);
@@ -732,8 +740,26 @@
 		IOCTL_DEBUGOUT("ioctl rcv'd: SIOCSIFCAP (Set Capabilities)");
 		reinit = 0;
 		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
-		if (mask & IFCAP_POLLING)
-			ifp->if_capenable ^= IFCAP_POLLING;
+#ifdef DEVICE_POLLING
+		if (mask & IFCAP_POLLING) {
+			if (ifr->ifr_reqcap & IFCAP_POLLING) {
+				error = ether_poll_register(em_poll, ifp);
+				if (error)
+					return(error);
+				EM_LOCK(adapter);
+				em_disable_intr(adapter);
+				ifp->if_capenable |= IFCAP_POLLING;
+				EM_UNLOCK(adapter);
+			} else {
+				error = ether_poll_deregister(ifp);
+				/* Enable interrupt even in error case */
+				EM_LOCK(adapter);
+				em_enable_intr(adapter);
+				ifp->if_capenable &= ~IFCAP_POLLING;
+				EM_UNLOCK(adapter);
+			}
+		}
+#endif
 		if (mask & IFCAP_HWCSUM) {
 			ifp->if_capenable ^= IFCAP_HWCSUM;
 			reinit = 1;
@@ -895,7 +921,7 @@
          * Only enable interrupts if we are not polling, make sure
          * they are off otherwise.
          */
-        if (ifp->if_flags & IFF_POLLING)
+        if (ifp->if_capenable & IFCAP_POLLING)
                 em_disable_intr(adapter);
         else
 #endif /* DEVICE_POLLING */
@@ -920,8 +946,6 @@
 
 
 #ifdef DEVICE_POLLING
-static poll_handler_t em_poll;
-        
 static void     
 em_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
 {
@@ -930,14 +954,6 @@
 
 	mtx_assert(&adapter->mtx, MA_OWNED);
 
-	if (!(ifp->if_capenable & IFCAP_POLLING)) {
-		ether_poll_deregister(ifp);
-		cmd = POLL_DEREGISTER;
-	}
-        if (cmd == POLL_DEREGISTER) {       /* final call, enable interrupts */
-                em_enable_intr(adapter);
-                return;
-        }
         if (cmd == POLL_AND_CHECK_STATUS) {
                 reg_icr = E1000_READ_REG(&adapter->hw, ICR);
                 if (reg_icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
@@ -948,13 +964,10 @@
 			callout_reset(&adapter->timer, hz, em_local_timer, adapter);
                 }
         }
-        if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
-                em_process_receive_interrupts(adapter, count);
-                em_clean_transmit_interrupts(adapter);
-        }
+	em_process_receive_interrupts(adapter, count);
+	em_clean_transmit_interrupts(adapter);
 	
-        if (ifp->if_drv_flags & IFF_DRV_RUNNING &&
-	    !IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+        if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
                 em_start_locked(ifp);
 }
         
@@ -964,7 +977,8 @@
         struct adapter *adapter = ifp->if_softc;
 
 	EM_LOCK(adapter);
-	em_poll_locked(ifp, cmd, count);
+	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+		em_poll_locked(ifp, cmd, count);
 	EM_UNLOCK(adapter);
 }
 #endif /* DEVICE_POLLING */
@@ -987,18 +1001,10 @@
         ifp = adapter->ifp;  
 
 #ifdef DEVICE_POLLING
-        if (ifp->if_flags & IFF_POLLING) {
+        if (ifp->if_capenable & IFCAP_POLLING) {
 		EM_UNLOCK(adapter);
                 return;
 	}
-
-	if ((ifp->if_capenable & IFCAP_POLLING) &&
-	    ether_poll_register(em_poll, ifp)) {
-                em_disable_intr(adapter);
-                em_poll_locked(ifp, 0, 1);
-		EM_UNLOCK(adapter);
-                return;
-        }
 #endif /* DEVICE_POLLING */
 
 	reg_icr = E1000_READ_REG(&adapter->hw, ICR);
@@ -1718,9 +1724,7 @@
 	mtx_assert(&adapter->mtx, MA_OWNED);
 
 	INIT_DEBUGOUT("em_stop: begin");
-#ifdef DEVICE_POLLING
-	ether_poll_deregister(ifp);
-#endif
+
 	em_disable_intr(adapter);
 	em_reset_hw(&adapter->hw);
 	callout_stop(&adapter->timer);
@@ -1976,7 +1980,6 @@
 
 #ifdef DEVICE_POLLING
 	ifp->if_capabilities |= IFCAP_POLLING;
-	ifp->if_capenable |= IFCAP_POLLING;
 #endif
 
 	/* 
Index: dev/fxp/if_fxp.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/fxp/if_fxp.c,v
retrieving revision 1.247
diff -u -r1.247 if_fxp.c
--- dev/fxp/if_fxp.c	27 Sep 2005 09:01:10 -0000	1.247
+++ dev/fxp/if_fxp.c	30 Sep 2005 15:37:08 -0000
@@ -773,7 +773,6 @@
 #ifdef DEVICE_POLLING
 	/* Inform the world we support polling. */
 	ifp->if_capabilities |= IFCAP_POLLING;
-	ifp->if_capenable |= IFCAP_POLLING;
 #endif
 
 	/*
@@ -891,6 +890,11 @@
 {
 	struct fxp_softc *sc = device_get_softc(dev);
 
+#ifdef DEVICE_POLLING
+	if (sc->ifp->if_capenable & IFCAP_POLLING)   
+		ether_poll_deregister(sc->ifp);
+#endif
+
 	FXP_LOCK(sc);
 	sc->suspended = 1;	/* Do same thing as we do for suspend */
 	/*
@@ -1448,15 +1452,11 @@
 	uint8_t statack;
 
 	FXP_LOCK(sc);
-	if (!(ifp->if_capenable & IFCAP_POLLING)) {
-		ether_poll_deregister(ifp);
-		cmd = POLL_DEREGISTER;
-	}
-	if (cmd == POLL_DEREGISTER) {	/* final call, enable interrupts */
-		CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, 0);
+	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
 		FXP_UNLOCK(sc);
 		return;
 	}
+
 	statack = FXP_SCB_STATACK_CXTNO | FXP_SCB_STATACK_CNA |
 	    FXP_SCB_STATACK_FR;
 	if (cmd == POLL_AND_CHECK_STATUS) {
@@ -1495,18 +1495,10 @@
 	}
 
 #ifdef DEVICE_POLLING
-	if (ifp->if_flags & IFF_POLLING) {
+	if (ifp->if_capenable & IFCAP_POLLING) {
 		FXP_UNLOCK(sc);
 		return;
 	}
-	if ((ifp->if_capenable & IFCAP_POLLING) &&
-	    ether_poll_register(fxp_poll, ifp)) {
-		/* disable interrupts */
-		CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, FXP_SCB_INTR_DISABLE);
-		FXP_UNLOCK(sc);
-		fxp_poll(ifp, 0, 1);
-		return;
-	}
 #endif
 	while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) {
 		/*
@@ -1837,9 +1829,6 @@
 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
 	ifp->if_timer = 0;
 
-#ifdef DEVICE_POLLING
-	ether_poll_deregister(ifp);
-#endif
 	/*
 	 * Cancel stats updater.
 	 */
@@ -2163,7 +2152,7 @@
 	 * ... but only do that if we are not polling. And because (presumably)
 	 * the default is interrupts on, we need to disable them explicitly!
 	 */
-	if ( ifp->if_flags & IFF_POLLING )
+	if (ifp->if_capenable & IFCAP_POLLING )
 		CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, FXP_SCB_INTR_DISABLE);
 	else
 #endif /* DEVICE_POLLING */
@@ -2418,11 +2407,30 @@
 		break;
 
 	case SIOCSIFCAP:
-		FXP_LOCK(sc);
 		mask = ifp->if_capenable ^ ifr->ifr_reqcap;
-		if (mask & IFCAP_POLLING)
-			ifp->if_capenable ^= IFCAP_POLLING;
+#ifdef DEVICE_POLLING
+		if (mask & IFCAP_POLLING) {
+			if (ifr->ifr_reqcap & IFCAP_POLLING) {
+				error = ether_poll_register(fxp_poll, ifp);
+				if (error)
+					return(error);
+				FXP_LOCK(sc);
+				CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL,
+				    FXP_SCB_INTR_DISABLE);
+				ifp->if_capenable |= IFCAP_POLLING;
+				FXP_UNLOCK(sc);
+			} else {
+				error = ether_poll_deregister(ifp);
+				/* Enable interrupts in any case */
+				FXP_LOCK(sc);
+				CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, 0);
+				ifp->if_capenable &= ~IFCAP_POLLING;
+				FXP_UNLOCK(sc);
+			}
+		}
+#endif
 		if (mask & IFCAP_VLAN_MTU) {
+			FXP_LOCK(sc);
 			ifp->if_capenable ^= IFCAP_VLAN_MTU;
 			if (sc->revision != FXP_REV_82557)
 				flag = FXP_FLAG_LONG_PKT_EN;
@@ -2431,8 +2439,8 @@
 			sc->flags ^= flag;
 			if (ifp->if_flags & IFF_UP)
 				fxp_init_body(sc);
+			FXP_UNLOCK(sc);
 		}
-		FXP_UNLOCK(sc);
 		break;
 
 	default:
Index: i386/i386/trap.c
===================================================================
RCS file: /home/ncvs/src/sys/i386/i386/trap.c,v
retrieving revision 1.280
diff -u -r1.280 trap.c
--- i386/i386/trap.c	28 Sep 2005 07:03:03 -0000	1.280
+++ i386/i386/trap.c	29 Sep 2005 09:42:21 -0000
@@ -160,11 +160,6 @@
 extern char *syscallnames[];
 #endif
 
-#ifdef DEVICE_POLLING
-extern u_int32_t poll_in_trap;
-extern int ether_poll(int count);
-#endif /* DEVICE_POLLING */
-
 /*
  * Exception, fault, and trap interface to the FreeBSD kernel.
  * This common code is called from assembly language IDT gate entry
@@ -272,11 +267,6 @@
 			trap_fatal(&frame, eva);
 	}
 
-#ifdef	DEVICE_POLLING
-	if (poll_in_trap)
-		ether_poll(poll_in_trap);
-#endif	/* DEVICE_POLLING */
-
         if ((ISPL(frame.tf_cs) == SEL_UPL) ||
 	    ((frame.tf_eflags & PSL_VM) && 
 		!(PCPU_GET(curpcb)->pcb_flags & PCB_VM86CALL))) {
Index: kern/kern_poll.c
===================================================================
RCS file: /home/ncvs/src/sys/kern/kern_poll.c,v
retrieving revision 1.22
diff -u -r1.22 kern_poll.c
--- kern/kern_poll.c	6 Sep 2005 11:09:18 -0000	1.22
+++ kern/kern_poll.c	30 Sep 2005 14:52:25 -0000
@@ -32,6 +32,7 @@
 #include <sys/systm.h>
 #include <sys/kernel.h>
 #include <sys/socket.h>			/* needed by net/if.h		*/
+#include <sys/sockio.h>
 #include <sys/sysctl.h>
 #include <sys/syslog.h>
 
@@ -44,14 +45,15 @@
 
 static void netisr_poll(void);		/* the two netisr handlers      */
 static void netisr_pollmore(void);
+static int poll_switch(SYSCTL_HANDLER_ARGS);
 
 void hardclock_device_poll(void);	/* hook from hardclock		*/
-void ether_poll(int);			/* polling while in trap	*/
+void ether_poll(int);			/* polling in idle loop		*/
 
 /*
  * Polling support for [network] device drivers.
  *
- * Drivers which support this feature try to register with the
+ * Drivers which support this feature can register with the
  * polling code.
  *
  * If registration is successful, the driver must disable interrupts,
@@ -64,10 +66,6 @@
  *  POLL_AND_CHECK_STATUS: as above, plus check status registers or do
  *	other more expensive operations. This command is issued periodically
  *	but less frequently than POLL_ONLY.
- *  POLL_DEREGISTER: deregister and return to interrupt mode.
- *
- * The first two commands are only issued if the interface is marked as
- * 'IFF_UP and IFF_DRV_RUNNING', the last one only if IFF_DRV_RUNNING is set.
  *
  * The count limit specifies how much work the handler can do during the
  * call -- typically this is the number of packets to be received, or
@@ -75,11 +73,9 @@
  * as the max time spent in the function grows roughly linearly with the
  * count).
  *
- * Deregistration can be requested by the driver itself (typically in the
- * *_stop() routine), or by the polling code, by invoking the handler.
- *
- * Polling can be globally enabled or disabled with the sysctl variable
- * kern.polling.enable (default is 0, disabled)
+ * Polling is enabled and disabled via setting IFCAP_POLLING flag on
+ * the interface. The driver ioctl handler should register interface
+ * with polling and disable interrupts, if registration was successful.
  *
  * A second variable controls the sharing of CPU between polling/kernel
  * network processing, and other activities (typically userlevel tasks):
@@ -91,7 +87,7 @@
  * The following constraints hold
  *
  *	1 <= poll_each_burst <= poll_burst <= poll_burst_max
- *	0 <= poll_in_trap <= poll_each_burst
+ *	0 <= poll_each_burst
  *	MIN_POLL_BURST_MAX <= poll_burst_max <= MAX_POLL_BURST_MAX
  */
 
@@ -117,10 +113,6 @@
 SYSCTL_UINT(_kern_polling, OID_AUTO, idle_poll, CTLFLAG_RW,
 	&poll_in_idle_loop, 0, "Enable device polling in idle loop");
 
-u_int32_t poll_in_trap;			/* used in trap.c */
-SYSCTL_UINT(_kern_polling, OID_AUTO, poll_in_trap, CTLFLAG_RW,
-	&poll_in_trap, 0, "Poll burst size during a trap");
-
 static u_int32_t user_frac = 50;
 SYSCTL_UINT(_kern_polling, OID_AUTO, user_frac, CTLFLAG_RW,
 	&user_frac, 0, "Desired user fraction of cpu time");
@@ -149,9 +141,9 @@
 SYSCTL_UINT(_kern_polling, OID_AUTO, handlers, CTLFLAG_RD,
 	&poll_handlers, 0, "Number of registered poll handlers");
 
-static int polling = 0;		/* global polling enable */
-SYSCTL_UINT(_kern_polling, OID_AUTO, enable, CTLFLAG_RW,
-	&polling, 0, "Polling enabled");
+static int polling = 0;
+SYSCTL_PROC(_kern_polling, OID_AUTO, enable, CTLTYPE_UINT | CTLFLAG_RW,
+	0, sizeof(int), poll_switch, "I", "Switch polling for all interfaces");
 
 static u_int32_t phase;
 SYSCTL_UINT(_kern_polling, OID_AUTO, phase, CTLFLAG_RW,
@@ -174,23 +166,9 @@
 struct pollrec {
 	poll_handler_t	*handler;
 	struct ifnet	*ifp;
-	/*
-	 * Flags of polling record (protected by poll_mtx).
-	 * PRF_RUNNING means that the handler is now executing.
-	 * PRF_LEAVING means that the handler is now deregistering.
-	 */
-#define	PRF_RUNNING	0x1
-#define	PRF_LEAVING	0x2
-	uint32_t	flags;
 };
 
 static struct pollrec pr[POLL_LIST_LEN];
-
-#define	PR_VALID(i)	(pr[(i)].handler != NULL &&			\
-			!(pr[(i)].flags & (PRF_RUNNING|PRF_LEAVING)) &&	\
-			(pr[(i)].ifp->if_drv_flags & IFF_DRV_RUNNING) &&\
-			(pr[(i)].ifp->if_flags & IFF_UP))
-
 static struct mtx	poll_mtx;
 
 static void
@@ -258,30 +236,24 @@
 }
 
 /*
- * ether_poll is called from the idle loop or from the trap handler.
+ * ether_poll is called from the idle loop.
  */
 void
 ether_poll(int count)
 {
 	int i;
 
+	NET_LOCK_GIANT();
 	mtx_lock(&poll_mtx);
 
 	if (count > poll_each_burst)
 		count = poll_each_burst;
 
-	for (i = 0 ; i < poll_handlers ; i++) {
-		if (PR_VALID(i)) {
-			pr[i].flags |= PRF_RUNNING;
-			mtx_unlock(&poll_mtx);
-			NET_LOCK_GIANT();
-			pr[i].handler(pr[i].ifp, POLL_ONLY, count);
-			NET_UNLOCK_GIANT();
-			mtx_lock(&poll_mtx);
-			pr[i].flags &= ~PRF_RUNNING;
-		}
-	}
+	for (i = 0 ; i < poll_handlers ; i++)
+		pr[i].handler(pr[i].ifp, POLL_ONLY, count);
+
 	mtx_unlock(&poll_mtx);
+	NET_UNLOCK_GIANT();
 }
 
 /*
@@ -403,60 +375,29 @@
 		residual_burst : poll_each_burst;
 	residual_burst -= cycles;
 
-	if (polling) {
-		for (i = 0 ; i < poll_handlers ; i++) {
-			if (PR_VALID(i)) {
-				pr[i].flags |= PRF_RUNNING;
-				mtx_unlock(&poll_mtx);
-				pr[i].handler(pr[i].ifp, arg, cycles);
-				mtx_lock(&poll_mtx);
-				pr[i].flags &= ~PRF_RUNNING;
-			}
-		}
-	} else {	/* unregister */
-		for (i = 0 ; i < poll_handlers ; i++) {
-			if (pr[i].handler != NULL &&
-			    pr[i].ifp->if_drv_flags & IFF_DRV_RUNNING) {
-				pr[i].ifp->if_flags &= ~IFF_POLLING;
-				pr[i].flags |= PRF_LEAVING;
-				mtx_unlock(&poll_mtx);
-				pr[i].handler(pr[i].ifp, POLL_DEREGISTER, 1);
-				mtx_lock(&poll_mtx);
-				pr[i].flags &= ~PRF_LEAVING;
-			}
-			pr[i].handler = NULL;
-		}
-		residual_burst = 0;
-		poll_handlers = 0;
-	}
+	for (i = 0 ; i < poll_handlers ; i++)
+		pr[i].handler(pr[i].ifp, arg, cycles);
 
 	phase = 4;
 	mtx_unlock(&poll_mtx);
 }
 
 /*
- * Try to register routine for polling. Returns 1 if successful
- * (and polling should be enabled), 0 otherwise.
+ * 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 *_intr() functions, so we do not need
- * further ifnet locking.
+ * This is called from within the *_ioctl() functions.
  */
 int
 ether_poll_register(poll_handler_t *h, struct ifnet *ifp)
 {
 	int i;
 
-	NET_ASSERT_GIANT();
+	KASSERT(h != NULL, ("%s: handler is NULL", __func__));
+	KASSERT(ifp != NULL, ("%s: ifp is NULL", __func__));
 
-	if (polling == 0) /* polling disabled, cannot register */
-		return 0;
-	if (h == NULL || ifp == NULL)		/* bad arguments	*/
-		return 0;
-	if ( !(ifp->if_flags & IFF_UP) )	/* must be up		*/
-		return 0;
-	if (ifp->if_flags & IFF_POLLING)	/* already polling	*/
-		return 0;
+	NET_ASSERT_GIANT();
 
 	mtx_lock(&poll_mtx);
 	if (poll_handlers >= POLL_LIST_LEN) {
@@ -474,7 +415,7 @@
 			verbose--;
 		}
 		mtx_unlock(&poll_mtx);
-		return 0; /* no polling for you */
+		return (ENOMEM); /* no polling for you */
 	}
 
 	for (i = 0 ; i < poll_handlers ; i++)
@@ -482,45 +423,39 @@
 			mtx_unlock(&poll_mtx);
 			log(LOG_DEBUG, "ether_poll_register: %s: handler"
 			    " already registered\n", ifp->if_xname);
-			return (0);
+			return (EEXIST);
 		}
 
 	pr[poll_handlers].handler = h;
 	pr[poll_handlers].ifp = ifp;
 	poll_handlers++;
-	ifp->if_flags |= IFF_POLLING;
 	mtx_unlock(&poll_mtx);
 	if (idlepoll_sleeping)
 		wakeup(&idlepoll_sleeping);
-	return 1; /* polling enabled in next call */
+	return (0);
 }
 
 /*
- * 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.
+ * Remove interface from the polling list. Called from *_ioctl(), too.
  */
 int
 ether_poll_deregister(struct ifnet *ifp)
 {
 	int i;
 
-	NET_ASSERT_GIANT();
+	KASSERT(ifp != NULL, ("%s: ifp is NULL", __func__));
 
-	if ( !ifp || !(ifp->if_flags & IFF_POLLING) ) {
-		return 0;
-	}
+	NET_ASSERT_GIANT();
 	mtx_lock(&poll_mtx);
+
 	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(&poll_mtx);
 		log(LOG_DEBUG, "ether_poll_deregister: %s: not found!\n",
 		    ifp->if_xname);
-		return (0);
+		mtx_unlock(&poll_mtx);
+		return (ENOENT);
 	}
 	poll_handlers--;
 	if (i < poll_handlers) { /* Last entry replaces this one. */
@@ -528,7 +463,60 @@
 		pr[i].ifp = pr[poll_handlers].ifp;
 	}
 	mtx_unlock(&poll_mtx);
-	return (1);
+	return (0);
+}
+
+/*
+ * Legacy interface for turning polling on all interfaces at one time.
+ */
+static int
+poll_switch(SYSCTL_HANDLER_ARGS)
+{
+	struct ifnet *ifp;
+	int error;
+	int val;
+
+	mtx_lock(&poll_mtx);
+	val = polling;
+	mtx_unlock(&poll_mtx);
+
+	error = sysctl_handle_int(oidp, &val, sizeof(int), req);
+	if (error || !req->newptr )
+		return (error);
+
+	if (val == polling)
+		return (0);
+
+	if (val < 0 || val > 1)
+		return (EINVAL);
+
+	mtx_lock(&poll_mtx);
+	polling = val;
+	mtx_unlock(&poll_mtx);
+
+	NET_LOCK_GIANT();
+	IFNET_RLOCK();
+	TAILQ_FOREACH(ifp, &ifnet, if_link) {
+		if (ifp->if_capabilities & IFCAP_POLLING) {
+			struct ifreq ifr;
+
+			if (val == 1)
+				ifr.ifr_reqcap =
+				    ifp->if_capenable | IFCAP_POLLING;
+			else
+				ifr.ifr_reqcap =
+				    ifp->if_capenable & ~IFCAP_POLLING;
+			IFF_LOCKGIANT(ifp);	/* LOR here */
+			(void) (*ifp->if_ioctl)(ifp, SIOCSIFCAP, (caddr_t)&ifr);
+			IFF_UNLOCKGIANT(ifp);
+		}
+	}
+	IFNET_RUNLOCK();
+	NET_UNLOCK_GIANT();
+
+	log(LOG_ERR, "kern.polling.enable is deprecated. Use ifconfig(8)");
+
+	return (0);
 }
 
 static void
Index: net/if.h
===================================================================
RCS file: /home/ncvs/src/sys/net/if.h,v
retrieving revision 1.98
diff -u -r1.98 if.h
--- net/if.h	9 Aug 2005 12:56:20 -0000	1.98
+++ net/if.h	29 Sep 2005 11:25:05 -0000
@@ -148,7 +148,7 @@
 #define	IFF_LINK2	0x4000		/* per link layer defined bit */
 #define	IFF_ALTPHYS	IFF_LINK2	/* use alternate physical connection */
 #define	IFF_MULTICAST	0x8000		/* (i) supports multicast */
-#define	IFF_POLLING	0x10000		/* (n) Interface is in polling mode. */
+/*			0x10000		*/
 #define	IFF_PPROMISC	0x20000		/* (n) user-requested promisc mode */
 #define	IFF_MONITOR	0x40000		/* (n) user-requested monitor mode */
 #define	IFF_STATICARP	0x80000		/* (n) static ARP */
@@ -166,8 +166,7 @@
 /* flags set internally only: */
 #define	IFF_CANTCHANGE \
 	(IFF_BROADCAST|IFF_POINTOPOINT|IFF_DRV_RUNNING|IFF_DRV_OACTIVE|\
-	    IFF_SIMPLEX|IFF_MULTICAST|IFF_ALLMULTI|IFF_SMART|IFF_PROMISC|\
-	    IFF_POLLING)
+	    IFF_SIMPLEX|IFF_MULTICAST|IFF_ALLMULTI|IFF_SMART|IFF_PROMISC)
 
 /*
  * Values for if_link_state.
Index: net/if_var.h
===================================================================
RCS file: /home/ncvs/src/sys/net/if_var.h,v
retrieving revision 1.102
diff -u -r1.102 if_var.h
--- net/if_var.h	9 Aug 2005 10:16:17 -0000	1.102
+++ net/if_var.h	29 Sep 2005 10:19:43 -0000
@@ -660,7 +660,7 @@
     LLADDR((struct sockaddr_dl *) ifaddr_byindex((ifp)->if_index)->ifa_addr)
 
 #ifdef DEVICE_POLLING
-enum poll_cmd {	POLL_ONLY, POLL_AND_CHECK_STATUS, POLL_DEREGISTER };
+enum poll_cmd {	POLL_ONLY, POLL_AND_CHECK_STATUS };
 
 typedef	void poll_handler_t(struct ifnet *ifp, enum poll_cmd cmd, int count);
 int    ether_poll_register(poll_handler_t *h, struct ifnet *ifp);


More information about the freebsd-net mailing list