mii.c revision 1.2 1 1.2 thorpej /* $NetBSD: mii.c,v 1.2 1997/11/17 08:52:38 thorpej Exp $ */
2 1.1 bouyer
3 1.1 bouyer /*
4 1.1 bouyer * Copyright (c) 1997 Manuel Bouyer. All rights reserved.
5 1.1 bouyer *
6 1.1 bouyer * Redistribution and use in source and binary forms, with or without
7 1.1 bouyer * modification, are permitted provided that the following conditions
8 1.1 bouyer * are met:
9 1.1 bouyer * 1. Redistributions of source code must retain the above copyright
10 1.1 bouyer * notice, this list of conditions and the following disclaimer.
11 1.1 bouyer * 2. Redistributions in binary form must reproduce the above copyright
12 1.1 bouyer * notice, this list of conditions and the following disclaimer in the
13 1.1 bouyer * documentation and/or other materials provided with the distribution.
14 1.1 bouyer * 3. All advertising materials mentioning features or use of this software
15 1.1 bouyer * must display the following acknowledgement:
16 1.2 thorpej * This product includes software developed by Manuel Bouyer.
17 1.1 bouyer * 4. The name of the author may not be used to endorse or promote products
18 1.1 bouyer * derived from this software without specific prior written permission.
19 1.1 bouyer *
20 1.1 bouyer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 1.1 bouyer * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 1.1 bouyer * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 1.1 bouyer * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 1.1 bouyer * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 1.1 bouyer * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 1.1 bouyer * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 1.1 bouyer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 1.1 bouyer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 1.1 bouyer * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 1.1 bouyer */
31 1.1 bouyer
32 1.1 bouyer #include <sys/param.h>
33 1.1 bouyer #include <sys/systm.h>
34 1.1 bouyer #include <sys/kernel.h>
35 1.1 bouyer #include <sys/device.h>
36 1.1 bouyer #include <sys/malloc.h>
37 1.1 bouyer #include <sys/socket.h>
38 1.1 bouyer #include <sys/sockio.h>
39 1.1 bouyer
40 1.1 bouyer #include <net/if.h>
41 1.1 bouyer #if defined(SIOCSIFMEDIA)
42 1.1 bouyer #include <net/if_media.h>
43 1.1 bouyer #endif
44 1.1 bouyer
45 1.1 bouyer #include <dev/mii/mii_adapter.h>
46 1.1 bouyer #include <dev/mii/mii_phy.h>
47 1.1 bouyer #include <dev/mii/generic_phy.h>
48 1.1 bouyer
49 1.1 bouyer #include "locators.h"
50 1.1 bouyer
51 1.1 bouyer /* The mii bus private data definitions */
52 1.1 bouyer
53 1.1 bouyer struct mii_softc {
54 1.1 bouyer struct device sc_dev;
55 1.1 bouyer mii_data_t *adapter;
56 1.1 bouyer mii_phy_t *phy[32];
57 1.1 bouyer mii_phy_t *current_phy;
58 1.1 bouyer };
59 1.1 bouyer
60 1.1 bouyer static void mii_sync __P((mii_data_t *));
61 1.1 bouyer static void mii_sendbit __P((mii_data_t *, u_int32_t, int));
62 1.1 bouyer
63 1.1 bouyer #ifdef __BROKEN_INDIRECT_CONFIG
64 1.1 bouyer int miimatch __P((struct device *, void *, void *));
65 1.1 bouyer int mii_configmatch __P((struct device *, void *, void *));
66 1.1 bouyer #else
67 1.1 bouyer int miimatch __P((struct device *, struct cfdata *, void *));
68 1.1 bouyer int mii_configmatch __P((struct device *, struct cfdata *, void *));
69 1.1 bouyer #endif
70 1.1 bouyer void miiattach __P((struct device *, struct device *, void *));
71 1.1 bouyer
72 1.1 bouyer int mii_print __P((void *, const char *));
73 1.1 bouyer
74 1.1 bouyer struct cfattach mii_ca = {
75 1.1 bouyer sizeof(struct mii_softc), miimatch, miiattach
76 1.1 bouyer };
77 1.1 bouyer
78 1.1 bouyer struct cfdriver mii_cd = {
79 1.1 bouyer NULL, "mii", DV_DULL
80 1.1 bouyer };
81 1.1 bouyer
82 1.2 thorpej int
83 1.2 thorpej mii_print(aux, pnp)
84 1.1 bouyer void *aux;
85 1.1 bouyer const char *pnp;
86 1.1 bouyer {
87 1.1 bouyer mii_phy_t *phy = aux;
88 1.2 thorpej
89 1.1 bouyer if (pnp)
90 1.2 thorpej printf("PHY ID 0x%x at %s", phy->phy_id, pnp);
91 1.1 bouyer printf(" dev %d", phy->dev);
92 1.1 bouyer return (UNCONF);
93 1.1 bouyer }
94 1.1 bouyer
95 1.1 bouyer #ifdef __BROKEN_INDIRECT_CONFIG
96 1.1 bouyer int
97 1.1 bouyer miimatch(parent, match, aux)
98 1.1 bouyer struct device *parent;
99 1.1 bouyer void *match, *aux;
100 1.1 bouyer {
101 1.1 bouyer #else
102 1.1 bouyer int
103 1.1 bouyer miimatch(parent, cf, aux)
104 1.1 bouyer struct device *parent;
105 1.1 bouyer struct cfdata *cf;
106 1.1 bouyer void *aux;
107 1.1 bouyer {
108 1.1 bouyer #endif
109 1.1 bouyer return 1;
110 1.1 bouyer }
111 1.1 bouyer
112 1.1 bouyer void
113 1.1 bouyer miiattach(parent, self, aux)
114 1.1 bouyer struct device *parent, *self;
115 1.1 bouyer void *aux;
116 1.1 bouyer {
117 1.1 bouyer int phy_id_l, phy_id_h;
118 1.1 bouyer int i;
119 1.1 bouyer mii_phy_t *phy;
120 1.1 bouyer struct mii_softc *sc = (struct mii_softc *)self;
121 1.1 bouyer mii_data_t *adapter = aux;
122 1.1 bouyer /* struct cfdata *cf; */
123 1.1 bouyer
124 1.1 bouyer printf("\n");
125 1.1 bouyer sc->adapter = adapter;
126 1.1 bouyer sc->adapter->mii_sc = sc;
127 1.1 bouyer sc->current_phy = NULL;
128 1.2 thorpej
129 1.2 thorpej for (i = 0; i < 32; i++) {
130 1.1 bouyer phy_id_h = mii_readreg(sc, i, PHY_IDH);
131 1.1 bouyer phy_id_l = mii_readreg(sc, i, PHY_IDL);
132 1.1 bouyer #ifdef MII_DEBUG
133 1.2 thorpej printf("Id of PHY 0x%x: 0x%x%x\n", i, phy_id_h, phy_id_l);
134 1.1 bouyer #endif
135 1.1 bouyer if (phy_id_h != -1 && phy_id_l != -1) {
136 1.1 bouyer phy = malloc(sizeof(mii_phy_t), M_DEVBUF, M_WAITOK);
137 1.2 thorpej phy->phy_id = ((phy_id_h & 0xffff) << 16) |
138 1.2 thorpej (phy_id_l & 0xffff);
139 1.1 bouyer phy->adapter_id = adapter->adapter_id;
140 1.1 bouyer phy->dev = i;
141 1.1 bouyer phy->mii_softc = sc;
142 1.1 bouyer #if 0
143 1.2 thorpej if ((cf = config_search(mii_configmatch, self,
144 1.2 thorpej phy)) != NULL) {
145 1.1 bouyer sc->phy[i] = phy;
146 1.2 thorpej config_attach(self, cf, phy, mii_print);
147 1.1 bouyer } else {
148 1.1 bouyer sc->phy[i] = NULL;
149 1.1 bouyer mii_print(phy, sc->sc_dev.dv_xname);
150 1.1 bouyer printf(" not configured\n");
151 1.1 bouyer free(phy, M_DEVBUF);
152 1.1 bouyer }
153 1.1 bouyer #else
154 1.2 thorpej if (config_found_sm(self, phy, mii_print,
155 1.2 thorpej mii_configmatch) != NULL) {
156 1.1 bouyer sc->phy[i] = phy;
157 1.1 bouyer } else {
158 1.1 bouyer sc->phy[i] = NULL;
159 1.1 bouyer free(phy, M_DEVBUF);
160 1.1 bouyer }
161 1.1 bouyer #endif
162 1.1 bouyer }
163 1.1 bouyer }
164 1.1 bouyer }
165 1.1 bouyer
166 1.1 bouyer #ifdef __BROKEN_INDIRECT_CONFIG
167 1.1 bouyer int
168 1.1 bouyer mii_configmatch(parent, match, aux)
169 1.1 bouyer struct device *parent;
170 1.1 bouyer void *match, *aux;
171 1.1 bouyer {
172 1.1 bouyer struct cfdata *cf =match;
173 1.1 bouyer #else
174 1.1 bouyer int
175 1.1 bouyer mii_configmatch(parent, cf, aux)
176 1.1 bouyer struct device *parent;
177 1.1 bouyer struct cfdata *cf;
178 1.1 bouyer void *aux;
179 1.1 bouyer {
180 1.1 bouyer #endif
181 1.1 bouyer mii_phy_t *phy = aux;
182 1.1 bouyer
183 1.1 bouyer if (cf->cf_loc[MIICF_DEV] != MIICF_DEV_DEFAULT &&
184 1.2 thorpej cf->cf_loc[MIICF_DEV] != phy->dev)
185 1.2 thorpej return (0);
186 1.1 bouyer return ((*cf->cf_attach->ca_match)(parent, cf, aux));
187 1.1 bouyer }
188 1.1 bouyer
189 1.1 bouyer static void
190 1.1 bouyer mii_sync(adapter)
191 1.1 bouyer mii_data_t* adapter;
192 1.1 bouyer {
193 1.1 bouyer int i;
194 1.1 bouyer
195 1.2 thorpej (*adapter->mii_clrbit)(adapter->adapter_softc, MII_TXEN);
196 1.2 thorpej for (i = 0; i < 32; i++) {
197 1.2 thorpej (*adapter->mii_clrbit)(adapter->adapter_softc, MII_CLOCK);
198 1.2 thorpej (*adapter->mii_setbit)(adapter->adapter_softc, MII_CLOCK);
199 1.1 bouyer }
200 1.1 bouyer }
201 1.1 bouyer
202 1.1 bouyer static void
203 1.1 bouyer mii_sendbit(adapter, data, nbits)
204 1.1 bouyer mii_data_t *adapter;
205 1.1 bouyer u_int32_t data;
206 1.1 bouyer int nbits;
207 1.1 bouyer {
208 1.1 bouyer int i;
209 1.1 bouyer
210 1.2 thorpej (*adapter->mii_setbit)(adapter->adapter_softc, MII_TXEN);
211 1.1 bouyer for (i = 1 << (nbits -1); i; i = i >> 1) {
212 1.2 thorpej (*adapter->mii_clrbit)(adapter->adapter_softc, MII_CLOCK);
213 1.2 thorpej (*adapter->mii_readbit)(adapter->adapter_softc, MII_CLOCK);
214 1.1 bouyer if (data & i)
215 1.2 thorpej (*adapter->mii_setbit)(adapter->adapter_softc,
216 1.2 thorpej MII_DATA);
217 1.1 bouyer else
218 1.2 thorpej (*adapter->mii_clrbit)(adapter->adapter_softc,
219 1.2 thorpej MII_DATA);
220 1.2 thorpej (*adapter->mii_setbit)(adapter->adapter_softc, MII_CLOCK);
221 1.2 thorpej (*adapter->mii_readbit)(adapter->adapter_softc, MII_CLOCK);
222 1.1 bouyer }
223 1.1 bouyer }
224 1.1 bouyer
225 1.2 thorpej int
226 1.2 thorpej mii_readreg(v, phy, reg)
227 1.1 bouyer void *v;
228 1.1 bouyer u_int16_t phy;
229 1.1 bouyer u_int16_t reg;
230 1.1 bouyer {
231 1.1 bouyer mii_data_t *adapter = ((struct mii_softc *)v)->adapter;
232 1.1 bouyer u_int16_t val = 0;
233 1.1 bouyer int err =0;
234 1.1 bouyer int i;
235 1.1 bouyer
236 1.1 bouyer if (adapter->mii_readreg) /* adapter has a special way to read PHYs */
237 1.2 thorpej return ((*adapter->mii_readreg)(adapter->adapter_softc,
238 1.2 thorpej phy, reg));
239 1.1 bouyer
240 1.1 bouyer /* else read using the control lines */
241 1.1 bouyer mii_sync(adapter);
242 1.1 bouyer mii_sendbit(adapter, MII_START, 2);
243 1.1 bouyer mii_sendbit(adapter, MII_READ, 2);
244 1.1 bouyer mii_sendbit(adapter, phy, 5);
245 1.1 bouyer mii_sendbit(adapter, reg, 5);
246 1.1 bouyer
247 1.2 thorpej (*adapter->mii_clrbit)(adapter->adapter_softc, MII_TXEN);
248 1.2 thorpej (*adapter->mii_clrbit)(adapter->adapter_softc, MII_CLOCK);
249 1.2 thorpej (*adapter->mii_setbit)(adapter->adapter_softc, MII_CLOCK);
250 1.2 thorpej (*adapter->mii_clrbit)(adapter->adapter_softc, MII_CLOCK);
251 1.1 bouyer
252 1.2 thorpej err = (*adapter->mii_readbit)(adapter->adapter_softc, MII_DATA);
253 1.2 thorpej (*adapter->mii_setbit)(adapter->adapter_softc, MII_CLOCK);
254 1.1 bouyer
255 1.2 thorpej for (i = 0; i < 16; i++) {
256 1.1 bouyer val = val << 1;
257 1.2 thorpej (*adapter->mii_clrbit)(adapter->adapter_softc, MII_CLOCK);
258 1.2 thorpej if (err == 0)
259 1.2 thorpej if ((*adapter->mii_readbit)(adapter->adapter_softc,
260 1.2 thorpej MII_DATA))
261 1.1 bouyer val |= 1;
262 1.2 thorpej (*adapter->mii_setbit)(adapter->adapter_softc, MII_CLOCK);
263 1.1 bouyer }
264 1.2 thorpej (*adapter->mii_clrbit)(adapter->adapter_softc, MII_CLOCK);
265 1.2 thorpej (*adapter->mii_setbit)(adapter->adapter_softc, MII_CLOCK);
266 1.1 bouyer
267 1.2 thorpej if (err == 0)
268 1.1 bouyer return val;
269 1.1 bouyer else
270 1.1 bouyer return -1;
271 1.1 bouyer }
272 1.1 bouyer
273 1.2 thorpej void
274 1.2 thorpej mii_writereg(v, phy, reg, data)
275 1.1 bouyer void *v;
276 1.1 bouyer u_int16_t phy;
277 1.1 bouyer u_int16_t reg;
278 1.1 bouyer u_int16_t data;
279 1.1 bouyer {
280 1.1 bouyer mii_data_t *adapter = ((struct mii_softc *)v)->adapter;
281 1.1 bouyer
282 1.2 thorpej if (adapter->mii_writereg) {
283 1.2 thorpej /* Interface has a special way of writing to the PHY. */
284 1.2 thorpej (*adapter->mii_writereg)(adapter, phy, reg, data);
285 1.1 bouyer return;
286 1.1 bouyer }
287 1.1 bouyer
288 1.1 bouyer /* else write using the control lines */
289 1.1 bouyer mii_sync(adapter);
290 1.1 bouyer mii_sendbit(adapter, MII_START, 2);
291 1.1 bouyer mii_sendbit(adapter, MII_WRITE, 2);
292 1.1 bouyer mii_sendbit(adapter, phy, 5);
293 1.1 bouyer mii_sendbit(adapter, reg, 5);
294 1.1 bouyer mii_sendbit(adapter, MII_ACK, 2);
295 1.1 bouyer mii_sendbit(adapter, data, 16);
296 1.1 bouyer
297 1.2 thorpej (*adapter->mii_clrbit)(adapter->adapter_softc, MII_CLOCK);
298 1.2 thorpej (*adapter->mii_setbit)(adapter->adapter_softc, MII_CLOCK);
299 1.1 bouyer }
300 1.1 bouyer
301 1.2 thorpej void
302 1.2 thorpej mii_media_add(ifmedia, adapter)
303 1.1 bouyer struct ifmedia *ifmedia;
304 1.1 bouyer mii_data_t *adapter;
305 1.1 bouyer {
306 1.1 bouyer struct mii_softc *sc = adapter->mii_sc;
307 1.1 bouyer int i;
308 1.1 bouyer u_int32_t media = 0;
309 1.1 bouyer
310 1.1 bouyer for (i = 0; i < 32; i++) {
311 1.1 bouyer if (sc->phy[i])
312 1.1 bouyer media |= sc->phy[i]->phy_media;
313 1.1 bouyer }
314 1.1 bouyer if (media & PHY_BNC)
315 1.1 bouyer ifmedia_add(ifmedia, IFM_ETHER | IFM_10_2, 0, NULL);
316 1.1 bouyer if (media & PHY_AUI)
317 1.1 bouyer ifmedia_add(ifmedia, IFM_ETHER | IFM_10_5, 0, NULL);
318 1.1 bouyer if (media & PHY_10baseT)
319 1.1 bouyer ifmedia_add(ifmedia, IFM_ETHER | IFM_10_T, 0, NULL);
320 1.1 bouyer if (media & PHY_10baseTfd)
321 1.1 bouyer ifmedia_add(ifmedia, IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL);
322 1.1 bouyer if (media & PHY_100baseTx)
323 1.1 bouyer ifmedia_add(ifmedia, IFM_ETHER | IFM_100_TX, 0, NULL);
324 1.1 bouyer if (media & PHY_100baseTxfd)
325 1.1 bouyer ifmedia_add(ifmedia, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL);
326 1.1 bouyer if (media & PHY_100baseT4)
327 1.1 bouyer ifmedia_add(ifmedia, IFM_ETHER | IFM_100_T4, 0, NULL);
328 1.1 bouyer ifmedia_add(ifmedia, IFM_ETHER | IFM_NONE, 0, NULL);
329 1.1 bouyer }
330 1.1 bouyer
331 1.2 thorpej int
332 1.2 thorpej mii_mediachg(adapter)
333 1.1 bouyer mii_data_t *adapter;
334 1.1 bouyer {
335 1.1 bouyer struct mii_softc *sc = adapter->mii_sc;
336 1.1 bouyer int i, best = -1, error = 0;
337 1.1 bouyer int media = adapter->mii_media_active;
338 1.1 bouyer
339 1.1 bouyer sc->current_phy = NULL;
340 1.1 bouyer
341 1.2 thorpej for (i = 0; i < 32; i++) {
342 1.1 bouyer if (sc->phy[i] == NULL)
343 1.1 bouyer continue;
344 1.2 thorpej switch (sc->phy[i]->phy_media_set(media,
345 1.2 thorpej sc->phy[i]->phy_softc)) {
346 1.2 thorpej case -1: /* PHY not available */
347 1.1 bouyer break;
348 1.2 thorpej case 0: /* link sucessfully selected */
349 1.1 bouyer sc->current_phy = sc->phy[i];
350 1.1 bouyer break;
351 1.2 thorpej case ENETDOWN: /* link selected but not up */
352 1.1 bouyer best = i;
353 1.1 bouyer break;
354 1.1 bouyer default:
355 1.1 bouyer break;
356 1.1 bouyer }
357 1.1 bouyer }
358 1.1 bouyer if (sc->current_phy == NULL) {
359 1.2 thorpej /*
360 1.2 thorpej * We didn't find a valid media. Select the best one (i.e.
361 1.2 thorpej * last supported but not up). If media != autoselect,
362 1.2 thorpej * don't report any error code.
363 1.2 thorpej */
364 1.1 bouyer if (best < 0)
365 1.2 thorpej return (EINVAL);
366 1.1 bouyer sc->current_phy = sc->phy[best];
367 1.2 thorpej error = sc->phy[best]->phy_media_set(media,
368 1.2 thorpej sc->phy[best]->phy_softc);
369 1.1 bouyer if (media != IFM_AUTO)
370 1.2 thorpej error = 0;
371 1.1 bouyer }
372 1.1 bouyer /* power down all but current phy */
373 1.2 thorpej for (i = 0; i < 32; i++) {
374 1.1 bouyer if (sc->phy[i] != sc->current_phy) {
375 1.1 bouyer if (sc->phy[i] == NULL)
376 1.1 bouyer mii_writereg(sc, i, PHY_CONTROL, CTRL_ISO);
377 1.1 bouyer else
378 1.1 bouyer sc->phy[i]->phy_pdown(sc->phy[i]->phy_softc);
379 1.1 bouyer }
380 1.1 bouyer }
381 1.2 thorpej return (error);
382 1.1 bouyer }
383 1.1 bouyer
384 1.2 thorpej void
385 1.2 thorpej mii_pollstat(adapter)
386 1.1 bouyer mii_data_t *adapter;
387 1.1 bouyer {
388 1.1 bouyer struct mii_softc *sc = adapter->mii_sc;
389 1.1 bouyer
390 1.1 bouyer adapter->mii_media_status = IFM_AVALID;
391 1.1 bouyer if (sc->current_phy == NULL)
392 1.1 bouyer return;
393 1.2 thorpej if ((*sc->current_phy->phy_status)(adapter->mii_media_active,
394 1.2 thorpej sc->current_phy->phy_softc) == 0)
395 1.1 bouyer adapter->mii_media_status |= IFM_ACTIVE;
396 1.1 bouyer }
397