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