|
@@ -1,11 +1,7 @@
|
|
|
/*
|
|
|
* marvell kirkwood ethernet (88e1116) driver
|
|
|
- * (as found in the sheevaplug).
|
|
|
+ * (as found in the sheevaplug & openrd).
|
|
|
* from /public/doc/marvell/sheeva/88f61xx.kirkwood.pdf
|
|
|
- *
|
|
|
- * features that could be implemented:
|
|
|
- * - ip4, tcp, udp checksum offloading
|
|
|
- * - multicast filtering
|
|
|
*/
|
|
|
|
|
|
#include "u.h"
|
|
@@ -23,14 +19,11 @@
|
|
|
|
|
|
#define MASK(v) ((1UL<<(v)) - 1)
|
|
|
|
|
|
-// #undef assert
|
|
|
-// #define assert(expr)
|
|
|
-
|
|
|
#define MIIDBG if(0)iprint
|
|
|
-#define diprint if(0)iprint
|
|
|
|
|
|
enum {
|
|
|
- Gberegs = Regbase + 0x72000,
|
|
|
+ Gbe0regs = Regbase + 0x72000,
|
|
|
+ Gbe1regs = Regbase + 0x76000,
|
|
|
|
|
|
Nrx = 512,
|
|
|
Ntx = 512,
|
|
@@ -43,6 +36,8 @@ enum {
|
|
|
Descralign = 16,
|
|
|
Bufalign = 8,
|
|
|
|
|
|
+ Pass = 1, /* accept packets */
|
|
|
+
|
|
|
Qno = 0, /* do everything on queue zero */
|
|
|
};
|
|
|
|
|
@@ -166,7 +161,7 @@ enum {
|
|
|
#define SDCipgintrx(v) ((((v)>>15) & 1)<<25) | (((v) & MASK(15))<<7)
|
|
|
|
|
|
/* portcfg */
|
|
|
- PCFGupromisc = 1<<0,
|
|
|
+ PCFGupromisc = 1<<0, /* unicast promiscuous mode */
|
|
|
#define Rxqdefault(q) ((q)<<1)
|
|
|
#define Rxqarp(q) ((q)<<4)
|
|
|
PCFGbcrejectnoiparp = 1<<7,
|
|
@@ -223,7 +218,7 @@ enum {
|
|
|
/* port serial control 1, psc1 */
|
|
|
PSC1loopback = 1<<1,
|
|
|
PSC1mii = 0<<2,
|
|
|
- PSC1rgmii = 1<<3,
|
|
|
+ PSC1rgmii = 1<<3, /* enable RGMII */
|
|
|
PSC1portreset = 1<<4,
|
|
|
PSC1clockbypass = 1<<5,
|
|
|
PSC1iban = 1<<6,
|
|
@@ -461,17 +456,13 @@ struct Gbereg {
|
|
|
Mibstats;
|
|
|
ulong _pad23[PAD(0x1400, 0x107c)];
|
|
|
|
|
|
- /* multicast filtering */
|
|
|
+ /* multicast filtering; each byte: Qno<<1 | Pass */
|
|
|
ulong dfsmt[64]; /* dest addr filter special m'cast table */
|
|
|
ulong dfomt[64]; /* dest addr filter other m'cast table */
|
|
|
-
|
|
|
/* unicast filtering */
|
|
|
ulong dfut[4]; /* dest addr filter unicast table */
|
|
|
};
|
|
|
|
|
|
-vlong etherstart;
|
|
|
-
|
|
|
-
|
|
|
static void getmibstats(Ctlr *);
|
|
|
|
|
|
static void
|
|
@@ -571,16 +562,16 @@ dump(uchar *bp, long max)
|
|
|
}
|
|
|
|
|
|
static void
|
|
|
-etheractive(void)
|
|
|
+etheractive(Ether *ether)
|
|
|
{
|
|
|
- etherstart = TK2MS(MACHP(0)->ticks)/1000;
|
|
|
+ ether->starttime = TK2MS(MACHP(0)->ticks)/1000;
|
|
|
}
|
|
|
|
|
|
static void
|
|
|
-ethercheck(void)
|
|
|
+ethercheck(Ether *ether)
|
|
|
{
|
|
|
- if (etherstart != 0 &&
|
|
|
- TK2MS(MACHP(0)->ticks)/1000 - etherstart > Etherstuck)
|
|
|
+ if (ether->starttime != 0 &&
|
|
|
+ TK2MS(MACHP(0)->ticks)/1000 - ether->starttime > Etherstuck)
|
|
|
iprint("ethernet stuck\n");
|
|
|
}
|
|
|
|
|
@@ -593,7 +584,7 @@ receive(Ether *ether)
|
|
|
Ctlr *ctlr = ether->ctlr;
|
|
|
Rx *r;
|
|
|
|
|
|
- ethercheck();
|
|
|
+ ethercheck(ether);
|
|
|
for (i = Nrx-2; i > 0; i--) {
|
|
|
r = &ctlr->rx[ctlr->rxhead];
|
|
|
assert(((uintptr)r & (Descralign - 1)) == 0);
|
|
@@ -629,7 +620,7 @@ receive(Ether *ether)
|
|
|
*/
|
|
|
b->rp += 2;
|
|
|
etheriq(ether, b, 1);
|
|
|
- etheractive();
|
|
|
+ etheractive(ether);
|
|
|
if (i % (Nrx / 2) == 0)
|
|
|
rxreplenish(ctlr);
|
|
|
}
|
|
@@ -637,8 +628,11 @@ receive(Ether *ether)
|
|
|
}
|
|
|
|
|
|
static void
|
|
|
-txreplenish(Ctlr *ctlr) /* free transmitted packets */
|
|
|
+txreplenish(Ether *ether) /* free transmitted packets */
|
|
|
{
|
|
|
+ Ctlr *ctlr;
|
|
|
+
|
|
|
+ ctlr = ether->ctlr;
|
|
|
while(ctlr->txtail != ctlr->txhead) {
|
|
|
cachedinvse(&ctlr->tx[ctlr->txtail].cs, BY2SE);
|
|
|
if(ctlr->tx[ctlr->txtail].cs & TCSdmaown)
|
|
@@ -648,7 +642,7 @@ txreplenish(Ctlr *ctlr) /* free transmitted packets */
|
|
|
freeb(ctlr->txb[ctlr->txtail]);
|
|
|
ctlr->txb[ctlr->txtail] = nil;
|
|
|
ctlr->txtail = NEXT(ctlr->txtail, Ntx);
|
|
|
- etheractive();
|
|
|
+ etheractive(ether);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -666,9 +660,9 @@ transmit(Ether *ether)
|
|
|
Gbereg *reg = ctlr->reg;
|
|
|
Tx *t;
|
|
|
|
|
|
- ethercheck();
|
|
|
+ ethercheck(ether);
|
|
|
ilock(ctlr);
|
|
|
- txreplenish(ctlr); /* reap old packets */
|
|
|
+ txreplenish(ether); /* reap old packets */
|
|
|
|
|
|
/* queue new packets; don't use more than half the tx descs. */
|
|
|
kick = 0;
|
|
@@ -759,14 +753,13 @@ interrupt(Ureg*, void *arg)
|
|
|
Ether *ether = arg;
|
|
|
Ctlr *ctlr = ether->ctlr;
|
|
|
Gbereg *reg = ctlr->reg;
|
|
|
- static int linkchg = 0;
|
|
|
|
|
|
handled = 0;
|
|
|
irq = reg->irq;
|
|
|
irqe = reg->irqe;
|
|
|
reg->irq = 0; /* extinguish intr causes */
|
|
|
reg->irqe = 0; /* " " " */
|
|
|
- ethercheck();
|
|
|
+ ethercheck(ether);
|
|
|
|
|
|
if(irq & Irxbufferq(Qno)) {
|
|
|
/*
|
|
@@ -795,7 +788,7 @@ interrupt(Ureg*, void *arg)
|
|
|
*/
|
|
|
if(irqe & IEphystschg) {
|
|
|
ether->link = (reg->ps0 & PS0linkup) != 0;
|
|
|
- linkchg = 1;
|
|
|
+ ether->linkchg = 1;
|
|
|
}
|
|
|
if(irqe & IEtxerrq(Qno))
|
|
|
ether->oerrs++;
|
|
@@ -822,10 +815,10 @@ interrupt(Ureg*, void *arg)
|
|
|
handled++;
|
|
|
}
|
|
|
|
|
|
- if(linkchg && (reg->ps1 & PS1an_done)) {
|
|
|
+ if(ether->linkchg && (reg->ps1 & PS1an_done)) {
|
|
|
handled++;
|
|
|
ether->link = (reg->ps0 & PS0linkup) != 0;
|
|
|
- linkchg = 0;
|
|
|
+ ether->linkchg = 0;
|
|
|
}
|
|
|
ctlr->newintrs++;
|
|
|
|
|
@@ -842,8 +835,6 @@ interrupt(Ureg*, void *arg)
|
|
|
intrclear(Irqlo, IRQ0gbe0sum);
|
|
|
}
|
|
|
|
|
|
-static int prom, mcast;
|
|
|
-
|
|
|
void
|
|
|
promiscuous(void *arg, int on)
|
|
|
{
|
|
@@ -852,8 +843,8 @@ promiscuous(void *arg, int on)
|
|
|
Gbereg *reg = ctlr->reg;
|
|
|
|
|
|
ilock(ctlr);
|
|
|
- ether->prom = prom = on;
|
|
|
- if(prom || mcast)
|
|
|
+ ether->prom = on;
|
|
|
+ if(on)
|
|
|
reg->portcfg |= PCFGupromisc;
|
|
|
else
|
|
|
reg->portcfg &= ~PCFGupromisc;
|
|
@@ -861,20 +852,9 @@ promiscuous(void *arg, int on)
|
|
|
}
|
|
|
|
|
|
void
|
|
|
-multicast(void *arg, uchar *addr, int on)
|
|
|
+multicast(void *, uchar *, int)
|
|
|
{
|
|
|
- Ether *e = arg;
|
|
|
- Ctlr *ctlr = e->ctlr;
|
|
|
- Gbereg *reg = ctlr->reg;
|
|
|
-
|
|
|
- mcast |= on;
|
|
|
- USED(addr);
|
|
|
- ilock(ctlr);
|
|
|
- if(prom || mcast)
|
|
|
- reg->portcfg |= PCFGupromisc; /* overkill */
|
|
|
- else
|
|
|
- reg->portcfg &= ~PCFGupromisc;
|
|
|
- iunlock(ctlr);
|
|
|
+ /* nothing to do; we always accept multicast */
|
|
|
}
|
|
|
|
|
|
static void quiesce(Gbereg *reg);
|
|
@@ -1047,10 +1027,17 @@ kirkwoodmii(Ether *ether)
|
|
|
ctlr->mii->mir = miird;
|
|
|
ctlr->mii->miw = miiwr;
|
|
|
|
|
|
+ phy = nil;
|
|
|
if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){
|
|
|
+ iprint("#l%d: etherkw: init mii failure\n", ether->ctlrno);
|
|
|
+ if (phy)
|
|
|
+ iprint("#l%d: etherkw: mii(...,~0) failed\n",
|
|
|
+ ether->ctlrno);
|
|
|
+ else
|
|
|
+ iprint("#l%d: etherkw: nil ctlr->mii->curphy\n",
|
|
|
+ ether->ctlrno);
|
|
|
free(ctlr->mii);
|
|
|
ctlr->mii = nil;
|
|
|
- iprint("etherkw: init mii failure\n");
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
@@ -1092,30 +1079,25 @@ kirkwoodmii(Ether *ether)
|
|
|
static int
|
|
|
miiphyinit(Mii *mii) /* magic numbers 'r' us */
|
|
|
{
|
|
|
- ulong reg, devadr;
|
|
|
+ ulong dev;
|
|
|
|
|
|
/* select mii phy */
|
|
|
- devadr = miird(mii, 0xEE, 0xEE);
|
|
|
-// print("devadr %lux\n", devadr);
|
|
|
- if (devadr == -1) {
|
|
|
+ dev = miird(mii, 0xEE, 0xEE); /* device address */
|
|
|
+// print("dev %lux\n", dev);
|
|
|
+ if (dev == -1) {
|
|
|
print("etherkw: can't read PHY dev address\n");
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
/* leds link & activity */
|
|
|
- miiwr(mii, devadr, 22, 0x3);
|
|
|
- reg = miird(mii, devadr, 10);
|
|
|
- reg &= ~0xf;
|
|
|
- reg |= 0x1;
|
|
|
- miiwr(mii, devadr, 10, reg);
|
|
|
- miiwr(mii, devadr, 22, 0);
|
|
|
+ miiwr(mii, dev, 22, 0x3);
|
|
|
+ miiwr(mii, dev, 10, (miird(mii, dev, 10) & ~0xf) | 1); /* magic */
|
|
|
+ miiwr(mii, dev, 22, 0);
|
|
|
|
|
|
/* enable RGMII delay on Tx and Rx for CPU port */
|
|
|
- miiwr(mii, devadr, 22, 2);
|
|
|
- reg = miird(mii, devadr, 21);
|
|
|
- reg |= (1<<5) | (1<<4);
|
|
|
- miiwr(mii, devadr, 21, reg);
|
|
|
- miiwr(mii, devadr, 22, 0);
|
|
|
+ miiwr(mii, dev, 22, 2);
|
|
|
+ miiwr(mii, dev, 21, miird(mii, dev, 21) | 1<<5 | 1<<4); /* magic */
|
|
|
+ miiwr(mii, dev, 22, 0);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -1167,16 +1149,12 @@ p32(uchar *p, ulong v)
|
|
|
*p = v;
|
|
|
}
|
|
|
|
|
|
-enum {
|
|
|
- Pass = 1,
|
|
|
-};
|
|
|
-
|
|
|
/*
|
|
|
* set ether->ea from hw mac address,
|
|
|
* configure unicast filtering to accept it.
|
|
|
*/
|
|
|
void
|
|
|
-archetheraddr(Ether *ether, Gbereg *reg, int queue)
|
|
|
+archetheraddr(Ether *ether, Gbereg *reg, int rxqno)
|
|
|
{
|
|
|
ulong nibble, ucreg, tbloff, regoff;
|
|
|
|
|
@@ -1191,8 +1169,12 @@ archetheraddr(Ether *ether, Gbereg *reg, int queue)
|
|
|
regoff *= 8;
|
|
|
ucreg = reg->dfut[tbloff];
|
|
|
ucreg &= 0xff << regoff;
|
|
|
- ucreg |= (queue << 1 | Pass) << regoff;
|
|
|
+ ucreg |= (rxqno << 1 | Pass) << regoff;
|
|
|
reg->dfut[tbloff] = ucreg;
|
|
|
+
|
|
|
+ /* accept all multicast too. set up special & other tables. */
|
|
|
+ memset(reg->dfsmt, Qno<<1 | Pass, sizeof reg->dfsmt);
|
|
|
+ memset(reg->dfomt, Qno<<1 | Pass, sizeof reg->dfomt);
|
|
|
}
|
|
|
|
|
|
static void
|
|
@@ -1269,7 +1251,7 @@ ctlrinit(Ether *ether)
|
|
|
reg->sdc = SDCrifb | SDCrxburst(Burst16) | SDCtxburst(Burst16) |
|
|
|
SDCrxnobyteswap | SDCtxnobyteswap |
|
|
|
SDCipgintrx(CLOCKFREQ/(Maxrxintrsec*64));
|
|
|
- reg->pxtfut = 0; // TFUTipginttx(CLOCKFREQ/(Maxrxintrsec*64));
|
|
|
+ reg->pxtfut = 0; /* TFUTipginttx(CLOCKFREQ/(Maxrxintrsec*64)) */
|
|
|
|
|
|
/* allow just these interrupts */
|
|
|
reg->irqmask = Irxbufferq(Qno) | Irxerr | Itxendq(Qno);
|
|
@@ -1280,6 +1262,8 @@ ctlrinit(Ether *ether)
|
|
|
reg->euirqmask = 0;
|
|
|
reg->euirq = 0;
|
|
|
|
|
|
+// archetheraddr(ether, ctlr->reg, Qno); /* 2nd location */
|
|
|
+
|
|
|
reg->tcqdp[Qno] = PADDR(&ctlr->tx[ctlr->txhead]);
|
|
|
for (i = 1; i < nelem(reg->tcqdp); i++)
|
|
|
reg->tcqdp[i] = 0;
|
|
@@ -1299,9 +1283,9 @@ ctlrinit(Ether *ether)
|
|
|
|
|
|
/* set ethernet MTU for leaky bucket mechanism to 0 (disabled) */
|
|
|
reg->pmtu = 0;
|
|
|
- reg->rqc = Rxqon(Qno);
|
|
|
|
|
|
- etheractive();
|
|
|
+ reg->rqc = Rxqon(Qno);
|
|
|
+ etheractive(ether);
|
|
|
|
|
|
snprint(name, sizeof name, "#l%drproc", ether->ctlrno);
|
|
|
kproc(name, rcvproc, ether);
|
|
@@ -1449,10 +1433,13 @@ reset(Ether *ether)
|
|
|
ether->ctlr = ctlr;
|
|
|
switch(ether->ctlrno) {
|
|
|
case 0:
|
|
|
- ctlr->reg = (Gbereg*)Gberegs;
|
|
|
+ ctlr->reg = (Gbereg*)Gbe0regs;
|
|
|
+ break;
|
|
|
+ case 1:
|
|
|
+ ctlr->reg = (Gbereg*)Gbe1regs;
|
|
|
break;
|
|
|
default:
|
|
|
- panic("etherkirdwood: bad ether ctlr #%d", ether->ctlrno);
|
|
|
+ panic("etherkw: bad ether ctlr #%d", ether->ctlrno);
|
|
|
}
|
|
|
|
|
|
/* io cfg 0: 1.8v gbe */
|
|
@@ -1471,8 +1458,8 @@ reset(Ether *ether)
|
|
|
ether->ctlr = nil;
|
|
|
return -1;
|
|
|
}
|
|
|
- miiphyinit(ctlr->mii);
|
|
|
- archetheraddr(ether, ctlr->reg, 0); /* 0 is the rx queue */
|
|
|
+ miiphyinit(ctlr->mii); /* commented-out in inferno */
|
|
|
+ archetheraddr(ether, ctlr->reg, Qno); /* original location */
|
|
|
|
|
|
ether->attach = attach;
|
|
|
ether->transmit = transmit;
|