1 /* $NetBSD: mii_physubr.c,v 1.49 2006/03/29 07:05:24 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1998, 1999, 2000, 2001 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, 9 * NASA Ames Research Center. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 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. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 * 39 * $FreeBSD: src/sys/dev/mii/mii_physubr.c,v 1.2.2.1 2000/12/12 19:29:14 wpaul Exp $ 40 * $DragonFly: src/sys/dev/netif/mii_layer/mii_physubr.c,v 1.13 2006/12/22 23:26:20 swildner Exp $ 41 */ 42 43 /* 44 * Subroutines common to all PHYs. 45 */ 46 47 #include <sys/param.h> 48 #include <sys/systm.h> 49 #include <sys/kernel.h> 50 #include <sys/socket.h> 51 #include <sys/errno.h> 52 #include <sys/module.h> 53 #include <sys/bus.h> 54 #include <sys/thread2.h> 55 56 #include <net/if.h> 57 #include <net/if_media.h> 58 59 #include "mii.h" 60 #include "miivar.h" 61 62 #include "miibus_if.h" 63 64 const struct mii_media mii_media_table[MII_NMEDIA] = { 65 [MII_MEDIA_NONE] = { .mm_bmcr = BMCR_ISO, 66 .mm_anar = ANAR_CSMA, 67 .mm_gtcr = 0 }, 68 69 [MII_MEDIA_10_T] = { .mm_bmcr = BMCR_S10, 70 .mm_anar = ANAR_CSMA | ANAR_10, 71 .mm_gtcr = 0 }, 72 73 [MII_MEDIA_10_T_FDX] = { .mm_bmcr = BMCR_S10 | BMCR_FDX, 74 .mm_anar = ANAR_CSMA | ANAR_10_FD, 75 .mm_gtcr = 0 }, 76 77 [MII_MEDIA_100_T4] = { .mm_bmcr = BMCR_S100, 78 .mm_anar = ANAR_CSMA | ANAR_T4, 79 .mm_gtcr = 0 }, 80 81 [MII_MEDIA_100_TX] = { .mm_bmcr = BMCR_S100, 82 .mm_anar = ANAR_CSMA | ANAR_TX, 83 .mm_gtcr = 0 }, 84 85 [MII_MEDIA_100_TX_FDX] = { .mm_bmcr = BMCR_S100 | BMCR_FDX, 86 .mm_anar = ANAR_CSMA | ANAR_TX_FD, 87 .mm_gtcr = 0 }, 88 89 [MII_MEDIA_1000_X] = { .mm_bmcr = BMCR_S1000, 90 .mm_anar = ANAR_CSMA, 91 .mm_gtcr = 0 }, 92 93 [MII_MEDIA_1000_X_FDX] = { .mm_bmcr = BMCR_S1000 | BMCR_FDX, 94 .mm_anar = ANAR_CSMA, 95 .mm_gtcr = 0 }, 96 97 [MII_MEDIA_1000_T] = { .mm_bmcr = BMCR_S1000, 98 .mm_anar = ANAR_CSMA, 99 .mm_gtcr = GTCR_ADV_1000THDX }, 100 101 [MII_MEDIA_1000_T_FDX] = { .mm_bmcr = BMCR_S1000, 102 .mm_anar = ANAR_CSMA, 103 .mm_gtcr = GTCR_ADV_1000TFDX } 104 }; 105 106 void 107 mii_softc_init(struct mii_softc *mii, struct mii_attach_args *ma) 108 { 109 callout_init(&mii->mii_auto_ch); 110 mii->mii_phy = ma->mii_phyno; 111 mii->mii_flags |= ma->mii_flags; 112 mii->mii_model = MII_MODEL(ma->mii_id2); 113 mii->mii_rev = MII_REV(ma->mii_id2); 114 115 if (mii->mii_reset == NULL) 116 mii->mii_reset = mii_phy_reset; 117 if (mii->mii_anegticks == 0) 118 mii->mii_anegticks = MII_ANEGTICKS; 119 } 120 121 int 122 mii_phy_auto(struct mii_softc *sc, int waitfor) 123 { 124 int i; 125 126 if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) { 127 /* 128 * Check for 1000BASE-X. Autonegotiation is a bit 129 * different on such devices. 130 */ 131 if (sc->mii_flags & MIIF_IS_1000X) { 132 uint16_t anar = 0; 133 134 if (sc->mii_extcapabilities & EXTSR_1000XFDX) 135 anar |= ANAR_X_FD; 136 if (sc->mii_extcapabilities & EXTSR_1000XHDX) 137 anar |= ANAR_X_HD; 138 139 if (sc->mii_flags & MIIF_DOPAUSE) { 140 /* XXX Asymmetric vs. symmetric? */ 141 anar |= ANLPAR_X_PAUSE_TOWARDS; 142 } 143 144 PHY_WRITE(sc, MII_ANAR, anar); 145 } else { 146 uint16_t anar; 147 148 anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | 149 ANAR_CSMA; 150 if (sc->mii_flags & MIIF_DOPAUSE) { 151 anar |= ANAR_FC; 152 /* XXX Only 1000BASE-T has PAUSE_ASYM? */ 153 if ((sc->mii_flags & MIIF_HAVE_GTCR) && 154 (sc->mii_extcapabilities & 155 (EXTSR_1000THDX|EXTSR_1000TFDX))) 156 anar |= ANAR_X_PAUSE_ASYM; 157 } 158 PHY_WRITE(sc, MII_ANAR, anar); 159 if (sc->mii_flags & MIIF_HAVE_GTCR) { 160 uint16_t gtcr = 0; 161 162 if (sc->mii_extcapabilities & EXTSR_1000TFDX) 163 gtcr |= GTCR_ADV_1000TFDX; 164 if (sc->mii_extcapabilities & EXTSR_1000THDX) 165 gtcr |= GTCR_ADV_1000THDX; 166 167 PHY_WRITE(sc, MII_100T2CR, gtcr); 168 } 169 } 170 PHY_WRITE(sc, MII_BMCR, BMCR_AUTOEN | BMCR_STARTNEG); 171 } 172 173 if (waitfor) { 174 /* Wait 500ms for it to complete. */ 175 for (i = 0; i < 500; i++) { 176 if (PHY_READ(sc, MII_BMSR) & BMSR_ACOMP) 177 return (0); 178 DELAY(1000); 179 } 180 181 /* 182 * Don't need to worry about clearing MIIF_DOINGAUTO. 183 * If that's set, a timeout is pending, and it will 184 * clear the flag. 185 */ 186 return (EIO); 187 } 188 189 /* 190 * Just let it finish asynchronously. This is for the benefit of 191 * the tick handler driving autonegotiation. Don't want 500ms 192 * delays all the time while the system is running! 193 */ 194 if (sc->mii_flags & MIIF_AUTOTSLEEP) { 195 sc->mii_flags |= MIIF_DOINGAUTO; 196 tsleep(&sc->mii_flags, 0, "miiaut", hz >> 1); 197 mii_phy_auto_timeout(sc); 198 } else if ((sc->mii_flags & MIIF_DOINGAUTO) == 0) { 199 sc->mii_flags |= MIIF_DOINGAUTO; 200 callout_reset(&sc->mii_auto_ch, hz >> 1, 201 mii_phy_auto_timeout, sc); 202 } 203 return (EJUSTRETURN); 204 } 205 206 void 207 mii_phy_auto_stop(struct mii_softc *sc) 208 { 209 if (sc->mii_flags & MIIF_DOINGAUTO) { 210 sc->mii_flags &= ~MIIF_DOINGAUTO; 211 callout_stop(&sc->mii_auto_ch); 212 } 213 } 214 215 /* XXX should use serializer */ 216 void 217 mii_phy_auto_timeout(void *arg) 218 { 219 struct mii_softc *sc = arg; 220 221 crit_enter(); 222 223 sc->mii_flags &= ~MIIF_DOINGAUTO; 224 225 /* Update the media status. */ 226 sc->mii_service(sc, sc->mii_pdata, MII_POLLSTAT); 227 228 crit_exit(); 229 } 230 231 void 232 mii_phy_reset(struct mii_softc *sc) 233 { 234 int reg, i; 235 236 if (sc->mii_flags & MIIF_NOISOLATE) 237 reg = BMCR_RESET; 238 else 239 reg = BMCR_RESET | BMCR_ISO; 240 PHY_WRITE(sc, MII_BMCR, reg); 241 242 /* 243 * It is best to allow a little time for the reset to settle 244 * in before we start polling the BMCR again. Notably, the 245 * DP83840A manual states that there should be a 500us delay 246 * between asserting software reset and attempting MII serial 247 * operations. Also, a DP83815 can get into a bad state on 248 * cable removal and reinsertion if we do not delay here. 249 */ 250 DELAY(500); 251 252 /* Wait 100ms for it to complete. */ 253 for (i = 0; i < 100; i++) { 254 reg = PHY_READ(sc, MII_BMCR); 255 if ((reg & BMCR_RESET) == 0) 256 break; 257 DELAY(1000); 258 } 259 260 if (sc->mii_inst != 0 && ((sc->mii_flags & MIIF_NOISOLATE) == 0)) 261 PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO); 262 } 263 264 /* 265 * Initialize generic PHY media based on BMSR, called when a PHY is 266 * attached. We expect to be set up to print a comma-separated list 267 * of media names. Does not print a newline. 268 */ 269 void 270 mii_phy_add_media(struct mii_softc *sc) 271 { 272 struct mii_data *mii = sc->mii_pdata; 273 const char *sep = ""; 274 int fdx = 0; 275 276 #define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL) 277 #define PRINT(s) kprintf("%s%s", sep, s); sep = ", " 278 279 if ((sc->mii_flags & MIIF_NOISOLATE) == 0) 280 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst), 281 MII_MEDIA_NONE); 282 283 /* 284 * There are different interpretations for the bits in 285 * HomePNA PHYs. And there is really only one media type 286 * that is supported. 287 */ 288 if (sc->mii_flags & MIIF_IS_HPNA) { 289 if (sc->mii_capabilities & BMSR_10THDX) { 290 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0, 291 sc->mii_inst), 292 MII_MEDIA_10_T); 293 PRINT("HomePNA1"); 294 } 295 return; 296 } 297 298 if (sc->mii_capabilities & BMSR_10THDX) { 299 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst), 300 MII_MEDIA_10_T); 301 PRINT("10baseT"); 302 } 303 if (sc->mii_capabilities & BMSR_10TFDX) { 304 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst), 305 MII_MEDIA_10_T_FDX); 306 PRINT("10baseT-FDX"); 307 fdx = 1; 308 } 309 if (sc->mii_capabilities & BMSR_100TXHDX) { 310 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst), 311 MII_MEDIA_100_TX); 312 PRINT("100baseTX"); 313 } 314 if (sc->mii_capabilities & BMSR_100TXFDX) { 315 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst), 316 MII_MEDIA_100_TX_FDX); 317 PRINT("100baseTX-FDX"); 318 fdx = 1; 319 } 320 if (sc->mii_capabilities & BMSR_100T4) { 321 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst), 322 MII_MEDIA_100_T4); 323 PRINT("100baseT4"); 324 } 325 326 if (sc->mii_extcapabilities & EXTSR_MEDIAMASK) { 327 /* 328 * XXX Right now only handle 1000SX and 1000TX. Need 329 * XXX to handle 1000LX and 1000CX some how. 330 * 331 * Note since it can take 5 seconds to auto-negotiate 332 * a gigabit link, we make anegticks 10 seconds for 333 * all the gigabit media types. 334 */ 335 if (sc->mii_extcapabilities & EXTSR_1000XHDX) { 336 sc->mii_anegticks = MII_ANEGTICKS_GIGE; 337 sc->mii_flags |= MIIF_IS_1000X; 338 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0, 339 sc->mii_inst), MII_MEDIA_1000_X); 340 PRINT("1000baseSX"); 341 } 342 if (sc->mii_extcapabilities & EXTSR_1000XFDX) { 343 sc->mii_anegticks = MII_ANEGTICKS_GIGE; 344 sc->mii_flags |= MIIF_IS_1000X; 345 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, 346 sc->mii_inst), MII_MEDIA_1000_X_FDX); 347 PRINT("1000baseSX-FDX"); 348 fdx = 1; 349 } 350 351 /* 352 * 1000baseT media needs to be able to manipulate 353 * master/slave mode. We set IFM_ETH_MASTER in 354 * the "don't care mask" and filter it out when 355 * the media is set. 356 * 357 * All 1000baseT PHYs have a 1000baseT control register. 358 */ 359 if (sc->mii_extcapabilities & EXTSR_1000THDX) { 360 sc->mii_anegticks = MII_ANEGTICKS_GIGE; 361 sc->mii_flags |= MIIF_HAVE_GTCR; 362 mii->mii_media.ifm_mask |= IFM_ETH_MASTER; 363 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, 364 sc->mii_inst), MII_MEDIA_1000_T); 365 PRINT("1000baseT"); 366 } 367 if (sc->mii_extcapabilities & EXTSR_1000TFDX) { 368 sc->mii_anegticks = MII_ANEGTICKS_GIGE; 369 sc->mii_flags |= MIIF_HAVE_GTCR; 370 mii->mii_media.ifm_mask |= IFM_ETH_MASTER; 371 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, 372 sc->mii_inst), MII_MEDIA_1000_T_FDX); 373 PRINT("1000baseT-FDX"); 374 fdx = 1; 375 } 376 } 377 378 if (sc->mii_capabilities & BMSR_ANEG) { 379 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 380 MII_NMEDIA); /* intentionally invalid index */ 381 PRINT("auto"); 382 } 383 #undef ADD 384 #undef PRINT 385 if (fdx != 0 && (sc->mii_flags & MIIF_DOPAUSE)) 386 mii->mii_media.ifm_mask |= IFM_ETH_FMASK; 387 } 388 389 void 390 mii_phy_set_media(struct mii_softc *sc) 391 { 392 struct mii_data *mii = sc->mii_pdata; 393 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 394 int bmcr, anar, gtcr; 395 396 if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) { 397 /* 398 * Force renegotiation if MIIF_DOPAUSE. 399 * 400 * XXX This is only necessary because many NICs don't 401 * XXX advertise PAUSE capabilities at boot time. Maybe 402 * XXX we should force this only once? 403 */ 404 if ((PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN) == 0 || 405 (sc->mii_flags & (MIIF_FORCEANEG | MIIF_DOPAUSE))) 406 mii_phy_auto(sc, 1); 407 return; 408 } 409 410 /* 411 * Table index is stored in the media entry. 412 */ 413 414 KASSERT(ife->ifm_data >= 0 && ife->ifm_data < MII_NMEDIA, 415 ("bogus ife->ifm_data (%d)\n", ife->ifm_data)); 416 417 anar = mii_media_table[ife->ifm_data].mm_anar; 418 bmcr = mii_media_table[ife->ifm_data].mm_bmcr; 419 gtcr = mii_media_table[ife->ifm_data].mm_gtcr; 420 421 if (mii->mii_media.ifm_media & IFM_ETH_MASTER) { 422 switch (IFM_SUBTYPE(ife->ifm_media)) { 423 case IFM_1000_T: 424 gtcr |= GTCR_MAN_MS|GTCR_ADV_MS; 425 break; 426 427 default: 428 panic("mii_phy_setmedia: MASTER on wrong media"); 429 } 430 } 431 432 if (mii->mii_media.ifm_media & IFM_FLOW) { 433 if (sc->mii_flags & MIIF_IS_1000X) { 434 anar |= ANAR_X_PAUSE_SYM | ANAR_X_PAUSE_ASYM; 435 } else { 436 anar |= ANAR_FC; 437 /* XXX Only 1000BASE-T has PAUSE_ASYM? */ 438 if ((sc->mii_flags & MIIF_HAVE_GTCR) && 439 (sc->mii_extcapabilities & 440 (EXTSR_1000THDX | EXTSR_1000TFDX))) 441 anar |= ANAR_X_PAUSE_ASYM; 442 } 443 } 444 445 if (ife->ifm_media & IFM_LOOP) 446 bmcr |= BMCR_LOOP; 447 448 PHY_WRITE(sc, MII_ANAR, anar); 449 PHY_WRITE(sc, MII_BMCR, bmcr); 450 if (sc->mii_flags & MIIF_HAVE_GTCR) 451 PHY_WRITE(sc, MII_100T2CR, gtcr); 452 } 453 454 int 455 mii_phy_tick(struct mii_softc *sc) 456 { 457 struct mii_data *mii = sc->mii_pdata; 458 struct ifmedia_entry *ife = mii->mii_media.ifm_cur; 459 int reg; 460 461 /* Just bail now if the interface is down. */ 462 if ((mii->mii_ifp->if_flags & IFF_UP) == 0) 463 return (EJUSTRETURN); 464 465 /* 466 * If we're not doing autonegotiation, we don't need to do 467 * any extra work here. However, we need to check the link 468 * status so we can generate an announcement if the status 469 * changes. 470 */ 471 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) 472 return (0); 473 474 /* Read the status register twice; BMSR_LINK is latch-low. */ 475 reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR); 476 if (reg & BMSR_LINK) { 477 /* 478 * See above. 479 */ 480 return (0); 481 } 482 483 /* 484 * Only retry autonegotiation every N seconds. 485 */ 486 KKASSERT(sc->mii_anegticks > 0); 487 if (++sc->mii_ticks != sc->mii_anegticks) 488 return (EJUSTRETURN); 489 490 sc->mii_ticks = 0; 491 sc->mii_reset(sc); /* Reset PHY */ 492 493 if (mii_phy_auto(sc, 0) == EJUSTRETURN) 494 return (EJUSTRETURN); 495 496 /* 497 * Might need to generate a status message if autonegotiation 498 * failed. 499 */ 500 return (0); 501 } 502 503 #ifdef notyet 504 static void 505 mii_phy_statusmsg(struct mii_softc *sc) 506 { 507 struct mii_data *mii = sc->mii_pdata; 508 struct ifnet *ifp = mii->mii_ifp; 509 int s; 510 511 crit_enter(); 512 if (mii->mii_media_status & IFM_AVALID) { 513 if (mii->mii_media_status & IFM_ACTIVE) 514 if_link_state_change(ifp, LINK_STATE_UP); 515 else 516 if_link_state_change(ifp, LINK_STATE_DOWN); 517 } else 518 if_link_state_change(ifp, LINK_STATE_UNKNOWN); 519 crit_exit(); 520 521 ifp->if_baudrate = ifmedia_baudrate(mii->mii_media_active); 522 } 523 #endif 524 525 void 526 mii_phy_update(struct mii_softc *sc, int cmd) 527 { 528 struct mii_data *mii = sc->mii_pdata; 529 530 if (sc->mii_media_active != mii->mii_media_active || 531 sc->mii_media_status != mii->mii_media_status || 532 cmd == MII_MEDIACHG) { 533 #ifdef notyet 534 mii_phy_statusmsg(sc); 535 #endif 536 MIIBUS_STATCHG(sc->mii_dev); 537 sc->mii_media_active = mii->mii_media_active; 538 sc->mii_media_status = mii->mii_media_status; 539 } 540 } 541 542 /* 543 * Return the flow control status flag from MII_ANAR & MII_ANLPAR. 544 */ 545 int 546 mii_phy_flowstatus(struct mii_softc *sc) 547 { 548 int anar, anlpar; 549 550 if ((sc->mii_flags & MIIF_DOPAUSE) == 0) 551 return (0); 552 553 anar = PHY_READ(sc, MII_ANAR); 554 anlpar = PHY_READ(sc, MII_ANLPAR); 555 556 if ((anar & ANAR_X_PAUSE_SYM) & (anlpar & ANLPAR_X_PAUSE_SYM)) 557 return (IFM_FLOW | IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE); 558 559 if ((anar & ANAR_X_PAUSE_SYM) == 0) { 560 if ((anar & ANAR_X_PAUSE_ASYM) && 561 ((anlpar & ANLPAR_X_PAUSE_TOWARDS) == 562 ANLPAR_X_PAUSE_TOWARDS)) 563 return (IFM_FLOW | IFM_ETH_TXPAUSE); 564 else 565 return (0); 566 } 567 568 if ((anar & ANAR_X_PAUSE_ASYM) == 0) { 569 if (anlpar & ANLPAR_X_PAUSE_SYM) 570 return (IFM_FLOW | IFM_ETH_TXPAUSE | IFM_ETH_RXPAUSE); 571 else 572 return (0); 573 } 574 575 switch (anlpar & ANLPAR_X_PAUSE_TOWARDS) { 576 case ANLPAR_X_PAUSE_NONE: 577 return (0); 578 579 case ANLPAR_X_PAUSE_ASYM: 580 return (IFM_FLOW | IFM_ETH_RXPAUSE); 581 582 default: 583 return (IFM_FLOW | IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE); 584 } 585 /* NOTREACHED */ 586 } 587 588 const struct mii_phydesc * 589 mii_phy_match(const struct mii_attach_args *ma, const struct mii_phydesc *mpd) 590 { 591 for (; mpd->mpd_name != NULL; mpd++) { 592 if (MII_OUI(ma->mii_id1, ma->mii_id2) == mpd->mpd_oui && 593 MII_MODEL(ma->mii_id2) == mpd->mpd_model) 594 return (mpd); 595 } 596 return (NULL); 597 } 598