Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fa12840e authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "icnss: For WDOG bite, shutdown after FW ready"

parents 0e390526 b70b942f
Loading
Loading
Loading
Loading
+95 −30
Original line number Diff line number Diff line
@@ -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 {
@@ -205,6 +206,7 @@ enum icnss_driver_state {
	ICNSS_PD_RESTART,
	ICNSS_MSA0_ASSIGNED,
	ICNSS_WLFW_EXISTS,
	ICNSS_WDOG_BITE,
};

struct ce_irq_list {
@@ -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;
@@ -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);
@@ -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);
@@ -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;
}

@@ -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);

@@ -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);

@@ -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);

@@ -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;
}

@@ -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);
+20 −8
Original line number Diff line number Diff line
@@ -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;
@@ -256,7 +257,7 @@ static void root_service_service_ind_cb(struct qmi_handle *handle,
		mutex_lock(&notif_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);
@@ -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) {
@@ -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);
@@ -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,
@@ -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;
+11 −0
Original line number Diff line number Diff line
@@ -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);
@@ -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);
};


+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
@@ -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)