|
|
1.1 ! root 1: /* STREAMS style driver for the DP8390 Ethernet interface */ ! 2: /* ! 3: * An interesting problem is how to manage the interface address binding, ! 4: * especially for upper protocols (specifically, the Internet ARP protocol) ! 5: * that need to advertise the physical host address, especially in the ! 6: * presence of multiple hardware adapters (or network types). ! 7: * ! 8: * For now, I am happy with having a specific version of ARP for each network ! 9: * type, and having ARP catch any M_PROTO SP_BIND messages going past. ! 10: */ ! 11: #include <sys/kernel.h> ! 12: #include <sys/dma.h> ! 13: #include <sys/stream.h> ! 14: #include <sys/strmlib.h> ! 15: #include <sys/strproto.h> ! 16: #include <sys/dp8390.h> ! 17: #include <sys/ether.h> ! 18: #include <sys/ints.h> ! 19: #include <sys/netstuff.h> ! 20: #include <string.h> ! 21: ! 22: /* ! 23: * Allow up to 8 minor devices connected to us - each one receives a copy of ! 24: * all incoming traffic, and each can place datagrams. ! 25: */ ! 26: #define MAXMINOR 8 ! 27: static queue_t * minortab[MAXMINOR]; ! 28: ! 29: #ifdef M68K ! 30: /* ! 31: * The 68070 uses memory mapped I/O exclusively, so treat the 8390 as a ! 32: * structure at a fixed location in memory. The header file also defines ! 33: * the padding of the structure on the 16-bit 68000 bus. ! 34: * ! 35: * We usually assign this to a local to put the base into an address ! 36: * register, which gets faster code than using the folded immediate address. ! 37: */ ! 38: #define DP8390 volatile dp8390 * ! 39: #define DP8390_BASE ((DP8390)(0x1FFC00 + PHYSICAL_SEG)) ! 40: #define DEVICE _device ! 41: #define DEVICE_REG DP8390 DEVICE = DP8390_BASE; ! 42: ! 43: #define input(dev, dp_reg) (dev)->dp_pg0rd.dp_reg ! 44: #define input1(dev, dp_reg) (dev)->dp_pg1rdwr.dp_reg ! 45: #define output(dev, dp_reg, val) (dev)->dp_pg0wr.dp_reg = val ! 46: #define output1(dev, dp_reg, val) (dev)->dp_pg1rdwr.dp_reg = val ! 47: #endif ! 48: ! 49: #ifdef IBMPC ! 50: /* ! 51: * The 8086 has special instructions for I/O, but if we treat the base ! 52: * address as a NEAR mode pointer (16-bit, current data segment) then cast ! 53: * it to a short for the I/O instructions, we'll have the right kind of ! 54: * effect. ! 55: * ! 56: * We DON'T assign the base to a local, since better code is produced by ! 57: * folding the constants and loading a new one into DX every I/O. ! 58: * ! 59: * Note that we emit a JMP $+2 just before the I/O instruction to waste a ! 60: * little time, as a NIC CS should not occur more often than 400ns. ! 61: */ ! 62: #define DP8390 dp8390 near * ! 63: #define DP8390_BASE ((DP8390)0x300) ! 64: #define DEVICE DP8390_BASE ! 65: #define DEVICE_REG ! 66: ! 67: #define _input(addr) (_DX=(UWORD)addr, __emit__ (0xEB, 0, 0xEB, 0, 0xEB, 0, 0xEB, 0, 0xEB, 0, 0xEC), _AL) ! 68: #define _output(addr,val) (_DX=(UWORD)addr, _AL = val, __emit__ (0xEB, 0, 0xEB, 0, 0xEB, 0, 0xEB, 0, 0xEB, 0, 0xEE)) ! 69: #define input(dev, dp_reg) _input (&(dev)->dp_pg0rd.dp_reg) ! 70: #define input1(dev, dp_reg) _input (&(dev)->dp_pg1rdwr.dp_reg) ! 71: #define output(dev, dp_reg, val) _output (&(dev)->dp_pg0wr.dp_reg,(val)) ! 72: #define output1(dev, dp_reg, val) _output (&(dev)->dp_pg1rdwr.dp_reg,(val)) ! 73: ! 74: ! 75: #define ETHER_IRQ 2 ! 76: ! 77: #endif ! 78: ! 79: ! 80: /* ! 81: * For scheduling remote DMA operations on the NIC, since there is only one ! 82: * channel on the NIC which is shared between remote read and remote write ! 83: * operations. Complicated since the TX buffer area is held until the NIC has ! 84: * actually completed the transmission, and because RX DMA may be halted in the ! 85: * middle of a packet due to STREAMS buffer depletion. ! 86: * ! 87: * Made a structure in the anticipation of one day having multiple interfaces. ! 88: */ ! 89: static struct ethcb { /* control block for a single interface */ ! 90: char tx_state; /* TX DMA in progress or TX DMA blocked */ ! 91: /* cleared when packet send completed */ ! 92: char rx_state; /* RX DMA in progress or waiting for buffers */ ! 93: char rx_pending; /* flag that RX packets for DMA are waiting */ ! 94: short rx_length; /* remaining length of RX packet */ ! 95: UWORD rx_base; /* NIC buffer address of RX DMA */ ! 96: mblk_t * rx_start; /* first mblk in RX packet */ ! 97: mblk_t * rx_current; /* current RX DMA buffer */ ! 98: short tx_length; /* length of packet being transmitted */ ! 99: ! 100: short tx_count; /* count packets sent */ ! 101: short rx_count; /* RX activity */ ! 102: ! 103: char tx_error; /* packet never ended transmission */ ! 104: short tx_lastcount; /* count at last timer tick */ ! 105: short rx_lastcount; /* count at last timre tick */ ! 106: ! 107: /* ! 108: * About write packet queueing - since this device effectively functions as a ! 109: * kind of multiplexor, flow control needs explicit attention. I use the ! 110: * general methods developed for the other multiplexing drivers (like TCP), ! 111: * namely the generic scheduler in my STREAMS implementation. ! 112: */ ! 113: /* schedule of driver queues that have output packets queued */ ! 114: struct schedule tx_sched; ! 115: ! 116: struct dp8390info dp8390info; ! 117: ! 118: /* useful addresses that we may wish to keep copies of */ ! 119: Eth_addr myaddr; /* our own address */ ! 120: ! 121: /* This flag gets set when the NIC tests OK */ ! 122: int netok; ! 123: ! 124: /* error counter extensions */ ! 125: int errcnt0, errcnt1, errcnt2; ! 126: } eth; ! 127: ! 128: ! 129: #define ETH LONG_TO_PTR (eth, struct ethcb *) ! 130: #define QETH ((struct ethcb *) q->q_ptr) ! 131: ! 132: /* ! 133: * Possible states for TX ! 134: */ ! 135: #define TX_IDLE 0 ! 136: #define TX_DMA 1 ! 137: #define TX_SEND 2 ! 138: /* ! 139: * Possible events for TX ! 140: */ ! 141: #define TXE_CRANK 0 ! 142: #define TXE_DMADONE 1 ! 143: #define TXE_SENDDONE 2 ! 144: ! 145: /* ! 146: * Possible states for RX. ! 147: * ! 148: * The two states RX_HALT and RX_BLOCKED distinguish whether or not to ! 149: * continue RX dma after a TX DMA or not. ! 150: */ ! 151: #define RX_IDLE 0 ! 152: #define RX_DMA 1 ! 153: #define RX_HALT 2 ! 154: #define RX_BLOCKED 3 ! 155: /* ! 156: * possible events for RX ! 157: */ ! 158: #define RXE_CRANK 0 ! 159: #define RXE_GOTMEM 1 ! 160: #define RXE_NOMEM 2 ! 161: #define RXE_DMADONE 3 ! 162: #define RXE_ALLDONE 4 ! 163: ! 164: /* ! 165: * To aid in detecting when the cable has been unplugged (which causes a ! 166: * constant collision state, so the backoff count doesn't get incremented). ! 167: */ ! 168: static P_TIMER eth_timer = NIL_TIMER; ! 169: ! 170: /* ! 171: * program the address into the address registers. ! 172: * Note : assumes that register set 1 has already been chosen! ! 173: */ ! 174: static void set_addr (int selpage) ! 175: { ! 176: DEVICE_REG ! 177: ! 178: if (selpage) ! 179: output (DEVICE, dp_cr, CR_PS_P1 | CR_DM_ABORT | CR_STA); ! 180: output1 (DEVICE, dp_par0, eth.myaddr.e[0]); ! 181: output1 (DEVICE, dp_par1, eth.myaddr.e[1]); ! 182: output1 (DEVICE, dp_par2, eth.myaddr.e[2]); ! 183: output1 (DEVICE, dp_par3, eth.myaddr.e[3]); ! 184: output1 (DEVICE, dp_par4, eth.myaddr.e[4]); ! 185: output1 (DEVICE, dp_par5, eth.myaddr.e[5]); ! 186: if (input1 (DEVICE, dp_par0) != eth.myaddr.e[0] || ! 187: input1 (DEVICE, dp_par1) != eth.myaddr.e[1] || ! 188: input1 (DEVICE, dp_par2) != eth.myaddr.e[2] || ! 189: input1 (DEVICE, dp_par3) != eth.myaddr.e[3] || ! 190: input1 (DEVICE, dp_par4) != eth.myaddr.e[4] || ! 191: input1 (DEVICE, dp_par5) != eth.myaddr.e[5] ) ! 192: STREAMS_DEBUG ("Device not accepting physical address!\n"); ! 193: if (selpage) ! 194: output (DEVICE, dp_cr, CR_PS_P0 | CR_DM_ABORT | CR_STA); ! 195: } ! 196: ! 197: /* ! 198: * Since the DMA channel to the DP8390 is word-wide, I have taken special care ! 199: * to deal with odd-length subunits of packets, or packets that are not word ! 200: * aligned with pullupmsg(). It's not fast, but such ugly messages should not ! 201: * occur often. ! 202: */ ! 203: ! 204: extern void streams_levels (void); ! 205: ! 206: static void eth_timer_func (ULONG eth) ! 207: { ! 208: char buf [4]; ! 209: TIMER_SET (eth_timer, 1, eth_timer_func, eth); ! 210: ! 211: if (ETH->tx_lastcount != ETH->tx_count) ! 212: ETH->tx_lastcount = ETH->tx_count; ! 213: else if (ETH->tx_state != TX_IDLE && ! 214: ETH->tx_error == 0) {/* packet send taking too long */ ! 215: mblk_t * temp; ! 216: ! 217: ETH->tx_error = 1; ! 218: ! 219: /* dispose of all the packets queued here */ ! 220: while (ETH->tx_sched.s_head != NULL) { ! 221: temp = getq (ETH->tx_sched.s_head); ! 222: freemsg (temp); ! 223: muxrobin (& ETH->tx_sched); ! 224: } ! 225: #if 1 ! 226: STREAMS_DEBUG ("Stuck in TX "); ! 227: #endif ! 228: } ! 229: if (ETH->rx_lastcount != ETH->rx_count) ! 230: ETH->rx_lastcount = ETH->rx_count; ! 231: else if (ETH->rx_state != RX_IDLE && ! 232: ETH->tx_error == 0) { ! 233: ETH->tx_error = 1; ! 234: STREAMS_DEBUG ("Stuck in RX "); ! 235: } ! 236: } ! 237: ! 238: ! 239: static UWORD dma_base; /* DMA base address in NIC */ ! 240: static UWORD dma_len; /* remote DMA length */ ! 241: static void *dma_buf; /* local buffer address */ ! 242: static int dma_dir; /* 1 => remote write */ ! 243: ! 244: /* start a piece of remote DMA, rounding the transfer size up */ ! 245: void dma_start (void) ! 246: { ! 247: DEVICE_REG ! 248: int xfer_len; ! 249: ! 250: if (dma_dir) { ! 251: output(DEVICE, dp_rbcr0, 15); /* dummy byte count */ ! 252: output(DEVICE, dp_rbcr1, 0); ! 253: output(DEVICE, dp_cr, CR_PS_P0 | CR_DM_RR | CR_STA); ! 254: // for (xfer_len = 0; xfer_len < 5; xfer_len ++) ! 255: // ; ! 256: } ! 257: ! 258: output(DEVICE, dp_rsar0, dma_base & 0xff); /* remote DMA base */ ! 259: output(DEVICE, dp_rsar1, dma_base >> 8 ); ! 260: if ((xfer_len = dma_len) & 1) ! 261: xfer_len++; ! 262: output(DEVICE, dp_rbcr0, xfer_len & 0xff); /* remote DMA count */ ! 263: output(DEVICE, dp_rbcr1, xfer_len >> 8 ); ! 264: ! 265: output(DEVICE, dp_cr, dma_dir ? ! 266: CR_PS_P0 | CR_DM_RW | CR_STA : ! 267: CR_PS_P0 | CR_DM_RR | CR_STA); ! 268: ! 269: dma_setup (DMA_0, (char *)dma_buf, xfer_len >> 1, ! 270: dma_dir ? DMAF_TODEV|DMAF_WORDWIDE|DMAF_BURST : ! 271: DMAF_TOMEM|DMAF_WORDWIDE|DMAF_BURST); ! 272: } ! 273: ! 274: /* ! 275: * During test, we want to poll for DMA completion. Also used when reading ! 276: * NIC packet header, since it's so short. ! 277: */ ! 278: void wait_for_dma (void) ! 279: { ! 280: DEVICE_REG ! 281: ! 282: for (;;) { ! 283: while ((input (DEVICE, dp_cr) & CR_DM_ABORT) == 0) ! 284: ; ! 285: if (dma_done (DMA_0) == -1) ! 286: break; ! 287: dma_reset (DMA_0); ! 288: dma_start (); /* restart */ ! 289: } ! 290: } ! 291: ! 292: /* ! 293: * retrieve NIC memory from "base" to "buffer" ! 294: */ ! 295: static INLINE void get_mem (int base, int len, void * buffer) ! 296: { ! 297: dma_base = base; ! 298: dma_len = len; ! 299: dma_buf = buffer; ! 300: dma_dir = 0; ! 301: dma_start (); ! 302: } ! 303: static INLINE void set_mem (int base, int len, unsigned char * buf) ! 304: { ! 305: dma_base = base; ! 306: dma_len = len; ! 307: dma_buf = buf; ! 308: dma_dir = 1; ! 309: dma_start (); ! 310: } ! 311: ! 312: /* send streams message block "mp" to NIC */ ! 313: static void send_block (queue_t * q, mblk_t * mp) ! 314: { ! 315: /* ! 316: * identify the losers, and fix them with pullupmsg(), which both ! 317: * concatenates (fixing length) and aligns at the same time. ! 318: */ ! 319: if ((mp->b_cont != NULL && ((mp->b_wptr - mp->b_rptr) & 1) != 0) || ! 320: ((ULONG)mp->b_rptr & 1) != 0) ! 321: pullupmsg (mp, -1); ! 322: ! 323: dma_base = (QETH->dp8390info.dpi_tbuf << 8) + QETH->tx_length; ! 324: dma_len = mp->b_wptr - mp->b_rptr; ! 325: dma_buf = mp->b_rptr; ! 326: dma_dir = 1; ! 327: ! 328: dma_start (); ! 329: } ! 330: ! 331: /* initiate transmission of the buffered packet, with length "len". */ ! 332: static void send_pkt (struct ethcb * eth) ! 333: { ! 334: DEVICE_REG ! 335: ! 336: if (eth->tx_length < 64) /* Ethernet magic */ ! 337: eth->tx_length = 64; ! 338: output (DEVICE, dp_tbcr0, eth->tx_length & 0xff); ! 339: output (DEVICE, dp_tbcr1, eth->tx_length >> 8); ! 340: output (DEVICE, dp_tpsr, eth->dp8390info.dpi_tbuf); ! 341: ! 342: output (DEVICE, dp_cr, CR_PS_P0|CR_DM_ABORT|CR_TXP|CR_STA); ! 343: } ! 344: ! 345: static void rx_next (struct ethcb * eth, int event); ! 346: static void tx_next (struct ethcb * eth, int event) ! 347: { ! 348: again: ! 349: SCREEN (26) = 'T'; ! 350: SCREEN (28) = eth->tx_state + '0'; ! 351: SCREEN (30) = event + '0'; ! 352: switch (eth->tx_state) { ! 353: case TX_IDLE: ! 354: if (event == TXE_CRANK) { ! 355: if (eth->tx_sched.s_head != NULL && ! 356: eth->rx_state != RX_DMA) { ! 357: eth->tx_count ++; ! 358: eth->tx_state = TX_DMA; ! 359: eth->tx_length = 0; ! 360: send_block (eth->tx_sched.s_head, ! 361: eth->tx_sched.s_head->q_first); ! 362: } ! 363: return; ! 364: } ! 365: break; ! 366: case TX_DMA: ! 367: if (event == TXE_DMADONE) { ! 368: mblk_t * temp = getq (eth->tx_sched.s_head), ! 369: * msg = temp->b_cont; ! 370: ! 371: eth->tx_length += dma_len; ! 372: freeb (temp); ! 373: if (msg != NULL) { ! 374: putbq (eth->tx_sched.s_head, msg); ! 375: send_block (eth->tx_sched.s_head, msg); ! 376: } else { ! 377: send_pkt (eth); /* spit it out */ ! 378: muxrobin (& eth->tx_sched); ! 379: eth->tx_state = TX_SEND; ! 380: ! 381: rx_next (eth, RXE_CRANK); ! 382: } ! 383: return; ! 384: } ! 385: if (event == TXE_CRANK) ! 386: return; ! 387: break; ! 388: case TX_SEND: ! 389: if (event == TXE_SENDDONE) { ! 390: eth->tx_error = 0; ! 391: eth->tx_state = TX_IDLE; ! 392: rx_next (eth, RXE_CRANK); ! 393: event = TXE_CRANK; ! 394: goto again; ! 395: } ! 396: if (event == TXE_CRANK) ! 397: return; ! 398: break; ! 399: } ! 400: STREAMS_DEBUG ("Bad TX state/event "); ! 401: } ! 402: ! 403: static void rx_got_mem (long eth) ! 404: { ! 405: short s = SPL7 (); ! 406: rx_next (LONG_TO_PTR (eth, struct ethcb *), RXE_GOTMEM); ! 407: SPLX (s); ! 408: } ! 409: static void rx_next (struct ethcb * eth, int event) ! 410: { ! 411: mblk_t * mp; ! 412: int len; ! 413: ! 414: again: ! 415: SCREEN (26) = 'R'; ! 416: SCREEN (28) = eth->rx_state + '0'; ! 417: SCREEN (30) = event + '0'; ! 418: switch (eth->rx_state) { ! 419: case RX_IDLE: ! 420: if (event == RXE_CRANK) { ! 421: if (eth->rx_pending && eth->tx_state != TX_DMA) { ! 422: /* busy wait on the header part */ ! 423: struct rcvdheader nic; ! 424: ! 425: get_mem (eth->dp8390info.dpi_next << 8, 4, & nic); ! 426: wait_for_dma (); ! 427: eth->dp8390info.dpi_next = nic.rp_next; ! 428: /* ! 429: * count in packet header includes FCS, which we ! 430: * are not really interested in. ! 431: */ ! 432: eth->rx_length = (nic.rp_rbch << 8) + nic.rp_rbcl - 4; ! 433: eth->rx_base = dma_base + 4; ! 434: if ((input (DEVICE, dp_isr) & ISR_RDC) == 0) ! 435: STREAMS_DEBUG ("IMPOSSIBLE 1"); ! 436: output (DEVICE, dp_isr, ISR_RDC); ! 437: ! 438: eth->rx_count ++; ! 439: eth->rx_state = RX_DMA; ! 440: event = RXE_DMADONE; ! 441: ! 442: if (input (DEVICE, dp_isr) & ISR_RDC) ! 443: STREAMS_DEBUG ("IMPOSSIBLE 2"); ! 444: goto again; ! 445: } ! 446: return; ! 447: } ! 448: break; ! 449: case RX_DMA: ! 450: len = eth->rx_length; ! 451: if (len > 768) { ! 452: if (len > 1024) ! 453: len = 1024; ! 454: } else if (len > 192) { ! 455: if (len > 256) ! 456: len = 256; ! 457: } else if (len > 64) ! 458: len = 64; ! 459: if (event == RXE_DMADONE) { ! 460: if (len == 0) { ! 461: event = RXE_ALLDONE; ! 462: goto again; ! 463: } ! 464: if ((mp = allocb (len, BPRI_MED)) == NULL) { ! 465: while (len < 1024) { ! 466: if ((mp = allocb (len, BPRI_LO)) != NULL) ! 467: break; ! 468: len *= 2; ! 469: } ! 470: if (len >= 1024) { ! 471: event = RXE_NOMEM; ! 472: goto again; ! 473: } ! 474: if (len > eth->rx_length) ! 475: len = eth->rx_length; ! 476: } ! 477: ! 478: eth->rx_count ++; ! 479: mp->b_wptr += len; ! 480: if (eth->rx_start == NULL) ! 481: eth->rx_start = mp; /* first buffer */ ! 482: else ! 483: eth->rx_current->b_cont = mp; /* link buffers */ ! 484: eth->rx_current = mp; ! 485: get_mem (eth->rx_base, len, mp->b_rptr); ! 486: /* take care to wrap the rx_base! */ ! 487: if (((eth->rx_base += len) >> 8) >= eth->dp8390info.dpi_pstop) ! 488: eth->rx_base -= (eth->dp8390info.dpi_pstop - eth->dp8390info.dpi_pstart) << 8; ! 489: eth->rx_length -= len; ! 490: return; ! 491: } ! 492: if (event == RXE_NOMEM) { ! 493: eth->rx_state = RX_HALT; ! 494: bufcall (len, BPRI_MED, rx_got_mem, (long) eth); ! 495: tx_next (eth, TXE_CRANK); ! 496: event = RXE_CRANK; ! 497: goto again; ! 498: } ! 499: if (event == RXE_ALLDONE) { ! 500: /* ! 501: * finished a piece of receive DMA - advance buffer ! 502: * queue endpoint over just received packet. In ! 503: * addition, we should check to see if there are any ! 504: * more buffered receive packets. ! 505: */ ! 506: output (DEVICE, dp_bnry, eth->dp8390info.dpi_next == eth->dp8390info.dpi_pstart ? ! 507: eth->dp8390info.dpi_pstop - 1 : ! 508: eth->dp8390info.dpi_next - 1); ! 509: output (DEVICE, dp_cr, CR_PS_P1 | CR_DM_ABORT | CR_STA); ! 510: if (input1 (DEVICE, dp_curr) == eth->dp8390info.dpi_next) ! 511: eth->rx_pending = 0; ! 512: output (DEVICE, dp_cr, CR_PS_P0 | CR_DM_ABORT | CR_STA); ! 513: if (eth->rx_start != NULL) { ! 514: /* send a copy of every message upwards */ ! 515: for (len = 0; len < MAXMINOR ; len ++) ! 516: if (minortab [len] && ! 517: (mp = dupmsg (eth->rx_start)) != NULL) ! 518: putq (minortab [len], mp); ! 519: SCREEN (22) ++; ! 520: freemsg (eth->rx_start); ! 521: eth->rx_start = eth->rx_current = NULL; ! 522: } ! 523: eth->rx_state = RX_IDLE; ! 524: tx_next (eth, TXE_CRANK); ! 525: event = RXE_CRANK; ! 526: goto again; ! 527: } ! 528: return; ! 529: case RX_HALT: ! 530: if (event == RXE_GOTMEM) { ! 531: if (eth->tx_state == TX_DMA) { ! 532: eth->rx_state = RX_BLOCKED; ! 533: return; ! 534: } ! 535: eth->rx_state = RX_DMA; ! 536: event = RXE_DMADONE; ! 537: goto again; ! 538: } ! 539: if (event == RXE_CRANK) ! 540: return; ! 541: break; ! 542: case RX_BLOCKED: ! 543: if (event == RXE_CRANK && eth->tx_state != TX_DMA) { ! 544: eth->rx_state = RX_DMA; ! 545: event = RXE_DMADONE; ! 546: goto again; ! 547: } ! 548: break; ! 549: default: ! 550: STREAMS_DEBUG ("Impossible state"); ! 551: return; ! 552: } ! 553: STREAMS_DEBUG ("Bad RX state/event combo "); ! 554: } ! 555: ! 556: ! 557: /* Referenced in "system.asm", here is the interrupt service routine */ ! 558: HW_INT_FUNC (void) etherint (void) ! 559: { ! 560: DEVICE_REG ! 561: UBYTE status = input (DEVICE, dp_isr); ! 562: static UBYTE reentry; ! 563: ! 564: if (reentry ++ != 0) { ! 565: STREAMS_DEBUG ("Reentry "); ! 566: reentry --; ! 567: return; ! 568: } ! 569: ! 570: /* ! 571: * GCC - specific kernel hack, save all used registers on entry to ! 572: * this function. We don't use INTERRUPT for the PC version since ! 573: * hardware IRQ handlers need assembly-language wrappers to give ! 574: * us enough stack to use STREAMS library routines. ! 575: */ ! 576: GNU_INTERRUPT; ! 577: ! 578: rescan: ! 579: /* reset the flag bits that were indicated for us */ ! 580: output (DEVICE, dp_isr, status); ! 581: ! 582: if (eth.netok == 0) { /* device not active! */ ! 583: reentry --; ! 584: return; ! 585: } ! 586: if ((status & ISR_PRX) != 0) { ! 587: eth.rx_pending = 1; ! 588: rx_next (& eth, RXE_CRANK); ! 589: } ! 590: SCREEN (16) ++; ! 591: if ((status & ISR_PTX) != 0) { ! 592: if ((input (DEVICE, dp_tsr) & ~(TSR_COL | TSR_CRS | TSR_PTX | TSR_DFR)) ! 593: != 0) ! 594: STREAMS_DEBUG ("Packet TX error\n"); ! 595: SCREEN (18) ++; ! 596: tx_next (& eth, TXE_SENDDONE); ! 597: } ! 598: /* ! 599: * The ISR_RDC bit is gated with CR_DM_ABORT since the fix for the ! 600: * NIC remote write problem causes spurious RDCs, which are not ! 601: * normally detected unless the TX DMA is delayed by arrive DMA to ! 602: * the NIC local memory. ! 603: */ ! 604: if ((status & ISR_RDC) != 0 && ! 605: (input (DEVICE, dp_cr) & CR_DM_ABORT) != 0) ! 606: if (dma_done (DMA_0) != -1) { ! 607: dma_reset (DMA_0); ! 608: dma_start (); ! 609: } else if (dma_dir) ! 610: tx_next (& eth, TXE_DMADONE); ! 611: else ! 612: rx_next (& eth, RXE_DMADONE); ! 613: ! 614: if ((status & (ISR_RXE | ISR_TXE | ISR_OVW | ISR_CNT)) != 0) { ! 615: if (status & ISR_RXE) ! 616: STREAMS_DEBUG ("Receive error\n"); ! 617: if (status & ISR_TXE) { ! 618: /* ! 619: * This can happen due to excessive collisions if ! 620: * there is an open cable end or due to a FIFO ! 621: * underrun (which indicates a board problem). ! 622: */ ! 623: if ((input (DEVICE, dp_tsr) & (TSR_FU)) != 0) ! 624: STREAMS_DEBUG ("TX FIFO underrun"); ! 625: tx_next (& eth, TXE_SENDDONE); ! 626: } ! 627: if (status & ISR_OVW) ! 628: STREAMS_DEBUG ("Buffer overflow\n"); ! 629: if (status & ISR_CNT) { ! 630: /* reset the error counters by reading them */ ! 631: eth.errcnt0 += input (DEVICE, dp_cntr0); ! 632: eth.errcnt1 += input (DEVICE, dp_cntr1); ! 633: eth.errcnt2 += input (DEVICE, dp_cntr2); ! 634: } ! 635: } ! 636: if ((status = input (DEVICE, dp_isr)) != 0) ! 637: goto rescan; ! 638: ! 639: reentry --; ! 640: } ! 641: ! 642: /* ! 643: * Routines for reading from/writing to the NIC memory. ! 644: */ ! 645: ! 646: /* queue a packet for transmission */ ! 647: static void queue_packet (queue_t *q, mblk_t *mp) ! 648: { ! 649: if (QETH->tx_error != 0) ! 650: return; ! 651: ! 652: short s = SPL7 (); ! 653: /* ! 654: * We queue the message "normally" for STREAMS so that flow control ! 655: * operates as one would expect. Then we place the streams queue onto ! 656: * our own "scheduling" list for processing by the NIC interrupt. ! 657: */ ! 658: putq (q, mp); ! 659: qschedule (q, & QETH->tx_sched); ! 660: ! 661: /* ! 662: * If there is no I/O presently being executed, we must start ! 663: * the ball rolling. ! 664: */ ! 665: tx_next (QETH, TXE_CRANK); ! 666: SPLX (s); ! 667: } ! 668: ! 669: /* ! 670: * Set up the DP8390. This initialisation procedure comes fairly directly ! 671: * from the NatSemi manual - much dark magic. ! 672: */ ! 673: static void chipinit (Eth_addr * addr) ! 674: { ! 675: unsigned char * testbuf, * test2; ! 676: mblk_t * testmem; ! 677: int i, start = -1, len; ! 678: DEVICE_REG ! 679: ! 680: if (input (DEVICE, dp_cr) == 0xFF) { ! 681: eth.netok = -1; ! 682: return; ! 683: } ! 684: ! 685: /* reset dp8390 */ ! 686: output(DEVICE, dp_cr, CR_STP|CR_PS_P0|CR_DM_ABORT); ! 687: ! 688: #ifdef M68K ! 689: output(DEVICE, dp_dcr, ! 690: DCR_LOOP | DCR_WORDWIDE | DCR_BIGENDIAN | DCR_8BYTES); ! 691: #endif ! 692: #ifdef IBMPC ! 693: set_hw_int (ETHER_IRQ, etherint); ! 694: output(DEVICE, dp_dcr, DCR_LOOP | DCR_WORDWIDE | DCR_8BYTES); ! 695: #endif ! 696: ! 697: output(DEVICE, dp_rbcr0, 0); ! 698: output(DEVICE, dp_rbcr1, 0); ! 699: output(DEVICE, dp_rcr, RCR_AB); ! 700: output(DEVICE, dp_tcr, TCR_INTERNAL); ! 701: output(DEVICE, dp_isr, 0xff); ! 702: output(DEVICE, dp_imr, 0); ! 703: ! 704: /* ! 705: * We start the device here (and shut it down later) since the ! 706: * Remote DMA doesn't work until we do, and we can't find out how ! 707: * much memory we have until we can DMA. (Sigh) ! 708: */ ! 709: output (DEVICE, dp_cr, CR_PS_P0 | CR_DM_ABORT | CR_STA); ! 710: ! 711: /* ! 712: * Since the NIC is in internal loopback mode (TCR_INTERNAL), and ! 713: * interrupts are disabled, we can now test the NIC's memory to ! 714: * determine how much there is. ! 715: */ ! 716: testmem = getbuf (1024); /* get temporary space */ ! 717: testbuf = testmem->b_rptr; ! 718: test2 = testbuf + 256; ! 719: ! 720: for (i = 0 ; i < 256 ; i ++) ! 721: testbuf [i] = i; ! 722: for (i = 0 ; i < 256 ; i ++) { ! 723: testbuf [0] = i; ! 724: testbuf [1] = ~i; ! 725: set_mem (i << 8, 256, testbuf); ! 726: wait_for_dma (); ! 727: } ! 728: ! 729: /* find start of memory */ ! 730: for (i = 0 ; i < 256 ; i++) { ! 731: testbuf [0] = i; ! 732: testbuf [1] = ~i; ! 733: get_mem (i << 8, 256, test2); ! 734: wait_for_dma (); ! 735: if (memcmp (test2, testbuf, 256) == 0) ! 736: /* got one - either start or extend a span */ ! 737: if (start < 0) { ! 738: start = i; ! 739: len = 1; ! 740: } else ! 741: len++; ! 742: else ! 743: if (start >= 0) ! 744: break; ! 745: } ! 746: if (len < 16) { /* needs at least 4k to work */ ! 747: eth.netok = -1; ! 748: goto alldone; ! 749: } ! 750: ! 751: eth.dp8390info.dpi_pstart = start + 8; ! 752: eth.dp8390info.dpi_pstop = start + len; ! 753: eth.dp8390info.dpi_tbuf = start; ! 754: ! 755: /* ! 756: * Since we're at it... if the board has an address PROM, it should ! 757: * be at address 0 (where the NIC has trouble locating RAM), so ! 758: * unless we're given an address, try finding our location. ! 759: */ ! 760: if (addr != NULL) ! 761: eth.myaddr = * addr; ! 762: else if (start > 0) { /* may have PROM, there's no RAM */ ! 763: get_mem (0, 12, testbuf); ! 764: wait_for_dma (); ! 765: ! 766: /* Fetch the PROM data from every second word */ ! 767: for (i = 0;i < 6;i++) ! 768: eth.myaddr.e [i] = testbuf [i + i]; ! 769: } ! 770: ! 771: STREAMS_DEBUG_LONG (len << 8, 16); ! 772: STREAMS_DEBUG ("h bytes of Ethernet memory, Address = $"); ! 773: for (i = 0 ; i < 6 ; i ++) ! 774: STREAMS_DEBUG_LONG (eth.myaddr.e [i], 16); ! 775: STREAMS_DEBUG (", IRQ "); ! 776: STREAMS_DEBUG_LONG (ETHER_IRQ, 10); ! 777: STREAMS_DEBUG ("\r\n"); ! 778: ! 779: output (DEVICE, dp_isr, 0xFF); ! 780: output (DEVICE, dp_tpsr, eth.dp8390info.dpi_tbuf); ! 781: output (DEVICE, dp_pstart, eth.dp8390info.dpi_pstart); ! 782: output (DEVICE, dp_bnry, eth.dp8390info.dpi_pstart); ! 783: output (DEVICE, dp_pstop, eth.dp8390info.dpi_pstop); ! 784: ! 785: output (DEVICE, dp_cr, CR_PS_P1|CR_DM_ABORT|CR_STP); ! 786: output1 (DEVICE, dp_curr, eth.dp8390info.dpi_pstart + 1); ! 787: eth.dp8390info.dpi_next = eth.dp8390info.dpi_pstart + 1; ! 788: ! 789: set_addr (0); ! 790: ! 791: output (DEVICE, dp_cr, CR_PS_P0|CR_DM_ABORT|CR_STA); ! 792: output (DEVICE, dp_tcr, 0); ! 793: output (DEVICE, dp_imr, 0x7F); /* all interrupts */ ! 794: ! 795: if ((eth_timer = TIMER_ALLOC ()) != NIL_TIMER) ! 796: TIMER_SET (eth_timer, 1, eth_timer_func, (long) & eth); ! 797: eth.netok ++; ! 798: ! 799: alldone: ! 800: freemsg (testmem); ! 801: } ! 802: ! 803: /* ! 804: * Shut down the E'net chip. Whenever I get around to it, this will send ! 805: * the ARP-style packet that indicates this station is dead'n'gone. This ! 806: * will use the poll-type DMA access shown in the open. ! 807: */ ! 808: static void chipoff (void) ! 809: { ! 810: DEVICE_REG ! 811: ! 812: if (eth.netok < 0) ! 813: return; ! 814: #ifdef IBMPC ! 815: set_hw_int (ETHER_IRQ, NULL); ! 816: #endif /* IBMPC */ ! 817: output (DEVICE, dp_imr, 0); ! 818: output (DEVICE, dp_cr, CR_PS_P0 | CR_DM_ABORT | CR_STP); ! 819: } ! 820: ! 821: /* ! 822: * stream open routine for the driver ! 823: */ ! 824: static int ethopen (queue_t * q, dev_t dev, int /* flag */, int sflag) ! 825: { ! 826: /* refuse to do anything unless everything checked out OK at boot */ ! 827: W (q)->q_ptr = q->q_ptr = & eth; ! 828: if (QETH->netok < 0) ! 829: return OPENFAIL; ! 830: if (QETH->netok == 0) { ! 831: chipinit (NULL); ! 832: if (QETH->netok < 0) ! 833: return OPENFAIL; ! 834: ! 835: } else ! 836: QETH->netok ++; ! 837: /* allow regular or clone device open */ ! 838: if (sflag == CLONEOPEN) { ! 839: for (dev = 0;dev < MAXMINOR;dev++) ! 840: if (minortab[dev] == NULL) ! 841: break; ! 842: } else ! 843: dev = minor(dev); ! 844: if (dev < 0 || dev >= MAXMINOR) ! 845: return OPENFAIL; ! 846: ! 847: minortab[dev] = q; ! 848: return dev; ! 849: } ! 850: ! 851: /* ethernet write put procedure */ ! 852: static void ethwput (queue_t * q, mblk_t * mp) ! 853: { ! 854: Framehdr * frame; ! 855: struct sp_bind * spbind; ! 856: Eth_addr * addr; ! 857: ! 858: switch (mp->b_datap->db_type) { ! 859: case M_PROTO: ! 860: spbind = (struct sp_bind *)mp->b_rptr; ! 861: addr = (Eth_addr *)(spbind + 1); ! 862: if (spbind->protoid == SP_BIND) { ! 863: if (spbind->family != AF_ENET) { ! 864: freemsg (mp); ! 865: return; ! 866: } ! 867: if (mp->b_wptr > (unsigned char *) addr) { ! 868: QETH->myaddr = * addr ++; ! 869: set_addr (1); ! 870: } ! 871: freemsg (mp); ! 872: mp = allocb (sizeof (struct sp_bind) + sizeof (Eth_addr), ! 873: BPRI_MED); ! 874: if (mp != NULL) { ! 875: spbind = (struct sp_bind *)mp->b_rptr; ! 876: addr = (Eth_addr *)(spbind + 1); ! 877: spbind->protoid = SP_BIND; ! 878: spbind->family = AF_ENET; ! 879: spbind->connect = TPS_BOUND; ! 880: * addr ++ = QETH->myaddr; ! 881: mp->b_wptr = (unsigned char *) addr; ! 882: mp->b_datap->db_type = M_PROTO; ! 883: qreply (q, mp); ! 884: } ! 885: return; ! 886: } ! 887: default: ! 888: nogood: ! 889: freemsg (mp); ! 890: break; ! 891: case M_DATA: ! 892: frame = (Framehdr *)mp->b_rptr; ! 893: if ((unsigned char *)(frame + 1) > mp->b_wptr) ! 894: goto nogood; ! 895: SCREEN (20) ++; ! 896: frame->f_srcaddr = QETH->myaddr; ! 897: queue_packet (q, mp); ! 898: break; ! 899: case M_FLUSH: ! 900: /* canonical flush processing */ ! 901: if ((* mp->b_rptr & FLUSHW) != 0) ! 902: flushq (q, FLUSHDATA); ! 903: if ((* mp->b_rptr & FLUSHR) != 0) { ! 904: flushq (RD(q), FLUSHDATA); ! 905: * mp->b_rptr &= ~FLUSHW; ! 906: qreply (q, mp); ! 907: } else ! 908: freemsg (mp); ! 909: break; ! 910: case M_IOCTL: ! 911: mp->b_datap->db_type = M_IOCNAK; ! 912: qreply (q, mp); ! 913: break; ! 914: } ! 915: } ! 916: ! 917: /* read service routine */ ! 918: static void ethrsrv (queue_t * q) ! 919: { ! 920: mblk_t * mp; ! 921: ! 922: while ((mp = getq (q)) != NULL) ! 923: if (canput (q->q_next)) ! 924: putnext (q, mp); ! 925: else { ! 926: putbq (q, mp); ! 927: break; ! 928: } ! 929: SCREEN (24) ++; ! 930: } ! 931: ! 932: /* close procedure - called on last close of stream */ ! 933: static int ethclose(queue_t *q) ! 934: { ! 935: int i; ! 936: ! 937: if (QETH->netok == 1) ! 938: chipoff (); ! 939: QETH->netok --; ! 940: for (i = 0;i < MAXMINOR;i++) ! 941: if (minortab[i] == q) ! 942: break; ! 943: minortab[i] = NULL; ! 944: return(0); ! 945: } ! 946: ! 947: static struct module_info ethrinfo = { ! 948: 0, "ether", 0, 1024, 1024, 0 ! 949: }; ! 950: static struct qinit ethread = { ! 951: NULLFUNC, ethrsrv, ethopen, ethclose, NULLFUNC, ! 952: ðrinfo, NULLSTAT ! 953: }, ethwrite = { ! 954: ethwput, NULLFUNC, NULLFUNC, NULLFUNC, NULLFUNC, ! 955: ðrinfo, NULLSTAT ! 956: }; ! 957: struct streamtab ethinfo = { ! 958: ðread, ðwrite, NULLINIT, NULLINIT ! 959: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.