shithub: riscv

Download patch

ref: 11ac75e78995da394d73d3676161fb4c815cf2d4
parent: 3b5e83f164b89f6028dc791ad8f5d373777e5b45
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Jan 5 15:16:14 EST 2025

devether: provide ethersetspeed() function to adjust queue sizes

When the link-speed changes, we want to adjust not
only the output queue limit (done by some drivers)
but also the input queue limit per netif file.

Now, instead of setting Ether->mbps directly,
drivers should call ethersetspeed(ether, mbps).

--- a/sys/src/9/bcm64/ethergenet.c
+++ b/sys/src/9/bcm64/ethergenet.c
@@ -768,7 +768,7 @@
 			REG(ctlr->regs[ExtRgmiiOobCtrl]) = (REG(ctlr->regs[ExtRgmiiOobCtrl]) & ~OobDisable) | RgmiiLink;
 			umaccmd(ctlr, cmd, CmdSpeedMask|CmdHdEn|CmdRxPauseIgn|CmdTxPauseIgn);
 
-			edev->mbps = phy->speed;
+			ethersetspeed(edev, phy->speed);
 		}
 		edev->link = link;
 		// print("#l%d: link %d speed %d\n", edev->ctlrno, edev->link, edev->mbps);
--- a/sys/src/9/cycv/ethercycv.c
+++ b/sys/src/9/cycv/ethercycv.c
@@ -127,20 +127,19 @@
 		}
 		v = mdread(c, MDPHYCTRL);
 		if((v & 0x40) != 0){
-			sp = "1000BASE-T";
 			while((mdread(c, MDGSTATUS) & RECVOK) != RECVOK)
 				;
-			edev->mbps = 1000;
 			c->r[MAC_CONFIG] &= ~(1<<15);
-
+			ethersetspeed(edev, 1000);
+			sp = "1000BASE-T";
 		}else if((v & 0x20) != 0){
-			sp = "100BASE-TX";
-			edev->mbps = 100;
 			c->r[MAC_CONFIG] = c->r[MAC_CONFIG] | (1<<15|1<<14);
+			ethersetspeed(edev, 100);
+			sp = "100BASE-TX";
 		}else if((v & 0x10) != 0){
-			sp = "10BASE-T";
-			edev->mbps = 10;
 			c->r[MAC_CONFIG] = c->r[MAC_CONFIG] & ~(1<<14) | 1<<15;
+			ethersetspeed(edev, 10);
+			sp = "10BASE-T";
 		}else
 			sp = "???";
 		if((v & 0x08) != 0){
--- a/sys/src/9/imx8/etherimx.c
+++ b/sys/src/9/imx8/etherimx.c
@@ -515,7 +515,7 @@
 			wr(ctlr, ENET_RCR, rcr);
 			wr(ctlr, ENET_TCR, tcr);
 
-			edev->mbps = phy->speed;
+			ethersetspeed(edev, phy->speed);
 
 			wr(ctlr, ENET_RDAR, RDAR_ACTIVE);
 		} 
--- a/sys/src/9/kw/ether1116.c
+++ b/sys/src/9/kw/ether1116.c
@@ -1281,7 +1281,7 @@
 		}
 	}
 
-	ether->mbps = phy->speed;
+	ethersetspeed(ether, phy->speed);
 	MIIDBG("#l%d: kirkwoodmii: fd %d speed %d tfc %d rfc %d\n",
 		ctlr->port, phy->fd, phy->speed, phy->tfc, phy->rfc);
 	MIIDBG("mii done\n");
--- a/sys/src/9/pc/ether8139.c
+++ b/sys/src/9/pc/ether8139.c
@@ -646,14 +646,10 @@
 			 */
 			msr = csr8r(ctlr, Msr);
 			if(!(msr & Linkb)){
-				if(!(msr & Speed10) && edev->mbps != 100){
-					edev->mbps = 100;
-					qsetlimit(edev->oq, 256*1024);
-				}
-				else if((msr & Speed10) && edev->mbps != 10){
-					edev->mbps = 10;
-					qsetlimit(edev->oq, 65*1024);
-				}
+				if(msr & Speed10)
+					ethersetspeed(edev, 10);
+				else
+					ethersetspeed(edev, 100);
 			}
 			isr &= ~(Clc|PunLc);
 		}
--- a/sys/src/9/pc/ether8169.c
+++ b/sys/src/9/pc/ether8169.c
@@ -876,7 +876,6 @@
 rtl8169link(Ether* edev)
 {
 	uint r;
-	int limit;
 	Ctlr *ctlr;
 
 	ctlr = edev->ctlr;
@@ -887,18 +886,14 @@
 	 * Could stall transmits if no link, maybe?
 	 */
 	edev->link = (r & Linksts) != 0;
-
-	limit = 256*1024;
-	if(r & Speed10){
-		edev->mbps = 10;
-		limit = 65*1024;
-	} else if(r & Speed100)
-		edev->mbps = 100;
-	else if(r & Speed1000)
-		edev->mbps = 1000;
-
-	if(edev->oq != nil)
-		qsetlimit(edev->oq, limit);
+	if(edev->link){
+		if(r & Speed10)
+			ethersetspeed(edev, 10);
+		else if(r & Speed100)
+			ethersetspeed(edev, 100);
+		else if(r & Speed1000)
+			ethersetspeed(edev, 1000);
+	}
 }
 
 static void
--- a/sys/src/9/pc/ether82563.c
+++ b/sys/src/9/pc/ether82563.c
@@ -1222,10 +1222,11 @@
 		}
 		i = (phy>>8) & 3;
 		e->link = i != 3 && (phy & Link) != 0;
-		if(e->link == 0)
+		if(e->link)
+			ethersetspeed(e, speedtab[i]);
+		else
 			i = 3;
 		c->speeds[i]++;
-		e->mbps = speedtab[i];
 		lsleep(c, Lsc);
 	}
 }
@@ -1278,10 +1279,11 @@
 			phywrite(c, phyno, Phyctl, phyread(c, phyno, Phyctl) | Ran | Ean);
 next:
 		e->link = (phy & Rtlink) != 0;
-		if(e->link == 0)
+		if(e->link)
+			ethersetspeed(e, speedtab[i]);
+		else
 			i = 3;
 		c->speeds[i]++;
-		e->mbps = speedtab[i];
 		if(c->type == i82563)
 			phyerrata(e, c, phyno);
 		lsleep(c, Lsc);
@@ -1306,12 +1308,12 @@
 		phy = csr32r(c, Pcsstat);
 		e->link = phy & Linkok;
 		i = 3;
-		if(e->link)
+		if(e->link){
 			i = (phy & 6) >> 1;
-		else if(phy & Anbad)
+			ethersetspeed(e, speedtab[i]);
+		}else if(phy & Anbad)
 			csr32w(c, Pcsctl, csr32r(c, Pcsctl) | Pan | Prestart);
 		c->speeds[i]++;
-		e->mbps = speedtab[i];
 		lsleep(c, Lsc | Omed);
 	}
 }
@@ -1334,10 +1336,11 @@
 		e->link = (rx & 1<<31) != 0;
 //		e->link = (csr32r(c, Status) & Lu) != 0;
 		i = 3;
-		if(e->link)
+		if(e->link){
 			i = 2;
+			ethersetspeed(e, speedtab[i]);
+		}
 		c->speeds[i]++;
-		e->mbps = speedtab[i];
 		lsleep(c, Lsc);
 	}
 }
--- a/sys/src/9/pc/ether82598.c
+++ b/sys/src/9/pc/ether82598.c
@@ -386,10 +386,11 @@
 		r = c->reg[Links];
 		e->link = (r & Lnkup) != 0;
 		i = 0;
-		if(e->link)
+		if(e->link){
 			i = 1 + ((r & Lnkspd) != 0);
+			ethersetspeed(e, speedtab[i]);
+		}
 		c->speeds[i]++;
-		e->mbps = speedtab[i];
 		c->lim = 0;
 		im(c, Lsc);
 		sleep(&c->lrendez, lim, c);
--- a/sys/src/9/pc/etherbcm.c
+++ b/sys/src/9/pc/etherbcm.c
@@ -331,12 +331,12 @@
 {
 	Ctlr *ctlr;
 	ulong i;
+	int mbps;
 
 	ctlr = edev->ctlr;
 	miir(ctlr, PhyStatus); /* dummy read necessary */
 	if(!(miir(ctlr, PhyStatus) & PhyLinkStatus)) {
 		edev->link = 0;
-		edev->mbps = 1000;
 		ctlr->duplex = 1;
 		print("bcm: no link\n");
 		goto out;
@@ -345,26 +345,26 @@
 	while((miir(ctlr, PhyStatus) & PhyAutoNegComplete) == 0);
 	i = miir(ctlr, PhyGbitStatus);
 	if(i & (Phy1000FD | Phy1000HD)) {
-		edev->mbps = 1000;
+		mbps = 1000;
 		ctlr->duplex = (i & Phy1000FD) != 0;
 	} else if(i = miir(ctlr, PhyPartnerStatus), i & (Phy100FD | Phy100HD)) {
-		edev->mbps = 100;
+		mbps = 100;
 		ctlr->duplex = (i & Phy100FD) != 0;
 	} else if(i & (Phy10FD | Phy10HD)) {
-		edev->mbps = 10;
+		mbps = 10;
 		ctlr->duplex = (i & Phy10FD) != 0;
 	} else {
 		edev->link = 0;
-		edev->mbps = 1000;
 		ctlr->duplex = 1;
 		print("bcm: link partner supports neither 10/100/1000 Mbps\n"); 
 		goto out;
 	}
-	print("bcm: %d Mbps link, %s duplex\n", edev->mbps, ctlr->duplex ? "full" : "half");
+	print("bcm: %d Mbps link, %s duplex\n", mbps, ctlr->duplex ? "full" : "half");
+	ethersetspeed(edev, mbps);
 out:
 	if(ctlr->duplex) csr32(ctlr, MACMode) &= ~MACHalfDuplex;
 	else csr32(ctlr, MACMode) |= MACHalfDuplex;
-	if(edev->mbps >= 1000)
+	if(mbps >= 1000)
 		csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortGMII;
 	else
 		csr32(ctlr, MACMode) = (csr32(ctlr, MACMode) & MACPortMask) | MACPortMII;
--- a/sys/src/9/pc/etherelnk3.c
+++ b/sys/src/9/pc/etherelnk3.c
@@ -1972,7 +1972,7 @@
 		}
 		XCVRDEBUG("mii anar: %uX\n", anar);
 		if(anar & 0x0100){		/* 100BASE-TXFD */
-			ether->mbps = 100;
+			ethersetspeed(ether, 100);
 			setfullduplex(port);
 		}
 		else if(anar & 0x0200){		/* 100BASE-T4 */
@@ -1979,7 +1979,7 @@
 			/* nothing to do */
 		}
 		else if(anar & 0x0080)		/* 100BASE-TX */
-			ether->mbps = 100;
+			ethersetspeed(ether, 100);
 		else if(anar & 0x0040)		/* 10BASE-TFD */
 			setfullduplex(port);
 		else{				/* 10BASE-T */
@@ -1998,7 +1998,7 @@
 		outs(port+MediaStatus, x);
 
 		if(x & dataRate100)
-			ether->mbps = 100;
+			ethersetspeed(ether, 100);
 		break;
 	case xcvr10BaseT:
 		/*
--- a/sys/src/9/pc/etherga620.c
+++ b/sys/src/9/pc/etherga620.c
@@ -581,13 +581,14 @@
 		case 0x06:		/* link state changed */
 			switch (code) {
 			case 1:
-				edev->mbps = 1000;
+				ethersetspeed(edev, 1000);
 				break;
 			case 2:
 				print("#l%d: link down\n", edev->ctlrno);
 				break;
 			case 3:
-				edev->mbps = 100;	/* it's 10 or 100 */
+				/* it's 10 or 100 */
+				ethersetspeed(edev, 100);
 				break;
 			}
 			if (code != 2)
--- a/sys/src/9/pc/etherwpi.c
+++ b/sys/src/9/pc/etherwpi.c
@@ -1586,8 +1586,6 @@
 			error("wifi disabled by switch");
 
 		if(ctlr->wifi == nil){
-			qsetlimit(edev->oq, MaxQueue);
-
 			ctlr->wifi = wifiattach(edev, transmit);
 			ctlr->wifi->rates = wpirates;
 		}
--- a/sys/src/9/pc/etherx550.c
+++ b/sys/src/9/pc/etherx550.c
@@ -348,10 +348,11 @@
 		r = c->reg[Links];
 		e->link = (r & Lnkup) != 0;
 		i = 0;
-		if(e->link)
+		if(e->link){
 			i = 1 + ((r & Lnkspd) != 0);
+			ethersetspeed(e, speedtab[i]);
+		}
 		c->speeds[i]++;
-		e->mbps = speedtab[i];
 		c->lim = 0;
 		im(c, Lsc);
 		sleep(&c->lrendez, lim, c);
--- a/sys/src/9/pc/etheryuk.c
+++ b/sys/src/9/pc/etheryuk.c
@@ -1358,7 +1358,7 @@
 static void
 link(Ether *e)
 {
-	uint i, s, spd;
+	uint i, s;
 	Ctlr *c;
 
 	c = e->ctlr;
@@ -1365,16 +1365,9 @@
 	i = phyread(c, Phyint);
 	s = phyread(c, Phylstat);
 	dprint("#l%d: yuk: link %.8ux %.8ux\n", e->ctlrno, i, s);
-	spd = 0;
 	e->link = (s & Plink) != 0;
-	if(e->link && c->feat&Ffiber)
-		spd = 1000;
-	else if(e->link){
-		spd = s & Physpd;
-		spd >>= 14;
-		spd = spdtab[spd];
-	}
-	e->mbps = spd;
+	if(e->link)
+		ethersetspeed(e, (c->feat&Ffiber)? 1000: spdtab[(s & Physpd) >> 14]);
 	dprint("#l%d: yuk: link %d spd %d\n", e->ctlrno, e->link, e->mbps);
 }
 
--- a/sys/src/9/port/devether.c
+++ b/sys/src/9/port/devether.c
@@ -373,11 +373,31 @@
 	ncard++;
 }
 
+static int
+etherqueuesize(Ether *ether)
+{
+	int lg, mb;
+	ulong bsz;
+
+	/* compute log10(mbps) into lg */
+	for(lg = 0, mb = ether->mbps; mb >= 10; lg++)
+		mb /= 10;
+	if (lg > 0)
+		lg--;
+	if (lg > 14)			/* 2^(14+17) = 2³¹ */
+		lg = 14;
+	/* allocate larger output queues for higher-speed interfaces */
+	bsz = 1UL << (lg + 17);		/* 2¹⁷ = 128K, bsz = 2ⁿ × 128K */
+	while (bsz > mainmem->maxsize / 8 && bsz > 128*1024)
+		bsz /= 2;
+if(0) print("#l%d: %d Mbps -> queue size %lud\n", ether->ctlrno, ether->mbps, bsz);
+	return (int)bsz;
+}
+
 static Ether*
 etherprobe(int cardno, int ctlrno, char *conf)
 {
-	int i, lg;
-	ulong mb, bsz;
+	int i;
 	Ether *ether;
 
 	ether = malloc(sizeof(Ether));
@@ -430,31 +450,31 @@
 	print("#l%d: %s: %dMbps port 0x%lluX irq %d ea %E\n",
 		ctlrno, ether->type, ether->mbps, (uvlong)ether->port, ether->irq, ether->ea);
 
-	/* compute log10(ether->mbps) into lg */
-	for(lg = 0, mb = ether->mbps; mb >= 10; lg++)
-		mb /= 10;
-	if (lg > 0)
-		lg--;
-	if (lg > 14)			/* 2^(14+17) = 2³¹ */
-		lg = 14;
-	/* allocate larger output queues for higher-speed interfaces */
-	bsz = 1UL << (lg + 17);		/* 2¹⁷ = 128K, bsz = 2ⁿ × 128K */
-	while (bsz > mainmem->maxsize / 8 && bsz > 128*1024)
-		bsz /= 2;
-
-	netifinit(ether, ether->name, Ntypes, bsz);
-	if(ether->oq == nil) {
-		ether->oq = qopen(bsz, Qmsg, 0, 0);
-		ether->limit = bsz;
+	netifinit(ether, ether->name, Ntypes, etherqueuesize(ether));
+	if(ether->oq == nil){
+		ether->oq = qopen(ether->limit, Qmsg, 0, 0);
+		if(ether->oq == nil)
+			panic("etherreset %s: can't allocate output queue", ether->name);
+	} else {
+		qsetlimit(ether->oq, ether->limit);
 	}
-	if(ether->oq == nil)
-		panic("etherreset %s: can't allocate output queue of %ld bytes", ether->name, bsz);
-
 	ether->alen = Eaddrlen;
 	memmove(ether->addr, ether->ea, Eaddrlen);
 	memset(ether->bcast, 0xFF, Eaddrlen);
 
 	return ether;
+}
+
+void
+ethersetspeed(Ether *ether, int mbps)
+{
+	if(ether->mbps == mbps)
+		return;
+	ether->mbps = mbps;
+	if(mbps <= 0 || ether->oq == nil)
+		return;
+	netifsetlimit(ether, etherqueuesize(ether));
+	qsetlimit(ether->oq, ether->limit);
 }
 
 static void netconsole(int);
--- a/sys/src/9/port/etherif.h
+++ b/sys/src/9/port/etherif.h
@@ -51,6 +51,7 @@
 	DMAT*	dmat;
 };
 
+extern void ethersetspeed(Ether*, int);
 extern void etheriq(Ether*, Block*);
 extern void addethercard(char*, int(*)(Ether*));
 extern ulong ethercrc(uchar*, int);
--- a/sys/src/9/port/etheriwl.c
+++ b/sys/src/9/port/etheriwl.c
@@ -4103,8 +4103,6 @@
 			error(err);
 
 		if(ctlr->wifi == nil){
-			qsetlimit(edev->oq, MaxQueue);
-
 			ctlr->wifi = wifiattach(edev, transmit);
 			/* tested with 2230, it has transmit issues using higher bit rates */
 			if(ctlr->family >= 7000 || ctlr->type != Type2030)
--- a/sys/src/9/port/netif.c
+++ b/sys/src/9/port/netif.c
@@ -16,7 +16,7 @@
  *  set up a new network interface
  */
 void
-netifinit(Netif *nif, char *name, int nfile, ulong limit)
+netifinit(Netif *nif, char *name, int nfile, int limit)
 {
 	if(strlen(name) >= sizeof nif->name)
 		panic("netifinit: name too long: %s", name);
@@ -27,6 +27,28 @@
 		panic("netifinit: no memory");
 	memset(nif->f, 0, nfile*sizeof(Netfile*));
 	nif->limit = limit;
+}
+
+/*
+ * adjust input queue sizes for all files
+ */
+void
+netifsetlimit(Netif *nif, int limit)
+{
+	Netfile *f;
+	int i;
+
+	qlock(nif);
+	nif->limit = limit;
+	for(i = 0; i < nif->nfile; i++){
+		f = nif->f[i];
+		if(f == nil)
+			continue;
+		qlock(f);
+		qsetlimit(f->in, nif->limit);
+		qunlock(f);
+	}
+	qunlock(nif);
 }
 
 /*
--- a/sys/src/9/port/netif.h
+++ b/sys/src/9/port/netif.h
@@ -108,7 +108,8 @@
 	char*	(*ifstat)(void*, char*, char*);
 };
 
-void	netifinit(Netif*, char*, int, ulong);
+void	netifinit(Netif*, char*, int, int);
+void	netifsetlimit(Netif *, int);
 Walkqid*	netifwalk(Netif*, Chan*, Chan*, char **, int);
 Chan*	netifopen(Netif*, Chan*, int);
 void	netifclose(Netif*, Chan*);
--- a/sys/src/9/port/wifi.c
+++ b/sys/src/9/port/wifi.c
@@ -817,7 +817,7 @@
 	while((wn = wifi->bss) != nil){
 		ether->link = (wn->status == Sassoc) || (wn->status == Sblocked);
 		if(ether->link && (rate = wn->actrate) != nil)
-			ether->mbps = ((*rate & 0x7f)+3)/4;
+			ethersetspeed(ether, ((*rate & 0x7f)+3)/4);
 		now = MACHP(0)->ticks;
 		if(wn->status != Sneedauth && TK2SEC(now - wn->lastseen) > 20 || goodbss(wifi, wn) == 0){
 			wifideauth(wifi, wn);
--- a/sys/src/9/ppc/etherfcc.c
+++ b/sys/src/9/ppc/etherfcc.c
@@ -870,7 +870,7 @@
 		print("link lost\n");
 		return;
 	}
-	ether->mbps = phy->speed;
+	ethersetspeed(ether, phy->speed);
 
 	if(phy->fd != ctlr->duplex)
 		print("set duplex\n");
--- a/sys/src/9/teg2/ether8169.c
+++ b/sys/src/9/teg2/ether8169.c
@@ -1275,7 +1275,6 @@
 rtl8169link(Ether* edev)
 {
 	uint r;
-	int limit;
 	Ctlr *ctlr;
 
 	ctlr = edev->ctlr;
@@ -1288,22 +1287,17 @@
 		}
 		return;
 	}
-	if (edev->link == 0) {
+	if(edev->link == 0) {
 		edev->link = 1;
 		csr8w(ctlr, Cr, Te|Re);
 		iprint("#l%d: link up\n", edev->ctlrno);
 	}
-	limit = 256*1024;
-	if(r & Speed10){
-		edev->mbps = 10;
-		limit = 65*1024;
-	} else if(r & Speed100)
-		edev->mbps = 100;
+	if(r & Speed10)
+		ethersetspeed(edev, 10);
+	else if(r & Speed100)
+		ethersetspeed(edev, 100);
 	else if(r & Speed1000)
-		edev->mbps = 1000;
-
-	if(edev->oq != nil)
-		qsetlimit(edev->oq, limit);
+		ethersetspeed(edev, 1000);
 }
 
 static void
--- a/sys/src/9/zynq/etherzynq.c
+++ b/sys/src/9/zynq/etherzynq.c
@@ -159,19 +159,19 @@
 			sp = "1000BASE-T";
 			while((mdread(c, MDGSTATUS) & RECVOK) != RECVOK)
 				;
-			edev->mbps = 1000;
 			c->r[NET_CFG] |= GIGE_EN;
 			slcr[GEM0_CLK_CTRL] = 1 << 20 | 8 << 8 | 1;
+			ethersetspeed(edev, 1000);
 		}else if((v & 0x20) != 0){
 			sp = "100BASE-TX";
-			edev->mbps = 100;
 			c->r[NET_CFG] = c->r[NET_CFG] & ~GIGE_EN | SPEED;
 			slcr[GEM0_CLK_CTRL] = 5 << 20 | 8 << 8 | 1;
+			ethersetspeed(edev, 100);
 		}else if((v & 0x10) != 0){
 			sp = "10BASE-T";
-			edev->mbps = 10;
 			c->r[NET_CFG] = c->r[NET_CFG] & ~(GIGE_EN | SPEED);
 			slcr[GEM0_CLK_CTRL] = 20 << 20 | 20 << 8 | 1;
+			ethersetspeed(edev, 10);
 		}else
 			sp = "???";
 		if((v & 0x08) != 0){
--