Commit bc0f4a87 authored by Andrew Lunn's avatar Andrew Lunn Committed by David S. Miller

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: default avatarAndrew Lunn <andrew@lunn.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a5597008
...@@ -57,61 +57,84 @@ static int fixed_phy_update_regs(struct fixed_phy *fp) ...@@ -57,61 +57,84 @@ static int fixed_phy_update_regs(struct fixed_phy *fp)
if (gpio_is_valid(fp->link_gpio)) if (gpio_is_valid(fp->link_gpio))
fp->status.link = !!gpio_get_value_cansleep(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) { if (fp->status.duplex) {
bmcr |= BMCR_FULLDPLX;
switch (fp->status.speed) { switch (fp->status.speed) {
case 1000: case 1000:
bmsr |= BMSR_ESTATEN; bmsr |= BMSR_ESTATEN;
bmcr |= BMCR_SPEED1000;
lpagb |= LPA_1000FULL;
break; break;
case 100: case 100:
bmsr |= BMSR_100FULL; bmsr |= BMSR_100FULL;
bmcr |= BMCR_SPEED100;
lpa |= LPA_100FULL;
break; break;
case 10: case 10:
bmsr |= BMSR_10FULL; bmsr |= BMSR_10FULL;
lpa |= LPA_10FULL;
break; break;
default: default:
pr_warn("fixed phy: unknown speed\n"); break;
return -EINVAL;
} }
} else { } else {
switch (fp->status.speed) { switch (fp->status.speed) {
case 1000: case 1000:
bmsr |= BMSR_ESTATEN; bmsr |= BMSR_ESTATEN;
bmcr |= BMCR_SPEED1000;
lpagb |= LPA_1000HALF;
break; break;
case 100: case 100:
bmsr |= BMSR_100HALF; bmsr |= BMSR_100HALF;
bmcr |= BMCR_SPEED100;
lpa |= LPA_100HALF;
break; break;
case 10: case 10:
bmsr |= BMSR_10HALF; bmsr |= BMSR_10HALF;
lpa |= LPA_10HALF;
break; break;
default: default:
pr_warn("fixed phy: unknown speed\n"); break;
return -EINVAL;
} }
} }
if (fp->status.pause) if (fp->status.link) {
lpa |= LPA_PAUSE_CAP; bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE;
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) if (fp->status.asym_pause)
lpa |= LPA_PAUSE_ASYM; lpa |= LPA_PAUSE_ASYM;
}
done:
fp->regs[MII_PHYSID1] = 0; fp->regs[MII_PHYSID1] = 0;
fp->regs[MII_PHYSID2] = 0; fp->regs[MII_PHYSID2] = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment