diff options
Diffstat (limited to 'drivers/soc/qcom/icnss.c')
-rw-r--r-- | drivers/soc/qcom/icnss.c | 35 |
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; |