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

Commit e55b24be authored by Mohammed Siddiq's avatar Mohammed Siddiq
Browse files

cnss2: Add platform driver code to handle hang event data



On SSR, FW writes hang data in the carved out region from
existing DDR memory, the platform driver copies the hang
event data from the fixed offset to local buffer and sends
the buffer and length to host driver via CNSS_HANG_EVENT
event.

Change-Id: I5928821770086547b4fe17c30a967ea059b39394
Signed-off-by: default avatarMohammed Siddiq <msiddiq@codeaurora.org>
parent fbad67d3
Loading
Loading
Loading
Loading
+59 −0
Original line number Diff line number Diff line
@@ -77,6 +77,9 @@ static DEFINE_SPINLOCK(time_sync_lock);
#define CNSS_DEBUG_DUMP_SRAM_START		0x1403D58
#define CNSS_DEBUG_DUMP_SRAM_SIZE		10

#define HANG_DATA_LENGTH		384
#define HANG_DATA_OFFSET		((3 * 1024 * 1024) - HANG_DATA_LENGTH)

static struct cnss_pci_reg ce_src[] = {
	{ "SRC_RING_BASE_LSB", QCA6390_CE_SRC_RING_BASE_LSB_OFFSET },
	{ "SRC_RING_BASE_MSB", QCA6390_CE_SRC_RING_BASE_MSB_OFFSET },
@@ -3778,6 +3781,59 @@ static void cnss_pci_remove_dump_seg(struct cnss_pci_data *pci_priv,
	cnss_minidump_remove_region(plat_priv, type, seg_no, va, pa, size);
}

int cnss_call_driver_uevent(struct cnss_pci_data *pci_priv,
			    enum cnss_driver_status status, void *data)
{
	struct cnss_uevent_data uevent_data;
	struct cnss_wlan_driver *driver_ops;

	driver_ops = pci_priv->driver_ops;
	if (!driver_ops || !driver_ops->update_event) {
		cnss_pr_dbg("Hang event driver ops is NULL\n");
		return -EINVAL;
	}

	cnss_pr_dbg("Calling driver uevent: %d\n", status);

	uevent_data.status = status;
	uevent_data.data = data;

	return driver_ops->update_event(pci_priv->pci_dev, &uevent_data);
}

static void cnss_pci_send_hang_event(struct cnss_pci_data *pci_priv)
{
	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
	struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
	struct cnss_hang_event hang_event = {0};
	void *hang_data_va = NULL;
	int i = 0;

	if (!fw_mem || !plat_priv->fw_mem_seg_len)
		return;

	for (i = 0; i < plat_priv->fw_mem_seg_len; i++) {
		if (fw_mem[i].type == QMI_WLFW_MEM_TYPE_DDR_V01 &&
		    fw_mem[i].va) {
			hang_data_va = fw_mem[i].va + HANG_DATA_OFFSET;
			hang_event.hang_event_data = kmemdup(hang_data_va,
							     HANG_DATA_LENGTH,
							     GFP_ATOMIC);
			if (!hang_event.hang_event_data) {
				cnss_pr_dbg("Hang data memory alloc failed\n");
				return;
			}
			hang_event.hang_event_data_len = HANG_DATA_LENGTH;
			break;
		}
	}

	cnss_call_driver_uevent(pci_priv, CNSS_HANG_EVENT, &hang_event);

	kfree(hang_event.hang_event_data);
	hang_event.hang_event_data = NULL;
}

void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv, bool in_panic)
{
	struct cnss_plat_data *plat_priv = pci_priv->plat_priv;
@@ -3789,6 +3845,9 @@ void cnss_pci_collect_dump_info(struct cnss_pci_data *pci_priv, bool in_panic)
	struct cnss_fw_mem *fw_mem = plat_priv->fw_mem;
	int ret, i, j;

	if (test_bit(CNSS_DEV_ERR_NOTIFY, &plat_priv->driver_state))
		cnss_pci_send_hang_event(pci_priv);

	if (test_bit(CNSS_MHI_RDDM_DONE, &pci_priv->mhi_state)) {
		cnss_pr_dbg("RAM dump is already collected, skip\n");
		return;
+2 −0
Original line number Diff line number Diff line
@@ -200,6 +200,8 @@ void cnss_pci_pm_runtime_put_noidle(struct cnss_pci_data *pci_priv);
void cnss_pci_pm_runtime_mark_last_busy(struct cnss_pci_data *pci_priv);
int cnss_pci_update_status(struct cnss_pci_data *pci_priv,
			   enum cnss_driver_status status);
int cnss_call_driver_uevent(struct cnss_pci_data *pci_priv,
			    enum cnss_driver_status status, void *data);
int cnss_pcie_is_device_down(struct cnss_pci_data *pci_priv);
int cnss_pci_suspend_bus(struct cnss_pci_data *pci_priv);
int cnss_pci_resume_bus(struct cnss_pci_data *pci_priv);
+21 −8
Original line number Diff line number Diff line
@@ -67,6 +67,25 @@ struct cnss_wlan_runtime_ops {
	int (*runtime_resume)(struct pci_dev *pdev);
};

enum cnss_driver_status {
	CNSS_UNINITIALIZED,
	CNSS_INITIALIZED,
	CNSS_LOAD_UNLOAD,
	CNSS_RECOVERY,
	CNSS_FW_DOWN,
	CNSS_HANG_EVENT,
};

struct cnss_hang_event {
	void *hang_event_data;
	u16 hang_event_data_len;
};

struct cnss_uevent_data {
	enum cnss_driver_status status;
	void *data;
};

struct cnss_wlan_driver {
	char *name;
	int  (*probe)(struct pci_dev *pdev, const struct pci_device_id *id);
@@ -83,18 +102,12 @@ struct cnss_wlan_driver {
	int  (*resume_noirq)(struct pci_dev *pdev);
	void (*modem_status)(struct pci_dev *pdev, int state);
	void (*update_status)(struct pci_dev *pdev, uint32_t status);
	int  (*update_event)(struct pci_dev *pdev,
			     struct cnss_uevent_data *uevent);
	struct cnss_wlan_runtime_ops *runtime_ops;
	const struct pci_device_id *id_table;
};

enum cnss_driver_status {
	CNSS_UNINITIALIZED,
	CNSS_INITIALIZED,
	CNSS_LOAD_UNLOAD,
	CNSS_RECOVERY,
	CNSS_FW_DOWN,
};

struct cnss_ce_tgt_pipe_cfg {
	u32 pipe_num;
	u32 pipe_dir;