aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2021-04-15 16:48:46 +0300
committerKalle Valo <kvalo@codeaurora.org>2021-04-18 09:37:38 +0300
commitc544d89b0d67d9b714846035913c270375c0ce00 (patch)
tree580c8340bb451c0196702b390ab6a52bf46da86b
parentbcma: remove unused function (diff)
downloadlinux-dev-c544d89b0d67d9b714846035913c270375c0ce00.tar.xz
linux-dev-c544d89b0d67d9b714846035913c270375c0ce00.zip
iwlwifi: pcie: don't enable BHs with IRQs disabled
After the fix from Jiri that disabled local IRQs instead of just BHs (necessary to fix an issue with submitting a command with IRQs already disabled), there was still a situation in which we could deep in there enable BHs, if the device config sets the apmg_wake_up_wa configuration, which is true on all 7000 series devices. To fix that, but not require reverting commit 1ed08f6fb5ae ("iwlwifi: remove flags argument for nic_access"), split up nic access into a version with BH manipulation to use most of the time, and without it for this specific case where the local IRQs are already disabled. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Luca Coelho <luciano.coelho@intel.com> Signed-off-by: Kalle Valo <kvalo@codeaurora.org> Link: https://lore.kernel.org/r/iwlwifi.20210415164821.d0f2edda1651.I75f762e0bed38914d1300ea198b86dd449b4b206@changeid
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/internal.h5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/trans.c24
-rw-r--r--drivers/net/wireless/intel/iwlwifi/pcie/tx.c4
3 files changed, 28 insertions, 5 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
index d9688c7bed07..76a512cd2e5c 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h
@@ -447,6 +447,11 @@ struct iwl_trans
const struct iwl_cfg_trans_params *cfg_trans);
void iwl_trans_pcie_free(struct iwl_trans *trans);
+bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans);
+#define _iwl_trans_pcie_grab_nic_access(trans) \
+ __cond_lock(nic_access_nobh, \
+ likely(__iwl_trans_pcie_grab_nic_access(trans)))
+
/*****************************************************
* RX
******************************************************/
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
index 861dbc03d183..239bc177a3e5 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c
@@ -1978,12 +1978,16 @@ static void iwl_trans_pcie_removal_wk(struct work_struct *wk)
module_put(THIS_MODULE);
}
-static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans)
+/*
+ * This version doesn't disable BHs but rather assumes they're
+ * already disabled.
+ */
+bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans)
{
int ret;
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
- spin_lock_bh(&trans_pcie->reg_lock);
+ spin_lock(&trans_pcie->reg_lock);
if (trans_pcie->cmd_hold_nic_awake)
goto out;
@@ -2068,7 +2072,7 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans)
}
err:
- spin_unlock_bh(&trans_pcie->reg_lock);
+ spin_unlock(&trans_pcie->reg_lock);
return false;
}
@@ -2081,6 +2085,20 @@ out:
return true;
}
+static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans)
+{
+ bool ret;
+
+ local_bh_disable();
+ ret = __iwl_trans_pcie_grab_nic_access(trans);
+ if (ret) {
+ /* keep BHs disabled until iwl_trans_pcie_release_nic_access */
+ return ret;
+ }
+ local_bh_enable();
+ return false;
+}
+
static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
index 0346505351f5..4f6c187eed69 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c
@@ -643,7 +643,7 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans,
* returned. This needs to be done only on NICs that have
* apmg_wake_up_wa set (see above.)
*/
- if (!iwl_trans_grab_nic_access(trans))
+ if (!_iwl_trans_pcie_grab_nic_access(trans))
return -EIO;
/*
@@ -652,7 +652,7 @@ static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans,
* already true, so it's OK to unconditionally set it to true.
*/
trans_pcie->cmd_hold_nic_awake = true;
- spin_unlock_bh(&trans_pcie->reg_lock);
+ spin_unlock(&trans_pcie->reg_lock);
return 0;
}