|
|
1.1 ! root 1: /************************************************************************** ! 2: ETHERBOOT - BOOTP/TFTP Bootstrap Program ! 3: ! 4: Author: Martin Renters ! 5: Date: May/94 ! 6: ! 7: This code is based heavily on David Greenman's if_ed.c driver ! 8: ! 9: Copyright (C) 1993-1994, David Greenman, Martin Renters. ! 10: This software may be used, modified, copied, distributed, and sold, in ! 11: both source and binary form provided that the above copyright and these ! 12: terms are retained. Under no circumstances are the authors responsible for ! 13: the proper functioning of this software, nor do the authors assume any ! 14: responsibility for damages incurred with its use. ! 15: ! 16: Multicast support added by Timothy Legge ([email protected]) 09/28/2003 ! 17: Relocation support added by Ken Yap ([email protected]) 28/12/02 ! 18: Card Detect support adapted from the eCos driver (Christian Plessl <[email protected]>) ! 19: Extracted from ns8390.c and adapted by Pantelis Koukousoulas <[email protected]> ! 20: **************************************************************************/ ! 21: ! 22: FILE_LICENCE ( BSD2 ); ! 23: ! 24: #include "ns8390.h" ! 25: #include "etherboot.h" ! 26: #include "nic.h" ! 27: #include <ipxe/ethernet.h> ! 28: #include <ipxe/isa.h> ! 29: #include <errno.h> ! 30: ! 31: #define ASIC_PIO NE_DATA ! 32: ! 33: static unsigned char eth_vendor, eth_flags; ! 34: static unsigned short eth_nic_base, eth_asic_base; ! 35: static unsigned char eth_memsize, eth_rx_start, eth_tx_start; ! 36: static Address eth_bmem, eth_rmem; ! 37: static unsigned char eth_drain_receiver; ! 38: ! 39: static struct nic_operations ne_operations; ! 40: static void ne_reset(struct nic *nic, struct isa_device *isa); ! 41: ! 42: static isa_probe_addr_t ne_probe_addrs[] = { 0x300, 0x280, 0x320, 0x340, 0x380, 0x220, }; ! 43: ! 44: /************************************************************************** ! 45: ETH_PIO_READ - Read a frame via Programmed I/O ! 46: **************************************************************************/ ! 47: static void eth_pio_read(unsigned int src, unsigned char *dst, unsigned int cnt) { ! 48: outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND); ! 49: outb(cnt, eth_nic_base + D8390_P0_RBCR0); ! 50: outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1); ! 51: outb(src, eth_nic_base + D8390_P0_RSAR0); ! 52: outb(src >> 8, eth_nic_base + D8390_P0_RSAR1); ! 53: outb(D8390_COMMAND_RD0 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND); ! 54: if (eth_flags & FLAG_16BIT) ! 55: cnt = (cnt + 1) >> 1; ! 56: ! 57: while (cnt--) { ! 58: if (eth_flags & FLAG_16BIT) { ! 59: *((unsigned short *) dst) = inw(eth_asic_base + ASIC_PIO); ! 60: dst += 2; ! 61: } else ! 62: *(dst++) = inb(eth_asic_base + ASIC_PIO); ! 63: } ! 64: } ! 65: ! 66: /************************************************************************** ! 67: ETH_PIO_WRITE - Write a frame via Programmed I/O ! 68: **************************************************************************/ ! 69: static void eth_pio_write(const unsigned char *src, unsigned int dst, ! 70: unsigned int cnt) { ! 71: outb(D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND); ! 72: outb(D8390_ISR_RDC, eth_nic_base + D8390_P0_ISR); ! 73: outb(cnt, eth_nic_base + D8390_P0_RBCR0); ! 74: outb(cnt >> 8, eth_nic_base + D8390_P0_RBCR1); ! 75: outb(dst, eth_nic_base + D8390_P0_RSAR0); ! 76: outb(dst >> 8, eth_nic_base + D8390_P0_RSAR1); ! 77: outb(D8390_COMMAND_RD1 | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND); ! 78: if (eth_flags & FLAG_16BIT) ! 79: cnt = (cnt + 1) >> 1; ! 80: ! 81: while (cnt--) { ! 82: ! 83: if (eth_flags & FLAG_16BIT) { ! 84: outw(*((unsigned short *) src), eth_asic_base + ASIC_PIO); ! 85: src += 2; ! 86: } else ! 87: outb(*(src++), eth_asic_base + ASIC_PIO); ! 88: } ! 89: } ! 90: ! 91: /************************************************************************** ! 92: enable_multicast - Enable Multicast ! 93: **************************************************************************/ ! 94: static void enable_multicast(unsigned short eth_nic_base) { ! 95: unsigned char mcfilter[8]; ! 96: int i; ! 97: ! 98: memset(mcfilter, 0xFF, 8); ! 99: outb(4, eth_nic_base + D8390_P0_RCR); ! 100: outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS1, eth_nic_base + D8390_P0_COMMAND); ! 101: for (i = 0; i < 8; i++) { ! 102: outb(mcfilter[i], eth_nic_base + 8 + i); ! 103: if (inb(eth_nic_base + 8 + i) != mcfilter[i]) ! 104: DBG("Error SMC 83C690 Multicast filter read/write mishap %d\n", ! 105: i); ! 106: } ! 107: outb(D8390_COMMAND_RD2 + D8390_COMMAND_PS0, eth_nic_base + D8390_P0_COMMAND); ! 108: outb(4 | 0x08, eth_nic_base + D8390_P0_RCR); ! 109: } ! 110: ! 111: /************************************************************************** ! 112: NE_PROBE1 - Look for an adapter on the ISA bus ! 113: **************************************************************************/ ! 114: static int ne_probe1(isa_probe_addr_t ioaddr) { ! 115: //From the eCos driver ! 116: unsigned int regd; ! 117: unsigned int state; ! 118: ! 119: state = inb(ioaddr); ! 120: outb(ioaddr, D8390_COMMAND_RD2 | D8390_COMMAND_PS1 | D8390_COMMAND_STP); ! 121: regd = inb(ioaddr + D8390_P0_TCR); ! 122: ! 123: if (inb(ioaddr + D8390_P0_TCR)) { ! 124: outb(ioaddr, state); ! 125: outb(ioaddr + 0x0d, regd); ! 126: return 0; ! 127: } ! 128: ! 129: return 1; ! 130: } ! 131: ! 132: /************************************************************************** ! 133: NE_PROBE - Initialize an adapter ??? ! 134: **************************************************************************/ ! 135: static int ne_probe(struct nic *nic, struct isa_device *isa) { ! 136: int i; ! 137: unsigned char c; ! 138: unsigned char romdata[16]; ! 139: unsigned char testbuf[32]; ! 140: ! 141: eth_vendor = VENDOR_NONE; ! 142: eth_drain_receiver = 0; ! 143: ! 144: nic->irqno = 0; ! 145: nic->ioaddr = isa->ioaddr; ! 146: eth_nic_base = isa->ioaddr; ! 147: ! 148: /****************************************************************** ! 149: Search for NE1000/2000 if no WD/SMC or 3com cards ! 150: ******************************************************************/ ! 151: if (eth_vendor == VENDOR_NONE) { ! 152: ! 153: static unsigned char test[] = "NE*000 memory"; ! 154: ! 155: eth_bmem = 0; /* No shared memory */ ! 156: ! 157: eth_flags = FLAG_PIO; ! 158: eth_asic_base = eth_nic_base + NE_ASIC_OFFSET; ! 159: eth_memsize = MEM_16384; ! 160: eth_tx_start = 32; ! 161: eth_rx_start = 32 + D8390_TXBUF_SIZE; ! 162: c = inb(eth_asic_base + NE_RESET); ! 163: outb(c, eth_asic_base + NE_RESET); ! 164: (void) inb(0x84); ! 165: outb(D8390_COMMAND_STP | D8390_COMMAND_RD2, eth_nic_base ! 166: + D8390_P0_COMMAND); ! 167: outb(D8390_RCR_MON, eth_nic_base + D8390_P0_RCR); ! 168: outb(D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base + D8390_P0_DCR); ! 169: outb(MEM_8192, eth_nic_base + D8390_P0_PSTART); ! 170: outb(MEM_16384, eth_nic_base + D8390_P0_PSTOP); ! 171: eth_pio_write((unsigned char *) test, 8192, sizeof(test)); ! 172: eth_pio_read(8192, testbuf, sizeof(test)); ! 173: if (!memcmp(test, testbuf, sizeof(test))) ! 174: goto out; ! 175: eth_flags |= FLAG_16BIT; ! 176: eth_memsize = MEM_32768; ! 177: eth_tx_start = 64; ! 178: eth_rx_start = 64 + D8390_TXBUF_SIZE; ! 179: outb(D8390_DCR_WTS | D8390_DCR_FT1 | D8390_DCR_LS, eth_nic_base ! 180: + D8390_P0_DCR); ! 181: outb(MEM_16384, eth_nic_base + D8390_P0_PSTART); ! 182: outb(MEM_32768, eth_nic_base + D8390_P0_PSTOP); ! 183: eth_pio_write((unsigned char *) test, 16384, sizeof(test)); ! 184: eth_pio_read(16384, testbuf, sizeof(test)); ! 185: if (!memcmp(testbuf, test, sizeof(test))) ! 186: goto out; ! 187: ! 188: ! 189: out: ! 190: if (eth_nic_base == 0) ! 191: return (0); ! 192: if (eth_nic_base > ISA_MAX_ADDR) /* PCI probably */ ! 193: eth_flags |= FLAG_16BIT; ! 194: eth_vendor = VENDOR_NOVELL; ! 195: eth_pio_read(0, romdata, sizeof(romdata)); ! 196: for (i = 0; i < ETH_ALEN; i++) { ! 197: nic->node_addr[i] = romdata[i + ((eth_flags & FLAG_16BIT) ? i : 0)]; ! 198: } ! 199: nic->ioaddr = eth_nic_base; ! 200: DBG("\nNE%c000 base %4.4x, MAC Addr %s\n", ! 201: (eth_flags & FLAG_16BIT) ? '2' : '1', eth_nic_base, eth_ntoa( ! 202: nic->node_addr)); ! 203: } ! 204: ! 205: if (eth_vendor == VENDOR_NONE) ! 206: return (0); ! 207: ! 208: if (eth_vendor != VENDOR_3COM) ! 209: eth_rmem = eth_bmem; ! 210: ! 211: ne_reset(nic, isa); ! 212: nic->nic_op = &ne_operations; ! 213: return 1; ! 214: } ! 215: ! 216: ! 217: /************************************************************************** ! 218: NE_DISABLE - Turn off adapter ! 219: **************************************************************************/ ! 220: static void ne_disable(struct nic *nic, struct isa_device *isa) { ! 221: ne_reset(nic, isa); ! 222: } ! 223: ! 224: ! 225: /************************************************************************** ! 226: NE_RESET - Reset adapter ! 227: **************************************************************************/ ! 228: static void ne_reset(struct nic *nic, struct isa_device *isa __unused) ! 229: { ! 230: int i; ! 231: ! 232: eth_drain_receiver = 0; ! 233: outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | ! 234: D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND); ! 235: if (eth_flags & FLAG_16BIT) ! 236: outb(0x49, eth_nic_base+D8390_P0_DCR); ! 237: else ! 238: outb(0x48, eth_nic_base+D8390_P0_DCR); ! 239: outb(0, eth_nic_base+D8390_P0_RBCR0); ! 240: outb(0, eth_nic_base+D8390_P0_RBCR1); ! 241: outb(0x20, eth_nic_base+D8390_P0_RCR); /* monitor mode */ ! 242: outb(2, eth_nic_base+D8390_P0_TCR); ! 243: outb(eth_tx_start, eth_nic_base+D8390_P0_TPSR); ! 244: outb(eth_rx_start, eth_nic_base+D8390_P0_PSTART); ! 245: ! 246: outb(eth_memsize, eth_nic_base+D8390_P0_PSTOP); ! 247: outb(eth_memsize - 1, eth_nic_base+D8390_P0_BOUND); ! 248: outb(0xFF, eth_nic_base+D8390_P0_ISR); ! 249: outb(0, eth_nic_base+D8390_P0_IMR); ! 250: outb(D8390_COMMAND_PS1 | ! 251: D8390_COMMAND_RD2 | D8390_COMMAND_STP, eth_nic_base+D8390_P0_COMMAND); ! 252: ! 253: for (i=0; i<ETH_ALEN; i++) ! 254: outb(nic->node_addr[i], eth_nic_base+D8390_P1_PAR0+i); ! 255: for (i=0; i<ETH_ALEN; i++) ! 256: outb(0xFF, eth_nic_base+D8390_P1_MAR0+i); ! 257: outb(eth_rx_start, eth_nic_base+D8390_P1_CURR); ! 258: outb(D8390_COMMAND_PS0 | ! 259: D8390_COMMAND_RD2 | D8390_COMMAND_STA, eth_nic_base+D8390_P0_COMMAND); ! 260: outb(0xFF, eth_nic_base+D8390_P0_ISR); ! 261: outb(0, eth_nic_base+D8390_P0_TCR); /* transmitter on */ ! 262: outb(4, eth_nic_base+D8390_P0_RCR); /* allow rx broadcast frames */ ! 263: ! 264: enable_multicast(eth_nic_base); ! 265: } ! 266: ! 267: ! 268: /************************************************************************** ! 269: NE_POLL - Wait for a frame ! 270: **************************************************************************/ ! 271: static int ne_poll(struct nic *nic __unused, int retrieve __unused) ! 272: { ! 273: int ret = 0; ! 274: unsigned char rstat, curr, next; ! 275: unsigned short len, frag; ! 276: unsigned short pktoff; ! 277: unsigned char *p; ! 278: struct ringbuffer pkthdr; ! 279: ! 280: rstat = inb(eth_nic_base+D8390_P0_RSR); ! 281: if (!(rstat & D8390_RSTAT_PRX)) return(0); ! 282: next = inb(eth_nic_base+D8390_P0_BOUND)+1; ! 283: if (next >= eth_memsize) next = eth_rx_start; ! 284: outb(D8390_COMMAND_PS1, eth_nic_base+D8390_P0_COMMAND); ! 285: curr = inb(eth_nic_base+D8390_P1_CURR); ! 286: outb(D8390_COMMAND_PS0, eth_nic_base+D8390_P0_COMMAND); ! 287: if (curr >= eth_memsize) curr=eth_rx_start; ! 288: if (curr == next) return(0); ! 289: ! 290: if ( ! retrieve ) return 1; ! 291: ! 292: pktoff = next << 8; ! 293: if (eth_flags & FLAG_PIO) ! 294: eth_pio_read(pktoff, (unsigned char *)&pkthdr, 4); ! 295: else ! 296: memcpy(&pkthdr, bus_to_virt(eth_rmem + pktoff), 4); ! 297: pktoff += sizeof(pkthdr); ! 298: /* incoming length includes FCS so must sub 4 */ ! 299: len = pkthdr.len - 4; ! 300: if ((pkthdr.status & D8390_RSTAT_PRX) == 0 || len < ETH_ZLEN ! 301: || len> ETH_FRAME_LEN) { ! 302: DBG("Bogus packet, ignoring\n"); ! 303: return (0); ! 304: } ! 305: else { ! 306: p = nic->packet; ! 307: nic->packetlen = len; /* available to caller */ ! 308: frag = (eth_memsize << 8) - pktoff; ! 309: if (len> frag) { /* We have a wrap-around */ ! 310: /* read first part */ ! 311: if (eth_flags & FLAG_PIO) ! 312: eth_pio_read(pktoff, p, frag); ! 313: else ! 314: memcpy(p, bus_to_virt(eth_rmem + pktoff), frag); ! 315: pktoff = eth_rx_start << 8; ! 316: p += frag; ! 317: len -= frag; ! 318: } ! 319: /* read second part */ ! 320: if (eth_flags & FLAG_PIO) ! 321: eth_pio_read(pktoff, p, len); ! 322: else ! 323: memcpy(p, bus_to_virt(eth_rmem + pktoff), len); ! 324: ret = 1; ! 325: } ! 326: next = pkthdr.next; /* frame number of next packet */ ! 327: if (next == eth_rx_start) ! 328: next = eth_memsize; ! 329: outb(next-1, eth_nic_base+D8390_P0_BOUND); ! 330: return(ret); ! 331: } ! 332: ! 333: ! 334: /************************************************************************** ! 335: NE_TRANSMIT - Transmit a frame ! 336: **************************************************************************/ ! 337: static void ne_transmit(struct nic *nic, const char *d, /* Destination */ ! 338: unsigned int t, /* Type */ ! 339: unsigned int s, /* size */ ! 340: const char *p) { /* Packet */ ! 341: ! 342: /* Programmed I/O */ ! 343: unsigned short type; ! 344: type = (t >> 8) | (t << 8); ! 345: eth_pio_write((unsigned char *) d, eth_tx_start << 8, ETH_ALEN); ! 346: eth_pio_write(nic->node_addr, (eth_tx_start << 8) + ETH_ALEN, ETH_ALEN); ! 347: /* bcc generates worse code without (const+const) below */ ! 348: eth_pio_write((unsigned char *) &type, (eth_tx_start << 8) + (ETH_ALEN ! 349: + ETH_ALEN), 2); ! 350: eth_pio_write((unsigned char *) p, (eth_tx_start << 8) + ETH_HLEN, s); ! 351: s += ETH_HLEN; ! 352: if (s < ETH_ZLEN) ! 353: s = ETH_ZLEN; ! 354: ! 355: outb(D8390_COMMAND_PS0 | D8390_COMMAND_RD2 | D8390_COMMAND_STA, ! 356: eth_nic_base + D8390_P0_COMMAND); ! 357: outb(eth_tx_start, eth_nic_base + D8390_P0_TPSR); ! 358: outb(s, eth_nic_base + D8390_P0_TBCR0); ! 359: outb(s >> 8, eth_nic_base + D8390_P0_TBCR1); ! 360: ! 361: outb(D8390_COMMAND_PS0 | D8390_COMMAND_TXP | D8390_COMMAND_RD2 ! 362: | D8390_COMMAND_STA, eth_nic_base + D8390_P0_COMMAND); ! 363: } ! 364: ! 365: static struct nic_operations ne_operations = { .connect = dummy_connect, ! 366: .poll = ne_poll, .transmit = ne_transmit, .irq = dummy_irq, ! 367: }; ! 368: ! 369: ISA_DRIVER ( ne_driver, ne_probe_addrs, ne_probe1, ! 370: GENERIC_ISAPNP_VENDOR, 0x0600 ); ! 371: ! 372: DRIVER ( "ne", nic_driver, isapnp_driver, ne_driver, ! 373: ne_probe, ne_disable ); ! 374: ! 375: ISA_ROM("ne","NE1000/2000 and clones");
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.