]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
wimax/i2400m: on device stop, clean up pending wake & TX work
authorInaky Perez-Gonzalez <inaky@linux.intel.com>
Wed, 16 Sep 2009 23:30:39 +0000 (16:30 -0700)
committerInaky Perez-Gonzalez <inaky@linux.intel.com>
Mon, 19 Oct 2009 06:56:05 +0000 (15:56 +0900)
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>
drivers/net/wimax/i2400m/driver.c
drivers/net/wimax/i2400m/i2400m.h
drivers/net/wimax/i2400m/netdev.c

index 07d12be0cf818feaccc16953f27eaa495444689d..a33df04310200b8017bdfa41f7234198f88f9295 100644 (file)
@@ -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);
index 916b1d319299ac9c1895f12060965395fb0cbda0..303eb78bce329c695fcdf0ba38ab6ed824bbaf73 100644 (file)
@@ -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);
 
index 960fb54675468030f060e4a57ac64baa68c89a78..0e8f6a046b9b88c16203e02dbf5f68cae830c009 100644 (file)
@@ -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
  *