diff --git a/cnss2/main.c b/cnss2/main.c index 5240218ba9..a17cd54f39 100644 --- a/cnss2/main.c +++ b/cnss2/main.c @@ -1884,18 +1884,29 @@ static void cnss_recovery_work_handler(struct work_struct *work) { } #else -static void cnss_recovery_work_handler(struct work_struct *work) +void cnss_recovery_handler(struct cnss_plat_data *plat_priv) { int ret; - struct cnss_plat_data *plat_priv = - container_of(work, struct cnss_plat_data, recovery_work); + set_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state); if (!plat_priv->recovery_enabled) panic("subsys-restart: Resetting the SoC wlan crashed\n"); cnss_bus_dev_shutdown(plat_priv); cnss_bus_dev_ramdump(plat_priv); + + /* If recovery is triggered before Host driver registration, + * avoid device power up because eventually device will be + * power up as part of driver registration. + */ + if (!test_bit(CNSS_DRIVER_REGISTER, &plat_priv->driver_state) || + !test_bit(CNSS_DRIVER_REGISTERED, &plat_priv->driver_state)) { + cnss_pr_dbg("Host driver not registered yet, ignore Device Power Up, 0x%lx\n", + plat_priv->driver_state); + return; + } + msleep(POWER_RESET_MIN_DELAY_MS); ret = cnss_bus_dev_powerup(plat_priv); @@ -1905,6 +1916,14 @@ static void cnss_recovery_work_handler(struct work_struct *work) return; } +static void cnss_recovery_work_handler(struct work_struct *work) +{ + struct cnss_plat_data *plat_priv = + container_of(work, struct cnss_plat_data, recovery_work); + + cnss_recovery_handler(plat_priv); +} + void cnss_device_crashed(struct device *dev) { struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); @@ -2012,6 +2031,18 @@ self_recovery: clear_bit(LINK_DOWN_SELF_RECOVERY, &plat_priv->ctrl_params.quirks); + /* If link down self recovery is triggered before Host driver + * registration, avoid device power up because eventually device + * will be power up as part of driver registration. + */ + + if (!test_bit(CNSS_DRIVER_REGISTER, &plat_priv->driver_state) || + !test_bit(CNSS_DRIVER_REGISTERED, &plat_priv->driver_state)) { + cnss_pr_dbg("Host driver not registered yet, ignore Device Power Up, 0x%lx\n", + plat_priv->driver_state); + return 0; + } + cnss_bus_dev_powerup(plat_priv); return 0; diff --git a/cnss2/main.h b/cnss2/main.h index abb239819f..2758eaf1e3 100644 --- a/cnss2/main.h +++ b/cnss2/main.h @@ -717,4 +717,5 @@ int cnss_get_feature_list(struct cnss_plat_data *plat_priv, int cnss_get_input_gpio_value(struct cnss_plat_data *plat_priv, int gpio_num); bool cnss_check_driver_loading_allowed(void); int cnss_dev_specific_power_on(struct cnss_plat_data *plat_priv); +void cnss_recovery_handler(struct cnss_plat_data *plat_priv); #endif /* _CNSS_MAIN_H */ diff --git a/cnss2/pci.c b/cnss2/pci.c index bf01dab70b..86e89ea983 100644 --- a/cnss2/pci.c +++ b/cnss2/pci.c @@ -5942,7 +5942,13 @@ void cnss_pci_device_crashed(struct cnss_pci_data *pci_priv) if (plat_priv->recovery_enabled) cnss_pci_collect_host_dump_info(pci_priv); - cnss_device_crashed(&pci_priv->pci_dev->dev); + + /* Call recovery handler in the DRIVER_RECOVERY event context + * instead of scheduling work. In that way complete recovery + * will be done as part of DRIVER_RECOVERY event and get + * serialized with other events. + */ + cnss_recovery_handler(plat_priv); } static int cnss_mhi_pm_runtime_get(struct mhi_controller *mhi_ctrl)