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.
This commit is contained in:
parent
990ceeef3b
commit
f0fc84aba3
2 changed files with 51 additions and 19 deletions
|
@ -9,7 +9,10 @@
|
||||||
#include "../port/ethermii.h"
|
#include "../port/ethermii.h"
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
Moduleclk = 125000000, /* 125Mhz */
|
Ptpclk = 100*Mhz,
|
||||||
|
Busclk = 266*Mhz,
|
||||||
|
Txclk = 125*Mhz,
|
||||||
|
|
||||||
Maxtu = 1518,
|
Maxtu = 1518,
|
||||||
|
|
||||||
R_BUF_SIZE = ((Maxtu+BLOCKALIGN-1)&~BLOCKALIGN),
|
R_BUF_SIZE = ((Maxtu+BLOCKALIGN-1)&~BLOCKALIGN),
|
||||||
|
@ -231,6 +234,7 @@ struct Ctlr
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
Mii;
|
Mii;
|
||||||
|
int done;
|
||||||
Rendez;
|
Rendez;
|
||||||
} mii[1];
|
} mii[1];
|
||||||
|
|
||||||
|
@ -245,7 +249,7 @@ static int
|
||||||
mdiodone(void *arg)
|
mdiodone(void *arg)
|
||||||
{
|
{
|
||||||
Ctlr *ctlr = arg;
|
Ctlr *ctlr = arg;
|
||||||
return rr(ctlr, ENET_EIR) & INT_MII;
|
return ctlr->mii->done || (rr(ctlr, ENET_EIR) & INT_MII) != 0;
|
||||||
}
|
}
|
||||||
static int
|
static int
|
||||||
mdiowait(Ctlr *ctlr)
|
mdiowait(Ctlr *ctlr)
|
||||||
|
@ -265,9 +269,13 @@ mdiow(Mii* mii, int phy, int addr, int data)
|
||||||
Ctlr *ctlr = mii->ctlr;
|
Ctlr *ctlr = mii->ctlr;
|
||||||
|
|
||||||
data &= 0xFFFF;
|
data &= 0xFFFF;
|
||||||
|
|
||||||
wr(ctlr, ENET_EIR, INT_MII);
|
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);
|
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;
|
return data;
|
||||||
}
|
}
|
||||||
static int
|
static int
|
||||||
|
@ -276,8 +284,11 @@ mdior(Mii* mii, int phy, int addr)
|
||||||
Ctlr *ctlr = mii->ctlr;
|
Ctlr *ctlr = mii->ctlr;
|
||||||
|
|
||||||
wr(ctlr, ENET_EIR, INT_MII);
|
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);
|
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;
|
return rr(ctlr, ENET_MMFR) & 0xFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,11 +300,13 @@ interrupt(Ureg*, void *arg)
|
||||||
u32int e;
|
u32int e;
|
||||||
|
|
||||||
e = rr(ctlr, ENET_EIR);
|
e = rr(ctlr, ENET_EIR);
|
||||||
wr(ctlr, ENET_EIR, e);
|
|
||||||
|
|
||||||
if(e & INT_RXF) wakeup(ctlr->rx);
|
if(e & INT_RXF) wakeup(ctlr->rx);
|
||||||
if(e & INT_TXF) wakeup(ctlr->tx);
|
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
|
static void
|
||||||
|
@ -450,13 +463,11 @@ linkproc(void *arg)
|
||||||
Ether *edev = arg;
|
Ether *edev = arg;
|
||||||
Ctlr *ctlr = edev->ctlr;
|
Ctlr *ctlr = edev->ctlr;
|
||||||
MiiPhy *phy;
|
MiiPhy *phy;
|
||||||
int link = -1;
|
int link = 0;
|
||||||
|
|
||||||
while(waserror())
|
while(waserror())
|
||||||
;
|
;
|
||||||
|
miiane(ctlr->mii, ~0, ~0, ~0);
|
||||||
miiane(ctlr->mii, ~0, AnaAP|AnaP, ~0);
|
|
||||||
|
|
||||||
for(;;){
|
for(;;){
|
||||||
miistatus(ctlr->mii);
|
miistatus(ctlr->mii);
|
||||||
phy = ctlr->mii->curphy;
|
phy = ctlr->mii->curphy;
|
||||||
|
@ -532,7 +543,7 @@ attach(Ether *edev)
|
||||||
wr(ctlr, ENET_RCR, RCR_MII_MODE | RCR_RGMII_EN | Maxtu<<RCR_MAX_FL_SHIFT);
|
wr(ctlr, ENET_RCR, RCR_MII_MODE | RCR_RGMII_EN | Maxtu<<RCR_MAX_FL_SHIFT);
|
||||||
|
|
||||||
/* set MII clock to 2.5Mhz, 10ns hold time */
|
/* 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;
|
ctlr->intmask |= INT_MII;
|
||||||
wr(ctlr, ENET_EIMR, ctlr->intmask);
|
wr(ctlr, ENET_EIMR, ctlr->intmask);
|
||||||
|
@ -586,8 +597,8 @@ attach(Ether *edev)
|
||||||
wr(ctlr, ENET_TFWR, TFWR_STRFWD);
|
wr(ctlr, ENET_TFWR, TFWR_STRFWD);
|
||||||
|
|
||||||
/* interrupt coalescing: 200 pkts, 1000 µs */
|
/* 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_RXIC0, IC_EN | 200<<IC_FT_SHIFT | ((1000*Txclk)/64000000)<<IC_TT_SHIFT);
|
||||||
wr(ctlr, ENET_TXIC0, IC_EN | 200<<IC_FT_SHIFT | ((1000*Moduleclk)/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;
|
ctlr->intmask |= INT_TXF | INT_RXF;
|
||||||
wr(ctlr, ENET_EIMR, ctlr->intmask);
|
wr(ctlr, ENET_EIMR, ctlr->intmask);
|
||||||
|
@ -708,9 +719,9 @@ pnp(Ether *edev)
|
||||||
setclkgate("enet1.ipp_ind_mac0_txclk", 0);
|
setclkgate("enet1.ipp_ind_mac0_txclk", 0);
|
||||||
setclkgate("sim_enet.mainclk", 0);
|
setclkgate("sim_enet.mainclk", 0);
|
||||||
|
|
||||||
setclkrate("enet1.ipg_clk", "system_pll1_div3", 266*Mhz);
|
setclkrate("enet1.ipg_clk", "system_pll1_div3", Busclk);
|
||||||
setclkrate("enet1.ipp_ind_mac0_txclk", "system_pll2_div8", Moduleclk);
|
setclkrate("enet1.ipp_ind_mac0_txclk", "system_pll2_div8", Txclk);
|
||||||
setclkrate("enet1.ipg_clk_time", "system_pll2_div10", 25*Mhz);
|
setclkrate("enet1.ipg_clk_time", "system_pll2_div10", Ptpclk);
|
||||||
|
|
||||||
setclkgate("enet1.ipp_ind_mac0_txclk", 1);
|
setclkgate("enet1.ipp_ind_mac0_txclk", 1);
|
||||||
setclkgate("sim_enet.mainclk", 1);
|
setclkgate("sim_enet.mainclk", 1);
|
||||||
|
|
|
@ -87,6 +87,8 @@ miireset(Mii* mii)
|
||||||
if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
|
if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
|
||||||
return -1;
|
return -1;
|
||||||
bmcr = mii->mir(mii, mii->curphy->phyno, Bmcr);
|
bmcr = mii->mir(mii, mii->curphy->phyno, Bmcr);
|
||||||
|
if(bmcr == -1)
|
||||||
|
return -1;
|
||||||
bmcr |= BmcrR;
|
bmcr |= BmcrR;
|
||||||
mii->miw(mii, mii->curphy->phyno, Bmcr, bmcr);
|
mii->miw(mii, mii->curphy->phyno, Bmcr, bmcr);
|
||||||
microdelay(1);
|
microdelay(1);
|
||||||
|
@ -104,6 +106,8 @@ miiane(Mii* mii, int a, int p, int e)
|
||||||
phyno = mii->curphy->phyno;
|
phyno = mii->curphy->phyno;
|
||||||
|
|
||||||
bmsr = mii->mir(mii, phyno, Bmsr);
|
bmsr = mii->mir(mii, phyno, Bmsr);
|
||||||
|
if(bmsr == -1)
|
||||||
|
return -1;
|
||||||
if(!(bmsr & BmsrAna))
|
if(!(bmsr & BmsrAna))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -113,6 +117,8 @@ miiane(Mii* mii, int a, int p, int e)
|
||||||
anar = mii->curphy->anar;
|
anar = mii->curphy->anar;
|
||||||
else{
|
else{
|
||||||
anar = mii->mir(mii, phyno, Anar);
|
anar = mii->mir(mii, phyno, Anar);
|
||||||
|
if(anar == -1)
|
||||||
|
return -1;
|
||||||
anar &= ~(AnaAP|AnaP|AnaT4|AnaTXFD|AnaTXHD|Ana10FD|Ana10HD);
|
anar &= ~(AnaAP|AnaP|AnaT4|AnaTXFD|AnaTXHD|Ana10FD|Ana10HD);
|
||||||
if(bmsr & Bmsr10THD)
|
if(bmsr & Bmsr10THD)
|
||||||
anar |= Ana10HD;
|
anar |= Ana10HD;
|
||||||
|
@ -133,6 +139,8 @@ miiane(Mii* mii, int a, int p, int e)
|
||||||
|
|
||||||
if(bmsr & BmsrEs){
|
if(bmsr & BmsrEs){
|
||||||
mscr = mii->mir(mii, phyno, Mscr);
|
mscr = mii->mir(mii, phyno, Mscr);
|
||||||
|
if(mscr == -1)
|
||||||
|
return -1;
|
||||||
mscr &= ~(Mscr1000TFD|Mscr1000THD);
|
mscr &= ~(Mscr1000TFD|Mscr1000THD);
|
||||||
if(e != ~0)
|
if(e != ~0)
|
||||||
mscr |= (Mscr1000TFD|Mscr1000THD) & e;
|
mscr |= (Mscr1000TFD|Mscr1000THD) & e;
|
||||||
|
@ -140,6 +148,8 @@ miiane(Mii* mii, int a, int p, int e)
|
||||||
mscr = mii->curphy->mscr;
|
mscr = mii->curphy->mscr;
|
||||||
else{
|
else{
|
||||||
r = mii->mir(mii, phyno, Esr);
|
r = mii->mir(mii, phyno, Esr);
|
||||||
|
if(r == -1)
|
||||||
|
return -1;
|
||||||
if(r & Esr1000THD)
|
if(r & Esr1000THD)
|
||||||
mscr |= Mscr1000THD;
|
mscr |= Mscr1000THD;
|
||||||
if(r & Esr1000TFD)
|
if(r & Esr1000TFD)
|
||||||
|
@ -148,9 +158,12 @@ miiane(Mii* mii, int a, int p, int e)
|
||||||
mii->curphy->mscr = mscr;
|
mii->curphy->mscr = mscr;
|
||||||
mii->miw(mii, phyno, 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);
|
r = mii->mir(mii, phyno, Bmcr);
|
||||||
|
if(r == -1)
|
||||||
|
return -1;
|
||||||
if(!(r & BmcrR)){
|
if(!(r & BmcrR)){
|
||||||
r |= BmcrAne|BmcrRan;
|
r |= BmcrAne|BmcrRan;
|
||||||
mii->miw(mii, phyno, Bmcr, r);
|
mii->miw(mii, phyno, Bmcr, r);
|
||||||
|
@ -175,12 +188,16 @@ miistatus(Mii* mii)
|
||||||
* (Read status twice as the Ls bit is sticky).
|
* (Read status twice as the Ls bit is sticky).
|
||||||
*/
|
*/
|
||||||
bmsr = mii->mir(mii, phyno, Bmsr);
|
bmsr = mii->mir(mii, phyno, Bmsr);
|
||||||
|
if(bmsr == -1)
|
||||||
|
return -1;
|
||||||
if(!(bmsr & (BmsrAnc|BmsrAna))) {
|
if(!(bmsr & (BmsrAnc|BmsrAna))) {
|
||||||
// print("miistatus: auto-neg incomplete\n");
|
// print("miistatus: auto-neg incomplete\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bmsr = mii->mir(mii, phyno, Bmsr);
|
bmsr = mii->mir(mii, phyno, Bmsr);
|
||||||
|
if(bmsr == -1)
|
||||||
|
return -1;
|
||||||
if(!(bmsr & BmsrLs)){
|
if(!(bmsr & BmsrLs)){
|
||||||
// print("miistatus: link down\n");
|
// print("miistatus: link down\n");
|
||||||
phy->link = 0;
|
phy->link = 0;
|
||||||
|
@ -190,6 +207,8 @@ miistatus(Mii* mii)
|
||||||
phy->speed = phy->fd = phy->rfc = phy->tfc = 0;
|
phy->speed = phy->fd = phy->rfc = phy->tfc = 0;
|
||||||
if(phy->mscr){
|
if(phy->mscr){
|
||||||
r = mii->mir(mii, phyno, Mssr);
|
r = mii->mir(mii, phyno, Mssr);
|
||||||
|
if(r == -1)
|
||||||
|
return -1;
|
||||||
if((phy->mscr & Mscr1000TFD) && (r & Mssr1000TFD)){
|
if((phy->mscr & Mscr1000TFD) && (r & Mssr1000TFD)){
|
||||||
phy->speed = 1000;
|
phy->speed = 1000;
|
||||||
phy->fd = 1;
|
phy->fd = 1;
|
||||||
|
@ -199,6 +218,8 @@ miistatus(Mii* mii)
|
||||||
}
|
}
|
||||||
|
|
||||||
anlpar = mii->mir(mii, phyno, Anlpar);
|
anlpar = mii->mir(mii, phyno, Anlpar);
|
||||||
|
if(anlpar == -1)
|
||||||
|
return -1;
|
||||||
if(phy->speed == 0){
|
if(phy->speed == 0){
|
||||||
r = phy->anar & anlpar;
|
r = phy->anar & anlpar;
|
||||||
if(r & AnaTXFD){
|
if(r & AnaTXFD){
|
||||||
|
|
Loading…
Reference in a new issue