|
|
1.1 ! root 1: /* ! 2: * Device driver for National Semiconductor DS8390 based ethernet ! 3: * adapters. By David Greenman, 29-April-1993 ! 4: * ! 5: * Copyright (C) 1993, David Greenman. This software may be used, modified, ! 6: * copied, distributed, and sold, in both source and binary form provided ! 7: * that the above copyright and these terms are retained. Under no ! 8: * circumstances is the author responsible for the proper functioning ! 9: * of this software, nor does the author assume any responsibility ! 10: * for damages incurred with its use. ! 11: * ! 12: * Currently supports the Western Digital/SMC 8003 and 8013 series ! 13: * and the 3Com 3c503 ! 14: */ ! 15: ! 16: /* ! 17: * if_ed.c,v 1.2.2.5 1993/07/27 06:00:45 cgd Exp ! 18: */ ! 19: ! 20: #include "ed.h" ! 21: #if NED > 0 ! 22: #include "bpfilter.h" ! 23: ! 24: #include "param.h" ! 25: #include "systm.h" ! 26: #include "select.h" ! 27: #include "errno.h" ! 28: #include "ioctl.h" ! 29: #include "mbuf.h" ! 30: #include "socket.h" ! 31: #include "syslog.h" ! 32: ! 33: #include "net/if.h" ! 34: #include "net/if_dl.h" ! 35: #include "net/if_types.h" ! 36: #include "net/netisr.h" ! 37: ! 38: #ifdef INET ! 39: #include "netinet/in.h" ! 40: #include "netinet/in_systm.h" ! 41: #include "netinet/in_var.h" ! 42: #include "netinet/ip.h" ! 43: #include "netinet/if_ether.h" ! 44: #endif ! 45: ! 46: #ifdef NS ! 47: #include "netns/ns.h" ! 48: #include "netns/ns_if.h" ! 49: #endif ! 50: ! 51: #if NBPFILTER > 0 ! 52: #include "net/bpf.h" ! 53: #include "net/bpfdesc.h" ! 54: #endif ! 55: ! 56: #include "i386/isa/isa.h" ! 57: #include "i386/isa/isa_device.h" ! 58: #include "i386/isa/icu.h" ! 59: #include "i386/isa/if_edreg.h" ! 60: ! 61: #include "i386/include/pio.h" ! 62: ! 63: ! 64: /* ! 65: * ed_softc: per line info and status ! 66: */ ! 67: struct ed_softc { ! 68: struct arpcom arpcom; /* ethernet common */ ! 69: ! 70: char *type_str; /* pointer to type string */ ! 71: u_char vendor; /* interface vendor */ ! 72: u_char type; /* interface type code */ ! 73: ! 74: u_short vector; /* interrupt vector */ ! 75: u_short asic_addr; /* ASIC I/O bus address */ ! 76: u_short nic_addr; /* NIC (DS8390) I/O bus address */ ! 77: ! 78: caddr_t smem_start; /* shared memory start address */ ! 79: caddr_t smem_end; /* shared memory end address */ ! 80: u_long smem_size; /* total shared memory size */ ! 81: caddr_t smem_ring; /* start of RX ring-buffer (in smem) */ ! 82: ! 83: caddr_t bpf; /* BPF "magic cookie" */ ! 84: ! 85: u_char memwidth; /* width of access to card mem 8 or 16 */ ! 86: u_char xmit_busy; /* transmitter is busy */ ! 87: u_char txb_cnt; /* Number of transmit buffers */ ! 88: u_char txb_next; /* Pointer to next buffer ready to xmit */ ! 89: u_short txb_next_len; /* next xmit buffer length */ ! 90: u_char data_buffered; /* data has been buffered in interface memory */ ! 91: u_char tx_page_start; /* first page of TX buffer area */ ! 92: ! 93: u_char rec_page_start; /* first page of RX ring-buffer */ ! 94: u_char rec_page_stop; /* last page of RX ring-buffer */ ! 95: u_char next_packet; /* pointer to next unread RX packet */ ! 96: } ed_softc[NED]; ! 97: ! 98: int ed_attach(), ed_init(), edintr(), ed_ioctl(), ed_probe(), ! 99: ed_start(), ed_reset(), ed_watchdog(); ! 100: ! 101: static void ed_stop(); ! 102: ! 103: static inline void ed_rint(); ! 104: static inline void ed_xmit(); ! 105: static inline char *ed_ring_copy(); ! 106: ! 107: extern int ether_output(); ! 108: ! 109: struct isa_driver eddriver = { ! 110: ed_probe, ! 111: ed_attach, ! 112: "ed" ! 113: }; ! 114: /* ! 115: * Interrupt conversion table for WD/SMC ASIC ! 116: * (IRQ* are defined in icu.h) ! 117: */ ! 118: static unsigned short ed_intr_mask[] = { ! 119: IRQ9, ! 120: IRQ3, ! 121: IRQ5, ! 122: IRQ7, ! 123: IRQ10, ! 124: IRQ11, ! 125: IRQ15, ! 126: IRQ4 ! 127: }; ! 128: ! 129: #define ETHER_MIN_LEN 64 ! 130: #define ETHER_MAX_LEN 1518 ! 131: #define ETHER_ADDR_LEN 6 ! 132: #define ETHER_HDR_SIZE 14 ! 133: ! 134: /* ! 135: * Determine if the device is present ! 136: * ! 137: * on entry: ! 138: * a pointer to an isa_device struct ! 139: * on exit: ! 140: * NULL if device not found ! 141: * or # of i/o addresses used (if found) ! 142: */ ! 143: int ! 144: ed_probe(isa_dev) ! 145: struct isa_device *isa_dev; ! 146: { ! 147: struct ed_softc *sc = &ed_softc[isa_dev->id_unit]; ! 148: int i, x; ! 149: u_int memsize; ! 150: u_char iptr, memwidth, sum, tmp; ! 151: ! 152: /* ! 153: * Setup initial i/o address for ASIC and NIC ! 154: */ ! 155: sc->asic_addr = isa_dev->id_iobase; ! 156: sc->vector = isa_dev->id_irq; ! 157: sc->smem_start = (caddr_t)isa_dev->id_maddr; ! 158: ! 159: /* ! 160: * Attempt to do a checksum over the station address PROM. ! 161: * This is mapped differently on the WD80x3 and 3C503, so if ! 162: * it fails, it might be a 3C503. There is a problem with ! 163: * this, though: some clone WD boards don't pass the ! 164: * checksum test. Danpex boards for one. We need to do ! 165: * additional checking for this case. ! 166: */ ! 167: for (sum = 0, i = 0; i < 8; ++i) { ! 168: sum += inb(sc->asic_addr + ED_WD_PROM + i); ! 169: } ! 170: ! 171: if (sum == ED_WD_ROM_CHECKSUM_TOTAL) { ! 172: goto type_WD80x3; ! 173: } else { ! 174: /* ! 175: * Do additional checking to make sure its a 3Com and ! 176: * not a broken WD clone ! 177: */ ! 178: goto type_3Com; ! 179: } ! 180: ! 181: type_WD80x3: ! 182: /* ! 183: * Looks like a WD/SMC board ! 184: */ ! 185: ! 186: sc->vendor = ED_VENDOR_WD_SMC; ! 187: sc->type = inb(sc->asic_addr + ED_WD_CARD_ID); ! 188: ! 189: sc->nic_addr = sc->asic_addr + ED_WD_NIC_OFFSET; ! 190: ! 191: /* reset card to force it into a known state. */ ! 192: outb(sc->asic_addr + ED_WD_MSR, ED_WD_MSR_RST); ! 193: DELAY(100); ! 194: outb(sc->asic_addr + ED_WD_MSR, inb(sc->asic_addr + ED_WD_MSR) & ~ED_WD_MSR_RST); ! 195: /* wait in the case this card is reading it's EEROM */ ! 196: DELAY(5000); ! 197: ! 198: /* ! 199: * Set initial values for width/size. ! 200: */ ! 201: switch (sc->type) { ! 202: case ED_TYPE_WD8003S: ! 203: sc->type_str = "WD8003S"; ! 204: memsize = 8192; ! 205: memwidth = 8; ! 206: break; ! 207: case ED_TYPE_WD8003E: ! 208: sc->type_str = "WD8003E"; ! 209: memsize = 8192; ! 210: memwidth = 8; ! 211: break; ! 212: case ED_TYPE_WD8013EBT: ! 213: sc->type_str = "WD8013EBT"; ! 214: memsize = 16384; ! 215: memwidth = 16; ! 216: break; ! 217: case ED_TYPE_WD8013EB: /* also WD8003EP */ ! 218: if (inb(sc->asic_addr + ED_WD_ICR) ! 219: & ED_WD_ICR_16BIT) { ! 220: memwidth = 16; ! 221: memsize = 16384; ! 222: sc->type_str = "WD8013EB"; ! 223: } else { ! 224: sc->type_str = "WD8003EP"; ! 225: memsize = 8192; ! 226: memwidth = 8; ! 227: } ! 228: break; ! 229: case ED_TYPE_WD8013EBP: ! 230: sc->type_str = "WD8013EBP"; ! 231: memsize = 16384; ! 232: memwidth = 16; ! 233: break; ! 234: case ED_TYPE_WD8013EPC: ! 235: sc->type_str = "WD8013EPC"; ! 236: memsize = 16384; ! 237: memwidth = 16; ! 238: break; ! 239: default: ! 240: sc->type_str = "unknown"; ! 241: memsize = 8192; ! 242: memwidth = 8; ! 243: break; ! 244: } ! 245: /* ! 246: * Make some adjustments to initial values depending on what is ! 247: * found in the ICR. ! 248: */ ! 249: if ((memwidth==16) ! 250: && ((inb(sc->asic_addr + ED_WD_ICR) & ED_WD_ICR_16BIT) == 0)) { ! 251: memwidth = 8; ! 252: memsize = 8192; ! 253: } ! 254: if (inb(sc->asic_addr + ED_WD_ICR) & ED_WD_ICR_MSZ) { ! 255: memsize = 32768; ! 256: } ! 257: ! 258: #if ED_DEBUG ! 259: printf("type=%s memwidth=%d memsize=%d id_msize=%d\n", ! 260: sc->type_str,memwidth,memsize,isa_dev->id_msize); ! 261: for (i=0; i<8; i++) ! 262: printf("%x -> %x\n", i, inb(sc->asic_addr + i)); ! 263: #endif ! 264: /* ! 265: * Allow the user to override the autoconfiguration ! 266: */ ! 267: if (isa_dev->id_msize) ! 268: memsize = isa_dev->id_msize; ! 269: /* ! 270: * (note that if the user specifies both of the following flags ! 271: * that '8bit' mode intentionally has precedence) ! 272: */ ! 273: if (isa_dev->id_flags & ED_FLAGS_FORCE_16BIT_MODE) ! 274: memwidth = 16; ! 275: if (isa_dev->id_flags & ED_FLAGS_FORCE_8BIT_MODE) ! 276: memwidth = 8; ! 277: ! 278: /* ! 279: * Check 83C584 interrupt configuration register if this board has one ! 280: * XXX - we could also check the IO address register. But why ! 281: * bother...if we get past this, it *has* to be correct. ! 282: */ ! 283: if (sc->type & ED_WD_SOFTCONFIG) { ! 284: /* ! 285: * Assemble together the encoded interrupt number. ! 286: */ ! 287: iptr = (inb(isa_dev->id_iobase + ED_WD_ICR) & ED_WD_ICR_IR2) | ! 288: ((inb(isa_dev->id_iobase + ED_WD_IRR) & ! 289: (ED_WD_IRR_IR0 | ED_WD_IRR_IR1)) >> 5); ! 290: /* ! 291: * Translate it using translation table, and check for correctness. ! 292: */ ! 293: if (ed_intr_mask[iptr] != isa_dev->id_irq) { ! 294: printf("ed%d: kernel configured irq doesn't match board configured irq\n", ! 295: isa_dev->id_unit); ! 296: return(0); ! 297: } ! 298: /* ! 299: * Enable the interrupt. ! 300: */ ! 301: outb(isa_dev->id_iobase + ED_WD_IRR, ! 302: inb(isa_dev->id_iobase + ED_WD_IRR) | ED_WD_IRR_IEN); ! 303: } ! 304: ! 305: sc->memwidth = memwidth; ! 306: /* ! 307: * allocate one xmit buffer if < 16k, two buffers otherwise ! 308: */ ! 309: if ((memsize < 16384) || (isa_dev->id_msize & ED_FLAGS_NO_DOUBLE_BUFFERING)) { ! 310: sc->smem_ring = sc->smem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE); ! 311: sc->txb_cnt = 1; ! 312: sc->rec_page_start = ED_TXBUF_SIZE; ! 313: } else { ! 314: sc->smem_ring = sc->smem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE * 2); ! 315: sc->txb_cnt = 2; ! 316: sc->rec_page_start = ED_TXBUF_SIZE * 2; ! 317: } ! 318: sc->smem_size = memsize; ! 319: sc->smem_end = sc->smem_start + memsize; ! 320: sc->rec_page_stop = memsize / ED_PAGE_SIZE; ! 321: sc->tx_page_start = ED_WD_PAGE_OFFSET; ! 322: ! 323: /* ! 324: * Get station address from on-board ROM ! 325: */ ! 326: for (i = 0; i < ETHER_ADDR_LEN; ++i) ! 327: sc->arpcom.ac_enaddr[i] = inb(sc->asic_addr + ED_WD_PROM + i); ! 328: ! 329: /* ! 330: * Set address and enable interface shared memory. ! 331: */ ! 332: outb(sc->asic_addr + ED_WD_MSR, ((kvtop(sc->smem_start) >> 13) & ! 333: ED_WD_MSR_ADDR) | ED_WD_MSR_MENB); ! 334: ! 335: /* ! 336: * Set upper address bits and 8/16 bit access to shared memory ! 337: */ ! 338: if (sc->type & ED_WD_SOFTCONFIG) { ! 339: if (memwidth == 8) { ! 340: outb(sc->asic_addr + ED_WD_LAAR, ! 341: ((kvtop(sc->smem_start) >> 19) & ED_WD_LAAR_ADDRHI)); ! 342: } else { ! 343: outb(sc->asic_addr + ED_WD_LAAR, ! 344: ED_WD_LAAR_L16EN | ED_WD_LAAR_M16EN | ! 345: ((kvtop(sc->smem_start) >> 19) & ED_WD_LAAR_ADDRHI)); ! 346: } ! 347: } ! 348: ! 349: /* ! 350: * Now zero memory and verify that it is clear ! 351: */ ! 352: bzero(sc->smem_start, memsize); ! 353: ! 354: for (i = 0; i < memsize; ++i) ! 355: if (sc->smem_start[i]) { ! 356: printf("ed%d: failed to clear shared memory at %x - check configuration\n", ! 357: isa_dev->id_unit, sc->smem_start + i); ! 358: ! 359: /* ! 360: * Disable 16 bit access to shared memory ! 361: */ ! 362: if (memwidth == 16) ! 363: outb(sc->asic_addr + ED_WD_LAAR, ! 364: inb(sc->asic_addr + ED_WD_LAAR) ! 365: & ~ED_WD_LAAR_M16EN); ! 366: ! 367: return(0); ! 368: } ! 369: ! 370: /* ! 371: * Disable 16bit access to shared memory - we leave it disabled so ! 372: * that 1) machines reboot properly when the board is set ! 373: * 16 bit mode and there are conflicting 8bit devices/ROMS ! 374: * in the same 128k address space as this boards shared ! 375: * memory. and 2) so that other 8 bit devices with shared ! 376: * memory can be used in this 128k region, too. ! 377: */ ! 378: if (memwidth == 16) ! 379: outb(sc->asic_addr + ED_WD_LAAR, inb(sc->asic_addr + ED_WD_LAAR) ! 380: & ~ED_WD_LAAR_M16EN); ! 381: ! 382: isa_dev->id_msize = memsize; ! 383: return (ED_WD_IO_PORTS); ! 384: ! 385: type_3Com: ! 386: /* ! 387: * Looks like a 3Com board ! 388: */ ! 389: ! 390: sc->vendor = ED_VENDOR_3COM; ! 391: sc->asic_addr = isa_dev->id_iobase + ED_3COM_ASIC_OFFSET; ! 392: sc->nic_addr = isa_dev->id_iobase + ED_3COM_NIC_OFFSET; ! 393: ! 394: sc->type_str = "3c503"; ! 395: ! 396: memsize = 8192; ! 397: ! 398: /* ! 399: * Verify that the kernel configured I/O address matches the board ! 400: * configured address ! 401: */ ! 402: switch (inb(sc->asic_addr + ED_3COM_BCFR)) { ! 403: case ED_3COM_BCFR_300: ! 404: if (isa_dev->id_iobase != 0x300) ! 405: return(0); ! 406: break; ! 407: case ED_3COM_BCFR_310: ! 408: if (isa_dev->id_iobase != 0x310) ! 409: return(0); ! 410: break; ! 411: case ED_3COM_BCFR_330: ! 412: if (isa_dev->id_iobase != 0x330) ! 413: return(0); ! 414: break; ! 415: case ED_3COM_BCFR_350: ! 416: if (isa_dev->id_iobase != 0x350) ! 417: return(0); ! 418: break; ! 419: case ED_3COM_BCFR_250: ! 420: if (isa_dev->id_iobase != 0x250) ! 421: return(0); ! 422: break; ! 423: case ED_3COM_BCFR_280: ! 424: if (isa_dev->id_iobase != 0x280) ! 425: return(0); ! 426: break; ! 427: case ED_3COM_BCFR_2A0: ! 428: if (isa_dev->id_iobase != 0x2a0) ! 429: return(0); ! 430: break; ! 431: case ED_3COM_BCFR_2E0: ! 432: if (isa_dev->id_iobase != 0x2e0) ! 433: return(0); ! 434: break; ! 435: default: ! 436: return(0); ! 437: } ! 438: ! 439: /* ! 440: * Verify that the kernel shared memory address matches the ! 441: * board configured address. ! 442: */ ! 443: switch (inb(sc->asic_addr + ED_3COM_PCFR)) { ! 444: case ED_3COM_PCFR_DC000: ! 445: if (kvtop(isa_dev->id_maddr) != 0xdc000) ! 446: return(0); ! 447: break; ! 448: case ED_3COM_PCFR_D8000: ! 449: if (kvtop(isa_dev->id_maddr) != 0xd8000) ! 450: return(0); ! 451: break; ! 452: case ED_3COM_PCFR_CC000: ! 453: if (kvtop(isa_dev->id_maddr) != 0xcc000) ! 454: return(0); ! 455: break; ! 456: case ED_3COM_PCFR_C8000: ! 457: if (kvtop(isa_dev->id_maddr) != 0xc8000) ! 458: return(0); ! 459: break; ! 460: default: ! 461: return(0); ! 462: } ! 463: ! 464: /* ! 465: * Reset NIC and ASIC ! 466: */ ! 467: outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_RST); ! 468: /* ! 469: * Wait for a while, then un-reset it ! 470: */ ! 471: DELAY(5000); ! 472: outb(sc->asic_addr + ED_3COM_CR, 0); ! 473: ! 474: /* ! 475: * Wait a bit for the NIC to recover from the reset ! 476: */ ! 477: DELAY(5000); ! 478: ! 479: /* ! 480: * The 3Com ASIC defaults to rather strange settings for the CR after ! 481: * a reset - it's important to set it so that the NIC I/O ! 482: * registers are mapped. The above setting of it to '0' only ! 483: * resets the reset condition - the CR is *not* set to zeros. ! 484: */ ! 485: outb(sc->asic_addr + ED_3COM_CR, 0); ! 486: ! 487: /* ! 488: * Determine if this is an 8bit or 16bit board ! 489: */ ! 490: ! 491: /* ! 492: * select page 0 registers ! 493: */ ! 494: outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP); ! 495: ! 496: /* ! 497: * Attempt to clear WTS bit. If it doesn't clear, then this is a ! 498: * 16bit board. ! 499: */ ! 500: outb(sc->nic_addr + ED_P0_DCR, 0); ! 501: ! 502: /* ! 503: * select page 2 registers ! 504: */ ! 505: outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_2|ED_CR_RD2|ED_CR_STP); ! 506: ! 507: /* ! 508: * The 3c503 forces the WTS bit to a one if this is a 16bit board ! 509: */ ! 510: if (inb(sc->nic_addr + ED_P2_DCR) & ED_DCR_WTS) ! 511: memwidth = 16; ! 512: else ! 513: memwidth = 8; ! 514: ! 515: /* ! 516: * select page 0 registers ! 517: */ ! 518: outb(sc->nic_addr + ED_P2_CR, ED_CR_RD2|ED_CR_STP); ! 519: ! 520: sc->txb_cnt = 1; ! 521: ! 522: sc->tx_page_start = ED_3COM_PAGE_OFFSET; ! 523: sc->rec_page_start = ED_TXBUF_SIZE + ED_3COM_PAGE_OFFSET; ! 524: sc->rec_page_stop = memsize / ED_PAGE_SIZE + ED_3COM_PAGE_OFFSET; ! 525: ! 526: sc->smem_size = memsize; ! 527: sc->smem_end = sc->smem_start + memsize; ! 528: sc->smem_ring = sc->smem_start + (ED_PAGE_SIZE * ED_TXBUF_SIZE); ! 529: ! 530: sc->memwidth = memwidth; ! 531: ! 532: /* ! 533: * Initialize GA page start/stop registers. Probably only needed ! 534: * if doing DMA, but what the hell. ! 535: */ ! 536: outb(sc->asic_addr + ED_3COM_PSTR, sc->rec_page_start); ! 537: outb(sc->asic_addr + ED_3COM_PSPR, sc->rec_page_stop); ! 538: ! 539: /* ! 540: * Set IRQ. 3c503 only allows a choice of irq 2-5. ! 541: */ ! 542: switch (isa_dev->id_irq) { ! 543: case IRQ2: ! 544: outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ2); ! 545: break; ! 546: case IRQ3: ! 547: outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ3); ! 548: break; ! 549: case IRQ4: ! 550: outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ4); ! 551: break; ! 552: case IRQ5: ! 553: outb(sc->asic_addr + ED_3COM_IDCFR, ED_3COM_IDCFR_IRQ5); ! 554: break; ! 555: default: ! 556: printf("ed%d: Invalid irq configuration\n", isa_dev->id_unit); ! 557: return(0); ! 558: } ! 559: ! 560: /* ! 561: * Initialize GA configuration register. Set bank and enable smem. ! 562: */ ! 563: outb(sc->asic_addr + ED_3COM_GACFR, ED_3COM_GACFR_RSEL | ! 564: ED_3COM_GACFR_MBS0); ! 565: ! 566: /* ! 567: * Initialize "Vector Pointer" registers. These gawd-awful things ! 568: * are compared to 20 bits of the address on ISA, and if they ! 569: * match, the shared memory is disabled. We set them to ! 570: * 0xffff0...allegedly the reset vector. ! 571: */ ! 572: outb(sc->asic_addr + ED_3COM_VPTR2, 0xff); ! 573: outb(sc->asic_addr + ED_3COM_VPTR1, 0xff); ! 574: outb(sc->asic_addr + ED_3COM_VPTR0, 0x00); ! 575: ! 576: /* ! 577: * Get station address from on-board ROM ! 578: */ ! 579: /* ! 580: * First, map ethernet address PROM over the top of where the NIC ! 581: * registers normally appear. ! 582: */ ! 583: outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_EALO); ! 584: ! 585: for (i = 0; i < ETHER_ADDR_LEN; ++i) ! 586: sc->arpcom.ac_enaddr[i] = inb(sc->nic_addr + i); ! 587: ! 588: /* ! 589: * Unmap PROM - select NIC registers. Tranceiver remains disabled at ! 590: * this point. It's enabled in ed_init so that the attach code ! 591: * is given a chance to set the default based on a compile-time ! 592: * config option ! 593: */ ! 594: outb(sc->asic_addr + ED_3COM_CR, 0); ! 595: ! 596: #if 0 ! 597: printf("Starting write\n"); ! 598: for (i = 0; i < 8192; ++i) ! 599: bzero(sc->smem_start, 8192); ! 600: printf("Done.\n"); ! 601: #endif ! 602: #if 0 ! 603: { char test_buf[1024]; ! 604: printf("starting write\n"); ! 605: for (i = 0; i < 8*8192; ++i) ! 606: bcopy(test_buf, sc->smem_start, 1024); ! 607: printf("starting read\n"); ! 608: for (i = 0; i < 8*8192; ++i) ! 609: bcopy(sc->smem_start, test_buf, 1024); ! 610: printf("done.\n"); ! 611: } ! 612: #endif ! 613: ! 614: /* ! 615: * Zero memory and verify that it is clear ! 616: */ ! 617: bzero(sc->smem_start, memsize); ! 618: ! 619: for (i = 0; i < memsize; ++i) ! 620: if (sc->smem_start[i]) { ! 621: printf("ed%d: failed to clear shared memory at %x - check configuration\n", ! 622: isa_dev->id_unit, sc->smem_start + i); ! 623: return(0); ! 624: } ! 625: ! 626: isa_dev->id_msize = memsize; ! 627: return(ED_3COM_IO_PORTS); ! 628: } ! 629: ! 630: /* ! 631: * Install interface into kernel networking data structures ! 632: */ ! 633: int ! 634: ed_attach(isa_dev) ! 635: struct isa_device *isa_dev; ! 636: { ! 637: struct ed_softc *sc = &ed_softc[isa_dev->id_unit]; ! 638: struct ifnet *ifp = &sc->arpcom.ac_if; ! 639: struct ifaddr *ifa; ! 640: struct sockaddr_dl *sdl; ! 641: ! 642: /* ! 643: * Set interface to stopped condition (reset) ! 644: */ ! 645: ed_stop(isa_dev->id_unit); ! 646: ! 647: /* ! 648: * Initialize ifnet structure ! 649: */ ! 650: ifp->if_unit = isa_dev->id_unit; ! 651: ifp->if_name = "ed" ; ! 652: ifp->if_mtu = ETHERMTU; ! 653: ifp->if_init = ed_init; ! 654: ifp->if_output = ether_output; ! 655: ifp->if_start = ed_start; ! 656: ifp->if_ioctl = ed_ioctl; ! 657: ifp->if_reset = ed_reset; ! 658: ifp->if_watchdog = ed_watchdog; ! 659: ! 660: /* ! 661: * Set default state for LLC0 flag (used to disable the tranceiver ! 662: * for AUI operation), based on compile-time config option. ! 663: */ ! 664: if (isa_dev->id_flags & ED_FLAGS_DISABLE_TRANCEIVER) ! 665: ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS ! 666: | IFF_LLC0); ! 667: else ! 668: ifp->if_flags = (IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS); ! 669: ! 670: /* ! 671: * Attach the interface ! 672: */ ! 673: if_attach(ifp); ! 674: ! 675: /* ! 676: * Search down the ifa address list looking for the AF_LINK type entry ! 677: */ ! 678: ifa = ifp->if_addrlist; ! 679: while ((ifa != 0) && (ifa->ifa_addr != 0) && ! 680: (ifa->ifa_addr->sa_family != AF_LINK)) ! 681: ifa = ifa->ifa_next; ! 682: /* ! 683: * If we find an AF_LINK type entry we fill in the hardware address. ! 684: * This is useful for netstat(1) to keep track of which interface ! 685: * is which. ! 686: */ ! 687: if ((ifa != 0) && (ifa->ifa_addr != 0)) { ! 688: /* ! 689: * Fill in the link-level address for this interface ! 690: */ ! 691: sdl = (struct sockaddr_dl *)ifa->ifa_addr; ! 692: sdl->sdl_type = IFT_ETHER; ! 693: sdl->sdl_alen = ETHER_ADDR_LEN; ! 694: sdl->sdl_slen = 0; ! 695: bcopy(sc->arpcom.ac_enaddr, LLADDR(sdl), ETHER_ADDR_LEN); ! 696: } ! 697: ! 698: /* ! 699: * Print additional info when attached ! 700: */ ! 701: printf("ed%d: address %s, type %s (%dbit) %s\n", isa_dev->id_unit, ! 702: ether_sprintf(sc->arpcom.ac_enaddr), sc->type_str, ! 703: sc->memwidth, ((sc->vendor == ED_VENDOR_3COM) && ! 704: (ifp->if_flags & IFF_LLC0)) ? "tranceiver disabled" : ""); ! 705: ! 706: /* ! 707: * If BPF is in the kernel, call the attach for it ! 708: */ ! 709: #if NBPFILTER > 0 ! 710: bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); ! 711: #endif ! 712: ! 713: } ! 714: ! 715: /* ! 716: * Reset interface. ! 717: */ ! 718: int ! 719: ed_reset(unit) ! 720: int unit; ! 721: { ! 722: int s; ! 723: ! 724: s = splnet(); ! 725: ! 726: /* ! 727: * Stop interface and re-initialize. ! 728: */ ! 729: ed_stop(unit); ! 730: ed_init(unit); ! 731: ! 732: s = splx(s); ! 733: } ! 734: ! 735: /* ! 736: * Take interface offline. ! 737: */ ! 738: void ! 739: ed_stop(unit) ! 740: int unit; ! 741: { ! 742: struct ed_softc *sc = &ed_softc[unit]; ! 743: int n = 5000; ! 744: ! 745: /* ! 746: * Stop everything on the interface, and select page 0 registers. ! 747: */ ! 748: outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP); ! 749: ! 750: /* ! 751: * Wait for interface to enter stopped state, but limit # of checks ! 752: * to 'n' (about 5ms). It shouldn't even take 5us on modern ! 753: * DS8390's, but just in case it's an old one. ! 754: */ ! 755: while (((inb(sc->nic_addr + ED_P0_ISR) & ED_ISR_RST) == 0) && --n); ! 756: ! 757: } ! 758: ! 759: /* ! 760: * Device timeout/watchdog routine. Entered if the device neglects to ! 761: * generate an interrupt after a transmit has been started on it. ! 762: */ ! 763: int ! 764: ed_watchdog(unit) ! 765: int unit; ! 766: { ! 767: log(LOG_ERR, "ed%d: device timeout\n", unit); ! 768: ! 769: ed_reset(unit); ! 770: } ! 771: ! 772: /* ! 773: * Initialize device. ! 774: */ ! 775: ed_init(unit) ! 776: int unit; ! 777: { ! 778: struct ed_softc *sc = &ed_softc[unit]; ! 779: struct ifnet *ifp = &sc->arpcom.ac_if; ! 780: int i, s; ! 781: u_char command; ! 782: ! 783: ! 784: /* address not known */ ! 785: if (ifp->if_addrlist == (struct ifaddr *)0) return; ! 786: ! 787: /* ! 788: * Initialize the NIC in the exact order outlined in the NS manual. ! 789: * This init procedure is "mandatory"...don't change what or when ! 790: * things happen. ! 791: */ ! 792: s = splnet(); ! 793: ! 794: /* reset transmitter flags */ ! 795: sc->data_buffered = 0; ! 796: sc->xmit_busy = 0; ! 797: sc->arpcom.ac_if.if_timer = 0; ! 798: ! 799: sc->txb_next = 0; ! 800: ! 801: /* This variable is used below - don't move this assignment */ ! 802: sc->next_packet = sc->rec_page_start + 1; ! 803: ! 804: /* ! 805: * Set interface for page 0, Remote DMA complete, Stopped ! 806: */ ! 807: outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STP); ! 808: ! 809: if (sc->memwidth == 16) { ! 810: /* ! 811: * Set FIFO threshold to 8, No auto-init Remote DMA, ! 812: * byte order=80x86, word-wide DMA xfers ! 813: */ ! 814: outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1|ED_DCR_WTS); ! 815: } else { ! 816: /* ! 817: * Same as above, but byte-wide DMA xfers ! 818: */ ! 819: outb(sc->nic_addr + ED_P0_DCR, ED_DCR_FT1); ! 820: } ! 821: ! 822: /* ! 823: * Clear Remote Byte Count Registers ! 824: */ ! 825: outb(sc->nic_addr + ED_P0_RBCR0, 0); ! 826: outb(sc->nic_addr + ED_P0_RBCR1, 0); ! 827: ! 828: /* ! 829: * Enable reception of broadcast packets ! 830: */ ! 831: outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB); ! 832: ! 833: /* ! 834: * Place NIC in internal loopback mode ! 835: */ ! 836: outb(sc->nic_addr + ED_P0_TCR, ED_TCR_LB0); ! 837: ! 838: /* ! 839: * Initialize transmit/receive (ring-buffer) Page Start ! 840: */ ! 841: outb(sc->nic_addr + ED_P0_TPSR, sc->tx_page_start); ! 842: outb(sc->nic_addr + ED_P0_PSTART, sc->rec_page_start); ! 843: ! 844: /* ! 845: * Initialize Receiver (ring-buffer) Page Stop and Boundry ! 846: */ ! 847: outb(sc->nic_addr + ED_P0_PSTOP, sc->rec_page_stop); ! 848: outb(sc->nic_addr + ED_P0_BNRY, sc->rec_page_start); ! 849: ! 850: /* ! 851: * Clear all interrupts. A '1' in each bit position clears the ! 852: * corresponding flag. ! 853: */ ! 854: outb(sc->nic_addr + ED_P0_ISR, 0xff); ! 855: ! 856: /* ! 857: * Enable the following interrupts: receive/transmit complete, ! 858: * receive/transmit error, and Receiver OverWrite. ! 859: * ! 860: * Counter overflow and Remote DMA complete are *not* enabled. ! 861: */ ! 862: outb(sc->nic_addr + ED_P0_IMR, ! 863: ED_IMR_PRXE|ED_IMR_PTXE|ED_IMR_RXEE|ED_IMR_TXEE|ED_IMR_OVWE); ! 864: ! 865: /* ! 866: * Program Command Register for page 1 ! 867: */ ! 868: outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STP); ! 869: ! 870: /* ! 871: * Copy out our station address ! 872: */ ! 873: for (i = 0; i < ETHER_ADDR_LEN; ++i) ! 874: outb(sc->nic_addr + ED_P1_PAR0 + i, sc->arpcom.ac_enaddr[i]); ! 875: ! 876: #if NBPFILTER > 0 ! 877: /* ! 878: * Initialize multicast address hashing registers to accept ! 879: * all multicasts (only used when in promiscuous mode) ! 880: */ ! 881: for (i = 0; i < 8; ++i) ! 882: outb(sc->nic_addr + ED_P1_MAR0 + i, 0xff); ! 883: #endif ! 884: ! 885: /* ! 886: * Set Current Page pointer to next_packet (initialized above) ! 887: */ ! 888: outb(sc->nic_addr + ED_P1_CURR, sc->next_packet); ! 889: ! 890: /* ! 891: * Set Command Register for page 0, Remote DMA complete, ! 892: * and interface Start. ! 893: */ ! 894: outb(sc->nic_addr + ED_P1_CR, ED_CR_RD2|ED_CR_STA); ! 895: ! 896: /* ! 897: * Take interface out of loopback ! 898: */ ! 899: outb(sc->nic_addr + ED_P0_TCR, 0); ! 900: ! 901: /* ! 902: * If this is a 3Com board, the tranceiver must be software enabled ! 903: * (there is no settable hardware default). ! 904: */ ! 905: if (sc->vendor == ED_VENDOR_3COM) { ! 906: if (ifp->if_flags & IFF_LLC0) { ! 907: outb(sc->asic_addr + ED_3COM_CR, 0); ! 908: } else { ! 909: outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL); ! 910: } ! 911: } ! 912: ! 913: /* ! 914: * Set 'running' flag, and clear output active flag. ! 915: */ ! 916: ifp->if_flags |= IFF_RUNNING; ! 917: ifp->if_flags &= ~IFF_OACTIVE; ! 918: ! 919: /* ! 920: * ...and attempt to start output ! 921: */ ! 922: ed_start(ifp); ! 923: ! 924: (void) splx(s); ! 925: } ! 926: ! 927: /* ! 928: * This routine actually starts the transmission on the interface ! 929: */ ! 930: static inline void ed_xmit(ifp) ! 931: struct ifnet *ifp; ! 932: { ! 933: struct ed_softc *sc = &ed_softc[ifp->if_unit]; ! 934: u_short len = sc->txb_next_len; ! 935: ! 936: /* ! 937: * Set NIC for page 0 register access ! 938: */ ! 939: outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA); ! 940: ! 941: /* ! 942: * Set TX buffer start page ! 943: */ ! 944: outb(sc->nic_addr + ED_P0_TPSR, sc->tx_page_start + ! 945: sc->txb_next * ED_TXBUF_SIZE); ! 946: ! 947: /* ! 948: * Set TX length ! 949: */ ! 950: outb(sc->nic_addr + ED_P0_TBCR0, len & 0xff); ! 951: outb(sc->nic_addr + ED_P0_TBCR1, len >> 8); ! 952: ! 953: /* ! 954: * Set page 0, Remote DMA complete, Transmit Packet, and *Start* ! 955: */ ! 956: outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_TXP|ED_CR_STA); ! 957: ! 958: sc->xmit_busy = 1; ! 959: sc->data_buffered = 0; ! 960: ! 961: /* ! 962: * Switch buffers if we are doing double-buffered transmits ! 963: */ ! 964: if ((sc->txb_next == 0) && (sc->txb_cnt > 1)) ! 965: sc->txb_next = 1; ! 966: else ! 967: sc->txb_next = 0; ! 968: ! 969: /* ! 970: * Set a timer just in case we never hear from the board again ! 971: */ ! 972: ifp->if_timer = 2; ! 973: } ! 974: ! 975: /* ! 976: * Start output on interface. ! 977: * We make two assumptions here: ! 978: * 1) that the current priority is set to splnet _before_ this code ! 979: * is called *and* is returned to the appropriate priority after ! 980: * return ! 981: * 2) that the IFF_OACTIVE flag is checked before this code is called ! 982: * (i.e. that the output part of the interface is idle) ! 983: */ ! 984: int ! 985: ed_start(ifp) ! 986: struct ifnet *ifp; ! 987: { ! 988: struct ed_softc *sc = &ed_softc[ifp->if_unit]; ! 989: struct mbuf *m0, *m; ! 990: caddr_t buffer; ! 991: int len; ! 992: u_char laar_tmp; ! 993: ! 994: outloop: ! 995: /* ! 996: * See if there is room to send more data (i.e. one or both of the ! 997: * buffers is empty). ! 998: */ ! 999: if (sc->data_buffered) ! 1000: if (sc->xmit_busy) { ! 1001: /* ! 1002: * No room. Indicate this to the outside world ! 1003: * and exit. ! 1004: */ ! 1005: ifp->if_flags |= IFF_OACTIVE; ! 1006: return; ! 1007: } else { ! 1008: /* ! 1009: * Data is buffered, but we're not transmitting, so ! 1010: * start the xmit on the buffered data. ! 1011: * Note that ed_xmit() resets the data_buffered flag ! 1012: * before returning. ! 1013: */ ! 1014: ed_xmit(ifp); ! 1015: } ! 1016: ! 1017: IF_DEQUEUE(&sc->arpcom.ac_if.if_snd, m); ! 1018: if (m == 0) { ! 1019: /* ! 1020: * The following isn't pretty; we are using the !OACTIVE flag to ! 1021: * indicate to the outside world that we can accept an additional ! 1022: * packet rather than that the transmitter is _actually_ ! 1023: * active. Indeed, the transmitter may be active, but if we haven't ! 1024: * filled the secondary buffer with data then we still want to ! 1025: * accept more. ! 1026: * Note that it isn't necessary to test the data_buffered flag - ! 1027: * we wouldn't have tried to de-queue the packet in the first place ! 1028: * if it was set. ! 1029: */ ! 1030: ifp->if_flags &= ~IFF_OACTIVE; ! 1031: return; ! 1032: } ! 1033: ! 1034: /* ! 1035: * Copy the mbuf chain into the transmit buffer ! 1036: */ ! 1037: /* ! 1038: * Enable 16bit access to shared memory on WD/SMC boards ! 1039: */ ! 1040: if (sc->memwidth == 16) ! 1041: if (sc->vendor == ED_VENDOR_WD_SMC) { ! 1042: laar_tmp = inb(sc->asic_addr + ED_WD_LAAR); ! 1043: outb(sc->asic_addr + ED_WD_LAAR, laar_tmp | ED_WD_LAAR_M16EN); ! 1044: } ! 1045: ! 1046: buffer = sc->smem_start + (sc->txb_next * ED_TXBUF_SIZE * ED_PAGE_SIZE); ! 1047: len = 0; ! 1048: for (m0 = m; m != 0; m = m->m_next) { ! 1049: bcopy(mtod(m, caddr_t), buffer, m->m_len); ! 1050: buffer += m->m_len; ! 1051: len += m->m_len; ! 1052: } ! 1053: ! 1054: /* ! 1055: * Restore previous shared mem access type ! 1056: */ ! 1057: if (sc->memwidth == 16) ! 1058: if (sc->vendor == ED_VENDOR_WD_SMC) { ! 1059: outb(sc->asic_addr + ED_WD_LAAR, laar_tmp); ! 1060: } ! 1061: ! 1062: sc->txb_next_len = MAX(len, ETHER_MIN_LEN); ! 1063: ! 1064: if (sc->txb_cnt > 1) ! 1065: /* ! 1066: * only set 'buffered' flag if doing multiple buffers ! 1067: */ ! 1068: sc->data_buffered = 1; ! 1069: ! 1070: if (sc->xmit_busy == 0) ! 1071: ed_xmit(ifp); ! 1072: /* ! 1073: * If there is BPF support in the configuration, tap off here. ! 1074: * The following has support for converting trailer packets ! 1075: * back to normal. ! 1076: */ ! 1077: #if NBPFILTER > 0 ! 1078: if (sc->bpf) { ! 1079: u_short etype; ! 1080: int off, datasize, resid; ! 1081: struct ether_header *eh; ! 1082: struct trailer_header { ! 1083: u_short ether_type; ! 1084: u_short ether_residual; ! 1085: } trailer_header; ! 1086: char ether_packet[ETHER_MAX_LEN]; ! 1087: char *ep; ! 1088: ! 1089: ep = ether_packet; ! 1090: ! 1091: /* ! 1092: * We handle trailers below: ! 1093: * Copy ether header first, then residual data, ! 1094: * then data. Put all this in a temporary buffer ! 1095: * 'ether_packet' and send off to bpf. Since the ! 1096: * system has generated this packet, we assume ! 1097: * that all of the offsets in the packet are ! 1098: * correct; if they're not, the system will almost ! 1099: * certainly crash in m_copydata. ! 1100: * We make no assumptions about how the data is ! 1101: * arranged in the mbuf chain (i.e. how much ! 1102: * data is in each mbuf, if mbuf clusters are ! 1103: * used, etc.), which is why we use m_copydata ! 1104: * to get the ether header rather than assume ! 1105: * that this is located in the first mbuf. ! 1106: */ ! 1107: /* copy ether header */ ! 1108: m_copydata(m0, 0, sizeof(struct ether_header), ep); ! 1109: eh = (struct ether_header *) ep; ! 1110: ep += sizeof(struct ether_header); ! 1111: etype = ntohs(eh->ether_type); ! 1112: if (etype >= ETHERTYPE_TRAIL && ! 1113: etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { ! 1114: datasize = ((etype - ETHERTYPE_TRAIL) << 9); ! 1115: off = datasize + sizeof(struct ether_header); ! 1116: ! 1117: /* copy trailer_header into a data structure */ ! 1118: m_copydata(m0, off, sizeof(struct trailer_header), ! 1119: &trailer_header.ether_type); ! 1120: ! 1121: /* copy residual data */ ! 1122: m_copydata(m0, off+sizeof(struct trailer_header), ! 1123: resid = ntohs(trailer_header.ether_residual) - ! 1124: sizeof(struct trailer_header), ep); ! 1125: ep += resid; ! 1126: ! 1127: /* copy data */ ! 1128: m_copydata(m0, sizeof(struct ether_header), ! 1129: datasize, ep); ! 1130: ep += datasize; ! 1131: ! 1132: /* restore original ether packet type */ ! 1133: eh->ether_type = trailer_header.ether_type; ! 1134: ! 1135: bpf_tap(sc->bpf, ether_packet, ep - ether_packet); ! 1136: } else ! 1137: bpf_mtap(sc->bpf, m0); ! 1138: } ! 1139: #endif ! 1140: ! 1141: m_freem(m0); ! 1142: ! 1143: /* ! 1144: * If we are doing double-buffering, a buffer might be free to ! 1145: * fill with another packet, so loop back to the top. ! 1146: */ ! 1147: if (sc->txb_cnt > 1) ! 1148: goto outloop; ! 1149: else { ! 1150: ifp->if_flags |= IFF_OACTIVE; ! 1151: return; ! 1152: } ! 1153: } ! 1154: ! 1155: /* ! 1156: * Ethernet interface receiver interrupt. ! 1157: */ ! 1158: static inline void /* only called from one place, so may as well integrate */ ! 1159: ed_rint(unit) ! 1160: int unit; ! 1161: { ! 1162: register struct ed_softc *sc = &ed_softc[unit]; ! 1163: u_char boundry, current; ! 1164: u_short len; ! 1165: struct ed_ring *packet_ptr; ! 1166: ! 1167: /* ! 1168: * Set NIC to page 1 registers to get 'current' pointer ! 1169: */ ! 1170: outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STA); ! 1171: ! 1172: /* ! 1173: * 'sc->next_packet' is the logical beginning of the ring-buffer - i.e. ! 1174: * it points to where new data has been buffered. The 'CURR' ! 1175: * (current) register points to the logical end of the ring-buffer ! 1176: * - i.e. it points to where additional new data will be added. ! 1177: * We loop here until the logical beginning equals the logical ! 1178: * end (or in other words, until the ring-buffer is empty). ! 1179: */ ! 1180: while (sc->next_packet != inb(sc->nic_addr + ED_P1_CURR)) { ! 1181: ! 1182: /* get pointer to this buffer header structure */ ! 1183: packet_ptr = (struct ed_ring *)(sc->smem_ring + ! 1184: (sc->next_packet - sc->rec_page_start) * ED_PAGE_SIZE); ! 1185: ! 1186: /* ! 1187: * The byte count includes the FCS - Frame Check Sequence (a ! 1188: * 32 bit CRC). ! 1189: */ ! 1190: len = packet_ptr->count; ! 1191: if ((len >= ETHER_MIN_LEN) && (len <= ETHER_MAX_LEN)) { ! 1192: /* ! 1193: * Go get packet. len - 4 removes CRC from length. ! 1194: * (packet_ptr + 1) points to data just after the packet ring ! 1195: * header (+4 bytes) ! 1196: */ ! 1197: ed_get_packet(sc, (caddr_t)(packet_ptr + 1), len - 4); ! 1198: ++sc->arpcom.ac_if.if_ipackets; ! 1199: } else { ! 1200: /* ! 1201: * Really BAD...probably indicates that the ring pointers ! 1202: * are corrupted. Also seen on early rev chips under ! 1203: * high load - the byte order of the length gets switched. ! 1204: */ ! 1205: log(LOG_ERR, ! 1206: "ed%d: shared memory corrupt - invalid packet length %d\n", ! 1207: unit, len); ! 1208: ed_reset(unit); ! 1209: return; ! 1210: } ! 1211: ! 1212: /* ! 1213: * Update next packet pointer ! 1214: */ ! 1215: sc->next_packet = packet_ptr->next_packet; ! 1216: ! 1217: /* ! 1218: * Update NIC boundry pointer - being careful to keep it ! 1219: * one buffer behind. (as recommended by NS databook) ! 1220: */ ! 1221: boundry = sc->next_packet - 1; ! 1222: if (boundry < sc->rec_page_start) ! 1223: boundry = sc->rec_page_stop - 1; ! 1224: ! 1225: /* ! 1226: * Set NIC to page 0 registers to update boundry register ! 1227: */ ! 1228: outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA); ! 1229: ! 1230: outb(sc->nic_addr + ED_P0_BNRY, boundry); ! 1231: ! 1232: /* ! 1233: * Set NIC to page 1 registers before looping to top (prepare to ! 1234: * get 'CURR' current pointer) ! 1235: */ ! 1236: outb(sc->nic_addr + ED_P0_CR, ED_CR_PAGE_1|ED_CR_RD2|ED_CR_STA); ! 1237: } ! 1238: } ! 1239: ! 1240: /* ! 1241: * Ethernet interface interrupt processor ! 1242: */ ! 1243: int ! 1244: edintr(unit) ! 1245: int unit; ! 1246: { ! 1247: struct ed_softc *sc = &ed_softc[unit]; ! 1248: u_char isr; ! 1249: ! 1250: /* ! 1251: * Set NIC to page 0 registers ! 1252: */ ! 1253: outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA); ! 1254: ! 1255: /* ! 1256: * loop until there are no more new interrupts ! 1257: */ ! 1258: while (isr = inb(sc->nic_addr + ED_P0_ISR)) { ! 1259: ! 1260: /* ! 1261: * reset all the bits that we are 'acknowleging' ! 1262: * by writing a '1' to each bit position that was set ! 1263: * (writing a '1' *clears* the bit) ! 1264: */ ! 1265: outb(sc->nic_addr + ED_P0_ISR, isr); ! 1266: ! 1267: /* ! 1268: * Transmit error. If a TX completed with an error, we end up ! 1269: * throwing the packet away. Really the only error that is ! 1270: * possible is excessive collisions, and in this case it is ! 1271: * best to allow the automatic mechanisms of TCP to backoff ! 1272: * the flow. Of course, with UDP we're screwed, but this is ! 1273: * expected when a network is heavily loaded. ! 1274: */ ! 1275: if (isr & ED_ISR_TXE) { ! 1276: u_char tsr = inb(sc->nic_addr + ED_P0_TSR); ! 1277: u_char ncr = inb(sc->nic_addr + ED_P0_NCR); ! 1278: ! 1279: /* ! 1280: * Excessive collisions (16) ! 1281: */ ! 1282: if ((tsr & ED_TSR_ABT) && (ncr == 0)) { ! 1283: /* ! 1284: * When collisions total 16, the P0_NCR will ! 1285: * indicate 0, and the TSR_ABT is set. ! 1286: */ ! 1287: sc->arpcom.ac_if.if_collisions += 16; ! 1288: } else ! 1289: sc->arpcom.ac_if.if_collisions += ncr; ! 1290: ! 1291: /* ! 1292: * update output errors counter ! 1293: */ ! 1294: ++sc->arpcom.ac_if.if_oerrors; ! 1295: ! 1296: /* ! 1297: * reset tx busy and output active flags ! 1298: */ ! 1299: sc->xmit_busy = 0; ! 1300: sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; ! 1301: ! 1302: /* ! 1303: * clear watchdog timer ! 1304: */ ! 1305: sc->arpcom.ac_if.if_timer = 0; ! 1306: } ! 1307: ! 1308: ! 1309: /* ! 1310: * Receiver Error. One or more of: CRC error, frame alignment error ! 1311: * FIFO overrun, or missed packet. ! 1312: */ ! 1313: if (isr & ED_ISR_RXE) { ! 1314: ++sc->arpcom.ac_if.if_ierrors; ! 1315: #ifdef ED_DEBUG ! 1316: printf("ed%d: receive error %x\n", unit, ! 1317: inb(sc->nic_addr + ED_P0_RSR)); ! 1318: #endif ! 1319: } ! 1320: ! 1321: /* ! 1322: * Overwrite warning. In order to make sure that a lockup ! 1323: * of the local DMA hasn't occurred, we reset and ! 1324: * re-init the NIC. The NSC manual suggests only a ! 1325: * partial reset/re-init is necessary - but some ! 1326: * chips seem to want more. The DMA lockup has been ! 1327: * seen only with early rev chips - Methinks this ! 1328: * bug was fixed in later revs. -DG ! 1329: */ ! 1330: if (isr & ED_ISR_OVW) { ! 1331: ++sc->arpcom.ac_if.if_ierrors; ! 1332: log(LOG_WARNING, ! 1333: "ed%d: warning - receiver ring buffer overrun\n", ! 1334: unit); ! 1335: /* ! 1336: * Stop/reset/re-init NIC ! 1337: */ ! 1338: ed_reset(unit); ! 1339: } ! 1340: ! 1341: /* ! 1342: * Transmission completed normally. ! 1343: */ ! 1344: if (isr & ED_ISR_PTX) { ! 1345: ! 1346: /* ! 1347: * reset tx busy and output active flags ! 1348: */ ! 1349: sc->xmit_busy = 0; ! 1350: sc->arpcom.ac_if.if_flags &= ~IFF_OACTIVE; ! 1351: ! 1352: /* ! 1353: * clear watchdog timer ! 1354: */ ! 1355: sc->arpcom.ac_if.if_timer = 0; ! 1356: ! 1357: /* ! 1358: * Update total number of successfully transmitted ! 1359: * packets. ! 1360: */ ! 1361: ++sc->arpcom.ac_if.if_opackets; ! 1362: ! 1363: /* ! 1364: * Add in total number of collisions on last ! 1365: * transmission. ! 1366: */ ! 1367: sc->arpcom.ac_if.if_collisions += inb(sc->nic_addr + ! 1368: ED_P0_TBCR0); ! 1369: } ! 1370: ! 1371: /* ! 1372: * Receive Completion. Go and get the packet. ! 1373: * XXX - Doing this on an error is dubious because there ! 1374: * shouldn't be any data to get (we've configured the ! 1375: * interface to not accept packets with errors). ! 1376: */ ! 1377: if (isr & (ED_ISR_PRX|ED_ISR_RXE)) { ! 1378: /* ! 1379: * Enable access to shared memory on WD/SMC boards ! 1380: */ ! 1381: if (sc->memwidth == 16) ! 1382: if (sc->vendor == ED_VENDOR_WD_SMC) { ! 1383: outb(sc->asic_addr + ED_WD_LAAR, ! 1384: inb(sc->asic_addr + ED_WD_LAAR) ! 1385: | ED_WD_LAAR_M16EN); ! 1386: } ! 1387: ! 1388: ed_rint (unit); ! 1389: ! 1390: /* ! 1391: * Disable access to shared memory ! 1392: */ ! 1393: if (sc->memwidth == 16) ! 1394: if (sc->vendor == ED_VENDOR_WD_SMC) { ! 1395: outb(sc->asic_addr + ED_WD_LAAR, ! 1396: inb(sc->asic_addr + ED_WD_LAAR) ! 1397: & ~ED_WD_LAAR_M16EN); ! 1398: } ! 1399: } ! 1400: ! 1401: /* ! 1402: * If it looks like the transmitter can take more data, ! 1403: * attempt to start output on the interface. If data is ! 1404: * already buffered and ready to go, send it first. ! 1405: */ ! 1406: if ((sc->arpcom.ac_if.if_flags & IFF_OACTIVE) == 0) { ! 1407: if (sc->data_buffered) ! 1408: ed_xmit(&sc->arpcom.ac_if); ! 1409: ed_start(&sc->arpcom.ac_if); ! 1410: } ! 1411: ! 1412: /* ! 1413: * return NIC CR to standard state: page 0, remote DMA complete, ! 1414: * start (toggling the TXP bit off, even if was just set ! 1415: * in the transmit routine, is *okay* - it is 'edge' ! 1416: * triggered from low to high) ! 1417: */ ! 1418: outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2|ED_CR_STA); ! 1419: ! 1420: /* ! 1421: * If the Network Talley Counters overflow, read them to ! 1422: * reset them. It appears that old 8390's won't ! 1423: * clear the ISR flag otherwise - resulting in an ! 1424: * infinite loop. ! 1425: */ ! 1426: if (isr & ED_ISR_CNT) { ! 1427: (void) inb(sc->nic_addr + ED_P0_CNTR0); ! 1428: (void) inb(sc->nic_addr + ED_P0_CNTR1); ! 1429: (void) inb(sc->nic_addr + ED_P0_CNTR2); ! 1430: } ! 1431: } ! 1432: } ! 1433: ! 1434: /* ! 1435: * Process an ioctl request. This code needs some work - it looks ! 1436: * pretty ugly. ! 1437: */ ! 1438: int ! 1439: ed_ioctl(ifp, command, data) ! 1440: register struct ifnet *ifp; ! 1441: int command; ! 1442: caddr_t data; ! 1443: { ! 1444: register struct ifaddr *ifa = (struct ifaddr *)data; ! 1445: struct ed_softc *sc = &ed_softc[ifp->if_unit]; ! 1446: struct ifreq *ifr = (struct ifreq *)data; ! 1447: int s, error = 0; ! 1448: ! 1449: s = splnet(); ! 1450: ! 1451: switch (command) { ! 1452: ! 1453: case SIOCSIFADDR: ! 1454: ifp->if_flags |= IFF_UP; ! 1455: ! 1456: switch (ifa->ifa_addr->sa_family) { ! 1457: #ifdef INET ! 1458: case AF_INET: ! 1459: ed_init(ifp->if_unit); /* before arpwhohas */ ! 1460: /* ! 1461: * See if another station has *our* IP address. ! 1462: * i.e.: There is an address conflict! If a ! 1463: * conflict exists, a message is sent to the ! 1464: * console. ! 1465: */ ! 1466: ((struct arpcom *)ifp)->ac_ipaddr = ! 1467: IA_SIN(ifa)->sin_addr; ! 1468: arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); ! 1469: break; ! 1470: #endif ! 1471: #ifdef NS ! 1472: /* ! 1473: * XXX - This code is probably wrong ! 1474: */ ! 1475: case AF_NS: ! 1476: { ! 1477: register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); ! 1478: ! 1479: if (ns_nullhost(*ina)) ! 1480: ina->x_host = ! 1481: *(union ns_host *)(sc->arpcom.ac_enaddr); ! 1482: else { ! 1483: /* ! 1484: * ! 1485: */ ! 1486: bcopy((caddr_t)ina->x_host.c_host, ! 1487: (caddr_t)sc->arpcom.ac_enaddr, ! 1488: sizeof(sc->arpcom.ac_enaddr)); ! 1489: } ! 1490: /* ! 1491: * Set new address ! 1492: */ ! 1493: ed_init(ifp->if_unit); ! 1494: break; ! 1495: } ! 1496: #endif ! 1497: default: ! 1498: ed_init(ifp->if_unit); ! 1499: break; ! 1500: } ! 1501: break; ! 1502: ! 1503: case SIOCSIFFLAGS: ! 1504: /* ! 1505: * If interface is marked down and it is running, then stop it ! 1506: */ ! 1507: if (((ifp->if_flags & IFF_UP) == 0) && ! 1508: (ifp->if_flags & IFF_RUNNING)) { ! 1509: ed_stop(ifp->if_unit); ! 1510: ifp->if_flags &= ~IFF_RUNNING; ! 1511: } else { ! 1512: /* ! 1513: * If interface is marked up and it is stopped, then start it ! 1514: */ ! 1515: if ((ifp->if_flags & IFF_UP) && ! 1516: ((ifp->if_flags & IFF_RUNNING) == 0)) ! 1517: ed_init(ifp->if_unit); ! 1518: } ! 1519: #if NBPFILTER > 0 ! 1520: if (ifp->if_flags & IFF_PROMISC) { ! 1521: /* ! 1522: * Set promiscuous mode on interface. ! 1523: * XXX - for multicasts to work, we would need to ! 1524: * write 1's in all bits of multicast ! 1525: * hashing array. For now we assume that ! 1526: * this was done in ed_init(). ! 1527: */ ! 1528: outb(sc->nic_addr + ED_P0_RCR, ! 1529: ED_RCR_PRO|ED_RCR_AM|ED_RCR_AB); ! 1530: } else { ! 1531: /* ! 1532: * XXX - for multicasts to work, we would need to ! 1533: * rewrite the multicast hashing array with the ! 1534: * proper hash (would have been destroyed above). ! 1535: */ ! 1536: outb(sc->nic_addr + ED_P0_RCR, ED_RCR_AB); ! 1537: } ! 1538: #endif ! 1539: /* ! 1540: * An unfortunate hack to provide the (required) software control ! 1541: * of the tranceiver for 3Com boards. The LLC0 flag disables ! 1542: * the tranceiver if set. ! 1543: */ ! 1544: if (sc->vendor == ED_VENDOR_3COM) { ! 1545: if (ifp->if_flags & IFF_LLC0) { ! 1546: outb(sc->asic_addr + ED_3COM_CR, 0); ! 1547: } else { ! 1548: outb(sc->asic_addr + ED_3COM_CR, ED_3COM_CR_XSEL); ! 1549: } ! 1550: } ! 1551: ! 1552: break; ! 1553: ! 1554: default: ! 1555: error = EINVAL; ! 1556: } ! 1557: (void) splx(s); ! 1558: return (error); ! 1559: } ! 1560: ! 1561: /* ! 1562: * Macro to calculate a new address within shared memory when given an offset ! 1563: * from an address, taking into account ring-wrap. ! 1564: */ ! 1565: #define ringoffset(sc, start, off, type) \ ! 1566: ((type)( ((caddr_t)(start)+(off) >= (sc)->smem_end) ? \ ! 1567: (((caddr_t)(start)+(off))) - (sc)->smem_end \ ! 1568: + (sc)->smem_ring: \ ! 1569: ((caddr_t)(start)+(off)) )) ! 1570: ! 1571: /* ! 1572: * Retreive packet from shared memory and send to the next level up via ! 1573: * ether_input(). If there is a BPF listener, give a copy to BPF, too. ! 1574: */ ! 1575: ed_get_packet(sc, buf, len) ! 1576: struct ed_softc *sc; ! 1577: char *buf; ! 1578: u_short len; ! 1579: { ! 1580: struct ether_header *eh; ! 1581: struct mbuf *m, *head, *ed_ring_to_mbuf(); ! 1582: u_short off; ! 1583: int resid; ! 1584: u_short etype; ! 1585: struct trailer_header { ! 1586: u_short trail_type; ! 1587: u_short trail_residual; ! 1588: } trailer_header; ! 1589: ! 1590: /* Allocate a header mbuf */ ! 1591: MGETHDR(m, M_DONTWAIT, MT_DATA); ! 1592: if (m == 0) ! 1593: goto bad; ! 1594: m->m_pkthdr.rcvif = &sc->arpcom.ac_if; ! 1595: m->m_pkthdr.len = len; ! 1596: m->m_len = 0; ! 1597: head = m; ! 1598: ! 1599: eh = (struct ether_header *)buf; ! 1600: ! 1601: /* The following sillines is to make NFS happy */ ! 1602: #define EROUND ((sizeof(struct ether_header) + 3) & ~3) ! 1603: #define EOFF (EROUND - sizeof(struct ether_header)) ! 1604: ! 1605: /* ! 1606: * The following assumes there is room for ! 1607: * the ether header in the header mbuf ! 1608: */ ! 1609: head->m_data += EOFF; ! 1610: bcopy(buf, mtod(head, caddr_t), sizeof(struct ether_header)); ! 1611: buf += sizeof(struct ether_header); ! 1612: head->m_len += sizeof(struct ether_header); ! 1613: len -= sizeof(struct ether_header); ! 1614: ! 1615: etype = ntohs((u_short)eh->ether_type); ! 1616: ! 1617: /* ! 1618: * Deal with trailer protocol: ! 1619: * If trailer protocol, calculate the datasize as 'off', ! 1620: * which is also the offset to the trailer header. ! 1621: * Set resid to the amount of packet data following the ! 1622: * trailer header. ! 1623: * Finally, copy residual data into mbuf chain. ! 1624: */ ! 1625: if (etype >= ETHERTYPE_TRAIL && ! 1626: etype < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER) { ! 1627: ! 1628: off = (etype - ETHERTYPE_TRAIL) << 9; ! 1629: if ((off + sizeof(struct trailer_header)) > len) ! 1630: goto bad; /* insanity */ ! 1631: ! 1632: eh->ether_type = *ringoffset(sc, buf, off, u_short *); ! 1633: resid = ntohs(*ringoffset(sc, buf, off+2, u_short *)); ! 1634: ! 1635: if ((off + resid) > len) goto bad; /* insanity */ ! 1636: ! 1637: resid -= sizeof(struct trailer_header); ! 1638: if (resid < 0) goto bad; /* insanity */ ! 1639: ! 1640: m = ed_ring_to_mbuf(sc, ringoffset(sc, buf, off+4, char *), head, resid); ! 1641: if (m == 0) goto bad; ! 1642: ! 1643: len = off; ! 1644: head->m_pkthdr.len -= 4; /* subtract trailer header */ ! 1645: } ! 1646: ! 1647: /* ! 1648: * Pull packet off interface. Or if this was a trailer packet, ! 1649: * the data portion is appended. ! 1650: */ ! 1651: m = ed_ring_to_mbuf(sc, buf, m, len); ! 1652: if (m == 0) goto bad; ! 1653: ! 1654: #if NBPFILTER > 0 ! 1655: /* ! 1656: * Check if there's a BPF listener on this interface. ! 1657: * If so, hand off the raw packet to bpf. ! 1658: */ ! 1659: if (sc->bpf) { ! 1660: bpf_mtap(sc->bpf, head); ! 1661: ! 1662: /* ! 1663: * Note that the interface cannot be in promiscuous mode if ! 1664: * there are no BPF listeners. And if we are in promiscuous ! 1665: * mode, we have to check if this packet is really ours. ! 1666: * ! 1667: * XXX This test does not support multicasts. ! 1668: */ ! 1669: if ((sc->arpcom.ac_if.if_flags & IFF_PROMISC) && ! 1670: bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr, ! 1671: sizeof(eh->ether_dhost)) != 0 && ! 1672: bcmp(eh->ether_dhost, etherbroadcastaddr, ! 1673: sizeof(eh->ether_dhost)) != 0) { ! 1674: ! 1675: m_freem(head); ! 1676: return; ! 1677: } ! 1678: } ! 1679: #endif ! 1680: ! 1681: /* ! 1682: * Fix up data start offset in mbuf to point past ether header ! 1683: */ ! 1684: m_adj(head, sizeof(struct ether_header)); ! 1685: ! 1686: /* ! 1687: * silly ether_input routine needs 'type' in host byte order ! 1688: */ ! 1689: eh->ether_type = ntohs(eh->ether_type); ! 1690: ! 1691: ether_input(&sc->arpcom.ac_if, eh, head); ! 1692: return; ! 1693: ! 1694: bad: if (head) ! 1695: m_freem(head); ! 1696: return; ! 1697: } ! 1698: ! 1699: /* ! 1700: * Supporting routines ! 1701: */ ! 1702: ! 1703: /* ! 1704: * Given a source and destination address, copy 'amount' of a packet from ! 1705: * the ring buffer into a linear destination buffer. Takes into account ! 1706: * ring-wrap. ! 1707: */ ! 1708: static inline char * ! 1709: ed_ring_copy(sc,src,dst,amount) ! 1710: struct ed_softc *sc; ! 1711: char *src; ! 1712: char *dst; ! 1713: u_short amount; ! 1714: { ! 1715: u_short tmp_amount; ! 1716: ! 1717: /* does copy wrap to lower addr in ring buffer? */ ! 1718: if (src + amount > sc->smem_end) { ! 1719: tmp_amount = sc->smem_end - src; ! 1720: bcopy(src,dst,tmp_amount); /* copy amount up to end of smem */ ! 1721: amount -= tmp_amount; ! 1722: src = sc->smem_ring; ! 1723: dst += tmp_amount; ! 1724: } ! 1725: ! 1726: bcopy(src, dst, amount); ! 1727: ! 1728: return(src + amount); ! 1729: } ! 1730: ! 1731: /* ! 1732: * Copy data from receive buffer to end of mbuf chain ! 1733: * allocate additional mbufs as needed. return pointer ! 1734: * to last mbuf in chain. ! 1735: * sc = ed info (softc) ! 1736: * src = pointer in ed ring buffer ! 1737: * dst = pointer to last mbuf in mbuf chain to copy to ! 1738: * amount = amount of data to copy ! 1739: */ ! 1740: struct mbuf * ! 1741: ed_ring_to_mbuf(sc,src,dst,total_len) ! 1742: struct ed_softc *sc; ! 1743: char *src; ! 1744: struct mbuf *dst; ! 1745: u_short total_len; ! 1746: { ! 1747: register struct mbuf *m = dst; ! 1748: ! 1749: while (total_len) { ! 1750: register u_short amount = min(total_len, M_TRAILINGSPACE(m)); ! 1751: ! 1752: if (amount == 0) { /* no more data in this mbuf, alloc another */ ! 1753: /* ! 1754: * If there is enough data for an mbuf cluster, attempt ! 1755: * to allocate one of those, otherwise, a regular ! 1756: * mbuf will do. ! 1757: * Note that a regular mbuf is always required, even if ! 1758: * we get a cluster - getting a cluster does not ! 1759: * allocate any mbufs, and one is needed to assign ! 1760: * the cluster to. The mbuf that has a cluster ! 1761: * extension can not be used to contain data - only ! 1762: * the cluster can contain data. ! 1763: */ ! 1764: dst = m; ! 1765: MGET(m, M_DONTWAIT, MT_DATA); ! 1766: if (m == 0) ! 1767: return (0); ! 1768: ! 1769: if (total_len >= MINCLSIZE) ! 1770: MCLGET(m, M_DONTWAIT); ! 1771: ! 1772: m->m_len = 0; ! 1773: dst->m_next = m; ! 1774: amount = min(total_len, M_TRAILINGSPACE(m)); ! 1775: } ! 1776: ! 1777: src = ed_ring_copy(sc, src, mtod(m, caddr_t) + m->m_len, amount); ! 1778: ! 1779: m->m_len += amount; ! 1780: total_len -= amount; ! 1781: ! 1782: } ! 1783: return (m); ! 1784: } ! 1785: #endif ! 1786:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.