iPXE
ne2k_isa.c
Go to the documentation of this file.
00001 /**************************************************************************
00002  ETHERBOOT -  BOOTP/TFTP Bootstrap Program
00003 
00004  Author: Martin Renters
00005  Date: May/94
00006 
00007  This code is based heavily on David Greenman's if_ed.c driver
00008 
00009  Copyright (C) 1993-1994, David Greenman, Martin Renters.
00010  This software may be used, modified, copied, distributed, and sold, in
00011  both source and binary form provided that the above copyright and these
00012  terms are retained. Under no circumstances are the authors responsible for
00013  the proper functioning of this software, nor do the authors assume any
00014  responsibility for damages incurred with its use.
00015 
00016  Multicast support added by Timothy Legge (timlegge@users.sourceforge.net) 09/28/2003
00017  Relocation support added by Ken Yap (ken_yap@users.sourceforge.net) 28/12/02
00018  Card Detect support adapted from the eCos driver (Christian Plessl <cplessl@ee.ethz.ch>)
00019  Extracted from ns8390.c and adapted by Pantelis Koukousoulas <pktoss@gmail.com>
00020  **************************************************************************/
00021 
00022 FILE_LICENCE ( BSD2 );
00023 
00024 #include "ns8390.h"
00025 #include "etherboot.h"
00026 #include "nic.h"
00027 #include <ipxe/ethernet.h>
00028 #include <ipxe/isa.h>
00029 #include <errno.h>
00030 
00031 #define ASIC_PIO NE_DATA
00032 
00033 static unsigned char eth_vendor, eth_flags;
00034 static unsigned short eth_nic_base, eth_asic_base;
00035 static unsigned char eth_memsize, eth_rx_start, eth_tx_start;
00036 static Address eth_bmem, eth_rmem;
00037 static unsigned char eth_drain_receiver;
00038 
00039 static struct nic_operations ne_operations;
00040 static void ne_reset(struct nic *nic, struct isa_device *isa);
00041 
00042 static isa_probe_addr_t ne_probe_addrs[] = { 0x300, 0x280, 0x320, 0x340, 0x380, 0x220, };
00043 
00044 /**************************************************************************
00045  ETH_PIO_READ - Read a frame via Programmed I/O
00046  **************************************************************************/
00047 static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt) {
00048         outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
00049         outb(cnt, eth_nic_base + D8390_P0_RBCR0);
00050         outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1);
00051         outb(src, eth_nic_base + D8390_P0_RSAR0);
00052         outb(src >> 8, eth_nic_base + D8390_P0_RSAR1);
00053         outb(D8390_COMMAND_RD0 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
00054         if (eth_flags & FLAG_16BIT)
00055                 cnt = (cnt + 1) >> 1;
00056 
00057         while (cnt--) {
00058                 if (eth_flags & FLAG_16BIT) {
00059                         *((unsigned short *) dst) = inw(eth_asic_base + ASIC_PIO);
00060                         dst += 2;
00061                 } else
00062                         *(dst++) = inb(eth_asic_base + ASIC_PIO);
00063         }
00064 }
00065 
00066 /**************************************************************************
00067  ETH_PIO_WRITE - Write a frame via Programmed I/O
00068  **************************************************************************/
00069 static void eth_pio_write(const unsigned char *src, unsigned int dst,
00070                 unsigned int cnt) {
00071         outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
00072         outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR);
00073         outb(cnt, eth_nic_base + D8390_P0_RBCR0);
00074         outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1);
00075         outb(dst, eth_nic_base + D8390_P0_RSAR0);
00076         outb(dst >> 8, eth_nic_base + D8390_P0_RSAR1);
00077         outb(D8390_COMMAND_RD1 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
00078         if (eth_flags & FLAG_16BIT)
00079                 cnt = (cnt + 1) >> 1;
00080 
00081         while (cnt--) {
00082 
00083                 if (eth_flags & FLAG_16BIT) {
00084                         outw(*((unsigned short *) src), eth_asic_base + ASIC_PIO);
00085                         src += 2;
00086                 } else
00087                         outb(*(src++), eth_asic_base + ASIC_PIO);
00088         }
00089 }
00090 
00091 /**************************************************************************
00092  enable_multicast - Enable Multicast
00093  **************************************************************************/
00094 static void enable_multicast(unsigned short eth_nic_base) {
00095         unsigned char mcfilter[8];
00096         int i;
00097 
00098         memset(mcfilter, 0xFF, 8);
00099         outb(4, eth_nic_base + D8390_P0_RCR);
00100         outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1, eth_nic_base + D8390_P0_COMMAND);
00101         for (i = 0; i < 8; i++) {
00102                 outb(mcfilter[i], eth_nic_base + 8 + i);
00103                 if (inb(eth_nic_base + 8 + i) != mcfilter[i])
00104                         DBG("Error SMC 83C690 Multicast filter read/write mishap %d\n",
00105                                         i);
00106         }
00107         outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0, eth_nic_base + D8390_P0_COMMAND);
00108         outb(4 | 0x08, eth_nic_base + D8390_P0_RCR);
00109 }
00110 
00111 /**************************************************************************
00112  NE_PROBE1 - Look for an adapter on the ISA bus
00113  **************************************************************************/
00114 static int ne_probe1(isa_probe_addr_t ioaddr) {
00115         //From the eCos driver
00116         unsigned int regd;
00117         unsigned int state;
00118 
00119         state = inb(ioaddr);
00120         outb(ioaddr, D8390_COMMAND_RD2 | D8390_COMMAND_PS1 | D8390_COMMAND_STP);
00121         regd = inb(ioaddr + D8390_P0_TCR);
00122 
00123         if (inb(ioaddr + D8390_P0_TCR)) {
00124                 outb(ioaddr, state);
00125                 outb(ioaddr + 0x0d, regd);
00126                 return 0;
00127         }
00128 
00129         return 1;
00130 }
00131 
00132 /**************************************************************************
00133  NE_PROBE - Initialize an adapter ???
00134  **************************************************************************/
00135 static int ne_probe(struct nic *nic, struct isa_device *isa) {
00136         int i;
00137         unsigned char c;
00138         unsigned char romdata[16];
00139         unsigned char testbuf[32];
00140 
00141         eth_vendor = VENDOR_NONE;
00142         eth_drain_receiver = 0;
00143 
00144         nic->irqno = 0;
00145         nic->ioaddr = isa->ioaddr;
00146         eth_nic_base = isa->ioaddr;
00147 
00148         /******************************************************************
00149          Search for NE1000/2000 if no WD/SMC or 3com cards
00150          ******************************************************************/
00151         if (eth_vendor == VENDOR_NONE) {
00152 
00153                 static unsigned char test[] = "NE*000 memory";
00154 
00155                 eth_bmem = 0; /* No shared memory */
00156 
00157                 eth_flags = FLAG_PIO;
00158                 eth_asic_base = eth_nic_base + NE_ASIC_OFFSET;
00159                 eth_memsize = MEM_16384;
00160                 eth_tx_start = 32;
00161                 eth_rx_start = 32 + D8390_TXBUF_SIZE;
00162                 c = inb(eth_asic_base + NE_RESET);
00163                 outb(c, eth_asic_base + NE_RESET);
00164                 (void) inb(0x84);
00165                 outb(D8390_COMMAND_STP | D8390_COMMAND_RD2, eth_nic_base
00166                                 + D8390_P0_COMMAND);
00167                 outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR);
00168                 outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR);
00169                 outb(MEM_8192, eth_nic_base + D8390_P0_PSTART);
00170                 outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP);
00171                 eth_pio_write((unsigned char *) test, 8192, sizeof(test));
00172                 eth_pio_read(8192, testbuf, sizeof(test));
00173                 if (!memcmp(test, testbuf, sizeof(test)))
00174                         goto out;
00175                 eth_flags |= FLAG_16BIT;
00176                 eth_memsize = MEM_32768;
00177                 eth_tx_start = 64;
00178                 eth_rx_start = 64 + D8390_TXBUF_SIZE;
00179                 outb(D8390_DCR_WTS | D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base
00180                                 + D8390_P0_DCR);
00181                 outb(MEM_16384, eth_nic_base + D8390_P0_PSTART);
00182                 outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP);
00183                 eth_pio_write((unsigned char *) test, 16384, sizeof(test));
00184                 eth_pio_read(16384, testbuf, sizeof(test));
00185                 if (!memcmp(testbuf, test, sizeof(test)))
00186                         goto out;
00187 
00188 
00189 out:
00190                 if (eth_nic_base == 0)
00191                         return (0);
00192                 if (eth_nic_base > ISA_MAX_ADDR) /* PCI probably */
00193                         eth_flags |= FLAG_16BIT;
00194                 eth_vendor = VENDOR_NOVELL;
00195                 eth_pio_read(0, romdata, sizeof(romdata));
00196                 for (i = 0; i < ETH_ALEN; i++) {
00197                         nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)];
00198                 }
00199                 nic->ioaddr = eth_nic_base;
00200                 DBG("\nNE%c000 base %4.4x, MAC Addr %s\n",
00201                                 (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base, eth_ntoa(
00202                                                 nic->node_addr));
00203         }
00204 
00205         if (eth_vendor == VENDOR_NONE)
00206                 return (0);
00207 
00208         if (eth_vendor != VENDOR_3COM)
00209                 eth_rmem = eth_bmem;
00210 
00211         ne_reset(nic, isa);
00212         nic->nic_op = &ne_operations;
00213         return 1;
00214 }
00215 
00216 
00217 /**************************************************************************
00218  NE_DISABLE - Turn off adapter
00219  **************************************************************************/
00220 static void ne_disable(struct nic *nic, struct isa_device *isa) {
00221         ne_reset(nic, isa);
00222 }
00223 
00224 
00225 /**************************************************************************
00226  NE_RESET - Reset adapter
00227  **************************************************************************/
00228 static void ne_reset(struct nic *nic, struct isa_device *isa __unused)
00229 {
00230         int i;
00231 
00232         eth_drain_receiver = 0;
00233         outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 |
00234                         D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
00235         if (eth_flags & FLAG_16BIT)
00236         outb(0x49, eth_nic_base+D8390_P0_DCR);
00237         else
00238         outb(0x48, eth_nic_base+D8390_P0_DCR);
00239         outb(0, eth_nic_base+D8390_P0_RBCR0);
00240         outb(0, eth_nic_base+D8390_P0_RBCR1);
00241         outb(0x20, eth_nic_base+D8390_P0_RCR); /* monitor mode */
00242         outb(2, eth_nic_base+D8390_P0_TCR);
00243         outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR);
00244         outb(eth_rx_start, eth_nic_base+D8390_P0_PSTART);
00245 
00246         outb(eth_memsize, eth_nic_base+D8390_P0_PSTOP);
00247         outb(eth_memsize - 1, eth_nic_base+D8390_P0_BOUND);
00248         outb(0xFF, eth_nic_base+D8390_P0_ISR);
00249         outb(0, eth_nic_base+D8390_P0_IMR);
00250         outb(D8390_COMMAND_PS1 |
00251                         D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND);
00252 
00253         for (i=0; i<ETH_ALEN; i++)
00254         outb(nic->node_addr[i], eth_nic_base+D8390_P1_PAR0+i);
00255         for (i=0; i<ETH_ALEN; i++)
00256         outb(0xFF, eth_nic_base+D8390_P1_MAR0+i);
00257         outb(eth_rx_start, eth_nic_base+D8390_P1_CURR);
00258         outb(D8390_COMMAND_PS0 |
00259                         D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND);
00260         outb(0xFF, eth_nic_base+D8390_P0_ISR);
00261         outb(0, eth_nic_base+D8390_P0_TCR); /* transmitter on */
00262         outb(4, eth_nic_base+D8390_P0_RCR); /* allow rx broadcast frames */
00263 
00264         enable_multicast(eth_nic_base);
00265 }
00266 
00267 
00268 /**************************************************************************
00269  NE_POLL - Wait for a frame
00270  **************************************************************************/
00271 static int ne_poll(struct nic *nic __unused, int retrieve __unused)
00272 {
00273         int ret = 0;
00274         unsigned char rstat, curr, next;
00275         unsigned short len, frag;
00276         unsigned short pktoff;
00277         unsigned char *p;
00278         struct ringbuffer pkthdr;
00279 
00280         rstat = inb(eth_nic_base+D8390_P0_RSR);
00281         if (!(rstat & D8390_RSTAT_PRX)) return(0);
00282         next = inb(eth_nic_base+D8390_P0_BOUND)+1;
00283         if (next >= eth_memsize) next = eth_rx_start;
00284         outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND);
00285         curr = inb(eth_nic_base+D8390_P1_CURR);
00286         outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND);
00287         if (curr >= eth_memsize) curr=eth_rx_start;
00288         if (curr == next) return(0);
00289 
00290         if ( ! retrieve ) return 1;
00291 
00292         pktoff = next << 8;
00293         if (eth_flags & FLAG_PIO)
00294         eth_pio_read(pktoff, (unsigned char *)&pkthdr, 4);
00295         else
00296         memcpy(&pkthdr, bus_to_virt(eth_rmem + pktoff), 4);
00297         pktoff += sizeof(pkthdr);
00298         /* incoming length includes FCS so must sub 4 */
00299         len = pkthdr.len - 4;
00300         if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN
00301                         || len> ETH_FRAME_LEN) {
00302                 DBG("Bogus packet, ignoring\n");
00303                 return (0);
00304         }
00305         else {
00306                 p = nic->packet;
00307                 nic->packetlen = len; /* available to caller */
00308                 frag = (eth_memsize << 8) - pktoff;
00309                 if (len> frag) { /* We have a wrap-around */
00310                         /* read first part */
00311                         if (eth_flags & FLAG_PIO)
00312                         eth_pio_read(pktoff, p, frag);
00313                         else
00314                         memcpy(p, bus_to_virt(eth_rmem + pktoff), frag);
00315                         pktoff = eth_rx_start << 8;
00316                         p += frag;
00317                         len -= frag;
00318                 }
00319                 /* read second part */
00320                 if (eth_flags & FLAG_PIO)
00321                 eth_pio_read(pktoff, p, len);
00322                 else
00323                 memcpy(p, bus_to_virt(eth_rmem + pktoff), len);
00324                 ret = 1;
00325         }
00326         next = pkthdr.next; /* frame number of next packet */
00327         if (next == eth_rx_start)
00328         next = eth_memsize;
00329         outb(next-1, eth_nic_base+D8390_P0_BOUND);
00330         return(ret);
00331 }
00332 
00333 
00334 /**************************************************************************
00335  NE_TRANSMIT - Transmit a frame
00336  **************************************************************************/
00337 static void ne_transmit(struct nic *nic, const char *d, /* Destination */
00338 unsigned int t, /* Type */
00339 unsigned int s, /* size */
00340 const char *p) { /* Packet */
00341 
00342         /* Programmed I/O */
00343         unsigned short type;
00344         type = (t >> 8) | (t << 8);
00345         eth_pio_write((unsigned char *) d, eth_tx_start << 8, ETH_ALEN);
00346         eth_pio_write(nic->node_addr, (eth_tx_start << 8) + ETH_ALEN, ETH_ALEN);
00347         /* bcc generates worse code without (const+const) below */
00348         eth_pio_write((unsigned char *) &type, (eth_tx_start << 8) + (ETH_ALEN
00349                         + ETH_ALEN), 2);
00350         eth_pio_write((unsigned char *) p, (eth_tx_start << 8) + ETH_HLEN, s);
00351         s += ETH_HLEN;
00352         if (s < ETH_ZLEN)
00353                 s = ETH_ZLEN;
00354 
00355         outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | D8390_COMMAND_STA,
00356                         eth_nic_base + D8390_P0_COMMAND);
00357         outb(eth_tx_start, eth_nic_base + D8390_P0_TPSR);
00358         outb(s, eth_nic_base + D8390_P0_TBCR0);
00359         outb(s >> 8, eth_nic_base + D8390_P0_TBCR1);
00360 
00361         outb(D8390_COMMAND_PS0 | D8390_COMMAND_TXP | D8390_COMMAND_RD2
00362                         | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND);
00363 }
00364 
00365 static struct nic_operations ne_operations = { .connect = dummy_connect,
00366                 .poll = ne_poll, .transmit = ne_transmit, .irq = dummy_irq,
00367 };
00368 
00369 ISA_DRIVER ( ne_driver, ne_probe_addrs, ne_probe1,
00370                 GENERIC_ISAPNP_VENDOR, 0x0600 );
00371 
00372 DRIVER ( "ne", nic_driver, isapnp_driver, ne_driver,
00373                 ne_probe, ne_disable );
00374 
00375 ISA_ROM("ne","NE1000/2000 and clones");