Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 27 Oct 2001 00:59:05 -0700
From:      Luigi Rizzo <rizzo@aciri.org>
To:        net@freebsd.org
Subject:   NEW CODE: polling support for device drivers.
Message-ID:  <20011027005905.A72758@iguana.aciri.org>

next in thread | raw e-mail | index | archive | help

--9jxsPFA5p3P2qPhR
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Maybe this can be of some interest to some of you using BSD boxes
as routers, and who are concerned with performance and robustness
to attacks. I would be grateful if some of you could have a look
at this and possibly provide feedback.

The patches attached here (for 4.4, i386 non-SMP) implement
polling-mode operation for (a couple at the moment) network device
drivers.

This mode of operation gives huge performance and stability benefits
under heavy load, at the price of a very modest (in many cases not
noticeable) increase in latency.

On our test box (Pentium 750 MHz, 21143 with "dc" driver), a stock
FreeBSD 4.4 was barely able to forward a single stream of 130kpps
through a 100Mbit interfac (well ok, that is not too bad!), but
the system was very unresponsive, and livelock as soon as you start
a second stream on a second interface.

With polling enabled, the same box could forward 180Kpps and be
completely responsive even when bombed with 4 full speed 100Mbit
stream (about 590Kpps). Your mileage might vary, depending on the
number of PCI buses, card type, etc.

Note, this is really a minimal set of diffs, providing the basic
mechanism for polling in the kernel, and very basic patches for a
couple of device driver ("dc" and "fxp").  Next in the works is a
system that limits to a programmable value the fraction of CPU time
spent in a driver context -- right now the tuning is semi-manual.

Instruction follow.

	cheers
	luigi

----------------------------------+-----------------------------------------
 Luigi RIZZO, luigi@iet.unipi.it  . ACIRI/ICSI (on leave from Univ. di Pisa)
 http://www.iet.unipi.it/~luigi/  . 1947 Center St, Berkeley CA 94704
 Phone: (510) 666 2927
----------------------------------+-----------------------------------------

INSTALLATION AND USE

 + make sure you have a device supported by the "dc" or "fxp" driver
   (the latter is not tested 100%, but should work)

 + (cd /sys ; patch < polling.patches )
 + add the following two lines to the kernel config:
	options HZ=1000
	options	XORP_ETHER_POLLING
 + build and install the kernel
 + at runtime use the following sysctl variables to control polling:

    sysctl net.xorp.polling=1	# 1 to enable polling, 0 to disable
    sysctl net.xorp.poll_burst_min=10 # controls cpu allocation

   CPU permitting, the system will forward a minimum of (
   poll_burst_min*HZ ) packets per second per interface, and more
   if there are any CPU cycles available.

   This parameter is only important if you expect to have CPU
   intensive tasks running on the router box -- otherwise, you can
   leave it set to a low value (5...20), and the system will use
   all the spare CPU cycles for forwarding.

   If you expect the system to be loaded, check the max forwarding
   speed setting the parameter to a low value when the system is
   unloaded, and then set the parameter to a suitable value to
   "reserve" the desired amount of CPU to forwarding.

   The additional latency introduced by polling can be as large as
   1/HZ seconds, which is why i suggest using HZ=1000 (corresponding
   to 1ms additional latency in the worst case).

Just for reference, the files touched by this diff are:

sys/conf/options.i386
	option definition

sys/i386/include/asnames.h
sys/net/if.h
sys/net/netisr.h
sys/sys/systm.h
	constants, variable and prototypes (mostly one-line changes)

sys/i386/i386/swtch.s
sys/i386/i386/trap.c
	calls to ether_poll from the idle loop and traps

sys/kern/kern_clock.c
	main polling routines

sys/dev/fxp/if_fxp.c
sys/pci/if_dc.c
sys/pci/if_dcreg.h
	device driver changes

Supporting polling for other devices should be reasonably simple,
following the example of the other two drivers.
---------------------------------------------------------------------

--9jxsPFA5p3P2qPhR
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="stable.xorp.diff.011026c"

Index: conf/options.i386
===================================================================
RCS file: /home/xorpc/u2/freebsd/src/sys/conf/options.i386,v
retrieving revision 1.132.2.8
diff -u -r1.132.2.8 options.i386
--- conf/options.i386	2001/10/03 07:15:37	1.132.2.8
+++ conf/options.i386	2001/10/27 00:23:01
@@ -208,5 +208,10 @@
 SMBFS
 
 # -------------------------------
+# Xorp stuff
+# -------------------------------
+XORP_ETHER_POLLING	opt_global.h
+
+# -------------------------------
 # EOF
 # -------------------------------
Index: dev/fxp/if_fxp.c
===================================================================
RCS file: /home/xorpc/u2/freebsd/src/sys/dev/fxp/if_fxp.c,v
retrieving revision 1.110.2.7
diff -u -r1.110.2.7 if_fxp.c
--- dev/fxp/if_fxp.c	2001/08/31 02:17:02	1.110.2.7
+++ dev/fxp/if_fxp.c	2001/10/27 00:31:29
@@ -1123,6 +1123,39 @@
 	}
 }
 
+static void fxp_intr_body(struct fxp_softc *sc, u_int8_t statack, int count);
+
+#ifdef XORP_ETHER_POLLING
+static poll_handler_t fxp_poll;
+
+static void
+fxp_poll(void *xsc, int cmd, int count)  
+{
+	struct fxp_softc *sc = xsc;
+	u_int8_t statack ;
+
+	statack = FXP_SCB_STATACK_CXTNO | FXP_SCB_STATACK_CNA |
+		FXP_SCB_STATACK_FR ;
+	if (cmd == 1) {
+		u_int8_t tmp ;
+		tmp = CSR_READ_1(sc, FXP_CSR_SCB_STATACK);
+		if (tmp == 0xff || tmp == 0)
+			return ; /* nothing to do */
+		tmp &= ~statack ;
+		/* ack what we can */
+		if (tmp != 0)
+			CSR_WRITE_1(sc, FXP_CSR_SCB_STATACK, tmp);
+		statack |= tmp ;
+	}
+	fxp_intr_body(sc, statack, count);
+	if (cmd == 2) {
+		sc->sc_if.if_ipending &= ~IFF_POLLING ;
+		/* enable interrupt */
+		CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, 0);
+	}
+}
+#endif /* XORP_ETHER_POLLING */
+
 /*
  * Process interface interrupts.
  */
@@ -1137,6 +1170,18 @@
 		return;
 	}
 
+#ifdef XORP_ETHER_POLLING
+	if (ifp->if_ipending & IFF_POLLING)
+		return ;
+	if (ether_poll_register(fxp_poll, xsc)) {
+		ifp->if_ipending |= IFF_POLLING ;
+		/* disable interrupts */
+		CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, FXP_SCB_INTR_DISABLE);
+		fxp_poll(xsc, 0, poll_burst);
+		return ;
+	}
+#endif
+
 	while ((statack = CSR_READ_1(sc, FXP_CSR_SCB_STATACK)) != 0) {
 		/*
 		 * It should not be possible to have all bits set; the
@@ -1151,6 +1196,14 @@
 		 * First ACK all the interrupts in this pass.
 		 */
 		CSR_WRITE_1(sc, FXP_CSR_SCB_STATACK, statack);
+		fxp_intr_body(sc, statack, -1);
+	}
+}
+
+static void
+fxp_intr_body(struct fxp_softc *sc, u_int8_t statack, int count)
+{
+	struct ifnet *ifp = &sc->sc_if;
 
 		/*
 		 * Free any finished transmit mbuf chains.
@@ -1201,7 +1254,9 @@
 			m = sc->rfa_headm;
 			rfa = (struct fxp_rfa *)(m->m_ext.ext_buf +
 			    RFA_ALIGNMENT_FUDGE);
-
+#ifdef XORP_ETHER_POLLING /* loop at most count times if count >=0 */
+			if (count < 0 || count-- > 0)
+#endif
 			if (rfa->rfa_status & FXP_RFA_STATUS_C) {
 				/*
 				 * Remove first packet from the chain.
@@ -1258,7 +1313,6 @@
 				fxp_scb_cmd(sc, FXP_SCB_COMMAND_RU_START);
 			}
 		}
-	}
 }
 
 /*
Index: i386/i386/swtch.s
===================================================================
RCS file: /home/xorpc/u2/freebsd/src/sys/i386/i386/swtch.s,v
retrieving revision 1.89.2.4
diff -u -r1.89.2.4 swtch.s
--- i386/i386/swtch.s	2001/07/26 02:29:10	1.89.2.4
+++ i386/i386/swtch.s	2001/10/26 21:54:19
@@ -246,6 +246,17 @@
 	call	_procrunnable
 	testl	%eax,%eax
 	CROSSJUMP(jnz, sw1a, jz)
+#ifdef	XORP_ETHER_POLLING
+	incl	_idle_done
+	pushl	_poll_burst
+	call	_ether_poll
+	addl	$4,%esp
+	sti
+	nop
+	cli
+	testl   %eax, %eax
+	jnz     idle_loop
+#endif
 	call	_vm_page_zero_idle
 	testl	%eax, %eax
 	jnz	idle_loop
Index: i386/i386/trap.c
===================================================================
RCS file: /home/xorpc/u2/freebsd/src/sys/i386/i386/trap.c,v
retrieving revision 1.147.2.5
diff -u -r1.147.2.5 trap.c
--- i386/i386/trap.c	2001/08/15 01:23:50	1.147.2.5
+++ i386/i386/trap.c	2001/10/26 21:47:16
@@ -266,6 +266,11 @@
 		enable_intr();
 	}
 
+#ifdef	XORP_ETHER_POLLING
+	if (poll_in_trap)
+		ether_poll(poll_in_trap);
+#endif /* XORP_ETHER_POLLING */
+
 #if defined(I586_CPU) && !defined(NO_F00F_HACK)
 restart:
 #endif
Index: i386/include/asnames.h
===================================================================
RCS file: /home/xorpc/u2/freebsd/src/sys/i386/include/Attic/asnames.h,v
retrieving revision 1.44.2.3
diff -u -r1.44.2.3 asnames.h
--- i386/include/asnames.h	2001/09/20 09:29:23	1.44.2.3
+++ i386/include/asnames.h	2001/10/27 00:32:28
@@ -210,6 +210,7 @@
 #define _eintrnames			eintrnames
 #define _end				end
 #define _etext				etext
+#define _ether_poll			ether_poll
 #define _exception			exception
 #define _fast_intr_lock			fast_intr_lock
 #define _fastmove			fastmove
@@ -225,6 +226,7 @@
 #define _get_mplock			get_mplock
 #define _get_syscall_lock		get_syscall_lock
 #define _idle				idle
+#define _idle_done 			idle_done
 #define _ihandlers			ihandlers
 #define _imen				imen
 #define _imen_lock			imen_lock
@@ -266,6 +268,7 @@
 #define _ovbcopy_vector			ovbcopy_vector
 #define _panic				panic
 #define _pc98_system_parameter		pc98_system_parameter
+#define _poll_burst			poll_burst
 #define _poly_div16			poly_div16
 #define _poly_div2			poly_div2
 #define _poly_div4			poly_div4
Index: kern/kern_clock.c
===================================================================
RCS file: /home/xorpc/u2/freebsd/src/sys/kern/kern_clock.c,v
retrieving revision 1.105.2.4
diff -u -r1.105.2.4 kern_clock.c
--- kern/kern_clock.c	2001/02/18 15:29:14	1.105.2.4
+++ kern/kern_clock.c	2001/10/27 00:45:42
@@ -67,6 +67,9 @@
 #include <sys/gmon.h>
 #endif
 
+#ifdef XORP_ETHER_POLLING
+#include <net/netisr.h>	/* for NETISR_POLL */
+#endif
 
 /*
  * Number of timecounters used to implement stable storage
@@ -188,6 +191,10 @@
 	psdiv = pscnt = 1;
 	cpu_initclocks();
 
+#ifdef XORP_ETHER_POLLING
+	register_netisr(NETISR_POLL, ether_poll1);
+#endif
+
 	/*
 	 * Compute profhz/stathz, and fix profhz if needed.
 	 */
@@ -236,6 +243,11 @@
 	tco_forward(0);
 	ticks++;
 
+#ifdef XORP_ETHER_POLLING
+	if (poll_handlers > 0)
+		schednetisr(NETISR_POLL);
+#endif
+
 	/*
 	 * Process callouts at a very low cpu priority, so we don't keep the
 	 * relatively high clock interrupt priority any longer than necessary.
@@ -999,3 +1011,202 @@
 	}
 #endif
 }
+
+#ifdef XORP_ETHER_POLLING
+#ifdef	SMP
+	error -- POLLING and SMP are not compatible yet
+#endif
+/*
+ * Polling support for device drivers.
+ */
+
+SYSCTL_NODE(_net, OID_AUTO, xorp, CTLFLAG_RW, 0, "Xorp parameters");
+
+u_int32_t idle_done;
+SYSCTL_ULONG(_net_xorp, OID_AUTO, idle_done, CTLFLAG_RD,
+	&idle_done, 0, "Have gone in idle_loop");
+
+u_int32_t poll_burst = 5;
+SYSCTL_ULONG(_net_xorp, OID_AUTO, poll_burst, CTLFLAG_RW,
+	&poll_burst, 0, "Current Polling burst size");
+
+u_int32_t poll_burst_min = 5;
+SYSCTL_ULONG(_net_xorp, OID_AUTO, poll_burst_min, CTLFLAG_RW,
+	&poll_burst_min, 0, "Min Polling burst size");
+
+u_int32_t poll_burst_max = 100;
+SYSCTL_ULONG(_net_xorp, OID_AUTO, poll_burst_max, CTLFLAG_RW,
+	&poll_burst_max, 0, "Max Polling burst size");
+
+u_int32_t poll_in_trap;
+SYSCTL_ULONG(_net_xorp, OID_AUTO, poll_in_trap, CTLFLAG_RW,
+	&poll_in_trap, 0, "Poll size while getting a trap ?");
+
+/*
+ * Devices that want to do polling must register for it,
+ * typically from the interrupt service routine, by calling
+ * ether_poll_register(handler, arg).
+ *
+ * The handler is called with 3 arguments: the "arg" passed at register
+ * time (typically a softc pointer), a command (see below) and a count limit.
+ * The command can be one of the following:
+ *  0: quick move of "count" packets from input/output queues.
+ *  1: as above, plus check status registers for errors etc.
+ *  2: unregister and return to interrupt mode.
+ *
+ * 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
+ * transmitted, etc. (drivers are free to interpret this number, as long
+ * as the max time spent in the function grows roughly linearly with the
+ * count).
+ */
+#define POLL_LIST_LEN  128
+struct pollrec {
+	poll_handler_t	*handler ;
+	void            *arg;
+};
+
+static struct pollrec pr[POLL_LIST_LEN];
+u_int32_t poll_handlers; /* next free entry in pr[]. */
+SYSCTL_ULONG(_net_xorp, OID_AUTO, poll_handlers, CTLFLAG_RD,
+	&poll_handlers, 0, "next entry in poll register array");
+
+/*
+ * this sysctl variable globally controls polling
+ */
+static int polling = 0 ;
+SYSCTL_ULONG(_net_xorp, OID_AUTO, polling, CTLFLAG_RW,
+	&polling, 0, "Polling enabled");
+
+
+/*
+ * ether_poll is called from the idle loop.
+ */
+int
+ether_poll(int count)
+{
+    static int i;
+    int s = splimp();
+
+    if (count > poll_burst)
+	count = poll_burst ;
+    if (i >= poll_handlers)
+       i = 0 ;
+    if (pr[i].handler)
+       (*pr[i].handler)(pr[i].arg, 0, count); /* quick check */
+    i++ ;
+    splx(s);
+    return 1; /* more polling */
+}
+
+/*
+ * A simple control loop to adapt the burst size to the CPU load, within
+ * predefined limit. In practice, only the minimum size counts, and should
+ * be small enough not to cause livelock. The actual value depends on
+ * CPU speed, number and type of interfaces, etc. The max size only
+ * serves to reserve some CPU to the polling routines at the beginning
+ * of heavy CPU load, but it rapidly decays to the min value under load.
+ *
+ * A better but more complex controller (to come) will account time spent
+ * in the interrupt/polling routines and tries to match it with a
+ * user-programmable threshold.
+ */
+static void update_poll_burst(void);
+
+static void
+update_poll_burst(void)
+{
+    static u_int32_t ready = 0 ; /* act when ready==0 */
+
+    if (ready-- > 0)
+	return ;
+    ready = hz/20 ;
+    if (poll_burst_min >= poll_burst_max)
+	poll_burst_min = poll_burst_max/2 ;
+    if (poll_burst_min > 50)
+	poll_burst_min = 50 ;
+    else if (poll_burst_min < 1)
+	poll_burst_min = 1 ;
+    if (idle_done > 0) {
+	if (poll_burst < poll_burst_max)
+	    poll_burst++ ;
+	else
+	    poll_burst = poll_burst_max;
+    } else { /* decreasing */
+	if (poll_burst <= poll_burst_min)
+	    poll_burst = poll_burst_min ;
+	else if (poll_burst < 4 * poll_burst_min )
+	    poll_burst -- ;
+	else
+	    poll_burst >>= 1 ;
+    }
+
+    idle_done = 0 ;
+}
+
+/*
+ * ether_poll1 is called by schednetisr when appropriate, typically once
+ * per tick. It is called at splnet() so first thing to do is to upgrade to
+ * splimp(), then recompute the burst size, and call all registered handlers.
+ */
+void
+ether_poll1(void)
+{
+    int i;
+    int s=splimp();
+    int arg = polling ? 1 /* poll */ : 2 /* unregister */ ;
+
+    update_poll_burst();
+
+    for (i = 0 ; i < poll_handlers ; i++) {
+	if (pr[i].handler) {
+	    (*pr[i].handler)(pr[i].arg, arg, poll_burst);
+	    if (arg == 2)
+		pr[i].handler=NULL;
+	}
+    }
+    if (arg == 2)
+	poll_handlers = 0;
+    splx(s);
+}
+
+/*
+ * Try to register routine for polling. Returns 1 if successful
+ * (and polling should be enabled), 0 otherwise.
+ * A device is not supposed to register itself multiple times.
+ */
+int
+ether_poll_register(poll_handler_t *h, void *arg)
+{
+    int s;
+
+    if (polling  == 0) /* polling disabled, cannot register */
+	return 0;
+    if (h == NULL || arg == NULL) /* bad arguments */
+	return 0 ;
+
+    s = splhigh();
+    if (poll_handlers >= POLL_LIST_LEN) { /* list full */
+	/*
+	 * This should never happen; if it does, it is probably a broken
+	 * driver trying to register multiple times. But checking this at
+	 * runtime is expensive, and won't solve problems anyways, so just
+	 * report the problem a few times and then give up.
+	 */
+	static int verbose = 10 ;
+	splx(s);
+	if (verbose >0) {
+	    printf("poll handlers list full -- maybe a broken driver ?\n");
+	    verbose-- ;
+	}
+	return 0; /* no polling for you */
+    }
+
+    pr[poll_handlers].handler = h ;
+    pr[poll_handlers].arg = arg ;
+    poll_handlers++ ;
+    splx(s);
+    return 1 ; /* polling enabled in next call */
+}
+
+#endif /* XORP_ETHER_POLLING */
Index: net/if.h
===================================================================
RCS file: /home/xorpc/u2/freebsd/src/sys/net/if.h,v
retrieving revision 1.58.2.2
diff -u -r1.58.2.2 if.h
--- net/if.h	2001/07/24 19:10:18	1.58.2.2
+++ net/if.h	2001/10/27 00:46:45
@@ -131,6 +131,15 @@
 #define	IFF_ALTPHYS	IFF_LINK2	/* use alternate physical connection */
 #define	IFF_MULTICAST	0x8000		/* supports multicast */
 
+/*
+ * The following flag(s) ought to go in if_flags, but we cannot change
+ * struct ifnet because of binary compatibility, so we store them in
+ * if_ipending, which is not used so far.
+ * If possible, make sure the value is not conflicting with other
+ * IFF flags, so we have an easier time when we want to merge them.
+ */
+#define	IFF_POLLING	0x10000		/* Interface is in polling mode. */
+
 /* flags set internally only: */
 #define	IFF_CANTCHANGE \
 	(IFF_BROADCAST|IFF_POINTOPOINT|IFF_RUNNING|IFF_OACTIVE|\
Index: net/netisr.h
===================================================================
RCS file: /home/xorpc/u2/freebsd/src/sys/net/netisr.h,v
retrieving revision 1.21.2.2
diff -u -r1.21.2.2 netisr.h
--- net/netisr.h	2001/03/06 00:55:07	1.21.2.2
+++ net/netisr.h	2001/10/25 23:23:58
@@ -52,6 +52,7 @@
  * interrupt used for scheduling the network code to calls
  * on the lowest level routine of each protocol.
  */
+#define	NETISR_POLL	1		/* polling callback */
 #define	NETISR_IP	2		/* same as AF_INET */
 #define	NETISR_NS	6		/* same as AF_NS */
 #define	NETISR_ATALK    16              /* same as AF_APPLETALK */
Index: pci/if_dc.c
===================================================================
RCS file: /home/xorpc/u2/freebsd/src/sys/pci/if_dc.c,v
retrieving revision 1.9.2.22
diff -u -r1.9.2.22 if_dc.c
--- pci/if_dc.c	2001/07/20 02:01:26	1.9.2.22
+++ pci/if_dc.c	2001/10/27 00:51:11
@@ -2318,6 +2318,13 @@
 	while(!(sc->dc_ldata->dc_rx_list[i].dc_status & DC_RXSTAT_OWN)) {
 		struct mbuf		*m0 = NULL;
 
+#ifdef XORP_ETHER_POLLING
+		if (ifp->if_ipending & IFF_POLLING) {
+			if (sc->rxcycles <= 0)
+				break ;
+			sc->rxcycles -- ;
+		}
+#endif /* XORP_ETHER_POLLING */
 		cur_rx = &sc->dc_ldata->dc_rx_list[i];
 		rxstat = cur_rx->dc_status;
 		m = sc->dc_cdata.dc_rx_chain[i];
@@ -2606,6 +2613,61 @@
 	return;
 }
 
+#ifdef XORP_ETHER_POLLING
+static poll_handler_t dc_poll;
+
+static void
+dc_poll(void *arg, int cmd, int count)
+{
+	struct	dc_softc *sc = arg ;
+	struct	ifnet *ifp = &sc->arpcom.ac_if;
+
+	sc->rxcycles = count ;
+	dc_rxeof(sc);
+	dc_txeof(sc);
+	if (ifp->if_snd.ifq_head != NULL && !(ifp->if_flags & IFF_OACTIVE))
+		dc_start(ifp);
+
+	if (cmd == 1) { /* also check status register */
+		u_int32_t          status;
+
+		status = CSR_READ_4(sc, DC_ISR);
+		status &= (DC_ISR_RX_WATDOGTIMEO|DC_ISR_RX_NOBUF|
+			DC_ISR_TX_NOBUF|DC_ISR_TX_IDLE|DC_ISR_TX_UNDERRUN|
+			DC_ISR_BUS_ERR);
+		if (!status)
+			return ;
+		/* ack what we have */
+		CSR_WRITE_4(sc, DC_ISR, status);
+
+		if (status & (DC_ISR_RX_WATDOGTIMEO|DC_ISR_RX_NOBUF) ) {
+			u_int32_t r = CSR_READ_4(sc, DC_FRAMESDISCARDED);
+			ifp->if_ierrors += (r & 0xffff) +
+				( (r >> 17) & 0x7ff ) ;
+
+			if (dc_rx_resync(sc))
+				dc_rxeof(sc);
+		}
+		/* restart transmit unit if necessary */
+		if (status & DC_ISR_TX_IDLE && sc->dc_cdata.dc_tx_cnt)
+			CSR_WRITE_4(sc, DC_TXSTART, 0xFFFFFFFF);
+
+		if (status & DC_ISR_TX_UNDERRUN)
+			dc_tx_underrun(sc);
+
+		if (status & DC_ISR_BUS_ERR) {
+			printf("dc_poll: dc%d bus error\n", sc->dc_unit);
+			dc_reset(sc);
+			dc_init(sc);
+		}
+	} else if (cmd == 2) { /* final call, enable interrupts */
+		ifp->if_ipending &= ~IFF_POLLING ;
+		/* Re-enable interrupts. */
+		CSR_WRITE_4(sc, DC_IMR, DC_INTRS);
+	}
+}
+#endif /* XORP_ETHER_POLLING */
+
 static void dc_intr(arg)
 	void			*arg;
 {
@@ -2614,11 +2676,24 @@
 	u_int32_t		status;
 
 	sc = arg;
+	ifp = &sc->arpcom.ac_if;
+
+#ifdef XORP_ETHER_POLLING
+	if (ifp->if_ipending & IFF_POLLING)
+		return ;
 
+	if (ether_poll_register(dc_poll, arg)) {
+		ifp->if_ipending |= IFF_POLLING ;
+		/* disable interrupts */
+		CSR_WRITE_4(sc, DC_IMR, 0x00000000);
+		dc_poll(sc, 0, poll_burst);
+		return ;
+	}
+#endif
+
 	if ( (CSR_READ_4(sc, DC_ISR) & DC_INTRS) == 0)
 		return ;
 
-	ifp = &sc->arpcom.ac_if;
 
 	/* Suppress unwanted interrupts */
 	if (!(ifp->if_flags & IFF_UP)) {
@@ -2875,6 +2950,11 @@
 		CSR_WRITE_4(sc, DC_BUSCTL, 0);
 	else
 		CSR_WRITE_4(sc, DC_BUSCTL, DC_BUSCTL_MRME|DC_BUSCTL_MRLE);
+	/*
+	 * Evenly share the bus between receive and transmit process.
+	 */
+	if (DC_IS_INTEL(sc))
+		DC_SETBIT(sc, DC_BUSCTL, DC_BUSCTL_ARBITRATION);
 	if (DC_IS_DAVICOM(sc) || DC_IS_INTEL(sc)) {
 		DC_SETBIT(sc, DC_BUSCTL, DC_BURSTLEN_USECA);
 	} else {
Index: pci/if_dcreg.h
===================================================================
RCS file: /home/xorpc/u2/freebsd/src/sys/pci/if_dcreg.h,v
retrieving revision 1.4.2.11
diff -u -r1.4.2.11 if_dcreg.h
--- pci/if_dcreg.h	2001/10/25 18:50:18	1.4.2.11
+++ pci/if_dcreg.h	2001/10/26 07:22:36
@@ -429,7 +429,7 @@
 #define DC_FILTER_HASHONLY	0x10400000
 
 #define DC_MAXFRAGS		16
-#define DC_RX_LIST_CNT		64
+#define DC_RX_LIST_CNT		192 /* was 64 */
 #define DC_TX_LIST_CNT		256
 #define DC_MIN_FRAMELEN		60
 #define DC_RXLEN		1536
@@ -659,6 +659,7 @@
 	bus_space_handle_t	dc_bhandle;	/* bus space handle */
 	bus_space_tag_t		dc_btag;	/* bus space tag */
 	void			*dc_intrhand;
+	int			rxcycles;	/* ... when polling */
 	struct resource		*dc_irq;
 	struct resource		*dc_res;
 	struct dc_type		*dc_info;	/* adapter info */
Index: sys/systm.h
===================================================================
RCS file: /home/xorpc/u2/freebsd/src/sys/sys/systm.h,v
retrieving revision 1.111.2.8
diff -u -r1.111.2.8 systm.h
--- sys/systm.h	2001/07/30 23:28:01	1.111.2.8
+++ sys/systm.h	2001/10/26 21:39:52
@@ -89,6 +89,17 @@
 #define	CONDSPLASSERT(cond, level, msg)
 #endif
 
+#ifdef	XORP_ETHER_POLLING
+extern u_int32_t poll_handlers;	/* how many handlers registered for polling */
+extern u_int32_t poll_in_trap;	/* do we poll devices in a trap ? */
+extern u_int32_t poll_burst;	/* how many pkts per poll cycle */
+
+typedef	void poll_handler_t __P((void *sc, int cmd, int count));
+int	ether_poll __P((int count));
+void	ether_poll1 __P((void));
+int	ether_poll_register __P((poll_handler_t *h, void *sc));
+#endif /* XORP_ETHER_POLLING */
+
 /*
  * General function declarations.
  */

--9jxsPFA5p3P2qPhR--

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-net" in the body of the message




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