From owner-freebsd-stable Mon Nov 26 12: 2:26 2001 Delivered-To: freebsd-stable@freebsd.org Received: from iguana.aciri.org (iguana.aciri.org [192.150.187.36]) by hub.freebsd.org (Postfix) with ESMTP id 4D3D437B41B; Mon, 26 Nov 2001 12:01:12 -0800 (PST) Received: (from rizzo@localhost) by iguana.aciri.org (8.11.3/8.11.1) id fAQJv4M89422; Mon, 26 Nov 2001 11:57:04 -0800 (PST) (envelope-from rizzo) Date: Mon, 26 Nov 2001 11:57:04 -0800 From: Luigi Rizzo To: net@freebsd.org Subject: Revised polling code for STABLE Message-ID: <20011126115704.L88153@iguana.aciri.org> References: <20011027005905.A72758@iguana.aciri.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="mP3DRpeJDSE+ciuQ" Content-Disposition: inline In-Reply-To: <20011027005905.A72758@iguana.aciri.org> User-Agent: Mutt/1.3.23i Sender: owner-freebsd-stable@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG --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 #endif +#ifdef XORP_ETHER_POLLING +#include /* needed by sys/if.h */ +#include /* for IFF_* flags */ +#include /* 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 #include #include +#include #include #include @@ -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