xref: /plan9/sys/src/9/rb/ethermii.c (revision f43f8ee646e2cb29aea7fd7bb5fc7318a3f4921f)
1*f43f8ee6SDavid du Colombier #include "u.h"
2*f43f8ee6SDavid du Colombier #include "../port/lib.h"
3*f43f8ee6SDavid du Colombier #include "mem.h"
4*f43f8ee6SDavid du Colombier #include "dat.h"
5*f43f8ee6SDavid du Colombier #include "fns.h"
6*f43f8ee6SDavid du Colombier #include "io.h"
7*f43f8ee6SDavid du Colombier #include "../port/error.h"
8*f43f8ee6SDavid du Colombier #include "../port/netif.h"
9*f43f8ee6SDavid du Colombier 
10*f43f8ee6SDavid du Colombier #include "etherif.h"
11*f43f8ee6SDavid du Colombier #include "ethermii.h"
12*f43f8ee6SDavid du Colombier 
13*f43f8ee6SDavid du Colombier int
mii(Mii * mii,int mask)14*f43f8ee6SDavid du Colombier mii(Mii* mii, int mask)
15*f43f8ee6SDavid du Colombier {
16*f43f8ee6SDavid du Colombier 	MiiPhy *miiphy;
17*f43f8ee6SDavid du Colombier 	int bit, oui, phyno, r, rmask;
18*f43f8ee6SDavid du Colombier 
19*f43f8ee6SDavid du Colombier 	/*
20*f43f8ee6SDavid du Colombier 	 * Probe through mii for PHYs in mask;
21*f43f8ee6SDavid du Colombier 	 * return the mask of those found in the current probe.
22*f43f8ee6SDavid du Colombier 	 * If the PHY has not already been probed, update
23*f43f8ee6SDavid du Colombier 	 * the Mii information.
24*f43f8ee6SDavid du Colombier 	 */
25*f43f8ee6SDavid du Colombier 	rmask = 0;
26*f43f8ee6SDavid du Colombier 	for(phyno = 0; phyno < NMiiPhy; phyno++){
27*f43f8ee6SDavid du Colombier 		bit = 1<<phyno;
28*f43f8ee6SDavid du Colombier 		if(!(mask & bit))
29*f43f8ee6SDavid du Colombier 			continue;
30*f43f8ee6SDavid du Colombier 		if(mii->mask & bit){
31*f43f8ee6SDavid du Colombier 			rmask |= bit;
32*f43f8ee6SDavid du Colombier 			continue;
33*f43f8ee6SDavid du Colombier 		}
34*f43f8ee6SDavid du Colombier 		if(mii->mir(mii, phyno, Bmsr) == -1)
35*f43f8ee6SDavid du Colombier 			continue;
36*f43f8ee6SDavid du Colombier 		r = mii->mir(mii, phyno, Phyidr1);
37*f43f8ee6SDavid du Colombier 		oui = (r & 0x3FFF)<<6;
38*f43f8ee6SDavid du Colombier 		r = mii->mir(mii, phyno, Phyidr2);
39*f43f8ee6SDavid du Colombier 		oui |= r>>10;
40*f43f8ee6SDavid du Colombier 		if(oui == 0xFFFFF || oui == 0)
41*f43f8ee6SDavid du Colombier 			continue;
42*f43f8ee6SDavid du Colombier 
43*f43f8ee6SDavid du Colombier 		if((miiphy = malloc(sizeof(MiiPhy))) == nil)
44*f43f8ee6SDavid du Colombier 			continue;
45*f43f8ee6SDavid du Colombier 
46*f43f8ee6SDavid du Colombier 		miiphy->mii = mii;
47*f43f8ee6SDavid du Colombier 		miiphy->oui = oui;
48*f43f8ee6SDavid du Colombier 		miiphy->phyno = phyno;
49*f43f8ee6SDavid du Colombier 
50*f43f8ee6SDavid du Colombier 		miiphy->anar = ~0;
51*f43f8ee6SDavid du Colombier 		miiphy->fc = ~0;
52*f43f8ee6SDavid du Colombier 		miiphy->mscr = ~0;
53*f43f8ee6SDavid du Colombier 
54*f43f8ee6SDavid du Colombier 		mii->phy[phyno] = miiphy;
55*f43f8ee6SDavid du Colombier 		if(mii->curphy == nil)
56*f43f8ee6SDavid du Colombier 			mii->curphy = miiphy;
57*f43f8ee6SDavid du Colombier 		mii->mask |= bit;
58*f43f8ee6SDavid du Colombier 		mii->nphy++;
59*f43f8ee6SDavid du Colombier 
60*f43f8ee6SDavid du Colombier 		rmask |= bit;
61*f43f8ee6SDavid du Colombier 	}
62*f43f8ee6SDavid du Colombier 	return rmask;
63*f43f8ee6SDavid du Colombier }
64*f43f8ee6SDavid du Colombier 
65*f43f8ee6SDavid du Colombier int
miimir(Mii * mii,int r)66*f43f8ee6SDavid du Colombier miimir(Mii* mii, int r)
67*f43f8ee6SDavid du Colombier {
68*f43f8ee6SDavid du Colombier 	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
69*f43f8ee6SDavid du Colombier 		return -1;
70*f43f8ee6SDavid du Colombier 	return mii->mir(mii, mii->curphy->phyno, r);
71*f43f8ee6SDavid du Colombier }
72*f43f8ee6SDavid du Colombier 
73*f43f8ee6SDavid du Colombier int
miimiw(Mii * mii,int r,int data)74*f43f8ee6SDavid du Colombier miimiw(Mii* mii, int r, int data)
75*f43f8ee6SDavid du Colombier {
76*f43f8ee6SDavid du Colombier 	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
77*f43f8ee6SDavid du Colombier 		return -1;
78*f43f8ee6SDavid du Colombier 	return mii->miw(mii, mii->curphy->phyno, r, data);
79*f43f8ee6SDavid du Colombier }
80*f43f8ee6SDavid du Colombier 
81*f43f8ee6SDavid du Colombier int
miireset(Mii * mii)82*f43f8ee6SDavid du Colombier miireset(Mii* mii)
83*f43f8ee6SDavid du Colombier {
84*f43f8ee6SDavid du Colombier 	int bmcr;
85*f43f8ee6SDavid du Colombier 
86*f43f8ee6SDavid du Colombier 	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
87*f43f8ee6SDavid du Colombier 		return -1;
88*f43f8ee6SDavid du Colombier 	bmcr = mii->mir(mii, mii->curphy->phyno, Bmcr);
89*f43f8ee6SDavid du Colombier 	bmcr |= BmcrR;
90*f43f8ee6SDavid du Colombier 	mii->miw(mii, mii->curphy->phyno, Bmcr, bmcr);
91*f43f8ee6SDavid du Colombier 	microdelay(1);
92*f43f8ee6SDavid du Colombier 
93*f43f8ee6SDavid du Colombier 	return 0;
94*f43f8ee6SDavid du Colombier }
95*f43f8ee6SDavid du Colombier 
96*f43f8ee6SDavid du Colombier int
miiane(Mii * mii,int a,int p,int e)97*f43f8ee6SDavid du Colombier miiane(Mii* mii, int a, int p, int e)
98*f43f8ee6SDavid du Colombier {
99*f43f8ee6SDavid du Colombier 	int anar, bmsr, mscr, r, phyno;
100*f43f8ee6SDavid du Colombier 
101*f43f8ee6SDavid du Colombier 	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
102*f43f8ee6SDavid du Colombier 		return -1;
103*f43f8ee6SDavid du Colombier 	phyno = mii->curphy->phyno;
104*f43f8ee6SDavid du Colombier 
105*f43f8ee6SDavid du Colombier 	bmsr = mii->mir(mii, phyno, Bmsr);
106*f43f8ee6SDavid du Colombier 	if(!(bmsr & BmsrAna))
107*f43f8ee6SDavid du Colombier 		return -1;
108*f43f8ee6SDavid du Colombier 
109*f43f8ee6SDavid du Colombier 	if(a != ~0)
110*f43f8ee6SDavid du Colombier 		anar = (AnaTXFD|AnaTXHD|Ana10FD|Ana10HD) & a;
111*f43f8ee6SDavid du Colombier 	else if(mii->curphy->anar != ~0)
112*f43f8ee6SDavid du Colombier 		anar = mii->curphy->anar;
113*f43f8ee6SDavid du Colombier 	else{
114*f43f8ee6SDavid du Colombier 		anar = mii->mir(mii, phyno, Anar);
115*f43f8ee6SDavid du Colombier 		anar &= ~(AnaAP|AnaP|AnaT4|AnaTXFD|AnaTXHD|Ana10FD|Ana10HD);
116*f43f8ee6SDavid du Colombier 		if(bmsr & Bmsr10THD)
117*f43f8ee6SDavid du Colombier 			anar |= Ana10HD;
118*f43f8ee6SDavid du Colombier 		if(bmsr & Bmsr10TFD)
119*f43f8ee6SDavid du Colombier 			anar |= Ana10FD;
120*f43f8ee6SDavid du Colombier 		if(bmsr & Bmsr100TXHD)
121*f43f8ee6SDavid du Colombier 			anar |= AnaTXHD;
122*f43f8ee6SDavid du Colombier 		if(bmsr & Bmsr100TXFD)
123*f43f8ee6SDavid du Colombier 			anar |= AnaTXFD;
124*f43f8ee6SDavid du Colombier 	}
125*f43f8ee6SDavid du Colombier 	mii->curphy->anar = anar;
126*f43f8ee6SDavid du Colombier 
127*f43f8ee6SDavid du Colombier 	if(p != ~0)
128*f43f8ee6SDavid du Colombier 		anar |= (AnaAP|AnaP) & p;
129*f43f8ee6SDavid du Colombier 	else if(mii->curphy->fc != ~0)
130*f43f8ee6SDavid du Colombier 		anar |= mii->curphy->fc;
131*f43f8ee6SDavid du Colombier 	mii->curphy->fc = (AnaAP|AnaP) & anar;
132*f43f8ee6SDavid du Colombier 
133*f43f8ee6SDavid du Colombier 	if(bmsr & BmsrEs){
134*f43f8ee6SDavid du Colombier 		mscr = mii->mir(mii, phyno, Mscr);
135*f43f8ee6SDavid du Colombier 		mscr &= ~(Mscr1000TFD|Mscr1000THD);
136*f43f8ee6SDavid du Colombier 		if(e != ~0)
137*f43f8ee6SDavid du Colombier 			mscr |= (Mscr1000TFD|Mscr1000THD) & e;
138*f43f8ee6SDavid du Colombier 		else if(mii->curphy->mscr != ~0)
139*f43f8ee6SDavid du Colombier 			mscr = mii->curphy->mscr;
140*f43f8ee6SDavid du Colombier 		else{
141*f43f8ee6SDavid du Colombier 			r = mii->mir(mii, phyno, Esr);
142*f43f8ee6SDavid du Colombier 			if(r & Esr1000THD)
143*f43f8ee6SDavid du Colombier 				mscr |= Mscr1000THD;
144*f43f8ee6SDavid du Colombier 			if(r & Esr1000TFD)
145*f43f8ee6SDavid du Colombier 				mscr |= Mscr1000TFD;
146*f43f8ee6SDavid du Colombier 		}
147*f43f8ee6SDavid du Colombier 		mii->curphy->mscr = mscr;
148*f43f8ee6SDavid du Colombier 		mii->miw(mii, phyno, Mscr, mscr);
149*f43f8ee6SDavid du Colombier 	}
150*f43f8ee6SDavid du Colombier 	mii->miw(mii, phyno, Anar, anar);
151*f43f8ee6SDavid du Colombier 
152*f43f8ee6SDavid du Colombier 	r = mii->mir(mii, phyno, Bmcr);
153*f43f8ee6SDavid du Colombier 	if(!(r & BmcrR)){
154*f43f8ee6SDavid du Colombier 		r |= BmcrAne|BmcrRan;
155*f43f8ee6SDavid du Colombier 		mii->miw(mii, phyno, Bmcr, r);
156*f43f8ee6SDavid du Colombier 	}
157*f43f8ee6SDavid du Colombier 
158*f43f8ee6SDavid du Colombier 	return 0;
159*f43f8ee6SDavid du Colombier }
160*f43f8ee6SDavid du Colombier 
161*f43f8ee6SDavid du Colombier int
miistatus(Mii * mii)162*f43f8ee6SDavid du Colombier miistatus(Mii* mii)
163*f43f8ee6SDavid du Colombier {
164*f43f8ee6SDavid du Colombier 	MiiPhy *phy;
165*f43f8ee6SDavid du Colombier 	int anlpar, bmsr, p, r, phyno;
166*f43f8ee6SDavid du Colombier 
167*f43f8ee6SDavid du Colombier 	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
168*f43f8ee6SDavid du Colombier 		return -1;
169*f43f8ee6SDavid du Colombier 	phy = mii->curphy;
170*f43f8ee6SDavid du Colombier 	phyno = phy->phyno;
171*f43f8ee6SDavid du Colombier 
172*f43f8ee6SDavid du Colombier 	/*
173*f43f8ee6SDavid du Colombier 	 * Check Auto-Negotiation is complete and link is up.
174*f43f8ee6SDavid du Colombier 	 * (Read status twice as the Ls bit is sticky).
175*f43f8ee6SDavid du Colombier 	 */
176*f43f8ee6SDavid du Colombier 	bmsr = mii->mir(mii, phyno, Bmsr);
177*f43f8ee6SDavid du Colombier 	if(!(bmsr & (BmsrAnc|BmsrAna))) {
178*f43f8ee6SDavid du Colombier 		// print("miistatus: auto-neg incomplete\n");
179*f43f8ee6SDavid du Colombier 		return -1;
180*f43f8ee6SDavid du Colombier 	}
181*f43f8ee6SDavid du Colombier 
182*f43f8ee6SDavid du Colombier 	bmsr = mii->mir(mii, phyno, Bmsr);
183*f43f8ee6SDavid du Colombier 	if(!(bmsr & BmsrLs)){
184*f43f8ee6SDavid du Colombier 		// print("miistatus: link down\n");
185*f43f8ee6SDavid du Colombier 		phy->link = 0;
186*f43f8ee6SDavid du Colombier 		return -1;
187*f43f8ee6SDavid du Colombier 	}
188*f43f8ee6SDavid du Colombier 
189*f43f8ee6SDavid du Colombier 	phy->speed = phy->fd = phy->rfc = phy->tfc = 0;
190*f43f8ee6SDavid du Colombier 	if(phy->mscr){
191*f43f8ee6SDavid du Colombier 		r = mii->mir(mii, phyno, Mssr);
192*f43f8ee6SDavid du Colombier 		if((phy->mscr & Mscr1000TFD) && (r & Mssr1000TFD)){
193*f43f8ee6SDavid du Colombier 			phy->speed = 1000;
194*f43f8ee6SDavid du Colombier 			phy->fd = 1;
195*f43f8ee6SDavid du Colombier 		}
196*f43f8ee6SDavid du Colombier 		else if((phy->mscr & Mscr1000THD) && (r & Mssr1000THD))
197*f43f8ee6SDavid du Colombier 			phy->speed = 1000;
198*f43f8ee6SDavid du Colombier 	}
199*f43f8ee6SDavid du Colombier 
200*f43f8ee6SDavid du Colombier 	anlpar = mii->mir(mii, phyno, Anlpar);
201*f43f8ee6SDavid du Colombier 	if(phy->speed == 0){
202*f43f8ee6SDavid du Colombier 		r = phy->anar & anlpar;
203*f43f8ee6SDavid du Colombier 		if(r & AnaTXFD){
204*f43f8ee6SDavid du Colombier 			phy->speed = 100;
205*f43f8ee6SDavid du Colombier 			phy->fd = 1;
206*f43f8ee6SDavid du Colombier 		}
207*f43f8ee6SDavid du Colombier 		else if(r & AnaTXHD)
208*f43f8ee6SDavid du Colombier 			phy->speed = 100;
209*f43f8ee6SDavid du Colombier 		else if(r & Ana10FD){
210*f43f8ee6SDavid du Colombier 			phy->speed = 10;
211*f43f8ee6SDavid du Colombier 			phy->fd = 1;
212*f43f8ee6SDavid du Colombier 		}
213*f43f8ee6SDavid du Colombier 		else if(r & Ana10HD)
214*f43f8ee6SDavid du Colombier 			phy->speed = 10;
215*f43f8ee6SDavid du Colombier 	}
216*f43f8ee6SDavid du Colombier 	if(phy->speed == 0) {
217*f43f8ee6SDavid du Colombier 		// print("miistatus: phy speed 0\n");
218*f43f8ee6SDavid du Colombier 		return -1;
219*f43f8ee6SDavid du Colombier 	}
220*f43f8ee6SDavid du Colombier 
221*f43f8ee6SDavid du Colombier 	if(phy->fd){
222*f43f8ee6SDavid du Colombier 		p = phy->fc;
223*f43f8ee6SDavid du Colombier 		r = anlpar & (AnaAP|AnaP);
224*f43f8ee6SDavid du Colombier 		if(p == AnaAP && r == (AnaAP|AnaP))
225*f43f8ee6SDavid du Colombier 			phy->tfc = 1;
226*f43f8ee6SDavid du Colombier 		else if(p == (AnaAP|AnaP) && r == AnaAP)
227*f43f8ee6SDavid du Colombier 			phy->rfc = 1;
228*f43f8ee6SDavid du Colombier 		else if((p & AnaP) && (r & AnaP))
229*f43f8ee6SDavid du Colombier 			phy->rfc = phy->tfc = 1;
230*f43f8ee6SDavid du Colombier 	}
231*f43f8ee6SDavid du Colombier 
232*f43f8ee6SDavid du Colombier 	phy->link = 1;
233*f43f8ee6SDavid du Colombier 
234*f43f8ee6SDavid du Colombier 	return 0;
235*f43f8ee6SDavid du Colombier }
236