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