mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-09 00:43:08 -04:00
net: sunhme: Just restart autonegotiation if we can't bring the link up
If we've tried regular autonegotiation and forcing the link mode, just restart autonegotiation instead of reinitializing the whole NIC. Signed-off-by: Sean Anderson <seanga2@gmail.com> Reviewed-by: Simon Horman <simon.horman@corigine.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
committed by
David S. Miller
parent
d61157414d
commit
70b1b4b862
@@ -589,8 +589,6 @@ static int set_happy_link_modes(struct happy_meal *hp, void __iomem *tregs)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int happy_meal_init(struct happy_meal *hp);
|
||||
|
||||
static int is_lucent_phy(struct happy_meal *hp)
|
||||
{
|
||||
void __iomem *tregs = hp->tcvregs;
|
||||
@@ -606,6 +604,124 @@ static int is_lucent_phy(struct happy_meal *hp)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* hp->happy_lock must be held */
|
||||
static void
|
||||
happy_meal_begin_auto_negotiation(struct happy_meal *hp,
|
||||
void __iomem *tregs,
|
||||
const struct ethtool_link_ksettings *ep)
|
||||
{
|
||||
int timeout;
|
||||
|
||||
/* Read all of the registers we are interested in now. */
|
||||
hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, MII_BMSR);
|
||||
hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR);
|
||||
hp->sw_physid1 = happy_meal_tcvr_read(hp, tregs, MII_PHYSID1);
|
||||
hp->sw_physid2 = happy_meal_tcvr_read(hp, tregs, MII_PHYSID2);
|
||||
|
||||
/* XXX Check BMSR_ANEGCAPABLE, should not be necessary though. */
|
||||
|
||||
hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, MII_ADVERTISE);
|
||||
if (!ep || ep->base.autoneg == AUTONEG_ENABLE) {
|
||||
/* Advertise everything we can support. */
|
||||
if (hp->sw_bmsr & BMSR_10HALF)
|
||||
hp->sw_advertise |= (ADVERTISE_10HALF);
|
||||
else
|
||||
hp->sw_advertise &= ~(ADVERTISE_10HALF);
|
||||
|
||||
if (hp->sw_bmsr & BMSR_10FULL)
|
||||
hp->sw_advertise |= (ADVERTISE_10FULL);
|
||||
else
|
||||
hp->sw_advertise &= ~(ADVERTISE_10FULL);
|
||||
if (hp->sw_bmsr & BMSR_100HALF)
|
||||
hp->sw_advertise |= (ADVERTISE_100HALF);
|
||||
else
|
||||
hp->sw_advertise &= ~(ADVERTISE_100HALF);
|
||||
if (hp->sw_bmsr & BMSR_100FULL)
|
||||
hp->sw_advertise |= (ADVERTISE_100FULL);
|
||||
else
|
||||
hp->sw_advertise &= ~(ADVERTISE_100FULL);
|
||||
happy_meal_tcvr_write(hp, tregs, MII_ADVERTISE, hp->sw_advertise);
|
||||
|
||||
/* XXX Currently no Happy Meal cards I know off support 100BaseT4,
|
||||
* XXX and this is because the DP83840 does not support it, changes
|
||||
* XXX would need to be made to the tx/rx logic in the driver as well
|
||||
* XXX so I completely skip checking for it in the BMSR for now.
|
||||
*/
|
||||
|
||||
ASD("Advertising [ %s%s%s%s]\n",
|
||||
hp->sw_advertise & ADVERTISE_10HALF ? "10H " : "",
|
||||
hp->sw_advertise & ADVERTISE_10FULL ? "10F " : "",
|
||||
hp->sw_advertise & ADVERTISE_100HALF ? "100H " : "",
|
||||
hp->sw_advertise & ADVERTISE_100FULL ? "100F " : "");
|
||||
|
||||
/* Enable Auto-Negotiation, this is usually on already... */
|
||||
hp->sw_bmcr |= BMCR_ANENABLE;
|
||||
happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr);
|
||||
|
||||
/* Restart it to make sure it is going. */
|
||||
hp->sw_bmcr |= BMCR_ANRESTART;
|
||||
happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr);
|
||||
|
||||
/* BMCR_ANRESTART self clears when the process has begun. */
|
||||
|
||||
timeout = 64; /* More than enough. */
|
||||
while (--timeout) {
|
||||
hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR);
|
||||
if (!(hp->sw_bmcr & BMCR_ANRESTART))
|
||||
break; /* got it. */
|
||||
udelay(10);
|
||||
}
|
||||
if (!timeout) {
|
||||
netdev_err(hp->dev,
|
||||
"Happy Meal would not start auto negotiation BMCR=0x%04x\n",
|
||||
hp->sw_bmcr);
|
||||
netdev_notice(hp->dev,
|
||||
"Performing force link detection.\n");
|
||||
goto force_link;
|
||||
} else {
|
||||
hp->timer_state = arbwait;
|
||||
}
|
||||
} else {
|
||||
force_link:
|
||||
/* Force the link up, trying first a particular mode.
|
||||
* Either we are here at the request of ethtool or
|
||||
* because the Happy Meal would not start to autoneg.
|
||||
*/
|
||||
|
||||
/* Disable auto-negotiation in BMCR, enable the duplex and
|
||||
* speed setting, init the timer state machine, and fire it off.
|
||||
*/
|
||||
if (!ep || ep->base.autoneg == AUTONEG_ENABLE) {
|
||||
hp->sw_bmcr = BMCR_SPEED100;
|
||||
} else {
|
||||
if (ep->base.speed == SPEED_100)
|
||||
hp->sw_bmcr = BMCR_SPEED100;
|
||||
else
|
||||
hp->sw_bmcr = 0;
|
||||
if (ep->base.duplex == DUPLEX_FULL)
|
||||
hp->sw_bmcr |= BMCR_FULLDPLX;
|
||||
}
|
||||
happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr);
|
||||
|
||||
if (!is_lucent_phy(hp)) {
|
||||
/* OK, seems we need do disable the transceiver for the first
|
||||
* tick to make sure we get an accurate link state at the
|
||||
* second tick.
|
||||
*/
|
||||
hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs,
|
||||
DP83840_CSCONFIG);
|
||||
hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB);
|
||||
happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG,
|
||||
hp->sw_csconfig);
|
||||
}
|
||||
hp->timer_state = ltrywait;
|
||||
}
|
||||
|
||||
hp->timer_ticks = 0;
|
||||
hp->happy_timer.expires = jiffies + (12 * HZ)/10; /* 1.2 sec. */
|
||||
add_timer(&hp->happy_timer);
|
||||
}
|
||||
|
||||
static void happy_meal_timer(struct timer_list *t)
|
||||
{
|
||||
struct happy_meal *hp = from_timer(hp, t, happy_timer);
|
||||
@@ -743,12 +859,7 @@ static void happy_meal_timer(struct timer_list *t)
|
||||
netdev_notice(hp->dev,
|
||||
"Link down, cable problem?\n");
|
||||
|
||||
ret = happy_meal_init(hp);
|
||||
if (ret) {
|
||||
/* ho hum... */
|
||||
netdev_err(hp->dev,
|
||||
"Error, cannot re-init the Happy Meal.\n");
|
||||
}
|
||||
happy_meal_begin_auto_negotiation(hp, tregs, NULL);
|
||||
goto out;
|
||||
}
|
||||
if (!is_lucent_phy(hp)) {
|
||||
@@ -1201,124 +1312,6 @@ static void happy_meal_init_rings(struct happy_meal *hp)
|
||||
HMD("done\n");
|
||||
}
|
||||
|
||||
/* hp->happy_lock must be held */
|
||||
static void
|
||||
happy_meal_begin_auto_negotiation(struct happy_meal *hp,
|
||||
void __iomem *tregs,
|
||||
const struct ethtool_link_ksettings *ep)
|
||||
{
|
||||
int timeout;
|
||||
|
||||
/* Read all of the registers we are interested in now. */
|
||||
hp->sw_bmsr = happy_meal_tcvr_read(hp, tregs, MII_BMSR);
|
||||
hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR);
|
||||
hp->sw_physid1 = happy_meal_tcvr_read(hp, tregs, MII_PHYSID1);
|
||||
hp->sw_physid2 = happy_meal_tcvr_read(hp, tregs, MII_PHYSID2);
|
||||
|
||||
/* XXX Check BMSR_ANEGCAPABLE, should not be necessary though. */
|
||||
|
||||
hp->sw_advertise = happy_meal_tcvr_read(hp, tregs, MII_ADVERTISE);
|
||||
if (!ep || ep->base.autoneg == AUTONEG_ENABLE) {
|
||||
/* Advertise everything we can support. */
|
||||
if (hp->sw_bmsr & BMSR_10HALF)
|
||||
hp->sw_advertise |= (ADVERTISE_10HALF);
|
||||
else
|
||||
hp->sw_advertise &= ~(ADVERTISE_10HALF);
|
||||
|
||||
if (hp->sw_bmsr & BMSR_10FULL)
|
||||
hp->sw_advertise |= (ADVERTISE_10FULL);
|
||||
else
|
||||
hp->sw_advertise &= ~(ADVERTISE_10FULL);
|
||||
if (hp->sw_bmsr & BMSR_100HALF)
|
||||
hp->sw_advertise |= (ADVERTISE_100HALF);
|
||||
else
|
||||
hp->sw_advertise &= ~(ADVERTISE_100HALF);
|
||||
if (hp->sw_bmsr & BMSR_100FULL)
|
||||
hp->sw_advertise |= (ADVERTISE_100FULL);
|
||||
else
|
||||
hp->sw_advertise &= ~(ADVERTISE_100FULL);
|
||||
happy_meal_tcvr_write(hp, tregs, MII_ADVERTISE, hp->sw_advertise);
|
||||
|
||||
/* XXX Currently no Happy Meal cards I know off support 100BaseT4,
|
||||
* XXX and this is because the DP83840 does not support it, changes
|
||||
* XXX would need to be made to the tx/rx logic in the driver as well
|
||||
* XXX so I completely skip checking for it in the BMSR for now.
|
||||
*/
|
||||
|
||||
ASD("Advertising [ %s%s%s%s]\n",
|
||||
hp->sw_advertise & ADVERTISE_10HALF ? "10H " : "",
|
||||
hp->sw_advertise & ADVERTISE_10FULL ? "10F " : "",
|
||||
hp->sw_advertise & ADVERTISE_100HALF ? "100H " : "",
|
||||
hp->sw_advertise & ADVERTISE_100FULL ? "100F " : "");
|
||||
|
||||
/* Enable Auto-Negotiation, this is usually on already... */
|
||||
hp->sw_bmcr |= BMCR_ANENABLE;
|
||||
happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr);
|
||||
|
||||
/* Restart it to make sure it is going. */
|
||||
hp->sw_bmcr |= BMCR_ANRESTART;
|
||||
happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr);
|
||||
|
||||
/* BMCR_ANRESTART self clears when the process has begun. */
|
||||
|
||||
timeout = 64; /* More than enough. */
|
||||
while (--timeout) {
|
||||
hp->sw_bmcr = happy_meal_tcvr_read(hp, tregs, MII_BMCR);
|
||||
if (!(hp->sw_bmcr & BMCR_ANRESTART))
|
||||
break; /* got it. */
|
||||
udelay(10);
|
||||
}
|
||||
if (!timeout) {
|
||||
netdev_err(hp->dev,
|
||||
"Happy Meal would not start auto negotiation BMCR=0x%04x\n",
|
||||
hp->sw_bmcr);
|
||||
netdev_notice(hp->dev,
|
||||
"Performing force link detection.\n");
|
||||
goto force_link;
|
||||
} else {
|
||||
hp->timer_state = arbwait;
|
||||
}
|
||||
} else {
|
||||
force_link:
|
||||
/* Force the link up, trying first a particular mode.
|
||||
* Either we are here at the request of ethtool or
|
||||
* because the Happy Meal would not start to autoneg.
|
||||
*/
|
||||
|
||||
/* Disable auto-negotiation in BMCR, enable the duplex and
|
||||
* speed setting, init the timer state machine, and fire it off.
|
||||
*/
|
||||
if (!ep || ep->base.autoneg == AUTONEG_ENABLE) {
|
||||
hp->sw_bmcr = BMCR_SPEED100;
|
||||
} else {
|
||||
if (ep->base.speed == SPEED_100)
|
||||
hp->sw_bmcr = BMCR_SPEED100;
|
||||
else
|
||||
hp->sw_bmcr = 0;
|
||||
if (ep->base.duplex == DUPLEX_FULL)
|
||||
hp->sw_bmcr |= BMCR_FULLDPLX;
|
||||
}
|
||||
happy_meal_tcvr_write(hp, tregs, MII_BMCR, hp->sw_bmcr);
|
||||
|
||||
if (!is_lucent_phy(hp)) {
|
||||
/* OK, seems we need do disable the transceiver for the first
|
||||
* tick to make sure we get an accurate link state at the
|
||||
* second tick.
|
||||
*/
|
||||
hp->sw_csconfig = happy_meal_tcvr_read(hp, tregs,
|
||||
DP83840_CSCONFIG);
|
||||
hp->sw_csconfig &= ~(CSCONFIG_TCVDISAB);
|
||||
happy_meal_tcvr_write(hp, tregs, DP83840_CSCONFIG,
|
||||
hp->sw_csconfig);
|
||||
}
|
||||
hp->timer_state = ltrywait;
|
||||
}
|
||||
|
||||
hp->timer_ticks = 0;
|
||||
hp->happy_timer.expires = jiffies + (12 * HZ)/10; /* 1.2 sec. */
|
||||
add_timer(&hp->happy_timer);
|
||||
}
|
||||
|
||||
/* hp->happy_lock must be held */
|
||||
static int happy_meal_init(struct happy_meal *hp)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user