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