aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wimax/i2400m/netdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wimax/i2400m/netdev.c')
-rw-r--r--drivers/net/wimax/i2400m/netdev.c53
1 files changed, 33 insertions, 20 deletions
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 *