mii.c revision 1.4 1 1.4 bouyer /* $NetBSD: mii.c,v 1.4 1998/02/11 19:02:11 bouyer 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.4 bouyer
78 1.4 bouyer int mii_adapter_print(aux, pnp)
79 1.4 bouyer void *aux;
80 1.4 bouyer const char *pnp;
81 1.4 bouyer {
82 1.4 bouyer if (pnp)
83 1.4 bouyer printf("mii at %s", pnp);
84 1.4 bouyer return UNCONF;
85 1.4 bouyer }
86 1.1 bouyer
87 1.2 thorpej int
88 1.2 thorpej mii_print(aux, pnp)
89 1.1 bouyer void *aux;
90 1.1 bouyer const char *pnp;
91 1.1 bouyer {
92 1.1 bouyer mii_phy_t *phy = aux;
93 1.2 thorpej
94 1.1 bouyer if (pnp)
95 1.2 thorpej printf("PHY ID 0x%x at %s", phy->phy_id, pnp);
96 1.1 bouyer printf(" dev %d", phy->dev);
97 1.1 bouyer return (UNCONF);
98 1.1 bouyer }
99 1.1 bouyer
100 1.1 bouyer #ifdef __BROKEN_INDIRECT_CONFIG
101 1.1 bouyer int
102 1.1 bouyer miimatch(parent, match, aux)
103 1.1 bouyer struct device *parent;
104 1.1 bouyer void *match, *aux;
105 1.1 bouyer {
106 1.1 bouyer #else
107 1.1 bouyer int
108 1.1 bouyer miimatch(parent, cf, aux)
109 1.1 bouyer struct device *parent;
110 1.1 bouyer struct cfdata *cf;
111 1.1 bouyer void *aux;
112 1.1 bouyer {
113 1.1 bouyer #endif
114 1.1 bouyer return 1;
115 1.1 bouyer }
116 1.1 bouyer
117 1.1 bouyer void
118 1.1 bouyer miiattach(parent, self, aux)
119 1.1 bouyer struct device *parent, *self;
120 1.1 bouyer void *aux;
121 1.1 bouyer {
122 1.1 bouyer int phy_id_l, phy_id_h;
123 1.1 bouyer int i;
124 1.1 bouyer mii_phy_t *phy;
125 1.1 bouyer struct mii_softc *sc = (struct mii_softc *)self;
126 1.1 bouyer mii_data_t *adapter = aux;
127 1.1 bouyer /* struct cfdata *cf; */
128 1.1 bouyer
129 1.1 bouyer printf("\n");
130 1.1 bouyer sc->adapter = adapter;
131 1.1 bouyer sc->adapter->mii_sc = sc;
132 1.1 bouyer sc->current_phy = NULL;
133 1.2 thorpej
134 1.2 thorpej for (i = 0; i < 32; i++) {
135 1.1 bouyer phy_id_h = mii_readreg(sc, i, PHY_IDH);
136 1.1 bouyer phy_id_l = mii_readreg(sc, i, PHY_IDL);
137 1.1 bouyer #ifdef MII_DEBUG
138 1.2 thorpej printf("Id of PHY 0x%x: 0x%x%x\n", i, phy_id_h, phy_id_l);
139 1.1 bouyer #endif
140 1.1 bouyer if (phy_id_h != -1 && phy_id_l != -1) {
141 1.1 bouyer phy = malloc(sizeof(mii_phy_t), M_DEVBUF, M_WAITOK);
142 1.2 thorpej phy->phy_id = ((phy_id_h & 0xffff) << 16) |
143 1.2 thorpej (phy_id_l & 0xffff);
144 1.1 bouyer phy->adapter_id = adapter->adapter_id;
145 1.1 bouyer phy->dev = i;
146 1.1 bouyer phy->mii_softc = sc;
147 1.1 bouyer #if 0
148 1.2 thorpej if ((cf = config_search(mii_configmatch, self,
149 1.2 thorpej phy)) != NULL) {
150 1.1 bouyer sc->phy[i] = phy;
151 1.2 thorpej config_attach(self, cf, phy, mii_print);
152 1.1 bouyer } else {
153 1.1 bouyer sc->phy[i] = NULL;
154 1.1 bouyer mii_print(phy, sc->sc_dev.dv_xname);
155 1.1 bouyer printf(" not configured\n");
156 1.1 bouyer free(phy, M_DEVBUF);
157 1.1 bouyer }
158 1.1 bouyer #else
159 1.2 thorpej if (config_found_sm(self, phy, mii_print,
160 1.2 thorpej mii_configmatch) != NULL) {
161 1.1 bouyer sc->phy[i] = phy;
162 1.1 bouyer } else {
163 1.1 bouyer sc->phy[i] = NULL;
164 1.1 bouyer free(phy, M_DEVBUF);
165 1.1 bouyer }
166 1.1 bouyer #endif
167 1.1 bouyer }
168 1.1 bouyer }
169 1.1 bouyer }
170 1.1 bouyer
171 1.1 bouyer #ifdef __BROKEN_INDIRECT_CONFIG
172 1.1 bouyer int
173 1.1 bouyer mii_configmatch(parent, match, aux)
174 1.1 bouyer struct device *parent;
175 1.1 bouyer void *match, *aux;
176 1.1 bouyer {
177 1.1 bouyer struct cfdata *cf =match;
178 1.1 bouyer #else
179 1.1 bouyer int
180 1.1 bouyer mii_configmatch(parent, cf, aux)
181 1.1 bouyer struct device *parent;
182 1.1 bouyer struct cfdata *cf;
183 1.1 bouyer void *aux;
184 1.1 bouyer {
185 1.1 bouyer #endif
186 1.1 bouyer mii_phy_t *phy = aux;
187 1.1 bouyer
188 1.1 bouyer if (cf->cf_loc[MIICF_DEV] != MIICF_DEV_DEFAULT &&
189 1.2 thorpej cf->cf_loc[MIICF_DEV] != phy->dev)
190 1.2 thorpej return (0);
191 1.1 bouyer return ((*cf->cf_attach->ca_match)(parent, cf, aux));
192 1.1 bouyer }
193 1.1 bouyer
194 1.1 bouyer static void
195 1.1 bouyer mii_sync(adapter)
196 1.1 bouyer mii_data_t* adapter;
197 1.1 bouyer {
198 1.1 bouyer int i;
199 1.1 bouyer
200 1.2 thorpej (*adapter->mii_clrbit)(adapter->adapter_softc, MII_TXEN);
201 1.2 thorpej for (i = 0; i < 32; i++) {
202 1.2 thorpej (*adapter->mii_clrbit)(adapter->adapter_softc, MII_CLOCK);
203 1.2 thorpej (*adapter->mii_setbit)(adapter->adapter_softc, MII_CLOCK);
204 1.1 bouyer }
205 1.1 bouyer }
206 1.1 bouyer
207 1.1 bouyer static void
208 1.1 bouyer mii_sendbit(adapter, data, nbits)
209 1.1 bouyer mii_data_t *adapter;
210 1.1 bouyer u_int32_t data;
211 1.1 bouyer int nbits;
212 1.1 bouyer {
213 1.1 bouyer int i;
214 1.1 bouyer
215 1.2 thorpej (*adapter->mii_setbit)(adapter->adapter_softc, MII_TXEN);
216 1.1 bouyer for (i = 1 << (nbits -1); i; i = i >> 1) {
217 1.2 thorpej (*adapter->mii_clrbit)(adapter->adapter_softc, MII_CLOCK);
218 1.2 thorpej (*adapter->mii_readbit)(adapter->adapter_softc, MII_CLOCK);
219 1.1 bouyer if (data & i)
220 1.2 thorpej (*adapter->mii_setbit)(adapter->adapter_softc,
221 1.2 thorpej MII_DATA);
222 1.1 bouyer else
223 1.2 thorpej (*adapter->mii_clrbit)(adapter->adapter_softc,
224 1.2 thorpej MII_DATA);
225 1.2 thorpej (*adapter->mii_setbit)(adapter->adapter_softc, MII_CLOCK);
226 1.2 thorpej (*adapter->mii_readbit)(adapter->adapter_softc, MII_CLOCK);
227 1.1 bouyer }
228 1.1 bouyer }
229 1.1 bouyer
230 1.2 thorpej int
231 1.2 thorpej mii_readreg(v, phy, reg)
232 1.1 bouyer void *v;
233 1.1 bouyer u_int16_t phy;
234 1.1 bouyer u_int16_t reg;
235 1.1 bouyer {
236 1.1 bouyer mii_data_t *adapter = ((struct mii_softc *)v)->adapter;
237 1.1 bouyer u_int16_t val = 0;
238 1.1 bouyer int err =0;
239 1.1 bouyer int i;
240 1.1 bouyer
241 1.1 bouyer if (adapter->mii_readreg) /* adapter has a special way to read PHYs */
242 1.2 thorpej return ((*adapter->mii_readreg)(adapter->adapter_softc,
243 1.2 thorpej phy, reg));
244 1.1 bouyer
245 1.1 bouyer /* else read using the control lines */
246 1.1 bouyer mii_sync(adapter);
247 1.1 bouyer mii_sendbit(adapter, MII_START, 2);
248 1.1 bouyer mii_sendbit(adapter, MII_READ, 2);
249 1.1 bouyer mii_sendbit(adapter, phy, 5);
250 1.1 bouyer mii_sendbit(adapter, reg, 5);
251 1.1 bouyer
252 1.2 thorpej (*adapter->mii_clrbit)(adapter->adapter_softc, MII_TXEN);
253 1.2 thorpej (*adapter->mii_clrbit)(adapter->adapter_softc, MII_CLOCK);
254 1.2 thorpej (*adapter->mii_setbit)(adapter->adapter_softc, MII_CLOCK);
255 1.2 thorpej (*adapter->mii_clrbit)(adapter->adapter_softc, MII_CLOCK);
256 1.1 bouyer
257 1.2 thorpej err = (*adapter->mii_readbit)(adapter->adapter_softc, MII_DATA);
258 1.2 thorpej (*adapter->mii_setbit)(adapter->adapter_softc, MII_CLOCK);
259 1.1 bouyer
260 1.2 thorpej for (i = 0; i < 16; i++) {
261 1.1 bouyer val = val << 1;
262 1.2 thorpej (*adapter->mii_clrbit)(adapter->adapter_softc, MII_CLOCK);
263 1.2 thorpej if (err == 0)
264 1.2 thorpej if ((*adapter->mii_readbit)(adapter->adapter_softc,
265 1.2 thorpej MII_DATA))
266 1.1 bouyer val |= 1;
267 1.2 thorpej (*adapter->mii_setbit)(adapter->adapter_softc, MII_CLOCK);
268 1.1 bouyer }
269 1.2 thorpej (*adapter->mii_clrbit)(adapter->adapter_softc, MII_CLOCK);
270 1.2 thorpej (*adapter->mii_setbit)(adapter->adapter_softc, MII_CLOCK);
271 1.1 bouyer
272 1.2 thorpej if (err == 0)
273 1.1 bouyer return val;
274 1.1 bouyer else
275 1.1 bouyer return -1;
276 1.1 bouyer }
277 1.1 bouyer
278 1.2 thorpej void
279 1.2 thorpej mii_writereg(v, phy, reg, data)
280 1.1 bouyer void *v;
281 1.1 bouyer u_int16_t phy;
282 1.1 bouyer u_int16_t reg;
283 1.1 bouyer u_int16_t data;
284 1.1 bouyer {
285 1.1 bouyer mii_data_t *adapter = ((struct mii_softc *)v)->adapter;
286 1.1 bouyer
287 1.2 thorpej if (adapter->mii_writereg) {
288 1.2 thorpej /* Interface has a special way of writing to the PHY. */
289 1.2 thorpej (*adapter->mii_writereg)(adapter, phy, reg, data);
290 1.1 bouyer return;
291 1.1 bouyer }
292 1.1 bouyer
293 1.1 bouyer /* else write using the control lines */
294 1.1 bouyer mii_sync(adapter);
295 1.1 bouyer mii_sendbit(adapter, MII_START, 2);
296 1.1 bouyer mii_sendbit(adapter, MII_WRITE, 2);
297 1.1 bouyer mii_sendbit(adapter, phy, 5);
298 1.1 bouyer mii_sendbit(adapter, reg, 5);
299 1.1 bouyer mii_sendbit(adapter, MII_ACK, 2);
300 1.1 bouyer mii_sendbit(adapter, data, 16);
301 1.1 bouyer
302 1.2 thorpej (*adapter->mii_clrbit)(adapter->adapter_softc, MII_CLOCK);
303 1.2 thorpej (*adapter->mii_setbit)(adapter->adapter_softc, MII_CLOCK);
304 1.1 bouyer }
305 1.1 bouyer
306 1.2 thorpej void
307 1.2 thorpej mii_media_add(ifmedia, adapter)
308 1.1 bouyer struct ifmedia *ifmedia;
309 1.1 bouyer mii_data_t *adapter;
310 1.1 bouyer {
311 1.1 bouyer struct mii_softc *sc = adapter->mii_sc;
312 1.1 bouyer int i;
313 1.1 bouyer u_int32_t media = 0;
314 1.1 bouyer
315 1.1 bouyer for (i = 0; i < 32; i++) {
316 1.1 bouyer if (sc->phy[i])
317 1.1 bouyer media |= sc->phy[i]->phy_media;
318 1.1 bouyer }
319 1.1 bouyer if (media & PHY_BNC)
320 1.1 bouyer ifmedia_add(ifmedia, IFM_ETHER | IFM_10_2, 0, NULL);
321 1.1 bouyer if (media & PHY_AUI)
322 1.1 bouyer ifmedia_add(ifmedia, IFM_ETHER | IFM_10_5, 0, NULL);
323 1.1 bouyer if (media & PHY_10baseT)
324 1.1 bouyer ifmedia_add(ifmedia, IFM_ETHER | IFM_10_T, 0, NULL);
325 1.1 bouyer if (media & PHY_10baseTfd)
326 1.1 bouyer ifmedia_add(ifmedia, IFM_ETHER | IFM_10_T | IFM_FDX, 0, NULL);
327 1.1 bouyer if (media & PHY_100baseTx)
328 1.1 bouyer ifmedia_add(ifmedia, IFM_ETHER | IFM_100_TX, 0, NULL);
329 1.1 bouyer if (media & PHY_100baseTxfd)
330 1.1 bouyer ifmedia_add(ifmedia, IFM_ETHER | IFM_100_TX | IFM_FDX, 0, NULL);
331 1.1 bouyer if (media & PHY_100baseT4)
332 1.1 bouyer ifmedia_add(ifmedia, IFM_ETHER | IFM_100_T4, 0, NULL);
333 1.1 bouyer ifmedia_add(ifmedia, IFM_ETHER | IFM_NONE, 0, NULL);
334 1.1 bouyer }
335 1.1 bouyer
336 1.2 thorpej int
337 1.2 thorpej mii_mediachg(adapter)
338 1.1 bouyer mii_data_t *adapter;
339 1.1 bouyer {
340 1.1 bouyer struct mii_softc *sc = adapter->mii_sc;
341 1.1 bouyer int i, best = -1, error = 0;
342 1.1 bouyer int media = adapter->mii_media_active;
343 1.1 bouyer
344 1.1 bouyer sc->current_phy = NULL;
345 1.1 bouyer
346 1.2 thorpej for (i = 0; i < 32; i++) {
347 1.1 bouyer if (sc->phy[i] == NULL)
348 1.1 bouyer continue;
349 1.2 thorpej switch (sc->phy[i]->phy_media_set(media,
350 1.2 thorpej sc->phy[i]->phy_softc)) {
351 1.2 thorpej case -1: /* PHY not available */
352 1.1 bouyer break;
353 1.2 thorpej case 0: /* link sucessfully selected */
354 1.1 bouyer sc->current_phy = sc->phy[i];
355 1.1 bouyer break;
356 1.2 thorpej case ENETDOWN: /* link selected but not up */
357 1.1 bouyer best = i;
358 1.1 bouyer break;
359 1.1 bouyer default:
360 1.1 bouyer break;
361 1.1 bouyer }
362 1.1 bouyer }
363 1.1 bouyer if (sc->current_phy == NULL) {
364 1.2 thorpej /*
365 1.2 thorpej * We didn't find a valid media. Select the best one (i.e.
366 1.2 thorpej * last supported but not up). If media != autoselect,
367 1.2 thorpej * don't report any error code.
368 1.2 thorpej */
369 1.1 bouyer if (best < 0)
370 1.2 thorpej return (EINVAL);
371 1.1 bouyer sc->current_phy = sc->phy[best];
372 1.2 thorpej error = sc->phy[best]->phy_media_set(media,
373 1.2 thorpej sc->phy[best]->phy_softc);
374 1.1 bouyer if (media != IFM_AUTO)
375 1.2 thorpej error = 0;
376 1.1 bouyer }
377 1.1 bouyer /* power down all but current phy */
378 1.2 thorpej for (i = 0; i < 32; i++) {
379 1.1 bouyer if (sc->phy[i] != sc->current_phy) {
380 1.1 bouyer if (sc->phy[i] == NULL)
381 1.1 bouyer mii_writereg(sc, i, PHY_CONTROL, CTRL_ISO);
382 1.1 bouyer else
383 1.1 bouyer sc->phy[i]->phy_pdown(sc->phy[i]->phy_softc);
384 1.1 bouyer }
385 1.1 bouyer }
386 1.2 thorpej return (error);
387 1.1 bouyer }
388 1.1 bouyer
389 1.2 thorpej void
390 1.2 thorpej mii_pollstat(adapter)
391 1.1 bouyer mii_data_t *adapter;
392 1.1 bouyer {
393 1.1 bouyer struct mii_softc *sc = adapter->mii_sc;
394 1.1 bouyer
395 1.1 bouyer adapter->mii_media_status = IFM_AVALID;
396 1.1 bouyer if (sc->current_phy == NULL)
397 1.1 bouyer return;
398 1.2 thorpej if ((*sc->current_phy->phy_status)(adapter->mii_media_active,
399 1.2 thorpej sc->current_phy->phy_softc) == 0)
400 1.1 bouyer adapter->mii_media_status |= IFM_ACTIVE;
401 1.1 bouyer }
402