Skip to content

Commit 79ce047

Browse files
Brian Hilldavem330
authored andcommitted
net: phy: Correctly handle MII ioctl which changes autonegotiation.
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 <[email protected]> Acked-by: Florian Fainelli <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 5337b5b commit 79ce047

File tree

1 file changed

+24
-12
lines changed

1 file changed

+24
-12
lines changed

drivers/net/phy/phy.c

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,7 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
352352
{
353353
struct mii_ioctl_data *mii_data = if_mii(ifr);
354354
u16 val = mii_data->val_in;
355+
bool change_autoneg = false;
355356

356357
switch (cmd) {
357358
case SIOCGMIIPHY:
@@ -367,22 +368,29 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
367368
if (mii_data->phy_id == phydev->addr) {
368369
switch (mii_data->reg_num) {
369370
case MII_BMCR:
370-
if ((val & (BMCR_RESET | BMCR_ANENABLE)) == 0)
371+
if ((val & (BMCR_RESET | BMCR_ANENABLE)) == 0) {
372+
if (phydev->autoneg == AUTONEG_ENABLE)
373+
change_autoneg = true;
371374
phydev->autoneg = AUTONEG_DISABLE;
372-
else
375+
if (val & BMCR_FULLDPLX)
376+
phydev->duplex = DUPLEX_FULL;
377+
else
378+
phydev->duplex = DUPLEX_HALF;
379+
if (val & BMCR_SPEED1000)
380+
phydev->speed = SPEED_1000;
381+
else if (val & BMCR_SPEED100)
382+
phydev->speed = SPEED_100;
383+
else phydev->speed = SPEED_10;
384+
}
385+
else {
386+
if (phydev->autoneg == AUTONEG_DISABLE)
387+
change_autoneg = true;
373388
phydev->autoneg = AUTONEG_ENABLE;
374-
if (!phydev->autoneg && (val & BMCR_FULLDPLX))
375-
phydev->duplex = DUPLEX_FULL;
376-
else
377-
phydev->duplex = DUPLEX_HALF;
378-
if (!phydev->autoneg && (val & BMCR_SPEED1000))
379-
phydev->speed = SPEED_1000;
380-
else if (!phydev->autoneg &&
381-
(val & BMCR_SPEED100))
382-
phydev->speed = SPEED_100;
389+
}
383390
break;
384391
case MII_ADVERTISE:
385-
phydev->advertising = val;
392+
phydev->advertising = mii_adv_to_ethtool_adv_t(val);
393+
change_autoneg = true;
386394
break;
387395
default:
388396
/* do nothing */
@@ -396,6 +404,10 @@ int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
396404
if (mii_data->reg_num == MII_BMCR &&
397405
val & BMCR_RESET)
398406
return phy_init_hw(phydev);
407+
408+
if (change_autoneg)
409+
return phy_start_aneg(phydev);
410+
399411
return 0;
400412

401413
case SIOCSHWTSTAMP:

0 commit comments

Comments
 (0)