net: phy: fixed_phy: Set phy capabilities even when link down.

What features a phy supports is masked in genphy_config_init() by
looking at the PHYs BMSR register.

If the link is down, fixed_phy_update_regs() will only set the auto-
negotiation capable bit in BMSR. Thus genphy_config_init() comes to
the conclusion the PHY can only perform 10/Half, and masks out the
higher speed features. If however the link it up, BMSR is set to
indicate the speed the PHY is capable of auto-negotiating, and
genphy_config_init() does not mask out the high speed features.

To fix this, when the link is down, have fixed_phy_update_regs() leave
the link status, auto-negotiation complete, and link partner
capabilities unset, but set all the local capabilities depending on
the fixed phy speed.

Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Andrew Lunn 2015-08-31 15:56:54 +02:00 committed by David S. Miller
parent a5597008db
commit bc0f4a87fc
1 changed files with 48 additions and 25 deletions

View File

@ -57,61 +57,84 @@ static int fixed_phy_update_regs(struct fixed_phy *fp)
if (gpio_is_valid(fp->link_gpio))
fp->status.link = !!gpio_get_value_cansleep(fp->link_gpio);
if (!fp->status.link)
goto done;
bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE;
if (fp->status.duplex) {
bmcr |= BMCR_FULLDPLX;
switch (fp->status.speed) {
case 1000:
bmsr |= BMSR_ESTATEN;
bmcr |= BMCR_SPEED1000;
lpagb |= LPA_1000FULL;
break;
case 100:
bmsr |= BMSR_100FULL;
bmcr |= BMCR_SPEED100;
lpa |= LPA_100FULL;
break;
case 10:
bmsr |= BMSR_10FULL;
lpa |= LPA_10FULL;
break;
default:
pr_warn("fixed phy: unknown speed\n");
return -EINVAL;
break;
}
} else {
switch (fp->status.speed) {
case 1000:
bmsr |= BMSR_ESTATEN;
bmcr |= BMCR_SPEED1000;
lpagb |= LPA_1000HALF;
break;
case 100:
bmsr |= BMSR_100HALF;
bmcr |= BMCR_SPEED100;
lpa |= LPA_100HALF;
break;
case 10:
bmsr |= BMSR_10HALF;
lpa |= LPA_10HALF;
break;
default:
pr_warn("fixed phy: unknown speed\n");
return -EINVAL;
break;
}
}
if (fp->status.pause)
lpa |= LPA_PAUSE_CAP;
if (fp->status.link) {
bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE;
if (fp->status.asym_pause)
lpa |= LPA_PAUSE_ASYM;
if (fp->status.duplex) {
bmcr |= BMCR_FULLDPLX;
switch (fp->status.speed) {
case 1000:
bmcr |= BMCR_SPEED1000;
lpagb |= LPA_1000FULL;
break;
case 100:
bmcr |= BMCR_SPEED100;
lpa |= LPA_100FULL;
break;
case 10:
lpa |= LPA_10FULL;
break;
default:
pr_warn("fixed phy: unknown speed\n");
return -EINVAL;
}
} else {
switch (fp->status.speed) {
case 1000:
bmcr |= BMCR_SPEED1000;
lpagb |= LPA_1000HALF;
break;
case 100:
bmcr |= BMCR_SPEED100;
lpa |= LPA_100HALF;
break;
case 10:
lpa |= LPA_10HALF;
break;
default:
pr_warn("fixed phy: unknown speed\n");
return -EINVAL;
}
}
if (fp->status.pause)
lpa |= LPA_PAUSE_CAP;
if (fp->status.asym_pause)
lpa |= LPA_PAUSE_ASYM;
}
done:
fp->regs[MII_PHYSID1] = 0;
fp->regs[MII_PHYSID2] = 0;