summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorInaky Perez-Gonzalez <inaky@linux.intel.com>2009-09-16 16:30:39 -0700
committerInaky Perez-Gonzalez <inaky@linux.intel.com>2009-10-19 15:56:05 +0900
commitac53aed9349242095a780f57ac0c995fb170c950 (patch)
tree2962df61c6bdee9f184bb278a8b25b4c5a6d219d
parentcb5b756f746b77c5323ae413a41e9a40ea33c453 (diff)
wimax/i2400m: on device stop, clean up pending wake & TX work
When the i2400m device needs to wake up an idle WiMAX connection, it schedules a workqueue job to do it. Currently, only when the network stack called the _stop() method this work struct was being cancelled. This has to be done every time the device is stopped. So add a call in i2400m_dev_stop() to take care of such cleanup, which is now wrapped in i2400m_net_wake_stop(). Signed-off-by: Inaky Perez-Gonzalez <inaky@linux.intel.com>
-rw-r--r--drivers/net/wimax/i2400m/driver.c1
-rw-r--r--drivers/net/wimax/i2400m/i2400m.h1
-rw-r--r--drivers/net/wimax/i2400m/netdev.c53
3 files changed, 35 insertions, 20 deletions
diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c
index 07d12be0cf81..a33df0431020 100644
--- a/drivers/net/wimax/i2400m/driver.c
+++ b/drivers/net/wimax/i2400m/driver.c
@@ -527,6 +527,7 @@ void __i2400m_dev_stop(struct i2400m *i2400m)
d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING);
+ i2400m_net_wake_stop(i2400m);
i2400m_dev_shutdown(i2400m);
i2400m->ready = 0;
i2400m->bus_dev_stop(i2400m);
diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h
index 916b1d319299..303eb78bce32 100644
--- a/drivers/net/wimax/i2400m/i2400m.h
+++ b/drivers/net/wimax/i2400m/i2400m.h
@@ -691,6 +691,7 @@ extern void i2400m_net_rx(struct i2400m *, struct sk_buff *, unsigned,
const void *, int);
extern void i2400m_net_erx(struct i2400m *, struct sk_buff *,
enum i2400m_cs);
+extern void i2400m_net_wake_stop(struct i2400m *);
enum i2400m_pt;
extern int i2400m_tx(struct i2400m *, const void *, size_t, enum i2400m_pt);
diff --git a/drivers/net/wimax/i2400m/netdev.c b/drivers/net/wimax/i2400m/netdev.c
index 960fb5467546..0e8f6a046b9b 100644
--- a/drivers/net/wimax/i2400m/netdev.c
+++ b/drivers/net/wimax/i2400m/netdev.c
@@ -113,11 +113,6 @@ int i2400m_open(struct net_device *net_dev)
}
-/*
- *
- * On kernel versions where cancel_work_sync() didn't return anything,
- * we rely on wake_tx_skb() being non-NULL.
- */
static
int i2400m_stop(struct net_device *net_dev)
{
@@ -125,21 +120,7 @@ int i2400m_stop(struct net_device *net_dev)
struct device *dev = i2400m_dev(i2400m);
d_fnstart(3, dev, "(net_dev %p [i2400m %p])\n", net_dev, i2400m);
- /* See i2400m_hard_start_xmit(), references are taken there
- * and here we release them if the work was still
- * pending. Note we can't differentiate work not pending vs
- * never scheduled, so the NULL check does that. */
- if (cancel_work_sync(&i2400m->wake_tx_ws) == 0
- && i2400m->wake_tx_skb != NULL) {
- unsigned long flags;
- struct sk_buff *wake_tx_skb;
- spin_lock_irqsave(&i2400m->tx_lock, flags);
- wake_tx_skb = i2400m->wake_tx_skb; /* compat help */
- i2400m->wake_tx_skb = NULL; /* compat help */
- spin_unlock_irqrestore(&i2400m->tx_lock, flags);
- i2400m_put(i2400m);
- kfree_skb(wake_tx_skb);
- }
+ i2400m_net_wake_stop(i2400m);
d_fnend(3, dev, "(net_dev %p [i2400m %p]) = 0\n", net_dev, i2400m);
return 0;
}
@@ -230,6 +211,38 @@ void i2400m_tx_prep_header(struct sk_buff *skb)
}
+
+/*
+ * Cleanup resources acquired during i2400m_net_wake_tx()
+ *
+ * This is called by __i2400m_dev_stop and means we have to make sure
+ * the workqueue is flushed from any pending work.
+ */
+void i2400m_net_wake_stop(struct i2400m *i2400m)
+{
+ struct device *dev = i2400m_dev(i2400m);
+
+ d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
+ /* See i2400m_hard_start_xmit(), references are taken there
+ * and here we release them if the work was still
+ * pending. Note we can't differentiate work not pending vs
+ * never scheduled, so the NULL check does that. */
+ if (cancel_work_sync(&i2400m->wake_tx_ws) == 0
+ && i2400m->wake_tx_skb != NULL) {
+ unsigned long flags;
+ struct sk_buff *wake_tx_skb;
+ spin_lock_irqsave(&i2400m->tx_lock, flags);
+ wake_tx_skb = i2400m->wake_tx_skb; /* compat help */
+ i2400m->wake_tx_skb = NULL; /* compat help */
+ spin_unlock_irqrestore(&i2400m->tx_lock, flags);
+ i2400m_put(i2400m);
+ kfree_skb(wake_tx_skb);
+ }
+ d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
+ return;
+}
+
+
/*
* TX an skb to an idle device
*