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