Return to BSD News archive
Xref: sserve comp.os.386bsd.development:959 comp.os.386bsd.misc:617 Path: sserve!newshost.anu.edu.au!munnari.oz.au!news.Hawaii.Edu!ames!elroy.jpl.nasa.gov!swrinde!cs.utexas.edu!uwm.edu!ogicse!psgrain!agora!implode!davidg From: davidg@implode.rain.com (David Greenman) Newsgroups: comp.os.386bsd.development,comp.os.386bsd.misc Subject: New ethernet device driver for WD/SMC 80x3 and 3Com 3c503 Message-ID: <CAL2KI.26o@implode.rain.com> Date: 22 Jul 93 20:36:18 GMT Article-I.D.: implode.CAL2KI.26o Organization: Delta Systems, Portland, OR. Lines: 2878 What follows is the first 'production' release of my 'ed' device driver. If you have any problems, please try hard to solve them yourself before sending me email or posting to the net. This code has been quite thoroughly tested, so if you have problems it is more than likely a problem with your configuration than with the driver. Please read the release notes carefully, they should answer most of the common questions. Hopefully this will be turned into a manual page sometime in the near future. David Greenman davidg@implode.rain.com ---------------------------------------------------------------------------- # This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # ed.relnotes # if_ed.c # if_edreg.h # echo x - ed.relnotes sed 's/^X//' >ed.relnotes << 'END-of-ed.relnotes' X X Release Notes for 'ed' Device Driver X David Greenman, 24-May-1993 X ------------------------------------ X XLast updated: 20-July-1993 X XINTRODUCTION X------------ X The 'ed' device driver is a new, high performance device driver supporting XWestern Digital/SMC 80x3 series (including 'EtherCard PLUS' 'Elite16') and the X3Com 3c503. All of the ethernet controllers use the DS8390 or 83C690 Network XInterface Controller (NIC). The differences between the boards are in their Xmemory capacity, bus width (8/16 bits), and special logic (asic) used to Xconfigure the shared memory and other things. Every effort has been made to Xconform to the manufactures' specifications for the NIC and asic. This includes Xboth normal operation and error recovery. X XPERFORMANCE X----------- X Xtransmit X-------- X The 8390 doesn't provide a mechanism for chained write buffers, so it is Xvery important for maximum performance to queue the next packet for Xtransmission as soon as the current one has completed. On boards with 16k or Xmore of memory, the shared memory is divided in a way that allows enough space Xfor two full size packets to be buffered for transmission. When sufficient Xdata is available for transmission, a packet is copied into the shared memory, Xthe transmission is started, and then an additional packet is copied into the Xshared memory (to a different memory area). As soon as the first packet has Xcompleted, transmission of a second packet can then be started immediately - Xin less time than the 9.6us interframe gap. This results in the highest Xperformance possible from ethernet. X XPackets go out on the 'wire' with the following format: X Xpreamble dest-addr src-addr type data FCS intr-frame X64bits 48bits 48bits 16bits 1500bytes 32bits 96bits X X With 10Mbits/sec, each bit is 100ns in duration. All of the above fields, Xexcept for data are of fixed length. With full sized packets (1500 bytes), the Xmaximum unidirectional data rate can be calculated as: 6.4us + 4.8us + 4.8us + X1.6us + 1200us + 3.2us + 9.6us = 1230.4us/packet = 812.74382 packets/second = X1219115.7 (1190k) bytes/second. With TCP, there is a 40 byte overhead for the XIP and TCP headers, so there is only 1460 bytes of data per packet. This Xreduces the maximum data rate to 1186606 bytes/second. With TCP, there will Xalso be periodic acknowledgments which will reduce this figure somewhat both Xbecause of the additional traffic in the reverse direction and because of the Xoccasional collisions that this will cause. Despite this, the data rate has Xstill been consistantly measured at 1125000 (~1100k) bytes/second through a TCP Xsocket. In these tests, the TCP window was set to 16384 bytes. With UDP, there Xis less overhead for the headers, and with 1472 bytes of data per packet, a Xdata rate of 1196358.9 (1168k) bytes/sec is possible. UDP performance hasn't Xbeen precisely measured with this device driver, but less precise tests show Xthis to be true (measured at around 1135k/second). X Xreceive X------- X The 8390 implements a shared memory ring-buffer to store incoming packets. XThe 8bit boards (3c503, and 8003) usually have only 8k bytes of shared memory. XThis is only enough room for about 4 full size (1500 byte) packets. This can Xsometimes be a problem, especially on the original WD8003E and 3c503. This is Xbecause these boards' shared memory access speed is also quite slow compared Xto newer boards - typically only about 1MB/second. The additional overhead of Xthis slow memory access, and the fact that there is only room for 4 full-sized Xpackets means that the ring-buffer will occassionally overflow. When this Xhappens, the board must be reset to avoid a lockup problem in early revision X8390's. Resetting the board will cause all of the data in the ring-buffer to Xbe lost - requiring it to be re-transmitted/received...slowing things even Xfurther. Because of these problems, maximum throughput on boards of this type Xis only about 400-600k per second. The 16bit boards (8013 series), however, Xhave 16k of memory as well as much faster memory access speed. Typical memory Xaccess speed on these boards is about 4MB/second. These boards generally have Xno problems keeping up with full ethernet speed. The only problem I've seen Xwith these boards is related to the (slow) performance of 386BSD's malloc code Xwhen additional mbufs must be added to the pool. This can sometimes increase Xthe total time to remove a packet enough for a ring-buffer overflow to occur. XThis tends to be highly transient, and quite rare on fast machines. I've only Xseen this problem when doing tests with large amounts of UDP traffic without Xany acknowledgments (uni-directional). Again, this has been very rare. X X All of the above tests were done using a 486DX2/66, 486DX/33, 386DX/40, X8-9Mhz ISA bus, with Bruce Evans' high speed spl()/interrupt modifications, a Xhigh performance version of in_cksum.c from Bakul Shah, with tcp_sendspace/ Xtcp_recvspace set to 16k, and MCLBYTES set to 2048 (to allow full MTU sized Xpackets). TCP tests were done with the 'ttcp' performance test utility, and Xalso with FTP client/server. UDP tests were done with a modified version of Xttcp (to work around a bug in 386BSD's UDP code related to queue depth), and Xalso with NFS. X XKERNEL INSTALLATION X------------------- X To 'install' this driver, the files if_ed.c and if_edreg.h must be copied Xinto the i386/isa kernel source directory and the following line must be Xadded into the file i386/conf/files.i386: X Xi386/isa/if_ed.c optional ed device-driver X X To build a kernel that includes this driver, first comment out any 'we' Xor 'ec' devices in your kernel config file. Then, add a line similar to Xthe following (modify to match your cards configuration): X Xdevice ed0 at isa? port 0x300 net irq 10 iomem 0xcc000 vector edintr X X Note that the 'iosiz' option is not needed because the driver automatically Xfigures this out. However, if you have problems with this, it can be specified Xto force the use of the size you specify. X On 3Com boards, the tranceiver must be enabled in software (there is no Xhardware default). In this driver, this is controlled using the "LLC0" link- Xlevel control flag. The default for this flag can be set in your kernel config Xfile by specifying 'flags 0x01' in the 'ed' device specification line (this Xis necessary for diskless support). Otherwise, the tranceiver is easily enabled Xand disabled with a command like "ifconfig ed0 -LLC0" to enable the tranceiver Xor "ifconfig ed0 LLC0" to disable it; this assumes that you have the modified Xifconfig(8) that originally appeared in the 386BSD patchkit. To specify the X'flags' option, use a line similar to: X Xdevice ed0 at isa? port 0x300 net irq 10 flags 0x01 iomem 0xcc000 vector edintr X X Flags can be similarly specified to force 8 or 16bit mode, and disabling Xthe use of transmitter double buffering. The various supported flag values Xare: X X FORCE_8BIT_MODE 0x02 X FORCE_16BIT_MODE 0x04 X DISABLE_DOUBLE_BUFFERING 0x08 X X To use multiple flags, simply add the values together. Note that these Xnumbers are in hexadecimal. If the FORCE_8BIT and FORCE_16BIT flags are Xboth specified, the 8BIT flag has precedence. X The use of the above flags should only be necessary under exceptional Xconditions where the probe routine incorrectly determines the board type. Or Xwhere the high performance of the transmitter causes problems with other Xvendors hardware. X X XKNOWN PROBLEMS X-------------- X X1) Early revision DS8390B chips have problems. They lock-up whenever the X receive ring-buffer overflows. They occassionally switch the byte order X of the length field in the packet ring header (several different causes X of this related to an off-by-one byte alignment) - resulting in "shared X memory corrupt - invalid length NNNNN" messages. The board is reset X whenever these problems occur, but otherwise there is no problem with X recovering from these conditions. X2) 16bit boards can conflict with 8bit BIOSs, BIOS extensions (like the VGA), X and 8bit devices with shared memory (again like the VGA, or perhaps a X second ethernet board). There is a work-around for this in the driver, X however. The problem is that the ethernet board stays in 16bit mode, X asserting its '16bit' signal on the ISA bus. This signal is shared by X other devices/ROMs in the same 128K memory segment as the ethernet card X - causing the CPU to read the 8bit ROMs as if they were 16bit wide. X The work-around involves setting the host access to the shared memory X to 16bits only when the memory is actually accessed, and setting it back X to 8bit mode all other times. Without this work-around, the machine will X hang whenever a reboot is attempted. This work-around also allows the X board to co-exist with other 8bit devices that have shared memory (like X 8bit VGA boards or perhaps a second ethernet board). This has only been X implemented for SMC/WD boards, but I haven't seen this problem with X 3Com boards (i.e. if you have a 3Com board, you might experiance the X above problem - I haven't specifically tested for it). X3) 16bit 3c503 boards seem to have a memory contention problem between the NIC X and the on-board shared memory that causes periodic fifo-overruns. I'm X looking for a work-around, but haven't found one yet. When this problem X occurs, the 3c503 drops the packet. Other than re-tranmissions/reduced X performance, no other effects of this problem have been seen. X4) The shared memory on 3Com boards is much slower than it is on SMC boards; X it's less than 2MB/second on the 16bit boards, and this can lead to X ring-buffer overruns resulting in additional lost data in heavy network X traffic. I'm working with 3Com on this problem too, but it looks pretty X hopeless. X5) Because the 16bit 3Com boards bank switch their memory in 8k banks, the X double buffering has not been implemented in those boards. Doing so X would significantly complicate the code. Not really a bug, but rather X a limitation that might be removed in the future. END-of-ed.relnotes echo x - if_ed.c sed 's/^X//' >if_ed.c << 'END-of-if_ed.c' X/* X * Device driver for National Semiconductor DS8390 based ethernet X * adapters. By David Greenman, 29-April-1993 X * X * Copyright (C) 1993, David Greenman. This software may be used, modified, X * copied, distributed, and sold, in both source and binary form provided X * that the above copyright and these terms are retained. Under no X * circumstances is the author responsible for the proper functioning X * of this software, nor does the author assume any responsibility X * for damages incurred with its use. X * X * Currently supports the Western Digital/SMC 8003 and 8013 series X * and the 3Com 3c503 X */ X X/* X * Modification history X * X * $Log: if_ed.c,v $ X * Revision 1.14 93/07/20 15:24:25 davidg X * ommision for force 16bit case fixed from last patch X * X * Revision 1.13 93/07/20 15:13:55 davidg X * Added config file override for memsize by using 'iosiz'. Also added X * config flags overrides to force 8/16bit mode and disable the use of X * double xmit buffers. X * X * Revision 1.12 93/07/07 06:27:44 davidg X * moved call to bpfattach to after this drivers attach printf - X * improves readability of startup messages. X * X * Revision 1.11 93/06/27 03:07:01 davidg X * fixed bugs in the 3Com part of the probe routine that were uncovered by X * the previous fix. X * X * Revision 1.10 93/06/25 19:23:19 davidg X * fixed bug that caused erroneous 'Invalid irq configuration' message when X * no board is present (during autoconfiguration). X * X * Revision 1.9 93/06/23 03:48:14 davidg X * fixed minor typo introduced when cleaning up probe routine X * X * Revision 1.8 93/06/23 03:37:19 davidg X * cleaned up/added some comments. Also improved readability of a part of X * the probe routine. X * X * Revision 1.7 93/06/22 04:45:01 davidg X * (no additional changes) Second beta release X * X * Revision 1.6 93/06/22 04:40:35 davidg X * minor definition fix to ed_reset() X * X * Revision 1.5 93/06/22 04:37:39 davidg X * fixed some comments X * X * Revision 1.4 93/06/22 04:34:34 davidg X * added support to use the LLC0 'link-level control' flag X * to disable the tranceiver for AUI operation on 3Com boards. X * The default for this flag can be set in the kernel config X * file - 'flags 0x01' sets the flag (disables the tranceiver). X * X * Revision 1.3 93/06/17 03:57:28 davidg X * fixed some printf's X * X * Revision 1.2 93/06/17 03:26:49 davidg X * fixed 3c503 code to determine 8/16bit board X * changed attach printf to work with Interim-0.1.5 and NetBSD X * X * Revision 1.1 93/06/14 22:21:24 davidg X * Beta release of device driver for SMC/WD80x3 and 3C503 ethernet boards. X * X * X */ X X#include "ed.h" X#if NED > 0 X#include "bpfilter.h" X X#include "param.h" X#include "errno.h" X#include "ioctl.h" X#include "mbuf.h" X#include "socket.h" X#include "syslog.h" X X#include "net/if.h" X#include "net/if_dl.h" X#include "net/if_types.h" X#include "net/netisr.h" X X#ifdef INET X#include "netinet/in.h" X#include "netinet/in_systm.h" X#include "netinet/in_var.h" X#include "netinet/ip.h" X#include "netinet/if_ether.h" X#endif X X#ifdef NS X#include "netns/ns.h" X#include "netns/ns_if.h" X#endif X X#if NBPFILTER > 0 X#include "net/bpf.h" X#include "net/bpfdesc.h" X#endif X X#include "i386/isa/isa.h" X#include "i386/isa/isa_device.h" X#include "i386/isa/icu.h" X#include "i386/isa/if_edreg.h" X X#include "i386/include/pio.h" X X X/* X * ed_softc: per line info and status X */ Xstruct ed_softc { X struct arpcom arpcom; /* ethernet common */ X X char *type_str; /* pointer to type string */ X u_char vendor; /* interface vendor */ X u_char type; /* interface type code */ X X u_short vector; /* interrupt vector */ X u_short asic_addr; /* ASIC I/O bus address */ X u_short nic_addr; /* NIC (DS8390) I/O bus address */ X X caddr_t smem_start; /* shared memory start address */ X caddr_t smem_end; /* shared memory end address */ X u_long smem_size; /* total shared memory size */ X caddr_t smem_ring; /* start of RX ring-buffer (in smem) */ X X caddr_t bpf; /* BPF "magic cookie" */ X X u_char memwidth; /* width of access to card mem 8 or 16 */ X u_char xmit_busy; /* transmitter is busy */ X u_char txb_cnt; /* Number of transmit buffers */ X u_char txb_next; /* Pointer to next buffer ready to xmit */ X u_short txb_next_len; /* next xmit buffer length */ X u_char data_buffered; /* data has been buffered in interface memory */ X u_char tx_page_start; /* first page of TX buffer area */ X X u_char rec_page_start; /* first page of RX ring-buffer */ X u_char rec_page_stop; /* last page of RX ring-buffer */ X u_char next_packet; /* pointer to next unread RX packet */ X} ed_softc[NED]; X Xint ed_attach(), ed_init(), edintr(), ed_ioctl(), ed_probe(), X ed_start(), ed_reset(), ed_watchdog(); X Xstatic void ed_stop(); X Xstatic inline void ed_rint(); Xstatic inline void ed_xmit(); Xstatic inline char *ed_ring_copy(); X Xextern int ether_output(); X Xstruct isa_driver eddriver = { X ed_probe, X ed_attach, X "ed" X}; X/* X * Interrupt conversion table for WD/SMC ASIC X * (IRQ* are defined in icu.h) X */ Xstatic unsigned short ed_intr_mask[] = { X IRQ9, X IRQ3, X IRQ5, X IRQ7, X IRQ10, X IRQ11, X IRQ15, X IRQ4 X}; X X#define ETHER_MIN_LEN 64 X#define ETHER_MAX_LEN 1518 X#define ETHER_ADDR_LEN 6 X#define ETHER_HDR_SIZE 14 X X/* X * Determine if the device is present X * X * on entry: X * a pointer to an isa_device struct X * on exit: X * NULL if device not found X * or # of i/o addresses used (if found) X */ Xint Xed_probe(isa_dev) X struct isa_device *isa_dev; X{ X struct ed_softc *sc = &ed_softc[isa_dev->id_unit]; X int i, x; X u_int memsize; X u_char iptr, memwidth, sum, tmp; X X /* X * Setup initial i/o address for ASIC and NIC X */ X sc->asic_addr = isa_dev->id_iobase; X sc->vector = isa_dev->id_irq; X sc->smem_start = (caddr_t)isa_dev->id_maddr; X X /* X * Attempt to do a checksum over the station address PROM. X * This is mapped differently on the WD80x3 and 3C503, so if X * it fails, it might be a 3C503. There is a problem with X * this, though: some clone WD boards don't pass the X * checksum test. Danpex boards for one. We need to do X * additional checking for this case. X */ X for (sum = 0, i = 0; i < 8; ++i) { X sum += inb(sc->asic_addr + ED_WD_PROM + i); X } X X if (sum == ED_WD_ROM_CHECKSUM_TOTAL) { X goto type_WD80x3; X } else { X /* X * Do additional checking to make sure its a 3Com and X * not a broken WD clone X */ X goto type_3Com; X } X Xtype_WD80x3: X /* X * Looks like a WD/SMC board X */ X X sc->vendor = ED_VENDOR_WD_SMC; X sc->type = inb(sc->asic_addr + ED_WD_CARD_ID); X X sc->nic_addr = sc->asic_addr + ED_WD_NIC_OFFSET; X X /* reset card to force it into a known state. */ X outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_RST); X DELAY(100); X outb(sc->asic_addr + ED_WD_MSR, inb(sc->asic_addr + ED_WD_MSR) & ~ED_WD_MSR_RST); X /* wait in the case this card is reading it's EEROM */ X DELAY(5000); X X /* X * Set initial values for width/size. X */ X switch (sc->type) { X case ED_TYPE_WD8003S: X sc->type_str = "WD8003S"; X memsize = 8192; X memwidth = 8; X break; X case ED_TYPE_WD8003E: X sc->type_str = "WD8003E"; X memsize = 8192; X memwidth = 8; X break; X case ED_TYPE_WD8013EBT: X sc->type_str = "WD8013EBT"; X memsize = 16384; X memwidth = 16; X break; X case ED_TYPE_WD8013EB: /* also WD8003EP */ X if (inb(sc->asic_addr + ED_WD_ICR) X & ED_WD_ICR_16BIT) { X memwidth = 16; X memsize = 16384; X sc->type_str = "WD8013EB"; X } else { X sc->type_str = "WD8003EP"; X memsize = 8192; X memwidth = 8; X } X break; X case ED_TYPE_WD8013EBP: X sc->type_str = "WD8013EBP"; X memsize = 16384; X memwidth = 16; X break; X case ED_TYPE_WD8013EPC: X sc->type_str = "WD8013EPC"; X memsize = 16384; X memwidth = 16; X break; X default: X sc->type_str = "unknown"; X memsize = 8192; X memwidth = 8; X break; X } X /* X * Make some adjustments to initial values depending on what is X * found in the ICR. X */ X if ((memwidth==16) X && ((inb(sc->asic_addr + ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) { X memwidth = 8; X memsize = 8192; X } X if (inb(sc->asic_addr + ED_WD_ICR) & ED_WD_ICR_MSZ) { X memsize = 32768; X } X X#if ED_DEBUG X printf("type=%s memwidth=%d memsize=%d id_msize=%d\n", X sc->type_str,memwidth,memsize,isa_dev->id_msize); X for (i=0; i<8; i++) X printf("%x -> %x\n", i, inb(sc->asic_addr + i)); X#endif X /* X * Allow the user to override the autoconfiguration X */ X if (isa_dev->id_msize) X memsize = isa_dev->id_msize; X /* X * (note that if the user specifies both of the following flags X * that '8bit' mode intentionally has precedence) X */ X if (isa_dev->id_flags & ED_FLAGS_FORCE_16BIT_MODE) X memwidth = 16; X if (isa_dev->id_flags & ED_FLAGS_FORCE_8BIT_MODE) X memwidth = 8; X X /* X * Check 83C584 interrupt configuration register if this board has one X * XXX - we could also check the IO address register. But why X * bother...if we get past this, it *has* to be correct. X */ X if (sc->type & ED_WD_SOFTCONFIG) { X /* X * Assemble together the encoded interrupt number. X */ X iptr = (inb(isa_dev->id_iobase + ED_WD_ICR) & ED_WD_ICR_IR2) | X ((inb(isa_dev->id_iobase + ED_WD_IRR) & X (ED_WD_IRR_IR0 | ED_WD_IRR_IR1)) >> 5); X /* X * Translate it using translation table, and check for correctness. X */ X if (ed_intr_mask[iptr] != isa_dev->id_irq) { X printf("ed%d: kernel configured irq doesn't match board configured irq\n", X isa_dev->id_unit); X return(0); X } X /* X * Enable the interrupt. X */ X outb(isa_dev->id_iobase + ED_WD_IRR, X inb(isa_dev->id_iobase + ED_WD_IRR) | ED_WD_IRR_IEN); X } X X sc->memwidth = memwidth; X /* X * allocate one xmit buffer if < 16k, two buffers otherwise X */ X if ((memsize < 16384) || (isa_dev->id_msize & ED_FLAGS_NO_DOUBLE_BUFFERING)) { X sc->smem_ring = sc->smem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE); X sc->txb_cnt = 1; X sc->rec_page_start = ED_TXBUF_SIZE; X } else { X sc->smem_ring = sc->smem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE * 2); X sc->txb_cnt = 2; X sc->rec_page_start = ED_TXBUF_SIZE * 2; X } X sc->smem_size = memsize; X sc->smem_end = sc->smem_start + memsize; X sc->rec_page_stop = memsize / ED_PAGE_SIZE; X sc->tx_page_start = ED_WD_PAGE_OFFSET; X X /* X * Get station address from on-board ROM X */ X for (i = 0; i < ETHER_ADDR_LEN; ++i) X sc->arpcom.ac_enaddr[i] = inb(sc->asic_addr + ED_WD_PROM + i); X X /* X * Set address and enable interface shared memory. X */ X outb(sc->asic_addr + ED_WD_MSR, ((kvtop(sc->smem_start) >> 13) & X ED_WD_MSR_ADDR) | ED_WD_MSR_MENB); X X /* X * Set upper address bits and 8/16 bit access to shared memory X */ X if (sc->type & ED_WD_SOFTCONFIG) { X if (memwidth == 8) { X outb(sc->asic_addr + ED_WD_LAAR, X ((kvtop(sc->smem_start) >> 19) & ED_WD_LAAR_ADDRHI)); X } else { X outb(sc->asic_addr + ED_WD_LAAR, X ED_WD_LAAR_L16EN | ED_WD_LAAR_M16EN | X ((kvtop(sc->smem_start) >> 19) & ED_WD_LAAR_ADDRHI)); X } X } X X /* X * Now zero memory and verify that it is clear X */ X bzero(sc->smem_start, memsize); X X for (i = 0; i < memsize; ++i) X if (sc->smem_start[i]) { X printf("ed%d: failed to clear shared memory at %x - check configuration\n", X isa_dev->id_unit, sc->smem_start + i); X X /* X * Disable 16 bit access to shared memory X */ X if (memwidth == 16) X outb(sc->asic_addr + ED_WD_LAAR, X inb(sc->asic_addr + ED_WD_LAAR) X & ~ED_WD_LAAR_M16EN); X X return(0); X } X X /* X * Disable 16bit access to shared memory - we leave it disabled so X * that 1) machines reboot properly when the board is set X * 16 bit mode and there are conflicting 8bit devices/ROMS X * in the same 128k address space as this boards shared X * memory. and 2) so that other 8 bit devices with shared X * memory can be used in this 128k region, too. X */ X if (memwidth == 16) X outb(sc->asic_addr + ED_WD_LAAR, inb(sc->asic_addr + ED_WD_LAAR) X & ~ED_WD_LAAR_M16EN); X X isa_dev->id_msize = memsize; X return (ED_WD_IO_PORTS); X Xtype_3Com: X /* X * Looks like a 3Com board X */ X X sc->vendor = ED_VENDOR_3COM; X sc->asic_addr = isa_dev->id_iobase + ED_3COM_ASIC_OFFSET; X sc->nic_addr = isa_dev->id_iobase + ED_3COM_NIC_OFFSET; X X sc->type_str = "3c503"; X X memsize = 8192; X X /* X * Verify that the kernel configured I/O address matches the board X * configured address X */ X switch (inb(sc->asic_addr + ED_3COM_BCFR)) { X case ED_3COM_BCFR_300: X if (isa_dev->id_iobase != 0x300) X return(0); X break; X case ED_3COM_BCFR_310: X if (isa_dev->id_iobase != 0x310) X return(0); X break; X case ED_3COM_BCFR_330: X if (isa_dev->id_iobase != 0x330) X return(0); X break; X case ED_3COM_BCFR_350: X if (isa_dev->id_iobase != 0x350) X return(0); X break; X case ED_3COM_BCFR_250: X if (isa_dev->id_iobase != 0x250) X return(0); X break; X case ED_3COM_BCFR_280: X if (isa_dev->id_iobase != 0x280) X return(0); X break; X case ED_3COM_BCFR_2A0: X if (isa_dev->id_iobase != 0x2a0) X return(0); X break; X case ED_3COM_BCFR_2E0: X if (isa_dev->id_iobase != 0x2e0) X return(0); X break; X default: X return(0); X } X X /* X * Verify that the kernel shared memory address matches the X * board configured address. X */ X switch (inb(sc->asic_addr + ED_3COM_PCFR)) { X case ED_3COM_PCFR_DC000: X if (kvtop(isa_dev->id_maddr) != 0xdc000) X return(0); X break; X case ED_3COM_PCFR_D8000: X if (kvtop(isa_dev->id_maddr) != 0xd8000) X return(0); X break; X case ED_3COM_PCFR_CC000: X if (kvtop(isa_dev->id_maddr) != 0xcc000) X return(0); X break; X case ED_3COM_PCFR_C8000: X if (kvtop(isa_dev->id_maddr) != 0xc8000) X return(0); X break; X default: X return(0); X } X X /* X * Reset NIC and ASIC X */ X outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_RST); X /* X * Wait for a while, then un-reset it X */ X DELAY(5000); X outb(sc->asic_addr + ED_3COM_CR, 0); X X /* X * Wait a bit for the NIC to recover from the reset X */ X DELAY(5000); X X /* X * The 3Com ASIC defaults to rather strange settings for the CR after X * a reset - it's important to set it so that the NIC I/O X * registers are mapped. The above setting of it to '0' only X * resets the reset condition - the CR is *not* set to zeros. X */ X outb(sc->asic_addr + ED_3COM_CR, 0); X X /* X * Determine if this is an 8bit or 16bit board X */ X X /* X * select page 0 registers X */ X outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP); X X /* X * Attempt to clear WTS bit. If it doesn't clear, then this is a X * 16bit board. X */ X outb(sc->nic_addr + ED_P0_DCR, 0); X X /* X * select page 2 registers X */ X outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_2|ED_CR_RD2|ED_CR_STP); X X /* X * The 3c503 forces the WTS bit to a one if this is a 16bit board X */ X if (inb(sc->nic_addr + ED_P2_DCR) & ED_DCR_WTS) X memwidth = 16; X else X memwidth = 8; X X /* X * select page 0 registers X */ X outb(sc->nic_addr + ED_P2_CR, ED_CR_RD2|ED_CR_STP); X X sc->txb_cnt = 1; X X sc->tx_page_start = ED_3COM_PAGE_OFFSET; X sc->rec_page_start = ED_TXBUF_SIZE + ED_3COM_PAGE_OFFSET; X sc->rec_page_stop = memsize / ED_PAGE_SIZE + ED_3COM_PAGE_OFFSET; X X sc->smem_size = memsize; X sc->smem_end = sc->smem_start + memsize; X sc->smem_ring = sc->smem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE); X X sc->memwidth = memwidth; X X /* X * Initialize GA page start/stop registers. Probably only needed X * if doing DMA, but what the hell. X */ X outb(sc->asic_addr + ED_3COM_PSTR, sc->rec_page_start); X outb(sc->asic_addr + ED_3COM_PSPR, sc->rec_page_stop); X X /* X * Set IRQ. 3c503 only allows a choice of irq 2-5. X */ X switch (isa_dev->id_irq) { X case IRQ2: X outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ2); X break; X case IRQ3: X outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ3); X break; X case IRQ4: X outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ4); X break; X case IRQ5: X outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ5); X break; X default: X printf("ed%d: Invalid irq configuration\n", isa_dev->id_unit); X return(0); X } X X /* X * Initialize GA configuration register. Set bank and enable smem. X */ X outb(sc->asic_addr + ED_3COM_GACFR, ED_3COM_GACFR_RSEL | X ED_3COM_GACFR_MBS0); X X /* X * Initialize "Vector Pointer" registers. These gawd-awful things X * are compared to 20 bits of the address on ISA, and if they X * match, the shared memory is disabled. We set them to X * 0xffff0...allegedly the reset vector. X */ X outb(sc->asic_addr + ED_3COM_VPTR2, 0xff); X outb(sc->asic_addr + ED_3COM_VPTR1, 0xff); X outb(sc->asic_addr + ED_3COM_VPTR0, 0x00); X X /* X * Get station address from on-board ROM X */ X /* X * First, map ethernet address PROM over the top of where the NIC X * registers normally appear. X */ X outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_EALO); X X for (i = 0; i < ETHER_ADDR_LEN; ++i) X sc->arpcom.ac_enaddr[i] = inb(sc->nic_addr + i); X X /* X * Unmap PROM - select NIC registers. Tranceiver remains disabled at X * this point. It's enabled in ed_init so that the attach code X * is given a chance to set the default based on a compile-time X * config option X */ X outb(sc->asic_addr + ED_3COM_CR, 0); X X#if 0 Xprintf("Starting write\n"); Xfor (i = 0; i < 8192; ++i) X bzero(sc->smem_start, 8192); Xprintf("Done.\n"); X#endif X#if 0 X{ char test_buf[1024]; Xprintf("starting write\n"); X for (i = 0; i < 8*8192; ++i) X bcopy(test_buf, sc->smem_start, 1024); Xprintf("starting read\n"); X for (i = 0; i < 8*8192; ++i) X bcopy(sc->smem_start, test_buf, 1024); Xprintf("done.\n"); X} X#endif X X /* X * Zero memory and verify that it is clear X */ X bzero(sc->smem_start, memsize); X X for (i = 0; i < memsize; ++i) X if (sc->smem_start[i]) { X printf("ed%d: failed to clear shared memory at %x - check configuration\n", X isa_dev->id_unit, sc->smem_start + i); X return(0); X } X X isa_dev->id_msize = memsize; X return(ED_3COM_IO_PORTS); X} X X/* X * Install interface into kernel networking data structures X */ Xint Xed_attach(isa_dev) X struct isa_device *isa_dev; X{ X struct ed_softc *sc = &ed_softc[isa_dev->id_unit]; X struct ifnet *ifp = &sc->arpcom.ac_if; X struct ifaddr *ifa; X struct sockaddr_dl *sdl; X X /* X * Set interface to stopped condition (reset) X */ X ed_stop(isa_dev->id_unit); X X /* X * Initialize ifnet structure X */ X ifp->if_unit = isa_dev->id_unit; X ifp->if_name = "ed" ; X ifp->if_mtu = ETHERMTU; X ifp->if_init = ed_init; X ifp->if_output = ether_output; X ifp->if_start = ed_start; X ifp->if_ioctl = ed_ioctl; X ifp->if_reset = ed_reset; X ifp->if_watchdog = ed_watchdog; X X /* X * Set default state for LLC0 flag (used to disable the tranceiver X * for AUI operation), based on compile-time config option. X */ X if (isa_dev->id_flags & ED_FLAGS_DISABLE_TRANCEIVER) X ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS X | IFF_LLC0); X else X ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS); X X /* X * Attach the interface X */ X if_attach(ifp); X X /* X * Search down the ifa address list looking for the AF_LINK type entry X */ X ifa = ifp->if_addrlist; X while ((ifa != 0) && (ifa->ifa_addr != 0) && X (ifa->ifa_addr->sa_family != AF_LINK)) X ifa = ifa->ifa_next; X /* X * If we find an AF_LINK type entry we fill in the hardware address. X * This is useful for netstat(1) to keep track of which interface X * is which. X */ X if ((ifa != 0) && (ifa->ifa_addr != 0)) { X /* X * Fill in the link-level address for this interface X */ X sdl = (struct sockaddr_dl *)ifa->ifa_addr; X sdl->sdl_type = IFT_ETHER; X sdl->sdl_alen = ETHER_ADDR_LEN; X sdl->sdl_slen = 0; X bcopy(sc->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN); X } X X /* X * Print additional info when attached X */ X printf("ed%d: address %s, type %s (%dbit) %s\n", isa_dev->id_unit, X ether_sprintf(sc->arpcom.ac_enaddr), sc->type_str, X sc->memwidth, ((sc->vendor == ED_VENDOR_3COM) && X (ifp->if_flags & IFF_LLC0)) ? "tranceiver disabled" : ""); X X /* X * If BPF is in the kernel, call the attach for it X */ X#if NBPFILTER > 0 X bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); X#endif X X} X X/* X * Reset interface. X */ Xint Xed_reset(unit) X int unit; X{ X int s; X X s = splnet(); X X /* X * Stop interface and re-initialize. X */ X ed_stop(unit); X ed_init(unit); X X s = splx(s); X} X X/* X * Take interface offline. X */ Xvoid Xed_stop(unit) X int unit; X{ X struct ed_softc *sc = &ed_softc[unit]; X int n = 5000; X X /* X * Stop everything on the interface, and select page 0 registers. X */ X outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP); X X /* X * Wait for interface to enter stopped state, but limit # of checks X * to 'n' (about 5ms). It shouldn't even take 5us on modern X * DS8390's, but just in case it's an old one. X */ X while ((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RST) == 0) { X if (--n == 0) X break; X } X} X X/* X * Device timeout/watchdog routine. Entered if the device neglects to X * generate an interrupt after a transmit has been started on it. X */ Xint Xed_watchdog(unit) X int unit; X{ X log(LOG_ERR, "ed%d: device timeout\n", unit); X X ed_reset(unit); X} X X/* X * Initialize device. X */ Xed_init(unit) X int unit; X{ X struct ed_softc *sc = &ed_softc[unit]; X struct ifnet *ifp = &sc->arpcom.ac_if; X int i, s; X u_char command; X X X /* address not known */ X if (ifp->if_addrlist == (struct ifaddr *)0) return; X X /* X * Initialize the NIC in the exact order outlined in the NS manual. X * This init procedure is "mandatory"...don't change what or when X * things happen. X */ X s = splnet(); X X /* reset transmitter flags */ X sc->data_buffered = 0; X sc->xmit_busy = 0; X sc->arpcom.ac_if.if_timer = 0; X X sc->txb_next = 0; X X /* This variable is used below - don't move this assignment */ X sc->next_packet = sc->rec_page_start + 1; X X /* X * Set interface for page 0, Remote DMA complete, Stopped X */ X outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP); X X if (sc->memwidth == 16) { X /* X * Set FIFO threshold to 8, No auto-init Remote DMA, X * byte order=80x86, word-wide DMA xfers X */ X outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1|ED_DCR_WTS); X } else { X /* X * Same as above, but byte-wide DMA xfers X */ X outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1); X } X X /* X * Clear Remote Byte Count Registers X */ X outb(sc->nic_addr + ED_P0_RBCR0, 0); X outb(sc->nic_addr + ED_P0_RBCR1, 0); X X /* X * Enable reception of broadcast packets X */ X outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB); X X /* X * Place NIC in internal loopback mode X */ X outb(sc->nic_addr + ED_P0_TCR, ED_TCR_LB0); X X /* X * Initialize transmit/receive (ring-buffer) Page Start X */ X outb(sc->nic_addr + ED_P0_TPSR, sc->tx_page_start); X outb(sc->nic_addr + ED_P0_PSTART, sc->rec_page_start); X X /* X * Initialize Receiver (ring-buffer) Page Stop and Boundry X */ X outb(sc->nic_addr + ED_P0_PSTOP, sc->rec_page_stop); X outb(sc->nic_addr + ED_P0_BNRY, sc->rec_page_start); X X /* X * Clear all interrupts. A '1' in each bit position clears the X * corresponding flag. X */ X outb(sc->nic_addr + ED_P0_ISR, 0xff); X X /* X * Enable the following interrupts: receive/transmit complete, X * receive/transmit error, and Receiver OverWrite. X * X * Counter overflow and Remote DMA complete are *not* enabled. X */ X outb(sc->nic_addr + ED_P0_IMR, X ED_IMR_PRXE|ED_IMR_PTXE|ED_IMR_RXEE|ED_IMR_TXEE|ED_IMR_OVWE); X X /* X * Program Command Register for page 1 X */ X outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STP); X X /* X * Copy out our station address X */ X for (i = 0; i < ETHER_ADDR_LEN; ++i) X outb(sc->nic_addr + ED_P1_PAR0 + i, sc->arpcom.ac_enaddr[i]); X X#if NBPFILTER > 0 X /* X * Initialize multicast address hashing registers to accept X * all multicasts (only used when in promiscuous mode) X */ X for (i = 0; i < 8; ++i) X outb(sc->nic_addr + ED_P1_MAR0 + i, 0xff); X#endif X X /* X * Set Current Page pointer to next_packet (initialized above) X */ X outb(sc->nic_addr + ED_P1_CURR, sc->next_packet); X X /* X * Set Command Register for page 0, Remote DMA complete, X * and interface Start. X */ X outb(sc->nic_addr + ED_P1_CR, ED_CR_RD2|ED_CR_STA); X X /* X * Take interface out of loopback X */ X outb(sc->nic_addr + ED_P0_TCR, 0); X X /* X * If this is a 3Com board, the tranceiver must be software enabled X * (there is no settable hardware default). X */ X if ((sc->vendor == ED_VENDOR_3COM) && (ifp->if_flags & IFF_LLC0)) { X outb(sc->asic_addr + ED_3COM_CR, 0); X } else { X outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL); X } X X /* X * Set 'running' flag, and clear output active flag. X */ X ifp->if_flags |= IFF_RUNNING; X ifp->if_flags &= ~IFF_OACTIVE; X X /* X * ...and attempt to start output X */ X ed_start(ifp); X X (void) splx(s); X} X X/* X * This routine actually starts the transmission on the interface X */ Xstatic inline void ed_xmit(ifp) X struct ifnet *ifp; X{ X struct ed_softc *sc = &ed_softc[ifp->if_unit]; X u_short len = sc->txb_next_len; X X /* X * Set NIC for page 0 register access X */ X outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA); X X /* X * Set TX buffer start page X */ X outb(sc->nic_addr + ED_P0_TPSR, sc->tx_page_start + X sc->txb_next * ED_TXBUF_SIZE); X X /* X * Set TX length X */ X outb(sc->nic_addr + ED_P0_TBCR0, len & 0xff); X outb(sc->nic_addr + ED_P0_TBCR1, len >> 8); X X /* X * Set page 0, Remote DMA complete, Transmit Packet, and *Start* X */ X outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_TXP|ED_CR_STA); X X sc->xmit_busy = 1; X sc->data_buffered = 0; X X /* X * Switch buffers if we are doing double-buffered transmits X */ X if ((sc->txb_next == 0) && (sc->txb_cnt > 1)) X sc->txb_next = 1; X else X sc->txb_next = 0; X X /* X * Set a timer just in case we never hear from the board again X */ X ifp->if_timer = 2; X} X X/* X * Start output on interface. X * We make two assumptions here: X * 1) that the current priority is set to splnet _before_ this code X * is called *and* is returned to the appropriate priority after X * return X * 2) that the IFF_OACTIVE flag is checked before this code is called X * (i.e. that the output part of the interface is idle) X */ Xint Xed_start(ifp) X struct ifnet *ifp; X{ X struct ed_softc *sc = &ed_softc[ifp->if_unit]; X struct mbuf *m0, *m; X caddr_t buffer; X int len; X u_char laar_tmp; X Xoutloop: X /* X * See if there is room to send more data (i.e. one or both of the X * buffers is empty). X */ X if (sc->data_buffered) X if (sc->xmit_busy) { X /* X * No room. Indicate this to the outside world X * and exit. X */ X ifp->if_flags |= IFF_OACTIVE; X return; X } else { X /* X * Data is buffered, but we're not transmitting, so X * start the xmit on the buffered data. X * Note that ed_xmit() resets the data_buffered flag X * before returning. X */ X ed_xmit(ifp); X } X X IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m); X if (m == 0) { X /* X * The following isn't pretty; we are using the !OACTIVE flag to X * indicate to the outside world that we can accept an additional X * packet rather than that the transmitter is _actually_ X * active. Indeed, the transmitter may be active, but if we haven't X * filled the secondary buffer with data then we still want to X * accept more. X * Note that it isn't necessary to test the data_buffered flag - X * we wouldn't have tried to de-queue the packet in the first place X * if it was set. X */ X ifp->if_flags &= ~IFF_OACTIVE; X return; X } X X /* X * Copy the mbuf chain into the transmit buffer X */ X /* X * Enable 16bit access to shared memory on WD/SMC boards X */ X if (sc->memwidth == 16) X if (sc->vendor == ED_VENDOR_WD_SMC) { X laar_tmp = inb(sc->asic_addr + ED_WD_LAAR); X outb(sc->asic_addr + ED_WD_LAAR, laar_tmp | ED_WD_LAAR_M16EN); X } X X buffer = sc->smem_start + (sc->txb_next * ED_TXBUF_SIZE * ED_PAGE_SIZE); X len = 0; X for (m0 = m; m != 0; m = m->m_next) { X bcopy(mtod(m, caddr_t), buffer, m->m_len); X buffer += m->m_len; X len += m->m_len; X } X X /* X * Restore previous shared mem access type X */ X if (sc->memwidth == 16) X if (sc->vendor == ED_VENDOR_WD_SMC) { X outb(sc->asic_addr + ED_WD_LAAR, laar_tmp); X } X X sc->txb_next_len = MAX(len, ETHER_MIN_LEN); X X if (sc->txb_cnt > 1) X /* X * only set 'buffered' flag if doing multiple buffers X */ X sc->data_buffered = 1; X X if (sc->xmit_busy == 0) X ed_xmit(ifp); X /* X * If there is BPF support in the configuration, tap off here. X * The following has support for converting trailer packets X * back to normal. X */ X#if NBPFILTER > 0 X if (sc->bpf) { X u_short etype; X int off, datasize, resid; X struct ether_header *eh; X struct trailer_header { X u_short ether_type; X u_short ether_residual; X } trailer_header; X char ether_packet[ETHER_MAX_LEN]; X char *ep; X X ep = ether_packet; X X /* X * We handle trailers below: X * Copy ether header first, then residual data, X * then data. Put all this in a temporary buffer X * 'ether_packet' and send off to bpf. Since the X * system has generated this packet, we assume X * that all of the offsets in the packet are X * correct; if they're not, the system will almost X * certainly crash in m_copydata. X * We make no assumptions about how the data is X * arranged in the mbuf chain (i.e. how much X * data is in each mbuf, if mbuf clusters are X * used, etc.), which is why we use m_copydata X * to get the ether header rather than assume X * that this is located in the first mbuf. X */ X /* copy ether header */ X m_copydata(m0, 0, sizeof(struct ether_header), ep); X eh = (struct ether_header *) ep; X ep += sizeof(struct ether_header); X etype = ntohs(eh->ether_type); X if (etype >= ETHERTYPE_TRAIL && X etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { X datasize = ((etype - ETHERTYPE_TRAIL) << 9); X off = datasize + sizeof(struct ether_header); X X /* copy trailer_header into a data structure */ X m_copydata(m0, off, sizeof(struct trailer_header), X &trailer_header.ether_type); X X /* copy residual data */ X m_copydata(m0, off+sizeof(struct trailer_header), X resid = ntohs(trailer_header.ether_residual) - X sizeof(struct trailer_header), ep); X ep += resid; X X /* copy data */ X m_copydata(m0, sizeof(struct ether_header), X datasize, ep); X ep += datasize; X X /* restore original ether packet type */ X eh->ether_type = trailer_header.ether_type; X X bpf_tap(sc->bpf, ether_packet, ep - ether_packet); X } else X bpf_mtap(sc->bpf, m0); X } X#endif X X m_freem(m0); X X /* X * If we are doing double-buffering, a buffer might be free to X * fill with another packet, so loop back to the top. X */ X if (sc->txb_cnt > 1) X goto outloop; X else { X ifp->if_flags |= IFF_OACTIVE; X return; X } X} X X/* X * Ethernet interface receiver interrupt. X */ Xstatic inline void /* only called from one place, so may as well integrate */ Xed_rint(unit) X int unit; X{ X register struct ed_softc *sc = &ed_softc[unit]; X u_char boundry, current; X u_short len; X struct ed_ring *packet_ptr; X X /* X * Set NIC to page 1 registers to get 'current' pointer X */ X outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STA); X X /* X * 'sc->next_packet' is the logical beginning of the ring-buffer - i.e. X * it points to where new data has been buffered. The 'CURR' X * (current) register points to the logical end of the ring-buffer X * - i.e. it points to where additional new data will be added. X * We loop here until the logical beginning equals the logical X * end (or in other words, until the ring-buffer is empty). X */ X while (sc->next_packet != inb(sc->nic_addr + ED_P1_CURR)) { X X /* get pointer to this buffer header structure */ X packet_ptr = (struct ed_ring *)(sc->smem_ring + X (sc->next_packet - sc->rec_page_start) * ED_PAGE_SIZE); X X /* X * The byte count includes the FCS - Frame Check Sequence (a X * 32 bit CRC). X */ X len = packet_ptr->count; X if ((len >= ETHER_MIN_LEN) && (len <= ETHER_MAX_LEN)) { X /* X * Go get packet. len - 4 removes CRC from length. X * (packet_ptr + 1) points to data just after the packet ring X * header (+4 bytes) X */ X ed_get_packet(sc, (caddr_t)(packet_ptr + 1), len - 4); X ++sc->arpcom.ac_if.if_ipackets; X } else { X /* X * Really BAD...probably indicates that the ring pointers X * are corrupted. Also seen on early rev chips under X * high load - the byte order of the length gets switched. X */ X log(LOG_ERR, X "ed%d: shared memory corrupt - invalid packet length %d\n", X unit, len); X ed_reset(unit); X return; X } X X /* X * Update next packet pointer X */ X sc->next_packet = packet_ptr->next_packet; X X /* X * Update NIC boundry pointer - being careful to keep it X * one buffer behind. (as recommended by NS databook) X */ X boundry = sc->next_packet - 1; X if (boundry < sc->rec_page_start) X boundry = sc->rec_page_stop - 1; X X /* X * Set NIC to page 0 registers to update boundry register X */ X outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA); X X outb(sc->nic_addr + ED_P0_BNRY, boundry); X X /* X * Set NIC to page 1 registers before looping to top (prepare to X * get 'CURR' current pointer) X */ X outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STA); X } X} X X/* X * Ethernet interface interrupt processor X */ Xint Xedintr(unit) X int unit; X{ X struct ed_softc *sc = &ed_softc[unit]; X u_char isr; X X /* X * Set NIC to page 0 registers X */ X outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA); X X /* X * loop until there are no more new interrupts X */ X while (isr = inb(sc->nic_addr + ED_P0_ISR)) { X X /* X * reset all the bits that we are 'acknowleging' X * by writing a '1' to each bit position that was set X * (writing a '1' *clears* the bit) X */ X outb(sc->nic_addr + ED_P0_ISR, isr); X X /* X * Transmit error. If a TX completed with an error, we end up X * throwing the packet away. Really the only error that is X * possible is excessive collisions, and in this case it is X * best to allow the automatic mechanisms of TCP to backoff X * the flow. Of course, with UDP we're screwed, but this is X * expected when a network is heavily loaded. X */ X if (isr & ED_ISR_TXE) { X u_char tsr = inb(sc->nic_addr + ED_P0_TSR); X u_char ncr = inb(sc->nic_addr + ED_P0_NCR); X X /* X * Excessive collisions (16) X */ X if ((tsr & ED_TSR_ABT) && (ncr == 0)) { X /* X * When collisions total 16, the P0_NCR will X * indicate 0, and the TSR_ABT is set. X */ X sc->arpcom.ac_if.if_collisions += 16; X } else X sc->arpcom.ac_if.if_collisions += ncr; X X /* X * update output errors counter X */ X ++sc->arpcom.ac_if.if_oerrors; X X /* X * reset tx busy and output active flags X */ X sc->xmit_busy = 0; X sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; X X /* X * clear watchdog timer X */ X sc->arpcom.ac_if.if_timer = 0; X } X X X /* X * Receiver Error. One or more of: CRC error, frame alignment error X * FIFO overrun, or missed packet. X */ X if (isr & ED_ISR_RXE) { X ++sc->arpcom.ac_if.if_ierrors; X#ifdef ED_DEBUG X printf("ed%d: receive error %x\n", unit, X inb(sc->nic_addr + ED_P0_RSR)); X#endif X } X X /* X * Overwrite warning. In order to make sure that a lockup X * of the local DMA hasn't occurred, we reset and X * re-init the NIC. The NSC manual suggests only a X * partial reset/re-init is necessary - but some X * chips seem to want more. The DMA lockup has been X * seen only with early rev chips - Methinks this X * bug was fixed in later revs. -DG X */ X if (isr & ED_ISR_OVW) { X ++sc->arpcom.ac_if.if_ierrors; X log(LOG_WARNING, X "ed%d: warning - receiver ring buffer overrun\n", X unit); X /* X * Stop/reset/re-init NIC X */ X ed_reset(unit); X } X X /* X * Transmission completed normally. X */ X if (isr & ED_ISR_PTX) { X X /* X * reset tx busy and output active flags X */ X sc->xmit_busy = 0; X sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; X X /* X * clear watchdog timer X */ X sc->arpcom.ac_if.if_timer = 0; X X /* X * Update total number of successfully transmitted X * packets. X */ X ++sc->arpcom.ac_if.if_opackets; X X /* X * Add in total number of collisions on last X * transmission. X */ X sc->arpcom.ac_if.if_collisions += inb(sc->nic_addr + X ED_P0_TBCR0); X } X X /* X * Receive Completion. Go and get the packet. X * XXX - Doing this on an error is dubious because there X * shouldn't be any data to get (we've configured the X * interface to not accept packets with errors). X */ X if (isr & (ED_ISR_PRX|ED_ISR_RXE)) { X /* X * Enable access to shared memory on WD/SMC boards X */ X if (sc->memwidth == 16) X if (sc->vendor == ED_VENDOR_WD_SMC) { X outb(sc->asic_addr + ED_WD_LAAR, X inb(sc->asic_addr + ED_WD_LAAR) X | ED_WD_LAAR_M16EN); X } X X ed_rint (unit); X X /* X * Disable access to shared memory X */ X if (sc->memwidth == 16) X if (sc->vendor == ED_VENDOR_WD_SMC) { X outb(sc->asic_addr + ED_WD_LAAR, X inb(sc->asic_addr + ED_WD_LAAR) X & ~ED_WD_LAAR_M16EN); X } X } X X /* X * If it looks like the transmitter can take more data, X * attempt to start output on the interface. If data is X * already buffered and ready to go, send it first. X */ X if ((sc->arpcom.ac_if.if_flags & IFF_OACTIVE) == 0) { X if (sc->data_buffered) X ed_xmit(&sc->arpcom.ac_if); X ed_start(&sc->arpcom.ac_if); X } X X /* X * return NIC CR to standard state before looping back X * to top: page 0, remote DMA complete, start X * (toggling the TXP bit off, even if was just set in the X * transmit routine, is *okay* - it is 'edge' triggered X * from low to high) X */ X outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA); X } X} X X/* X * Process an ioctl request. This code needs some work - it looks X * pretty ugly. X */ Xint Xed_ioctl(ifp, command, data) X register struct ifnet *ifp; X int command; X caddr_t data; X{ X register struct ifaddr *ifa = (struct ifaddr *)data; X struct ed_softc *sc = &ed_softc[ifp->if_unit]; X struct ifreq *ifr = (struct ifreq *)data; X int s, error = 0; X X s = splnet(); X X switch (command) { X X case SIOCSIFADDR: X ifp->if_flags |= IFF_UP; X X switch (ifa->ifa_addr->sa_family) { X#ifdef INET X case AF_INET: X ed_init(ifp->if_unit); /* before arpwhohas */ X /* X * See if another station has *our* IP address. X * i.e.: There is an address conflict! If a X * conflict exists, a message is sent to the X * console. X */ X ((struct arpcom *)ifp)->ac_ipaddr = X IA_SIN(ifa)->sin_addr; X arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); X break; X#endif X#ifdef NS X /* X * XXX - This code is probably wrong X */ X case AF_NS: X { X register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); X X if (ns_nullhost(*ina)) X ina->x_host = X *(union ns_host *)(sc->arpcom.ac_enaddr); X else { X /* X * X */ X bcopy((caddr_t)ina->x_host.c_host, X (caddr_t)sc->arpcom.ac_enaddr, X sizeof(sc->arpcom.ac_enaddr)); X } X /* X * Set new address X */ X ed_init(ifp->if_unit); X break; X } X#endif X default: X ed_init(ifp->if_unit); X break; X } X break; X X case SIOCSIFFLAGS: X /* X * If interface is marked down and it is running, then stop it X */ X if (((ifp->if_flags & IFF_UP) == 0) && X (ifp->if_flags & IFF_RUNNING)) { X ed_stop(ifp->if_unit); X ifp->if_flags &= ~IFF_RUNNING; X } else { X /* X * If interface is marked up and it is stopped, then start it X */ X if ((ifp->if_flags & IFF_UP) && X ((ifp->if_flags & IFF_RUNNING) == 0)) X ed_init(ifp->if_unit); X } X#if NBPFILTER > 0 X if (ifp->if_flags & IFF_PROMISC) { X /* X * Set promiscuous mode on interface. X * XXX - for multicasts to work, we would need to X * write 1's in all bits of multicast X * hashing array. For now we assume that X * this was done in ed_init(). X */ X outb(sc->nic_addr + ED_P0_RCR, X ED_RCR_PRO|ED_RCR_AM|ED_RCR_AB); X } else { X /* X * XXX - for multicasts to work, we would need to X * rewrite the multicast hashing array with the X * proper hash (would have been destroyed above). X */ X outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB); X } X#endif X /* X * An unfortunate hack to provide the (required) software control X * of the tranceiver for 3Com boards. The LLC0 flag disables X * the tranceiver if set. X */ X if ((sc->vendor == ED_VENDOR_3COM) && (ifp->if_flags & IFF_LLC0)) { X outb(sc->asic_addr + ED_3COM_CR, 0); X } else { X outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL); X } X X break; X X default: X error = EINVAL; X } X (void) splx(s); X return (error); X} X X/* X * Macro to calculate a new address within shared memory when given an offset X * from an address, taking into account ring-wrap. X */ X#define ringoffset(sc, start, off, type) \ X ((type)( ((caddr_t)(start)+(off) >= (sc)->smem_end) ? \ X (((caddr_t)(start)+(off))) - (sc)->smem_end \ X + (sc)->smem_ring: \ X ((caddr_t)(start)+(off)) )) X X/* X * Retreive packet from shared memory and send to the next level up via X * ether_input(). If there is a BPF listener, give a copy to BPF, too. X */ Xed_get_packet(sc, buf, len) X struct ed_softc *sc; X char *buf; X u_short len; X{ X struct ether_header *eh; X struct mbuf *m, *head, *ed_ring_to_mbuf(); X u_short off; X int resid; X u_short etype; X struct trailer_header { X u_short trail_type; X u_short trail_residual; X } trailer_header; X X /* Allocate a header mbuf */ X MGETHDR(m, M_DONTWAIT, MT_DATA); X if (m == 0) X goto bad; X m->m_pkthdr.rcvif = &sc->arpcom.ac_if; X m->m_pkthdr.len = len; X m->m_len = 0; X head = m; X X eh = (struct ether_header *)buf; X X /* The following sillines is to make NFS happy */ X#define EROUND ((sizeof(struct ether_header) + 3) & ~3) X#define EOFF (EROUND - sizeof(struct ether_header)) X X /* X * The following assumes there is room for X * the ether header in the header mbuf X */ X head->m_data += EOFF; X bcopy(buf, mtod(head, caddr_t), sizeof(struct ether_header)); X buf += sizeof(struct ether_header); X head->m_len += sizeof(struct ether_header); X len -= sizeof(struct ether_header); X X etype = ntohs((u_short)eh->ether_type); X X /* X * Deal with trailer protocol: X * If trailer protocol, calculate the datasize as 'off', X * which is also the offset to the trailer header. X * Set resid to the amount of packet data following the X * trailer header. X * Finally, copy residual data into mbuf chain. X */ X if (etype >= ETHERTYPE_TRAIL && X etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { X X off = (etype - ETHERTYPE_TRAIL) << 9; X if ((off + sizeof(struct trailer_header)) > len) X goto bad; /* insanity */ X X eh->ether_type = *ringoffset(sc, buf, off, u_short *); X resid = ntohs(*ringoffset(sc, buf, off+2, u_short *)); X X if ((off + resid) > len) goto bad; /* insanity */ X X resid -= sizeof(struct trailer_header); X if (resid < 0) goto bad; /* insanity */ X X m = ed_ring_to_mbuf(sc, ringoffset(sc, buf, off+4, char *), head, resid); X if (m == 0) goto bad; X X len = off; X head->m_pkthdr.len -= 4; /* subtract trailer header */ X } X X /* X * Pull packet off interface. Or if this was a trailer packet, X * the data portion is appended. X */ X m = ed_ring_to_mbuf(sc, buf, m, len); X if (m == 0) goto bad; X X#if NBPFILTER > 0 X /* X * Check if there's a BPF listener on this interface. X * If so, hand off the raw packet to bpf. X */ X if (sc->bpf) { X bpf_mtap(sc->bpf, head); X X /* X * Note that the interface cannot be in promiscuous mode if X * there are no BPF listeners. And if we are in promiscuous X * mode, we have to check if this packet is really ours. X * X * XXX This test does not support multicasts. X */ X if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) && X bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, X sizeof(eh->ether_dhost)) != 0 && X bcmp(eh->ether_dhost, etherbroadcastaddr, X sizeof(eh->ether_dhost)) != 0) { X X m_freem(head); X return; X } X } X#endif X X /* X * Fix up data start offset in mbuf to point past ether header X */ X m_adj(head, sizeof(struct ether_header)); X X /* X * silly ether_input routine needs 'type' in host byte order X */ X eh->ether_type = ntohs(eh->ether_type); X X ether_input(&sc->arpcom.ac_if, eh, head); X return; X Xbad: if (head) X m_freem(head); X return; X} X X/* X * Supporting routines X */ X X/* X * Given a source and destination address, copy 'amount' of a packet from X * the ring buffer into a linear destination buffer. Takes into account X * ring-wrap. X */ Xstatic inline char * Xed_ring_copy(sc,src,dst,amount) X struct ed_softc *sc; X char *src; X char *dst; X u_short amount; X{ X u_short tmp_amount; X X /* does copy wrap to lower addr in ring buffer? */ X if (src + amount > sc->smem_end) { X tmp_amount = sc->smem_end - src; X bcopy(src,dst,tmp_amount); /* copy amount up to end of smem */ X amount -= tmp_amount; X src = sc->smem_ring; X dst += tmp_amount; X } X X bcopy(src, dst, amount); X X return(src + amount); X} X X/* X * Copy data from receive buffer to end of mbuf chain X * allocate additional mbufs as needed. return pointer X * to last mbuf in chain. X * sc = ed info (softc) X * src = pointer in ed ring buffer X * dst = pointer to last mbuf in mbuf chain to copy to X * amount = amount of data to copy X */ Xstruct mbuf * Xed_ring_to_mbuf(sc,src,dst,total_len) X struct ed_softc *sc; X char *src; X struct mbuf *dst; X u_short total_len; X{ X register struct mbuf *m = dst; X X while (total_len) { X register u_short amount = min(total_len, M_TRAILINGSPACE(m)); X X if (amount == 0) { /* no more data in this mbuf, alloc another */ X /* X * If there is enough data for an mbuf cluster, attempt X * to allocate one of those, otherwise, a regular X * mbuf will do. X * Note that a regular mbuf is always required, even if X * we get a cluster - getting a cluster does not X * allocate any mbufs, and one is needed to assign X * the cluster to. The mbuf that has a cluster X * extension can not be used to contain data - only X * the cluster can contain data. X */ X dst = m; X MGET(m, M_DONTWAIT, MT_DATA); X if (m == 0) X return (0); X X if (total_len >= MINCLSIZE) X MCLGET(m, M_DONTWAIT); X X m->m_len = 0; X dst->m_next = m; X amount = min(total_len, M_TRAILINGSPACE(m)); X } X X src = ed_ring_copy(sc, src, mtod(m, caddr_t) + m->m_len, amount); X X m->m_len += amount; X total_len -= amount; X X } X return (m); X} X#endif X END-of-if_ed.c echo x - if_edreg.h sed 's/^X//' >if_edreg.h << 'END-of-if_edreg.h' X/* X * National Semiconductor DS8390 NIC register definitions X * X * $Log: if_edreg.h,v $ X * Revision 1.3 93/07/20 15:25:25 davidg X * added config flags for forcing 8/16bit mode and disabling double X * xmit buffers. X * X * Revision 1.2 93/06/23 03:03:05 davidg X * added some additional definitions for the 83C584 bus interface X * chip (SMC/WD boards) X * X * Revision 1.1 93/06/23 03:01:07 davidg X * Initial revision X * X */ X X/* X * Page 0 register offsets X */ X#define ED_P0_CR 0x00 /* Command Register */ X X#define ED_P0_CLDA0 0x01 /* Current Local DMA Addr low (read) */ X#define ED_P0_PSTART 0x01 /* Page Start register (write) */ X X#define ED_P0_CLDA1 0x02 /* Current Local DMA Addr high (read) */ X#define ED_P0_PSTOP 0x02 /* Page Stop register (write) */ X X#define ED_P0_BNRY 0x03 /* Boundary Pointer */ X X#define ED_P0_TSR 0x04 /* Transmit Status Register (read) */ X#define ED_P0_TPSR 0x04 /* Transmit Page Start (write) */ X X#define ED_P0_NCR 0x05 /* Number of Collisions Reg (read) */ X#define ED_P0_TBCR0 0x05 /* Transmit Byte count, low (write) */ X X#define ED_P0_FIFO 0x06 /* FIFO register (read) */ X#define ED_P0_TBCR1 0x06 /* Transmit Byte count, high (write) */ X X#define ED_P0_ISR 0x07 /* Interrupt Status Register */ X X#define ED_P0_CRDA0 0x08 /* Current Remote DMA Addr low (read) */ X#define ED_P0_RSAR0 0x08 /* Remote Start Address low (write) */ X X#define ED_P0_CRDA1 0x09 /* Current Remote DMA Addr high (read) */ X#define ED_P0_RSAR1 0x09 /* Remote Start Address high (write) */ X X#define ED_P0_RBCR0 0x0a /* Remote Byte Count low (write) */ X X#define ED_P0_RBCR1 0x0b /* Remote Byte Count high (write) */ X X#define ED_P0_RSR 0x0c /* Receive Status (read) */ X#define ED_P0_RCR 0x0c /* Receive Configuration Reg (write) */ X X#define ED_P0_CNTR0 0x0d /* frame alignment error counter (read) */ X#define ED_P0_TCR 0x0d /* Transmit Configuration Reg (write) */ X X#define ED_P0_CNTR1 0x0e /* CRC error counter (read) */ X#define ED_P0_DCR 0x0e /* Data Configuration Reg (write) */ X X#define ED_P0_CNTR2 0x0f /* missed packet counter (read) */ X#define ED_P0_IMR 0x0f /* Interrupt Mask Register (write) */ X X/* X * Page 1 register offsets X */ X#define ED_P1_CR 0x00 /* Command Register */ X#define ED_P1_PAR0 0x01 /* Physical Address Register 0 */ X#define ED_P1_PAR1 0x02 /* Physical Address Register 1 */ X#define ED_P1_PAR2 0x03 /* Physical Address Register 2 */ X#define ED_P1_PAR3 0x04 /* Physical Address Register 3 */ X#define ED_P1_PAR4 0x05 /* Physical Address Register 4 */ X#define ED_P1_PAR5 0x06 /* Physical Address Register 5 */ X#define ED_P1_CURR 0x07 /* Current RX ring-buffer page */ X#define ED_P1_MAR0 0x08 /* Multicast Address Register 0 */ X#define ED_P1_MAR1 0x09 /* Multicast Address Register 1 */ X#define ED_P1_MAR2 0x0a /* Multicast Address Register 2 */ X#define ED_P1_MAR3 0x0b /* Multicast Address Register 3 */ X#define ED_P1_MAR4 0x0c /* Multicast Address Register 4 */ X#define ED_P1_MAR5 0x0d /* Multicast Address Register 5 */ X#define ED_P1_MAR6 0x0e /* Multicast Address Register 6 */ X#define ED_P1_MAR7 0x0f /* Multicast Address Register 7 */ X X/* X * Page 2 register offsets X */ X#define ED_P2_CR 0x00 /* Command Register */ X#define ED_P2_PSTART 0x01 /* Page Start (read) */ X#define ED_P2_CLDA0 0x01 /* Current Local DMA Addr 0 (write) */ X#define ED_P2_PSTOP 0x02 /* Page Stop (read) */ X#define ED_P2_CLDA1 0x02 /* Current Local DMA Addr 1 (write) */ X#define ED_P2_RNPP 0x03 /* Remote Next Packet Pointer */ X#define ED_P2_TPSR 0x04 /* Transmit Page Start (read) */ X#define ED_P2_LNPP 0x05 /* Local Next Packet Pointer */ X#define ED_P2_ACU 0x06 /* Address Counter Upper */ X#define ED_P2_ACL 0x07 /* Address Counter Lower */ X#define ED_P2_RCR 0x0c /* Receive Configuration Register (read) */ X#define ED_P2_TCR 0x0d /* Transmit Configuration Register (read) */ X#define ED_P2_DCR 0x0e /* Data Configuration Register (read) */ X#define ED_P2_IMR 0x0f /* Interrupt Mask Register (read) */ X X/* X * Command Register (CR) definitions X */ X X/* X * STP: SToP. Software reset command. Takes the controller offline. No X * packets will be received or transmitted. Any reception or X * transmission in progress will continue to completion before X * entering reset state. To exit this state, the STP bit must X * reset and the STA bit must be set. The software reset has X * executed only when indicated by the RST bit in the ISR being X * set. X */ X#define ED_CR_STP 0x01 X X/* X * STA: STArt. This bit is used to activate the NIC after either power-up, X * or when the NIC has been put in reset mode by software command X * or error. X */ X#define ED_CR_STA 0x02 X X/* X * TXP: Transmit Packet. This bit must be set to indicate transmission of X * a packet. TXP is internally reset either after the transmission is X * completed or aborted. This bit should be set only after the Transmit X * Byte Count and Transmit Page Start register have been programmed. X */ X#define ED_CR_TXP 0x04 X X/* X * RD0, RD1, RD2: Remote DMA Command. These three bits control the operation X * of the remote DMA channel. RD2 can be set to abort any remote DMA X * command in progress. The Remote Byte Count registers should be cleared X * when a remote DMA has been aborted. The Remote Start Addresses are not X * restored to the starting address if the remote DMA is aborted. X * X * RD2 RD1 RD0 function X * 0 0 0 not allowed X * 0 0 1 remote read X * 0 1 0 remote write X * 0 1 1 send packet X * 1 X X abort X */ X#define ED_CR_RD0 0x08 X#define ED_CR_RD1 0x10 X#define ED_CR_RD2 0x20 X X/* X * PS0, PS1: Page Select. The two bits select which register set or 'page' to X * access. X * X * PS1 PS0 page X * 0 0 0 X * 0 1 1 X * 1 0 2 X * 1 1 reserved X */ X#define ED_CR_PS0 0x40 X#define ED_CR_PS1 0x80 X/* bit encoded aliases */ X#define ED_CR_PAGE_0 0x00 /* (for consistency) */ X#define ED_CR_PAGE_1 0x40 X#define ED_CR_PAGE_2 0x80 X X/* X * Interrupt Status Register (ISR) definitions X */ X X/* X * PRX: Packet Received. Indicates packet received with no errors. X */ X#define ED_ISR_PRX 0x01 X X/* X * PTX: Packet Transmitted. Indicates packet transmitted with no errors. X */ X#define ED_ISR_PTX 0x02 X X/* X * RXE: Receive Error. Indicates that a packet was received with one or more X * the following errors: CRC error, frame alignment error, FIFO overrun, X * missed packet. X */ X#define ED_ISR_RXE 0x04 X X/* X * TXE: Transmission Error. Indicates that an attempt to transmit a packet X * resulted in one or more of the following errors: excessive X * collisions, FIFO underrun. X */ X#define ED_ISR_TXE 0x08 X X/* X * OVW: OverWrite. Indicates a receive ring-buffer overrun. Incoming network X * would exceed (has exceeded?) the boundry pointer, resulting in data X * that was previously received and not yet read from the buffer to be X * overwritten. X */ X#define ED_ISR_OVW 0x10 X X/* X * CNT: Counter Overflow. Set when the MSB of one or more of the Network Talley X * Counters has been set. X */ X#define ED_ISR_CNT 0x20 X X/* X * RDC: Remote Data Complete. Indicates that a Remote DMA operation has completed. X */ X#define ED_ISR_RDC 0x40 X X/* X * RST: Reset status. Set when the NIC enters the reset state and cleared when a X * Start Command is issued to the CR. This bit is also set when a receive X * ring-buffer overrun (OverWrite) occurs and is cleared when one or more X * packets have been removed from the ring. This is a read-only bit. X */ X#define ED_ISR_RST 0x80 X X/* X * Interrupt Mask Register (IMR) definitions X */ X X/* X * PRXE: Packet Received interrupt Enable. If set, a received packet will cause X * an interrupt. X */ X#define ED_IMR_PRXE 0x01 X X/* X * PTXE: Packet Transmit interrupt Enable. If set, an interrupt is generated when X * a packet transmission completes. X */ X#define ED_IMR_PTXE 0x02 X X/* X * RXEE: Receive Error interrupt Enable. If set, an interrupt will occur whenever a X * packet is received with an error. X */ X#define ED_IMR_RXEE 0x04 X X/* X * TXEE: Transmit Error interrupt Enable. If set, an interrupt will occur whenever X * a transmission results in an error. X */ X#define ED_IMR_TXEE 0x08 X X/* X * OVWE: OverWrite error interrupt Enable. If set, an interrupt is generated whenever X * the receive ring-buffer is overrun. i.e. when the boundry pointer is exceeded. X */ X#define ED_IMR_OVWE 0x10 X X/* X * CNTE: Counter overflow interrupt Enable. If set, an interrupt is generated whenever X * the MSB of one or more of the Network Statistics counters has been set. X */ X#define ED_IMR_CNTE 0x20 X X/* X * RDCE: Remote DMA Complete interrupt Enable. If set, an interrupt is generated X * when a remote DMA transfer has completed. X */ X#define ED_IMR_RDCE 0x40 X X/* X * bit 7 is unused/reserved X */ X X/* X * Data Configuration Register (DCR) definitions X */ X X/* X * WTS: Word Transfer Select. WTS establishes byte or word transfers for X * both remote and local DMA transfers X */ X#define ED_DCR_WTS 0x01 X X/* X * BOS: Byte Order Select. BOS sets the byte order for the host. X * Should be 0 for 80x86, and 1 for 68000 series processors X */ X#define ED_DCR_BOS 0x02 X X/* X * LAS: Long Address Select. When LAS is 1, the contents of the remote X * DMA registers RSAR0 and RSAR1 are used to provide A16-A31 X */ X#define ED_DCR_LAS 0x04 X X/* X * LS: Loopback Select. When 0, loopback mode is selected. Bits D1 and D2 X * of the TCR must also be programmed for loopback operation. X * When 1, normal operation is selected. X */ X#define ED_DCR_LS 0x08 X X/* X * AR: Auto-initialize Remote. When 0, data must be removed from ring-buffer X * under program control. When 1, remote DMA is automatically initiated X * and the boundry pointer is automatically updated X */ X#define ED_DCR_AR 0x10 X X/* X * FT0, FT1: Fifo Threshold select. X * FT1 FT0 Word-width Byte-width X * 0 0 1 word 2 bytes X * 0 1 2 words 4 bytes X * 1 0 4 words 8 bytes X * 1 1 8 words 12 bytes X * X * During transmission, the FIFO threshold indicates the number of bytes X * or words that the FIFO has filled from the local DMA before BREQ is X * asserted. The transmission threshold is 16 bytes minus the receiver X * threshold. X */ X#define ED_DCR_FT0 0x20 X#define ED_DCR_FT1 0x40 X X/* X * bit 7 (0x80) is unused/reserved X */ X X/* X * Transmit Configuration Register (TCR) definitions X */ X X/* X * CRC: Inhibit CRC. If 0, CRC will be appended by the transmitter, if 0, CRC X * is not appended by the transmitter. X */ X#define ED_TCR_CRC 0x01 X X/* X * LB0, LB1: Loopback control. These two bits set the type of loopback that is X * to be performed. X * X * LB1 LB0 mode X * 0 0 0 - normal operation (DCR_LS = 0) X * 0 1 1 - internal loopback (DCR_LS = 0) X * 1 0 2 - external loopback (DCR_LS = 1) X * 1 1 3 - external loopback (DCR_LS = 0) X */ X#define ED_TCR_LB0 0x02 X#define ED_TCR_LB1 0x04 X X/* X * ATD: Auto Transmit Disable. Clear for normal operation. When set, allows X * another station to disable the NIC's transmitter by transmitting to X * a multicast address hashing to bit 62. Reception of a multicast address X * hashing to bit 63 enables the transmitter. X */ X#define ED_TCR_ATD 0x08 X X/* X * OFST: Collision Offset enable. This bit when set modifies the backoff X * algorithm to allow prioritization of nodes. X */ X#define ED_TCR_OFST 0x10 X X/* X * bits 5, 6, and 7 are unused/reserved X */ X X/* X * Transmit Status Register (TSR) definitions X */ X X/* X * PTX: Packet Transmitted. Indicates successful transmission of packet. X */ X#define ED_TSR_PTX 0x01 X X/* X * bit 1 (0x02) is unused/reserved X */ X X/* X * COL: Transmit Collided. Indicates that the transmission collided at least X * once with another station on the network. X */ X#define ED_TSR_COL 0x04 X X/* X * ABT: Transmit aborted. Indicates that the transmission was aborted due to X * excessive collisions. X */ X#define ED_TSR_ABT 0x08 X X/* X * CRS: Carrier Sense Lost. Indicates that carrier was lost during the X * transmission of the packet. (Transmission is not aborted because X * of a loss of carrier) X */ X#define ED_TSR_CRS 0x10 X X/* X * FU: FIFO Underrun. Indicates that the NIC wasn't able to access bus/ X * transmission memory before the FIFO emptied. Transmission of the X * packet was aborted. X */ X#define ED_TSR_FU 0x20 X X/* X * CDH: CD Heartbeat. Indicates that the collision detection circuitry X * isn't working correctly during a collision heartbeat test. X */ X#define ED_TSR_CDH 0x40 X X/* X * OWC: Out of Window Collision: Indicates that a collision occurred after X * a slot time (51.2us). The transmission is rescheduled just as in X * normal collisions. X */ X#define ED_TSR_OWC 0x80 X X/* X * Receiver Configuration Register (RCR) definitions X */ X X/* X * SEP: Save Errored Packets. If 0, error packets are discarded. If set to 1, X * packets with CRC and frame errors are not discarded. X */ X#define ED_RCR_SEP 0x01 X X/* X * AR: Accept Runt packet. If 0, packet with less than 64 byte are discarded. X * If set to 1, packets with less than 64 byte are not discarded. X */ X#define ED_RCR_AR 0x02 X X/* X * AB: Accept Broadcast. If set, packets sent to the broadcast address will be X * accepted. X */ X#define ED_RCR_AB 0x04 X X/* X * AM: Accept Multicast. If set, packets sent to a multicast address are checked X * for a match in the hashing array. If clear, multicast packets are ignored. X */ X#define ED_RCR_AM 0x08 X X/* X * PRO: Promiscuous Physical. If set, all packets with a physical addresses are X * accepted. If clear, a physical destination address must match this X * station's address. Note: for full promiscuous mode, RCR_AB and RCR_AM X * must also be set. In addition, the multicast hashing array must be set X * to all 1's so that all multicast addresses are accepted. X */ X#define ED_RCR_PRO 0x10 X X/* X * MON: Monitor Mode. If set, packets will be checked for good CRC and framing, X * but are not stored in the ring-buffer. If clear, packets are stored (normal X * operation). X */ X#define ED_RCR_MON 0x20 X X/* X * bits 6 and 7 are unused/reserved. X */ X X/* X * Receiver Status Register (RSR) definitions X */ X X/* X * PRX: Packet Received without error. X */ X#define ED_RSR_PRX 0x01 X X/* X * CRC: CRC error. Indicates that a packet has a CRC error. Also set for frame X * alignment errors. X */ X#define ED_RSR_CRC 0x02 X X/* X * FAE: Frame Alignment Error. Indicates that the incoming packet did not end on X * a byte boundry and the CRC did not match at the last byte boundry. X */ X#define ED_RSR_FAE 0x04 X X/* X * FO: FIFO Overrun. Indicates that the FIFO was not serviced (during local DMA) X * causing it to overrun. Reception of the packet is aborted. X */ X#define ED_RSR_FO 0x08 X X/* X * MPA: Missed Packet. Indicates that the received packet couldn't be stored in X * the ring-buffer because of insufficient buffer space (exceeding the X * boundry pointer), or because the transfer to the ring-buffer was inhibited X * by RCR_MON - monitor mode. X */ X#define ED_RSR_MPA 0x10 X X/* X * PHY: Physical address. If 0, the packet received was sent to a physical address. X * If 1, the packet was accepted because of a multicast/broadcast address X * match. X */ X#define ED_RSR_PHY 0x20 X X/* X * DIS: Receiver Disabled. Set to indicate that the receiver has enetered monitor X * mode. Cleared when the receiver exits monitor mode. X */ X#define ED_RSR_DIS 0x40 X X/* X * DFR: Deferring. Set to indicate a 'jabber' condition. The CRS and COL inputs X * are active, and the transceiver has set the CD line as a result of the X * jabber. X */ X#define ED_RSR_DFR 0x80 X X/* X * receive ring discriptor X * X * The National Semiconductor DS8390 Network interface controller uses X * the following receive ring headers. The way this works is that the X * memory on the interface card is chopped up into 256 bytes blocks. X * A contiguous portion of those blocks are marked for receive packets X * by setting start and end block #'s in the NIC. For each packet that X * is put into the receive ring, one of these headers (4 bytes each) is X * tacked onto the front. X */ Xstruct ed_ring { X struct edr_status { /* received packet status */ X u_char rs_prx:1, /* packet received intack */ X rs_crc:1, /* crc error */ X rs_fae:1, /* frame alignment error */ X rs_fo:1, /* fifo overrun */ X rs_mpa:1, /* packet received intack */ X rs_phy:1, /* packet received intack */ X rs_dis:1, /* packet received intack */ X rs_dfr:1; /* packet received intack */ X } ed_rcv_status; /* received packet status */ X u_char next_packet; /* pointer to next packet */ X u_short count; /* bytes in packet (length + 4) */ X}; X X/* X * Common constants X */ X#define ED_PAGE_SIZE 256 /* Size of RAM pages in bytes */ X#define ED_TXBUF_SIZE 6 /* Size of TX buffer in pages */ X X/* X * Vendor types X */ X#define ED_VENDOR_WD_SMC 0x00 /* Western Digital/SMC */ X#define ED_VENDOR_3COM 0x01 /* 3Com */ X X/* X * Compile-time config flags X */ X/* X * this sets the default for enabling/disablng the tranceiver X */ X#define ED_FLAGS_DISABLE_TRANCEIVER 0x01 X X/* X * This forces the board to be used in 8/16bit mode even if it X * autoconfigs differently X */ X#define ED_FLAGS_FORCE_8BIT_MODE 0x02 X#define ED_FLAGS_FORCE_16BIT_MODE 0x04 X X/* X * This disables the use of double transmit buffers. X */ X#define ED_FLAGS_NO_DOUBLE_BUFFERING 0x08 X X/* X * Definitions for Western digital/SMC WD80x3 series ASIC X */ X/* X * Memory Select Register (MSR) X */ X#define ED_WD_MSR 0 X X#define ED_WD_MSR_ADDR 0x3f /* Memory decode bits 18-13 */ X#define ED_WD_MSR_MENB 0x40 /* Memory enable */ X#define ED_WD_MSR_RST 0x80 /* Reset board */ X X/* X * Interface Configuration Register (ICR) X */ X#define ED_WD_ICR 1 X X#define ED_WD_ICR_16BIT 0x01 /* 16-bit interface */ X#define ED_WD_ICR_OAR 0x02 /* select register. 0=BIO 1=EAR */ X#define ED_WD_ICR_IR2 0x04 /* high order bit of encoded IRQ */ X#define ED_WD_ICR_MSZ 0x08 /* memory size (0=8k 1=32k) */ X#define ED_WD_ICR_RLA 0x10 /* recall LAN address */ X#define ED_WD_ICR_RX7 0x20 /* recall all but i/o and LAN address */ X#define ED_WD_ICR_RIO 0x40 /* recall i/o address */ X#define ED_WD_ICR_STO 0x80 /* store to non-volatile memory */ X X/* X * IO Address Register (IAR) X */ X#define ED_WD_IAR 2 X X/* X * EEROM Address Register X */ X#define ED_WD_EAR 3 X X/* X * Interrupt Request Register (IRR) X */ X#define ED_WD_IRR 4 X X#define ED_WD_IRR_0WS 0x01 /* use 0 wait-states on 8 bit bus */ X#define ED_WD_IRR_OUT1 0x02 /* WD83C584 pin 1 output */ X#define ED_WD_IRR_OUT2 0x04 /* WD83C584 pin 2 output */ X#define ED_WD_IRR_OUT3 0x08 /* WD83C584 pin 3 output */ X#define ED_WD_IRR_FLASH 0x10 /* Flash RAM is in the ROM socket */ X X/* X * The three bit of the encoded IRQ are decoded as follows: X * X * IR2 IR1 IR0 IRQ X * 0 0 0 2/9 X * 0 0 1 3 X * 0 1 0 5 X * 0 1 1 7 X * 1 0 0 10 X * 1 0 1 11 X * 1 1 0 15 X * 1 1 1 4 X */ X#define ED_WD_IRR_IR0 0x20 /* bit 0 of encoded IRQ */ X#define ED_WD_IRR_IR1 0x40 /* bit 1 of encoded IRQ */ X#define ED_WD_IRR_IEN 0x80 /* Interrupt enable */ X X/* X * LA Address Register (LAAR) X */ X#define ED_WD_LAAR 5 X X#define ED_WD_LAAR_ADDRHI 0x1f /* bits 23-19 of RAM address */ X#define ED_WD_LAAR_0WS16 0x20 /* enable 0 wait-states on 16 bit bus */ X#define ED_WD_LAAR_L16EN 0x40 /* enable 16-bit operation */ X#define ED_WD_LAAR_M16EN 0x80 /* enable 16-bit memory access */ X X/* i/o base offset to station address/card-ID PROM */ X#define ED_WD_PROM 8 X X/* i/o base offset to CARD ID */ X#define ED_WD_CARD_ID ED_WD_PROM+6 X X#define ED_TYPE_WD8003S 0x02 X#define ED_TYPE_WD8003E 0x03 X#define ED_TYPE_WD8013EBT 0x05 X#define ED_TYPE_WD8013EB 0x27 X#define ED_TYPE_WD8013EBP 0x2c X#define ED_TYPE_WD8013EPC 0x29 X X/* Bit definitions in card ID */ X#define ED_WD_REV_MASK 0x1f /* Revision mask */ X#define ED_WD_SOFTCONFIG 0x20 /* Soft config */ X#define ED_WD_LARGERAM 0x40 /* Large RAM */ X#define ED_MICROCHANEL 0x80 /* Microchannel bus (vs. isa) */ X X/* X * Checksum total. All 8 bytes in station address PROM will add up to this X */ X#define ED_WD_ROM_CHECKSUM_TOTAL 0xFF X X#define ED_WD_NIC_OFFSET 0x10 /* I/O base offset to NIC */ X#define ED_WD_ASIC_OFFSET 0 /* I/O base offset to ASIC */ X#define ED_WD_IO_PORTS 32 /* # of i/o addresses used */ X X#define ED_WD_PAGE_OFFSET 0 /* page offset for NIC access to mem */ X X/* X * Definitions for 3Com 3c503 X */ X#define ED_3COM_NIC_OFFSET 0 X#define ED_3COM_ASIC_OFFSET 0x400 /* offset to nic i/o regs */ X X/* X * XXX - The I/O address range is fragmented in the 3c503; this is the X * number of regs at iobase. X */ X#define ED_3COM_IO_PORTS 16 /* # of i/o addresses used */ X X#define ED_3COM_PAGE_OFFSET 0x20 /* memory starts in second bank */ X X/* X * Page Start Register. Must match PSTART in NIC X */ X#define ED_3COM_PSTR 0 X X/* X * Page Stop Register. Must match PSTOP in NIC X */ X#define ED_3COM_PSPR 1 X X/* X * Drq Timer Register. Determines number of bytes to be transfered during X * a DMA burst. X */ X#define ED_3COM_DQTR 2 X X/* X * Base Configuration Register. Read-only register which contains the X * board-configured I/O base address of the adapter. Bit encoded. X */ X#define ED_3COM_BCFR 3 X X#define ED_3COM_BCFR_2E0 0x01 X#define ED_3COM_BCFR_2A0 0x02 X#define ED_3COM_BCFR_280 0x04 X#define ED_3COM_BCFR_250 0x08 X#define ED_3COM_BCFR_350 0x10 X#define ED_3COM_BCFR_330 0x20 X#define ED_3COM_BCFR_310 0x40 X#define ED_3COM_BCFR_300 0x80 X X/* X * EPROM Configuration Register. Read-only register which contains the X * board-configured memory base address. Bit encoded. X */ X#define ED_3COM_PCFR 4 X X#define ED_3COM_PCFR_C8000 0x10 X#define ED_3COM_PCFR_CC000 0x20 X#define ED_3COM_PCFR_D8000 0x40 X#define ED_3COM_PCFR_DC000 0x80 X X/* X * GA Configuration Register. Gate-Array Configuration Register. X */ X#define ED_3COM_GACFR 5 X X/* X * mbs2 mbs1 mbs0 start address X * 0 0 0 0x0000 X * 0 0 1 0x2000 X * 0 1 0 0x4000 X * 0 1 1 0x6000 X * X * Note that with adapters with only 8K, the setting for 0x2000 must X * always be used. X */ X#define ED_3COM_GACFR_MBS0 0x01 X#define ED_3COM_GACFR_MBS1 0x02 X#define ED_3COM_GACFR_MBS2 0x04 X X#define ED_3COM_GACFR_RSEL 0x08 /* enable shared memory */ X#define ED_3COM_GACFR_TEST 0x10 /* for GA testing */ X#define ED_3COM_GACFR_OWS 0x20 /* select 0WS access to GA */ X#define ED_3COM_GACFR_TCM 0x40 /* Mask DMA interrupts */ X#define ED_3COM_GACFR_NIM 0x80 /* Mask NIC interrupts */ X X/* X * Control Register. Miscellaneous control functions. X */ X#define ED_3COM_CR 6 X X#define ED_3COM_CR_RST 0x01 /* Reset GA and NIC */ X#define ED_3COM_CR_XSEL 0x02 /* Transceiver select. BNC=1(def) AUI=0 */ X#define ED_3COM_CR_EALO 0x04 /* window EA PROM 0-15 to I/O base */ X#define ED_3COM_CR_EAHI 0x08 /* window EA PROM 16-31 to I/O base */ X#define ED_3COM_CR_SHARE 0x10 /* select interrupt sharing option */ X#define ED_3COM_CR_DBSEL 0x20 /* Double buffer select */ X#define ED_3COM_CR_DDIR 0x40 /* DMA direction select */ X#define ED_3COM_CR_START 0x80 /* Start DMA controller */ X X/* X * Status Register. Miscellaneous status information. X */ X#define ED_3COM_STREG 7 X X#define ED_3COM_STREG_REV 0x07 /* GA revision */ X#define ED_3COM_STREG_DIP 0x08 /* DMA in progress */ X#define ED_3COM_STREG_DTC 0x10 /* DMA terminal count */ X#define ED_3COM_STREG_OFLW 0x20 /* Overflow */ X#define ED_3COM_STREG_UFLW 0x40 /* Underflow */ X#define ED_3COM_STREG_DPRDY 0x80 /* Data port ready */ X X/* X * Interrupt/DMA Configuration Register X */ X#define ED_3COM_IDCFR 8 X X#define ED_3COM_IDCFR_DRQ0 0x01 /* DMA request 1 select */ X#define ED_3COM_IDCFR_DRQ1 0x02 /* DMA request 2 select */ X#define ED_3COM_IDCFR_DRQ2 0x04 /* DMA request 3 select */ X#define ED_3COM_IDCFR_UNUSED 0x08 /* not used */ X#define ED_3COM_IDCFR_IRQ2 0x10 /* Interrupt request 2 select */ X#define ED_3COM_IDCFR_IRQ3 0x20 /* Interrupt request 3 select */ X#define ED_3COM_IDCFR_IRQ4 0x40 /* Interrupt request 4 select */ X#define ED_3COM_IDCFR_IRQ5 0x80 /* Interrupt request 5 select */ X X/* X * DMA Address Register MSB X */ X#define ED_3COM_DAMSB 9 X X/* X * DMA Address Register LSB X */ X#define ED_3COM_DALSB 0x0a X X/* X * Vector Pointer Register 2 X */ X#define ED_3COM_VPTR2 0x0b X X/* X * Vector Pointer Register 1 X */ X#define ED_3COM_VPTR1 0x0c X X/* X * Vector Pointer Register 0 X */ X#define ED_3COM_VPTR0 0x0d X X/* X * Register File Access MSB X */ X#define ED_3COM_RFMSB 0x0e X X/* X * Register File Access LSB X */ X#define ED_3COM_RFLSB 0x0f END-of-if_edreg.h exit