summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2019-03-26 07:12:50 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2019-03-26 07:12:49 -0700
commit6a53afbc7e9d19c219064cd703a0bd757fb6a4a4 (patch)
treee09cb4d34cbea2d5a03f87095a913ef48b967c73
parent9ccdcef08733fd335433167841fa631127adadc3 (diff)
parent1174076aa273369f86d2d46ad679dc0862c80db8 (diff)
Merge "icnss: Defer modem graceful shutdown until probe complete"
-rw-r--r--drivers/soc/qcom/icnss.c30
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);