diff options
author | gibbs <gibbs@FreeBSD.org> | 1994-11-13 10:12:37 +0000 |
---|---|---|
committer | gibbs <gibbs@FreeBSD.org> | 1994-11-13 10:12:37 +0000 |
commit | 0edcf3a920d949d54b090185fc27b6b4129b2b1e (patch) | |
tree | 1a15ff134bbbbad6c4651eb7de4a8700465365b6 /sys/dev/ep | |
parent | cb198fadcd00ee84de8e4dbe0ac2bf839aaf86f5 (diff) | |
download | FreeBSD-src-0edcf3a920d949d54b090185fc27b6b4129b2b1e.zip FreeBSD-src-0edcf3a920d949d54b090185fc27b6b4129b2b1e.tar.gz |
Andres Vega Garcia's improvements to the ep driver. This driver is a merging
of the 1.1.5 driver, a recent version of the NetBSD driver, Andres'
transmission start threshold code, and all other relavent changes to the driver
since it was brought into 2.0. The multicast support from NetBSD has not be
folded in yet. I've tested it under high loads for two weeks and it is now
robust enough to be included in the GENERIC kernel.
Reviewed by: gibbs
Submitted by: vega@sophia.inria.fr (Andres Vega Garcia)
Diffstat (limited to 'sys/dev/ep')
-rw-r--r-- | sys/dev/ep/if_ep.c | 2125 | ||||
-rw-r--r-- | sys/dev/ep/if_epreg.h | 299 |
2 files changed, 1405 insertions, 1019 deletions
diff --git a/sys/dev/ep/if_ep.c b/sys/dev/ep/if_ep.c index a526ca3..9534182 100644 --- a/sys/dev/ep/if_ep.c +++ b/sys/dev/ep/if_ep.c @@ -1,28 +1,253 @@ /* - * Copyright (c) 1993 Herb Peyerl <hpeyerl@novatel.ca> - * All rights reserved. - * + * Copyright (c) 1993 Herb Peyerl <hpeyerl@novatel.ca> All rights reserved. + * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * From: if_ep.c,v 1.9 1994/01/25 10:46:29 deraadt Exp - * $Id: if_ep.c,v 1.13 1994/09/16 13:33:41 davidg Exp $ + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. The name + * of the author may not be used to endorse or promote products derived from + * this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * From: if_ep.c,v 1.9 1994/01/25 10:46:29 deraadt Exp $ $Id: if_ep.c,v 1.9 + * 1994/05/02 22:27:33 ats Exp $ + * + * October 26, 1994 + * + * Modified by: Andres Vega Garcia + * INRIA - Sophia Antipolis, France + * e-mail: avega@sophia.inria.fr + * finger: avega@pax.inria.fr + * + * + * What is new: + * + * 1) We can recognize more than 1 board. + * + * 2) The problem which used to happen with high trafic is corrected, + * (No more need to 'down' and 'up' the interface). + * + * 3) In the transmission, we use the TX start threshold in a more dynamic + * fashion (IMO the throughput is higher this way). + * + * 4) In the reception, we use the RX early threshold, that parameter is + * adapted as the packets arrive (IMO the throughput is higher this way). + * + * 5) Supports EISA cards. + * + * NB 0: The 32 bits acces is allowed for the EISA configured cards, thoung I + * wasn't able to test the code added. + * + * NB 1: I added the option EP_LOCAL_STATS, it can be temporary as IMO is just + * used while working on this driver and the program that displays this + * information (epstat). + * + * NB 2: About trailers, I didn't care if this implementation was OK, I just + * adapted it to have the same behaviour as in the original driver (donne + * just for epread()). + * + * + * Some driver statistics can be viewed with the epstat utility. In order to + * use this, you have to compile if_ep.c with + * + * -DEP_LOCAL_STATS + * + * which can be included in your machine config file (e.g. GENERICAH_EP) + * as an option (option EP_LOCAL_STATS). + * + * + * Modifications since FreeBSD 1.1.5.1 Release: + * + * This explanation concerns the epstart(), epread() and epintr() functions. + * + * ========================================================================= + * epstart() + * ========================================================================= + * + * + * Let's see what the idea is: + * + * + * Packet |------------------ LEN ---------------------| + * + * A + * CPU |---------------|----------------------------| + * + * + * Card |----------------------------| + * + * + * + * We suppose the Card is able to *write* bytes (send them to the media) + * at the speed S_CARD (bytes/s), and that is faster than the speed of the CPU, + * S_CPU, to write bytes to the TX FIFO, then, we have to write A bytes to the + * FIFO before enableing the transmision in the card. This way both, the card + * and the CPU must finish their writing at the same time. + * + * + * Let TX_RATE = S_CPU / S_CARD, where TX_RATE <= 1 + * + * We can find that: + * + * (1) A = LEN * (1 - TX_RATE) + * + * + * Let TX_RATE_R be the *very real* value. + * + * If TX_RATE > TX_RATE_R + * We are supposing the CPU is faster than it really is and + * certainly the card will *finish* before the CPU, having a + * TX Underrun Error, then, in such a case, we have to do: + * + * TX_RATE -= STEP, where STEP is the step at which we + * move TX_RATE + * + * If TX_RATE < TX_RATE_R + * We won't have the TX Underrun Error but it is possible that + * we don't use eficiently the TX START THRESH. feature. + * We prevent this by doing: + * + * TX_RATE += STEP every time we have sent succesfuly + * (without Underrun) a certain number + * of packets. + * + * Now, to avoid dealing with reals I used a FACTOR, then (1) will be + * transformed: + * + * Let tx_rate = FACTOR * TX_RATE, tx_rate is the parameter + * really used. + * + * A = (LEN * (FACTOR - tx_rate)) / FACTOR + * + * Actually FACTOR = 64 + * + * (2) A = (LEN * (64 - tx_rate)) >> 6 + * + * As I want to have some margin, and + * as I have to write a number multiple of 4: + * + * A = tx_start_threshold = (((LEN * (64 - tx_rate)) >> 6) & ~3) + 16 + * + * + * ========================================================================= + * epread() + * ========================================================================= + * + * I mantain an estimation of the RX packet's average length, and an + * estimation of the RX latency. + * + * Every time I receive a complete packet I compute the average packet's + * length, rx_avg_pkt: + * + * DELTA = LEN - rx_avg_pkt, where LEN is this packet's length + * + * if DELTA > 0 + * rx_avg_pkt += AVG_UP * DELTA + * else + * rx_avg_pkt += AVG_DOWN *DELTA + * + * + * AVG_UP < AVG_DOWN + * + * In the first case, I'm interested in being conservative about the + * average packet'length, because if I let it go up *too fast*, a shorter packet + * than expected will probably cause an RX Overrun Error. But if I consider + * the next packet will be smaller than it will, I just will have to wait + * for the packet to complete reception. + * + * In the other case, I'm interested in leting the rx_avg_pkt follow + * the real packet's lenght closer, as it is important not to think the average + * packet is bigger than it realy is. If I don't do that, and the rx_avg_pkt + * goes down *too slow*, I'll find myself thinking the packets are big when they + * are really small and I'll have probably Rx Overrun Errors. + * + * Actualy: + * + * AVG_UP = 1/32 + * AVG_DOWN = 1/8 + * + * + * Every time I receive an incomplete packet I recompute the RX latency + * (rx_latency). + * + * I know that if rx_latency = 0, when I go read the bytes from the RX + * FIFO, I'll find as many bytes as I programmed in the RX Early Threshold, but + * if rx_latency > 0, I'll find more bytes. + * + * Let CUR_LAT be the RX latency seen by this packet. + * + * CUR_LAT = LEN - rx_early_threshold, where LEN is the number of + * bytes I have just received. + * + * DELTA = CUR_LAT - rx_latency + * + * + * if DELTA >= 0 + * rx_latency += LAT_UP * DELTA + * else + * rx_latency += LAT_DOWN * DELTA + * + * + * LAT_UP > LAT_DOWN + * + * In a similar way as for rx average packet's length, I try to be more + * conservative in the more critical case. + * + * In the first case, I have to follow closer the incremets of the RX + * latency, because if I don't, I can find myself thinking that we (CPU) are + * *enough fast* and wait up to the last minute to go read data to find we have + * had RX Overrun Error. + * + * In the other case I must be more conservative to avoid falling in + * the situation I have just described, because if I go down *to fast* I'll + * think we are enough fast and we'll wake up later than due. + * + * Actually: + * + * LAT_UP = 1/4 + * LAT_DOWN = 1/32 + * + * Finally, I compute the rx_early_threshold for the next packet as: + * + * rx_early_threshold = rx_avg_pkt - rx_latency + * + * But, as I want to have a margin and + * as I have to write a value multiple of 4. + * + * + * rx_early_threshold = (rx_avg_pkt - rx_latency - 16) & ~3 + * + * + * But if I have to wait for the rest of an incomplete packet + * from which I have already received CUR_LEN bytes: + * + * + * rx_early_threshold = (rx_avg_pkt-CUR_LEN - rx_latency - 16) & ~3 + * + * + * ========================================================================= + * epintr() + * ========================================================================= + * + * For this function I just tryed to do what is stated in the + * Etherlink III Technical Reference. + * + * It was here where I really solved the problem that used to happen with + * high traffic. + * + * + * Andres + * avega@pax.inria.fr */ #include "ep.h" @@ -34,13 +259,13 @@ #if defined(__FreeBSD__) #include <sys/systm.h> #include <sys/kernel.h> +#include <sys/devconf.h> #endif #include <sys/mbuf.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <sys/errno.h> #include <sys/syslog.h> -#include <sys/devconf.h> #if defined(__NetBSD__) #include <sys/select.h> #endif @@ -71,359 +296,324 @@ #include <i386/isa/isa_device.h> #include <i386/isa/icu.h> #include <i386/isa/if_epreg.h> -#include <i386/isa/elink.h> - -/* For backwards compatibility */ -#ifndef IFF_ALTPHYS -#define IFF_ALTPHYS IFF_LINK0 -#endif - - -#define ETHER_MIN_LEN 64 -#define ETHER_MAX_LEN 1518 -#define ETHER_ADDR_LEN 6 - -/* - * Ethernet software status per interface. - */ -struct ep_softc { - struct arpcom arpcom; /* Ethernet common part */ - ushort ep_iobase; /* i/o bus address */ - char ep_connectors; /* Connectors on this card. */ -#define MAX_MBS 8 /* # of mbufs we keep around */ - struct mbuf *mb[MAX_MBS]; /* spare mbuf storage. */ - int next_mb; /* Which mbuf to use next. */ - int last_mb; /* Last mbuf. */ - int tx_start_thresh; /* Current TX_start_thresh. */ - int tx_succ_ok; /* # packets sent in sequence w/o underrun */ - caddr_t bpf; /* BPF "magic cookie" */ - char bus32bit; /* 32bit access possible */ -} ep_softc[NEP]; static int epprobe __P((struct isa_device *)); static int epattach __P((struct isa_device *)); static int epioctl __P((struct ifnet * ifp, int, caddr_t)); +static void epmbuffill __P((caddr_t, int)); +static void epmbufempty __P((struct ep_softc *)); void epinit __P((int)); void epintr __P((int)); -void epmbuffill __P((void *)); -static void epmbufempty __P((struct ep_softc *)); void epread __P((struct ep_softc *)); void epreset __P((int)); void epstart __P((struct ifnet *)); void epstop __P((int)); void epwatchdog __P((int)); +static int send_ID_sequence __P((int)); +static int get_eeprom_data __P((int, int)); + +struct ep_softc ep_softc[NEP]; + +#define ep_ftst(f) (sc->stat&(f)) +#define ep_fset(f) (sc->stat|=(f)) +#define ep_frst(f) (sc->stat&=~(f)) + struct isa_driver epdriver = { - epprobe, - epattach, - "ep" + epprobe, + epattach, + "ep" }; static struct kern_devconf kdc_ep[NEP] = { { - 0, 0, 0, /* filled in by dev_attach */ - "ep", 0, { MDDT_ISA, 0, "net" }, - isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, - &kdc_isa0, /* parent */ - 0, /* parentdata */ - DC_BUSY, /* network interfaces are always ``open'' */ - "3Com 3C509 Ethernet adapter" + 0, 0, 0, /* filled in by dev_attach */ + "ep", 0, { MDDT_ISA, 0, "net" }, + isa_generic_externalize, 0, 0, ISA_EXTERNALLEN, + &kdc_isa0, /* parent */ + 0, /* parentdata */ + DC_BUSY, /* network interfaces are always ``open'' */ + "3Com 3C509 Ethernet adapter" } }; static inline void ep_registerdev(struct isa_device *id) { - if(id->id_unit) - kdc_ep[id->id_unit] = kdc_ep[0]; - kdc_ep[id->id_unit].kdc_unit = id->id_unit; - kdc_ep[id->id_unit].kdc_parentdata = id; - dev_attach(&kdc_ep[id->id_unit]); + if(id->id_unit) + kdc_ep[id->id_unit] = kdc_ep[0]; + kdc_ep[id->id_unit].kdc_unit = id->id_unit; + kdc_ep[id->id_unit].kdc_parentdata = id; + dev_attach(&kdc_ep[id->id_unit]); } -static int send_ID_sequence __P((u_short)); -static u_short epreadeeprom __P((int, int)); -static int epbusyeeprom __P((int, ushort)); - +int ep_current_tag = EP_LAST_TAG + 1; -#define MAXEPCARDS 20 /* if you have 21 cards in your machine... you lose */ +int ep_board[EP_MAX_BOARDS + 1]; -static struct epcard { - int iobase; - u_short irq; - char available; - char bus32bit; -} epcards[MAXEPCARDS]; +static int +eeprom_rdy(is) + struct isa_device *is; +{ + int i; -static int nepcards; + for (i = 0; is_eeprom_busy(IS_BASE) && i < MAX_EEPROMBUSY; i++); + if (i >= MAX_EEPROMBUSY) { + printf("ep%d: eeprom failed to come ready.\n", is->id_unit); + return (0); + } + return (1); +} -static void -epaddcard(p, i, mode) - short p; - u_short i; - char mode; +static int +ep_look_for_board_at(is) + struct isa_device *is; { - if (nepcards >= sizeof(epcards)/sizeof(epcards[0])) - return; - epcards[nepcards].iobase = p; - epcards[nepcards].irq = 1 << ((i == 2) ? 9 : i); - epcards[nepcards].available = 1; - epcards[nepcards].bus32bit = mode; - nepcards++; -} + int data, i, j, io_base, id_port = EP_ID_PORT; + int nisa = 0, neisa = 0; + + if (ep_current_tag == (EP_LAST_TAG + 1)) { + /* Come here just one time */ + + /* Look for the EISA boards, leave them activated */ + for(j = 1; j < 16; j++) { + io_base = (j * EP_EISA_START) | EP_EISA_W0; + if (inw(io_base + EP_W0_MFG_ID) != MFG_ID) + continue; + + /* we must found 0x1f if the board is EISA configurated */ + if ((inw(io_base + EP_W0_ADDRESS_CFG) & 0x1f) != 0x1f) + continue; + + /* Reset and Enable the card */ + outb(io_base + EP_W0_CONFIG_CTRL, W0_P4_CMD_RESET_ADAPTER); + DELAY(1000); /* we must wait at least 1 ms */ + outb(io_base + EP_W0_CONFIG_CTRL, W0_P4_CMD_ENABLE_ADAPTER); + + /* + * Once activated, all the registers are mapped in the range + * x000 - x00F, where x is the slot number. + */ + ep_board[neisa++] = j * EP_EISA_START; + } + ep_current_tag--; + + /* Look for the ISA boards. Init and leave them actived */ + outb(id_port, 0xc0); /* Global reset */ + DELAY(1000); + for (i = 0; i < EP_MAX_BOARDS; i++) { + outb(id_port, 0); + outb(id_port, 0); + send_ID_sequence(id_port); + + data = get_eeprom_data(id_port, EEPROM_MFG_ID); + if (data != MFG_ID) + break; + + /* resolve contention using the Ethernet address */ + for (j = 0; j < 3; j++) + data = get_eeprom_data(id_port, j); + ep_board[neisa+nisa++] = + (get_eeprom_data(id_port, EEPROM_ADDR_CFG) & 0x1f) * 0x10 + 0x200; + outb(id_port, ep_current_tag); /* tags board */ + outb(id_port, ACTIVATE_ADAPTER_TO_CONFIG); + ep_current_tag--; + } + + ep_board[neisa+nisa] = 0; + if (neisa) { + printf("%d 3C5x9 board(s) on EISA found at", neisa); + for (j = 0; ep_board[j]; j++) + if (ep_board[j] >= EP_EISA_START) + printf(" 0x%x", ep_board[j]); + printf("\n"); + } + if (nisa) { + printf("%d 3C5x9 board(s) on ISA found at", nisa); + for (j = 0; ep_board[j]; j++) + if (ep_board[j] < EP_EISA_START) + printf(" 0x%x", ep_board[j]); + printf("\n"); + } + } + + for (i = 0; ep_board[i] && ep_board[i] != IS_BASE; i++); + if (ep_board[i] == IS_BASE) { + if (inw(IS_BASE + EP_W0_EEPROM_COMMAND) & EEPROM_TST_MODE) + printf("ep%d: 3c5x9 at 0x%x in test mode. Erase pencil mark!\n", + is->id_unit, IS_BASE); + return (1); + } + return (0); +} /* - * 3c579 cards on the EISA bus are probed by their slot number. 3c509 - * cards on the ISA bus are probed in ethernet address order. The probe - * sequence requires careful orchestration, and we'd like like to allow - * the irq and base address to be wildcarded. So, we probe all the cards - * the first time epprobe() is called. On subsequent calls we look for - * matching cards. + * get_e: gets a 16 bits word from the EEPROM. we must have set the window + * before */ +static int +get_e(is, offset) + struct isa_device *is; + int offset; +{ + if (!eeprom_rdy(is)) + return (0xffff); + outw(IS_BASE + EP_W0_EEPROM_COMMAND, EEPROM_CMD_RD | offset); + if (!eeprom_rdy(is)) + return (0xffff); + return (inw(IS_BASE + EP_W0_EEPROM_DATA)); +} + int epprobe(is) - struct isa_device *is; + struct isa_device *is; { - struct ep_softc *sc = &ep_softc[is->id_unit]; - static int probed; - int slot, iobase, i; - u_short k, k2; - u_short prodid; - - if (probed==0) { - probed = 1; - - /* find all EISA cards */ - for (slot = 1; slot < 16; slot++) { - iobase = 0x1000 * slot; - outw(iobase + EP_COMMAND, GLOBAL_RESET); - DELAY(1000); - if (inw(iobase + EISA_VENDOR) != MFG_ID) - continue; - k = inw(iobase + EISA_MODEL); -#ifdef EP_DEBUG -printf("prod id = %x ", k); -prodid = k; -#endif - if ((k & 0xf0ff) != PROD_ID) - continue; - - k = inw(iobase + EP_W0_CONFIG_CTRL); - /* enable adapter */ - outw(iobase + EP_W0_CONFIG_CTRL, k | 1); -#ifdef EP_DEBUG -printf("config = %x ", k); -#endif + struct ep_softc *sc = &ep_softc[is->id_unit]; + u_short k; + int i; - /* read in eeprom address configuration */ - if (epbusyeeprom(slot - 1, iobase)) - continue; - outw(iobase + EP_W0_EEPROM_COMMAND, READ_EEPROM | EEPROM_ADDR_CFG); - if (epbusyeeprom(slot - 1, iobase)) - continue; - k = inw(iobase + EP_W0_EEPROM_DATA); -#ifdef EP_DEBUG -printf("addr_cfg = %x ", k); -#endif - outw(iobase + EP_W0_ADDRESS_CFG, k); - /* read in eeprom resource configuration */ - if (epbusyeeprom(slot - 1, iobase)) - continue; - outw(iobase + EP_W0_EEPROM_COMMAND, READ_EEPROM | EEPROM_RESOURCE_CFG); - if (epbusyeeprom(slot - 1, iobase)) - continue; - k2 = inw(iobase + EP_W0_EEPROM_DATA); - -#ifdef EP_DEBUG -/** XXXXXXXXXXXXXXXXXXXXX*/ -/* This doesn't give back the actual IRQ number as it should be , ATS */ -/* In the moment simply hardcoded the IRQ's for testing purposes */ -printf("resource config = %x\n", k2); -if (prodid == 0x9150) /* the 3c509 card */ - k2 = 7 << 12; -else - k2 = 3 << 12; /* the eisa 3c579 card set to irq 3 */ -#endif - - outw(iobase + EP_W0_RESOURCE_CFG, k2); - epaddcard(iobase, k2 >> 12, 1); - } + if (!ep_look_for_board_at(is)) + return (0); + /* + * The iobase was found and MFG_ID was 0x6d50. PROD_ID should be + * 0x9[0-f]50 + */ + GO_WINDOW(0); + k = get_e(is, EEPROM_PROD_ID); + if ((k & 0xf0ff) != (PROD_ID & 0xf0ff)) { + printf("epprobe: ignoring model %04x\n", k); + return (0); + } - /* find all isa cards */ -#ifdef 0 - outw(BASE + EP_COMMAND, GLOBAL_RESET); -#endif - DELAY(1000); - elink_reset(); /* global reset to ELINK_ID_PORT */ - DELAY(1000); - - for (slot = 0; slot < 10; slot++) { - outb(ELINK_ID_PORT, 0x00); - elink_idseq(ELINK_509_POLY); - DELAY(1000); - - k = epreadeeprom(ELINK_ID_PORT, EEPROM_MFG_ID); - if (k != MFG_ID) - continue; - k = epreadeeprom(ELINK_ID_PORT, EEPROM_PROD_ID); - if ((k & 0xf0ff) != PROD_ID) - continue; - - k = epreadeeprom(ELINK_ID_PORT, EEPROM_ADDR_CFG); - k = (k & 0x1f) * 0x10 + 0x200; - - k2 = epreadeeprom(ELINK_ID_PORT, EEPROM_RESOURCE_CFG); - k2 >>= 12; - epaddcard(k, k2, 0); - - /* so card will not respond to contention again */ - outb(ELINK_ID_PORT, TAG_ADAPTER_0 + 1); - - /* - * XXX: this should probably not be done here - * because it enables the drq/irq lines from - * the board. Perhaps it should be done after - * we have checked for irq/drq collisions? - */ - outb(ELINK_ID_PORT, ACTIVATE_ADAPTER_TO_CONFIG); - } - /* XXX should we sort by ethernet address? */ - } + k = get_e(is, EEPROM_RESOURCE_CFG); + k >>= 12; + if (is->id_irq != (1 << ((k == 2) ? 9 : k))) { + printf("epprobe: interrupt number %d doesn't match\n",is->id_irq); + return (0); + } - /* - * a very specific search order: - * exact iobase & irq - * exact iobase, wildcard irq - * wildcard iobase, exact irq - * wildcard iobase & irq - * else fail.. - */ - if (is->id_iobase != 0 && is->id_irq != (u_short)0) { - for (i = 0; i<nepcards; i++) { - if (epcards[i].available == 0) - continue; - if (is->id_iobase == epcards[i].iobase && - is->id_irq == epcards[i].irq) - goto good; - } - } - if (is->id_iobase != 0 && is->id_irq == (u_short)0) { - for (i = 0; i<nepcards; i++) { - if (epcards[i].available == 0) - continue; - if (is->id_iobase == epcards[i].iobase) - goto good; - } - } - if (is->id_iobase == 0 && is->id_irq != (u_short)0) { - for (i = 0; i<nepcards; i++) { - if (epcards[i].available == 0) - continue; - if (is->id_irq == epcards[i].irq) - goto good; - } - } - return 0; + if (BASE >= EP_EISA_START) /* we have an EISA board, we allow 32 bits access */ + sc->stat = F_ACCESS_32_BITS; + else + sc->stat = 0; -good: - epcards[i].available = 0; - sc->bus32bit = epcards[i].bus32bit; - is->id_iobase = epcards[i].iobase; + /* By now, the adapter is already activated */ - return (0x10); /* 16 bytes of I/O space used. */ + return (0x10); /* 16 bytes of I/O space used. */ } +static char *ep_conn_type[] = {"UTP", "AUI", "???", "BNC"}; + static int epattach(is) - struct isa_device *is; + struct isa_device *is; { - struct ep_softc *sc = &ep_softc[is->id_unit]; - struct ifnet *ifp = &sc->arpcom.ac_if; - u_short i; - struct ifaddr *ifa; - struct sockaddr_dl *sdl; - - sc->ep_iobase = is->id_iobase; - - printf("ep%d: ", is->id_unit); - - sc->ep_connectors = 0; - i = inw(is->id_iobase + EP_W0_CONFIG_CTRL); - if (i & IS_AUI) { - printf("aui"); - sc->ep_connectors |= AUI; - } - if (i & IS_BNC) { - if (sc->ep_connectors) - printf("/"); - printf("bnc"); - sc->ep_connectors |= BNC; - } - if (i & IS_UTP) { - if (sc->ep_connectors) - printf("/"); - printf("utp"); - sc->ep_connectors |= UTP; - } - if (!sc->ep_connectors) - printf("no connectors!"); - - /* - * Read the station address from the eeprom - */ - for (i = 0; i < 3; i++) { - u_short *p; - GO_WINDOW(0); - if (epbusyeeprom(is->id_unit, sc->ep_iobase)) - return(0); - outw(BASE + EP_W0_EEPROM_COMMAND, READ_EEPROM | i); - if (epbusyeeprom(is->id_unit, sc->ep_iobase)) - return(0); - p =(u_short *)&sc->arpcom.ac_enaddr[i*2]; - *p = htons(inw(BASE + EP_W0_EEPROM_DATA)); - GO_WINDOW(2); - outw(BASE + EP_W2_ADDR_0 + (i * 2), ntohs(*p)); - } - printf(" address %s\n", ether_sprintf(sc->arpcom.ac_enaddr)); - - ifp->if_unit = is->id_unit; - ifp->if_name = "ep"; - ifp->if_mtu = ETHERMTU; - ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | - IFF_MULTICAST ; - ifp->if_init = epinit; - ifp->if_output = ether_output; - ifp->if_start = epstart; - ifp->if_ioctl = epioctl; - ifp->if_watchdog = epwatchdog; - - if_attach(ifp); - ep_registerdev(is); + struct ep_softc *sc = &ep_softc[is->id_unit]; + struct ifnet *ifp = &sc->arpcom.ac_if; + u_short i, j, *p; + struct ifaddr *ifa; + struct sockaddr_dl *sdl; + + /* BASE = IS_BASE; */ + sc->ep_io_addr = is->id_iobase; + + printf("ep%d: ", is->id_unit); + + sc->ep_connectors = 0; + i = inw(IS_BASE + EP_W0_CONFIG_CTRL); + j = inw(IS_BASE + EP_W0_ADDRESS_CFG) >> 14; + if (i & IS_AUI) { + printf("aui"); + sc->ep_connectors |= AUI; + } + if (i & IS_BNC) { + if (sc->ep_connectors) + printf("/"); + printf("bnc"); + sc->ep_connectors |= BNC; + } + if (i & IS_UTP) { + if (sc->ep_connectors) + printf("/"); + printf("utp"); + sc->ep_connectors |= UTP; + } + if (!(sc->ep_connectors & 7)) + printf("no connectors!"); + else + printf("[*%s*]", ep_conn_type[j]); + + /* + * Read the station address from the eeprom + */ + p = (u_short *) & sc->arpcom.ac_enaddr; + for (i = 0; i < 3; i++) { + GO_WINDOW(0); + p[i] = htons(get_e(is, i)); + GO_WINDOW(2); + outw(BASE + EP_W2_ADDR_0 + (i * 2), ntohs(p[i])); + } + printf(" address %s\n", ether_sprintf(sc->arpcom.ac_enaddr)); + + ifp->if_unit = is->id_unit; + ifp->if_name = "ep"; + ifp->if_mtu = ETHERMTU; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS; + ifp->if_init = epinit; + ifp->if_output = ether_output; + ifp->if_start = epstart; + ifp->if_ioctl = epioctl; + ifp->if_watchdog = epwatchdog; + + if_attach(ifp); + ep_registerdev(is); + + /* + * Fill the hardware address into ifa_addr if we find an AF_LINK entry. + * We need to do this so bpf's can get the hardware addr of this card. + * netstat likes this too! + */ + ifa = ifp->if_addrlist; + while ((ifa != 0) && (ifa->ifa_addr != 0) && + (ifa->ifa_addr->sa_family != AF_LINK)) + ifa = ifa->ifa_next; + + if ((ifa != 0) && (ifa->ifa_addr != 0)) { + sdl = (struct sockaddr_dl *) ifa->ifa_addr; + sdl->sdl_type = IFT_ETHER; + sdl->sdl_alen = ETHER_ADDR_LEN; + sdl->sdl_slen = 0; + bcopy(sc->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN); + } + /* we give some initial parameters */ + sc->rx_avg_pkt = 128; + + /* + * NOTE: In all this I multiply everything by 64. + * W_s = the speed the CPU is able to write to the TX FIFO. + * T_s = the speed the board sends the info to the Ether. + * W_s/T_s = 16 (represents 16/64) => W_s = 25 % of T_s. + * This will give us for a packet of 1500 bytes + * tx_start_thresh=1125 and for a pkt of 64 bytes tx_start_threshold=48. + * We prefer to start thinking the CPU is much slower than the Ethernet + * transmission. + */ + sc->tx_rate = TX_INIT_RATE; + sc->tx_counter = 0; + sc->rx_latency = RX_INIT_LATENCY; + sc->rx_early_thresh = RX_INIT_EARLY_THRESH; +#ifdef EP_LOCAL_STATS + sc->rx_no_first = sc->rx_no_mbuf = + sc->rx_bpf_disc = sc->rx_overrunf = sc->rx_overrunl = + sc->tx_underrun = 0; +#endif + ep_fset(F_RX_FIRST); + sc->top = sc->mcur = 0; - /* - * Fill the hardware address into ifa_addr if we find an - * AF_LINK entry. We need to do this so bpf's can get the hardware - * addr of this card. netstat likes this too! - */ - ifa = ifp->if_addrlist; - while ((ifa != 0) && (ifa->ifa_addr != 0) && - (ifa->ifa_addr->sa_family != AF_LINK)) - ifa = ifa->ifa_next; - - if ((ifa != 0) && (ifa->ifa_addr != 0)) { - sdl = (struct sockaddr_dl *) ifa->ifa_addr; - sdl->sdl_type = IFT_ETHER; - sdl->sdl_alen = ETHER_ADDR_LEN; - sdl->sdl_slen = 0; - bcopy(sc->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN); - } #if NBPFILTER > 0 - bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); + bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); #endif - - sc->tx_start_thresh = 20; /* probably a good starting point. */ - - return 1; + return 1; } @@ -433,752 +623,847 @@ epattach(is) */ void epinit(unit) - int unit; + int unit; { - register struct ep_softc *sc = &ep_softc[unit]; - register struct ifnet *ifp = &sc->arpcom.ac_if; - int s, i; + register struct ep_softc *sc = &ep_softc[unit]; + register struct ifnet *ifp = &sc->arpcom.ac_if; + int s, i; - if (ifp->if_addrlist == (struct ifaddr *) 0) - return; + if (ifp->if_addrlist == (struct ifaddr *) 0) + return; - s = splimp(); - while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS) - ; + s = splimp(); + while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); - GO_WINDOW(0); + GO_WINDOW(0); - /* Disable the card */ - outw(BASE + EP_W0_CONFIG_CTRL, 0); + /* Disable the card */ + outw(BASE + EP_W0_CONFIG_CTRL, 0); - /* Enable the card */ - outw(BASE + EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ); + /* Enable the card */ + outw(BASE + EP_W0_CONFIG_CTRL, ENABLE_DRQ_IRQ); - GO_WINDOW(2); + GO_WINDOW(2); - /* Reload the ether_addr. */ - for (i = 0; i < 6; i++) - outb(BASE + EP_W2_ADDR_0 + i, sc->arpcom.ac_enaddr[i]); + /* Reload the ether_addr. */ + for (i = 0; i < 6; i++) + outb(BASE + EP_W2_ADDR_0 + i, sc->arpcom.ac_enaddr[i]); - outw(BASE + EP_COMMAND, RX_RESET); - outw(BASE + EP_COMMAND, TX_RESET); + outw(BASE + EP_COMMAND, RX_RESET); + outw(BASE + EP_COMMAND, TX_RESET); - /* Window 1 is operating window */ - GO_WINDOW(1); - for (i = 0; i < 31; i++) - inb(BASE + EP_W1_TX_STATUS); + /* Window 1 is operating window */ + GO_WINDOW(1); + for (i = 0; i < 31; i++) + inb(BASE + EP_W1_TX_STATUS); - /* get rid of stray intr's */ - outw(BASE + EP_COMMAND, ACK_INTR | 0xff); + /* get rid of stray intr's */ + outw(BASE + EP_COMMAND, ACK_INTR | 0xff); - outw(BASE + EP_COMMAND, SET_RD_0_MASK | S_CARD_FAILURE | S_RX_COMPLETE | - S_TX_COMPLETE | S_TX_AVAIL); - outw(BASE + EP_COMMAND, SET_INTR_MASK | S_CARD_FAILURE | S_RX_COMPLETE | - S_TX_COMPLETE | S_TX_AVAIL); + outw(BASE + EP_COMMAND, SET_RD_0_MASK | S_5_INTS); - outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | - FIL_MULTICAST | FIL_BRDCST); + outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS); + + outw(BASE + EP_COMMAND, SET_RX_FILTER | FIL_INDIVIDUAL | + FIL_GROUP | FIL_BRDCST); /* - * you can `ifconfig (link0|-link0) ep0' to get the following + * you can `ifconfig ep0 (bnc|aui)' to get the following * behaviour: - * -link0 disable AUI/UTP. enable BNC. - * link0 disable BNC. enable AUI. if the card has a UTP + * bnc disable AUI/UTP. enable BNC. + * aui disable BNC. enable AUI. if the card has a UTP * connector, that is enabled too. not sure, but it * seems you have to be careful to not plug things * into both AUI & UTP. */ #if defined(__NetBSD__) - if (!(ifp->if_flags & IFF_LINK0) && (sc->ep_connectors & BNC)) { + if (!(ifp->if_flags & IFF_LINK0) && (sc->ep_connectors & BNC)) { #else - if (!(ifp->if_flags & IFF_ALTPHYS) && (sc->ep_connectors & BNC)) { + if (!(ifp->if_flags & IFF_ALTPHYS) && (sc->ep_connectors & BNC)) { #endif - outw(BASE + EP_COMMAND, START_TRANSCEIVER); - DELAY(1000); - } + outw(BASE + EP_COMMAND, START_TRANSCEIVER); + DELAY(1000); + } #if defined(__NetBSD__) - if ((ifp->if_flags & IFF_LINK0) && (sc->ep_connectors & UTP)) { + if ((ifp->if_flags & IFF_LINK0) && (sc->ep_connectors & UTP)) { #else - if ((ifp->if_flags & IFF_ALTPHYS) && (sc->ep_connectors & UTP)) { + if ((ifp->if_flags & IFF_ALTPHYS) && (sc->ep_connectors & UTP)) { #endif - GO_WINDOW(4); - outw(BASE + EP_W4_MEDIA_TYPE, ENABLE_UTP); - GO_WINDOW(1); - } - - outw(BASE + EP_COMMAND, RX_ENABLE); - outw(BASE + EP_COMMAND, TX_ENABLE); - - ifp->if_flags |= IFF_RUNNING; - ifp->if_flags &= ~IFF_OACTIVE; /* just in case */ - /* - * Store up a bunch of mbuf's for use later. (MAX_MBS). First we - * free up any that we had in case we're being called from intr or - * somewhere else. - */ - sc->last_mb = 0; - sc->next_mb = 0; - epmbuffill((void *)sc); - - epstart(ifp); - - splx(s); + GO_WINDOW(4); + outw(BASE + EP_W4_MEDIA_TYPE, ENABLE_UTP); + GO_WINDOW(1); + } + outw(BASE + EP_COMMAND, RX_ENABLE); + outw(BASE + EP_COMMAND, TX_ENABLE); + + ifp->if_flags |= IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; /* just in case */ + + sc->tx_rate = TX_INIT_RATE; + sc->tx_counter = 0; + sc->rx_latency = RX_INIT_LATENCY; + sc->rx_early_thresh = RX_INIT_EARLY_THRESH; +#ifdef EP_LOCAL_STATS + sc->rx_no_first = sc->rx_no_mbuf = + sc->rx_bpf_disc = sc->rx_overrunf = sc->rx_overrunl = + sc->tx_underrun = 0; +#endif + ep_fset(F_RX_FIRST); + ep_frst(F_RX_TRAILER); + if (sc->top) { + m_freem(sc->top); + sc->top = sc->mcur = 0; + } + outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | sc->rx_early_thresh); + + /* + * Store up a bunch of mbuf's for use later. (MAX_MBS). First we free up + * any that we had in case we're being called from intr or somewhere + * else. + */ + sc->last_mb = 0; + sc->next_mb = 0; + epmbuffill((caddr_t) sc, 0); + + epstart(ifp); + + splx(s); } static const char padmap[] = {0, 3, 2, 1}; void epstart(ifp) - struct ifnet *ifp; + struct ifnet *ifp; { - register struct ep_softc *sc = &ep_softc[ifp->if_unit]; - struct mbuf *m, *top; - int s, len, pad; - - s = splimp(); - if (sc->arpcom.ac_if.if_flags & IFF_OACTIVE) { - splx(s); - return; - } - + register struct ep_softc *sc = &ep_softc[ifp->if_unit]; + register u_int len; + register struct mbuf *m; + struct mbuf *top; + int s, pad; + + s = splimp(); + if (sc->arpcom.ac_if.if_flags & IFF_OACTIVE) { + splx(s); + return; + } startagain: - /* Sneak a peek at the next packet */ - m = sc->arpcom.ac_if.if_snd.ifq_head; - if (m == 0) { - splx(s); - return; - } + /* Sneak a peek at the next packet */ + m = sc->arpcom.ac_if.if_snd.ifq_head; + if (m == 0) { + splx(s); + return; + } #if 0 - len = m->m_pkthdr.len; + len = m->m_pkthdr.len; #else - for (len = 0, top = m; m; m = m->m_next) - len += m->m_len; + for (len = 0, top = m; m; m = m->m_next) + len += m->m_len; #endif - pad = padmap[len & 3]; - - /* - * The 3c509 automatically pads short packets to minimum ethernet - * length, but we drop packets that are too large. Perhaps we should - * truncate them instead? - */ - if (len + pad > ETHER_MAX_LEN) { - /* packet is obviously too large: toss it */ - ++sc->arpcom.ac_if.if_oerrors; - IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m); - m_freem(m); - goto readcheck; - } - - if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) { - /* no room in FIFO */ - outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | (len + pad + 4)); - sc->arpcom.ac_if.if_flags |= IFF_OACTIVE; - splx(s); - return; - } else { - outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | 2044); - } + pad = padmap[len & 3]; + /* + * The 3c509 automatically pads short packets to minimum ethernet length, + * but we drop packets that are too large. Perhaps we should truncate + * them instead? + */ + if (len + pad > ETHER_MAX_LEN) { + /* packet is obviously too large: toss it */ + ++sc->arpcom.ac_if.if_oerrors; IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m); - if (m == 0) { /* not really needed */ - splx(s); - return; + m_freem(m); + goto readcheck; + } + if (inw(BASE + EP_W1_FREE_TX) < len + pad + 4) { + /* no room in FIFO */ + outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | (len + pad + 4)); + sc->arpcom.ac_if.if_flags |= IFF_OACTIVE; + splx(s); + return; + } + IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m); + + outw(BASE + EP_W1_TX_PIO_WR_1, len); + outw(BASE + EP_W1_TX_PIO_WR_1, 0x0); /* Second dword meaningless */ + + /* compute the Tx start threshold for this packet */ + sc->tx_start_thresh = len = + (((len * (64 - sc->tx_rate)) >> 6) & ~3) + 16; + outw(BASE + EP_COMMAND, SET_TX_START_THRESH | len); + + for (top = m; m != 0; m = m->m_next) + if(ep_ftst(F_ACCESS_32_BITS)) { + outsl(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), + m->m_len / 4); + if (m->m_len & 3) + outsb(BASE + EP_W1_TX_PIO_WR_1, + mtod(m, caddr_t) + m->m_len / 4, + m->m_len & 3); + } else { + outsw(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), m->m_len / 2); + if (m->m_len & 1) + outb(BASE + EP_W1_TX_PIO_WR_1, + *(mtod(m, caddr_t) + m->m_len - 1)); } - outw(BASE + EP_COMMAND, SET_TX_START_THRESH | - (len / 4 + sc->tx_start_thresh)); - - outw(BASE + EP_W1_TX_PIO_WR_1, len); - outw(BASE + EP_W1_TX_PIO_WR_1, 0xffff); /* Second dword meaningless */ - - for (top = m; m != 0; m = m->m_next) { - if (sc->bus32bit) { - if(m->m_len > 3) - outsl(BASE + EP_W1_TX_PIO_WR_1, - mtod(m, caddr_t), m->m_len/4); - if(m->m_len & 3) - outsb(BASE + EP_W1_TX_PIO_WR_1, - mtod(m, caddr_t) + (m->m_len & ~3), m->m_len & 3); - } else { - if (m->m_len > 1) - outsw(BASE + EP_W1_TX_PIO_WR_1, mtod(m, caddr_t), - m->m_len/2); - if (m->m_len & 1) - outb(BASE + EP_W1_TX_PIO_WR_1, - *(mtod(m, caddr_t) + m->m_len - 1)); - } - } - while (pad--) - outb(BASE + EP_W1_TX_PIO_WR_1, 0); /* Padding */ + while (pad--) + outb(BASE + EP_W1_TX_PIO_WR_1, 0); /* Padding */ #if NBPFILTER > 0 - if (sc->bpf) { - u_short etype; - int off, datasize, resid; - struct ether_header *eh; - struct trailer_header { - u_short ether_type; - u_short ether_residual; - } trailer_header; - char ether_packet[ETHER_MAX_LEN]; - char *ep; - - ep = ether_packet; - - /* - * We handle trailers below: - * Copy ether header first, then residual data, - * then data. Put all this in a temporary buffer - * 'ether_packet' and send off to bpf. Since the - * system has generated this packet, we assume - * that all of the offsets in the packet are - * correct; if they're not, the system will almost - * certainly crash in m_copydata. - * We make no assumptions about how the data is - * arranged in the mbuf chain (i.e. how much - * data is in each mbuf, if mbuf clusters are - * used, etc.), which is why we use m_copydata - * to get the ether header rather than assume - * that this is located in the first mbuf. - */ - /* copy ether header */ - m_copydata(top, 0, sizeof(struct ether_header), ep); - eh = (struct ether_header *) ep; - ep += sizeof(struct ether_header); - eh->ether_type = etype = ntohs(eh->ether_type); - if (etype >= ETHERTYPE_TRAIL && - etype < ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER) { - datasize = ((etype - ETHERTYPE_TRAIL) << 9); - off = datasize + sizeof(struct ether_header); - - /* copy trailer_header into a data structure */ - m_copydata(top, off, sizeof(struct trailer_header), - (caddr_t)&trailer_header.ether_type); - - /* copy residual data */ - resid = trailer_header.ether_residual - - sizeof(struct trailer_header); - resid = ntohs(resid); - m_copydata(top, off + sizeof(struct trailer_header), - resid, ep); - ep += resid; - - /* copy data */ - m_copydata(top, sizeof(struct ether_header), - datasize, ep); - ep += datasize; - - /* restore original ether packet type */ - eh->ether_type = trailer_header.ether_type; - - bpf_tap(sc->bpf, ether_packet, ep - ether_packet); - } else - bpf_mtap(sc->bpf, top); - } -#endif + if (sc->bpf) { + u_short etype; + int off, datasize, resid; + struct ether_header *eh; + struct trailer_header { + u_short ether_type; + u_short ether_residual; + } trailer_header; + char ether_packet[ETHER_MAX_LEN]; + char *ep; - m_freem(top); - ++sc->arpcom.ac_if.if_opackets; + ep = ether_packet; /* - * Is another packet coming in? We don't want to overflow the - * tiny RX fifo. + * We handle trailers below: Copy ether header first, then residual + * data, then data. Put all this in a temporary buffer 'ether_packet' + * and send off to bpf. Since the system has generated this packet, + * we assume that all of the offsets in the packet are correct; if + * they're not, the system will almost certainly crash in m_copydata. + * We make no assumptions about how the data is arranged in the mbuf + * chain (i.e. how much data is in each mbuf, if mbuf clusters are + * used, etc.), which is why we use m_copydata to get the ether + * header rather than assume that this is located in the first mbuf. */ + /* copy ether header */ + m_copydata(top, 0, sizeof(struct ether_header), ep); + eh = (struct ether_header *) ep; + ep += sizeof(struct ether_header); + eh->ether_type = etype = ntohs(eh->ether_type); + if (etype >= ETHERTYPE_TRAIL && + etype < ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER) { + datasize = ((etype - ETHERTYPE_TRAIL) << 9); + off = datasize + sizeof(struct ether_header); + + /* copy trailer_header into a data structure */ + m_copydata(top, off, sizeof(struct trailer_header), + (caddr_t) & trailer_header.ether_type); + + /* copy residual data */ + resid = trailer_header.ether_residual - + sizeof(struct trailer_header); + resid = ntohs(resid); + m_copydata(top, off + sizeof(struct trailer_header), + resid, ep); + ep += resid; + + /* copy data */ + m_copydata(top, sizeof(struct ether_header), + datasize, ep); + ep += datasize; + + /* restore original ether packet type */ + eh->ether_type = trailer_header.ether_type; + + bpf_tap(sc->bpf, ether_packet, ep - ether_packet); + } else + bpf_mtap(sc->bpf, top); + } +#endif + + sc->arpcom.ac_if.if_opackets++; + m_freem(top); + /* + * Every 1024*4 packets we increment the tx_rate if we haven't had + * errors, that in the case it has abnormaly goten too low + */ + if (!(++sc->tx_counter & (1024 * 4 - 1)) && + sc->tx_rate < TX_INIT_MAX_RATE) + sc->tx_rate++; + + /* + * Is another packet coming in? We don't want to overflow the tiny RX + * fifo. + */ readcheck: - if (inw(BASE + EP_W1_RX_STATUS) & RX_BYTES_MASK) { - splx(s); - return; + if (inw(BASE + EP_W1_RX_STATUS) & RX_BYTES_MASK) { + /* + * we check if we have packets left, in that case we prepare to come + * back later + */ + if (sc->arpcom.ac_if.if_snd.ifq_head) { + outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | + sc->tx_start_thresh); } - goto startagain; + splx(s); + return; + } + goto startagain; } void epintr(unit) - int unit; + int unit; { - int status, i; - register struct ep_softc *sc = &ep_softc[unit]; - struct ifnet *ifp = &sc->arpcom.ac_if; - struct mbuf *m; - - status = 0; -checkintr: - status = inw(BASE + EP_STATUS) & - (S_TX_COMPLETE | S_TX_AVAIL | S_RX_COMPLETE | S_CARD_FAILURE); - if (status == 0) { - /* No interrupts. */ - outw(BASE + EP_COMMAND, C_INTR_LATCH); - return; + int i; + register int status; + register struct ep_softc *sc = &ep_softc[unit]; + struct ifnet *ifp = &sc->arpcom.ac_if; + struct mbuf *m; + + outw(BASE + EP_COMMAND, SET_INTR_MASK); /* disable all Ints */ + outw(BASE + EP_COMMAND, C_INTR_LATCH); /* ACK int Latch */ + + while ((status = inw(BASE + EP_STATUS)) & S_5_INTS) { + if (status & (S_RX_COMPLETE | S_RX_EARLY)) { + /* we just need ACK for RX_EARLY */ + if (status & S_RX_EARLY) + outw(BASE + EP_COMMAND, C_RX_EARLY); + epread(sc); + continue; } - /* important that we do this first. */ - outw(BASE + EP_COMMAND, ACK_INTR | status); - if (status & S_TX_AVAIL) { - status &= ~S_TX_AVAIL; - inw(BASE + EP_W1_FREE_TX); - sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; - epstart(&sc->arpcom.ac_if); - } - if (status & S_RX_COMPLETE) { - status &= ~S_RX_COMPLETE; - epread(sc); + /* we need ACK */ + outw(BASE + EP_COMMAND, C_TX_AVAIL); + sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; + epstart(&sc->arpcom.ac_if); } if (status & S_CARD_FAILURE) { - printf("ep%d: reset (status: %x)\n", unit, status); - outw(BASE + EP_COMMAND, C_INTR_LATCH); - epinit(unit); - return; +#ifdef EP_LOCAL_STATS + printf("\nep%d:\n\tStatus: %x\n", unit, status); + GO_WINDOW(4); + printf("\tFIFO Diagnostic: %x\n", inw(BASE + EP_W4_FIFO_DIAG)); + printf("\tStat: %x\n", sc->stat); + printf("\tIpackets=%d, Opackets=%d\n", + sc->arpcom.ac_if.if_ipackets, sc->arpcom.ac_if.if_opackets); + printf("\tNOF=%d, NOMB=%d, BPFD=%d, RXOF=%d, RXOL=%d, TXU=%d\n", + sc->rx_no_first, sc->rx_no_mbuf, sc->rx_bpf_disc, sc->rx_overrunf, + sc->rx_overrunl, sc->tx_underrun); +#else + printf("ep%d: Status: %x\n", unit, status); +#endif + epinit(unit); + return; } if (status & S_TX_COMPLETE) { - status &= ~S_TX_COMPLETE; - /* - * We need to read TX_STATUS until we get a 0 status in - * order to turn off the interrupt flag. - */ - while ((i = inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE) { - outw(BASE + EP_W1_TX_STATUS, 0x0); - if (i & (TXS_MAX_COLLISION | TXS_JABBER | TXS_UNDERRUN)) { - if (i & TXS_MAX_COLLISION) - ++sc->arpcom.ac_if.if_collisions; - if (i & (TXS_JABBER | TXS_UNDERRUN)) { - outw(BASE + EP_COMMAND, TX_RESET); - if (i & TXS_UNDERRUN) { - if (sc->tx_start_thresh < ETHER_MAX_LEN) { - sc->tx_start_thresh += 20; - outw(BASE + EP_COMMAND, - SET_TX_START_THRESH | - sc->tx_start_thresh); - } - } - } - outw(BASE + EP_COMMAND, TX_ENABLE); - ++sc->arpcom.ac_if.if_oerrors; + /* we need ACK. we do it at the end */ + /* + * We need to read TX_STATUS until we get a 0 status in order to + * turn off the interrupt flag. + */ + while ((status = inb(BASE + EP_W1_TX_STATUS)) & TXS_COMPLETE) { + if (status & TXS_SUCCES_INTR_REQ); + else if (status & (TXS_UNDERRUN | TXS_JABBER | TXS_MAX_COLLISION)) { + outw(BASE + EP_COMMAND, TX_RESET); + if (status & TXS_UNDERRUN) { + if (sc->tx_rate > 1) { + sc->tx_rate--; /* Actually in steps of 1/64 */ + sc->tx_counter = 0; /* We reset it */ } +#ifdef EP_LOCAL_STATS + sc->tx_underrun++; +#endif + } else { + if (status & TXS_JABBER); + else /* TXS_MAX_COLLISION - we shouldn't get here */ + ++sc->arpcom.ac_if.if_collisions; + } + ++sc->arpcom.ac_if.if_oerrors; + outw(BASE + EP_COMMAND, TX_ENABLE); + /* + * To have a tx_avail_int but giving the chance to the + * Reception + */ + if (sc->arpcom.ac_if.if_snd.ifq_head) { + outw(BASE + EP_COMMAND, SET_TX_AVAIL_THRESH | 8); + } } - epstart(ifp); - } - goto checkintr; + outb(BASE + EP_W1_TX_STATUS, 0x0); /* pops up the next + * status */ + } /* while */ + } /* end TX_COMPLETE */ + } + /* re-enable ints */ + outw(BASE + EP_COMMAND, SET_INTR_MASK | S_5_INTS); } void epread(sc) - register struct ep_softc *sc; + register struct ep_softc *sc; { - struct ether_header *eh; - struct mbuf *mcur, *m, *m0, *top; - int totlen, lenthisone; - int save_totlen; - u_short etype; - int off, resid; - int count, spinwait; - int i; - - totlen = inw(BASE + EP_W1_RX_STATUS); - off = 0; - top = 0; - - if (totlen & ERR_RX) { - ++sc->arpcom.ac_if.if_ierrors; - goto out; + struct ether_header *eh; + struct mbuf *top, *mcur, *m; + int lenthisone; + + short rx_fifo2, status; + register short delta; + register short rx_fifo; + u_short etype; + + /* + * XXX I have just adapted the code for the protocol trailing processing + * as programed in the original driver. FreeBSD 1.1.5.1 release + */ + status = inw(BASE + EP_W1_RX_STATUS); + +read_again: + + if (status & ERR_RX) { + ++sc->arpcom.ac_if.if_ierrors; + if (status & ERR_RX_OVERRUN) { + /* + * we can think the rx latency is actually greather than we + * expect + */ +#ifdef EP_LOCAL_STATS + if (ep_ftst(F_RX_FIRST)) + sc->rx_overrunf++; + else + sc->rx_overrunl++; +#endif + if (sc->rx_latency < ETHERMTU) + sc->rx_latency += 16; } - save_totlen = totlen &= RX_BYTES_MASK; /* Lower 11 bits = RX bytes. */ - - m = sc->mb[sc->next_mb]; - sc->mb[sc->next_mb] = 0; - - if (m == 0) { - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == 0) - goto out; + goto out; + } + rx_fifo = rx_fifo2 = status & RX_BYTES_MASK; + + if (ep_ftst(F_RX_FIRST)) { + if (m = sc->mb[sc->next_mb]) { + sc->mb[sc->next_mb] = 0; + sc->next_mb = (sc->next_mb + 1) % MAX_MBS; + m->m_data = m->m_pktdat; + m->m_flags = M_PKTHDR; } else { - /* Convert one of our saved mbuf's */ - sc->next_mb = (sc->next_mb + 1) % MAX_MBS; - m->m_data = m->m_pktdat; - m->m_flags = M_PKTHDR; + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (!m) + goto out; } - - top = m0 = m; /* We assign top so we can "goto out" */ + sc->top = sc->mcur = top = m; #define EROUND ((sizeof(struct ether_header) + 3) & ~3) #define EOFF (EROUND - sizeof(struct ether_header)) - m0->m_data += EOFF; + top->m_data += EOFF; + /* Read what should be the header. */ insw(BASE + EP_W1_RX_PIO_RD_1, - mtod(m0, caddr_t), sizeof(struct ether_header) / 2); - m->m_len = sizeof(struct ether_header); - totlen -= sizeof(struct ether_header); + mtod(top, caddr_t), sizeof(struct ether_header) / 2); + top->m_len = sizeof(struct ether_header); + rx_fifo -= sizeof(struct ether_header); + sc->cur_len = rx_fifo2; + /* - * mostly deal with trailer here. (untested) - * We do this in a couple of parts. First we check for a trailer, if - * we have one we convert the mbuf back to a regular mbuf and set the offset and - * subtract sizeof(struct ether_header) from the pktlen. - * After we've read the packet off the interface (all except for the trailer - * header, we then get a header mbuf, read the trailer into it, and fix up - * the mbuf pointer chain. + * Test for trailers. + * I didn't care if this implementation was OK, I just adapted it to + * have the same behaviour as in the original driver */ - eh = mtod(m, struct ether_header *); - eh->ether_type = etype = ntohs((u_short) eh->ether_type); + eh = mtod(top, struct ether_header *); + etype = eh->ether_type = ntohs((u_short) eh->ether_type); if (etype >= ETHERTYPE_TRAIL && etype < ETHERTYPE_TRAIL + ETHERTYPE_NTRAILER) { - m->m_data = m->m_dat; /* Convert back to regular mbuf. */ - m->m_flags = 0; /* This sucks but non-trailers are the norm */ - off = (etype - ETHERTYPE_TRAIL) * 512; - if (off >= ETHERMTU) { - m_freem(m); - return; /* sanity */ - } - totlen -= sizeof(struct ether_header); /* We don't read the trailer */ - m->m_data += 2 * sizeof(u_short); /* Get rid of type & len */ - } - while (totlen > 0) { - lenthisone = min(totlen, M_TRAILINGSPACE(m)); - if (lenthisone == 0) { /* no room in this one */ - mcur = m; - m = sc->mb[sc->next_mb]; - sc->mb[sc->next_mb] = 0; - if (!m) { - MGET(m, M_DONTWAIT, MT_DATA); - if (m == 0) - goto out; - } else { - timeout(epmbuffill, (caddr_t)sc, 0); - sc->next_mb = (sc->next_mb + 1) % MAX_MBS; - } - if (totlen >= MINCLSIZE) - MCLGET(m, M_DONTWAIT); - m->m_len = 0; - mcur->m_next = m; - lenthisone = min(totlen, M_TRAILINGSPACE(m)); - } - if (sc->bus32bit) { - if(totlen > 3) { - lenthisone &= ~3; - insl(BASE + EP_W1_RX_PIO_RD_1, - mtod(m, caddr_t) + m->m_len, lenthisone / 4); - } else - insb(BASE + EP_W1_RX_PIO_RD_1, - mtod(m, caddr_t) + m->m_len, lenthisone); - } else { - if (totlen > 1) { - lenthisone &= ~1; - insw(BASE + EP_W1_RX_PIO_RD_1, - mtod(m, caddr_t) + m->m_len, lenthisone / 2); - } else - *(mtod(m, caddr_t) + m->m_len) = - inb(BASE + EP_W1_RX_PIO_RD_1); - } - m->m_len += lenthisone; - totlen -= lenthisone; + if ((etype - ETHERTYPE_TRAIL) * 512 >= ETHERMTU) + goto out; + m->m_data = m->m_dat; /* Convert back to regular mbuf. */ + m->m_flags = 0; /* This sucks but non-trailers are the norm */ + m->m_data += 2 * sizeof(u_short); /* Get rid of type & len */ + + sc->cur_len = sizeof(struct ether_header); + ep_fset(F_RX_TRAILER); + + /* in the case of trailers, we prefer to have the packet complete */ + if (status & ERR_RX_INCOMPLETE) { + ep_frst(F_RX_FIRST); + outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | 2032); /* disable */ + return; + } else + /* We don't read the trailer, next we are reading the data */ + rx_fifo -= sizeof(struct ether_header); } - if (off) { - top = sc->mb[sc->next_mb]; + } else { + /* come here if we didn't have a complete packet last time */ + top = sc->top; + m = sc->mcur; + sc->cur_len += rx_fifo2; + if (ep_ftst(F_RX_TRAILER)) + /* We don't read the trailer */ + rx_fifo -= sizeof(struct ether_header); + } + + /* Reads what is left in the RX FIFO */ + while (rx_fifo > 0) { + lenthisone = min(rx_fifo, M_TRAILINGSPACE(m)); + if (lenthisone == 0) { /* no room in this one */ + mcur = m; + if (m = sc->mb[sc->next_mb]) { sc->mb[sc->next_mb] = 0; - if (top == 0) { - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (top == 0) { - top = m0; - goto out; - } - } else { - /* Convert one of our saved mbuf's */ - sc->next_mb = (sc->next_mb + 1) % MAX_MBS; - top->m_data = top->m_pktdat; - top->m_flags = M_PKTHDR; - } - insw(BASE + EP_W1_RX_PIO_RD_1, mtod(top, caddr_t), - sizeof(struct ether_header)); - top->m_next = m0; - top->m_len = sizeof(struct ether_header); - /* XXX Accomodate for type and len from beginning of trailer */ - top->m_pkthdr.len = save_totlen - (2 * sizeof(u_short)); + sc->next_mb = (sc->next_mb + 1) % MAX_MBS; + } else { + MGET(m, M_DONTWAIT, MT_DATA); + if (!m) + goto out; + } + + if (rx_fifo >= MINCLSIZE) + MCLGET(m, M_DONTWAIT); + m->m_len = 0; + mcur->m_next = m; + lenthisone = min(rx_fifo, M_TRAILINGSPACE(m)); + } + if (ep_ftst(F_ACCESS_32_BITS)) { /* default for EISA configured cards*/ + insl(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len, + lenthisone / 4); + m->m_len += (lenthisone & ~3); + if (lenthisone & 3) + insb(BASE + EP_W1_RX_PIO_RD_1, + mtod(m, caddr_t) + m->m_len, + lenthisone & 3); + m->m_len += (lenthisone & 3); + } else { + insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t) + m->m_len, + lenthisone / 2); + m->m_len += lenthisone; + if (lenthisone & 1) + *(mtod(m, caddr_t) + m->m_len - 1) = inb(BASE + EP_W1_RX_PIO_RD_1); + } + rx_fifo -= lenthisone; + } + + if (ep_ftst(F_RX_TRAILER)) {/* reads the trailer */ + if (m = sc->mb[sc->next_mb]) { + sc->mb[sc->next_mb] = 0; + sc->next_mb = (sc->next_mb + 1) % MAX_MBS; + m->m_data = m->m_pktdat; + m->m_flags = M_PKTHDR; } else { - top = m0; - top->m_pkthdr.len = save_totlen; + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (!m) + goto out; } + insw(BASE + EP_W1_RX_PIO_RD_1, mtod(m, caddr_t), + sizeof(struct ether_header)); + m->m_len = sizeof(struct ether_header); + m->m_next = top; + sc->top = top = m; + /* XXX Accomodate for type and len from beginning of trailer */ + sc->cur_len -= (2 * sizeof(u_short)); + ep_frst(F_RX_TRAILER); + goto all_pkt; + } + + if (status & ERR_RX_INCOMPLETE) { /* we haven't received the complete + * packet */ + sc->mcur = m; +#ifdef EP_LOCAL_STATS + sc->rx_no_first++; /* to know how often we come here */ +#endif + /* + * Re-compute rx_latency, the factor used is 1/4 to go up and 1/32 to + * go down + */ + delta = rx_fifo2 - sc->rx_early_thresh; /* last latency seen LLS */ + delta -= sc->rx_latency;/* LLS - estimated_latency */ + if (delta >= 0) + sc->rx_latency += (delta / 4); + else + sc->rx_latency += (delta / 32); + ep_frst(F_RX_FIRST); + if (!((status = inw(BASE + EP_W1_RX_STATUS)) & ERR_RX_INCOMPLETE)) { + /* we see if by now, the packet has completly arrived */ + goto read_again; + } + /* compute rx_early_threshold */ + delta = (sc->rx_avg_pkt - sc->cur_len - sc->rx_latency - 16) & ~3; + if (delta < MIN_RX_EARLY_THRESHL) + delta = MIN_RX_EARLY_THRESHL; + + outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | + (sc->rx_early_thresh = delta)); + return; + } +all_pkt: + outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK); + /* + * recompute average packet's length, the factor used is 1/8 to go down + * and 1/32 to go up + */ + delta = sc->cur_len - sc->rx_avg_pkt; + if (delta > 0) + sc->rx_avg_pkt += (delta / 32); + else + sc->rx_avg_pkt += (delta / 8); + delta = (sc->rx_avg_pkt - sc->rx_latency - 16) & ~3; + if (delta < MIN_RX_EARLY_THRESHF) + delta = MIN_RX_EARLY_THRESHF; + sc->rx_early_thresh = delta; + ++sc->arpcom.ac_if.if_ipackets; + ep_fset(F_RX_FIRST); + ep_frst(F_RX_TRAILER); + top->m_pkthdr.rcvif = &sc->arpcom.ac_if; + top->m_pkthdr.len = sc->cur_len; - top->m_pkthdr.rcvif = &sc->arpcom.ac_if; - outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK); - while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS) - ; - ++sc->arpcom.ac_if.if_ipackets; #if NBPFILTER > 0 - if (sc->bpf) { - bpf_mtap(sc->bpf, top); + if (sc->bpf) { + bpf_mtap(sc->bpf, top); - /* - * Note that the interface cannot be in promiscuous mode if - * there are no BPF listeners. And if we are in promiscuous - * mode, we have to check if this packet is really ours. - */ - if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) && - (eh->ether_dhost[0] & 1) == 0 && - bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, - sizeof(eh->ether_dhost)) != 0 && - bcmp(eh->ether_dhost, etherbroadcastaddr, - sizeof(eh->ether_dhost)) != 0) { - m_freem(top); - return; - } + /* + * Note that the interface cannot be in promiscuous mode if there are + * no BPF listeners. And if we are in promiscuous mode, we have to + * check if this packet is really ours. + */ + eh = mtod(top, struct ether_header *); + if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) && + (eh->ether_dhost[0] & 1) == 0 && + bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, + sizeof(eh->ether_dhost)) != 0 && + bcmp(eh->ether_dhost, etherbroadcastaddr, + sizeof(eh->ether_dhost)) != 0) { + if (sc->top) { + m_freem(sc->top); + sc->top = 0; + } + ep_fset(F_RX_FIRST); + ep_frst(F_RX_TRAILER); +#ifdef EP_LOCAL_STATS + sc->rx_bpf_disc++; +#endif + while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); + outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | delta); + return; } + } #endif - m_adj(top, sizeof(struct ether_header)); - ether_input(&sc->arpcom.ac_if, eh, top); - return; - -out: outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK); - while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS) - ; - if (top) - m_freem(top); + eh = mtod(top, struct ether_header *); + m_adj(top, sizeof(struct ether_header)); + ether_input(&sc->arpcom.ac_if, eh, top); + if (!sc->mb[sc->next_mb]) + epmbuffill((caddr_t) sc, 0); + sc->top = 0; + while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); + outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | delta); + return; + +out: + outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK); + if (sc->top) { + m_freem(sc->top); + sc->top = 0; +#ifdef EP_LOCAL_STATS + sc->rx_no_mbuf++; +#endif + } + delta = (sc->rx_avg_pkt - sc->rx_latency - 16) & ~3; + if (delta < MIN_RX_EARLY_THRESHF) + delta = MIN_RX_EARLY_THRESHF; + ep_fset(F_RX_FIRST); + ep_frst(F_RX_TRAILER); + while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); + outw(BASE + EP_COMMAND, SET_RX_EARLY_THRESH | + (sc->rx_early_thresh = delta)); } - /* * Look familiar? */ static int epioctl(ifp, cmd, data) - register struct ifnet *ifp; - int cmd; - caddr_t data; + register struct ifnet *ifp; + int cmd; + caddr_t data; { - register struct ifaddr *ifa = (struct ifaddr *) data; - struct ep_softc *sc = &ep_softc[ifp->if_unit]; - struct ifreq *ifr = (struct ifreq *) data; - int s, error = 0; - - switch (cmd) { - case SIOCSIFADDR: - ifp->if_flags |= IFF_UP; - switch (ifa->ifa_addr->sa_family) { + register struct ifaddr *ifa = (struct ifaddr *) data; + struct ep_softc *sc = &ep_softc[ifp->if_unit]; + struct ifreq *ifr = (struct ifreq *) data; + int s, error = 0; + + switch (cmd) { + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; + switch (ifa->ifa_addr->sa_family) { #ifdef INET - case AF_INET: - epinit(ifp->if_unit); /* before arpwhohas */ - ((struct arpcom *) ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr; - arpwhohas((struct arpcom *) ifp, &IA_SIN(ifa)->sin_addr); - break; + case AF_INET: + epinit(ifp->if_unit); /* before arpwhohas */ + ((struct arpcom *) ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr; + arpwhohas((struct arpcom *) ifp, &IA_SIN(ifa)->sin_addr); + break; #endif #ifdef NS - case AF_NS: - { - register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); - - if (ns_nullhost(*ina)) - ina->x_host = - *(union ns_host *)(sc->arpcom.ac_enaddr); - else { - ifp->if_flags &= ~IFF_RUNNING; - bcopy((caddr_t) ina->x_host.c_host, - (caddr_t)sc->arpcom.ac_enaddr, - sizeof(sc->arpcom.ac_enaddr)); - } - epinit(ifp->if_unit); - break; - } -#endif - default: - epinit(ifp->if_unit); - break; + case AF_NS: + { + register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); + + if (ns_nullhost(*ina)) + ina->x_host = + *(union ns_host *) (sc->arpcom.ac_enaddr); + else { + ifp->if_flags &= ~IFF_RUNNING; + bcopy((caddr_t) ina->x_host.c_host, + (caddr_t) sc->arpcom.ac_enaddr, + sizeof(sc->arpcom.ac_enaddr)); } + epinit(ifp->if_unit); break; - case SIOCSIFFLAGS: - if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) { - ifp->if_flags &= ~IFF_RUNNING; - epstop(ifp->if_unit); - epmbufempty(sc); - break; - } - if (ifp->if_flags & IFF_UP && (ifp->if_flags & IFF_RUNNING) == 0) - epinit(ifp->if_unit); - break; + } +#endif + default: + epinit(ifp->if_unit); + break; + } + break; + case SIOCSIFFLAGS: + if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & IFF_RUNNING) { + ifp->if_flags &= ~IFF_RUNNING; + epstop(ifp->if_unit); + epmbufempty(sc); + break; + } + if (ifp->if_flags & IFF_UP && (ifp->if_flags & IFF_RUNNING) == 0) + epinit(ifp->if_unit); + break; #ifdef notdef - case SIOCGHWADDR: - bcopy((caddr_t) sc->sc_addr, (caddr_t) &ifr->ifr_data, - sizeof(sc->sc_addr)); - break; + case SIOCGHWADDR: + bcopy((caddr_t) sc->sc_addr, (caddr_t) & ifr->ifr_data, + sizeof(sc->sc_addr)); + break; #endif - case SIOCSIFMTU: + case SIOCSIFMTU: /* * Set the interface MTU. */ - if (ifr->ifr_mtu > ETHERMTU) { - error = EINVAL; + if (ifr->ifr_mtu > ETHERMTU) { + error = EINVAL; } else { - ifp->if_mtu = ifr->ifr_mtu; + ifp->if_mtu = ifr->ifr_mtu; } - break; + break; - default: + default: error = EINVAL; - } - return (error); + } + return (error); } void epreset(unit) - int unit; + int unit; { - int s = splimp(); + int s = splimp(); - epstop(unit); - epinit(unit); - splx(s); + epstop(unit); + epinit(unit); + splx(s); } void epwatchdog(unit) - int unit; + int unit; { - struct ep_softc *sc = &ep_softc[unit]; + struct ep_softc *sc = &ep_softc[unit]; - log(LOG_ERR, "ep%d: watchdog\n", unit); - ++sc->arpcom.ac_if.if_oerrors; + log(LOG_ERR, "ep%d: watchdog\n", unit); + ++sc->arpcom.ac_if.if_oerrors; - epreset(unit); + epreset(unit); } void epstop(unit) - int unit; + int unit; { - struct ep_softc *sc = &ep_softc[unit]; - - outw(BASE + EP_COMMAND, RX_DISABLE); - outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK); - while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS) - ; - outw(BASE + EP_COMMAND, TX_DISABLE); - outw(BASE + EP_COMMAND, STOP_TRANSCEIVER); - outw(BASE + EP_COMMAND, RX_RESET); - outw(BASE + EP_COMMAND, TX_RESET); - outw(BASE + EP_COMMAND, C_INTR_LATCH); - outw(BASE + EP_COMMAND, SET_RD_0_MASK); - outw(BASE + EP_COMMAND, SET_INTR_MASK); - outw(BASE + EP_COMMAND, SET_RX_FILTER); + struct ep_softc *sc = &ep_softc[unit]; + + outw(BASE + EP_COMMAND, RX_DISABLE); + outw(BASE + EP_COMMAND, RX_DISCARD_TOP_PACK); + while (inw(BASE + EP_STATUS) & S_COMMAND_IN_PROGRESS); + outw(BASE + EP_COMMAND, TX_DISABLE); + outw(BASE + EP_COMMAND, STOP_TRANSCEIVER); + outw(BASE + EP_COMMAND, RX_RESET); + outw(BASE + EP_COMMAND, TX_RESET); + outw(BASE + EP_COMMAND, C_INTR_LATCH); + outw(BASE + EP_COMMAND, SET_RD_0_MASK); + outw(BASE + EP_COMMAND, SET_INTR_MASK); + outw(BASE + EP_COMMAND, SET_RX_FILTER); } -/* - * This is adapted straight from the book. There's probably a better way. - */ static int send_ID_sequence(port) - u_short port; + int port; { - char cx, al; + int cx, al; - cx = 0x0ff; - al = 0x0ff; - - outb(port, 0x0); - DELAY(1000); - outb(port, 0x0); - DELAY(1000); - -loop1: cx--; + for (al = 0xff, cx = 0; cx < 255; cx++) { outb(port, al); - if (!(al & 0x80)) { - al = al << 1; - goto loop1; - } - al = al << 1; - al ^= 0xcf; - if (cx) - goto loop1; - - return(1); + al <<= 1; + if (al & 0x100) + al ^= 0xcf; + } + return (1); } /* - * We get eeprom data from the id_port given an offset into the - * eeprom. Basically; after the ID_sequence is sent to all of - * the cards; they enter the ID_CMD state where they will accept - * command requests. 0x80-0xbf loads the eeprom data. We then - * read the port 16 times and with every read; the cards check - * for contention (ie: if one card writes a 0 bit and another - * writes a 1 bit then the host sees a 0. At the end of the cycle; - * each card compares the data on the bus; if there is a difference - * then that card goes into ID_WAIT state again). In the meantime; - * one bit of data is returned in the AX register which is conveniently - * returned to us by inb(). Hence; we read 16 times getting one - * bit of data with each read. + * We get eeprom data from the id_port given an offset into the eeprom. + * Basically; after the ID_sequence is sent to all of the cards; they enter + * the ID_CMD state where they will accept command requests. 0x80-0xbf loads + * the eeprom data. We then read the port 16 times and with every read; the + * cards check for contention (ie: if one card writes a 0 bit and another + * writes a 1 bit then the host sees a 0. At the end of the cycle; each card + * compares the data on the bus; if there is a difference then that card goes + * into ID_WAIT state again). In the meantime; one bit of data is returned in + * the AX register which is conveniently returned to us by inb(). Hence; we + * read 16 times getting one bit of data with each read. */ -static u_short -epreadeeprom(id_port, offset) - int id_port; - int offset; -{ - int i, data = 0; - outb(id_port, 0x80 + offset); - DELAY(1000); - for (i = 0; i < 16; i++) - data = (data << 1) | (inw(id_port) & 1); - return (data); -} - static int -epbusyeeprom(unit, base) - int unit; ushort base; +get_eeprom_data(id_port, offset) + int id_port; + int offset; { - int i = 0, j; - - while (i++ < 100) { - j = inw(base + EP_W0_EEPROM_COMMAND); - if (j & EEPROM_BUSY) - DELAY(100); - else - break; - } - if (i >= 100) { - printf("\nep%d: eeprom failed to come ready.\n", unit); - return (1); - } - if (j & EEPROM_TST_MODE) { - printf("\nep%d: 3c509 in test mode. Erase pencil mark!\n", unit); - return (1); - } - return (0); + int i, data = 0; + outb(id_port, 0x80 + offset); + DELAY(1000); + for (i = 0; i < 16; i++) + data = (data << 1) | (inw(id_port) & 1); + return (data); } -void -epmbuffill(sp) - void *sp; +/* + * We suppose this is always called inside a splimp(){...}splx() region + */ +static void +epmbuffill(sp, dummy_arg) + caddr_t sp; + int dummy_arg; { - struct ep_softc *sc = (struct ep_softc *)sp; - int s, i; - - s = splimp(); - i = sc->last_mb; - do { - if(sc->mb[i] == NULL) - MGET(sc->mb[i], M_DONTWAIT, MT_DATA); - if(sc->mb[i] == NULL) - break; - i = (i + 1) % MAX_MBS; - } while (i != sc->next_mb); - sc->last_mb = i; - splx(s); + struct ep_softc *sc = (struct ep_softc *) sp; + int i; + + i = sc->last_mb; + do { + if (sc->mb[i] == NULL) + MGET(sc->mb[i], M_DONTWAIT, MT_DATA); + if (sc->mb[i] == NULL) + break; + i = (i + 1) % MAX_MBS; + } while (i != sc->next_mb); + sc->last_mb = i; } static void epmbufempty(sc) - struct ep_softc *sc; + struct ep_softc *sc; { - int s, i; + int s, i; - s = splimp(); - for (i = 0; i<MAX_MBS; i++) { - if (sc->mb[i]) { - m_freem(sc->mb[i]); - sc->mb[i] = NULL; - } + s = splimp(); + for (i = 0; i < MAX_MBS; i++) { + if (sc->mb[i]) { + m_freem(sc->mb[i]); + sc->mb[i] = NULL; } - sc->last_mb = sc->next_mb = 0; - untimeout(epmbuffill, sc); - splx(s); + } + sc->last_mb = sc->next_mb = 0; + splx(s); } -#endif /* NEP > 0 */ +#endif /* NEP > 0 */ diff --git a/sys/dev/ep/if_epreg.h b/sys/dev/ep/if_epreg.h index 2b2bcb9..2dc7a98 100644 --- a/sys/dev/ep/if_epreg.h +++ b/sys/dev/ep/if_epreg.h @@ -1,30 +1,119 @@ /* - * Copyright (c) 1993 Herb Peyerl (hpeyerl@novatel.ca) - * All rights reserved. - * + * Copyright (c) 1993 Herb Peyerl (hpeyerl@novatel.ca) All rights reserved. + * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. The name of the author may not be used to endorse or promote products - * derived from this software withough specific prior written permission - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * $Id: if_epreg.h,v 1.2 1994/01/10 19:13:50 ats Exp $ + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. The name + * of the author may not be used to endorse or promote products derived from + * this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Id: if_epreg.h,v 1.2 1994/01/10 19:13:50 ats Exp $ Modified by: + * + October 2, 1994 + + Modified by: Andres Vega Garcia + + INRIA - Sophia Antipolis, France + e-mail: avega@sophia.inria.fr + finger: avega@pax.inria.fr + + */ + +/* + * Ethernet software status per interface. + */ +struct ep_softc { + struct arpcom arpcom; /* Ethernet common part */ + short ep_io_addr; /* i/o bus address */ +#define MAX_MBS 8 /* # of mbufs we keep around */ + struct mbuf *mb[MAX_MBS]; /* spare mbuf storage. */ + int next_mb; /* Which mbuf to use next. */ + int last_mb; /* Last mbuf. */ + struct mbuf *top, *mcur; + short tx_start_thresh; /* Current TX_start_thresh. */ + short tx_rate; + short tx_counter; + short rx_early_thresh; /* Current RX_early_thresh. */ + short rx_latency; + short rx_avg_pkt; + short cur_len; + caddr_t bpf; /* BPF "magic cookie" */ + u_short ep_connectors; /* Connectors on this card. */ + int stat; /* some flags */ +#define F_RX_FIRST 0x1 +#define F_WAIT_TRAIL 0x2 +#define F_RX_TRAILER 0x4 + +#define F_ACCESS_32_BITS 0x100 + +#ifdef EP_LOCAL_STATS + short tx_underrun; + short rx_no_first; + short rx_no_mbuf; + short rx_bpf_disc; + short rx_overrunf; + short rx_overrunl; +#endif +}; + +/* + * Some global constants + */ +#define ETHER_MIN_LEN 64 +#define ETHER_MAX_LEN 1518 +#define ETHER_ADDR_LEN 6 + +#define TX_INIT_RATE 16 +#define TX_INIT_MAX_RATE 64 +#define RX_INIT_LATENCY 64 +#define RX_INIT_EARLY_THRESH 64 +#define MIN_RX_EARLY_THRESHF 16 /* not less than ether_header */ +#define MIN_RX_EARLY_THRESHL 4 + +#define EEPROMSIZE 0x40 +#define MAX_EEPROMBUSY 1000 +#define EP_LAST_TAG 0xd7 +#define EP_MAX_BOARDS 16 +#define EP_ID_PORT 0x100 + +/* + * some macros to acces long named fields + */ +#define IS_BASE (is->id_iobase) +#define BASE (sc->ep_io_addr) + +/* + * Commands to read/write EEPROM trough EEPROM command register (Window 0, + * Offset 0xa) */ +#define EEPROM_CMD_RD 0x0080 /* Read: Address required (5 bits) */ +#define EEPROM_CMD_WR 0x0040 /* Write: Address required (5 bits) */ +#define EEPROM_CMD_ERASE 0x00c0 /* Erase: Address required (5 bits) */ +#define EEPROM_CMD_EWEN 0x0030 /* Erase/Write Enable: No data required */ + +#define EEPROM_BUSY (1<<15) +#define EEPROM_TST_MODE (1<<14) + +/* + * Some short functions, worth to let them be a macro + */ +#define is_eeprom_busy(b) (inw((b)+EP_W0_EEPROM_COMMAND)&EEPROM_BUSY) +#define GO_WINDOW(x) outw(BASE+EP_COMMAND, WINDOW_SELECT|(x)) + /************************************************************************** - * * + * * * These define the EEPROM data structure. They are used in the probe * function to verify the existance of the adapter after having sent * the ID_Sequence. @@ -39,7 +128,7 @@ #define EEPROM_PROD_ID 0x3 /* 0x9[0-f]50 */ #define EEPROM_MFG_ID 0x7 /* 0x6d50 */ #define EEPROM_ADDR_CFG 0x8 /* Base addr */ -#define EEPROM_RESOURCE_CFG 0x9 /* IRQ. Bits 12-15 */ +#define EEPROM_RESOURCE_CFG 0x9 /* IRQ. Bits 12-15 */ /************************************************************************** * * @@ -50,32 +139,35 @@ * * **************************************************************************/ -#define EP_COMMAND 0x0e /* Write. BASE+0x0e is always a command reg. */ -#define EP_STATUS 0x0e /* Read. BASE+0x0e is always status reg. */ -#define EP_WINDOW 0x0f /* Read. BASE+0x0f is always window reg. */ +#define EP_COMMAND 0x0e /* Write. BASE+0x0e is always a + * command reg. */ +#define EP_STATUS 0x0e /* Read. BASE+0x0e is always status + * reg. */ +#define EP_WINDOW 0x0f /* Read. BASE+0x0f is always window + * reg. */ /* * Window 0 registers. Setup. */ - /* Write */ +/* Write */ #define EP_W0_EEPROM_DATA 0x0c #define EP_W0_EEPROM_COMMAND 0x0a #define EP_W0_RESOURCE_CFG 0x08 #define EP_W0_ADDRESS_CFG 0x06 #define EP_W0_CONFIG_CTRL 0x04 - /* Read */ +/* Read */ #define EP_W0_PRODUCT_ID 0x02 #define EP_W0_MFG_ID 0x00 /* * Window 1 registers. Operating Set. */ - /* Write */ +/* Write */ #define EP_W1_TX_PIO_WR_2 0x02 #define EP_W1_TX_PIO_WR_1 0x00 - /* Read */ +/* Read */ #define EP_W1_FREE_TX 0x0c -#define EP_W1_TX_STATUS 0x0b /* byte */ -#define EP_W1_TIMER 0x0a /* byte */ +#define EP_W1_TX_STATUS 0x0b /* byte */ +#define EP_W1_TIMER 0x0a /* byte */ #define EP_W1_RX_STATUS 0x08 #define EP_W1_RX_PIO_RD_2 0x02 #define EP_W1_RX_PIO_RD_1 0x00 @@ -83,7 +175,7 @@ /* * Window 2 registers. Station Address Setup/Read */ - /* Read/Write */ +/* Read/Write */ #define EP_W2_ADDR_5 0x05 #define EP_W2_ADDR_4 0x04 #define EP_W2_ADDR_3 0x03 @@ -91,17 +183,17 @@ #define EP_W2_ADDR_1 0x01 #define EP_W2_ADDR_0 0x00 -/* +/* * Window 3 registers. FIFO Management. */ - /* Read */ +/* Read */ #define EP_W3_FREE_TX 0x0c #define EP_W3_FREE_RX 0x0a /* * Window 4 registers. Diagnostics. */ - /* Read/Write */ +/* Read/Write */ #define EP_W4_MEDIA_TYPE 0x0a #define EP_W4_CTRLR_STATUS 0x08 #define EP_W4_NET_DIAG 0x06 @@ -112,7 +204,7 @@ /* * Window 5 Registers. Results and Internal status. */ - /* Read */ +/* Read */ #define EP_W5_READ_0_MASK 0x0c #define EP_W5_INTR_MASK 0x0a #define EP_W5_RX_FILTER 0x08 @@ -123,7 +215,7 @@ /* * Window 6 registers. Statistics. */ - /* Read/Write */ +/* Read/Write */ #define TX_TOTAL_OK 0x0c #define RX_TOTAL_OK 0x0a #define TX_DEFERRALS 0x08 @@ -150,13 +242,17 @@ * 10-0: 11-bit arg if any. For commands with no args; * this can be set to anything. */ -#define GLOBAL_RESET (u_short) 0x0000 /* Wait at least 1ms after issuing */ +#define GLOBAL_RESET (u_short) 0x0000 /* Wait at least 1ms + * after issuing */ #define WINDOW_SELECT (u_short) (0x1<<11) -#define START_TRANSCEIVER (u_short) (0x2<<11) /* Read ADDR_CFG reg to determine - whether this is needed. If so; - wait 800 uSec before using trans- - ceiver. */ -#define RX_DISABLE (u_short) (0x3<<11) /* state disabled on power-up */ +#define START_TRANSCEIVER (u_short) (0x2<<11) /* Read ADDR_CFG reg to + * determine whether + * this is needed. If + * so; wait 800 uSec + * before using trans- + * ceiver. */ +#define RX_DISABLE (u_short) (0x3<<11) /* state disabled on + * power-up */ #define RX_ENABLE (u_short) (0x4<<11) #define RX_RESET (u_short) (0x5<<11) #define RX_DISCARD_TOP_PACK (u_short) (0x8<<11) @@ -164,32 +260,32 @@ #define TX_DISABLE (u_short) (0xa<<11) #define TX_RESET (u_short) (0xb<<11) #define REQ_INTR (u_short) (0xc<<11) - /* - * The following C_* acknowledge the various interrupts. - * Some of them don't do anything. See the manual. - */ -#define ACK_INTR (u_short) (0x6800) -# define C_INTR_LATCH (u_short) (ACK_INTR|0x1) -# define C_CARD_FAILURE (u_short) (ACK_INTR|0x2) -# define C_TX_COMPLETE (u_short) (ACK_INTR|0x4) -# define C_TX_AVAIL (u_short) (ACK_INTR|0x8) -# define C_RX_COMPLETE (u_short) (ACK_INTR|0x10) -# define C_RX_EARLY (u_short) (ACK_INTR|0x20) -# define C_INT_RQD (u_short) (ACK_INTR|0x40) -# define C_UPD_STATS (u_short) (ACK_INTR|0x80) #define SET_INTR_MASK (u_short) (0xe<<11) #define SET_RD_0_MASK (u_short) (0xf<<11) #define SET_RX_FILTER (u_short) (0x10<<11) -# define FIL_INDIVIDUAL (u_short) (0x1) -# define FIL_MULTICAST (u_short) (0x2) -# define FIL_BRDCST (u_short) (0x4) -# define FIL_PROMISC (u_short) (0x8) +#define FIL_INDIVIDUAL (u_short) (0x1) +#define FIL_GROUP (u_short) (0x2) +#define FIL_BRDCST (u_short) (0x4) +#define FIL_ALL (u_short) (0x8) #define SET_RX_EARLY_THRESH (u_short) (0x11<<11) #define SET_TX_AVAIL_THRESH (u_short) (0x12<<11) #define SET_TX_START_THRESH (u_short) (0x13<<11) #define STATS_ENABLE (u_short) (0x15<<11) #define STATS_DISABLE (u_short) (0x16<<11) #define STOP_TRANSCEIVER (u_short) (0x17<<11) +/* + * The following C_* acknowledge the various interrupts. Some of them don't + * do anything. See the manual. + */ +#define ACK_INTR (u_short) (0x6800) +#define C_INTR_LATCH (u_short) (ACK_INTR|0x1) +#define C_CARD_FAILURE (u_short) (ACK_INTR|0x2) +#define C_TX_COMPLETE (u_short) (ACK_INTR|0x4) +#define C_TX_AVAIL (u_short) (ACK_INTR|0x8) +#define C_RX_COMPLETE (u_short) (ACK_INTR|0x10) +#define C_RX_EARLY (u_short) (ACK_INTR|0x20) +#define C_INT_RQD (u_short) (ACK_INTR|0x40) +#define C_UPD_STATS (u_short) (ACK_INTR|0x80) /* * Status register. All windows. @@ -217,10 +313,13 @@ #define S_RX_EARLY (u_short) (0x20) #define S_INT_RQD (u_short) (0x40) #define S_UPD_STATS (u_short) (0x80) +#define S_5_INTS (S_CARD_FAILURE|S_TX_COMPLETE|\ + S_TX_AVAIL|S_RX_COMPLETE|S_RX_EARLY) #define S_COMMAND_IN_PROGRESS (u_short) (0x1000) /* - * FIFO Registers. RX Status. + * FIFO Registers. + * RX Status. Window 1/Port 08 * * 15: Incomplete or FIFO empty. * 14: 1: Error in RX Packet 0: Incomplete or no error. @@ -235,18 +334,18 @@ * * 10-0: RX Bytes (0-1514) */ -#define ERR_INCOMPLETE (u_short) (0x8000) -#define ERR_RX (u_short) (0x4000) -#define ERR_RX_PACKET (u_short) (0x2000) -#define ERR_OVERRUN (u_short) (0x1000) -#define ERR_RUNT (u_short) (0x1300) -#define ERR_ALIGNMENT (u_short) (0x1400) -#define ERR_CRC (u_short) (0x1500) -#define ERR_OVERSIZE (u_short) (0x1100) -#define ERR_DRIBBLE (u_short) (0x200) +#define ERR_RX_INCOMPLETE (u_short) (0x1<<15) +#define ERR_RX (u_short) (0x1<<14) +#define ERR_RX_OVERRUN (u_short) (0x8<<11) +#define ERR_RX_RUN_PKT (u_short) (0xb<<11) +#define ERR_RX_ALIGN (u_short) (0xc<<11) +#define ERR_RX_CRC (u_short) (0xd<<11) +#define ERR_RX_OVERSIZE (u_short) (0x9<<11) +#define ERR_RX_DRIBBLE (u_short) (0x2<<11) /* - * TX Status + * FIFO Registers. + * TX Status. Window 1/Port 0B * * Reports the transmit status of a completed transmission. Writing this * register pops the transmit completion stack. @@ -263,44 +362,46 @@ * */ #define TXS_COMPLETE 0x80 -#define TXS_INTR_REQ 0x40 +#define TXS_SUCCES_INTR_REQ 0x40 #define TXS_JABBER 0x20 #define TXS_UNDERRUN 0x10 #define TXS_MAX_COLLISION 0x8 #define TXS_STATUS_OVERFLOW 0x4 /* - * Misc defines for various things. + * Configuration control register. + * Window 0/Port 04 */ -#define TAG_ADAPTER_0 0xd0 -#define ACTIVATE_ADAPTER_TO_CONFIG 0xff -#define ENABLE_DRQ_IRQ 0x0001 -#define MFG_ID 0x6d50 -#define PROD_ID 0x9050 -#define BASE sc->ep_iobase -#define GO_WINDOW(x) outw(BASE+EP_COMMAND, WINDOW_SELECT|x) -#define AUI 0x1 -#define BNC 0x2 -#define UTP 0x4 +/* Read */ #define IS_AUI (1<<13) #define IS_BNC (1<<12) #define IS_UTP (1<<9) -#define EEPROM_BUSY (1<<15) -#define EEPROM_TST_MODE (1<<14) -#define READ_EEPROM (1<<7) -#define ETHER_ADDR_LEN 6 -#define ETHER_MAX 1536 +/* Write */ +#define ENABLE_DRQ_IRQ 0x0001 +#define W0_P4_CMD_RESET_ADAPTER 0x4 +#define W0_P4_CMD_ENABLE_ADAPTER 0x1 +/* + * Media type and status. + * Window 4/Port 0A + */ #define ENABLE_UTP 0xc0 #define DISABLE_UTP 0x0 -#define RX_BYTES_MASK (u_short) (0x07ff) - /* - * EISA registers (offset from slot base) + * Misc defines for various things. */ -#define EISA_VENDOR 0x0c80 /* vendor ID (2 ports) */ -#define EISA_MODEL 0x0c82 /* model number (2 ports) */ -#define EISA_CONTROL 0x0c84 -#define EISA_RESET 0x04 -#define EISA_ERROR 0x02 -#define EISA_ENABLE 0x01 +#define ACTIVATE_ADAPTER_TO_CONFIG 0xff /* to the id_port */ +#define MFG_ID 0x6d50 /* in EEPROM and W0 ADDR_CONFIG */ +#define PROD_ID 0x9150 + +#define AUI 0x1 +#define BNC 0x2 +#define UTP 0x4 + +#define ETHER_ADDR_LEN 6 +#define ETHER_MAX 1536 +#define RX_BYTES_MASK (u_short) (0x07ff) + + /* EISA support */ +#define EP_EISA_START 0x1000 +#define EP_EISA_W0 0x0c80 |