Skip to content

Commit

Permalink
net: phy: Correctly handle MII ioctl which changes autonegotiation.
Browse files Browse the repository at this point in the history
When advertised capabilities are changed with mii-tool, such as:
mii-tool -A 10baseT
the existing handler has two errors.

- An actual PHY register value is provided by mii-tool, and this
  must be mapped to internal state with mii_adv_to_ethtool_adv_t().
- The PHY state machine needs to be told that autonegotiation has
  again been performed.  If not, the MAC will not be notified of
  the new link speed and duplex, resulting in a possible config
  mismatch.

Signed-off-by: Brian Hill <Brian@houston-radar.com>
Acked-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Brian Hill authored and David S. Miller committed Nov 11, 2014
1 parent 5337b5b commit 79ce047
Showing 1 changed file with 24 additions and 12 deletions.
36 changes: 24 additions & 12 deletions drivers/net/phy/phy.c
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
{
struct mii_ioctl_data *mii_data = if_mii(ifr);
u16 val = mii_data->val_in;
bool change_autoneg = false;

switch (cmd) {
case SIOCGMIIPHY:
Expand All @@ -367,22 +368,29 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
if (mii_data->phy_id == phydev->addr) {
switch (mii_data->reg_num) {
case MII_BMCR:
if ((val & (BMCR_RESET | BMCR_ANENABLE)) == 0)
if ((val & (BMCR_RESET | BMCR_ANENABLE)) == 0) {
if (phydev->autoneg == AUTONEG_ENABLE)
change_autoneg = true;
phydev->autoneg = AUTONEG_DISABLE;
else
if (val & BMCR_FULLDPLX)
phydev->duplex = DUPLEX_FULL;
else
phydev->duplex = DUPLEX_HALF;
if (val & BMCR_SPEED1000)
phydev->speed = SPEED_1000;
else if (val & BMCR_SPEED100)
phydev->speed = SPEED_100;
else phydev->speed = SPEED_10;
}
else {
if (phydev->autoneg == AUTONEG_DISABLE)
change_autoneg = true;
phydev->autoneg = AUTONEG_ENABLE;
if (!phydev->autoneg && (val & BMCR_FULLDPLX))
phydev->duplex = DUPLEX_FULL;
else
phydev->duplex = DUPLEX_HALF;
if (!phydev->autoneg && (val & BMCR_SPEED1000))
phydev->speed = SPEED_1000;
else if (!phydev->autoneg &&
(val & BMCR_SPEED100))
phydev->speed = SPEED_100;
}
break;
case MII_ADVERTISE:
phydev->advertising = val;
phydev->advertising = mii_adv_to_ethtool_adv_t(val);
change_autoneg = true;
break;
default:
/* do nothing */
Expand All @@ -396,6 +404,10 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
if (mii_data->reg_num == MII_BMCR &&
val & BMCR_RESET)
return phy_init_hw(phydev);

if (change_autoneg)
return phy_start_aneg(phydev);

return 0;

case SIOCSHWTSTAMP:
Expand Down

0 comments on commit 79ce047

Please sign in to comment.