ref: f0fc84aba3a40557539e7c014454b916a101759d
parent: 990ceeef3bfd9d56e2e6dd39cf5ac185b1a2de08
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Jun 19 14:07:50 EDT 2022
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.
--- 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 {
Mii;
+ int done;
Rendez;
} mii[1];
@@ -245,7 +249,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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);
--- a/sys/src/9/port/ethermii.c
+++ b/sys/src/9/port/ethermii.c
@@ -87,6 +87,8 @@
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 @@
phyno = mii->curphy->phyno;
bmsr = mii->mir(mii, phyno, Bmsr);
+ if(bmsr == -1)
+ return -1;
if(!(bmsr & BmsrAna))
return -1;
@@ -113,6 +117,8 @@
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 @@
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 @@
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 @@
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,6 +188,8 @@
* (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;
@@ -181,6 +196,8 @@
}
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 @@
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 @@
}
anlpar = mii->mir(mii, phyno, Anlpar);
+ if(anlpar == -1)
+ return -1;
if(phy->speed == 0){
r = phy->anar & anlpar;
if(r & AnaTXFD){