aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-tx.c
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/iwlwifi/iwl-tx.c
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/iwlwifi/iwl-tx.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c59
1 files changed, 49 insertions, 10 deletions
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