From owner-freebsd-net Sat Oct 27 1: 2:54 2001 Delivered-To: freebsd-net@freebsd.org Received: from iguana.aciri.org (iguana.aciri.org [192.150.187.36]) by hub.freebsd.org (Postfix) with ESMTP id 2B97437B408; Sat, 27 Oct 2001 01:02:30 -0700 (PDT) Received: (from rizzo@localhost) by iguana.aciri.org (8.11.3/8.11.1) id f9R7x5973174; Sat, 27 Oct 2001 00:59:05 -0700 (PDT) (envelope-from rizzo) Date: Sat, 27 Oct 2001 00:59:05 -0700 From: Luigi Rizzo To: net@freebsd.org Subject: NEW CODE: polling support for device drivers. Message-ID: <20011027005905.A72758@iguana.aciri.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="9jxsPFA5p3P2qPhR" Content-Disposition: inline User-Agent: Mutt/1.3.23i Sender: owner-freebsd-net@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.org --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 #endif +#ifdef XORP_ETHER_POLLING +#include /* 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