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