iwlwifi: mvm: retry init flow if failed
In some very rare cases the init flow may fail. In many cases, this is recoverable, so we can retry. Implement a loop to retry two more times after the first attempt failed. This can happen in two different situations, namely during probe and during mac80211 start. For the first case, a simple loop is enough. For the second case, we need to add a flag to prevent mac80211 from trying to restart it as well, leaving full control with the driver. Cc: <stable@vger.kernel.org> Signed-off-by: Mordechay Goodstein <mordechay.goodstein@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.20211110150132.57514296ecab.I52a0411774b700bdc7dedb124d8b59bf99456eb2@changeid
This commit is contained in:
		
							parent
							
								
									1b54403c9c
								
							
						
					
					
						commit
						5283dd677e
					
				| @ -1313,23 +1313,31 @@ _iwl_op_mode_start(struct iwl_drv *drv, struct iwlwifi_opmode_table *op) | ||||
| 	const struct iwl_op_mode_ops *ops = op->ops; | ||||
| 	struct dentry *dbgfs_dir = NULL; | ||||
| 	struct iwl_op_mode *op_mode = NULL; | ||||
| 	int retry, max_retry = !!iwlwifi_mod_params.fw_restart * IWL_MAX_INIT_RETRY; | ||||
| 
 | ||||
| 	for (retry = 0; retry <= max_retry; retry++) { | ||||
| 
 | ||||
| #ifdef CONFIG_IWLWIFI_DEBUGFS | ||||
| 	drv->dbgfs_op_mode = debugfs_create_dir(op->name, | ||||
| 						drv->dbgfs_drv); | ||||
| 	dbgfs_dir = drv->dbgfs_op_mode; | ||||
| 		drv->dbgfs_op_mode = debugfs_create_dir(op->name, | ||||
| 							drv->dbgfs_drv); | ||||
| 		dbgfs_dir = drv->dbgfs_op_mode; | ||||
| #endif | ||||
| 
 | ||||
| 	op_mode = ops->start(drv->trans, drv->trans->cfg, &drv->fw, dbgfs_dir); | ||||
| 		op_mode = ops->start(drv->trans, drv->trans->cfg, | ||||
| 				     &drv->fw, dbgfs_dir); | ||||
| 
 | ||||
| 		if (op_mode) | ||||
| 			return op_mode; | ||||
| 
 | ||||
| 		IWL_ERR(drv, "retry init count %d\n", retry); | ||||
| 
 | ||||
| #ifdef CONFIG_IWLWIFI_DEBUGFS | ||||
| 	if (!op_mode) { | ||||
| 		debugfs_remove_recursive(drv->dbgfs_op_mode); | ||||
| 		drv->dbgfs_op_mode = NULL; | ||||
| 	} | ||||
| #endif | ||||
| 	} | ||||
| 
 | ||||
| 	return op_mode; | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| static void _iwl_op_mode_stop(struct iwl_drv *drv) | ||||
|  | ||||
| @ -89,4 +89,7 @@ void iwl_drv_stop(struct iwl_drv *drv); | ||||
| #define IWL_EXPORT_SYMBOL(sym) | ||||
| #endif | ||||
| 
 | ||||
| /* max retry for init flow */ | ||||
| #define IWL_MAX_INIT_RETRY 2 | ||||
| 
 | ||||
| #endif /* __iwl_drv_h__ */ | ||||
|  | ||||
| @ -16,6 +16,7 @@ | ||||
| #include <net/ieee80211_radiotap.h> | ||||
| #include <net/tcp.h> | ||||
| 
 | ||||
| #include "iwl-drv.h" | ||||
| #include "iwl-op-mode.h" | ||||
| #include "iwl-io.h" | ||||
| #include "mvm.h" | ||||
| @ -1117,9 +1118,30 @@ static int iwl_mvm_mac_start(struct ieee80211_hw *hw) | ||||
| { | ||||
| 	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | ||||
| 	int ret; | ||||
| 	int retry, max_retry = 0; | ||||
| 
 | ||||
| 	mutex_lock(&mvm->mutex); | ||||
| 	ret = __iwl_mvm_mac_start(mvm); | ||||
| 
 | ||||
| 	/* we are starting the mac not in error flow, and restart is enabled */ | ||||
| 	if (!test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status) && | ||||
| 	    iwlwifi_mod_params.fw_restart) { | ||||
| 		max_retry = IWL_MAX_INIT_RETRY; | ||||
| 		/*
 | ||||
| 		 * This will prevent mac80211 recovery flows to trigger during | ||||
| 		 * init failures | ||||
| 		 */ | ||||
| 		set_bit(IWL_MVM_STATUS_STARTING, &mvm->status); | ||||
| 	} | ||||
| 
 | ||||
| 	for (retry = 0; retry <= max_retry; retry++) { | ||||
| 		ret = __iwl_mvm_mac_start(mvm); | ||||
| 		if (!ret) | ||||
| 			break; | ||||
| 
 | ||||
| 		IWL_ERR(mvm, "mac start retry %d\n", retry); | ||||
| 	} | ||||
| 	clear_bit(IWL_MVM_STATUS_STARTING, &mvm->status); | ||||
| 
 | ||||
| 	mutex_unlock(&mvm->mutex); | ||||
| 
 | ||||
| 	return ret; | ||||
|  | ||||
| @ -1123,6 +1123,8 @@ struct iwl_mvm { | ||||
|  * @IWL_MVM_STATUS_FIRMWARE_RUNNING: firmware is running | ||||
|  * @IWL_MVM_STATUS_NEED_FLUSH_P2P: need to flush P2P bcast STA | ||||
|  * @IWL_MVM_STATUS_IN_D3: in D3 (or at least about to go into it) | ||||
|  * @IWL_MVM_STATUS_STARTING: starting mac, | ||||
|  *	used to disable restart flow while in STARTING state | ||||
|  */ | ||||
| enum iwl_mvm_status { | ||||
| 	IWL_MVM_STATUS_HW_RFKILL, | ||||
| @ -1134,6 +1136,7 @@ enum iwl_mvm_status { | ||||
| 	IWL_MVM_STATUS_FIRMWARE_RUNNING, | ||||
| 	IWL_MVM_STATUS_NEED_FLUSH_P2P, | ||||
| 	IWL_MVM_STATUS_IN_D3, | ||||
| 	IWL_MVM_STATUS_STARTING, | ||||
| }; | ||||
| 
 | ||||
| /* Keep track of completed init configuration */ | ||||
|  | ||||
| @ -1600,6 +1600,9 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error) | ||||
| 	 */ | ||||
| 	if (!mvm->fw_restart && fw_error) { | ||||
| 		iwl_fw_error_collect(&mvm->fwrt, false); | ||||
| 	} else if (test_bit(IWL_MVM_STATUS_STARTING, | ||||
| 			    &mvm->status)) { | ||||
| 		IWL_ERR(mvm, "Starting mac, retry will be triggered anyway\n"); | ||||
| 	} else if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) { | ||||
| 		struct iwl_mvm_reprobe *reprobe; | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user