--- /sys/src/9k/386/devether.c +++ /sys/src/9k/386/devether.c @@ -148,7 +148,7 @@ etheriq(Ether* ether, Block* bp, int fromwire) ep = ðer->f[Ntypes]; multi = pkt->d[0] & 1; - /* check for valid multcast addresses */ + /* check for valid multicast addresses */ if(multi && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 && ether->prom == 0){ if(!activemulti(ether, pkt->d, sizeof(pkt->d))){ if(fromwire){ @@ -233,6 +233,8 @@ etheroq(Ether* ether, Block* bp) } if(!loopback){ + if(qfull(ether->oq)) + print("etheroq: WARNING: ether->oq full!\n"); qbwrite(ether->oq, bp); if(ether->transmit != nil) ether->transmit(ether); @@ -266,13 +268,13 @@ etherwrite(Chan* chan, void* buf, long n, vlong) return n; } free(cb); - if(ether->ctl!=nil) - return ether->ctl(ether,buf,n); + if(ether->ctl != nil) + return ether->ctl(ether, buf, n); error(Ebadctl); } - if(n > ether->maxmtu) + if(n > ether->mtu) error(Etoobig); if(n < ether->minmtu) error(Etoosmall); @@ -309,7 +311,7 @@ etherbwrite(Chan* chan, Block* bp, vlong) } ether = etherxx[chan->devno]; - if(n > ether->maxmtu){ + if(n > ether->mtu){ freeb(bp); error(Etoobig); } @@ -369,12 +371,15 @@ etherprobe(int cardno, int ctlrno) char buf[128], name[32]; ether = malloc(sizeof(Ether)); + if(ether == nil) + error(Enomem); memset(ether, 0, sizeof(Ether)); ether->ctlrno = ctlrno; ether->tbdf = -1; ether->mbps = 10; ether->minmtu = ETHERMINTU; ether->maxmtu = ETHERMAXTU; + ether->mtu = ETHERMAXTU; if(cardno < 0){ if(isaconfig("ether", ctlrno, ether) == 0){ @@ -437,16 +442,15 @@ etherprobe(int cardno, int ctlrno) sprint(buf+i, "\n"); print(buf); - if (ether->mbps >= 1000) { + if(ether->mbps >= 1000){ netifinit(ether, name, Ntypes, 512*1024); if(ether->oq == 0) ether->oq = qopen(512*1024, Qmsg, 0, 0); - } else if(ether->mbps >= 100){ + }else if(ether->mbps >= 100){ netifinit(ether, name, Ntypes, 256*1024); if(ether->oq == 0) ether->oq = qopen(256*1024, Qmsg, 0, 0); - } - else{ + }else{ netifinit(ether, name, Ntypes, 128*1024); if(ether->oq == 0) ether->oq = qopen(128*1024, Qmsg, 0, 0); @@ -501,7 +505,7 @@ ethershutdown(void) if(ether == nil) continue; if(ether->shutdown == nil) { - print("#l%d: no shutdown fuction\n", i); + print("#l%d: no shutdown function\n", i); continue; } (*ether->shutdown)(ether); --- /sys/src/9k/386/ether8169.c +++ /sys/src/9k/386/ether8169.c @@ -114,7 +114,7 @@ enum { /* Tcr */ Macv15 = 0x38800000, /* RTL8100E */ Macv25 = 0x28000000, /* RTL8168D */ Macv2c = 0x2c000000, /* RTL8168E */ - Macv2ca = 0x2c800000, /* RTL8111E */ + Macv34 = 0x2c800000, /* RTL8168E/8111E */ Ifg0 = 0x01000000, /* Interframe Gap 0 */ Ifg1 = 0x02000000, /* Interframe Gap 1 */ }; @@ -296,6 +296,10 @@ typedef struct Ctlr { int rcr; /* receive configuration register */ int imr; +// Watermark wmrb; + Watermark wmrd; + Watermark wmtd; + QLock slock; /* statistics */ Dtcc* dtcc; uint txdu; @@ -508,8 +512,10 @@ rtl8169ifstat(Ether* edev, void* a, long n, ulong offset) nexterror(); } + dtcc = ctlr->dtcc; + assert(dtcc); csr32w(ctlr, Dtccr+4, 0); - csr32w(ctlr, Dtccr, PCIWADDR(ctlr->dtcc)|Cmd); + csr32w(ctlr, Dtccr, PCIWADDR(dtcc)|Cmd); for(timeo = 0; timeo < 1000; timeo++){ if(!(csr32r(ctlr, Dtccr) & Cmd)) break; @@ -566,6 +572,10 @@ rtl8169ifstat(Ether* edev, void* a, long n, ulong offset) if(ctlr->mii != nil && ctlr->mii->curphy != nil) miidumpphy(ctlr->mii, p, e); +// p = seprintmark(p, e, &ctlr->wmrb); + p = seprintmark(p, e, &ctlr->wmrd); + p = seprintmark(p, e, &ctlr->wmtd); + USED(p); n = readstr(offset, a, n, alloc); @@ -736,7 +746,7 @@ rtl8169init(Ether* edev) case Macv15: case Macv25: case Macv2c: - case Macv2ca: + case Macv34: break; } @@ -847,8 +857,10 @@ rtl8169attach(Ether* edev) qunlock(&ctlr->alock); error(Enomem); } - memset(ctlr->dtcc, 0, sizeof(Dtcc)); /* paranoia */ rtl8169init(edev); +// initmark(&ctlr->wmrb, Nrb, "rcv bufs unprocessed"); + initmark(&ctlr->wmrd, Nrd-1, "rcv descrs processed at once"); + initmark(&ctlr->wmtd, Ntd-1, "xmit descr queue len"); ctlr->init = 1; } qunlock(&ctlr->alock); @@ -953,6 +965,8 @@ rtl8169transmit(Ether* edev) coherence(); d->control |= Own|Fs|Ls|((BLEN(bp)<wmtd, (x + Ntd - ctlr->tdh) % Ntd); x = NEXT(x, ctlr->ntd); ctlr->ntq++; } @@ -970,7 +984,7 @@ static void rtl8169receive(Ether* edev) { D *d; - int rdh; + int rdh, passed; Block *bp; Ctlr *ctlr; u32int control; @@ -978,6 +992,7 @@ rtl8169receive(Ether* edev) ctlr = edev->ctlr; rdh = ctlr->rdh; + passed = 0; for(;;){ d = &ctlr->rd[rdh]; @@ -1021,6 +1036,7 @@ rtl8169receive(Ether* edev) break; } etheriq(edev, bp, 1); + passed++; } else{ if(!(control & Res)) @@ -1036,6 +1052,8 @@ rtl8169receive(Ether* edev) if(ctlr->nrdfree < ctlr->nrd/2) rtl8169replenish(ctlr); } + /* note how many rds had full buffers */ + notemark(&ctlr->wmrd, passed); ctlr->rdh = rdh; } --- /sys/src/9k/386/ether82563.c +++ /sys/src/9k/386/ether82563.c @@ -320,14 +320,18 @@ enum { /* Receive Delay Timer Ring */ Fpd = 0x80000000, /* Flush partial Descriptor Block */ }; -typedef struct Rd { /* Receive Descriptor */ +typedef struct Ctlr Ctlr; +typedef struct Rd Rd; +typedef struct Td Td; + +struct Rd { /* Receive Descriptor */ u32int addr[2]; u16int length; u16int checksum; u8int status; u8int errors; u16int special; -} Rd; +}; enum { /* Rd status */ Rdd = 0x01, /* Descriptor Done */ @@ -349,11 +353,11 @@ enum { /* Rd errors */ Rxe = 0x80, /* RX Data Error */ }; -typedef struct { /* Transmit Descriptor */ +struct Td { /* Transmit Descriptor */ u32int addr[2]; /* Data */ u32int control; u32int status; -} Td; +}; enum { /* Tdesc control */ LenMASK = 0x000FFFFF, /* Data/Packet Length Field */ @@ -410,8 +414,9 @@ enum { }; enum { - Nrd = 256, /* power of two */ + Nrd = 512, /* power of two */ Ntd = 64, /* power of two */ + /* 1024 buffers can be filled in 12 ms. at full line rate */ Nrb = 1024, /* private receive buffers per Ctlr */ }; @@ -433,15 +438,15 @@ enum { static int rbtab[] = { 0, 9014, - 1514, - 1514, + ETHERMAXTU, + ETHERMAXTU, 9234, 9234, 8192, /* terrible performance above 8k */ - 1514, - 1514, - 1514, - 1514, + ETHERMAXTU, + ETHERMAXTU, + ETHERMAXTU, + ETHERMAXTU, 9018, }; @@ -460,7 +465,6 @@ static char *tname[] = { "i82579", }; -typedef struct Ctlr Ctlr; struct Ctlr { int port; Pcidev *pcidev; @@ -474,7 +478,7 @@ struct Ctlr { int attached; int nrd; int ntd; - int nrb; /* how many this Ctlr has in the pool */ + int nrb; /* # rcv bufs this Ctlr has in the pool */ unsigned rbsz; /* unsigned for % and / by 1024 */ int *nic; @@ -484,6 +488,10 @@ struct Ctlr { Rendez lrendez; int lim; + Watermark wmrb; + Watermark wmrd; + Watermark wmtd; + QLock slock; uint statistics[Nstatistics]; uint lsleep; @@ -502,7 +510,7 @@ struct Ctlr { Rendez rrendez; int rim; - int rdfree; + int rdfree; /* rx descriptors awaiting packets */ Rd *rdba; /* receive descriptor base address */ Block **rb; /* receive buffers */ int rdh; /* receive descriptor head */ @@ -512,7 +520,6 @@ struct Ctlr { Rendez trendez; QLock tlock; - int tbusy; Td *tdba; /* transmit descriptor base address */ Block **tb; /* transmit buffers */ int tdh; /* transmit descriptor head */ @@ -532,6 +539,7 @@ static Ctlr* i82563ctlrtail; static Lock i82563rblock; /* free receive Blocks */ static Block* i82563rbpool; +static int nrbfull; /* # of rcv Blocks with data awaiting processing */ static char* statistics[] = { "CRC Error", @@ -674,6 +682,7 @@ i82563ifstat(Ether* edev, void* a, long n, ulong offset) p = seprint(p, e, "speeds: 10:%ud 100:%ud 1000:%ud ?:%ud\n", ctlr->speeds[0], ctlr->speeds[1], ctlr->speeds[2], ctlr->speeds[3]); p = seprint(p, e, "type: %s\n", tname[ctlr->type]); + p = seprint(p, e, "nrbfull (rcv blocks outstanding): %d\n", nrbfull); // p = seprint(p, e, "eeprom:"); // for(i = 0; i < 0x40; i++){ @@ -683,6 +692,10 @@ i82563ifstat(Ether* edev, void* a, long n, ulong offset) // } // p = seprint(p, e, "\n"); + p = seprintmark(p, e, &ctlr->wmrb); + p = seprintmark(p, e, &ctlr->wmrd); + p = seprintmark(p, e, &ctlr->wmtd); + USED(p); n = readstr(offset, a, n, s); free(s); @@ -813,6 +826,7 @@ i82563rbfree(Block* b) ilock(&i82563rblock); b->next = i82563rbpool; i82563rbpool = b; + nrbfull--; iunlock(&i82563rblock); } @@ -865,24 +879,24 @@ i82563txinit(Ctlr* ctlr) #define Next(x, m) (((x)+1) & (m)) static int -i82563cleanup(Ctlr *c) +i82563cleanup(Ctlr *ctlr) { Block *b; int tdh, m, n; - tdh = c->tdh; - m = c->ntd-1; - while(c->tdba[n = Next(tdh, m)].status & Tdd){ + tdh = ctlr->tdh; + m = ctlr->ntd-1; + while(ctlr->tdba[n = Next(tdh, m)].status & Tdd){ tdh = n; - if((b = c->tb[tdh]) != nil){ - c->tb[tdh] = nil; + if((b = ctlr->tb[tdh]) != nil){ + ctlr->tb[tdh] = nil; freeb(b); }else iprint("82563 tx underrun!\n"); - c->tdba[tdh].status = 0; + ctlr->tdba[tdh].status = 0; } - return c->tdh = tdh; + return ctlr->tdh = tdh; } static void @@ -919,6 +933,8 @@ i82563transmit(Ether* edev) td->addr[0] = PCIWADDR(bp->rp); td->control = Ide|Rs|Ifcs|Teop|BLEN(bp); ctlr->tb[tdt] = bp; + /* note size of queue of tds awaiting transmission */ + notemark(&ctlr->wmtd, (tdt + Ntd - tdh) % Ntd); tdt = Next(tdt, m); } if(ctlr->tdt != tdt){ @@ -940,22 +956,18 @@ i82563replenish(Ctlr* ctlr) while(Next(rdt, m) != ctlr->rdh){ rd = &ctlr->rdba[rdt]; if(ctlr->rb[rdt] != nil){ - iprint("82563: tx overrun\n"); + print("#l%d: 82563: rx overrun\n", ctlr->edev->ctlrno); break; } bp = i82563rballoc(); - if(bp == nil){ - vlong now; - static vlong lasttime; - - /* don't flood the console */ - now = tk2ms(sys->ticks); - if (now - lasttime > 2000) - iprint("#l%d: 82563: all %d rx buffers in use\n", - ctlr->edev->ctlrno, ctlr->nrb); - lasttime = now; - break; - } + if(bp == nil) + /* + * this almost never gets better. likely there's a bug + * elsewhere in the kernel that is failing to free a + * receive Block. + */ + panic("#l%d: 82563: all %d rx buffers in use, nrbfull %d", + ctlr->edev->ctlrno, ctlr->nrb, nrbfull); ctlr->rb[rdt] = bp; rd->addr[0] = PCIWADDR(bp->rp); // rd->addr[1] = 0; @@ -1057,7 +1069,7 @@ i82563rproc(void* arg) Rd *rd; Block *bp; Ctlr *ctlr; - int r, m, rdh, rim; + int r, m, rdh, rim, passed; Ether *edev; edev = arg; @@ -1070,16 +1082,17 @@ i82563rproc(void* arg) m = ctlr->nrd-1; for(;;){ + i82563replenish(ctlr); i82563im(ctlr, Rxt0|Rxo|Rxdmt0|Rxseq|Ack); ctlr->rsleep++; -// coherence(); sleep(&ctlr->rrendez, i82563rim, ctlr); rdh = ctlr->rdh; + passed = 0; for(;;){ - rd = &ctlr->rdba[rdh]; rim = ctlr->rim; ctlr->rim = 0; + rd = &ctlr->rdba[rdh]; if(!(rd->status & Rdd)) break; @@ -1115,7 +1128,12 @@ i82563rproc(void* arg) bp->checksum = rd->checksum; bp->flag |= Bpktck; } + ilock(&i82563rblock); + nrbfull++; + iunlock(&i82563rblock); + notemark(&ctlr->wmrb, nrbfull); etheriq(edev, bp, 1); + passed++; } else { if (rd->status & Reop && rd->errors) print("%s: input packet error %#ux\n", @@ -1124,19 +1142,26 @@ i82563rproc(void* arg) } ctlr->rb[rdh] = nil; + /* rd needs to be replenished to accept another pkt */ rd->status = 0; ctlr->rdfree--; ctlr->rdh = rdh = Next(rdh, m); - if(ctlr->nrd-ctlr->rdfree >= 32 || (rim & Rxdmt0)) + /* + * if number of rds ready for packets is too low, + * set up the unready ones. + */ + if(ctlr->rdfree <= ctlr->nrd - 32 || (rim & Rxdmt0)) i82563replenish(ctlr); } + /* note how many rds had full buffers */ + notemark(&ctlr->wmrd, passed); } } static int -i82563lim(void* c) +i82563lim(void* ctlr) { - return ((Ctlr*)c)->lim != 0; + return ((Ctlr*)ctlr)->lim != 0; } static int speedtab[] = { @@ -1144,14 +1169,14 @@ static int speedtab[] = { }; static uint -phyread(Ctlr *c, int reg) +phyread(Ctlr *ctlr, int reg) { uint phy, i; - csr32w(c, Mdic, MDIrop | 1<ctlr; + ctlr = e->ctlr; - if(c->type == i82573 && (phy = phyread(c, Phyier)) != ~0) - phywrite(c, Phyier, phy | Lscie | Ancie | Spdie | Panie); + if(ctlr->type == i82573 && (phy = phyread(ctlr, Phyier)) != ~0) + phywrite(ctlr, Phyier, phy | Lscie | Ancie | Spdie | Panie); for(;;){ - phy = phyread(c, Physsr); + phy = phyread(ctlr, Physsr); if(phy == ~0) goto next; i = (phy>>14) & 3; - switch(c->type){ + switch(ctlr->type){ case i82563: - a = phyread(c, Phyisr) & Ane; + a = phyread(ctlr, Phyisr) & Ane; break; case i82571: case i82572: case i82575: case i82576: - a = phyread(c, Phylhr) & Anf; + a = phyread(ctlr, Phylhr) & Anf; i = (i-1) & 3; break; default: @@ -1216,18 +1241,18 @@ i82563lproc(void *v) break; } if(a) - phywrite(c, Phyctl, phyread(c, Phyctl) | Ran | Ean); + phywrite(ctlr, Phyctl, phyread(ctlr, Phyctl) | Ran | Ean); e->link = (phy & Rtlink) != 0; if(e->link){ - c->speeds[i]++; + ctlr->speeds[i]++; if (speedtab[i]) e->mbps = speedtab[i]; } next: - c->lim = 0; - i82563im(c, Lsc); - c->lsleep++; - sleep(&c->lrendez, i82563lim, c); + ctlr->lim = 0; + i82563im(ctlr, Lsc); + ctlr->lsleep++; + sleep(&ctlr->lrendez, i82563lim, ctlr); } } @@ -1235,12 +1260,12 @@ static void i82563tproc(void *v) { Ether *e; - Ctlr *c; + Ctlr *ctlr; e = v; - c = e->ctlr; + ctlr = e->ctlr; for(;;){ - sleep(&c->trendez, return0, 0); + sleep(&ctlr->trendez, return0, 0); i82563transmit(e); } } @@ -1293,9 +1318,13 @@ i82563attach(Ether* edev) bp->free = i82563rbfree; freeb(bp); } + nrbfull = 0; ctlr->edev = edev; /* point back to Ether* */ ctlr->attached = 1; + initmark(&ctlr->wmrb, Nrb, "rcv bufs unprocessed"); + initmark(&ctlr->wmrd, Nrd-1, "rcv descrs processed at once"); + initmark(&ctlr->wmtd, Ntd-1, "xmit descr queue len"); snprint(name, sizeof name, "#l%dl", edev->ctlrno); kproc(name, i82563lproc, edev); @@ -1325,7 +1354,7 @@ i82563interrupt(Ureg*, void* arg) ilock(&ctlr->imlock); csr32w(ctlr, Imc, ~0); im = ctlr->im; - i = 1000; /* don't livelock */ + i = Nrd; /* don't livelock */ for(icr = csr32r(ctlr, Icr); icr & ctlr->im && i-- > 0; icr = csr32r(ctlr, Icr)){ if(icr & Lsc){ @@ -1363,7 +1392,7 @@ i82575interrupt(Ureg*, void *) } static int -i82563detach(Ctlr* ctlr) +i82563detach0(Ctlr* ctlr) { int r, timeo; @@ -1425,7 +1454,7 @@ i82563detach(Ctlr* ctlr) r += ctlr->pba & 0xffff; r >>= 1; csr32w(ctlr, Pba, r); - } else if(ctlr->type == i82573 && ctlr->rbsz > 1514) + } else if(ctlr->type == i82573 && ctlr->rbsz > ETHERMAXTU) csr32w(ctlr, Pba, 14); ctlr->pba = csr32r(ctlr, Pba); @@ -1435,6 +1464,18 @@ i82563detach(Ctlr* ctlr) return 0; } +static int +i82563detach(Ctlr* ctlr) +{ + int r; + static Lock detlck; + + ilock(&detlck); + r = i82563detach0(ctlr); + iunlock(&detlck); + return r; +} + static void i82563shutdown(Ether* ether) { @@ -1444,9 +1485,13 @@ i82563shutdown(Ether* ether) static ushort eeread(Ctlr *ctlr, int adr) { + ulong n; + csr32w(ctlr, Eerd, EEstart | adr << 2); - while ((csr32r(ctlr, Eerd) & EEdone) == 0) + for (n = 1000000; (csr32r(ctlr, Eerd) & EEdone) == 0 && n-- > 0; ) ; + if (n == 0) + panic("i82563: eeread stuck"); return csr32r(ctlr, Eerd) >> 16; } @@ -1484,12 +1529,13 @@ fcycle(Ctlr *, Flash *f) } static int -fread(Ctlr *c, Flash *f, int ladr) +fread(Ctlr *ctlr, Flash *f, int ladr) { ushort s; + ulong n; delay(1); - if(fcycle(c, f) == -1) + if(fcycle(ctlr, f) == -1) return -1; f->reg[Fsts] |= Fdone; f->reg32[Faddr] = ladr; @@ -1501,40 +1547,42 @@ fread(Ctlr *c, Flash *f, int ladr) s &= ~(2*Flcycle); /* read */ f->reg[Fctl] = s | Fgo; - while((f->reg[Fsts] & Fdone) == 0) + for (n = 1000000; (f->reg[Fsts] & Fdone) == 0 && n-- > 0; ) ; + if (n == 0) + panic("i82563: fread stuck"); if(f->reg[Fsts] & (Fcerr|Ael)) return -1; return f->reg32[Fdata] & 0xffff; } static int -fload(Ctlr *c) +fload(Ctlr *ctlr) { ulong data, io, r, adr; ushort sum; Flash f; - io = c->pcidev->mem[1].bar & ~0x0f; - f.reg = vmap(io, c->pcidev->mem[1].size); + io = ctlr->pcidev->mem[1].bar & ~0x0f; + f.reg = vmap(io, ctlr->pcidev->mem[1].size); if(f.reg == nil) return -1; f.reg32 = (void*)f.reg; f.base = f.reg32[Bfpr] & 0x1fff; - f.lim = f.reg32[Bfpr]>>16 & 0x1fff; - if(csr32r(c, Eec) & (1<<22)) - f.base += f.lim+1 - f.base >> 1; + f.lim = (f.reg32[Bfpr]>>16) & 0x1fff; + if(csr32r(ctlr, Eec) & (1<<22)) + f.base += (f.lim + 1 - f.base) >> 1; r = f.base << 12; sum = 0; for (adr = 0; adr < 0x40; adr++) { - data = fread(c, &f, r + adr*2); + data = fread(ctlr, &f, r + adr*2); if(data == -1) break; - c->eeprom[adr] = data; + ctlr->eeprom[adr] = data; sum += data; } - vunmap(f.reg, c->pcidev->mem[1].size); + vunmap(f.reg, ctlr->pcidev->mem[1].size); return sum; } @@ -1687,7 +1735,13 @@ i82563pci(void) ctlr->port = io; ctlr->pcidev = p; ctlr->type = type; - ctlr->rbsz = rbtab[type]; + /* + * on the assumption that allowing jumbo packets makes + * the controller much slower (as is true of the 82579), + * never allow jumbos. + */ + // ctlr->rbsz = rbtab[type]; + ctlr->rbsz = ETHERMAXTU; ctlr->nic = mem; if(i82563reset(ctlr)){ --- /sys/src/9k/386/ether82598.c +++ /sys/src/9k/386/ether82598.c @@ -207,6 +207,10 @@ enum { Lmsmask = 7, }; +typedef struct Ctlr Ctlr; +typedef struct Rd Rd; +typedef struct Td Td; + typedef struct { uint reg; char *name; @@ -262,14 +266,14 @@ enum { Rdd = 1<<0, /* descriptor done */ }; -typedef struct { +struct Rd { /* Receive Descriptor */ u32int addr[2]; ushort length; ushort cksum; uchar status; uchar errors; ushort vlan; -} Rd; +}; enum { /* Td cmd */ @@ -282,7 +286,7 @@ enum { Tdd = 1<<0, /* descriptor done */ }; -typedef struct { +struct Td { /* Transmit Descriptor */ u32int addr[2]; ushort length; uchar cso; @@ -290,9 +294,9 @@ typedef struct { uchar status; uchar css; ushort vlan; -} Td; +}; -typedef struct { +struct Ctlr { Pcidev *p; Ether *edev; int type; @@ -303,39 +307,43 @@ typedef struct { uchar flag; int nrd; int ntd; - int nrb; + int nrb; /* # bufs this Ctlr has in the pool */ uint rbsz; int procsrunning; int attached; - Lock slock; - Lock alock; /* attach lock */ + Watermark wmrb; + Watermark wmrd; + Watermark wmtd; + + QLock slock; + QLock alock; /* attach lock */ QLock tlock; Rendez lrendez; Rendez trendez; Rendez rrendez; - uint im; + uint im; /* interrupt mask */ uint lim; uint rim; uint tim; Lock imlock; - Rd *rdba; - Block **rb; - uint rdt; - uint rdfree; + Rd* rdba; /* receive descriptor base address */ + Block** rb; /* receive buffers */ + int rdt; /* receive descriptor tail */ + int rdfree; /* rx descriptors awaiting packets */ - Td *tdba; - uint tdh; - uint tdt; - Block **tb; + Td* tdba; /* transmit descriptor base address */ + int tdh; /* transmit descriptor head */ + int tdt; /* transmit descriptor tail */ + Block** tb; /* transmit buffers */ - uchar ra[Eaddrlen]; - uchar mta[128]; + uchar ra[Eaddrlen]; /* receive address */ + uchar mta[128]; /* multicast table array */ ulong stats[nelem(stattab)]; uint speeds[3]; -} Ctlr; +}; enum { I82598 = 1, @@ -346,18 +354,19 @@ static Ctlr *ctlrtab[4]; static int nctlr; static Lock rblock; static Block *rbpool; +static int nrbfull; /* # of rcv Blocks with data awaiting processing */ static Block *rballoc(void); static void -readstats(Ctlr *c) +readstats(Ctlr *ctlr) { int i; - lock(&c->slock); - for(i = 0; i < nelem(c->stats); i++) - c->stats[i] += c->reg[stattab[i].reg >> 2]; - unlock(&c->slock); + qlock(&ctlr->slock); + for(i = 0; i < nelem(ctlr->stats); i++) + ctlr->stats[i] += ctlr->reg[stattab[i].reg >> 2]; + qunlock(&ctlr->slock); } static int speedtab[] = { @@ -367,28 +376,32 @@ static int speedtab[] = { }; static long -ifstat(Ether *e, void *a, long n, ulong offset) +ifstat(Ether *edev, void *a, long n, ulong offset) { uint i, *t; - char *s, *p, *q; - Ctlr *c; + char *s, *p, *e; + Ctlr *ctlr; - c = e->ctlr; + ctlr = edev->ctlr; p = s = malloc(READSTR); if(p == nil) error(Enomem); - q = p + READSTR; + e = p + READSTR; - readstats(c); + readstats(ctlr); for(i = 0; i < nelem(stattab); i++) - if(c->stats[i] > 0) - p = seprint(p, q, "%.10s %uld\n", stattab[i].name, - c->stats[i]); - t = c->speeds; - p = seprint(p, q, "speeds: 0:%d 1000:%d 10000:%d\n", t[0], t[1], t[2]); - p = seprint(p, q, "mtu: min:%d max:%d\n", e->minmtu, e->maxmtu); - seprint(p, q, "rdfree %d rdh %ld rdt %ld\n", c->rdfree, c->reg[Rdt], - c->reg[Rdh]); + if(ctlr->stats[i] > 0) + p = seprint(p, e, "%.10s %uld\n", stattab[i].name, + ctlr->stats[i]); + t = ctlr->speeds; + p = seprint(p, e, "speeds: 0:%d 1000:%d 10000:%d\n", t[0], t[1], t[2]); + p = seprint(p, e, "mtu: min:%d max:%d\n", edev->minmtu, edev->maxmtu); + p = seprint(p, e, "rdfree %d rdh %ld rdt %ld\n", ctlr->rdfree, ctlr->reg[Rdt], + ctlr->reg[Rdh]); + p = seprintmark(p, e, &ctlr->wmrb); + p = seprintmark(p, e, &ctlr->wmrd); + p = seprintmark(p, e, &ctlr->wmtd); + USED(p); n = readstr(offset, a, n, s); free(s); @@ -396,12 +409,12 @@ ifstat(Ether *e, void *a, long n, ulong offset) } static void -ienable(Ctlr *c, int i) +ienable(Ctlr *ctlr, int i) { - ilock(&c->imlock); - c->im |= i; - c->reg[Ims] = c->im; - iunlock(&c->imlock); + ilock(&ctlr->imlock); + ctlr->im |= i; + ctlr->reg[Ims] = ctlr->im; + iunlock(&ctlr->imlock); } static int @@ -414,23 +427,23 @@ static void lproc(void *v) { int r, i; - Ctlr *c; + Ctlr *ctlr; Ether *e; e = v; - c = e->ctlr; + ctlr = e->ctlr; for (;;) { - r = c->reg[Links]; + r = ctlr->reg[Links]; e->link = (r & Lnkup) != 0; i = 0; if(e->link) i = 1 + ((r & Lnkspd) != 0); - c->speeds[i]++; + ctlr->speeds[i]++; e->mbps = speedtab[i]; - c->lim = 0; - ienable(c, Lsc); - sleep(&c->lrendez, lim, c); - c->lim = 0; + ctlr->lim = 0; + ienable(ctlr, Lsc); + sleep(&ctlr->lrendez, lim, ctlr); + ctlr->lim = 0; } } @@ -531,23 +544,24 @@ rbfree(Block *b) ilock(&rblock); b->next = rbpool; rbpool = b; + nrbfull--; iunlock(&rblock); } static int -cleanup(Ctlr *c, int tdh) +cleanup(Ctlr *ctlr, int tdh) { Block *b; uint m, n; - m = c->ntd - 1; - while(c->tdba[n = NEXTPOW2(tdh, m)].status & Tdd){ + m = ctlr->ntd - 1; + while(ctlr->tdba[n = NEXTPOW2(tdh, m)].status & Tdd){ tdh = n; - b = c->tb[tdh]; - c->tb[tdh] = 0; + b = ctlr->tb[tdh]; + ctlr->tb[tdh] = 0; if (b) freeb(b); - c->tdba[tdh].status = 0; + ctlr->tdba[tdh].status = 0; } return tdh; } @@ -556,42 +570,44 @@ void transmit(Ether *e) { uint i, m, tdt, tdh; - Ctlr *c; + Ctlr *ctlr; Block *b; Td *t; - c = e->ctlr; - if(!canqlock(&c->tlock)){ - ienable(c, Itx0); + ctlr = e->ctlr; + if(!canqlock(&ctlr->tlock)){ + ienable(ctlr, Itx0); return; } - tdh = c->tdh = cleanup(c, c->tdh); - tdt = c->tdt; - m = c->ntd - 1; + tdh = ctlr->tdh = cleanup(ctlr, ctlr->tdh); + tdt = ctlr->tdt; + m = ctlr->ntd - 1; for(i = 0; ; i++){ if(NEXTPOW2(tdt, m) == tdh){ /* ring full? */ - ienable(c, Itx0); + ienable(ctlr, Itx0); break; } if((b = qget(e->oq)) == nil) break; - assert(c->tdba != nil); - t = c->tdba + tdt; + assert(ctlr->tdba != nil); + t = ctlr->tdba + tdt; t->addr[0] = PCIWADDR(b->rp); t->length = BLEN(b); t->cmd = Ifcs | Teop; if (!Goslow) t->cmd |= Rs; - c->tb[tdt] = b; + ctlr->tb[tdt] = b; + /* note size of queue of tds awaiting transmission */ + notemark(&ctlr->wmtd, (tdt + Ntd - tdh) % Ntd); tdt = NEXTPOW2(tdt, m); } if(i) { coherence(); - c->reg[Tdt] = c->tdt = tdt; /* make new Tds active */ + ctlr->reg[Tdt] = ctlr->tdt = tdt; /* make new Tds active */ coherence(); - ienable(c, Itx0); + ienable(ctlr, Itx0); } - qunlock(&c->tlock); + qunlock(&ctlr->tlock); } static int @@ -603,94 +619,115 @@ tim(void *c) static void tproc(void *v) { - Ctlr *c; + Ctlr *ctlr; Ether *e; e = v; - c = e->ctlr; + ctlr = e->ctlr; for (;;) { - sleep(&c->trendez, tim, c); /* transmit kicks us */ - c->tim = 0; + sleep(&ctlr->trendez, tim, ctlr); /* xmit interrupt kicks us */ + ctlr->tim = 0; transmit(e); } } static void -rxinit(Ctlr *c) +rxinit(Ctlr *ctlr) { - int i, is598; + int i, is598, autoc; + ulong until; Block *b; - c->reg[Rxctl] &= ~Rxen; - c->reg[Rxdctl] = 0; - for(i = 0; i < c->nrd; i++){ - b = c->rb[i]; - c->rb[i] = 0; + ctlr->reg[Rxctl] &= ~Rxen; + ctlr->reg[Rxdctl] = 0; + for(i = 0; i < ctlr->nrd; i++){ + b = ctlr->rb[i]; + ctlr->rb[i] = 0; if(b) freeb(b); } - c->rdfree = 0; + ctlr->rdfree = 0; coherence(); - c->reg[Fctrl] |= Bam; - c->reg[Fctrl] &= ~(Upe | Mpe); + ctlr->reg[Fctrl] |= Bam; + ctlr->reg[Fctrl] &= ~(Upe | Mpe); /* intel gets some csums wrong (e.g., errata 44) */ - c->reg[Rxcsum] &= ~Ippcse; - c->reg[Hlreg0] &= ~Jumboen; /* jumbos are a bad idea */ - c->reg[Hlreg0] |= Txcrcen | Rxcrcstrip | Txpaden; - c->reg[Srrctl] = (c->rbsz + 1024 - 1) / 1024; - c->reg[Mhadd] = c->rbsz << 16; - - c->reg[Rbal] = PCIWADDR(c->rdba); - c->reg[Rbah] = 0; - c->reg[Rdlen] = c->nrd*sizeof(Rd); /* must be multiple of 128 */ - c->reg[Rdh] = 0; - c->reg[Rdt] = c->rdt = 0; + ctlr->reg[Rxcsum] &= ~Ippcse; + ctlr->reg[Hlreg0] &= ~Jumboen; /* jumbos are a bad idea */ + ctlr->reg[Hlreg0] |= Txcrcen | Rxcrcstrip | Txpaden; + ctlr->reg[Srrctl] = (ctlr->rbsz + 1024 - 1) / 1024; + ctlr->reg[Mhadd] = ctlr->rbsz << 16; + + ctlr->reg[Rbal] = PCIWADDR(ctlr->rdba); + ctlr->reg[Rbah] = 0; + ctlr->reg[Rdlen] = ctlr->nrd*sizeof(Rd); /* must be multiple of 128 */ + ctlr->reg[Rdh] = 0; + ctlr->reg[Rdt] = ctlr->rdt = 0; coherence(); - is598 = (c->type == I82598); + is598 = (ctlr->type == I82598); if (is598) - c->reg[Rdrxctl] = Rdmt¼; + ctlr->reg[Rdrxctl] = Rdmt¼; else { - c->reg[Rdrxctl] |= Crcstrip; - c->reg[Rdrxctl] &= ~Rscfrstsize; + ctlr->reg[Rdrxctl] |= Crcstrip; + ctlr->reg[Rdrxctl] &= ~Rscfrstsize; } if (Goslow && is598) - c->reg[Rxdctl] = 8<reg[Rxdctl] = 8<reg[Rxdctl] = Renable; + ctlr->reg[Rxdctl] = Renable; coherence(); - while (!(c->reg[Rxdctl] & Renable)) + + /* + * don't wait forever like an idiot (and hang the system), + * maybe it's disconnected. + */ + until = TK2MS(sys->ticks) + 250; + while (!(ctlr->reg[Rxdctl] & Renable) && TK2MS(sys->ticks) < until) ; - c->reg[Rxctl] |= Rxen | (c->type == I82598? Dmbyps: 0); + if(!(ctlr->reg[Rxdctl] & Renable)) + print("#l%d: Renable didn't come on, might be disconnected\n", + ctlr->edev->ctlrno); + + ctlr->reg[Rxctl] |= Rxen | (is598? Dmbyps: 0); + + if (is598){ + autoc = ctlr->reg[Autoc]; + /* what is this rubbish and why do we care? */ + print("#l%d: autoc %#ux; lms %d (3 is 10g sfp)\n", + ctlr->edev->ctlrno, autoc, (autoc>>Lmsshift) & Lmsmask); + ctlr->reg[Autoc] |= Flu; + coherence(); + delay(50); + } } static void -replenish(Ctlr *c, uint rdh) +replenish(Ctlr *ctlr, uint rdh) { int rdt, m, i; Block *b; Rd *r; - m = c->nrd - 1; + m = ctlr->nrd - 1; i = 0; - for(rdt = c->rdt; NEXTPOW2(rdt, m) != rdh; rdt = NEXTPOW2(rdt, m)){ - r = c->rdba + rdt; + for(rdt = ctlr->rdt; NEXTPOW2(rdt, m) != rdh; rdt = NEXTPOW2(rdt, m)){ + r = ctlr->rdba + rdt; if((b = rballoc()) == nil){ - print("82598: no buffers\n"); + print("#l%d: no buffers\n", ctlr->edev->ctlrno); break; } - c->rb[rdt] = b; + ctlr->rb[rdt] = b; r->addr[0] = PCIWADDR(b->rp); r->addr[1] = 0; r->status = 0; - c->rdfree++; + ctlr->rdfree++; i++; } if(i) { coherence(); - c->reg[Rdt] = c->rdt = rdt; /* hand back recycled rdescs */ + ctlr->reg[Rdt] = ctlr->rdt = rdt; /* hand back recycled rdescs */ coherence(); } } @@ -704,63 +741,75 @@ rim(void *v) void rproc(void *v) { + int passed; uint m, rdh; - Block *b; - Ctlr *c; + Block *bp; + Ctlr *ctlr; Ether *e; Rd *r; e = v; - c = e->ctlr; - m = c->nrd - 1; + ctlr = e->ctlr; + m = ctlr->nrd - 1; for (rdh = 0; ; ) { - replenish(c, rdh); - ienable(c, Irx0); - sleep(&c->rrendez, rim, c); + replenish(ctlr, rdh); + ienable(ctlr, Irx0); + sleep(&ctlr->rrendez, rim, ctlr); + passed = 0; for (;;) { - c->rim = 0; - r = c->rdba + rdh; + ctlr->rim = 0; + r = ctlr->rdba + rdh; if(!(r->status & Rdd)) break; /* wait for pkts to arrive */ - b = c->rb[rdh]; - c->rb[rdh] = 0; + bp = ctlr->rb[rdh]; + ctlr->rb[rdh] = 0; if (r->length > ETHERMAXTU) - print("82598: got jumbo of %d bytes\n", r->length); - b->wp += r->length; - b->lim = b->wp; /* lie like a dog */ + print("#l%d: got jumbo of %d bytes\n", + e->ctlrno, r->length); + bp->wp += r->length; + bp->lim = bp->wp; /* lie like a dog */ // r->status = 0; - etheriq(e, b, 1); - c->rdfree--; + + ilock(&rblock); + nrbfull++; + iunlock(&rblock); + notemark(&ctlr->wmrb, nrbfull); + etheriq(e, bp, 1); + + passed++; + ctlr->rdfree--; rdh = NEXTPOW2(rdh, m); - if (c->rdfree <= c->nrd - 16) - replenish(c, rdh); + if (ctlr->rdfree <= ctlr->nrd - 16) + replenish(ctlr, rdh); } + /* note how many rds had full buffers */ + notemark(&ctlr->wmrd, passed); } } static void promiscuous(void *a, int on) { - Ctlr *c; + Ctlr *ctlr; Ether *e; e = a; - c = e->ctlr; + ctlr = e->ctlr; if(on) - c->reg[Fctrl] |= Upe | Mpe; + ctlr->reg[Fctrl] |= Upe | Mpe; else - c->reg[Fctrl] &= ~(Upe | Mpe); + ctlr->reg[Fctrl] &= ~(Upe | Mpe); } static void multicast(void *a, uchar *ea, int on) { int b, i; - Ctlr *c; + Ctlr *ctlr; Ether *e; e = a; - c = e->ctlr; + ctlr = e->ctlr; /* * multiple ether addresses can hash to the same filter bit, @@ -773,14 +822,14 @@ multicast(void *a, uchar *ea, int on) b = (ea[5]&1)<<4 | ea[4]>>4; b = 1 << b; if(on) - c->mta[i] |= b; + ctlr->mta[i] |= b; // else -// c->mta[i] &= ~b; - c->reg[Mta+i] = c->mta[i]; +// ctlr->mta[i] &= ~b; + ctlr->reg[Mta+i] = ctlr->mta[i]; } static void -freemem(Ctlr *c) +freemem(Ctlr *ctlr) { Block *b; @@ -788,46 +837,46 @@ freemem(Ctlr *c) b->free = 0; freeb(b); } - free(c->rdba); - c->rdba = nil; - free(c->tdba); - c->tdba = nil; - free(c->rb); - c->rb = nil; - free(c->tb); - c->tb = nil; + free(ctlr->rdba); + ctlr->rdba = nil; + free(ctlr->tdba); + ctlr->tdba = nil; + free(ctlr->rb); + ctlr->rb = nil; + free(ctlr->tb); + ctlr->tb = nil; } static int -detach(Ctlr *c) +detach(Ctlr *ctlr) { int i, is598; - c->reg[Imc] = ~0; - c->reg[Ctrl] |= Rst; + ctlr->reg[Imc] = ~0; + ctlr->reg[Ctrl] |= Rst; for(i = 0; i < 100; i++){ delay(1); - if((c->reg[Ctrl] & Rst) == 0) + if((ctlr->reg[Ctrl] & Rst) == 0) break; } if (i >= 100) return -1; - is598 = (c->type == I82598); + is598 = (ctlr->type == I82598); if (is598) { /* errata */ delay(50); - c->reg[Ecc] &= ~(1<<21 | 1<<18 | 1<<9 | 1<<6); + ctlr->reg[Ecc] &= ~(1<<21 | 1<<18 | 1<<9 | 1<<6); } /* not cleared by reset; kill it manually. */ for(i = 1; i < 16; i++) - c->reg[is598? Rah98: Rah99] &= ~Enable; + ctlr->reg[is598? Rah98: Rah99] &= ~Enable; for(i = 0; i < 128; i++) - c->reg[Mta + i] = 0; + ctlr->reg[Mta + i] = 0; for(i = 1; i < (is598? 640: 128); i++) - c->reg[Vfta + i] = 0; + ctlr->reg[Vfta + i] = 0; -// freemem(c); // TODO - c->attached = 0; +// freemem(ctlr); // TODO + ctlr->attached = 0; return 0; } @@ -840,133 +889,133 @@ shutdown(Ether *e) /* ≤ 20ms */ static ushort -eeread(Ctlr *c, int i) +eeread(Ctlr *ctlr, int i) { - c->reg[Eerd] = EEstart | i<<2; - while((c->reg[Eerd] & EEdone) == 0) + ctlr->reg[Eerd] = EEstart | i<<2; + while((ctlr->reg[Eerd] & EEdone) == 0) ; - return c->reg[Eerd] >> 16; + return ctlr->reg[Eerd] >> 16; } static int -eeload(Ctlr *c) +eeload(Ctlr *ctlr) { ushort u, v, p, l, i, j; - if((eeread(c, 0) & 0xc0) != 0x40) + if((eeread(ctlr, 0) & 0xc0) != 0x40) return -1; u = 0; for(i = 0; i < 0x40; i++) - u += eeread(c, i); + u += eeread(ctlr, i); for(i = 3; i < 0xf; i++){ - p = eeread(c, i); - l = eeread(c, p++); + p = eeread(ctlr, i); + l = eeread(ctlr, p++); if((int)p + l + 1 > 0xffff) continue; for(j = p; j < p + l; j++) - u += eeread(c, j); + u += eeread(ctlr, j); } if(u != 0xbaba) return -1; - if(c->reg[Status] & (1<<3)) - u = eeread(c, 10); + if(ctlr->reg[Status] & (1<<3)) + u = eeread(ctlr, 10); else - u = eeread(c, 9); + u = eeread(ctlr, 9); u++; for(i = 0; i < Eaddrlen;){ - v = eeread(c, u + i/2); - c->ra[i++] = v; - c->ra[i++] = v>>8; + v = eeread(ctlr, u + i/2); + ctlr->ra[i++] = v; + ctlr->ra[i++] = v>>8; } - c->ra[5] += (c->reg[Status] & 0xc) >> 2; + ctlr->ra[5] += (ctlr->reg[Status] & 0xc) >> 2; return 0; } static int -reset(Ctlr *c) +reset(Ctlr *ctlr) { int i, is598; uchar *p; - if(detach(c)){ + if(detach(ctlr)){ print("82598: reset timeout\n"); return -1; } - if(eeload(c)){ + if(eeload(ctlr)){ print("82598: eeprom failure\n"); return -1; } - p = c->ra; - is598 = (c->type == I82598); - c->reg[is598? Ral98: Ral99] = p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0]; - c->reg[is598? Rah98: Rah99] = p[5]<<8 | p[4] | Enable; + p = ctlr->ra; + is598 = (ctlr->type == I82598); + ctlr->reg[is598? Ral98: Ral99] = p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0]; + ctlr->reg[is598? Rah98: Rah99] = p[5]<<8 | p[4] | Enable; - readstats(c); - for(i = 0; istats); i++) - c->stats[i] = 0; + readstats(ctlr); + for(i = 0; istats); i++) + ctlr->stats[i] = 0; - c->reg[Ctrlext] |= 1 << 16; /* required by errata (spec change 4) */ + ctlr->reg[Ctrlext] |= 1 << 16; /* required by errata (spec change 4) */ if (Goslow) { /* make some guesses for flow control */ - c->reg[Fcrtl] = 0x10000 | Enable; - c->reg[Fcrth] = 0x40000 | Enable; - c->reg[Rcrtv] = 0x6000; + ctlr->reg[Fcrtl] = 0x10000 | Enable; + ctlr->reg[Fcrth] = 0x40000 | Enable; + ctlr->reg[Rcrtv] = 0x6000; } else - c->reg[Fcrtl] = c->reg[Fcrth] = c->reg[Rcrtv] = 0; + ctlr->reg[Fcrtl] = ctlr->reg[Fcrth] = ctlr->reg[Rcrtv] = 0; /* configure interrupt mapping (don't ask) */ - c->reg[Ivar+0] = 0 | 1<<7; - c->reg[Ivar+64/4] = 1 | 1<<7; -// c->reg[Ivar+97/4] = (2 | 1<<7) << (8*(97%4)); + ctlr->reg[Ivar+0] = 0 | 1<<7; + ctlr->reg[Ivar+64/4] = 1 | 1<<7; +// ctlr->reg[Ivar+97/4] = (2 | 1<<7) << (8*(97%4)); if (Goslow) { /* interrupt throttling goes here. */ for(i = Itr; i < Itr + 20; i++) - c->reg[i] = 128; /* ¼µs intervals */ - c->reg[Itr + Itx0] = 256; + ctlr->reg[i] = 128; /* ¼µs intervals */ + ctlr->reg[Itr + Itx0] = 256; } else { /* don't throttle */ for(i = Itr; i < Itr + 20; i++) - c->reg[i] = 0; /* ¼µs intervals */ - c->reg[Itr + Itx0] = 0; + ctlr->reg[i] = 0; /* ¼µs intervals */ + ctlr->reg[Itr + Itx0] = 0; } return 0; } static void -txinit(Ctlr *c) +txinit(Ctlr *ctlr) { Block *b; int i; if (Goslow) - c->reg[Txdctl] = 16<reg[Txdctl] = 16<reg[Txdctl] = 0; - if (c->type == I82599) - c->reg[Dtxctl99] = 0; + ctlr->reg[Txdctl] = 0; + if (ctlr->type == I82599) + ctlr->reg[Dtxctl99] = 0; coherence(); - for(i = 0; i < c->ntd; i++){ - b = c->tb[i]; - c->tb[i] = 0; + for(i = 0; i < ctlr->ntd; i++){ + b = ctlr->tb[i]; + ctlr->tb[i] = 0; if(b) freeb(b); } - assert(c->tdba != nil); - memset(c->tdba, 0, c->ntd * sizeof(Td)); - c->reg[Tdbal] = PCIWADDR(c->tdba); - c->reg[Tdbah] = 0; - c->reg[Tdlen] = c->ntd*sizeof(Td); /* must be multiple of 128 */ - c->reg[Tdh] = 0; - c->tdh = c->ntd - 1; - c->reg[Tdt] = c->tdt = 0; + assert(ctlr->tdba != nil); + memset(ctlr->tdba, 0, ctlr->ntd * sizeof(Td)); + ctlr->reg[Tdbal] = PCIWADDR(ctlr->tdba); + ctlr->reg[Tdbah] = 0; + ctlr->reg[Tdlen] = ctlr->ntd*sizeof(Td); /* must be multiple of 128 */ + ctlr->reg[Tdh] = 0; + ctlr->tdh = ctlr->ntd - 1; + ctlr->reg[Tdt] = ctlr->tdt = 0; coherence(); - if (c->type == I82599) - c->reg[Dtxctl99] |= Te; + if (ctlr->type == I82599) + ctlr->reg[Dtxctl99] |= Te; coherence(); - c->reg[Txdctl] |= Ten; + ctlr->reg[Txdctl] |= Ten; coherence(); - while (!(c->reg[Txdctl] & Ten)) + while (!(ctlr->reg[Txdctl] & Ten)) ; } @@ -974,51 +1023,58 @@ static void attach(Ether *e) { Block *b; - Ctlr *c; + Ctlr *ctlr; char buf[KNAMELEN]; - c = e->ctlr; - c->edev = e; /* point back to Ether* */ - lock(&c->alock); + ctlr = e->ctlr; + ctlr->edev = e; /* point back to Ether* */ + qlock(&ctlr->alock); if(waserror()){ - unlock(&c->alock); - freemem(c); + reset(ctlr); + freemem(ctlr); + qunlock(&ctlr->alock); nexterror(); } - if(c->rdba == nil) { - c->nrd = Nrd; - c->ntd = Ntd; - c->rdba = mallocalign(c->nrd * sizeof *c->rdba, Descalign, 0, 0); - c->tdba = mallocalign(c->ntd * sizeof *c->tdba, Descalign, 0, 0); - c->rb = malloc(c->nrd * sizeof(Block *)); - c->tb = malloc(c->ntd * sizeof(Block *)); - if (c->rdba == nil || c->tdba == nil || - c->rb == nil || c->tb == nil) + if(ctlr->rdba == nil) { + ctlr->nrd = Nrd; + ctlr->ntd = Ntd; + ctlr->rdba = mallocalign(ctlr->nrd * sizeof *ctlr->rdba, + Descalign, 0, 0); + ctlr->tdba = mallocalign(ctlr->ntd * sizeof *ctlr->tdba, + Descalign, 0, 0); + ctlr->rb = malloc(ctlr->nrd * sizeof(Block *)); + ctlr->tb = malloc(ctlr->ntd * sizeof(Block *)); + if (ctlr->rdba == nil || ctlr->tdba == nil || + ctlr->rb == nil || ctlr->tb == nil) error(Enomem); - for(c->nrb = 0; c->nrb < 2*Nrb; c->nrb++){ - b = allocb(c->rbsz + 4*KiB); /* see rbfree() */ + for(ctlr->nrb = 0; ctlr->nrb < 2*Nrb; ctlr->nrb++){ + b = allocb(ctlr->rbsz + 4*KiB); /* see rbfree() */ if(b == nil) error(Enomem); b->free = rbfree; freeb(b); } } - if (!c->attached) { - rxinit(c); - txinit(c); - if (!c->procsrunning) { + if (!ctlr->attached) { + rxinit(ctlr); + txinit(ctlr); + nrbfull = 0; + if (!ctlr->procsrunning) { snprint(buf, sizeof buf, "#l%dl", e->ctlrno); kproc(buf, lproc, e); snprint(buf, sizeof buf, "#l%dr", e->ctlrno); kproc(buf, rproc, e); snprint(buf, sizeof buf, "#l%dt", e->ctlrno); kproc(buf, tproc, e); - c->procsrunning = 1; + ctlr->procsrunning = 1; } - c->attached = 1; + initmark(&ctlr->wmrb, Nrb, "rcv bufs unprocessed"); + initmark(&ctlr->wmrd, Nrd-1, "rcv descrs processed at once"); + initmark(&ctlr->wmtd, Ntd-1, "xmit descr queue len"); + ctlr->attached = 1; } - unlock(&c->alock); + qunlock(&ctlr->alock); poperror(); } @@ -1026,33 +1082,33 @@ static void interrupt(Ureg*, void *v) { int icr, im; - Ctlr *c; + Ctlr *ctlr; Ether *e; e = v; - c = e->ctlr; - ilock(&c->imlock); - c->reg[Imc] = ~0; /* disable all intrs */ - im = c->im; - while((icr = c->reg[Icr] & c->im) != 0){ + ctlr = e->ctlr; + ilock(&ctlr->imlock); + ctlr->reg[Imc] = ~0; /* disable all intrs */ + im = ctlr->im; + while((icr = ctlr->reg[Icr] & ctlr->im) != 0){ if(icr & Irx0){ im &= ~Irx0; - c->rim = Irx0; - wakeup(&c->rrendez); + ctlr->rim = Irx0; + wakeup(&ctlr->rrendez); } if(icr & Itx0){ im &= ~Itx0; - c->tim = Itx0; - wakeup(&c->trendez); + ctlr->tim = Itx0; + wakeup(&ctlr->trendez); } if(icr & Lsc){ im &= ~Lsc; - c->lim = Lsc; - wakeup(&c->lrendez); + ctlr->lim = Lsc; + wakeup(&ctlr->lrendez); } } - c->reg[Ims] = c->im = im; /* enable only intrs we didn't service */ - iunlock(&c->imlock); + ctlr->reg[Ims] = ctlr->im = im; /* enable only intrs we didn't service */ + iunlock(&ctlr->imlock); } static void @@ -1061,7 +1117,7 @@ scan(void) int type, pciregs, pcimsix; ulong io, iomsi; void *mem, *memmsi; - Ctlr *c; + Ctlr *ctlr; Pcidev *p; p = 0; @@ -1088,7 +1144,7 @@ scan(void) continue; } pciregs = 0; - if(nctlr == nelem(ctlrtab)){ + if(nctlr >= nelem(ctlrtab)){ print("i82598: too many controllers\n"); return; } @@ -1110,27 +1166,27 @@ scan(void) continue; } - c = malloc(sizeof *c); - if(c == nil) { + ctlr = malloc(sizeof *ctlr); + if(ctlr == nil) { vunmap(mem, p->mem[pciregs].size); vunmap(memmsi, p->mem[pcimsix].size); error(Enomem); } - c->p = p; - c->type = type; - c->physreg = io; - c->reg = (ulong *)(vlong)mem; -iprint("598 io %lux -> mem %#p reg %#p\n", io, mem, c->reg); - c->rbsz = Rbsz; - if(reset(c)){ + ctlr->p = p; + ctlr->type = type; + ctlr->physreg = io; + ctlr->reg = (ulong *)(vlong)mem; +iprint("598 io %lux -> mem %#p reg %#p\n", io, mem, ctlr->reg); + ctlr->rbsz = Rbsz; + if(reset(ctlr)){ print("i82598: can't reset\n"); - free(c); + free(ctlr); vunmap(mem, p->mem[pciregs].size); vunmap(memmsi, p->mem[pcimsix].size); continue; } pcisetbme(p); - ctlrtab[nctlr++] = c; + ctlrtab[nctlr++] = ctlr; } } @@ -1138,36 +1194,39 @@ static int pnp(Ether *e) { int i; - Ctlr *c = nil; + Ctlr *ctlr; if(nctlr == 0) scan(); + ctlr = nil; for(i = 0; i < nctlr; i++){ - c = ctlrtab[i]; - if(c == nil || c->flag & Factive) + ctlr = ctlrtab[i]; + if(ctlr == nil || ctlr->flag & Factive) continue; - if(e->port == 0 || e->port == PTR2UINT(c->reg)) + if(e->port == 0 || e->port == PTR2UINT(ctlr->reg)) break; } if (i >= nctlr) return -1; - c->flag |= Factive; - e->ctlr = c; - e->port = c->physreg; - e->irq = c->p->intl; - e->tbdf = c->p->tbdf; + ctlr->flag |= Factive; + e->ctlr = ctlr; + e->port = (uintptr)ctlr->physreg; + e->irq = ctlr->p->intl; + e->tbdf = ctlr->p->tbdf; e->mbps = 10000; e->maxmtu = ETHERMAXTU; - memmove(e->ea, c->ra, Eaddrlen); + memmove(e->ea, ctlr->ra, Eaddrlen); + e->arg = e; e->attach = attach; - e->ctl = ctl; - e->ifstat = ifstat; + e->detach = shutdown; + e->transmit = transmit; e->interrupt = interrupt; + e->ifstat = ifstat; + e->shutdown = shutdown; + e->ctl = ctl; e->multicast = multicast; e->promiscuous = promiscuous; - e->shutdown = shutdown; - e->transmit = transmit; return 0; } @@ -1176,4 +1235,5 @@ void ether82598link(void) { addethercard("i82598", pnp); + addethercard("i10gbe", pnp); } --- /sys/src/9k/386/etherigbe.c +++ /sys/src/9k/386/etherigbe.c @@ -452,7 +452,7 @@ enum { }; typedef struct Ctlr Ctlr; -typedef struct Ctlr { +struct Ctlr { u32int port; Pcidev* pcidev; Ctlr* next; @@ -467,7 +467,7 @@ typedef struct Ctlr { void* alloc; /* receive/transmit descriptors */ int nrd; int ntd; - int nrb; /* how many this Ctlr has in the pool */ + int nrb; /* # bufs this Ctlr has in the pool */ u32int* nic; Lock imlock; @@ -496,7 +496,7 @@ typedef struct Ctlr { Rendez rrendez; int rim; - int rdfree; + int rdfree; /* rx descriptors awaiting packets */ Rd* rdba; /* receive descriptor base address */ Block** rb; /* receive buffers */ int rdh; /* receive descriptor head */ @@ -504,7 +504,6 @@ typedef struct Ctlr { int rdtr; /* receive delay timer ring value */ Lock tlock; - int tbusy; int tdfree; Td* tdba; /* transmit descriptor base address */ Block** tb; /* transmit buffers */ @@ -514,7 +513,7 @@ typedef struct Ctlr { int txcw; int fcrtl; int fcrth; -} Ctlr; +}; #define csr32r(c, r) (*((c)->nic+((r)/4))) #define csr32w(c, r, v) (*((c)->nic+((r)/4)) = (v)) @@ -1144,12 +1143,15 @@ igberproc(void* arg) * an indication of whether the checksums were * calculated and valid. */ + /* ignore checksum offload as it has known bugs. */ + rd->errors &= ~(Ipe | Tcpe); if((rd->status & Reop) && rd->errors == 0){ bp = ctlr->rb[rdh]; ctlr->rb[rdh] = nil; bp->wp += rd->length; bp->next = nil; - if(!(rd->status & Ixsm)){ + /* ignore checksum offload as it has known bugs. */ + if(0 && !(rd->status & Ixsm)){ ctlr->ixsm++; if(rd->status & Ipcs){ /* --- /sys/src/9k/386/etherm10g.c +++ /sys/src/9k/386/etherm10g.c @@ -1,10 +1,12 @@ /* - * myricom 10 Gb ethernet driver + * myricom 10g-pcie-8a 10 Gb ethernet driver * © 2007 erik quanstrom, coraid * * the card is big endian. - * we use u64int rather than uintptr to hold addresses so that + * we use uvlong rather than uintptr to hold addresses so that * we don't get "warning: stupid shift" on 32-bit architectures. + * + * appears to have massively-bloated buffers. */ #include "u.h" #include "../port/lib.h" @@ -35,9 +37,9 @@ static char Etimeout[] = "timeout"; enum { Epromsz = 256, - Maxslots= 1024, + Maxslots= 1024, /* rcv descriptors; wasteful: only 9 needed */ Align = 4096, - Maxmtu = 9000, + Maxmtu = 9000, /* jumbos; bad idea */ Noconf = 0xffffffff, Fwoffset= 1*MiB, @@ -98,8 +100,8 @@ typedef union { typedef ulong Slot; typedef struct { - u16int cksum; - u16int len; + ushort cksum; + ushort len; } Slotparts; enum { @@ -110,10 +112,10 @@ enum { }; typedef struct { - u32int high; - u32int low; - u16int hdroff; - u16int len; + ulong high; + ulong low; + ushort hdroff; + ushort len; uchar pad; uchar nrdma; uchar chkoff; @@ -127,7 +129,7 @@ typedef struct { Block **bring; // uchar *wcfifo; /* what the heck is a w/c fifo? */ int size; /* of buffers in the z8's memory */ - u32int segsz; + ulong segsz; uint n; /* rxslots */ uint m; /* mask; rxslots must be a power of two */ uint i; /* number of segments (not frames) queued */ @@ -150,7 +152,7 @@ static Bpool bgpool = { .size = Maxmtu, }; typedef struct { Bpool *pool; /* free buffers */ - u32int *lanai; /* rx ring; we have no permanent host shadow */ + ulong *lanai; /* rx ring; we have no permanent host shadow */ Block **host; /* called "info" in myricom driver */ // uchar *wcfifo; /* cmd submission fifo */ uint m; @@ -185,7 +187,7 @@ enum { typedef struct { Slot *entry; - u64int busaddr; + uvlong busaddr; uint m; uint n; uint i; @@ -196,7 +198,7 @@ typedef struct Ctlr { QLock; int state; int kprocs; - u64int port; + uvlong port; Pcidev* pcidev; Ctlr* next; int active; @@ -207,32 +209,32 @@ typedef struct Ctlr { int ramsz; uchar *ram; - u32int *irqack; - u32int *irqdeass; - u32int *coal; + ulong *irqack; + ulong *irqdeass; + ulong *coal; char eprom[Epromsz]; ulong serial; /* unit serial number */ QLock cmdl; Cmd *cmd; /* address of command return */ - u64int cprt; /* bus address of command */ + uvlong cprt; /* bus address of command */ - u64int boot; /* boot address */ + uvlong boot; /* boot address */ Done done; Tx tx; Rx sm; Rx bg; Stats *stats; - u64int statsprt; + uvlong statsprt; Rendez rxrendez; Rendez txrendez; int msi; - u32int linkstat; - u32int nrdma; + ulong linkstat; + ulong nrdma; } Ctlr; static Ctlr *ctlrs; @@ -304,13 +306,13 @@ pciecap(Pcidev *p, int cap) uint off, i; off = 0x100; - while(((i = pcicfgr32(p, off))&0xffff) != cap){ + while(((i = pcicfgr32(p, off)) & 0xffff) != cap){ off = i >> 20; - print("pciecap offset = %ud\n", off); + print("m10g: pciecap offset = %ud", off); if(off < 0x100 || off >= 4*KiB - 1) return 0; } - print("pciecap found = %ud\n", off); + print("m10g: pciecap found = %ud", off); return off; } @@ -333,7 +335,7 @@ whichfw(Pcidev *p) { char *s; int i, off, lanes, ecrc; - u32int cap; + ulong cap; /* check the number of configured lanes. */ off = pcicap(p, PciCapPCIe); @@ -345,33 +347,30 @@ whichfw(Pcidev *p) /* check AERC register. we need it on. */ off = pciecap(p, PcieAERC); - print("%d offset\n", off); + print("; offset %d returned\n", off); cap = 0; if(off != 0){ off += AercCCR; cap = pcicfgr32(p, off); - print("%ud cap\n", cap); + print("m10g: %lud cap\n", cap); } ecrc = (cap>>4) & 0xf; /* if we don't like the aerc, kick it here. */ - print("m10g %d lanes; ecrc=%d; ", lanes, ecrc); + print("m10g: %d lanes; ecrc=%d; ", lanes, ecrc); if(s = getconf("myriforce")){ i = atoi(s); if(i != 4*KiB || i != 2*KiB) i = 2*KiB; - print("fw=%d [forced]\n", i); + print("fw = %d [forced]\n", i); return i; } - if(lanes <= 4){ + if(lanes <= 4) print("fw = 4096 [lanes]\n"); - return 4*KiB; - } - if(ecrc & 10){ + else if(ecrc & 10) print("fw = 4096 [ecrc set]\n"); - return 4*KiB; - } - print("fw = 4096 [default]\n"); + else + print("fw = 4096 [default]\n"); return 4*KiB; } @@ -403,10 +402,10 @@ parseeprom(Ctlr *c) return 0; } -static u16int -pbit16(u16int i) +static ushort +pbit16(ushort i) { - u16int j; + ushort j; uchar *p; p = (uchar*)&j; @@ -415,20 +414,20 @@ pbit16(u16int i) return j; } -static u16int +static ushort gbit16(uchar i[2]) { - u16int j; + ushort j; j = i[1]; j |= i[0]<<8; return j; } -static u32int -pbit32(u32int i) +static ulong +pbit32(ulong i) { - u32int j; + ulong j; uchar *p; p = (uchar*)&j; @@ -439,10 +438,10 @@ pbit32(u32int i) return j; } -static u32int +static ulong gbit32(uchar i[4]) { - u32int j; + ulong j; j = i[3]; j |= i[2]<<8; @@ -452,7 +451,7 @@ gbit32(uchar i[4]) } static void -prepcmd(uint *cmd, int i) +prepcmd(ulong *cmd, int i) { while(i-- > 0) cmd[i] = pbit32(cmd[i]); @@ -469,10 +468,10 @@ prepcmd(uint *cmd, int i) * 40 byte = 5 int pad. */ -u32int -cmd(Ctlr *c, int type, u64int data) +ulong +cmd(Ctlr *c, int type, uvlong data) { - u32int buf[16], i; + ulong buf[16], i; Cmd *cmd; qlock(&c->cmdl); @@ -488,30 +487,31 @@ cmd(Ctlr *c, int type, u64int data) coherence(); memmove(c->ram + Cmdoff, buf, sizeof buf); - if(waserror()) + if(waserror()){ + qunlock(&c->cmdl); nexterror(); + } for(i = 0; i < 15; i++){ if(cmd->i[1] != Noconf){ poperror(); i = gbit32(cmd->c); qunlock(&c->cmdl); if(cmd->i[1] != 0) - dprint("[%ux]", i); - return i; + dprint("[%lux]", i); + return i; /* normal return */ } tsleep(&up->sleep, return0, 0, 1); } - qunlock(&c->cmdl); iprint("m10g: cmd timeout [%ux %ux] cmd=%d\n", cmd->i[0], cmd->i[1], type); error(Etimeout); return ~0; /* silence! */ } -u32int +ulong maccmd(Ctlr *c, int type, uchar *m) { - u32int buf[16], i; + ulong buf[16], i; Cmd *cmd; qlock(&c->cmdl); @@ -527,20 +527,21 @@ maccmd(Ctlr *c, int type, uchar *m) coherence(); memmove(c->ram + Cmdoff, buf, sizeof buf); - if(waserror()) + if(waserror()){ + qunlock(&c->cmdl); nexterror(); + } for(i = 0; i < 15; i++){ if(cmd->i[1] != Noconf){ poperror(); i = gbit32(cmd->c); qunlock(&c->cmdl); if(cmd->i[1] != 0) - dprint("[%ux]", i); - return i; + dprint("[%lux]", i); + return i; /* normal return */ } tsleep(&up->sleep, return0, 0, 1); } - qunlock(&c->cmdl); iprint("m10g: maccmd timeout [%ux %ux] cmd=%d\n", cmd->i[0], cmd->i[1], type); error(Etimeout); @@ -553,10 +554,10 @@ enum { DMAwrite= 0x1, }; -u32int -dmatestcmd(Ctlr *c, int type, u64int addr, int len) +ulong +dmatestcmd(Ctlr *c, int type, uvlong addr, int len) { - u32int buf[16], i; + ulong buf[16], i; memset(buf, 0, sizeof buf); memset(c->cmd, Noconf, sizeof *c->cmd); @@ -570,15 +571,12 @@ dmatestcmd(Ctlr *c, int type, u64int addr, int len) coherence(); memmove(c->ram + Cmdoff, buf, sizeof buf); - if(waserror()) - nexterror(); for(i = 0; i < 15; i++){ if(c->cmd->i[1] != Noconf){ i = gbit32(c->cmd->c); if(i == 0) error(Eio); - poperror(); - return i; + return i; /* normal return */ } tsleep(&up->sleep, return0, 0, 5); } @@ -586,10 +584,10 @@ dmatestcmd(Ctlr *c, int type, u64int addr, int len) return ~0; /* silence! */ } -u32int +ulong rdmacmd(Ctlr *c, int on) { - u32int buf[16], i; + ulong buf[16], i; memset(buf, 0, sizeof buf); c->cmd->i[0] = 0; @@ -603,35 +601,31 @@ rdmacmd(Ctlr *c, int on) prepcmd(buf, 6); memmove(c->ram + Rdmaoff, buf, sizeof buf); - if(waserror()) - nexterror(); for(i = 0; i < 20; i++){ - if(c->cmd->i[0] == Noconf){ - poperror(); - return gbit32(c->cmd->c); - } + if(c->cmd->i[0] == Noconf) + return gbit32(c->cmd->c); /* normal return */ tsleep(&up->sleep, return0, 0, 1); } - error(Etimeout); iprint("m10g: rdmacmd timeout\n"); + error(Etimeout); return ~0; /* silence! */ } static int loadfw(Ctlr *c, int *align) { - uint *f, *s, sz; + ulong *f, *s, sz; int i; if((*align = whichfw(c->pcidev)) == 4*KiB){ - f = (u32int*)fw4k; + f = (ulong*)fw4k; sz = sizeof fw4k; }else{ - f = (u32int*)fw2k; + f = (ulong*)fw2k; sz = sizeof fw2k; } - s = (u32int*)(c->ram + Fwoffset); + s = (ulong*)(c->ram + Fwoffset); for(i = 0; i < sz / 4; i++) s[i] = f[i]; return sz & ~3; @@ -641,7 +635,7 @@ static int bootfw(Ctlr *c) { int i, sz, align; - uint buf[16]; + ulong buf[16]; Cmd* cmd; if((sz = loadfw(c, &align)) == 0) @@ -668,7 +662,7 @@ bootfw(Ctlr *c) break; delay(1); } - dprint("[%ux %ux]", gbit32(cmd->c), gbit32(cmd->c+4)); + dprint("[%lux %lux]", gbit32(cmd->c), gbit32(cmd->c+4)); if(i == 20){ print("m10g: cannot load fw\n"); return -1; @@ -682,13 +676,13 @@ static int kickthebaby(Pcidev *p, Ctlr *c) { /* don't kick the baby! */ - u32int code; + ulong code; pcicfgw8(p, 0x10 + c->boot, 0x3); pcicfgw32(p, 0x18 + c->boot, 0xfffffff0); code = pcicfgr32(p, 0x14 + c->boot); - dprint("reboot status = %ux\n", code); + dprint("reboot status = %lux\n", code); if(code != 0xfffffff0) return -1; return 0; @@ -712,7 +706,7 @@ enum { }; static char * -fwtype(u32int type) +fwtype(ulong type) { switch(type){ case Tmx: @@ -730,21 +724,20 @@ fwtype(u32int type) static int chkfw(Ctlr *c) { - uintptr off; + ulong off, type; Fwhdr *h; - u32int type; off = gbit32(c->ram+0x3c); - dprint("firmware %llux\n", (u64int)off); + dprint("firmware %lux\n", off); if((off&3) || off + sizeof *h > c->ramsz){ - print("!m10g: bad firmware %llux\n", (u64int)off); + print("!m10g: bad firmware %lux\n", off); return -1; } h = (Fwhdr*)(c->ram + off); type = gbit32(h->type); dprint("\t" "type %s\n", fwtype(type)); dprint("\t" "vers %s\n", h->version); - dprint("\t" "ramsz %ux\n", gbit32(h->ramsz)); + dprint("\t" "ramsz %lux\n", gbit32(h->ramsz)); if(type != Teth){ print("!m10g: bad card type %s\n", fwtype(type)); return -1; @@ -756,7 +749,7 @@ chkfw(Ctlr *c) static int reset(Ether *e, Ctlr *c) { - u32int i, sz; + ulong i, sz; if(waserror()){ print("m10g: reset error\n"); @@ -769,22 +762,22 @@ reset(Ether *e, Ctlr *c) cmd(c, CSintrqsz, c->done.n * sizeof *c->done.entry); cmd(c, CSintrqdma, c->done.busaddr); - c->irqack = (u32int*)(c->ram + cmd(c, CGirqackoff, 0)); + c->irqack = (ulong*)(c->ram + cmd(c, CGirqackoff, 0)); /* required only if we're not doing msi? */ - c->irqdeass = (u32int*)(c->ram + cmd(c, CGirqdeassoff, 0)); + c->irqdeass = (ulong*)(c->ram + cmd(c, CGirqdeassoff, 0)); /* this is the driver default, why fiddle with this? */ - c->coal = (u32int*)(c->ram + cmd(c, CGcoaloff, 0)); + c->coal = (ulong*)(c->ram + cmd(c, CGcoaloff, 0)); *c->coal = pbit32(25); dprint("dma stats:\n"); rdmacmd(c, 1); sz = c->tx.segsz; i = dmatestcmd(c, DMAread, c->done.busaddr, sz); - print("\t" "read: %ud MB/s\n", ((i>>16)*sz*2)/(i&0xffff)); + print("m10g: read %lud MB/s;", ((i>>16)*sz*2) / (i&0xffff)); i = dmatestcmd(c, DMAwrite, c->done.busaddr, sz); - print("\t" "write: %ud MB/s\n", ((i>>16)*sz*2)/(i&0xffff)); + print(" write %lud MB/s;", ((i>>16)*sz*2) / (i&0xffff)); i = dmatestcmd(c, DMAwrite|DMAread, c->done.busaddr, sz); - print("\t" "r/w: %ud MB/s\n", ((i>>16)*sz*2*2)/(i&0xffff)); + print(" r/w %lud MB/s\n", ((i>>16)*sz*2*2) / (i&0xffff)); memset(c->done.entry, 0, c->done.n * sizeof *c->done.entry); maccmd(c, CSmac, c->ra); @@ -814,8 +807,8 @@ ctlrfree(Ctlr *c) static int setmem(Pcidev *p, Ctlr *c) { - u32int i; - u64int raddr; + ulong i; + uvlong raddr; Done *d; void *mem; @@ -863,27 +856,25 @@ whichrx(Ctlr *c, int sz) static Block* balloc(Rx* rx) { - Block *b; + Block *bp; ilock(rx->pool); - if((b = rx->pool->head) != nil){ - rx->pool->head = b->next; - b->next = nil; + if((bp = rx->pool->head) != nil){ + rx->pool->head = bp->next; + bp->next = nil; +// ainc(&bp->ref); /* prevent bp from being freed */ rx->pool->n--; } iunlock(rx->pool); - return b; + return bp; } static void -smbfree(Block *b) +rbfree(Block *b, Bpool *p) { - Bpool *p; - b->rp = b->wp = (uchar*)ROUNDUP((uintptr)b->base, 4*KiB); - b->flag &= ~(Bpktck|Btcpck|Budpck|Bipck); + b->flag &= ~(Bipck | Budpck | Btcpck | Bpktck); - p = &smpool; ilock(p); b->next = p->head; p->head = b; @@ -893,26 +884,21 @@ smbfree(Block *b) } static void -bgbfree(Block *b) +smbfree(Block *b) { - Bpool *p; - - b->rp = b->wp = (uchar*)ROUNDUP((uintptr)b->base, 4*KiB); - b->flag &= ~(Bpktck|Btcpck|Budpck|Bipck); + rbfree(b, &smpool); +} - p = &bgpool; - ilock(p); - b->next = p->head; - p->head = b; - p->n++; - p->cnt++; - iunlock(p); +static void +bgbfree(Block *b) +{ + rbfree(b, &bgpool); } static void replenish(Rx *rx) { - u32int buf[16], i, idx, e; + ulong buf[16], i, idx, e; Bpool *p; Block *b; @@ -926,7 +912,7 @@ replenish(Rx *rx) idx = rx->cnt & rx->m; for(i = 0; i < 8; i++){ b = balloc(rx); - buf[i*2] = pbit32((u64int)PCIWADDR(b->wp) >> 32); + buf[i*2] = pbit32((uvlong)PCIWADDR(b->wp) >> 32); buf[i*2+1] = pbit32(PCIWADDR(b->wp)); rx->host[idx+i] = b; assert(b); @@ -937,7 +923,7 @@ replenish(Rx *rx) e -= 8; } if(e && p->n > 7+1) - print("should panic? pool->n = %d\n", p->n); + print("m10g: should panic? pool->n = %d\n", p->n); } /* @@ -987,7 +973,7 @@ open0(Ether *e, Ctlr *c) entries = cmd(c, CGrxrgsz, 0)/8; c->sm.pool = &smpool; cmd(c, CSsmallsz, c->sm.pool->size); - c->sm.lanai = (u32int*)(c->ram + cmd(c, CGsmallrxoff, 0)); + c->sm.lanai = (ulong*)(c->ram + cmd(c, CGsmallrxoff, 0)); c->sm.n = entries; c->sm.m = entries-1; c->sm.host = emalign(entries * sizeof *c->sm.host); @@ -995,7 +981,7 @@ open0(Ether *e, Ctlr *c) c->bg.pool = &bgpool; c->bg.pool->size = nextpow(2 + e->maxmtu); /* 2-byte alignment pad */ cmd(c, CSbigsz, c->bg.pool->size); - c->bg.lanai = (u32int*)(c->ram + cmd(c, CGbigrxoff, 0)); + c->bg.lanai = (ulong*)(c->ram + cmd(c, CGbigrxoff, 0)); c->bg.n = entries; c->bg.m = entries-1; c->bg.host = emalign(entries * sizeof *c->bg.host); @@ -1026,7 +1012,7 @@ static Block* nextblock(Ctlr *c) { uint i; - u16int l, k; + ushort l, k; Block *b; Done *d; Rx *rx; @@ -1104,7 +1090,7 @@ m10rx(void *v) } static void -txcleanup(Tx *tx, u32int n) +txcleanup(Tx *tx, ulong n) { Block *b; uint j, l, m; @@ -1129,7 +1115,7 @@ txcleanup(Tx *tx, u32int n) if(tx->cnt == tx->i) return; if(l++ == m){ - iprint("tx ovrun: %ud %uld\n", n, tx->npkt); + iprint("m10g: tx ovrun: %lud %lud\n", n, tx->npkt); return; } } @@ -1200,8 +1186,8 @@ nsegments(Block *b, int segsz) static void m10gtransmit(Ether *e) { - u16int slen; - u32int i, cnt, rdma, nseg, count, end, bus, len, segsz; + ushort slen; + ulong i, cnt, rdma, nseg, count, end, bus, len, segsz; uchar flags; Block *b; Ctlr *c; @@ -1228,7 +1214,7 @@ m10gtransmit(Ether *e) rdma = nseg = nsegments(b, segsz); bus = PCIWADDR(b->rp); for(; len; len -= slen){ - end = bus + segsz & ~(segsz-1); + end = (bus + segsz) & ~(segsz-1); slen = end - bus; if(slen > len) slen = len; @@ -1244,7 +1230,7 @@ m10gtransmit(Ether *e) flags &= ~SFfirst; rdma = 1; } - tx->bring[i + nseg - 1 & tx->m] = b; + tx->bring[(i + nseg - 1) & tx->m] = b; if(1 || count > 0){ submittx(tx, count); count = 0; @@ -1259,7 +1245,7 @@ m10gtransmit(Ether *e) static void checkstats(Ether *e, Ctlr *c, Stats *s) { - u32int i; + ulong i; if(s->updated == 0) return; @@ -1274,7 +1260,7 @@ checkstats(Ether *e, Ctlr *c, Stats *s) } i = gbit32(s->nrdma); if(i != c->nrdma){ - dprint("m10g: rdma timeout %d\n", i); + dprint("m10g: rdma timeout %ld\n", i); c->nrdma = i; } } @@ -1356,7 +1342,7 @@ m10gdetach(Ctlr *c) dprint("m10gdetach\n"); // reset(e->ctlr); vunmap(c->ram, c->pcidev->mem[0].size); - ctlrfree(c); + ctlrfree(c); /* this is a bad idea: don't free c */ return -1; } @@ -1374,32 +1360,30 @@ lstcount(Block *b) static long m10gifstat(Ether *e, void *v, long n, ulong off) { - int l, lim; char *p; Ctlr *c; Stats s; c = e->ctlr; - lim = 2*READSTR-1; - p = malloc(lim+1); - l = 0; + p = malloc(READSTR+1); + if(p == nil) + error(Enomem); /* no point in locking this because this is done via dma. */ memmove(&s, c->stats, sizeof s); - // l += - snprint(p+l, lim, - "txcnt = %ud\n" "linkstat = %ud\n" "dlink = %ud\n" - "derror = %ud\n" "drunt = %ud\n" "doverrun = %ud\n" - "dnosm = %ud\n" "dnobg = %ud\n" "nrdma = %ud\n" + snprint(p, READSTR, + "txcnt = %lud\n" "linkstat = %lud\n" "dlink = %lud\n" + "derror = %lud\n" "drunt = %lud\n" "doverrun = %lud\n" + "dnosm = %lud\n" "dnobg = %lud\n" "nrdma = %lud\n" "txstopped = %ud\n" "down = %ud\n" "updated = %ud\n" "valid = %ud\n\n" - "tx pkt = %uld\n" "tx bytes = %lld\n" + "tx pkt = %lud\n" "tx bytes = %lld\n" "tx cnt = %ud\n" "tx n = %ud\n" "tx i = %ud\n" "sm cnt = %ud\n" "sm i = %ud\n" "sm n = %ud\n" "sm lst = %ud\n" "bg cnt = %ud\n" "bg i = %ud\n" "bg n = %ud\n" "bg lst = %ud\n" - "segsz = %ud\n" "coal = %d\n", + "segsz = %lud\n" "coal = %lud\n", gbit32(s.txcnt), gbit32(s.linkstat), gbit32(s.dlink), gbit32(s.derror), gbit32(s.drunt), gbit32(s.doverrun), gbit32(s.dnosm), gbit32(s.dnobg), gbit32(s.nrdma), @@ -1566,18 +1550,30 @@ m10gpci(void) Ctlr *t, *c; t = 0; - for(p = 0; p = pcimatch(p, 0x14c1, 0x0008); ){ + for(p = 0; p = pcimatch(p, 0x14c1, 0); ){ + switch(p->did){ + case 0x8: /* 8a */ + break; + case 0x9: /* 8a with msi-x fw */ + case 0xa: /* 8b */ + case 0xb: /* 8b2 */ + case 0xc: /* 2-8b2 */ + /* untested */ + break; + default: + print("etherm10g: unknown myricom did %#ux\n", p->did); + continue; + } c = malloc(sizeof *c); if(c == nil) - continue; - memset(c, 0, sizeof *c); + break; c->pcidev = p; c->id = p->did<<16 | p->vid; c->boot = pcicap(p, PciCapVND); // kickthebaby(p, c); pcisetbme(p); if(setmem(p, c) == -1){ - print("m10g failed\n"); + print("m10g: setmem failed\n"); free(c); /* cleanup */ continue; @@ -1620,13 +1616,11 @@ m10gpnp(Ether *e) e->interrupt = m10ginterrupt; e->ifstat = m10gifstat; e->ctl = m10gctl; -// e->power = m10gpower; e->shutdown = m10gshutdown; e->arg = e; e->promiscuous = m10gpromiscuous; e->multicast = m10gmulticast; - return 0; } --- /sys/src/9k/386/kbd.c +++ /sys/src/9k/386/kbd.c @@ -1,3 +1,6 @@ +/* + * keyboard input + */ #include "u.h" #include "../port/lib.h" #include "mem.h" @@ -51,10 +54,14 @@ enum { Scroll= KF|21, Nscan= 128, + + Int= 0, /* kbscans indices */ + Ext, + Nscans, }; /* - * The codes at 0x79 and 0x81 are produed by the PFU Happy Hacking keyboard. + * The codes at 0x79 and 0x7b are produced by the PFU Happy Hacking keyboard. * A 'standard' keyboard doesn't produce anything above 0x58. */ Rune kbtab[Nscan] = @@ -137,7 +144,7 @@ Rune kbtabaltgr[Nscan] = [0x78] No, Up, No, No, No, No, No, No, }; -Rune kbtabctrl[] = +Rune kbtabctrl[Nscan] = { [0x00] No, '', '', '', '', '', '', '', [0x08] '', '', '', '', ' ', '', '\b', '\t', @@ -172,11 +179,11 @@ static Queue *kbdq; int mouseshifted; void (*kbdmouse)(int); -static int nokbd = 1; static Lock i8042lock; static uchar ccc; static void (*auxputc)(int, int); +static int nokbd = 1; /* flag: no PS/2 keyboard */ /* * wait for output no longer busy @@ -210,19 +217,31 @@ inready(void) return 0; } +/* + * ask 8042 to enable the use of address bit 20 + */ +void +i8042a20(void) +{ + outready(); + outb(Cmd, 0xD1); + outready(); + outb(Data, 0xDF); + outready(); +} + /* * ask 8042 to reset the machine */ void i8042reset(void) { - ushort *s = KADDR(0x472); int i, x; if(nokbd) return; - *s = 0x1234; /* BIOS warm-boot flag */ + *((ushort*)KADDR(0x472)) = 0x1234; /* BIOS warm-boot flag */ /* * newer reset the machine command @@ -250,7 +269,10 @@ i8042auxcmd(int cmd) { unsigned int c; int tries; + static int badkbd; + if(badkbd) + return -1; c = 0; tries = 0; @@ -274,6 +296,7 @@ i8042auxcmd(int cmd) if(c != 0xFA){ print("i8042: %2.2ux returned to the %2.2ux command\n", c, cmd); + badkbd = 1; /* don't keep trying; there might not be one */ return -1; } return 0; @@ -297,68 +320,93 @@ i8042auxcmds(uchar *cmd, int ncmd) return i; } -struct { - int esc1; - int esc2; - int alt; - int altgr; - int caps; - int ctl; - int num; - int shift; - int collecting; - int nk; - Rune kc[5]; - int buttons; -} kbscan; +typedef struct Kbscan Kbscan; +struct Kbscan { + int esc1; + int esc2; + int alt; + int altgr; + int caps; + int ctl; + int num; + int shift; + int collecting; + int nk; + Rune kc[5]; + int buttons; +}; + +Kbscan kbscans[Nscans]; /* kernel and external scan code state */ + +static int kdebug; /* - * keyboard interrupt + * set keyboard's leds for lock states (scroll, numeric, caps). + * + * at least one keyboard (from Qtronics) also sets its numeric-lock + * behaviour to match the led state, though it has no numeric keypad, + * and some BIOSes bring the system up with numeric-lock set and no + * setting to change that. this combination steals the keys for these + * characters and makes it impossible to generate them: uiolkjm&*(). + * thus we'd like to be able to force the numeric-lock led (and behaviour) off. */ static void -i8042intr(Ureg*, void*) +setleds(Kbscan *kbscan) { - int s, c, i; - int keyup; + int leds; - /* - * get status - */ - ilock(&i8042lock); - s = inb(Status); - if(!(s&Inready)){ - iunlock(&i8042lock); + if(nokbd || kbscan != &kbscans[Int]) return; - } + leds = 0; + if(kbscan->num) + leds |= 1<<1; + if(0 && kbscan->caps) /* we don't implement caps lock */ + leds |= 1<<2; - /* - * get the character - */ - c = inb(Data); + ilock(&i8042lock); + outready(); + outb(Data, 0xed); /* `reset keyboard lock states' */ + if(inready() == 0) + inb(Data); + + outready(); + outb(Data, leds); + if(inready() == 0) + inb(Data); + + outready(); iunlock(&i8042lock); +} - /* - * if it's the aux port... - */ - if(s & Minready){ - if(auxputc != nil) - auxputc(c, kbscan.shift); - return; - } +/* + * Scan code processing + */ +void +kbdputsc(int c, int external) +{ + int i, keyup; + Kbscan *kbscan; + if(external) + kbscan = &kbscans[Ext]; + else + kbscan = &kbscans[Int]; + + if(kdebug) + print("sc %x ms %d\n", c, mouseshifted); /* * e0's is the first of a 2 character sequence, e1 the first * of a 3 character sequence (on the safari) */ if(c == 0xe0){ - kbscan.esc1 = 1; + kbscan->esc1 = 1; return; } else if(c == 0xe1){ - kbscan.esc2 = 2; + kbscan->esc2 = 2; return; } - keyup = c&0x80; + keyup = c & 0x80; c &= 0x7f; if(c > sizeof kbtab){ c |= keyup; @@ -367,22 +415,22 @@ i8042intr(Ureg*, void*) return; } - if(kbscan.esc1){ + if(kbscan->esc1){ c = kbtabesc1[c]; - kbscan.esc1 = 0; - } else if(kbscan.esc2){ - kbscan.esc2--; + kbscan->esc1 = 0; + } else if(kbscan->esc2){ + kbscan->esc2--; return; - } else if(kbscan.shift) + } else if(kbscan->shift) c = kbtabshift[c]; - else if(kbscan.altgr) + else if(kbscan->altgr) c = kbtabaltgr[c]; - else if(kbscan.ctl) + else if(kbscan->ctl) c = kbtabctrl[c]; else c = kbtab[c]; - if(kbscan.caps && c<='z' && c>='a') + if(kbscan->caps && c<='z' && c>='a') c += 'A' - 'a'; /* @@ -391,26 +439,28 @@ i8042intr(Ureg*, void*) if(keyup){ switch(c){ case Latin: - kbscan.alt = 0; + kbscan->alt = 0; break; case Shift: - kbscan.shift = 0; + kbscan->shift = 0; mouseshifted = 0; + if(kdebug) + print("shiftclr\n"); break; case Ctrl: - kbscan.ctl = 0; + kbscan->ctl = 0; break; case Altgr: - kbscan.altgr = 0; + kbscan->altgr = 0; break; case Kmouse|1: case Kmouse|2: case Kmouse|3: case Kmouse|4: case Kmouse|5: - kbscan.buttons &= ~(1<<(c-Kmouse-1)); + kbscan->buttons &= ~(1<<(c-Kmouse-1)); if(kbdmouse) - kbdmouse(kbscan.buttons); + kbdmouse(kbscan->buttons); break; } return; @@ -420,39 +470,43 @@ i8042intr(Ureg*, void*) * normal character */ if(!(c & (Spec|KF))){ - if(kbscan.ctl) - if(kbscan.alt && c == Del) + if(kbscan->ctl) + if(kbscan->alt && c == Del) exit(0); - if(!kbscan.collecting){ + if(!kbscan->collecting){ kbdputc(kbdq, c); return; } - kbscan.kc[kbscan.nk++] = c; - c = latin1(kbscan.kc, kbscan.nk); + kbscan->kc[kbscan->nk++] = c; + c = latin1(kbscan->kc, kbscan->nk); if(c < -1) /* need more keystrokes */ return; if(c != -1) /* valid sequence */ kbdputc(kbdq, c); else /* dump characters */ - for(i=0; ink; i++) + kbdputc(kbdq, kbscan->kc[i]); + kbscan->nk = 0; + kbscan->collecting = 0; return; } else { switch(c){ case Caps: - kbscan.caps ^= 1; + kbscan->caps ^= 1; return; case Num: - kbscan.num ^= 1; + kbscan->num ^= 1; + if(!external) + setleds(kbscan); return; case Shift: - kbscan.shift = 1; + kbscan->shift = 1; + if(kdebug) + print("shift\n"); mouseshifted = 1; return; case Latin: - kbscan.alt = 1; + kbscan->alt = 1; /* * VMware and Qemu use Ctl-Alt as the key combination * to make the VM give up keyboard and mouse focus. @@ -463,31 +517,74 @@ i8042intr(Ureg*, void*) * As a clumsy hack around this, we look for ctl-alt * and don't treat it as the start of a compose sequence. */ - if(!kbscan.ctl){ - kbscan.collecting = 1; - kbscan.nk = 0; + if(!kbscan->ctl){ + kbscan->collecting = 1; + kbscan->nk = 0; } return; case Ctrl: - kbscan.ctl = 1; + kbscan->ctl = 1; return; case Altgr: - kbscan.altgr = 1; + kbscan->altgr = 1; return; case Kmouse|1: case Kmouse|2: case Kmouse|3: case Kmouse|4: case Kmouse|5: - kbscan.buttons |= 1<<(c-Kmouse-1); + kbscan->buttons |= 1<<(c-Kmouse-1); if(kbdmouse) - kbdmouse(kbscan.buttons); + kbdmouse(kbscan->buttons); return; + case KF|11: + print("kbd debug on, F12 turns it off\n"); + kdebug = 1; + break; + case KF|12: + kdebug = 0; + break; } } kbdputc(kbdq, c); } +/* + * keyboard interrupt + */ +static void +i8042intr(Ureg*, void*) +{ + int s, c; + + /* + * get status + */ + ilock(&i8042lock); + s = inb(Status); + if(!(s&Inready)){ + iunlock(&i8042lock); + return; + } + + /* + * get the character + */ + c = inb(Data); + iunlock(&i8042lock); + + /* + * if it's the aux port... + */ + if(s & Minready){ + if(auxputc != nil) + auxputc(c, kbscans[Int].shift); + return; + } + + kbdputsc(c, Int); +} + void i8042auxenable(void (*putc)(int, int)) { @@ -506,7 +603,7 @@ i8042auxenable(void (*putc)(int, int)) outb(Data, ccc); if(outready() < 0) print(err); - outb(Cmd, 0xA8); /* auxilliary device enable */ + outb(Cmd, 0xA8); /* auxiliary device enable */ if(outready() < 0){ iunlock(&i8042lock); return; @@ -535,7 +632,7 @@ kbdinit(void) int c, try; /* wait for a quiescent controller */ - try = 1000; + try = 500; while(try-- > 0 && (c = inb(Status)) & (Outbusy | Inready)) { if(c & Inready) inb(Data); @@ -567,6 +664,12 @@ kbdinit(void) /* disable mouse */ if (outbyte(Cmd, 0x60) < 0 || outbyte(Data, ccc) < 0) print("i8042: kbdinit mouse disable failed\n"); + + /* see http://www.computer-engineering.org/ps2keyboard for codes */ + if(getconf("*typematic") != nil) + /* set typematic rate/delay (0 -> delay=250ms & rate=30cps) */ + if(outbyte(Data, 0xf3) < 0 || outbyte(Data, 0) < 0) + print("i8042: kbdinit set typematic rate failed\n"); } void @@ -582,6 +685,9 @@ kbdenable(void) ioalloc(Cmd, 1, 0, "kbd"); intrenable(IrqKBD, i8042intr, 0, BUSUNKNOWN, "kbd"); + + kbscans[Int].num = 0; + setleds(&kbscans[Int]); } void @@ -611,12 +717,12 @@ kbdputmap(ushort m, ushort scanc, Rune r) } int -kbdgetmap(int offset, int *t, int *sc, Rune *r) +kbdgetmap(uint offset, int *t, int *sc, Rune *r) { + if ((int)offset < 0) + error(Ebadarg); *t = offset/Nscan; *sc = offset%Nscan; - if(*t < 0 || *sc < 0) - error(Ebadarg); switch(*t) { default: return 0; --- /sys/src/9k/386/pci.c +++ /sys/src/9k/386/pci.c @@ -16,6 +16,8 @@ struct int ptr; }PCICONS; +int pcivga; + int pcilog(char *fmt, ...) { @@ -191,6 +193,8 @@ pcibusmap(Pcidev *root, ulong *pmema, ulong *pioa, int wrreg) ntb *= (PciCIS-PciBAR0)/4; table = malloc(2*ntb*sizeof(Pcisiz)); + if(table == nil) + panic("pcibusmap: no memory"); itb = table; mtb = table+ntb; @@ -355,6 +359,7 @@ pcibusmap(Pcidev *root, ulong *pmema, ulong *pioa, int wrreg) } } +/* side effect: if a video controller is seen, set pcivga non-zero */ static int pcilscan(int bno, Pcidev** list) { @@ -380,6 +385,8 @@ pcilscan(int bno, Pcidev** list) if(l == 0xFFFFFFFF || l == 0) continue; p = malloc(sizeof(*p)); + if(p == nil) + panic("pcilscan: no memory"); p->tbdf = tbdf; p->vid = l; p->did = l>>16; @@ -413,9 +420,11 @@ pcilscan(int bno, Pcidev** list) * and work out the sizes. */ switch(p->ccrb) { + case 0x03: /* display controller */ + pcivga = 1; + /* fall through */ case 0x01: /* mass storage controller */ case 0x02: /* network controller */ - case 0x03: /* display controller */ case 0x04: /* multimedia device */ case 0x07: /* simple comm. controllers */ case 0x08: /* base system peripherals */ @@ -659,6 +668,7 @@ static Bridge southbridges[] = { { 0x8086, 0x3a48, pIIxget, pIIxset }, /* Intel 82801JI */ { 0x8086, 0x2916, pIIxget, pIIxset }, /* Intel 82801? */ { 0x8086, 0x1c02, pIIxget, pIIxset }, /* Intel 6 Series/C200 */ + { 0x8086, 0x1c44, pIIxget, pIIxset }, /* Intel 6 Series/Z68 Express */ { 0x8086, 0x1e53, pIIxget, pIIxset }, /* Intel 7 Series/C216 */ { 0x1106, 0x0586, viaget, viaset }, /* Viatech 82C586 */ { 0x1106, 0x0596, viaget, viaset }, /* Viatech 82C596 */ @@ -719,13 +729,16 @@ pcirouting(void) if(p[0] == '$' && p[1] == 'P' && p[2] == 'I' && p[3] == 'R') break; - if(p >= (uchar *)KADDR(0xfffff)) + if(p >= (uchar *)KADDR(0xfffff)) { + // print("no PCI intr routing table found\n"); return; + } r = (Router *)p; - print("PCI interrupt routing table version %d.%d at %#p\n", - r->version[0], r->version[1], r); + if (0) + print("PCI interrupt routing table version %d.%d at %#p\n", + r->version[0], r->version[1], r); tbdf = (BusPCI << 24)|(r->bus << 16)|(r->devfn << 8); sbpci = pcimatchtbdf(tbdf); --- /sys/src/9k/386/sdiahci.c +++ /sys/src/9k/386/sdiahci.c @@ -1,10 +1,6 @@ /* * ahci serial ata driver * copyright © 2007-8 coraid, inc. - * - * there was a great deal of locking of single operations (e.g., - * atomic assignments); it's not clear what that locking was intended to - * prevent. */ #include "u.h" @@ -954,7 +950,7 @@ updatedrive(Drive *d) case Devpresent: /* device but no phy comm. */ if((p->sstatus & Intpm) == Intslumber || (p->sstatus & Intpm) == Intpartpwr) - d->state = Dnew; /* slumbering */ + d->state = Dnew; /* slumbering */ else d->state = Derror; break; @@ -971,7 +967,7 @@ updatedrive(Drive *d) diskstates[s0], diskstates[d->state], p->sstatus); /* print pulled message here. */ if(s0 == Dready && d->state != Dready) - idprint("%s: pulled\n", name); + idprint("%s: pulled\n", name); /* wtf? */ if(d->state != Dready) d->portm.flag |= Ferror; ewake = 1; @@ -1026,6 +1022,14 @@ configdrive(Drive *d) return 0; } +static void +setstate(Drive *d, int state) +{ + ilock(d); + d->state = state; + iunlock(d); +} + static void resetdisk(Drive *d) { @@ -1054,10 +1058,10 @@ resetdisk(Drive *d) iunlock(d); qlock(&d->portm); - if(p->cmd&Ast && ahciswreset(&d->portc) == -1){ - d->state = Dportreset; /* get a bigger stick. */ - } else { - d->state = Dmissing; + if(p->cmd&Ast && ahciswreset(&d->portc) == -1) + setstate(d, Dportreset); /* get a bigger stick. */ + else { + setstate(d, Dmissing); configdrive(d); } dprint("ahci: %s: resetdisk: %s → %s\n", (d->unit? d->unit->name: nil), @@ -1095,9 +1099,7 @@ newdrive(Drive *d) if(ahcirecover(c) == -1) goto lose; } - - d->state = Dready; - + setstate(d, Dready); qunlock(c->pm); idprint("%s: %sLBA %,llud sectors: %s %s %s %s\n", d->unit->name, @@ -1107,7 +1109,7 @@ newdrive(Drive *d) lose: idprint("%s: can't be initialized\n", d->unit->name); - d->state = Dnull; + setstate(d, Dnull); qunlock(c->pm); return -1; } @@ -1295,9 +1297,12 @@ isctlrjabbering(Ctlr *c, ulong cause) c->intrs = 0; c->lastintr0 = now; } - if (++c->intrs > Maxintrspertick) - panic("sdiahci: too many intrs per tick for no serviced " - "drive; cause %#lux mport %d", cause, c->mport); + if (++c->intrs > Maxintrspertick) { + iprint("sdiahci: %lud intrs per tick for no serviced " + "drive; cause %#lux mport %d\n", + c->intrs, cause, c->mport); + c->intrs = 0; + } } static void @@ -1310,9 +1315,11 @@ isdrivejabbering(Drive *d) d->intrs = 0; d->lastintr0 = now; } - if (++d->intrs > Maxintrspertick) - panic("sdiahci: too many interrupts per tick for %s", - d->unit->name); + if (++d->intrs > Maxintrspertick) { + iprint("sdiahci: %lud interrupts per tick for %s\n", + d->intrs, d->unit->name); + d->intrs = 0; + } } static void @@ -1643,7 +1650,7 @@ waitready(Drive *d) esleep(250); } print("%s: not responding; offline\n", d->unit->name); - d->state = Doffline; + setstate(d, Doffline); return -1; } @@ -1653,7 +1660,7 @@ lockready(Drive *d) int i; qlock(&d->portm); - while ((i = waitready(d)) == 1) { + while ((i = waitready(d)) == 1) { /* could wait forever? */ qunlock(&d->portm); esleep(1); qlock(&d->portm); @@ -1710,6 +1717,7 @@ retry: esleep(1); goto retry; } + /* d->portm qlock held here */ ilock(d); d->portm.flag = 0; @@ -1723,8 +1731,15 @@ retry: while(waserror()) ; - sleep(&d->portm, ahciclear, &as); + /* don't sleep here forever */ + tsleep(&d->portm, ahciclear, &as, 3*1000); poperror(); + if(!ahciclear(&as)) { + qunlock(&d->portm); + print("%s: ahciclear not true after 3 seconds\n", name); + r->status = SDcheck; + return SDcheck; + } d->active--; ilock(d); @@ -1846,6 +1861,7 @@ retry: esleep(1); goto retry; } + /* d->portm qlock held here */ ilock(d); d->portm.flag = 0; iunlock(d); @@ -1858,8 +1874,15 @@ retry: while(waserror()) ; - sleep(&d->portm, ahciclear, &as); + /* don't sleep here forever */ + tsleep(&d->portm, ahciclear, &as, 3*1000); poperror(); + if(!ahciclear(&as)) { + qunlock(&d->portm); + print("%s: ahciclear not true after 3 seconds\n", name); + r->status = SDcheck; + return SDcheck; + } d->active--; ilock(d); @@ -1900,7 +1923,8 @@ retry: } /* - * configure drives 0-5 as ahci sata (c.f. errata) + * configure drives 0-5 as ahci sata (c.f. errata). + * what about 6 & 7, as claimed by marvell 0x9123? */ static int iaahcimode(Pcidev *p) @@ -1935,7 +1959,8 @@ didtype(Pcidev *p) /* * 0x27c4 is the intel 82801 in compatibility (not sata) mode. */ - if (p->did == 0x24d1 || /* 82801eb/er */ + if (p->did == 0x1e02 || /* c210 */ + p->did == 0x24d1 || /* 82801eb/er */ (p->did & 0xfffb) == 0x27c1 || /* 82801g[bh]m ich7 */ p->did == 0x2821 || /* 82801h[roh] */ (p->did & 0xfffe) == 0x2824 || /* 82801h[b] */ @@ -1953,15 +1978,13 @@ didtype(Pcidev *p) } break; case 0x1b4b: - /* can't cope with sata 3 yet; touching sd files will hang */ - if (p->did == 0x9123) { - print("ahci: ignoring sata 3 controller\n"); - return -1; - } + if (p->did == 0x9123) + print("ahci: marvell sata 3 controller has delusions " + "of something on unit 7\n"); break; } if(p->ccrb == Pcibcstore && p->ccru == Pciscsata && p->ccrp == 1){ - print("ahci: Tunk: VID %#4.4ux DID %#4.4ux\n", p->vid, p->did); + print("ahci: Tunk: vid %#4.4ux did %#4.4ux\n", p->vid, p->did); return Tunk; } return -1; @@ -2169,7 +2192,9 @@ forcemode(Drive *d, char *mode) break; if(i == nelem(modename)) i = 0; + ilock(d); d->mode = i; + iunlock(d); } static void @@ -2198,7 +2223,7 @@ forcestate(Drive *d, char *state) break; if(i == nelem(diskstates)) error(Ebadctl); - d->state = i; + setstate(d, i); } /* --- /sys/src/9k/386/uarti8250.c +++ /sys/src/9k/386/uarti8250.c @@ -3,6 +3,7 @@ #include "mem.h" #include "dat.h" #include "fns.h" +#include "../port/error.h" /* * 8250 UART and compatibles. @@ -160,8 +161,10 @@ i8250status(Uart* uart, void* buf, long n, long offset) Ctlr *ctlr; uchar ier, lcr, mcr, msr; - ctlr = uart->regs; p = malloc(READSTR); + if(p == nil) + error(Enomem); + ctlr = uart->regs; mcr = ctlr->sticky[Mcr]; msr = csr8r(ctlr, Msr); ier = ctlr->sticky[Ier]; @@ -566,7 +569,7 @@ i8250enable(Uart* uart, int ie) * the transmitter is really empty. * Also, reading the Iir outwith i8250interrupt() * can be dangerous, but this should only happen - * once, before interrupts are enabled. + * once before interrupts are enabled. */ ilock(ctlr); if(!ctlr->checkfifo){ @@ -787,7 +790,8 @@ i8250console(char* cfg) // if(csr8r(ctlr, Scr) != 0x55) // return nil; - (*uart->phys->enable)(uart, 0); + if(!uart->enabled) + (*uart->phys->enable)(uart, 0); uartctl(uart, "b9600 l8 pn s1 i1"); if(*cmd != '\0') uartctl(uart, cmd); --- /sys/src/9k/386/uartpci.c +++ /sys/src/9k/386/uartpci.c @@ -5,13 +5,17 @@ #include "fns.h" #include "io.h" +#include "../port/error.h" extern PhysUart i8250physuart; extern PhysUart pciphysuart; extern void* i8250alloc(int, int, int); +static Uart *perlehead, *perletail; + static Uart* -uartpci(int ctlrno, Pcidev* p, int barno, int n, int freq, char* name) +uartpci(int ctlrno, Pcidev* p, int barno, int n, int freq, char* name, + int iosize) { int i, io; void *ctlr; @@ -26,10 +30,11 @@ uartpci(int ctlrno, Pcidev* p, int barno, int n, int freq, char* name) } head = uart = malloc(sizeof(Uart)*n); - + if(uart == nil) + error(Enomem); for(i = 0; i < n; i++){ ctlr = i8250alloc(io, p->intl, p->tbdf); - io += 8; + io += iosize; if(ctlr == nil) continue; @@ -38,45 +43,86 @@ uartpci(int ctlrno, Pcidev* p, int barno, int n, int freq, char* name) kstrdup(&uart->name, buf); uart->freq = freq; uart->phys = &i8250physuart; + /* print("#t: %s port %#x freq %,ldHz irq %d\n", + uart->name, io - iosize, uart->freq, p->intl); /**/ if(uart != head) (uart-1)->next = uart; uart++; } + if (head) { + if(perlehead != nil) + perletail->next = head; + else + perlehead = head; + for(perletail = head; perletail->next != nil; + perletail = perletail->next) + ; + } return head; } +static Uart * +ultraport16si(int ctlrno, Pcidev *p, ulong freq) +{ + int io, i; + char *name; + Uart *uart; + + name = "Ultraport16si"; /* 16L788 UARTs */ + io = p->mem[4].bar & ~1; + if (ioalloc(io, p->mem[4].size, 0, name) < 0) { + print("uartpci: can't get IO space to set %s to rs-232\n", name); + return nil; + } + for (i = 0; i < 16; i++) { + outb(io, i << 4); + outb(io, (i << 4) + 1); /* set to RS232 mode (Don't ask!) */ + } + + uart = uartpci(ctlrno, p, 2, 8, freq, name, 16); + if(uart) + uart = uartpci(ctlrno, p, 3, 8, freq, name, 16); + return uart; +} + static Uart* uartpcipnp(void) { Pcidev *p; char *name; - int ctlrno, n, subid; - Uart *head, *tail, *uart; + int ctlrno, subid; + ulong freq; + Uart *uart; /* * Loop through all PCI devices looking for simple serial - * controllers (ccrb == 0x07) and configure the ones which + * controllers (ccrb == Pcibccomm (7)) and configure the ones which * are familiar. All suitable devices are configured to * simply point to the generic i8250 driver. */ - head = tail = nil; + perlehead = perletail = nil; ctlrno = 0; for(p = pcimatch(nil, 0, 0); p != nil; p = pcimatch(p, 0, 0)){ - if(p->ccrb != 0x07 || p->ccru > 2) + /* StarTech PCI8S9503V has ccru == 0x80 (other) */ + if(p->ccrb != Pcibccomm || p->ccru > 2 && p->ccru != 0x80) continue; - switch((p->did<<16)|p->vid){ + switch(p->did<<16 | p->vid){ default: continue; case (0x9835<<16)|0x9710: /* StarTech PCI2S550 */ - uart = uartpci(ctlrno, p, 0, 1, 1843200, "PCI2S550-0"); + uart = uartpci(ctlrno, p, 0, 1, 1843200, "PCI2S550-0", 8); if(uart == nil) continue; - uart->next = uartpci(ctlrno, p, 1, 1, 1843200, "PCI2S550-1"); + uart->next = uartpci(ctlrno, p, 1, 1, 1843200, + "PCI2S550-1", 8); + if(uart->next == nil) + continue; break; - case (0x9501<<16)|0x1415: /* Oxford Semi OX16PCI954 */ - case (0x950A<<16)|0x1415: + case (0x950A<<16)|0x1415: /* Oxford Semi OX16PCI954 */ + case (0x9501<<16)|0x1415: + case (0x9521<<16)|0x1415: /* * These are common devices used by 3rd-party * manufacturers. @@ -87,19 +133,31 @@ uartpcipnp(void) subid |= pcicfgr16(p, PciSID)<<16; switch(subid){ default: + print("oxsemi uart %.8#ux of vid %#ux did %#ux unknown\n", + subid, p->vid, p->did); continue; case (0<<16)|0x1415: /* StarTech PCI4S550 */ - uart = uartpci(ctlrno, p, 0, 4, 18432000, "PCI4S550-0"); - if(uart == nil) - continue; + uart = uartpci(ctlrno, p, 0, 4, 1843200, + "starport-pex4s", 8); + break; + case (1<<16)|0x1415: + uart = uartpci(ctlrno, p, 0, 2, 14745600, + "starport-pex2s", 8); break; case (0x2000<<16)|0x131F:/* SIIG CyberSerial PCIe */ - uart = uartpci(ctlrno, p, 0, 1, 18432000, "CyberSerial-1S"); - if(uart == nil) - continue; + uart = uartpci(ctlrno, p, 0, 1, 18432000, + "CyberSerial-1S", 8); break; } break; + case (0x9505<<16)|0x1415: /* Oxford Semi OXuPCI952 */ + name = "SATAGear-IOI-102"; /* PciSVID=1415, PciSID=0 */ + if (uartpci(ctlrno, p, 0, 1, 14745600, name, 8) != nil) + ctlrno++; + if (uartpci(ctlrno, p, 1, 1, 14745600, name, 8) != nil) + ctlrno++; + uart = nil; /* don't ctlrno++ below */ + break; case (0x9050<<16)|0x10B5: /* Perle PCI-Fast4 series */ case (0x9030<<16)|0x10B5: /* Perle Ultraport series */ /* @@ -110,42 +168,50 @@ uartpcipnp(void) */ subid = pcicfgr16(p, PciSVID); subid |= pcicfgr16(p, PciSID)<<16; + freq = 7372800; switch(subid){ default: + print("uartpci: unknown perle subid %#ux\n", + subid); continue; + case (0x1588<<16)|0x10B5: /* StarTech PCI8S9503V (P588UG) */ + name = "P588UG"; + /* max. baud rate is 921,600 */ + freq = 1843200; + uart = uartpci(ctlrno, p, 2, 8, freq, name, 8); + break; case (0x0011<<16)|0x12E0: /* Perle PCI-Fast16 */ - n = 16; name = "PCI-Fast16"; + uart = uartpci(ctlrno, p, 2, 16, freq, name, 8); break; case (0x0021<<16)|0x12E0: /* Perle PCI-Fast8 */ - n = 8; name = "PCI-Fast8"; + uart = uartpci(ctlrno, p, 2, 8, freq, name, 8); break; case (0x0031<<16)|0x12E0: /* Perle PCI-Fast4 */ - n = 4; name = "PCI-Fast4"; + uart = uartpci(ctlrno, p, 2, 4, freq, name, 8); break; case (0x0021<<16)|0x155F: /* Perle Ultraport8 */ - n = 8; name = "Ultraport8"; /* 16C754 UARTs */ + uart = uartpci(ctlrno, p, 2, 8, freq, name, 8); + break; + case (0x0041<<16)|0x155F: /* Perle Ultraport16 */ + name = "Ultraport16"; + uart = uartpci(ctlrno, p, 2, 16, 2 * freq, + name, 8); + break; + case (0x0241<<16)|0x155F: /* Perle Ultraport16 */ + uart = ultraport16si(ctlrno, p, 4 * freq); break; } - uart = uartpci(ctlrno, p, 2, n, 7372800, name); - if(uart == nil) - continue; break; } - - if(head != nil) - tail->next = uart; - else - head = uart; - for(tail = uart; tail->next != nil; tail = tail->next) - ; - ctlrno++; + if(uart) + ctlrno++; } - return head; + return perlehead; } PhysUart pciphysuart = { --- /sys/src/9k/k10/k10aoe +++ /sys/src/9k/k10/k10aoe @@ -161,6 +161,7 @@ port systab taslock tod + watermarks # #dir --- /sys/src/9k/k10/k10cpu +++ /sys/src/9k/k10/k10cpu @@ -155,6 +155,7 @@ port systab taslock tod + watermarks # #dir --- /sys/src/9k/k10/k10root +++ /sys/src/9k/k10/k10root @@ -157,6 +157,7 @@ port systab taslock tod + watermarks # #dir --- /sys/src/9k/port/netif.h +++ /sys/src/9k/port/netif.h @@ -16,6 +16,7 @@ enum Nstatqid, Ntypeqid, Nifstatqid, + Nmtuqid, }; /* @@ -75,6 +76,9 @@ struct Netif int alen; /* address length */ int mbps; /* megabits per sec */ int link; /* link status */ + int minmtu; + int maxmtu; + int mtu; uchar addr[Nmaxaddr]; uchar bcast[Nmaxaddr]; Netaddr *maddr; /* known multicast addresses */ @@ -88,8 +92,8 @@ struct Netif /* statistics */ int misses; - int inpackets; - int outpackets; + uvlong inpackets; + uvlong outpackets; int crcs; /* input crc errors */ int oerrs; /* output errors */ int frames; /* framing errors */ @@ -101,6 +105,7 @@ struct Netif void *arg; void (*promiscuous)(void*, int); void (*multicast)(void*, uchar*, int); + int (*hwmtu)(void*, int); /* get/set mtu */ void (*scanbs)(void*, uint); /* scan for base stations */ }; --- /sys/src/9k/port/portdat.h +++ /sys/src/9k/port/portdat.h @@ -48,6 +48,7 @@ typedef struct Uart Uart; typedef struct Waitq Waitq; typedef struct Walkqid Walkqid; typedef struct Watchdog Watchdog; +typedef struct Watermark Watermark; typedef int Devgen(Chan*, char*, Dirtab*, int, int, Dir*); #pragma incomplete DevConf @@ -946,6 +947,16 @@ struct Watchdog void (*stat)(char*, char*); /* watchdog statistics */ }; +struct Watermark +{ + int highwater; + int curr; + int max; + int hitmax; /* count: how many times hit max? */ + char *name; +}; + + /* queue state bits, Qmsg, Qcoalesce, and Qkick can be set in qopen */ enum { --- /sys/src/9k/port/portfns.h +++ /sys/src/9k/port/portfns.h @@ -129,6 +129,7 @@ void iallocsummary(void); void ilock(Lock*); void iunlock(Lock*); void initimage(void); +void initmark(Watermark *, int, char *); int iprint(char*, ...); void isdir(Chan*); int iseve(void); @@ -138,7 +139,7 @@ int ispages(void*); int isphysseg(char*); void ixsummary(void); int kbdcr2nl(Queue*, int); -int kbdgetmap(int, int*, int*, Rune*); +int kbdgetmap(uint, int*, int*, Rune*); int kbdputc(Queue*, int); void kbdputmap(ushort, ushort, Rune); void kickpager(void); @@ -192,6 +193,7 @@ Pgrp* newpgrp(void); Rgrp* newrgrp(void); Proc* newproc(void); void nexterror(void); +void notemark(Watermark *, int); int nrand(int); uvlong ns2fastticks(uvlong); int okaddr(uintptr, long, int); @@ -296,6 +298,7 @@ void schedinit(void); long seconds(void); void segclock(uintptr); void segpage(Segment*, Page*); +char* seprintmark(char *, char *, Watermark *); int setcolor(ulong, ulong, ulong, ulong); void setkernur(Ureg*, Proc*); int setlabel(Label*); --- /dev/null +++ /sys/src/9k/port/watermarks.c @@ -0,0 +1,40 @@ +/* + * high-watermark measurements + */ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" + +void +initmark(Watermark *wp, int max, char *name) +{ + memset(wp, 0, sizeof *wp); + wp->max = max; + wp->name = name; +} + +void +notemark(Watermark *wp, int val) +{ + /* enforce obvious limits */ + if (val < 0) + val = 0; + else if (val > wp->max) + val = wp->max; + + if (val > wp->highwater) { + wp->highwater = val; + if (val == wp->max && wp->curr < val) + wp->hitmax++; + } + wp->curr = val; +} + +char * +seprintmark(char *buf, char *ebuf, Watermark *wp) +{ + return seprint(buf, ebuf, "%s:\thighwater %d/%d curr %d hitmax %d\n", + wp->name, wp->highwater, wp->max, wp->curr, wp->hitmax); +}