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