| plan 9 kernel history: overview | file list | diff list |
pc/ether82557.c (diff list | history)
| 1996/0418/sys/src/9/pc/ether82557.c:108,115 – 1996/0419/sys/src/9/pc/ether82557.c:108,113 (short | long) | ||
| 1996/0418 | ushort size; Etherpkt; | |
| 1996/0418/sys/src/9/pc/ether82557.c:437,444 – 1996/0419/sys/src/9/pc/ether82557.c:435,440 | ||
| 1996/0418 | rfd->rbd = NullPointer; rfd->count = 0; rfd->size = sizeof(Etherpkt); | |
| 1996/0419/sys/src/9/pc/ether82557.c:6,11 – 1996/0423/sys/src/9/pc/ether82557.c:6,13 (short | long) | ||
| 1996/0418 | * the PCI scanning code could be made common to other adapters; * PCI code needs rewritten to handle byte, word, dword accesses * and using the devno as a bus+dev+function triplet; | |
| 1996/0423 | * tidy/fix locking; * optionally use memory-mapped registers; | |
| 1996/0418 | * stats. */ #include "u.h" | |
| 1996/0419/sys/src/9/pc/ether82557.c:30,36 – 1996/0423/sys/src/9/pc/ether82557.c:32,38 | ||
| 1996/0418 | Ack = 0x01, /* byte */ Command = 0x02, /* byte or word (word includes Interrupt) */ Interrupt = 0x03, /* byte */ | |
| 1996/0423 | General = 0x04, /* dword */ | |
| 1996/0418 | Port = 0x08, /* dword */ Fcr = 0x0C, /* Flash control register */ Ecr = 0x0E, /* EEPROM control register */ | |
| 1996/0419/sys/src/9/pc/ether82557.c:156,162 – 1996/0423/sys/src/9/pc/ether82557.c:158,164 | ||
| 1996/0418 | CbC = 0x00008000, /* execution Complete */ CbNOP = 0x00000000, | |
| 1996/0423 | CbIAS = 0x00010000, /* Individual Address Setup */ | |
| 1996/0418 | CbConfigure = 0x00020000, CbMAS = 0x00030000, /* Multicast Address Setup */ CbTransmit = 0x00040000, | |
| 1996/0419/sys/src/9/pc/ether82557.c:237,243 – 1996/0423/sys/src/9/pc/ether82557.c:239,245 | ||
| 1996/0418 | } ctlr->cbqbusy = 1; | |
| 1996/0423 | csr32w(ctlr, General, PADDR(ctlr->cbqhead->rp)); | |
| 1996/0418 | while(csr8r(ctlr, Command)) ; csr8w(ctlr, Command, CUstart); | |
| 1996/0419/sys/src/9/pc/ether82557.c:278,284 – 1996/0423/sys/src/9/pc/ether82557.c:280,286 | ||
| 1996/0418 | ilock(&ctlr->rlock); status = csr16r(ctlr, Status); if((status & RUstatus) == RUidle){ | |
| 1996/0423 | csr32w(ctlr, General, PADDR(ctlr->rfd[ctlr->rfdx]->rp)); | |
| 1996/0418 | while(csr8r(ctlr, Command)) ; csr8w(ctlr, Command, RUstart); | |
| 1996/0419/sys/src/9/pc/ether82557.c:617,632 – 1996/0423/sys/src/9/pc/ether82557.c:619,634 | ||
| 1996/0418 | if((x & 0x05) != 0x05) print("PCI command = %uX\n", x); | |
| 1996/0423 | csr32w(ctlr, General, 0); | |
| 1996/0418 | while(csr8r(ctlr, Command)) ; | |
| 1996/0423 | csr8w(ctlr, Command, LoadRUB); | |
| 1996/0418 | while(csr8r(ctlr, Command)) ; | |
| 1996/0423 | csr8w(ctlr, Command, LoadCUB); | |
| 1996/0418 | /* | |
| 1996/0423 | * Initialise the receive frame and configuration areas. | |
| 1996/0418 | */ ctlrinit(ctlr); | |
| 1996/0423/sys/src/9/pc/ether82557.c:214,220 – 1996/0601/sys/src/9/pc/ether82557.c:214,220 (short | long) | ||
| 1996/0418 | 0x60, /* inter-frame spacing */ 0x00, 0xF2, | |
| 1996/0601 | 0xC8, /* promiscuous mode off */ | |
| 1996/0418 | 0x00, 0x40, 0xF2, /* transmit padding enable */ | |
| 1996/0423/sys/src/9/pc/ether82557.c:652,658 – 1996/0601/sys/src/9/pc/ether82557.c:652,659 | ||
| 1996/0418 | x = dp83840r(ctlr, i, 0x1B); if((x & 0x0200) == 0){ ctlr->configdata[8] = 1; | |
| 1996/0601 | ctlr->configdata[15] &= ~0x80; ether->mbps = 100; | |
| 1996/0418 | } break; } | |
| 1996/0601/sys/src/9/pc/ether82557.c:6,14 – 1996/0607/sys/src/9/pc/ether82557.c:6,12 (short | long) | ||
| 1996/0418 | * the PCI scanning code could be made common to other adapters; * PCI code needs rewritten to handle byte, word, dword accesses * and using the devno as a bus+dev+function triplet; | |
| 1996/0423 |
| |
| 1996/0418 |
| |
| 1996/0607 | * optionally use memory-mapped registers. | |
| 1996/0418 | */ #include "u.h" #include "../port/lib.h" | |
| 1996/0601/sys/src/9/pc/ether82557.c:141,147 – 1996/0607/sys/src/9/pc/ether82557.c:139,145 | ||
| 1996/0418 | typedef struct Cb { int command; ulong link; | |
| 1996/0607 | uchar data[24]; /* CbIAS + CbConfigure */ | |
| 1996/0418 | } Cb; typedef struct TxCB { | |
| 1996/0601/sys/src/9/pc/ether82557.c:185,200 – 1996/0607/sys/src/9/pc/ether82557.c:183,200 | ||
| 1996/0418 | uchar configdata[24]; | |
| 1996/0607 | Lock rlock; /* registers */ | |
| 1996/0418 |
| |
| 1996/0607 | Block* rfd[Nrfd]; /* receive side */ | |
| 1996/0418 | int rfdl; int rfdx; | |
| 1996/0607 | Block* cbqhead; /* transmit side */ | |
| 1996/0418 | Block* cbqtail; int cbqbusy; | |
| 1996/0607 | Lock dlock; /* dump statistical counters */ ulong dump[17]; | |
| 1996/0418 | } Ctlr; static uchar configdata[24] = { | |
| 1996/0601/sys/src/9/pc/ether82557.c:239,247 – 1996/0607/sys/src/9/pc/ether82557.c:239,247 | ||
| 1996/0418 | } ctlr->cbqbusy = 1; | |
| 1996/0423 |
| |
| 1996/0418 | while(csr8r(ctlr, Command)) ; | |
| 1996/0607 | csr32w(ctlr, General, PADDR(ctlr->cbqhead->rp)); | |
| 1996/0418 | csr8w(ctlr, Command, CUstart); } | |
| 1996/0601/sys/src/9/pc/ether82557.c:250,256 – 1996/0607/sys/src/9/pc/ether82557.c:250,255 | ||
| 1996/0418 | { Cb *cb; | |
| 1996/0601/sys/src/9/pc/ether82557.c:266,273 – 1996/0607/sys/src/9/pc/ether82557.c:265,270 | ||
| 1996/0418 | if(ctlr->cbqbusy == 0) custart(ctlr); | |
| 1996/0601/sys/src/9/pc/ether82557.c:280,302 – 1996/0607/sys/src/9/pc/ether82557.c:277,296 | ||
| 1996/0418 | ilock(&ctlr->rlock); status = csr16r(ctlr, Status); if((status & RUstatus) == RUidle){ | |
| 1996/0423 |
| |
| 1996/0418 | while(csr8r(ctlr, Command)) ; | |
| 1996/0607 | csr32w(ctlr, General, PADDR(ctlr->rfd[ctlr->rfdx]->rp)); | |
| 1996/0418 | csr8w(ctlr, Command, RUstart); } iunlock(&ctlr->rlock); } | |
| 1996/0607 | static Block* configure(Ctlr* ctlr, int promiscuous) | |
| 1996/0418 | { | |
| 1996/0601/sys/src/9/pc/ether82557.c:306,317 – 1996/0607/sys/src/9/pc/ether82557.c:300,383 | ||
| 1996/0418 | memmove(cb->data, ctlr->configdata, sizeof(ctlr->configdata)); if(promiscuous) cb->data[15] |= 0x01; | |
| 1996/0607 | return bp; } static void promiscuous(void* arg, int on) { Ctlr *ctlr; Block *bp; ctlr = ((Ether*)arg)->ctlr; bp = configure(ctlr, on); ilock(&ctlr->rlock); | |
| 1996/0418 | action(ctlr, bp); | |
| 1996/0607 | iunlock(&ctlr->rlock); | |
| 1996/0418 | } static long | |
| 1996/0607 | ifstat(Ether* ether, void* a, long n, ulong offset) { Ctlr *ctlr; char buf[512]; int len; ctlr = ether->ctlr; lock(&ctlr->dlock); ctlr->dump[16] = 0; ilock(&ctlr->rlock); while(csr8r(ctlr, Command)) ; csr8w(ctlr, Command, DumpSC); iunlock(&ctlr->rlock); /* * Wait for completion status, should be 0xA005. */ while(ctlr->dump[16] == 0) ; ether->oerrs = ctlr->dump[1]+ctlr->dump[2]+ctlr->dump[3]; ether->crcs = ctlr->dump[10]; ether->frames = ctlr->dump[11]; ether->buffs = ctlr->dump[12]+ctlr->dump[15]; ether->overflows = ctlr->dump[13]; if(n == 0){ unlock(&ctlr->dlock); return 0; } len = sprint(buf, "transmit good frames: %ld\n", ctlr->dump[0]); len += sprint(buf+len, "transmit maximum collisions errors: %ld\n", ctlr->dump[1]); len += sprint(buf+len, "transmit late collisions errors: %ld\n", ctlr->dump[2]); len += sprint(buf+len, "transmit underrun errors: %ld\n", ctlr->dump[3]); len += sprint(buf+len, "transmit lost carrier sense: %ld\n", ctlr->dump[4]); len += sprint(buf+len, "transmit deferred: %ld\n", ctlr->dump[5]); len += sprint(buf+len, "transmit single collisions: %ld\n", ctlr->dump[6]); len += sprint(buf+len, "transmit multiple collisions: %ld\n", ctlr->dump[7]); len += sprint(buf+len, "transmit total collisions: %ld\n", ctlr->dump[8]); len += sprint(buf+len, "receive good frames: %ld\n", ctlr->dump[9]); len += sprint(buf+len, "receive CRC errors: %ld\n", ctlr->dump[10]); len += sprint(buf+len, "receive alignment errors: %ld\n", ctlr->dump[11]); len += sprint(buf+len, "receive resource errors: %ld\n", ctlr->dump[12]); len += sprint(buf+len, "receive overrun errors: %ld\n", ctlr->dump[13]); len += sprint(buf+len, "receive collision detect errors: %ld\n", ctlr->dump[14]); sprint(buf+len, "receive short frame errors: %ld\n", ctlr->dump[15]); unlock(&ctlr->dlock); return readstr(offset, a, n, buf); } static long | |
| 1996/0418 | write(Ether* ether, void* buf, long n) { | |
| 1996/0607 | Ctlr *ctlr; | |
| 1996/0418 | Block *bp; TxCB *txcb; | |
| 1996/0601/sys/src/9/pc/ether82557.c:330,336 – 1996/0607/sys/src/9/pc/ether82557.c:396,405 | ||
| 1996/0418 | memmove(bp->wp+Eaddrlen, ether->ea, Eaddrlen); bp->wp += n; | |
| 1996/0607 | ctlr = ether->ctlr; ilock(&ctlr->rlock); action(ctlr, bp); iunlock(&ctlr->rlock); | |
| 1996/0418 | ether->outpackets++; | |
| 1996/0601/sys/src/9/pc/ether82557.c:349,367 – 1996/0607/sys/src/9/pc/ether82557.c:418,440 | ||
| 1996/0418 | ether = arg; ctlr = ether->ctlr; | |
| 1996/0607 | ilock(&ctlr->rlock); | |
| 1996/0418 | for(;;){ status = csr16r(ctlr, Status); csr8w(ctlr, Ack, (status>>8) & 0xFF); | |
| 1996/0607 | if((status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI)) == 0) break; | |
| 1996/0418 | if(status & StatFR){ bp = ctlr->rfd[ctlr->rfdx]; rfd = (Rfd*)bp->rp; while(rfd->field & RfdC){ | |
| 1996/0607 | if(rfd->field & RfdOK){ etherrloop(ether, rfd, rfd->count & 0x3FFF); ether->inpackets++; } else print("%s#%d: rfd->field %uX\n", ctlr->type, ctlr->ctlrno, rfd->field); | |
| 1996/0418 | /* * Reinitialise the frame for reception and bump | |
| 1996/0601/sys/src/9/pc/ether82557.c:390,401 – 1996/0607/sys/src/9/pc/ether82557.c:463,474 | ||
| 1996/0418 | while(csr8r(ctlr, Command)) ; csr8w(ctlr, Command, RUresume); | |
| 1996/0607 | print("%s#%d: status %uX\n", ctlr->type, ctlr->ctlrno, status); | |
| 1996/0418 | status &= ~StatRNR; } if(status & StatCNA){ | |
| 1996/0601/sys/src/9/pc/ether82557.c:403,409 – 1996/0607/sys/src/9/pc/ether82557.c:476,481 | ||
| 1996/0418 | freeb(bp); } custart(ctlr); | |
| 1996/0601/sys/src/9/pc/ether82557.c:411,416 – 1996/0607/sys/src/9/pc/ether82557.c:483,489 | ||
| 1996/0418 | if(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI)) panic("%s#%d: status %uX\n", ctlr->type, ctlr->ctlrno, status); } | |
| 1996/0607 | iunlock(&ctlr->rlock); | |
| 1996/0418 | } static void | |
| 1996/0601/sys/src/9/pc/ether82557.c:612,632 – 1996/0607/sys/src/9/pc/ether82557.c:685,710 | ||
| 1996/0418 | ctlr->type = ether->type; ctlr->port = port; | |
| 1996/0607 | ilock(&ctlr->rlock); | |
| 1996/0418 | csr32w(ctlr, Port, 0); delay(1); | |
| 1996/0423 |
| |
| 1996/0418 | while(csr8r(ctlr, Command)) ; | |
| 1996/0607 | csr32w(ctlr, General, 0); | |
| 1996/0423 | csr8w(ctlr, Command, LoadRUB); | |
| 1996/0607 | ||
| 1996/0418 | while(csr8r(ctlr, Command)) ; | |
| 1996/0423 | csr8w(ctlr, Command, LoadCUB); | |
| 1996/0418 | ||
| 1996/0607 | while(csr8r(ctlr, Command)) ; csr32w(ctlr, General, PADDR(ctlr->dump)); csr8w(ctlr, Command, LoadDCA); | |
| 1996/0418 | /* | |
| 1996/0423 | * Initialise the receive frame and configuration areas. | |
| 1996/0418 | */ | |
| 1996/0601/sys/src/9/pc/ether82557.c:638,645 – 1996/0607/sys/src/9/pc/ether82557.c:716,723 | ||
| 1996/0418 | * configuration. However, should check for the existence of the PHY * and, if found, check whether to use 82503 (serial) or MII (nibble) * mode. Verify the PHY is a National Semiconductor DP83840 by looking | |
| 1996/0607 | * at the Organizationally Unique Identifier (OUI) in registers 2 and * 3 which should be 0x80017. | |
| 1996/0418 | */ for(i = 1; i < 32; i++){ if((x = dp83840r(ctlr, i, 2)) == 0xFFFF) | |
| 1996/0601/sys/src/9/pc/ether82557.c:661,667 – 1996/0607/sys/src/9/pc/ether82557.c:739,746 | ||
| 1996/0418 | /* * Load the chip configuration */ | |
| 1996/0607 | bp = configure(ctlr, 0); action(ctlr, bp); | |
| 1996/0418 | /* * Check if the adapter's station address is to be overridden. | |
| 1996/0601/sys/src/9/pc/ether82557.c:686,691 – 1996/0607/sys/src/9/pc/ether82557.c:765,772 | ||
| 1996/0418 | memmove(cb->data, ether->ea, Eaddrlen); action(ctlr, bp); | |
| 1996/0607 | iunlock(&ctlr->rlock); | |
| 1996/0418 | /* * Linkage to the generic ethernet driver. */ | |
| 1996/0601/sys/src/9/pc/ether82557.c:693,700 – 1996/0607/sys/src/9/pc/ether82557.c:774,782 | ||
| 1996/0418 | ether->attach = attach; ether->write = write; ether->interrupt = interrupt; | |
| 1996/0607 | ether->ifstat = ifstat; | |
| 1996/0418 |
| |
| 1996/0607 | ether->promiscuous = promiscuous; | |
| 1996/0418 | ether->arg = ether; return 0; | |
| 1996/0607/sys/src/9/pc/ether82557.c:434,440 – 1996/0608/sys/src/9/pc/ether82557.c:434,439 (short | long) | ||
| 1996/0607 | etherrloop(ether, rfd, rfd->count & 0x3FFF); ether->inpackets++; } | |
| 1996/0418 | /* * Reinitialise the frame for reception and bump | |
| 1996/0607/sys/src/9/pc/ether82557.c:463,469 – 1996/0608/sys/src/9/pc/ether82557.c:462,467 | ||
| 1996/0418 | while(csr8r(ctlr, Command)) ; csr8w(ctlr, Command, RUresume); | |
| 1996/0607 |
| |
| 1996/0418 | status &= ~StatRNR; } | |
| 1996/0608/sys/src/9/pc/ether82557.c:183,189 – 1996/0622/sys/src/9/pc/ether82557.c:183,189 (short | long) | ||
| 1996/0418 | uchar configdata[24]; | |
| 1996/0607 |
| |
| 1996/0622 | Lock lock; | |
| 1996/0418 | ||
| 1996/0607 | Block* rfd[Nrfd]; /* receive side */ | |
| 1996/0418 | int rfdl; | |
| 1996/0608/sys/src/9/pc/ether82557.c:193,199 – 1996/0622/sys/src/9/pc/ether82557.c:193,199 | ||
| 1996/0418 | Block* cbqtail; int cbqbusy; | |
| 1996/0607 |
| |
| 1996/0622 | Lock dlock; /* dump statistical counters */ | |
| 1996/0607 | ulong dump[17]; | |
| 1996/0418 | } Ctlr; | |
| 1996/0608/sys/src/9/pc/ether82557.c:274,280 – 1996/0622/sys/src/9/pc/ether82557.c:274,280 | ||
| 1996/0418 | Ctlr *ctlr; ctlr = ether->ctlr; | |
| 1996/0622 | ilock(&ctlr->lock); | |
| 1996/0418 | status = csr16r(ctlr, Status); if((status & RUstatus) == RUidle){ while(csr8r(ctlr, Command)) | |
| 1996/0608/sys/src/9/pc/ether82557.c:282,288 – 1996/0622/sys/src/9/pc/ether82557.c:282,288 | ||
| 1996/0607 | csr32w(ctlr, General, PADDR(ctlr->rfd[ctlr->rfdx]->rp)); | |
| 1996/0418 | csr8w(ctlr, Command, RUstart); } | |
| 1996/0622 | iunlock(&ctlr->lock); | |
| 1996/0418 | } | |
| 1996/0607 | static Block* | |
| 1996/0608/sys/src/9/pc/ether82557.c:313,321 – 1996/0622/sys/src/9/pc/ether82557.c:313,321 | ||
| 1996/0607 | ctlr = ((Ether*)arg)->ctlr; bp = configure(ctlr, on); | |
| 1996/0622 | ilock(&ctlr->lock); | |
| 1996/0418 | action(ctlr, bp); | |
| 1996/0607 |
| |
| 1996/0622 | iunlock(&ctlr->lock); | |
| 1996/0418 | } static long | |
| 1996/0608/sys/src/9/pc/ether82557.c:329,339 – 1996/0622/sys/src/9/pc/ether82557.c:329,339 | ||
| 1996/0607 | lock(&ctlr->dlock); ctlr->dump[16] = 0; | |
| 1996/0622 | ilock(&ctlr->lock); | |
| 1996/0607 | while(csr8r(ctlr, Command)) ; csr8w(ctlr, Command, DumpSC); | |
| 1996/0622 | iunlock(&ctlr->lock); | |
| 1996/0607 | /* * Wait for completion status, should be 0xA005. | |
| 1996/0608/sys/src/9/pc/ether82557.c:397,405 – 1996/0622/sys/src/9/pc/ether82557.c:397,405 | ||
| 1996/0418 | bp->wp += n; | |
| 1996/0607 | ctlr = ether->ctlr; | |
| 1996/0622 | ilock(&ctlr->lock); | |
| 1996/0607 | action(ctlr, bp); | |
| 1996/0622 | iunlock(&ctlr->lock); | |
| 1996/0418 | ether->outpackets++; | |
| 1996/0608/sys/src/9/pc/ether82557.c:418,424 – 1996/0622/sys/src/9/pc/ether82557.c:418,424 | ||
| 1996/0418 | ether = arg; ctlr = ether->ctlr; | |
| 1996/0607 |
| |
| 1996/0622 | ilock(&ctlr->lock); | |
| 1996/0418 | for(;;){ status = csr16r(ctlr, Status); csr8w(ctlr, Ack, (status>>8) & 0xFF); | |
| 1996/0608/sys/src/9/pc/ether82557.c:481,487 – 1996/0622/sys/src/9/pc/ether82557.c:481,487 | ||
| 1996/0418 | if(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI)) panic("%s#%d: status %uX\n", ctlr->type, ctlr->ctlrno, status); } | |
| 1996/0607 |
| |
| 1996/0622 | iunlock(&ctlr->lock); | |
| 1996/0418 | } static void | |
| 1996/0608/sys/src/9/pc/ether82557.c:600,606 – 1996/0622/sys/src/9/pc/ether82557.c:600,606 | ||
| 1996/0418 | static Adapter *adapter; static int | |
| 1996/0622 | i82557pci(Ether* ether, int* pcidevno) | |
| 1996/0418 | { PCIcfg pcicfg; static int devno = 0; | |
| 1996/0608/sys/src/9/pc/ether82557.c:666,672 – 1996/0622/sys/src/9/pc/ether82557.c:666,672 | ||
| 1996/0418 | break; } } | |
| 1996/0622 | if(port == 0 && (port = i82557pci(ether, &pcidevno)) == 0) | |
| 1996/0418 | return -1; /* | |
| 1996/0608/sys/src/9/pc/ether82557.c:683,689 – 1996/0622/sys/src/9/pc/ether82557.c:683,689 | ||
| 1996/0418 | ctlr->type = ether->type; ctlr->port = port; | |
| 1996/0607 |
| |
| 1996/0622 | ilock(&ctlr->lock); | |
| 1996/0607 | ||
| 1996/0418 | csr32w(ctlr, Port, 0); delay(1); | |
| 1996/0608/sys/src/9/pc/ether82557.c:763,769 – 1996/0622/sys/src/9/pc/ether82557.c:763,769 | ||
| 1996/0418 | memmove(cb->data, ether->ea, Eaddrlen); action(ctlr, bp); | |
| 1996/0607 |
| |
| 1996/0622 | iunlock(&ctlr->lock); | |
| 1996/0607 | ||
| 1996/0418 | /* * Linkage to the generic ethernet driver. | |
| 1996/0622/sys/src/9/pc/ether82557.c:6,11 – 1996/0625/sys/src/9/pc/ether82557.c:6,12 (short | long) | ||
| 1996/0418 | * the PCI scanning code could be made common to other adapters; * PCI code needs rewritten to handle byte, word, dword accesses * and using the devno as a bus+dev+function triplet; | |
| 1996/0625 | * auto-negotiation; | |
| 1996/0607 | * optionally use memory-mapped registers. | |
| 1996/0418 | */ #include "u.h" | |
| 1996/0622/sys/src/9/pc/ether82557.c:725,735 – 1996/0625/sys/src/9/pc/ether82557.c:726,743 | ||
| 1996/0418 | if(x != 0x80017) continue; | |
| 1996/0625 | x = dp83840r(ctlr, i, 0x19); if((x & 0x0040) == 0){ ether->mbps = 100; | |
| 1996/0418 | ctlr->configdata[8] = 1; | |
| 1996/0601 | ctlr->configdata[15] &= ~0x80; | |
| 1996/0625 | } else{ x = dp83840r(ctlr, i, 0x1B); if((x & 0x0200) == 0){ ctlr->configdata[8] = 1; ctlr->configdata[15] &= ~0x80; } | |
| 1996/0418 | } break; } | |
| 1996/0625/sys/src/9/pc/ether82557.c:4,11 – 1997/0327/sys/src/9/pc/ether82557.c:4,9 (short | long) | ||
| 1996/0418 | * of smarts, unfortunately none of them are in the right place. * To do: * the PCI scanning code could be made common to other adapters; | |
| 1996/0625 | * auto-negotiation; | |
| 1996/0607 | * optionally use memory-mapped registers. | |
| 1996/0418 | */ | |
| 1996/0625/sys/src/9/pc/ether82557.c:108,114 – 1997/0327/sys/src/9/pc/ether82557.c:106,112 | ||
| 1996/0418 | ushort count; ushort size; | |
| 1997/0327 | uchar data[sizeof(Etherpkt)]; | |
| 1996/0418 | } Rfd; enum { /* field */ | |
| 1996/0625/sys/src/9/pc/ether82557.c:137,157 – 1997/0327/sys/src/9/pc/ether82557.c:135,162 | ||
| 1996/0418 | RfdEOF = 0x00008000, }; | |
| 1997/0327 | typedef struct Cb Cb; | |
| 1996/0418 | typedef struct Cb { | |
| 1996/0607 |
| |
| 1996/0418 |
| |
| 1997/0327 | Cb* next; Block* bp; | |
| 1996/0418 |
| |
| 1997/0327 | union { uchar data[24]; /* CbIAS + CbConfigure */ struct { ulong tbd; ushort count; uchar threshold; uchar number; | |
| 1996/0418 | ||
| 1997/0327 | ulong tba; ushort tbasz; ushort pad; }; }; } Cb; | |
| 1996/0418 | enum { /* action command */ CbOK = 0x00002000, /* DMA completed OK */ CbC = 0x00008000, /* execution Complete */ | |
| 1996/0625/sys/src/9/pc/ether82557.c:165,171 – 1997/0327/sys/src/9/pc/ether82557.c:170,176 | ||
| 1996/0418 | CbDiagnose = 0x00070000, CbCommand = 0x00070000, /* mask */ | |
| 1997/0327 | CbSF = 0x00080000, /* Flexible-mode CbTransmit */ | |
| 1996/0418 | CbI = 0x20000000, /* Interrupt after completion */ CbS = 0x40000000, /* Suspend after completion */ | |
| 1996/0625/sys/src/9/pc/ether82557.c:178,199 – 1997/0327/sys/src/9/pc/ether82557.c:183,206 | ||
| 1996/0418 | typedef struct Ctlr { int port; | |
| 1996/0622 |
| |
| 1997/0327 | Lock rlock; /* registers */ | |
| 1996/0418 | ||
| 1996/0607 |
| |
| 1996/0418 |
| |
| 1997/0327 | Lock rfdlock; /* receive side */ Block* rfdhead; Block* rfdtail; int nrfd; | |
| 1996/0418 | ||
| 1996/0607 |
| |
| 1996/0418 |
| |
| 1997/0327 | Lock cbqlock; /* transmit side */ Cb* cbqhead; Cb* cbqtail; | |
| 1996/0418 | int cbqbusy; | |
| 1996/0607 | ||
| 1997/0327 | Lock cbplock; /* pool of free Cb's */ Cb* cbpool; | |
| 1996/0622 | Lock dlock; /* dump statistical counters */ | |
| 1996/0607 | ulong dump[17]; | |
| 1996/0418 | } Ctlr; | |
| 1996/0625/sys/src/9/pc/ether82557.c:200,212 – 1997/0327/sys/src/9/pc/ether82557.c:207,219 | ||
| 1996/0418 | static uchar configdata[24] = { 0x16, /* byte count */ | |
| 1997/0327 | 0x08, /* Rx/Tx FIFO limit */ | |
| 1996/0418 | 0x00, /* adaptive IFS */ 0x00, | |
| 1997/0327 | 0x00, /* Rx DMA maximum byte count */ 0x80, /* Tx DMA maximum byte count */ 0x32, /* !late SCB, CNA interrupts */ 0x03, /* discard short Rx frames */ | |
| 1996/0418 | 0x00, /* 503/MII */ 0x00, | |
| 1996/0625/sys/src/9/pc/ether82557.c:218,224 – 1997/0327/sys/src/9/pc/ether82557.c:225,231 | ||
| 1996/0601 | 0xC8, /* promiscuous mode off */ | |
| 1996/0418 | 0x00, 0x40, | |
| 1997/0327 | 0xF3, /* transmit padding enable */ | |
| 1996/0418 | 0x80, /* full duplex pin enable */ 0x3F, /* no Multi IA */ 0x05, /* no Multi Cast ALL */ | |
| 1996/0625/sys/src/9/pc/ether82557.c:231,237 – 1997/0327/sys/src/9/pc/ether82557.c:238,294 | ||
| 1996/0418 | #define csr16w(c, r, w) (outs((c)->port+(r), (ushort)(w))) #define csr32w(c, r, l) (outl((c)->port+(r), (ulong)(l))) | |
| 1997/0327 | static Block* rfdalloc(ulong link) { Block *bp; Rfd *rfd; if(bp = iallocb(sizeof(Rfd))){ rfd = (Rfd*)bp->rp; rfd->field = 0; rfd->link = link; rfd->rbd = NullPointer; rfd->count = 0; rfd->size = sizeof(Etherpkt); } return bp; } static Cb* cballoc(Ctlr* ctlr, int command) { Cb *cb; ilock(&ctlr->cbplock); if(cb = ctlr->cbpool){ ctlr->cbpool = cb->next; iunlock(&ctlr->cbplock); cb->next = 0; cb->bp = 0; } else{ iunlock(&ctlr->cbplock); cb = smalloc(sizeof(Cb)); } cb->command = command; cb->link = NullPointer; return cb; } | |
| 1996/0418 | static void | |
| 1997/0327 | cbfree(Ctlr* ctlr, Cb* cb) { ilock(&ctlr->cbplock); cb->next = ctlr->cbpool; ctlr->cbpool = cb; iunlock(&ctlr->cbplock); } static void | |
| 1996/0418 | custart(Ctlr* ctlr) { if(ctlr->cbqhead == 0){ | |
| 1996/0625/sys/src/9/pc/ether82557.c:240,271 – 1997/0327/sys/src/9/pc/ether82557.c:297,331 | ||
| 1996/0418 | } ctlr->cbqbusy = 1; | |
| 1997/0327 | ilock(&ctlr->rlock); | |
| 1996/0418 | while(csr8r(ctlr, Command)) ; | |
| 1996/0607 |
| |
| 1997/0327 | csr32w(ctlr, General, PADDR(&ctlr->cbqhead->command)); | |
| 1996/0418 | csr8w(ctlr, Command, CUstart); | |
| 1997/0327 | iunlock(&ctlr->rlock); | |
| 1996/0418 | } static void | |
| 1997/0327 | action(Ctlr* ctlr, Cb* cb) | |
| 1996/0418 | { | |
| 1997/0327 | Cb* tail; | |
| 1996/0418 |
| |
| 1997/0327 | ilock(&ctlr->cbqlock); | |
| 1996/0418 | if(ctlr->cbqhead){ | |
| 1997/0327 | tail = ctlr->cbqtail; tail->next = cb; tail->link = PADDR(&cb->command); tail->command &= ~CbEL; | |
| 1996/0418 | } else | |
| 1997/0327 | ctlr->cbqhead = cb; ctlr->cbqtail = cb; | |
| 1996/0418 |
| |
| 1997/0327 | if(!ctlr->cbqbusy) | |
| 1996/0418 | custart(ctlr); | |
| 1997/0327 | iunlock(&ctlr->cbqlock); | |
| 1996/0418 | } static void | |
| 1996/0625/sys/src/9/pc/ether82557.c:275,322 – 1997/0327/sys/src/9/pc/ether82557.c:335,367 | ||
| 1996/0418 | Ctlr *ctlr; ctlr = ether->ctlr; | |
| 1996/0622 |
| |
| 1997/0327 | ilock(&ctlr->rlock); | |
| 1996/0418 | status = csr16r(ctlr, Status); if((status & RUstatus) == RUidle){ while(csr8r(ctlr, Command)) ; | |
| 1996/0607 |
| |
| 1997/0327 | csr32w(ctlr, General, PADDR(ctlr->rfdhead->rp)); | |
| 1996/0418 | csr8w(ctlr, Command, RUstart); } | |
| 1996/0622 |
| |
| 1997/0327 | iunlock(&ctlr->rlock); | |
| 1996/0418 | } | |
| 1996/0607 |
| |
| 1997/0327 | static void | |
| 1996/0607 | configure(Ctlr* ctlr, int promiscuous) | |
| 1996/0418 | { | |
| 1997/0327 | cb = cballoc(ctlr, CbConfigure); | |
| 1996/0418 | memmove(cb->data, ctlr->configdata, sizeof(ctlr->configdata)); if(promiscuous) cb->data[15] |= 0x01; | |
| 1996/0607 |
| |
| 1997/0327 | action(ctlr, cb); | |
| 1996/0607 | } static void promiscuous(void* arg, int on) { | |
| 1996/0622 |
| |
| 1996/0418 |
| |
| 1996/0622 |
| |
| 1997/0327 | configure(((Ether*)arg)->ctlr, on); | |
| 1996/0418 | } static long | |
| 1996/0625/sys/src/9/pc/ether82557.c:330,340 – 1997/0327/sys/src/9/pc/ether82557.c:375,385 | ||
| 1996/0607 | lock(&ctlr->dlock); ctlr->dump[16] = 0; | |
| 1996/0622 |
| |
| 1997/0327 | ilock(&ctlr->rlock); | |
| 1996/0607 | while(csr8r(ctlr, Command)) ; csr8w(ctlr, Command, DumpSC); | |
| 1996/0622 |
| |
| 1997/0327 | iunlock(&ctlr->rlock); | |
| 1996/0607 | /* * Wait for completion status, should be 0xA005. | |
| 1996/0625/sys/src/9/pc/ether82557.c:375,410 – 1997/0327/sys/src/9/pc/ether82557.c:420,448 | ||
| 1996/0607 | return readstr(offset, a, n, buf); } | |
| 1996/0418 |
| |
| 1997/0327 | static void transmit(Ether* ether) | |
| 1996/0418 | { | |
| 1996/0607 | Ctlr *ctlr; | |
| 1996/0418 | Block *bp; | |
| 1997/0327 | Cb *cb; | |
| 1996/0418 |
| |
| 1997/0327 | bp = qget(ether->oq); if(bp == nil) return; | |
| 1996/0418 |
| |
| 1996/0607 | ctlr = ether->ctlr; | |
| 1996/0622 |
| |
| 1996/0607 |
| |
| 1996/0622 |
| |
| 1996/0418 |
| |
| 1997/0327 | cb = cballoc(ctlr, CbSF|CbTransmit); cb->bp = bp; cb->tbd = PADDR(&cb->tba); cb->count = 0; cb->threshold = 2; cb->number = 1; cb->tba = PADDR(bp->rp); cb->tbasz = BLEN(bp); | |
| 1996/0418 |
| |
| 1997/0327 | action(ctlr, cb); | |
| 1996/0418 | } static void | |
| 1996/0625/sys/src/9/pc/ether82557.c:411,417 – 1997/0327/sys/src/9/pc/ether82557.c:449,456 | ||
| 1996/0418 | interrupt(Ureg*, void* arg) { Rfd *rfd; | |
| 1997/0327 | Cb* cb; Block *bp, *xbp; | |
| 1996/0418 | Ctlr *ctlr; Ether *ether; int status; | |
| 1996/0625/sys/src/9/pc/ether82557.c:419,459 – 1997/0327/sys/src/9/pc/ether82557.c:458,526 | ||
| 1996/0418 | ether = arg; ctlr = ether->ctlr; | |
| 1996/0622 |
| |
| 1996/0418 | for(;;){ | |
| 1997/0327 | lock(&ctlr->rlock); | |
| 1996/0418 | status = csr16r(ctlr, Status); csr8w(ctlr, Ack, (status>>8) & 0xFF); | |
| 1997/0327 | unlock(&ctlr->rlock); | |
| 1996/0418 | ||
| 1996/0607 |
| |
| 1997/0327 | if(!(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI))) | |
| 1996/0607 | break; | |
| 1996/0418 | if(status & StatFR){ | |
| 1997/0327 | bp = ctlr->rfdhead; | |
| 1996/0418 | rfd = (Rfd*)bp->rp; while(rfd->field & RfdC){ | |
| 1996/0607 |
| |
| 1997/0327 | /* * If it's an OK receive frame and a replacement buffer * can be allocated then * adjust the received buffer pointers for the * actual data received; * initialise the replacement buffer to point to * the next in the ring; * pass the received buffer on for disposal; * initialise bp to point to the replacement. * If not, just adjust the necessary fields for reuse. */ if((rfd->field & RfdOK) && (xbp = rfdalloc(rfd->link))){ bp->rp += sizeof(Rfd)-sizeof(Etherpkt); bp->wp = bp->rp + (rfd->count & 0x3FFF); xbp->next = bp->next; bp->next = 0; etheriq(ether, bp, 1); bp = xbp; | |
| 1996/0607 | } | |
| 1997/0327 | else{ rfd->field = 0; rfd->count = 0; } | |
| 1996/0418 | /* | |
| 1997/0327 | * The ring tail pointer follows the head with with one * unused buffer in between to defeat hardware prefetch; * once the tail pointer has been bumped on to the next * and the new tail has the Suspend bit set, it can be * removed from the old tail buffer. * As a replacement for the current head buffer may have * been allocated above, ensure that the new tail points * to it (next and link). | |
| 1996/0418 | */ | |
| 1997/0327 | rfd = (Rfd*)ctlr->rfdtail->rp; ctlr->rfdtail = ctlr->rfdtail->next; ctlr->rfdtail->next = bp; ((Rfd*)ctlr->rfdtail->rp)->link = PADDR(bp->rp); ((Rfd*)ctlr->rfdtail->rp)->field |= RfdS; | |
| 1996/0418 | rfd->field &= ~RfdS; | |
| 1997/0327 | /* * Finally done with the current (possibly replaced) * head, move on to the next and maintain the sentinel * between tail and head. */ ctlr->rfdhead = bp->next; bp = ctlr->rfdhead; | |
| 1996/0418 | rfd = (Rfd*)bp->rp; } status &= ~StatFR; | |
| 1996/0625/sys/src/9/pc/ether82557.c:460,488 – 1997/0327/sys/src/9/pc/ether82557.c:527,560 | ||
| 1996/0418 | } if(status & StatRNR){ | |
| 1997/0327 | lock(&ctlr->rlock); | |
| 1996/0418 | while(csr8r(ctlr, Command)) ; csr8w(ctlr, Command, RUresume); | |
| 1997/0327 | unlock(&ctlr->rlock); | |
| 1996/0418 | status &= ~StatRNR; } if(status & StatCNA){ | |
| 1997/0327 | lock(&ctlr->cbqlock); while(cb = ctlr->cbqhead){ if(!(cb->command & CbC)) | |
| 1996/0418 | break; | |
| 1997/0327 | ctlr->cbqhead = cb->next; if(cb->bp) freeb(cb->bp); cbfree(ctlr, cb); | |
| 1996/0418 | } custart(ctlr); | |
| 1997/0327 | unlock(&ctlr->cbqlock); | |
| 1996/0418 | status &= ~StatCNA; } if(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI)) | |
| 1997/0327 | panic("#l%d: status %uX\n", ether->ctlrno, status); | |
| 1996/0418 | } | |
| 1996/0622 |
| |
| 1996/0418 | } static void | |
| 1996/0625/sys/src/9/pc/ether82557.c:493,521 – 1997/0327/sys/src/9/pc/ether82557.c:565,593 | ||
| 1996/0418 | Rfd *rfd; ulong link; | |
| 1997/0327 | /* * Create the Receive Frame Area (RFA) as a ring of allocated * buffers. * A sentinel buffer is maintained between the last buffer in * the ring (marked with RfdS) and the head buffer to defeat the * hardware prefetch of the next RFD and allow dynamic buffer * allocation. */ | |
| 1996/0418 | link = NullPointer; | |
| 1997/0327 | for(i = 0; i < Nrfd; i++){ bp = rfdalloc(link); if(ctlr->rfdhead == nil) ctlr->rfdtail = bp; bp->next = ctlr->rfdhead; ctlr->rfdhead = bp; link = PADDR(bp->rp); | |
| 1996/0418 | } | |
| 1997/0327 | ctlr->rfdtail->next = ctlr->rfdhead; rfd = (Rfd*)ctlr->rfdtail->rp; rfd->link = PADDR(ctlr->rfdhead->rp); rfd->field |= RfdS; ctlr->rfdhead = ctlr->rfdhead->next; | |
| 1996/0418 |
| |
| 1996/0625/sys/src/9/pc/ether82557.c:572,578 – 1997/0327/sys/src/9/pc/ether82557.c:644,650 | ||
| 1996/0418 | delay(1); csr16w(ctlr, Ecr, data); delay(1); | |
| 1997/0327 | if(!(csr16r(ctlr, Ecr) & EEdo)) | |
| 1996/0418 | break; } | |
| 1996/0625/sys/src/9/pc/ether82557.c:591,641 – 1997/0327/sys/src/9/pc/ether82557.c:663,712 | ||
| 1996/0418 | return data; } | |
| 1997/0327 | typedef struct Adapter { int port; int irq; int tbdf; } Adapter; static Block* adapter; | |
| 1996/0418 |
| |
| 1996/0622 |
| |
| 1997/0327 | static void i82557adapter(Block** bpp, int port, int irq, int tbdf) | |
| 1996/0418 | { | |
| 1997/0327 | Block *bp; | |
| 1996/0418 | Adapter *ap; | |
| 1997/0327 | bp = allocb(sizeof(Adapter)); ap = (Adapter*)bp->rp; ap->port = port; ap->irq = irq; ap->tbdf = tbdf; | |
| 1996/0418 |
| |
| 1997/0327 | bp->next = *bpp; *bpp = bp; } static int i82557pci(Ether* ether) { static Pcidev *p; int irq, port; while(p = pcimatch(p, 0x8086, 0x1229)){ /* * bar[0] is the memory-mapped register address (4KB), * bar[1] is the I/O port register address (32 bytes) and * bar[2] is for the flash ROM (1MB). */ port = p->bar[1] & ~0x01; irq = p->intl; if(ether->port == 0 || ether->port == port){ ether->irq = irq; ether->tbdf = p->tbdf; return port; | |
| 1996/0418 | } | |
| 1997/0327 | i82557adapter(&adapter, port, irq, p->tbdf); | |
| 1996/0418 | } return 0; | |
| 1996/0625/sys/src/9/pc/ether82557.c:644,654 – 1997/0327/sys/src/9/pc/ether82557.c:715,725 | ||
| 1996/0418 | static int reset(Ether* ether) { | |
| 1997/0327 | int i, port, x; Block *bp, **bpp; Adapter *ap; | |
| 1996/0418 | uchar ea[Eaddrlen]; Ctlr *ctlr; | |
| 1996/0625/sys/src/9/pc/ether82557.c:657,673 – 1997/0327/sys/src/9/pc/ether82557.c:728,746 | ||
| 1996/0418 | * already been found. If not, scan for another. */ port = 0; | |
| 1997/0327 | bpp = &adapter; for(bp = *bpp; bp; bp = bp->next){ ap = (Adapter*)bp->rp; | |
| 1996/0418 | if(ether->port == 0 || ether->port == ap->port){ | |
| 1997/0327 | port = ap->port; | |
| 1996/0418 | ether->irq = ap->irq; | |
| 1997/0327 | ether->tbdf = ap->tbdf; *bpp = bp->next; freeb(bp); | |
| 1996/0418 | break; } } | |
| 1996/0622 |
| |
| 1997/0327 | if(port == 0 && (port = i82557pci(ether)) == 0) | |
| 1996/0418 | return -1; /* | |
| 1996/0625/sys/src/9/pc/ether82557.c:680,691 – 1997/0327/sys/src/9/pc/ether82557.c:753,761 | ||
| 1996/0418 | */ ether->ctlr = malloc(sizeof(Ctlr)); ctlr = ether->ctlr; | |
| 1996/0622 |
| |
| 1996/0607 | ||
| 1997/0327 | ilock(&ctlr->rlock); | |
| 1996/0418 | csr32w(ctlr, Port, 0); delay(1); | |
| 1996/0625/sys/src/9/pc/ether82557.c:702,709 – 1997/0327/sys/src/9/pc/ether82557.c:772,779 | ||
| 1996/0607 | ; csr32w(ctlr, General, PADDR(ctlr->dump)); csr8w(ctlr, Command, LoadDCA); | |
| 1997/0327 | iunlock(&ctlr->rlock); | |
| 1996/0607 | ||
| 1996/0418 | /* | |
| 1996/0423 | * Initialise the receive frame and configuration areas. | |
| 1996/0418 | */ | |
| 1996/0625/sys/src/9/pc/ether82557.c:727,733 – 1997/0327/sys/src/9/pc/ether82557.c:797,803 | ||
| 1996/0418 | continue; | |
| 1996/0625 | x = dp83840r(ctlr, i, 0x19); | |
| 1997/0327 | if(!(x & 0x0040)){ | |
| 1996/0625 | ether->mbps = 100; | |
| 1996/0418 | ctlr->configdata[8] = 1; | |
| 1996/0601 | ctlr->configdata[15] &= ~0x80; | |
| 1996/0625/sys/src/9/pc/ether82557.c:734,740 – 1997/0327/sys/src/9/pc/ether82557.c:804,810 | ||
| 1996/0625 | } else{ x = dp83840r(ctlr, i, 0x1B); | |
| 1997/0327 | if(!(x & 0x0200)){ | |
| 1996/0625 | ctlr->configdata[8] = 1; ctlr->configdata[15] &= ~0x80; } | |
| 1996/0625/sys/src/9/pc/ether82557.c:745,752 – 1997/0327/sys/src/9/pc/ether82557.c:815,821 | ||
| 1996/0418 | /* * Load the chip configuration */ | |
| 1996/0607 |
| |
| 1997/0327 | configure(ctlr, 0); | |
| 1996/0418 | /* * Check if the adapter's station address is to be overridden. | |
| 1996/0625/sys/src/9/pc/ether82557.c:754,777 – 1997/0327/sys/src/9/pc/ether82557.c:823,840 | ||
| 1996/0418 | * the station address with the Individual Address Setup command. */ memset(ea, 0, Eaddrlen); | |
| 1997/0327 | if(!memcmp(ea, ether->ea, Eaddrlen)){ | |
| 1996/0418 | for(i = 0; i < Eaddrlen/2; i++){ x = hy93c46r(ctlr, i); | |
| 1997/0327 | ether->ea[2*i] = x; ether->ea[2*i+1] = x>>8; | |
| 1996/0418 | } } | |
| 1997/0327 | cb = cballoc(ctlr, CbIAS); | |
| 1996/0418 | memmove(cb->data, ether->ea, Eaddrlen); | |
| 1997/0327 | action(ctlr, cb); | |
| 1996/0418 | ||
| 1996/0622 |
| |
| 1996/0607 | ||
| 1996/0418 | /* * Linkage to the generic ethernet driver. | |
| 1996/0625/sys/src/9/pc/ether82557.c:778,784 – 1997/0327/sys/src/9/pc/ether82557.c:841,847 | ||
| 1996/0418 | */ ether->port = port; ether->attach = attach; | |
| 1997/0327 | ether->transmit = transmit; | |
| 1996/0418 | ether->interrupt = interrupt; | |
| 1996/0607 | ether->ifstat = ifstat; | |
| 1996/0418 | ||
| 1997/0327/sys/src/9/pc/ether82557.c:367,378 – 1997/0417/sys/src/9/pc/ether82557.c:367,380 (short | long) | ||
| 1996/0418 | static long | |
| 1996/0607 | ifstat(Ether* ether, void* a, long n, ulong offset) { | |
| 1997/0417 | char *p; | |
| 1996/0607 | int len; | |
| 1997/0417 | Ctlr *ctlr; ulong dump[17]; | |
| 1996/0607 | ctlr = ether->ctlr; lock(&ctlr->dlock); | |
| 1997/0417 | ||
| 1996/0607 | ctlr->dump[16] = 0; | |
| 1997/0327 | ilock(&ctlr->rlock); | |
| 1997/0327/sys/src/9/pc/ether82557.c:398,423 – 1997/0417/sys/src/9/pc/ether82557.c:400,430 | ||
| 1996/0607 | return 0; } | |
| 1997/0417 | memmove(dump, ctlr->dump, sizeof(dump)); | |
| 1996/0607 | unlock(&ctlr->dlock); | |
| 1997/0417 | p = malloc(READSTR); len = snprint(p, READSTR, "transmit good frames: %ld\n", dump[0]); len += snprint(p+len, READSTR-len, "transmit maximum collisions errors: %ld\n", dump[1]); len += snprint(p+len, READSTR-len, "transmit late collisions errors: %ld\n", dump[2]); len += snprint(p+len, READSTR-len, "transmit underrun errors: %ld\n", dump[3]); len += snprint(p+len, READSTR-len, "transmit lost carrier sense: %ld\n", dump[4]); len += snprint(p+len, READSTR-len, "transmit deferred: %ld\n", dump[5]); len += snprint(p+len, READSTR-len, "transmit single collisions: %ld\n", dump[6]); len += snprint(p+len, READSTR-len, "transmit multiple collisions: %ld\n", dump[7]); len += snprint(p+len, READSTR-len, "transmit total collisions: %ld\n", dump[8]); len += snprint(p+len, READSTR-len, "receive good frames: %ld\n", dump[9]); len += snprint(p+len, READSTR-len, "receive CRC errors: %ld\n", dump[10]); len += snprint(p+len, READSTR-len, "receive alignment errors: %ld\n", dump[11]); len += snprint(p+len, READSTR-len, "receive resource errors: %ld\n", dump[12]); len += snprint(p+len, READSTR-len, "receive overrun errors: %ld\n", dump[13]); len += snprint(p+len, READSTR-len, "receive collision detect errors: %ld\n", dump[14]); snprint(p+len, READSTR-len, "receive short frame errors: %ld\n", dump[15]); n = readstr(offset, a, n, p); free(p); return n; | |
| 1996/0607 | } | |
| 1997/0327 | static void | |
| 1997/0417/sys/src/9/pc/ether82557.c:1,10 – 1997/0628/sys/src/9/pc/ether82557.c:1,11 (short | long) | ||
| 1996/0418 | /* * Intel 82557 Fast Ethernet PCI Bus LAN Controller * as found on the Intel EtherExpress PRO/100B. This chip is full | |
| 1997/0628 | * of smarts, unfortunately they're not all in the right place. | |
| 1996/0418 | * To do: * the PCI scanning code could be made common to other adapters; | |
| 1996/0625 | * auto-negotiation; | |
| 1997/0628 | * full-duplex; | |
| 1996/0607 | * optionally use memory-mapped registers. | |
| 1996/0418 | */ #include "u.h" | |
| 1997/0628/sys/src/9/pc/ether82557.c:1,11 – 1997/0723/sys/src/9/pc/ether82557.c:1,10 (short | long) | ||
| 1996/0418 | /* * Intel 82557 Fast Ethernet PCI Bus LAN Controller * as found on the Intel EtherExpress PRO/100B. This chip is full | |
| 1997/0628 |
| |
| 1997/0723 | * of smarts, unfortunately none of them are in the right place. | |
| 1996/0418 | * To do: * the PCI scanning code could be made common to other adapters; | |
| 1996/0625 | * auto-negotiation; | |
| 1997/0628 |
| |
| 1996/0607 | * optionally use memory-mapped registers. | |
| 1996/0418 | */ #include "u.h" | |
| 1997/0628/sys/src/9/pc/ether82557.c:694,705 – 1997/0723/sys/src/9/pc/ether82557.c:693,704 | ||
| 1997/0327 | *bpp = bp; } | |
| 1997/0723 | static void i82557pci(void) | |
| 1997/0327 | { | |
| 1997/0723 | Pcidev *p; | |
| 1997/0327 | ||
| 1997/0723 | p = nil; | |
| 1997/0327 | while(p = pcimatch(p, 0x8086, 0x1229)){ /* * bar[0] is the memory-mapped register address (4KB), | |
| 1997/0628/sys/src/9/pc/ether82557.c:706,723 – 1997/0723/sys/src/9/pc/ether82557.c:705,712 | ||
| 1997/0327 | * bar[1] is the I/O port register address (32 bytes) and * bar[2] is for the flash ROM (1MB). */ | |
| 1996/0418 |
| |
| 1997/0327 |
| |
| 1997/0723 | i82557adapter(&adapter, p->bar[1] & ~0x01, p->intl, p->tbdf); | |
| 1996/0418 | } | |
| 1997/0628/sys/src/9/pc/ether82557.c:729,735 – 1997/0723/sys/src/9/pc/ether82557.c:718,730 | ||
| 1996/0418 | uchar ea[Eaddrlen]; Ctlr *ctlr; Cb *cb; | |
| 1997/0723 | static int scandone; | |
| 1996/0418 | ||
| 1997/0723 | if(scandone == 0){ i82557pci(); scandone = 1; } | |
| 1996/0418 | /* * Any adapter matches if no ether->port is supplied, otherwise the * ports must match. First see if an adapter that fits the bill has | |
| 1997/0628/sys/src/9/pc/ether82557.c:747,754 – 1997/0723/sys/src/9/pc/ether82557.c:742,750 | ||
| 1997/0327 | freeb(bp); | |
| 1996/0418 | break; } | |
| 1997/0723 | bpp = &bp->next; | |
| 1996/0418 | } | |
| 1997/0327 |
| |
| 1997/0723 | if(port == 0) | |
| 1996/0418 | return -1; /* | |
| 1997/0628/sys/src/9/pc/ether82557.c:792,800 – 1997/0723/sys/src/9/pc/ether82557.c:788,796 | ||
| 1996/0418 | * EtherExpress PRO/100B appears to bring it up with a sensible default * configuration. However, should check for the existence of the PHY * and, if found, check whether to use 82503 (serial) or MII (nibble) | |
| 1996/0607 |
| |
| 1997/0723 | * mode. Verify the PHY is a National Semiconductor DP83840 (OUI 0x80017) * or an Intel 82555 (OUI 0xAA00) by looking at the Organizationally Unique * Identifier (OUI) in registers 2 and 3. | |
| 1996/0418 | */ for(i = 1; i < 32; i++){ if((x = dp83840r(ctlr, i, 2)) == 0xFFFF) | |
| 1997/0628/sys/src/9/pc/ether82557.c:801,808 – 1997/0723/sys/src/9/pc/ether82557.c:797,804 | ||
| 1996/0418 | continue; x <<= 6; x |= dp83840r(ctlr, i, 3)>>10; | |
| 1997/0723 | if(x != 0x80017 && x != 0xAA00) print("#l%d: unrecognised PHY - OUI 0x%4.4uX\n", ether->ctlrno, x); | |
| 1996/0418 | ||
| 1996/0625 | x = dp83840r(ctlr, i, 0x19); | |
| 1997/0327 | if(!(x & 0x0040)){ | |
| 1997/0723/sys/src/9/pc/ether82557.c:1,10 – 1997/0806/sys/src/9/pc/ether82557.c:1,11 (short | long) | ||
| 1996/0418 | /* * Intel 82557 Fast Ethernet PCI Bus LAN Controller * as found on the Intel EtherExpress PRO/100B. This chip is full | |
| 1997/0723 |
| |
| 1997/0806 | * of smarts, unfortunately they're not all in the right place. | |
| 1996/0418 | * To do: * the PCI scanning code could be made common to other adapters; | |
| 1996/0625 | * auto-negotiation; | |
| 1997/0806 | * full-duplex; | |
| 1996/0607 | * optionally use memory-mapped registers. | |
| 1996/0418 | */ #include "u.h" | |
| 1997/0723/sys/src/9/pc/ether82557.c:27,33 – 1997/0806/sys/src/9/pc/ether82557.c:28,34 | ||
| 1996/0418 | enum { /* CSR */ Status = 0x00, /* byte or word (word includes Ack) */ Ack = 0x01, /* byte */ | |
| 1997/0806 | CommandR = 0x02, /* byte or word (word includes Interrupt) */ | |
| 1996/0418 | Interrupt = 0x03, /* byte */ | |
| 1996/0423 | General = 0x04, /* dword */ | |
| 1996/0418 | Port = 0x08, /* dword */ | |
| 1997/0723/sys/src/9/pc/ether82557.c:298,307 – 1997/0806/sys/src/9/pc/ether82557.c:299,308 | ||
| 1996/0418 | ctlr->cbqbusy = 1; | |
| 1997/0327 | ilock(&ctlr->rlock); | |
| 1996/0418 |
| |
| 1997/0806 | while(csr8r(ctlr, CommandR)) | |
| 1996/0418 | ; | |
| 1997/0327 | csr32w(ctlr, General, PADDR(&ctlr->cbqhead->command)); | |
| 1996/0418 |
| |
| 1997/0806 | csr8w(ctlr, CommandR, CUstart); | |
| 1997/0327 | iunlock(&ctlr->rlock); | |
| 1996/0418 | } | |
| 1997/0723/sys/src/9/pc/ether82557.c:338,347 – 1997/0806/sys/src/9/pc/ether82557.c:339,348 | ||
| 1997/0327 | ilock(&ctlr->rlock); | |
| 1996/0418 | status = csr16r(ctlr, Status); if((status & RUstatus) == RUidle){ | |
| 1997/0806 | while(csr8r(ctlr, CommandR)) | |
| 1996/0418 | ; | |
| 1997/0327 | csr32w(ctlr, General, PADDR(ctlr->rfdhead->rp)); | |
| 1996/0418 |
| |
| 1997/0806 | csr8w(ctlr, CommandR, RUstart); | |
| 1996/0418 | } | |
| 1997/0327 | iunlock(&ctlr->rlock); | |
| 1996/0418 | } | |
| 1997/0723/sys/src/9/pc/ether82557.c:378,386 – 1997/0806/sys/src/9/pc/ether82557.c:379,387 | ||
| 1996/0607 | ctlr->dump[16] = 0; | |
| 1997/0327 | ilock(&ctlr->rlock); | |
| 1996/0607 |
| |
| 1997/0806 | while(csr8r(ctlr, CommandR)) | |
| 1996/0607 | ; | |
| 1997/0806 | csr8w(ctlr, CommandR, DumpSC); | |
| 1997/0327 | iunlock(&ctlr->rlock); | |
| 1996/0607 | /* | |
| 1997/0723/sys/src/9/pc/ether82557.c:535,543 – 1997/0806/sys/src/9/pc/ether82557.c:536,544 | ||
| 1996/0418 | if(status & StatRNR){ | |
| 1997/0327 | lock(&ctlr->rlock); | |
| 1996/0418 |
| |
| 1997/0806 | while(csr8r(ctlr, CommandR)) | |
| 1996/0418 | ; | |
| 1997/0806 | csr8w(ctlr, CommandR, RUresume); | |
| 1997/0327 | unlock(&ctlr->rlock); | |
| 1996/0418 | status &= ~StatRNR; | |
| 1997/0723/sys/src/9/pc/ether82557.c:726,734 – 1997/0806/sys/src/9/pc/ether82557.c:727,734 | ||
| 1997/0723 | } | |
| 1996/0418 | /* | |
| 1997/0806 | * Any adapter matches if no port is supplied, * otherwise the ports must match. | |
| 1996/0418 | */ port = 0; | |
| 1997/0327 | bpp = &adapter; | |
| 1997/0723/sys/src/9/pc/ether82557.c:763,781 – 1997/0806/sys/src/9/pc/ether82557.c:763,781 | ||
| 1996/0418 | csr32w(ctlr, Port, 0); delay(1); | |
| 1997/0806 | while(csr8r(ctlr, CommandR)) | |
| 1996/0418 | ; | |
| 1996/0607 | csr32w(ctlr, General, 0); | |
| 1996/0423 |
| |
| 1997/0806 | csr8w(ctlr, CommandR, LoadRUB); | |
| 1996/0607 | ||
| 1996/0418 |
| |
| 1997/0806 | while(csr8r(ctlr, CommandR)) | |
| 1996/0418 | ; | |
| 1996/0423 |
| |
| 1997/0806 | csr8w(ctlr, CommandR, LoadCUB); | |
| 1996/0418 | ||
| 1996/0607 |
| |
| 1997/0806 | while(csr8r(ctlr, CommandR)) | |
| 1996/0607 | ; csr32w(ctlr, General, PADDR(ctlr->dump)); | |
| 1997/0806 | csr8w(ctlr, CommandR, LoadDCA); | |
| 1997/0327 | iunlock(&ctlr->rlock); | |
| 1996/0607 | ||
| 1996/0418 | /* | |
| 1997/0723/sys/src/9/pc/ether82557.c:827,833 – 1997/0806/sys/src/9/pc/ether82557.c:827,833 | ||
| 1996/0418 | * the station address with the Individual Address Setup command. */ memset(ea, 0, Eaddrlen); | |
| 1997/0327 |
| |
| 1997/0806 | if(memcmp(ea, ether->ea, Eaddrlen) == 0){ | |
| 1996/0418 | for(i = 0; i < Eaddrlen/2; i++){ x = hy93c46r(ctlr, i); | |
| 1997/0327 | ether->ea[2*i] = x; | |
| 1997/0806/sys/src/9/pc/ether82557.c:405,426 – 1997/0807/sys/src/9/pc/ether82557.c:405,426 (short | long) | ||
| 1996/0607 | unlock(&ctlr->dlock); | |
| 1997/0417 | p = malloc(READSTR); | |
| 1997/0807 | len = snprint(p, READSTR, "transmit good frames: %lud\n", dump[0]); len += snprint(p+len, READSTR-len, "transmit maximum collisions errors: %lud\n", dump[1]); len += snprint(p+len, READSTR-len, "transmit late collisions errors: %lud\n", dump[2]); len += snprint(p+len, READSTR-len, "transmit underrun errors: %lud\n", dump[3]); len += snprint(p+len, READSTR-len, "transmit lost carrier sense: %lud\n", dump[4]); len += snprint(p+len, READSTR-len, "transmit deferred: %lud\n", dump[5]); len += snprint(p+len, READSTR-len, "transmit single collisions: %lud\n", dump[6]); len += snprint(p+len, READSTR-len, "transmit multiple collisions: %lud\n", dump[7]); len += snprint(p+len, READSTR-len, "transmit total collisions: %lud\n", dump[8]); len += snprint(p+len, READSTR-len, "receive good frames: %lud\n", dump[9]); len += snprint(p+len, READSTR-len, "receive CRC errors: %lud\n", dump[10]); len += snprint(p+len, READSTR-len, "receive alignment errors: %lud\n", dump[11]); len += snprint(p+len, READSTR-len, "receive resource errors: %lud\n", dump[12]); len += snprint(p+len, READSTR-len, "receive overrun errors: %lud\n", dump[13]); len += snprint(p+len, READSTR-len, "receive collision detect errors: %lud\n", dump[14]); snprint(p+len, READSTR-len, "receive short frame errors: %lud\n", dump[15]); | |
| 1997/0417 | n = readstr(offset, a, n, p); free(p); | |
| 1997/0807/sys/src/9/pc/ether82557.c:4,12 – 1997/0823/sys/src/9/pc/ether82557.c:4,12 (short | long) | ||
| 1997/0806 | * of smarts, unfortunately they're not all in the right place. | |
| 1996/0418 | * To do: * the PCI scanning code could be made common to other adapters; | |
| 1996/0625 |
| |
| 1997/0806 |
| |
| 1996/0607 |
| |
| 1997/0823 | * auto-negotiation, full-duplex; * optionally use memory-mapped registers; * detach for PCI reset problems (also towards loadable drivers). | |
| 1996/0418 | */ #include "u.h" #include "../port/lib.h" | |
| 1997/0807/sys/src/9/pc/ether82557.c:21,26 – 1997/0823/sys/src/9/pc/ether82557.c:21,27 | ||
| 1996/0418 | enum { Nrfd = 64, /* receive frame area */ | |
| 1997/0823 | Ncb = 64, /* maximum control blocks queued */ | |
| 1996/0418 | NullPointer = 0xFFFFFFFF, /* 82557 NULL pointer */ }; | |
| 1997/0807/sys/src/9/pc/ether82557.c:132,147 – 1997/0823/sys/src/9/pc/ether82557.c:133,146 | ||
| 1996/0418 | }; enum { /* count */ | |
| 1997/0823 | RfdF = 0x4000, RfdEOF = 0x8000, | |
| 1996/0418 | }; | |
| 1997/0327 | typedef struct Cb Cb; | |
| 1996/0418 | typedef struct Cb { | |
| 1997/0327 |
| |
| 1996/0418 |
| |
| 1997/0823 | ushort status; ushort command; | |
| 1996/0418 | ulong link; | |
| 1997/0327 | union { uchar data[24]; /* CbIAS + CbConfigure */ | |
| 1997/0807/sys/src/9/pc/ether82557.c:156,207 – 1997/0823/sys/src/9/pc/ether82557.c:155,214 | ||
| 1997/0327 | ushort pad; }; }; | |
| 1997/0823 | Block* bp; Cb* next; | |
| 1997/0327 | } Cb; | |
| 1996/0418 | enum { /* action command */ | |
| 1997/0823 | CbU = 0x1000, /* transmit underrun */ CbOK = 0x2000, /* DMA completed OK */ CbC = 0x8000, /* execution Complete */ | |
| 1996/0418 |
| |
| 1996/0423 |
| |
| 1996/0418 |
| |
| 1997/0823 | CbNOP = 0x0000, CbIAS = 0x0001, /* Individual Address Setup */ CbConfigure = 0x0002, CbMAS = 0x0003, /* Multicast Address Setup */ CbTransmit = 0x0004, CbDump = 0x0006, CbDiagnose = 0x0007, CbCommand = 0x0007, /* mask */ | |
| 1996/0418 | ||
| 1997/0327 |
| |
| 1997/0823 | CbSF = 0x0008, /* Flexible-mode CbTransmit */ | |
| 1996/0418 |
| |
| 1997/0823 | CbI = 0x2000, /* Interrupt after completion */ CbS = 0x4000, /* Suspend after completion */ CbEL = 0x8000, /* End of List */ | |
| 1996/0418 | }; enum { /* CbTransmit count */ | |
| 1997/0823 | CbEOF = 0x8000, | |
| 1996/0418 | }; typedef struct Ctlr { | |
| 1997/0823 | Lock slock; /* attach */ int state; | |
| 1996/0418 | int port; | |
| 1997/0327 | Lock rlock; /* registers */ | |
| 1997/0823 | int command; /* last command issued */ | |
| 1996/0418 | ||
| 1997/0327 |
| |
| 1997/0823 | Block* rfdhead; /* receive side */ | |
| 1997/0327 | Block* rfdtail; int nrfd; | |
| 1996/0418 | ||
| 1997/0327 |
| |
| 1996/0418 |
| |
| 1997/0823 | Lock cblock; /* transmit side */ int action; uchar configdata[24]; int threshold; int ncb; Cb* cbr; Cb* cbhead; Cb* cbtail; int cbq; int cbqmax; | |
| 1996/0607 | ||
| 1997/0327 |
| |
| 1996/0622 | Lock dlock; /* dump statistical counters */ | |
| 1996/0607 | ulong dump[17]; | |
| 1996/0418 | } Ctlr; | |
| 1997/0807/sys/src/9/pc/ether82557.c:239,244 – 1997/0823/sys/src/9/pc/ether82557.c:246,298 | ||
| 1996/0418 | #define csr16w(c, r, w) (outs((c)->port+(r), (ushort)(w))) #define csr32w(c, r, l) (outl((c)->port+(r), (ulong)(l))) | |
| 1997/0823 | static void command(Ctlr* ctlr, int c, int v) { ilock(&ctlr->rlock); /* * Only back-to-back CUresume can be done * without waiting for any previous command to complete. * This should be the common case. */ if(c == CUresume && ctlr->command == CUresume){ csr8w(ctlr, CommandR, c); iunlock(&ctlr->rlock); return; } while(csr8r(ctlr, CommandR)) ; switch(c){ case CUstart: case LoadDCA: case LoadCUB: case RUstart: case LoadHDS: case LoadRUB: csr32w(ctlr, General, v); break; /* case CUnop: case CUresume: case DumpSC: case ResetSA: case RUresume: case RUabort: */ default: break; } csr8w(ctlr, CommandR, c); ctlr->command = c; iunlock(&ctlr->rlock); } | |
| 1997/0327 | static Block* rfdalloc(ulong link) { | |
| 1997/0807/sys/src/9/pc/ether82557.c:257,370 – 1997/0823/sys/src/9/pc/ether82557.c:311,330 | ||
| 1997/0327 | return bp; } | |
| 1996/0418 | static void | |
| 1997/0327 |
| |
| 1996/0418 |
| |
| 1997/0327 |
| |
| 1997/0806 |
| |
| 1996/0418 |
| |
| 1997/0327 |
| |
| 1997/0806 |
| |
| 1997/0327 |
| |
| 1996/0418 |
| |
| 1997/0327 |
| |
| 1996/0418 |
| |
| 1997/0327 |
| |
| 1996/0418 |
| |
| 1997/0327 |
| |
| 1996/0418 |
| |
| 1997/0327 |
| |
| 1996/0418 |
| |
| 1997/0327 |
| |
| 1996/0418 | ||
| 1997/0327 |
| |
| 1996/0418 |
| |
| 1997/0327 |
| |
| 1996/0418 |
| |
| 1997/0327 |
| |
| 1996/0418 |
| |
| 1997/0806 |
| |
| 1996/0418 |
| |
| 1997/0327 |
| |
| 1997/0806 |
| |
| 1997/0823 | lock(&ctlr->slock); if(ctlr->state == 0){ command(ctlr, RUstart, PADDR(ctlr->rfdhead->rp)); ctlr->state = 1; | |
| 1996/0418 | } | |
| 1997/0327 |
| |
| 1997/0823 | unlock(&ctlr->slock); | |
| 1996/0418 | } | |
| 1997/0327 |
| |
| 1996/0607 |
| |
| 1996/0418 |
| |
| 1997/0327 |
| |
| 1996/0418 |
| |
| 1997/0327 |
| |
| 1996/0607 |
| |
| 1997/0327 |
| |
| 1996/0418 |
| |
| 1996/0607 | ifstat(Ether* ether, void* a, long n, ulong offset) { | |
| 1997/0807/sys/src/9/pc/ether82557.c:376,392 – 1997/0823/sys/src/9/pc/ether82557.c:336,348 | ||
| 1996/0607 | ctlr = ether->ctlr; lock(&ctlr->dlock); | |
| 1997/0417 | ||
| 1996/0607 |
| |
| 1997/0327 |
| |
| 1997/0806 |
| |
| 1996/0607 |
| |
| 1997/0806 |
| |
| 1997/0327 |
| |
| 1996/0607 |
| |
| 1997/0823 | * Start the command then * wait for completion status, * should be 0xA005. | |
| 1996/0607 | */ | |
| 1997/0823 | ctlr->dump[16] = 0; command(ctlr, DumpSC, 0); | |
| 1996/0607 | while(ctlr->dump[16] == 0) ; | |
| 1997/0807/sys/src/9/pc/ether82557.c:420,426 – 1997/0823/sys/src/9/pc/ether82557.c:376,384 | ||
| 1997/0807 | len += snprint(p+len, READSTR-len, "receive resource errors: %lud\n", dump[12]); len += snprint(p+len, READSTR-len, "receive overrun errors: %lud\n", dump[13]); len += snprint(p+len, READSTR-len, "receive collision detect errors: %lud\n", dump[14]); | |
| 1997/0823 | len += snprint(p+len, READSTR-len, "receive short frame errors: %lud\n", dump[15]); snprint(p+len, READSTR-len, "cbqmax: %lud\n", ctlr->cbqmax); ctlr->cbqmax = 0; | |
| 1997/0417 | n = readstr(offset, a, n, p); free(p); | |
| 1997/0807/sys/src/9/pc/ether82557.c:429,456 – 1997/0823/sys/src/9/pc/ether82557.c:387,484 | ||
| 1996/0607 | } | |
| 1997/0327 | static void | |
| 1997/0823 | txstart(Ether* ether) | |
| 1996/0418 | { | |
| 1996/0607 | Ctlr *ctlr; | |
| 1996/0418 | Block *bp; | |
| 1997/0327 | Cb *cb; | |
| 1996/0418 | ||
| 1997/0327 |
| |
| 1997/0823 | ctlr = ether->ctlr; while(ctlr->cbq < (ctlr->ncb-1)){ cb = ctlr->cbhead->next; if(ctlr->action == 0){ bp = qget(ether->oq); if(bp == nil) break; | |
| 1996/0418 | ||
| 1997/0823 | cb->command = CbS|CbSF|CbTransmit; cb->tbd = PADDR(&cb->tba); cb->count = 0; cb->threshold = ctlr->threshold; cb->number = 1; cb->tba = PADDR(bp->rp); cb->bp = bp; cb->tbasz = BLEN(bp); } else if(ctlr->action == CbConfigure){ cb->command = CbS|CbConfigure; memmove(cb->data, ctlr->configdata, sizeof(ctlr->configdata)); ctlr->action = 0; } else if(ctlr->action == CbIAS){ cb->command = CbS|CbIAS; memmove(cb->data, ether->ea, Eaddrlen); ctlr->action = 0; } else{ print("#l%d: action 0x%uX\n", ether->ctlrno, ctlr->action); ctlr->action = 0; break; } cb->status = 0; ctlr->cbhead->command &= ~CbS; ctlr->cbhead = cb; ctlr->cbq++; } command(ctlr, CUresume, 0); if(ctlr->cbq > ctlr->cbqmax) ctlr->cbqmax = ctlr->cbq; } static void configure(Ether* ether, int promiscuous) { Ctlr *ctlr; | |
| 1996/0607 | ctlr = ether->ctlr; | |
| 1997/0823 | ilock(&ctlr->cblock); if(promiscuous){ ctlr->configdata[6] |= 0x80; /* Save Bad Frames */ ctlr->configdata[6] &= ~0x40; /* !Discard Overrun Rx Frames */ ctlr->configdata[7] &= ~0x01; /* !Discard Short Rx Frames */ ctlr->configdata[15] |= 0x01; /* Promiscuous mode */ ctlr->configdata[18] &= ~0x01; /* (!Padding enable?), !stripping enable */ ctlr->configdata[21] |= 0x08; /* Multi Cast ALL */ } else{ ctlr->configdata[6] &= ~0x80; ctlr->configdata[7] |= 0x01; ctlr->configdata[15] &= ~0x01; ctlr->configdata[18] |= 0x01; /* 0x03? */ ctlr->configdata[21] &= ~0x08; } ctlr->action = CbConfigure; txstart(ether); iunlock(&ctlr->cblock); } | |
| 1996/0418 | ||
| 1997/0327 |
| |
| 1997/0823 | static void promiscuous(void* arg, int on) { configure(arg, on); } | |
| 1996/0418 | ||
| 1997/0327 |
| |
| 1997/0823 | static void transmit(Ether* ether) { Ctlr *ctlr; ctlr = ether->ctlr; ilock(&ctlr->cblock); txstart(ether); iunlock(&ctlr->cblock); | |
| 1996/0418 | } static void | |
| 1997/0807/sys/src/9/pc/ether82557.c:535,562 – 1997/0823/sys/src/9/pc/ether82557.c:563,594 | ||
| 1996/0418 | } if(status & StatRNR){ | |
| 1997/0327 |
| |
| 1997/0806 |
| |
| 1996/0418 |
| |
| 1997/0806 |
| |
| 1997/0327 |
| |
| 1996/0418 | ||
| 1997/0823 | command(ctlr, RUresume, 0); | |
| 1996/0418 | status &= ~StatRNR; } if(status & StatCNA){ | |
| 1997/0327 |
| |
| 1997/0823 | lock(&ctlr->cblock); cb = ctlr->cbtail; while(ctlr->cbq){ if(!(cb->status & CbC)) | |
| 1996/0418 | break; | |
| 1997/0327 |
| |
| 1997/0823 | if(cb->bp){ | |
| 1997/0327 | freeb(cb->bp); | |
| 1997/0823 | cb->bp = nil; } if((cb->status & CbU) && ctlr->threshold < 0xE0) ctlr->threshold++; ctlr->cbq--; cb = cb->next; | |
| 1996/0418 | } | |
| 1997/0327 |
| |
| 1997/0823 | ctlr->cbtail = cb; | |
| 1996/0418 | ||
| 1997/0823 | txstart(ether); unlock(&ctlr->cblock); | |
| 1996/0418 | status &= ~StatCNA; } | |
| 1997/0807/sys/src/9/pc/ether82557.c:596,602 – 1997/0823/sys/src/9/pc/ether82557.c:628,653 | ||
| 1997/0327 | rfd->field |= RfdS; ctlr->rfdhead = ctlr->rfdhead->next; | |
| 1996/0418 | ||
| 1997/0823 | /* * Create a ring of control blocks for the * transmit side. */ ilock(&ctlr->cblock); ctlr->cbr = malloc(ctlr->ncb*sizeof(Cb)); for(i = 0; i < ctlr->ncb; i++){ ctlr->cbr[i].status = CbC|CbOK; ctlr->cbr[i].command = CbS|CbNOP; ctlr->cbr[i].link = PADDR(&ctlr->cbr[NEXT(i, ctlr->ncb)].status); ctlr->cbr[i].next = &ctlr->cbr[NEXT(i, ctlr->ncb)]; } ctlr->cbhead = ctlr->cbr; ctlr->cbtail = ctlr->cbr; ctlr->cbq = 0; | |
| 1996/0418 | memmove(ctlr->configdata, configdata, sizeof(configdata)); | |
| 1997/0823 | ctlr->threshold = 8; iunlock(&ctlr->cblock); | |
| 1996/0418 | } static int | |
| 1997/0807/sys/src/9/pc/ether82557.c:718,724 – 1997/0823/sys/src/9/pc/ether82557.c:769,774 | ||
| 1997/0327 | Adapter *ap; | |
| 1996/0418 | uchar ea[Eaddrlen]; Ctlr *ctlr; | |
| 1997/0723 | static int scandone; | |
| 1996/0418 | ||
| 1997/0723 | if(scandone == 0){ | |
| 1997/0807/sys/src/9/pc/ether82557.c:749,755 – 1997/0823/sys/src/9/pc/ether82557.c:799,805 | ||
| 1996/0418 | /* * Allocate a controller structure and start to initialise it. | |
| 1997/0823 | * Perform a software reset after which should ensure busmastering | |
| 1996/0418 | * is still enabled. The EtherExpress PRO/100B appears to leave * the PCI configuration alone (see the 'To do' list above) so punt * for now. | |
| 1997/0807/sys/src/9/pc/ether82557.c:762,786 – 1997/0823/sys/src/9/pc/ether82557.c:812,827 | ||
| 1997/0327 | ilock(&ctlr->rlock); | |
| 1996/0418 | csr32w(ctlr, Port, 0); delay(1); | |
| 1997/0806 |
| |
| 1996/0418 |
| |
| 1996/0607 |
| |
| 1997/0806 |
| |
| 1996/0607 | ||
| 1997/0806 |
| |
| 1996/0418 |
| |
| 1997/0806 |
| |
| 1996/0418 | ||
| 1997/0806 |
| |
| 1996/0607 |
| |
| 1997/0806 |
| |
| 1997/0327 | iunlock(&ctlr->rlock); | |
| 1996/0607 | ||
| 1997/0823 | command(ctlr, LoadRUB, 0); command(ctlr, LoadCUB, 0); command(ctlr, LoadDCA, PADDR(ctlr->dump)); | |
| 1996/0418 | /* | |
| 1996/0423 |
| |
| 1997/0823 | * Initialise the receive frame, transmit ring and configuration areas. | |
| 1996/0418 | */ | |
| 1997/0823 | ctlr->ncb = Ncb; | |
| 1996/0418 | ctlrinit(ctlr); /* | |
| 1997/0807/sys/src/9/pc/ether82557.c:817,825 – 1997/0823/sys/src/9/pc/ether82557.c:858,869 | ||
| 1996/0418 | } /* | |
| 1997/0823 | * Load the chip configuration and start it off. | |
| 1996/0418 | */ | |
| 1997/0327 |
| |
| 1997/0823 | if(ether->oq == 0) ether->oq = qopen(256*1024, 1, 0, 0); configure(ether, 0); command(ctlr, CUstart, PADDR(&ctlr->cbr->status)); | |
| 1996/0418 | /* * Check if the adapter's station address is to be overridden. | |
| 1997/0807/sys/src/9/pc/ether82557.c:835,844 – 1997/0823/sys/src/9/pc/ether82557.c:879,888 | ||
| 1996/0418 | } } | |
| 1997/0327 |
| |
| 1996/0418 |
| |
| 1997/0327 |
| |
| 1996/0418 | ||
| 1997/0823 | ilock(&ctlr->cblock); ctlr->action = CbIAS; txstart(ether); iunlock(&ctlr->cblock); | |
| 1996/0607 | ||
| 1996/0418 | /* * Linkage to the generic ethernet driver. | |
| 1997/0823/sys/src/9/pc/ether82557.c:255,266 – 1997/1011/sys/src/9/pc/ether82557.c:255,268 (short | long) | ||
| 1997/0823 | * Only back-to-back CUresume can be done * without waiting for any previous command to complete. * This should be the common case. | |
| 1997/1011 | * Unfortunately there's a chip errata where back-to-back * CUresumes can be lost, the fix is to always wait. | |
| 1997/0823 | if(c == CUresume && ctlr->command == CUresume){ csr8w(ctlr, CommandR, c); iunlock(&ctlr->rlock); return; } | |
| 1997/1011 | */ | |
| 1997/0823 | while(csr8r(ctlr, CommandR)) ; | |
| 1997/0823/sys/src/9/pc/ether82557.c:757,763 – 1997/1011/sys/src/9/pc/ether82557.c:759,765 | ||
| 1997/0327 | * bar[1] is the I/O port register address (32 bytes) and * bar[2] is for the flash ROM (1MB). */ | |
| 1997/0723 |
| |
| 1997/1011 | i82557adapter(&adapter, p->mem[1].bar & ~0x01, p->intl, p->tbdf); | |
| 1996/0418 | } } | |
| 1997/1011/sys/src/9/pc/ether82557.c:190,196 – 1998/0304/sys/src/9/pc/ether82557.c:190,200 (short | long) | ||
| 1997/0823 | int state; | |
| 1996/0418 | int port; | |
| 1998/0304 | ushort eeprom[0x40]; | |
| 1996/0418 | ||
| 1998/0304 | Rendez timer; /* watchdog timer for receive lockup errata */ int tick; | |
| 1997/0327 | Lock rlock; /* registers */ | |
| 1997/0823 | int command; /* last command issued */ | |
| 1996/0418 | ||
| 1997/1011/sys/src/9/pc/ether82557.c:208,213 – 1998/0304/sys/src/9/pc/ether82557.c:212,218 | ||
| 1997/0823 | Cb* cbtail; int cbq; int cbqmax; | |
| 1998/0304 | int cbqmaxhw; | |
| 1996/0607 | ||
| 1996/0622 | Lock dlock; /* dump statistical counters */ | |
| 1996/0607 | ulong dump[17]; | |
| 1997/1011/sys/src/9/pc/ether82557.c:230,236 – 1998/0304/sys/src/9/pc/ether82557.c:235,241 | ||
| 1996/0418 | 0x60, /* inter-frame spacing */ 0x00, 0xF2, | |
| 1996/0601 |
| |
| 1998/0304 | 0xC8, /* 503, promiscuous mode off */ | |
| 1996/0418 | 0x00, 0x40, | |
| 1997/0327 | 0xF3, /* transmit padding enable */ | |
| 1997/1011/sys/src/9/pc/ether82557.c:314,322 – 1998/0304/sys/src/9/pc/ether82557.c:319,360 | ||
| 1997/0327 | } | |
| 1996/0418 | static void | |
| 1998/0304 | watchdog(void* arg) { Ether *ether; Ctlr *ctlr; static void txstart(Ether*); ether = arg; for(;;){ ctlr = ether->ctlr; tsleep(&ctlr->timer, return0, 0, 4000); /* * Hmmm. This doesn't seem right. Currently * the device can't be disabled but it may be in * the future. */ ctlr = ether->ctlr; if(ctlr == nil || ctlr->state == 0){ print("%s: exiting\n", up->text); pexit("disabled", 0); } if(ctlr->tick++){ ilock(&ctlr->cblock); ctlr->action = CbMAS; txstart(ether); iunlock(&ctlr->cblock); } } } static void | |
| 1996/0418 | attach(Ether* ether) { Ctlr *ctlr; | |
| 1998/0304 | char name[NAMELEN]; | |
| 1996/0418 | ctlr = ether->ctlr; | |
| 1997/0823 | lock(&ctlr->slock); | |
| 1997/1011/sys/src/9/pc/ether82557.c:323,328 – 1998/0304/sys/src/9/pc/ether82557.c:361,376 | ||
| 1997/0823 | if(ctlr->state == 0){ command(ctlr, RUstart, PADDR(ctlr->rfdhead->rp)); ctlr->state = 1; | |
| 1998/0304 | /* * Start the watchdog timer for the receive lockup errata * unless the EEPROM compatibility word indicates it may be * omitted. */ if((ctlr->eeprom[0x03] & 0x0003) != 0x0003){ snprint(name, NAMELEN, "#l%dwatchdog", ether->ctlrno); kproc(name, watchdog, ether); } | |
| 1996/0418 | } | |
| 1997/0823 | unlock(&ctlr->slock); | |
| 1996/0418 | } | |
| 1997/1011/sys/src/9/pc/ether82557.c:379,386 – 1998/0304/sys/src/9/pc/ether82557.c:427,437 | ||
| 1997/0807 | len += snprint(p+len, READSTR-len, "receive overrun errors: %lud\n", dump[13]); len += snprint(p+len, READSTR-len, "receive collision detect errors: %lud\n", dump[14]); | |
| 1997/0823 | len += snprint(p+len, READSTR-len, "receive short frame errors: %lud\n", dump[15]); | |
| 1998/0304 | if(ctlr->cbqmax > ctlr->cbqmaxhw) ctlr->cbqmaxhw = ctlr->cbqmax; len += snprint(p+len, READSTR-len, "cbqmax: %lud\n", ctlr->cbqmax); ctlr->cbqmax = 0; snprint(p+len, READSTR-len, "threshold: %lud\n", ctlr->threshold); | |
| 1997/0417 | n = readstr(offset, a, n, p); free(p); | |
| 1997/1011/sys/src/9/pc/ether82557.c:422,427 – 1998/0304/sys/src/9/pc/ether82557.c:473,483 | ||
| 1997/0823 | memmove(cb->data, ether->ea, Eaddrlen); ctlr->action = 0; } | |
| 1998/0304 | else if(ctlr->action == CbMAS){ cb->command = CbS|CbMAS; memset(cb->data, 0, sizeof(cb->data)); ctlr->action = 0; } | |
| 1997/0823 | else{ print("#l%d: action 0x%uX\n", ether->ctlrno, ctlr->action); ctlr->action = 0; | |
| 1997/1011/sys/src/9/pc/ether82557.c:456,461 – 1998/0304/sys/src/9/pc/ether82557.c:512,518 | ||
| 1997/0823 | } else{ ctlr->configdata[6] &= ~0x80; | |
| 1998/0304 | ctlr->configdata[6] |= 0x40; | |
| 1997/0823 | ctlr->configdata[7] |= 0x01; ctlr->configdata[15] &= ~0x01; ctlr->configdata[18] |= 0x01; /* 0x03? */ | |
| 1997/1011/sys/src/9/pc/ether82557.c:505,510 – 1998/0304/sys/src/9/pc/ether82557.c:562,574 | ||
| 1997/0327 | if(!(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI))) | |
| 1996/0607 | break; | |
| 1996/0418 | ||
| 1998/0304 | /* * If the watchdog timer for the receiver lockup errata is running, * let it know the receiver is active. */ if(status & (StatFR|StatRNR)) ctlr->tick = 0; | |
| 1996/0418 | if(status & StatFR){ | |
| 1997/0327 | bp = ctlr->rfdhead; | |
| 1996/0418 | rfd = (Rfd*)bp->rp; | |
| 1997/1011/sys/src/9/pc/ether82557.c:648,673 – 1998/0304/sys/src/9/pc/ether82557.c:712,734 | ||
| 1997/0823 | ||
| 1996/0418 | memmove(ctlr->configdata, configdata, sizeof(configdata)); | |
| 1997/0823 | ctlr->threshold = 8; | |
| 1998/0304 | ctlr->tick = 0; | |
| 1997/0823 | iunlock(&ctlr->cblock); | |
| 1996/0418 | } static int | |
| 1998/0304 | miir(Ctlr* ctlr, int phyadd, int regadd) | |
| 1996/0418 | { int mcr, timo; | |
| 1998/0304 | for(timo = 64; timo; timo--){ | |
| 1996/0418 | mcr = csr32r(ctlr, Mcr); if(mcr & MDIready) break; | |
| 1998/0304 | microdelay(1); | |
| 1996/0418 | } if(mcr & MDIready) | |
| 1997/1011/sys/src/9/pc/ether82557.c:677,682 – 1998/0304/sys/src/9/pc/ether82557.c:738,763 | ||
| 1996/0418 | } static int | |
| 1998/0304 | miiw(Ctlr* ctlr, int phyadd, int regadd, int data) { int mcr, timo; csr32w(ctlr, Mcr, MDIwrite|(phyadd<<21)|(regadd<<16)|(data & 0xFFFF)); mcr = 0; for(timo = 64; timo; timo--){ mcr = csr32r(ctlr, Mcr); if(mcr & MDIready) break; microdelay(1); } if(mcr & MDIready) return 0; return -1; } static int | |
| 1996/0418 | hy93c46r(Ctlr* ctlr, int r) { int i, op, data; | |
| 1997/1011/sys/src/9/pc/ether82557.c:685,691 – 1998/0304/sys/src/9/pc/ether82557.c:766,772 | ||
| 1996/0418 | * Hyundai HY93C46 or equivalent serial EEPROM. * This sequence for reading a 16-bit register 'r' * in the EEPROM is taken straight from Section | |
| 1998/0304 | * 3.3.4.2 of the Intel 82557 User's Guide. | |
| 1996/0418 | */ csr16w(ctlr, Ecr, EEcs); op = EEstart|EEread; | |
| 1997/1011/sys/src/9/pc/ether82557.c:693,701 – 1998/0304/sys/src/9/pc/ether82557.c:774,782 | ||
| 1996/0418 | data = (((op>>i) & 0x01)<<2)|EEcs; csr16w(ctlr, Ecr, data); csr16w(ctlr, Ecr, data|EEsk); | |
| 1998/0304 | microdelay(1); | |
| 1996/0418 | csr16w(ctlr, Ecr, data); | |
| 1998/0304 | microdelay(1); | |
| 1996/0418 | } for(i = EEaddrsz-1; i >= 0; i--){ | |
| 1997/1011/sys/src/9/pc/ether82557.c:704,710 – 1998/0304/sys/src/9/pc/ether82557.c:785,791 | ||
| 1996/0418 | csr16w(ctlr, Ecr, data|EEsk); delay(1); csr16w(ctlr, Ecr, data); | |
| 1998/0304 | microdelay(1); | |
| 1997/0327 | if(!(csr16r(ctlr, Ecr) & EEdo)) | |
| 1996/0418 | break; } | |
| 1997/1011/sys/src/9/pc/ether82557.c:712,722 – 1998/0304/sys/src/9/pc/ether82557.c:793,803 | ||
| 1996/0418 | data = 0; for(i = 15; i >= 0; i--){ csr16w(ctlr, Ecr, EEcs|EEsk); | |
| 1998/0304 | microdelay(1); | |
| 1996/0418 | if(csr16r(ctlr, Ecr) & EEdo) data |= (1<<i); csr16w(ctlr, Ecr, EEcs); | |
| 1998/0304 | microdelay(1); | |
| 1996/0418 | } csr16w(ctlr, Ecr, 0); | |
| 1997/1011/sys/src/9/pc/ether82557.c:766,772 – 1998/0304/sys/src/9/pc/ether82557.c:847,854 | ||
| 1996/0418 | static int reset(Ether* ether) { | |
| 1997/0327 |
| |
| 1998/0304 | int an, i, phyaddr, port, x; unsigned short sum; | |
| 1997/0327 | Block *bp, **bpp; Adapter *ap; | |
| 1996/0418 | uchar ea[Eaddrlen]; | |
| 1997/1011/sys/src/9/pc/ether82557.c:827,863 – 1998/0304/sys/src/9/pc/ether82557.c:909,977 | ||
| 1996/0418 | ctlrinit(ctlr); /* | |
| 1997/0723 |
| |
| 1998/0304 | * Read the EEPROM. | |
| 1996/0418 | */ | |
| 1997/0723 |
| |
| 1998/0304 | sum = 0; for(i = 0; i < 0x40; i++){ x = hy93c46r(ctlr, i); ctlr->eeprom[i] = x; sum += x; } if(sum != 0xBABA) print("#l%d: EEPROM checksum - 0x%4.4uX\n", ether->ctlrno, sum); | |
| 1996/0418 | ||
| 1996/0625 |
| |
| 1997/0327 |
| |
| 1998/0304 | /* * Eeprom[6] indicates whether there is a PHY and whether * it's not 10Mb-only, in which case use the given PHY address * to set any PHY specific options and determine the speed. * If no PHY, assume 82503 (serial) operation. */ if((ctlr->eeprom[6] & 0x1F00) && !(ctlr->eeprom[6] & 0x8000)){ phyaddr = ctlr->eeprom[6] & 0x00FF; /* * Resolve the highest common ability of the two * link partners. In descending order: * 0x0100 100BASE-TX Full Duplex * 0x0200 100BASE-T4 * 0x0080 100BASE-TX * 0x0040 10BASE-T Full Duplex * 0x0020 10BASE-T */ an = miir(ctlr, phyaddr, 0x04); an &= miir(ctlr, phyaddr, 0x05) & 0x03E0; if(an & 0x380) | |
| 1996/0625 | ether->mbps = 100; | |
| 1996/0418 |
| |
| 1996/0601 |
| |
| 1996/0625 |
| |
| 1997/0327 |
| |
| 1996/0625 |
| |
| 1998/0304 | switch((ctlr->eeprom[6]>>8) & 0x001F){ case 0x04: /* DP83840 */ case 0x0A: /* DP83840A */ /* * The DP83840[A] requires some tweaking for * reliable operation. */ x = miir(ctlr, phyaddr, 0x17) & ~0x0520; x |= 0x0020; for(i = 0; i < ether->nopt; i++){ if(cistrcmp(ether->opt[i], "congestioncontrol")) continue; x |= 0x0100; break; | |
| 1996/0625 | } | |
| 1998/0304 | if(an & 0x0140) x |= 0x0400; miiw(ctlr, phyaddr, 0x17, x); break; | |
| 1996/0418 | } | |
| 1998/0304 | ctlr->configdata[8] = 1; ctlr->configdata[15] &= ~0x80; | |
| 1996/0418 | } | |
| 1998/0304 | else{ ctlr->configdata[8] = 0; ctlr->configdata[15] |= 0x80; } | |
| 1996/0418 | /* | |
| 1997/0823 | * Load the chip configuration and start it off. | |
| 1997/1011/sys/src/9/pc/ether82557.c:875,881 – 1998/0304/sys/src/9/pc/ether82557.c:989,995 | ||
| 1996/0418 | memset(ea, 0, Eaddrlen); | |
| 1997/0806 | if(memcmp(ea, ether->ea, Eaddrlen) == 0){ | |
| 1996/0418 | for(i = 0; i < Eaddrlen/2; i++){ | |
| 1998/0304 | x = ctlr->eeprom[i]; | |
| 1997/0327 | ether->ea[2*i] = x; ether->ea[2*i+1] = x>>8; | |
| 1996/0418 | } | |
| 1998/0304/sys/src/9/pc/ether82557.c:554,563 – 1998/0331/sys/src/9/pc/ether82557.c:554,563 (short | long) | ||
|
Use ilock instead of lock in interrupt handler. XXX - Is this necessary? rsc Fri Mar 4 12:44:25 2005 | ||
| 1996/0418 | ctlr = ether->ctlr; for(;;){ | |
| 1997/0327 |
| |
| 1998/0331 | ilock(&ctlr->rlock); | |
| 1996/0418 | status = csr16r(ctlr, Status); csr8w(ctlr, Ack, (status>>8) & 0xFF); | |
| 1997/0327 |
| |
| 1998/0331 | iunlock(&ctlr->rlock); | |
| 1996/0418 | ||
| 1997/0327 | if(!(status & (StatCX|StatFR|StatCNA|StatRNR|StatMDI|StatSWI))) | |
| 1996/0607 | break; | |
| 1998/0304/sys/src/9/pc/ether82557.c:634,640 – 1998/0331/sys/src/9/pc/ether82557.c:634,640 | ||
| 1996/0418 | } if(status & StatCNA){ | |
| 1997/0823 |
| |
| 1998/0331 | ilock(&ctlr->cblock); | |
| 1997/0823 | cb = ctlr->cbtail; while(ctlr->cbq){ | |
| 1998/0304/sys/src/9/pc/ether82557.c:653,659 – 1998/0331/sys/src/9/pc/ether82557.c:653,659 | ||
| 1997/0823 | ctlr->cbtail = cb; | |
| 1996/0418 | ||
| 1997/0823 | txstart(ether); | |
| 1998/0331 | iunlock(&ctlr->cblock); | |
| 1997/0823 | ||
| 1996/0418 | status &= ~StatCNA; } | |
| 1998/0331/sys/src/9/pc/ether82557.c:530,535 – 1998/0507/sys/src/9/pc/ether82557.c:530,542 (short | long) | ||
|
Add multicast function.
rsc Fri Mar 4 12:44:25 2005 | ||
| 1997/0823 | } | |
| 1996/0418 | ||
| 1997/0823 | static void | |
| 1998/0507 | multicast(void* arg, uchar *addr, int on) { USED(addr, on); configure(arg, 1); } static void | |
| 1997/0823 | transmit(Ether* ether) { Ctlr *ctlr; | |
| 1998/0331/sys/src/9/pc/ether82557.c:1010,1015 – 1998/0507/sys/src/9/pc/ether82557.c:1017,1023 | ||
| 1996/0607 | ether->ifstat = ifstat; | |
| 1996/0418 | ||
| 1996/0607 | ether->promiscuous = promiscuous; | |
| 1998/0507 | ether->multicast = multicast; | |
| 1996/0418 | ether->arg = ether; return 0; | |
| 1998/0507/sys/src/9/pc/ether82557.c:854,860 – 1998/0511/sys/src/9/pc/ether82557.c:854,860 (short | long) | ||
|
Add auto-negotiation for 82555. Add fullduplex and speed options for cards that cannot auto-negotiate. rsc Fri Mar 4 12:44:25 2005 | ||
| 1996/0418 | static int reset(Ether* ether) { | |
| 1998/0304 |
| |
| 1998/0511 | int anar, anlpar, bmcr, bmsr, force, i, phyaddr, port, x; | |
| 1998/0304 | unsigned short sum; | |
| 1997/0327 | Block *bp, **bpp; Adapter *ap; | |
| 1998/0507/sys/src/9/pc/ether82557.c:945,954 – 1998/0511/sys/src/9/pc/ether82557.c:945,958 | ||
| 1998/0304 | * 0x0040 10BASE-T Full Duplex * 0x0020 10BASE-T */ | |
| 1996/0625 |
| |
| 1998/0511 | anar = miir(ctlr, phyaddr, 0x04); anlpar = miir(ctlr, phyaddr, 0x05) & 0x03E0; anar &= anlpar; bmcr = 0; if(anar & 0x380) bmcr = 0x2000; if(anar & 0x0140) bmcr |= 0x0100; | |
| 1998/0304 | switch((ctlr->eeprom[6]>>8) & 0x001F){ | |
| 1998/0507/sys/src/9/pc/ether82557.c:957,965 – 1998/0511/sys/src/9/pc/ether82557.c:961,972 | ||
| 1998/0304 | /* * The DP83840[A] requires some tweaking for * reliable operation. | |
| 1998/0511 | * The manual says bit 10 should be unconditionally * set although it supposedly only affects full-duplex * operation (an & 0x0140). | |
| 1998/0304 | */ x = miir(ctlr, phyaddr, 0x17) & ~0x0520; | |
| 1998/0511 | x |= 0x0420; | |
| 1998/0304 | for(i = 0; i < ether->nopt; i++){ if(cistrcmp(ether->opt[i], "congestioncontrol")) continue; | |
| 1998/0507/sys/src/9/pc/ether82557.c:966,975 – 1998/0511/sys/src/9/pc/ether82557.c:973,1047 | ||
| 1998/0304 | x |= 0x0100; break; | |
| 1996/0625 | } | |
| 1998/0304 |
| |
| 1998/0511 | /* * If the link partner can't autonegotiate, determine * the speed from elsewhere. */ if(anlpar == 0){ miir(ctlr, phyaddr, 0x01); bmsr = miir(ctlr, phyaddr, 0x01); x = miir(ctlr, phyaddr, 0x19); if((bmsr & 0x0004) && !(x & 0x0040)) bmcr = 0x2000; } | |
| 1998/0304 | break; | |
| 1998/0511 | case 0x07: /* Intel 82555 */ /* * Auto-negotiation may fail if the other end is * a DP83840A and the cable is short. */ miir(ctlr, phyaddr, 0x01); bmsr = miir(ctlr, phyaddr, 0x01); if((miir(ctlr, phyaddr, 0) & 0x1000) && !(bmsr & 0x0020)){ miiw(ctlr, phyaddr, 0x1A, 0x2010); x = miir(ctlr, phyaddr, 0); miiw(ctlr, phyaddr, 0, 0x0200|x); for(i = 0; i < 3000; i++){ delay(1); if(miir(ctlr, phyaddr, 0x01) & 0x0020) break; } miiw(ctlr, phyaddr, 0x1A, 0x2000); anar = miir(ctlr, phyaddr, 0x04); anlpar = miir(ctlr, phyaddr, 0x05) & 0x03E0; anar &= anlpar; bmcr = 0; if(anar & 0x380) bmcr = 0x2000; if(anar & 0x0140) bmcr |= 0x0100; } break; } /* * Force speed and duplex if no auto-negotiation. */ if(anlpar == 0){ force = 0; for(i = 0; i < ether->nopt; i++){ if(cistrcmp(ether->opt[i], "fullduplex") == 0){ force = 1; bmcr |= 0x0100; ctlr->configdata[19] |= 0x40; } else if(cistrcmp(ether->opt[i], "speed") == 0){ force = 1; x = strtol(ðer->opt[i][6], 0, 0); if(x == 10) bmcr &= ~0x2000; else if(x == 100) bmcr |= 0x2000; else force = 0; } } if(force) miiw(ctlr, phyaddr, 0x00, bmcr); | |
| 1996/0418 | } | |
| 1998/0304 | ctlr->configdata[8] = 1; | |
| 1998/0511/sys/src/9/pc/ether82557.c:108,114 – 1998/0522/sys/src/9/pc/ether82557.c:108,114 (short | long) | ||
|
Bug fix?: call coherence after changing card data.
Buf fix? or paranoia: use 1700 instead of sizeof(Etherpkt) and don't discard overruns. rsc Fri Mar 4 12:44:25 2005 | ||
| 1996/0418 | ushort count; ushort size; | |
| 1997/0327 |
| |
| 1998/0522 | uchar data[1700]; | |
| 1996/0418 | } Rfd; enum { /* field */ | |
| 1998/0511/sys/src/9/pc/ether82557.c:485,490 – 1998/0522/sys/src/9/pc/ether82557.c:485,491 | ||
| 1997/0823 | } cb->status = 0; | |
| 1998/0522 | coherence(); | |
| 1997/0823 | ctlr->cbhead->command &= ~CbS; ctlr->cbhead = cb; ctlr->cbq++; | |
| 1998/0511/sys/src/9/pc/ether82557.c:504,510 – 1998/0522/sys/src/9/pc/ether82557.c:505,511 | ||
| 1997/0823 | ilock(&ctlr->cblock); if(promiscuous){ ctlr->configdata[6] |= 0x80; /* Save Bad Frames */ | |
| 1998/0522 | //ctlr->configdata[6] &= ~0x40; /* !Discard Overrun Rx Frames */ | |
| 1997/0823 | ctlr->configdata[7] &= ~0x01; /* !Discard Short Rx Frames */ ctlr->configdata[15] |= 0x01; /* Promiscuous mode */ ctlr->configdata[18] &= ~0x01; /* (!Padding enable?), !stripping enable */ | |
| 1998/0511/sys/src/9/pc/ether82557.c:512,518 – 1998/0522/sys/src/9/pc/ether82557.c:513,519 | ||
| 1997/0823 | } else{ ctlr->configdata[6] &= ~0x80; | |
| 1998/0304 |
| |
| 1998/0522 | //ctlr->configdata[6] |= 0x40; | |
| 1997/0823 | ctlr->configdata[7] |= 0x01; ctlr->configdata[15] &= ~0x01; ctlr->configdata[18] |= 0x01; /* 0x03? */ | |
| 1998/0511/sys/src/9/pc/ether82557.c:592,598 – 1998/0522/sys/src/9/pc/ether82557.c:593,599 | ||
| 1997/0327 | * If not, just adjust the necessary fields for reuse. */ if((rfd->field & RfdOK) && (xbp = rfdalloc(rfd->link))){ | |
| 1998/0522 | bp->rp += sizeof(Rfd)-sizeof(rfd->data); | |
| 1997/0327 | bp->wp = bp->rp + (rfd->count & 0x3FFF); xbp->next = bp->next; | |
| 1998/0511/sys/src/9/pc/ether82557.c:621,626 – 1998/0522/sys/src/9/pc/ether82557.c:622,628 | ||
| 1997/0327 | ctlr->rfdtail->next = bp; ((Rfd*)ctlr->rfdtail->rp)->link = PADDR(bp->rp); ((Rfd*)ctlr->rfdtail->rp)->field |= RfdS; | |
| 1998/0522 | coherence(); | |
| 1996/0418 | rfd->field &= ~RfdS; | |
| 1997/0327 | /* | |
| 1998/0522/sys/src/9/pc/ether82557.c:429,437 – 1998/0825/sys/src/9/pc/ether82557.c:429,437 (short | long) | ||
|
Bug fix: print format.
rsc Fri Mar 4 12:44:25 2005 | ||
| 1997/0823 | len += snprint(p+len, READSTR-len, "receive short frame errors: %lud\n", dump[15]); | |
| 1998/0304 | if(ctlr->cbqmax > ctlr->cbqmaxhw) ctlr->cbqmaxhw = ctlr->cbqmax; | |
| 1998/0825 | len += snprint(p+len, READSTR-len, "cbqmax: %d\n", ctlr->cbqmax); | |
| 1998/0304 | ctlr->cbqmax = 0; | |
| 1998/0825 | snprint(p+len, READSTR-len, "threshold: %d\n", ctlr->threshold); | |
| 1997/0417 | n = readstr(offset, a, n, p); free(p); | |
| 1998/0825/sys/src/9/pc/ether82557.c:192,197 – 1998/0929/sys/src/9/pc/ether82557.c:192,199 (short | long) | ||
| 1996/0418 | int port; | |
| 1998/0304 | ushort eeprom[0x40]; | |
| 1996/0418 | ||
| 1998/0929 | Lock miilock; | |
| 1998/0304 | Rendez timer; /* watchdog timer for receive lockup errata */ int tick; | |
| 1998/0825/sys/src/9/pc/ether82557.c:379,385 – 1998/0929/sys/src/9/pc/ether82557.c:381,387 | ||
| 1996/0607 | ifstat(Ether* ether, void* a, long n, ulong offset) { | |
| 1997/0417 | char *p; | |
| 1996/0607 |
| |
| 1998/0929 | int i, len, phyaddr; | |
| 1997/0417 | Ctlr *ctlr; ulong dump[17]; | |
| 1996/0607 | ||
| 1998/0825/sys/src/9/pc/ether82557.c:431,438 – 1998/0929/sys/src/9/pc/ether82557.c:433,459 | ||
| 1998/0304 | ctlr->cbqmaxhw = ctlr->cbqmax; | |
| 1998/0825 | len += snprint(p+len, READSTR-len, "cbqmax: %d\n", ctlr->cbqmax); | |
| 1998/0304 | ctlr->cbqmax = 0; | |
| 1998/0825 |
| |
| 1998/0929 | len += snprint(p+len, READSTR-len, "threshold: %d\n", ctlr->threshold); | |
| 1997/0417 | ||
| 1998/0929 | len += snprint(p+len, READSTR-len, "eeprom:"); for(i = 0; i < 0x40; i++){ if(i && ((i & 0x07) == 0)) len += snprint(p+len, READSTR-len, "\n "); len += snprint(p+len, READSTR-len, " %4.4uX", ctlr->eeprom[i]); } if((ctlr->eeprom[6] & 0x1F00) && !(ctlr->eeprom[6] & 0x8000)){ phyaddr = ctlr->eeprom[6] & 0x00FF; len += snprint(p+len, READSTR-len, "\nphy %2d:", phyaddr); for(i = 0; i < 6; i++){ static int miir(Ctlr*, int, int); len += snprint(p+len, READSTR-len, " %4.4uX", miir(ctlr, phyaddr, i)); } } snprint(p+len, READSTR-len, "\n"); | |
| 1997/0417 | n = readstr(offset, a, n, p); free(p); | |
| 1998/0825/sys/src/9/pc/ether82557.c:731,736 – 1998/0929/sys/src/9/pc/ether82557.c:752,758 | ||
| 1996/0418 | { int mcr, timo; | |
| 1998/0929 | lock(&ctlr->miilock); | |
| 1996/0418 | csr32w(ctlr, Mcr, MDIread|(phyadd<<21)|(regadd<<16)); mcr = 0; | |
| 1998/0304 | for(timo = 64; timo; timo--){ | |
| 1998/0825/sys/src/9/pc/ether82557.c:739,744 – 1998/0929/sys/src/9/pc/ether82557.c:761,767 | ||
| 1996/0418 | break; | |
| 1998/0304 | microdelay(1); | |
| 1996/0418 | } | |
| 1998/0929 | unlock(&ctlr->miilock); | |
| 1996/0418 | if(mcr & MDIready) return mcr & 0xFFFF; | |
| 1998/0825/sys/src/9/pc/ether82557.c:751,756 – 1998/0929/sys/src/9/pc/ether82557.c:774,780 | ||
| 1998/0304 | { int mcr, timo; | |
| 1998/0929 | lock(&ctlr->miilock); | |
| 1998/0304 | csr32w(ctlr, Mcr, MDIwrite|(phyadd<<21)|(regadd<<16)|(data & 0xFFFF)); mcr = 0; for(timo = 64; timo; timo--){ | |
| 1998/0825/sys/src/9/pc/ether82557.c:759,764 – 1998/0929/sys/src/9/pc/ether82557.c:783,789 | ||
| 1998/0304 | break; microdelay(1); } | |
| 1998/0929 | unlock(&ctlr->miilock); | |
| 1998/0304 | if(mcr & MDIready) return 0; | |
| 1998/0825/sys/src/9/pc/ether82557.c:853,862 – 1998/0929/sys/src/9/pc/ether82557.c:878,899 | ||
| 1996/0418 | } } | |
| 1998/0929 | static char* mediatable[9] = { "10BASE-T", /* TP */ "10BASE-2", /* BNC */ "10BASE-5", /* AUI */ "100BASE-TX", "10BASE-TFD", "100BASE-TXFD", "100BASE-T4", "100BASE-FX", "100BASE-FXFD", }; | |
| 1996/0418 | static int reset(Ether* ether) { | |
| 1998/0511 |
| |
| 1998/0929 | int anar, anlpar, bmcr, bmsr, i, k, medium, phyaddr, port, x; | |
| 1998/0304 | unsigned short sum; | |
| 1997/0327 | Block *bp, **bpp; Adapter *ap; | |
| 1998/0825/sys/src/9/pc/ether82557.c:1024,1048 – 1998/0929/sys/src/9/pc/ether82557.c:1061,1106 | ||
| 1998/0511 | * Force speed and duplex if no auto-negotiation. */ if(anlpar == 0){ | |
| 1998/0929 | medium = -1; | |
| 1998/0511 | for(i = 0; i < ether->nopt; i++){ | |
| 1998/0929 | for(k = 0; k < nelem(mediatable); k++){ if(cistrcmp(mediatable[k], ether->opt[i])) continue; medium = k; break; } switch(medium){ default: break; case 0x00: /* 10BASE-T */ case 0x01: /* 10BASE-2 */ case 0x02: /* 10BASE-5 */ bmcr &= ~(0x2000|0x0100); ctlr->configdata[19] &= ~0x40; break; case 0x03: /* 100BASE-TX */ case 0x06: /* 100BASE-T4 */ case 0x07: /* 100BASE-FX */ ctlr->configdata[19] &= ~0x40; bmcr |= 0x2000; break; case 0x04: /* 10BASE-TFD */ bmcr = (bmcr & ~0x2000)|0x0100; | |
| 1998/0511 | ctlr->configdata[19] |= 0x40; | |
| 1998/0929 | break; case 0x05: /* 100BASE-TXFD */ case 0x08: /* 100BASE-FXFD */ bmcr |= 0x2000|0x0100; ctlr->configdata[19] |= 0x40; break; | |
| 1998/0511 | } | |
| 1998/0929 | if(medium != -1) | |
| 1998/0511 | miiw(ctlr, phyaddr, 0x00, bmcr); | |
| 1996/0418 | } | |
| 1998/0304 | ||
| 1998/0929/sys/src/9/pc/ether82557.c:570,580 – 1998/0930/sys/src/9/pc/ether82557.c:570,659 (short | long) | ||
| 1996/0418 | } static void | |
| 1998/0930 | receive(Ether* ether) | |
| 1996/0418 | { Rfd *rfd; | |
| 1998/0930 | Ctlr *ctlr; int count; Block *bp, *pbp, *xbp; ctlr = ether->ctlr; bp = ctlr->rfdhead; for(rfd = (Rfd*)bp->rp; rfd->field & RfdC; rfd = (Rfd*)bp->rp){ /* * If it's an OK receive frame * 1) save the count * 2) if it's small, try to allocate a block and copy * the data, then adjust the necessary fields for reuse; * 3) if it's big, try to allocate a new Rfd and if * successful * adjust the received buffer pointers for the * actual data received; * initialise the replacement buffer to point to * the next in the ring; * initialise bp to point to the replacement; * 4) if there's a good packet, pass it on for disposal. */ if(rfd->field & RfdOK){ pbp = nil; count = rfd->count & 0x3FFF; if((count < ETHERMAXTU/4) && (pbp = iallocb(count))){ memmove(pbp->rp, bp->rp+sizeof(Rfd)-sizeof(rfd->data), count); pbp->wp = pbp->rp + count; rfd->count = 0; rfd->field = 0; } else if(xbp = rfdalloc(rfd->link)){ bp->rp += sizeof(Rfd)-sizeof(rfd->data); bp->wp = bp->rp + count; xbp->next = bp->next; bp->next = 0; pbp = bp; bp = xbp; } if(pbp != nil) etheriq(ether, pbp, 1); } else{ rfd->count = 0; rfd->field = 0; } /* * The ring tail pointer follows the head with with one * unused buffer in between to defeat hardware prefetch; * once the tail pointer has been bumped on to the next * and the new tail has the Suspend bit set, it can be * removed from the old tail buffer. * As a replacement for the current head buffer may have * been allocated above, ensure that the new tail points * to it (next and link). */ rfd = (Rfd*)ctlr->rfdtail->rp; ctlr->rfdtail = ctlr->rfdtail->next; ctlr->rfdtail->next = bp; ((Rfd*)ctlr->rfdtail->rp)->link = PADDR(bp->rp); ((Rfd*)ctlr->rfdtail->rp)->field |= RfdS; coherence(); rfd->field &= ~RfdS; /* * Finally done with the current (possibly replaced) * head, move on to the next and maintain the sentinel * between tail and head. */ ctlr->rfdhead = bp->next; bp = ctlr->rfdhead; } } static void interrupt(Ureg*, void* arg) { | |
| 1997/0327 | Cb* cb; | |
| 1996/0418 | Ctlr *ctlr; Ether *ether; int status; | |
| 1998/0929/sys/src/9/pc/ether82557.c:599,660 – 1998/0930/sys/src/9/pc/ether82557.c:678,684 | ||
| 1998/0304 | ctlr->tick = 0; | |
| 1996/0418 | if(status & StatFR){ | |
| 1997/0327 |
| |
| 1996/0418 |
| |
| 1997/0327 |
| |
| 1998/0522 |
| |
| 1997/0327 |
| |
| 1996/0607 |
| |
| 1997/0327 |
| |
| 1996/0418 |
| |
| 1997/0327 |
| |
| 1996/0418 |
| |
| 1997/0327 |
| |
| 1998/0522 |
| |
| 1996/0418 |
| |
| 1997/0327 |
| |
| 1996/0418 |
| |
| 1998/0930 | receive(ether); | |
| 1996/0418 | status &= ~StatFR; } | |
| 1998/0930/sys/src/9/pc/ether82557.c:226,232 – 1998/1024/sys/src/9/pc/ether82557.c:226,233 (short | long) | ||
| 1996/0418 | 0x00, /* adaptive IFS */ 0x00, | |
| 1997/0327 | 0x00, /* Rx DMA maximum byte count */ | |
| 1998/1024 | // 0x80, /* Tx DMA maximum byte count */ 0x00, /* Tx DMA maximum byte count */ | |
| 1997/0327 | 0x32, /* !late SCB, CNA interrupts */ 0x03, /* discard short Rx frames */ | |
| 1996/0418 | 0x00, /* 503/MII */ | |
| 1998/0930/sys/src/9/pc/ether82557.c:343,354 – 1998/1024/sys/src/9/pc/ether82557.c:344,355 | ||
| 1998/0304 | pexit("disabled", 0); } | |
| 1998/1024 | ilock(&ctlr->cblock); | |
| 1998/0304 | if(ctlr->tick++){ | |
| 1998/1024 | iunlock(&ctlr->cblock); | |
| 1998/0304 | } } | |
| 1998/0930/sys/src/9/pc/ether82557.c:674,681 – 1998/1024/sys/src/9/pc/ether82557.c:675,685 | ||
| 1998/0304 | * If the watchdog timer for the receiver lockup errata is running, * let it know the receiver is active. */ | |
| 1998/1024 | if(status & (StatFR|StatRNR)){ ilock(&ctlr->cblock); | |
| 1998/0304 | ctlr->tick = 0; | |
| 1998/1024 | iunlock(&ctlr->cblock); } | |
| 1998/0304 | ||
| 1996/0418 | if(status & StatFR){ | |
| 1998/0930 | receive(ether); | |
| 1998/0930/sys/src/9/pc/ether82557.c:765,771 – 1998/1024/sys/src/9/pc/ether82557.c:769,775 | ||
| 1997/0823 | ctlr->cbq = 0; | |
| 1996/0418 | memmove(ctlr->configdata, configdata, sizeof(configdata)); | |
| 1997/0823 |
| |
| 1998/1024 | ctlr->threshold = 80; | |
| 1998/0304 | ctlr->tick = 0; | |
| 1997/0823 | iunlock(&ctlr->cblock); | |
| 1998/0930/sys/src/9/pc/ether82557.c:1127,1132 – 1998/1024/sys/src/9/pc/ether82557.c:1131,1139 | ||
| 1998/0929 | if(medium != -1) | |
| 1998/0511 | miiw(ctlr, phyaddr, 0x00, bmcr); | |
| 1996/0418 | } | |
| 1998/1024 | if(bmcr & 0x2000) ether->mbps = 100; | |
| 1998/0304 | ctlr->configdata[8] = 1; ctlr->configdata[15] &= ~0x80; | |
| 1998/1024/sys/src/9/pc/ether82557.c:362,367 – 1998/1126/sys/src/9/pc/ether82557.c:362,370 (short | long) | ||
| 1996/0418 | ctlr = ether->ctlr; | |
| 1997/0823 | lock(&ctlr->slock); if(ctlr->state == 0){ | |
| 1998/1126 | ilock(&ctlr->rlock); csr8w(ctlr, Interrupt, 0); iunlock(&ctlr->rlock); | |
| 1997/0823 | command(ctlr, RUstart, PADDR(ctlr->rfdhead->rp)); ctlr->state = 1; | |
| 1998/0304 | ||
| 1998/1024/sys/src/9/pc/ether82557.c:970,975 – 1998/1126/sys/src/9/pc/ether82557.c:973,979 | ||
| 1997/0327 | ilock(&ctlr->rlock); | |
| 1996/0418 | csr32w(ctlr, Port, 0); delay(1); | |
| 1998/1126 | csr8w(ctlr, Interrupt, InterruptM); | |
| 1997/0327 | iunlock(&ctlr->rlock); | |
| 1996/0607 | ||
| 1997/0823 | command(ctlr, LoadRUB, 0); | |
| Too many diffs (26 > 25). Stopping. | ||