aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wimax/i2400m
diff options
context:
space:
mode:
authorInaky Perez-Gonzalez <inaky@linux.intel.com>2009-09-16 19:30:39 -0400
committerInaky Perez-Gonzalez <inaky@linux.intel.com>2009-10-19 02:56:05 -0400
commitac53aed9349242095a780f57ac0c995fb170c950 (patch)
tree2962df61c6bdee9f184bb278a8b25b4c5a6d219d /drivers/net/wimax/i2400m
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>
Diffstat (limited to 'drivers/net/wimax/i2400m')
-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)
527 527
528 d_fnstart(3, dev, "(i2400m %p)\n", i2400m); 528 d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
529 wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING); 529 wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING);
530 i2400m_net_wake_stop(i2400m);
530 i2400m_dev_shutdown(i2400m); 531 i2400m_dev_shutdown(i2400m);
531 i2400m->ready = 0; 532 i2400m->ready = 0;
532 i2400m->bus_dev_stop(i2400m); 533 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,
691 const void *, int); 691 const void *, int);
692extern void i2400m_net_erx(struct i2400m *, struct sk_buff *, 692extern void i2400m_net_erx(struct i2400m *, struct sk_buff *,
693 enum i2400m_cs); 693 enum i2400m_cs);
694extern void i2400m_net_wake_stop(struct i2400m *);
694enum i2400m_pt; 695enum i2400m_pt;
695extern int i2400m_tx(struct i2400m *, const void *, size_t, enum i2400m_pt); 696extern int i2400m_tx(struct i2400m *, const void *, size_t, enum i2400m_pt);
696 697
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)
113} 113}
114 114
115 115
116/*
117 *
118 * On kernel versions where cancel_work_sync() didn't return anything,
119 * we rely on wake_tx_skb() being non-NULL.
120 */
121static 116static
122int i2400m_stop(struct net_device *net_dev) 117int i2400m_stop(struct net_device *net_dev)
123{ 118{
@@ -125,21 +120,7 @@ int i2400m_stop(struct net_device *net_dev)
125 struct device *dev = i2400m_dev(i2400m); 120 struct device *dev = i2400m_dev(i2400m);
126 121
127 d_fnstart(3, dev, "(net_dev %p [i2400m %p])\n", net_dev, i2400m); 122 d_fnstart(3, dev, "(net_dev %p [i2400m %p])\n", net_dev, i2400m);
128 /* See i2400m_hard_start_xmit(), references are taken there 123 i2400m_net_wake_stop(i2400m);
129 * and here we release them if the work was still
130 * pending. Note we can't differentiate work not pending vs
131 * never scheduled, so the NULL check does that. */
132 if (cancel_work_sync(&i2400m->wake_tx_ws) == 0
133 && i2400m->wake_tx_skb != NULL) {
134 unsigned long flags;
135 struct sk_buff *wake_tx_skb;
136 spin_lock_irqsave(&i2400m->tx_lock, flags);
137 wake_tx_skb = i2400m->wake_tx_skb; /* compat help */
138 i2400m->wake_tx_skb = NULL; /* compat help */
139 spin_unlock_irqrestore(&i2400m->tx_lock, flags);
140 i2400m_put(i2400m);
141 kfree_skb(wake_tx_skb);
142 }
143 d_fnend(3, dev, "(net_dev %p [i2400m %p]) = 0\n", net_dev, i2400m); 124 d_fnend(3, dev, "(net_dev %p [i2400m %p]) = 0\n", net_dev, i2400m);
144 return 0; 125 return 0;
145} 126}
@@ -230,6 +211,38 @@ void i2400m_tx_prep_header(struct sk_buff *skb)
230} 211}
231 212
232 213
214
215/*
216 * Cleanup resources acquired during i2400m_net_wake_tx()
217 *
218 * This is called by __i2400m_dev_stop and means we have to make sure
219 * the workqueue is flushed from any pending work.
220 */
221void i2400m_net_wake_stop(struct i2400m *i2400m)
222{
223 struct device *dev = i2400m_dev(i2400m);
224
225 d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
226 /* See i2400m_hard_start_xmit(), references are taken there
227 * and here we release them if the work was still
228 * pending. Note we can't differentiate work not pending vs
229 * never scheduled, so the NULL check does that. */
230 if (cancel_work_sync(&i2400m->wake_tx_ws) == 0
231 && i2400m->wake_tx_skb != NULL) {
232 unsigned long flags;
233 struct sk_buff *wake_tx_skb;
234 spin_lock_irqsave(&i2400m->tx_lock, flags);
235 wake_tx_skb = i2400m->wake_tx_skb; /* compat help */
236 i2400m->wake_tx_skb = NULL; /* compat help */
237 spin_unlock_irqrestore(&i2400m->tx_lock, flags);
238 i2400m_put(i2400m);
239 kfree_skb(wake_tx_skb);
240 }
241 d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
242 return;
243}
244
245
233/* 246/*
234 * TX an skb to an idle device 247 * TX an skb to an idle device
235 * 248 *