aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorZhu Yi <yi.zhu@intel.com>2010-03-23 03:45:03 -0400
committerReinette Chatre <reinette.chatre@intel.com>2010-04-02 15:18:26 -0400
commitde0f60ea94e132c858caa64a44b2012e1e8580b0 (patch)
treec7269d53625c58fe69befc61c3c347f7c8faf89c /drivers/net/wireless
parent04f2dec1c3d375c4072613880f28f43b66524876 (diff)
iwlwifi: avoid Tx queue memory allocation in interface down
We used to free all the Tx queues memory when interface is brought down and reallocate them again in interface up. This requires order-4 allocation for txq->cmd[]. In situations like s2ram, this usually leads to allocation failure in the memory subsystem. The patch fixed this problem by allocating the Tx queues memory only at the first time. Later iwl_down/iwl_up only initialize but don't free and reallocate them. The memory is freed at the device removal time. BTW, we have already done this for the Rx queue. This fixed bug https://bugzilla.kernel.org/show_bug.cgi?id=15551 Signed-off-by: Zhu Yi <yi.zhu@intel.com> Acked-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c11
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c59
3 files changed, 60 insertions, 15 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 112149e9b31e..894bcb8b8b37 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -307,10 +307,13 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
307 307
308 spin_unlock_irqrestore(&priv->lock, flags); 308 spin_unlock_irqrestore(&priv->lock, flags);
309 309
310 /* Allocate and init all Tx and Command queues */ 310 /* Allocate or reset and init all Tx and Command queues */
311 ret = iwl_txq_ctx_reset(priv); 311 if (!priv->txq) {
312 if (ret) 312 ret = iwl_txq_ctx_alloc(priv);
313 return ret; 313 if (ret)
314 return ret;
315 } else
316 iwl_txq_ctx_reset(priv);
314 317
315 set_bit(STATUS_INIT, &priv->status); 318 set_bit(STATUS_INIT, &priv->status);
316 319
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 4ef7739f9e8e..732590f5fe30 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -442,7 +442,8 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
442/***************************************************** 442/*****************************************************
443* TX 443* TX
444******************************************************/ 444******************************************************/
445int iwl_txq_ctx_reset(struct iwl_priv *priv); 445int iwl_txq_ctx_alloc(struct iwl_priv *priv);
446void iwl_txq_ctx_reset(struct iwl_priv *priv);
446void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq); 447void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
447int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, 448int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
448 struct iwl_tx_queue *txq, 449 struct iwl_tx_queue *txq,
@@ -456,6 +457,8 @@ void iwl_free_tfds_in_queue(struct iwl_priv *priv,
456void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); 457void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
457int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq, 458int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
458 int slots_num, u32 txq_id); 459 int slots_num, u32 txq_id);
460void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
461 int slots_num, u32 txq_id);
459void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id); 462void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id);
460int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn); 463int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn);
461int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid); 464int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid);
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 6aa309032f4e..343d81ad2653 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -433,6 +433,26 @@ out_free_arrays:
433} 433}
434EXPORT_SYMBOL(iwl_tx_queue_init); 434EXPORT_SYMBOL(iwl_tx_queue_init);
435 435
436void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
437 int slots_num, u32 txq_id)
438{
439 int actual_slots = slots_num;
440
441 if (txq_id == IWL_CMD_QUEUE_NUM)
442 actual_slots++;
443
444 memset(txq->meta, 0, sizeof(struct iwl_cmd_meta) * actual_slots);
445
446 txq->need_update = 0;
447
448 /* Initialize queue's high/low-water marks, and head/tail indexes */
449 iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
450
451 /* Tell device where to find queue */
452 priv->cfg->ops->lib->txq_init(priv, txq);
453}
454EXPORT_SYMBOL(iwl_tx_queue_reset);
455
436/** 456/**
437 * iwl_hw_txq_ctx_free - Free TXQ Context 457 * iwl_hw_txq_ctx_free - Free TXQ Context
438 * 458 *
@@ -444,8 +464,7 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
444 464
445 /* Tx queues */ 465 /* Tx queues */
446 if (priv->txq) { 466 if (priv->txq) {
447 for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; 467 for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
448 txq_id++)
449 if (txq_id == IWL_CMD_QUEUE_NUM) 468 if (txq_id == IWL_CMD_QUEUE_NUM)
450 iwl_cmd_queue_free(priv); 469 iwl_cmd_queue_free(priv);
451 else 470 else
@@ -461,15 +480,15 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
461EXPORT_SYMBOL(iwl_hw_txq_ctx_free); 480EXPORT_SYMBOL(iwl_hw_txq_ctx_free);
462 481
463/** 482/**
464 * iwl_txq_ctx_reset - Reset TX queue context 483 * iwl_txq_ctx_alloc - allocate TX queue context
465 * Destroys all DMA structures and initialize them again 484 * Allocate all Tx DMA structures and initialize them
466 * 485 *
467 * @param priv 486 * @param priv
468 * @return error code 487 * @return error code
469 */ 488 */
470int iwl_txq_ctx_reset(struct iwl_priv *priv) 489int iwl_txq_ctx_alloc(struct iwl_priv *priv)
471{ 490{
472 int ret = 0; 491 int ret;
473 int txq_id, slots_num; 492 int txq_id, slots_num;
474 unsigned long flags; 493 unsigned long flags;
475 494
@@ -527,8 +546,31 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
527 return ret; 546 return ret;
528} 547}
529 548
549void iwl_txq_ctx_reset(struct iwl_priv *priv)
550{
551 int txq_id, slots_num;
552 unsigned long flags;
553
554 spin_lock_irqsave(&priv->lock, flags);
555
556 /* Turn off all Tx DMA fifos */
557 priv->cfg->ops->lib->txq_set_sched(priv, 0);
558
559 /* Tell NIC where to find the "keep warm" buffer */
560 iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
561
562 spin_unlock_irqrestore(&priv->lock, flags);
563
564 /* Alloc and init all Tx queues, including the command queue (#4) */
565 for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
566 slots_num = txq_id == IWL_CMD_QUEUE_NUM ?
567 TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
568 iwl_tx_queue_reset(priv, &priv->txq[txq_id], slots_num, txq_id);
569 }
570}
571
530/** 572/**
531 * iwl_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory 573 * iwl_txq_ctx_stop - Stop all Tx DMA channels
532 */ 574 */
533void iwl_txq_ctx_stop(struct iwl_priv *priv) 575void iwl_txq_ctx_stop(struct iwl_priv *priv)
534{ 576{
@@ -548,9 +590,6 @@ void iwl_txq_ctx_stop(struct iwl_priv *priv)
548 1000); 590 1000);
549 } 591 }
550 spin_unlock_irqrestore(&priv->lock, flags); 592 spin_unlock_irqrestore(&priv->lock, flags);
551
552 /* Deallocate memory for all Tx queues */
553 iwl_hw_txq_ctx_free(priv);
554} 593}
555EXPORT_SYMBOL(iwl_txq_ctx_stop); 594EXPORT_SYMBOL(iwl_txq_ctx_stop);
556 595