// SPDX-License-Identifier: GPL-2.0 /* Marvell OcteonTx2 RVU Devlink * * Copyright (C) 2020 Marvell. * */ #include #include "rvu.h" #include "rvu_reg.h" #include "rvu_struct.h" #define DRV_NAME "octeontx2-af" static int rvu_report_pair_start(struct devlink_fmsg *fmsg, const char *name) { int err; err = devlink_fmsg_pair_nest_start(fmsg, name); if (err) return err; return devlink_fmsg_obj_nest_start(fmsg); } static int rvu_report_pair_end(struct devlink_fmsg *fmsg) { int err; err = devlink_fmsg_obj_nest_end(fmsg); if (err) return err; return devlink_fmsg_pair_nest_end(fmsg); } static bool rvu_common_request_irq(struct rvu *rvu, int offset, const char *name, irq_handler_t fn) { struct rvu_devlink *rvu_dl = rvu->rvu_dl; int rc; sprintf(&rvu->irq_name[offset * NAME_SIZE], name); rc = request_irq(pci_irq_vector(rvu->pdev, offset), fn, 0, &rvu->irq_name[offset * NAME_SIZE], rvu_dl); if (rc) dev_warn(rvu->dev, "Failed to register %s irq\n", name); else rvu->irq_allocated[offset] = true; return rvu->irq_allocated[offset]; } static void rvu_npa_intr_work(struct work_struct *work) { struct rvu_npa_health_reporters *rvu_npa_health_reporter; rvu_npa_health_reporter = container_of(work, struct rvu_npa_health_reporters, intr_work); devlink_health_report(rvu_npa_health_reporter->rvu_hw_npa_intr_reporter, "NPA_AF_RVU Error", rvu_npa_health_reporter->npa_event_ctx); } static irqreturn_t rvu_npa_af_rvu_intr_handler(int irq, void *rvu_irq) { struct rvu_npa_event_ctx *npa_event_context; struct rvu_devlink *rvu_dl = rvu_irq; struct rvu *rvu; int blkaddr; u64 intr; rvu = rvu_dl->rvu; blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0); if (blkaddr < 0) return IRQ_NONE; npa_event_context = rvu_dl->rvu_npa_health_reporter->npa_event_ctx; intr = rvu_read64(rvu, blkaddr, NPA_AF_RVU_INT); npa_event_context->npa_af_rvu_int = intr; /* Clear interrupts */ rvu_write64(rvu, blkaddr, NPA_AF_RVU_INT, intr); rvu_write64(rvu, blkaddr, NPA_AF_RVU_INT_ENA_W1C, ~0ULL); queue_work(rvu_dl->devlink_wq, &rvu_dl->rvu_npa_health_reporter->intr_work); return IRQ_HANDLED; } static void rvu_npa_gen_work(struct work_struct *work) { struct rvu_npa_health_reporters *rvu_npa_health_reporter; rvu_npa_health_reporter = container_of(work, struct rvu_npa_health_reporters, gen_work); devlink_health_report(rvu_npa_health_reporter->rvu_hw_npa_gen_reporter, "NPA_AF_GEN Error", rvu_npa_health_reporter->npa_event_ctx); } static irqreturn_t rvu_npa_af_gen_intr_handler(int irq, void *rvu_irq) { struct rvu_npa_event_ctx *npa_event_context; struct rvu_devlink *rvu_dl = rvu_irq; struct rvu *rvu; int blkaddr; u64 intr; rvu = rvu_dl->rvu; blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0); if (blkaddr < 0) return IRQ_NONE; npa_event_context = rvu_dl->rvu_npa_health_reporter->npa_event_ctx; intr = rvu_read64(rvu, blkaddr, NPA_AF_GEN_INT); npa_event_context->npa_af_rvu_gen = intr; /* Clear interrupts */ rvu_write64(rvu, blkaddr, NPA_AF_GEN_INT, intr); rvu_write64(rvu, blkaddr, NPA_AF_GEN_INT_ENA_W1C, ~0ULL); queue_work(rvu_dl->devlink_wq, &rvu_dl->rvu_npa_health_reporter->gen_work); return IRQ_HANDLED; } static void rvu_npa_err_work(struct work_struct *work) { struct rvu_npa_health_reporters *rvu_npa_health_reporter; rvu_npa_health_reporter = container_of(work, struct rvu_npa_health_reporters, err_work); devlink_health_report(rvu_npa_health_reporter->rvu_hw_npa_err_reporter, "NPA_AF_ERR Error", rvu_npa_health_reporter->npa_event_ctx); } static irqreturn_t rvu_npa_af_err_intr_handler(int irq, void *rvu_irq) { struct rvu_npa_event_ctx *npa_event_context; struct rvu_devlink *rvu_dl = rvu_irq; struct rvu *rvu; int blkaddr; u64 intr; rvu = rvu_dl->rvu; blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0); if (blkaddr < 0) return IRQ_NONE; npa_event_context = rvu_dl->rvu_npa_health_reporter->npa_event_ctx; intr = rvu_read64(rvu, blkaddr, NPA_AF_ERR_INT); npa_event_context->npa_af_rvu_err = intr; /* Clear interrupts */ rvu_write64(rvu, blkaddr, NPA_AF_ERR_INT, intr); rvu_write64(rvu, blkaddr, NPA_AF_ERR_INT_ENA_W1C, ~0ULL); queue_work(rvu_dl->devlink_wq, &rvu_dl->rvu_npa_health_reporter->err_work); return IRQ_HANDLED; } static void rvu_npa_ras_work(struct work_struct *work) { struct rvu_npa_health_reporters *rvu_npa_health_reporter; rvu_npa_health_reporter = container_of(work, struct rvu_npa_health_reporters, ras_work); devlink_health_report(rvu_npa_health_reporter->rvu_hw_npa_ras_reporter, "HW NPA_AF_RAS Error reported", rvu_npa_health_reporter->npa_event_ctx); } static irqreturn_t rvu_npa_af_ras_intr_handler(int irq, void *rvu_irq) { struct rvu_npa_event_ctx *npa_event_context; struct rvu_devlink *rvu_dl = rvu_irq; struct rvu *rvu; int blkaddr; u64 intr; rvu = rvu_dl->rvu; blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0); if (blkaddr < 0) return IRQ_NONE; npa_event_context = rvu_dl->rvu_npa_health_reporter->npa_event_ctx; intr = rvu_read64(rvu, blkaddr, NPA_AF_RAS); npa_event_context->npa_af_rvu_ras = intr; /* Clear interrupts */ rvu_write64(rvu, blkaddr, NPA_AF_RAS, intr); rvu_write64(rvu, blkaddr, NPA_AF_RAS_ENA_W1C, ~0ULL); queue_work(rvu_dl->devlink_wq, &rvu_dl->rvu_npa_health_reporter->ras_work); return IRQ_HANDLED; } static void rvu_npa_unregister_interrupts(struct rvu *rvu) { struct rvu_devlink *rvu_dl = rvu->rvu_dl; int i, offs, blkaddr; u64 reg; blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0); if (blkaddr < 0) return; reg = rvu_read64(rvu, blkaddr, NPA_PRIV_AF_INT_CFG); offs = reg & 0x3FF; rvu_write64(rvu, blkaddr, NPA_AF_RVU_INT_ENA_W1C, ~0ULL); rvu_write64(rvu, blkaddr, NPA_AF_GEN_INT_ENA_W1C, ~0ULL); rvu_write64(rvu, blkaddr, NPA_AF_ERR_INT_ENA_W1C, ~0ULL); rvu_write64(rvu, blkaddr, NPA_AF_RAS_ENA_W1C, ~0ULL); for (i = 0; i < NPA_AF_INT_VEC_CNT; i++) if (rvu->irq_allocated[offs + i]) { free_irq(pci_irq_vector(rvu->pdev, offs + i), rvu_dl); rvu->irq_allocated[offs + i] = false; } } static int rvu_npa_register_interrupts(struct rvu *rvu) { int blkaddr, base; bool rc; blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0); if (blkaddr < 0) return blkaddr; /* Get NPA AF MSIX vectors offset. */ base = rvu_read64(rvu, blkaddr, NPA_PRIV_AF_INT_CFG) & 0x3ff; if (!base) { dev_warn(rvu->dev, "Failed to get NPA_AF_INT vector offsets\n"); return 0; } /* Register and enable NPA_AF_RVU_INT interrupt */ rc = rvu_common_request_irq(rvu, base + NPA_AF_INT_VEC_RVU, "NPA_AF_RVU_INT", rvu_npa_af_rvu_intr_handler); if (!rc) goto err; rvu_write64(rvu, blkaddr, NPA_AF_RVU_INT_ENA_W1S, ~0ULL); /* Register and enable NPA_AF_GEN_INT interrupt */ rc = rvu_common_request_irq(rvu, base + NPA_AF_INT_VEC_GEN, "NPA_AF_RVU_GEN", rvu_npa_af_gen_intr_handler); if (!rc) goto err; rvu_write64(rvu, blkaddr, NPA_AF_GEN_INT_ENA_W1S, ~0ULL); /* Register and enable NPA_AF_ERR_INT interrupt */ rc = rvu_common_request_irq(rvu, base + NPA_AF_INT_VEC_AF_ERR, "NPA_AF_ERR_INT", rvu_npa_af_err_intr_handler); if (!rc) goto err; rvu_write64(rvu, blkaddr, NPA_AF_ERR_INT_ENA_W1S, ~0ULL); /* Register and enable NPA_AF_RAS interrupt */ rc = rvu_common_request_irq(rvu, base + NPA_AF_INT_VEC_POISON, "NPA_AF_RAS", rvu_npa_af_ras_intr_handler); if (!rc) goto err; rvu_write64(rvu, blkaddr, NPA_AF_RAS_ENA_W1S, ~0ULL); return 0; err: rvu_npa_unregister_interrupts(rvu); return rc; } static int rvu_npa_report_show(struct devlink_fmsg *fmsg, void *ctx, enum npa_af_rvu_health health_reporter) { struct rvu_npa_event_ctx *npa_event_context; unsigned int intr_val, alloc_dis, free_dis; int err; npa_event_context = ctx; switch (health_reporter) { case NPA_AF_RVU_GEN: intr_val = npa_event_context->npa_af_rvu_gen; err = rvu_report_pair_start(fmsg, "NPA_AF_GENERAL"); if (err) return err; err = devlink_fmsg_u64_pair_put(fmsg, "\tNPA General Interrupt Reg ", npa_event_context->npa_af_rvu_gen); if (err) return err; if (intr_val & BIT_ULL(32)) { err = devlink_fmsg_string_put(fmsg, "\n\tUnmap PF Error"); if (err) return err; } free_dis = FIELD_GET(GENMASK(15, 0), intr_val); if (free_dis & BIT(NPA_INPQ_NIX0_RX)) { err = devlink_fmsg_string_put(fmsg, "\n\tNIX0: free disabled RX"); if (err) return err; } if (free_dis & BIT(NPA_INPQ_NIX0_TX)) { err = devlink_fmsg_string_put(fmsg, "\n\tNIX0:free disabled TX"); if (err) return err; } if (free_dis & BIT(NPA_INPQ_NIX1_RX)) { err = devlink_fmsg_string_put(fmsg, "\n\tNIX1: free disabled RX"); if (err) return err; } if (free_dis & BIT(NPA_INPQ_NIX1_TX)) { err = devlink_fmsg_string_put(fmsg, "\n\tNIX1:free disabled TX"); if (err) return err; } if (free_dis & BIT(NPA_INPQ_SSO)) { err = devlink_fmsg_string_put(fmsg, "\n\tFree Disabled for SSO"); if (err) return err; } if (free_dis & BIT(NPA_INPQ_TIM)) { err = devlink_fmsg_string_put(fmsg, "\n\tFree Disabled for TIM"); if (err) return err; } if (free_dis & BIT(NPA_INPQ_DPI)) { err = devlink_fmsg_string_put(fmsg, "\n\tFree Disabled for DPI"); if (err) return err; } if (free_dis & BIT(NPA_INPQ_AURA_OP)) { err = devlink_fmsg_string_put(fmsg, "\n\tFree Disabled for AURA"); if (err) return err; } alloc_dis = FIELD_GET(GENMASK(31, 16), intr_val); if (alloc_dis & BIT(NPA_INPQ_NIX0_RX)) { err = devlink_fmsg_string_put(fmsg, "\n\tNIX0: alloc disabled RX"); if (err) return err; } if (alloc_dis & BIT(NPA_INPQ_NIX0_TX)) { err = devlink_fmsg_string_put(fmsg, "\n\tNIX0:alloc disabled TX"); if (err) return err; } if (alloc_dis & BIT(NPA_INPQ_NIX1_RX)) { err = devlink_fmsg_string_put(fmsg, "\n\tNIX1: alloc disabled RX"); if (err) return err; } if (alloc_dis & BIT(NPA_INPQ_NIX1_TX)) { err = devlink_fmsg_string_put(fmsg, "\n\tNIX1:alloc disabled TX"); if (err) return err; } if (alloc_dis & BIT(NPA_INPQ_SSO)) { err = devlink_fmsg_string_put(fmsg, "\n\tAlloc Disabled for SSO"); if (err) return err; } if (alloc_dis & BIT(NPA_INPQ_TIM)) { err = devlink_fmsg_string_put(fmsg, "\n\tAlloc Disabled for TIM"); if (err) return err; } if (alloc_dis & BIT(NPA_INPQ_DPI)) { err = devlink_fmsg_string_put(fmsg, "\n\tAlloc Disabled for DPI"); if (err) return err; } if (alloc_dis & BIT(NPA_INPQ_AURA_OP)) { err = devlink_fmsg_string_put(fmsg, "\n\tAlloc Disabled for AURA"); if (err) return err; } err = rvu_report_pair_end(fmsg); if (err) return err; break; case NPA_AF_RVU_ERR: err = rvu_report_pair_start(fmsg, "NPA_AF_ERR"); if (err) return err; err = devlink_fmsg_u64_pair_put(fmsg, "\tNPA Error Interrupt Reg ", npa_event_context->npa_af_rvu_err); if (err) return err; if (npa_event_context->npa_af_rvu_err & BIT_ULL(14)) { err = devlink_fmsg_string_put(fmsg, "\n\tFault on NPA_AQ_INST_S read"); if (err) return err; } if (npa_event_context->npa_af_rvu_err & BIT_ULL(13)) { err = devlink_fmsg_string_put(fmsg, "\n\tFault on NPA_AQ_RES_S write"); if (err) return err; } if (npa_event_context->npa_af_rvu_err & BIT_ULL(12)) { err = devlink_fmsg_string_put(fmsg, "\n\tAQ Doorbell Error"); if (err) return err; } err = rvu_report_pair_end(fmsg); if (err) return err; break; case NPA_AF_RVU_RAS: err = rvu_report_pair_start(fmsg, "NPA_AF_RVU_RAS"); if (err) return err; err = devlink_fmsg_u64_pair_put(fmsg, "\tNPA RAS Interrupt Reg ", npa_event_context->npa_af_rvu_ras); if (err) return err; if (npa_event_context->npa_af_rvu_ras & BIT_ULL(34)) { err = devlink_fmsg_string_put(fmsg, "\n\tPoison data on NPA_AQ_INST_S"); if (err) return err; } if (npa_event_context->npa_af_rvu_ras & BIT_ULL(33)) { err = devlink_fmsg_string_put(fmsg, "\n\tPoison data on NPA_AQ_RES_S"); if (err) return err; } if (npa_event_context->npa_af_rvu_ras & BIT_ULL(32)) { err = devlink_fmsg_string_put(fmsg, "\n\tPoison data on HW context"); if (err) return err; } err = rvu_report_pair_end(fmsg); if (err) return err; break; case NPA_AF_RVU_INTR: err = rvu_report_pair_start(fmsg, "NPA_AF_RVU"); if (err) return err; err = devlink_fmsg_u64_pair_put(fmsg, "\tNPA RVU Interrupt Reg ", npa_event_context->npa_af_rvu_int); if (err) return err; if (npa_event_context->npa_af_rvu_int & BIT_ULL(0)) { err = devlink_fmsg_string_put(fmsg, "\n\tUnmap Slot Error"); if (err) return err; } return rvu_report_pair_end(fmsg); default: return -EINVAL; } return 0; } static int rvu_hw_npa_intr_dump(struct devlink_health_reporter *reporter, struct devlink_fmsg *fmsg, void *ctx, struct netlink_ext_ack *netlink_extack) { struct rvu *rvu = devlink_health_reporter_priv(reporter); struct rvu_devlink *rvu_dl = rvu->rvu_dl; struct rvu_npa_event_ctx *npa_ctx; npa_ctx = rvu_dl->rvu_npa_health_reporter->npa_event_ctx; return ctx ? rvu_npa_report_show(fmsg, ctx, NPA_AF_RVU_INTR) : rvu_npa_report_show(fmsg, npa_ctx, NPA_AF_RVU_INTR); } static int rvu_hw_npa_intr_recover(struct devlink_health_reporter *reporter, void *ctx, struct netlink_ext_ack *netlink_extack) { struct rvu *rvu = devlink_health_reporter_priv(reporter); struct rvu_npa_event_ctx *npa_event_ctx = ctx; int blkaddr; blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0); if (blkaddr < 0) return blkaddr; if (npa_event_ctx->npa_af_rvu_int) rvu_write64(rvu, blkaddr, NPA_AF_RVU_INT_ENA_W1S, ~0ULL); return 0; } static int rvu_hw_npa_gen_dump(struct devlink_health_reporter *reporter, struct devlink_fmsg *fmsg, void *ctx, struct netlink_ext_ack *netlink_extack) { struct rvu *rvu = devlink_health_reporter_priv(reporter); struct rvu_devlink *rvu_dl = rvu->rvu_dl; struct rvu_npa_event_ctx *npa_ctx; npa_ctx = rvu_dl->rvu_npa_health_reporter->npa_event_ctx; return ctx ? rvu_npa_report_show(fmsg, ctx, NPA_AF_RVU_GEN) : rvu_npa_report_show(fmsg, npa_ctx, NPA_AF_RVU_GEN); } static int rvu_hw_npa_gen_recover(struct devlink_health_reporter *reporter, void *ctx, struct netlink_ext_ack *netlink_extack) { struct rvu *rvu = devlink_health_reporter_priv(reporter); struct rvu_npa_event_ctx *npa_event_ctx = ctx; int blkaddr; blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0); if (blkaddr < 0) return blkaddr; if (npa_event_ctx->npa_af_rvu_gen) rvu_write64(rvu, blkaddr, NPA_AF_GEN_INT_ENA_W1S, ~0ULL); return 0; } static int rvu_hw_npa_err_dump(struct devlink_health_reporter *reporter, struct devlink_fmsg *fmsg, void *ctx, struct netlink_ext_ack *netlink_extack) { struct rvu *rvu = devlink_health_reporter_priv(reporter); struct rvu_devlink *rvu_dl = rvu->rvu_dl; struct rvu_npa_event_ctx *npa_ctx; npa_ctx = rvu_dl->rvu_npa_health_reporter->npa_event_ctx; return ctx ? rvu_npa_report_show(fmsg, ctx, NPA_AF_RVU_ERR) : rvu_npa_report_show(fmsg, npa_ctx, NPA_AF_RVU_ERR); } static int rvu_hw_npa_err_recover(struct devlink_health_reporter *reporter, void *ctx, struct netlink_ext_ack *netlink_extack) { struct rvu *rvu = devlink_health_reporter_priv(reporter); struct rvu_npa_event_ctx *npa_event_ctx = ctx; int blkaddr; blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0); if (blkaddr < 0) return blkaddr; if (npa_event_ctx->npa_af_rvu_err) rvu_write64(rvu, blkaddr, NPA_AF_ERR_INT_ENA_W1S, ~0ULL); return 0; } static int rvu_hw_npa_ras_dump(struct devlink_health_reporter *reporter, struct devlink_fmsg *fmsg, void *ctx, struct netlink_ext_ack *netlink_extack) { struct rvu *rvu = devlink_health_reporter_priv(reporter); struct rvu_devlink *rvu_dl = rvu->rvu_dl; struct rvu_npa_event_ctx *npa_ctx; npa_ctx = rvu_dl->rvu_npa_health_reporter->npa_event_ctx; return ctx ? rvu_npa_report_show(fmsg, ctx, NPA_AF_RVU_RAS) : rvu_npa_report_show(fmsg, npa_ctx, NPA_AF_RVU_RAS); } static int rvu_hw_npa_ras_recover(struct devlink_health_reporter *reporter, void *ctx, struct netlink_ext_ack *netlink_extack) { struct rvu *rvu = devlink_health_reporter_priv(reporter); struct rvu_npa_event_ctx *npa_event_ctx = ctx; int blkaddr; blkaddr = rvu_get_blkaddr(rvu, BLKTYPE_NPA, 0); if (blkaddr < 0) return blkaddr; if (npa_event_ctx->npa_af_rvu_ras) rvu_write64(rvu, blkaddr, NPA_AF_RAS_ENA_W1S, ~0ULL); return 0; } RVU_REPORTERS(hw_npa_intr); RVU_REPORTERS(hw_npa_gen); RVU_REPORTERS(hw_npa_err); RVU_REPORTERS(hw_npa_ras); static void rvu_npa_health_reporters_destroy(struct rvu_devlink *rvu_dl); static int rvu_npa_register_reporters(struct rvu_devlink *rvu_dl) { struct rvu_npa_health_reporters *rvu_reporters; struct rvu_npa_event_ctx *npa_event_context; struct rvu *rvu = rvu_dl->rvu; rvu_reporters = kzalloc(sizeof(*rvu_reporters), GFP_KERNEL); if (!rvu_reporters) return -ENOMEM; rvu_dl->rvu_npa_health_reporter = rvu_reporters; npa_event_context = kzalloc(sizeof(*npa_event_context), GFP_KERNEL); if (!npa_event_context) return -ENOMEM; rvu_reporters->npa_event_ctx = npa_event_context; rvu_reporters->rvu_hw_npa_intr_reporter = devlink_health_reporter_create(rvu_dl->dl, &rvu_hw_npa_intr_reporter_ops, 0, rvu); if (IS_ERR(rvu_reporters->rvu_hw_npa_intr_reporter)) { dev_warn(rvu->dev, "Failed to create hw_npa_intr reporter, err=%ld\n", PTR_ERR(rvu_reporters->rvu_hw_npa_intr_reporter)); return PTR_ERR(rvu_reporters->rvu_hw_npa_intr_reporter); } rvu_reporters->rvu_hw_npa_gen_reporter = devlink_health_reporter_create(rvu_dl->dl, &rvu_hw_npa_gen_reporter_ops, 0, rvu); if (IS_ERR(rvu_reporters->rvu_hw_npa_gen_reporter)) { dev_warn(rvu->dev, "Failed to create hw_npa_gen reporter, err=%ld\n", PTR_ERR(rvu_reporters->rvu_hw_npa_gen_reporter)); return PTR_ERR(rvu_reporters->rvu_hw_npa_gen_reporter); } rvu_reporters->rvu_hw_npa_err_reporter = devlink_health_reporter_create(rvu_dl->dl, &rvu_hw_npa_err_reporter_ops, 0, rvu); if (IS_ERR(rvu_reporters->rvu_hw_npa_err_reporter)) { dev_warn(rvu->dev, "Failed to create hw_npa_err reporter, err=%ld\n", PTR_ERR(rvu_reporters->rvu_hw_npa_err_reporter)); return PTR_ERR(rvu_reporters->rvu_hw_npa_err_reporter); } rvu_reporters->rvu_hw_npa_ras_reporter = devlink_health_reporter_create(rvu_dl->dl, &rvu_hw_npa_ras_reporter_ops, 0, rvu); if (IS_ERR(rvu_reporters->rvu_hw_npa_ras_reporter)) { dev_warn(rvu->dev, "Failed to create hw_npa_ras reporter, err=%ld\n", PTR_ERR(rvu_reporters->rvu_hw_npa_ras_reporter)); return PTR_ERR(rvu_reporters->rvu_hw_npa_ras_reporter); } rvu_dl->devlink_wq = create_workqueue("rvu_devlink_wq"); if (!rvu_dl->devlink_wq) goto err; INIT_WORK(&rvu_reporters->intr_work, rvu_npa_intr_work); INIT_WORK(&rvu_reporters->err_work, rvu_npa_err_work); INIT_WORK(&rvu_reporters->gen_work, rvu_npa_gen_work); INIT_WORK(&rvu_reporters->ras_work, rvu_npa_ras_work); return 0; err: rvu_npa_health_reporters_destroy(rvu_dl); return -ENOMEM; } static int rvu_npa_health_reporters_create(struct rvu_devlink *rvu_dl) { struct rvu *rvu = rvu_dl->rvu; int err; err = rvu_npa_register_reporters(rvu_dl); if (err) { dev_warn(rvu->dev, "Failed to create npa reporter, err =%d\n", err); return err; } rvu_npa_register_interrupts(rvu); return 0; } static void rvu_npa_health_reporters_destroy(struct rvu_devlink *rvu_dl) { struct rvu_npa_health_reporters *npa_reporters; struct rvu *rvu = rvu_dl->rvu; npa_reporters = rvu_dl->rvu_npa_health_reporter; if (!npa_reporters->rvu_hw_npa_ras_reporter) return; if (!IS_ERR_OR_NULL(npa_reporters->rvu_hw_npa_intr_reporter)) devlink_health_reporter_destroy(npa_reporters->rvu_hw_npa_intr_reporter); if (!IS_ERR_OR_NULL(npa_reporters->rvu_hw_npa_gen_reporter)) devlink_health_reporter_destroy(npa_reporters->rvu_hw_npa_gen_reporter); if (!IS_ERR_OR_NULL(npa_reporters->rvu_hw_npa_err_reporter)) devlink_health_reporter_destroy(npa_reporters->rvu_hw_npa_err_reporter); if (!IS_ERR_OR_NULL(npa_reporters->rvu_hw_npa_ras_reporter)) devlink_health_reporter_destroy(npa_reporters->rvu_hw_npa_ras_reporter); rvu_npa_unregister_interrupts(rvu); kfree(rvu_dl->rvu_npa_health_reporter->npa_event_ctx); kfree(rvu_dl->rvu_npa_health_reporter); } static int rvu_health_reporters_create(struct rvu *rvu) { struct rvu_devlink *rvu_dl; rvu_dl = rvu->rvu_dl; return rvu_npa_health_reporters_create(rvu_dl); } static void rvu_health_reporters_destroy(struct rvu *rvu) { struct rvu_devlink *rvu_dl; if (!rvu->rvu_dl) return; rvu_dl = rvu->rvu_dl; rvu_npa_health_reporters_destroy(rvu_dl); } static int rvu_devlink_info_get(struct devlink *devlink, struct devlink_info_req *req, struct netlink_ext_ack *extack) { return devlink_info_driver_name_put(req, DRV_NAME); } static const struct devlink_ops rvu_devlink_ops = { .info_get = rvu_devlink_info_get, }; int rvu_register_dl(struct rvu *rvu) { struct rvu_devlink *rvu_dl; struct devlink *dl; int err; rvu_dl = kzalloc(sizeof(*rvu_dl), GFP_KERNEL); if (!rvu_dl) return -ENOMEM; dl = devlink_alloc(&rvu_devlink_ops, sizeof(struct rvu_devlink)); if (!dl) { dev_warn(rvu->dev, "devlink_alloc failed\n"); kfree(rvu_dl); return -ENOMEM; } err = devlink_register(dl, rvu->dev); if (err) { dev_err(rvu->dev, "devlink register failed with error %d\n", err); devlink_free(dl); kfree(rvu_dl); return err; } rvu_dl->dl = dl; rvu_dl->rvu = rvu; rvu->rvu_dl = rvu_dl; return rvu_health_reporters_create(rvu); } void rvu_unregister_dl(struct rvu *rvu) { struct rvu_devlink *rvu_dl = rvu->rvu_dl; struct devlink *dl = rvu_dl->dl; if (!dl) return; rvu_health_reporters_destroy(rvu); devlink_unregister(dl); devlink_free(dl); kfree(rvu_dl); }