shithub: plan9front

Download patch

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	Sat Jun 18 19:37:12 2022
+++ b/sys/src/9/imx8/etherimx.c	Sun Jun 19 14:07:50 2022
@@ -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	Sat Jun 18 19:37:12 2022
+++ b/sys/src/9/port/ethermii.c	Sun Jun 19 14:07:50 2022
@@ -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,12 +188,16 @@
 	 * (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 @@
 	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){