summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZeng Zhaoming <b32542@freescale.com>2010-12-14 07:39:30 +0800
committerZeng Zhaoming <b32542@freescale.com>2010-12-14 08:27:46 +0800
commitc6b55f9d8b751ee7e5a6232dac5a5e3dc9c344a5 (patch)
tree6ed9d728664b193e0add565f3786743a92bd58f6
parent3862b1becab6968996a605845ca2e827273903f1 (diff)
ENGR00136921 FEC: Fix nfs not works after kernel suspend and resume on i.MX28
Fec phy state changing occurs in delay works, which in normal task context. And package sending mostly happens in softirq context, only happens in ksoftirq while network traffic is heavy and some _many retries_ situation. Linux network qdisc code keep raising NET_TX_SOFTIRQ softirq if package not send out when netdev queue set to start. And the subsequenece process will loop in softirq context for 10ms. Since Imx28 HZ set to 100Hz, the next timer interrupt will trigger softirq again. this loop prevent network link changing to up status. And cause a chicken-egg problem. To break this loop, we need to set netdev transmit queue stop when link is down, and start it when link becomes up. commit 757bfe446bab7661d12a8772ca10b7a490c8aa47 try to resolve this problem, but hand-merge mistake introduce a power resume bug. Reported-by: Peter Chen <peter.chen@freescale.com> Signed-off-by: Zeng Zhaoming <b32542@freescale.com>
-rw-r--r--drivers/net/fec.c13
1 files changed, 9 insertions, 4 deletions
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index f58196019287..2f159b56fc67 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -682,7 +682,6 @@ static void fec_enet_adjust_link(struct net_device *dev)
if (phy_dev->link) {
if (fep->full_duplex != phy_dev->duplex) {
fec_restart(dev, phy_dev->duplex);
- netif_wake_queue(dev);
status_change = 1;
}
}
@@ -690,8 +689,15 @@ static void fec_enet_adjust_link(struct net_device *dev)
/* Link on or off change */
if (phy_dev->link != fep->link) {
fep->link = phy_dev->link;
- if (phy_dev->link)
+ if (phy_dev->link) {
fec_restart(dev, phy_dev->duplex);
+
+ /* if link becomes up and tx be stopped, start it */
+ if (netif_queue_stopped(dev)) {
+ netif_start_queue(dev);
+ netif_wake_queue(dev);
+ }
+ }
else
fec_stop(dev);
status_change = 1;
@@ -1024,7 +1030,6 @@ fec_enet_open(struct net_device *dev)
}
phy_start(fep->phy_dev);
fec_restart(dev, fep->phy_dev->duplex);
- netif_start_queue(dev);
fep->opened = 1;
return 0;
}
@@ -1036,7 +1041,6 @@ fec_enet_close(struct net_device *dev)
/* Don't know what to do yet. */
fep->opened = 0;
- netif_stop_queue(dev);
fec_stop(dev);
if (fep->phy_dev) {
@@ -1421,6 +1425,7 @@ fec_stop(struct net_device *dev)
fec_ptp_stop(fep->ptp_priv);
writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
+ netif_stop_queue(dev);
fep->link = 0;
}