root/drivers/net/mii.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mii_get_an
  2. mii_ethtool_gset
  3. mii_ethtool_get_link_ksettings
  4. mii_ethtool_sset
  5. mii_ethtool_set_link_ksettings
  6. mii_check_gmii_support
  7. mii_link_ok
  8. mii_nway_restart
  9. mii_check_link
  10. mii_check_media
  11. generic_mii_ioctl

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

/* [<][>][^][v][top][bottom][index][help] */