summaryrefslogtreecommitdiff
path: root/os/boot/pc/ether8169.c
diff options
context:
space:
mode:
Diffstat (limited to 'os/boot/pc/ether8169.c')
-rw-r--r--os/boot/pc/ether8169.c379
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;
}