diff options
Diffstat (limited to 'drivers/net/wimax/i2400m/netdev.c')
-rw-r--r-- | drivers/net/wimax/i2400m/netdev.c | 53 |
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 | */ | ||
121 | static | 116 | static |
122 | int i2400m_stop(struct net_device *net_dev) | 117 | int 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 | */ | ||
221 | void 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 | * |