Commit c544d89b authored by Johannes Berg's avatar Johannes Berg Committed by Kalle Valo
Browse files

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 1ed08f6f
("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: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/iwlwifi.20210415164821.d0f2edda1651.I75f762e0bed38914d1300ea198b86dd449b4b206@changeid
parent fa84df70
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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
******************************************************/
+21 −3
Original line number Diff line number Diff line
@@ -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 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans)
	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);
+2 −2
Original line number Diff line number Diff line
@@ -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;
}