aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorRob Herring <rob.herring@calxeda.com>2013-08-30 17:49:21 -0400
committerDavid S. Miller <davem@davemloft.net>2013-09-03 22:21:15 -0400
commit8746f671ef04114ab25f5a35ec6219efbdf3703e (patch)
tree1abd7ba59fd2cb956e99afee1f199e4fac92ecac /drivers/net
parentef07387faf33a95e011993200902d490b605407d (diff)
net: calxedaxgmac: fix race between xgmac_tx_complete and xgmac_tx_err
It is possible for the xgmac_tx_complete to run concurrently with xgmac_tx_err since there are no locks. Fix this by moving the tx error handling to a workqueue so we can disable napi while we reset the transmitter. Reported-by: Andreas Herrmann <andreas.herrmann@calxeda.com> Signed-off-by: Rob Herring <rob.herring@calxeda.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ethernet/calxeda/xgmac.c38
1 files changed, 18 insertions, 20 deletions
diff --git a/drivers/net/ethernet/calxeda/xgmac.c b/drivers/net/ethernet/calxeda/xgmac.c
index d41af68ccb63..df7e3e2579f1 100644
--- a/drivers/net/ethernet/calxeda/xgmac.c
+++ b/drivers/net/ethernet/calxeda/xgmac.c
@@ -393,6 +393,7 @@ struct xgmac_priv {
393 char rx_pause; 393 char rx_pause;
394 char tx_pause; 394 char tx_pause;
395 int wolopts; 395 int wolopts;
396 struct work_struct tx_timeout_work;
396}; 397};
397 398
398/* XGMAC Configuration Settings */ 399/* XGMAC Configuration Settings */
@@ -897,21 +898,18 @@ static void xgmac_tx_complete(struct xgmac_priv *priv)
897 netif_wake_queue(priv->dev); 898 netif_wake_queue(priv->dev);
898} 899}
899 900
900/** 901static void xgmac_tx_timeout_work(struct work_struct *work)
901 * xgmac_tx_err:
902 * @priv: pointer to the private device structure
903 * Description: it cleans the descriptors and restarts the transmission
904 * in case of errors.
905 */
906static void xgmac_tx_err(struct xgmac_priv *priv)
907{ 902{
908 u32 reg, value, inten; 903 u32 reg, value;
904 struct xgmac_priv *priv =
905 container_of(work, struct xgmac_priv, tx_timeout_work);
909 906
910 netif_stop_queue(priv->dev); 907 napi_disable(&priv->napi);
911 908
912 inten = readl(priv->base + XGMAC_DMA_INTR_ENA);
913 writel(0, priv->base + XGMAC_DMA_INTR_ENA); 909 writel(0, priv->base + XGMAC_DMA_INTR_ENA);
914 910
911 netif_tx_lock(priv->dev);
912
915 reg = readl(priv->base + XGMAC_DMA_CONTROL); 913 reg = readl(priv->base + XGMAC_DMA_CONTROL);
916 writel(reg & ~DMA_CONTROL_ST, priv->base + XGMAC_DMA_CONTROL); 914 writel(reg & ~DMA_CONTROL_ST, priv->base + XGMAC_DMA_CONTROL);
917 do { 915 do {
@@ -927,9 +925,15 @@ static void xgmac_tx_err(struct xgmac_priv *priv)
927 925
928 writel(DMA_STATUS_TU | DMA_STATUS_TPS | DMA_STATUS_NIS | DMA_STATUS_AIS, 926 writel(DMA_STATUS_TU | DMA_STATUS_TPS | DMA_STATUS_NIS | DMA_STATUS_AIS,
929 priv->base + XGMAC_DMA_STATUS); 927 priv->base + XGMAC_DMA_STATUS);
930 writel(inten, priv->base + XGMAC_DMA_INTR_ENA);
931 928
929 netif_tx_unlock(priv->dev);
932 netif_wake_queue(priv->dev); 930 netif_wake_queue(priv->dev);
931
932 napi_enable(&priv->napi);
933
934 /* Enable interrupts */
935 writel(DMA_INTR_DEFAULT_MASK, priv->base + XGMAC_DMA_STATUS);
936 writel(DMA_INTR_DEFAULT_MASK, priv->base + XGMAC_DMA_INTR_ENA);
933} 937}
934 938
935static int xgmac_hw_init(struct net_device *dev) 939static int xgmac_hw_init(struct net_device *dev)
@@ -1225,9 +1229,7 @@ static int xgmac_poll(struct napi_struct *napi, int budget)
1225static void xgmac_tx_timeout(struct net_device *dev) 1229static void xgmac_tx_timeout(struct net_device *dev)
1226{ 1230{
1227 struct xgmac_priv *priv = netdev_priv(dev); 1231 struct xgmac_priv *priv = netdev_priv(dev);
1228 1232 schedule_work(&priv->tx_timeout_work);
1229 /* Clear Tx resources and restart transmitting again */
1230 xgmac_tx_err(priv);
1231} 1233}
1232 1234
1233/** 1235/**
@@ -1366,7 +1368,6 @@ static irqreturn_t xgmac_pmt_interrupt(int irq, void *dev_id)
1366static irqreturn_t xgmac_interrupt(int irq, void *dev_id) 1368static irqreturn_t xgmac_interrupt(int irq, void *dev_id)
1367{ 1369{
1368 u32 intr_status; 1370 u32 intr_status;
1369 bool tx_err = false;
1370 struct net_device *dev = (struct net_device *)dev_id; 1371 struct net_device *dev = (struct net_device *)dev_id;
1371 struct xgmac_priv *priv = netdev_priv(dev); 1372 struct xgmac_priv *priv = netdev_priv(dev);
1372 struct xgmac_extra_stats *x = &priv->xstats; 1373 struct xgmac_extra_stats *x = &priv->xstats;
@@ -1396,16 +1397,12 @@ static irqreturn_t xgmac_interrupt(int irq, void *dev_id)
1396 if (intr_status & DMA_STATUS_TPS) { 1397 if (intr_status & DMA_STATUS_TPS) {
1397 netdev_err(priv->dev, "transmit process stopped\n"); 1398 netdev_err(priv->dev, "transmit process stopped\n");
1398 x->tx_process_stopped++; 1399 x->tx_process_stopped++;
1399 tx_err = true; 1400 schedule_work(&priv->tx_timeout_work);
1400 } 1401 }
1401 if (intr_status & DMA_STATUS_FBI) { 1402 if (intr_status & DMA_STATUS_FBI) {
1402 netdev_err(priv->dev, "fatal bus error\n"); 1403 netdev_err(priv->dev, "fatal bus error\n");
1403 x->fatal_bus_error++; 1404 x->fatal_bus_error++;
1404 tx_err = true;
1405 } 1405 }
1406
1407 if (tx_err)
1408 xgmac_tx_err(priv);
1409 } 1406 }
1410 1407
1411 /* TX/RX NORMAL interrupts */ 1408 /* TX/RX NORMAL interrupts */
@@ -1708,6 +1705,7 @@ static int xgmac_probe(struct platform_device *pdev)
1708 ndev->netdev_ops = &xgmac_netdev_ops; 1705 ndev->netdev_ops = &xgmac_netdev_ops;
1709 SET_ETHTOOL_OPS(ndev, &xgmac_ethtool_ops); 1706 SET_ETHTOOL_OPS(ndev, &xgmac_ethtool_ops);
1710 spin_lock_init(&priv->stats_lock); 1707 spin_lock_init(&priv->stats_lock);
1708 INIT_WORK(&priv->tx_timeout_work, xgmac_tx_timeout_work);
1711 1709
1712 priv->device = &pdev->dev; 1710 priv->device = &pdev->dev;
1713 priv->dev = ndev; 1711 priv->dev = ndev;