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