[PATCH net-next v2 3/8] eth: mpnic: allocate MSI-X vectors
From: Daniel Zahka
Date: Thu Sep 24 2026 - 20:37:27 EST
Request one vector for FW generated interrupts and then one vector per
CPU to use for the completion queues. Nothing requests a handler yet,
that comes with the NAPI vectors.
Signed-off-by: Daniel Zahka <daniel.zahka@xxxxxxxxx>
---
drivers/net/ethernet/meta/mpnic/Makefile | 1 +
drivers/net/ethernet/meta/mpnic/mpnic.h | 15 +++++++
drivers/net/ethernet/meta/mpnic/mpnic_irq.c | 64 +++++++++++++++++++++++++++++
drivers/net/ethernet/meta/mpnic/mpnic_pci.c | 9 +++-
4 files changed, 88 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/meta/mpnic/Makefile b/drivers/net/ethernet/meta/mpnic/Makefile
index 9dcaa1c72605..3aa7c6a5ab5e 100644
--- a/drivers/net/ethernet/meta/mpnic/Makefile
+++ b/drivers/net/ethernet/meta/mpnic/Makefile
@@ -9,5 +9,6 @@ obj-$(CONFIG_MPNIC) += mpnic.o
mpnic-y := \
mpnic_init.o \
+ mpnic_irq.o \
mpnic_pci.o \
# End of mpnic-y
diff --git a/drivers/net/ethernet/meta/mpnic/mpnic.h b/drivers/net/ethernet/meta/mpnic/mpnic.h
index 67d48b7ce315..628fd48c997d 100644
--- a/drivers/net/ethernet/meta/mpnic/mpnic.h
+++ b/drivers/net/ethernet/meta/mpnic/mpnic.h
@@ -4,6 +4,7 @@
#ifndef _MPNIC_H_
#define _MPNIC_H_
+#include <linux/interrupt.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/types.h>
@@ -14,11 +15,19 @@
#define MPNIC_MAX_TXQS 1024u
#define MPNIC_MAX_RXQS 1024u
+/* misc IRQ entries are allocated before the completion queue IRQs */
+enum {
+ MPNIC_FW_MSIX_ENTRY,
+ MPNIC_NON_NAPI_VECTORS
+};
+
struct mpnic_dev {
struct device *dev;
u32 __iomem *uc_addr0;
+ u16 num_irqs;
+
u32 mps;
u32 readrq;
u8 relaxed_ord;
@@ -28,6 +37,12 @@ u64 mpnic_rd64(struct mpnic_dev *mpd, u32 reg);
int mpnic_dev_init(struct mpnic_dev *mpd);
+int mpnic_request_irq(struct mpnic_dev *mpd, int nr, irq_handler_t handler,
+ unsigned long flags, const char *name, void *data);
+void mpnic_free_irq(struct mpnic_dev *mpd, int nr, void *data);
+void mpnic_free_irqs(struct mpnic_dev *mpd);
+int mpnic_alloc_irqs(struct mpnic_dev *mpd);
+
static inline void mpnic_wr64(struct mpnic_dev *mpd, u32 reg, u64 val)
{
u32 __iomem *csr = READ_ONCE(mpd->uc_addr0);
diff --git a/drivers/net/ethernet/meta/mpnic/mpnic_irq.c b/drivers/net/ethernet/meta/mpnic/mpnic_irq.c
new file mode 100644
index 000000000000..bcc33655cbbe
--- /dev/null
+++ b/drivers/net/ethernet/meta/mpnic/mpnic_irq.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) Meta Platforms, Inc. and affiliates. */
+
+#include <linux/cpumask.h>
+#include <linux/interrupt.h>
+#include <linux/minmax.h>
+#include <linux/pci.h>
+
+#include "mpnic.h"
+
+int mpnic_request_irq(struct mpnic_dev *mpd, int nr, irq_handler_t handler,
+ unsigned long flags, const char *name, void *data)
+{
+ struct pci_dev *pdev = to_pci_dev(mpd->dev);
+ int irq = pci_irq_vector(pdev, nr);
+
+ if (irq < 0)
+ return irq;
+
+ return request_irq(irq, handler, flags, name, data);
+}
+
+void mpnic_free_irq(struct mpnic_dev *mpd, int nr, void *data)
+{
+ struct pci_dev *pdev = to_pci_dev(mpd->dev);
+ int irq = pci_irq_vector(pdev, nr);
+
+ if (irq < 0)
+ return;
+
+ free_irq(irq, data);
+}
+
+void mpnic_free_irqs(struct mpnic_dev *mpd)
+{
+ struct pci_dev *pdev = to_pci_dev(mpd->dev);
+
+ mpd->num_irqs = 0;
+ pci_free_irq_vectors(pdev);
+}
+
+int mpnic_alloc_irqs(struct mpnic_dev *mpd)
+{
+ unsigned int wanted_irqs = MPNIC_NON_NAPI_VECTORS;
+ struct pci_dev *pdev = to_pci_dev(mpd->dev);
+ int num_irqs;
+
+ wanted_irqs += min_t(unsigned int, num_online_cpus(), MPNIC_MAX_RXQS);
+ num_irqs = pci_alloc_irq_vectors(pdev, MPNIC_NON_NAPI_VECTORS + 1,
+ wanted_irqs, PCI_IRQ_MSIX);
+ if (num_irqs < 0) {
+ dev_err(mpd->dev, "Failed to allocate MSI-X entries: %d\n",
+ num_irqs);
+ return num_irqs;
+ }
+
+ if (num_irqs < wanted_irqs)
+ dev_warn(mpd->dev, "Allocated %d IRQs, expected %u\n",
+ num_irqs, wanted_irqs);
+
+ mpd->num_irqs = num_irqs;
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/meta/mpnic/mpnic_pci.c b/drivers/net/ethernet/meta/mpnic/mpnic_pci.c
index 68a64377e6c5..127b71b44b0f 100644
--- a/drivers/net/ethernet/meta/mpnic/mpnic_pci.c
+++ b/drivers/net/ethernet/meta/mpnic/mpnic_pci.c
@@ -112,12 +112,18 @@ static int mpnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pci_set_master(pdev);
pci_save_state(pdev);
- err = mpnic_dev_init(mpd);
+ err = mpnic_alloc_irqs(mpd);
if (err)
goto err_free_mpd;
+ err = mpnic_dev_init(mpd);
+ if (err)
+ goto err_free_irqs;
+
return 0;
+err_free_irqs:
+ mpnic_free_irqs(mpd);
err_free_mpd:
kfree(mpd);
@@ -132,6 +138,7 @@ static void mpnic_remove(struct pci_dev *pdev)
{
struct mpnic_dev *mpd = pci_get_drvdata(pdev);
+ mpnic_free_irqs(mpd);
kfree(mpd);
}
--
2.52.0