diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-tx.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-tx.c | 88 |
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 | */ | ||
270 | void 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 | } | ||
281 | EXPORT_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 | */ |
286 | static int iwl_queue_init(struct iwl_priv *priv, struct iwl_queue *q, | 268 | static 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 | */ | ||
427 | void 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 | } | ||
438 | EXPORT_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 | */ | ||
510 | void 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 | } | ||
540 | EXPORT_SYMBOL(iwl_txq_ctx_stop); | ||
499 | 541 | ||
500 | /* | 542 | /* |
501 | * handle build REPLY_TX command notification. | 543 | * handle build REPLY_TX command notification. |