Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 26 Nov 2001 11:57:04 -0800
From:      Luigi Rizzo <rizzo@aciri.org>
To:        net@freebsd.org
Subject:   Revised polling code for STABLE
Message-ID:  <20011126115704.L88153@iguana.aciri.org>
In-Reply-To: <20011027005905.A72758@iguana.aciri.org>
References:  <20011027005905.A72758@iguana.aciri.org>

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

--mP3DRpeJDSE+ciuQ
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

[Bcc to -stable in case someone is interested there]

Attached you can find the latest version of the polling code
for STABLE (which is useful to make boxes much more robust
to attacks and have much better responsiveness under [over]load).

Note that this code is only useful for RELENG_4, x86, non-SMP
boxes.

This version includes driver modifications for the following
drivers:

    fxp (this is for version 1.110.2.7 of the driver, i.e.
	the one in FreeBSD 4.4; hopefully the change should
	work for the newer driver as well without too
	many changes)

    dc

    sis (this one includes an i386 optimization which avoids
	an additional copy of the packet. The performance
	improvement I have measured from this can be as high as
	50% in some embedded systems with not a lot of CPU power).

Other drivers should be modified mostly following what is done in
the above drivers.
	
The sysctl variables to control polling mode are:

    net.xorp.polling
	set to 1 to enable polling, 0 to disable (default)

    net.xorp.poll_burst_max
	how many packets are processed at most at each clock
	tick. Defaults to 100.

    net.xorp.poll_burst
	how many packets are processed at each clock tick.
	Automatically adjusted depending on system load
	between 1 and net.xorp.poll_burst_max

    net.xorp.poll_in_trap
	how many packets are processed at each trap.
	Upper bounded by net.xorp.poll_burst.

    net.xorp.sis_quick
	set to 1 (default) to avoid the additional copy in the
	sis driver. There should be no reason to turn this off
	except seeing how much you are gaining.

Installation is trivial:

  + (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 sysctl variables listed above to control polling.
    Basically you just need to turn on net.xorp.polling

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
    sys/pci/if_sis.c
    sys/pci/if_sisreg.h
	device driver changes

Have fun, please report success or problems if you use this code.

	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
----------------------------------+-----------------------------------------

--mP3DRpeJDSE+ciuQ
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="stable.xorp.diff.011126a"

Index: sys/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
--- sys/conf/options.i386	2001/10/03 07:15:37	1.132.2.8
+++ sys/conf/options.i386	2001/10/27 00:23:01
@@ -208,5 +208,10 @@
 SMBFS
 
 # -------------------------------
+# Xorp stuff
+# -------------------------------
+XORP_ETHER_POLLING	opt_global.h
+
+# -------------------------------
 # EOF
 # -------------------------------
Index: sys/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
--- sys/dev/fxp/if_fxp.c	2001/08/31 02:17:02	1.110.2.7
+++ sys/dev/fxp/if_fxp.c	2001/11/23 17:54:41
@@ -1123,6 +1123,38 @@
 	}
 }
 
+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(struct ifnet *ifp, int cmd, int count)  
+{
+	struct fxp_softc *sc = ifp->if_softc;
+	u_int8_t statack ;
+
+	if (cmd == 2) {		/* final call, enable interrupts */
+		CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, 0);
+		return;
+	}
+	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);
+}
+#endif /* XORP_ETHER_POLLING */
+
 /*
  * Process interface interrupts.
  */
@@ -1130,9 +1162,21 @@
 fxp_intr(void *xsc)
 {
 	struct fxp_softc *sc = xsc;
-	struct ifnet *ifp = &sc->sc_if;
 	u_int8_t statack;
 
+#ifdef XORP_ETHER_POLLING
+	struct ifnet *ifp = &sc->sc_if;
+
+	if (ifp->if_ipending & IFF_POLLING)
+		return ;
+	if (ether_poll_register(fxp_poll, ifp)) {
+		/* disable interrupts */
+		CSR_WRITE_1(sc, FXP_CSR_SCB_INTRCNTL, FXP_SCB_INTR_DISABLE);
+		fxp_poll(ifp, 0, poll_burst);
+		return ;
+	}
+#endif
+
 	if (sc->suspended) {
 		return;
 	}
@@ -1151,7 +1195,15 @@
 		 * 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 +1253,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 +1312,6 @@
 				fxp_scb_cmd(sc, FXP_SCB_COMMAND_RU_START);
 			}
 		}
-	}
 }
 
 /*
Index: sys/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
--- sys/i386/i386/swtch.s	2001/07/26 02:29:10	1.89.2.4
+++ sys/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: sys/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
--- sys/i386/i386/trap.c	2001/08/15 01:23:50	1.147.2.5
+++ sys/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: sys/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
--- sys/i386/include/asnames.h	2001/09/20 09:29:23	1.44.2.3
+++ sys/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: sys/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
--- sys/kern/kern_clock.c	2001/02/18 15:29:14	1.105.2.4
+++ sys/kern/kern_clock.c	2001/11/23 18:01:12
@@ -67,7 +67,14 @@
 #include <sys/gmon.h>
 #endif
 
+#ifdef XORP_ETHER_POLLING
+#include <sys/socket.h>	/* needed by sys/if.h */
+#include <net/if.h>	/* for IFF_* flags */
+#include <net/netisr.h>	/* for NETISR_POLL */
 
+static void update_poll_threshold(struct clockframe *frame);
+#endif
+
 /*
  * Number of timecounters used to implement stable storage
  */
@@ -188,6 +195,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 +247,12 @@
 	tco_forward(0);
 	ticks++;
 
+#ifdef XORP_ETHER_POLLING
+	update_poll_threshold(frame);
+	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 +1016,203 @@
 	}
 #endif
 }
+
+#ifdef XORP_ETHER_POLLING
+/*
+ * 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_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 ?");
+
+static u_int32_t user_frac = 50;
+SYSCTL_ULONG(_net_xorp, OID_AUTO, user_frac, CTLFLAG_RW,
+	&user_frac, 0, "Desired user fraction of cpu time");
+
+/*
+ * 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 (a struct ifnet 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.
+ * Commands 0 and 1 are only issued if the interface is marked as 'IFF_UP',
+ * command 2 is issued inconditionally.
+ *
+ * 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 ;
+	struct ifnet	*ifp;
+};
+
+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");
+
+/*
+ * poll state reflects from what context we are polling.
+ */
+enum poll_states {
+	POLL_NONE, POLL_INTR, POLL_IDLE,
+};
+static enum poll_states poll_state = POLL_NONE;
+
+/*
+ * ether_poll is called from the idle loop or from trap handlers.
+ */
+int
+ether_poll(int count)
+{
+	static int i;
+	int s = splimp();
+
+	poll_state = POLL_IDLE;
+	if (count > poll_burst)
+		count = poll_burst;
+	if (i >= poll_handlers)
+		i = 0;
+	if (pr[i].handler && pr[i].ifp->if_flags & IFF_UP)
+		pr[i].handler(pr[i].ifp, 0, count); /* quick check */
+	i++ ;
+	poll_state = POLL_NONE;
+	splx(s);
+	return 1; /* more polling */
+}
+
+/*
+ * keep statistics on how much userland could used the CPU
+ */
+
+static void
+update_poll_threshold(struct clockframe *frame)
+{
+	static u_int32_t ready = 0 ; /* act when ready==0 */
+
+	if (poll_state == POLL_INTR) {
+		/*
+		 * We are spending too much time in polling,
+		 * so we need to lower the threshold.
+		 */
+		if (poll_burst >= 2)
+			poll_burst >>= 1 ;
+	} else if (idle_done > 0 && ready == 0 && poll_burst < poll_burst_max)
+		poll_burst++;
+
+	idle_done = 0 ;
+
+	if (ready-- > 0)
+		return ;
+
+	ready = hz/10 ;
+}
+
+/*
+ * 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(), and call all registered handlers.
+ */
+void
+ether_poll1(void)
+{
+	int i;
+	int s=splimp();
+
+	poll_state = POLL_INTR ;
+	if (polling) {
+		for (i = 0 ; i < poll_handlers ; i++)
+			if (pr[i].handler && pr[i].ifp->if_flags & IFF_UP)
+				pr[i].handler(pr[i].ifp, 1, poll_burst);
+	} else {	/* unregister */
+		for (i = 0 ; i < poll_handlers ; i++) {
+			if (pr[i].handler) {
+				pr[i].ifp->if_ipending &= ~IFF_POLLING;
+				pr[i].handler(pr[i].ifp, 2, poll_burst);
+			}
+			pr[i].handler=NULL;
+		}
+		poll_handlers = 0;
+	}
+	poll_state = POLL_NONE;
+	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, struct ifnet *ifp)
+{
+	int s;
+
+	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_ipending & IFF_POLLING)	/* sorry, already polling */
+		return 0;
+
+	s = splhigh();
+	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 ;
+		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].ifp = ifp;
+	poll_handlers++;
+	ifp->if_ipending |= IFF_POLLING;
+	splx(s);
+	return 1; /* polling enabled in next call */
+}
+
+#endif /* XORP_ETHER_POLLING */
Index: sys/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
--- sys/net/if.h	2001/07/24 19:10:18	1.58.2.2
+++ sys/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: sys/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
--- sys/net/netisr.h	2001/03/06 00:55:07	1.21.2.2
+++ sys/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: sys/pci/if_dc.c
===================================================================
RCS file: /home/xorpc/u2/freebsd/src/sys/pci/if_dc.c,v
retrieving revision 1.9.2.23
diff -u -r1.9.2.23 if_dc.c
--- sys/pci/if_dc.c	2001/10/28 17:23:24	1.9.2.23
+++ sys/pci/if_dc.c	2001/11/23 17:55:52
@@ -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(struct ifnet *ifp, int cmd, int count)
+{
+	struct	dc_softc *sc = ifp->if_softc;
+
+	if (cmd == 2) { /* final call, enable interrupts */
+		/* Re-enable interrupts. */
+		CSR_WRITE_4(sc, DC_IMR, DC_INTRS);
+		return;
+	}
+	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);
+		}
+	}
+}
+#endif /* XORP_ETHER_POLLING */
+
 static void dc_intr(arg)
 	void			*arg;
 {
@@ -2614,11 +2676,21 @@
 	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, ifp)) { /* ok, disable interrupts */
+		CSR_WRITE_4(sc, DC_IMR, 0x00000000);
+		dc_poll(ifp, 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)) {
Index: sys/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
--- sys/pci/if_dcreg.h	2001/10/25 18:50:18	1.4.2.11
+++ sys/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/pci/if_sis.c
===================================================================
RCS file: /home/xorpc/u2/freebsd/src/sys/pci/if_sis.c,v
retrieving revision 1.13.4.7
diff -u -r1.13.4.7 if_sis.c
--- sys/pci/if_sis.c	2001/02/21 22:17:51	1.13.4.7
+++ sys/pci/if_sis.c	2001/11/26 18:37:21
@@ -64,6 +64,7 @@
 #include <sys/malloc.h>
 #include <sys/kernel.h>
 #include <sys/socket.h>
+#include <sys/sysctl.h>
 
 #include <net/if.h>
 #include <net/if_arp.h>
@@ -1091,6 +1092,11 @@
 	return(0);
 }
 
+int sis_quick=1;
+SYSCTL_DECL(_net_xorp);
+SYSCTL_INT(_net_xorp, OID_AUTO, sis_quick, CTLFLAG_RW,
+            &sis_quick,0,"do not mdevget in sis driver");
+
 /*
  * A frame has been uploaded: pass the resulting mbuf chain up to
  * the higher level protocols.
@@ -1111,6 +1117,13 @@
 	while(SIS_OWNDESC(&sc->sis_ldata->sis_rx_list[i])) {
 		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->sis_ldata->sis_rx_list[i];
 		rxstat = cur_rx->sis_rxstat;
 		m = cur_rx->sis_mbuf;
@@ -1132,7 +1145,15 @@
 			continue;
 		}
 
-		/* No errors; receive the packet. */	
+#ifdef __i386__
+	    if (sis_quick) {
+		m->m_pkthdr.rcvif = ifp;
+		m->m_pkthdr.len = m->m_len = total_len;
+		sis_newbuf(sc, cur_rx, NULL);
+	    } else
+#endif
+	    {
+		struct mbuf		*m0 = NULL;
 		m0 = m_devget(mtod(m, char *) - ETHER_ALIGN,
 		    total_len + ETHER_ALIGN, 0, ifp, NULL);
 		sis_newbuf(sc, cur_rx, m);
@@ -1142,7 +1163,7 @@
 		}
 		m_adj(m0, ETHER_ALIGN);
 		m = m0;
-
+	    }
 		ifp->if_ipackets++;
 		eh = mtod(m, struct ether_header *);
 
@@ -1260,6 +1281,53 @@
 	return;
 }
 
+
+#ifdef XORP_ETHER_POLLING
+static poll_handler_t sis_poll;
+
+static void
+sis_poll(struct ifnet *ifp, int cmd, int count)
+{
+	struct  sis_softc *sc = ifp->if_softc ;
+
+	if (cmd == 2) {		/* final call, enable interrupts */
+		CSR_WRITE_4(sc, SIS_IER, 1);
+		return;
+	}
+
+	/*
+	 * On the sis, reading the status register also clears it.
+	 * So before returning to intr mode we must make sure that all
+	 * possible pending sources of interrupts have been served.
+	 * In practice this means run to completion the *eof routines,
+	 * and then call the interrupt routine
+	 */
+	sc->rxcycles = count ;
+	sis_rxeof(sc);
+	sis_txeof(sc);
+	if (ifp->if_snd.ifq_head != NULL)
+		sis_start(ifp);
+
+	if (sc->rxcycles > 0 || cmd == 1) { /* also check status register */
+		u_int32_t          status;
+
+		/* Reading the ISR register clears all interrupts. */
+		status = CSR_READ_4(sc, SIS_ISR);
+
+		if (status & (SIS_ISR_RX_ERR|SIS_ISR_RX_OFLOW))
+                        sis_rxeoc(sc);
+        
+		if (status & (SIS_ISR_RX_IDLE))
+			SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE);
+
+                if (status & SIS_ISR_SYSERR) {
+                        sis_reset(sc);
+                        sis_init(sc);
+                }
+	}
+}
+#endif /* XORP_ETHER_POLLING */
+
 static void sis_intr(arg)
 	void			*arg;
 {
@@ -1270,6 +1338,16 @@
 	sc = arg;
 	ifp = &sc->arpcom.ac_if;
 
+#ifdef XORP_ETHER_POLLING
+	if (ifp->if_ipending & IFF_POLLING)
+		return ;
+	if (ether_poll_register(sis_poll, ifp)) { /* ok, disable interrupts */
+		CSR_WRITE_4(sc, SIS_IER, 0);
+		sis_poll(ifp, 0, poll_burst);
+		return ;
+	}
+#endif
+
 	/* Supress unwanted interrupts */
 	if (!(ifp->if_flags & IFF_UP)) {
 		sis_stop(sc);
@@ -1286,19 +1364,19 @@
 		if ((status & SIS_INTRS) == 0)
 			break;
 
-		if ((status & SIS_ISR_TX_DESC_OK) ||
-		    (status & SIS_ISR_TX_ERR) ||
-		    (status & SIS_ISR_TX_OK) ||
-		    (status & SIS_ISR_TX_IDLE))
+		if (status &
+		    (SIS_ISR_TX_DESC_OK|SIS_ISR_TX_ERR| \
+		     SIS_ISR_TX_OK|SIS_ISR_TX_IDLE) )
 			sis_txeof(sc);
 
-		if ((status & SIS_ISR_RX_DESC_OK) ||
-		    (status & SIS_ISR_RX_OK))
+		if (status & (SIS_ISR_RX_DESC_OK|SIS_ISR_RX_OK|SIS_ISR_RX_IDLE))
 			sis_rxeof(sc);
 
-		if ((status & SIS_ISR_RX_ERR) ||
-		    (status & SIS_ISR_RX_OFLOW)) {
+		if (status & (SIS_ISR_RX_ERR|SIS_ISR_RX_OFLOW))
 			sis_rxeoc(sc);
+
+		if (status & (SIS_ISR_RX_IDLE)) {
+			SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE);
 		}
 
 		if (status & SIS_ISR_SYSERR) {
@@ -1546,6 +1624,9 @@
 	 * Enable interrupts.
 	 */
 	CSR_WRITE_4(sc, SIS_IMR, SIS_INTRS);
+#ifdef XORP_ETHER_POLLING
+	if (!(ifp->if_ipending & IFF_POLLING))
+#endif
 	CSR_WRITE_4(sc, SIS_IER, 1);
 
 	/* Enable receiver and transmitter. */
Index: sys/pci/if_sisreg.h
===================================================================
RCS file: /home/xorpc/u2/freebsd/src/sys/pci/if_sisreg.h,v
retrieving revision 1.1.4.3
diff -u -r1.1.4.3 if_sisreg.h
--- sys/pci/if_sisreg.h	2001/02/21 22:17:51	1.1.4.3
+++ sys/pci/if_sisreg.h	2001/10/31 02:25:29
@@ -305,7 +305,7 @@
 
 #define SIS_LASTDESC(x)		(!((x)->sis_ctl & SIS_CMDSTS_MORE)))
 #define SIS_OWNDESC(x)		((x)->sis_ctl & SIS_CMDSTS_OWN)
-#define SIS_INC(x, y)		(x) = (x + 1) % y
+#define SIS_INC(x, y)		{ if (++(x) == y) x=0 ; }
 #define SIS_RXBYTES(x)		((x)->sis_ctl & SIS_CMDSTS_BUFLEN)
 
 #define SIS_RXSTAT_COLL		0x00010000
@@ -401,6 +401,7 @@
 	struct sis_list_data	*sis_ldata;
 	struct sis_ring_data	sis_cdata;
 	struct callout_handle	sis_stat_ch;
+	int			rxcycles;
 };
 
 /*
Index: sys/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/sys/systm.h	2001/07/30 23:28:01	1.111.2.8
+++ sys/sys/systm.h	2001/11/25 16:34:15
@@ -89,6 +89,21 @@
 #define	CONDSPLASSERT(cond, level, msg)
 #endif
 
+#ifdef XORP_ETHER_POLLING
+#ifdef SMP
+#error XORP_ETHER_POLLING not yet compatible with SMP
+#endif
+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 */
+
+struct	ifnet ; /* keep compiler quiet */
+typedef	void poll_handler_t __P((struct ifnet *ifp, int cmd, int count));
+int	ether_poll __P((int count));
+void	ether_poll1 __P((void));
+int	ether_poll_register __P((poll_handler_t *h, struct ifnet *sc));
+#endif /* XORP_ETHER_POLLING */
+
 /*
  * General function declarations.
  */

--mP3DRpeJDSE+ciuQ--

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




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