From f0fc84aba3a40557539e7c014454b916a101759d Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sun, 19 Jun 2022 18:07:50 +0000 Subject: 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. --- sys/src/9/imx8/etherimx.c | 47 +++++++++++++++++++++++++++++------------------ sys/src/9/port/ethermii.c | 23 ++++++++++++++++++++++- 2 files changed, 51 insertions(+), 19 deletions(-) (limited to 'sys/src') diff --git a/sys/src/9/imx8/etherimx.c b/sys/src/9/imx8/etherimx.c index 2f3d8ed28..9b816920f 100644 --- a/sys/src/9/imx8/etherimx.c +++ b/sys/src/9/imx8/etherimx.c @@ -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<ctlr; wr(ctlr, ENET_EIR, INT_MII); + ctlr->mii->done = 0; + wr(ctlr, ENET_MMFR, MMFR_RD | MMFR_ST | MMFR_TA | phy<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<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<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); diff --git a/sys/src/9/port/ethermii.c b/sys/src/9/port/ethermii.c index d75c35072..dcb3915e2 100644 --- a/sys/src/9/port/ethermii.c +++ b/sys/src/9/port/ethermii.c @@ -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){ -- cgit v1.2.3