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

Commit 5e6e9898 authored by Mohammed Siddiq's avatar Mohammed Siddiq
Browse files

icnss: Add icnss code to handle hang event data



When crash happens, FW write crash info into a MSA0 memory
region. The address offset & length of this memory region
is sent to platform driver on MSA Ready indication. The
platform driver calculates the address, generates virtual
address via ioremap, on receiving SMP2P interrupt it copies
the hang event data from MSA0 region to local buffer and
sends the buffer and length to host driver via FW_DOWN Uevent.

Change-Id: I4228e8189cb69d0fbe52fa2e81e340b4eb19f89b
Signed-off-by: default avatarMohammed Siddiq <msiddiq@codeaurora.org>
parent 575172bd
Loading
Loading
Loading
Loading
+43 −10
Original line number Diff line number Diff line
@@ -571,6 +571,27 @@ int icnss_power_off(struct device *dev)
}
EXPORT_SYMBOL(icnss_power_off);

int icnss_update_fw_down_params(struct icnss_priv *priv,
				struct icnss_uevent_fw_down_data *fw_down_data,
				bool crashed)
{
	fw_down_data->crashed = crashed;

	if (!priv->hang_event_data_va)
		return -EINVAL;

	priv->hang_event_data = kmemdup(priv->hang_event_data_va,
					priv->hang_event_data_len,
					GFP_ATOMIC);
	if (!priv->hang_event_data)
		return -ENOMEM;

	// Update the hang event params
	fw_down_data->hang_event_data = priv->hang_event_data;
	fw_down_data->hang_event_data_len = priv->hang_event_data_len;
	return 0;
}

static irqreturn_t fw_error_fatal_handler(int irq, void *ctx)
{
	struct icnss_priv *priv = ctx;
@@ -587,6 +608,7 @@ static irqreturn_t fw_crash_indication_handler(int irq, void *ctx)
{
	struct icnss_priv *priv = ctx;
	struct icnss_uevent_fw_down_data fw_down_data = {0};
	int ret = 0;

	icnss_pr_err("Received early crash indication from FW\n");

@@ -595,9 +617,18 @@ static irqreturn_t fw_crash_indication_handler(int irq, void *ctx)
		icnss_ignore_fw_timeout(true);

		if (test_bit(ICNSS_FW_READY, &priv->state)) {
			fw_down_data.crashed = true;
			ret = icnss_update_fw_down_params(priv, &fw_down_data,
							  true);
			if (ret)
				icnss_pr_err("Unable to allocate memory for Hang event data\n");

			icnss_call_driver_uevent(priv, ICNSS_UEVENT_FW_DOWN,
						 &fw_down_data);

			if (!ret) {
				kfree(priv->hang_event_data);
				priv->hang_event_data = NULL;
			}
		}
	}

@@ -1426,7 +1457,7 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
	struct notif_data *notif = data;
	struct icnss_priv *priv = container_of(nb, struct icnss_priv,
					       modem_ssr_nb);
	struct icnss_uevent_fw_down_data fw_down_data;
	struct icnss_uevent_fw_down_data fw_down_data = {0};

	icnss_pr_vdbg("Modem-Notify: event %lu\n", code);

@@ -1449,11 +1480,12 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,
		set_bit(ICNSS_FW_DOWN, &priv->state);
		icnss_ignore_fw_timeout(true);

		if (test_bit(ICNSS_FW_READY, &priv->state)) {
			fw_down_data.crashed = !!notif->crashed;
		if (test_bit(ICNSS_FW_READY, &priv->state))
			icnss_call_driver_uevent(priv,
						 ICNSS_UEVENT_FW_DOWN,
						 &fw_down_data);
		}
		return NOTIFY_OK;
	}

@@ -1476,12 +1508,12 @@ static int icnss_modem_notifier_nb(struct notifier_block *nb,

	event_data->crashed = notif->crashed;

	if (test_bit(ICNSS_FW_READY, &priv->state)) {
		fw_down_data.crashed = !!notif->crashed;
	if (test_bit(ICNSS_FW_READY, &priv->state))
		icnss_call_driver_uevent(priv,
					 ICNSS_UEVENT_FW_DOWN,
					 &fw_down_data);

	}
	icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
				ICNSS_EVENT_SYNC, event_data);

@@ -1545,7 +1577,7 @@ static int icnss_service_notifier_notify(struct notifier_block *nb,
					       service_notifier_nb);
	enum pd_subsys_state *state = data;
	struct icnss_event_pd_service_down_data *event_data;
	struct icnss_uevent_fw_down_data fw_down_data;
	struct icnss_uevent_fw_down_data fw_down_data = {0};
	enum icnss_pdr_cause_index cause = ICNSS_ROOT_PD_CRASH;

	icnss_pr_dbg("PD service notification: 0x%lx state: 0x%lx\n",
@@ -1598,12 +1630,13 @@ static int icnss_service_notifier_notify(struct notifier_block *nb,
		set_bit(ICNSS_FW_DOWN, &priv->state);
		icnss_ignore_fw_timeout(true);

		if (test_bit(ICNSS_FW_READY, &priv->state)) {
			fw_down_data.crashed = event_data->crashed;
		if (test_bit(ICNSS_FW_READY, &priv->state))
			icnss_call_driver_uevent(priv,
						 ICNSS_UEVENT_FW_DOWN,
						 &fw_down_data);
		}
	}

	clear_bit(ICNSS_HOST_TRIGGERED_PDR, &priv->state);
	icnss_driver_event_post(ICNSS_DRIVER_EVENT_PD_SERVICE_DOWN,
+5 −1
Original line number Diff line number Diff line
@@ -253,6 +253,7 @@ struct icnss_stats {
#define WLFW_MAX_NUM_CE 12
#define WLFW_MAX_NUM_SVC 24
#define WLFW_MAX_NUM_SHADOW_REG 24
#define WLFW_MAX_HANG_EVENT_DATA_SIZE 400

struct service_notifier_context {
	void *handle;
@@ -350,7 +351,10 @@ struct icnss_priv {
	bool is_ssr;
	struct kobject *icnss_kobject;
	atomic_t is_shutdown;

	phys_addr_t hang_event_data_pa;
	void __iomem *hang_event_data_va;
	uint16_t hang_event_data_len;
	void *hang_event_data;
};

struct icnss_reg_info {
+59 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <linux/ipc_logging.h>
#include <linux/thread_info.h>
#include <linux/soc/qcom/qmi.h>
#include <linux/platform_device.h>
#include <soc/qcom/icnss.h>
#include <soc/qcom/service-locator.h>
#include <soc/qcom/service-notifier.h>
@@ -1012,7 +1013,7 @@ int wlfw_dynamic_feature_mask_send_sync_msg(struct icnss_priv *priv,
void icnss_handle_rejuvenate(struct icnss_priv *priv)
{
	struct icnss_event_pd_service_down_data *event_data;
	struct icnss_uevent_fw_down_data fw_down_data;
	struct icnss_uevent_fw_down_data fw_down_data = {0};

	event_data = kzalloc(sizeof(*event_data), GFP_KERNEL);
	if (event_data == NULL)
@@ -1047,6 +1048,10 @@ static void msa_ready_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
			     struct qmi_txn *txn, const void *data)
{
	struct icnss_priv *priv = container_of(qmi, struct icnss_priv, qmi);
	struct device *dev = &priv->pdev->dev;
	const struct wlfw_msa_ready_ind_msg_v01 *ind_msg = data;
	uint64_t msa_base_addr = priv->msa_pa;
	phys_addr_t hang_data_phy_addr;

	icnss_pr_dbg("Received MSA Ready Indication\n");

@@ -1056,6 +1061,59 @@ static void msa_ready_ind_cb(struct qmi_handle *qmi, struct sockaddr_qrtr *sq,
	}

	priv->stats.msa_ready_ind++;

	/* Check if the length is valid &
	 * the length should not be 0 and
	 * should be <=  WLFW_MAX_HANG_EVENT_DATA_SIZE(400)
	 */

	if (ind_msg->hang_data_length_valid &&
	    ind_msg->hang_data_length &&
	    ind_msg->hang_data_length <= WLFW_MAX_HANG_EVENT_DATA_SIZE)
		priv->hang_event_data_len = ind_msg->hang_data_length;
	else
		goto out;

	/* Check if the offset is valid &
	 * the offset should be in range of 0 to msa_mem_size-hang_data_length
	 */

	if (ind_msg->hang_data_addr_offset_valid &&
	    (ind_msg->hang_data_addr_offset <= (priv->msa_mem_size -
						 ind_msg->hang_data_length)))
		hang_data_phy_addr = msa_base_addr +
						ind_msg->hang_data_addr_offset;
	else
		goto out;

	if (priv->hang_event_data_pa == hang_data_phy_addr)
		goto exit;

	priv->hang_event_data_pa = hang_data_phy_addr;
	priv->hang_event_data_va = devm_ioremap(dev, priv->hang_event_data_pa,
						ind_msg->hang_data_length);

	if (!priv->hang_event_data_va) {
		icnss_pr_err("Hang Data ioremap failed: phy addr: %pa\n",
			     &priv->hang_event_data_pa);
		goto fail;
	}
exit:
	icnss_pr_dbg("Hang Event Data details,Offset:0x%x, Length:0x%x,va_addr: 0x%pK\n",
		     ind_msg->hang_data_addr_offset,
		     ind_msg->hang_data_length,
		     priv->hang_event_data_va);

	return;

out:
	icnss_pr_err("Invalid Hang Data details, Offset:0x%x, Length:0x%x",
		     ind_msg->hang_data_addr_offset,
		     ind_msg->hang_data_length);
fail:
	priv->hang_event_data_va = NULL;
	priv->hang_event_data_pa = 0;
	priv->hang_event_data_len = 0;
}

static void pin_connect_result_ind_cb(struct qmi_handle *qmi,
+37 −1
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
 */
#include <linux/soc/qcom/qmi.h>

@@ -512,6 +512,42 @@ struct qmi_elem_info wlfw_fw_ready_ind_msg_v01_ei[] = {
};

struct qmi_elem_info wlfw_msa_ready_ind_msg_v01_ei[] = {
	{
		.data_type      = QMI_OPT_FLAG,
		.elem_len       = 1,
		.elem_size      = sizeof(u8),
		.array_type       = NO_ARRAY,
		.tlv_type       = 0x10,
		.offset         = offsetof(struct wlfw_msa_ready_ind_msg_v01,
					   hang_data_addr_offset_valid),
	},
	{
		.data_type      = QMI_UNSIGNED_4_BYTE,
		.elem_len       = 1,
		.elem_size      = sizeof(u32),
		.array_type       = NO_ARRAY,
		.tlv_type       = 0x10,
		.offset         = offsetof(struct wlfw_msa_ready_ind_msg_v01,
					   hang_data_addr_offset),
	},
	{
		.data_type      = QMI_OPT_FLAG,
		.elem_len       = 1,
		.elem_size      = sizeof(u8),
		.array_type       = NO_ARRAY,
		.tlv_type       = 0x11,
		.offset         = offsetof(struct wlfw_msa_ready_ind_msg_v01,
					   hang_data_length_valid),
	},
	{
		.data_type      = QMI_UNSIGNED_2_BYTE,
		.elem_len       = 1,
		.elem_size      = sizeof(u16),
		.array_type       = NO_ARRAY,
		.tlv_type       = 0x11,
		.offset         = offsetof(struct wlfw_msa_ready_ind_msg_v01,
					   hang_data_length),
	},
	{
		.data_type      = QMI_EOTI,
		.array_type       = NO_ARRAY,
+6 −3
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
 */
#ifndef WLAN_FIRMWARE_SERVICE_V01_H
#define WLAN_FIRMWARE_SERVICE_V01_H
@@ -211,9 +211,12 @@ struct wlfw_fw_ready_ind_msg_v01 {
extern struct qmi_elem_info wlfw_fw_ready_ind_msg_v01_ei[];

struct wlfw_msa_ready_ind_msg_v01 {
	char placeholder;
	u8 hang_data_addr_offset_valid;
	u32 hang_data_addr_offset;
	u8 hang_data_length_valid;
	u16 hang_data_length;
};
#define WLFW_MSA_READY_IND_MSG_V01_MAX_MSG_LEN 0
#define WLFW_MSA_READY_IND_MSG_V01_MAX_MSG_LEN 12
extern struct qmi_elem_info wlfw_msa_ready_ind_msg_v01_ei[];

struct wlfw_pin_connect_result_ind_msg_v01 {
Loading