aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMohamed Abbas <mohamed.abbas@intel.com>2009-05-22 14:01:51 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-05-22 14:06:08 -0400
commit4752c93c30441f98f7ed723001b1a5e3e5619829 (patch)
treede868a2003d2328ad3bd048e75bc16b7e327bd7f
parentef850d7cb301bda9155c096269557a4586b58071 (diff)
iwlcore: Allow skb allocation from tasklet.
If RX queue becomes empty then we need to restock the queue from tasklet to prevent ucode from starving. A caller to iwl_rx_allocate will decide if allocated buffer should come from GFP_ATOMIC or GFP_KERNEL. Signed-off-by: Mohamed Abbas <mohamed.abbas@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c15
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-rx.c25
4 files changed, 34 insertions, 10 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index fa24b019c62c..be1058bdc4c5 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -831,6 +831,7 @@ void iwl_rx_handle(struct iwl_priv *priv)
831 unsigned long flags; 831 unsigned long flags;
832 u8 fill_rx = 0; 832 u8 fill_rx = 0;
833 u32 count = 8; 833 u32 count = 8;
834 int total_empty;
834 835
835 /* uCode's read index (stored in shared DRAM) indicates the last Rx 836 /* uCode's read index (stored in shared DRAM) indicates the last Rx
836 * buffer that the driver may process (last buffer filled by ucode). */ 837 * buffer that the driver may process (last buffer filled by ucode). */
@@ -841,7 +842,12 @@ void iwl_rx_handle(struct iwl_priv *priv)
841 if (i == r) 842 if (i == r)
842 IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i); 843 IWL_DEBUG_RX(priv, "r = %d, i = %d\n", r, i);
843 844
844 if (iwl_rx_queue_space(rxq) > (RX_QUEUE_SIZE / 2)) 845 /* calculate total frames need to be restock after handling RX */
846 total_empty = r - priv->rxq.write_actual;
847 if (total_empty < 0)
848 total_empty += RX_QUEUE_SIZE;
849
850 if (total_empty > (RX_QUEUE_SIZE / 2))
845 fill_rx = 1; 851 fill_rx = 1;
846 852
847 while (i != r) { 853 while (i != r) {
@@ -918,7 +924,7 @@ void iwl_rx_handle(struct iwl_priv *priv)
918 count++; 924 count++;
919 if (count >= 8) { 925 if (count >= 8) {
920 priv->rxq.read = i; 926 priv->rxq.read = i;
921 iwl_rx_queue_restock(priv); 927 iwl_rx_replenish_now(priv);
922 count = 0; 928 count = 0;
923 } 929 }
924 } 930 }
@@ -926,7 +932,10 @@ void iwl_rx_handle(struct iwl_priv *priv)
926 932
927 /* Backtrack one entry */ 933 /* Backtrack one entry */
928 priv->rxq.read = i; 934 priv->rxq.read = i;
929 iwl_rx_queue_restock(priv); 935 if (fill_rx)
936 iwl_rx_replenish_now(priv);
937 else
938 iwl_rx_queue_restock(priv);
930} 939}
931 940
932/* call this function to flush any scheduled tasklet */ 941/* call this function to flush any scheduled tasklet */
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index cbd87afbf9ae..87df1b767941 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -318,10 +318,11 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv,
318 struct iwl_rx_queue *q); 318 struct iwl_rx_queue *q);
319void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); 319void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
320void iwl_rx_replenish(struct iwl_priv *priv); 320void iwl_rx_replenish(struct iwl_priv *priv);
321void iwl_rx_replenish_now(struct iwl_priv *priv);
321int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq); 322int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq);
322int iwl_rx_queue_restock(struct iwl_priv *priv); 323int iwl_rx_queue_restock(struct iwl_priv *priv);
323int iwl_rx_queue_space(const struct iwl_rx_queue *q); 324int iwl_rx_queue_space(const struct iwl_rx_queue *q);
324void iwl_rx_allocate(struct iwl_priv *priv); 325void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority);
325void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); 326void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
326int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); 327int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
327/* Handlers */ 328/* Handlers */
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 2076742effdd..770cd1b062ff 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -382,6 +382,7 @@ struct iwl_rx_queue {
382 u32 read; 382 u32 read;
383 u32 write; 383 u32 write;
384 u32 free_count; 384 u32 free_count;
385 u32 write_actual;
385 struct list_head rx_free; 386 struct list_head rx_free;
386 struct list_head rx_used; 387 struct list_head rx_used;
387 int need_update; 388 int need_update;
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c
index 7a432829e79f..c845089701eb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-rx.c
@@ -145,12 +145,14 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, struct iwl_rx_queue *q)
145 goto exit_unlock; 145 goto exit_unlock;
146 } 146 }
147 147
148 iwl_write_direct32(priv, rx_wrt_ptr_reg, q->write & ~0x7); 148 q->write_actual = (q->write & ~0x7);
149 iwl_write_direct32(priv, rx_wrt_ptr_reg, q->write_actual);
149 150
150 /* Else device is assumed to be awake */ 151 /* Else device is assumed to be awake */
151 } else { 152 } else {
152 /* Device expects a multiple of 8 */ 153 /* Device expects a multiple of 8 */
153 iwl_write32(priv, rx_wrt_ptr_reg, q->write & ~0x7); 154 q->write_actual = (q->write & ~0x7);
155 iwl_write_direct32(priv, rx_wrt_ptr_reg, q->write_actual);
154 } 156 }
155 157
156 q->need_update = 0; 158 q->need_update = 0;
@@ -212,7 +214,7 @@ int iwl_rx_queue_restock(struct iwl_priv *priv)
212 214
213 /* If we've added more space for the firmware to place data, tell it. 215 /* If we've added more space for the firmware to place data, tell it.
214 * Increment device's write pointer in multiples of 8. */ 216 * Increment device's write pointer in multiples of 8. */
215 if (write != (rxq->write & ~0x7)) { 217 if (rxq->write_actual != (rxq->write & ~0x7)) {
216 spin_lock_irqsave(&rxq->lock, flags); 218 spin_lock_irqsave(&rxq->lock, flags);
217 rxq->need_update = 1; 219 rxq->need_update = 1;
218 spin_unlock_irqrestore(&rxq->lock, flags); 220 spin_unlock_irqrestore(&rxq->lock, flags);
@@ -232,7 +234,7 @@ EXPORT_SYMBOL(iwl_rx_queue_restock);
232 * Also restock the Rx queue via iwl_rx_queue_restock. 234 * Also restock the Rx queue via iwl_rx_queue_restock.
233 * This is called as a scheduled work item (except for during initialization) 235 * This is called as a scheduled work item (except for during initialization)
234 */ 236 */
235void iwl_rx_allocate(struct iwl_priv *priv) 237void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority)
236{ 238{
237 struct iwl_rx_queue *rxq = &priv->rxq; 239 struct iwl_rx_queue *rxq = &priv->rxq;
238 struct list_head *element; 240 struct list_head *element;
@@ -254,7 +256,8 @@ void iwl_rx_allocate(struct iwl_priv *priv)
254 256
255 /* Alloc a new receive buffer */ 257 /* Alloc a new receive buffer */
256 rxb->skb = alloc_skb(priv->hw_params.rx_buf_size + 256, 258 rxb->skb = alloc_skb(priv->hw_params.rx_buf_size + 256,
257 GFP_KERNEL); 259 priority);
260
258 if (!rxb->skb) { 261 if (!rxb->skb) {
259 IWL_CRIT(priv, "Can not allocate SKB buffers\n"); 262 IWL_CRIT(priv, "Can not allocate SKB buffers\n");
260 /* We don't reschedule replenish work here -- we will 263 /* We don't reschedule replenish work here -- we will
@@ -289,7 +292,7 @@ void iwl_rx_replenish(struct iwl_priv *priv)
289{ 292{
290 unsigned long flags; 293 unsigned long flags;
291 294
292 iwl_rx_allocate(priv); 295 iwl_rx_allocate(priv, GFP_KERNEL);
293 296
294 spin_lock_irqsave(&priv->lock, flags); 297 spin_lock_irqsave(&priv->lock, flags);
295 iwl_rx_queue_restock(priv); 298 iwl_rx_queue_restock(priv);
@@ -297,6 +300,14 @@ void iwl_rx_replenish(struct iwl_priv *priv)
297} 300}
298EXPORT_SYMBOL(iwl_rx_replenish); 301EXPORT_SYMBOL(iwl_rx_replenish);
299 302
303void iwl_rx_replenish_now(struct iwl_priv *priv)
304{
305 iwl_rx_allocate(priv, GFP_ATOMIC);
306
307 iwl_rx_queue_restock(priv);
308}
309EXPORT_SYMBOL(iwl_rx_replenish_now);
310
300 311
301/* Assumes that the skb field of the buffers in 'pool' is kept accurate. 312/* Assumes that the skb field of the buffers in 'pool' is kept accurate.
302 * If an SKB has been detached, the POOL needs to have its SKB set to NULL 313 * If an SKB has been detached, the POOL needs to have its SKB set to NULL
@@ -352,6 +363,7 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv)
352 /* Set us so that we have processed and used all buffers, but have 363 /* Set us so that we have processed and used all buffers, but have
353 * not restocked the Rx queue with fresh buffers */ 364 * not restocked the Rx queue with fresh buffers */
354 rxq->read = rxq->write = 0; 365 rxq->read = rxq->write = 0;
366 rxq->write_actual = 0;
355 rxq->free_count = 0; 367 rxq->free_count = 0;
356 rxq->need_update = 0; 368 rxq->need_update = 0;
357 return 0; 369 return 0;
@@ -390,6 +402,7 @@ void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq)
390 /* Set us so that we have processed and used all buffers, but have 402 /* Set us so that we have processed and used all buffers, but have
391 * not restocked the Rx queue with fresh buffers */ 403 * not restocked the Rx queue with fresh buffers */
392 rxq->read = rxq->write = 0; 404 rxq->read = rxq->write = 0;
405 rxq->write_actual = 0;
393 rxq->free_count = 0; 406 rxq->free_count = 0;
394 spin_unlock_irqrestore(&rxq->lock, flags); 407 spin_unlock_irqrestore(&rxq->lock, flags);
395} 408}