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