diff options
author | Mohamed Abbas <mohamed.abbas@intel.com> | 2009-05-22 14:01:51 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-05-22 14:06:08 -0400 |
commit | 4752c93c30441f98f7ed723001b1a5e3e5619829 (patch) | |
tree | de868a2003d2328ad3bd048e75bc16b7e327bd7f /drivers/net | |
parent | ef850d7cb301bda9155c096269557a4586b58071 (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>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 15 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-dev.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-rx.c | 25 |
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); |
319 | void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); | 319 | void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); |
320 | void iwl_rx_replenish(struct iwl_priv *priv); | 320 | void iwl_rx_replenish(struct iwl_priv *priv); |
321 | void iwl_rx_replenish_now(struct iwl_priv *priv); | ||
321 | int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq); | 322 | int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq); |
322 | int iwl_rx_queue_restock(struct iwl_priv *priv); | 323 | int iwl_rx_queue_restock(struct iwl_priv *priv); |
323 | int iwl_rx_queue_space(const struct iwl_rx_queue *q); | 324 | int iwl_rx_queue_space(const struct iwl_rx_queue *q); |
324 | void iwl_rx_allocate(struct iwl_priv *priv); | 325 | void iwl_rx_allocate(struct iwl_priv *priv, gfp_t priority); |
325 | void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); | 326 | void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb); |
326 | int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); | 327 | int 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 | */ |
235 | void iwl_rx_allocate(struct iwl_priv *priv) | 237 | void 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 | } |
298 | EXPORT_SYMBOL(iwl_rx_replenish); | 301 | EXPORT_SYMBOL(iwl_rx_replenish); |
299 | 302 | ||
303 | void iwl_rx_replenish_now(struct iwl_priv *priv) | ||
304 | { | ||
305 | iwl_rx_allocate(priv, GFP_ATOMIC); | ||
306 | |||
307 | iwl_rx_queue_restock(priv); | ||
308 | } | ||
309 | EXPORT_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 | } |