aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-tx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-tx.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c88
1 files changed, 65 insertions, 23 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 0ebab967d5e7..0b822b5ab523 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -263,24 +263,6 @@ EXPORT_SYMBOL(iwl_queue_space);
263 263
264 264
265/** 265/**
266 * iwl_hw_txq_ctx_free - Free TXQ Context
267 *
268 * Destroy all TX DMA queues and structures
269 */
270void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
271{
272 int txq_id;
273
274 /* Tx queues */
275 for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
276 iwl_tx_queue_free(priv, &priv->txq[txq_id]);
277
278 /* Keep-warm buffer */
279 iwl_kw_free(priv);
280}
281EXPORT_SYMBOL(iwl_hw_txq_ctx_free);
282
283/**
284 * iwl_queue_init - Initialize queue's high/low-water and read/write indexes 266 * iwl_queue_init - Initialize queue's high/low-water and read/write indexes
285 */ 267 */
286static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, 268static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q,
@@ -437,6 +419,24 @@ static int iwl_tx_queue_init(struct iwl_priv *priv,
437 419
438 return 0; 420 return 0;
439} 421}
422/**
423 * iwl_hw_txq_ctx_free - Free TXQ Context
424 *
425 * Destroy all TX DMA queues and structures
426 */
427void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
428{
429 int txq_id;
430
431 /* Tx queues */
432 for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
433 iwl_tx_queue_free(priv, &priv->txq[txq_id]);
434
435 /* Keep-warm buffer */
436 iwl_kw_free(priv);
437}
438EXPORT_SYMBOL(iwl_hw_txq_ctx_free);
439
440 440
441/** 441/**
442 * iwl_txq_ctx_reset - Reset TX queue context 442 * iwl_txq_ctx_reset - Reset TX queue context
@@ -449,6 +449,7 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
449{ 449{
450 int ret = 0; 450 int ret = 0;
451 int txq_id, slots_num; 451 int txq_id, slots_num;
452 unsigned long flags;
452 453
453 iwl_kw_free(priv); 454 iwl_kw_free(priv);
454 455
@@ -461,11 +462,19 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
461 IWL_ERROR("Keep Warm allocation failed"); 462 IWL_ERROR("Keep Warm allocation failed");
462 goto error_kw; 463 goto error_kw;
463 } 464 }
465 spin_lock_irqsave(&priv->lock, flags);
466 ret = iwl_grab_nic_access(priv);
467 if (unlikely(ret)) {
468 spin_unlock_irqrestore(&priv->lock, flags);
469 goto error_reset;
470 }
464 471
465 /* Turn off all Tx DMA fifos */ 472 /* Turn off all Tx DMA fifos */
466 ret = priv->cfg->ops->lib->disable_tx_fifo(priv); 473 priv->cfg->ops->lib->txq_set_sched(priv, 0);
467 if (unlikely(ret)) 474
468 goto error_reset; 475 iwl_release_nic_access(priv);
476 spin_unlock_irqrestore(&priv->lock, flags);
477
469 478
470 /* Tell nic where to find the keep-warm buffer */ 479 /* Tell nic where to find the keep-warm buffer */
471 ret = iwl_kw_init(priv); 480 ret = iwl_kw_init(priv);
@@ -474,8 +483,7 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
474 goto error_reset; 483 goto error_reset;
475 } 484 }
476 485
477 /* Alloc and init all (default 16) Tx queues, 486 /* Alloc and init all Tx queues, including the command queue (#4) */
478 * including the command queue (#4) */
479 for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { 487 for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
480 slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? 488 slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ?
481 TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; 489 TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
@@ -496,6 +504,40 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
496 error_kw: 504 error_kw:
497 return ret; 505 return ret;
498} 506}
507/**
508 * iwl_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory
509 */
510void iwl_txq_ctx_stop(struct iwl_priv *priv)
511{
512
513 int txq_id;
514 unsigned long flags;
515
516
517 /* Turn off all Tx DMA fifos */
518 spin_lock_irqsave(&priv->lock, flags);
519 if (iwl_grab_nic_access(priv)) {
520 spin_unlock_irqrestore(&priv->lock, flags);
521 return;
522 }
523
524 priv->cfg->ops->lib->txq_set_sched(priv, 0);
525
526 /* Stop each Tx DMA channel, and wait for it to be idle */
527 for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
528 iwl_write_direct32(priv,
529 FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), 0x0);
530 iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG,
531 FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE
532 (txq_id), 200);
533 }
534 iwl_release_nic_access(priv);
535 spin_unlock_irqrestore(&priv->lock, flags);
536
537 /* Deallocate memory for all Tx queues */
538 iwl_hw_txq_ctx_free(priv);
539}
540EXPORT_SYMBOL(iwl_txq_ctx_stop);
499 541
500/* 542/*
501 * handle build REPLY_TX command notification. 543 * handle build REPLY_TX command notification.