summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoerg Ahrens <joerg@hydrops.han.de>2006-12-14 22:29:54 +0100
committerAdrian Bunk <bunk@stusta.de>2006-12-14 22:29:54 +0100
commit2d3ecb5f57adf4aa9702086aa6727f3a0a255962 (patch)
treeadd5188717a92ef72a27305c55417dd270cc1089
parent2a9d7dbf7566a36221b4066e57f4c3212bff1ef0 (diff)
xirc2ps_cs: Cannot reset card in atomic context
I am using a Xircom CEM33 pcmcia NIC which has occasional hardware problems. If the netdev watchdog detects a transmit timeout, do_reset is called which msleeps - this is illegal in atomic context. This patch schedules the timeout handling as a workqueue item. Signed-off-by: Adrian Bunk <bunk@stusta.de>
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c18
1 files changed, 14 insertions, 4 deletions
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index 593d8adee891..14a523c44403 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -345,6 +345,7 @@ typedef struct local_info_t {
void __iomem *dingo_ccr; /* only used for CEM56 cards */
unsigned last_ptr_value; /* last packets transmitted value */
const char *manf_str;
+ struct work_struct tx_timeout_task;
} local_info_t;
/****************
@@ -352,6 +353,7 @@ typedef struct local_info_t {
*/
static int do_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void do_tx_timeout(struct net_device *dev);
+static void xirc2ps_tx_timeout_task(void *data);
static struct net_device_stats *do_get_stats(struct net_device *dev);
static void set_addresses(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
@@ -591,6 +593,7 @@ xirc2ps_attach(struct pcmcia_device *p_dev)
#ifdef HAVE_TX_TIMEOUT
dev->tx_timeout = do_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
+ INIT_WORK(&local->tx_timeout_task, xirc2ps_tx_timeout_task, dev);
#endif
link->handle = p_dev;
@@ -1374,17 +1377,24 @@ xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/*====================================================================*/
static void
-do_tx_timeout(struct net_device *dev)
+xirc2ps_tx_timeout_task(void *data)
{
- local_info_t *lp = netdev_priv(dev);
- printk(KERN_NOTICE "%s: transmit timed out\n", dev->name);
- lp->stats.tx_errors++;
+ struct net_device *dev = data;
/* reset the card */
do_reset(dev,1);
dev->trans_start = jiffies;
netif_wake_queue(dev);
}
+static void
+do_tx_timeout(struct net_device *dev)
+{
+ local_info_t *lp = netdev_priv(dev);
+ lp->stats.tx_errors++;
+ printk(KERN_NOTICE "%s: transmit timed out\n", dev->name);
+ schedule_work(&lp->tx_timeout_task);
+}
+
static int
do_start_xmit(struct sk_buff *skb, struct net_device *dev)
{