aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrank Li <Frank.Li@freescale.com>2013-05-07 10:08:44 -0400
committerDavid S. Miller <davem@davemloft.net>2013-05-08 16:13:30 -0400
commit54309fa60b5f57b90c1842176f6045e665d21142 (patch)
tree31bb2d5574adc10d342a01b2081c9907e917c554
parent2c006994520f3a4bb1d47a6afe5c58ff856497ce (diff)
net: fec: fix kernel oops when plug/unplug cable many times
reproduce steps 1. flood ping from other machine ping -f -s 41000 IP 2. run below script while [ 1 ]; do ethtool -s eth0 autoneg off; sleep 3;ethtool -s eth0 autoneg on; sleep 4; done; You can see oops in one hour. The reason is fec_restart clear BD but NAPI may use it. The solution is disable NAPI and stop xmit when reset BD. disable NAPI may sleep, so fec_restart can't be call in atomic context. Signed-off-by: Frank Li <Frank.Li@freescale.com> Reviewed-by: Lucas Stach <l.stach@pengutronix.de> Tested-by: Lucas Stach <l.stach@pengutronix.de> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/freescale/fec.h10
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c44
2 files changed, 39 insertions, 15 deletions
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index ceb4d43c132d..9ce5b7185fda 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -198,6 +198,11 @@ struct bufdesc_ex {
198#define FLAG_RX_CSUM_ENABLED (BD_ENET_RX_ICE | BD_ENET_RX_PCR) 198#define FLAG_RX_CSUM_ENABLED (BD_ENET_RX_ICE | BD_ENET_RX_PCR)
199#define FLAG_RX_CSUM_ERROR (BD_ENET_RX_ICE | BD_ENET_RX_PCR) 199#define FLAG_RX_CSUM_ERROR (BD_ENET_RX_ICE | BD_ENET_RX_PCR)
200 200
201struct fec_enet_delayed_work {
202 struct delayed_work delay_work;
203 bool timeout;
204};
205
201/* The FEC buffer descriptors track the ring buffers. The rx_bd_base and 206/* The FEC buffer descriptors track the ring buffers. The rx_bd_base and
202 * tx_bd_base always point to the base of the buffer descriptors. The 207 * tx_bd_base always point to the base of the buffer descriptors. The
203 * cur_rx and cur_tx point to the currently available buffer. 208 * cur_rx and cur_tx point to the currently available buffer.
@@ -232,9 +237,6 @@ struct fec_enet_private {
232 /* The ring entries to be free()ed */ 237 /* The ring entries to be free()ed */
233 struct bufdesc *dirty_tx; 238 struct bufdesc *dirty_tx;
234 239
235 /* hold while accessing the HW like ringbuffer for tx/rx but not MAC */
236 spinlock_t hw_lock;
237
238 struct platform_device *pdev; 240 struct platform_device *pdev;
239 241
240 int opened; 242 int opened;
@@ -269,7 +271,7 @@ struct fec_enet_private {
269 int hwts_rx_en; 271 int hwts_rx_en;
270 int hwts_tx_en; 272 int hwts_tx_en;
271 struct timer_list time_keep; 273 struct timer_list time_keep;
272 274 struct fec_enet_delayed_work delay_work;
273}; 275};
274 276
275void fec_ptp_init(struct net_device *ndev, struct platform_device *pdev); 277void fec_ptp_init(struct net_device *ndev, struct platform_device *pdev);
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index e25bf832e6b3..aff0310a778b 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -445,6 +445,13 @@ fec_restart(struct net_device *ndev, int duplex)
445 u32 rcntl = OPT_FRAME_SIZE | 0x04; 445 u32 rcntl = OPT_FRAME_SIZE | 0x04;
446 u32 ecntl = 0x2; /* ETHEREN */ 446 u32 ecntl = 0x2; /* ETHEREN */
447 447
448 if (netif_running(ndev)) {
449 netif_device_detach(ndev);
450 napi_disable(&fep->napi);
451 netif_stop_queue(ndev);
452 netif_tx_lock(ndev);
453 }
454
448 /* Whack a reset. We should wait for this. */ 455 /* Whack a reset. We should wait for this. */
449 writel(1, fep->hwp + FEC_ECNTRL); 456 writel(1, fep->hwp + FEC_ECNTRL);
450 udelay(10); 457 udelay(10);
@@ -605,6 +612,13 @@ fec_restart(struct net_device *ndev, int duplex)
605 612
606 /* Enable interrupts we wish to service */ 613 /* Enable interrupts we wish to service */
607 writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); 614 writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
615
616 if (netif_running(ndev)) {
617 netif_device_attach(ndev);
618 napi_enable(&fep->napi);
619 netif_wake_queue(ndev);
620 netif_tx_unlock(ndev);
621 }
608} 622}
609 623
610static void 624static void
@@ -644,8 +658,22 @@ fec_timeout(struct net_device *ndev)
644 658
645 ndev->stats.tx_errors++; 659 ndev->stats.tx_errors++;
646 660
647 fec_restart(ndev, fep->full_duplex); 661 fep->delay_work.timeout = true;
648 netif_wake_queue(ndev); 662 schedule_delayed_work(&(fep->delay_work.delay_work), 0);
663}
664
665static void fec_enet_work(struct work_struct *work)
666{
667 struct fec_enet_private *fep =
668 container_of(work,
669 struct fec_enet_private,
670 delay_work.delay_work.work);
671
672 if (fep->delay_work.timeout) {
673 fep->delay_work.timeout = false;
674 fec_restart(fep->netdev, fep->full_duplex);
675 netif_wake_queue(fep->netdev);
676 }
649} 677}
650 678
651static void 679static void
@@ -1024,16 +1052,12 @@ static void fec_enet_adjust_link(struct net_device *ndev)
1024{ 1052{
1025 struct fec_enet_private *fep = netdev_priv(ndev); 1053 struct fec_enet_private *fep = netdev_priv(ndev);
1026 struct phy_device *phy_dev = fep->phy_dev; 1054 struct phy_device *phy_dev = fep->phy_dev;
1027 unsigned long flags;
1028
1029 int status_change = 0; 1055 int status_change = 0;
1030 1056
1031 spin_lock_irqsave(&fep->hw_lock, flags);
1032
1033 /* Prevent a state halted on mii error */ 1057 /* Prevent a state halted on mii error */
1034 if (fep->mii_timeout && phy_dev->state == PHY_HALTED) { 1058 if (fep->mii_timeout && phy_dev->state == PHY_HALTED) {
1035 phy_dev->state = PHY_RESUMING; 1059 phy_dev->state = PHY_RESUMING;
1036 goto spin_unlock; 1060 return;
1037 } 1061 }
1038 1062
1039 if (phy_dev->link) { 1063 if (phy_dev->link) {
@@ -1061,9 +1085,6 @@ static void fec_enet_adjust_link(struct net_device *ndev)
1061 } 1085 }
1062 } 1086 }
1063 1087
1064spin_unlock:
1065 spin_unlock_irqrestore(&fep->hw_lock, flags);
1066
1067 if (status_change) 1088 if (status_change)
1068 phy_print_status(phy_dev); 1089 phy_print_status(phy_dev);
1069} 1090}
@@ -1732,7 +1753,6 @@ static int fec_enet_init(struct net_device *ndev)
1732 return -ENOMEM; 1753 return -ENOMEM;
1733 1754
1734 memset(cbd_base, 0, PAGE_SIZE); 1755 memset(cbd_base, 0, PAGE_SIZE);
1735 spin_lock_init(&fep->hw_lock);
1736 1756
1737 fep->netdev = ndev; 1757 fep->netdev = ndev;
1738 1758
@@ -1952,6 +1972,7 @@ fec_probe(struct platform_device *pdev)
1952 if (fep->bufdesc_ex && fep->ptp_clock) 1972 if (fep->bufdesc_ex && fep->ptp_clock)
1953 netdev_info(ndev, "registered PHC device %d\n", fep->dev_id); 1973 netdev_info(ndev, "registered PHC device %d\n", fep->dev_id);
1954 1974
1975 INIT_DELAYED_WORK(&(fep->delay_work.delay_work), fec_enet_work);
1955 return 0; 1976 return 0;
1956 1977
1957failed_register: 1978failed_register:
@@ -1984,6 +2005,7 @@ fec_drv_remove(struct platform_device *pdev)
1984 struct fec_enet_private *fep = netdev_priv(ndev); 2005 struct fec_enet_private *fep = netdev_priv(ndev);
1985 int i; 2006 int i;
1986 2007
2008 cancel_delayed_work_sync(&(fep->delay_work.delay_work));
1987 unregister_netdev(ndev); 2009 unregister_netdev(ndev);
1988 fec_enet_mii_remove(fep); 2010 fec_enet_mii_remove(fep);
1989 del_timer_sync(&fep->time_keep); 2011 del_timer_sync(&fep->time_keep);