shithub: riscv

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
+++ 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){