xref: /linux/drivers/accel/qaic/qaic_ssr.c (revision 6bc1fe6c748caaf926eaf14c8a262f4c65aead9f)
19675093aSJeffrey Hugo // SPDX-License-Identifier: GPL-2.0-only
29675093aSJeffrey Hugo 
39675093aSJeffrey Hugo /* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. */
49675093aSJeffrey Hugo /* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. */
59675093aSJeffrey Hugo 
69675093aSJeffrey Hugo #include <asm/byteorder.h>
79675093aSJeffrey Hugo #include <drm/drm_file.h>
89675093aSJeffrey Hugo #include <drm/drm_managed.h>
9*6bc1fe6cSPranjal Ramajor Asha Kanojiya #include <linux/devcoredump.h>
109675093aSJeffrey Hugo #include <linux/device.h>
119675093aSJeffrey Hugo #include <linux/kernel.h>
129675093aSJeffrey Hugo #include <linux/mhi.h>
139675093aSJeffrey Hugo #include <linux/workqueue.h>
149675093aSJeffrey Hugo 
159675093aSJeffrey Hugo #include "qaic.h"
169675093aSJeffrey Hugo #include "qaic_ssr.h"
179675093aSJeffrey Hugo 
189675093aSJeffrey Hugo #define SSR_RESP_MSG_SZ 32
19*6bc1fe6cSPranjal Ramajor Asha Kanojiya #define SSR_MHI_BUF_SIZE SZ_64K
20*6bc1fe6cSPranjal Ramajor Asha Kanojiya #define SSR_MEM_READ_DATA_SIZE ((u64)SSR_MHI_BUF_SIZE - sizeof(struct ssr_crashdump))
21*6bc1fe6cSPranjal Ramajor Asha Kanojiya #define SSR_MEM_READ_CHUNK_SIZE ((u64)SSR_MEM_READ_DATA_SIZE - sizeof(struct ssr_memory_read_rsp))
229675093aSJeffrey Hugo 
239675093aSJeffrey Hugo #define DEBUG_TRANSFER_INFO		BIT(0)
249675093aSJeffrey Hugo #define DEBUG_TRANSFER_INFO_RSP		BIT(1)
259675093aSJeffrey Hugo #define MEMORY_READ			BIT(2)
269675093aSJeffrey Hugo #define MEMORY_READ_RSP			BIT(3)
279675093aSJeffrey Hugo #define DEBUG_TRANSFER_DONE		BIT(4)
289675093aSJeffrey Hugo #define DEBUG_TRANSFER_DONE_RSP		BIT(5)
299675093aSJeffrey Hugo #define SSR_EVENT			BIT(8)
309675093aSJeffrey Hugo #define SSR_EVENT_RSP			BIT(9)
319675093aSJeffrey Hugo 
329675093aSJeffrey Hugo #define SSR_EVENT_NACK		BIT(0)
339675093aSJeffrey Hugo #define BEFORE_SHUTDOWN		BIT(1)
349675093aSJeffrey Hugo #define AFTER_SHUTDOWN		BIT(2)
359675093aSJeffrey Hugo #define BEFORE_POWER_UP		BIT(3)
369675093aSJeffrey Hugo #define AFTER_POWER_UP		BIT(4)
379675093aSJeffrey Hugo 
38*6bc1fe6cSPranjal Ramajor Asha Kanojiya struct debug_info_table {
39*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Save preferences. Default is mandatory */
40*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	u64 save_perf;
41*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Base address of the debug region */
42*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	u64 mem_base;
43*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Size of debug region in bytes */
44*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	u64 len;
45*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Description */
46*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	char desc[20];
47*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Filename of debug region */
48*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	char filename[20];
49*6bc1fe6cSPranjal Ramajor Asha Kanojiya };
50*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
519675093aSJeffrey Hugo struct _ssr_hdr {
529675093aSJeffrey Hugo 	__le32 cmd;
539675093aSJeffrey Hugo 	__le32 len;
549675093aSJeffrey Hugo 	__le32 dbc_id;
559675093aSJeffrey Hugo };
569675093aSJeffrey Hugo 
579675093aSJeffrey Hugo struct ssr_hdr {
589675093aSJeffrey Hugo 	u32 cmd;
599675093aSJeffrey Hugo 	u32 len;
609675093aSJeffrey Hugo 	u32 dbc_id;
619675093aSJeffrey Hugo };
629675093aSJeffrey Hugo 
63*6bc1fe6cSPranjal Ramajor Asha Kanojiya struct ssr_debug_transfer_info {
64*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_hdr hdr;
65*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	u32 resv;
66*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	u64 tbl_addr;
67*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	u64 tbl_len;
68*6bc1fe6cSPranjal Ramajor Asha Kanojiya } __packed;
69*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
709675093aSJeffrey Hugo struct ssr_debug_transfer_info_rsp {
719675093aSJeffrey Hugo 	struct _ssr_hdr hdr;
729675093aSJeffrey Hugo 	__le32 ret;
739675093aSJeffrey Hugo } __packed;
749675093aSJeffrey Hugo 
75*6bc1fe6cSPranjal Ramajor Asha Kanojiya struct ssr_memory_read {
76*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct _ssr_hdr hdr;
77*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	__le32 resv;
78*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	__le64 addr;
79*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	__le64 len;
80*6bc1fe6cSPranjal Ramajor Asha Kanojiya } __packed;
81*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
82*6bc1fe6cSPranjal Ramajor Asha Kanojiya struct ssr_memory_read_rsp {
83*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct _ssr_hdr hdr;
84*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	__le32 resv;
85*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	u8 data[];
86*6bc1fe6cSPranjal Ramajor Asha Kanojiya } __packed;
87*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
88*6bc1fe6cSPranjal Ramajor Asha Kanojiya struct ssr_debug_transfer_done {
89*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct _ssr_hdr hdr;
90*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	__le32 resv;
91*6bc1fe6cSPranjal Ramajor Asha Kanojiya } __packed;
92*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
93*6bc1fe6cSPranjal Ramajor Asha Kanojiya struct ssr_debug_transfer_done_rsp {
94*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct _ssr_hdr hdr;
95*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	__le32 ret;
96*6bc1fe6cSPranjal Ramajor Asha Kanojiya } __packed;
97*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
989675093aSJeffrey Hugo struct ssr_event {
999675093aSJeffrey Hugo 	struct ssr_hdr hdr;
1009675093aSJeffrey Hugo 	u32 event;
1019675093aSJeffrey Hugo } __packed;
1029675093aSJeffrey Hugo 
1039675093aSJeffrey Hugo struct ssr_event_rsp {
1049675093aSJeffrey Hugo 	struct _ssr_hdr hdr;
1059675093aSJeffrey Hugo 	__le32 event;
1069675093aSJeffrey Hugo } __packed;
1079675093aSJeffrey Hugo 
1089675093aSJeffrey Hugo struct ssr_resp {
1099675093aSJeffrey Hugo 	/* Work struct to schedule work coming on QAIC_SSR channel */
1109675093aSJeffrey Hugo 	struct work_struct work;
1119675093aSJeffrey Hugo 	/* Root struct of device, used to access device resources */
1129675093aSJeffrey Hugo 	struct qaic_device *qdev;
1139675093aSJeffrey Hugo 	/* Buffer used by MHI for transfer requests */
1149675093aSJeffrey Hugo 	u8 data[] __aligned(8);
1159675093aSJeffrey Hugo };
1169675093aSJeffrey Hugo 
117*6bc1fe6cSPranjal Ramajor Asha Kanojiya /* SSR crashdump book keeping structure */
118*6bc1fe6cSPranjal Ramajor Asha Kanojiya struct ssr_dump_info {
119*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* DBC associated with this SSR crashdump */
120*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct dma_bridge_chan *dbc;
121*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/*
122*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 * It will be used when we complete the crashdump download and switch
123*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 * to waiting on SSR events
124*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 */
125*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_resp *resp;
126*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* MEMORY READ request MHI buffer.*/
127*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_memory_read *read_buf_req;
128*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* TRUE: ->read_buf_req is queued for MHI transaction. FALSE: Otherwise */
129*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	bool read_buf_req_queued;
130*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Address of table in host */
131*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	void *tbl_addr;
132*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Total size of table */
133*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	u64 tbl_len;
134*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Offset of table(->tbl_addr) where the new chunk will be dumped */
135*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	u64 tbl_off;
136*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Address of table in device/target */
137*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	u64 tbl_addr_dev;
138*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Ptr to the entire dump */
139*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	void *dump_addr;
140*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Entire crashdump size */
141*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	u64 dump_sz;
142*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Offset of crashdump(->dump_addr) where the new chunk will be dumped */
143*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	u64 dump_off;
144*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Points to the table entry we are currently downloading */
145*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct debug_info_table *tbl_ent;
146*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Offset in the current table entry(->tbl_ent) for next chuck */
147*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	u64 tbl_ent_off;
148*6bc1fe6cSPranjal Ramajor Asha Kanojiya };
149*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
150*6bc1fe6cSPranjal Ramajor Asha Kanojiya struct ssr_crashdump {
151*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/*
152*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 * Points to a book keeping struct maintained by MHI SSR device while
153*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 * downloading a SSR crashdump. It is NULL when crashdump downloading
154*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 * not in progress.
155*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 */
156*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_dump_info *dump_info;
157*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Work struct to schedule work coming on QAIC_SSR channel */
158*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct work_struct work;
159*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Root struct of device, used to access device resources */
160*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct qaic_device *qdev;
161*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Buffer used by MHI for transfer requests */
162*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	u8 data[];
163*6bc1fe6cSPranjal Ramajor Asha Kanojiya };
164*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
165*6bc1fe6cSPranjal Ramajor Asha Kanojiya #define QAIC_SSR_DUMP_V1_MAGIC 0x1234567890abcdef
166*6bc1fe6cSPranjal Ramajor Asha Kanojiya #define QAIC_SSR_DUMP_V1_VER   1
167*6bc1fe6cSPranjal Ramajor Asha Kanojiya struct dump_file_meta {
168*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	u64 magic;
169*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	u64 version;
170*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	u64 size;		/* Total size of the entire dump */
171*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	u64 tbl_len;		/* Length of the table in byte */
172*6bc1fe6cSPranjal Ramajor Asha Kanojiya };
173*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
174*6bc1fe6cSPranjal Ramajor Asha Kanojiya /*
175*6bc1fe6cSPranjal Ramajor Asha Kanojiya  * Layout of crashdump
176*6bc1fe6cSPranjal Ramajor Asha Kanojiya  *              +------------------------------------------+
177*6bc1fe6cSPranjal Ramajor Asha Kanojiya  *              |         Crashdump Meta structure         |
178*6bc1fe6cSPranjal Ramajor Asha Kanojiya  *              | type: struct dump_file_meta              |
179*6bc1fe6cSPranjal Ramajor Asha Kanojiya  *              +------------------------------------------+
180*6bc1fe6cSPranjal Ramajor Asha Kanojiya  *              |             Crashdump Table              |
181*6bc1fe6cSPranjal Ramajor Asha Kanojiya  *              | type: array of struct debug_info_table   |
182*6bc1fe6cSPranjal Ramajor Asha Kanojiya  *              |                                          |
183*6bc1fe6cSPranjal Ramajor Asha Kanojiya  *              |                                          |
184*6bc1fe6cSPranjal Ramajor Asha Kanojiya  *              |                                          |
185*6bc1fe6cSPranjal Ramajor Asha Kanojiya  *              +------------------------------------------+
186*6bc1fe6cSPranjal Ramajor Asha Kanojiya  *              |                Crashdump                 |
187*6bc1fe6cSPranjal Ramajor Asha Kanojiya  *              |                                          |
188*6bc1fe6cSPranjal Ramajor Asha Kanojiya  *              |                                          |
189*6bc1fe6cSPranjal Ramajor Asha Kanojiya  *              |                                          |
190*6bc1fe6cSPranjal Ramajor Asha Kanojiya  *              |                                          |
191*6bc1fe6cSPranjal Ramajor Asha Kanojiya  *              |                                          |
192*6bc1fe6cSPranjal Ramajor Asha Kanojiya  *              +------------------------------------------+
193*6bc1fe6cSPranjal Ramajor Asha Kanojiya  */
194*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
195*6bc1fe6cSPranjal Ramajor Asha Kanojiya static void free_ssr_dump_info(struct ssr_crashdump *ssr_crash)
196*6bc1fe6cSPranjal Ramajor Asha Kanojiya {
197*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_dump_info *dump_info = ssr_crash->dump_info;
198*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
199*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	ssr_crash->dump_info = NULL;
200*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (!dump_info)
201*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		return;
202*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (!dump_info->read_buf_req_queued)
203*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		kfree(dump_info->read_buf_req);
204*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	vfree(dump_info->tbl_addr);
205*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	vfree(dump_info->dump_addr);
206*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	kfree(dump_info);
207*6bc1fe6cSPranjal Ramajor Asha Kanojiya }
208*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
2099675093aSJeffrey Hugo void qaic_clean_up_ssr(struct qaic_device *qdev)
2109675093aSJeffrey Hugo {
211*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_crashdump *ssr_crash = qdev->ssr_mhi_buf;
212*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
213*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (!ssr_crash)
214*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		return;
215*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
2169675093aSJeffrey Hugo 	qaic_dbc_exit_ssr(qdev);
217*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	free_ssr_dump_info(ssr_crash);
218*6bc1fe6cSPranjal Ramajor Asha Kanojiya }
219*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
220*6bc1fe6cSPranjal Ramajor Asha Kanojiya static int alloc_dump(struct ssr_dump_info *dump_info)
221*6bc1fe6cSPranjal Ramajor Asha Kanojiya {
222*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct debug_info_table *tbl_ent = dump_info->tbl_addr;
223*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct dump_file_meta *dump_meta;
224*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	u64 tbl_sz_lp = 0;
225*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	u64 dump_size = 0;
226*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
227*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	while (tbl_sz_lp < dump_info->tbl_len) {
228*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		le64_to_cpus(&tbl_ent->save_perf);
229*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		le64_to_cpus(&tbl_ent->mem_base);
230*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		le64_to_cpus(&tbl_ent->len);
231*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
232*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		if (tbl_ent->len == 0)
233*6bc1fe6cSPranjal Ramajor Asha Kanojiya 			return -EINVAL;
234*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
235*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		dump_size += tbl_ent->len;
236*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		tbl_ent++;
237*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		tbl_sz_lp += sizeof(*tbl_ent);
238*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	}
239*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
240*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	dump_info->dump_sz = dump_size + dump_info->tbl_len + sizeof(*dump_meta);
241*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	dump_info->dump_addr = vzalloc(dump_info->dump_sz);
242*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (!dump_info->dump_addr)
243*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		return -ENOMEM;
244*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
245*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Copy crashdump meta and table */
246*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	dump_meta = dump_info->dump_addr;
247*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	dump_meta->magic = QAIC_SSR_DUMP_V1_MAGIC;
248*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	dump_meta->version = QAIC_SSR_DUMP_V1_VER;
249*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	dump_meta->size = dump_info->dump_sz;
250*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	dump_meta->tbl_len = dump_info->tbl_len;
251*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	memcpy(dump_info->dump_addr + sizeof(*dump_meta), dump_info->tbl_addr, dump_info->tbl_len);
252*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Offset by crashdump meta and table (copied above) */
253*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	dump_info->dump_off = dump_info->tbl_len + sizeof(*dump_meta);
254*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
255*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	return 0;
256*6bc1fe6cSPranjal Ramajor Asha Kanojiya }
257*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
258*6bc1fe6cSPranjal Ramajor Asha Kanojiya static int send_xfer_done(struct qaic_device *qdev, void *resp, u32 dbc_id)
259*6bc1fe6cSPranjal Ramajor Asha Kanojiya {
260*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_debug_transfer_done *xfer_done;
261*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	int ret;
262*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
263*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	xfer_done = kmalloc(sizeof(*xfer_done), GFP_KERNEL);
264*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (!xfer_done) {
265*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		ret = -ENOMEM;
266*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		goto out;
267*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	}
268*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
269*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	ret = mhi_queue_buf(qdev->ssr_ch, DMA_FROM_DEVICE, resp, SSR_RESP_MSG_SZ, MHI_EOT);
270*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (ret)
271*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		goto free_xfer_done;
272*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
273*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	xfer_done->hdr.cmd = cpu_to_le32(DEBUG_TRANSFER_DONE);
274*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	xfer_done->hdr.len = cpu_to_le32(sizeof(*xfer_done));
275*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	xfer_done->hdr.dbc_id = cpu_to_le32(dbc_id);
276*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
277*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	ret = mhi_queue_buf(qdev->ssr_ch, DMA_TO_DEVICE, xfer_done, sizeof(*xfer_done), MHI_EOT);
278*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (ret)
279*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		goto free_xfer_done;
280*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
281*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	return 0;
282*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
283*6bc1fe6cSPranjal Ramajor Asha Kanojiya free_xfer_done:
284*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	kfree(xfer_done);
285*6bc1fe6cSPranjal Ramajor Asha Kanojiya out:
286*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	return ret;
287*6bc1fe6cSPranjal Ramajor Asha Kanojiya }
288*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
289*6bc1fe6cSPranjal Ramajor Asha Kanojiya static int mem_read_req(struct qaic_device *qdev, u64 dest_addr, u64 dest_len)
290*6bc1fe6cSPranjal Ramajor Asha Kanojiya {
291*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_crashdump *ssr_crash = qdev->ssr_mhi_buf;
292*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_memory_read *read_buf_req;
293*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_dump_info *dump_info;
294*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	int ret;
295*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
296*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	dump_info = ssr_crash->dump_info;
297*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	ret = mhi_queue_buf(qdev->ssr_ch, DMA_FROM_DEVICE, ssr_crash->data, SSR_MEM_READ_DATA_SIZE,
298*6bc1fe6cSPranjal Ramajor Asha Kanojiya 			    MHI_EOT);
299*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (ret)
300*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		goto out;
301*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
302*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	read_buf_req = dump_info->read_buf_req;
303*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	read_buf_req->hdr.cmd = cpu_to_le32(MEMORY_READ);
304*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	read_buf_req->hdr.len = cpu_to_le32(sizeof(*read_buf_req));
305*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	read_buf_req->hdr.dbc_id = cpu_to_le32(qdev->ssr_dbc);
306*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	read_buf_req->addr = cpu_to_le64(dest_addr);
307*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	read_buf_req->len = cpu_to_le64(dest_len);
308*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
309*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	ret = mhi_queue_buf(qdev->ssr_ch, DMA_TO_DEVICE, read_buf_req, sizeof(*read_buf_req),
310*6bc1fe6cSPranjal Ramajor Asha Kanojiya 			    MHI_EOT);
311*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (!ret)
312*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		dump_info->read_buf_req_queued = true;
313*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
314*6bc1fe6cSPranjal Ramajor Asha Kanojiya out:
315*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	return ret;
316*6bc1fe6cSPranjal Ramajor Asha Kanojiya }
317*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
318*6bc1fe6cSPranjal Ramajor Asha Kanojiya static int ssr_copy_table(struct ssr_dump_info *dump_info, void *data, u64 len)
319*6bc1fe6cSPranjal Ramajor Asha Kanojiya {
320*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (len > dump_info->tbl_len - dump_info->tbl_off)
321*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		return -EINVAL;
322*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
323*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	memcpy(dump_info->tbl_addr + dump_info->tbl_off, data, len);
324*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	dump_info->tbl_off += len;
325*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
326*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Entire table has been downloaded, alloc dump memory */
327*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (dump_info->tbl_off == dump_info->tbl_len) {
328*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		dump_info->tbl_ent = dump_info->tbl_addr;
329*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		return alloc_dump(dump_info);
330*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	}
331*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
332*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	return 0;
333*6bc1fe6cSPranjal Ramajor Asha Kanojiya }
334*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
335*6bc1fe6cSPranjal Ramajor Asha Kanojiya static int ssr_copy_dump(struct ssr_dump_info *dump_info, void *data, u64 len)
336*6bc1fe6cSPranjal Ramajor Asha Kanojiya {
337*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct debug_info_table *tbl_ent;
338*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
339*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	tbl_ent = dump_info->tbl_ent;
340*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
341*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (len > tbl_ent->len - dump_info->tbl_ent_off)
342*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		return -EINVAL;
343*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
344*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	memcpy(dump_info->dump_addr + dump_info->dump_off, data, len);
345*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	dump_info->dump_off += len;
346*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	dump_info->tbl_ent_off += len;
347*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
348*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/*
349*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 * Current segment (a entry in table) of the crashdump is complete,
350*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 * move to next one
351*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 */
352*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (tbl_ent->len == dump_info->tbl_ent_off) {
353*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		dump_info->tbl_ent++;
354*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		dump_info->tbl_ent_off = 0;
355*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	}
356*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
357*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	return 0;
358*6bc1fe6cSPranjal Ramajor Asha Kanojiya }
359*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
360*6bc1fe6cSPranjal Ramajor Asha Kanojiya static void ssr_dump_worker(struct work_struct *work)
361*6bc1fe6cSPranjal Ramajor Asha Kanojiya {
362*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_crashdump *ssr_crash = container_of(work, struct ssr_crashdump, work);
363*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct qaic_device *qdev = ssr_crash->qdev;
364*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_memory_read_rsp *mem_rd_resp;
365*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct debug_info_table *tbl_ent;
366*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_dump_info *dump_info;
367*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	u64 dest_addr, dest_len;
368*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct _ssr_hdr *_hdr;
369*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_hdr hdr;
370*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	u64 data_len;
371*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	int ret;
372*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
373*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	mem_rd_resp = (struct ssr_memory_read_rsp *)ssr_crash->data;
374*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	_hdr = &mem_rd_resp->hdr;
375*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	hdr.cmd = le32_to_cpu(_hdr->cmd);
376*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	hdr.len = le32_to_cpu(_hdr->len);
377*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	hdr.dbc_id = le32_to_cpu(_hdr->dbc_id);
378*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
379*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (hdr.dbc_id != qdev->ssr_dbc)
380*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		goto reset_device;
381*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
382*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	dump_info = ssr_crash->dump_info;
383*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (!dump_info)
384*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		goto reset_device;
385*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
386*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (hdr.cmd != MEMORY_READ_RSP)
387*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		goto free_dump_info;
388*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
389*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (hdr.len > SSR_MEM_READ_DATA_SIZE)
390*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		goto free_dump_info;
391*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
392*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	data_len = hdr.len - sizeof(*mem_rd_resp);
393*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
394*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (dump_info->tbl_off < dump_info->tbl_len) /* Chunk belongs to table */
395*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		ret = ssr_copy_table(dump_info, mem_rd_resp->data, data_len);
396*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	else /* Chunk belongs to crashdump */
397*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		ret = ssr_copy_dump(dump_info, mem_rd_resp->data, data_len);
398*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
399*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (ret)
400*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		goto free_dump_info;
401*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
402*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (dump_info->tbl_off < dump_info->tbl_len) {
403*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		/* Continue downloading table */
404*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		dest_addr = dump_info->tbl_addr_dev + dump_info->tbl_off;
405*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		dest_len = min(SSR_MEM_READ_CHUNK_SIZE, dump_info->tbl_len - dump_info->tbl_off);
406*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		ret = mem_read_req(qdev, dest_addr, dest_len);
407*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	} else if (dump_info->dump_off < dump_info->dump_sz) {
408*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		/* Continue downloading crashdump */
409*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		tbl_ent = dump_info->tbl_ent;
410*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		dest_addr = tbl_ent->mem_base + dump_info->tbl_ent_off;
411*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		dest_len = min(SSR_MEM_READ_CHUNK_SIZE, tbl_ent->len - dump_info->tbl_ent_off);
412*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		ret = mem_read_req(qdev, dest_addr, dest_len);
413*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	} else {
414*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		/* Crashdump download complete */
415*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		ret = send_xfer_done(qdev, dump_info->resp->data, hdr.dbc_id);
416*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	}
417*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
418*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Most likely a MHI xfer has failed */
419*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (ret)
420*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		goto free_dump_info;
421*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
422*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	return;
423*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
424*6bc1fe6cSPranjal Ramajor Asha Kanojiya free_dump_info:
425*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Free the allocated memory */
426*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	free_ssr_dump_info(ssr_crash);
427*6bc1fe6cSPranjal Ramajor Asha Kanojiya reset_device:
428*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/*
429*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 * After subsystem crashes in device crashdump collection begins but
430*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 * something went wrong while collecting crashdump, now instead of
431*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 * handling this error we just reset the device as the best effort has
432*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 * been made
433*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 */
434*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	mhi_soc_reset(qdev->mhi_cntrl);
435*6bc1fe6cSPranjal Ramajor Asha Kanojiya }
436*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
437*6bc1fe6cSPranjal Ramajor Asha Kanojiya static struct ssr_dump_info *alloc_dump_info(struct qaic_device *qdev,
438*6bc1fe6cSPranjal Ramajor Asha Kanojiya 					     struct ssr_debug_transfer_info *debug_info)
439*6bc1fe6cSPranjal Ramajor Asha Kanojiya {
440*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_dump_info *dump_info;
441*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	int ret;
442*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
443*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	le64_to_cpus(&debug_info->tbl_len);
444*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	le64_to_cpus(&debug_info->tbl_addr);
445*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
446*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (debug_info->tbl_len == 0 ||
447*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	    debug_info->tbl_len % sizeof(struct debug_info_table) != 0) {
448*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		ret = -EINVAL;
449*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		goto out;
450*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	}
451*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
452*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Allocate SSR crashdump book keeping structure */
453*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	dump_info = kzalloc(sizeof(*dump_info), GFP_KERNEL);
454*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (!dump_info) {
455*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		ret = -ENOMEM;
456*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		goto out;
457*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	}
458*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
459*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Buffer used to send MEMORY READ request to device via MHI */
460*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	dump_info->read_buf_req = kzalloc(sizeof(*dump_info->read_buf_req), GFP_KERNEL);
461*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (!dump_info->read_buf_req) {
462*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		ret = -ENOMEM;
463*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		goto free_dump_info;
464*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	}
465*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
466*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* Crashdump meta table buffer */
467*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	dump_info->tbl_addr = vzalloc(debug_info->tbl_len);
468*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (!dump_info->tbl_addr) {
469*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		ret = -ENOMEM;
470*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		goto free_read_buf_req;
471*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	}
472*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
473*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	dump_info->tbl_addr_dev = debug_info->tbl_addr;
474*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	dump_info->tbl_len = debug_info->tbl_len;
475*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
476*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	return dump_info;
477*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
478*6bc1fe6cSPranjal Ramajor Asha Kanojiya free_read_buf_req:
479*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	kfree(dump_info->read_buf_req);
480*6bc1fe6cSPranjal Ramajor Asha Kanojiya free_dump_info:
481*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	kfree(dump_info);
482*6bc1fe6cSPranjal Ramajor Asha Kanojiya out:
483*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	return ERR_PTR(ret);
484*6bc1fe6cSPranjal Ramajor Asha Kanojiya }
485*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
486*6bc1fe6cSPranjal Ramajor Asha Kanojiya static int dbg_xfer_info_rsp(struct qaic_device *qdev, struct dma_bridge_chan *dbc,
487*6bc1fe6cSPranjal Ramajor Asha Kanojiya 			     struct ssr_debug_transfer_info *debug_info)
488*6bc1fe6cSPranjal Ramajor Asha Kanojiya {
489*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_debug_transfer_info_rsp *debug_rsp;
490*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_crashdump *ssr_crash = NULL;
491*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	int ret = 0, ret2;
492*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
493*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	debug_rsp = kmalloc(sizeof(*debug_rsp), GFP_KERNEL);
494*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (!debug_rsp)
495*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		return -ENOMEM;
496*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
497*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (!qdev->ssr_mhi_buf) {
498*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		ret = -ENOMEM;
499*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		goto send_rsp;
500*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	}
501*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
502*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (dbc->state != DBC_STATE_BEFORE_POWER_UP) {
503*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		ret = -EINVAL;
504*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		goto send_rsp;
505*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	}
506*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
507*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	ssr_crash = qdev->ssr_mhi_buf;
508*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	ssr_crash->dump_info = alloc_dump_info(qdev, debug_info);
509*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (IS_ERR(ssr_crash->dump_info)) {
510*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		ret = PTR_ERR(ssr_crash->dump_info);
511*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		ssr_crash->dump_info = NULL;
512*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	}
513*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
514*6bc1fe6cSPranjal Ramajor Asha Kanojiya send_rsp:
515*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	debug_rsp->hdr.cmd = cpu_to_le32(DEBUG_TRANSFER_INFO_RSP);
516*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	debug_rsp->hdr.len = cpu_to_le32(sizeof(*debug_rsp));
517*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	debug_rsp->hdr.dbc_id = cpu_to_le32(dbc->id);
518*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/*
519*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 * 0 = Return an ACK confirming the host is ready to download crashdump
520*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 * 1 = Return an NACK confirming the host is not ready to download crashdump
521*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 */
522*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	debug_rsp->ret = cpu_to_le32(ret ? 1 : 0);
523*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
524*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	ret2 = mhi_queue_buf(qdev->ssr_ch, DMA_TO_DEVICE, debug_rsp, sizeof(*debug_rsp), MHI_EOT);
525*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (ret2) {
526*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		free_ssr_dump_info(ssr_crash);
527*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		kfree(debug_rsp);
528*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		return ret2;
529*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	}
530*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
531*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	return ret;
532*6bc1fe6cSPranjal Ramajor Asha Kanojiya }
533*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
534*6bc1fe6cSPranjal Ramajor Asha Kanojiya static void dbg_xfer_done_rsp(struct qaic_device *qdev, struct dma_bridge_chan *dbc,
535*6bc1fe6cSPranjal Ramajor Asha Kanojiya 			      struct ssr_debug_transfer_done_rsp *xfer_rsp)
536*6bc1fe6cSPranjal Ramajor Asha Kanojiya {
537*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_crashdump *ssr_crash = qdev->ssr_mhi_buf;
538*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	u32 status = le32_to_cpu(xfer_rsp->ret);
539*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct device *dev = &qdev->pdev->dev;
540*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_dump_info *dump_info;
541*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
542*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	dump_info = ssr_crash->dump_info;
543*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (!dump_info)
544*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		return;
545*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
546*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (status) {
547*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		free_ssr_dump_info(ssr_crash);
548*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		return;
549*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	}
550*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
551*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	dev_coredumpv(dev, dump_info->dump_addr, dump_info->dump_sz, GFP_KERNEL);
552*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/* dev_coredumpv will free dump_info->dump_addr */
553*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	dump_info->dump_addr = NULL;
554*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	free_ssr_dump_info(ssr_crash);
5559675093aSJeffrey Hugo }
5569675093aSJeffrey Hugo 
5579675093aSJeffrey Hugo static void ssr_worker(struct work_struct *work)
5589675093aSJeffrey Hugo {
5599675093aSJeffrey Hugo 	struct ssr_resp *resp = container_of(work, struct ssr_resp, work);
5609675093aSJeffrey Hugo 	struct ssr_hdr *hdr = (struct ssr_hdr *)resp->data;
561*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_dump_info *dump_info = NULL;
5629675093aSJeffrey Hugo 	struct qaic_device *qdev = resp->qdev;
563*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_crashdump *ssr_crash;
5649675093aSJeffrey Hugo 	struct ssr_event_rsp *event_rsp;
5659675093aSJeffrey Hugo 	struct dma_bridge_chan *dbc;
5669675093aSJeffrey Hugo 	struct ssr_event *event;
5679675093aSJeffrey Hugo 	u32 ssr_event_ack;
5689675093aSJeffrey Hugo 	int ret;
5699675093aSJeffrey Hugo 
5709675093aSJeffrey Hugo 	le32_to_cpus(&hdr->cmd);
5719675093aSJeffrey Hugo 	le32_to_cpus(&hdr->len);
5729675093aSJeffrey Hugo 	le32_to_cpus(&hdr->dbc_id);
5739675093aSJeffrey Hugo 
5749675093aSJeffrey Hugo 	if (hdr->len > SSR_RESP_MSG_SZ)
5759675093aSJeffrey Hugo 		goto out;
5769675093aSJeffrey Hugo 
5779675093aSJeffrey Hugo 	if (hdr->dbc_id >= qdev->num_dbc)
5789675093aSJeffrey Hugo 		goto out;
5799675093aSJeffrey Hugo 
5809675093aSJeffrey Hugo 	dbc = &qdev->dbc[hdr->dbc_id];
5819675093aSJeffrey Hugo 
5829675093aSJeffrey Hugo 	switch (hdr->cmd) {
5839675093aSJeffrey Hugo 	case DEBUG_TRANSFER_INFO:
584*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		ret = dbg_xfer_info_rsp(qdev, dbc, (struct ssr_debug_transfer_info *)resp->data);
585*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		if (ret)
5869675093aSJeffrey Hugo 			break;
5879675093aSJeffrey Hugo 
588*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		ssr_crash = qdev->ssr_mhi_buf;
589*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		dump_info = ssr_crash->dump_info;
590*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		dump_info->dbc = dbc;
591*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		dump_info->resp = resp;
5929675093aSJeffrey Hugo 
593*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		/* Start by downloading debug table */
594*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		ret = mem_read_req(qdev, dump_info->tbl_addr_dev,
595*6bc1fe6cSPranjal Ramajor Asha Kanojiya 				   min(dump_info->tbl_len, SSR_MEM_READ_CHUNK_SIZE));
5969675093aSJeffrey Hugo 		if (ret) {
597*6bc1fe6cSPranjal Ramajor Asha Kanojiya 			free_ssr_dump_info(ssr_crash);
598*6bc1fe6cSPranjal Ramajor Asha Kanojiya 			break;
5999675093aSJeffrey Hugo 		}
600*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
601*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		/*
602*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		 * Till now everything went fine, which means that we will be
603*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		 * collecting crashdump chunk by chunk. Do not queue a response
604*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		 * buffer for SSR cmds till the crashdump is complete.
605*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		 */
6069675093aSJeffrey Hugo 		return;
6079675093aSJeffrey Hugo 	case SSR_EVENT:
6089675093aSJeffrey Hugo 		event = (struct ssr_event *)hdr;
6099675093aSJeffrey Hugo 		le32_to_cpus(&event->event);
6109675093aSJeffrey Hugo 		ssr_event_ack = event->event;
611*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		ssr_crash = qdev->ssr_mhi_buf;
6129675093aSJeffrey Hugo 
6139675093aSJeffrey Hugo 		switch (event->event) {
6149675093aSJeffrey Hugo 		case BEFORE_SHUTDOWN:
6159675093aSJeffrey Hugo 			set_dbc_state(qdev, hdr->dbc_id, DBC_STATE_BEFORE_SHUTDOWN);
6169675093aSJeffrey Hugo 			qaic_dbc_enter_ssr(qdev, hdr->dbc_id);
6179675093aSJeffrey Hugo 			break;
6189675093aSJeffrey Hugo 		case AFTER_SHUTDOWN:
6199675093aSJeffrey Hugo 			set_dbc_state(qdev, hdr->dbc_id, DBC_STATE_AFTER_SHUTDOWN);
6209675093aSJeffrey Hugo 			break;
6219675093aSJeffrey Hugo 		case BEFORE_POWER_UP:
6229675093aSJeffrey Hugo 			set_dbc_state(qdev, hdr->dbc_id, DBC_STATE_BEFORE_POWER_UP);
6239675093aSJeffrey Hugo 			break;
6249675093aSJeffrey Hugo 		case AFTER_POWER_UP:
625*6bc1fe6cSPranjal Ramajor Asha Kanojiya 			/*
626*6bc1fe6cSPranjal Ramajor Asha Kanojiya 			 * If dump info is a non NULL value it means that we
627*6bc1fe6cSPranjal Ramajor Asha Kanojiya 			 * have received this SSR event while downloading a
628*6bc1fe6cSPranjal Ramajor Asha Kanojiya 			 * crashdump for this DBC is still in progress. NACK
629*6bc1fe6cSPranjal Ramajor Asha Kanojiya 			 * the SSR event
630*6bc1fe6cSPranjal Ramajor Asha Kanojiya 			 */
631*6bc1fe6cSPranjal Ramajor Asha Kanojiya 			if (ssr_crash && ssr_crash->dump_info) {
632*6bc1fe6cSPranjal Ramajor Asha Kanojiya 				free_ssr_dump_info(ssr_crash);
633*6bc1fe6cSPranjal Ramajor Asha Kanojiya 				ssr_event_ack = SSR_EVENT_NACK;
634*6bc1fe6cSPranjal Ramajor Asha Kanojiya 				break;
635*6bc1fe6cSPranjal Ramajor Asha Kanojiya 			}
636*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
6379675093aSJeffrey Hugo 			set_dbc_state(qdev, hdr->dbc_id, DBC_STATE_AFTER_POWER_UP);
6389675093aSJeffrey Hugo 			break;
6399675093aSJeffrey Hugo 		default:
6409675093aSJeffrey Hugo 			break;
6419675093aSJeffrey Hugo 		}
6429675093aSJeffrey Hugo 
6439675093aSJeffrey Hugo 		event_rsp = kmalloc(sizeof(*event_rsp), GFP_KERNEL);
6449675093aSJeffrey Hugo 		if (!event_rsp)
6459675093aSJeffrey Hugo 			break;
6469675093aSJeffrey Hugo 
6479675093aSJeffrey Hugo 		event_rsp->hdr.cmd = cpu_to_le32(SSR_EVENT_RSP);
6489675093aSJeffrey Hugo 		event_rsp->hdr.len = cpu_to_le32(sizeof(*event_rsp));
6499675093aSJeffrey Hugo 		event_rsp->hdr.dbc_id = cpu_to_le32(hdr->dbc_id);
6509675093aSJeffrey Hugo 		event_rsp->event = cpu_to_le32(ssr_event_ack);
6519675093aSJeffrey Hugo 
6529675093aSJeffrey Hugo 		ret = mhi_queue_buf(qdev->ssr_ch, DMA_TO_DEVICE, event_rsp, sizeof(*event_rsp),
6539675093aSJeffrey Hugo 				    MHI_EOT);
6549675093aSJeffrey Hugo 		if (ret)
6559675093aSJeffrey Hugo 			kfree(event_rsp);
6569675093aSJeffrey Hugo 
657*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		if (event->event == AFTER_POWER_UP && ssr_event_ack != SSR_EVENT_NACK) {
6589675093aSJeffrey Hugo 			qaic_dbc_exit_ssr(qdev);
6599675093aSJeffrey Hugo 			set_dbc_state(qdev, hdr->dbc_id, DBC_STATE_IDLE);
6609675093aSJeffrey Hugo 		}
6619675093aSJeffrey Hugo 
6629675093aSJeffrey Hugo 		break;
663*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	case DEBUG_TRANSFER_DONE_RSP:
664*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		dbg_xfer_done_rsp(qdev, dbc, (struct ssr_debug_transfer_done_rsp *)hdr);
665*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		break;
6669675093aSJeffrey Hugo 	default:
6679675093aSJeffrey Hugo 		break;
6689675093aSJeffrey Hugo 	}
6699675093aSJeffrey Hugo 
6709675093aSJeffrey Hugo out:
6719675093aSJeffrey Hugo 	ret = mhi_queue_buf(qdev->ssr_ch, DMA_FROM_DEVICE, resp->data, SSR_RESP_MSG_SZ, MHI_EOT);
6729675093aSJeffrey Hugo 	if (ret)
6739675093aSJeffrey Hugo 		kfree(resp);
6749675093aSJeffrey Hugo }
6759675093aSJeffrey Hugo 
6769675093aSJeffrey Hugo static int qaic_ssr_mhi_probe(struct mhi_device *mhi_dev, const struct mhi_device_id *id)
6779675093aSJeffrey Hugo {
6789675093aSJeffrey Hugo 	struct qaic_device *qdev = pci_get_drvdata(to_pci_dev(mhi_dev->mhi_cntrl->cntrl_dev));
6799675093aSJeffrey Hugo 	struct ssr_resp *resp;
6809675093aSJeffrey Hugo 	int ret;
6819675093aSJeffrey Hugo 
6829675093aSJeffrey Hugo 	ret = mhi_prepare_for_transfer(mhi_dev);
6839675093aSJeffrey Hugo 	if (ret)
6849675093aSJeffrey Hugo 		return ret;
6859675093aSJeffrey Hugo 
6869675093aSJeffrey Hugo 	resp = kzalloc(sizeof(*resp) + SSR_RESP_MSG_SZ, GFP_KERNEL);
6879675093aSJeffrey Hugo 	if (!resp) {
6889675093aSJeffrey Hugo 		mhi_unprepare_from_transfer(mhi_dev);
6899675093aSJeffrey Hugo 		return -ENOMEM;
6909675093aSJeffrey Hugo 	}
6919675093aSJeffrey Hugo 
6929675093aSJeffrey Hugo 	resp->qdev = qdev;
6939675093aSJeffrey Hugo 	INIT_WORK(&resp->work, ssr_worker);
6949675093aSJeffrey Hugo 
6959675093aSJeffrey Hugo 	ret = mhi_queue_buf(mhi_dev, DMA_FROM_DEVICE, resp->data, SSR_RESP_MSG_SZ, MHI_EOT);
6969675093aSJeffrey Hugo 	if (ret) {
6979675093aSJeffrey Hugo 		kfree(resp);
6989675093aSJeffrey Hugo 		mhi_unprepare_from_transfer(mhi_dev);
6999675093aSJeffrey Hugo 		return ret;
7009675093aSJeffrey Hugo 	}
7019675093aSJeffrey Hugo 
7029675093aSJeffrey Hugo 	dev_set_drvdata(&mhi_dev->dev, qdev);
7039675093aSJeffrey Hugo 	qdev->ssr_ch = mhi_dev;
7049675093aSJeffrey Hugo 
7059675093aSJeffrey Hugo 	return 0;
7069675093aSJeffrey Hugo }
7079675093aSJeffrey Hugo 
7089675093aSJeffrey Hugo static void qaic_ssr_mhi_remove(struct mhi_device *mhi_dev)
7099675093aSJeffrey Hugo {
7109675093aSJeffrey Hugo 	struct qaic_device *qdev;
7119675093aSJeffrey Hugo 
7129675093aSJeffrey Hugo 	qdev = dev_get_drvdata(&mhi_dev->dev);
7139675093aSJeffrey Hugo 	mhi_unprepare_from_transfer(qdev->ssr_ch);
7149675093aSJeffrey Hugo 	qdev->ssr_ch = NULL;
7159675093aSJeffrey Hugo }
7169675093aSJeffrey Hugo 
7179675093aSJeffrey Hugo static void qaic_ssr_mhi_ul_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result)
7189675093aSJeffrey Hugo {
719*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct qaic_device *qdev = dev_get_drvdata(&mhi_dev->dev);
720*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_crashdump *ssr_crash = qdev->ssr_mhi_buf;
721*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct _ssr_hdr *hdr = mhi_result->buf_addr;
722*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_dump_info *dump_info;
723*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
724*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (mhi_result->transaction_status) {
725*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		kfree(mhi_result->buf_addr);
726*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		return;
727*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	}
728*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
729*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/*
730*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 * MEMORY READ is used to download crashdump. And crashdump is
731*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 * downloaded chunk by chunk in a series of MEMORY READ SSR commands.
732*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 * Hence to avoid too many kmalloc() and kfree() of the same MEMORY READ
733*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 * request buffer, we allocate only one such buffer and free it only
734*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 * once.
735*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 */
736*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (le32_to_cpu(hdr->cmd) == MEMORY_READ) {
737*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		dump_info = ssr_crash->dump_info;
738*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		if (dump_info) {
739*6bc1fe6cSPranjal Ramajor Asha Kanojiya 			dump_info->read_buf_req_queued = false;
740*6bc1fe6cSPranjal Ramajor Asha Kanojiya 			return;
741*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		}
742*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	}
743*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
7449675093aSJeffrey Hugo 	kfree(mhi_result->buf_addr);
7459675093aSJeffrey Hugo }
7469675093aSJeffrey Hugo 
7479675093aSJeffrey Hugo static void qaic_ssr_mhi_dl_xfer_cb(struct mhi_device *mhi_dev, struct mhi_result *mhi_result)
7489675093aSJeffrey Hugo {
7499675093aSJeffrey Hugo 	struct ssr_resp *resp = container_of(mhi_result->buf_addr, struct ssr_resp, data);
7509675093aSJeffrey Hugo 	struct qaic_device *qdev = dev_get_drvdata(&mhi_dev->dev);
751*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_crashdump *ssr_crash = qdev->ssr_mhi_buf;
752*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	bool memory_read_rsp = false;
753*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
754*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (ssr_crash && ssr_crash->data == mhi_result->buf_addr)
755*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		memory_read_rsp = true;
7569675093aSJeffrey Hugo 
7579675093aSJeffrey Hugo 	if (mhi_result->transaction_status) {
758*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		/* Do not free SSR crashdump buffer as it allocated via managed APIs */
759*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		if (!memory_read_rsp)
7609675093aSJeffrey Hugo 			kfree(resp);
7619675093aSJeffrey Hugo 		return;
7629675093aSJeffrey Hugo 	}
763*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
764*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (memory_read_rsp)
765*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		queue_work(qdev->ssr_wq, &ssr_crash->work);
766*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	else
7679675093aSJeffrey Hugo 		queue_work(qdev->ssr_wq, &resp->work);
7689675093aSJeffrey Hugo }
7699675093aSJeffrey Hugo 
7709675093aSJeffrey Hugo static const struct mhi_device_id qaic_ssr_mhi_match_table[] = {
7719675093aSJeffrey Hugo 	{ .chan = "QAIC_SSR", },
7729675093aSJeffrey Hugo 	{},
7739675093aSJeffrey Hugo };
7749675093aSJeffrey Hugo 
7759675093aSJeffrey Hugo static struct mhi_driver qaic_ssr_mhi_driver = {
7769675093aSJeffrey Hugo 	.id_table = qaic_ssr_mhi_match_table,
7779675093aSJeffrey Hugo 	.remove = qaic_ssr_mhi_remove,
7789675093aSJeffrey Hugo 	.probe = qaic_ssr_mhi_probe,
7799675093aSJeffrey Hugo 	.ul_xfer_cb = qaic_ssr_mhi_ul_xfer_cb,
7809675093aSJeffrey Hugo 	.dl_xfer_cb = qaic_ssr_mhi_dl_xfer_cb,
7819675093aSJeffrey Hugo 	.driver = {
7829675093aSJeffrey Hugo 		.name = "qaic_ssr",
7839675093aSJeffrey Hugo 	},
7849675093aSJeffrey Hugo };
7859675093aSJeffrey Hugo 
786*6bc1fe6cSPranjal Ramajor Asha Kanojiya int qaic_ssr_init(struct qaic_device *qdev, struct drm_device *drm)
7879675093aSJeffrey Hugo {
788*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	struct ssr_crashdump *ssr_crash;
789*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
7909675093aSJeffrey Hugo 	qdev->ssr_dbc = QAIC_SSR_DBC_SENTINEL;
791*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
792*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	/*
793*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 * Device requests only one SSR at a time. So allocating only one
794*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 * buffer to download crashdump is good enough.
795*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	 */
796*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	ssr_crash = drmm_kzalloc(drm, SSR_MHI_BUF_SIZE, GFP_KERNEL);
797*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	if (!ssr_crash)
798*6bc1fe6cSPranjal Ramajor Asha Kanojiya 		return -ENOMEM;
799*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
800*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	ssr_crash->qdev = qdev;
801*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	INIT_WORK(&ssr_crash->work, ssr_dump_worker);
802*6bc1fe6cSPranjal Ramajor Asha Kanojiya 	qdev->ssr_mhi_buf = ssr_crash;
803*6bc1fe6cSPranjal Ramajor Asha Kanojiya 
8049675093aSJeffrey Hugo 	return 0;
8059675093aSJeffrey Hugo }
8069675093aSJeffrey Hugo 
8079675093aSJeffrey Hugo int qaic_ssr_register(void)
8089675093aSJeffrey Hugo {
8099675093aSJeffrey Hugo 	return mhi_driver_register(&qaic_ssr_mhi_driver);
8109675093aSJeffrey Hugo }
8119675093aSJeffrey Hugo 
8129675093aSJeffrey Hugo void qaic_ssr_unregister(void)
8139675093aSJeffrey Hugo {
8149675093aSJeffrey Hugo 	mhi_driver_unregister(&qaic_ssr_mhi_driver);
8159675093aSJeffrey Hugo }
816