lkml.org 
[lkml]   [2009]   [Jan]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[patch 10/94] iwlwifi: use GFP_KERNEL to allocate Rx SKB memory
2.6.28-stable review patch.  If anyone has any objections, please let us know.

------------------
From: Zhu Yi <yi.zhu@intel.com>

commit f1bc4ac61f2c08515afd80c6dc3962aa6d0b138b upstream.

Previously we allocate Rx SKB with GFP_ATOMIC flag. This is because we need
to hold a spinlock to protect the two rx_used and rx_free lists operation
in the rxq.

spin_lock();
...
element = rxq->rx_used.next;
element->skb = alloc_skb(..., GFP_ATOMIC);
list_del(element);
list_add_tail(&element->list, &rxq->rx_free);
...
spin_unlock();

After spliting the rx_used delete and rx_free insert into two operations,
we don't require the skb allocation in an atomic context any more (the
function itself is scheduled in a workqueue).

spin_lock();
...
element = rxq->rx_used.next;
list_del(element);
...
spin_unlock();
...
element->skb = alloc_skb(..., GFP_KERNEL);
...
spin_lock()
...
list_add_tail(&element->list, &rxq->rx_free);
...
spin_unlock();

This patch should fix the "iwlagn: Can not allocate SKB buffers" warning
we see recently.

Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Acked-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

---
drivers/net/wireless/iwlwifi/iwl-agn.c | 12 +-----------
drivers/net/wireless/iwlwifi/iwl-rx.c | 29 +++++++++++++++++++----------
2 files changed, 20 insertions(+), 21 deletions(-)
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -1334,16 +1334,6 @@ static void iwl_setup_rx_handlers(struct
priv->cfg->ops->lib->rx_handler_setup(priv);
}

-/*
- * this should be called while priv->lock is locked
-*/
-static void __iwl_rx_replenish(struct iwl_priv *priv)
-{
- iwl_rx_allocate(priv);
- iwl_rx_queue_restock(priv);
-}
-
-
/**
* iwl_rx_handle - Main entry function for receiving responses from uCode
*
@@ -1451,7 +1441,7 @@ void iwl_rx_handle(struct iwl_priv *priv
count++;
if (count >= 8) {
priv->rxq.read = i;
- __iwl_rx_replenish(priv);
+ iwl_rx_queue_restock(priv);
count = 0;
}
}
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -245,25 +245,31 @@ void iwl_rx_allocate(struct iwl_priv *pr
struct list_head *element;
struct iwl_rx_mem_buffer *rxb;
unsigned long flags;
- spin_lock_irqsave(&rxq->lock, flags);
- while (!list_empty(&rxq->rx_used)) {
+
+ while (1) {
+ spin_lock_irqsave(&rxq->lock, flags);
+
+ if (list_empty(&rxq->rx_used)) {
+ spin_unlock_irqrestore(&rxq->lock, flags);
+ return;
+ }
element = rxq->rx_used.next;
rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
+ list_del(element);
+
+ spin_unlock_irqrestore(&rxq->lock, flags);

/* Alloc a new receive buffer */
rxb->skb = alloc_skb(priv->hw_params.rx_buf_size + 256,
- __GFP_NOWARN | GFP_ATOMIC);
+ GFP_KERNEL);
if (!rxb->skb) {
- if (net_ratelimit())
- printk(KERN_CRIT DRV_NAME
- ": Can not allocate SKB buffers\n");
+ printk(KERN_CRIT DRV_NAME
+ "Can not allocate SKB buffers\n");
/* We don't reschedule replenish work here -- we will
* call the restock method and if it still needs
* more buffers it will schedule replenish */
break;
}
- priv->alloc_rxb_skb++;
- list_del(element);

/* Get physical address of RB/SKB */
rxb->real_dma_addr = pci_map_single(
@@ -277,12 +283,15 @@ void iwl_rx_allocate(struct iwl_priv *pr
rxb->aligned_dma_addr = ALIGN(rxb->real_dma_addr, 256);
skb_reserve(rxb->skb, rxb->aligned_dma_addr - rxb->real_dma_addr);

+ spin_lock_irqsave(&rxq->lock, flags);
+
list_add_tail(&rxb->list, &rxq->rx_free);
rxq->free_count++;
+ priv->alloc_rxb_skb++;
+
+ spin_unlock_irqrestore(&rxq->lock, flags);
}
- spin_unlock_irqrestore(&rxq->lock, flags);
}
-EXPORT_SYMBOL(iwl_rx_allocate);

void iwl_rx_replenish(struct iwl_priv *priv)
{


\
 
 \ /
  Last update: 2009-01-15 21:09    [from the cache]
©2003-2011 Jasper Spaans