1*4fd4ca98SLizhi Hou // SPDX-License-Identifier: GPL-2.0 2*4fd4ca98SLizhi Hou /* 3*4fd4ca98SLizhi Hou * Copyright (C) 2023-2024, Advanced Micro Devices, Inc. 4*4fd4ca98SLizhi Hou */ 5*4fd4ca98SLizhi Hou 6*4fd4ca98SLizhi Hou #include <drm/drm_cache.h> 7*4fd4ca98SLizhi Hou #include <drm/drm_device.h> 8*4fd4ca98SLizhi Hou #include <drm/drm_print.h> 9*4fd4ca98SLizhi Hou #include <drm/gpu_scheduler.h> 10*4fd4ca98SLizhi Hou #include <linux/dma-mapping.h> 11*4fd4ca98SLizhi Hou #include <linux/kthread.h> 12*4fd4ca98SLizhi Hou #include <linux/kernel.h> 13*4fd4ca98SLizhi Hou 14*4fd4ca98SLizhi Hou #include "aie2_msg_priv.h" 15*4fd4ca98SLizhi Hou #include "aie2_pci.h" 16*4fd4ca98SLizhi Hou #include "amdxdna_mailbox.h" 17*4fd4ca98SLizhi Hou #include "amdxdna_pci_drv.h" 18*4fd4ca98SLizhi Hou 19*4fd4ca98SLizhi Hou struct async_event { 20*4fd4ca98SLizhi Hou struct amdxdna_dev_hdl *ndev; 21*4fd4ca98SLizhi Hou struct async_event_msg_resp resp; 22*4fd4ca98SLizhi Hou struct workqueue_struct *wq; 23*4fd4ca98SLizhi Hou struct work_struct work; 24*4fd4ca98SLizhi Hou u8 *buf; 25*4fd4ca98SLizhi Hou dma_addr_t addr; 26*4fd4ca98SLizhi Hou u32 size; 27*4fd4ca98SLizhi Hou }; 28*4fd4ca98SLizhi Hou 29*4fd4ca98SLizhi Hou struct async_events { 30*4fd4ca98SLizhi Hou struct workqueue_struct *wq; 31*4fd4ca98SLizhi Hou u8 *buf; 32*4fd4ca98SLizhi Hou dma_addr_t addr; 33*4fd4ca98SLizhi Hou u32 size; 34*4fd4ca98SLizhi Hou u32 event_cnt; 35*4fd4ca98SLizhi Hou struct async_event event[] __counted_by(event_cnt); 36*4fd4ca98SLizhi Hou }; 37*4fd4ca98SLizhi Hou 38*4fd4ca98SLizhi Hou /* 39*4fd4ca98SLizhi Hou * Below enum, struct and lookup tables are porting from XAIE util header file. 40*4fd4ca98SLizhi Hou * 41*4fd4ca98SLizhi Hou * Below data is defined by AIE device and it is used for decode error message 42*4fd4ca98SLizhi Hou * from the device. 43*4fd4ca98SLizhi Hou */ 44*4fd4ca98SLizhi Hou 45*4fd4ca98SLizhi Hou enum aie_module_type { 46*4fd4ca98SLizhi Hou AIE_MEM_MOD = 0, 47*4fd4ca98SLizhi Hou AIE_CORE_MOD, 48*4fd4ca98SLizhi Hou AIE_PL_MOD, 49*4fd4ca98SLizhi Hou }; 50*4fd4ca98SLizhi Hou 51*4fd4ca98SLizhi Hou enum aie_error_category { 52*4fd4ca98SLizhi Hou AIE_ERROR_SATURATION = 0, 53*4fd4ca98SLizhi Hou AIE_ERROR_FP, 54*4fd4ca98SLizhi Hou AIE_ERROR_STREAM, 55*4fd4ca98SLizhi Hou AIE_ERROR_ACCESS, 56*4fd4ca98SLizhi Hou AIE_ERROR_BUS, 57*4fd4ca98SLizhi Hou AIE_ERROR_INSTRUCTION, 58*4fd4ca98SLizhi Hou AIE_ERROR_ECC, 59*4fd4ca98SLizhi Hou AIE_ERROR_LOCK, 60*4fd4ca98SLizhi Hou AIE_ERROR_DMA, 61*4fd4ca98SLizhi Hou AIE_ERROR_MEM_PARITY, 62*4fd4ca98SLizhi Hou /* Unknown is not from XAIE, added for better category */ 63*4fd4ca98SLizhi Hou AIE_ERROR_UNKNOWN, 64*4fd4ca98SLizhi Hou }; 65*4fd4ca98SLizhi Hou 66*4fd4ca98SLizhi Hou /* Don't pack, unless XAIE side changed */ 67*4fd4ca98SLizhi Hou struct aie_error { 68*4fd4ca98SLizhi Hou __u8 row; 69*4fd4ca98SLizhi Hou __u8 col; 70*4fd4ca98SLizhi Hou __u32 mod_type; 71*4fd4ca98SLizhi Hou __u8 event_id; 72*4fd4ca98SLizhi Hou }; 73*4fd4ca98SLizhi Hou 74*4fd4ca98SLizhi Hou struct aie_err_info { 75*4fd4ca98SLizhi Hou u32 err_cnt; 76*4fd4ca98SLizhi Hou u32 ret_code; 77*4fd4ca98SLizhi Hou u32 rsvd; 78*4fd4ca98SLizhi Hou struct aie_error payload[] __counted_by(err_cnt); 79*4fd4ca98SLizhi Hou }; 80*4fd4ca98SLizhi Hou 81*4fd4ca98SLizhi Hou struct aie_event_category { 82*4fd4ca98SLizhi Hou u8 event_id; 83*4fd4ca98SLizhi Hou enum aie_error_category category; 84*4fd4ca98SLizhi Hou }; 85*4fd4ca98SLizhi Hou 86*4fd4ca98SLizhi Hou #define EVENT_CATEGORY(id, cat) { id, cat } 87*4fd4ca98SLizhi Hou static const struct aie_event_category aie_ml_mem_event_cat[] = { 88*4fd4ca98SLizhi Hou EVENT_CATEGORY(88U, AIE_ERROR_ECC), 89*4fd4ca98SLizhi Hou EVENT_CATEGORY(90U, AIE_ERROR_ECC), 90*4fd4ca98SLizhi Hou EVENT_CATEGORY(91U, AIE_ERROR_MEM_PARITY), 91*4fd4ca98SLizhi Hou EVENT_CATEGORY(92U, AIE_ERROR_MEM_PARITY), 92*4fd4ca98SLizhi Hou EVENT_CATEGORY(93U, AIE_ERROR_MEM_PARITY), 93*4fd4ca98SLizhi Hou EVENT_CATEGORY(94U, AIE_ERROR_MEM_PARITY), 94*4fd4ca98SLizhi Hou EVENT_CATEGORY(95U, AIE_ERROR_MEM_PARITY), 95*4fd4ca98SLizhi Hou EVENT_CATEGORY(96U, AIE_ERROR_MEM_PARITY), 96*4fd4ca98SLizhi Hou EVENT_CATEGORY(97U, AIE_ERROR_DMA), 97*4fd4ca98SLizhi Hou EVENT_CATEGORY(98U, AIE_ERROR_DMA), 98*4fd4ca98SLizhi Hou EVENT_CATEGORY(99U, AIE_ERROR_DMA), 99*4fd4ca98SLizhi Hou EVENT_CATEGORY(100U, AIE_ERROR_DMA), 100*4fd4ca98SLizhi Hou EVENT_CATEGORY(101U, AIE_ERROR_LOCK), 101*4fd4ca98SLizhi Hou }; 102*4fd4ca98SLizhi Hou 103*4fd4ca98SLizhi Hou static const struct aie_event_category aie_ml_core_event_cat[] = { 104*4fd4ca98SLizhi Hou EVENT_CATEGORY(55U, AIE_ERROR_ACCESS), 105*4fd4ca98SLizhi Hou EVENT_CATEGORY(56U, AIE_ERROR_STREAM), 106*4fd4ca98SLizhi Hou EVENT_CATEGORY(57U, AIE_ERROR_STREAM), 107*4fd4ca98SLizhi Hou EVENT_CATEGORY(58U, AIE_ERROR_BUS), 108*4fd4ca98SLizhi Hou EVENT_CATEGORY(59U, AIE_ERROR_INSTRUCTION), 109*4fd4ca98SLizhi Hou EVENT_CATEGORY(60U, AIE_ERROR_ACCESS), 110*4fd4ca98SLizhi Hou EVENT_CATEGORY(62U, AIE_ERROR_ECC), 111*4fd4ca98SLizhi Hou EVENT_CATEGORY(64U, AIE_ERROR_ECC), 112*4fd4ca98SLizhi Hou EVENT_CATEGORY(65U, AIE_ERROR_ACCESS), 113*4fd4ca98SLizhi Hou EVENT_CATEGORY(66U, AIE_ERROR_ACCESS), 114*4fd4ca98SLizhi Hou EVENT_CATEGORY(67U, AIE_ERROR_LOCK), 115*4fd4ca98SLizhi Hou EVENT_CATEGORY(70U, AIE_ERROR_INSTRUCTION), 116*4fd4ca98SLizhi Hou EVENT_CATEGORY(71U, AIE_ERROR_STREAM), 117*4fd4ca98SLizhi Hou EVENT_CATEGORY(72U, AIE_ERROR_BUS), 118*4fd4ca98SLizhi Hou }; 119*4fd4ca98SLizhi Hou 120*4fd4ca98SLizhi Hou static const struct aie_event_category aie_ml_mem_tile_event_cat[] = { 121*4fd4ca98SLizhi Hou EVENT_CATEGORY(130U, AIE_ERROR_ECC), 122*4fd4ca98SLizhi Hou EVENT_CATEGORY(132U, AIE_ERROR_ECC), 123*4fd4ca98SLizhi Hou EVENT_CATEGORY(133U, AIE_ERROR_DMA), 124*4fd4ca98SLizhi Hou EVENT_CATEGORY(134U, AIE_ERROR_DMA), 125*4fd4ca98SLizhi Hou EVENT_CATEGORY(135U, AIE_ERROR_STREAM), 126*4fd4ca98SLizhi Hou EVENT_CATEGORY(136U, AIE_ERROR_STREAM), 127*4fd4ca98SLizhi Hou EVENT_CATEGORY(137U, AIE_ERROR_STREAM), 128*4fd4ca98SLizhi Hou EVENT_CATEGORY(138U, AIE_ERROR_BUS), 129*4fd4ca98SLizhi Hou EVENT_CATEGORY(139U, AIE_ERROR_LOCK), 130*4fd4ca98SLizhi Hou }; 131*4fd4ca98SLizhi Hou 132*4fd4ca98SLizhi Hou static const struct aie_event_category aie_ml_shim_tile_event_cat[] = { 133*4fd4ca98SLizhi Hou EVENT_CATEGORY(64U, AIE_ERROR_BUS), 134*4fd4ca98SLizhi Hou EVENT_CATEGORY(65U, AIE_ERROR_STREAM), 135*4fd4ca98SLizhi Hou EVENT_CATEGORY(66U, AIE_ERROR_STREAM), 136*4fd4ca98SLizhi Hou EVENT_CATEGORY(67U, AIE_ERROR_BUS), 137*4fd4ca98SLizhi Hou EVENT_CATEGORY(68U, AIE_ERROR_BUS), 138*4fd4ca98SLizhi Hou EVENT_CATEGORY(69U, AIE_ERROR_BUS), 139*4fd4ca98SLizhi Hou EVENT_CATEGORY(70U, AIE_ERROR_BUS), 140*4fd4ca98SLizhi Hou EVENT_CATEGORY(71U, AIE_ERROR_BUS), 141*4fd4ca98SLizhi Hou EVENT_CATEGORY(72U, AIE_ERROR_DMA), 142*4fd4ca98SLizhi Hou EVENT_CATEGORY(73U, AIE_ERROR_DMA), 143*4fd4ca98SLizhi Hou EVENT_CATEGORY(74U, AIE_ERROR_LOCK), 144*4fd4ca98SLizhi Hou }; 145*4fd4ca98SLizhi Hou 146*4fd4ca98SLizhi Hou static enum aie_error_category 147*4fd4ca98SLizhi Hou aie_get_error_category(u8 row, u8 event_id, enum aie_module_type mod_type) 148*4fd4ca98SLizhi Hou { 149*4fd4ca98SLizhi Hou const struct aie_event_category *lut; 150*4fd4ca98SLizhi Hou int num_entry; 151*4fd4ca98SLizhi Hou int i; 152*4fd4ca98SLizhi Hou 153*4fd4ca98SLizhi Hou switch (mod_type) { 154*4fd4ca98SLizhi Hou case AIE_PL_MOD: 155*4fd4ca98SLizhi Hou lut = aie_ml_shim_tile_event_cat; 156*4fd4ca98SLizhi Hou num_entry = ARRAY_SIZE(aie_ml_shim_tile_event_cat); 157*4fd4ca98SLizhi Hou break; 158*4fd4ca98SLizhi Hou case AIE_CORE_MOD: 159*4fd4ca98SLizhi Hou lut = aie_ml_core_event_cat; 160*4fd4ca98SLizhi Hou num_entry = ARRAY_SIZE(aie_ml_core_event_cat); 161*4fd4ca98SLizhi Hou break; 162*4fd4ca98SLizhi Hou case AIE_MEM_MOD: 163*4fd4ca98SLizhi Hou if (row == 1) { 164*4fd4ca98SLizhi Hou lut = aie_ml_mem_tile_event_cat; 165*4fd4ca98SLizhi Hou num_entry = ARRAY_SIZE(aie_ml_mem_tile_event_cat); 166*4fd4ca98SLizhi Hou } else { 167*4fd4ca98SLizhi Hou lut = aie_ml_mem_event_cat; 168*4fd4ca98SLizhi Hou num_entry = ARRAY_SIZE(aie_ml_mem_event_cat); 169*4fd4ca98SLizhi Hou } 170*4fd4ca98SLizhi Hou break; 171*4fd4ca98SLizhi Hou default: 172*4fd4ca98SLizhi Hou return AIE_ERROR_UNKNOWN; 173*4fd4ca98SLizhi Hou } 174*4fd4ca98SLizhi Hou 175*4fd4ca98SLizhi Hou for (i = 0; i < num_entry; i++) { 176*4fd4ca98SLizhi Hou if (event_id != lut[i].event_id) 177*4fd4ca98SLizhi Hou continue; 178*4fd4ca98SLizhi Hou 179*4fd4ca98SLizhi Hou return lut[i].category; 180*4fd4ca98SLizhi Hou } 181*4fd4ca98SLizhi Hou 182*4fd4ca98SLizhi Hou return AIE_ERROR_UNKNOWN; 183*4fd4ca98SLizhi Hou } 184*4fd4ca98SLizhi Hou 185*4fd4ca98SLizhi Hou static u32 aie2_error_backtrack(struct amdxdna_dev_hdl *ndev, void *err_info, u32 num_err) 186*4fd4ca98SLizhi Hou { 187*4fd4ca98SLizhi Hou struct aie_error *errs = err_info; 188*4fd4ca98SLizhi Hou u32 err_col = 0; /* assume that AIE has less than 32 columns */ 189*4fd4ca98SLizhi Hou int i; 190*4fd4ca98SLizhi Hou 191*4fd4ca98SLizhi Hou /* Get err column bitmap */ 192*4fd4ca98SLizhi Hou for (i = 0; i < num_err; i++) { 193*4fd4ca98SLizhi Hou struct aie_error *err = &errs[i]; 194*4fd4ca98SLizhi Hou enum aie_error_category cat; 195*4fd4ca98SLizhi Hou 196*4fd4ca98SLizhi Hou cat = aie_get_error_category(err->row, err->event_id, err->mod_type); 197*4fd4ca98SLizhi Hou XDNA_ERR(ndev->xdna, "Row: %d, Col: %d, module %d, event ID %d, category %d", 198*4fd4ca98SLizhi Hou err->row, err->col, err->mod_type, 199*4fd4ca98SLizhi Hou err->event_id, cat); 200*4fd4ca98SLizhi Hou 201*4fd4ca98SLizhi Hou if (err->col >= 32) { 202*4fd4ca98SLizhi Hou XDNA_WARN(ndev->xdna, "Invalid column number"); 203*4fd4ca98SLizhi Hou break; 204*4fd4ca98SLizhi Hou } 205*4fd4ca98SLizhi Hou 206*4fd4ca98SLizhi Hou err_col |= (1 << err->col); 207*4fd4ca98SLizhi Hou } 208*4fd4ca98SLizhi Hou 209*4fd4ca98SLizhi Hou return err_col; 210*4fd4ca98SLizhi Hou } 211*4fd4ca98SLizhi Hou 212*4fd4ca98SLizhi Hou static int aie2_error_async_cb(void *handle, const u32 *data, size_t size) 213*4fd4ca98SLizhi Hou { 214*4fd4ca98SLizhi Hou struct async_event_msg_resp *resp; 215*4fd4ca98SLizhi Hou struct async_event *e = handle; 216*4fd4ca98SLizhi Hou 217*4fd4ca98SLizhi Hou if (data) { 218*4fd4ca98SLizhi Hou resp = (struct async_event_msg_resp *)data; 219*4fd4ca98SLizhi Hou e->resp.type = resp->type; 220*4fd4ca98SLizhi Hou wmb(); /* Update status in the end, so that no lock for here */ 221*4fd4ca98SLizhi Hou e->resp.status = resp->status; 222*4fd4ca98SLizhi Hou } 223*4fd4ca98SLizhi Hou queue_work(e->wq, &e->work); 224*4fd4ca98SLizhi Hou return 0; 225*4fd4ca98SLizhi Hou } 226*4fd4ca98SLizhi Hou 227*4fd4ca98SLizhi Hou static int aie2_error_event_send(struct async_event *e) 228*4fd4ca98SLizhi Hou { 229*4fd4ca98SLizhi Hou drm_clflush_virt_range(e->buf, e->size); /* device can access */ 230*4fd4ca98SLizhi Hou return aie2_register_asyn_event_msg(e->ndev, e->addr, e->size, e, 231*4fd4ca98SLizhi Hou aie2_error_async_cb); 232*4fd4ca98SLizhi Hou } 233*4fd4ca98SLizhi Hou 234*4fd4ca98SLizhi Hou static void aie2_error_worker(struct work_struct *err_work) 235*4fd4ca98SLizhi Hou { 236*4fd4ca98SLizhi Hou struct aie_err_info *info; 237*4fd4ca98SLizhi Hou struct amdxdna_dev *xdna; 238*4fd4ca98SLizhi Hou struct async_event *e; 239*4fd4ca98SLizhi Hou u32 max_err; 240*4fd4ca98SLizhi Hou u32 err_col; 241*4fd4ca98SLizhi Hou 242*4fd4ca98SLizhi Hou e = container_of(err_work, struct async_event, work); 243*4fd4ca98SLizhi Hou 244*4fd4ca98SLizhi Hou xdna = e->ndev->xdna; 245*4fd4ca98SLizhi Hou 246*4fd4ca98SLizhi Hou if (e->resp.status == MAX_AIE2_STATUS_CODE) 247*4fd4ca98SLizhi Hou return; 248*4fd4ca98SLizhi Hou 249*4fd4ca98SLizhi Hou e->resp.status = MAX_AIE2_STATUS_CODE; 250*4fd4ca98SLizhi Hou 251*4fd4ca98SLizhi Hou print_hex_dump_debug("AIE error: ", DUMP_PREFIX_OFFSET, 16, 4, 252*4fd4ca98SLizhi Hou e->buf, 0x100, false); 253*4fd4ca98SLizhi Hou 254*4fd4ca98SLizhi Hou info = (struct aie_err_info *)e->buf; 255*4fd4ca98SLizhi Hou XDNA_DBG(xdna, "Error count %d return code %d", info->err_cnt, info->ret_code); 256*4fd4ca98SLizhi Hou 257*4fd4ca98SLizhi Hou max_err = (e->size - sizeof(*info)) / sizeof(struct aie_error); 258*4fd4ca98SLizhi Hou if (unlikely(info->err_cnt > max_err)) { 259*4fd4ca98SLizhi Hou WARN_ONCE(1, "Error count too large %d\n", info->err_cnt); 260*4fd4ca98SLizhi Hou return; 261*4fd4ca98SLizhi Hou } 262*4fd4ca98SLizhi Hou err_col = aie2_error_backtrack(e->ndev, info->payload, info->err_cnt); 263*4fd4ca98SLizhi Hou if (!err_col) { 264*4fd4ca98SLizhi Hou XDNA_WARN(xdna, "Did not get error column"); 265*4fd4ca98SLizhi Hou return; 266*4fd4ca98SLizhi Hou } 267*4fd4ca98SLizhi Hou 268*4fd4ca98SLizhi Hou mutex_lock(&xdna->dev_lock); 269*4fd4ca98SLizhi Hou /* Re-sent this event to firmware */ 270*4fd4ca98SLizhi Hou if (aie2_error_event_send(e)) 271*4fd4ca98SLizhi Hou XDNA_WARN(xdna, "Unable to register async event"); 272*4fd4ca98SLizhi Hou mutex_unlock(&xdna->dev_lock); 273*4fd4ca98SLizhi Hou } 274*4fd4ca98SLizhi Hou 275*4fd4ca98SLizhi Hou int aie2_error_async_events_send(struct amdxdna_dev_hdl *ndev) 276*4fd4ca98SLizhi Hou { 277*4fd4ca98SLizhi Hou struct amdxdna_dev *xdna = ndev->xdna; 278*4fd4ca98SLizhi Hou struct async_event *e; 279*4fd4ca98SLizhi Hou int i, ret; 280*4fd4ca98SLizhi Hou 281*4fd4ca98SLizhi Hou drm_WARN_ON(&xdna->ddev, !mutex_is_locked(&xdna->dev_lock)); 282*4fd4ca98SLizhi Hou for (i = 0; i < ndev->async_events->event_cnt; i++) { 283*4fd4ca98SLizhi Hou e = &ndev->async_events->event[i]; 284*4fd4ca98SLizhi Hou ret = aie2_error_event_send(e); 285*4fd4ca98SLizhi Hou if (ret) 286*4fd4ca98SLizhi Hou return ret; 287*4fd4ca98SLizhi Hou } 288*4fd4ca98SLizhi Hou 289*4fd4ca98SLizhi Hou return 0; 290*4fd4ca98SLizhi Hou } 291*4fd4ca98SLizhi Hou 292*4fd4ca98SLizhi Hou void aie2_error_async_events_free(struct amdxdna_dev_hdl *ndev) 293*4fd4ca98SLizhi Hou { 294*4fd4ca98SLizhi Hou struct amdxdna_dev *xdna = ndev->xdna; 295*4fd4ca98SLizhi Hou struct async_events *events; 296*4fd4ca98SLizhi Hou 297*4fd4ca98SLizhi Hou events = ndev->async_events; 298*4fd4ca98SLizhi Hou 299*4fd4ca98SLizhi Hou mutex_unlock(&xdna->dev_lock); 300*4fd4ca98SLizhi Hou destroy_workqueue(events->wq); 301*4fd4ca98SLizhi Hou mutex_lock(&xdna->dev_lock); 302*4fd4ca98SLizhi Hou 303*4fd4ca98SLizhi Hou dma_free_noncoherent(xdna->ddev.dev, events->size, events->buf, 304*4fd4ca98SLizhi Hou events->addr, DMA_FROM_DEVICE); 305*4fd4ca98SLizhi Hou kfree(events); 306*4fd4ca98SLizhi Hou } 307*4fd4ca98SLizhi Hou 308*4fd4ca98SLizhi Hou int aie2_error_async_events_alloc(struct amdxdna_dev_hdl *ndev) 309*4fd4ca98SLizhi Hou { 310*4fd4ca98SLizhi Hou struct amdxdna_dev *xdna = ndev->xdna; 311*4fd4ca98SLizhi Hou u32 total_col = ndev->total_col; 312*4fd4ca98SLizhi Hou u32 total_size = ASYNC_BUF_SIZE * total_col; 313*4fd4ca98SLizhi Hou struct async_events *events; 314*4fd4ca98SLizhi Hou int i, ret; 315*4fd4ca98SLizhi Hou 316*4fd4ca98SLizhi Hou events = kzalloc(struct_size(events, event, total_col), GFP_KERNEL); 317*4fd4ca98SLizhi Hou if (!events) 318*4fd4ca98SLizhi Hou return -ENOMEM; 319*4fd4ca98SLizhi Hou 320*4fd4ca98SLizhi Hou events->buf = dma_alloc_noncoherent(xdna->ddev.dev, total_size, &events->addr, 321*4fd4ca98SLizhi Hou DMA_FROM_DEVICE, GFP_KERNEL); 322*4fd4ca98SLizhi Hou if (!events->buf) { 323*4fd4ca98SLizhi Hou ret = -ENOMEM; 324*4fd4ca98SLizhi Hou goto free_events; 325*4fd4ca98SLizhi Hou } 326*4fd4ca98SLizhi Hou events->size = total_size; 327*4fd4ca98SLizhi Hou events->event_cnt = total_col; 328*4fd4ca98SLizhi Hou 329*4fd4ca98SLizhi Hou events->wq = alloc_ordered_workqueue("async_wq", 0); 330*4fd4ca98SLizhi Hou if (!events->wq) { 331*4fd4ca98SLizhi Hou ret = -ENOMEM; 332*4fd4ca98SLizhi Hou goto free_buf; 333*4fd4ca98SLizhi Hou } 334*4fd4ca98SLizhi Hou 335*4fd4ca98SLizhi Hou for (i = 0; i < events->event_cnt; i++) { 336*4fd4ca98SLizhi Hou struct async_event *e = &events->event[i]; 337*4fd4ca98SLizhi Hou u32 offset = i * ASYNC_BUF_SIZE; 338*4fd4ca98SLizhi Hou 339*4fd4ca98SLizhi Hou e->ndev = ndev; 340*4fd4ca98SLizhi Hou e->wq = events->wq; 341*4fd4ca98SLizhi Hou e->buf = &events->buf[offset]; 342*4fd4ca98SLizhi Hou e->addr = events->addr + offset; 343*4fd4ca98SLizhi Hou e->size = ASYNC_BUF_SIZE; 344*4fd4ca98SLizhi Hou e->resp.status = MAX_AIE2_STATUS_CODE; 345*4fd4ca98SLizhi Hou INIT_WORK(&e->work, aie2_error_worker); 346*4fd4ca98SLizhi Hou } 347*4fd4ca98SLizhi Hou 348*4fd4ca98SLizhi Hou ndev->async_events = events; 349*4fd4ca98SLizhi Hou 350*4fd4ca98SLizhi Hou XDNA_DBG(xdna, "Async event count %d, buf total size 0x%x", 351*4fd4ca98SLizhi Hou events->event_cnt, events->size); 352*4fd4ca98SLizhi Hou return 0; 353*4fd4ca98SLizhi Hou 354*4fd4ca98SLizhi Hou free_buf: 355*4fd4ca98SLizhi Hou dma_free_noncoherent(xdna->ddev.dev, events->size, events->buf, 356*4fd4ca98SLizhi Hou events->addr, DMA_FROM_DEVICE); 357*4fd4ca98SLizhi Hou free_events: 358*4fd4ca98SLizhi Hou kfree(events); 359*4fd4ca98SLizhi Hou return ret; 360*4fd4ca98SLizhi Hou } 361