summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@felloff.net>2022-06-19 18:07:50 +0000
committercinap_lenrek <cinap_lenrek@felloff.net>2022-06-19 18:07:50 +0000
commitf0fc84aba3a40557539e7c014454b916a101759d (patch)
tree99d2aca21bc90311fc8a1b83cb6298a28eb148b7 /sys
parent990ceeef3bfd9d56e2e6dd39cf5ac185b1a2de08 (diff)
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.
Diffstat (limited to 'sys')
-rw-r--r--sys/src/9/imx8/etherimx.c47
-rw-r--r--sys/src/9/port/ethermii.c23
2 files changed, 51 insertions, 19 deletions
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<<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);
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){