diff options
author | Abhijeet Kolekar <abhijeet.kolekar@intel.com> | 2009-04-30 13:56:26 -0700 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-05-06 15:14:59 -0400 |
commit | 722404983b9deb21e4f786224201ca2ab27a1c48 (patch) | |
tree | 97b1e9de442c5c3aad267743abf23a6177e33cdb /drivers/net | |
parent | 84379cba44042a4caf793f821be8bd1a9b8235c2 (diff) |
iwl3945: fix lock dependency
Patch seperates rx_used and rx_free into two
different atomic contexts. We can now avoid using GFP_ATOMIC
for skb allocation and use GFP_KERNEL.
Signed-off-by: Abhijeet Kolekar <abhijeet.kolekar@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl3945-base.c | 37 |
1 files changed, 17 insertions, 20 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 5cd4321d7cf..dc0359ce1ec 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -1344,15 +1344,24 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv) 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, - __GFP_NOWARN | GFP_ATOMIC); + GFP_KERNEL); if (!rxb->skb) { if (net_ratelimit()) IWL_CRIT(priv, ": Can not allocate SKB buffers\n"); @@ -1370,18 +1379,18 @@ static void iwl3945_rx_allocate(struct iwl_priv *priv) */ skb_reserve(rxb->skb, 4); - priv->alloc_rxb_skb++; - list_del(element); - /* Get physical address of RB/SKB */ rxb->real_dma_addr = pci_map_single(priv->pci_dev, rxb->skb->data, priv->hw_params.rx_buf_size, PCI_DMA_FROMDEVICE); + + spin_lock_irqsave(&rxq->lock, flags); list_add_tail(&rxb->list, &rxq->rx_free); + priv->alloc_rxb_skb++; rxq->free_count++; + spin_unlock_irqrestore(&rxq->lock, flags); } - spin_unlock_irqrestore(&rxq->lock, flags); } void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) @@ -1414,18 +1423,6 @@ void iwl3945_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq) spin_unlock_irqrestore(&rxq->lock, flags); } -/* - * this should be called while priv->lock is locked - */ -static void __iwl3945_rx_replenish(void *data) -{ - struct iwl_priv *priv = data; - - iwl3945_rx_allocate(priv); - iwl3945_rx_queue_restock(priv); -} - - void iwl3945_rx_replenish(void *data) { struct iwl_priv *priv = data; @@ -1644,7 +1641,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv) count++; if (count >= 8) { priv->rxq.read = i; - __iwl3945_rx_replenish(priv); + iwl3945_rx_queue_restock(priv); count = 0; } } |