1 /* 2 3 mii.c: MII interface library 4 5 Maintained by Jeff Garzik <jgarzik@pobox.com> 6 Copyright 2001,2002 Jeff Garzik 7 8 Various code came from myson803.c and other files by 9 Donald Becker. Copyright: 10 11 Written 1998-2002 by Donald Becker. 12 13 This software may be used and distributed according 14 to the terms of the GNU General Public License (GPL), 15 incorporated herein by reference. Drivers based on 16 or derived from this code fall under the GPL and must 17 retain the authorship, copyright and license notice. 18 This file is not a complete program and may only be 19 used when the entire operating system is licensed 20 under the GPL. 21 22 The author may be reached as becker@scyld.com, or C/O 23 Scyld Computing Corporation 24 410 Severn Ave., Suite 210 25 Annapolis MD 21403 26 27 28 */ 29 30 #include <linux/kernel.h> 31 #include <linux/module.h> 32 #include <linux/netdevice.h> 33 #include <linux/ethtool.h> 34 #include <linux/mii.h> 35 36 static u32 mii_get_an(struct mii_if_info *mii, u16 addr) 37 { 38 int advert; 39 40 advert = mii->mdio_read(mii->dev, mii->phy_id, addr); 41 42 return mii_lpa_to_ethtool_lpa_t(advert); 43 } 44 45 /** 46 * mii_ethtool_gset - get settings that are specified in @ecmd 47 * @mii: MII interface 48 * @ecmd: requested ethtool_cmd 49 * 50 * The @ecmd parameter is expected to have been cleared before calling 51 * mii_ethtool_gset(). 52 * 53 * Returns 0 for success, negative on error. 54 */ 55 int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) 56 { 57 struct net_device *dev = mii->dev; 58 u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0; 59 u32 nego; 60 61 ecmd->supported = 62 (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | 63 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | 64 SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII); 65 if (mii->supports_gmii) 66 ecmd->supported |= SUPPORTED_1000baseT_Half | 67 SUPPORTED_1000baseT_Full; 68 69 /* only supports twisted-pair */ 70 ecmd->port = PORT_MII; 71 72 /* only supports internal transceiver */ 73 ecmd->transceiver = XCVR_INTERNAL; 74 75 /* this isn't fully supported at higher layers */ 76 ecmd->phy_address = mii->phy_id; 77 ecmd->mdio_support = ETH_MDIO_SUPPORTS_C22; 78 79 ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII; 80 81 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); 82 bmsr = mii->mdio_read(dev, mii->phy_id, MII_BMSR); 83 if (mii->supports_gmii) { 84 ctrl1000 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000); 85 stat1000 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000); 86 } 87 88 ecmd->advertising |= mii_get_an(mii, MII_ADVERTISE); 89 if (mii->supports_gmii) 90 ecmd->advertising |= 91 mii_ctrl1000_to_ethtool_adv_t(ctrl1000); 92 93 if (bmcr & BMCR_ANENABLE) { 94 ecmd->advertising |= ADVERTISED_Autoneg; 95 ecmd->autoneg = AUTONEG_ENABLE; 96 97 if (bmsr & BMSR_ANEGCOMPLETE) { 98 ecmd->lp_advertising = mii_get_an(mii, MII_LPA); 99 ecmd->lp_advertising |= 100 mii_stat1000_to_ethtool_lpa_t(stat1000); 101 } else { 102 ecmd->lp_advertising = 0; 103 } 104 105 nego = ecmd->advertising & ecmd->lp_advertising; 106 107 if (nego & (ADVERTISED_1000baseT_Full | 108 ADVERTISED_1000baseT_Half)) { 109 ethtool_cmd_speed_set(ecmd, SPEED_1000); 110 ecmd->duplex = !!(nego & ADVERTISED_1000baseT_Full); 111 } else if (nego & (ADVERTISED_100baseT_Full | 112 ADVERTISED_100baseT_Half)) { 113 ethtool_cmd_speed_set(ecmd, SPEED_100); 114 ecmd->duplex = !!(nego & ADVERTISED_100baseT_Full); 115 } else { 116 ethtool_cmd_speed_set(ecmd, SPEED_10); 117 ecmd->duplex = !!(nego & ADVERTISED_10baseT_Full); 118 } 119 } else { 120 ecmd->autoneg = AUTONEG_DISABLE; 121 122 ethtool_cmd_speed_set(ecmd, 123 ((bmcr & BMCR_SPEED1000 && 124 (bmcr & BMCR_SPEED100) == 0) ? 125 SPEED_1000 : 126 ((bmcr & BMCR_SPEED100) ? 127 SPEED_100 : SPEED_10))); 128 ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; 129 } 130 131 mii->full_duplex = ecmd->duplex; 132 133 /* ignore maxtxpkt, maxrxpkt for now */ 134 135 return 0; 136 } 137 138 /** 139 * mii_ethtool_get_link_ksettings - get settings that are specified in @cmd 140 * @mii: MII interface 141 * @cmd: requested ethtool_link_ksettings 142 * 143 * The @cmd parameter is expected to have been cleared before calling 144 * mii_ethtool_get_link_ksettings(). 145 */ 146 void mii_ethtool_get_link_ksettings(struct mii_if_info *mii, 147 struct ethtool_link_ksettings *cmd) 148 { 149 struct net_device *dev = mii->dev; 150 u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0; 151 u32 nego, supported, advertising, lp_advertising; 152 153 supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | 154 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | 155 SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII); 156 if (mii->supports_gmii) 157 supported |= SUPPORTED_1000baseT_Half | 158 SUPPORTED_1000baseT_Full; 159 160 /* only supports twisted-pair */ 161 cmd->base.port = PORT_MII; 162 163 /* this isn't fully supported at higher layers */ 164 cmd->base.phy_address = mii->phy_id; 165 cmd->base.mdio_support = ETH_MDIO_SUPPORTS_C22; 166 167 advertising = ADVERTISED_TP | ADVERTISED_MII; 168 169 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); 170 bmsr = mii->mdio_read(dev, mii->phy_id, MII_BMSR); 171 if (mii->supports_gmii) { 172 ctrl1000 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000); 173 stat1000 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000); 174 } 175 176 advertising |= mii_get_an(mii, MII_ADVERTISE); 177 if (mii->supports_gmii) 178 advertising |= mii_ctrl1000_to_ethtool_adv_t(ctrl1000); 179 180 if (bmcr & BMCR_ANENABLE) { 181 advertising |= ADVERTISED_Autoneg; 182 cmd->base.autoneg = AUTONEG_ENABLE; 183 184 if (bmsr & BMSR_ANEGCOMPLETE) { 185 lp_advertising = mii_get_an(mii, MII_LPA); 186 lp_advertising |= 187 mii_stat1000_to_ethtool_lpa_t(stat1000); 188 } else { 189 lp_advertising = 0; 190 } 191 192 nego = advertising & lp_advertising; 193 194 if (nego & (ADVERTISED_1000baseT_Full | 195 ADVERTISED_1000baseT_Half)) { 196 cmd->base.speed = SPEED_1000; 197 cmd->base.duplex = !!(nego & ADVERTISED_1000baseT_Full); 198 } else if (nego & (ADVERTISED_100baseT_Full | 199 ADVERTISED_100baseT_Half)) { 200 cmd->base.speed = SPEED_100; 201 cmd->base.duplex = !!(nego & ADVERTISED_100baseT_Full); 202 } else { 203 cmd->base.speed = SPEED_10; 204 cmd->base.duplex = !!(nego & ADVERTISED_10baseT_Full); 205 } 206 } else { 207 cmd->base.autoneg = AUTONEG_DISABLE; 208 209 cmd->base.speed = ((bmcr & BMCR_SPEED1000 && 210 (bmcr & BMCR_SPEED100) == 0) ? 211 SPEED_1000 : 212 ((bmcr & BMCR_SPEED100) ? 213 SPEED_100 : SPEED_10)); 214 cmd->base.duplex = (bmcr & BMCR_FULLDPLX) ? 215 DUPLEX_FULL : DUPLEX_HALF; 216 217 lp_advertising = 0; 218 } 219 220 mii->full_duplex = cmd->base.duplex; 221 222 ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, 223 supported); 224 ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, 225 advertising); 226 ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising, 227 lp_advertising); 228 229 /* ignore maxtxpkt, maxrxpkt for now */ 230 } 231 232 /** 233 * mii_ethtool_sset - set settings that are specified in @ecmd 234 * @mii: MII interface 235 * @ecmd: requested ethtool_cmd 236 * 237 * Returns 0 for success, negative on error. 238 */ 239 int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) 240 { 241 struct net_device *dev = mii->dev; 242 u32 speed = ethtool_cmd_speed(ecmd); 243 244 if (speed != SPEED_10 && 245 speed != SPEED_100 && 246 speed != SPEED_1000) 247 return -EINVAL; 248 if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) 249 return -EINVAL; 250 if (ecmd->port != PORT_MII) 251 return -EINVAL; 252 if (ecmd->transceiver != XCVR_INTERNAL) 253 return -EINVAL; 254 if (ecmd->phy_address != mii->phy_id) 255 return -EINVAL; 256 if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE) 257 return -EINVAL; 258 if ((speed == SPEED_1000) && (!mii->supports_gmii)) 259 return -EINVAL; 260 261 /* ignore supported, maxtxpkt, maxrxpkt */ 262 263 if (ecmd->autoneg == AUTONEG_ENABLE) { 264 u32 bmcr, advert, tmp; 265 u32 advert2 = 0, tmp2 = 0; 266 267 if ((ecmd->advertising & (ADVERTISED_10baseT_Half | 268 ADVERTISED_10baseT_Full | 269 ADVERTISED_100baseT_Half | 270 ADVERTISED_100baseT_Full | 271 ADVERTISED_1000baseT_Half | 272 ADVERTISED_1000baseT_Full)) == 0) 273 return -EINVAL; 274 275 /* advertise only what has been requested */ 276 advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE); 277 tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4); 278 if (mii->supports_gmii) { 279 advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000); 280 tmp2 = advert2 & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); 281 } 282 tmp |= ethtool_adv_to_mii_adv_t(ecmd->advertising); 283 284 if (mii->supports_gmii) 285 tmp2 |= 286 ethtool_adv_to_mii_ctrl1000_t(ecmd->advertising); 287 if (advert != tmp) { 288 mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp); 289 mii->advertising = tmp; 290 } 291 if ((mii->supports_gmii) && (advert2 != tmp2)) 292 mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2); 293 294 /* turn on autonegotiation, and force a renegotiate */ 295 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); 296 bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); 297 mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr); 298 299 mii->force_media = 0; 300 } else { 301 u32 bmcr, tmp; 302 303 /* turn off auto negotiation, set speed and duplexity */ 304 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); 305 tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | 306 BMCR_SPEED1000 | BMCR_FULLDPLX); 307 if (speed == SPEED_1000) 308 tmp |= BMCR_SPEED1000; 309 else if (speed == SPEED_100) 310 tmp |= BMCR_SPEED100; 311 if (ecmd->duplex == DUPLEX_FULL) { 312 tmp |= BMCR_FULLDPLX; 313 mii->full_duplex = 1; 314 } else 315 mii->full_duplex = 0; 316 if (bmcr != tmp) 317 mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp); 318 319 mii->force_media = 1; 320 } 321 return 0; 322 } 323 324 /** 325 * mii_ethtool_set_link_ksettings - set settings that are specified in @cmd 326 * @mii: MII interfaces 327 * @cmd: requested ethtool_link_ksettings 328 * 329 * Returns 0 for success, negative on error. 330 */ 331 int mii_ethtool_set_link_ksettings(struct mii_if_info *mii, 332 const struct ethtool_link_ksettings *cmd) 333 { 334 struct net_device *dev = mii->dev; 335 u32 speed = cmd->base.speed; 336 337 if (speed != SPEED_10 && 338 speed != SPEED_100 && 339 speed != SPEED_1000) 340 return -EINVAL; 341 if (cmd->base.duplex != DUPLEX_HALF && cmd->base.duplex != DUPLEX_FULL) 342 return -EINVAL; 343 if (cmd->base.port != PORT_MII) 344 return -EINVAL; 345 if (cmd->base.phy_address != mii->phy_id) 346 return -EINVAL; 347 if (cmd->base.autoneg != AUTONEG_DISABLE && 348 cmd->base.autoneg != AUTONEG_ENABLE) 349 return -EINVAL; 350 if ((speed == SPEED_1000) && (!mii->supports_gmii)) 351 return -EINVAL; 352 353 /* ignore supported, maxtxpkt, maxrxpkt */ 354 355 if (cmd->base.autoneg == AUTONEG_ENABLE) { 356 u32 bmcr, advert, tmp; 357 u32 advert2 = 0, tmp2 = 0; 358 u32 advertising; 359 360 ethtool_convert_link_mode_to_legacy_u32( 361 &advertising, cmd->link_modes.advertising); 362 363 if ((advertising & (ADVERTISED_10baseT_Half | 364 ADVERTISED_10baseT_Full | 365 ADVERTISED_100baseT_Half | 366 ADVERTISED_100baseT_Full | 367 ADVERTISED_1000baseT_Half | 368 ADVERTISED_1000baseT_Full)) == 0) 369 return -EINVAL; 370 371 /* advertise only what has been requested */ 372 advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE); 373 tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4); 374 if (mii->supports_gmii) { 375 advert2 = mii->mdio_read(dev, mii->phy_id, 376 MII_CTRL1000); 377 tmp2 = advert2 & 378 ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); 379 } 380 tmp |= ethtool_adv_to_mii_adv_t(advertising); 381 382 if (mii->supports_gmii) 383 tmp2 |= ethtool_adv_to_mii_ctrl1000_t(advertising); 384 if (advert != tmp) { 385 mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp); 386 mii->advertising = tmp; 387 } 388 if ((mii->supports_gmii) && (advert2 != tmp2)) 389 mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2); 390 391 /* turn on autonegotiation, and force a renegotiate */ 392 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); 393 bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); 394 mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr); 395 396 mii->force_media = 0; 397 } else { 398 u32 bmcr, tmp; 399 400 /* turn off auto negotiation, set speed and duplexity */ 401 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR); 402 tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 | 403 BMCR_SPEED1000 | BMCR_FULLDPLX); 404 if (speed == SPEED_1000) 405 tmp |= BMCR_SPEED1000; 406 else if (speed == SPEED_100) 407 tmp |= BMCR_SPEED100; 408 if (cmd->base.duplex == DUPLEX_FULL) { 409 tmp |= BMCR_FULLDPLX; 410 mii->full_duplex = 1; 411 } else { 412 mii->full_duplex = 0; 413 } 414 if (bmcr != tmp) 415 mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp); 416 417 mii->force_media = 1; 418 } 419 return 0; 420 } 421 422 /** 423 * mii_check_gmii_support - check if the MII supports Gb interfaces 424 * @mii: the MII interface 425 */ 426 int mii_check_gmii_support(struct mii_if_info *mii) 427 { 428 int reg; 429 430 reg = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR); 431 if (reg & BMSR_ESTATEN) { 432 reg = mii->mdio_read(mii->dev, mii->phy_id, MII_ESTATUS); 433 if (reg & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF)) 434 return 1; 435 } 436 437 return 0; 438 } 439 440 /** 441 * mii_link_ok - is link status up/ok 442 * @mii: the MII interface 443 * 444 * Returns 1 if the MII reports link status up/ok, 0 otherwise. 445 */ 446 int mii_link_ok (struct mii_if_info *mii) 447 { 448 /* first, a dummy read, needed to latch some MII phys */ 449 mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR); 450 if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS) 451 return 1; 452 return 0; 453 } 454 455 /** 456 * mii_nway_restart - restart NWay (autonegotiation) for this interface 457 * @mii: the MII interface 458 * 459 * Returns 0 on success, negative on error. 460 */ 461 int mii_nway_restart (struct mii_if_info *mii) 462 { 463 int bmcr; 464 int r = -EINVAL; 465 466 /* if autoneg is off, it's an error */ 467 bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR); 468 469 if (bmcr & BMCR_ANENABLE) { 470 bmcr |= BMCR_ANRESTART; 471 mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr); 472 r = 0; 473 } 474 475 return r; 476 } 477 478 /** 479 * mii_check_link - check MII link status 480 * @mii: MII interface 481 * 482 * If the link status changed (previous != current), call 483 * netif_carrier_on() if current link status is Up or call 484 * netif_carrier_off() if current link status is Down. 485 */ 486 void mii_check_link (struct mii_if_info *mii) 487 { 488 int cur_link = mii_link_ok(mii); 489 int prev_link = netif_carrier_ok(mii->dev); 490 491 if (cur_link && !prev_link) 492 netif_carrier_on(mii->dev); 493 else if (prev_link && !cur_link) 494 netif_carrier_off(mii->dev); 495 } 496 497 /** 498 * mii_check_media - check the MII interface for a carrier/speed/duplex change 499 * @mii: the MII interface 500 * @ok_to_print: OK to print link up/down messages 501 * @init_media: OK to save duplex mode in @mii 502 * 503 * Returns 1 if the duplex mode changed, 0 if not. 504 * If the media type is forced, always returns 0. 505 */ 506 unsigned int mii_check_media (struct mii_if_info *mii, 507 unsigned int ok_to_print, 508 unsigned int init_media) 509 { 510 unsigned int old_carrier, new_carrier; 511 int advertise, lpa, media, duplex; 512 int lpa2 = 0; 513 514 /* check current and old link status */ 515 old_carrier = netif_carrier_ok(mii->dev) ? 1 : 0; 516 new_carrier = (unsigned int) mii_link_ok(mii); 517 518 /* if carrier state did not change, this is a "bounce", 519 * just exit as everything is already set correctly 520 */ 521 if ((!init_media) && (old_carrier == new_carrier)) 522 return 0; /* duplex did not change */ 523 524 /* no carrier, nothing much to do */ 525 if (!new_carrier) { 526 netif_carrier_off(mii->dev); 527 if (ok_to_print) 528 netdev_info(mii->dev, "link down\n"); 529 return 0; /* duplex did not change */ 530 } 531 532 /* 533 * we have carrier, see who's on the other end 534 */ 535 netif_carrier_on(mii->dev); 536 537 if (mii->force_media) { 538 if (ok_to_print) 539 netdev_info(mii->dev, "link up\n"); 540 return 0; /* duplex did not change */ 541 } 542 543 /* get MII advertise and LPA values */ 544 if ((!init_media) && (mii->advertising)) 545 advertise = mii->advertising; 546 else { 547 advertise = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE); 548 mii->advertising = advertise; 549 } 550 lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA); 551 if (mii->supports_gmii) 552 lpa2 = mii->mdio_read(mii->dev, mii->phy_id, MII_STAT1000); 553 554 /* figure out media and duplex from advertise and LPA values */ 555 media = mii_nway_result(lpa & advertise); 556 duplex = (media & ADVERTISE_FULL) ? 1 : 0; 557 if (lpa2 & LPA_1000FULL) 558 duplex = 1; 559 560 if (ok_to_print) 561 netdev_info(mii->dev, "link up, %uMbps, %s-duplex, lpa 0x%04X\n", 562 lpa2 & (LPA_1000FULL | LPA_1000HALF) ? 1000 : 563 media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ? 564 100 : 10, 565 duplex ? "full" : "half", 566 lpa); 567 568 if ((init_media) || (mii->full_duplex != duplex)) { 569 mii->full_duplex = duplex; 570 return 1; /* duplex changed */ 571 } 572 573 return 0; /* duplex did not change */ 574 } 575 576 /** 577 * generic_mii_ioctl - main MII ioctl interface 578 * @mii_if: the MII interface 579 * @mii_data: MII ioctl data structure 580 * @cmd: MII ioctl command 581 * @duplex_chg_out: pointer to @duplex_changed status if there was no 582 * ioctl error 583 * 584 * Returns 0 on success, negative on error. 585 */ 586 int generic_mii_ioctl(struct mii_if_info *mii_if, 587 struct mii_ioctl_data *mii_data, int cmd, 588 unsigned int *duplex_chg_out) 589 { 590 int rc = 0; 591 unsigned int duplex_changed = 0; 592 593 if (duplex_chg_out) 594 *duplex_chg_out = 0; 595 596 mii_data->phy_id &= mii_if->phy_id_mask; 597 mii_data->reg_num &= mii_if->reg_num_mask; 598 599 switch(cmd) { 600 case SIOCGMIIPHY: 601 mii_data->phy_id = mii_if->phy_id; 602 fallthrough; 603 604 case SIOCGMIIREG: 605 mii_data->val_out = 606 mii_if->mdio_read(mii_if->dev, mii_data->phy_id, 607 mii_data->reg_num); 608 break; 609 610 case SIOCSMIIREG: { 611 u16 val = mii_data->val_in; 612 613 if (mii_data->phy_id == mii_if->phy_id) { 614 switch(mii_data->reg_num) { 615 case MII_BMCR: { 616 unsigned int new_duplex = 0; 617 if (val & (BMCR_RESET|BMCR_ANENABLE)) 618 mii_if->force_media = 0; 619 else 620 mii_if->force_media = 1; 621 if (mii_if->force_media && 622 (val & BMCR_FULLDPLX)) 623 new_duplex = 1; 624 if (mii_if->full_duplex != new_duplex) { 625 duplex_changed = 1; 626 mii_if->full_duplex = new_duplex; 627 } 628 break; 629 } 630 case MII_ADVERTISE: 631 mii_if->advertising = val; 632 break; 633 default: 634 /* do nothing */ 635 break; 636 } 637 } 638 639 mii_if->mdio_write(mii_if->dev, mii_data->phy_id, 640 mii_data->reg_num, val); 641 break; 642 } 643 644 default: 645 rc = -EOPNOTSUPP; 646 break; 647 } 648 649 if ((rc == 0) && (duplex_chg_out) && (duplex_changed)) 650 *duplex_chg_out = 1; 651 652 return rc; 653 } 654 655 MODULE_AUTHOR ("Jeff Garzik <jgarzik@pobox.com>"); 656 MODULE_DESCRIPTION ("MII hardware support library"); 657 MODULE_LICENSE("GPL"); 658 659 EXPORT_SYMBOL(mii_link_ok); 660 EXPORT_SYMBOL(mii_nway_restart); 661 EXPORT_SYMBOL(mii_ethtool_gset); 662 EXPORT_SYMBOL(mii_ethtool_get_link_ksettings); 663 EXPORT_SYMBOL(mii_ethtool_sset); 664 EXPORT_SYMBOL(mii_ethtool_set_link_ksettings); 665 EXPORT_SYMBOL(mii_check_link); 666 EXPORT_SYMBOL(mii_check_media); 667 EXPORT_SYMBOL(mii_check_gmii_support); 668 EXPORT_SYMBOL(generic_mii_ioctl); 669 670