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;
@ -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){