| plan 9 kernel history: overview | file list | diff list |
1993/1118/pc/ether8390.c (diff list | history)
| 1993/1117/sys/src/9/pc/ether8390.c:14,19 – 1993/1118/sys/src/9/pc/ether8390.c:14,22 (short | long | prev | next) | ||
| 1992/1222 | ||
| 1993/1116 | #include "etherif.h" | |
| 1992/1222 | ||
| 1993/1118 | extern int dp8390inb(ulong); extern void dp8390outb(ulong, uchar); | |
| 1992/1222 | enum { Cr = 0x00, /* command register, all pages */ | |
| 1993/1117/sys/src/9/pc/ether8390.c:149,158 – 1993/1118/sys/src/9/pc/ether8390.c:152,160 | ||
| 1992/1222 | static void | |
| 1993/1117 | dp8390disable(Dp8390 *dp8390) | |
| 1992/1222 | { | |
| 1993/1117 |
| |
| 1993/1118 | ulong port = dp8390->dp8390; | |
| 1992/1222 | int timo; | |
| 1993/1117 |
| |
| 1992/1222 | /* * Stop the chip. Set the Stp bit and wait for the chip * to finish whatever was on its tiny mind before it sets | |
| 1993/1117/sys/src/9/pc/ether8390.c:171,179 – 1993/1118/sys/src/9/pc/ether8390.c:173,180 | ||
| 1993/0212 | static void | |
| 1993/1117 | dp8390ring(Dp8390 *dp8390) | |
| 1993/0212 | { | |
| 1993/1117 |
| |
| 1993/1118 | ulong port = dp8390->dp8390; | |
| 1993/0212 | ||
| 1993/1117 |
| |
| 1993/1117/sys/src/9/pc/ether8390.c:188,198 – 1993/1118/sys/src/9/pc/ether8390.c:189,198 | ||
| 1992/1222 | void | |
| 1993/1116 | dp8390setea(Ether *ether) | |
| 1992/1222 | { | |
| 1993/1117 |
| |
| 1993/1118 | ulong port = ((Dp8390*)ether->private)->dp8390; | |
| 1992/1222 | uchar cr; int i; | |
| 1993/1117 |
| |
| 1992/1222 | /* * Set the ethernet address into the chip. * Take care to restore the command register | |
| 1993/1117/sys/src/9/pc/ether8390.c:210,220 – 1993/1118/sys/src/9/pc/ether8390.c:210,219 | ||
| 1993/0915 | void | |
| 1993/1116 | dp8390getea(Ether *ether) | |
| 1993/0915 | { | |
| 1993/1117 |
| |
| 1993/1118 | ulong port = ((Dp8390*)ether->private)->dp8390; | |
| 1993/0915 | uchar cr; int i; | |
| 1993/1117 |
| |
| 1993/0915 | /* | |
| 1993/1116 | * Get the ethernet address from the chip. | |
| 1993/0915 | * Take care to restore the command register | |
| 1993/1117/sys/src/9/pc/ether8390.c:232,242 – 1993/1118/sys/src/9/pc/ether8390.c:231,240 | ||
| 1993/1116 | static void* | |
| 1993/1117 | dp8390read(Dp8390 *dp8390, void *to, ulong from, ulong len) | |
| 1992/1222 | { | |
| 1993/1117 |
| |
| 1993/1118 | ulong port = dp8390->dp8390; | |
| 1992/1222 | uchar cr; int timo; | |
| 1993/1117 |
| |
| 1992/1222 | /* | |
| 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 | |
| 1993/1117/sys/src/9/pc/ether8390.c:282,303 – 1993/1118/sys/src/9/pc/ether8390.c:280,301 | ||
| 1992/1222 | } | |
| 1993/1116 | static void* | |
| 1993/1118 | dp8390write(Dp8390 *dp8390, ulong to, void *from, ulong len) | |
| 1992/1222 | { | |
| 1993/0915 |
| |
| 1993/1118 | ulong port = dp8390->dp8390; ulong crda; | |
| 1992/1222 | uchar cr; | |
| 1993/1117 |
| |
| 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/0915 |
| |
| 1993/1118 | cr = dp8390inb(port+Cr) & ~Txp; dp8390outb(port+Cr, Page0|RDMAabort|Sta); dp8390outb(port+Isr, Rdc); | |
| 1992/1222 | ||
| 1993/1116 |
| |
| 1993/1118 | if(dp8390->bit16) | |
| 1993/0212 | len = ROUNDUP(len, 2); | |
| 1992/1222 | /* | |
| 1993/1117/sys/src/9/pc/ether8390.c:305,329 – 1993/1118/sys/src/9/pc/ether8390.c:303,327 | ||
| 1993/0212 | * This is straight from the DP8390[12D] datasheet, hence * the initial set up for read. | |
| 1992/1222 | */ | |
| 1993/1116 |
| |
| 1993/0915 |
| |
| 1993/1118 | crda = to-1-dp8390->bit16; dp8390outb(port+Rbcr0, (len+1+dp8390->bit16) & 0xFF); dp8390outb(port+Rbcr1, ((len+1+dp8390->bit16)>>8) & 0xFF); dp8390outb(port+Rsar0, crda & 0xFF); dp8390outb(port+Rsar1, (crda>>8) & 0xFF); dp8390outb(port+Cr, Page0|RDMAread|Sta); | |
| 1992/1222 | ||
| 1993/0212 | for(;;){ | |
| 1993/0915 |
| |
| 1993/1118 | crda = dp8390inb(port+Crda0); crda |= dp8390inb(port+Crda1)<<8; | |
| 1993/0212 | if(crda == to){ /* * Start the remote DMA write and make sure * the registers are correct. */ | |
| 1993/0915 |
| |
| 1993/1118 | dp8390outb(port+Cr, Page0|RDMAwrite|Sta); | |
| 1992/1222 | ||
| 1993/0915 |
| |
| 1993/1118 | crda = dp8390inb(port+Crda0); crda |= dp8390inb(port+Crda1)<<8; | |
| 1993/0212 | if(crda != to) panic("crda write %d to %d\n", crda, to); | |
| 1993/1117/sys/src/9/pc/ether8390.c:334,343 – 1993/1118/sys/src/9/pc/ether8390.c:332,341 | ||
| 1992/1222 | /* | |
| 1993/0212 | * Pump the data into the I/O port. | |
| 1992/1222 | */ | |
| 1993/1116 |
| |
| 1993/1118 | if(dp8390->bit16) outss(dp8390->data, from, len/2); | |
| 1992/1222 | else | |
| 1993/1116 |
| |
| 1993/1118 | outsb(dp8390->data, from, len); | |
| 1992/1222 | /* * Wait for the remote DMA to finish. We'll need | |
| 1993/1117/sys/src/9/pc/ether8390.c:344,366 – 1993/1118/sys/src/9/pc/ether8390.c:342,365 | ||
| 1992/1222 | * a timeout here if this ever gets called before * we know there really is a chip there. */ | |
| 1993/0915 |
| |
| 1993/1118 | while((dp8390inb(port+Isr) & Rdc) == 0) | |
| 1992/1222 | ; | |
| 1993/0915 |
| |
| 1993/1118 | dp8390outb(port+Isr, Rdc); dp8390outb(port+Cr, cr); | |
| 1992/1222 | return (void*)to; } | |
| 1993/0212 | static uchar | |
| 1993/0915 |
| |
| 1993/1118 | getcurr(Dp8390 *dp8390) | |
| 1993/0212 | { | |
| 1993/1118 | ulong port = dp8390->dp8390; | |
| 1993/0212 | uchar cr, curr; | |
| 1993/0915 |
| |
| 1993/1118 | cr = dp8390inb(port+Cr) & ~Txp; dp8390outb(port+Cr, Page1|(~(Ps1|Ps0) & cr)); curr = dp8390inb(port+Curr); dp8390outb(port+Cr, cr); | |
| 1993/0212 | return curr; } | |
| 1993/1117/sys/src/9/pc/ether8390.c:367,384 – 1993/1118/sys/src/9/pc/ether8390.c:366,388 | ||
| 1993/0213 | static void | |
| 1993/1116 | receive(Ether *ether) | |
| 1993/0213 | { | |
| 1993/0212 |
| |
| 1993/1118 | Dp8390 *dp8390; uchar curr, *pkt; | |
| 1992/1222 | Hdr hdr; | |
| 1993/0915 |
| |
| 1993/1118 | ulong port, data, len, len1; | |
| 1993/1116 | ushort type; Netfile *f, **fp, **ep; | |
| 1992/1222 | ||
| 1993/1117 |
| |
| 1993/1116 |
| |
| 1993/1118 | dp8390 = ether->private; port = dp8390->dp8390; for(curr = getcurr(dp8390); dp8390->nxtpkt != curr; curr = getcurr(dp8390)){ | |
| 1993/1116 | ether->inpackets++; | |
| 1992/1222 | ||
| 1993/1116 |
| |
| 1993/1118 | data = dp8390->nxtpkt*Dp8390BufSz; if(dp8390->ram) memmove(&hdr, (void*)(ether->mem+data), sizeof(Hdr)); else dp8390read(dp8390, &hdr, data, sizeof(Hdr)); | |
| 1992/1222 | /* | |
| 1993/0212 | * Don't believe the upper byte count, work it | |
| 1993/1117/sys/src/9/pc/ether8390.c:385,394 – 1993/1118/sys/src/9/pc/ether8390.c:389,398 | ||
| 1993/0212 | * out from the software next-page pointer and * the current next-page pointer. | |
| 1992/1222 | */ | |
| 1993/1116 |
| |
| 1993/1118 | if(hdr.next > dp8390->nxtpkt) len1 = hdr.next - dp8390->nxtpkt - 1; | |
| 1993/0212 | else | |
| 1993/1116 |
| |
| 1993/1118 | len1 = (dp8390->pstop-dp8390->nxtpkt) + (hdr.next-dp8390->pstart) - 1; | |
| 1993/0212 | if(hdr.len0 > (Dp8390BufSz-sizeof(Hdr))) len1--; | |
| 1993/1117/sys/src/9/pc/ether8390.c:397,409 – 1993/1118/sys/src/9/pc/ether8390.c:401,413 | ||
| 1993/0212 | /* * Chip is badly scrogged, reinitialise the ring. */ | |
| 1993/1116 |
| |
| 1993/1118 | if(hdr.next < dp8390->pstart || hdr.next >= dp8390->pstop | |
| 1993/0212 | || len < 60 || len > sizeof(Etherpkt)){ | |
| 1993/1118 | print("dp8390: H#%2.2ux#%2.2ux#%2.2ux#%2.2ux,%d\n", | |
| 1993/0212 | hdr.status, hdr.next, hdr.len0, hdr.len1, len); | |
| 1993/0915 |
| |
| 1993/1116 |
| |
| 1993/0915 |
| |
| 1993/1118 | dp8390outb(port+Cr, Page0|RDMAabort|Stp); dp8390ring(dp8390); dp8390outb(port+Cr, Page0|RDMAabort|Sta); | |
| 1992/1222 | return; } | |
| 1993/1117/sys/src/9/pc/ether8390.c:412,431 – 1993/1118/sys/src/9/pc/ether8390.c:416,442 | ||
| 1993/1116 | * If the packet wraps round the hardware ring, read it in two pieces. | |
| 1993/0212 | */ | |
| 1993/1116 | if((hdr.status & (Fo|Fae|Crce|Prxok)) == Prxok){ | |
| 1993/1118 | pkt = (uchar*)ðer->rpkt; | |
| 1992/1222 | data += sizeof(Hdr); | |
| 1993/0212 |
| |
| 1993/1118 | len1 = len; | |
| 1993/0212 | ||
| 1993/1116 |
| |
| 1993/1118 | if((data+len1) >= dp8390->pstop*Dp8390BufSz){ ulong count = dp8390->pstop*Dp8390BufSz - data; | |
| 1993/0212 | ||
| 1993/1116 |
| |
| 1993/1118 | if(dp8390->ram) memmove(pkt, (void*)(ether->mem+data), count); else dp8390read(dp8390, pkt, data, count); | |
| 1993/0212 | pkt += count; | |
| 1993/1116 |
| |
| 1993/0212 |
| |
| 1993/1118 | data = dp8390->pstart*Dp8390BufSz; len1 -= count; | |
| 1992/1222 | } | |
| 1993/0212 |
| |
| 1993/1116 |
| |
| 1993/1118 | if(len1){ if(dp8390->ram) memmove(pkt, (void*)(ether->mem+data), len1); else dp8390read(dp8390, pkt, data, len1); } | |
| 1993/0212 | ||
| 1993/1116 | /* * Copy the packet to whoever wants it. | |
| 1993/1117/sys/src/9/pc/ether8390.c:440,530 – 1993/1118/sys/src/9/pc/ether8390.c:451,564 | ||
| 1992/1222 | } | |
| 1993/0212 | /* | |
| 1993/1118 | * Finished with this packet, update the | |
| 1993/0212 | * hardware and software ring pointers. */ | |
| 1993/1116 |
| |
| 1993/1118 | dp8390->nxtpkt = hdr.next; | |
| 1993/0212 | hdr.next--; | |
| 1993/1116 |
| |
| 1993/0915 |
| |
| 1993/1118 | if(hdr.next < dp8390->pstart) hdr.next = dp8390->pstop-1; dp8390outb(port+Bnry, hdr.next); | |
| 1992/1222 | } } | |
| 1993/0212 |
| |
| 1992/1222 |
| |
| 1993/1116 |
| |
| 1993/1118 | static int istxbusy(void *arg) | |
| 1992/1222 | { | |
| 1993/0915 |
| |
| 1992/1222 |
| |
| 1993/1118 | return ((Dp8390*)arg)->busy == 0; } | |
| 1993/0212 | ||
| 1993/1117 |
| |
| 1993/1116 |
| |
| 1993/1118 | static long write(Ether *ether, void *buf, long n) { Dp8390 *dp8390; ulong port; | |
| 1993/0213 | ||
| 1993/1116 |
| |
| 1993/1118 | dp8390 = ether->private; port = dp8390->dp8390; | |
| 1993/0213 | ||
| 1993/1116 |
| |
| 1993/0213 | ||
| 1993/0915 |
| |
| 1993/1118 | qlock(ðer->tlock); if(waserror()) { qunlock(ðer->tlock); nexterror(); | |
| 1993/0212 | } | |
| 1993/1118 | tsleep(ðer->tr, istxbusy, dp8390, 10000); if(dp8390->busy) print("dp8390: transmitter jammed\n"); dp8390->busy = 1; if(dp8390->ram) memmove((void*)(ether->mem+dp8390->tstart*Dp8390BufSz), buf, n); else dp8390write(dp8390, dp8390->tstart*Dp8390BufSz, buf, n); dp8390outb(port+Tbcr0, n & 0xFF); dp8390outb(port+Tbcr1, (n>>8) & 0xFF); dp8390outb(port+Cr, Page0|RDMAabort|Txp|Sta); poperror(); qunlock(ðer->tlock); return n; | |
| 1993/0212 | } | |
| 1993/1116 | static void overflow(Ether *ether) | |
| 1993/0212 | { | |
| 1993/0915 |
| |
| 1993/1118 | Dp8390 *dp8390; ulong port; | |
| 1993/0212 | uchar txp; int resend; | |
| 1993/1117 |
| |
| 1993/1118 | dp8390 = ether->private; port = dp8390->dp8390; | |
| 1993/0212 | /* * The following procedure is taken from the DP8390[12D] datasheet, * it seems pretty adamant that this is what has to be done. */ | |
| 1993/0915 |
| |
| 1993/1118 | txp = dp8390inb(port+Cr) & Txp; dp8390outb(port+Cr, Page0|RDMAabort|Stp); | |
| 1993/0212 | delay(2); | |
| 1993/0915 |
| |
| 1993/1118 | dp8390outb(port+Rbcr0, 0); dp8390outb(port+Rbcr1, 0); | |
| 1993/0212 | resend = 0; | |
| 1993/0915 |
| |
| 1993/1118 | if(txp && (dp8390inb(port+Isr) & (Txe|Ptx)) == 0) | |
| 1993/0212 | resend = 1; | |
| 1993/0915 |
| |
| 1993/1116 |
| |
| 1993/0915 |
| |
| 1993/1116 |
| |
| 1993/0915 |
| |
| 1993/1118 | dp8390outb(port+Tcr, Lb); dp8390outb(port+Cr, Page0|RDMAabort|Sta); receive(ether); dp8390outb(port+Isr, Ovw); dp8390outb(port+Tcr, 0); | |
| 1993/0212 | if(resend) | |
| 1993/0915 |
| |
| 1993/1118 | dp8390outb(port+Cr, Page0|RDMAabort|Txp|Sta); | |
| 1993/0212 | } | |
| 1993/1116 | static void interrupt(Ether *ether) | |
| 1993/0212 | { | |
| 1993/0915 |
| |
| 1993/1118 | Dp8390 *dp8390; ulong port; | |
| 1993/0212 | uchar isr, r; | |
| 1992/1222 | ||
| 1993/1117 |
| |
| 1993/1118 | dp8390 = ether->private; port = dp8390->dp8390; | |
| 1992/1222 | /* * While there is something of interest, * clear all the interrupts and process. */ | |
| 1993/0915 |
| |
| 1993/1118 | dp8390outb(port+Imr, 0x00); while(isr = dp8390inb(port+Isr)){ | |
| 1992/1222 | if(isr & Ovw){ | |
| 1993/1116 | overflow(ether); | |
| 1993/0915 |
| |
| 1993/1118 | dp8390outb(port+Isr, Ovw); | |
| 1993/1116 | ether->overflows++; | |
| 1992/1222 | } | |
| 1993/1117/sys/src/9/pc/ether8390.c:534,540 – 1993/1118/sys/src/9/pc/ether8390.c:568,574 | ||
| 1992/1222 | */ if(isr & (Rxe|Prx)){ | |
| 1993/1116 | receive(ether); | |
| 1993/0915 |
| |
| 1993/1118 | dp8390outb(port+Isr, Rxe|Prx); | |
| 1992/1222 | } /* | |
| 1993/1117/sys/src/9/pc/ether8390.c:543,593 – 1993/1118/sys/src/9/pc/ether8390.c:577,626 | ||
| 1992/1222 | * and wake the output routine. */ if(isr & (Txe|Ptx)){ | |
| 1993/0915 |
| |
| 1993/1118 | r = dp8390inb(port+Tsr); | |
| 1993/0212 | if(isr & Txe){ | |
| 1993/1116 |
| |
| 1993/0212 |
| |
| 1993/1118 | if((r & (Cdh|Fu|Crs|Abt))) print("dp8390: Tsr#%2.2ux\n", r); | |
| 1993/1116 | ether->oerrs++; | |
| 1993/0212 | } | |
| 1993/0915 |
| |
| 1993/1118 | dp8390outb(port+Isr, Txe|Ptx); | |
| 1993/0212 | if(isr & Ptx) | |
| 1993/1116 | ether->outpackets++; | |
| 1993/1118 | dp8390->busy = 0; | |
| 1993/1116 | wakeup(ðer->tr); | |
| 1992/1222 | } | |
| 1993/0212 | if(isr & Cnt){ | |
| 1993/1116 |
| |
| 1993/0915 |
| |
| 1993/1118 | ether->frames += dp8390inb(port+Cntr0); ether->crcs += dp8390inb(port+Cntr1); ether->buffs += dp8390inb(port+Cntr2); dp8390outb(port+Isr, Cnt); | |
| 1993/0212 | } | |
| 1992/1222 | } | |
| 1993/0915 |
| |
| 1993/1118 | dp8390outb(port+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe); | |
| 1993/1116 | } static void | |
| 1993/1118 | promiscuous(void *arg, int on) | |
| 1993/1116 | { | |
| 1993/1117 |
| |
| 1993/1118 | Dp8390 *dp8390 = ((Ether*)arg)->private; | |
| 1993/1117 |
| |
| 1993/1116 | /* * Set/reset promiscuous mode. */ if(on) | |
| 1993/1118 | dp8390outb(dp8390->dp8390+Rcr, Pro|Ab); | |
| 1993/1116 | else | |
| 1993/1118 | dp8390outb(dp8390->dp8390+Rcr, Ab); | |
| 1993/1116 | } | |
| 1993/1118 | static void attach(Ether *ether) | |
| 1993/1116 | { | |
| 1993/1117 |
| |
| 1993/1118 | Dp8390 *dp8390 = ether->private; | |
| 1993/1117 |
| |
| 1993/1116 | /* * Enable the chip for transmit/receive. * The init routine leaves the chip in monitor | |
| 1993/1117/sys/src/9/pc/ether8390.c:594,625 – 1993/1118/sys/src/9/pc/ether8390.c:627,661 | ||
| 1993/1116 | * mode. Clear the missed-packet counter, it * increments while in monitor mode. */ | |
| 1993/1118 | dp8390outb(dp8390->dp8390+Rcr, Ab); dp8390inb(dp8390->dp8390+Cntr2); | |
| 1993/1116 | } | |
| 1993/1118 | int | |
| 1993/1116 | dp8390reset(Ether *ether) { | |
| 1993/1118 | Dp8390 *dp8390; ulong port; | |
| 1993/1116 | ||
| 1993/1117 |
| |
| 1993/1118 | dp8390 = ether->private; port = dp8390->dp8390; | |
| 1993/1116 | /* * This is the initialisation procedure described * as 'mandatory' in the datasheet, with references * to the 3Com503 technical reference manual. */ | |
| 1993/1118 | dp8390disable(dp8390); if(dp8390->bit16) dp8390outb(port+Dcr, Ft4|Ls|Wts); | |
| 1993/1116 | else | |
| 1993/1118 | dp8390outb(port+Dcr, Ft4|Ls); | |
| 1993/1116 |
| |
| 1993/1118 | dp8390outb(port+Rbcr0, 0); dp8390outb(port+Rbcr1, 0); | |
| 1993/1116 |
| |
| 1993/1118 | dp8390outb(port+Tcr, 0); dp8390outb(port+Rcr, Mon); | |
| 1993/1116 | /* * Init the ring hardware and software ring pointers. | |
| 1993/1117/sys/src/9/pc/ether8390.c:626,642 – 1993/1118/sys/src/9/pc/ether8390.c:662,678 | ||
| 1993/1116 | * Can't initialise ethernet address as we may not know * it yet. */ | |
| 1993/1118 | dp8390ring(dp8390); dp8390outb(port+Tpsr, dp8390->tstart); | |
| 1993/1116 |
| |
| 1993/1118 | dp8390outb(port+Isr, 0xFF); dp8390outb(port+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe); | |
| 1993/1116 | /* * Leave the chip initialised, * but in monitor mode. */ | |
| 1993/1118 | dp8390outb(port+Cr, Page0|RDMAabort|Sta); | |
| 1993/1116 | /* * Set up the software configuration. | |