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