aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/intel/iwlwifi/pcie
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2015-11-24 13:24:24 +0200
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2015-12-13 08:52:52 +0200
commit0cd58eaab1482ab75800f68cd0033286232827f1 (patch)
treee16105c724436a3570207218b0e5977e4915c6f6 /drivers/net/wireless/intel/iwlwifi/pcie
parent3f50a69077b5b8086fd16cfa0b71138082126a69 (diff)
downloadlinux-0cd58eaab1482ab75800f68cd0033286232827f1.tar.gz
iwlwifi: pcie: allow the op_mode to block the tx queues
In certain flows (see next patches), the op_mode may need to block the Tx queues for a short period. Provide an API for that. The transport is in charge of counting the number of times the queues are blocked since the op_mode may block the queues several times in a row before unblocking them. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/pcie')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/internal.h1
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/trans.c28
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/tx.c4
3 files changed, 32 insertions, 1 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
index 44dc09d84d42..31f30a2dd654 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
@@ -278,6 +278,7 @@ struct iwl_txq {
bool frozen;
u8 active;
bool ampdu;
+ bool block;
unsigned long wd_timeout;
};
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index efef4871478d..316162a45989 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -1673,6 +1673,33 @@ next_queue:
}
}
+static void iwl_trans_pcie_block_txq_ptrs(struct iwl_trans *trans, bool block)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ int i;
+
+ for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) {
+ struct iwl_txq *txq = &trans_pcie->txq[i];
+
+ if (i == trans_pcie->cmd_queue)
+ continue;
+
+ spin_lock_bh(&txq->lock);
+
+ if (!block && !(WARN_ON_ONCE(!txq->block))) {
+ txq->block--;
+ if (!txq->block) {
+ iwl_write32(trans, HBUS_TARG_WRPTR,
+ txq->q.write_ptr | (i << 8));
+ }
+ } else if (block) {
+ txq->block++;
+ }
+
+ spin_unlock_bh(&txq->lock);
+ }
+}
+
#define IWL_FLUSH_WAIT_MS 2000
static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans, u32 txq_bm)
@@ -2467,6 +2494,7 @@ static const struct iwl_trans_ops trans_ops_pcie = {
.wait_tx_queue_empty = iwl_trans_pcie_wait_txq_empty,
.freeze_txq_timer = iwl_trans_pcie_freeze_txq_timer,
+ .block_txq_ptrs = iwl_trans_pcie_block_txq_ptrs,
.write8 = iwl_trans_pcie_write8,
.write32 = iwl_trans_pcie_write32,
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
index a8c8a4a7420b..95ba920edb1d 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
@@ -318,7 +318,9 @@ static void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans,
* trying to tx (during RFKILL, we're not trying to tx).
*/
IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq_id, txq->q.write_ptr);
- iwl_write32(trans, HBUS_TARG_WRPTR, txq->q.write_ptr | (txq_id << 8));
+ if (!txq->block)
+ iwl_write32(trans, HBUS_TARG_WRPTR,
+ txq->q.write_ptr | (txq_id << 8));
}
void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans)