aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorPhil Sutter <phil@nwl.cc>2010-05-29 09:23:34 -0400
committerDavid S. Miller <davem@davemloft.net>2010-06-02 09:12:18 -0400
commitceb3d2394532540a52ce34f71e67c8d008913f79 (patch)
tree8bd8cb8d9af745ed0aa2e55a1b0e8ef51b74020a /drivers/net
parent2df4a0fa1540c460ec69788ab2a901cc72a75644 (diff)
korina: fix deadlock on RX FIFO overrun
By calling korina_restart(), the IRQ handler tries to disable the interrupt it's currently serving. This leads to a deadlock since disable_irq() waits for any running IRQ handlers to finish before returning. This patch addresses the issue by turning korina_restart() into a workqueue task, which is then scheduled when needed. Reproducing the deadlock is easily done using e.g. GNU netcat to send large amounts of UDP data to the host running this driver. Note that the same problem (and fix) applies to TX FIFO underruns, but apparently these are less easy to trigger. Signed-off-by: Phil Sutter <phil@nwl.cc> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/korina.c27
1 files changed, 13 insertions, 14 deletions
diff --git a/drivers/net/korina.c b/drivers/net/korina.c
index 26bf1b76b997..13533f937e05 100644
--- a/drivers/net/korina.c
+++ b/drivers/net/korina.c
@@ -135,6 +135,7 @@ struct korina_private {
135 struct napi_struct napi; 135 struct napi_struct napi;
136 struct timer_list media_check_timer; 136 struct timer_list media_check_timer;
137 struct mii_if_info mii_if; 137 struct mii_if_info mii_if;
138 struct work_struct restart_task;
138 struct net_device *dev; 139 struct net_device *dev;
139 int phy_addr; 140 int phy_addr;
140}; 141};
@@ -890,12 +891,12 @@ static int korina_init(struct net_device *dev)
890 891
891/* 892/*
892 * Restart the RC32434 ethernet controller. 893 * Restart the RC32434 ethernet controller.
893 * FIXME: check the return status where we call it
894 */ 894 */
895static int korina_restart(struct net_device *dev) 895static void korina_restart_task(struct work_struct *work)
896{ 896{
897 struct korina_private *lp = netdev_priv(dev); 897 struct korina_private *lp = container_of(work,
898 int ret; 898 struct korina_private, restart_task);
899 struct net_device *dev = lp->dev;
899 900
900 /* 901 /*
901 * Disable interrupts 902 * Disable interrupts
@@ -916,10 +917,9 @@ static int korina_restart(struct net_device *dev)
916 917
917 napi_disable(&lp->napi); 918 napi_disable(&lp->napi);
918 919
919 ret = korina_init(dev); 920 if (korina_init(dev) < 0) {
920 if (ret < 0) {
921 printk(KERN_ERR "%s: cannot restart device\n", dev->name); 921 printk(KERN_ERR "%s: cannot restart device\n", dev->name);
922 return ret; 922 return;
923 } 923 }
924 korina_multicast_list(dev); 924 korina_multicast_list(dev);
925 925
@@ -927,8 +927,6 @@ static int korina_restart(struct net_device *dev)
927 enable_irq(lp->ovr_irq); 927 enable_irq(lp->ovr_irq);
928 enable_irq(lp->tx_irq); 928 enable_irq(lp->tx_irq);
929 enable_irq(lp->rx_irq); 929 enable_irq(lp->rx_irq);
930
931 return ret;
932} 930}
933 931
934static void korina_clear_and_restart(struct net_device *dev, u32 value) 932static void korina_clear_and_restart(struct net_device *dev, u32 value)
@@ -937,7 +935,7 @@ static void korina_clear_and_restart(struct net_device *dev, u32 value)
937 935
938 netif_stop_queue(dev); 936 netif_stop_queue(dev);
939 writel(value, &lp->eth_regs->ethintfc); 937 writel(value, &lp->eth_regs->ethintfc);
940 korina_restart(dev); 938 schedule_work(&lp->restart_task);
941} 939}
942 940
943/* Ethernet Tx Underflow interrupt */ 941/* Ethernet Tx Underflow interrupt */
@@ -962,11 +960,8 @@ static irqreturn_t korina_und_interrupt(int irq, void *dev_id)
962static void korina_tx_timeout(struct net_device *dev) 960static void korina_tx_timeout(struct net_device *dev)
963{ 961{
964 struct korina_private *lp = netdev_priv(dev); 962 struct korina_private *lp = netdev_priv(dev);
965 unsigned long flags;
966 963
967 spin_lock_irqsave(&lp->lock, flags); 964 schedule_work(&lp->restart_task);
968 korina_restart(dev);
969 spin_unlock_irqrestore(&lp->lock, flags);
970} 965}
971 966
972/* Ethernet Rx Overflow interrupt */ 967/* Ethernet Rx Overflow interrupt */
@@ -1086,6 +1081,8 @@ static int korina_close(struct net_device *dev)
1086 1081
1087 napi_disable(&lp->napi); 1082 napi_disable(&lp->napi);
1088 1083
1084 cancel_work_sync(&lp->restart_task);
1085
1089 free_irq(lp->rx_irq, dev); 1086 free_irq(lp->rx_irq, dev);
1090 free_irq(lp->tx_irq, dev); 1087 free_irq(lp->tx_irq, dev);
1091 free_irq(lp->ovr_irq, dev); 1088 free_irq(lp->ovr_irq, dev);
@@ -1198,6 +1195,8 @@ static int korina_probe(struct platform_device *pdev)
1198 } 1195 }
1199 setup_timer(&lp->media_check_timer, korina_poll_media, (unsigned long) dev); 1196 setup_timer(&lp->media_check_timer, korina_poll_media, (unsigned long) dev);
1200 1197
1198 INIT_WORK(&lp->restart_task, korina_restart_task);
1199
1201 printk(KERN_INFO "%s: " DRV_NAME "-" DRV_VERSION " " DRV_RELDATE "\n", 1200 printk(KERN_INFO "%s: " DRV_NAME "-" DRV_VERSION " " DRV_RELDATE "\n",
1202 dev->name); 1201 dev->name);
1203out: 1202out: