git: 9front

Download patch

ref: 2f411a1a3b137ccbd459682923bdc85afd08c48e
parent: 2a6b2973a234da111bc51464d92a54318babb9c2
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Fri Mar 20 18:09:44 EDT 2026

ethermii: support phy register extension using paging

Some phys extend the available register address
space in custom ways by providing page registers.

To access these registers from devmii, we need to
write the page register first before doing the
normal register access, all while holding the
mii lock so it wont interfere with concurrent
accesses by the driver itself.

This adds a function pointer int (*pagereg)(int *page, int reg)
to the MiiPhy struct, that the driver can set.

This function handles paging, eg. we threat bits [8:23]
of the register as a page number and the pagereg function
returns the paging register and value (in page) to be written.

Some phy's have completely non-standard registers
such as phy 1 on i82579 and upwards that should not
be probed. To still create the MiiPhy entry, provide
a miiphy() function that the driver can call to
create it.

--- a/sys/src/9/port/devmii.c
+++ b/sys/src/9/port/devmii.c
@@ -280,7 +280,7 @@
 	case Qmii:
 		if(len != 2)
 			error(Eshort);
-		if(offset >= 0x20)
+		if(offset & ~0xFFFF1FULL)
 			return 0;
 		miimiw(getphy(c), (int)offset, getword(data));
 		return len;
@@ -318,7 +318,7 @@
 	case Qmii:
 		if(len != 2)
 			error(Eshort);
-		if(offset >= 0x20)
+		if(offset & ~0xFFFF1FULL)
 			return 0;
 		w = miimir(getphy(c), (int)offset);
 		if(w == -1)
--- a/sys/src/9/port/ethermii.c
+++ b/sys/src/9/port/ethermii.c
@@ -15,6 +15,37 @@
 void (*addmiibus)(Mii*) = dummy;
 void (*delmiibus)(Mii*) = dummy;
 
+static MiiPhy*
+newphy(Mii *mii, int phyno)
+{
+	MiiPhy *phy;
+
+	phy = malloc(sizeof(MiiPhy));
+	if(phy == nil)
+		return nil;
+
+	phy->mii = mii;
+	phy->phyno = phyno;
+
+	phy->id = 0;
+	phy->oui = 0;
+
+	phy->anar = ~0;
+	phy->fc = ~0;
+	phy->mscr = ~0;
+
+	phy->pagereg = nil;
+
+	mii->phy[phyno] = phy;
+	if(mii->curphy == nil)
+		mii->curphy = phy;
+
+	mii->mask |= 1<<phyno;
+	mii->nphy++;
+	
+	return phy;
+}
+
 uint
 mii(Mii* mii, uint mask)
 {
@@ -51,24 +82,13 @@
 		if(oui == 0xFFFFF || oui == 0)
 			continue;
 
-		if((phy = malloc(sizeof(MiiPhy))) == nil)
+		phy = newphy(mii, phyno);
+		if(phy == nil)
 			continue;
 
-		phy->mii = mii;
 		phy->id = id;
 		phy->oui = oui;
-		phy->phyno = phyno;
 
-		phy->anar = ~0;
-		phy->fc = ~0;
-		phy->mscr = ~0;
-
-		mii->phy[phyno] = phy;
-		if(mii->curphy == nil)
-			mii->curphy = phy;
-		mii->mask |= bit;
-		mii->nphy++;
-
 		rmask |= bit;
 	}
 
@@ -78,8 +98,42 @@
 	return rmask;
 }
 
+MiiPhy*
+miiphy(Mii *mii, int phyno)
+{
+	MiiPhy *phy;
+
+	assert((uint)phyno < NMiiPhy);
+
+	qlock(mii);
+	if((phy = mii->phy[phyno]) == nil)
+		phy = newphy(mii, phyno);
+	qunlock(mii);
+
+	return phy;
+}
+
+static int
+setpage(MiiPhy *phy, int reg)
+{
+	Mii *mii;
+	int page, preg;
+
+	if(phy->pagereg == nil)
+		return 0;
+
+	page = (reg >> 8) & 0xFFFF;
+	reg &= 0x1F;
+	preg = (*phy->pagereg)(&page, reg);
+	if(preg < 0 || page < 0 || preg == reg)
+		return 0;
+
+	mii = phy->mii;
+	return (*mii->miw)(mii, phy->phyno, preg & 0x1F, page & 0xFFFF);
+}
+
 int
-miimir(MiiPhy *phy, int r)
+miimir(MiiPhy *phy, int reg)
 {
 	Mii *mii;
 	int ret;
@@ -86,12 +140,14 @@
 
 	if(phy == nil || (mii = phy->mii) == nil)
 		return -1;
+
 	qlock(mii);
 	if(up != nil && waserror()){
 		qunlock(mii);
 		nexterror();
 	}
-	ret = (*mii->mir)(mii, phy->phyno, r & 0x1F);
+	if((ret = setpage(phy, reg)) >= 0)
+		ret = (*mii->mir)(mii, phy->phyno, reg & 0x1F);
 	qunlock(mii);
 	if(up != nil) poperror();
 	return ret;
@@ -98,7 +154,7 @@
 }
 
 int
-miimiw(MiiPhy *phy, int r, int data)
+miimiw(MiiPhy *phy, int reg, int data)
 {
 	Mii *mii;
 	int ret;
@@ -110,7 +166,8 @@
 		qunlock(mii);
 		nexterror();
 	}
-	ret = (*mii->miw)(mii, phy->phyno, r & 0x1F, data & 0xFFFF);
+	if((ret = setpage(phy, reg)) >= 0)
+		ret = (*mii->miw)(mii, phy->phyno, reg & 0x1F, data & 0xFFFF);
 	qunlock(mii);
 	if(up != nil) poperror();
 	return ret;
--- a/sys/src/9/port/ethermii.h
+++ b/sys/src/9/port/ethermii.h
@@ -138,9 +138,12 @@
 	int	fd;
 	int	rfc;
 	int	tfc;
+
+	int	(*pagereg)(int*, int);
 };
 
 extern uint mii(Mii*, uint);
+extern MiiPhy* miiphy(Mii*, int);
 extern int miiane(MiiPhy*, int, int, int);
 extern int miianec45(MiiPhy*, int);
 extern int miimir(MiiPhy*, int);
--