|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1994 Shantanu Goel ! 3: * All Rights Reserved. ! 4: * ! 5: * Permission to use, copy, modify and distribute this software and its ! 6: * documentation is hereby granted, provided that both the copyright ! 7: * notice and this permission notice appear in all copies of the ! 8: * software, derivative works or modified versions, and any portions ! 9: * thereof, and that both notices appear in supporting documentation. ! 10: * ! 11: * THE AUTHOR ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 12: * CONDITION. THE AUTHOR DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 13: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 14: */ ! 15: ! 16: /* ! 17: * Written 1992,1993 by Donald Becker. ! 18: * ! 19: * Copyright 1993 United States Government as represented by the ! 20: * Director, National Security Agency. This software may be used and ! 21: * distributed according to the terms of the GNU Public License, ! 22: * incorporated herein by reference. ! 23: * ! 24: * The Author may be reached as [email protected] or ! 25: * C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715 ! 26: */ ! 27: ! 28: #include <ul.h> ! 29: #include <wd.h> ! 30: #include <hpp.h> ! 31: #if NUL > 0 || NWD > 0 || NHPP > 0 ! 32: /* ! 33: * Generic NS8390 routines. ! 34: * Derived from the Linux driver by Donald Becker. ! 35: * ! 36: * Shantanu Goel ([email protected]) ! 37: */ ! 38: #include <sys/types.h> ! 39: #include <device/device_types.h> ! 40: #include <device/errno.h> ! 41: #include <device/io_req.h> ! 42: #include <device/if_hdr.h> ! 43: #include <device/if_ether.h> ! 44: #include <device/net_status.h> ! 45: #include <device/net_io.h> ! 46: #include <chips/busses.h> ! 47: #include <i386/machspl.h> ! 48: #include <i386/pio.h> ! 49: #include <i386at/gpl/if_nsreg.h> ! 50: ! 51: #define IO_DELAY __asm__ __volatile__ ("outb %al,$0x80") ! 52: #define outb_p(p, v) { outb(p, v); IO_DELAY; } ! 53: #define inb_p(p) ({ unsigned char _v; _v = inb(p); IO_DELAY; _v; }) ! 54: ! 55: #define NSDEBUG ! 56: #ifdef NSDEBUG ! 57: int nsdebug = 0; ! 58: #define DEBUGF(stmt) { if (nsdebug) stmt; } ! 59: #else ! 60: #define DEBUGF(stmt) ! 61: #endif ! 62: ! 63: void nsxint(struct nssoftc *); ! 64: void nsrint(struct nssoftc *); ! 65: void nsxmit(struct nssoftc *, unsigned, int); ! 66: void nsrxoverrun(struct nssoftc *); ! 67: ! 68: /* ! 69: * Initialize the NIC. ! 70: * Must be called at splimp(). ! 71: */ ! 72: void ! 73: nsinit(sc) ! 74: struct nssoftc *sc; ! 75: { ! 76: int port = sc->sc_port, i, rxconfig; ! 77: int endcfg = sc->sc_word16 ? (0x48 | ENDCFG_WTS) : 0x48; ! 78: struct ifnet *ifp = &sc->sc_if; ! 79: ! 80: /* ! 81: * Reset the board. ! 82: */ ! 83: (*sc->sc_reset)(sc); ! 84: ! 85: sc->sc_oactive = 0; ! 86: sc->sc_txing = 0; ! 87: sc->sc_timer = 0; ! 88: sc->sc_tx1 = sc->sc_tx2 = 0; ! 89: sc->sc_curpg = sc->sc_rxstrtpg; ! 90: ! 91: /* ! 92: * Follow National Semiconductor's recommendations for ! 93: * initializing the DP83902. ! 94: */ ! 95: outb_p(port, E8390_NODMA+E8390_PAGE0+E8390_STOP); /* 0x21 */ ! 96: outb_p(port + EN0_DCFG, endcfg); /* 0x48 or 0x49 */ ! 97: ! 98: /* ! 99: * Clear remote byte count registers. ! 100: */ ! 101: outb_p(port + EN0_RCNTLO, 0); ! 102: outb_p(port + EN0_RCNTHI, 0); ! 103: ! 104: /* ! 105: * Set to monitor and loopback mode -- this is vital! ! 106: */ ! 107: outb_p(port + EN0_RXCR, E8390_RXOFF); /* 0x20 */ ! 108: outb_p(port + EN0_TXCR, E8390_TXOFF); /* 0x02 */ ! 109: ! 110: /* ! 111: * Set transmit page and receive ring. ! 112: */ ! 113: outb_p(port + EN0_TPSR, sc->sc_txstrtpg); ! 114: outb_p(port + EN0_STARTPG, sc->sc_rxstrtpg); ! 115: outb_p(port + EN0_BOUNDARY, sc->sc_stoppg - 1); ! 116: outb_p(port + EN0_STOPPG, sc->sc_stoppg); ! 117: ! 118: /* ! 119: * Clear pending interrupts and mask. ! 120: */ ! 121: outb_p(port + EN0_ISR, 0xff); ! 122: ! 123: /* ! 124: * Enable the following interrupts: receive/transmit complete, ! 125: * receive/transmit error, and Receiver OverWrite. ! 126: * ! 127: * Counter overflow and Remote DMA complete are *not* enabled. ! 128: */ ! 129: outb_p(port + EN0_IMR, ENISR_RX | ENISR_TX | ENISR_RX_ERR | ! 130: ENISR_TX_ERR | ENISR_OVER ); ! 131: ! 132: /* ! 133: * Copy station address into 8390 registers. ! 134: */ ! 135: outb_p(port, E8390_NODMA + E8390_PAGE1 + E8390_STOP); /* 0x61 */ ! 136: for (i = 0; i < ETHER_ADDR_LEN; i++) ! 137: outb_p(port + EN1_PHYS + i, sc->sc_addr[i]); ! 138: ! 139: /* ! 140: * Set up to accept all multicast packets. ! 141: */ ! 142: for (i = 0; i < 8; i++) ! 143: outb_p(port + EN1_MULT + i, 0xff); ! 144: ! 145: /* ! 146: * Initialize CURRent pointer ! 147: */ ! 148: outb_p(port + EN1_CURPAG, sc->sc_rxstrtpg); ! 149: ! 150: /* ! 151: * Program command register for page 0. ! 152: */ ! 153: outb_p(port, E8390_NODMA + E8390_PAGE0 + E8390_STOP); ! 154: ! 155: #if 0 ! 156: outb_p(port + EN0_ISR, 0xff); ! 157: outb_p(port + EN0_IMR, ENISR_ALL); ! 158: #endif ! 159: ! 160: outb_p(port + E8390_CMD, E8390_NODMA + E8390_PAGE0 + E8390_START); ! 161: outb_p(port + EN0_TXCR, E8390_TXCONFIG); /* xmit on */ ! 162: ! 163: /* 3c503 TechMan says rxconfig only after the NIC is started. */ ! 164: rxconfig = E8390_RXCONFIG; ! 165: if (ifp->if_flags & IFF_ALLMULTI) ! 166: rxconfig |= 0x08; ! 167: if (ifp->if_flags & IFF_PROMISC) ! 168: rxconfig |= 0x10; ! 169: outb_p(port + EN0_RXCR, rxconfig); /* rx on */ ! 170: ! 171: /* ! 172: * Mark interface as up and start output. ! 173: */ ! 174: ifp->if_flags |= IFF_RUNNING; ! 175: nsstart(sc); ! 176: } ! 177: ! 178: /* ! 179: * Start output on interface. ! 180: * Must be called at splimp(). ! 181: */ ! 182: void ! 183: nsstart(sc) ! 184: struct nssoftc *sc; ! 185: { ! 186: io_req_t ior; ! 187: struct ifnet *ifp = &sc->sc_if; ! 188: ! 189: /* ! 190: * Drop packets if interface is down. ! 191: */ ! 192: if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { ! 193: while (1) { ! 194: IF_DEQUEUE(&ifp->if_snd, ior); ! 195: if (ior == 0) ! 196: return; ! 197: iodone(ior); ! 198: } ! 199: } ! 200: /* ! 201: * If transmitter is busy, bail out. ! 202: */ ! 203: if (sc->sc_oactive) ! 204: return; ! 205: ! 206: /* ! 207: * Dequeue a packet. ! 208: */ ! 209: IF_DEQUEUE(&ifp->if_snd, ior); ! 210: if (ior == 0) ! 211: return; ! 212: ! 213: /* Mask interrupts from the ethercard. */ ! 214: outb( sc->sc_port + EN0_IMR, 0x00); ! 215: ! 216: if (sc->sc_pingpong) { ! 217: int count, output_page; ! 218: ! 219: if (sc->sc_tx1 == 0) { ! 220: output_page = sc->sc_txstrtpg; ! 221: sc->sc_tx1 = count = (*sc->sc_output)(sc, ! 222: ior->io_count, ! 223: ior->io_data, ! 224: sc->sc_txstrtpg); ! 225: } else if (sc->sc_tx2 == 0) { ! 226: output_page = sc->sc_txstrtpg + 6; ! 227: sc->sc_tx2 = count = (*sc->sc_output)(sc, ! 228: ior->io_count, ! 229: ior->io_data, ! 230: output_page); ! 231: } else { ! 232: sc->sc_oactive = 1; ! 233: IF_PREPEND(&ifp->if_snd, ior); ! 234: return; ! 235: } ! 236: ! 237: DEBUGF({ ! 238: struct ether_header *eh; ! 239: ! 240: eh = (struct ether_header *)ior->io_data; ! 241: printf("send: %s%d: %x:%x:%x:%x:%x:%x, " ! 242: "olen %d, len %d\n", ! 243: sc->sc_name, sc->sc_unit, ! 244: eh->ether_dhost[0], eh->ether_dhost[1], ! 245: eh->ether_dhost[2], eh->ether_dhost[3], ! 246: eh->ether_dhost[4], eh->ether_dhost[5], ! 247: ior->io_count, count); ! 248: }); ! 249: ! 250: if (!sc->sc_txing) { ! 251: nsxmit(sc, count, output_page); ! 252: if (output_page == sc->sc_txstrtpg) ! 253: sc->sc_tx1 = -1, sc->sc_lasttx = -1; ! 254: else ! 255: sc->sc_tx2 = -1, sc->sc_lasttx = -2; ! 256: } ! 257: sc->sc_oactive = (sc->sc_tx1 && sc->sc_tx2); ! 258: } else { ! 259: int count; ! 260: ! 261: count = (*sc->sc_output)(sc, ior->io_count, ! 262: ior->io_data, sc->sc_txstrtpg); ! 263: ! 264: DEBUGF({ ! 265: struct ether_header *eh; ! 266: ! 267: eh = (struct ether_header *)ior->io_data; ! 268: printf("send: %s%d: %x:%x:%x:%x:%x:%x, " ! 269: "olen %d, len %d\n", ! 270: sc->sc_name, sc->sc_unit, ! 271: eh->ether_dhost[0], eh->ether_dhost[1], ! 272: eh->ether_dhost[2], eh->ether_dhost[3], ! 273: eh->ether_dhost[4], eh->ether_dhost[5], ! 274: ior->io_count, count); ! 275: }); ! 276: ! 277: nsxmit(sc, count, sc->sc_txstrtpg); ! 278: sc->sc_oactive = 1; ! 279: } ! 280: ! 281: /* reenable 8390 interrupts. */ ! 282: outb_p(sc->sc_port + EN0_IMR, ENISR_ALL); ! 283: ! 284: iodone(ior); ! 285: } ! 286: ! 287: /* ! 288: * Interrupt routine. ! 289: * Called by board level driver. ! 290: */ ! 291: void ! 292: nsintr(sc) ! 293: struct nssoftc *sc; ! 294: { ! 295: int port = sc->sc_port; ! 296: int interrupts, boguscount = 0; ! 297: struct ifnet *ifp = &sc->sc_if; ! 298: ! 299: if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) { ! 300: DEBUGF(printf("nsintr: %s%d: interface down\n", ! 301: sc->sc_name, sc->sc_unit)); ! 302: return; ! 303: } ! 304: ! 305: /* ! 306: * Change to page 0 and read intr status reg. ! 307: */ ! 308: outb_p(port + E8390_CMD, E8390_NODMA+E8390_PAGE0); ! 309: ! 310: while ((interrupts = inb_p(port + EN0_ISR)) != 0 && ++boguscount < 9) { ! 311: if (interrupts & ENISR_RDC) { ! 312: /* ! 313: * Ack meaningless DMA complete. ! 314: */ ! 315: outb_p(port + EN0_ISR, ENISR_RDC); ! 316: } ! 317: ! 318: if (interrupts & ENISR_OVER) ! 319: nsrxoverrun(sc); ! 320: else if (interrupts & (ENISR_RX+ENISR_RX_ERR)) { ! 321: nsrint(sc); ! 322: } ! 323: ! 324: if (interrupts & ENISR_TX) { ! 325: nsxint(sc); ! 326: } ! 327: else if (interrupts & ENISR_COUNTERS) { ! 328: /* ! 329: * XXX - We really should be storing statistics ! 330: * about the interface. For now we just drop them. ! 331: */ ! 332: ! 333: /* reading resets the counters! */ ! 334: (void) inb_p(port + EN0_COUNTER0); /* frame */ ! 335: (void) inb_p(port + EN0_COUNTER1); /* crc */ ! 336: (void) inb_p(port + EN0_COUNTER2); /* miss */ ! 337: ! 338: DEBUGF(printf("%s%d: acked counter interrupt.\n", ! 339: sc->sc_name, sc->sc_unit)); ! 340: ! 341: outb_p(port + EN0_ISR, ENISR_COUNTERS); /* ack intr */ ! 342: } ! 343: ! 344: if (interrupts & ENISR_TX_ERR) { ! 345: DEBUGF(printf("acking transmit error\n")); ! 346: outb_p(port + EN0_ISR, ENISR_TX_ERR); /* ack intr */ ! 347: } ! 348: ! 349: outb_p(port + E8390_CMD, E8390_NODMA+E8390_PAGE0+E8390_START); ! 350: } ! 351: ! 352: DEBUGF({ ! 353: if (interrupts) { ! 354: printf("%s%d: unknown interrupt 0x%x", ! 355: sc->sc_name, sc->sc_unit, interrupts); ! 356: outb_p(port + E8390_CMD, ! 357: E8390_NODMA+E8390_PAGE0+E8390_START); ! 358: outb_p(port + EN0_ISR, 0xff); /* ack all intrs */ ! 359: } ! 360: }) ! 361: } ! 362: ! 363: /* ! 364: * Process a transmit interrupt. ! 365: */ ! 366: void ! 367: nsxint(sc) ! 368: struct nssoftc *sc; ! 369: { ! 370: int port = sc->sc_port, status; ! 371: struct ifnet *ifp = &sc->sc_if; ! 372: ! 373: status = inb(port + EN0_TSR); ! 374: outb_p(port + EN0_ISR, ENISR_TX); /* ack intr */ ! 375: ! 376: sc->sc_txing = 0; ! 377: sc->sc_timer = 0; ! 378: sc->sc_oactive = 0; ! 379: ! 380: if (sc->sc_pingpong) { ! 381: if (sc->sc_tx1 < 0) { ! 382: if (sc->sc_lasttx != 1 && sc->sc_lasttx != -1) ! 383: printf("%s%d: bogus last_tx_buffer %d," ! 384: "tx1 = %d\n", ! 385: sc->sc_name, sc->sc_unit, ! 386: sc->sc_lasttx, sc->sc_tx1); ! 387: sc->sc_tx1 = 0; ! 388: if (sc->sc_tx2 > 0) { ! 389: nsxmit(sc, sc->sc_tx2, sc->sc_txstrtpg + 6); ! 390: sc->sc_tx2 = -1; ! 391: sc->sc_lasttx = 2; ! 392: } else ! 393: sc->sc_lasttx = 20; ! 394: } else if (sc->sc_tx2 < 0) { ! 395: if (sc->sc_lasttx != 2 && sc->sc_lasttx != -2) ! 396: printf("%s%d: bogus last_tx_buffer %d," ! 397: "tx2 = %d\n", ! 398: sc->sc_name, sc->sc_unit, ! 399: sc->sc_lasttx, sc->sc_tx2); ! 400: sc->sc_tx2 = 0; ! 401: if (sc->sc_tx1 > 0) { ! 402: nsxmit(sc, sc->sc_tx1, sc->sc_txstrtpg); ! 403: sc->sc_tx1 = -1; ! 404: sc->sc_lasttx = 1; ! 405: } else ! 406: sc->sc_lasttx = 10; ! 407: } else ! 408: printf("%s%d: unexpected TX-done interrupt, " ! 409: "lasttx = %d\n", ! 410: sc->sc_name, sc->sc_unit, sc->sc_lasttx); ! 411: } ! 412: /* ! 413: * Update stats. ! 414: */ ! 415: if (status & ENTSR_COL) { ! 416: if (status & ENTSR_ABT) ! 417: ifp->if_collisions += 16; ! 418: else ! 419: ifp->if_collisions += inb(port + EN0_NCR); ! 420: } ! 421: if (status & ENTSR_PTX) { ! 422: DEBUGF(printf("sent: %s%d\n", sc->sc_name, sc->sc_unit)); ! 423: ifp->if_opackets++; ! 424: } else ! 425: ifp->if_oerrors++; ! 426: ! 427: /* ! 428: * Start output on interface. ! 429: */ ! 430: nsstart(sc); ! 431: } ! 432: ! 433: /* ! 434: * Process a receive interrupt. ! 435: */ ! 436: void ! 437: nsrint(sc) ! 438: struct nssoftc *sc; ! 439: { ! 440: int port = sc->sc_port; ! 441: int rxing_page, this_frame, next_frame, current_offset; ! 442: int rx_pkt_count = 0; ! 443: int num_rx_pages = sc->sc_stoppg - sc->sc_rxstrtpg; ! 444: struct nspkthdr rx_frame; ! 445: struct ifnet *ifp = &sc->sc_if; ! 446: ! 447: while (++rx_pkt_count < 10) { ! 448: int pkt_len; ! 449: ! 450: /* ! 451: * Get the rx page (incoming packet pointer). ! 452: */ ! 453: outb_p(port + E8390_CMD, E8390_NODMA+E8390_PAGE1); ! 454: rxing_page = inb_p(port + EN1_CURPAG); ! 455: outb_p(port + E8390_CMD, E8390_NODMA+E8390_PAGE0); ! 456: ! 457: /* ! 458: * Remove one frame from the ring. ! 459: * Boundary is always a page behind. ! 460: */ ! 461: this_frame = inb_p(port + EN0_BOUNDARY) + 1; ! 462: if (this_frame >= sc->sc_stoppg) ! 463: this_frame = sc->sc_rxstrtpg; ! 464: ! 465: DEBUGF({ ! 466: if (this_frame != sc->sc_curpg) ! 467: printf("%s%d: mismatched read page pointers " ! 468: "%x vs %x\n", ! 469: sc->sc_name, sc->sc_unit, ! 470: this_frame, sc->sc_curpg); ! 471: }); ! 472: ! 473: if (this_frame == rxing_page) { ! 474: DEBUGF(printf("this_frame = rxing_page!\n")); ! 475: break; ! 476: } ! 477: ! 478: current_offset = this_frame << 8; ! 479: (*sc->sc_input)(sc, sizeof(rx_frame), (char *)&rx_frame, ! 480: current_offset); ! 481: ! 482: pkt_len = rx_frame.count - sizeof(rx_frame); ! 483: ! 484: next_frame = this_frame + 1 + ((pkt_len + 4) >> 8); ! 485: ! 486: if (rx_frame.next != next_frame ! 487: && rx_frame.next != next_frame + 1 ! 488: && rx_frame.next != next_frame - num_rx_pages ! 489: && rx_frame.next != next_frame + 1 - num_rx_pages) { ! 490: sc->sc_curpg = rxing_page; ! 491: outb(port + EN0_BOUNDARY, sc->sc_curpg - 1); ! 492: ifp->if_ierrors++; ! 493: DEBUGF(printf("INPUT ERROR?\n")); ! 494: continue; ! 495: } ! 496: if (pkt_len < 60 || pkt_len > 1518) { ! 497: ifp->if_ierrors++; ! 498: DEBUGF(printf("%s%d: bad packet length %d\n", ! 499: sc->sc_name, sc->sc_unit, pkt_len)); ! 500: } else if ((rx_frame.status & 0x0f) == ENRSR_RXOK) { ! 501: ipc_kmsg_t kmsg; ! 502: ! 503: kmsg = net_kmsg_get(); ! 504: if (kmsg == 0) { ! 505: DEBUGF(printf("%s%d: dropped packet\n", ! 506: sc->sc_name, sc->sc_unit)); ! 507: ifp->if_rcvdrops++; ! 508: } else { ! 509: int len, off; ! 510: struct ether_header *eh; ! 511: struct packet_header *pkt; ! 512: ! 513: ifp->if_ipackets++; ! 514: off = current_offset + sizeof(rx_frame); ! 515: eh = ((struct ether_header *) ! 516: (&net_kmsg(kmsg)->header[0])); ! 517: (*sc->sc_input)(sc, ! 518: sizeof(struct ether_header), ! 519: (char *)eh, off); ! 520: off += sizeof(struct ether_header); ! 521: len = pkt_len - sizeof(struct ether_header); ! 522: ! 523: DEBUGF(printf("rcv: %s%d: %x:%x:%x:%x:%x:%x, " ! 524: "len %d, type 0x%x\n", ! 525: sc->sc_name, sc->sc_unit, ! 526: eh->ether_shost[0], ! 527: eh->ether_shost[1], ! 528: eh->ether_shost[2], ! 529: eh->ether_shost[3], ! 530: eh->ether_shost[4], ! 531: eh->ether_shost[5], ! 532: len, eh->ether_type)); ! 533: ! 534: pkt = ((struct packet_header *) ! 535: (&net_kmsg(kmsg)->packet[0])); ! 536: (*sc->sc_input)(sc, len, (char *)(pkt+1), off); ! 537: pkt->type = eh->ether_type; ! 538: pkt->length = len+sizeof(struct packet_header); ! 539: net_packet(ifp, kmsg, pkt->length, ! 540: ethernet_priority(kmsg)); ! 541: } ! 542: } else { ! 543: DEBUGF(printf("%s%d: bogus packet: " ! 544: "status=0x%x nxpg=0x%x size=%d\n", ! 545: sc->sc_name, sc->sc_unit, ! 546: rx_frame.status, rx_frame.next, ! 547: rx_frame.count)); ! 548: ifp->if_ierrors++; ! 549: } ! 550: next_frame = rx_frame.next; ! 551: if (next_frame >= sc->sc_stoppg) { ! 552: DEBUGF(printf("%s%d: next frame inconsistency, 0x%x\n", ! 553: sc->sc_name, sc->sc_unit, next_frame)); ! 554: next_frame = sc->sc_rxstrtpg; ! 555: } ! 556: sc->sc_curpg = next_frame; ! 557: outb(port + EN0_BOUNDARY, next_frame - 1); ! 558: } ! 559: ! 560: /* ! 561: * Bug alert! Reset ENISR_OVER to avoid spurious overruns! ! 562: */ ! 563: outb_p(port + EN0_ISR, ENISR_RX+ENISR_RX_ERR+ENISR_OVER); ! 564: } ! 565: ! 566: /* ! 567: * Handle a receive overrun condition. ! 568: * ! 569: * XXX - this needs to be gone over in light of the NS documentation. ! 570: */ ! 571: void ! 572: nsrxoverrun(sc) ! 573: struct nssoftc *sc; ! 574: { ! 575: int port = sc->sc_port, i; ! 576: extern unsigned delaycount; ! 577: ! 578: printf("%s%d: receive overrun\n", sc->sc_name, sc->sc_unit); ! 579: ! 580: /* ! 581: * We should already be stopped and in page0, but just to be sure... ! 582: */ ! 583: outb_p(port + E8390_CMD, E8390_NODMA+E8390_PAGE0+E8390_STOP); ! 584: ! 585: /* ! 586: * Clear remote byte counter registers. ! 587: */ ! 588: outb_p(port + EN0_RCNTLO, 0); ! 589: outb_p(port + EN0_RCNTHI, 0); ! 590: ! 591: /* ! 592: * Wait for reset to complete. ! 593: */ ! 594: for (i = delaycount*2; i && !(inb_p(port+EN0_ISR) & ENISR_RESET); i--) ! 595: ; ! 596: if (i == 0) { ! 597: printf("%s%d: reset did not complete at overrun\n", ! 598: sc->sc_name, sc->sc_unit); ! 599: nsinit(sc); ! 600: return; ! 601: } ! 602: /* ! 603: * Disable transmitter. ! 604: */ ! 605: outb_p(port + EN0_TXCR, E8390_TXOFF); ! 606: ! 607: /* ! 608: * Remove packets. ! 609: */ ! 610: nsrint(sc); ! 611: ! 612: outb_p(port + EN0_ISR, 0xff); ! 613: outb_p(port + E8390_CMD, E8390_NODMA+E8390_PAGE0+E8390_START); ! 614: outb_p(port + EN0_TXCR, E8390_TXCONFIG); ! 615: } ! 616: ! 617: /* ! 618: * Trigger a transmit start. ! 619: */ ! 620: void ! 621: nsxmit(sc, length, start_page) ! 622: struct nssoftc *sc; ! 623: unsigned length; ! 624: int start_page; ! 625: { ! 626: int port = sc->sc_port; ! 627: ! 628: sc->sc_txing = 1; ! 629: outb_p(port, E8390_NODMA+E8390_PAGE0); ! 630: if (inb_p(port) & E8390_TRANS) { ! 631: printf("%s%d: nsxmit() called with the transmitter busy\n", ! 632: sc->sc_name, sc->sc_unit); ! 633: return; ! 634: } ! 635: outb_p(port + EN0_TCNTLO, length & 0xff); ! 636: outb_p(port + EN0_TCNTHI, (length >> 8) & 0xff); ! 637: outb_p(port + EN0_TPSR, start_page); ! 638: outb_p(port, E8390_NODMA+E8390_TRANS+E8390_START); ! 639: sc->sc_timer = 4; ! 640: } ! 641: ! 642: #endif /* NUL > 0 || NWD > 0 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.