LCOV - code coverage report
Current view: top level - drivers/net - mii.c (source / functions) Hit Total Coverage
Test: Real Lines: 61 246 24.8 %
Date: 2020-10-17 15:46:16 Functions: 5 11 45.5 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       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                 :          2 : static u32 mii_get_an(struct mii_if_info *mii, u16 addr)
      37                 :            : {
      38                 :            :         int advert;
      39                 :            : 
      40                 :          2 :         advert = mii->mdio_read(mii->dev, mii->phy_id, addr);
      41                 :            : 
      42                 :          2 :         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                 :          2 : int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
      56                 :            : {
      57                 :          2 :         struct net_device *dev = mii->dev;
      58                 :            :         u16 bmcr, bmsr, ctrl1000 = 0, stat1000 = 0;
      59                 :            :         u32 nego;
      60                 :            : 
      61                 :          2 :         ecmd->supported =
      62                 :            :             (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
      63                 :            :              SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
      64                 :            :              SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
      65                 :          2 :         if (mii->supports_gmii)
      66                 :          0 :                 ecmd->supported |= SUPPORTED_1000baseT_Half |
      67                 :            :                         SUPPORTED_1000baseT_Full;
      68                 :            : 
      69                 :            :         /* only supports twisted-pair */
      70                 :          2 :         ecmd->port = PORT_MII;
      71                 :            : 
      72                 :            :         /* only supports internal transceiver */
      73                 :          2 :         ecmd->transceiver = XCVR_INTERNAL;
      74                 :            : 
      75                 :            :         /* this isn't fully supported at higher layers */
      76                 :          2 :         ecmd->phy_address = mii->phy_id;
      77                 :          2 :         ecmd->mdio_support = ETH_MDIO_SUPPORTS_C22;
      78                 :            : 
      79                 :          2 :         ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
      80                 :            : 
      81                 :          2 :         bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
      82                 :          2 :         bmsr = mii->mdio_read(dev, mii->phy_id, MII_BMSR);
      83                 :          2 :         if (mii->supports_gmii) {
      84                 :          0 :                 ctrl1000 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
      85                 :          0 :                 stat1000 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000);
      86                 :            :         }
      87                 :          2 :         if (bmcr & BMCR_ANENABLE) {
      88                 :          2 :                 ecmd->advertising |= ADVERTISED_Autoneg;
      89                 :          2 :                 ecmd->autoneg = AUTONEG_ENABLE;
      90                 :            : 
      91                 :          2 :                 ecmd->advertising |= mii_get_an(mii, MII_ADVERTISE);
      92                 :          2 :                 if (mii->supports_gmii)
      93                 :          0 :                         ecmd->advertising |=
      94                 :            :                                         mii_ctrl1000_to_ethtool_adv_t(ctrl1000);
      95                 :            : 
      96                 :          2 :                 if (bmsr & BMSR_ANEGCOMPLETE) {
      97                 :          2 :                         ecmd->lp_advertising = mii_get_an(mii, MII_LPA);
      98                 :          2 :                         ecmd->lp_advertising |=
      99                 :            :                                         mii_stat1000_to_ethtool_lpa_t(stat1000);
     100                 :            :                 } else {
     101                 :          0 :                         ecmd->lp_advertising = 0;
     102                 :            :                 }
     103                 :            : 
     104                 :          2 :                 nego = ecmd->advertising & ecmd->lp_advertising;
     105                 :            : 
     106                 :          2 :                 if (nego & (ADVERTISED_1000baseT_Full |
     107                 :            :                             ADVERTISED_1000baseT_Half)) {
     108                 :            :                         ethtool_cmd_speed_set(ecmd, SPEED_1000);
     109                 :          0 :                         ecmd->duplex = !!(nego & ADVERTISED_1000baseT_Full);
     110                 :          2 :                 } else if (nego & (ADVERTISED_100baseT_Full |
     111                 :            :                                    ADVERTISED_100baseT_Half)) {
     112                 :            :                         ethtool_cmd_speed_set(ecmd, SPEED_100);
     113                 :          2 :                         ecmd->duplex = !!(nego & ADVERTISED_100baseT_Full);
     114                 :            :                 } else {
     115                 :            :                         ethtool_cmd_speed_set(ecmd, SPEED_10);
     116                 :          0 :                         ecmd->duplex = !!(nego & ADVERTISED_10baseT_Full);
     117                 :            :                 }
     118                 :            :         } else {
     119                 :          0 :                 ecmd->autoneg = AUTONEG_DISABLE;
     120                 :            : 
     121                 :          0 :                 ethtool_cmd_speed_set(ecmd,
     122                 :          0 :                                       ((bmcr & BMCR_SPEED1000 &&
     123                 :            :                                         (bmcr & BMCR_SPEED100) == 0) ?
     124                 :            :                                        SPEED_1000 :
     125                 :          0 :                                        ((bmcr & BMCR_SPEED100) ?
     126                 :            :                                         SPEED_100 : SPEED_10)));
     127                 :          0 :                 ecmd->duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
     128                 :            :         }
     129                 :            : 
     130                 :          2 :         mii->full_duplex = ecmd->duplex;
     131                 :            : 
     132                 :            :         /* ignore maxtxpkt, maxrxpkt for now */
     133                 :            : 
     134                 :          2 :         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                 :          0 : void mii_ethtool_get_link_ksettings(struct mii_if_info *mii,
     146                 :            :                                     struct ethtool_link_ksettings *cmd)
     147                 :            : {
     148                 :          0 :         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                 :          0 :         if (mii->supports_gmii)
     156                 :            :                 supported |= SUPPORTED_1000baseT_Half |
     157                 :            :                         SUPPORTED_1000baseT_Full;
     158                 :            : 
     159                 :            :         /* only supports twisted-pair */
     160                 :          0 :         cmd->base.port = PORT_MII;
     161                 :            : 
     162                 :            :         /* this isn't fully supported at higher layers */
     163                 :          0 :         cmd->base.phy_address = mii->phy_id;
     164                 :          0 :         cmd->base.mdio_support = ETH_MDIO_SUPPORTS_C22;
     165                 :            : 
     166                 :            :         advertising = ADVERTISED_TP | ADVERTISED_MII;
     167                 :            : 
     168                 :          0 :         bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
     169                 :          0 :         bmsr = mii->mdio_read(dev, mii->phy_id, MII_BMSR);
     170                 :          0 :         if (mii->supports_gmii) {
     171                 :          0 :                 ctrl1000 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
     172                 :          0 :                 stat1000 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000);
     173                 :            :         }
     174                 :          0 :         if (bmcr & BMCR_ANENABLE) {
     175                 :            :                 advertising |= ADVERTISED_Autoneg;
     176                 :          0 :                 cmd->base.autoneg = AUTONEG_ENABLE;
     177                 :            : 
     178                 :          0 :                 advertising |= mii_get_an(mii, MII_ADVERTISE);
     179                 :          0 :                 if (mii->supports_gmii)
     180                 :          0 :                         advertising |= mii_ctrl1000_to_ethtool_adv_t(ctrl1000);
     181                 :            : 
     182                 :          0 :                 if (bmsr & BMSR_ANEGCOMPLETE) {
     183                 :          0 :                         lp_advertising = mii_get_an(mii, MII_LPA);
     184                 :          0 :                         lp_advertising |=
     185                 :            :                                         mii_stat1000_to_ethtool_lpa_t(stat1000);
     186                 :            :                 } else {
     187                 :            :                         lp_advertising = 0;
     188                 :            :                 }
     189                 :            : 
     190                 :          0 :                 nego = advertising & lp_advertising;
     191                 :            : 
     192                 :          0 :                 if (nego & (ADVERTISED_1000baseT_Full |
     193                 :            :                             ADVERTISED_1000baseT_Half)) {
     194                 :          0 :                         cmd->base.speed = SPEED_1000;
     195                 :          0 :                         cmd->base.duplex = !!(nego & ADVERTISED_1000baseT_Full);
     196                 :          0 :                 } else if (nego & (ADVERTISED_100baseT_Full |
     197                 :            :                                    ADVERTISED_100baseT_Half)) {
     198                 :          0 :                         cmd->base.speed = SPEED_100;
     199                 :          0 :                         cmd->base.duplex = !!(nego & ADVERTISED_100baseT_Full);
     200                 :            :                 } else {
     201                 :          0 :                         cmd->base.speed = SPEED_10;
     202                 :          0 :                         cmd->base.duplex = !!(nego & ADVERTISED_10baseT_Full);
     203                 :            :                 }
     204                 :            :         } else {
     205                 :          0 :                 cmd->base.autoneg = AUTONEG_DISABLE;
     206                 :            : 
     207                 :          0 :                 cmd->base.speed = ((bmcr & BMCR_SPEED1000 &&
     208                 :            :                                     (bmcr & BMCR_SPEED100) == 0) ?
     209                 :            :                                    SPEED_1000 :
     210                 :          0 :                                    ((bmcr & BMCR_SPEED100) ?
     211                 :            :                                     SPEED_100 : SPEED_10));
     212                 :          0 :                 cmd->base.duplex = (bmcr & BMCR_FULLDPLX) ?
     213                 :          0 :                         DUPLEX_FULL : DUPLEX_HALF;
     214                 :            : 
     215                 :            :                 lp_advertising = 0;
     216                 :            :         }
     217                 :            : 
     218                 :          0 :         mii->full_duplex = cmd->base.duplex;
     219                 :            : 
     220                 :          0 :         ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
     221                 :            :                                                 supported);
     222                 :          0 :         ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
     223                 :            :                                                 advertising);
     224                 :          0 :         ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising,
     225                 :            :                                                 lp_advertising);
     226                 :            : 
     227                 :            :         /* ignore maxtxpkt, maxrxpkt for now */
     228                 :          0 : }
     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                 :          0 : int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
     238                 :            : {
     239                 :          0 :         struct net_device *dev = mii->dev;
     240                 :            :         u32 speed = ethtool_cmd_speed(ecmd);
     241                 :            : 
     242                 :          0 :         if (speed != SPEED_10 &&
     243                 :          0 :             speed != SPEED_100 &&
     244                 :            :             speed != SPEED_1000)
     245                 :            :                 return -EINVAL;
     246                 :          0 :         if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
     247                 :            :                 return -EINVAL;
     248                 :          0 :         if (ecmd->port != PORT_MII)
     249                 :            :                 return -EINVAL;
     250                 :          0 :         if (ecmd->transceiver != XCVR_INTERNAL)
     251                 :            :                 return -EINVAL;
     252                 :          0 :         if (ecmd->phy_address != mii->phy_id)
     253                 :            :                 return -EINVAL;
     254                 :          0 :         if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
     255                 :            :                 return -EINVAL;
     256                 :          0 :         if ((speed == SPEED_1000) && (!mii->supports_gmii))
     257                 :            :                 return -EINVAL;
     258                 :            : 
     259                 :            :         /* ignore supported, maxtxpkt, maxrxpkt */
     260                 :            : 
     261                 :          0 :         if (ecmd->autoneg == AUTONEG_ENABLE) {
     262                 :            :                 u32 bmcr, advert, tmp;
     263                 :            :                 u32 advert2 = 0, tmp2 = 0;
     264                 :            : 
     265                 :          0 :                 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                 :          0 :                 advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
     275                 :          0 :                 tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
     276                 :          0 :                 if (mii->supports_gmii) {
     277                 :          0 :                         advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
     278                 :          0 :                         tmp2 = advert2 & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
     279                 :            :                 }
     280                 :          0 :                 tmp |= ethtool_adv_to_mii_adv_t(ecmd->advertising);
     281                 :            : 
     282                 :          0 :                 if (mii->supports_gmii)
     283                 :          0 :                         tmp2 |=
     284                 :            :                               ethtool_adv_to_mii_ctrl1000_t(ecmd->advertising);
     285                 :          0 :                 if (advert != tmp) {
     286                 :          0 :                         mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
     287                 :          0 :                         mii->advertising = tmp;
     288                 :            :                 }
     289                 :          0 :                 if ((mii->supports_gmii) && (advert2 != tmp2))
     290                 :          0 :                         mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
     291                 :            : 
     292                 :            :                 /* turn on autonegotiation, and force a renegotiate */
     293                 :          0 :                 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
     294                 :          0 :                 bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
     295                 :          0 :                 mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
     296                 :            : 
     297                 :          0 :                 mii->force_media = 0;
     298                 :            :         } else {
     299                 :            :                 u32 bmcr, tmp;
     300                 :            : 
     301                 :            :                 /* turn off auto negotiation, set speed and duplexity */
     302                 :          0 :                 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
     303                 :          0 :                 tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
     304                 :            :                                BMCR_SPEED1000 | BMCR_FULLDPLX);
     305                 :          0 :                 if (speed == SPEED_1000)
     306                 :          0 :                         tmp |= BMCR_SPEED1000;
     307                 :          0 :                 else if (speed == SPEED_100)
     308                 :          0 :                         tmp |= BMCR_SPEED100;
     309                 :          0 :                 if (ecmd->duplex == DUPLEX_FULL) {
     310                 :          0 :                         tmp |= BMCR_FULLDPLX;
     311                 :          0 :                         mii->full_duplex = 1;
     312                 :            :                 } else
     313                 :          0 :                         mii->full_duplex = 0;
     314                 :          0 :                 if (bmcr != tmp)
     315                 :          0 :                         mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
     316                 :            : 
     317                 :          0 :                 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                 :          0 : int mii_ethtool_set_link_ksettings(struct mii_if_info *mii,
     330                 :            :                                    const struct ethtool_link_ksettings *cmd)
     331                 :            : {
     332                 :          0 :         struct net_device *dev = mii->dev;
     333                 :          0 :         u32 speed = cmd->base.speed;
     334                 :            : 
     335                 :          0 :         if (speed != SPEED_10 &&
     336                 :          0 :             speed != SPEED_100 &&
     337                 :            :             speed != SPEED_1000)
     338                 :            :                 return -EINVAL;
     339                 :          0 :         if (cmd->base.duplex != DUPLEX_HALF && cmd->base.duplex != DUPLEX_FULL)
     340                 :            :                 return -EINVAL;
     341                 :          0 :         if (cmd->base.port != PORT_MII)
     342                 :            :                 return -EINVAL;
     343                 :          0 :         if (cmd->base.phy_address != mii->phy_id)
     344                 :            :                 return -EINVAL;
     345                 :          0 :         if (cmd->base.autoneg != AUTONEG_DISABLE &&
     346                 :            :             cmd->base.autoneg != AUTONEG_ENABLE)
     347                 :            :                 return -EINVAL;
     348                 :          0 :         if ((speed == SPEED_1000) && (!mii->supports_gmii))
     349                 :            :                 return -EINVAL;
     350                 :            : 
     351                 :            :         /* ignore supported, maxtxpkt, maxrxpkt */
     352                 :            : 
     353                 :          0 :         if (cmd->base.autoneg == AUTONEG_ENABLE) {
     354                 :            :                 u32 bmcr, advert, tmp;
     355                 :            :                 u32 advert2 = 0, tmp2 = 0;
     356                 :            :                 u32 advertising;
     357                 :            : 
     358                 :          0 :                 ethtool_convert_link_mode_to_legacy_u32(
     359                 :          0 :                         &advertising, cmd->link_modes.advertising);
     360                 :            : 
     361                 :          0 :                 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                 :          0 :                         return -EINVAL;
     368                 :            : 
     369                 :            :                 /* advertise only what has been requested */
     370                 :          0 :                 advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
     371                 :          0 :                 tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
     372                 :          0 :                 if (mii->supports_gmii) {
     373                 :          0 :                         advert2 = mii->mdio_read(dev, mii->phy_id,
     374                 :            :                                                  MII_CTRL1000);
     375                 :          0 :                         tmp2 = advert2 &
     376                 :            :                                 ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
     377                 :            :                 }
     378                 :          0 :                 tmp |= ethtool_adv_to_mii_adv_t(advertising);
     379                 :            : 
     380                 :          0 :                 if (mii->supports_gmii)
     381                 :          0 :                         tmp2 |= ethtool_adv_to_mii_ctrl1000_t(advertising);
     382                 :          0 :                 if (advert != tmp) {
     383                 :          0 :                         mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
     384                 :          0 :                         mii->advertising = tmp;
     385                 :            :                 }
     386                 :          0 :                 if ((mii->supports_gmii) && (advert2 != tmp2))
     387                 :          0 :                         mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
     388                 :            : 
     389                 :            :                 /* turn on autonegotiation, and force a renegotiate */
     390                 :          0 :                 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
     391                 :          0 :                 bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
     392                 :          0 :                 mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
     393                 :            : 
     394                 :          0 :                 mii->force_media = 0;
     395                 :            :         } else {
     396                 :            :                 u32 bmcr, tmp;
     397                 :            : 
     398                 :            :                 /* turn off auto negotiation, set speed and duplexity */
     399                 :          0 :                 bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
     400                 :          0 :                 tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
     401                 :            :                                BMCR_SPEED1000 | BMCR_FULLDPLX);
     402                 :          0 :                 if (speed == SPEED_1000)
     403                 :          0 :                         tmp |= BMCR_SPEED1000;
     404                 :          0 :                 else if (speed == SPEED_100)
     405                 :          0 :                         tmp |= BMCR_SPEED100;
     406                 :          0 :                 if (cmd->base.duplex == DUPLEX_FULL) {
     407                 :          0 :                         tmp |= BMCR_FULLDPLX;
     408                 :          0 :                         mii->full_duplex = 1;
     409                 :            :                 } else {
     410                 :          0 :                         mii->full_duplex = 0;
     411                 :            :                 }
     412                 :          0 :                 if (bmcr != tmp)
     413                 :          0 :                         mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
     414                 :            : 
     415                 :          0 :                 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                 :          0 : int mii_check_gmii_support(struct mii_if_info *mii)
     425                 :            : {
     426                 :            :         int reg;
     427                 :            : 
     428                 :          0 :         reg = mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
     429                 :          0 :         if (reg & BMSR_ESTATEN) {
     430                 :          0 :                 reg = mii->mdio_read(mii->dev, mii->phy_id, MII_ESTATUS);
     431                 :          0 :                 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                 :          2 : int mii_link_ok (struct mii_if_info *mii)
     445                 :            : {
     446                 :            :         /* first, a dummy read, needed to latch some MII phys */
     447                 :          2 :         mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
     448                 :          2 :         if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
     449                 :            :                 return 1;
     450                 :          0 :         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                 :          2 : 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                 :          2 :         bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
     466                 :            : 
     467                 :          2 :         if (bmcr & BMCR_ANENABLE) {
     468                 :          2 :                 bmcr |= BMCR_ANRESTART;
     469                 :          2 :                 mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
     470                 :            :                 r = 0;
     471                 :            :         }
     472                 :            : 
     473                 :          2 :         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                 :          0 : void mii_check_link (struct mii_if_info *mii)
     485                 :            : {
     486                 :          0 :         int cur_link = mii_link_ok(mii);
     487                 :          0 :         int prev_link = netif_carrier_ok(mii->dev);
     488                 :            : 
     489                 :          0 :         if (cur_link && !prev_link)
     490                 :          0 :                 netif_carrier_on(mii->dev);
     491                 :          0 :         else if (prev_link && !cur_link)
     492                 :          0 :                 netif_carrier_off(mii->dev);
     493                 :          0 : }
     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                 :          2 : 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                 :          2 :         old_carrier = netif_carrier_ok(mii->dev) ? 1 : 0;
     514                 :          2 :         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                 :          2 :         if ((!init_media) && (old_carrier == new_carrier))
     520                 :            :                 return 0; /* duplex did not change */
     521                 :            : 
     522                 :            :         /* no carrier, nothing much to do */
     523                 :          2 :         if (!new_carrier) {
     524                 :          0 :                 netif_carrier_off(mii->dev);
     525                 :          0 :                 if (ok_to_print)
     526                 :          0 :                         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                 :          2 :         netif_carrier_on(mii->dev);
     534                 :            : 
     535                 :          2 :         if (mii->force_media) {
     536                 :          0 :                 if (ok_to_print)
     537                 :          0 :                         netdev_info(mii->dev, "link up\n");
     538                 :            :                 return 0; /* duplex did not change */
     539                 :            :         }
     540                 :            : 
     541                 :            :         /* get MII advertise and LPA values */
     542                 :          2 :         if ((!init_media) && (mii->advertising))
     543                 :            :                 advertise = mii->advertising;
     544                 :            :         else {
     545                 :          2 :                 advertise = mii->mdio_read(mii->dev, mii->phy_id, MII_ADVERTISE);
     546                 :          2 :                 mii->advertising = advertise;
     547                 :            :         }
     548                 :          2 :         lpa = mii->mdio_read(mii->dev, mii->phy_id, MII_LPA);
     549                 :          2 :         if (mii->supports_gmii)
     550                 :          0 :                 lpa2 = mii->mdio_read(mii->dev, mii->phy_id, MII_STAT1000);
     551                 :            : 
     552                 :            :         /* figure out media and duplex from advertise and LPA values */
     553                 :          2 :         media = mii_nway_result(lpa & advertise);
     554                 :          2 :         duplex = (media & ADVERTISE_FULL) ? 1 : 0;
     555                 :          2 :         if (lpa2 & LPA_1000FULL)
     556                 :            :                 duplex = 1;
     557                 :            : 
     558                 :          2 :         if (ok_to_print)
     559                 :          2 :                 netdev_info(mii->dev, "link up, %uMbps, %s-duplex, lpa 0x%04X\n",
     560                 :          2 :                             lpa2 & (LPA_1000FULL | LPA_1000HALF) ? 1000 :
     561                 :          2 :                             media & (ADVERTISE_100FULL | ADVERTISE_100HALF) ?
     562                 :          2 :                             100 : 10,
     563                 :            :                             duplex ? "full" : "half",
     564                 :            :                             lpa);
     565                 :            : 
     566                 :          2 :         if ((init_media) || (mii->full_duplex != duplex)) {
     567                 :          2 :                 mii->full_duplex = duplex;
     568                 :          2 :                 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                 :          0 : 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                 :          0 :         if (duplex_chg_out)
     592                 :          0 :                 *duplex_chg_out = 0;
     593                 :            : 
     594                 :          0 :         mii_data->phy_id &= mii_if->phy_id_mask;
     595                 :          0 :         mii_data->reg_num &= mii_if->reg_num_mask;
     596                 :            : 
     597                 :          0 :         switch(cmd) {
     598                 :            :         case SIOCGMIIPHY:
     599                 :          0 :                 mii_data->phy_id = mii_if->phy_id;
     600                 :            :                 /* fall through */
     601                 :            : 
     602                 :            :         case SIOCGMIIREG:
     603                 :          0 :                 mii_data->val_out =
     604                 :          0 :                         mii_if->mdio_read(mii_if->dev, mii_data->phy_id,
     605                 :            :                                           mii_data->reg_num);
     606                 :          0 :                 break;
     607                 :            : 
     608                 :            :         case SIOCSMIIREG: {
     609                 :          0 :                 u16 val = mii_data->val_in;
     610                 :            : 
     611                 :          0 :                 if (mii_data->phy_id == mii_if->phy_id) {
     612                 :          0 :                         switch(mii_data->reg_num) {
     613                 :            :                         case MII_BMCR: {
     614                 :            :                                 unsigned int new_duplex = 0;
     615                 :          0 :                                 if (val & (BMCR_RESET|BMCR_ANENABLE))
     616                 :          0 :                                         mii_if->force_media = 0;
     617                 :            :                                 else
     618                 :          0 :                                         mii_if->force_media = 1;
     619                 :          0 :                                 if (mii_if->force_media &&
     620                 :          0 :                                     (val & BMCR_FULLDPLX))
     621                 :            :                                         new_duplex = 1;
     622                 :          0 :                                 if (mii_if->full_duplex != new_duplex) {
     623                 :            :                                         duplex_changed = 1;
     624                 :          0 :                                         mii_if->full_duplex = new_duplex;
     625                 :            :                                 }
     626                 :            :                                 break;
     627                 :            :                         }
     628                 :            :                         case MII_ADVERTISE:
     629                 :          0 :                                 mii_if->advertising = val;
     630                 :          0 :                                 break;
     631                 :            :                         default:
     632                 :            :                                 /* do nothing */
     633                 :            :                                 break;
     634                 :            :                         }
     635                 :            :                 }
     636                 :            : 
     637                 :          0 :                 mii_if->mdio_write(mii_if->dev, mii_data->phy_id,
     638                 :          0 :                                    mii_data->reg_num, val);
     639                 :          0 :                 break;
     640                 :            :         }
     641                 :            : 
     642                 :            :         default:
     643                 :            :                 rc = -EOPNOTSUPP;
     644                 :            :                 break;
     645                 :            :         }
     646                 :            : 
     647                 :          0 :         if ((rc == 0) && (duplex_chg_out) && (duplex_changed))
     648                 :          0 :                 *duplex_chg_out = 1;
     649                 :            : 
     650                 :          0 :         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                 :            : 
    

Generated by: LCOV version 1.14