ref: 4160504d0abf308a1230a52099af6394267055ec
parent: 2f411a1a3b137ccbd459682923bdc85afd08c48e
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Fri Mar 20 18:18:56 EDT 2026
ether82563: use ethermii for phy access This lets us access phy registers using devmii for debugging and diagnostics.
--- a/sys/src/9/pc/ether82563.c
+++ b/sys/src/9/pc/ether82563.c
@@ -13,6 +13,7 @@
#include "../port/error.h"
#include "../port/netif.h"
#include "../port/etherif.h"
+#include "../port/ethermii.h"
/*
* note: the 82575, 82576 and 82580 are operated using registers aliased
@@ -175,25 +176,15 @@
};
enum { /* phy interface */- Phyctl = 0, /* phy ctl register */
- Physr = 1, /* phy status register */
- Phyid1 = 2, /* phy id1 */
- Phyid2 = 3, /* phy id2 */
Phyisr = 19, /* 82563 phy interrupt status register */
Phylhr = 19, /* 8257[12] link health register */
Physsr = 17, /* phy secondary status register */
Phyprst = 193<<8 | 17, /* 8256[34] phy port reset */
Phyier = 18, /* 82573 phy interrupt enable register */
- Phypage = 22, /* 8256[34] page register */
Phystat = 26, /* 82580 phy status */
- Phyapage = 29,
Rtlink = 1<<10, /* realtime link status */
Phyan = 1<<11, /* phy has autonegotiated */
- /* Phyctl bits */
- Ran = 1<<9, /* restart auto negotiation */
- Ean = 1<<12, /* enable auto negotiation */
-
/* Phyprst bits */
Prst = 1<<0, /* reset the port */
@@ -526,6 +517,7 @@
Proc *lproc;
Rendez lrendez;
int lim;
+ Mii mii;
QLock slock;
u32int statistics[Nstatistics];
@@ -1127,9 +1119,10 @@
10, 100, 1000, 0
};
-static uint
-phyread(Ctlr *c, int phyno, int reg)
+static int
+mir(Mii *mii, int phyno, int reg)
{+ Ctlr *c = mii->ctlr;
uint phy, i;
csr32w(c, Mdic, MDIrop | phyno<<MDIpSHIFT | reg<<MDIrSHIFT);
@@ -1140,16 +1133,15 @@
break;
microdelay(1);
}
- if((phy & (MDIe|MDIready)) != MDIready){- print("#l%d: %s: phy %d wedged %.8ux\n", c->edev->ctlrno, cname(c), phyno, phy);- return ~0;
- }
+ if((phy & (MDIe|MDIready)) != MDIready)
+ return -1;
return phy & 0xffff;
}
-static uint
-phywrite0(Ctlr *c, int phyno, int reg, ushort val)
+static int
+miw(Mii *mii, int phyno, int reg, int val)
{+ Ctlr *c = mii->ctlr;
uint phy, i;
csr32w(c, Mdic, MDIwop | phyno<<MDIpSHIFT | reg<<MDIrSHIFT | val);
@@ -1161,43 +1153,18 @@
microdelay(1);
}
if((phy & (MDIe|MDIready)) != MDIready)
- return ~0;
+ return -1;
return 0;
}
-static uint
-setpage(Ctlr *c, uint phyno, uint p, uint r)
-{- uint pr;
-
- if(c->type == i82563){- if(r >= 16 && r <= 28 && r != 22)
- pr = Phypage;
- else if(r == 30 || r == 31)
- pr = Phyapage;
- else
- return 0;
- return phywrite0(c, phyno, pr, p);
- }else if(p == 0)
- return 0;
- return ~0;
-}
-
-static uint
-phywrite(Ctlr *c, uint phyno, uint reg, ushort v)
-{- if(setpage(c, phyno, reg>>8, reg & 0xff) == ~0)
- panic("#l%d: %s: bad phy reg %.4ux", c->edev->ctlrno, cname(c), reg);- return phywrite0(c, phyno, reg & 0xff, v);
-}
-
static void
-phyerrata(Ctlr *c, uint phyno)
+phyerrata(Ctlr *c, MiiPhy *p)
{ if(c->edev->mbps == 0){ if(c->phyerrata == 0){c->phyerrata++;
- phywrite(c, phyno, Phyprst, Prst); /* try a port reset */
+
+ miimiw(p, Phyprst, Prst);
print("#l%d: %s: phy port reset\n", c->edev->ctlrno, cname(c));}
}else
@@ -1204,28 +1171,6 @@
c->phyerrata = 0;
}
-static uint
-phyprobe(Ctlr *c, uint mask)
-{- uint phy, phyno;
-
- for(phyno=0; mask != 0; phyno++, mask>>=1){- if((mask & 1) == 0)
- continue;
- if(phyread(c, phyno, Physr) == ~0)
- continue;
- phy = (phyread(c, phyno, Phyid1) & 0x3FFF)<<6;
- phy |= phyread(c, phyno, Phyid2) >> 10;
- if(phy == 0xFFFFF || phy == 0)
- continue;
- print("#l%d: %s: phy%d oui %#ux\n", c->edev->ctlrno, cname(c),- phyno, phy);
- return phyno;
- }
- print("#l%d: %s: no phy\n", c->edev->ctlrno, cname(c));- return ~0;
-}
-
static void
lsleep(Ctlr *c, uint m)
{@@ -1235,12 +1180,27 @@
sleep(&c->lrendez, i82563lim, c);
}
+/*
+ * Phy address 1 uses page register 31. Note that pageno
+ * is 11 bits and number must be written as (page << 5)
+ * into the 16-bit page register.
+ */
+static int
+i82579phy1pagereg(int *page, int reg)
+{+ if(reg < 16)
+ return -1;
+ *page <<= 5;
+ return 31;
+}
+
static void
phyl79proc(void *v)
{- uint i, r, phy, phyno;
Ctlr *c;
Ether *e;
+ MiiPhy *p;
+ int i, r;
e = v;
c = e->ctlr;
@@ -1254,26 +1214,34 @@
lsleep(c, Lsc);
tsleep(&up->sleep, return0, 0, 1500);
- while((phyno = phyprobe(c, 3<<1)) == ~0)
+ /*
+ * Phy registers are spread over two phy addresses 1 and 2.
+ * Phy address 2 contains the ID registers.
+ */
+ while(mii(&c->mii, 1<<2) <= 0 || (p = c->mii.curphy) == nil)
lsleep(c, Lsc);
+ miiphy(&c->mii, 1)->pagereg = i82579phy1pagereg;
+
+ addmiibus(&c->mii);
+
for(;;){- phy = 0;
+ r = 0;
for(i=0; i<4; i++){tsleep(&up->sleep, return0, 0, 150);
- phy = phyread(c, phyno, Phystat);
- if(phy == ~0)
+ r = miimir(p, Phystat);
+ if(r < 0)
continue;
- if(phy & Ans){- r = phyread(c, phyno, Phyctl);
- if(r == ~0)
+ if(r & Ans){+ r = miimir(p, Bmcr);
+ if(r < 0)
continue;
- phywrite(c, phyno, Phyctl, r | Ran | Ean);
+ miimiw(p, Bmcr, r | BmcrRan|BmcrAne);
}
break;
}
- i = (phy>>8) & 3;
- if(i != 3 && (phy & Link) != 0){+ i = (r>>8) & 3;
+ if(i != 3 && (r & Link) != 0){ethersetspeed(e, speedtab[i]);
ethersetlink(e, 1);
}else{@@ -1285,12 +1253,25 @@
}
}
+static int
+i82563pagereg(int*, int reg)
+{+ if(reg >= 30)
+ return 29;
+
+ if(reg >= 16 && reg != 22 && reg != 29)
+ return 22;
+
+ return -1;
+}
+
static void
phylproc(void *v)
{- uint a, i, phy, phyno;
Ctlr *c;
Ether *e;
+ MiiPhy *p;
+ int i, r, a;
e = v;
c = e->ctlr;
@@ -1299,20 +1280,25 @@
while(waserror())
procerror(c, &c->lproc);
- while((phyno = phyprobe(c, 3<<1)) == ~0)
+ while(mii(&c->mii, 3<<1) <= 0 || (p = c->mii.curphy) == nil)
lsleep(c, Lsc);
- if(c->type == i82573 && (phy = phyread(c, phyno, Phyier)) != ~0)
- phywrite(c, phyno, Phyier, phy | Lscie | Ancie | Spdie | Panie);
+ if(c->type == i82563)
+ p->pagereg = i82563pagereg;
+ addmiibus(&c->mii);
+
+ if(c->type == i82573 && (r = miimir(p, Phyier)) >= 0)
+ miimiw(p, Phyier, r | Lscie | Ancie | Spdie | Panie);
+
for(;;){- phy = phyread(c, phyno, Physsr);
- if(phy == ~0){- phy = 0;
+ r = miimir(p, Physsr);
+ if(r < 0){+ r = 0;
i = 3;
goto next;
}
- i = (phy>>14) & 3;
+ i = (r>>14) & 3;
switch(c->type){default:
a = 0;
@@ -1321,20 +1307,20 @@
case i82578:
case i82578m:
case i82583:
- a = phyread(c, phyno, Phyisr) & Ane;
+ a = miimir(p, Phyisr) & Ane;
break;
case i82571:
case i82572:
case i82575:
case i82576:
- a = phyread(c, phyno, Phylhr) & Anf;
+ a = miimir(p, Phylhr) & Anf;
i = (i-1) & 3;
break;
}
if(a)
- phywrite(c, phyno, Phyctl, phyread(c, phyno, Phyctl) | Ran | Ean);
+ miimiw(p, Bmcr, miimir(p, Bmcr) | BmcrRan|BmcrAne);
next:
- if(phy & Rtlink){+ if(r & Rtlink){ethersetspeed(e, speedtab[i]);
ethersetlink(e, 1);
}else{@@ -1343,7 +1329,7 @@
}
c->speeds[i]++;
if(c->type == i82563)
- phyerrata(c, phyno);
+ phyerrata(c, p);
lsleep(c, Lsc);
}
}
@@ -2269,6 +2255,11 @@
break;
}
}
+
+ ctlr->mii.name = edev->name;
+ ctlr->mii.ctlr = ctlr;
+ ctlr->mii.mir = mir;
+ ctlr->mii.miw = miw;
edev->ctlr = ctlr;
edev->port = ctlr->port;
--- a/sys/src/9/pc/mkfile
+++ b/sys/src/9/pc/mkfile
@@ -135,6 +135,7 @@
trap.$O main.$O: /sys/include/tos.h
uartaxp.$O: uartaxp.i
ether8169.$O: ../port/ethermii.h
+ether82563.$O: ../port/ethermii.h
etherdp83820.$O: ../port/ethermii.h
etheri225.$O: ../port/ethermii.h
etherigbe.$O: ../port/ethermii.h
--- a/sys/src/9/pc/pc
+++ b/sys/src/9/pc/pc
@@ -56,7 +56,7 @@
ether8139 pci
ether8169 pci ethermii
ether82557 pci
- ether82563 pci
+ ether82563 pci ethermii
ether82598 pci
ether83815 pci
etherx550 pci
--- a/sys/src/9/pc64/mkfile
+++ b/sys/src/9/pc64/mkfile
@@ -142,6 +142,7 @@
trap.$O main.$O: /sys/include/tos.h
ether8169.$O: ../port/ethermii.h
+ether82563.$O: ../port/ethermii.h
etherdp83820.$O: ../port/ethermii.h
etheri225.$O: ../port/ethermii.h
etherigbe.$O: ../port/ethermii.h
--- a/sys/src/9/pc64/pc64
+++ b/sys/src/9/pc64/pc64
@@ -56,7 +56,7 @@
# should be obsoleted by igbe
# ether82543gc pci
# ether82557 pci
- ether82563 pci
+ ether82563 pci ethermii
ether82598 pci
etherx550 pci
# ether83815 pci
--
⑨