summaryrefslogtreecommitdiff
path: root/drivers/soc/qcom/icnss.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/soc/qcom/icnss.c')
-rw-r--r--drivers/soc/qcom/icnss.c35
1 files changed, 31 insertions, 4 deletions
diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c
index feeed645fc47..a40c75990bfb 100644
--- a/drivers/soc/qcom/icnss.c
+++ b/drivers/soc/qcom/icnss.c
@@ -45,6 +45,7 @@
#include <soc/qcom/service-locator.h>
#include <soc/qcom/service-notifier.h>
#include <soc/qcom/socinfo.h>
+#include <soc/qcom/ramdump.h>
#include "wlan_firmware_service_v01.h"
@@ -463,6 +464,7 @@ static struct icnss_priv {
struct qpnp_vadc_chip *vadc_dev;
uint64_t vph_pwr;
atomic_t pm_count;
+ struct ramdump_device *msa0_dump_dev;
} *penv;
static void icnss_hw_write_reg(void *base, u32 offset, u32 val)
@@ -2657,8 +2659,6 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv,
out:
ret = icnss_hw_power_off(priv);
- icnss_remove_msa_permissions(priv);
-
kfree(data);
return ret;
@@ -2763,6 +2763,16 @@ static int icnss_qmi_wlfw_clnt_svc_event_notify(struct notifier_block *this,
return ret;
}
+static int icnss_msa0_ramdump(struct icnss_priv *priv)
+{
+ struct ramdump_segment segment;
+
+ memset(&segment, 0, sizeof(segment));
+ segment.v_address = priv->msa_va;
+ segment.size = priv->msa_mem_size;
+ return do_ramdump(priv->msa0_dump_dev, &segment, 1);
+}
+
static struct notifier_block wlfw_clnt_nb = {
.notifier_call = icnss_qmi_wlfw_clnt_svc_event_notify,
};
@@ -2778,9 +2788,19 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
icnss_pr_dbg("Modem-Notify: event %lu\n", code);
+ if (code == SUBSYS_AFTER_SHUTDOWN) {
+ icnss_remove_msa_permissions(priv);
+ icnss_pr_info("Collecting msa0 segment dump\n");
+ icnss_msa0_ramdump(priv);
+ return NOTIFY_OK;
+ }
+
if (code != SUBSYS_BEFORE_SHUTDOWN)
return NOTIFY_OK;
+ if (test_bit(ICNSS_PDR_ENABLED, &priv->state))
+ return NOTIFY_OK;
+
icnss_pr_info("Modem went down, state: %lx\n", priv->state);
event_data = kzalloc(sizeof(*data), GFP_KERNEL);
@@ -2936,8 +2956,6 @@ static int icnss_get_service_location_notify(struct notifier_block *nb,
set_bit(ICNSS_PDR_ENABLED, &priv->state);
- icnss_modem_ssr_unregister_notifier(priv);
-
icnss_pr_dbg("PD restart enabled, state: 0x%lx\n", priv->state);
return NOTIFY_OK;
@@ -3000,6 +3018,11 @@ static int icnss_enable_recovery(struct icnss_priv *priv)
goto enable_pdr;
}
+ priv->msa0_dump_dev = create_ramdump_device("wcss_msa0",
+ &priv->pdev->dev);
+ if (!priv->msa0_dump_dev)
+ return -ENOMEM;
+
icnss_modem_ssr_register_notifier(priv);
if (test_bit(SSR_ONLY, &quirks)) {
icnss_pr_dbg("PDR disabled through module parameter\n");
@@ -4511,6 +4534,8 @@ static int icnss_remove(struct platform_device *pdev)
icnss_modem_ssr_unregister_notifier(penv);
+ destroy_ramdump_device(penv->msa0_dump_dev);
+
icnss_pdr_unregister_notifier(penv);
qmi_svc_event_notifier_unregister(WLFW_SERVICE_ID_V01,
@@ -4522,6 +4547,8 @@ static int icnss_remove(struct platform_device *pdev)
icnss_hw_power_off(penv);
+ icnss_remove_msa_permissions(penv);
+
dev_set_drvdata(&pdev->dev, NULL);
return 0;