Commit b3500b47 authored by Emmanuel Grumbach's avatar Emmanuel Grumbach Committed by Kalle Valo

iwlwifi: fix load in rfkill flow for unified firmware

When we have a single image (same firmware image for INIT and
OPERATIONAL), we couldn't load the driver and register to the
stack if we had hardware RF-Kill asserted.

Fix this. This required a few changes:

1) Run the firmware as part of the INIT phase even if its
   ucode_type is not IWL_UCODE_INIT.
2) Send the commands that are sent to the unified image in
   INIT flow even in RF-Kill.
3) Don't ask the transport to stop the hardware upon RF-Kill
   interrupt if the RF-Kill is asserted.
4) Allow the RF-Kill interrupt to take us out of L1A so that
   the RF-Kill interrupt will be received by the host (to
   enable the radio).
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 23f57bfa
...@@ -311,6 +311,8 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, ...@@ -311,6 +311,8 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
int ret; int ret;
enum iwl_ucode_type old_type = mvm->fwrt.cur_fw_img; enum iwl_ucode_type old_type = mvm->fwrt.cur_fw_img;
static const u16 alive_cmd[] = { MVM_ALIVE }; static const u16 alive_cmd[] = { MVM_ALIVE };
bool run_in_rfkill =
ucode_type == IWL_UCODE_INIT || iwl_mvm_has_unified_ucode(mvm);
if (ucode_type == IWL_UCODE_REGULAR && if (ucode_type == IWL_UCODE_REGULAR &&
iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_START_FROM_ALIVE) && iwl_fw_dbg_conf_usniffer(mvm->fw, FW_DBG_START_FROM_ALIVE) &&
...@@ -328,7 +330,12 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, ...@@ -328,7 +330,12 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm,
alive_cmd, ARRAY_SIZE(alive_cmd), alive_cmd, ARRAY_SIZE(alive_cmd),
iwl_alive_fn, &alive_data); iwl_alive_fn, &alive_data);
ret = iwl_trans_start_fw(mvm->trans, fw, ucode_type == IWL_UCODE_INIT); /*
* We want to load the INIT firmware even in RFKILL
* For the unified firmware case, the ucode_type is not
* INIT, but we still need to run it.
*/
ret = iwl_trans_start_fw(mvm->trans, fw, run_in_rfkill);
if (ret) { if (ret) {
iwl_fw_set_current_image(&mvm->fwrt, old_type); iwl_fw_set_current_image(&mvm->fwrt, old_type);
iwl_remove_notification(&mvm->notif_wait, &alive_wait); iwl_remove_notification(&mvm->notif_wait, &alive_wait);
...@@ -433,7 +440,8 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) ...@@ -433,7 +440,8 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
* commands * commands
*/ */
ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(SYSTEM_GROUP, ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(SYSTEM_GROUP,
INIT_EXTENDED_CFG_CMD), 0, INIT_EXTENDED_CFG_CMD),
CMD_SEND_IN_RFKILL,
sizeof(init_cfg), &init_cfg); sizeof(init_cfg), &init_cfg);
if (ret) { if (ret) {
IWL_ERR(mvm, "Failed to run init config command: %d\n", IWL_ERR(mvm, "Failed to run init config command: %d\n",
...@@ -457,7 +465,8 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) ...@@ -457,7 +465,8 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
} }
ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(REGULATORY_AND_NVM_GROUP, ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(REGULATORY_AND_NVM_GROUP,
NVM_ACCESS_COMPLETE), 0, NVM_ACCESS_COMPLETE),
CMD_SEND_IN_RFKILL,
sizeof(nvm_complete), &nvm_complete); sizeof(nvm_complete), &nvm_complete);
if (ret) { if (ret) {
IWL_ERR(mvm, "Failed to run complete NVM access: %d\n", IWL_ERR(mvm, "Failed to run complete NVM access: %d\n",
...@@ -482,6 +491,8 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) ...@@ -482,6 +491,8 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
} }
} }
mvm->rfkill_safe_init_done = true;
return 0; return 0;
error: error:
...@@ -526,7 +537,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) ...@@ -526,7 +537,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
lockdep_assert_held(&mvm->mutex); lockdep_assert_held(&mvm->mutex);
if (WARN_ON_ONCE(mvm->calibrating)) if (WARN_ON_ONCE(mvm->rfkill_safe_init_done))
return 0; return 0;
iwl_init_notification_wait(&mvm->notif_wait, iwl_init_notification_wait(&mvm->notif_wait,
...@@ -576,7 +587,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) ...@@ -576,7 +587,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
goto remove_notif; goto remove_notif;
} }
mvm->calibrating = true; mvm->rfkill_safe_init_done = true;
/* Send TX valid antennas before triggering calibrations */ /* Send TX valid antennas before triggering calibrations */
ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm)); ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm));
...@@ -612,7 +623,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) ...@@ -612,7 +623,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
remove_notif: remove_notif:
iwl_remove_notification(&mvm->notif_wait, &calib_wait); iwl_remove_notification(&mvm->notif_wait, &calib_wait);
out: out:
mvm->calibrating = false; mvm->rfkill_safe_init_done = false;
if (iwlmvm_mod_params.init_dbg && !mvm->nvm_data) { if (iwlmvm_mod_params.init_dbg && !mvm->nvm_data) {
/* we want to debug INIT and we have no NVM - fake */ /* we want to debug INIT and we have no NVM - fake */
mvm->nvm_data = kzalloc(sizeof(struct iwl_nvm_data) + mvm->nvm_data = kzalloc(sizeof(struct iwl_nvm_data) +
......
...@@ -1209,7 +1209,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) ...@@ -1209,7 +1209,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
mvm->scan_status = 0; mvm->scan_status = 0;
mvm->ps_disabled = false; mvm->ps_disabled = false;
mvm->calibrating = false; mvm->rfkill_safe_init_done = false;
/* just in case one was running */ /* just in case one was running */
iwl_mvm_cleanup_roc_te(mvm); iwl_mvm_cleanup_roc_te(mvm);
......
...@@ -880,7 +880,7 @@ struct iwl_mvm { ...@@ -880,7 +880,7 @@ struct iwl_mvm {
struct iwl_mvm_vif *bf_allowed_vif; struct iwl_mvm_vif *bf_allowed_vif;
bool hw_registered; bool hw_registered;
bool calibrating; bool rfkill_safe_init_done;
bool support_umac_log; bool support_umac_log;
u32 ampdu_ref; u32 ampdu_ref;
......
...@@ -1209,7 +1209,8 @@ void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state) ...@@ -1209,7 +1209,8 @@ void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state)
static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
{ {
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
bool calibrating = READ_ONCE(mvm->calibrating); bool rfkill_safe_init_done = READ_ONCE(mvm->rfkill_safe_init_done);
bool unified = iwl_mvm_has_unified_ucode(mvm);
if (state) if (state)
set_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); set_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status);
...@@ -1218,15 +1219,23 @@ static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) ...@@ -1218,15 +1219,23 @@ static bool iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
iwl_mvm_set_rfkill_state(mvm); iwl_mvm_set_rfkill_state(mvm);
/* iwl_run_init_mvm_ucode is waiting for results, abort it */ /* iwl_run_init_mvm_ucode is waiting for results, abort it. */
if (calibrating) if (rfkill_safe_init_done)
iwl_abort_notification_waits(&mvm->notif_wait); iwl_abort_notification_waits(&mvm->notif_wait);
/*
* Don't ask the transport to stop the firmware. We'll do it
* after cfg80211 takes us down.
*/
if (unified)
return false;
/* /*
* Stop the device if we run OPERATIONAL firmware or if we are in the * Stop the device if we run OPERATIONAL firmware or if we are in the
* middle of the calibrations. * middle of the calibrations.
*/ */
return state && (mvm->fwrt.cur_fw_img != IWL_UCODE_INIT || calibrating); return state && (mvm->fwrt.cur_fw_img != IWL_UCODE_INIT ||
rfkill_safe_init_done);
} }
static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb) static void iwl_mvm_free_skb(struct iwl_op_mode *op_mode, struct sk_buff *skb)
......
...@@ -928,7 +928,7 @@ static inline void iwl_enable_rfkill_int(struct iwl_trans *trans) ...@@ -928,7 +928,7 @@ static inline void iwl_enable_rfkill_int(struct iwl_trans *trans)
MSIX_HW_INT_CAUSES_REG_RF_KILL); MSIX_HW_INT_CAUSES_REG_RF_KILL);
} }
if (trans->cfg->device_family == IWL_DEVICE_FAMILY_9000) { if (trans->cfg->device_family >= IWL_DEVICE_FAMILY_9000) {
/* /*
* On 9000-series devices this bit isn't enabled by default, so * On 9000-series devices this bit isn't enabled by default, so
* when we power down the device we need set the bit to allow it * when we power down the device we need set the bit to allow it
......
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