From cd7f41586760004dbf0029a3112faceba75c2a11 Mon Sep 17 00:00:00 2001 From: Manikandan Mohan Date: Tue, 18 Aug 2020 15:24:32 -0700 Subject: [PATCH] cnss2: Wait for power up complete during SSR restart Update SSR power up function to wait for FW recovery complete to avoid race condition with linux PM sleep entry. Change-Id: Ief0d64e7699956ba30f2ff84732e36f6b2fdc3b0 Signed-off-by: Manikandan Mohan --- drivers/net/wireless/cnss2/main.c | 27 ++++++++++++++++++++++++--- drivers/net/wireless/cnss2/main.h | 1 + drivers/net/wireless/cnss2/pci.c | 8 +++++--- 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/cnss2/main.c b/drivers/net/wireless/cnss2/main.c index aec49bf1478b..a451d106b03a 100644 --- a/drivers/net/wireless/cnss2/main.c +++ b/drivers/net/wireless/cnss2/main.c @@ -895,6 +895,7 @@ static inline void cnss_unregister_esoc(struct cnss_plat_data *plat_priv) {} static int cnss_subsys_powerup(const struct subsys_desc *subsys_desc) { struct cnss_plat_data *plat_priv; + int ret = 0; if (!subsys_desc->dev) { cnss_pr_err("dev from subsys_desc is NULL\n"); @@ -912,7 +913,10 @@ static int cnss_subsys_powerup(const struct subsys_desc *subsys_desc) return 0; } - return cnss_bus_dev_powerup(plat_priv); + ret = cnss_bus_dev_powerup(plat_priv); + if (ret) + __pm_relax(plat_priv->recovery_ws); + return ret; } static int cnss_subsys_shutdown(const struct subsys_desc *subsys_desc, @@ -998,7 +1002,11 @@ static void cnss_recovery_work_handler(struct work_struct *work) cnss_bus_dev_shutdown(plat_priv); msleep(RECOVERY_DELAY_MS); - cnss_bus_dev_powerup(plat_priv); + + ret = cnss_bus_dev_powerup(plat_priv); + if (ret) + __pm_relax(plat_priv->recovery_ws); + return; } void cnss_device_crashed(struct device *dev) @@ -1058,6 +1066,14 @@ static int cnss_do_recovery(struct cnss_plat_data *plat_priv, return 0; } + /* FW recovery sequence has multiple steps and firmware load requires + * linux PM in awake state. Thus hold the cnss wake source until + * WLAN MISSION enabled. + */ + pm_wakeup_ws_event(plat_priv->recovery_ws, RECOVERY_TIMEOUT + + cnss_get_boot_timeout(NULL), + true); + switch (reason) { case CNSS_REASON_LINK_DOWN: if (!cnss_bus_check_link_status(plat_priv)) { @@ -1079,7 +1095,6 @@ static int cnss_do_recovery(struct cnss_plat_data *plat_priv, cnss_recovery_reason_to_str(reason), reason); break; } - cnss_bus_device_crashed(plat_priv); return 0; @@ -2358,6 +2373,11 @@ static int cnss_misc_init(struct cnss_plat_data *plat_priv) init_completion(&plat_priv->recovery_complete); mutex_init(&plat_priv->dev_lock); mutex_init(&plat_priv->driver_ops_lock); + plat_priv->recovery_ws = + wakeup_source_register(&plat_priv->plat_dev->dev, + "CNSS_FW_RECOVERY"); + if (!plat_priv->recovery_ws) + cnss_pr_err("Failed to setup FW recovery wake source\n"); return 0; } @@ -2372,6 +2392,7 @@ static void cnss_misc_deinit(struct cnss_plat_data *plat_priv) unregister_reboot_notifier(&plat_priv->reboot_nb); unregister_pm_notifier(&cnss_pm_notifier); del_timer(&plat_priv->fw_boot_timer); + wakeup_source_unregister(plat_priv->recovery_ws); } static void cnss_init_control_params(struct cnss_plat_data *plat_priv) diff --git a/drivers/net/wireless/cnss2/main.h b/drivers/net/wireless/cnss2/main.h index fef2466fb3a8..1ebe33c1e79d 100644 --- a/drivers/net/wireless/cnss2/main.h +++ b/drivers/net/wireless/cnss2/main.h @@ -411,6 +411,7 @@ struct cnss_plat_data { struct qmi_handle coex_qmi; struct qmi_handle ims_qmi; struct qmi_txn txn; + struct wakeup_source *recovery_ws; u64 dynamic_feature; void *get_info_cb_ctx; int (*get_info_cb)(void *ctx, void *event, int event_len); diff --git a/drivers/net/wireless/cnss2/pci.c b/drivers/net/wireless/cnss2/pci.c index cba709e316e1..994fefe33f7b 100644 --- a/drivers/net/wireless/cnss2/pci.c +++ b/drivers/net/wireless/cnss2/pci.c @@ -1443,7 +1443,6 @@ int cnss_pci_call_driver_probe(struct cnss_pci_data *pci_priv) ret); goto out; } - clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state); complete(&plat_priv->recovery_complete); } else if (test_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state)) { ret = pci_priv->driver_ops->probe(pci_priv->pci_dev, @@ -1453,7 +1452,6 @@ int cnss_pci_call_driver_probe(struct cnss_pci_data *pci_priv) ret); goto out; } - clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state); clear_bit(CNSS_DRIVER_LOADING, &plat_priv->driver_state); set_bit(CNSS_DRIVER_PROBED, &plat_priv->driver_state); complete_all(&plat_priv->power_up_complete); @@ -1466,13 +1464,17 @@ int cnss_pci_call_driver_probe(struct cnss_pci_data *pci_priv) ret); goto out; } - clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state); clear_bit(CNSS_DRIVER_IDLE_RESTART, &plat_priv->driver_state); complete_all(&plat_priv->power_up_complete); } else { complete(&plat_priv->power_up_complete); } + if (test_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state)) { + clear_bit(CNSS_DRIVER_RECOVERY, &plat_priv->driver_state); + __pm_relax(plat_priv->recovery_ws); + } + cnss_pci_start_time_sync_update(pci_priv); return 0;