diff options
author | Christian Lamparter <chunkeey@googlemail.com> | 2010-01-17 17:19:25 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-01-19 16:43:12 -0500 |
commit | d713804c6032b95cd3035014e16fadebb9655c6f (patch) | |
tree | 45a67bdae414c6610af651ae6d62df494224282a /drivers/net/wireless/p54/p54pci.c | |
parent | 288c8ce8047695fd8872dd5db3ef21a9679c402f (diff) |
p54pci: move tx cleanup into tasklet
This patch moves the tx cleanup routines out of the critical
interrupt context and into the (previously known as rx) tasklet.
The main goal of this operation is to remove the extensive
usage of spin_lock_irqsaves in the generic p54common library.
The next step would be to modify p54usb to do the
rx processing inside a tasklet (just like usbnet).
Signed-off-by: Christian Lamparter <chunkeey@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/p54/p54pci.c')
-rw-r--r-- | drivers/net/wireless/p54/p54pci.c | 56 |
1 files changed, 29 insertions, 27 deletions
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index 4bf4c213baec..48cae48ed6eb 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c | |||
@@ -234,25 +234,26 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index, | |||
234 | p54p_refill_rx_ring(dev, ring_index, ring, ring_limit, rx_buf); | 234 | p54p_refill_rx_ring(dev, ring_index, ring, ring_limit, rx_buf); |
235 | } | 235 | } |
236 | 236 | ||
237 | /* caller must hold priv->lock */ | ||
238 | static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, | 237 | static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, |
239 | int ring_index, struct p54p_desc *ring, u32 ring_limit, | 238 | int ring_index, struct p54p_desc *ring, u32 ring_limit, |
240 | void **tx_buf) | 239 | struct sk_buff **tx_buf) |
241 | { | 240 | { |
241 | unsigned long flags; | ||
242 | struct p54p_priv *priv = dev->priv; | 242 | struct p54p_priv *priv = dev->priv; |
243 | struct p54p_ring_control *ring_control = priv->ring_control; | 243 | struct p54p_ring_control *ring_control = priv->ring_control; |
244 | struct p54p_desc *desc; | 244 | struct p54p_desc *desc; |
245 | struct sk_buff *skb; | ||
245 | u32 idx, i; | 246 | u32 idx, i; |
246 | 247 | ||
247 | i = (*index) % ring_limit; | 248 | i = (*index) % ring_limit; |
248 | (*index) = idx = le32_to_cpu(ring_control->device_idx[1]); | 249 | (*index) = idx = le32_to_cpu(ring_control->device_idx[1]); |
249 | idx %= ring_limit; | 250 | idx %= ring_limit; |
250 | 251 | ||
252 | spin_lock_irqsave(&priv->lock, flags); | ||
251 | while (i != idx) { | 253 | while (i != idx) { |
252 | desc = &ring[i]; | 254 | desc = &ring[i]; |
253 | if (tx_buf[i]) | 255 | |
254 | if (FREE_AFTER_TX((struct sk_buff *) tx_buf[i])) | 256 | skb = tx_buf[i]; |
255 | p54_free_skb(dev, tx_buf[i]); | ||
256 | tx_buf[i] = NULL; | 257 | tx_buf[i] = NULL; |
257 | 258 | ||
258 | pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), | 259 | pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), |
@@ -263,17 +264,32 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, | |||
263 | desc->len = 0; | 264 | desc->len = 0; |
264 | desc->flags = 0; | 265 | desc->flags = 0; |
265 | 266 | ||
267 | if (skb && FREE_AFTER_TX(skb)) { | ||
268 | spin_unlock_irqrestore(&priv->lock, flags); | ||
269 | p54_free_skb(dev, skb); | ||
270 | spin_lock_irqsave(&priv->lock, flags); | ||
271 | } | ||
272 | |||
266 | i++; | 273 | i++; |
267 | i %= ring_limit; | 274 | i %= ring_limit; |
268 | } | 275 | } |
276 | spin_unlock_irqrestore(&priv->lock, flags); | ||
269 | } | 277 | } |
270 | 278 | ||
271 | static void p54p_rx_tasklet(unsigned long dev_id) | 279 | static void p54p_tasklet(unsigned long dev_id) |
272 | { | 280 | { |
273 | struct ieee80211_hw *dev = (struct ieee80211_hw *)dev_id; | 281 | struct ieee80211_hw *dev = (struct ieee80211_hw *)dev_id; |
274 | struct p54p_priv *priv = dev->priv; | 282 | struct p54p_priv *priv = dev->priv; |
275 | struct p54p_ring_control *ring_control = priv->ring_control; | 283 | struct p54p_ring_control *ring_control = priv->ring_control; |
276 | 284 | ||
285 | p54p_check_tx_ring(dev, &priv->tx_idx_mgmt, 3, ring_control->tx_mgmt, | ||
286 | ARRAY_SIZE(ring_control->tx_mgmt), | ||
287 | priv->tx_buf_mgmt); | ||
288 | |||
289 | p54p_check_tx_ring(dev, &priv->tx_idx_data, 1, ring_control->tx_data, | ||
290 | ARRAY_SIZE(ring_control->tx_data), | ||
291 | priv->tx_buf_data); | ||
292 | |||
277 | p54p_check_rx_ring(dev, &priv->rx_idx_mgmt, 2, ring_control->rx_mgmt, | 293 | p54p_check_rx_ring(dev, &priv->rx_idx_mgmt, 2, ring_control->rx_mgmt, |
278 | ARRAY_SIZE(ring_control->rx_mgmt), priv->rx_buf_mgmt); | 294 | ARRAY_SIZE(ring_control->rx_mgmt), priv->rx_buf_mgmt); |
279 | 295 | ||
@@ -288,38 +304,24 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id) | |||
288 | { | 304 | { |
289 | struct ieee80211_hw *dev = dev_id; | 305 | struct ieee80211_hw *dev = dev_id; |
290 | struct p54p_priv *priv = dev->priv; | 306 | struct p54p_priv *priv = dev->priv; |
291 | struct p54p_ring_control *ring_control = priv->ring_control; | ||
292 | __le32 reg; | 307 | __le32 reg; |
293 | 308 | ||
294 | spin_lock(&priv->lock); | 309 | spin_lock(&priv->lock); |
295 | reg = P54P_READ(int_ident); | 310 | reg = P54P_READ(int_ident); |
296 | if (unlikely(reg == cpu_to_le32(0xFFFFFFFF))) { | 311 | if (unlikely(reg == cpu_to_le32(0xFFFFFFFF))) { |
297 | spin_unlock(&priv->lock); | 312 | goto out; |
298 | return IRQ_HANDLED; | ||
299 | } | 313 | } |
300 | |||
301 | P54P_WRITE(int_ack, reg); | 314 | P54P_WRITE(int_ack, reg); |
302 | 315 | ||
303 | reg &= P54P_READ(int_enable); | 316 | reg &= P54P_READ(int_enable); |
304 | 317 | ||
305 | if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)) { | 318 | if (reg & cpu_to_le32(ISL38XX_INT_IDENT_UPDATE)) |
306 | p54p_check_tx_ring(dev, &priv->tx_idx_mgmt, | 319 | tasklet_schedule(&priv->tasklet); |
307 | 3, ring_control->tx_mgmt, | 320 | else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)) |
308 | ARRAY_SIZE(ring_control->tx_mgmt), | ||
309 | priv->tx_buf_mgmt); | ||
310 | |||
311 | p54p_check_tx_ring(dev, &priv->tx_idx_data, | ||
312 | 1, ring_control->tx_data, | ||
313 | ARRAY_SIZE(ring_control->tx_data), | ||
314 | priv->tx_buf_data); | ||
315 | |||
316 | tasklet_schedule(&priv->rx_tasklet); | ||
317 | |||
318 | } else if (reg & cpu_to_le32(ISL38XX_INT_IDENT_INIT)) | ||
319 | complete(&priv->boot_comp); | 321 | complete(&priv->boot_comp); |
320 | 322 | ||
323 | out: | ||
321 | spin_unlock(&priv->lock); | 324 | spin_unlock(&priv->lock); |
322 | |||
323 | return reg ? IRQ_HANDLED : IRQ_NONE; | 325 | return reg ? IRQ_HANDLED : IRQ_NONE; |
324 | } | 326 | } |
325 | 327 | ||
@@ -368,7 +370,7 @@ static void p54p_stop(struct ieee80211_hw *dev) | |||
368 | unsigned int i; | 370 | unsigned int i; |
369 | struct p54p_desc *desc; | 371 | struct p54p_desc *desc; |
370 | 372 | ||
371 | tasklet_kill(&priv->rx_tasklet); | 373 | tasklet_kill(&priv->tasklet); |
372 | 374 | ||
373 | P54P_WRITE(int_enable, cpu_to_le32(0)); | 375 | P54P_WRITE(int_enable, cpu_to_le32(0)); |
374 | P54P_READ(int_enable); | 376 | P54P_READ(int_enable); |
@@ -559,7 +561,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, | |||
559 | priv->common.tx = p54p_tx; | 561 | priv->common.tx = p54p_tx; |
560 | 562 | ||
561 | spin_lock_init(&priv->lock); | 563 | spin_lock_init(&priv->lock); |
562 | tasklet_init(&priv->rx_tasklet, p54p_rx_tasklet, (unsigned long)dev); | 564 | tasklet_init(&priv->tasklet, p54p_tasklet, (unsigned long)dev); |
563 | 565 | ||
564 | err = request_firmware(&priv->firmware, "isl3886pci", | 566 | err = request_firmware(&priv->firmware, "isl3886pci", |
565 | &priv->pdev->dev); | 567 | &priv->pdev->dev); |