mii.c (213364) | mii.c (213878) |
---|---|
1/* $NetBSD: mii.c,v 1.12 1999/08/03 19:41:49 drochner Exp $ */ 2 3/*- 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, --- 17 unchanged lines hidden (view full) --- 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. 31 */ 32 33#include <sys/cdefs.h> | 1/* $NetBSD: mii.c,v 1.12 1999/08/03 19:41:49 drochner Exp $ */ 2 3/*- 4 * Copyright (c) 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, --- 17 unchanged lines hidden (view full) --- 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. 31 */ 32 33#include <sys/cdefs.h> |
34__FBSDID("$FreeBSD: head/sys/dev/mii/mii.c 213364 2010-10-02 18:53:12Z marius $"); | 34__FBSDID("$FreeBSD: head/sys/dev/mii/mii.c 213878 2010-10-14 22:01:40Z marius $"); |
35 36/* 37 * MII bus layer, glues MII-capable network interface drivers to sharable 38 * PHY drivers. This exports an interface compatible with BSD/OS 3.0's, 39 * plus some NetBSD extensions. 40 */ 41 42#include <sys/param.h> --- 10 unchanged lines hidden (view full) --- 53#include <dev/mii/mii.h> 54#include <dev/mii/miivar.h> 55 56MODULE_VERSION(miibus, 1); 57 58#include "miibus_if.h" 59 60static int miibus_print_child(device_t dev, device_t child); | 35 36/* 37 * MII bus layer, glues MII-capable network interface drivers to sharable 38 * PHY drivers. This exports an interface compatible with BSD/OS 3.0's, 39 * plus some NetBSD extensions. 40 */ 41 42#include <sys/param.h> --- 10 unchanged lines hidden (view full) --- 53#include <dev/mii/mii.h> 54#include <dev/mii/miivar.h> 55 56MODULE_VERSION(miibus, 1); 57 58#include "miibus_if.h" 59 60static int miibus_print_child(device_t dev, device_t child); |
61static int miibus_read_ivar(device_t dev, device_t child, int which, 62 uintptr_t *result); |
|
61static int miibus_child_location_str(device_t bus, device_t child, char *buf, 62 size_t buflen); 63static int miibus_child_pnpinfo_str(device_t bus, device_t child, char *buf, 64 size_t buflen); 65static int miibus_readreg(device_t, int, int); 66static int miibus_writereg(device_t, int, int, int); 67static void miibus_statchg(device_t); 68static void miibus_linkchg(device_t); 69static void miibus_mediainit(device_t); 70 71static device_method_t miibus_methods[] = { 72 /* device interface */ 73 DEVMETHOD(device_probe, miibus_probe), 74 DEVMETHOD(device_attach, miibus_attach), 75 DEVMETHOD(device_detach, miibus_detach), 76 DEVMETHOD(device_shutdown, bus_generic_shutdown), 77 78 /* bus interface */ 79 DEVMETHOD(bus_print_child, miibus_print_child), | 63static int miibus_child_location_str(device_t bus, device_t child, char *buf, 64 size_t buflen); 65static int miibus_child_pnpinfo_str(device_t bus, device_t child, char *buf, 66 size_t buflen); 67static int miibus_readreg(device_t, int, int); 68static int miibus_writereg(device_t, int, int, int); 69static void miibus_statchg(device_t); 70static void miibus_linkchg(device_t); 71static void miibus_mediainit(device_t); 72 73static device_method_t miibus_methods[] = { 74 /* device interface */ 75 DEVMETHOD(device_probe, miibus_probe), 76 DEVMETHOD(device_attach, miibus_attach), 77 DEVMETHOD(device_detach, miibus_detach), 78 DEVMETHOD(device_shutdown, bus_generic_shutdown), 79 80 /* bus interface */ 81 DEVMETHOD(bus_print_child, miibus_print_child), |
82 DEVMETHOD(bus_read_ivar, miibus_read_ivar), |
|
80 DEVMETHOD(bus_driver_added, bus_generic_driver_added), 81 DEVMETHOD(bus_child_pnpinfo_str, miibus_child_pnpinfo_str), 82 DEVMETHOD(bus_child_location_str, miibus_child_location_str), 83 84 /* MII interface */ 85 DEVMETHOD(miibus_readreg, miibus_readreg), 86 DEVMETHOD(miibus_writereg, miibus_writereg), 87 DEVMETHOD(miibus_statchg, miibus_statchg), --- 7 unchanged lines hidden (view full) --- 95 96driver_t miibus_driver = { 97 "miibus", 98 miibus_methods, 99 sizeof(struct mii_data) 100}; 101 102struct miibus_ivars { | 83 DEVMETHOD(bus_driver_added, bus_generic_driver_added), 84 DEVMETHOD(bus_child_pnpinfo_str, miibus_child_pnpinfo_str), 85 DEVMETHOD(bus_child_location_str, miibus_child_location_str), 86 87 /* MII interface */ 88 DEVMETHOD(miibus_readreg, miibus_readreg), 89 DEVMETHOD(miibus_writereg, miibus_writereg), 90 DEVMETHOD(miibus_statchg, miibus_statchg), --- 7 unchanged lines hidden (view full) --- 98 99driver_t miibus_driver = { 100 "miibus", 101 miibus_methods, 102 sizeof(struct mii_data) 103}; 104 105struct miibus_ivars { |
106 struct ifnet *ifp; |
|
103 ifm_change_cb_t ifmedia_upd; 104 ifm_stat_cb_t ifmedia_sts; | 107 ifm_change_cb_t ifmedia_upd; 108 ifm_stat_cb_t ifmedia_sts; |
109 int mii_flags; |
|
105}; 106 | 110}; 111 |
107/* 108 * Helper function used by network interface drivers, attaches PHYs 109 * to the network interface driver parent. 110 */ | |
111int 112miibus_probe(device_t dev) 113{ | 112int 113miibus_probe(device_t dev) 114{ |
114 struct mii_attach_args ma, *args; 115 struct mii_data *mii; 116 device_t child = NULL, parent; 117 int bmsr, capmask = 0xFFFFFFFF; | |
118 | 115 |
119 mii = device_get_softc(dev); 120 parent = device_get_parent(dev); 121 LIST_INIT(&mii->mii_phys); 122 123 for (ma.mii_phyno = 0; ma.mii_phyno < MII_NPHY; ma.mii_phyno++) { 124 /* 125 * Check to see if there is a PHY at this address. Note, 126 * many braindead PHYs report 0/0 in their ID registers, 127 * so we test for media in the BMSR. 128 */ 129 bmsr = MIIBUS_READREG(parent, ma.mii_phyno, MII_BMSR); 130 if (bmsr == 0 || bmsr == 0xffff || 131 (bmsr & (BMSR_EXTSTAT | BMSR_MEDIAMASK)) == 0) { 132 /* Assume no PHY at this address. */ 133 continue; 134 } 135 136 /* 137 * Extract the IDs. Braindead PHYs will be handled by 138 * the `ukphy' driver, as we have no ID information to 139 * match on. 140 */ 141 ma.mii_id1 = MIIBUS_READREG(parent, ma.mii_phyno, 142 MII_PHYIDR1); 143 ma.mii_id2 = MIIBUS_READREG(parent, ma.mii_phyno, 144 MII_PHYIDR2); 145 146 ma.mii_data = mii; 147 ma.mii_capmask = capmask; 148 149 args = malloc(sizeof(struct mii_attach_args), 150 M_DEVBUF, M_NOWAIT); 151 bcopy((char *)&ma, (char *)args, sizeof(ma)); 152 child = device_add_child(dev, NULL, -1); 153 device_set_ivars(child, args); 154 } 155 156 if (child == NULL) 157 return (ENXIO); 158 | |
159 device_set_desc(dev, "MII bus"); 160 | 116 device_set_desc(dev, "MII bus"); 117 |
161 return (0); | 118 return (BUS_PROBE_SPECIFIC); |
162} 163 164int 165miibus_attach(device_t dev) 166{ 167 struct miibus_ivars *ivars; | 119} 120 121int 122miibus_attach(device_t dev) 123{ 124 struct miibus_ivars *ivars; |
125 struct mii_attach_args *ma; |
|
168 struct mii_data *mii; | 126 struct mii_data *mii; |
127 device_t *children; 128 int i, nchildren; |
|
169 170 mii = device_get_softc(dev); | 129 130 mii = device_get_softc(dev); |
171 /* 172 * Note that each NIC's softc must start with an ifnet pointer. 173 * XXX: EVIL HACK! 174 */ 175 mii->mii_ifp = *(struct ifnet**)device_get_softc(device_get_parent(dev)); 176 mii->mii_ifp->if_capabilities |= IFCAP_LINKSTATE; 177 mii->mii_ifp->if_capenable |= IFCAP_LINKSTATE; | 131 nchildren = 0; 132 if (device_get_children(dev, &children, &nchildren) == 0) { 133 for (i = 0; i < nchildren; i++) { 134 ma = device_get_ivars(children[i]); 135 ma->mii_data = mii; 136 } 137 free(children, M_TEMP); 138 } 139 if (nchildren == 0) { 140 device_printf(dev, "cannot get children"); 141 return (ENXIO); 142 } |
178 ivars = device_get_ivars(dev); 179 ifmedia_init(&mii->mii_media, IFM_IMASK, ivars->ifmedia_upd, 180 ivars->ifmedia_sts); | 143 ivars = device_get_ivars(dev); 144 ifmedia_init(&mii->mii_media, IFM_IMASK, ivars->ifmedia_upd, 145 ivars->ifmedia_sts); |
181 bus_generic_attach(dev); | 146 mii->mii_ifp = ivars->ifp; 147 mii->mii_ifp->if_capabilities |= IFCAP_LINKSTATE; 148 mii->mii_ifp->if_capenable |= IFCAP_LINKSTATE; 149 LIST_INIT(&mii->mii_phys); |
182 | 150 |
183 return (0); | 151 return (bus_generic_attach(dev)); |
184} 185 186int 187miibus_detach(device_t dev) 188{ 189 struct mii_data *mii; 190 191 bus_generic_detach(dev); --- 14 unchanged lines hidden (view full) --- 206 retval = bus_print_child_header(dev, child); 207 retval += printf(" PHY %d", ma->mii_phyno); 208 retval += bus_print_child_footer(dev, child); 209 210 return (retval); 211} 212 213static int | 152} 153 154int 155miibus_detach(device_t dev) 156{ 157 struct mii_data *mii; 158 159 bus_generic_detach(dev); --- 14 unchanged lines hidden (view full) --- 174 retval = bus_print_child_header(dev, child); 175 retval += printf(" PHY %d", ma->mii_phyno); 176 retval += bus_print_child_footer(dev, child); 177 178 return (retval); 179} 180 181static int |
214miibus_child_pnpinfo_str(device_t bus, device_t child, char *buf, | 182miibus_read_ivar(device_t dev, device_t child __unused, int which, 183 uintptr_t *result) 184{ 185 struct miibus_ivars *ivars; 186 187 /* 188 * NB: this uses the instance variables of the miibus rather than 189 * its PHY children. 190 */ 191 ivars = device_get_ivars(dev); 192 switch (which) { 193 case MIIBUS_IVAR_FLAGS: 194 *result = ivars->mii_flags; 195 break; 196 default: 197 return (ENOENT); 198 } 199 return (0); 200} 201 202static int 203miibus_child_pnpinfo_str(device_t bus __unused, device_t child, char *buf, |
215 size_t buflen) 216{ 217 struct mii_attach_args *ma; 218 219 ma = device_get_ivars(child); 220 snprintf(buf, buflen, "oui=0x%x model=0x%x rev=0x%x", 221 MII_OUI(ma->mii_id1, ma->mii_id2), 222 MII_MODEL(ma->mii_id2), MII_REV(ma->mii_id2)); 223 return (0); 224} 225 226static int | 204 size_t buflen) 205{ 206 struct mii_attach_args *ma; 207 208 ma = device_get_ivars(child); 209 snprintf(buf, buflen, "oui=0x%x model=0x%x rev=0x%x", 210 MII_OUI(ma->mii_id1, ma->mii_id2), 211 MII_MODEL(ma->mii_id2), MII_REV(ma->mii_id2)); 212 return (0); 213} 214 215static int |
227miibus_child_location_str(device_t bus, device_t child, char *buf, | 216miibus_child_location_str(device_t bus __unused, device_t child, char *buf, |
228 size_t buflen) 229{ 230 struct mii_attach_args *ma; 231 232 ma = device_get_ivars(child); 233 snprintf(buf, buflen, "phyno=%d", ma->mii_phyno); 234 return (0); 235} --- 66 unchanged lines hidden (view full) --- 302 media = m->ifm_media; 303 if (media == (IFM_ETHER | IFM_AUTO)) 304 break; 305 } 306 307 ifmedia_set(&mii->mii_media, media); 308} 309 | 217 size_t buflen) 218{ 219 struct mii_attach_args *ma; 220 221 ma = device_get_ivars(child); 222 snprintf(buf, buflen, "phyno=%d", ma->mii_phyno); 223 return (0); 224} --- 66 unchanged lines hidden (view full) --- 291 media = m->ifm_media; 292 if (media == (IFM_ETHER | IFM_AUTO)) 293 break; 294 } 295 296 ifmedia_set(&mii->mii_media, media); 297} 298 |
299/* 300 * Helper function used by network interface drivers, attaches the miibus and 301 * the PHYs to the network interface driver parent. 302 */ |
|
310int | 303int |
311mii_phy_probe(device_t dev, device_t *child, ifm_change_cb_t ifmedia_upd, 312 ifm_stat_cb_t ifmedia_sts) | 304mii_attach(device_t dev, device_t *miibus, struct ifnet *ifp, 305 ifm_change_cb_t ifmedia_upd, ifm_stat_cb_t ifmedia_sts, int capmask, 306 int phyloc, int offloc, int flags) |
313{ | 307{ |
314 struct miibus_ivars *ivars; 315 int bmsr, i; | 308 struct miibus_ivars *ivars; 309 struct mii_attach_args ma, *args; 310 device_t *children, phy; 311 int bmsr, first, i, nchildren, offset, phymax, phymin, rv; |
316 | 312 |
317 ivars = malloc(sizeof(*ivars), M_DEVBUF, M_NOWAIT); 318 if (ivars == NULL) 319 return (ENOMEM); 320 ivars->ifmedia_upd = ifmedia_upd; 321 ivars->ifmedia_sts = ifmedia_sts; 322 *child = device_add_child(dev, "miibus", -1); 323 device_set_ivars(*child, ivars); | 313 if (phyloc != MII_PHY_ANY && offloc != MII_OFFSET_ANY) { 314 printf("%s: phyloc and offloc specified", __func__); 315 return (EINVAL); 316 } |
324 | 317 |
325 for (i = 0; i < MII_NPHY; i++) { 326 bmsr = MIIBUS_READREG(dev, i, MII_BMSR); 327 if (bmsr == 0 || bmsr == 0xffff || 328 (bmsr & (BMSR_EXTSTAT | BMSR_MEDIAMASK)) == 0) { 329 /* Assume no PHY at this address. */ 330 continue; 331 } else 332 break; | 318 if (offloc != MII_OFFSET_ANY && (offloc < 0 || offloc >= MII_NPHY)) { 319 printf("%s: ivalid offloc %d", __func__, offloc); 320 return (EINVAL); |
333 } 334 | 321 } 322 |
335 if (i == MII_NPHY) { 336 device_delete_child(dev, *child); 337 *child = NULL; 338 return (ENXIO); | 323 if (phyloc == MII_PHY_ANY) { 324 phymin = 0; 325 phymax = MII_NPHY - 1; 326 } else { 327 if (phyloc < 0 || phyloc >= MII_NPHY) { 328 printf("%s: ivalid phyloc %d", __func__, phyloc); 329 return (EINVAL); 330 } 331 phymin = phymax = phyloc; |
339 } 340 | 332 } 333 |
341 bus_generic_attach(dev); | 334 first = 0; 335 if (*miibus == NULL) { 336 first = 1; 337 ivars = malloc(sizeof(*ivars), M_DEVBUF, M_NOWAIT); 338 if (ivars == NULL) 339 return (ENOMEM); 340 ivars->ifp = ifp; 341 ivars->ifmedia_upd = ifmedia_upd; 342 ivars->ifmedia_sts = ifmedia_sts; 343 ivars->mii_flags = flags; 344 *miibus = device_add_child(dev, "miibus", -1); 345 if (*miibus == NULL) { 346 rv = ENXIO; 347 goto fail; 348 } 349 device_set_ivars(*miibus, ivars); 350 } else { 351 ivars = device_get_ivars(*miibus); 352 if (ivars->ifp != ifp || ivars->ifmedia_upd != ifmedia_upd || 353 ivars->ifmedia_sts != ifmedia_sts || 354 ivars->mii_flags != flags) { 355 printf("%s: non-matching invariant", __func__); 356 return (EINVAL); 357 } 358 /* 359 * Assignment of the attach arguments mii_data for the first 360 * pass is done in miibus_attach(), i.e. once the miibus softc 361 * has been allocated. 362 */ 363 ma.mii_data = device_get_softc(*miibus); 364 } |
342 | 365 |
366 ma.mii_capmask = capmask; 367 368 phy = NULL; 369 offset = 0; 370 for (ma.mii_phyno = phymin; ma.mii_phyno <= phymax; ma.mii_phyno++) { 371 /* 372 * Make sure we haven't already configured a PHY at this 373 * address. This allows mii_attach() to be called 374 * multiple times. 375 */ 376 if (device_get_children(*miibus, &children, &nchildren) == 0) { 377 for (i = 0; i < nchildren; i++) { 378 args = device_get_ivars(children[i]); 379 if (args->mii_phyno == ma.mii_phyno) { 380 /* 381 * Yes, there is already something 382 * configured at this address. 383 */ 384 free(children, M_TEMP); 385 goto skip; 386 } 387 } 388 free(children, M_TEMP); 389 } 390 391 /* 392 * Check to see if there is a PHY at this address. Note, 393 * many braindead PHYs report 0/0 in their ID registers, 394 * so we test for media in the BMSR. 395 */ 396 bmsr = MIIBUS_READREG(dev, ma.mii_phyno, MII_BMSR); 397 if (bmsr == 0 || bmsr == 0xffff || 398 (bmsr & (BMSR_EXTSTAT | BMSR_MEDIAMASK)) == 0) { 399 /* Assume no PHY at this address. */ 400 continue; 401 } 402 403 /* 404 * There is a PHY at this address. If we were given an 405 * `offset' locator, skip this PHY if it doesn't match. 406 */ 407 if (offloc != MII_OFFSET_ANY && offloc != offset) 408 goto skip; 409 410 /* 411 * Extract the IDs. Braindead PHYs will be handled by 412 * the `ukphy' driver, as we have no ID information to 413 * match on. 414 */ 415 ma.mii_id1 = MIIBUS_READREG(dev, ma.mii_phyno, MII_PHYIDR1); 416 ma.mii_id2 = MIIBUS_READREG(dev, ma.mii_phyno, MII_PHYIDR2); 417 418 args = malloc(sizeof(struct mii_attach_args), M_DEVBUF, 419 M_NOWAIT); 420 if (args == NULL) 421 goto skip; 422 bcopy((char *)&ma, (char *)args, sizeof(ma)); 423 phy = device_add_child(*miibus, NULL, -1); 424 if (phy == NULL) { 425 free(args, M_DEVBUF); 426 goto skip; 427 } 428 device_set_ivars(phy, args); 429 skip: 430 offset++; 431 } 432 433 if (first != 0) { 434 if (phy == NULL) { 435 rv = ENXIO; 436 goto fail; 437 } 438 rv = bus_generic_attach(dev); 439 if (rv != 0) 440 goto fail; 441 } 442 rv = bus_generic_attach(*miibus); 443 if (rv != 0) 444 goto fail; 445 |
|
343 return (0); | 446 return (0); |
447 448 fail: 449 if (*miibus != NULL) 450 device_delete_child(dev, *miibus); 451 free(ivars, M_DEVBUF); 452 if (first != 0) 453 *miibus = NULL; 454 return (rv); |
|
344} 345 | 455} 456 |
457int 458mii_phy_probe(device_t dev, device_t *child, ifm_change_cb_t ifmedia_upd, 459 ifm_stat_cb_t ifmedia_sts) 460{ 461 struct ifnet *ifp; 462 463 /* 464 * Note that each NIC's softc must start with an ifnet pointer. 465 * XXX: EVIL HACK! 466 */ 467 ifp = *(struct ifnet **)device_get_softc(dev); 468 return (mii_attach(dev, child, ifp, ifmedia_upd, ifmedia_sts, 469 BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0)); 470} 471 |
|
346/* 347 * Media changed; notify all PHYs. 348 */ 349int 350mii_mediachg(struct mii_data *mii) 351{ 352 struct mii_softc *child; 353 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; --- 81 unchanged lines hidden --- | 472/* 473 * Media changed; notify all PHYs. 474 */ 475int 476mii_mediachg(struct mii_data *mii) 477{ 478 struct mii_softc *child; 479 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; --- 81 unchanged lines hidden --- |