Commit a4082843 authored by Arik Nemtsov's avatar Arik Nemtsov Committed by Emmanuel Grumbach

iwlwifi: trans: divide stop_hw into stop_device/op_mode_leave

The stop_hw trans callback is not well defined. It is missing in many
cleanup flows and the division of labor between stop_device/stop_hw
is cumbersome. Remove stop_hw and use stop_device to perform both.
Implement this for all current transports.

PCIE needs some extra configuration the op-mode is leaving to configure
RF kill. Expose this explicitly as a new op_mode_leave trans callback.
Take the call to stop_device outside iwl_run_mvm_init_ucode, this
makes more sense and WARN when we want to run the INIT firmware while
it has run already.
Signed-off-by: default avatarArik Nemtsov <arik@wizery.com>
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
parent 8b206d19
...@@ -322,12 +322,6 @@ static void iwlagn_mac_stop(struct ieee80211_hw *hw) ...@@ -322,12 +322,6 @@ static void iwlagn_mac_stop(struct ieee80211_hw *hw)
flush_workqueue(priv->workqueue); flush_workqueue(priv->workqueue);
/* User space software may expect getting rfkill changes
* even if interface is down, trans->down will leave the RF
* kill interrupt enabled
*/
iwl_trans_stop_hw(priv->trans, false);
IWL_DEBUG_MAC80211(priv, "leave\n"); IWL_DEBUG_MAC80211(priv, "leave\n");
} }
......
...@@ -1313,7 +1313,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, ...@@ -1313,7 +1313,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
} }
/* Reset chip to save power until we load uCode during "up". */ /* Reset chip to save power until we load uCode during "up". */
iwl_trans_stop_hw(priv->trans, false); iwl_trans_stop_device(priv->trans);
priv->nvm_data = iwl_parse_eeprom_data(priv->trans->dev, priv->cfg, priv->nvm_data = iwl_parse_eeprom_data(priv->trans->dev, priv->cfg,
priv->eeprom_blob, priv->eeprom_blob,
...@@ -1458,7 +1458,7 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode) ...@@ -1458,7 +1458,7 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
dev_kfree_skb(priv->beacon_skb); dev_kfree_skb(priv->beacon_skb);
iwl_trans_stop_hw(priv->trans, true); iwl_trans_op_mode_leave(priv->trans);
ieee80211_free_hw(priv->hw); ieee80211_free_hw(priv->hw);
} }
......
...@@ -100,8 +100,7 @@ ...@@ -100,8 +100,7 @@
* start_fw * start_fw
* *
* 5) Then when finished (or reset): * 5) Then when finished (or reset):
* stop_fw (a.k.a. stop device for the moment) * stop_device
* stop_hw
* *
* 6) Eventually, the free function will be called. * 6) Eventually, the free function will be called.
*/ */
...@@ -361,9 +360,7 @@ struct iwl_trans; ...@@ -361,9 +360,7 @@ struct iwl_trans;
* *
* @start_hw: starts the HW- from that point on, the HW can send interrupts * @start_hw: starts the HW- from that point on, the HW can send interrupts
* May sleep * May sleep
* @stop_hw: stops the HW- from that point on, the HW will be in low power but * @op_mode_leave: Turn off the HW RF kill indication if on
* will still issue interrupt if the HW RF kill is triggered unless
* op_mode_leaving is true.
* May sleep * May sleep
* @start_fw: allocates and inits all the resources for the transport * @start_fw: allocates and inits all the resources for the transport
* layer. Also kick a fw image. * layer. Also kick a fw image.
...@@ -371,8 +368,11 @@ struct iwl_trans; ...@@ -371,8 +368,11 @@ struct iwl_trans;
* @fw_alive: called when the fw sends alive notification. If the fw provides * @fw_alive: called when the fw sends alive notification. If the fw provides
* the SCD base address in SRAM, then provide it here, or 0 otherwise. * the SCD base address in SRAM, then provide it here, or 0 otherwise.
* May sleep * May sleep
* @stop_device:stops the whole device (embedded CPU put to reset) * @stop_device: stops the whole device (embedded CPU put to reset) and stops
* May sleep * the HW. From that point on, the HW will be in low power but will still
* issue interrupt if the HW RF kill is triggered. This callback must do
* the right thing and not crash even if start_hw() was called but not
* start_fw(). May sleep
* @d3_suspend: put the device into the correct mode for WoWLAN during * @d3_suspend: put the device into the correct mode for WoWLAN during
* suspend. This is optional, if not implemented WoWLAN will not be * suspend. This is optional, if not implemented WoWLAN will not be
* supported. This callback may sleep. * supported. This callback may sleep.
...@@ -418,7 +418,7 @@ struct iwl_trans; ...@@ -418,7 +418,7 @@ struct iwl_trans;
struct iwl_trans_ops { struct iwl_trans_ops {
int (*start_hw)(struct iwl_trans *iwl_trans); int (*start_hw)(struct iwl_trans *iwl_trans);
void (*stop_hw)(struct iwl_trans *iwl_trans, bool op_mode_leaving); void (*op_mode_leave)(struct iwl_trans *iwl_trans);
int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw, int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw,
bool run_in_rfkill); bool run_in_rfkill);
void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr); void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);
...@@ -540,15 +540,14 @@ static inline int iwl_trans_start_hw(struct iwl_trans *trans) ...@@ -540,15 +540,14 @@ static inline int iwl_trans_start_hw(struct iwl_trans *trans)
return trans->ops->start_hw(trans); return trans->ops->start_hw(trans);
} }
static inline void iwl_trans_stop_hw(struct iwl_trans *trans, static inline void iwl_trans_op_mode_leave(struct iwl_trans *trans)
bool op_mode_leaving)
{ {
might_sleep(); might_sleep();
trans->ops->stop_hw(trans, op_mode_leaving); if (trans->ops->op_mode_leave)
trans->ops->op_mode_leave(trans);
if (op_mode_leaving) trans->op_mode = NULL;
trans->op_mode = NULL;
trans->state = IWL_TRANS_NO_FW; trans->state = IWL_TRANS_NO_FW;
} }
......
...@@ -241,7 +241,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) ...@@ -241,7 +241,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 (mvm->init_ucode_complete) if (WARN_ON_ONCE(mvm->init_ucode_complete))
return 0; return 0;
iwl_init_notification_wait(&mvm->notif_wait, iwl_init_notification_wait(&mvm->notif_wait,
...@@ -287,7 +287,8 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) ...@@ -287,7 +287,8 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
IWL_DEBUG_RF_KILL(mvm, IWL_DEBUG_RF_KILL(mvm,
"jump over all phy activities due to RF kill\n"); "jump over all phy activities due to RF kill\n");
iwl_remove_notification(&mvm->notif_wait, &calib_wait); iwl_remove_notification(&mvm->notif_wait, &calib_wait);
return 1; ret = 1;
goto out;
} }
/* Send TX valid antennas before triggering calibrations */ /* Send TX valid antennas before triggering calibrations */
...@@ -319,9 +320,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm) ...@@ -319,9 +320,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
error: error:
iwl_remove_notification(&mvm->notif_wait, &calib_wait); iwl_remove_notification(&mvm->notif_wait, &calib_wait);
out: out:
if (!iwlmvm_mod_params.init_dbg) { if (iwlmvm_mod_params.init_dbg && !mvm->nvm_data) {
iwl_trans_stop_device(mvm->trans);
} else if (!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) +
sizeof(struct ieee80211_channel) + sizeof(struct ieee80211_channel) +
...@@ -370,11 +369,16 @@ int iwl_mvm_up(struct iwl_mvm *mvm) ...@@ -370,11 +369,16 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
ret = -ERFKILL; ret = -ERFKILL;
goto error; goto error;
} }
/* should stop & start HW since that INIT image just loaded */ if (!iwlmvm_mod_params.init_dbg) {
iwl_trans_stop_hw(mvm->trans, false); /*
ret = iwl_trans_start_hw(mvm->trans); * should stop and start HW since that INIT
if (ret) * image just loaded
return ret; */
iwl_trans_stop_device(mvm->trans);
ret = iwl_trans_start_hw(mvm->trans);
if (ret)
return ret;
}
} }
if (iwlmvm_mod_params.init_dbg) if (iwlmvm_mod_params.init_dbg)
......
...@@ -405,7 +405,6 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac, ...@@ -405,7 +405,6 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
{ {
iwl_trans_stop_device(mvm->trans); iwl_trans_stop_device(mvm->trans);
iwl_trans_stop_hw(mvm->trans, false);
mvm->scan_status = IWL_MVM_SCAN_NONE; mvm->scan_status = IWL_MVM_SCAN_NONE;
...@@ -477,7 +476,6 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) ...@@ -477,7 +476,6 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
cancel_work_sync(&mvm->roc_done_wk); cancel_work_sync(&mvm->roc_done_wk);
iwl_trans_stop_device(mvm->trans); iwl_trans_stop_device(mvm->trans);
iwl_trans_stop_hw(mvm->trans, false);
iwl_mvm_async_handlers_purge(mvm); iwl_mvm_async_handlers_purge(mvm);
/* async_handlers_list is empty and will stay empty: HW is stopped */ /* async_handlers_list is empty and will stay empty: HW is stopped */
......
...@@ -436,16 +436,13 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, ...@@ -436,16 +436,13 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
mutex_lock(&mvm->mutex); mutex_lock(&mvm->mutex);
err = iwl_run_init_mvm_ucode(mvm, true); err = iwl_run_init_mvm_ucode(mvm, true);
iwl_trans_stop_device(trans);
mutex_unlock(&mvm->mutex); mutex_unlock(&mvm->mutex);
/* returns 0 if successful, 1 if success but in rfkill */ /* returns 0 if successful, 1 if success but in rfkill */
if (err < 0 && !iwlmvm_mod_params.init_dbg) { if (err < 0 && !iwlmvm_mod_params.init_dbg) {
IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err); IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", err);
goto out_free; goto out_free;
} }
/* Stop the hw after the ALIVE and NVM has been read */
if (!iwlmvm_mod_params.init_dbg)
iwl_trans_stop_hw(mvm->trans, false);
} }
scan_size = sizeof(struct iwl_scan_cmd) + scan_size = sizeof(struct iwl_scan_cmd) +
...@@ -478,7 +475,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, ...@@ -478,7 +475,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
iwl_phy_db_free(mvm->phy_db); iwl_phy_db_free(mvm->phy_db);
kfree(mvm->scan_cmd); kfree(mvm->scan_cmd);
if (!iwlwifi_mod_params.nvm_file) if (!iwlwifi_mod_params.nvm_file)
iwl_trans_stop_hw(trans, true); iwl_trans_op_mode_leave(trans);
ieee80211_free_hw(mvm->hw); ieee80211_free_hw(mvm->hw);
return NULL; return NULL;
} }
...@@ -502,7 +499,7 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode) ...@@ -502,7 +499,7 @@ static void iwl_op_mode_mvm_stop(struct iwl_op_mode *op_mode)
kfree(mvm->d3_resume_sram); kfree(mvm->d3_resume_sram);
#endif #endif
iwl_trans_stop_hw(mvm->trans, true); iwl_trans_op_mode_leave(mvm->trans);
iwl_phy_db_free(mvm->phy_db); iwl_phy_db_free(mvm->phy_db);
mvm->phy_db = NULL; mvm->phy_db = NULL;
......
...@@ -340,7 +340,7 @@ static void check_exit_ctkill(struct work_struct *work) ...@@ -340,7 +340,7 @@ static void check_exit_ctkill(struct work_struct *work)
iwl_trans_start_hw(mvm->trans); iwl_trans_start_hw(mvm->trans);
temp = check_nic_temperature(mvm); temp = check_nic_temperature(mvm);
iwl_trans_stop_hw(mvm->trans, false); iwl_trans_stop_device(mvm->trans);
if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) { if (temp < MIN_TEMPERATURE || temp > MAX_TEMPERATURE) {
IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n"); IWL_DEBUG_TEMP(mvm, "Failed to measure NIC temperature\n");
......
...@@ -641,6 +641,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) ...@@ -641,6 +641,7 @@ static void iwl_trans_pcie_stop_device(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);
unsigned long flags; unsigned long flags;
bool hw_rfkill;
/* tell the device to stop sending interrupts */ /* tell the device to stop sending interrupts */
spin_lock_irqsave(&trans_pcie->irq_lock, flags); spin_lock_irqsave(&trans_pcie->irq_lock, flags);
...@@ -681,8 +682,6 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) ...@@ -681,8 +682,6 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
iwl_disable_interrupts(trans); iwl_disable_interrupts(trans);
spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
iwl_enable_rfkill_int(trans);
/* stop and reset the on-board processor */ /* stop and reset the on-board processor */
iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
...@@ -692,6 +691,25 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) ...@@ -692,6 +691,25 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status); clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status); clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status);
clear_bit(STATUS_RFKILL, &trans_pcie->status); clear_bit(STATUS_RFKILL, &trans_pcie->status);
/*
* Even if we stop the HW, we still want the RF kill
* interrupt
*/
iwl_enable_rfkill_int(trans);
/*
* Check again since the RF kill state may have changed while
* all the interrupts were disabled, in this case we couldn't
* receive the RF kill interrupt and update the state in the
* op_mode.
*/
hw_rfkill = iwl_is_rfkill_set(trans);
if (hw_rfkill)
set_bit(STATUS_RFKILL, &trans_pcie->status);
else
clear_bit(STATUS_RFKILL, &trans_pcie->status);
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
} }
static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test) static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test)
...@@ -806,13 +824,12 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) ...@@ -806,13 +824,12 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
return 0; return 0;
} }
static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans, static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans)
bool op_mode_leaving)
{ {
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
bool hw_rfkill;
unsigned long flags; unsigned long flags;
/* disable interrupts - don't enable HW RF kill interrupt */
spin_lock_irqsave(&trans_pcie->irq_lock, flags); spin_lock_irqsave(&trans_pcie->irq_lock, flags);
iwl_disable_interrupts(trans); iwl_disable_interrupts(trans);
spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
...@@ -824,27 +841,6 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans, ...@@ -824,27 +841,6 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
iwl_pcie_disable_ict(trans); iwl_pcie_disable_ict(trans);
if (!op_mode_leaving) {
/*
* Even if we stop the HW, we still want the RF kill
* interrupt
*/
iwl_enable_rfkill_int(trans);
/*
* Check again since the RF kill state may have changed while
* all the interrupts were disabled, in this case we couldn't
* receive the RF kill interrupt and update the state in the
* op_mode.
*/
hw_rfkill = iwl_is_rfkill_set(trans);
if (hw_rfkill)
set_bit(STATUS_RFKILL, &trans_pcie->status);
else
clear_bit(STATUS_RFKILL, &trans_pcie->status);
iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
}
} }
static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val) static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val)
...@@ -1457,7 +1453,7 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans, ...@@ -1457,7 +1453,7 @@ static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
static const struct iwl_trans_ops trans_ops_pcie = { static const struct iwl_trans_ops trans_ops_pcie = {
.start_hw = iwl_trans_pcie_start_hw, .start_hw = iwl_trans_pcie_start_hw,
.stop_hw = iwl_trans_pcie_stop_hw, .op_mode_leave = iwl_trans_pcie_op_mode_leave,
.fw_alive = iwl_trans_pcie_fw_alive, .fw_alive = iwl_trans_pcie_fw_alive,
.start_fw = iwl_trans_pcie_start_fw, .start_fw = iwl_trans_pcie_start_fw,
.stop_device = iwl_trans_pcie_stop_device, .stop_device = iwl_trans_pcie_stop_device,
......
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