diff options
| author | Linux Build Service Account <lnxbuild@localhost> | 2019-03-26 07:12:50 -0700 |
|---|---|---|
| committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2019-03-26 07:12:49 -0700 |
| commit | 6a53afbc7e9d19c219064cd703a0bd757fb6a4a4 (patch) | |
| tree | e09cb4d34cbea2d5a03f87095a913ef48b967c73 | |
| parent | 9ccdcef08733fd335433167841fa631127adadc3 (diff) | |
| parent | 1174076aa273369f86d2d46ad679dc0862c80db8 (diff) | |
Merge "icnss: Defer modem graceful shutdown until probe complete"
| -rw-r--r-- | drivers/soc/qcom/icnss.c | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 8ada7af7fb79..fcfb649aedee 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -75,6 +75,8 @@ module_param(qmi_timeout, ulong, 0600); #define ICNSS_MAX_PROBE_CNT 2 +#define PROBE_TIMEOUT 5000 + #define icnss_ipc_log_string(_x...) do { \ if (icnss_ipc_log_context) \ ipc_log_string(icnss_ipc_log_context, _x); \ @@ -299,6 +301,7 @@ enum icnss_driver_state { ICNSS_FW_DOWN, ICNSS_DRIVER_UNLOADING, ICNSS_REJUVENATE, + ICNSS_DRIVER_LOADING, }; struct ce_irq_list { @@ -491,6 +494,7 @@ static struct icnss_priv { u8 requesting_sub_system; u16 line_number; char function_name[QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1]; + struct completion driver_probed; } *penv; #ifdef CONFIG_ICNSS_DEBUG @@ -2203,6 +2207,8 @@ static int icnss_call_driver_probe(struct icnss_priv *priv) icnss_hw_power_on(priv); + set_bit(ICNSS_DRIVER_LOADING, &priv->state); + reinit_completion(&penv->driver_probed); while (probe_cnt < ICNSS_MAX_PROBE_CNT) { ret = priv->ops->probe(&priv->pdev->dev); probe_cnt++; @@ -2212,9 +2218,13 @@ static int icnss_call_driver_probe(struct icnss_priv *priv) if (ret < 0) { icnss_pr_err("Driver probe failed: %d, state: 0x%lx, probe_cnt: %d\n", ret, priv->state, probe_cnt); + complete(&penv->driver_probed); + clear_bit(ICNSS_DRIVER_LOADING, &penv->state); goto out; } + complete(&penv->driver_probed); + clear_bit(ICNSS_DRIVER_LOADING, &penv->state); set_bit(ICNSS_DRIVER_PROBED, &priv->state); return 0; @@ -2350,6 +2360,8 @@ static int icnss_driver_event_register_driver(void *data) if (ret) goto out; + set_bit(ICNSS_DRIVER_LOADING, &penv->state); + reinit_completion(&penv->driver_probed); while (probe_cnt < ICNSS_MAX_PROBE_CNT) { ret = penv->ops->probe(&penv->pdev->dev); probe_cnt++; @@ -2359,9 +2371,13 @@ static int icnss_driver_event_register_driver(void *data) if (ret) { icnss_pr_err("Driver probe failed: %d, state: 0x%lx, probe_cnt: %d\n", ret, penv->state, probe_cnt); + clear_bit(ICNSS_DRIVER_LOADING, &penv->state); + complete(&penv->driver_probed); goto power_off; } + complete(&penv->driver_probed); + clear_bit(ICNSS_DRIVER_LOADING, &penv->state); set_bit(ICNSS_DRIVER_PROBED, &penv->state); return 0; @@ -2584,6 +2600,13 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, if (code != SUBSYS_BEFORE_SHUTDOWN) return NOTIFY_OK; + if (code == SUBSYS_BEFORE_SHUTDOWN && !notif->crashed && + test_bit(ICNSS_DRIVER_LOADING, &priv->state)) { + if (!wait_for_completion_timeout(&priv->driver_probed, + PROBE_TIMEOUT)) + icnss_pr_err("wlan driver probe timeout\n"); + } + if (code == SUBSYS_BEFORE_SHUTDOWN && !notif->crashed) { ret = wlfw_send_modem_shutdown_msg(); if (ret) @@ -3981,6 +4004,9 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv) continue; case ICNSS_DRIVER_UNLOADING: seq_puts(s, "DRIVER UNLOADING"); + continue; + case ICNSS_DRIVER_LOADING: + seq_puts(s, "WLAN DRIVER LOADING"); } seq_printf(s, "UNKNOWN-%d", i); @@ -4652,6 +4678,8 @@ static int icnss_probe(struct platform_device *pdev) penv = priv; + init_completion(&priv->driver_probed); + icnss_pr_info("Platform driver probed successfully\n"); return 0; @@ -4674,6 +4702,8 @@ static int icnss_remove(struct platform_device *pdev) icnss_debugfs_destroy(penv); + complete_all(&penv->driver_probed); + icnss_modem_ssr_unregister_notifier(penv); destroy_ramdump_device(penv->msa0_dump_dev); |
