1 /* $NetBSD: mii.c,v 1.12 1999/08/03 19:41:49 drochner Exp $ */
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
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 THE
30 * POSSIBILITY OF SUCH DAMAGE.
35 #define malloc(size, tag, flags) kernel_malloc(size, tag, flags)
36 #define free(pointer, tag) kernel_free(pointer, tag)
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
43 * MII bus layer, glues MII-capable network interface drivers to sharable
44 * PHY drivers. This exports an interface compatible with BSD/OS 3.0's,
45 * plus some NetBSD extensions.
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/socket.h>
51 #include <sys/malloc.h>
52 #include <sys/module.h>
56 #include <net/if_var.h>
57 #include <net/if_media.h>
59 #include <dev/mii/mii.h>
60 #include <dev/mii/miivar.h>
62 MODULE_VERSION(miibus
, 1);
64 #include "miibus_if.h"
66 static device_attach_t miibus_attach
;
67 static bus_child_location_str_t miibus_child_location_str
;
68 static bus_child_pnpinfo_str_t miibus_child_pnpinfo_str
;
69 static device_detach_t miibus_detach
;
70 static bus_hinted_child_t miibus_hinted_child
;
71 static bus_print_child_t miibus_print_child
;
72 static device_probe_t miibus_probe
;
73 static bus_read_ivar_t miibus_read_ivar
;
74 static miibus_readreg_t miibus_readreg
;
75 static miibus_statchg_t miibus_statchg
;
76 static miibus_writereg_t miibus_writereg
;
77 static miibus_linkchg_t miibus_linkchg
;
78 static miibus_mediainit_t miibus_mediainit
;
80 static unsigned char mii_bitreverse(unsigned char x
);
82 static device_method_t miibus_methods
[] = {
83 /* device interface */
84 DEVMETHOD(device_probe
, miibus_probe
),
85 DEVMETHOD(device_attach
, miibus_attach
),
86 DEVMETHOD(device_detach
, miibus_detach
),
87 DEVMETHOD(device_shutdown
, bus_generic_shutdown
),
90 DEVMETHOD(bus_print_child
, miibus_print_child
),
91 DEVMETHOD(bus_read_ivar
, miibus_read_ivar
),
92 DEVMETHOD(bus_child_pnpinfo_str
, miibus_child_pnpinfo_str
),
93 DEVMETHOD(bus_child_location_str
, miibus_child_location_str
),
94 DEVMETHOD(bus_hinted_child
, miibus_hinted_child
),
97 DEVMETHOD(miibus_readreg
, miibus_readreg
),
98 DEVMETHOD(miibus_writereg
, miibus_writereg
),
99 DEVMETHOD(miibus_statchg
, miibus_statchg
),
100 DEVMETHOD(miibus_linkchg
, miibus_linkchg
),
101 DEVMETHOD(miibus_mediainit
, miibus_mediainit
),
106 devclass_t miibus_devclass
;
108 driver_t miibus_driver
= {
111 sizeof(struct mii_data
)
114 struct miibus_ivars
{
116 ifm_change_cb_t ifmedia_upd
;
117 ifm_stat_cb_t ifmedia_sts
;
123 miibus_probe(device_t dev
)
126 device_set_desc(dev
, "MII bus");
128 return (BUS_PROBE_SPECIFIC
);
132 miibus_attach(device_t dev
)
134 struct miibus_ivars
*ivars
;
135 struct mii_attach_args
*ma
;
136 struct mii_data
*mii
;
140 mii
= device_get_softc(dev
);
141 if (device_get_children(dev
, &children
, &nchildren
) == 0) {
142 for (i
= 0; i
< nchildren
; i
++) {
143 ma
= device_get_ivars(children
[i
]);
146 free(children
, M_TEMP
);
148 if (nchildren
== 0) {
149 device_printf(dev
, "cannot get children\n");
152 ivars
= device_get_ivars(dev
);
153 ifmedia_init(&mii
->mii_media
, IFM_IMASK
, ivars
->ifmedia_upd
,
155 mii
->mii_ifp
= ivars
->ifp
;
156 if_setcapabilitiesbit(mii
->mii_ifp
, IFCAP_LINKSTATE
, 0);
157 if_setcapenablebit(mii
->mii_ifp
, IFCAP_LINKSTATE
, 0);
158 LIST_INIT(&mii
->mii_phys
);
160 return (bus_generic_attach(dev
));
164 miibus_detach(device_t dev
)
166 struct mii_data
*mii
;
168 bus_generic_detach(dev
);
169 mii
= device_get_softc(dev
);
170 ifmedia_removeall(&mii
->mii_media
);
177 miibus_print_child(device_t dev
, device_t child
)
179 struct mii_attach_args
*ma
;
182 ma
= device_get_ivars(child
);
183 retval
= bus_print_child_header(dev
, child
);
184 retval
+= printf(" PHY %d", ma
->mii_phyno
);
185 retval
+= bus_print_child_footer(dev
, child
);
191 miibus_read_ivar(device_t dev
, device_t child __unused
, int which
,
194 struct miibus_ivars
*ivars
;
197 * NB: this uses the instance variables of the miibus rather than
200 ivars
= device_get_ivars(dev
);
202 case MIIBUS_IVAR_FLAGS
:
203 *result
= ivars
->mii_flags
;
212 miibus_child_pnpinfo_str(device_t dev __unused
, device_t child
, char *buf
,
215 struct mii_attach_args
*ma
;
217 ma
= device_get_ivars(child
);
218 snprintf(buf
, buflen
, "oui=0x%x model=0x%x rev=0x%x",
219 MII_OUI(ma
->mii_id1
, ma
->mii_id2
),
220 MII_MODEL(ma
->mii_id2
), MII_REV(ma
->mii_id2
));
225 miibus_child_location_str(device_t dev __unused
, device_t child
, char *buf
,
228 struct mii_attach_args
*ma
;
230 ma
= device_get_ivars(child
);
231 snprintf(buf
, buflen
, "phyno=%d", ma
->mii_phyno
);
236 miibus_hinted_child(device_t dev
, const char *name
, int unit
)
238 struct miibus_ivars
*ivars
;
239 struct mii_attach_args
*args
, *ma
;
240 device_t
*children
, phy
;
244 if (resource_int_value(name
, unit
, "phyno", &val
) != 0)
246 if (device_get_children(dev
, &children
, &nchildren
) != 0)
249 for (i
= 0; i
< nchildren
; i
++) {
250 args
= device_get_ivars(children
[i
]);
251 if (args
->mii_phyno
== val
) {
256 free(children
, M_TEMP
);
259 * Don't add a PHY that was automatically identified by having media
260 * in its BMSR twice, only allow to alter its attach arguments.
263 ma
= malloc(sizeof(struct mii_attach_args
), M_DEVBUF
,
267 phy
= device_add_child(dev
, name
, unit
);
272 ivars
= device_get_ivars(dev
);
274 ma
->mii_offset
= ivars
->mii_offset
++;
277 ma
->mii_capmask
= BMSR_DEFCAPMASK
;
278 device_set_ivars(phy
, ma
);
281 if (resource_int_value(name
, unit
, "id1", &val
) == 0)
283 if (resource_int_value(name
, unit
, "id2", &val
) == 0)
285 if (resource_int_value(name
, unit
, "capmask", &val
) == 0)
286 ma
->mii_capmask
= val
;
290 miibus_readreg(device_t dev
, int phy
, int reg
)
294 parent
= device_get_parent(dev
);
295 return (MIIBUS_READREG(parent
, phy
, reg
));
299 miibus_writereg(device_t dev
, int phy
, int reg
, int data
)
303 parent
= device_get_parent(dev
);
304 return (MIIBUS_WRITEREG(parent
, phy
, reg
, data
));
308 miibus_statchg(device_t dev
)
311 struct mii_data
*mii
;
313 parent
= device_get_parent(dev
);
314 MIIBUS_STATCHG(parent
);
316 mii
= device_get_softc(dev
);
317 if_setbaudrate(mii
->mii_ifp
, ifmedia_baudrate(mii
->mii_media_active
));
321 miibus_linkchg(device_t dev
)
323 struct mii_data
*mii
;
327 parent
= device_get_parent(dev
);
328 MIIBUS_LINKCHG(parent
);
330 mii
= device_get_softc(dev
);
332 if (mii
->mii_media_status
& IFM_AVALID
) {
333 if (mii
->mii_media_status
& IFM_ACTIVE
)
334 link_state
= LINK_STATE_UP
;
336 link_state
= LINK_STATE_DOWN
;
338 link_state
= LINK_STATE_UNKNOWN
;
339 if_link_state_change(mii
->mii_ifp
, link_state
);
343 miibus_mediainit(device_t dev
)
345 struct mii_data
*mii
;
346 struct ifmedia_entry
*m
;
349 /* Poke the parent in case it has any media of its own to add. */
350 MIIBUS_MEDIAINIT(device_get_parent(dev
));
352 mii
= device_get_softc(dev
);
353 LIST_FOREACH(m
, &mii
->mii_media
.ifm_list
, ifm_list
) {
354 media
= m
->ifm_media
;
355 if (media
== (IFM_ETHER
| IFM_AUTO
))
359 ifmedia_set(&mii
->mii_media
, media
);
363 * Helper function used by network interface drivers, attaches the miibus and
364 * the PHYs to the network interface driver parent.
367 mii_attach(device_t dev
, device_t
*miibus
, if_t ifp
,
368 ifm_change_cb_t ifmedia_upd
, ifm_stat_cb_t ifmedia_sts
, int capmask
,
369 int phyloc
, int offloc
, int flags
)
371 struct miibus_ivars
*ivars
;
372 struct mii_attach_args
*args
, ma
;
373 device_t
*children
, phy
;
374 int bmsr
, first
, i
, nchildren
, phymax
, phymin
, rv
;
377 if (phyloc
!= MII_PHY_ANY
&& offloc
!= MII_OFFSET_ANY
) {
378 printf("%s: phyloc and offloc specified\n", __func__
);
382 if (offloc
!= MII_OFFSET_ANY
&& (offloc
< 0 || offloc
>= MII_NPHY
)) {
383 printf("%s: invalid offloc %d\n", __func__
, offloc
);
387 if (phyloc
== MII_PHY_ANY
) {
389 phymax
= MII_NPHY
- 1;
391 if (phyloc
< 0 || phyloc
>= MII_NPHY
) {
392 printf("%s: invalid phyloc %d\n", __func__
, phyloc
);
395 phymin
= phymax
= phyloc
;
399 if (*miibus
== NULL
) {
401 ivars
= malloc(sizeof(*ivars
), M_DEVBUF
, M_NOWAIT
);
405 ivars
->ifmedia_upd
= ifmedia_upd
;
406 ivars
->ifmedia_sts
= ifmedia_sts
;
407 ivars
->mii_flags
= flags
;
408 *miibus
= device_add_child(dev
, "miibus", -1);
409 if (*miibus
== NULL
) {
413 device_set_ivars(*miibus
, ivars
);
415 ivars
= device_get_ivars(*miibus
);
416 if (ivars
->ifp
!= ifp
|| ivars
->ifmedia_upd
!= ifmedia_upd
||
417 ivars
->ifmedia_sts
!= ifmedia_sts
||
418 ivars
->mii_flags
!= flags
) {
419 printf("%s: non-matching invariant\n", __func__
);
423 * Assignment of the attach arguments mii_data for the first
424 * pass is done in miibus_attach(), i.e. once the miibus softc
425 * has been allocated.
427 ma
.mii_data
= device_get_softc(*miibus
);
430 ma
.mii_capmask
= capmask
;
432 if (resource_int_value(device_get_name(*miibus
),
433 device_get_unit(*miibus
), "phymask", &phymask
) != 0)
434 phymask
= 0xffffffff;
436 if (device_get_children(*miibus
, &children
, &nchildren
) != 0) {
440 ivars
->mii_offset
= 0;
441 for (ma
.mii_phyno
= phymin
; ma
.mii_phyno
<= phymax
; ma
.mii_phyno
++) {
443 * Make sure we haven't already configured a PHY at this
444 * address. This allows mii_attach() to be called
447 for (i
= 0; i
< nchildren
; i
++) {
448 args
= device_get_ivars(children
[i
]);
449 if (args
->mii_phyno
== ma
.mii_phyno
) {
451 * Yes, there is already something
452 * configured at this address.
459 * Check to see if there is a PHY at this address. Note,
460 * many braindead PHYs report 0/0 in their ID registers,
461 * so we test for media in the BMSR.
463 bmsr
= MIIBUS_READREG(dev
, ma
.mii_phyno
, MII_BMSR
);
464 if (bmsr
== 0 || bmsr
== 0xffff ||
465 (bmsr
& (BMSR_EXTSTAT
| BMSR_MEDIAMASK
)) == 0) {
466 /* Assume no PHY at this address. */
471 * There is a PHY at this address. If we were given an
472 * `offset' locator, skip this PHY if it doesn't match.
474 if (offloc
!= MII_OFFSET_ANY
&& offloc
!= ivars
->mii_offset
)
478 * Skip this PHY if it's not included in the phymask hint.
480 if ((phymask
& (1 << ma
.mii_phyno
)) == 0)
484 * Extract the IDs. Braindead PHYs will be handled by
485 * the `ukphy' driver, as we have no ID information to
488 ma
.mii_id1
= MIIBUS_READREG(dev
, ma
.mii_phyno
, MII_PHYIDR1
);
489 ma
.mii_id2
= MIIBUS_READREG(dev
, ma
.mii_phyno
, MII_PHYIDR2
);
491 ma
.mii_offset
= ivars
->mii_offset
;
492 args
= malloc(sizeof(struct mii_attach_args
), M_DEVBUF
,
496 bcopy((char *)&ma
, (char *)args
, sizeof(ma
));
497 phy
= device_add_child(*miibus
, NULL
, -1);
499 free(args
, M_DEVBUF
);
502 device_set_ivars(phy
, args
);
506 free(children
, M_TEMP
);
509 rv
= device_set_driver(*miibus
, &miibus_driver
);
512 bus_enumerate_hinted_children(*miibus
);
513 rv
= device_get_children(*miibus
, &children
, &nchildren
);
516 free(children
, M_TEMP
);
517 if (nchildren
== 0) {
521 rv
= bus_generic_attach(dev
);
525 /* Attaching of the PHY drivers is done in miibus_attach(). */
528 rv
= bus_generic_attach(*miibus
);
536 device_delete_child(dev
, *miibus
);
537 free(ivars
, M_DEVBUF
);
544 * Media changed; notify all PHYs.
547 mii_mediachg(struct mii_data
*mii
)
549 struct mii_softc
*child
;
550 struct ifmedia_entry
*ife
= mii
->mii_media
.ifm_cur
;
553 mii
->mii_media_status
= 0;
554 mii
->mii_media_active
= IFM_NONE
;
556 LIST_FOREACH(child
, &mii
->mii_phys
, mii_list
) {
558 * If the media indicates a different PHY instance,
561 if (IFM_INST(ife
->ifm_media
) != child
->mii_inst
) {
562 if ((child
->mii_flags
& MIIF_NOISOLATE
) != 0) {
563 device_printf(child
->mii_dev
, "%s: "
564 "can't handle non-zero PHY instance %d\n",
565 __func__
, child
->mii_inst
);
568 PHY_WRITE(child
, MII_BMCR
, PHY_READ(child
, MII_BMCR
) |
572 rv
= PHY_SERVICE(child
, mii
, MII_MEDIACHG
);
580 * Call the PHY tick routines, used during autonegotiation.
583 mii_tick(struct mii_data
*mii
)
585 struct mii_softc
*child
;
586 struct ifmedia_entry
*ife
= mii
->mii_media
.ifm_cur
;
588 LIST_FOREACH(child
, &mii
->mii_phys
, mii_list
) {
590 * If this PHY instance isn't currently selected, just skip
593 if (IFM_INST(ife
->ifm_media
) != child
->mii_inst
)
595 (void)PHY_SERVICE(child
, mii
, MII_TICK
);
600 * Get media status from PHYs.
603 mii_pollstat(struct mii_data
*mii
)
605 struct mii_softc
*child
;
606 struct ifmedia_entry
*ife
= mii
->mii_media
.ifm_cur
;
608 mii
->mii_media_status
= 0;
609 mii
->mii_media_active
= IFM_NONE
;
611 LIST_FOREACH(child
, &mii
->mii_phys
, mii_list
) {
613 * If we're not polling this PHY instance, just skip it.
615 if (IFM_INST(ife
->ifm_media
) != child
->mii_inst
)
617 (void)PHY_SERVICE(child
, mii
, MII_POLLSTAT
);
622 mii_bitreverse(unsigned char x
)
624 static unsigned const char nibbletab
[16] = {
625 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15
628 return ((nibbletab
[x
& 15] << 4) | nibbletab
[x
>> 4]);
632 mii_oui(u_int id1
, u_int id2
)
636 h
= (id1
<< 6) | (id2
>> 10);
638 return ((mii_bitreverse(h
>> 16) << 16) |
639 (mii_bitreverse((h
>> 8) & 0xff) << 8) |
640 mii_bitreverse(h
& 0xff));
644 mii_phy_mac_match(struct mii_softc
*mii
, const char *name
)
647 return (strcmp(device_get_name(device_get_parent(mii
->mii_dev
)),
652 mii_dev_mac_match(device_t parent
, const char *name
)
655 return (strcmp(device_get_name(device_get_parent(
656 device_get_parent(parent
))), name
) == 0);
660 mii_phy_mac_softc(struct mii_softc
*mii
)
663 return (device_get_softc(device_get_parent(mii
->mii_dev
)));
667 mii_dev_mac_softc(device_t parent
)
670 return (device_get_softc(device_get_parent(device_get_parent(parent
))));