nix_inl_cpt_cq_cb() dispatched through inl_dev->work_cb() without a NULL
check, unlike the SSO sibling path. A CPT completion processed before the
callback is registered or after it is cleared caused a NULL
function-pointer call on the interrupt thread, crashing the PMD.
Snapshot the callback once and skip dispatch when it is NULL; the entries
are still drained and the interrupt acknowledged, so the queue does not
stall.
Fixes: a7d64a7740e0 ("net/cnxk: handle soft expiry")
Cc: [email protected]
Signed-off-by: Aarnav JP <[email protected]>
---
drivers/common/cnxk/roc_nix_inl_dev_irq.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/common/cnxk/roc_nix_inl_dev_irq.c
b/drivers/common/cnxk/roc_nix_inl_dev_irq.c
index 977b5e05e2..82f8c5edfb 100644
--- a/drivers/common/cnxk/roc_nix_inl_dev_irq.c
+++ b/drivers/common/cnxk/roc_nix_inl_dev_irq.c
@@ -50,6 +50,7 @@ nix_inl_cpt_cq_cb(struct roc_cpt_lf *lf)
{
struct idev_cfg *idev = idev_get_cfg();
struct nix_inl_dev *inl_dev = NULL;
+ roc_nix_inl_sso_work_cb_t work_cb;
enum nix_inl_event_type cq_type;
uint32_t port_id = UINT32_MAX;
union cpt_lf_cq_base cq_base;
@@ -102,6 +103,9 @@ nix_inl_cpt_cq_cb(struct roc_cpt_lf *lf)
port_id = roc_nix->port_id;
}
+ /* Snapshot once so the test and the call use the same pointer */
+ work_cb = inl_dev->work_cb;
+
for (i = 0; i < count; i++) {
cq_s = (struct cpt_cq_s
*)(uintptr_t)((((uint64_t)cq_base.s.addr << 7)) +
(head << 5));
@@ -129,7 +133,8 @@ nix_inl_cpt_cq_cb(struct roc_cpt_lf *lf)
goto done;
}
gw[1] = (uint64_t)(uintptr_t)wqe;
- inl_dev->work_cb(gw, sa, cq_type, (void *)cq_s,
port_id);
+ if (work_cb)
+ work_cb(gw, sa, cq_type, (void *)cq_s, port_id);
}
done:
head = (head + 1) % lf->cq_size;
--
2.43.0