xref: /linux/drivers/net/ethernet/marvell/octeontx2/af/rvu_devlink.c (revision 26fbb4c8c7c3ee9a4c3b4de555a8587b5a19154e)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Marvell OcteonTx2 RVU Devlink
3  *
4  * Copyright (C) 2020 Marvell.
5  *
6  */
7 
8 #include<linux/bitfield.h>
9 
10 #include "rvu.h"
11 #include "rvu_reg.h"
12 #include "rvu_struct.h"
13 
14 #define DRV_NAME "octeontx2-af"
15 
16 static int rvu_report_pair_start(struct devlink_fmsg *fmsg, const char *name)
17 {
18 	int err;
19 
20 	err = devlink_fmsg_pair_nest_start(fmsg, name);
21 	if (err)
22 		return err;
23 
24 	return  devlink_fmsg_obj_nest_start(fmsg);
25 }
26 
27 static int rvu_report_pair_end(struct devlink_fmsg *fmsg)
28 {
29 	int err;
30 
31 	err = devlink_fmsg_obj_nest_end(fmsg);
32 	if (err)
33 		return err;
34 
35 	return devlink_fmsg_pair_nest_end(fmsg);
36 }
37 
38 static bool rvu_common_request_irq(struct rvu *rvu, int offset,
39 				   const char *name, irq_handler_t fn)
40 {
41 	struct rvu_devlink *rvu_dl = rvu->rvu_dl;
42 	int rc;
43 
44 	sprintf(&rvu->irq_name[offset * NAME_SIZE], name);
45 	rc = request_irq(pci_irq_vector(rvu->pdev, offset), fn, 0,
46 			 &rvu->irq_name[offset * NAME_SIZE], rvu_dl);
47 	if (rc)
48 		dev_warn(rvu->dev, "Failed to register %s irq\n", name);
49 	else
50 		rvu->irq_allocated[offset] = true;
51 
52 	return rvu->irq_allocated[offset];
53 }
54 
55 static void rvu_npa_intr_work(struct work_struct *work)
56 {
57 	struct rvu_npa_health_reporters *rvu_npa_health_reporter;
58 
59 	rvu_npa_health_reporter = container_of(work, struct rvu_npa_health_reporters, intr_work);
60 	devlink_health_report(rvu_npa_health_reporter->rvu_hw_npa_intr_reporter,
61 			      "NPA_AF_RVU Error",
62 			      rvu_npa_health_reporter->npa_event_ctx);
63 }
64 
65 static irqreturn_t rvu_npa_af_rvu_intr_handler(int irq, void *rvu_irq)
66 {
67 	struct rvu_npa_event_ctx *npa_event_context;
68 	struct rvu_devlink *rvu_dl = rvu_irq;
69 	struct rvu *rvu;
70 	int blkaddr;
71 	u64 intr;
72 
73 	rvu = rvu_dl->rvu;
74 	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0);
75 	if (blkaddr < 0)
76 		return IRQ_NONE;
77 
78 	npa_event_context = rvu_dl->rvu_npa_health_reporter->npa_event_ctx;
79 	intr = rvu_read64(rvu, blkaddr, NPA_AF_RVU_INT);
80 	npa_event_context->npa_af_rvu_int = intr;
81 
82 	/* Clear interrupts */
83 	rvu_write64(rvu, blkaddr, NPA_AF_RVU_INT, intr);
84 	rvu_write64(rvu, blkaddr, NPA_AF_RVU_INT_ENA_W1C, ~0ULL);
85 	queue_work(rvu_dl->devlink_wq, &rvu_dl->rvu_npa_health_reporter->intr_work);
86 
87 	return IRQ_HANDLED;
88 }
89 
90 static void rvu_npa_gen_work(struct work_struct *work)
91 {
92 	struct rvu_npa_health_reporters *rvu_npa_health_reporter;
93 
94 	rvu_npa_health_reporter = container_of(work, struct rvu_npa_health_reporters, gen_work);
95 	devlink_health_report(rvu_npa_health_reporter->rvu_hw_npa_gen_reporter,
96 			      "NPA_AF_GEN Error",
97 			      rvu_npa_health_reporter->npa_event_ctx);
98 }
99 
100 static irqreturn_t rvu_npa_af_gen_intr_handler(int irq, void *rvu_irq)
101 {
102 	struct rvu_npa_event_ctx *npa_event_context;
103 	struct rvu_devlink *rvu_dl = rvu_irq;
104 	struct rvu *rvu;
105 	int blkaddr;
106 	u64 intr;
107 
108 	rvu = rvu_dl->rvu;
109 	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0);
110 	if (blkaddr < 0)
111 		return IRQ_NONE;
112 
113 	npa_event_context = rvu_dl->rvu_npa_health_reporter->npa_event_ctx;
114 	intr = rvu_read64(rvu, blkaddr, NPA_AF_GEN_INT);
115 	npa_event_context->npa_af_rvu_gen = intr;
116 
117 	/* Clear interrupts */
118 	rvu_write64(rvu, blkaddr, NPA_AF_GEN_INT, intr);
119 	rvu_write64(rvu, blkaddr, NPA_AF_GEN_INT_ENA_W1C, ~0ULL);
120 	queue_work(rvu_dl->devlink_wq, &rvu_dl->rvu_npa_health_reporter->gen_work);
121 
122 	return IRQ_HANDLED;
123 }
124 
125 static void rvu_npa_err_work(struct work_struct *work)
126 {
127 	struct rvu_npa_health_reporters *rvu_npa_health_reporter;
128 
129 	rvu_npa_health_reporter = container_of(work, struct rvu_npa_health_reporters, err_work);
130 	devlink_health_report(rvu_npa_health_reporter->rvu_hw_npa_err_reporter,
131 			      "NPA_AF_ERR Error",
132 			      rvu_npa_health_reporter->npa_event_ctx);
133 }
134 
135 static irqreturn_t rvu_npa_af_err_intr_handler(int irq, void *rvu_irq)
136 {
137 	struct rvu_npa_event_ctx *npa_event_context;
138 	struct rvu_devlink *rvu_dl = rvu_irq;
139 	struct rvu *rvu;
140 	int blkaddr;
141 	u64 intr;
142 
143 	rvu = rvu_dl->rvu;
144 	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0);
145 	if (blkaddr < 0)
146 		return IRQ_NONE;
147 	npa_event_context = rvu_dl->rvu_npa_health_reporter->npa_event_ctx;
148 	intr = rvu_read64(rvu, blkaddr, NPA_AF_ERR_INT);
149 	npa_event_context->npa_af_rvu_err = intr;
150 
151 	/* Clear interrupts */
152 	rvu_write64(rvu, blkaddr, NPA_AF_ERR_INT, intr);
153 	rvu_write64(rvu, blkaddr, NPA_AF_ERR_INT_ENA_W1C, ~0ULL);
154 	queue_work(rvu_dl->devlink_wq, &rvu_dl->rvu_npa_health_reporter->err_work);
155 
156 	return IRQ_HANDLED;
157 }
158 
159 static void rvu_npa_ras_work(struct work_struct *work)
160 {
161 	struct rvu_npa_health_reporters *rvu_npa_health_reporter;
162 
163 	rvu_npa_health_reporter = container_of(work, struct rvu_npa_health_reporters, ras_work);
164 	devlink_health_report(rvu_npa_health_reporter->rvu_hw_npa_ras_reporter,
165 			      "HW NPA_AF_RAS Error reported",
166 			      rvu_npa_health_reporter->npa_event_ctx);
167 }
168 
169 static irqreturn_t rvu_npa_af_ras_intr_handler(int irq, void *rvu_irq)
170 {
171 	struct rvu_npa_event_ctx *npa_event_context;
172 	struct rvu_devlink *rvu_dl = rvu_irq;
173 	struct rvu *rvu;
174 	int blkaddr;
175 	u64 intr;
176 
177 	rvu = rvu_dl->rvu;
178 	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0);
179 	if (blkaddr < 0)
180 		return IRQ_NONE;
181 
182 	npa_event_context = rvu_dl->rvu_npa_health_reporter->npa_event_ctx;
183 	intr = rvu_read64(rvu, blkaddr, NPA_AF_RAS);
184 	npa_event_context->npa_af_rvu_ras = intr;
185 
186 	/* Clear interrupts */
187 	rvu_write64(rvu, blkaddr, NPA_AF_RAS, intr);
188 	rvu_write64(rvu, blkaddr, NPA_AF_RAS_ENA_W1C, ~0ULL);
189 	queue_work(rvu_dl->devlink_wq, &rvu_dl->rvu_npa_health_reporter->ras_work);
190 
191 	return IRQ_HANDLED;
192 }
193 
194 static void rvu_npa_unregister_interrupts(struct rvu *rvu)
195 {
196 	struct rvu_devlink *rvu_dl = rvu->rvu_dl;
197 	int i, offs, blkaddr;
198 	u64 reg;
199 
200 	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0);
201 	if (blkaddr < 0)
202 		return;
203 
204 	reg = rvu_read64(rvu, blkaddr, NPA_PRIV_AF_INT_CFG);
205 	offs = reg & 0x3FF;
206 
207 	rvu_write64(rvu, blkaddr, NPA_AF_RVU_INT_ENA_W1C, ~0ULL);
208 	rvu_write64(rvu, blkaddr, NPA_AF_GEN_INT_ENA_W1C, ~0ULL);
209 	rvu_write64(rvu, blkaddr, NPA_AF_ERR_INT_ENA_W1C, ~0ULL);
210 	rvu_write64(rvu, blkaddr, NPA_AF_RAS_ENA_W1C, ~0ULL);
211 
212 	for (i = 0; i < NPA_AF_INT_VEC_CNT; i++)
213 		if (rvu->irq_allocated[offs + i]) {
214 			free_irq(pci_irq_vector(rvu->pdev, offs + i), rvu_dl);
215 			rvu->irq_allocated[offs + i] = false;
216 		}
217 }
218 
219 static int rvu_npa_register_interrupts(struct rvu *rvu)
220 {
221 	int blkaddr, base;
222 	bool rc;
223 
224 	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0);
225 	if (blkaddr < 0)
226 		return blkaddr;
227 
228 	/* Get NPA AF MSIX vectors offset. */
229 	base = rvu_read64(rvu, blkaddr, NPA_PRIV_AF_INT_CFG) & 0x3ff;
230 	if (!base) {
231 		dev_warn(rvu->dev,
232 			 "Failed to get NPA_AF_INT vector offsets\n");
233 		return 0;
234 	}
235 
236 	/* Register and enable NPA_AF_RVU_INT interrupt */
237 	rc = rvu_common_request_irq(rvu, base +  NPA_AF_INT_VEC_RVU,
238 				    "NPA_AF_RVU_INT",
239 				    rvu_npa_af_rvu_intr_handler);
240 	if (!rc)
241 		goto err;
242 	rvu_write64(rvu, blkaddr, NPA_AF_RVU_INT_ENA_W1S, ~0ULL);
243 
244 	/* Register and enable NPA_AF_GEN_INT interrupt */
245 	rc = rvu_common_request_irq(rvu, base + NPA_AF_INT_VEC_GEN,
246 				    "NPA_AF_RVU_GEN",
247 				    rvu_npa_af_gen_intr_handler);
248 	if (!rc)
249 		goto err;
250 	rvu_write64(rvu, blkaddr, NPA_AF_GEN_INT_ENA_W1S, ~0ULL);
251 
252 	/* Register and enable NPA_AF_ERR_INT interrupt */
253 	rc = rvu_common_request_irq(rvu, base + NPA_AF_INT_VEC_AF_ERR,
254 				    "NPA_AF_ERR_INT",
255 				    rvu_npa_af_err_intr_handler);
256 	if (!rc)
257 		goto err;
258 	rvu_write64(rvu, blkaddr, NPA_AF_ERR_INT_ENA_W1S, ~0ULL);
259 
260 	/* Register and enable NPA_AF_RAS interrupt */
261 	rc = rvu_common_request_irq(rvu, base + NPA_AF_INT_VEC_POISON,
262 				    "NPA_AF_RAS",
263 				    rvu_npa_af_ras_intr_handler);
264 	if (!rc)
265 		goto err;
266 	rvu_write64(rvu, blkaddr, NPA_AF_RAS_ENA_W1S, ~0ULL);
267 
268 	return 0;
269 err:
270 	rvu_npa_unregister_interrupts(rvu);
271 	return rc;
272 }
273 
274 static int rvu_npa_report_show(struct devlink_fmsg *fmsg, void *ctx,
275 			       enum npa_af_rvu_health health_reporter)
276 {
277 	struct rvu_npa_event_ctx *npa_event_context;
278 	unsigned int alloc_dis, free_dis;
279 	u64 intr_val;
280 	int err;
281 
282 	npa_event_context = ctx;
283 	switch (health_reporter) {
284 	case NPA_AF_RVU_GEN:
285 		intr_val = npa_event_context->npa_af_rvu_gen;
286 		err = rvu_report_pair_start(fmsg, "NPA_AF_GENERAL");
287 		if (err)
288 			return err;
289 		err = devlink_fmsg_u64_pair_put(fmsg, "\tNPA General Interrupt Reg ",
290 						npa_event_context->npa_af_rvu_gen);
291 		if (err)
292 			return err;
293 		if (intr_val & BIT_ULL(32)) {
294 			err = devlink_fmsg_string_put(fmsg, "\n\tUnmap PF Error");
295 			if (err)
296 				return err;
297 		}
298 
299 		free_dis = FIELD_GET(GENMASK(15, 0), intr_val);
300 		if (free_dis & BIT(NPA_INPQ_NIX0_RX)) {
301 			err = devlink_fmsg_string_put(fmsg, "\n\tNIX0: free disabled RX");
302 			if (err)
303 				return err;
304 		}
305 		if (free_dis & BIT(NPA_INPQ_NIX0_TX)) {
306 			err = devlink_fmsg_string_put(fmsg, "\n\tNIX0:free disabled TX");
307 			if (err)
308 				return err;
309 		}
310 		if (free_dis & BIT(NPA_INPQ_NIX1_RX)) {
311 			err = devlink_fmsg_string_put(fmsg, "\n\tNIX1: free disabled RX");
312 			if (err)
313 				return err;
314 		}
315 		if (free_dis & BIT(NPA_INPQ_NIX1_TX)) {
316 			err = devlink_fmsg_string_put(fmsg, "\n\tNIX1:free disabled TX");
317 			if (err)
318 				return err;
319 		}
320 		if (free_dis & BIT(NPA_INPQ_SSO)) {
321 			err = devlink_fmsg_string_put(fmsg, "\n\tFree Disabled for SSO");
322 			if (err)
323 				return err;
324 		}
325 		if (free_dis & BIT(NPA_INPQ_TIM)) {
326 			err = devlink_fmsg_string_put(fmsg, "\n\tFree Disabled for TIM");
327 			if (err)
328 				return err;
329 		}
330 		if (free_dis & BIT(NPA_INPQ_DPI)) {
331 			err = devlink_fmsg_string_put(fmsg, "\n\tFree Disabled for DPI");
332 			if (err)
333 				return err;
334 		}
335 		if (free_dis & BIT(NPA_INPQ_AURA_OP)) {
336 			err = devlink_fmsg_string_put(fmsg, "\n\tFree Disabled for AURA");
337 			if (err)
338 				return err;
339 		}
340 
341 		alloc_dis = FIELD_GET(GENMASK(31, 16), intr_val);
342 		if (alloc_dis & BIT(NPA_INPQ_NIX0_RX)) {
343 			err = devlink_fmsg_string_put(fmsg, "\n\tNIX0: alloc disabled RX");
344 			if (err)
345 				return err;
346 		}
347 		if (alloc_dis & BIT(NPA_INPQ_NIX0_TX)) {
348 			err = devlink_fmsg_string_put(fmsg, "\n\tNIX0:alloc disabled TX");
349 			if (err)
350 				return err;
351 		}
352 		if (alloc_dis & BIT(NPA_INPQ_NIX1_RX)) {
353 			err = devlink_fmsg_string_put(fmsg, "\n\tNIX1: alloc disabled RX");
354 			if (err)
355 				return err;
356 		}
357 		if (alloc_dis & BIT(NPA_INPQ_NIX1_TX)) {
358 			err = devlink_fmsg_string_put(fmsg, "\n\tNIX1:alloc disabled TX");
359 			if (err)
360 				return err;
361 		}
362 		if (alloc_dis & BIT(NPA_INPQ_SSO)) {
363 			err = devlink_fmsg_string_put(fmsg, "\n\tAlloc Disabled for SSO");
364 			if (err)
365 				return err;
366 		}
367 		if (alloc_dis & BIT(NPA_INPQ_TIM)) {
368 			err = devlink_fmsg_string_put(fmsg, "\n\tAlloc Disabled for TIM");
369 			if (err)
370 				return err;
371 		}
372 		if (alloc_dis & BIT(NPA_INPQ_DPI)) {
373 			err = devlink_fmsg_string_put(fmsg, "\n\tAlloc Disabled for DPI");
374 			if (err)
375 				return err;
376 		}
377 		if (alloc_dis & BIT(NPA_INPQ_AURA_OP)) {
378 			err = devlink_fmsg_string_put(fmsg, "\n\tAlloc Disabled for AURA");
379 			if (err)
380 				return err;
381 		}
382 		err = rvu_report_pair_end(fmsg);
383 		if (err)
384 			return err;
385 		break;
386 	case NPA_AF_RVU_ERR:
387 		err = rvu_report_pair_start(fmsg, "NPA_AF_ERR");
388 		if (err)
389 			return err;
390 		err = devlink_fmsg_u64_pair_put(fmsg, "\tNPA Error Interrupt Reg ",
391 						npa_event_context->npa_af_rvu_err);
392 		if (err)
393 			return err;
394 
395 		if (npa_event_context->npa_af_rvu_err & BIT_ULL(14)) {
396 			err = devlink_fmsg_string_put(fmsg, "\n\tFault on NPA_AQ_INST_S read");
397 			if (err)
398 				return err;
399 		}
400 		if (npa_event_context->npa_af_rvu_err & BIT_ULL(13)) {
401 			err = devlink_fmsg_string_put(fmsg, "\n\tFault on NPA_AQ_RES_S write");
402 			if (err)
403 				return err;
404 		}
405 		if (npa_event_context->npa_af_rvu_err & BIT_ULL(12)) {
406 			err = devlink_fmsg_string_put(fmsg, "\n\tAQ Doorbell Error");
407 			if (err)
408 				return err;
409 		}
410 		err = rvu_report_pair_end(fmsg);
411 		if (err)
412 			return err;
413 		break;
414 	case NPA_AF_RVU_RAS:
415 		err = rvu_report_pair_start(fmsg, "NPA_AF_RVU_RAS");
416 		if (err)
417 			return err;
418 		err = devlink_fmsg_u64_pair_put(fmsg, "\tNPA RAS Interrupt Reg ",
419 						npa_event_context->npa_af_rvu_ras);
420 		if (err)
421 			return err;
422 		if (npa_event_context->npa_af_rvu_ras & BIT_ULL(34)) {
423 			err = devlink_fmsg_string_put(fmsg, "\n\tPoison data on NPA_AQ_INST_S");
424 			if (err)
425 				return err;
426 		}
427 		if (npa_event_context->npa_af_rvu_ras & BIT_ULL(33)) {
428 			err = devlink_fmsg_string_put(fmsg, "\n\tPoison data on NPA_AQ_RES_S");
429 			if (err)
430 				return err;
431 		}
432 		if (npa_event_context->npa_af_rvu_ras & BIT_ULL(32)) {
433 			err = devlink_fmsg_string_put(fmsg, "\n\tPoison data on HW context");
434 			if (err)
435 				return err;
436 		}
437 		err = rvu_report_pair_end(fmsg);
438 		if (err)
439 			return err;
440 		break;
441 	case NPA_AF_RVU_INTR:
442 		err = rvu_report_pair_start(fmsg, "NPA_AF_RVU");
443 		if (err)
444 			return err;
445 		err = devlink_fmsg_u64_pair_put(fmsg, "\tNPA RVU Interrupt Reg ",
446 						npa_event_context->npa_af_rvu_int);
447 		if (err)
448 			return err;
449 		if (npa_event_context->npa_af_rvu_int & BIT_ULL(0)) {
450 			err = devlink_fmsg_string_put(fmsg, "\n\tUnmap Slot Error");
451 			if (err)
452 				return err;
453 		}
454 		return rvu_report_pair_end(fmsg);
455 	default:
456 		return -EINVAL;
457 	}
458 
459 	return 0;
460 }
461 
462 static int rvu_hw_npa_intr_dump(struct devlink_health_reporter *reporter,
463 				struct devlink_fmsg *fmsg, void *ctx,
464 				struct netlink_ext_ack *netlink_extack)
465 {
466 	struct rvu *rvu = devlink_health_reporter_priv(reporter);
467 	struct rvu_devlink *rvu_dl = rvu->rvu_dl;
468 	struct rvu_npa_event_ctx *npa_ctx;
469 
470 	npa_ctx = rvu_dl->rvu_npa_health_reporter->npa_event_ctx;
471 
472 	return ctx ? rvu_npa_report_show(fmsg, ctx, NPA_AF_RVU_INTR) :
473 		     rvu_npa_report_show(fmsg, npa_ctx, NPA_AF_RVU_INTR);
474 }
475 
476 static int rvu_hw_npa_intr_recover(struct devlink_health_reporter *reporter,
477 				   void *ctx, struct netlink_ext_ack *netlink_extack)
478 {
479 	struct rvu *rvu = devlink_health_reporter_priv(reporter);
480 	struct rvu_npa_event_ctx *npa_event_ctx = ctx;
481 	int blkaddr;
482 
483 	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0);
484 	if (blkaddr < 0)
485 		return blkaddr;
486 
487 	if (npa_event_ctx->npa_af_rvu_int)
488 		rvu_write64(rvu, blkaddr, NPA_AF_RVU_INT_ENA_W1S, ~0ULL);
489 
490 	return 0;
491 }
492 
493 static int rvu_hw_npa_gen_dump(struct devlink_health_reporter *reporter,
494 			       struct devlink_fmsg *fmsg, void *ctx,
495 			       struct netlink_ext_ack *netlink_extack)
496 {
497 	struct rvu *rvu = devlink_health_reporter_priv(reporter);
498 	struct rvu_devlink *rvu_dl = rvu->rvu_dl;
499 	struct rvu_npa_event_ctx *npa_ctx;
500 
501 	npa_ctx = rvu_dl->rvu_npa_health_reporter->npa_event_ctx;
502 
503 	return ctx ? rvu_npa_report_show(fmsg, ctx, NPA_AF_RVU_GEN) :
504 		     rvu_npa_report_show(fmsg, npa_ctx, NPA_AF_RVU_GEN);
505 }
506 
507 static int rvu_hw_npa_gen_recover(struct devlink_health_reporter *reporter,
508 				  void *ctx, struct netlink_ext_ack *netlink_extack)
509 {
510 	struct rvu *rvu = devlink_health_reporter_priv(reporter);
511 	struct rvu_npa_event_ctx *npa_event_ctx = ctx;
512 	int blkaddr;
513 
514 	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0);
515 	if (blkaddr < 0)
516 		return blkaddr;
517 
518 	if (npa_event_ctx->npa_af_rvu_gen)
519 		rvu_write64(rvu, blkaddr, NPA_AF_GEN_INT_ENA_W1S, ~0ULL);
520 
521 	return 0;
522 }
523 
524 static int rvu_hw_npa_err_dump(struct devlink_health_reporter *reporter,
525 			       struct devlink_fmsg *fmsg, void *ctx,
526 			       struct netlink_ext_ack *netlink_extack)
527 {
528 	struct rvu *rvu = devlink_health_reporter_priv(reporter);
529 	struct rvu_devlink *rvu_dl = rvu->rvu_dl;
530 	struct rvu_npa_event_ctx *npa_ctx;
531 
532 	npa_ctx = rvu_dl->rvu_npa_health_reporter->npa_event_ctx;
533 
534 	return ctx ? rvu_npa_report_show(fmsg, ctx, NPA_AF_RVU_ERR) :
535 		     rvu_npa_report_show(fmsg, npa_ctx, NPA_AF_RVU_ERR);
536 }
537 
538 static int rvu_hw_npa_err_recover(struct devlink_health_reporter *reporter,
539 				  void *ctx, struct netlink_ext_ack *netlink_extack)
540 {
541 	struct rvu *rvu = devlink_health_reporter_priv(reporter);
542 	struct rvu_npa_event_ctx *npa_event_ctx = ctx;
543 	int blkaddr;
544 
545 	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0);
546 	if (blkaddr < 0)
547 		return blkaddr;
548 
549 	if (npa_event_ctx->npa_af_rvu_err)
550 		rvu_write64(rvu, blkaddr, NPA_AF_ERR_INT_ENA_W1S, ~0ULL);
551 
552 	return 0;
553 }
554 
555 static int rvu_hw_npa_ras_dump(struct devlink_health_reporter *reporter,
556 			       struct devlink_fmsg *fmsg, void *ctx,
557 			       struct netlink_ext_ack *netlink_extack)
558 {
559 	struct rvu *rvu = devlink_health_reporter_priv(reporter);
560 	struct rvu_devlink *rvu_dl = rvu->rvu_dl;
561 	struct rvu_npa_event_ctx *npa_ctx;
562 
563 	npa_ctx = rvu_dl->rvu_npa_health_reporter->npa_event_ctx;
564 
565 	return ctx ? rvu_npa_report_show(fmsg, ctx, NPA_AF_RVU_RAS) :
566 		     rvu_npa_report_show(fmsg, npa_ctx, NPA_AF_RVU_RAS);
567 }
568 
569 static int rvu_hw_npa_ras_recover(struct devlink_health_reporter *reporter,
570 				  void *ctx, struct netlink_ext_ack *netlink_extack)
571 {
572 	struct rvu *rvu = devlink_health_reporter_priv(reporter);
573 	struct rvu_npa_event_ctx *npa_event_ctx = ctx;
574 	int blkaddr;
575 
576 	blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0);
577 	if (blkaddr < 0)
578 		return blkaddr;
579 
580 	if (npa_event_ctx->npa_af_rvu_ras)
581 		rvu_write64(rvu, blkaddr, NPA_AF_RAS_ENA_W1S, ~0ULL);
582 
583 	return 0;
584 }
585 
586 RVU_REPORTERS(hw_npa_intr);
587 RVU_REPORTERS(hw_npa_gen);
588 RVU_REPORTERS(hw_npa_err);
589 RVU_REPORTERS(hw_npa_ras);
590 
591 static void rvu_npa_health_reporters_destroy(struct rvu_devlink *rvu_dl);
592 
593 static int rvu_npa_register_reporters(struct rvu_devlink *rvu_dl)
594 {
595 	struct rvu_npa_health_reporters *rvu_reporters;
596 	struct rvu_npa_event_ctx *npa_event_context;
597 	struct rvu *rvu = rvu_dl->rvu;
598 
599 	rvu_reporters = kzalloc(sizeof(*rvu_reporters), GFP_KERNEL);
600 	if (!rvu_reporters)
601 		return -ENOMEM;
602 
603 	rvu_dl->rvu_npa_health_reporter = rvu_reporters;
604 	npa_event_context = kzalloc(sizeof(*npa_event_context), GFP_KERNEL);
605 	if (!npa_event_context)
606 		return -ENOMEM;
607 
608 	rvu_reporters->npa_event_ctx = npa_event_context;
609 	rvu_reporters->rvu_hw_npa_intr_reporter =
610 		devlink_health_reporter_create(rvu_dl->dl, &rvu_hw_npa_intr_reporter_ops, 0, rvu);
611 	if (IS_ERR(rvu_reporters->rvu_hw_npa_intr_reporter)) {
612 		dev_warn(rvu->dev, "Failed to create hw_npa_intr reporter, err=%ld\n",
613 			 PTR_ERR(rvu_reporters->rvu_hw_npa_intr_reporter));
614 		return PTR_ERR(rvu_reporters->rvu_hw_npa_intr_reporter);
615 	}
616 
617 	rvu_reporters->rvu_hw_npa_gen_reporter =
618 		devlink_health_reporter_create(rvu_dl->dl, &rvu_hw_npa_gen_reporter_ops, 0, rvu);
619 	if (IS_ERR(rvu_reporters->rvu_hw_npa_gen_reporter)) {
620 		dev_warn(rvu->dev, "Failed to create hw_npa_gen reporter, err=%ld\n",
621 			 PTR_ERR(rvu_reporters->rvu_hw_npa_gen_reporter));
622 		return PTR_ERR(rvu_reporters->rvu_hw_npa_gen_reporter);
623 	}
624 
625 	rvu_reporters->rvu_hw_npa_err_reporter =
626 		devlink_health_reporter_create(rvu_dl->dl, &rvu_hw_npa_err_reporter_ops, 0, rvu);
627 	if (IS_ERR(rvu_reporters->rvu_hw_npa_err_reporter)) {
628 		dev_warn(rvu->dev, "Failed to create hw_npa_err reporter, err=%ld\n",
629 			 PTR_ERR(rvu_reporters->rvu_hw_npa_err_reporter));
630 		return PTR_ERR(rvu_reporters->rvu_hw_npa_err_reporter);
631 	}
632 
633 	rvu_reporters->rvu_hw_npa_ras_reporter =
634 		devlink_health_reporter_create(rvu_dl->dl, &rvu_hw_npa_ras_reporter_ops, 0, rvu);
635 	if (IS_ERR(rvu_reporters->rvu_hw_npa_ras_reporter)) {
636 		dev_warn(rvu->dev, "Failed to create hw_npa_ras reporter, err=%ld\n",
637 			 PTR_ERR(rvu_reporters->rvu_hw_npa_ras_reporter));
638 		return PTR_ERR(rvu_reporters->rvu_hw_npa_ras_reporter);
639 	}
640 
641 	rvu_dl->devlink_wq = create_workqueue("rvu_devlink_wq");
642 	if (!rvu_dl->devlink_wq)
643 		goto err;
644 
645 	INIT_WORK(&rvu_reporters->intr_work, rvu_npa_intr_work);
646 	INIT_WORK(&rvu_reporters->err_work, rvu_npa_err_work);
647 	INIT_WORK(&rvu_reporters->gen_work, rvu_npa_gen_work);
648 	INIT_WORK(&rvu_reporters->ras_work, rvu_npa_ras_work);
649 
650 	return 0;
651 err:
652 	rvu_npa_health_reporters_destroy(rvu_dl);
653 	return -ENOMEM;
654 }
655 
656 static int rvu_npa_health_reporters_create(struct rvu_devlink *rvu_dl)
657 {
658 	struct rvu *rvu = rvu_dl->rvu;
659 	int err;
660 
661 	err = rvu_npa_register_reporters(rvu_dl);
662 	if (err) {
663 		dev_warn(rvu->dev, "Failed to create npa reporter, err =%d\n",
664 			 err);
665 		return err;
666 	}
667 	rvu_npa_register_interrupts(rvu);
668 
669 	return 0;
670 }
671 
672 static void rvu_npa_health_reporters_destroy(struct rvu_devlink *rvu_dl)
673 {
674 	struct rvu_npa_health_reporters *npa_reporters;
675 	struct rvu *rvu = rvu_dl->rvu;
676 
677 	npa_reporters = rvu_dl->rvu_npa_health_reporter;
678 
679 	if (!npa_reporters->rvu_hw_npa_ras_reporter)
680 		return;
681 	if (!IS_ERR_OR_NULL(npa_reporters->rvu_hw_npa_intr_reporter))
682 		devlink_health_reporter_destroy(npa_reporters->rvu_hw_npa_intr_reporter);
683 
684 	if (!IS_ERR_OR_NULL(npa_reporters->rvu_hw_npa_gen_reporter))
685 		devlink_health_reporter_destroy(npa_reporters->rvu_hw_npa_gen_reporter);
686 
687 	if (!IS_ERR_OR_NULL(npa_reporters->rvu_hw_npa_err_reporter))
688 		devlink_health_reporter_destroy(npa_reporters->rvu_hw_npa_err_reporter);
689 
690 	if (!IS_ERR_OR_NULL(npa_reporters->rvu_hw_npa_ras_reporter))
691 		devlink_health_reporter_destroy(npa_reporters->rvu_hw_npa_ras_reporter);
692 
693 	rvu_npa_unregister_interrupts(rvu);
694 	kfree(rvu_dl->rvu_npa_health_reporter->npa_event_ctx);
695 	kfree(rvu_dl->rvu_npa_health_reporter);
696 }
697 
698 static int rvu_health_reporters_create(struct rvu *rvu)
699 {
700 	struct rvu_devlink *rvu_dl;
701 
702 	rvu_dl = rvu->rvu_dl;
703 	return rvu_npa_health_reporters_create(rvu_dl);
704 }
705 
706 static void rvu_health_reporters_destroy(struct rvu *rvu)
707 {
708 	struct rvu_devlink *rvu_dl;
709 
710 	if (!rvu->rvu_dl)
711 		return;
712 
713 	rvu_dl = rvu->rvu_dl;
714 	rvu_npa_health_reporters_destroy(rvu_dl);
715 }
716 
717 static int rvu_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req,
718 				struct netlink_ext_ack *extack)
719 {
720 	return devlink_info_driver_name_put(req, DRV_NAME);
721 }
722 
723 static const struct devlink_ops rvu_devlink_ops = {
724 	.info_get = rvu_devlink_info_get,
725 };
726 
727 int rvu_register_dl(struct rvu *rvu)
728 {
729 	struct rvu_devlink *rvu_dl;
730 	struct devlink *dl;
731 	int err;
732 
733 	rvu_dl = kzalloc(sizeof(*rvu_dl), GFP_KERNEL);
734 	if (!rvu_dl)
735 		return -ENOMEM;
736 
737 	dl = devlink_alloc(&rvu_devlink_ops, sizeof(struct rvu_devlink));
738 	if (!dl) {
739 		dev_warn(rvu->dev, "devlink_alloc failed\n");
740 		kfree(rvu_dl);
741 		return -ENOMEM;
742 	}
743 
744 	err = devlink_register(dl, rvu->dev);
745 	if (err) {
746 		dev_err(rvu->dev, "devlink register failed with error %d\n", err);
747 		devlink_free(dl);
748 		kfree(rvu_dl);
749 		return err;
750 	}
751 
752 	rvu_dl->dl = dl;
753 	rvu_dl->rvu = rvu;
754 	rvu->rvu_dl = rvu_dl;
755 
756 	return rvu_health_reporters_create(rvu);
757 }
758 
759 void rvu_unregister_dl(struct rvu *rvu)
760 {
761 	struct rvu_devlink *rvu_dl = rvu->rvu_dl;
762 	struct devlink *dl = rvu_dl->dl;
763 
764 	if (!dl)
765 		return;
766 
767 	rvu_health_reporters_destroy(rvu);
768 	devlink_unregister(dl);
769 	devlink_free(dl);
770 	kfree(rvu_dl);
771 }
772