aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhu Yi <yi.zhu@intel.com>2010-04-02 16:38:54 -0400
committerReinette Chatre <reinette.chatre@intel.com>2010-04-09 15:41:26 -0400
commit470058e0ad82fcfaaffd57307d8bf8c094e8e9d7 (patch)
tree1d539469c372b2cca3a8c11a1913b527819dad0b
parent57e40d36e59f828f43d60b2662041991dcd78044 (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>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-lib.c11
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c39
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c20
4 files changed, 58 insertions, 15 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index 384b45c519f1..c465c8590833 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -512,10 +512,13 @@ int iwlagn_hw_nic_init(struct iwl_priv *priv)
512 512
513 spin_unlock_irqrestore(&priv->lock, flags); 513 spin_unlock_irqrestore(&priv->lock, flags);
514 514
515 /* Allocate and init all Tx and Command queues */ 515 /* Allocate or reset and init all Tx and Command queues */
516 ret = iwlagn_txq_ctx_reset(priv); 516 if (!priv->txq) {
517 if (ret) 517 ret = iwlagn_txq_ctx_alloc(priv);
518 return ret; 518 if (ret)
519 return ret;
520 } else
521 iwlagn_txq_ctx_reset(priv);
519 522
520 set_bit(STATUS_INIT, &priv->status); 523 set_bit(STATUS_INIT, &priv->status);
521 524
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index a76e14351b5a..3077eac58880 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -809,8 +809,7 @@ void iwlagn_hw_txq_ctx_free(struct iwl_priv *priv)
809 809
810 /* Tx queues */ 810 /* Tx queues */
811 if (priv->txq) { 811 if (priv->txq) {
812 for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; 812 for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
813 txq_id++)
814 if (txq_id == IWL_CMD_QUEUE_NUM) 813 if (txq_id == IWL_CMD_QUEUE_NUM)
815 iwl_cmd_queue_free(priv); 814 iwl_cmd_queue_free(priv);
816 else 815 else
@@ -825,15 +824,15 @@ void iwlagn_hw_txq_ctx_free(struct iwl_priv *priv)
825} 824}
826 825
827/** 826/**
828 * iwlagn_txq_ctx_reset - Reset TX queue context 827 * iwlagn_txq_ctx_alloc - allocate TX queue context
829 * Destroys all DMA structures and initialize them again 828 * Allocate all Tx DMA structures and initialize them
830 * 829 *
831 * @param priv 830 * @param priv
832 * @return error code 831 * @return error code
833 */ 832 */
834int iwlagn_txq_ctx_reset(struct iwl_priv *priv) 833int iwlagn_txq_ctx_alloc(struct iwl_priv *priv)
835{ 834{
836 int ret = 0; 835 int ret;
837 int txq_id, slots_num; 836 int txq_id, slots_num;
838 unsigned long flags; 837 unsigned long flags;
839 838
@@ -891,8 +890,31 @@ int iwlagn_txq_ctx_reset(struct iwl_priv *priv)
891 return ret; 890 return ret;
892} 891}
893 892
893void iwlagn_txq_ctx_reset(struct iwl_priv *priv)
894{
895 int txq_id, slots_num;
896 unsigned long flags;
897
898 spin_lock_irqsave(&priv->lock, flags);
899
900 /* Turn off all Tx DMA fifos */
901 priv->cfg->ops->lib->txq_set_sched(priv, 0);
902
903 /* Tell NIC where to find the "keep warm" buffer */
904 iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
905
906 spin_unlock_irqrestore(&priv->lock, flags);
907
908 /* Alloc and init all Tx queues, including the command queue (#4) */
909 for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
910 slots_num = txq_id == IWL_CMD_QUEUE_NUM ?
911 TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
912 iwl_tx_queue_reset(priv, &priv->txq[txq_id], slots_num, txq_id);
913 }
914}
915
894/** 916/**
895 * iwlagn_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory 917 * iwlagn_txq_ctx_stop - Stop all Tx DMA channels
896 */ 918 */
897void iwlagn_txq_ctx_stop(struct iwl_priv *priv) 919void iwlagn_txq_ctx_stop(struct iwl_priv *priv)
898{ 920{
@@ -912,9 +934,6 @@ void iwlagn_txq_ctx_stop(struct iwl_priv *priv)
912 1000); 934 1000);
913 } 935 }
914 spin_unlock_irqrestore(&priv->lock, flags); 936 spin_unlock_irqrestore(&priv->lock, flags);
915
916 /* Deallocate memory for all Tx queues */
917 iwlagn_hw_txq_ctx_free(priv);
918} 937}
919 938
920/* 939/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index 608060abe80c..5d3142287e14 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -145,7 +145,8 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
145 struct iwl_rx_mem_buffer *rxb); 145 struct iwl_rx_mem_buffer *rxb);
146int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index); 146int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index);
147void iwlagn_hw_txq_ctx_free(struct iwl_priv *priv); 147void iwlagn_hw_txq_ctx_free(struct iwl_priv *priv);
148int iwlagn_txq_ctx_reset(struct iwl_priv *priv); 148int iwlagn_txq_ctx_alloc(struct iwl_priv *priv);
149void iwlagn_txq_ctx_reset(struct iwl_priv *priv);
149void iwlagn_txq_ctx_stop(struct iwl_priv *priv); 150void iwlagn_txq_ctx_stop(struct iwl_priv *priv);
150 151
151static inline u32 iwl_tx_status_to_mac80211(u32 status) 152static inline u32 iwl_tx_status_to_mac80211(u32 status)
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index aea6a2eee9c3..c3c6505a8c69 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -394,6 +394,26 @@ out_free_arrays:
394} 394}
395EXPORT_SYMBOL(iwl_tx_queue_init); 395EXPORT_SYMBOL(iwl_tx_queue_init);
396 396
397void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
398 int slots_num, u32 txq_id)
399{
400 int actual_slots = slots_num;
401
402 if (txq_id == IWL_CMD_QUEUE_NUM)
403 actual_slots++;
404
405 memset(txq->meta, 0, sizeof(struct iwl_cmd_meta) * actual_slots);
406
407 txq->need_update = 0;
408
409 /* Initialize queue's high/low-water marks, and head/tail indexes */
410 iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
411
412 /* Tell device where to find queue */
413 priv->cfg->ops->lib->txq_init(priv, txq);
414}
415EXPORT_SYMBOL(iwl_tx_queue_reset);
416
397/*************** HOST COMMAND QUEUE FUNCTIONS *****/ 417/*************** HOST COMMAND QUEUE FUNCTIONS *****/
398 418
399/** 419/**