aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorChristian Lamparter <chunkeey@googlemail.com>2010-01-17 17:19:25 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-01-19 16:43:12 -0500
commitd713804c6032b95cd3035014e16fadebb9655c6f (patch)
tree45a67bdae414c6610af651ae6d62df494224282a /drivers/net
parent288c8ce8047695fd8872dd5db3ef21a9679c402f (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')
-rw-r--r--drivers/net/wireless/p54/p54pci.c56
-rw-r--r--drivers/net/wireless/p54/p54pci.h6
2 files changed, 32 insertions, 30 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 */
238static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, 237static 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
271static void p54p_rx_tasklet(unsigned long dev_id) 279static 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
323out:
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);
diff --git a/drivers/net/wireless/p54/p54pci.h b/drivers/net/wireless/p54/p54pci.h
index fbb683953fb2..2feead617a3b 100644
--- a/drivers/net/wireless/p54/p54pci.h
+++ b/drivers/net/wireless/p54/p54pci.h
@@ -92,7 +92,7 @@ struct p54p_priv {
92 struct p54_common common; 92 struct p54_common common;
93 struct pci_dev *pdev; 93 struct pci_dev *pdev;
94 struct p54p_csr __iomem *map; 94 struct p54p_csr __iomem *map;
95 struct tasklet_struct rx_tasklet; 95 struct tasklet_struct tasklet;
96 const struct firmware *firmware; 96 const struct firmware *firmware;
97 spinlock_t lock; 97 spinlock_t lock;
98 struct p54p_ring_control *ring_control; 98 struct p54p_ring_control *ring_control;
@@ -101,8 +101,8 @@ struct p54p_priv {
101 u32 rx_idx_mgmt, tx_idx_mgmt; 101 u32 rx_idx_mgmt, tx_idx_mgmt;
102 struct sk_buff *rx_buf_data[8]; 102 struct sk_buff *rx_buf_data[8];
103 struct sk_buff *rx_buf_mgmt[4]; 103 struct sk_buff *rx_buf_mgmt[4];
104 void *tx_buf_data[32]; 104 struct sk_buff *tx_buf_data[32];
105 void *tx_buf_mgmt[4]; 105 struct sk_buff *tx_buf_mgmt[4];
106 struct completion boot_comp; 106 struct completion boot_comp;
107}; 107};
108 108