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