diff 44143b94e3e716ffd9ebd1b5e08b9fcb69f22dd5 uncommitted --- a/sys/src/9/pc/ether8169.c +++ b/sys/src/9/pc/ether8169.c @@ -43,6 +43,7 @@ Config3 = 0x54, /* Configuration Register 3 */ Config4 = 0x55, /* Configuration Register 4 */ Config5 = 0x56, /* Configuration Register 5 */ + Tdfnr = 0x57, /* ? */ Timerint = 0x58, /* Timer Interrupt */ Mulint = 0x5C, /* Multiple Interrupt Select */ Phyar = 0x60, /* PHY Access */ @@ -51,15 +52,41 @@ Tbilpar = 0x6A, /* TBI Auto-Negotiation Link Partner */ Phystatus = 0x6C, /* PHY Status */ Pmch = 0x6F, /* power management */ + Ephyar = 0x80, /* EPHY Access */ Ldps = 0x82, /* link down power saving */ + Dllpr = 0xD0, /* ? */ + Twicmd = 0xD2, /* ? */ Rms = 0xDA, /* Receive Packet Maximum Size */ Cplusc = 0xE0, /* C+ Command */ Coal = 0xE2, /* Interrupt Mitigation (Coalesce) */ Rdsar = 0xE4, /* Receive Descriptor Start Address */ Etx = 0xEC, /* Early Transmit Threshold */ + + Misc = 0xF0, /* Miscellaneous */ }; +enum { /* RTL8125 Family registers */ + Intcfg0 = 0x34, + Imr8125 = 0x38, + Isr8125 = 0x3c, + Intcfg1 = 0x7a, + Tppoll8125 = 0x90, + Macocp8125 = 0xb0, + Phyar8125 = 0xb8, + Mcu = 0xd3, + Coal8125 = 0xa00, + Phyocp8125 = 0xa40, + Misc8125 = 0xf2, + Rssctl = 0x4500, + Qnumctl = 0x4800, + + Timerint0 = 0x0058, + Timerint1 = 0x005c, + Timerint2 = 0x008c, + Timerint3 = 0x00f4, +}; + enum { /* Dtccr */ Reset = 0x00000001, /* Reset */ Dump = 0x00000008, /* Dump */ @@ -99,8 +126,9 @@ Lbk0 = 0x00020000, /* Loopback Test 0 */ Lbk1 = 0x00040000, /* Loopback Test 1 */ Ifg2 = 0x00080000, /* Interframe Gap 2 */ - HwveridSHIFT = 23, /* Hardware Version ID */ - HwveridMASK = 0x7C800000, + + Hwveridmask1 = 0x7CF00000, + Hwveridmask2 = 0x7C800000, Macv01 = 0x00000000, /* RTL8169 */ Macv02 = 0x00800000, /* RTL8169S/8110S */ Macv03 = 0x04000000, /* RTL8169S/8110S */ @@ -114,7 +142,6 @@ Macv13 = 0x34000000, /* RTL8101E */ Macv14 = 0x30800000, /* RTL8100E */ Macv15 = 0x38800000, /* RTL8100E */ -// Macv19 = 0x3c000000, /* dup Macv12a: RTL8111c-gr */ Macv25 = 0x28000000, /* RTL8168D */ Macv26 = 0x48000000, /* RTL8111/8168B */ Macv27 = 0x2c800000, /* RTL8111e */ @@ -128,6 +155,13 @@ Macv44 = 0x5c800000, /* RTL8411B */ Macv45 = 0x54000000, /* RTL8111HN/8168H */ Macv51 = 0x50000000, /* RTL8168EP */ + Macv61 = 0x60900000, /* RTL8125A (untested) */ + Macv63 = 0x64100000, /* RTL8125B */ + Macv64 = 0x68800000, /* RTL8125D (untested) */ + Macv65 = 0x68900000, /* RTL8125D (untested) */ + Macv66 = 0x68100000, /* RTL8125BP (untested) */ + Macv70 = 0x64900000, /* RTL8126A (untested) */ + Macv71 = 0x64a00000, /* RTL8126A (untested) */ Ifg0 = 0x01000000, /* Interframe Gap 0 */ Ifg1 = 0x02000000, /* Interframe Gap 1 */ @@ -145,41 +179,50 @@ MrxdmaMASK = 0x00000700, Mrxdmaunlimited = 0x00000700, RxfthSHIFT = 13, /* Receive Buffer Length */ + Rxpso = 0x00000800, /* RX Pause Slot On */ RxfthMASK = 0x0000E000, Rxfth256 = 0x00008000, Rxfthnone = 0x0000E000, Rer8 = 0x00010000, /* Accept Error Packets > 8 bytes */ MulERINT = 0x01000000, /* Multiple Early Interrupt Select */ + Rx8125fetchdflt = 0x40000000 /* 8125-specific */ }; enum { /* Cr9346 */ - Eedo = 0x01, /* */ - Eedi = 0x02, /* */ - Eesk = 0x04, /* */ - Eecs = 0x08, /* */ + Eedo = 0x01, + Eedi = 0x02, + Eesk = 0x04, + Eecs = 0x08, Eem0 = 0x40, /* Operating Mode */ Eem1 = 0x80, + Eewc = 0xc0, /* write config */ }; enum { /* Phyar */ DataMASK = 0x0000FFFF, /* 16-bit GMII/MII Register Data */ - DataSHIFT = 0, RegaddrMASK = 0x001F0000, /* 5-bit GMII/MII Register Address */ RegaddrSHIFT = 16, - Flag = 0x80000000, /* */ + Flag = 0x80000000, }; enum { /* Phystatus */ Fd = 0x01, /* Full Duplex */ Linksts = 0x02, /* Link Status */ - Speed10 = 0x04, /* */ - Speed100 = 0x08, /* */ - Speed1000 = 0x10, /* */ - Rxflow = 0x20, /* */ - Txflow = 0x40, /* */ - Entbi = 0x80, /* */ + Speed10 = 0x04, + Speed100 = 0x08, + Speed1000 = 0x10, + Rxflow = 0x20, + Txflow = 0x40, + Entbi = 0x80, + Speed2500 = 0x0400, /* 8125 family only (2-byte accessing) */ + Speed5000 = 0x1000, + }; +enum { /* Mcu */ + Ooben = 0x80 +}; + enum { /* Cplusc */ Txenb = 0x0001, /* enable C+ transmit mode */ Rxenb = 0x0002, /* enable C+ receive mode */ @@ -191,6 +234,17 @@ Endian = 0x0200, /* Endian Mode */ }; +enum { /* Misc/Misc8125 */ + Rxdven = 0x00080000, /* RXDV gate enable */ + Rxdven8125 = 0x00000008 +}; + +enum { + Clkreqen = 0x80, /* Config2 */ + + Pmestatus = 0x01 /* Config5 */ +}; + typedef struct D D; /* Transmit/Receive Descriptor */ struct D { u32int control; @@ -260,15 +314,6 @@ u16int txundrn; }; -enum { /* Variants */ - Rtl8100e = (0x8136<<16)|0x10EC, /* RTL810[01]E: pci -e */ - Rtl8169c = (0x0116<<16)|0x16EC, /* RTL8169C+ (USR997902) */ - Rtl8111b = (0x8161<<16)|0x10EC, /* RTL8111/8168/8411: pci-e */ - Rtl8169sc = (0x8167<<16)|0x10EC, /* RTL8169SC */ - Rtl8168b = (0x8168<<16)|0x10EC, /* RTL8168B: pci-e */ - Rtl8169 = (0x8169<<16)|0x10EC, /* RTL8169 */ -}; - typedef struct Ctlr Ctlr; typedef struct Ctlr { Lock; @@ -282,10 +327,10 @@ int init; /* */ Rendez reset; - int pciv; /* */ int macv; /* MAC version */ int phyv; /* PHY version */ int pcie; /* flag: pci-express device? */ + int is8125; /* flag: uses RTL8125 family registers? */ uvlong mchash; /* multicast hash */ @@ -339,53 +384,86 @@ #define csr16w(c, r, w) (outs((c)->port+(r), (u16int)(w))) #define csr32w(c, r, l) (outl((c)->port+(r), (u32int)(l))) +static uint +rtl8125macr(Ctlr *ctlr, int r) +{ + csr32w(ctlr, Macocp8125, r << 15); + return csr32r(ctlr, Macocp8125); +} + +static void +rtl8125macw(Ctlr *ctlr, int r, int v) +{ + csr32w(ctlr, Macocp8125, Flag | (r << 15) | v); +} + +static uint +rtl8169miireg(Ctlr *ctlr, int ra, int *phy, int *data) +{ + uint r; + + if(ctlr->is8125){ + *phy = Phyar8125; + r = ((Phyocp8125 + ra/8) << 4) + ((ra % 8) << 1); + r = (r >> 1) << 16; + if(data) + r |= Flag | *data; + }else{ + *phy = Phyar; + r = (ra << 16) & RegaddrMASK; + if(data) + r |= Flag | (*data & DataMASK); + } + return r; +} + static int -rtl8169miimir(Mii* mii, int pa, int ra) +rtl8169miimir(Mii *mii, int pa, int ra) { + Ctlr *ctlr; uint r; int timeo; - Ctlr *ctlr; + int phy; if(pa != 1) return -1; - ctlr = mii->ctlr; - r = (ra<<16) & RegaddrMASK; - csr32w(ctlr, Phyar, r); + ctlr = mii->ctlr; + r = rtl8169miireg(ctlr, ra, &phy, nil); + csr32w(ctlr, phy, r); delay(1); for(timeo = 0; timeo < 2000; timeo++){ - if((r = csr32r(ctlr, Phyar)) & Flag) + if((r = csr32r(ctlr, phy)) & Flag) break; microdelay(100); } if(!(r & Flag)) return -1; - - return (r & DataMASK)>>DataSHIFT; + return r & DataMASK; } static int -rtl8169miimiw(Mii* mii, int pa, int ra, int data) +rtl8169miimiw(Mii *mii, int pa, int ra, int data) { + Ctlr *ctlr; uint r; int timeo; - Ctlr *ctlr; + int phy; if(pa != 1) return -1; - ctlr = mii->ctlr; - r = Flag|((ra<<16) & RegaddrMASK)|((data<ctlr; + r = rtl8169miireg(ctlr, ra, &phy, &data); + csr32w(ctlr, phy, r); delay(1); for(timeo = 0; timeo < 2000; timeo++){ - if(!((r = csr32r(ctlr, Phyar)) & Flag)) + if(!((r = csr32r(ctlr, phy)) & Flag)) break; microdelay(100); } if(r & Flag) return -1; - return 0; } @@ -411,7 +489,14 @@ case Macv28: case Macv29: case Macv30: - csr8w(ctlr, Pmch, csr8r(ctlr, Pmch) | 0x80); + case Macv61: + case Macv63: + case Macv64: + case Macv65: + case Macv66: + case Macv70: + case Macv71: + csr8w(ctlr, Pmch, csr8r(ctlr, Pmch) | 0xc0); break; } rtl8169miimiw(ctlr->mii, 1, 0x1f, 0); @@ -427,9 +512,8 @@ rtl8169miimiw(ctlr->mii, 1, 0x0B, 0x0000); /* magic */ } - if(mii(ctlr->mii, (1<<1)) == 0 || (phy = ctlr->mii->curphy) == nil){ + if(mii(ctlr->mii, (1<<1)) == 0 || (phy = ctlr->mii->curphy) == nil) error("no phy"); - } print("#l%d: rtl8169: oui %#ux phyno %d, macv = %#8.8ux phyv = %#4.4ux\n", edev->ctlrno, phy->oui, phy->phyno, ctlr->macv, ctlr->phyv); @@ -445,7 +529,7 @@ rtl8169promiscuous(void* arg, int on) { Ether *edev; - Ctlr * ctlr; + Ctlr *ctlr; edev = arg; ctlr = edev->ctlr; @@ -471,13 +555,13 @@ ulong c, crc, carry; crc = ~0UL; - for (i = 0; i < len; i++) { + for(i = 0; i < len; i++){ c = addr[i]; - for (j = 0; j < 8; j++) { + for(j = 0; j < 8; j++){ carry = ((crc & (1UL << 31))? 1: 0) ^ (c & 1); crc <<= 1; c >>= 1; - if (carry) + if(carry) crc = (crc ^ Etherpolybe) | carry; } } @@ -497,7 +581,7 @@ Ether *edev; Ctlr *ctlr; - if (!add) + if(!add) return; /* ok to keep receiving on old mcast addrs */ edev = ether; @@ -510,10 +594,10 @@ csr32w(ctlr, Rcr, ctlr->rcr); /* pci-e variants reverse the order of the hash byte registers */ - if (ctlr->pcie) { + if(ctlr->pcie){ csr32w(ctlr, Mar0, swabl(ctlr->mchash>>32)); csr32w(ctlr, Mar0+4, swabl(ctlr->mchash)); - } else { + }else{ csr32w(ctlr, Mar0, ctlr->mchash); csr32w(ctlr, Mar0+4, ctlr->mchash>>32); } @@ -609,13 +693,22 @@ } static void -rtl8169halt(Ctlr* ctlr) +rtl8169setimr(Ctlr *ctlr, int mask) { - csr8w(ctlr, Cr, 0); + ctlr->imr = mask; + if(ctlr->is8125) + csr32w(ctlr, Imr8125, mask); + else + csr16w(ctlr, Imr, mask); +} - ctlr->imr = 0; - csr16w(ctlr, Imr, 0); - csr16w(ctlr, Isr, ~0); +static void +rtl8169setisr(Ctlr *ctlr, int status) +{ + if(ctlr->is8125) + csr32w(ctlr, Isr8125, status); + else + csr16w(ctlr, Isr, status); } static int @@ -624,6 +717,24 @@ u32int r; int timeo; + if(ctlr->is8125){ + csr8w(ctlr, Misc8125, csr8r(ctlr, Misc8125) | Rxdven8125); + delay(2); + + for(timeo = 0; timeo < 3000; timeo++){ + microdelay(50); + if((csr8r(ctlr, Mcu) & (0x10|0x20)) == (0x10|0x20)) + break; + } + if(ctlr->macv == Macv63) + for(timeo = 0; timeo < 3000; timeo++){ + microdelay(50); + if((csr16r(ctlr, Coal) & 0x0103) == 0x0103) + break; + } + delay(2); + } + /* * Soft reset the controller. */ @@ -634,8 +745,6 @@ break; delay(1); } - rtl8169halt(ctlr); - if(r & Rst) return -1; return 0; @@ -642,6 +751,28 @@ } static void +rtl8169halt(Ctlr* ctlr) +{ + uint r; + + r = csr32r(ctlr, Rcr); + r &= ~(Aap|Apm|Am|Ab|Ar|Aer); + csr32w(ctlr, Rcr, r); + + rtl8169setimr(ctlr, 0); + rtl8169setisr(ctlr, ~0); + if(ctlr->is8125){ + if(ctlr->macv == Macv70 || ctlr->macv == Macv71) + csr8w(ctlr, Intcfg0, csr8r(ctlr, Intcfg0) & ~0x01); + csr32w(ctlr, Timerint0, 0); + csr32w(ctlr, Timerint1, 0); + csr32w(ctlr, Timerint2, 0); + csr32w(ctlr, Timerint3, 0); + } + rtl8169reset(ctlr); +} + +static void rtl8169replenish(Ctlr* ctlr) { D *d; @@ -667,23 +798,15 @@ } } +/* + * Initialize Rx & Tx descriptors + */ static void -rtl8169init(Ether* edev) +rtl8169trdinit(Ctlr *ctlr) { - int i, timeo; - u32int r; Block *bp; - Ctlr *ctlr; - u64int pa; - u16int cplusc; + int i; - ctlr = edev->ctlr; - ilock(ctlr); - if(rtl8169reset(ctlr) < 0){ - iunlock(ctlr); - error("reset failed"); - } - memset(ctlr->td, 0, sizeof(D)*ctlr->ntd); ctlr->tdh = ctlr->tdt = ctlr->ntq = 0; ctlr->td[ctlr->ntd-1].control = Eor; @@ -692,7 +815,6 @@ ctlr->tb[i] = nil; freeb(bp); } - memset(ctlr->rd, 0, sizeof(D)*ctlr->nrd); ctlr->rdh = ctlr->rdt = ctlr->nrq = 0; ctlr->rd[ctlr->nrd-1].control = Eor; @@ -706,11 +828,293 @@ growbp(&ctlr->pool, ctlr->nrd*4); } rtl8169replenish(ctlr); +} - cplusc = csr16r(ctlr, Cplusc); - cplusc &= ~(Endian|Rxchksum); - cplusc |= Txenb|Mulrw; +static int +rtl8125phyw(Ctlr *ctlr, int r, int v) +{ + int i; + + r = Flag | (r >> 1) << 16 | v; + csr32w(ctlr, Phyar8125, r); + for (i = 0; i < 100; i++){ + delay(1); + if(!(csr32r(ctlr, Phyar8125) & Flag)) + break; + } + if(csr32r(ctlr, Phyar8125) & Flag) + return -1; + return 0; +} + +static int +rtl8125phyr(Ctlr *ctlr, int r) +{ + int i; + + r = (r >> 1) << 16; + csr32w(ctlr, Phyar8125, r); + for (i = 0; i < 100; i++) { + delay(1); + r = csr32r(ctlr, Phyar8125); + if(r & Flag) + break; + } + if(!(r & Flag)) + return -1; + return r & 0xffff; +} + +static void +rtl8125patchmcu(Ctlr *ctlr, int p) +{ + uint r; + + if(ctlr->macv == Macv70 || ctlr->macv == Macv71) + return; + + r = rtl8125phyr(ctlr, 0xb820); + if(p) + r |= 0x0010; + else + r &= ~0x0010; + rtl8125phyw(ctlr, 0xb820, r); +} + +static void +rtl8125phywait(Ctlr *ctlr, int state) +{ + int timeo; + + for(timeo = 0; timeo < 100; timeo++){ + if((rtl8125phyr(ctlr, 0xa420) & 7) == state) + break; + microdelay(1); + } +} + +static void +rtl8125fifowait(Ctlr *ctlr) +{ + int timeo; + + for(timeo = 0; timeo < 10; timeo++){ + microdelay(100); + if(csr16r(ctlr, Twicmd) & 0x0200) + break; + } +} + +static void +rtl8125hwinit(Ctlr *ctlr) +{ + int i; + + csr32w(ctlr, Rcr, csr32r(ctlr, Rcr) & ~(Aap|Apm|Am|Ab|Ar|Aer)); + + /* disable RealWoW support */ + rtl8125macw(ctlr, 0xc0bc, 0x00ff); + + rtl8169reset(ctlr); + + /* disable oob(?) */ + csr8w(ctlr, Mcu, csr8r(ctlr, Mcu) & ~Ooben); + + rtl8125macw(ctlr, 0xe8de, rtl8125macr(ctlr, 0xe8de) & ~0x4000); + + rtl8125fifowait(ctlr); + rtl8125macw(ctlr, 0xc0aa, 0x07d0); + rtl8125macw(ctlr, 0xc0a6, 0x01b5); + rtl8125macw(ctlr, 0xc01e, 0x5555); + rtl8125fifowait(ctlr); + + if(rtl8125macr(ctlr, 0xd42c) & 0x0100){ + rtl8125phywait(ctlr, 2); + rtl8125macw(ctlr, 0xd408, rtl8125macr(ctlr, 0xd408) & ~0x0100); + if(ctlr->macv == Macv63) + rtl8125phyw(ctlr, 0xa466, rtl8125phyr(ctlr, 0xa466) & ~0x0001); + rtl8125phyw(ctlr, 0xa468, rtl8125phyr(ctlr, 0xa468) & ~0x000a); + } + + csr8w(ctlr, Cr9346, csr8r(ctlr, Cr9346) | Eewc); + csr8w(ctlr, Config5, csr8r(ctlr, Config5) & ~Pmestatus); + if(ctlr->macv == Macv70 || ctlr->macv == Macv71) + csr8w(ctlr, Intcfg0, csr8r(ctlr, Intcfg0) & ~0x08); + else + csr8w(ctlr, Config2, csr8r(ctlr, Config2) & ~Clkreqen); + csr8w(ctlr, Cr9346, csr8r(ctlr, Cr9346) & ~Eewc); + + csr8w(ctlr, 0xf1, csr8r(ctlr, 0xf1) & ~0x80); + rtl8125macw(ctlr, 0xd40a, rtl8125macr(ctlr, 0xd40a) & ~0x0010); + rtl8125macw(ctlr, 0xfc38, 0); + for(i = 0xfc28; i < 0xfc38; i += 2) + rtl8125macw(ctlr, i, 0); + delay(3); + rtl8125macw(ctlr, 0xfc26, 0); + + /* Disable phy power saving */ + if(ctlr->macv != Macv70 && ctlr->macv != Macv71) + if(rtl8125phyr(ctlr, 0xc416) != 0x0500){ + rtl8125patchmcu(ctlr, 1); + rtl8125phyw(ctlr, 0xc416, 0); + rtl8125phyw(ctlr, 0xc416, 0x0500); + rtl8125patchmcu(ctlr, 0); + } +} + +/* + * Additional RTL8125 family specific initialization + */ +static void +rtl8125init(Ctlr *ctlr) +{ + int timeo; + int v; + uint r; + + csr8w(ctlr, Cr9346, csr8r(ctlr, Cr9346) | Eewc); + + csr8w(ctlr, 0xf1, csr8r(ctlr, 0xf1) & ~0x80); + if(ctlr->macv == Macv70 || ctlr->macv == Macv71) + csr8w(ctlr, Intcfg0, csr8r(ctlr, Intcfg0) & ~0x08); + else + csr8w(ctlr, Config2, csr8r(ctlr, Config2) & ~Clkreqen); + csr8w(ctlr, Config5, csr8r(ctlr, Config5) & ~Pmestatus); + + if(ctlr->macv == Macv70 || ctlr->macv == Macv71) + csr8w(ctlr, Config3, csr8r(ctlr, Config3) & ~0x02); + + /* Disable interrupt coalescing */ + csr8w(ctlr, Intcfg0, 0); + for(r = Coal8125; r < Coal8125+0x80; r += 4) + csr32w(ctlr, r, 0); switch(ctlr->macv){ + case Macv63: + case Macv70: + case Macv71: + csr16w(ctlr, Intcfg1, 0); + break; + case Macv61: + case Macv64: + case Macv65: + case Macv66: + for(; r < Coal8125+0x100; r += 4) + csr32w(ctlr, r, 0); + break; + } + + csr16w(ctlr, 0x0382, 0x221b); + + csr8w(ctlr, Rssctl, 0); + csr16w(ctlr, Qnumctl, 0); + csr8w(ctlr, Config1, csr8r(ctlr, Config1) & ~0x10); + + rtl8125macw(ctlr, 0xc140, 0xffff); + rtl8125macw(ctlr, 0xc142, 0xffff); + + v = rtl8125macr(ctlr, 0xd3e2) & ~0x0fff; + rtl8125macw(ctlr, 0xd3e2, v | 0x03a9); + + rtl8125macw(ctlr, 0xd3e4, rtl8125macr(ctlr, 0xd3e4) & ~0x00ff); + rtl8125macw(ctlr, 0xe860, rtl8125macr(ctlr, 0xe860) | 0x0080); + rtl8125macw(ctlr, 0xeb58, rtl8125macr(ctlr, 0xeb58) | 0x0001); + + if(ctlr->macv == Macv70 || ctlr->macv == Macv71) + csr8w(ctlr, 0xd8, csr8r(ctlr, 0xd8) & ~0x02); + + v = rtl8125macr(ctlr, 0xe614) & ~0x0700; + switch(ctlr->macv){ + case Macv61: + case Macv70: + case Macv71: + rtl8125macw(ctlr, 0xe614, v | 0x0400); + break; + default: + rtl8125macw(ctlr, 0xe614, v | 0x0200); + } + + rtl8125macw(ctlr, 0xe63e, rtl8125macr(ctlr, 0xe63e) & ~0x0c00); + + switch(ctlr->macv){ + case Macv61: + case Macv70: + case Macv71: + rtl8125macw(ctlr, 0xe63e, (rtl8125macr(ctlr, 0xe63e) & ~0x0030) | 0x0020); + break; + default: + rtl8125macw(ctlr, 0xe63e, rtl8125macr(ctlr, 0xe63e) & ~0x0030); + } + + rtl8125macw(ctlr, 0xc0b4, rtl8125macr(ctlr, 0xc0b4) | 0x000c); + + rtl8125macw(ctlr, 0xeb6a, (rtl8125macr(ctlr, 0xeb6a) & ~0x00ff) | 0x0033); + rtl8125macw(ctlr, 0xeb50, (rtl8125macr(ctlr, 0xeb50) & ~0x03e0) | 0x0040); + rtl8125macw(ctlr, 0xe056, (rtl8125macr(ctlr, 0xe056) & ~0x00f0) | 0x0030); + + csr8w(ctlr, Tdfnr, 0x10); + csr8w(ctlr, Dllpr, csr8r(ctlr, Dllpr) | 0x80); + + rtl8125macw(ctlr, 0xe040, rtl8125macr(ctlr, 0xe040) & ~0x1000); + + rtl8125macw(ctlr, 0xea1c, (rtl8125macr(ctlr, 0xea1c) & ~0x0003) | 0x0001); + rtl8125macw(ctlr, 0xe0c0, (rtl8125macr(ctlr, 0xe0c0) & ~0x4f0f) | 0x4403); + rtl8125macw(ctlr, 0xe052, rtl8125macr(ctlr, 0xe052) | 0x0068); + rtl8125macw(ctlr, 0xe052, rtl8125macr(ctlr, 0xe052) & ~0x0080); + rtl8125macw(ctlr, 0xc0ac, (rtl8125macr(ctlr, 0xc0ac) & ~0x0080) | 0x1f00); + rtl8125macw(ctlr, 0xd430, (rtl8125macr(ctlr, 0xd430) & ~0x0fff) | 0x047f); + if(ctlr->macv == Macv61) + rtl8125macw(ctlr, 0xe84c, 0x00c0); + else + rtl8125macw(ctlr, 0xe84c, 0x0080); + + csr8w(ctlr, Dllpr, csr8r(ctlr, Dllpr) | 0x40); + + if(ctlr->macv == Macv61) + csr8w(ctlr, Mcu, csr8r(ctlr, Mcu) | 0x01); + + /* Disable EEE plus. */ + rtl8125macw(ctlr, 0xe080, rtl8125macr(ctlr, 0xe080) & ~0x0002); + + if(ctlr->macv == Macv70 || ctlr->macv == Macv71) + v = ~0x0304; + else + v = ~0x0004; + rtl8125macw(ctlr, 0xea1c, rtl8125macr(ctlr, 0xea1c) & v); + rtl8125macw(ctlr, 0xeb54, rtl8125macr(ctlr, 0xeb54) | 0x0001); + microdelay(1); + rtl8125macw(ctlr, 0xeb54, rtl8125macr(ctlr, 0xeb54) & ~0x0001); + csr32w(ctlr, 0x1880, csr32r(ctlr, 0x1880) & ~0x0030); + rtl8125macw(ctlr, 0xe098, 0xc302); + + for(timeo = 0; timeo < 10; timeo++){ + if(!(rtl8125macr(ctlr, 0xe00e) & 0x2000)) + break; + delay(1); + } +} + +static void +rtl8169init(Ctlr *ctlr) +{ + int timeo; + u32int r; + u64int pa; + u16int cplusc; + + ilock(ctlr); + if(rtl8169reset(ctlr) < 0){ + iunlock(ctlr); + error("reset failed"); + } + + r = csr32r(ctlr, Rcr); + r &= ~(Aap|Apm|Am|Ab|Ar|Aer); + csr32w(ctlr, Rcr, r); + + rtl8169trdinit(ctlr); + + cplusc = csr16r(ctlr, Cplusc) & ~(Endian|Rxchksum); + switch(ctlr->macv){ case Macv40: case Macv42: case Macv44: @@ -722,12 +1126,11 @@ cplusc |= Rxenb; break; } - csr16w(ctlr, Cplusc, cplusc); + csr16w(ctlr, Cplusc, cplusc|Txenb|Mulrw); pa = PCIWADDR(ctlr->td); csr32w(ctlr, Tnpds+4, pa>>32); csr32w(ctlr, Tnpds, pa); - pa = PCIWADDR(ctlr->rd); csr32w(ctlr, Rdsar+4, pa>>32); csr32w(ctlr, Rdsar, pa); @@ -745,7 +1148,12 @@ error("reset failed"); } - /* pre-RTL8168G controllers need TX/RX before configuration */ + if(ctlr->is8125) + rtl8125init(ctlr); + else + /* disable interrupt coalescing */ + csr16w(ctlr, Coal, 0); + switch(ctlr->macv){ case Macv40: case Macv42: @@ -752,24 +1160,43 @@ case Macv44: case Macv45: case Macv51: - /* RXDV gating */ - i = csr32r(ctlr, 0x00F0); - csr32w(ctlr, 0x00F0, i&~0x00080000); + /* disable rxdv gate */ + csr32w(ctlr, Misc, csr32r(ctlr, Misc) & ~Rxdven); break; + case Macv61: + case Macv63: + case Macv64: + case Macv65: + case Macv66: + case Macv70: + case Macv71: + csr32w(ctlr, Misc8125, csr32r(ctlr, Misc8125) & ~Rxdven8125); + break; default: + /* pre-RTL8168G controllers need TX/RX before configuration */ csr8w(ctlr, Cr, Te|Re); } csr32w(ctlr, Tcr, Ifg1|Ifg0|Mtxdmaunlimited); ctlr->tcr = csr32r(ctlr, Tcr); + ctlr->rcr = Ab|Am|Apm|Mrxdmaunlimited; switch(ctlr->macv){ case Macv42: case Macv45: case Macv51: - ctlr->rcr = Rxfth256|Mrxdmaunlimited|Ab|Am|Apm; + ctlr->rcr |= Rxfth256; break; + case Macv61: + case Macv63: + case Macv64: + case Macv65: + case Macv66: + case Macv70: + case Macv71: + ctlr->rcr |= Rx8125fetchdflt|Rxpso; + break; default: - ctlr->rcr = Rxfthnone|Mrxdmaunlimited|Ab|Am|Apm; + ctlr->rcr |= Rxfthnone; break; } ctlr->mchash = 0; @@ -781,14 +1208,11 @@ csr8w(ctlr, Etx, 0x3f); csr16w(ctlr, Rms, 0x3fff); - csr16w(ctlr, Coal, 0); - /* no early rx interrupts */ r = csr16r(ctlr, Mulint) & 0xF000; csr16w(ctlr, Mulint, r); - ctlr->imr = Serr|Fovw|Punlc|Rdu|Ter|Rer|Rok|Tdu; - csr16w(ctlr, Imr, ctlr->imr); + rtl8169setimr(ctlr, Serr|Fovw|Punlc|Rdu|Ter|Rer|Rok|Tdu); csr32w(ctlr, Mpc, 0); @@ -798,6 +1222,13 @@ case Macv44: case Macv45: case Macv51: + case Macv61: + case Macv63: + case Macv64: + case Macv65: + case Macv66: + case Macv70: + case Macv71: csr8w(ctlr, Cr, Te|Re); default: break; @@ -817,7 +1248,7 @@ for(;;){ ctlr = edev->ctlr; sleep(&ctlr->reset, return0, nil); - rtl8169init(edev); + rtl8169init(ctlr); } } @@ -875,8 +1306,14 @@ nexterror(); } - rtl8169init(edev); - rtl8169mii(edev); + if(ctlr->is8125){ + rtl8125hwinit(ctlr); + rtl8169mii(edev); + // rtl8125phyconf(ctlr); + } + rtl8169init(ctlr); + if(!ctlr->is8125) + rtl8169mii(edev); ctlr->init = 1; poperror(); @@ -891,16 +1328,14 @@ static void rtl8169link(Ether* edev) { + Ctlr *ctlr = edev->ctlr; uint r; - Ctlr *ctlr; - ctlr = edev->ctlr; - /* * Maybe the link changed - do we care very much? * Could stall transmits if no link, maybe? */ - r = csr8r(ctlr, Phystatus); + r = ctlr->is8125? csr16r(ctlr, Phystatus): csr8r(ctlr, Phystatus); if(r & Linksts){ if(r & Speed10) ethersetspeed(edev, 10); @@ -908,10 +1343,15 @@ ethersetspeed(edev, 100); else if(r & Speed1000) ethersetspeed(edev, 1000); + else if(ctlr->is8125){ + if(r & Speed2500) + ethersetspeed(edev, 2500); + else if(r & Speed5000) + ethersetspeed(edev, 5000); + } ethersetlink(edev, 1); - } else { + }else ethersetlink(edev, 0); - } } static void @@ -968,7 +1408,10 @@ if(ctlr->ntq > 0){ coherence(); - csr8w(ctlr, Tppoll, Npq); + if(ctlr->is8125) + csr8w(ctlr, Tppoll8125, 1); + else + csr8w(ctlr, Tppoll, Npq); } unlock(ctlr); } @@ -1050,21 +1493,37 @@ wakeup(&ctlr->reset); } +static uint +rtl8169getintr(Ctlr *ctlr) +{ + u32int isr; + + if(ctlr->is8125){ + isr = csr32r(ctlr, Isr8125); + if(isr == 0xFFFFFFFF) + return 0; + }else{ + isr = csr16r(ctlr, Isr); + if(isr == 0xFFFF) + return 0; + } + if((isr & ctlr->imr) == 0) + return 0; + rtl8169setisr(ctlr, isr); + return isr; +} + static void rtl8169interrupt(Ureg*, void* arg) { Ctlr *ctlr; Ether *edev; - u32int isr; + uint isr; edev = arg; ctlr = edev->ctlr; - while((isr = csr16r(ctlr, Isr)) != 0 && isr != 0xFFFF){ - csr16w(ctlr, Isr, isr); - if((isr & ctlr->imr) == 0) - break; - + while(isr = rtl8169getintr(ctlr)){ if(isr & Serr) ctlr->serr++; if(isr & Fovw) @@ -1095,18 +1554,21 @@ static void rtl8169shutdown(Ether *edev) { - Ctlr *ctlr = edev->ctlr; - - rtl8169halt(ctlr); + rtl8169halt(edev->ctlr); } int -vetmacv(Ctlr *ctlr, uint *macv) +vetmacv(Ctlr *ctlr, int *macv) { - *macv = csr32r(ctlr, Tcr) & HwveridMASK; - switch(*macv){ - default: - return -1; + int mask; + + /* + * Try a more restrictive mask first to catch more specific nics. + */ + mask = Hwveridmask1; + ctlr->is8125 = 0; +Again: + switch(*macv = (csr32r(ctlr, Tcr) & mask)){ case Macv01: case Macv02: case Macv03: @@ -1134,17 +1596,32 @@ case Macv45: case Macv51: break; + case Macv61: + case Macv63: + case Macv64: + case Macv65: + case Macv66: + case Macv70: + case Macv71: + ctlr->is8125 = 1; + break; + default: + if(mask == Hwveridmask2) + return -1; + mask = Hwveridmask2; + goto Again; } return 0; } +#define Pciid(vid, did) ((vid) << 16 | (did)) + static void rtl8169pci(void) { Pcidev *p; Ctlr *ctlr; - int i, port, pcie; - uint macv; + int port, pcie; p = nil; while(p = pcimatch(p, 0, 0)){ @@ -1152,21 +1629,21 @@ continue; pcie = 0; - switch(i = ((p->did<<16)|p->vid)){ - default: - continue; - case Rtl8100e: /* RTL810[01]E ? */ - case Rtl8168b: /* RTL8168B */ - case Rtl8111b: /* RTL8111/8168/8411 */ + switch(Pciid(p->vid, p->did)){ + case Pciid(Vrealtek, 0x8136): /* RTL810[01]E ? */ + case Pciid(Vrealtek, 0x8168): /* RTL8168B */ + case Pciid(Vrealtek, 0x8161): /* RTL8111/8168/8411 */ + case Pciid(Vrealtek, 0x8125): /* RTL8125[ABD] */ + case Pciid(Vrealtek, 0x8126): /* RTL8126A */ pcie = 1; + case Pciid(Vrealtek, 0x8167): /* RTL8169SC */ + case Pciid(Vrealtek, 0x8169): /* RTL8169 */ + /* Some realtek chips are behind other VIDs */ + case Pciid(0x1259, 0xc107): /* Corega CG-LAPCIGT */ + case Pciid(0x16ec, 0x0116): /* RTL8169C+ (USR997902) */ break; - case Rtl8169c: /* RTL8169C */ - case Rtl8169sc: /* RTL8169SC */ - case Rtl8169: /* RTL8169 */ - break; - case (0xC107<<16)|0x1259: /* Corega CG-LAPCIGT */ - i = Rtl8169; - break; + default: + continue; } if(p->mem[0].size == 0 || (p->mem[0].bar & 1) == 0) @@ -1185,24 +1662,22 @@ } ctlr->port = port; ctlr->pcidev = p; - ctlr->pciv = i; ctlr->pcie = pcie; - pcienable(p); - if(vetmacv(ctlr, &macv) == -1){ - print("rtl8169: %T: unknown mac %.4ux %.8ux\n", p->tbdf, p->did, macv); + + /* + * Extract the chip hardware version needed to configure each properly. + */ + if(vetmacv(ctlr, &ctlr->macv) == -1){ + print("rtl8169: %T: unknown mac %.4ux %.8ux\n", p->tbdf, p->did, ctlr->macv); pcidisable(p); iofree(port); free(ctlr); continue; } + rtl8169halt(ctlr); - /* - * Extract the chip hardware version, - * needed to configure each properly. - */ - ctlr->macv = macv; if(rtl8169ctlrhead != nil) rtl8169ctlrtail->next = ctlr; else