Commit 72bc934c authored by Johannes Berg's avatar Johannes Berg Committed by Luca Coelho

iwlwifi: pcie: avoid unnecessarily taking spinlock

Most devices don't set the apmg_wake_up_wa flag, so we don't do
anything for them. Avoid taking the spinlock for every command
unless the device needs this workaround.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
Link: https://lore.kernel.org/r/iwlwifi.20210330162204.1ab60af3f318.I51cc202f68a2a953223e70c3e8610343412961b6@changeidSigned-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent 7686fd52
...@@ -181,16 +181,20 @@ static void iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans) ...@@ -181,16 +181,20 @@ static void iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans)
{ {
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
lockdep_assert_held(&trans_pcie->reg_lock);
if (!trans->trans_cfg->base_params->apmg_wake_up_wa) if (!trans->trans_cfg->base_params->apmg_wake_up_wa)
return; return;
if (WARN_ON(!trans_pcie->cmd_hold_nic_awake))
spin_lock(&trans_pcie->reg_lock);
if (WARN_ON(!trans_pcie->cmd_hold_nic_awake)) {
spin_unlock(&trans_pcie->reg_lock);
return; return;
}
trans_pcie->cmd_hold_nic_awake = false; trans_pcie->cmd_hold_nic_awake = false;
__iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
spin_unlock(&trans_pcie->reg_lock);
} }
/* /*
...@@ -198,7 +202,6 @@ static void iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans) ...@@ -198,7 +202,6 @@ static void iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans)
*/ */
static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id) static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id)
{ {
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_txq *txq = trans->txqs.txq[txq_id]; struct iwl_txq *txq = trans->txqs.txq[txq_id];
if (!txq) { if (!txq) {
...@@ -222,12 +225,9 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id) ...@@ -222,12 +225,9 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id)
iwl_txq_free_tfd(trans, txq); iwl_txq_free_tfd(trans, txq);
txq->read_ptr = iwl_txq_inc_wrap(trans, txq->read_ptr); txq->read_ptr = iwl_txq_inc_wrap(trans, txq->read_ptr);
if (txq->read_ptr == txq->write_ptr) { if (txq->read_ptr == txq->write_ptr &&
spin_lock(&trans_pcie->reg_lock); txq_id == trans->txqs.cmd.q_id)
if (txq_id == trans->txqs.cmd.q_id)
iwl_pcie_clear_cmd_in_flight(trans); iwl_pcie_clear_cmd_in_flight(trans);
spin_unlock(&trans_pcie->reg_lock);
}
} }
while (!skb_queue_empty(&txq->overflow_q)) { while (!skb_queue_empty(&txq->overflow_q)) {
...@@ -629,22 +629,23 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans, ...@@ -629,22 +629,23 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans,
const struct iwl_host_cmd *cmd) const struct iwl_host_cmd *cmd)
{ {
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int ret; int ret = 0;
lockdep_assert_held(&trans_pcie->reg_lock);
/* Make sure the NIC is still alive in the bus */ /* Make sure the NIC is still alive in the bus */
if (test_bit(STATUS_TRANS_DEAD, &trans->status)) if (test_bit(STATUS_TRANS_DEAD, &trans->status))
return -ENODEV; return -ENODEV;
if (!trans->trans_cfg->base_params->apmg_wake_up_wa)
return 0;
spin_lock(&trans_pcie->reg_lock);
/* /*
* wake up the NIC to make sure that the firmware will see the host * wake up the NIC to make sure that the firmware will see the host
* command - we will let the NIC sleep once all the host commands * command - we will let the NIC sleep once all the host commands
* returned. This needs to be done only on NICs that have * returned. This needs to be done only on NICs that have
* apmg_wake_up_wa set. * apmg_wake_up_wa set (see above.)
*/ */
if (trans->trans_cfg->base_params->apmg_wake_up_wa && if (!trans_pcie->cmd_hold_nic_awake) {
!trans_pcie->cmd_hold_nic_awake) {
__iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
...@@ -657,12 +658,14 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans, ...@@ -657,12 +658,14 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans,
__iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
IWL_ERR(trans, "Failed to wake NIC for hcmd\n"); IWL_ERR(trans, "Failed to wake NIC for hcmd\n");
return -EIO; ret = -EIO;
} } else {
trans_pcie->cmd_hold_nic_awake = true; trans_pcie->cmd_hold_nic_awake = true;
} }
}
spin_unlock(&trans_pcie->reg_lock);
return 0; return ret;
} }
/* /*
...@@ -674,7 +677,6 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans, ...@@ -674,7 +677,6 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans,
*/ */
static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx) static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
{ {
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_txq *txq = trans->txqs.txq[txq_id]; struct iwl_txq *txq = trans->txqs.txq[txq_id];
int nfreed = 0; int nfreed = 0;
u16 r; u16 r;
...@@ -705,12 +707,8 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx) ...@@ -705,12 +707,8 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
} }
} }
if (txq->read_ptr == txq->write_ptr) { if (txq->read_ptr == txq->write_ptr)
/* BHs are also disabled due to txq->lock */
spin_lock(&trans_pcie->reg_lock);
iwl_pcie_clear_cmd_in_flight(trans); iwl_pcie_clear_cmd_in_flight(trans);
spin_unlock(&trans_pcie->reg_lock);
}
iwl_txq_progress(txq); iwl_txq_progress(txq);
} }
...@@ -914,7 +912,6 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id, ...@@ -914,7 +912,6 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id,
int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
struct iwl_host_cmd *cmd) struct iwl_host_cmd *cmd)
{ {
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
struct iwl_txq *txq = trans->txqs.txq[trans->txqs.cmd.q_id]; struct iwl_txq *txq = trans->txqs.txq[trans->txqs.cmd.q_id];
struct iwl_device_cmd *out_cmd; struct iwl_device_cmd *out_cmd;
struct iwl_cmd_meta *out_meta; struct iwl_cmd_meta *out_meta;
...@@ -1161,19 +1158,16 @@ int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, ...@@ -1161,19 +1158,16 @@ int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
if (txq->read_ptr == txq->write_ptr && txq->wd_timeout) if (txq->read_ptr == txq->write_ptr && txq->wd_timeout)
mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout); mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout);
spin_lock(&trans_pcie->reg_lock);
ret = iwl_pcie_set_cmd_in_flight(trans, cmd); ret = iwl_pcie_set_cmd_in_flight(trans, cmd);
if (ret < 0) { if (ret < 0) {
idx = ret; idx = ret;
goto unlock_reg; goto out;
} }
/* Increment and update queue's write index */ /* Increment and update queue's write index */
txq->write_ptr = iwl_txq_inc_wrap(trans, txq->write_ptr); txq->write_ptr = iwl_txq_inc_wrap(trans, txq->write_ptr);
iwl_pcie_txq_inc_wr_ptr(trans, txq); iwl_pcie_txq_inc_wr_ptr(trans, txq);
unlock_reg:
spin_unlock(&trans_pcie->reg_lock);
out: out:
spin_unlock_irqrestore(&txq->lock, flags); spin_unlock_irqrestore(&txq->lock, flags);
free_dup_buf: free_dup_buf:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment