| plan 9 kernel history: overview | file list | diff list |
1993/1116/pc/ether8390.c (diff list | history)
| 1993/0915/sys/src/9/pc/ether8390.c:8,18 – 1993/1116/sys/src/9/pc/ether8390.c:8,18 (short | long | prev | next) | ||
| 1992/1222 | #include "mem.h" #include "dat.h" #include "fns.h" | |
| 1993/1116 | #include "../port/error.h" #include "../port/netif.h" | |
| 1992/1222 |
| |
| 1993/1116 | #include "etherif.h" | |
| 1992/1222 | enum { Cr = 0x00, /* command register, all pages */ | |
| 1993/0915/sys/src/9/pc/ether8390.c:147,158 – 1993/1116/sys/src/9/pc/ether8390.c:147,158 | ||
| 1992/1222 | } Hdr; static void | |
| 1993/1116 | dp8390disable(Ether *ether) | |
| 1992/1222 | { | |
| 1993/0915 | ulong dp8390; | |
| 1992/1222 | int timo; | |
| 1993/0915 |
| |
| 1993/1116 | dp8390 = ether->dp8390; | |
| 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/0915/sys/src/9/pc/ether8390.c:169,264 – 1993/1116/sys/src/9/pc/ether8390.c:169,198 | ||
| 1992/1222 | } | |
| 1993/0212 | static void | |
| 1993/1116 | dp8390ring(Ether *ether) | |
| 1993/0212 | { | |
| 1993/0915 | ulong dp8390; | |
| 1993/0212 | ||
| 1993/0915 |
| |
| 1993/1116 | dp8390 = ether->dp8390; dp8390outb(dp8390+Pstart, ether->pstart); dp8390outb(dp8390+Pstop, ether->pstop); dp8390outb(dp8390+Bnry, ether->pstop-1); | |
| 1993/0212 | ||
| 1993/0915 | dp8390outb(dp8390+Cr, Page1|RDMAabort|Stp); | |
| 1993/1116 | dp8390outb(dp8390+Curr, ether->pstart); | |
| 1993/0915 | dp8390outb(dp8390+Cr, Page0|RDMAabort|Stp); | |
| 1993/0212 |
| |
| 1993/1116 | ether->nxtpkt = ether->pstart; | |
| 1993/0212 | } | |
| 1992/1222 | void | |
| 1993/1116 | dp8390setea(Ether *ether) | |
| 1992/1222 | { | |
| 1993/0915 | ulong dp8390; | |
| 1992/1222 |
| |
| 1993/0212 |
| |
| 1992/1222 |
| |
| 1993/0212 |
| |
| 1993/0915 |
| |
| 1992/1222 |
| |
| 1993/0915 |
| |
| 1992/1222 | ||
| 1993/0915 |
| |
| 1992/1222 | ||
| 1993/0915 |
| |
| 1992/1222 |
| |
| 1993/0212 |
| |
| 1992/1222 |
| |
| 1993/0212 |
| |
| 1993/0915 |
| |
| 1992/1222 | ||
| 1993/0915 |
| |
| 1993/0212 | ||
| 1992/1222 |
| |
| 1993/0213 |
| |
| 1992/1222 |
| |
| 1993/0915 |
| |
| 1992/1222 |
| |
| 1993/0212 |
| |
| 1993/0213 |
| |
| 1992/1222 |
| |
| 1993/0212 |
| |
| 1993/0213 |
| |
| 1992/1222 |
| |
| 1993/0212 |
| |
| 1992/1222 |
| |
| 1993/0212 |
| |
| 1992/1222 |
| |
| 1993/0212 |
| |
| 1992/1222 |
| |
| 1993/0915 |
| |
| 1992/1222 | uchar cr; int i; | |
| 1993/0915 |
| |
| 1993/1116 | dp8390 = ether->dp8390; | |
| 1992/1222 | /* * Set the ethernet address into the chip. * Take care to restore the command register | |
| 1993/0915/sys/src/9/pc/ether8390.c:268,288 – 1993/1116/sys/src/9/pc/ether8390.c:202,222 | ||
| 1992/1222 | */ | |
| 1993/0915 | cr = dp8390inb(dp8390+Cr) & ~Txp; dp8390outb(dp8390+Cr, Page1|(~(Ps1|Ps0) & cr)); | |
| 1992/1222 |
| |
| 1993/0915 |
| |
| 1993/1116 | for(i = 0; i < sizeof(ether->ea); i++) dp8390outb(dp8390+Par0+i, ether->ea[i]); | |
| 1993/0915 | dp8390outb(dp8390+Cr, cr); | |
| 1992/1222 | } | |
| 1993/0915 | void | |
| 1993/1116 | dp8390getea(Ether *ether) | |
| 1993/0915 | { ulong dp8390; uchar cr; int i; | |
| 1993/1116 | dp8390 = ether->dp8390; | |
| 1993/0915 | /* | |
| 1993/1116 | * Get the ethernet address from the chip. | |
| 1993/0915 | * Take care to restore the command register * afterwards. We don't care about multicast * addresses as we never set the multicast | |
| 1993/0915/sys/src/9/pc/ether8390.c:290,308 – 1993/1116/sys/src/9/pc/ether8390.c:224,242 | ||
| 1993/0915 | */ cr = dp8390inb(dp8390+Cr) & ~Txp; dp8390outb(dp8390+Cr, Page1|(~(Ps1|Ps0) & cr)); | |
| 1993/1116 | for(i = 0; i < sizeof(ether->ea); i++) ether->ea[i] = dp8390inb(dp8390+Par0+i); | |
| 1993/0915 | dp8390outb(dp8390+Cr, cr); } | |
| 1992/1222 |
| |
| 1993/1116 | static void* dp8390read(Ether *ether, void *to, ulong from, ulong len) | |
| 1992/1222 | { | |
| 1993/0915 | ulong dp8390; | |
| 1992/1222 | uchar cr; int timo; | |
| 1993/0915 |
| |
| 1993/1116 | dp8390 = ether->dp8390; | |
| 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/0915/sys/src/9/pc/ether8390.c:315,321 – 1993/1116/sys/src/9/pc/ether8390.c:249,255 | ||
| 1992/1222 | /* * Set up the remote DMA address and count. */ | |
| 1993/0212 |
| |
| 1993/1116 | if(ether->bit16) | |
| 1992/1222 | len = ROUNDUP(len, 2); | |
| 1993/0915 | dp8390outb(dp8390+Rbcr0, len & 0xFF); dp8390outb(dp8390+Rbcr1, (len>>8) & 0xFF); | |
| 1993/0915/sys/src/9/pc/ether8390.c:327,336 – 1993/1116/sys/src/9/pc/ether8390.c:261,270 | ||
| 1992/1222 | * out of the I/O port. */ | |
| 1993/0915 | dp8390outb(dp8390+Cr, Page0|RDMAread|Sta); | |
| 1993/0212 |
| |
| 1993/1116 | if(ether->bit16) inss(ether->data, to, len/2); | |
| 1992/1222 | else | |
| 1993/0212 |
| |
| 1993/1116 | insb(ether->data, to, len); | |
| 1992/1222 | /* * Wait for the remote DMA to complete. The timeout | |
| 1993/0915/sys/src/9/pc/ether8390.c:347,359 – 1993/1116/sys/src/9/pc/ether8390.c:281,293 | ||
| 1992/1222 | return to; } | |
| 1993/1116 | static void* dp8390write(Ether *ether, ulong to, void *from, ulong len) | |
| 1992/1222 | { | |
| 1993/0915 | ulong dp8390, crda; | |
| 1992/1222 | uchar cr; | |
| 1993/0915 |
| |
| 1993/1116 | dp8390 = ether->dp8390; | |
| 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 | |
| 1993/0915/sys/src/9/pc/ether8390.c:363,369 – 1993/1116/sys/src/9/pc/ether8390.c:297,303 | ||
| 1993/0915 | dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta); dp8390outb(dp8390+Isr, Rdc); | |
| 1992/1222 | ||
| 1993/0212 |
| |
| 1993/1116 | if(ether->bit16) | |
| 1993/0212 | len = ROUNDUP(len, 2); | |
| 1992/1222 | /* | |
| 1993/0915/sys/src/9/pc/ether8390.c:371,379 – 1993/1116/sys/src/9/pc/ether8390.c:305,313 | ||
| 1993/0212 | * This is straight from the DP8390[12D] datasheet, hence * the initial set up for read. | |
| 1992/1222 | */ | |
| 1993/0212 |
| |
| 1993/0915 |
| |
| 1993/1116 | crda = to-1-ether->bit16; dp8390outb(dp8390+Rbcr0, (len+1+ether->bit16) & 0xFF); dp8390outb(dp8390+Rbcr1, ((len+1+ether->bit16)>>8) & 0xFF); | |
| 1993/0915 | dp8390outb(dp8390+Rsar0, crda & 0xFF); dp8390outb(dp8390+Rsar1, (crda>>8) & 0xFF); dp8390outb(dp8390+Cr, Page0|RDMAread|Sta); | |
| 1993/0915/sys/src/9/pc/ether8390.c:400,409 – 1993/1116/sys/src/9/pc/ether8390.c:334,343 | ||
| 1992/1222 | /* | |
| 1993/0212 | * Pump the data into the I/O port. | |
| 1992/1222 | */ | |
| 1993/0212 |
| |
| 1993/1116 | if(ether->bit16) outss(ether->data, from, len/2); | |
| 1992/1222 | else | |
| 1993/0212 |
| |
| 1993/1116 | outsb(ether->data, from, len); | |
| 1992/1222 | /* * Wait for the remote DMA to finish. We'll need | |
| 1993/0915/sys/src/9/pc/ether8390.c:431,487 – 1993/1116/sys/src/9/pc/ether8390.c:365,394 | ||
| 1993/0212 | } | |
| 1993/0213 | static void | |
| 1993/0915 |
| |
| 1993/1116 | receive(Ether *ether) | |
| 1993/0213 | { | |
| 1993/0915 |
| |
| 1993/0213 |
| |
| 1993/0915 |
| |
| 1993/0213 |
| |
| 1992/1222 |
| |
| 1993/0212 | uchar curr, len1, *pkt; | |
| 1992/1222 | Hdr hdr; | |
| 1993/0915 | ulong dp8390, data, len; | |
| 1993/1116 | ushort type; Netfile *f, **fp, **ep; | |
| 1992/1222 | ||
| 1993/0915 |
| |
| 1993/0213 |
| |
| 1993/0915 |
| |
| 1993/1116 | dp8390 = ether->dp8390; for(curr = getcurr(dp8390); ether->nxtpkt != curr; curr = getcurr(dp8390)){ ether->inpackets++; | |
| 1992/1222 |
| |
| 1993/1116 | data = ether->nxtpkt*Dp8390BufSz; (*ether->read)(ctlr, &hdr, data, sizeof(Hdr)); | |
| 1992/1222 | ||
| 1993/0212 |
| |
| 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 |
| |
| 1993/1116 | if(hdr.next > ether->nxtpkt) len1 = hdr.next - ether->nxtpkt - 1; | |
| 1993/0212 | else | |
| 1993/1116 | len1 = (ether->pstop-ether->nxtpkt) + (hdr.next-ether->pstart) - 1; | |
| 1993/0212 | if(hdr.len0 > (Dp8390BufSz-sizeof(Hdr))) len1--; | |
| 1993/0915/sys/src/9/pc/ether8390.c:490,530 – 1993/1116/sys/src/9/pc/ether8390.c:397,442 | ||
| 1993/0212 | /* * Chip is badly scrogged, reinitialise the ring. */ | |
| 1993/1116 | if(hdr.next < ether->pstart || hdr.next >= ether->pstop | |
| 1993/0212 | || 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); | |
| 1993/0915 | dp8390outb(dp8390+Cr, Page0|RDMAabort|Stp); | |
| 1993/0212 |
| |
| 1993/1116 | dp8390ring(ether); | |
| 1993/0915 | dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta); | |
| 1992/1222 | return; } | |
| 1993/0212 | /* | |
| 1993/1116 | * If it's a good packet read it in to the software buffer. * If the packet wraps round the hardware ring, read it in two pieces. | |
| 1993/0212 | */ | |
| 1992/1222 |
| |
| 1993/0212 |
| |
| 1993/1116 | if((hdr.status & (Fo|Fae|Crce|Prxok)) == Prxok){ pkt = ether->rpkt; | |
| 1992/1222 | data += sizeof(Hdr); | |
| 1993/0212 | ring->len = len; | |
| 1993/1116 | if((data+len) >= ether->pstop*Dp8390BufSz){ ulong count = ether->pstop*Dp8390BufSz - data; | |
| 1993/0212 |
| |
| 1993/1116 | (*ether->read)(ctlr, pkt, data, count); | |
| 1993/0212 | pkt += count; | |
| 1993/1116 | data = ether->pstart*Dp8390BufSz; | |
| 1993/0212 | len -= count; | |
| 1992/1222 | } | |
| 1993/0212 | if(len) | |
| 1993/1116 | (*ether->read)(ctlr, pkt, data, len); | |
| 1993/0212 | ||
| 1992/1222 |
| |
| 1993/1116 | /* * Copy the packet to whoever wants it. */ type = (ether->rpkt.type[0]<<8)|ether->rpkt.type[1]; ep = ðer->f[Ntypes]; for(fp = ether->f; fp < ep; fp++) { f = *fp; if(f && (f->type == type || f->type < 0)) qproduce(f->in, ðer->rpkt, len); } | |
| 1992/1222 | } | |
| 1993/0212 | /* | |
| 1993/0915/sys/src/9/pc/ether8390.c:531,541 – 1993/1116/sys/src/9/pc/ether8390.c:443,453 | ||
| 1993/0212 | * Finished woth this packet, update the * hardware and software ring pointers. */ | |
| 1993/1116 | ether->nxtpkt = hdr.next; | |
| 1993/0212 | hdr.next--; | |
| 1993/1116 | if(hdr.next < ether->pstart) hdr.next = ether->pstop-1; | |
| 1993/0915 | dp8390outb(dp8390+Bnry, hdr.next); | |
| 1992/1222 | } } | |
| 1993/0915/sys/src/9/pc/ether8390.c:544,561 – 1993/1116/sys/src/9/pc/ether8390.c:456,473 | ||
| 1993/0212 | * Initiate a transmission. Must be called splhi(). */ | |
| 1992/1222 | void | |
| 1993/1116 | dp8390transmit(Ether *ether) | |
| 1992/1222 | { | |
| 1993/0915 | ulong dp8390; | |
| 1992/1222 | RingBuf *ring; | |
| 1993/0212 | ||
| 1993/0915 |
| |
| 1993/0212 |
| |
| 1993/1116 | dp8390 = ether->dp8390; ring = ðer->tb[ether->ti]; if(ether->tbusy == 0 && ring->owner == Interface){ | |
| 1993/0213 |
| |
| 1993/1116 | ether->tbusy = 1; | |
| 1993/0213 | ||
| 1993/0212 |
| |
| 1993/1116 | (*ether->write)(ctlr, ether->tstart*Dp8390BufSz, ring->pkt, ring->len); | |
| 1993/0213 | ||
| 1993/0915 | dp8390outb(dp8390+Tbcr0, ring->len & 0xFF); dp8390outb(dp8390+Tbcr1, (ring->len>>8) & 0xFF); | |
| 1993/0915/sys/src/9/pc/ether8390.c:563,576 – 1993/1116/sys/src/9/pc/ether8390.c:475,488 | ||
| 1993/0212 | } } | |
| 1993/1116 | static void overflow(Ether *ether) | |
| 1993/0212 | { | |
| 1993/0915 | ulong dp8390; | |
| 1993/0212 | uchar txp; int resend; | |
| 1993/0915 |
| |
| 1993/1116 | dp8390 = ether->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/sys/src/9/pc/ether8390.c:587,595 – 1993/1116/sys/src/9/pc/ether8390.c:499,507 | ||
| 1993/0212 | ||
| 1993/0915 | dp8390outb(dp8390+Tcr, Lb); dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta); | |
| 1993/0212 |
| |
| 1993/1116 | (*ether->receive)(ether); | |
| 1993/0915 | dp8390outb(dp8390+Isr, Ovw); | |
| 1993/0212 |
| |
| 1993/1116 | wakeup(ðer->rr); | |
| 1993/0915 | dp8390outb(dp8390+Tcr, 0); | |
| 1993/0212 | if(resend) | |
| 1993/0915/sys/src/9/pc/ether8390.c:596,627 – 1993/1116/sys/src/9/pc/ether8390.c:508,520 | ||
| 1993/0915 | dp8390outb(dp8390+Cr, Page0|RDMAabort|Txp|Sta); | |
| 1993/0212 | } | |
| 1993/1116 | static void interrupt(Ether *ether) | |
| 1993/0212 | { | |
| 1992/1222 |
| |
| 1993/0212 |
| |
| 1992/1222 |
| |
| 1993/0212 |
| |
| 1992/1222 |
| |
| 1993/0915 | ulong dp8390; | |
| 1992/1222 |
| |
| 1993/0212 | uchar isr, r; | |
| 1992/1222 | ||
| 1993/0915 |
| |
| 1993/1116 | dp8390 = ether->dp8390; | |
| 1992/1222 | /* * While there is something of interest, * clear all the interrupts and process. | |
| 1993/0915/sys/src/9/pc/ether8390.c:630,650 – 1993/1116/sys/src/9/pc/ether8390.c:523,540 | ||
| 1993/0915 | while(isr = dp8390inb(dp8390+Isr)){ | |
| 1992/1222 | if(isr & Ovw){ | |
| 1993/0212 |
| |
| 1993/1116 | overflow(ether); | |
| 1993/0915 | dp8390outb(dp8390+Isr, Ovw); | |
| 1992/1222 |
| |
| 1993/1116 | ether->overflows++; | |
| 1992/1222 | } /* * We have received packets. | |
| 1993/1116 | * Take a spin round the ring. and | |
| 1992/1222 | */ if(isr & (Rxe|Prx)){ | |
| 1993/0212 |
| |
| 1993/1116 | receive(ether); | |
| 1993/0915 | dp8390outb(dp8390+Isr, Rxe|Prx); | |
| 1992/1222 |
| |
| 1993/0915/sys/src/9/pc/ether8390.c:655,684 – 1993/1116/sys/src/9/pc/ether8390.c:545,646 | ||
| 1992/1222 | if(isr & (Txe|Ptx)){ | |
| 1993/0915 | r = dp8390inb(dp8390+Tsr); | |
| 1993/0212 | if(isr & Txe){ | |
| 1993/1116 | if((r & (Cdh|Fu|Crs|Abt)) && ether->debug) | |
| 1993/0212 | print("Tsr#%2.2ux|", r); | |
| 1993/1116 | ether->oerrs++; | |
| 1993/0212 | } | |
| 1993/0915 | dp8390outb(dp8390+Isr, Txe|Ptx); | |
| 1993/0212 | if(isr & Ptx) | |
| 1992/1222 |
| |
| 1993/0212 |
| |
| 1992/1222 |
| |
| 1993/0212 |
| |
| 1992/1222 |
| |
| 1993/1116 | ether->outpackets++; wakeup(ðer->tr); | |
| 1992/1222 | } | |
| 1993/0212 | if(isr & Cnt){ | |
| 1993/0915 |
| |
| 1993/1116 | ether->frames += dp8390inb(dp8390+Cntr0); ether->crcs += dp8390inb(dp8390+Cntr1); ether->buffs += dp8390inb(dp8390+Cntr2); | |
| 1993/0915 | dp8390outb(dp8390+Isr, Cnt); | |
| 1993/0212 | } | |
| 1992/1222 | } | |
| 1993/0915 | dp8390outb(dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe); | |
| 1993/1116 | } static void promiscuous(Ether *ether, int on) { /* * Set/reset promiscuous mode. */ if(on) dp8390outb(ether->dp8390+Rcr, Pro|Ab); else dp8390outb(ether->dp8390+Rcr, Ab); } void dp8390attach(Ether *ether) { /* * Enable the chip for transmit/receive. * The init routine leaves the chip in monitor * mode. Clear the missed-packet counter, it * increments while in monitor mode. */ dp8390outb(ether->dp8390+Rcr, Ab); dp8390inb(ether->dp8390+Cntr2); } static int dp8390reset(Ether *ether) { ulong dp8390; dp8390 = ether->dp8390; /* * This is the initialisation procedure described * as 'mandatory' in the datasheet, with references * to the 3Com503 technical reference manual. */ dp8390disable(ether); if(ether->bit16) dp8390outb(dp8390+Dcr, Ft4|Ls|Wts); else dp8390outb(dp8390+Dcr, Ft4|Ls); dp8390outb(dp8390+Rbcr0, 0); dp8390outb(dp8390+Rbcr1, 0); dp8390outb(dp8390+Tcr, 0); dp8390outb(dp8390+Rcr, Mon); /* * Init the ring hardware and software ring pointers. * Can't initialise ethernet address as we may not know * it yet. */ dp8390ring(ether); dp8390outb(dp8390+Tpsr, ether->tstart); dp8390outb(dp8390+Isr, 0xFF); dp8390outb(dp8390+Imr, Cnte|Ovwe|Txee|Rxee|Ptxe|Prxe); /* * Leave the chip initialised, * but in monitor mode. */ dp8390outb(dp8390+Cr, Page0|RDMAabort|Sta); /* * Set up the software configuration. */ ether->attach = attach; ether->write = write; ether->interrupt = interrupt; ether->promiscuous = promiscuous; ether->arg = ether; return 0; | |
| 1992/1222 | } | |