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:
cinap_lenrek 2022-06-19 18:07:50 +00:00
parent 990ceeef3b
commit f0fc84aba3
2 changed files with 51 additions and 19 deletions

View file

@ -9,7 +9,10 @@
#include "../port/ethermii.h" #include "../port/ethermii.h"
enum { enum {
Moduleclk = 125000000, /* 125Mhz */ Ptpclk = 100*Mhz,
Busclk = 266*Mhz,
Txclk = 125*Mhz,
Maxtu = 1518, Maxtu = 1518,
R_BUF_SIZE = ((Maxtu+BLOCKALIGN-1)&~BLOCKALIGN), R_BUF_SIZE = ((Maxtu+BLOCKALIGN-1)&~BLOCKALIGN),
@ -231,6 +234,7 @@ struct Ctlr
struct { struct {
Mii; Mii;
int done;
Rendez; Rendez;
} mii[1]; } mii[1];
@ -245,7 +249,7 @@ static int
mdiodone(void *arg) mdiodone(void *arg)
{ {
Ctlr *ctlr = arg; Ctlr *ctlr = arg;
return rr(ctlr, ENET_EIR) & INT_MII; return ctlr->mii->done || (rr(ctlr, ENET_EIR) & INT_MII) != 0;
} }
static int static int
mdiowait(Ctlr *ctlr) mdiowait(Ctlr *ctlr)
@ -265,9 +269,13 @@ mdiow(Mii* mii, int phy, int addr, int data)
Ctlr *ctlr = mii->ctlr; Ctlr *ctlr = mii->ctlr;
data &= 0xFFFF; data &= 0xFFFF;
wr(ctlr, ENET_EIR, INT_MII); 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); 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; return data;
} }
static int static int
@ -276,8 +284,11 @@ mdior(Mii* mii, int phy, int addr)
Ctlr *ctlr = mii->ctlr; Ctlr *ctlr = mii->ctlr;
wr(ctlr, ENET_EIR, INT_MII); 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); 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; return rr(ctlr, ENET_MMFR) & 0xFFFF;
} }
@ -289,11 +300,13 @@ interrupt(Ureg*, void *arg)
u32int e; u32int e;
e = rr(ctlr, ENET_EIR); e = rr(ctlr, ENET_EIR);
wr(ctlr, ENET_EIR, e);
if(e & INT_RXF) wakeup(ctlr->rx); if(e & INT_RXF) wakeup(ctlr->rx);
if(e & INT_TXF) wakeup(ctlr->tx); 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 static void
@ -450,13 +463,11 @@ linkproc(void *arg)
Ether *edev = arg; Ether *edev = arg;
Ctlr *ctlr = edev->ctlr; Ctlr *ctlr = edev->ctlr;
MiiPhy *phy; MiiPhy *phy;
int link = -1; int link = 0;
while(waserror()) while(waserror())
; ;
miiane(ctlr->mii, ~0, ~0, ~0);
miiane(ctlr->mii, ~0, AnaAP|AnaP, ~0);
for(;;){ for(;;){
miistatus(ctlr->mii); miistatus(ctlr->mii);
phy = ctlr->mii->curphy; phy = ctlr->mii->curphy;
@ -505,7 +516,7 @@ linkproc(void *arg)
edev->mbps = phy->speed; edev->mbps = phy->speed;
wr(ctlr, ENET_RDAR, RDAR_ACTIVE); wr(ctlr, ENET_RDAR, RDAR_ACTIVE);
} }
edev->link = link; edev->link = link;
print("#l%d: link %d speed %d\n", edev->ctlrno, edev->link, edev->mbps); 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); wr(ctlr, ENET_RCR, RCR_MII_MODE | RCR_RGMII_EN | Maxtu<<RCR_MAX_FL_SHIFT);
/* set MII clock to 2.5Mhz, 10ns hold time */ /* 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; ctlr->intmask |= INT_MII;
wr(ctlr, ENET_EIMR, ctlr->intmask); wr(ctlr, ENET_EIMR, ctlr->intmask);
@ -586,8 +597,8 @@ attach(Ether *edev)
wr(ctlr, ENET_TFWR, TFWR_STRFWD); wr(ctlr, ENET_TFWR, TFWR_STRFWD);
/* interrupt coalescing: 200 pkts, 1000 µs */ /* 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_RXIC0, IC_EN | 200<<IC_FT_SHIFT | ((1000*Txclk)/64000000)<<IC_TT_SHIFT);
wr(ctlr, ENET_TXIC0, IC_EN | 200<<IC_FT_SHIFT | ((1000*Moduleclk)/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; ctlr->intmask |= INT_TXF | INT_RXF;
wr(ctlr, ENET_EIMR, ctlr->intmask); wr(ctlr, ENET_EIMR, ctlr->intmask);
@ -708,9 +719,9 @@ pnp(Ether *edev)
setclkgate("enet1.ipp_ind_mac0_txclk", 0); setclkgate("enet1.ipp_ind_mac0_txclk", 0);
setclkgate("sim_enet.mainclk", 0); setclkgate("sim_enet.mainclk", 0);
setclkrate("enet1.ipg_clk", "system_pll1_div3", 266*Mhz); setclkrate("enet1.ipg_clk", "system_pll1_div3", Busclk);
setclkrate("enet1.ipp_ind_mac0_txclk", "system_pll2_div8", Moduleclk); setclkrate("enet1.ipp_ind_mac0_txclk", "system_pll2_div8", Txclk);
setclkrate("enet1.ipg_clk_time", "system_pll2_div10", 25*Mhz); setclkrate("enet1.ipg_clk_time", "system_pll2_div10", Ptpclk);
setclkgate("enet1.ipp_ind_mac0_txclk", 1); setclkgate("enet1.ipp_ind_mac0_txclk", 1);
setclkgate("sim_enet.mainclk", 1); setclkgate("sim_enet.mainclk", 1);

View file

@ -87,6 +87,8 @@ miireset(Mii* mii)
if(mii == nil || mii->ctlr == nil || mii->curphy == nil) if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
return -1; return -1;
bmcr = mii->mir(mii, mii->curphy->phyno, Bmcr); bmcr = mii->mir(mii, mii->curphy->phyno, Bmcr);
if(bmcr == -1)
return -1;
bmcr |= BmcrR; bmcr |= BmcrR;
mii->miw(mii, mii->curphy->phyno, Bmcr, bmcr); mii->miw(mii, mii->curphy->phyno, Bmcr, bmcr);
microdelay(1); microdelay(1);
@ -104,6 +106,8 @@ miiane(Mii* mii, int a, int p, int e)
phyno = mii->curphy->phyno; phyno = mii->curphy->phyno;
bmsr = mii->mir(mii, phyno, Bmsr); bmsr = mii->mir(mii, phyno, Bmsr);
if(bmsr == -1)
return -1;
if(!(bmsr & BmsrAna)) if(!(bmsr & BmsrAna))
return -1; return -1;
@ -113,6 +117,8 @@ miiane(Mii* mii, int a, int p, int e)
anar = mii->curphy->anar; anar = mii->curphy->anar;
else{ else{
anar = mii->mir(mii, phyno, Anar); anar = mii->mir(mii, phyno, Anar);
if(anar == -1)
return -1;
anar &= ~(AnaAP|AnaP|AnaT4|AnaTXFD|AnaTXHD|Ana10FD|Ana10HD); anar &= ~(AnaAP|AnaP|AnaT4|AnaTXFD|AnaTXHD|Ana10FD|Ana10HD);
if(bmsr & Bmsr10THD) if(bmsr & Bmsr10THD)
anar |= Ana10HD; anar |= Ana10HD;
@ -133,6 +139,8 @@ miiane(Mii* mii, int a, int p, int e)
if(bmsr & BmsrEs){ if(bmsr & BmsrEs){
mscr = mii->mir(mii, phyno, Mscr); mscr = mii->mir(mii, phyno, Mscr);
if(mscr == -1)
return -1;
mscr &= ~(Mscr1000TFD|Mscr1000THD); mscr &= ~(Mscr1000TFD|Mscr1000THD);
if(e != ~0) if(e != ~0)
mscr |= (Mscr1000TFD|Mscr1000THD) & e; mscr |= (Mscr1000TFD|Mscr1000THD) & e;
@ -140,6 +148,8 @@ miiane(Mii* mii, int a, int p, int e)
mscr = mii->curphy->mscr; mscr = mii->curphy->mscr;
else{ else{
r = mii->mir(mii, phyno, Esr); r = mii->mir(mii, phyno, Esr);
if(r == -1)
return -1;
if(r & Esr1000THD) if(r & Esr1000THD)
mscr |= Mscr1000THD; mscr |= Mscr1000THD;
if(r & Esr1000TFD) if(r & Esr1000TFD)
@ -148,9 +158,12 @@ miiane(Mii* mii, int a, int p, int e)
mii->curphy->mscr = mscr; mii->curphy->mscr = mscr;
mii->miw(mii, phyno, 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); r = mii->mir(mii, phyno, Bmcr);
if(r == -1)
return -1;
if(!(r & BmcrR)){ if(!(r & BmcrR)){
r |= BmcrAne|BmcrRan; r |= BmcrAne|BmcrRan;
mii->miw(mii, phyno, Bmcr, r); mii->miw(mii, phyno, Bmcr, r);
@ -175,12 +188,16 @@ miistatus(Mii* mii)
* (Read status twice as the Ls bit is sticky). * (Read status twice as the Ls bit is sticky).
*/ */
bmsr = mii->mir(mii, phyno, Bmsr); bmsr = mii->mir(mii, phyno, Bmsr);
if(bmsr == -1)
return -1;
if(!(bmsr & (BmsrAnc|BmsrAna))) { if(!(bmsr & (BmsrAnc|BmsrAna))) {
// print("miistatus: auto-neg incomplete\n"); // print("miistatus: auto-neg incomplete\n");
return -1; return -1;
} }
bmsr = mii->mir(mii, phyno, Bmsr); bmsr = mii->mir(mii, phyno, Bmsr);
if(bmsr == -1)
return -1;
if(!(bmsr & BmsrLs)){ if(!(bmsr & BmsrLs)){
// print("miistatus: link down\n"); // print("miistatus: link down\n");
phy->link = 0; phy->link = 0;
@ -190,6 +207,8 @@ miistatus(Mii* mii)
phy->speed = phy->fd = phy->rfc = phy->tfc = 0; phy->speed = phy->fd = phy->rfc = phy->tfc = 0;
if(phy->mscr){ if(phy->mscr){
r = mii->mir(mii, phyno, Mssr); r = mii->mir(mii, phyno, Mssr);
if(r == -1)
return -1;
if((phy->mscr & Mscr1000TFD) && (r & Mssr1000TFD)){ if((phy->mscr & Mscr1000TFD) && (r & Mssr1000TFD)){
phy->speed = 1000; phy->speed = 1000;
phy->fd = 1; phy->fd = 1;
@ -199,6 +218,8 @@ miistatus(Mii* mii)
} }
anlpar = mii->mir(mii, phyno, Anlpar); anlpar = mii->mir(mii, phyno, Anlpar);
if(anlpar == -1)
return -1;
if(phy->speed == 0){ if(phy->speed == 0){
r = phy->anar & anlpar; r = phy->anar & anlpar;
if(r & AnaTXFD){ if(r & AnaTXFD){