diff options
| author | Charles.Forsyth <devnull@localhost> | 2008-06-11 14:21:44 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2008-06-11 14:21:44 +0000 |
| commit | 8a8c2d742b51525f66c2210e3c8a251de10022ff (patch) | |
| tree | 8282ce595e5fbe2e487dc20f54891d9e9e7cbf37 /os/boot/pc/ether8169.c | |
| parent | 31a18a6996a6b5927e39cc553696c167e6c88e3d (diff) | |
20080611-1520
Diffstat (limited to 'os/boot/pc/ether8169.c')
| -rw-r--r-- | os/boot/pc/ether8169.c | 379 |
1 files changed, 245 insertions, 134 deletions
diff --git a/os/boot/pc/ether8169.c b/os/boot/pc/ether8169.c index 5b36f7c3..009dfcde 100644 --- a/os/boot/pc/ether8169.c +++ b/os/boot/pc/ether8169.c @@ -17,13 +17,10 @@ #include "fns.h" #include "io.h" - typedef struct QLock { int r; } QLock; #define qlock(i) while(0) #define qunlock(i) while(0) #define iallocb allocb -extern void mb386(void); -#define coherence() mb386() #define iprint print #define mallocalign(n, a, o, s) ialloc((n), (a)) @@ -108,6 +105,16 @@ enum { /* Tcr */ Ifg2 = 0x00080000, /* Interframe Gap 2 */ HwveridSHIFT = 23, /* Hardware Version ID */ HwveridMASK = 0x7C800000, + Macv01 = 0x00000000, /* RTL8169 */ + Macv02 = 0x00800000, /* RTL8169S/8110S */ + Macv03 = 0x04000000, /* RTL8169S/8110S */ + Macv04 = 0x10000000, /* RTL8169SB/8110SB */ + Macv05 = 0x18000000, /* RTL8169SC/8110SC */ + Macv11 = 0x30000000, /* RTL8168B/8111B */ + Macv12 = 0x38000000, /* RTL8169B/8111B */ + Macv13 = 0x34000000, /* RTL8101E */ + Macv14 = 0x30800000, /* RTL8100E */ + Macv15 = 0x38800000, /* RTL8100E */ Ifg0 = 0x01000000, /* Interframe Gap 0 */ Ifg1 = 0x02000000, /* Interframe Gap 1 */ }; @@ -236,18 +243,31 @@ struct Dtcc { u16int txundrn; }; +enum { /* Variants */ + Rtl8100e = (0x8136<<16)|0x10EC, /* RTL810[01]E ? */ + Rtl8169c = (0x0116<<16)|0x16EC, /* RTL8169C+ (USR997902) */ + Rtl8169sc = (0x8167<<16)|0x10EC, /* RTL8169SC */ + Rtl8168b = (0x8168<<16)|0x10EC, /* RTL8168B */ + Rtl8169 = (0x8169<<16)|0x10EC, /* RTL8169 */ +}; + typedef struct Ctlr Ctlr; typedef struct Ctlr { int port; Pcidev* pcidev; Ctlr* next; int active; - uint id; + + void* nic; QLock alock; /* attach */ Lock ilock; /* init */ int init; /* */ + int pciv; /* */ + int macv; /* MAC version */ + int phyv; /* PHY version */ + Mii* mii; Lock tlock; /* transmit */ @@ -287,8 +307,8 @@ typedef struct Ctlr { uint fovw; } Ctlr; -static Ctlr* ctlrhead; -static Ctlr* ctlrtail; +static Ctlr* rtl8169ctlrhead; +static Ctlr* rtl8169ctlrtail; #define csr8r(c, r) (inb((c)->port+(r))) #define csr16r(c, r) (ins((c)->port+(r))) @@ -360,36 +380,59 @@ rtl8169mii(Ctlr* ctlr) ctlr->mii->mir = rtl8169miimir; ctlr->mii->miw = rtl8169miimiw; ctlr->mii->ctlr = ctlr; - rtl8169miimiw(ctlr->mii, 1, 0x0B, 0x0000); /* magic */ - if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){ + /* + * Get rev number out of Phyidr2 so can config properly. + * There's probably more special stuff for Macv0[234] needed here. + */ + ctlr->phyv = rtl8169miimir(ctlr->mii, 1, Phyidr2) & 0x0F; + if(ctlr->macv == Macv02){ + csr8w(ctlr, 0x82, 1); /* magic */ + rtl8169miimiw(ctlr->mii, 1, 0x0B, 0x0000); /* magic */ + } + + if(mii(ctlr->mii, (1<<1)) == 0 || (phy = ctlr->mii->curphy) == nil){ free(ctlr->mii); ctlr->mii = nil; return -1; } - print("oui %X phyno %d\n", phy->oui, phy->phyno); + print("oui %#ux phyno %d, macv = %#8.8ux phyv = %#4.4ux\n", + phy->oui, phy->phyno, ctlr->macv, ctlr->phyv); miiane(ctlr->mii, ~0, ~0, ~0); return 0; } +static void +rtl8169halt(Ctlr* ctlr) +{ + csr8w(ctlr, Cr, 0); + csr16w(ctlr, Imr, 0); + csr16w(ctlr, Isr, ~0); +} + static int rtl8169reset(Ctlr* ctlr) { + u32int r; int timeo; /* * Soft reset the controller. */ csr8w(ctlr, Cr, Rst); - for(timeo = 0; timeo < 1000; timeo++){ - if(!(csr8r(ctlr, Cr) & Rst)) - return 0; + for(r = timeo = 0; timeo < 1000; timeo++){ + r = csr8r(ctlr, Cr); + if(!(r & Rst)) + break; delay(1); } + rtl8169halt(ctlr); - return -1; + if(r & Rst) + return -1; + return 0; } static void @@ -399,14 +442,6 @@ rtl8169detach(Ether* edev) } static void -rtl8169halt(Ctlr* ctlr) -{ - csr8w(ctlr, Cr, 0); - csr16w(ctlr, Imr, 0); - csr16w(ctlr, Isr, ~0); -} - -static void rtl8169replenish(Ctlr* ctlr) { D *d; @@ -420,7 +455,7 @@ rtl8169replenish(Ctlr* ctlr) /* * simple allocation for now */ - bp = malloc(Mps); + bp = mallocalign(Mps, 8, 0, 0); ctlr->rb[rdt] = bp; d->addrlo = PCIWADDR(bp); d->addrhi = 0; @@ -433,11 +468,12 @@ rtl8169replenish(Ctlr* ctlr) ctlr->rdt = rdt; } -static void +static int rtl8169init(Ether* edev) { - uint r; + u32int r; Ctlr *ctlr; + u8int cplusc; ctlr = edev->ctlr; ilock(&ctlr->ilock); @@ -445,12 +481,6 @@ rtl8169init(Ether* edev) rtl8169halt(ctlr); /* - * Setting Mulrw in Cplusc disables the Tx/Rx DMA burst settings - * in Tcr/Rcr. - */ - csr16w(ctlr, Cplusc, (1<<14)|Rxchksum|Mulrw); /* magic (1<<14) */ - - /* * MAC Address. * Must put chip into config register write enable mode. */ @@ -461,45 +491,95 @@ rtl8169init(Ether* edev) csr32w(ctlr, Idr0+4, r); /* - * Enable receiver/transmitter. - * Need to do this first or some of the settings below - * won't take. - */ - csr8w(ctlr, Cr, Te|Re); - - /* * Transmitter. - * Mtps is in units of 128. */ memset(ctlr->td, 0, sizeof(D)*ctlr->ntd); ctlr->tdh = ctlr->tdt = 0; ctlr->td[ctlr->ntd-1].control = Eor; - ctlr->mtps = HOWMANY(Mps, 128); /* * Receiver. + * Need to do something here about the multicast filter. */ memset(ctlr->rd, 0, sizeof(D)*ctlr->nrd); ctlr->rdh = ctlr->rdt = 0; ctlr->rd[ctlr->nrd-1].control = Eor; - - //for(i = 0; i < ctlr->nrd; i++){ - // if((bp = ctlr->rb[i]) != nil){ - // ctlr->rb[i] = nil; - // freeb(bp); - // } - //} rtl8169replenish(ctlr); - ctlr->rcr = Rxfth256|Mrxdmaunlimited|Ab|Apm; + ctlr->rcr = Rxfthnone|Mrxdmaunlimited|Ab|Apm; + + /* + * Mtps is in units of 128 except for the RTL8169 + * where is is 32. If using jumbo frames should be + * set to 0x3F. + * Setting Mulrw in Cplusc disables the Tx/Rx DMA burst + * settings in Tcr/Rcr; the (1<<14) is magic. + */ + ctlr->mtps = HOWMANY(Mps, 128); + cplusc = csr16r(ctlr, Cplusc) & ~(1<<14); + cplusc |= Rxchksum|Mulrw; + switch(ctlr->macv){ + default: + return -1; + case Macv01: + ctlr->mtps = HOWMANY(Mps, 32); + break; + case Macv02: + case Macv03: + cplusc |= (1<<14); /* magic */ + break; + case Macv05: + /* + * This is interpreted from clearly bogus code + * in the manufacturer-supplied driver, it could + * be wrong. Untested. + */ + r = csr8r(ctlr, Config2) & 0x07; + if(r == 0x01) /* 66MHz PCI */ + csr32w(ctlr, 0x7C, 0x0007FFFF); /* magic */ + else + csr32w(ctlr, 0x7C, 0x0007FF00); /* magic */ + pciclrmwi(ctlr->pcidev); + break; + case Macv13: + /* + * This is interpreted from clearly bogus code + * in the manufacturer-supplied driver, it could + * be wrong. Untested. + */ + pcicfgw8(ctlr->pcidev, 0x68, 0x00); /* magic */ + pcicfgw8(ctlr->pcidev, 0x69, 0x08); /* magic */ + break; + case Macv04: + case Macv11: + case Macv12: + case Macv14: + case Macv15: + break; + } + + /* + * Enable receiver/transmitter. + * Need to do this first or some of the settings below + * won't take. + */ + switch(ctlr->pciv){ + default: + csr8w(ctlr, Cr, Te|Re); + csr32w(ctlr, Tcr, Ifg1|Ifg0|Mtxdmaunlimited); + csr32w(ctlr, Rcr, ctlr->rcr); + case Rtl8169sc: + case Rtl8168b: + break; + } /* * Interrupts. * Disable Tdu|Tok for now, the transmit routine will tidy. - * Tdu means the NIC ran out of descritors to send, so it + * Tdu means the NIC ran out of descriptors to send, so it * doesn't really need to ever be on. */ csr32w(ctlr, Timerint, 0); - csr16w(ctlr, Imr, Serr|Timeout/*|Tdu*/|Fovw|Punlc|Rdu|Ter/*|Tok*/|Rer|Rok); + csr16w(ctlr, Imr, Serr|Timeout|Fovw|Punlc|Rdu|Ter|Rer|Rok); /* * Clear missed-packet counter; @@ -515,20 +595,41 @@ rtl8169init(Ether* edev) csr32w(ctlr, Rdsar+4, 0); csr32w(ctlr, Rdsar, PCIWADDR(ctlr->rd)); csr16w(ctlr, Rms, Mps); - csr16w(ctlr, Mulint, 0); + r = csr16r(ctlr, Mulint) & 0xF000; + csr16w(ctlr, Mulint, r); + csr16w(ctlr, Cplusc, cplusc); /* * Set configuration. */ - csr32w(ctlr, Tcr, Ifg1|Ifg0|Mtxdmaunlimited); - csr32w(ctlr, Rcr, ctlr->rcr); - csr16w(ctlr, 0xE2, 0); /* magic */ + switch(ctlr->pciv){ + default: + break; + case Rtl8169sc: + csr16w(ctlr, 0xE2, 0); /* magic */ + csr8w(ctlr, Cr, Te|Re); + csr32w(ctlr, Tcr, Ifg1|Ifg0|Mtxdmaunlimited); + csr32w(ctlr, Rcr, ctlr->rcr); + break; + case Rtl8168b: + case Rtl8169c: + csr16w(ctlr, 0xE2, 0); /* magic */ + csr16w(ctlr, Cplusc, 0x2000); /* magic */ + csr8w(ctlr, Cr, Te|Re); + csr32w(ctlr, Tcr, Ifg1|Ifg0|Mtxdmaunlimited); + csr32w(ctlr, Rcr, ctlr->rcr); + csr16w(ctlr, Rms, 0x0800); + csr8w(ctlr, Mtps, 0x3F); + break; + } csr8w(ctlr, Cr9346, 0); iunlock(&ctlr->ilock); - //rtl8169mii(ctlr); +// rtl8169mii(ctlr); + + return 0; } static void @@ -665,7 +766,7 @@ rtl8169receive(Ether* edev) else{ /* * Error stuff here. - print("control %8.8uX\n", control); + print("control %#8.8ux\n", control); */ } d->control &= Eor; @@ -688,7 +789,7 @@ rtl8169interrupt(Ureg*, void* arg) edev = arg; ctlr = edev->ctlr; - while((isr = csr16r(ctlr, Isr)) != 0){ + while((isr = csr16r(ctlr, Isr)) != 0 && isr != 0xFFFF){ csr16w(ctlr, Isr, isr); if(isr & (Fovw|Punlc|Rdu|Rer|Rok)){ rtl8169receive(edev); @@ -711,7 +812,7 @@ rtl8169interrupt(Ureg*, void* arg) } if(isr & Punlc){ - //rtl8169link(edev); +// rtl8169link(edev); isr &= ~Punlc; } @@ -719,104 +820,104 @@ rtl8169interrupt(Ureg*, void* arg) * Some of the reserved bits get set sometimes... */ if(isr & (Serr|Timeout|Tdu|Fovw|Punlc|Rdu|Ter|Tok|Rer|Rok)) - panic("rtl8169interrupt: imr %4.4uX isr %4.4uX\n", + panic("rtl8169interrupt: imr %#4.4ux isr %#4.4ux\n", csr16r(ctlr, Imr), isr); } } -static Ctlr* -rtl8169match(Ether* edev, int id) +static void +rtl8169pci(void) { Pcidev *p; Ctlr *ctlr; - int port; + int i, port; + u32int bar; - /* - * Any adapter matches if no edev->port is supplied, - * otherwise the ports must match. - */ - for(ctlr = ctlrhead; ctlr != nil; ctlr = ctlr->next){ - if(ctlr->active) + p = nil; + while(p = pcimatch(p, 0, 0)){ + if(p->ccrb != 0x02 || p->ccru != 0) continue; - p = ctlr->pcidev; - if(((p->did<<16)|p->vid) != id) - continue; - port = p->mem[0].bar & ~0x01; - if(edev->port != 0 && edev->port != port) + + switch(i = ((p->did<<16)|p->vid)){ + default: continue; + case Rtl8100e: /* RTL810[01]E ? */ + case Rtl8169c: /* RTL8169C */ + case Rtl8169sc: /* RTL8169SC */ + case Rtl8168b: /* RTL8168B */ + case Rtl8169: /* RTL8169 */ + break; + case (0xC107<<16)|0x1259: /* Corega CG-LAPCIGT */ + i = Rtl8169; + break; + } + bar = p->mem[0].bar; + port = bar & ~0x01; + if(ioalloc(port, p->mem[0].size, 0, "rtl8169") < 0){ + print("rtl8169: port %#ux in use\n", port); + continue; + } + ctlr = malloc(sizeof(Ctlr)); ctlr->port = port; - if(rtl8169reset(ctlr)) + ctlr->pcidev = p; + ctlr->pciv = i; + + if(pcigetpms(p) > 0){ + pcisetpms(p, 0); + + for(i = 0; i < 6; i++) + pcicfgw32(p, PciBAR0+i*4, p->mem[i].bar); + pcicfgw8(p, PciINTL, p->intl); + pcicfgw8(p, PciLTR, p->ltr); + pcicfgw8(p, PciCLS, p->cls); + pcicfgw16(p, PciPCR, p->pcr); + } + + if(rtl8169reset(ctlr)){ + iofree(port); + free(ctlr); continue; + } - csr8w(ctlr, 0x82, 1); /* magic */ + /* + * Extract the chip hardware version, + * needed to configure each properly. + */ + ctlr->macv = csr32r(ctlr, Tcr) & HwveridMASK; rtl8169mii(ctlr); pcisetbme(p); - ctlr->active = 1; - return ctlr; + + if(rtl8169ctlrhead != nil) + rtl8169ctlrtail->next = ctlr; + else + rtl8169ctlrhead = ctlr; + rtl8169ctlrtail = ctlr; } - return nil; } -static struct { - char* name; - int id; -} rtl8169pci[] = { - { "rtl8169", (0x8169<<16)|0x10EC, }, /* generic */ - { "CG-LAPCIGT", (0xC107<<16)|0x1259, }, /* Corega CG-LAPCIGT */ - { nil }, -}; - int rtl8169pnp(Ether* edev) { - Pcidev *p; + u32int r; Ctlr *ctlr; - int i, id; - uchar ea[Eaddrlen]; - /* - * Make a list of all ethernet controllers - * if not already done. - */ - if(ctlrhead == nil){ - p = nil; - while(p = pcimatch(p, 0, 0)){ - if(p->ccrb != 0x02 || p->ccru != 0) - continue; - ctlr = malloc(sizeof(Ctlr)); - ctlr->pcidev = p; - ctlr->id = (p->did<<16)|p->vid; - - if(ctlrhead != nil) - ctlrtail->next = ctlr; - else - ctlrhead = ctlr; - ctlrtail = ctlr; - } - } + if(rtl8169ctlrhead == nil) + rtl8169pci(); /* - * Is it an RTL8169 under a different name? - * Normally a search is made through all the found controllers - * for one which matches any of the known vid+did pairs. - * If a vid+did pair is specified a search is made for that - * specific controller only. + * Any adapter matches if no edev->port is supplied, + * otherwise the ports must match. */ - id = 0; - for(i = 0; i < edev->nopt; i++){ - if(cistrncmp(edev->opt[i], "id=", 3) == 0) - id = strtol(&edev->opt[i][3], nil, 0); - } - - ctlr = nil; - if(id != 0) - ctlr = rtl8169match(edev, id); - else for(i = 0; rtl8169pci[i].name; i++){ - if((ctlr = rtl8169match(edev, rtl8169pci[i].id)) != nil) + for(ctlr = rtl8169ctlrhead; ctlr != nil; ctlr = ctlr->next){ + if(ctlr->active) + continue; + if(edev->port == 0 || edev->port == ctlr->port){ + ctlr->active = 1; break; + } } if(ctlr == nil) return -1; @@ -825,23 +926,33 @@ rtl8169pnp(Ether* edev) edev->port = ctlr->port; edev->irq = ctlr->pcidev->intl; edev->tbdf = ctlr->pcidev->tbdf; +// edev->mbps = 100; /* + * Pull the MAC address out of the chip. */ - memset(ea, 0, Eaddrlen); - i = csr32r(ctlr, Idr0); - edev->ea[0] = i; - edev->ea[1] = i>>8; - edev->ea[2] = i>>16; - edev->ea[3] = i>>24; - i = csr32r(ctlr, Idr0+4); - edev->ea[4] = i; - edev->ea[5] = i>>8; + r = csr32r(ctlr, Idr0); + edev->ea[0] = r; + edev->ea[1] = r>>8; + edev->ea[2] = r>>16; + edev->ea[3] = r>>24; + r = csr32r(ctlr, Idr0+4); + edev->ea[4] = r; + edev->ea[5] = r>>8; + /* + * Linkage to the generic ethernet driver. + */ edev->attach = rtl8169attach; edev->transmit = rtl8169transmit; edev->interrupt = rtl8169interrupt; edev->detach = rtl8169detach; +// edev->ifstat = rtl8169ifstat; +// edev->ctl = nil; +// +// edev->arg = edev; +// edev->promiscuous = rtl8169promiscuous; +// edev->multicast = rtl8169multicast; return 0; } |
