diff options
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/pcie/trans.c')
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/pcie/trans.c | 72 |
1 files changed, 43 insertions, 29 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 85f44d8f1c41..a6c171c5b26f 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2045,17 +2045,52 @@ void iwl_trans_pcie_log_scd_error(struct iwl_trans *trans, struct iwl_txq *txq) iwl_read_direct32(trans, FH_TX_TRB_REG(fifo))); } -static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm) +static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, int txq_idx) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_txq *txq; - int cnt; unsigned long now = jiffies; + u8 wr_ptr; + + if (!test_bit(txq_idx, trans_pcie->queue_used)) + return -EINVAL; + + IWL_DEBUG_TX_QUEUES(trans, "Emptying queue %d...\n", txq_idx); + txq = trans_pcie->txq[txq_idx]; + wr_ptr = ACCESS_ONCE(txq->write_ptr); + + while (txq->read_ptr != ACCESS_ONCE(txq->write_ptr) && + !time_after(jiffies, + now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS))) { + u8 write_ptr = ACCESS_ONCE(txq->write_ptr); + + if (WARN_ONCE(wr_ptr != write_ptr, + "WR pointer moved while flushing %d -> %d\n", + wr_ptr, write_ptr)) + return -ETIMEDOUT; + usleep_range(1000, 2000); + } + + if (txq->read_ptr != txq->write_ptr) { + IWL_ERR(trans, + "fail to flush all tx fifo queues Q %d\n", txq_idx); + iwl_trans_pcie_log_scd_error(trans, txq); + return -ETIMEDOUT; + } + + IWL_DEBUG_TX_QUEUES(trans, "Queue %d is now empty.\n", txq_idx); + + return 0; +} + +static int iwl_trans_pcie_wait_txqs_empty(struct iwl_trans *trans, u32 txq_bm) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int cnt; int ret = 0; /* waiting for all the tx frames complete might take a while */ for (cnt = 0; cnt < trans->cfg->base_params->num_of_queues; cnt++) { - u8 wr_ptr; if (cnt == trans_pcie->cmd_queue) continue; @@ -2064,34 +2099,11 @@ static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm) if (!(BIT(cnt) & txq_bm)) continue; - IWL_DEBUG_TX_QUEUES(trans, "Emptying queue %d...\n", cnt); - txq = trans_pcie->txq[cnt]; - wr_ptr = ACCESS_ONCE(txq->write_ptr); - - while (txq->read_ptr != ACCESS_ONCE(txq->write_ptr) && - !time_after(jiffies, - now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS))) { - u8 write_ptr = ACCESS_ONCE(txq->write_ptr); - - if (WARN_ONCE(wr_ptr != write_ptr, - "WR pointer moved while flushing %d -> %d\n", - wr_ptr, write_ptr)) - return -ETIMEDOUT; - usleep_range(1000, 2000); - } - - if (txq->read_ptr != txq->write_ptr) { - IWL_ERR(trans, - "fail to flush all tx fifo queues Q %d\n", cnt); - ret = -ETIMEDOUT; + ret = iwl_trans_pcie_wait_txq_empty(trans, cnt); + if (ret) break; - } - IWL_DEBUG_TX_QUEUES(trans, "Queue %d is now empty.\n", cnt); } - if (ret) - iwl_trans_pcie_log_scd_error(trans, txq); - return ret; } @@ -2862,7 +2874,6 @@ static void iwl_trans_pcie_resume(struct iwl_trans *trans) .ref = iwl_trans_pcie_ref, \ .unref = iwl_trans_pcie_unref, \ .dump_data = iwl_trans_pcie_dump_data, \ - .wait_tx_queues_empty = iwl_trans_pcie_wait_txq_empty, \ .d3_suspend = iwl_trans_pcie_d3_suspend, \ .d3_resume = iwl_trans_pcie_d3_resume @@ -2892,6 +2903,8 @@ static const struct iwl_trans_ops trans_ops_pcie = { .txq_set_shared_mode = iwl_trans_pcie_txq_set_shared_mode, + .wait_tx_queues_empty = iwl_trans_pcie_wait_txqs_empty, + .freeze_txq_timer = iwl_trans_pcie_freeze_txq_timer, .block_txq_ptrs = iwl_trans_pcie_block_txq_ptrs, }; @@ -2911,6 +2924,7 @@ static const struct iwl_trans_ops trans_ops_pcie_gen2 = { .txq_alloc = iwl_trans_pcie_dyn_txq_alloc, .txq_free = iwl_trans_pcie_dyn_txq_free, + .wait_txq_empty = iwl_trans_pcie_wait_txq_empty, }; struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, |