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