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 #include #include @@ -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 +#include +#include +#include + +#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); }