Loading drivers/soc/qcom/icnss.c +95 −30 Original line number Diff line number Diff line Loading @@ -181,6 +181,7 @@ enum icnss_driver_event_type { struct icnss_event_pd_service_down_data { bool crashed; bool fw_rejuvenate; bool wdog_bite; }; struct icnss_driver_event { Loading @@ -205,6 +206,7 @@ enum icnss_driver_state { ICNSS_PD_RESTART, ICNSS_MSA0_ASSIGNED, ICNSS_WLFW_EXISTS, ICNSS_WDOG_BITE, }; struct ce_irq_list { Loading Loading @@ -1701,6 +1703,23 @@ static int icnss_driver_event_server_exit(void *data) return 0; } static int icnss_call_driver_uevent(struct icnss_priv *priv, enum icnss_uevent uevent, void *data) { struct icnss_uevent_data uevent_data; if (!priv->ops || !priv->ops->uevent) return 0; icnss_pr_dbg("Calling driver uevent state: 0x%lx, uevent: %d\n", priv->state, uevent); uevent_data.uevent = uevent; uevent_data.data = data; return priv->ops->uevent(&priv->pdev->dev, &uevent_data); } static int icnss_call_driver_probe(struct icnss_priv *priv) { int ret; Loading Loading @@ -1728,17 +1747,39 @@ out: return ret; } static int icnss_call_driver_shutdown(struct icnss_priv *priv) { if (!test_bit(ICNSS_DRIVER_PROBED, &penv->state)) goto out; if (!priv->ops || !priv->ops->shutdown) goto out; icnss_pr_dbg("Calling driver shutdown state: 0x%lx\n", priv->state); priv->ops->shutdown(&priv->pdev->dev); out: return 0; } static int icnss_pd_restart_complete(struct icnss_priv *priv) { int ret; clear_bit(ICNSS_PD_RESTART, &priv->state); icnss_pm_relax(priv); if (test_bit(ICNSS_WDOG_BITE, &priv->state)) { icnss_call_driver_shutdown(priv); clear_bit(ICNSS_WDOG_BITE, &priv->state); } clear_bit(ICNSS_PD_RESTART, &priv->state); if (!priv->ops || !priv->ops->reinit) goto out; if (!test_bit(ICNSS_DRIVER_PROBED, &penv->state)) if (!test_bit(ICNSS_DRIVER_PROBED, &priv->state)) goto call_probe; icnss_pr_dbg("Calling driver reinit state: 0x%lx\n", priv->state); Loading Loading @@ -1775,6 +1816,8 @@ static int icnss_driver_event_fw_ready_ind(void *data) set_bit(ICNSS_FW_READY, &penv->state); icnss_call_driver_uevent(penv, ICNSS_UEVENT_FW_READY, NULL); icnss_pr_info("WLAN FW is ready: 0x%lx\n", penv->state); icnss_hw_power_off(penv); Loading Loading @@ -1874,23 +1917,30 @@ static int icnss_call_driver_remove(struct icnss_priv *priv) return 0; } static int icnss_call_driver_shutdown(struct icnss_priv *priv) static int icnss_fw_crashed(struct icnss_priv *priv, struct icnss_event_pd_service_down_data *event_data) { icnss_pr_dbg("Calling driver shutdown state: 0x%lx\n", priv->state); icnss_pr_dbg("FW crashed, state: 0x%lx, wdog_bite: %d\n", priv->state, event_data->wdog_bite); set_bit(ICNSS_PD_RESTART, &priv->state); clear_bit(ICNSS_FW_READY, &priv->state); icnss_pm_stay_awake(priv); if (!test_bit(ICNSS_DRIVER_PROBED, &penv->state)) return 0; icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_CRASHED, NULL); if (!priv->ops || !priv->ops->shutdown) return 0; if (event_data->wdog_bite) { set_bit(ICNSS_WDOG_BITE, &priv->state); goto out; } priv->ops->shutdown(&priv->pdev->dev); icnss_call_driver_shutdown(priv); if (event_data->fw_rejuvenate) wlfw_rejuvenate_ack_send_sync_msg(priv); out: return 0; } Loading @@ -1911,13 +1961,10 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv, } if (event_data->crashed) icnss_call_driver_shutdown(priv); icnss_fw_crashed(priv, event_data); else icnss_call_driver_remove(priv); if (event_data->fw_rejuvenate) wlfw_rejuvenate_ack_send_sync_msg(priv); out: ret = icnss_hw_power_off(priv); Loading Loading @@ -2064,7 +2111,8 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, if (test_bit(ICNSS_PDR_ENABLED, &priv->state)) return NOTIFY_OK; icnss_pr_info("Modem went down, state: %lx\n", priv->state); icnss_pr_info("Modem went down, state: %lx, crashed: %d\n", priv->state, notif->crashed); event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); Loading @@ -2073,6 +2121,9 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, event_data->crashed = notif->crashed; if (notif->crashed == CRASH_STATUS_WDOG_BITE) event_data->wdog_bite = true; icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, ICNSS_EVENT_SYNC, event_data); Loading Loading @@ -2137,30 +2188,41 @@ static int icnss_service_notifier_notify(struct notifier_block *nb, enum pd_subsys_state *state = data; struct icnss_event_pd_service_down_data *event_data; switch (notification) { case SERVREG_NOTIF_SERVICE_STATE_DOWN_V01: icnss_pr_info("Service down, data: 0x%p, state: 0x%lx\n", data, priv->state); icnss_pr_dbg("PD service notification: 0x%lx state: 0x%lx\n", notification, priv->state); if (notification != SERVREG_NOTIF_SERVICE_STATE_DOWN_V01) goto done; event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); if (event_data == NULL) return notifier_from_errno(-ENOMEM); if (state == NULL || *state != SHUTDOWN) if (state == NULL) { event_data->crashed = true; goto event_post; } icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, ICNSS_EVENT_SYNC, event_data); icnss_pr_info("PD service down, pd_state: %d, state: 0x%lx\n", *state, priv->state); switch (*state) { case ROOT_PD_WDOG_BITE: event_data->crashed = true; event_data->wdog_bite = true; break; case SERVREG_NOTIF_SERVICE_STATE_UP_V01: icnss_pr_dbg("Service up, state: 0x%lx\n", priv->state); case ROOT_PD_SHUTDOWN: break; default: icnss_pr_dbg("Service state Unknown, notification: 0x%lx, state: 0x%lx\n", notification, priv->state); return NOTIFY_DONE; event_data->crashed = true; break; } event_post: icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, ICNSS_EVENT_SYNC, event_data); done: return NOTIFY_OK; } Loading Loading @@ -3226,6 +3288,9 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv) case ICNSS_WLFW_EXISTS: seq_puts(s, "WLAN FW EXISTS"); continue; case ICNSS_WDOG_BITE: seq_puts(s, "MODEM WDOG BITE"); continue; } seq_printf(s, "UNKNOWN-%d", i); Loading drivers/soc/qcom/service-notifier.c +20 −8 Original line number Diff line number Diff line Loading @@ -229,6 +229,7 @@ static void root_service_service_ind_cb(struct qmi_handle *handle, struct msg_desc ind_desc; struct qmi_servreg_notif_state_updated_ind_msg_v01 ind_msg = { QMI_STATE_MIN_VAL, "", 0xFFFF }; enum pd_subsys_state state = USER_PD_STATE_CHANGE; int rc; ind_desc.msg_id = SERVREG_NOTIF_STATE_UPDATED_IND_MSG; Loading Loading @@ -256,7 +257,7 @@ static void root_service_service_ind_cb(struct qmi_handle *handle, mutex_lock(¬if_add_lock); mutex_lock(&service_list_lock); rc = service_notif_queue_notification(service_notif, ind_msg.curr_state, NULL); ind_msg.curr_state, &state); if (rc & NOTIFY_STOP_MASK) pr_err("Notifier callback aborted for %s with error %d\n", ind_msg.service_name, rc); Loading Loading @@ -373,6 +374,7 @@ static void root_service_service_arrive(struct work_struct *work) mutex_lock(&service_list_lock); list_for_each_entry(service_notif, &service_list, list) { if (service_notif->instance_id == data->instance_id) { enum pd_subsys_state state = ROOT_PD_UP; rc = register_notif_listener(service_notif, data, &curr_state); if (rc) { Loading @@ -380,7 +382,7 @@ static void root_service_service_arrive(struct work_struct *work) service_notif->service_path, rc); } else { rc = service_notif_queue_notification( service_notif, curr_state, NULL); service_notif, curr_state, &state); if (rc & NOTIFY_STOP_MASK) pr_err("Notifier callback aborted for %s error:%d\n", service_notif->service_path, rc); Loading Loading @@ -434,7 +436,7 @@ static void root_service_exit_work(struct work_struct *work) { struct qmi_client_info *data = container_of(work, struct qmi_client_info, svc_exit); root_service_service_exit(data, UNKNOWN); root_service_service_exit(data, ROOT_PD_DOWN); } static int service_event_notify(struct notifier_block *this, Loading Loading @@ -466,14 +468,24 @@ static int ssr_event_notify(struct notifier_block *this, struct qmi_client_info *info = container_of(this, struct qmi_client_info, ssr_notifier); struct notif_data *notif = data; enum pd_subsys_state state; switch (code) { case SUBSYS_BEFORE_SHUTDOWN: pr_debug("Root PD DOWN(SSR notification), crashed?%d\n", pr_debug("Root PD DOWN(SSR notification), state:%d\n", notif->crashed); if (notif->crashed) root_service_service_exit(info, CRASHED); else root_service_service_exit(info, SHUTDOWN); switch (notif->crashed) { case CRASH_STATUS_ERR_FATAL: state = ROOT_PD_ERR_FATAL; break; case CRASH_STATUS_WDOG_BITE: state = ROOT_PD_WDOG_BITE; break; default: state = ROOT_PD_SHUTDOWN; break; } root_service_service_exit(info, state); break; default: break; Loading include/soc/qcom/icnss.h +11 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,16 @@ #define ICNSS_MAX_IRQ_REGISTRATIONS 12 #define ICNSS_MAX_TIMESTAMP_LEN 32 enum icnss_uevent { ICNSS_UEVENT_FW_READY, ICNSS_UEVENT_FW_CRASHED, }; struct icnss_uevent_data { enum icnss_uevent uevent; void *data; }; struct icnss_driver_ops { char *name; int (*probe)(struct device *dev); Loading @@ -28,6 +38,7 @@ struct icnss_driver_ops { int (*pm_resume)(struct device *dev); int (*suspend_noirq)(struct device *dev); int (*resume_noirq)(struct device *dev); int (*uevent)(struct device *dev, struct icnss_uevent_data *uevent); }; Loading include/soc/qcom/service-notifier.h +7 −4 Original line number Diff line number Diff line /* * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. * Copyright (c) 2015-2017, 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 Loading @@ -25,9 +25,12 @@ enum qmi_servreg_notif_service_state_enum_type_v01 { }; enum pd_subsys_state { CRASHED, SHUTDOWN, UNKNOWN, ROOT_PD_DOWN, ROOT_PD_UP, ROOT_PD_ERR_FATAL, ROOT_PD_WDOG_BITE, ROOT_PD_SHUTDOWN, USER_PD_STATE_CHANGE, }; #if defined(CONFIG_MSM_SERVICE_NOTIFIER) Loading Loading
drivers/soc/qcom/icnss.c +95 −30 Original line number Diff line number Diff line Loading @@ -181,6 +181,7 @@ enum icnss_driver_event_type { struct icnss_event_pd_service_down_data { bool crashed; bool fw_rejuvenate; bool wdog_bite; }; struct icnss_driver_event { Loading @@ -205,6 +206,7 @@ enum icnss_driver_state { ICNSS_PD_RESTART, ICNSS_MSA0_ASSIGNED, ICNSS_WLFW_EXISTS, ICNSS_WDOG_BITE, }; struct ce_irq_list { Loading Loading @@ -1701,6 +1703,23 @@ static int icnss_driver_event_server_exit(void *data) return 0; } static int icnss_call_driver_uevent(struct icnss_priv *priv, enum icnss_uevent uevent, void *data) { struct icnss_uevent_data uevent_data; if (!priv->ops || !priv->ops->uevent) return 0; icnss_pr_dbg("Calling driver uevent state: 0x%lx, uevent: %d\n", priv->state, uevent); uevent_data.uevent = uevent; uevent_data.data = data; return priv->ops->uevent(&priv->pdev->dev, &uevent_data); } static int icnss_call_driver_probe(struct icnss_priv *priv) { int ret; Loading Loading @@ -1728,17 +1747,39 @@ out: return ret; } static int icnss_call_driver_shutdown(struct icnss_priv *priv) { if (!test_bit(ICNSS_DRIVER_PROBED, &penv->state)) goto out; if (!priv->ops || !priv->ops->shutdown) goto out; icnss_pr_dbg("Calling driver shutdown state: 0x%lx\n", priv->state); priv->ops->shutdown(&priv->pdev->dev); out: return 0; } static int icnss_pd_restart_complete(struct icnss_priv *priv) { int ret; clear_bit(ICNSS_PD_RESTART, &priv->state); icnss_pm_relax(priv); if (test_bit(ICNSS_WDOG_BITE, &priv->state)) { icnss_call_driver_shutdown(priv); clear_bit(ICNSS_WDOG_BITE, &priv->state); } clear_bit(ICNSS_PD_RESTART, &priv->state); if (!priv->ops || !priv->ops->reinit) goto out; if (!test_bit(ICNSS_DRIVER_PROBED, &penv->state)) if (!test_bit(ICNSS_DRIVER_PROBED, &priv->state)) goto call_probe; icnss_pr_dbg("Calling driver reinit state: 0x%lx\n", priv->state); Loading Loading @@ -1775,6 +1816,8 @@ static int icnss_driver_event_fw_ready_ind(void *data) set_bit(ICNSS_FW_READY, &penv->state); icnss_call_driver_uevent(penv, ICNSS_UEVENT_FW_READY, NULL); icnss_pr_info("WLAN FW is ready: 0x%lx\n", penv->state); icnss_hw_power_off(penv); Loading Loading @@ -1874,23 +1917,30 @@ static int icnss_call_driver_remove(struct icnss_priv *priv) return 0; } static int icnss_call_driver_shutdown(struct icnss_priv *priv) static int icnss_fw_crashed(struct icnss_priv *priv, struct icnss_event_pd_service_down_data *event_data) { icnss_pr_dbg("Calling driver shutdown state: 0x%lx\n", priv->state); icnss_pr_dbg("FW crashed, state: 0x%lx, wdog_bite: %d\n", priv->state, event_data->wdog_bite); set_bit(ICNSS_PD_RESTART, &priv->state); clear_bit(ICNSS_FW_READY, &priv->state); icnss_pm_stay_awake(priv); if (!test_bit(ICNSS_DRIVER_PROBED, &penv->state)) return 0; icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_CRASHED, NULL); if (!priv->ops || !priv->ops->shutdown) return 0; if (event_data->wdog_bite) { set_bit(ICNSS_WDOG_BITE, &priv->state); goto out; } priv->ops->shutdown(&priv->pdev->dev); icnss_call_driver_shutdown(priv); if (event_data->fw_rejuvenate) wlfw_rejuvenate_ack_send_sync_msg(priv); out: return 0; } Loading @@ -1911,13 +1961,10 @@ static int icnss_driver_event_pd_service_down(struct icnss_priv *priv, } if (event_data->crashed) icnss_call_driver_shutdown(priv); icnss_fw_crashed(priv, event_data); else icnss_call_driver_remove(priv); if (event_data->fw_rejuvenate) wlfw_rejuvenate_ack_send_sync_msg(priv); out: ret = icnss_hw_power_off(priv); Loading Loading @@ -2064,7 +2111,8 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, if (test_bit(ICNSS_PDR_ENABLED, &priv->state)) return NOTIFY_OK; icnss_pr_info("Modem went down, state: %lx\n", priv->state); icnss_pr_info("Modem went down, state: %lx, crashed: %d\n", priv->state, notif->crashed); event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); Loading @@ -2073,6 +2121,9 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb, event_data->crashed = notif->crashed; if (notif->crashed == CRASH_STATUS_WDOG_BITE) event_data->wdog_bite = true; icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, ICNSS_EVENT_SYNC, event_data); Loading Loading @@ -2137,30 +2188,41 @@ static int icnss_service_notifier_notify(struct notifier_block *nb, enum pd_subsys_state *state = data; struct icnss_event_pd_service_down_data *event_data; switch (notification) { case SERVREG_NOTIF_SERVICE_STATE_DOWN_V01: icnss_pr_info("Service down, data: 0x%p, state: 0x%lx\n", data, priv->state); icnss_pr_dbg("PD service notification: 0x%lx state: 0x%lx\n", notification, priv->state); if (notification != SERVREG_NOTIF_SERVICE_STATE_DOWN_V01) goto done; event_data = kzalloc(sizeof(*event_data), GFP_KERNEL); if (event_data == NULL) return notifier_from_errno(-ENOMEM); if (state == NULL || *state != SHUTDOWN) if (state == NULL) { event_data->crashed = true; goto event_post; } icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, ICNSS_EVENT_SYNC, event_data); icnss_pr_info("PD service down, pd_state: %d, state: 0x%lx\n", *state, priv->state); switch (*state) { case ROOT_PD_WDOG_BITE: event_data->crashed = true; event_data->wdog_bite = true; break; case SERVREG_NOTIF_SERVICE_STATE_UP_V01: icnss_pr_dbg("Service up, state: 0x%lx\n", priv->state); case ROOT_PD_SHUTDOWN: break; default: icnss_pr_dbg("Service state Unknown, notification: 0x%lx, state: 0x%lx\n", notification, priv->state); return NOTIFY_DONE; event_data->crashed = true; break; } event_post: icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN, ICNSS_EVENT_SYNC, event_data); done: return NOTIFY_OK; } Loading Loading @@ -3226,6 +3288,9 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv) case ICNSS_WLFW_EXISTS: seq_puts(s, "WLAN FW EXISTS"); continue; case ICNSS_WDOG_BITE: seq_puts(s, "MODEM WDOG BITE"); continue; } seq_printf(s, "UNKNOWN-%d", i); Loading
drivers/soc/qcom/service-notifier.c +20 −8 Original line number Diff line number Diff line Loading @@ -229,6 +229,7 @@ static void root_service_service_ind_cb(struct qmi_handle *handle, struct msg_desc ind_desc; struct qmi_servreg_notif_state_updated_ind_msg_v01 ind_msg = { QMI_STATE_MIN_VAL, "", 0xFFFF }; enum pd_subsys_state state = USER_PD_STATE_CHANGE; int rc; ind_desc.msg_id = SERVREG_NOTIF_STATE_UPDATED_IND_MSG; Loading Loading @@ -256,7 +257,7 @@ static void root_service_service_ind_cb(struct qmi_handle *handle, mutex_lock(¬if_add_lock); mutex_lock(&service_list_lock); rc = service_notif_queue_notification(service_notif, ind_msg.curr_state, NULL); ind_msg.curr_state, &state); if (rc & NOTIFY_STOP_MASK) pr_err("Notifier callback aborted for %s with error %d\n", ind_msg.service_name, rc); Loading Loading @@ -373,6 +374,7 @@ static void root_service_service_arrive(struct work_struct *work) mutex_lock(&service_list_lock); list_for_each_entry(service_notif, &service_list, list) { if (service_notif->instance_id == data->instance_id) { enum pd_subsys_state state = ROOT_PD_UP; rc = register_notif_listener(service_notif, data, &curr_state); if (rc) { Loading @@ -380,7 +382,7 @@ static void root_service_service_arrive(struct work_struct *work) service_notif->service_path, rc); } else { rc = service_notif_queue_notification( service_notif, curr_state, NULL); service_notif, curr_state, &state); if (rc & NOTIFY_STOP_MASK) pr_err("Notifier callback aborted for %s error:%d\n", service_notif->service_path, rc); Loading Loading @@ -434,7 +436,7 @@ static void root_service_exit_work(struct work_struct *work) { struct qmi_client_info *data = container_of(work, struct qmi_client_info, svc_exit); root_service_service_exit(data, UNKNOWN); root_service_service_exit(data, ROOT_PD_DOWN); } static int service_event_notify(struct notifier_block *this, Loading Loading @@ -466,14 +468,24 @@ static int ssr_event_notify(struct notifier_block *this, struct qmi_client_info *info = container_of(this, struct qmi_client_info, ssr_notifier); struct notif_data *notif = data; enum pd_subsys_state state; switch (code) { case SUBSYS_BEFORE_SHUTDOWN: pr_debug("Root PD DOWN(SSR notification), crashed?%d\n", pr_debug("Root PD DOWN(SSR notification), state:%d\n", notif->crashed); if (notif->crashed) root_service_service_exit(info, CRASHED); else root_service_service_exit(info, SHUTDOWN); switch (notif->crashed) { case CRASH_STATUS_ERR_FATAL: state = ROOT_PD_ERR_FATAL; break; case CRASH_STATUS_WDOG_BITE: state = ROOT_PD_WDOG_BITE; break; default: state = ROOT_PD_SHUTDOWN; break; } root_service_service_exit(info, state); break; default: break; Loading
include/soc/qcom/icnss.h +11 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,16 @@ #define ICNSS_MAX_IRQ_REGISTRATIONS 12 #define ICNSS_MAX_TIMESTAMP_LEN 32 enum icnss_uevent { ICNSS_UEVENT_FW_READY, ICNSS_UEVENT_FW_CRASHED, }; struct icnss_uevent_data { enum icnss_uevent uevent; void *data; }; struct icnss_driver_ops { char *name; int (*probe)(struct device *dev); Loading @@ -28,6 +38,7 @@ struct icnss_driver_ops { int (*pm_resume)(struct device *dev); int (*suspend_noirq)(struct device *dev); int (*resume_noirq)(struct device *dev); int (*uevent)(struct device *dev, struct icnss_uevent_data *uevent); }; Loading
include/soc/qcom/service-notifier.h +7 −4 Original line number Diff line number Diff line /* * Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. * Copyright (c) 2015-2017, 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 Loading @@ -25,9 +25,12 @@ enum qmi_servreg_notif_service_state_enum_type_v01 { }; enum pd_subsys_state { CRASHED, SHUTDOWN, UNKNOWN, ROOT_PD_DOWN, ROOT_PD_UP, ROOT_PD_ERR_FATAL, ROOT_PD_WDOG_BITE, ROOT_PD_SHUTDOWN, USER_PD_STATE_CHANGE, }; #if defined(CONFIG_MSM_SERVICE_NOTIFIER) Loading