xref: /linux/drivers/accel/amdxdna/aie2_error.c (revision 2c1ed907520c50326b8f604907a8478b27881a2e)
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
aie_get_error_category(u8 row,u8 event_id,enum aie_module_type mod_type)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 
aie2_error_backtrack(struct amdxdna_dev_hdl * ndev,void * err_info,u32 num_err)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 
aie2_error_async_cb(void * handle,const u32 * data,size_t size)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 
aie2_error_event_send(struct async_event * e)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 
aie2_error_worker(struct work_struct * err_work)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 
aie2_error_async_events_send(struct amdxdna_dev_hdl * ndev)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 
aie2_error_async_events_free(struct amdxdna_dev_hdl * ndev)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 
aie2_error_async_events_alloc(struct amdxdna_dev_hdl * ndev)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