etherimx: fix link negotiation
mdio interrupt command completion handling was broken, as the interrupt handler would clear the mii status register before mdiodone() sees it. handle errors in miistatus() and miiane(), to not get confused.
This commit is contained in:
parent
990ceeef3b
commit
f0fc84aba3
2 changed files with 51 additions and 19 deletions
|
@ -9,7 +9,10 @@
|
|||
#include "../port/ethermii.h"
|
||||
|
||||
enum {
|
||||
Moduleclk = 125000000, /* 125Mhz */
|
||||
Ptpclk = 100*Mhz,
|
||||
Busclk = 266*Mhz,
|
||||
Txclk = 125*Mhz,
|
||||
|
||||
Maxtu = 1518,
|
||||
|
||||
R_BUF_SIZE = ((Maxtu+BLOCKALIGN-1)&~BLOCKALIGN),
|
||||
|
@ -231,6 +234,7 @@ struct Ctlr
|
|||
|
||||
struct {
|
||||
Mii;
|
||||
int done;
|
||||
Rendez;
|
||||
} mii[1];
|
||||
|
||||
|
@ -245,7 +249,7 @@ static int
|
|||
mdiodone(void *arg)
|
||||
{
|
||||
Ctlr *ctlr = arg;
|
||||
return rr(ctlr, ENET_EIR) & INT_MII;
|
||||
return ctlr->mii->done || (rr(ctlr, ENET_EIR) & INT_MII) != 0;
|
||||
}
|
||||
static int
|
||||
mdiowait(Ctlr *ctlr)
|
||||
|
@ -265,9 +269,13 @@ mdiow(Mii* mii, int phy, int addr, int data)
|
|||
Ctlr *ctlr = mii->ctlr;
|
||||
|
||||
data &= 0xFFFF;
|
||||
|
||||
wr(ctlr, ENET_EIR, INT_MII);
|
||||
ctlr->mii->done = 0;
|
||||
|
||||
wr(ctlr, ENET_MMFR, MMFR_WR | MMFR_ST | MMFR_TA | phy<<MMFR_PA_SHIFT | addr<<MMFR_RA_SHIFT | data);
|
||||
if(mdiowait(ctlr) < 0) return -1;
|
||||
if(mdiowait(ctlr) < 0)
|
||||
return -1;
|
||||
return data;
|
||||
}
|
||||
static int
|
||||
|
@ -276,8 +284,11 @@ mdior(Mii* mii, int phy, int addr)
|
|||
Ctlr *ctlr = mii->ctlr;
|
||||
|
||||
wr(ctlr, ENET_EIR, INT_MII);
|
||||
ctlr->mii->done = 0;
|
||||
|
||||
wr(ctlr, ENET_MMFR, MMFR_RD | MMFR_ST | MMFR_TA | phy<<MMFR_PA_SHIFT | addr<<MMFR_RA_SHIFT);
|
||||
if(mdiowait(ctlr) < 0) return -1;
|
||||
if(mdiowait(ctlr) < 0)
|
||||
return -1;
|
||||
return rr(ctlr, ENET_MMFR) & 0xFFFF;
|
||||
}
|
||||
|
||||
|
@ -289,11 +300,13 @@ interrupt(Ureg*, void *arg)
|
|||
u32int e;
|
||||
|
||||
e = rr(ctlr, ENET_EIR);
|
||||
wr(ctlr, ENET_EIR, e);
|
||||
|
||||
if(e & INT_RXF) wakeup(ctlr->rx);
|
||||
if(e & INT_TXF) wakeup(ctlr->tx);
|
||||
if(e & INT_MII) wakeup(ctlr->mii);
|
||||
if(e & INT_MII) {
|
||||
ctlr->mii->done = 1;
|
||||
wakeup(ctlr->mii);
|
||||
}
|
||||
wr(ctlr, ENET_EIR, e);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -450,13 +463,11 @@ linkproc(void *arg)
|
|||
Ether *edev = arg;
|
||||
Ctlr *ctlr = edev->ctlr;
|
||||
MiiPhy *phy;
|
||||
int link = -1;
|
||||
int link = 0;
|
||||
|
||||
while(waserror())
|
||||
;
|
||||
|
||||
miiane(ctlr->mii, ~0, AnaAP|AnaP, ~0);
|
||||
|
||||
miiane(ctlr->mii, ~0, ~0, ~0);
|
||||
for(;;){
|
||||
miistatus(ctlr->mii);
|
||||
phy = ctlr->mii->curphy;
|
||||
|
@ -505,7 +516,7 @@ linkproc(void *arg)
|
|||
edev->mbps = phy->speed;
|
||||
|
||||
wr(ctlr, ENET_RDAR, RDAR_ACTIVE);
|
||||
}
|
||||
}
|
||||
edev->link = link;
|
||||
print("#l%d: link %d speed %d\n", edev->ctlrno, edev->link, edev->mbps);
|
||||
}
|
||||
|
@ -532,7 +543,7 @@ attach(Ether *edev)
|
|||
wr(ctlr, ENET_RCR, RCR_MII_MODE | RCR_RGMII_EN | Maxtu<<RCR_MAX_FL_SHIFT);
|
||||
|
||||
/* set MII clock to 2.5Mhz, 10ns hold time */
|
||||
wr(ctlr, ENET_MSCR, ((Moduleclk/(2*2500000))-1)<<MSCR_SPEED_SHIFT | ((Moduleclk/10000000)-1)<<MSCR_HOLD_SHIFT);
|
||||
wr(ctlr, ENET_MSCR, ((Busclk/(2*2500000))-1)<<MSCR_SPEED_SHIFT | ((Busclk/1000000)-1)<<MSCR_HOLD_SHIFT);
|
||||
|
||||
ctlr->intmask |= INT_MII;
|
||||
wr(ctlr, ENET_EIMR, ctlr->intmask);
|
||||
|
@ -586,8 +597,8 @@ attach(Ether *edev)
|
|||
wr(ctlr, ENET_TFWR, TFWR_STRFWD);
|
||||
|
||||
/* interrupt coalescing: 200 pkts, 1000 µs */
|
||||
wr(ctlr, ENET_RXIC0, IC_EN | 200<<IC_FT_SHIFT | ((1000*Moduleclk)/64000000)<<IC_TT_SHIFT);
|
||||
wr(ctlr, ENET_TXIC0, IC_EN | 200<<IC_FT_SHIFT | ((1000*Moduleclk)/64000000)<<IC_TT_SHIFT);
|
||||
wr(ctlr, ENET_RXIC0, IC_EN | 200<<IC_FT_SHIFT | ((1000*Txclk)/64000000)<<IC_TT_SHIFT);
|
||||
wr(ctlr, ENET_TXIC0, IC_EN | 200<<IC_FT_SHIFT | ((1000*Txclk)/64000000)<<IC_TT_SHIFT);
|
||||
|
||||
ctlr->intmask |= INT_TXF | INT_RXF;
|
||||
wr(ctlr, ENET_EIMR, ctlr->intmask);
|
||||
|
@ -708,9 +719,9 @@ pnp(Ether *edev)
|
|||
setclkgate("enet1.ipp_ind_mac0_txclk", 0);
|
||||
setclkgate("sim_enet.mainclk", 0);
|
||||
|
||||
setclkrate("enet1.ipg_clk", "system_pll1_div3", 266*Mhz);
|
||||
setclkrate("enet1.ipp_ind_mac0_txclk", "system_pll2_div8", Moduleclk);
|
||||
setclkrate("enet1.ipg_clk_time", "system_pll2_div10", 25*Mhz);
|
||||
setclkrate("enet1.ipg_clk", "system_pll1_div3", Busclk);
|
||||
setclkrate("enet1.ipp_ind_mac0_txclk", "system_pll2_div8", Txclk);
|
||||
setclkrate("enet1.ipg_clk_time", "system_pll2_div10", Ptpclk);
|
||||
|
||||
setclkgate("enet1.ipp_ind_mac0_txclk", 1);
|
||||
setclkgate("sim_enet.mainclk", 1);
|
||||
|
|
|
@ -87,6 +87,8 @@ miireset(Mii* mii)
|
|||
if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
|
||||
return -1;
|
||||
bmcr = mii->mir(mii, mii->curphy->phyno, Bmcr);
|
||||
if(bmcr == -1)
|
||||
return -1;
|
||||
bmcr |= BmcrR;
|
||||
mii->miw(mii, mii->curphy->phyno, Bmcr, bmcr);
|
||||
microdelay(1);
|
||||
|
@ -104,6 +106,8 @@ miiane(Mii* mii, int a, int p, int e)
|
|||
phyno = mii->curphy->phyno;
|
||||
|
||||
bmsr = mii->mir(mii, phyno, Bmsr);
|
||||
if(bmsr == -1)
|
||||
return -1;
|
||||
if(!(bmsr & BmsrAna))
|
||||
return -1;
|
||||
|
||||
|
@ -113,6 +117,8 @@ miiane(Mii* mii, int a, int p, int e)
|
|||
anar = mii->curphy->anar;
|
||||
else{
|
||||
anar = mii->mir(mii, phyno, Anar);
|
||||
if(anar == -1)
|
||||
return -1;
|
||||
anar &= ~(AnaAP|AnaP|AnaT4|AnaTXFD|AnaTXHD|Ana10FD|Ana10HD);
|
||||
if(bmsr & Bmsr10THD)
|
||||
anar |= Ana10HD;
|
||||
|
@ -133,6 +139,8 @@ miiane(Mii* mii, int a, int p, int e)
|
|||
|
||||
if(bmsr & BmsrEs){
|
||||
mscr = mii->mir(mii, phyno, Mscr);
|
||||
if(mscr == -1)
|
||||
return -1;
|
||||
mscr &= ~(Mscr1000TFD|Mscr1000THD);
|
||||
if(e != ~0)
|
||||
mscr |= (Mscr1000TFD|Mscr1000THD) & e;
|
||||
|
@ -140,6 +148,8 @@ miiane(Mii* mii, int a, int p, int e)
|
|||
mscr = mii->curphy->mscr;
|
||||
else{
|
||||
r = mii->mir(mii, phyno, Esr);
|
||||
if(r == -1)
|
||||
return -1;
|
||||
if(r & Esr1000THD)
|
||||
mscr |= Mscr1000THD;
|
||||
if(r & Esr1000TFD)
|
||||
|
@ -148,9 +158,12 @@ miiane(Mii* mii, int a, int p, int e)
|
|||
mii->curphy->mscr = mscr;
|
||||
mii->miw(mii, phyno, Mscr, mscr);
|
||||
}
|
||||
mii->miw(mii, phyno, Anar, anar);
|
||||
if(mii->miw(mii, phyno, Anar, anar) == -1)
|
||||
return -1;
|
||||
|
||||
r = mii->mir(mii, phyno, Bmcr);
|
||||
if(r == -1)
|
||||
return -1;
|
||||
if(!(r & BmcrR)){
|
||||
r |= BmcrAne|BmcrRan;
|
||||
mii->miw(mii, phyno, Bmcr, r);
|
||||
|
@ -175,12 +188,16 @@ miistatus(Mii* mii)
|
|||
* (Read status twice as the Ls bit is sticky).
|
||||
*/
|
||||
bmsr = mii->mir(mii, phyno, Bmsr);
|
||||
if(bmsr == -1)
|
||||
return -1;
|
||||
if(!(bmsr & (BmsrAnc|BmsrAna))) {
|
||||
// print("miistatus: auto-neg incomplete\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
bmsr = mii->mir(mii, phyno, Bmsr);
|
||||
if(bmsr == -1)
|
||||
return -1;
|
||||
if(!(bmsr & BmsrLs)){
|
||||
// print("miistatus: link down\n");
|
||||
phy->link = 0;
|
||||
|
@ -190,6 +207,8 @@ miistatus(Mii* mii)
|
|||
phy->speed = phy->fd = phy->rfc = phy->tfc = 0;
|
||||
if(phy->mscr){
|
||||
r = mii->mir(mii, phyno, Mssr);
|
||||
if(r == -1)
|
||||
return -1;
|
||||
if((phy->mscr & Mscr1000TFD) && (r & Mssr1000TFD)){
|
||||
phy->speed = 1000;
|
||||
phy->fd = 1;
|
||||
|
@ -199,6 +218,8 @@ miistatus(Mii* mii)
|
|||
}
|
||||
|
||||
anlpar = mii->mir(mii, phyno, Anlpar);
|
||||
if(anlpar == -1)
|
||||
return -1;
|
||||
if(phy->speed == 0){
|
||||
r = phy->anar & anlpar;
|
||||
if(r & AnaTXFD){
|
||||
|
|
Loading…
Reference in a new issue