summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorYuanyuan Liu <yuanliu@codeaurora.org>2017-12-15 16:20:37 -0800
committerYuanyuan Liu <yuanliu@codeaurora.org>2017-12-20 10:53:14 -0800
commitdaee03cd523688c19ea53052731464633723637a (patch)
tree712f1c9c7f661efab850ed9161d6148572915138 /drivers
parente1fe906b59110ddb0847f30085db84434637f045 (diff)
icnss: Do not send uevent when driver is unloading
If modem crashed during wlan driver unloading, icnss driver will call driver uevent callback to send FW down uevent when it receives BEFORE_SHUTDOWN notification. If wlan driver is de-initialized just before the callback is called, kernel will panic as driver's context is freed. This can be avoid by not sending uevent when wlan host driver is unloading. Instead, icnss driver will provide an API to host driver to check if WLAN FW is down or not. CRs-Fixed: 2161425 Change-Id: I569fd85366522606ececeda74df85c51b9b2fc28 Signed-off-by: Yuanyuan Liu <yuanliu@codeaurora.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/soc/qcom/icnss.c23
1 files changed, 21 insertions, 2 deletions
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index 1935f18c72f8..4ec3b6762cfd 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -297,6 +297,7 @@ enum icnss_driver_state {
ICNSS_SHUTDOWN_DONE,
ICNSS_HOST_TRIGGERED_PDR,
ICNSS_FW_DOWN,
+ ICNSS_DRIVER_UNLOADING,
};
struct ce_irq_list {
@@ -1167,6 +1168,16 @@ bool icnss_is_fw_ready(void)
}
EXPORT_SYMBOL(icnss_is_fw_ready);
+bool icnss_is_fw_down(void)
+{
+ if (!penv)
+ return false;
+ else
+ return test_bit(ICNSS_FW_DOWN, &penv->state);
+}
+EXPORT_SYMBOL(icnss_is_fw_down);
+
+
int icnss_power_off(struct device *dev)
{
struct icnss_priv *priv = dev_get_drvdata(dev);
@@ -2297,9 +2308,11 @@ static int icnss_driver_event_unregister_driver(void *data)
goto out;
}
+ set_bit(ICNSS_DRIVER_UNLOADING, &penv->state);
if (penv->ops)
penv->ops->remove(&penv->pdev->dev);
+ clear_bit(ICNSS_DRIVER_UNLOADING, &penv->state);
clear_bit(ICNSS_DRIVER_PROBED, &penv->state);
penv->ops = NULL;
@@ -2322,8 +2335,10 @@ static int icnss_call_driver_remove(struct icnss_priv *priv)
if (!priv->ops || !priv->ops->remove)
return 0;
+ set_bit(ICNSS_DRIVER_UNLOADING, &penv->state);
penv->ops->remove(&priv->pdev->dev);
+ clear_bit(ICNSS_DRIVER_UNLOADING, &penv->state);
clear_bit(ICNSS_DRIVER_PROBED, &priv->state);
icnss_hw_power_off(penv);
@@ -2529,7 +2544,8 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
icnss_ignore_qmi_timeout(true);
fw_down_data.crashed = !!notif->crashed;
- if (test_bit(ICNSS_FW_READY, &priv->state))
+ if (test_bit(ICNSS_FW_READY, &priv->state) &&
+ !test_bit(ICNSS_DRIVER_UNLOADING, &priv->state))
icnss_call_driver_uevent(priv,
ICNSS_UEVENT_FW_DOWN,
&fw_down_data);
@@ -2673,7 +2689,8 @@ event_post:
icnss_ignore_qmi_timeout(true);
fw_down_data.crashed = event_data->crashed;
- if (test_bit(ICNSS_FW_READY, &priv->state))
+ if (test_bit(ICNSS_FW_READY, &priv->state) &&
+ !test_bit(ICNSS_DRIVER_UNLOADING, &priv->state))
icnss_call_driver_uevent(priv,
ICNSS_UEVENT_FW_DOWN,
&fw_down_data);
@@ -3891,6 +3908,8 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv)
case ICNSS_FW_DOWN:
seq_puts(s, "FW DOWN");
continue;
+ case ICNSS_DRIVER_UNLOADING:
+ seq_puts(s, "DRIVER UNLOADING");
}
seq_printf(s, "UNKNOWN-%d", i);