diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 6f9e46c430fb..165a17491b00 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -288,7 +288,7 @@ enum icnss_driver_state { ICNSS_DRIVER_UNLOADING, ICNSS_REJUVENATE, ICNSS_MODE_ON, - ICNSS_DRIVER_LOADING, + ICNSS_BLOCK_SHUTDOWN, }; struct ce_irq_list { @@ -478,7 +478,7 @@ static struct icnss_priv { struct mutex dev_lock; uint32_t fw_error_fatal_irq; uint32_t fw_early_crash_irq; - struct completion driver_probed; + struct completion unblock_shutdown; } *penv; #ifdef CONFIG_ICNSS_DEBUG @@ -1168,6 +1168,21 @@ bool icnss_is_fw_ready(void) } EXPORT_SYMBOL(icnss_is_fw_ready); +void icnss_block_shutdown(bool status) +{ + if (!penv) + return; + + if (status) { + set_bit(ICNSS_BLOCK_SHUTDOWN, &penv->state); + reinit_completion(&penv->unblock_shutdown); + } else { + clear_bit(ICNSS_BLOCK_SHUTDOWN, &penv->state); + complete(&penv->unblock_shutdown); + } +} +EXPORT_SYMBOL(icnss_block_shutdown); + bool icnss_is_fw_down(void) { if (!penv) @@ -2261,8 +2276,7 @@ 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); + icnss_block_shutdown(true); while (probe_cnt < ICNSS_MAX_PROBE_CNT) { ret = priv->ops->probe(&priv->pdev->dev); probe_cnt++; @@ -2272,13 +2286,11 @@ 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); + icnss_block_shutdown(false); goto out; } - complete(&penv->driver_probed); - clear_bit(ICNSS_DRIVER_LOADING, &penv->state); + icnss_block_shutdown(false); set_bit(ICNSS_DRIVER_PROBED, &priv->state); return 0; @@ -2417,8 +2429,7 @@ 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); + icnss_block_shutdown(true); while (probe_cnt < ICNSS_MAX_PROBE_CNT) { ret = penv->ops->probe(&penv->pdev->dev); probe_cnt++; @@ -2428,13 +2439,11 @@ 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); + icnss_block_shutdown(false); goto power_off; } - complete(&penv->driver_probed); - clear_bit(ICNSS_DRIVER_LOADING, &penv->state); + icnss_block_shutdown(false); set_bit(ICNSS_DRIVER_PROBED, &penv->state); return 0; @@ -2703,8 +2712,8 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, 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, + test_bit(ICNSS_BLOCK_SHUTDOWN, &priv->state)) { + if (!wait_for_completion_timeout(&priv->unblock_shutdown, PROBE_TIMEOUT)) icnss_pr_err("wlan driver probe timeout\n"); } @@ -4075,8 +4084,8 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv) case ICNSS_MODE_ON: seq_puts(s, "MODE ON DONE"); continue; - case ICNSS_DRIVER_LOADING: - seq_puts(s, "WLAN DRIVER LOADING"); + case ICNSS_BLOCK_SHUTDOWN: + seq_puts(s, "BLOCK SHUTDOWN"); } seq_printf(s, "UNKNOWN-%d", i); @@ -4748,7 +4757,7 @@ static int icnss_probe(struct platform_device *pdev) penv = priv; - init_completion(&priv->driver_probed); + init_completion(&priv->unblock_shutdown); icnss_pr_info("Platform driver probed successfully\n"); @@ -4772,7 +4781,7 @@ static int icnss_remove(struct platform_device *pdev) icnss_debugfs_destroy(penv); - complete_all(&penv->driver_probed); + complete_all(&penv->unblock_shutdown); icnss_modem_ssr_unregister_notifier(penv); diff --git a/include/soc/qcom/icnss.h b/include/soc/qcom/icnss.h index 7ef3db418100..0732a6fd33d1 100644 --- a/include/soc/qcom/icnss.h +++ b/include/soc/qcom/icnss.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2015-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -144,4 +144,5 @@ extern bool icnss_is_fw_ready(void); extern bool icnss_is_fw_down(void); extern bool icnss_is_rejuvenate(void); extern int icnss_trigger_recovery(struct device *dev); +extern void icnss_block_shutdown(bool status); #endif /* _ICNSS_WLAN_H_ */