1 /* $NetBSD: mii.c,v 1.12 1999/08/03 19:41:49 drochner Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-2-Clause-NetBSD 5 * 6 * Copyright (c) 1998 The NetBSD Foundation, Inc. 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to The NetBSD Foundation 10 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 11 * NASA Ames Research Center. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 38 /* 39 * MII bus layer, glues MII-capable network interface drivers to sharable 40 * PHY drivers. This exports an interface compatible with BSD/OS 3.0's, 41 * plus some NetBSD extensions. 42 */ 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/socket.h> 47 #include <sys/malloc.h> 48 #include <sys/module.h> 49 #include <sys/bus.h> 50 #include <sys/sbuf.h> 51 52 #include <net/if.h> 53 #include <net/if_var.h> 54 #include <net/if_media.h> 55 56 #include <dev/mii/mii.h> 57 #include <dev/mii/miivar.h> 58 59 MODULE_VERSION(miibus, 1); 60 61 #include "miibus_if.h" 62 63 static device_attach_t miibus_attach; 64 static bus_child_detached_t miibus_child_detached; 65 static bus_child_location_t miibus_child_location; 66 static bus_child_pnpinfo_t miibus_child_pnpinfo; 67 static device_detach_t miibus_detach; 68 static bus_hinted_child_t miibus_hinted_child; 69 static bus_print_child_t miibus_print_child; 70 static device_probe_t miibus_probe; 71 static bus_read_ivar_t miibus_read_ivar; 72 static miibus_readreg_t miibus_readreg; 73 static miibus_statchg_t miibus_statchg; 74 static miibus_writereg_t miibus_writereg; 75 static miibus_linkchg_t miibus_linkchg; 76 static miibus_mediainit_t miibus_mediainit; 77 78 static unsigned char mii_bitreverse(unsigned char x); 79 80 static device_method_t miibus_methods[] = { 81 /* device interface */ 82 DEVMETHOD(device_probe, miibus_probe), 83 DEVMETHOD(device_attach, miibus_attach), 84 DEVMETHOD(device_detach, miibus_detach), 85 DEVMETHOD(device_shutdown, bus_generic_shutdown), 86 87 /* bus interface */ 88 DEVMETHOD(bus_print_child, miibus_print_child), 89 DEVMETHOD(bus_read_ivar, miibus_read_ivar), 90 DEVMETHOD(bus_child_detached, miibus_child_detached), 91 DEVMETHOD(bus_child_pnpinfo, miibus_child_pnpinfo), 92 DEVMETHOD(bus_child_location, miibus_child_location), 93 DEVMETHOD(bus_hinted_child, miibus_hinted_child), 94 95 /* MII interface */ 96 DEVMETHOD(miibus_readreg, miibus_readreg), 97 DEVMETHOD(miibus_writereg, miibus_writereg), 98 DEVMETHOD(miibus_statchg, miibus_statchg), 99 DEVMETHOD(miibus_linkchg, miibus_linkchg), 100 DEVMETHOD(miibus_mediainit, miibus_mediainit), 101 102 DEVMETHOD_END 103 }; 104 105 devclass_t miibus_devclass; 106 107 driver_t miibus_driver = { 108 "miibus", 109 miibus_methods, 110 sizeof(struct mii_data) 111 }; 112 113 struct miibus_ivars { 114 if_t ifp; 115 ifm_change_cb_t ifmedia_upd; 116 ifm_stat_cb_t ifmedia_sts; 117 u_int mii_flags; 118 u_int mii_offset; 119 }; 120 121 static int 122 miibus_probe(device_t dev) 123 { 124 125 device_set_desc(dev, "MII bus"); 126 127 return (BUS_PROBE_SPECIFIC); 128 } 129 130 static int 131 miibus_attach(device_t dev) 132 { 133 struct miibus_ivars *ivars; 134 struct mii_attach_args *ma; 135 struct mii_data *mii; 136 device_t *children; 137 int i, nchildren; 138 139 mii = device_get_softc(dev); 140 if (device_get_children(dev, &children, &nchildren) == 0) { 141 for (i = 0; i < nchildren; i++) { 142 ma = device_get_ivars(children[i]); 143 ma->mii_data = mii; 144 } 145 free(children, M_TEMP); 146 } 147 if (nchildren == 0) { 148 device_printf(dev, "cannot get children\n"); 149 return (ENXIO); 150 } 151 ivars = device_get_ivars(dev); 152 ifmedia_init(&mii->mii_media, IFM_IMASK, ivars->ifmedia_upd, 153 ivars->ifmedia_sts); 154 mii->mii_ifp = ivars->ifp; 155 if_setcapabilitiesbit(mii->mii_ifp, IFCAP_LINKSTATE, 0); 156 if_setcapenablebit(mii->mii_ifp, IFCAP_LINKSTATE, 0); 157 LIST_INIT(&mii->mii_phys); 158 159 return (bus_generic_attach(dev)); 160 } 161 162 static int 163 miibus_detach(device_t dev) 164 { 165 struct mii_data *mii; 166 struct miibus_ivars *ivars; 167 168 ivars = device_get_ivars(dev); 169 bus_generic_detach(dev); 170 mii = device_get_softc(dev); 171 ifmedia_removeall(&mii->mii_media); 172 free(ivars, M_DEVBUF); 173 mii->mii_ifp = NULL; 174 175 return (0); 176 } 177 178 static void 179 miibus_child_detached(device_t dev, device_t child) 180 { 181 struct mii_attach_args *args; 182 183 args = device_get_ivars(child); 184 free(args, M_DEVBUF); 185 } 186 187 static int 188 miibus_print_child(device_t dev, device_t child) 189 { 190 struct mii_attach_args *ma; 191 int retval; 192 193 ma = device_get_ivars(child); 194 retval = bus_print_child_header(dev, child); 195 retval += printf(" PHY %d", ma->mii_phyno); 196 retval += bus_print_child_footer(dev, child); 197 198 return (retval); 199 } 200 201 static int 202 miibus_read_ivar(device_t dev, device_t child __unused, int which, 203 uintptr_t *result) 204 { 205 struct miibus_ivars *ivars; 206 207 /* 208 * NB: this uses the instance variables of the miibus rather than 209 * its PHY children. 210 */ 211 ivars = device_get_ivars(dev); 212 switch (which) { 213 case MIIBUS_IVAR_FLAGS: 214 *result = ivars->mii_flags; 215 break; 216 default: 217 return (ENOENT); 218 } 219 return (0); 220 } 221 222 static int 223 miibus_child_pnpinfo(device_t dev __unused, device_t child, struct sbuf *sb) 224 { 225 struct mii_attach_args *ma; 226 227 ma = device_get_ivars(child); 228 sbuf_printf(sb, "oui=0x%x model=0x%x rev=0x%x", 229 MII_OUI(ma->mii_id1, ma->mii_id2), 230 MII_MODEL(ma->mii_id2), MII_REV(ma->mii_id2)); 231 return (0); 232 } 233 234 static int 235 miibus_child_location(device_t dev __unused, device_t child, struct sbuf *sb) 236 { 237 struct mii_attach_args *ma; 238 239 ma = device_get_ivars(child); 240 sbuf_printf(sb, "phyno=%d", ma->mii_phyno); 241 return (0); 242 } 243 244 static void 245 miibus_hinted_child(device_t dev, const char *name, int unit) 246 { 247 struct miibus_ivars *ivars; 248 struct mii_attach_args *args, *ma; 249 device_t *children, phy; 250 int i, nchildren; 251 u_int val; 252 253 if (resource_int_value(name, unit, "phyno", &val) != 0) 254 return; 255 if (device_get_children(dev, &children, &nchildren) != 0) 256 return; 257 ma = NULL; 258 for (i = 0; i < nchildren; i++) { 259 args = device_get_ivars(children[i]); 260 if (args->mii_phyno == val) { 261 ma = args; 262 break; 263 } 264 } 265 free(children, M_TEMP); 266 267 /* 268 * Don't add a PHY that was automatically identified by having media 269 * in its BMSR twice, only allow to alter its attach arguments. 270 */ 271 if (ma == NULL) { 272 ma = malloc(sizeof(struct mii_attach_args), M_DEVBUF, 273 M_NOWAIT); 274 if (ma == NULL) 275 return; 276 phy = device_add_child(dev, name, unit); 277 if (phy == NULL) { 278 free(ma, M_DEVBUF); 279 return; 280 } 281 ivars = device_get_ivars(dev); 282 ma->mii_phyno = val; 283 ma->mii_offset = ivars->mii_offset++; 284 ma->mii_id1 = 0; 285 ma->mii_id2 = 0; 286 ma->mii_capmask = BMSR_DEFCAPMASK; 287 device_set_ivars(phy, ma); 288 } 289 290 if (resource_int_value(name, unit, "id1", &val) == 0) 291 ma->mii_id1 = val; 292 if (resource_int_value(name, unit, "id2", &val) == 0) 293 ma->mii_id2 = val; 294 if (resource_int_value(name, unit, "capmask", &val) == 0) 295 ma->mii_capmask = val; 296 } 297 298 static int 299 miibus_readreg(device_t dev, int phy, int reg) 300 { 301 device_t parent; 302 303 parent = device_get_parent(dev); 304 return (MIIBUS_READREG(parent, phy, reg)); 305 } 306 307 static int 308 miibus_writereg(device_t dev, int phy, int reg, int data) 309 { 310 device_t parent; 311 312 parent = device_get_parent(dev); 313 return (MIIBUS_WRITEREG(parent, phy, reg, data)); 314 } 315 316 static void 317 miibus_statchg(device_t dev) 318 { 319 device_t parent; 320 struct mii_data *mii; 321 322 parent = device_get_parent(dev); 323 MIIBUS_STATCHG(parent); 324 325 mii = device_get_softc(dev); 326 if_setbaudrate(mii->mii_ifp, ifmedia_baudrate(mii->mii_media_active)); 327 } 328 329 static void 330 miibus_linkchg(device_t dev) 331 { 332 struct mii_data *mii; 333 device_t parent; 334 int link_state; 335 336 parent = device_get_parent(dev); 337 MIIBUS_LINKCHG(parent); 338 339 mii = device_get_softc(dev); 340 341 if (mii->mii_media_status & IFM_AVALID) { 342 if (mii->mii_media_status & IFM_ACTIVE) 343 link_state = LINK_STATE_UP; 344 else 345 link_state = LINK_STATE_DOWN; 346 } else 347 link_state = LINK_STATE_UNKNOWN; 348 if_link_state_change(mii->mii_ifp, link_state); 349 } 350 351 static void 352 miibus_mediainit(device_t dev) 353 { 354 struct mii_data *mii; 355 struct ifmedia_entry *m; 356 int media = 0; 357 358 /* Poke the parent in case it has any media of its own to add. */ 359 MIIBUS_MEDIAINIT(device_get_parent(dev)); 360 361 mii = device_get_softc(dev); 362 LIST_FOREACH(m, &mii->mii_media.ifm_list, ifm_list) { 363 media = m->ifm_media; 364 if (media == (IFM_ETHER | IFM_AUTO)) 365 break; 366 } 367 368 ifmedia_set(&mii->mii_media, media); 369 } 370 371 /* 372 * Helper function used by network interface drivers, attaches the miibus and 373 * the PHYs to the network interface driver parent. 374 */ 375 int 376 mii_attach(device_t dev, device_t *miibus, if_t ifp, 377 ifm_change_cb_t ifmedia_upd, ifm_stat_cb_t ifmedia_sts, int capmask, 378 int phyloc, int offloc, int flags) 379 { 380 struct miibus_ivars *ivars; 381 struct mii_attach_args *args, ma; 382 device_t *children, phy; 383 int bmsr, first, i, nchildren, phymax, phymin, rv; 384 uint32_t phymask; 385 386 if (phyloc != MII_PHY_ANY && offloc != MII_OFFSET_ANY) { 387 printf("%s: phyloc and offloc specified\n", __func__); 388 return (EINVAL); 389 } 390 391 if (offloc != MII_OFFSET_ANY && (offloc < 0 || offloc >= MII_NPHY)) { 392 printf("%s: invalid offloc %d\n", __func__, offloc); 393 return (EINVAL); 394 } 395 396 if (phyloc == MII_PHY_ANY) { 397 phymin = 0; 398 phymax = MII_NPHY - 1; 399 } else { 400 if (phyloc < 0 || phyloc >= MII_NPHY) { 401 printf("%s: invalid phyloc %d\n", __func__, phyloc); 402 return (EINVAL); 403 } 404 phymin = phymax = phyloc; 405 } 406 407 first = 0; 408 if (*miibus == NULL) { 409 first = 1; 410 ivars = malloc(sizeof(*ivars), M_DEVBUF, M_NOWAIT); 411 if (ivars == NULL) 412 return (ENOMEM); 413 ivars->ifp = ifp; 414 ivars->ifmedia_upd = ifmedia_upd; 415 ivars->ifmedia_sts = ifmedia_sts; 416 ivars->mii_flags = flags; 417 *miibus = device_add_child(dev, "miibus", -1); 418 if (*miibus == NULL) { 419 rv = ENXIO; 420 goto fail; 421 } 422 device_set_ivars(*miibus, ivars); 423 } else { 424 ivars = device_get_ivars(*miibus); 425 if (ivars->ifp != ifp || ivars->ifmedia_upd != ifmedia_upd || 426 ivars->ifmedia_sts != ifmedia_sts || 427 ivars->mii_flags != flags) { 428 printf("%s: non-matching invariant\n", __func__); 429 return (EINVAL); 430 } 431 /* 432 * Assignment of the attach arguments mii_data for the first 433 * pass is done in miibus_attach(), i.e. once the miibus softc 434 * has been allocated. 435 */ 436 ma.mii_data = device_get_softc(*miibus); 437 } 438 439 ma.mii_capmask = capmask; 440 441 if (resource_int_value(device_get_name(*miibus), 442 device_get_unit(*miibus), "phymask", &phymask) != 0) 443 phymask = 0xffffffff; 444 445 if (device_get_children(*miibus, &children, &nchildren) != 0) { 446 children = NULL; 447 nchildren = 0; 448 } 449 ivars->mii_offset = 0; 450 for (ma.mii_phyno = phymin; ma.mii_phyno <= phymax; ma.mii_phyno++) { 451 /* 452 * Make sure we haven't already configured a PHY at this 453 * address. This allows mii_attach() to be called 454 * multiple times. 455 */ 456 for (i = 0; i < nchildren; i++) { 457 args = device_get_ivars(children[i]); 458 if (args->mii_phyno == ma.mii_phyno) { 459 /* 460 * Yes, there is already something 461 * configured at this address. 462 */ 463 goto skip; 464 } 465 } 466 467 /* 468 * Check to see if there is a PHY at this address. Note, 469 * many braindead PHYs report 0/0 in their ID registers, 470 * so we test for media in the BMSR. 471 */ 472 bmsr = MIIBUS_READREG(dev, ma.mii_phyno, MII_BMSR); 473 if (bmsr == 0 || bmsr == 0xffff || 474 (bmsr & (BMSR_EXTSTAT | BMSR_MEDIAMASK)) == 0) { 475 /* Assume no PHY at this address. */ 476 continue; 477 } 478 479 /* 480 * There is a PHY at this address. If we were given an 481 * `offset' locator, skip this PHY if it doesn't match. 482 */ 483 if (offloc != MII_OFFSET_ANY && offloc != ivars->mii_offset) 484 goto skip; 485 486 /* 487 * Skip this PHY if it's not included in the phymask hint. 488 */ 489 if ((phymask & (1 << ma.mii_phyno)) == 0) 490 goto skip; 491 492 /* 493 * Extract the IDs. Braindead PHYs will be handled by 494 * the `ukphy' driver, as we have no ID information to 495 * match on. 496 */ 497 ma.mii_id1 = MIIBUS_READREG(dev, ma.mii_phyno, MII_PHYIDR1); 498 ma.mii_id2 = MIIBUS_READREG(dev, ma.mii_phyno, MII_PHYIDR2); 499 500 ma.mii_offset = ivars->mii_offset; 501 args = malloc(sizeof(struct mii_attach_args), M_DEVBUF, 502 M_NOWAIT); 503 if (args == NULL) 504 goto skip; 505 bcopy((char *)&ma, (char *)args, sizeof(ma)); 506 phy = device_add_child(*miibus, NULL, -1); 507 if (phy == NULL) { 508 free(args, M_DEVBUF); 509 goto skip; 510 } 511 device_set_ivars(phy, args); 512 skip: 513 ivars->mii_offset++; 514 } 515 free(children, M_TEMP); 516 517 if (first != 0) { 518 rv = device_set_driver(*miibus, &miibus_driver); 519 if (rv != 0) 520 goto fail; 521 bus_enumerate_hinted_children(*miibus); 522 rv = device_get_children(*miibus, &children, &nchildren); 523 if (rv != 0) 524 goto fail; 525 free(children, M_TEMP); 526 if (nchildren == 0) { 527 rv = ENXIO; 528 goto fail; 529 } 530 rv = bus_generic_attach(dev); 531 if (rv != 0) 532 goto fail; 533 534 /* Attaching of the PHY drivers is done in miibus_attach(). */ 535 return (0); 536 } 537 rv = bus_generic_attach(*miibus); 538 if (rv != 0) 539 goto fail; 540 541 return (0); 542 543 fail: 544 if (*miibus != NULL) 545 device_delete_child(dev, *miibus); 546 free(ivars, M_DEVBUF); 547 if (first != 0) 548 *miibus = NULL; 549 return (rv); 550 } 551 552 /* 553 * Media changed; notify all PHYs. 554 */ 555 int 556 mii_mediachg(struct mii_data *mii) 557 { 558 struct mii_softc *child; 559 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 560 int rv; 561 562 mii->mii_media_status = 0; 563 mii->mii_media_active = IFM_NONE; 564 565 LIST_FOREACH(child, &mii->mii_phys, mii_list) { 566 /* 567 * If the media indicates a different PHY instance, 568 * isolate this one. 569 */ 570 if (IFM_INST(ife->ifm_media) != child->mii_inst) { 571 if ((child->mii_flags & MIIF_NOISOLATE) != 0) { 572 device_printf(child->mii_dev, "%s: " 573 "can't handle non-zero PHY instance %d\n", 574 __func__, child->mii_inst); 575 continue; 576 } 577 PHY_WRITE(child, MII_BMCR, PHY_READ(child, MII_BMCR) | 578 BMCR_ISO); 579 continue; 580 } 581 rv = PHY_SERVICE(child, mii, MII_MEDIACHG); 582 if (rv) 583 return (rv); 584 } 585 return (0); 586 } 587 588 /* 589 * Call the PHY tick routines, used during autonegotiation. 590 */ 591 void 592 mii_tick(struct mii_data *mii) 593 { 594 struct mii_softc *child; 595 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 596 597 LIST_FOREACH(child, &mii->mii_phys, mii_list) { 598 /* 599 * If this PHY instance isn't currently selected, just skip 600 * it. 601 */ 602 if (IFM_INST(ife->ifm_media) != child->mii_inst) 603 continue; 604 (void)PHY_SERVICE(child, mii, MII_TICK); 605 } 606 } 607 608 /* 609 * Get media status from PHYs. 610 */ 611 void 612 mii_pollstat(struct mii_data *mii) 613 { 614 struct mii_softc *child; 615 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 616 617 mii->mii_media_status = 0; 618 mii->mii_media_active = IFM_NONE; 619 620 LIST_FOREACH(child, &mii->mii_phys, mii_list) { 621 /* 622 * If we're not polling this PHY instance, just skip it. 623 */ 624 if (IFM_INST(ife->ifm_media) != child->mii_inst) 625 continue; 626 (void)PHY_SERVICE(child, mii, MII_POLLSTAT); 627 } 628 } 629 630 static unsigned char 631 mii_bitreverse(unsigned char x) 632 { 633 static unsigned const char nibbletab[16] = { 634 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 635 }; 636 637 return ((nibbletab[x & 15] << 4) | nibbletab[x >> 4]); 638 } 639 640 u_int 641 mii_oui(u_int id1, u_int id2) 642 { 643 u_int h; 644 645 h = (id1 << 6) | (id2 >> 10); 646 647 return ((mii_bitreverse(h >> 16) << 16) | 648 (mii_bitreverse((h >> 8) & 0xff) << 8) | 649 mii_bitreverse(h & 0xff)); 650 } 651 652 int 653 mii_phy_mac_match(struct mii_softc *mii, const char *name) 654 { 655 656 return (strcmp(device_get_name(device_get_parent(mii->mii_dev)), 657 name) == 0); 658 } 659 660 int 661 mii_dev_mac_match(device_t parent, const char *name) 662 { 663 664 return (strcmp(device_get_name(device_get_parent( 665 device_get_parent(parent))), name) == 0); 666 } 667 668 void * 669 mii_phy_mac_softc(struct mii_softc *mii) 670 { 671 672 return (device_get_softc(device_get_parent(mii->mii_dev))); 673 } 674 675 void * 676 mii_dev_mac_softc(device_t parent) 677 { 678 679 return (device_get_softc(device_get_parent(device_get_parent(parent)))); 680 } 681