icnss2: Add support for WPSS SSR

Add support to enable WPSS recovery and handle
subsystem restart.

Change-Id: I1b1e91680b280940d19c7eab9f54401ca4ac02d7
Signed-off-by: Naman Padhiar <npadhiar@codeaurora.org>
This commit is contained in:
Naman Padhiar 2020-12-24 01:55:27 +05:30
commit 74a8a7d227
2 changed files with 104 additions and 4 deletions

View file

@ -1560,6 +1560,63 @@ static void icnss_update_state_send_modem_shutdown(struct icnss_priv *priv,
}
}
static int icnss_wpss_notifier_nb(struct notifier_block *nb,
unsigned long code,
void *data)
{
struct icnss_event_pd_service_down_data *event_data;
struct notif_data *notif = data;
struct icnss_priv *priv = container_of(nb, struct icnss_priv,
wpss_ssr_nb);
struct icnss_uevent_fw_down_data fw_down_data = {0};
icnss_pr_vdbg("WPSS-Notify: event %lu\n", code);
if (code == SUBSYS_AFTER_SHUTDOWN) {
icnss_pr_info("Collecting msa0 segment dump\n");
icnss_msa0_ramdump(priv);
goto out;
}
if (code != SUBSYS_BEFORE_SHUTDOWN)
goto out;
priv->is_ssr = true;
icnss_pr_info("WPSS went down, state: 0x%lx, crashed: %d\n",
priv->state, notif->crashed);
set_bit(ICNSS_FW_DOWN, &priv->state);
if (notif->crashed)
priv->stats.recovery.root_pd_crash++;
else
priv->stats.recovery.root_pd_shutdown++;
icnss_ignore_fw_timeout(true);
event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
if (event_data == NULL)
return notifier_from_errno(-ENOMEM);
event_data->crashed = notif->crashed;
fw_down_data.crashed = !!notif->crashed;
if (test_bit(ICNSS_FW_READY, &priv->state)) {
clear_bit(ICNSS_FW_READY, &priv->state);
fw_down_data.crashed = !!notif->crashed;
icnss_call_driver_uevent(priv,
ICNSS_UEVENT_FW_DOWN,
&fw_down_data);
}
icnss_driver_event_post(priv, ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
ICNSS_EVENT_SYNC, event_data);
out:
icnss_pr_vdbg("Exit %s,state: 0x%lx\n", __func__, priv->state);
return NOTIFY_OK;
}
static int icnss_modem_notifier_nb(struct notifier_block *nb,
unsigned long code,
void *data)
@ -1633,6 +1690,30 @@ out:
return NOTIFY_OK;
}
static int icnss_wpss_ssr_register_notifier(struct icnss_priv *priv)
{
int ret = 0;
priv->wpss_ssr_nb.notifier_call = icnss_wpss_notifier_nb;
/*
* Assign priority of icnss wpss notifier callback over IPA
* modem notifier callback which is 0
*/
priv->wpss_ssr_nb.priority = 1;
priv->wpss_notify_handler =
subsys_notif_register_notifier("wpss", &priv->wpss_ssr_nb);
if (IS_ERR(priv->wpss_notify_handler)) {
ret = PTR_ERR(priv->wpss_notify_handler);
icnss_pr_err("WPSS register notifier failed: %d\n", ret);
}
set_bit(ICNSS_SSR_REGISTERED, &priv->state);
return ret;
}
static int icnss_modem_ssr_register_notifier(struct icnss_priv *priv)
{
int ret = 0;
@ -1657,6 +1738,18 @@ static int icnss_modem_ssr_register_notifier(struct icnss_priv *priv)
return ret;
}
static int icnss_wpss_ssr_unregister_notifier(struct icnss_priv *priv)
{
if (!test_and_clear_bit(ICNSS_SSR_REGISTERED, &priv->state))
return 0;
subsys_notif_unregister_notifier(priv->wpss_notify_handler,
&priv->wpss_ssr_nb);
priv->wpss_notify_handler = NULL;
return 0;
}
static int icnss_modem_ssr_unregister_notifier(struct icnss_priv *priv)
{
if (!test_and_clear_bit(ICNSS_SSR_REGISTERED, &priv->state))
@ -1957,6 +2050,11 @@ static int icnss_enable_recovery(struct icnss_priv *priv)
if (ret)
return ret;
if (priv->device_id == WCN6750_DEVICE_ID) {
icnss_wpss_ssr_register_notifier(priv);
return 0;
}
icnss_modem_ssr_register_notifier(priv);
if (test_bit(SSR_ONLY, &priv->ctrl_params.quirks)) {
icnss_pr_dbg("PDR disabled through module parameter\n");
@ -3519,20 +3617,20 @@ static int icnss_remove(struct platform_device *pdev)
complete_all(&priv->unblock_shutdown);
icnss_modem_ssr_unregister_notifier(priv);
destroy_ramdump_device(priv->msa0_dump_dev);
if (priv->device_id == WCN6750_DEVICE_ID) {
icnss_wpss_ssr_unregister_notifier(priv);
destroy_ramdump_device(priv->m3_dump_dev_seg1);
destroy_ramdump_device(priv->m3_dump_dev_seg2);
destroy_ramdump_device(priv->m3_dump_dev_seg3);
destroy_ramdump_device(priv->m3_dump_dev_seg4);
destroy_ramdump_device(priv->m3_dump_dev_seg5);
} else {
icnss_modem_ssr_unregister_notifier(priv);
icnss_pdr_unregister_notifier(priv);
}
icnss_pdr_unregister_notifier(priv);
icnss_unregister_fw_service(priv);
if (priv->event_wq)
destroy_workqueue(priv->event_wq);

View file

@ -386,7 +386,9 @@ struct icnss_priv {
int total_domains;
struct notifier_block get_service_nb;
void *modem_notify_handler;
void *wpss_notify_handler;
struct notifier_block modem_ssr_nb;
struct notifier_block wpss_ssr_nb;
uint32_t diag_reg_read_addr;
uint32_t diag_reg_read_mem_type;
uint32_t diag_reg_read_len;