| plan 9 kernel history: overview | file list | diff list |
1993/0212/pc/ether8390.c (diff list | history)
| 1992/1222/sys/src/9/pc/ether8390.c:24,32 – 1993/0212/sys/src/9/pc/ether8390.c:24,34 (short | long | prev | next) | ||
| 1992/1222 | RDMAwrite = (2<<3), /* remote DMA write */ RDMAsend = (3<<3), /* remote DMA send packet */ RDMAabort = (4<<3), /* abort/complete remote DMA */ | |
| 1993/0212 | Ps0 = 0x40, /* page select */ Ps1 = 0x80, /* page select */ Page0 = 0x00, Page1 = Ps0, Page2 = Ps1, | |
| 1992/1222 | }; enum { /* Page 0, read */ | |
| 1992/1222/sys/src/9/pc/ether8390.c:38,44 – 1993/0212/sys/src/9/pc/ether8390.c:40,46 | ||
| 1992/1222 | Fifo = 0x06, /* FIFO */ Isr = 0x07, /* interrupt status register (R/W) */ Crda0 = 0x08, /* current remote DMA address 0 */ | |
| 1993/0212 | Crda1 = 0x09, /* current remote DMA address 1 */ | |
| 1992/1222 | Rsr = 0x0C, /* receive status register */ Cntr0 = 0x0D, /* frame alignment errors */ Cntr1 = 0x0E, /* CRC errors */ | |
| 1992/1222/sys/src/9/pc/ether8390.c:144,158 – 1993/0212/sys/src/9/pc/ether8390.c:146,154 | ||
| 1992/1222 | uchar len1; } Hdr; | |
| 1992/1222/sys/src/9/pc/ether8390.c:163,216 – 1993/0212/sys/src/9/pc/ether8390.c:159,221 | ||
| 1992/1222 | * chip there if this is called when probing for a device * at boot. */ | |
| 1993/0212 | dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Stp); dp8390outb(ctlr->card.dp8390+Rbcr0, 0); dp8390outb(ctlr->card.dp8390+Rbcr1, 0); for(timo = 10000; (dp8390inb(ctlr->card.dp8390+Isr) & Rst) == 0 && timo; timo--) | |
| 1992/1222 | ; } | |
| 1993/0212 | static void dp8390ring(Ctlr *ctlr) { dp8390outb(ctlr->card.dp8390+Pstart, ctlr->card.pstart); dp8390outb(ctlr->card.dp8390+Pstop, ctlr->card.pstop); dp8390outb(ctlr->card.dp8390+Bnry, ctlr->card.pstop-1); dp8390outb(ctlr->card.dp8390+Cr, Page1|RDMAabort|Stp); dp8390outb(ctlr->card.dp8390+Curr, ctlr->card.pstart); dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Stp); ctlr->card.nxtpkt = ctlr->card.pstart; } | |
| 1992/1222 | void dp8390reset(Ctlr *ctlr) { | |
| 1993/0212 | * as 'mandatory' in the datasheet, with references * to the 3Com503 technical reference manual. | |
| 1992/1222 | */ dp8390disable(ctlr); | |
| 1993/0212 | if(ctlr->card.bit16) dp8390outb(ctlr->card.dp8390+Dcr, Ft4|Ls|Wts); | |
| 1992/1222 | else | |
| 1993/0212 | dp8390outb(ctlr->card.dp8390+Dcr, Ft4|Ls); | |
| 1992/1222 |
| |
| 1993/0212 | dp8390outb(ctlr->card.dp8390+Rbcr0, 0); dp8390outb(ctlr->card.dp8390+Rbcr1, 0); | |
| 1992/1222 |
| |
| 1993/0212 | dp8390outb(ctlr->card.dp8390+Tcr, 0); dp8390outb(ctlr->card.dp8390+Rcr, Mon); | |
| 1992/1222 |
| |
| 1993/0212 | * Init the ring hardware and software ring pointers. * Can't initialise ethernet address as we may not know * it yet. | |
| 1992/1222 | */ | |
| 1993/0212 | dp8390ring(ctlr); dp8390outb(ctlr->card.dp8390+Tpsr, ctlr->card.tstart); | |
| 1992/1222 | ||
| 1993/0212 | dp8390outb(ctlr->card.dp8390+Isr, 0xFF); dp8390outb(ctlr->card.dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe); | |
| 1992/1222 | /* * Leave the chip initialised, * but in internal loopback mode. */ | |
| 1993/0212 | dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta); | |
| 1992/1222 | } void | |
| 1992/1222/sys/src/9/pc/ether8390.c:218,242 – 1993/0212/sys/src/9/pc/ether8390.c:223,249 | ||
| 1992/1222 | { /* * Enable the chip for transmit/receive. | |
| 1993/0212 | * The init routine leaves the chip in monitor * mode. | |
| 1992/1222 | */ | |
| 1993/0212 | dp8390outb(ctlr->card.dp8390+Rcr, Ab); | |
| 1992/1222 | } void dp8390mode(Ctlr *ctlr, int on) { | |
| 1993/0212 | /* * Set/reset promiscuous mode. */ | |
| 1992/1222 | if(on) | |
| 1993/0212 | dp8390outb(ctlr->card.dp8390+Rcr, Pro|Ab); | |
| 1992/1222 | else | |
| 1993/0212 | dp8390outb(ctlr->card.dp8390+Rcr, Ab); | |
| 1992/1222 | } void dp8390setea(Ctlr *ctlr) { | |
| 1992/1222/sys/src/9/pc/ether8390.c:247,304 – 1993/0212/sys/src/9/pc/ether8390.c:254,300 | ||
| 1992/1222 | * addresses as we never set the multicast * enable. */ | |
| 1993/0212 | cr = dp8390inb(ctlr->card.dp8390+Cr) & ~Txp; dp8390outb(ctlr->card.dp8390+Cr, Page1|(~(Ps1|Ps0) & cr)); | |
| 1992/1222 | for(i = 0; i < sizeof(ctlr->ea); i++) | |
| 1993/0212 | dp8390outb(ctlr->card.dp8390+Par0+i, ctlr->ea[i]); dp8390outb(ctlr->card.dp8390+Cr, cr); | |
| 1992/1222 | } void* dp8390read(Ctlr *ctlr, void *to, ulong from, ulong len) { | |
| 1993/0212 | * Read some data at offset 'from' in the card's memory | |
| 1992/1222 | * using the DP8390 remote DMA facility, and place it at * 'to' in main memory, via the I/O data port. */ | |
| 1993/0212 | cr = dp8390inb(ctlr->card.dp8390+Cr) & ~Txp; dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta); dp8390outb(ctlr->card.dp8390+Isr, Rdc); | |
| 1992/1222 | /* * Set up the remote DMA address and count. */ | |
| 1993/0212 | if(ctlr->card.bit16) | |
| 1992/1222 | len = ROUNDUP(len, 2); | |
| 1993/0212 | dp8390outb(ctlr->card.dp8390+Rbcr0, len & 0xFF); dp8390outb(ctlr->card.dp8390+Rbcr1, (len>>8) & 0xFF); dp8390outb(ctlr->card.dp8390+Rsar0, from & 0xFF); dp8390outb(ctlr->card.dp8390+Rsar1, (from>>8) & 0xFF); | |
| 1992/1222 | /* * Start the remote DMA read and suck the data * out of the I/O port. */ | |
| 1993/0212 | dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAread|Sta); if(ctlr->card.bit16) inss(ctlr->card.data, to, len/2); | |
| 1992/1222 | else | |
| 1993/0212 | insb(ctlr->card.data, to, len); | |
| 1992/1222 | /* * Wait for the remote DMA to complete. The timeout | |
| 1992/1222/sys/src/9/pc/ether8390.c:307,317 – 1993/0212/sys/src/9/pc/ether8390.c:303,313 | ||
| 1992/1222 | * to the miracles of the bus, we could get this far * and still be talking to a slot full of nothing. */ | |
| 1993/0212 | for(timo = 10000; (dp8390inb(ctlr->card.dp8390+Isr) & Rdc) == 0 && timo; timo--) | |
| 1992/1222 | ; | |
| 1993/0212 | dp8390outb(ctlr->card.dp8390+Isr, Rdc); dp8390outb(ctlr->card.dp8390+Cr, cr); | |
| 1992/1222 | return to; } | |
| 1992/1222/sys/src/9/pc/ether8390.c:318,369 – 1993/0212/sys/src/9/pc/ether8390.c:314,372 | ||
| 1992/1222 | void* dp8390write(Ctlr *ctlr, ulong to, void *from, ulong len) { | |
| 1993/0212 | ulong crda; | |
| 1992/1222 | /* | |
| 1993/0212 | * Write some data to offset 'to' in the card's memory | |
| 1992/1222 | * using the DP8390 remote DMA facility, reading it at * 'from' in main memory, via the I/O data port. */ | |
| 1993/0212 | cr = dp8390inb(ctlr->card.dp8390+Cr) & ~Txp; dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta); dp8390outb(ctlr->card.dp8390+Isr, Rdc); | |
| 1992/1222 | ||
| 1993/0212 | if(ctlr->card.bit16) len = ROUNDUP(len, 2); | |
| 1992/1222 | /* * Set up the remote DMA address and count. | |
| 1993/0212 | * This is straight from the DP8390[12D] datasheet, hence * the initial set up for read. | |
| 1992/1222 | */ | |
| 1993/0212 | crda = to-1-ctlr->card.bit16; dp8390outb(ctlr->card.dp8390+Rbcr0, (len+1+ctlr->card.bit16) & 0xFF); dp8390outb(ctlr->card.dp8390+Rbcr1, ((len+1+ctlr->card.bit16)>>8) & 0xFF); dp8390outb(ctlr->card.dp8390+Rsar0, crda & 0xFF); dp8390outb(ctlr->card.dp8390+Rsar1, (crda>>8) & 0xFF); dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAread|Sta); | |
| 1992/1222 |
| |
| 1993/0212 | for(;;){ crda = dp8390inb(ctlr->card.dp8390+Crda0); crda |= dp8390inb(ctlr->card.dp8390+Crda1)<<8; if(crda == to){ /* * Start the remote DMA write and make sure * the registers are correct. */ dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAwrite|Sta); | |
| 1992/1222 | ||
| 1993/0212 | crda = dp8390inb(ctlr->card.dp8390+Crda0); crda |= dp8390inb(ctlr->card.dp8390+Crda1)<<8; if(crda != to) panic("crda write %d to %d\n", crda, to); break; } } | |
| 1992/1222 | /* | |
| 1993/0212 | * Pump the data into the I/O port. | |
| 1992/1222 | */ | |
| 1993/0212 | if(ctlr->card.bit16) outss(ctlr->card.data, from, len/2); | |
| 1992/1222 | else | |
| 1993/0212 | outsb(ctlr->card.data, from, len); | |
| 1992/1222 | /* * Wait for the remote DMA to finish. We'll need | |
| 1992/1222/sys/src/9/pc/ether8390.c:370,405 – 1993/0212/sys/src/9/pc/ether8390.c:373,407 | ||
| 1992/1222 | * a timeout here if this ever gets called before * we know there really is a chip there. */ | |
| 1993/0212 | while((dp8390inb(ctlr->card.dp8390+Isr) & Rdc) == 0) | |
| 1992/1222 | ; | |
| 1993/0212 | dp8390outb(ctlr->card.dp8390+Isr, Rdc); dp8390outb(ctlr->card.dp8390+Cr, cr); | |
| 1992/1222 | return (void*)to; } | |
| 1993/0212 | static uchar getcurr(Ctlr *ctlr) { uchar cr, curr; cr = dp8390inb(ctlr->card.dp8390+Cr) & ~Txp; dp8390outb(ctlr->card.dp8390+Cr, Page1|(~(Ps1|Ps0) & cr)); curr = dp8390inb(ctlr->card.dp8390+Curr); dp8390outb(ctlr->card.dp8390+Cr, cr); return curr; } | |
| 1992/1222 | void dp8390receive(Ctlr *ctlr) { | |
| 1993/0212 | uchar curr, len1, *pkt; | |
| 1992/1222 | Hdr hdr; | |
| 1993/0212 | ulong data, len; | |
| 1992/1222 |
| |
| 1993/0212 | for(curr = getcurr(ctlr); ctlr->card.nxtpkt != curr; curr = getcurr(ctlr)){ | |
| 1992/1222 | /* * Hack to keep away from the card's memory while it is receiving * a packet. This is only a problem on the NCR 3170 Safari. | |
| 1992/1222/sys/src/9/pc/ether8390.c:411,421 – 1993/0212/sys/src/9/pc/ether8390.c:413,423 | ||
| 1992/1222 | uchar a, b, c; for(;;delay(10)){ | |
| 1993/0212 | a = dp8390inb(ctlr->card.dp8390+Clda0); b = dp8390inb(ctlr->card.dp8390+Clda0); | |
| 1992/1222 | if(a != b) continue; | |
| 1993/0212 | c = dp8390inb(ctlr->card.dp8390+Clda0); | |
| 1992/1222 | if(c != b) continue; break; | |
| 1992/1222/sys/src/9/pc/ether8390.c:424,486 – 1993/0212/sys/src/9/pc/ether8390.c:426,564 | ||
| 1992/1222 | ctlr->inpackets++; | |
| 1993/0212 | data = ctlr->card.nxtpkt*Dp8390BufSz; (*ctlr->card.read)(ctlr, &hdr, data, sizeof(Hdr)); | |
| 1992/1222 | /* | |
| 1993/0212 | * Don't believe the upper byte count, work it * out from the software next-page pointer and * the current next-page pointer. | |
| 1992/1222 | */ | |
| 1993/0212 | if(hdr.next > ctlr->card.nxtpkt) len1 = hdr.next - ctlr->card.nxtpkt - 1; else len1 = (ctlr->card.pstop-ctlr->card.nxtpkt) + (hdr.next-ctlr->card.pstart) - 1; if(hdr.len0 > (Dp8390BufSz-sizeof(Hdr))) len1--; len = ((len1<<8)|hdr.len0)-4; /* * Chip is badly scrogged, reinitialise the ring. */ if(hdr.next < ctlr->card.pstart || hdr.next >= ctlr->card.pstop || len < 60 || len > sizeof(Etherpkt)){ print("H#%2.2ux#%2.2ux#%2.2ux#%2.2ux,%d|", hdr.status, hdr.next, hdr.len0, hdr.len1, len); dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Stp); dp8390ring(ctlr); dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta); | |
| 1992/1222 | return; } | |
| 1993/0212 | /* * If it's a good packet and we have a place to put it, * read it in to the software ring. * If the packet wraps round the hardware ring, read it * in two pieces. */ | |
| 1992/1222 | ring = &ctlr->rb[ctlr->ri]; | |
| 1993/0212 | if((hdr.status & (Fo|Fae|Crce|Prxok)) == Prxok && ring->owner == Interface){ pkt = ring->pkt; | |
| 1992/1222 | data += sizeof(Hdr); | |
| 1993/0212 | ring->len = len; if((data+len) >= ctlr->card.pstop*Dp8390BufSz){ ulong count = ctlr->card.pstop*Dp8390BufSz - data; (*ctlr->card.read)(ctlr, pkt, data, count); pkt += count; data = ctlr->card.pstart*Dp8390BufSz; len -= count; | |
| 1992/1222 | } | |
| 1993/0212 | if(len) (*ctlr->card.read)(ctlr, pkt, data, len); | |
| 1992/1222 | ring->owner = Host; ctlr->ri = NEXT(ctlr->ri, ctlr->nrb); } | |
| 1993/0212 | /* * Finished woth this packet, update the * hardware and software ring pointers. */ ctlr->card.nxtpkt = hdr.next; hdr.next--; if(hdr.next < ctlr->card.pstart) hdr.next = ctlr->card.pstop-1; dp8390outb(ctlr->card.dp8390+Bnry, hdr.next); | |
| 1992/1222 | } } | |
| 1993/0212 | /* * Initiate a transmission. Must be called splhi(). */ | |
| 1992/1222 | void dp8390transmit(Ctlr *ctlr) { | |
| 1993/0212 | ring = &ctlr->tb[ctlr->ti]; if(ctlr->tbusy == 0 && ring->owner == Interface){ (*ctlr->card.write)(ctlr, ctlr->card.tstart*Dp8390BufSz, ring->pkt, ring->len); dp8390outb(ctlr->card.dp8390+Tbcr0, ring->len & 0xFF); dp8390outb(ctlr->card.dp8390+Tbcr1, (ring->len>>8) & 0xFF); dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Txp|Sta); ctlr->tbusy = 1; } } void dp8390overflow(Ctlr *ctlr) { uchar txp; int resend; /* * The following procedure is taken from the DP8390[12D] datasheet, * it seems pretty adamant that this is what has to be done. */ txp = dp8390inb(ctlr->card.dp8390+Cr) & Txp; dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Stp); delay(2); dp8390outb(ctlr->card.dp8390+Rbcr0, 0); dp8390outb(ctlr->card.dp8390+Rbcr1, 0); resend = 0; if(txp && (dp8390inb(ctlr->card.dp8390+Isr) & (Txe|Ptx)) == 0) resend = 1; dp8390outb(ctlr->card.dp8390+Tcr, Lb); dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Sta); (*ctlr->card.receive)(ctlr); dp8390outb(ctlr->card.dp8390+Isr, Ovw); wakeup(&ctlr->rr); dp8390outb(ctlr->card.dp8390+Tcr, 0); if(resend) dp8390outb(ctlr->card.dp8390+Cr, Page0|RDMAabort|Txp|Sta); } void dp8390watch(Ctlr *ctlr) { | |
| 1992/1222 | int s; | |
| 1993/0212 | /* * Stub watchdog routine. * Whine if a transmit takes too long. */ | |
| 1992/1222 | s = splhi(); | |
| 1993/0212 | if(ctlr->tbusy){ ctlr->tbusy++; if(ctlr->tbusy > 1 && ctlr->debug) print("TB%d|", ctlr->tbusy); | |
| 1992/1222 | } splx(s); } | |
| 1992/1222/sys/src/9/pc/ether8390.c:488,524 – 1993/0212/sys/src/9/pc/ether8390.c:566,586 | ||
| 1992/1222 | void dp8390intr(Ctlr *ctlr) { | |
| 1993/0212 | uchar isr, r; | |
| 1992/1222 | /* * While there is something of interest, * clear all the interrupts and process. */ | |
| 1993/0212 | dp8390outb(ctlr->card.dp8390+Imr, 0x00); while(isr = dp8390inb(ctlr->card.dp8390+Isr)){ | |
| 1992/1222 | if(isr & Ovw){ | |
| 1993/0212 | if(ctlr->card.overflow) (*ctlr->card.overflow)(ctlr); dp8390outb(ctlr->card.dp8390+Isr, Ovw); | |
| 1992/1222 | ctlr->overflows++; | |
| 1992/1222/sys/src/9/pc/ether8390.c:527,561 – 1993/0212/sys/src/9/pc/ether8390.c:589,631 | ||
| 1992/1222 | * wakeup the kproc. */ if(isr & (Rxe|Prx)){ | |
| 1993/0212 | (*ctlr->card.receive)(ctlr); dp8390outb(ctlr->card.dp8390+Isr, Rxe|Prx); | |
| 1992/1222 | wakeup(&ctlr->rr); } /* | |
| 1993/0212 | r = dp8390inb(ctlr->card.dp8390+Tsr); if(isr & Txe){ if((r & (Cdh|Fu|Crs|Abt)) && ctlr->debug) print("Tsr#%2.2ux|", r); ctlr->oerrs++; } dp8390outb(ctlr->card.dp8390+Isr, Txe|Ptx); if(isr & Ptx) ctlr->outpackets++; | |
| 1992/1222 | ring = &ctlr->tb[ctlr->ti]; ring->owner = Host; | |
| 1993/0212 | ctlr->tbusy = 0; | |
| 1992/1222 | ctlr->ti = NEXT(ctlr->ti, ctlr->ntb); | |
| 1993/0212 | (*ctlr->card.transmit)(ctlr); | |
| 1992/1222 | wakeup(&ctlr->tr); } | |
| 1993/0212 | if(isr & Cnt){ ctlr->frames += dp8390inb(ctlr->card.dp8390+Cntr0); ctlr->crcs += dp8390inb(ctlr->card.dp8390+Cntr1); ctlr->buffs += dp8390inb(ctlr->card.dp8390+Cntr2); dp8390outb(ctlr->card.dp8390+Isr, Cnt); } | |
| 1992/1222 | } | |
| 1993/0212 | dp8390outb(ctlr->card.dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe); | |
| 1992/1222 | } | |