FreeBSD/Linux Kernel Cross Reference
sys/dev/mii/dcphy.c
1 /*-
2 * Copyright (c) 1997, 1998, 1999
3 * Bill Paul <wpaul@ee.columbia.edu>. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Bill Paul.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include <sys/cdefs.h>
34 __FBSDID("$FreeBSD: releng/6.0/sys/dev/mii/dcphy.c 146734 2005-05-29 04:42:30Z nyan $");
35
36 /*
37 * Pseudo-driver for internal NWAY support on DEC 21143 and workalike
38 * controllers. Technically we're abusing the miibus code to handle
39 * media selection and NWAY support here since there is no MII
40 * interface. However the logical operations are roughly the same,
41 * and the alternative is to create a fake MII interface in the driver,
42 * which is harder to do.
43 */
44
45 #include <sys/param.h>
46 #include <sys/systm.h>
47 #include <sys/kernel.h>
48 #include <sys/socket.h>
49 #include <sys/errno.h>
50 #include <sys/lock.h>
51 #include <sys/module.h>
52 #include <sys/mutex.h>
53 #include <sys/bus.h>
54
55 #include <net/if.h>
56 #include <net/if_arp.h>
57 #include <net/if_media.h>
58
59 #include <dev/mii/mii.h>
60 #include <dev/mii/miivar.h>
61 #include "miidevs.h"
62
63 #include <machine/bus.h>
64 #include <machine/resource.h>
65 #include <sys/bus.h>
66
67 #include <dev/pci/pcivar.h>
68
69 #include <pci/if_dcreg.h>
70
71 #include "miibus_if.h"
72
73 #define DC_SETBIT(sc, reg, x) \
74 CSR_WRITE_4(sc, reg, \
75 CSR_READ_4(sc, reg) | x)
76
77 #define DC_CLRBIT(sc, reg, x) \
78 CSR_WRITE_4(sc, reg, \
79 CSR_READ_4(sc, reg) & ~x)
80
81 #define MIIF_AUTOTIMEOUT 0x0004
82
83 /*
84 * This is the subsystem ID for the built-in 21143 ethernet
85 * in several Compaq Presario systems. Apparently these are
86 * 10Mbps only, so we need to treat them specially.
87 */
88 #define COMPAQ_PRESARIO_ID 0xb0bb0e11
89
90 static int dcphy_probe(device_t);
91 static int dcphy_attach(device_t);
92
93 static device_method_t dcphy_methods[] = {
94 /* device interface */
95 DEVMETHOD(device_probe, dcphy_probe),
96 DEVMETHOD(device_attach, dcphy_attach),
97 DEVMETHOD(device_detach, mii_phy_detach),
98 DEVMETHOD(device_shutdown, bus_generic_shutdown),
99 { 0, 0 }
100 };
101
102 static devclass_t dcphy_devclass;
103
104 static driver_t dcphy_driver = {
105 "dcphy",
106 dcphy_methods,
107 sizeof(struct mii_softc)
108 };
109
110 DRIVER_MODULE(dcphy, miibus, dcphy_driver, dcphy_devclass, 0, 0);
111
112 static int dcphy_service(struct mii_softc *, struct mii_data *, int);
113 static void dcphy_status(struct mii_softc *);
114 static void dcphy_reset(struct mii_softc *);
115 static int dcphy_auto(struct mii_softc *);
116
117 static int
118 dcphy_probe(dev)
119 device_t dev;
120 {
121 struct mii_attach_args *ma;
122
123 ma = device_get_ivars(dev);
124
125 /*
126 * The dc driver will report the 21143 vendor and device
127 * ID to let us know that it wants us to attach.
128 */
129 if (ma->mii_id1 != DC_VENDORID_DEC ||
130 ma->mii_id2 != DC_DEVICEID_21143)
131 return(ENXIO);
132
133 device_set_desc(dev, "Intel 21143 NWAY media interface");
134
135 return (0);
136 }
137
138 static int
139 dcphy_attach(dev)
140 device_t dev;
141 {
142 struct mii_softc *sc;
143 struct mii_attach_args *ma;
144 struct mii_data *mii;
145 struct dc_softc *dc_sc;
146
147 sc = device_get_softc(dev);
148 ma = device_get_ivars(dev);
149 sc->mii_dev = device_get_parent(dev);
150 mii = device_get_softc(sc->mii_dev);
151 LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
152
153 sc->mii_inst = mii->mii_instance;
154 sc->mii_phy = ma->mii_phyno;
155 sc->mii_service = dcphy_service;
156 sc->mii_pdata = mii;
157
158 sc->mii_flags |= MIIF_NOISOLATE;
159 mii->mii_instance++;
160
161 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
162
163 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
164 BMCR_ISO);
165
166 /*dcphy_reset(sc);*/
167 dc_sc = mii->mii_ifp->if_softc;
168 CSR_WRITE_4(dc_sc, DC_10BTSTAT, 0);
169 CSR_WRITE_4(dc_sc, DC_10BTCTRL, 0);
170
171 switch(pci_read_config(device_get_parent(sc->mii_dev),
172 DC_PCI_CSID, 4)) {
173 case COMPAQ_PRESARIO_ID:
174 /* Example of how to only allow 10Mbps modes. */
175 sc->mii_capabilities = BMSR_ANEG|BMSR_10TFDX|BMSR_10THDX;
176 break;
177 default:
178 if (dc_sc->dc_pmode == DC_PMODE_SIA) {
179 sc->mii_capabilities =
180 BMSR_ANEG|BMSR_10TFDX|BMSR_10THDX;
181 } else {
182 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP,
183 sc->mii_inst), BMCR_LOOP|BMCR_S100);
184
185 sc->mii_capabilities =
186 BMSR_ANEG|BMSR_100TXFDX|BMSR_100TXHDX|
187 BMSR_10TFDX|BMSR_10THDX;
188 }
189 break;
190 }
191
192 sc->mii_capabilities &= ma->mii_capmask;
193 device_printf(dev, " ");
194 mii_add_media(sc);
195 printf("\n");
196 #undef ADD
197
198 MIIBUS_MEDIAINIT(sc->mii_dev);
199 return(0);
200 }
201
202 static int
203 dcphy_service(sc, mii, cmd)
204 struct mii_softc *sc;
205 struct mii_data *mii;
206 int cmd;
207 {
208 struct dc_softc *dc_sc;
209 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
210 int reg;
211 u_int32_t mode;
212
213 dc_sc = mii->mii_ifp->if_softc;
214
215 switch (cmd) {
216 case MII_POLLSTAT:
217 /*
218 * If we're not polling our PHY instance, just return.
219 */
220 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
221 return (0);
222 }
223 break;
224
225 case MII_MEDIACHG:
226 /*
227 * If the media indicates a different PHY instance,
228 * isolate ourselves.
229 */
230 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
231 return (0);
232 }
233
234 /*
235 * If the interface is not up, don't do anything.
236 */
237 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
238 break;
239
240 sc->mii_flags = 0;
241 mii->mii_media_active = IFM_NONE;
242 mode = CSR_READ_4(dc_sc, DC_NETCFG);
243 mode &= ~(DC_NETCFG_FULLDUPLEX|DC_NETCFG_PORTSEL|
244 DC_NETCFG_PCS|DC_NETCFG_SCRAMBLER|DC_NETCFG_SPEEDSEL);
245
246 switch (IFM_SUBTYPE(ife->ifm_media)) {
247 case IFM_AUTO:
248 /*dcphy_reset(sc);*/
249 (void) dcphy_auto(sc);
250 break;
251 case IFM_100_T4:
252 /*
253 * XXX Not supported as a manual setting right now.
254 */
255 return (EINVAL);
256 case IFM_100_TX:
257 dcphy_reset(sc);
258 DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
259 mode |= DC_NETCFG_PORTSEL|DC_NETCFG_PCS|
260 DC_NETCFG_SCRAMBLER;
261 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
262 mode |= DC_NETCFG_FULLDUPLEX;
263 else
264 mode &= ~DC_NETCFG_FULLDUPLEX;
265 CSR_WRITE_4(dc_sc, DC_NETCFG, mode);
266 break;
267 case IFM_10_T:
268 DC_CLRBIT(dc_sc, DC_SIARESET, DC_SIA_RESET);
269 DC_CLRBIT(dc_sc, DC_10BTCTRL, 0xFFFF);
270 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
271 DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3D);
272 else
273 DC_SETBIT(dc_sc, DC_10BTCTRL, 0x7F3F);
274 DC_SETBIT(dc_sc, DC_SIARESET, DC_SIA_RESET);
275 DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
276 mode &= ~DC_NETCFG_PORTSEL;
277 mode |= DC_NETCFG_SPEEDSEL;
278 if ((ife->ifm_media & IFM_GMASK) == IFM_FDX)
279 mode |= DC_NETCFG_FULLDUPLEX;
280 else
281 mode &= ~DC_NETCFG_FULLDUPLEX;
282 CSR_WRITE_4(dc_sc, DC_NETCFG, mode);
283 break;
284 default:
285 return(EINVAL);
286 }
287 break;
288
289 case MII_TICK:
290 /*
291 * If we're not currently selected, just return.
292 */
293 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
294 return (0);
295
296 /*
297 * Is the interface even up?
298 */
299 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
300 return (0);
301
302 /*
303 * Only used for autonegotiation.
304 */
305 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
306 break;
307
308 reg = CSR_READ_4(dc_sc, DC_10BTSTAT);
309 if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100))
310 break;
311
312 /*
313 * Only retry autonegotiation every 5 seconds.
314 *
315 * Otherwise, fall through to calling dcphy_status()
316 * since real Intel 21143 chips don't show valid link
317 * status until autonegotiation is switched off, and
318 * that only happens in dcphy_status(). Without this,
319 * successful autonegotiation is never recognised on
320 * these chips.
321 */
322 if (++sc->mii_ticks <= 50)
323 break;
324
325 sc->mii_ticks = 0;
326 dcphy_auto(sc);
327
328 break;
329 }
330
331 /* Update the media status. */
332 dcphy_status(sc);
333
334 /* Callback if something changed. */
335 mii_phy_update(sc, cmd);
336 return (0);
337 }
338
339 static void
340 dcphy_status(sc)
341 struct mii_softc *sc;
342 {
343 struct mii_data *mii = sc->mii_pdata;
344 int reg, anlpar, tstat = 0;
345 struct dc_softc *dc_sc;
346
347 dc_sc = mii->mii_ifp->if_softc;
348
349 mii->mii_media_status = IFM_AVALID;
350 mii->mii_media_active = IFM_ETHER;
351
352 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
353 return;
354
355 reg = CSR_READ_4(dc_sc, DC_10BTSTAT);
356 if (!(reg & DC_TSTAT_LS10) || !(reg & DC_TSTAT_LS100))
357 mii->mii_media_status |= IFM_ACTIVE;
358
359 if (CSR_READ_4(dc_sc, DC_10BTCTRL) & DC_TCTL_AUTONEGENBL) {
360 /* Erg, still trying, I guess... */
361 tstat = CSR_READ_4(dc_sc, DC_10BTSTAT);
362 if ((tstat & DC_TSTAT_ANEGSTAT) != DC_ASTAT_AUTONEGCMP) {
363 if ((DC_IS_MACRONIX(dc_sc) || DC_IS_PNICII(dc_sc)) &&
364 (tstat & DC_TSTAT_ANEGSTAT) == DC_ASTAT_DISABLE)
365 goto skip;
366 mii->mii_media_active |= IFM_NONE;
367 return;
368 }
369
370 if (tstat & DC_TSTAT_LP_CAN_NWAY) {
371 anlpar = tstat >> 16;
372 if (anlpar & ANLPAR_T4 &&
373 sc->mii_capabilities & BMSR_100TXHDX)
374 mii->mii_media_active |= IFM_100_T4;
375 else if (anlpar & ANLPAR_TX_FD &&
376 sc->mii_capabilities & BMSR_100TXFDX)
377 mii->mii_media_active |= IFM_100_TX|IFM_FDX;
378 else if (anlpar & ANLPAR_TX &&
379 sc->mii_capabilities & BMSR_100TXHDX)
380 mii->mii_media_active |= IFM_100_TX;
381 else if (anlpar & ANLPAR_10_FD)
382 mii->mii_media_active |= IFM_10_T|IFM_FDX;
383 else if (anlpar & ANLPAR_10)
384 mii->mii_media_active |= IFM_10_T;
385 else
386 mii->mii_media_active |= IFM_NONE;
387 if (DC_IS_INTEL(dc_sc))
388 DC_CLRBIT(dc_sc, DC_10BTCTRL,
389 DC_TCTL_AUTONEGENBL);
390 return;
391 }
392 /*
393 * If the other side doesn't support NWAY, then the
394 * best we can do is determine if we have a 10Mbps or
395 * 100Mbps link. There's no way to know if the link
396 * is full or half duplex, so we default to half duplex
397 * and hope that the user is clever enough to manually
398 * change the media settings if we're wrong.
399 */
400 if (!(reg & DC_TSTAT_LS100))
401 mii->mii_media_active |= IFM_100_TX;
402 else if (!(reg & DC_TSTAT_LS10))
403 mii->mii_media_active |= IFM_10_T;
404 else
405 mii->mii_media_active |= IFM_NONE;
406 if (DC_IS_INTEL(dc_sc))
407 DC_CLRBIT(dc_sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
408 return;
409 }
410
411 skip:
412
413 if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_SPEEDSEL)
414 mii->mii_media_active |= IFM_10_T;
415 else
416 mii->mii_media_active |= IFM_100_TX;
417 if (CSR_READ_4(dc_sc, DC_NETCFG) & DC_NETCFG_FULLDUPLEX)
418 mii->mii_media_active |= IFM_FDX;
419
420 return;
421 }
422
423 static int
424 dcphy_auto(mii)
425 struct mii_softc *mii;
426 {
427 struct dc_softc *sc;
428
429 sc = mii->mii_pdata->mii_ifp->if_softc;
430
431 DC_CLRBIT(sc, DC_NETCFG, DC_NETCFG_PORTSEL);
432 DC_SETBIT(sc, DC_NETCFG, DC_NETCFG_FULLDUPLEX);
433 DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET);
434 if (mii->mii_capabilities & BMSR_100TXHDX)
435 CSR_WRITE_4(sc, DC_10BTCTRL, 0x3FFFF);
436 else
437 CSR_WRITE_4(sc, DC_10BTCTRL, 0xFFFF);
438 DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET);
439 DC_SETBIT(sc, DC_10BTCTRL, DC_TCTL_AUTONEGENBL);
440 DC_SETBIT(sc, DC_10BTSTAT, DC_ASTAT_TXDISABLE);
441
442 return(EJUSTRETURN);
443 }
444
445 static void
446 dcphy_reset(mii)
447 struct mii_softc *mii;
448 {
449 struct dc_softc *sc;
450
451 sc = mii->mii_pdata->mii_ifp->if_softc;
452
453 DC_CLRBIT(sc, DC_SIARESET, DC_SIA_RESET);
454 DELAY(1000);
455 DC_SETBIT(sc, DC_SIARESET, DC_SIA_RESET);
456
457 return;
458 }
459
Cache object: e39531cb77acc91e2959b453bf40773f
|