From: Manish Awasthi <mawasthi@linux.microsoft.com>
To: kys@microsoft.com, haiyangz@microsoft.com, wei.liu@kernel.org,
decui@microsoft.com, longli@microsoft.com, andrew+netdev@lunn.ch,
davem@davemloft.net, edumazet@google.com, kuba@kernel.org,
pabeni@redhat.com, kotaranov@microsoft.com
Cc: horms@kernel.org, linux-hyperv@vger.kernel.org,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-rdma@vger.kernel.org, bpf@vger.kernel.org,
nipun.gupta@amd.com, nikhil.agarwal@amd.com,
gargaditya@linux.microsoft.com, ernis@linux.microsoft.com,
kees@kernel.org, paulros@microsoft.com, mawasthi@microsoft.com
Subject: [PATCH net-next 4/4] net: mana: Add support for CDX device ID 0x00C2
Date: Thu, 24 Sep 2026 17:30:54 +0000 [thread overview]
Message-ID: <20260924173054.589291-5-mawasthi@linux.microsoft.com> (raw)
In-Reply-To: <20260924173054.589291-1-mawasthi@linux.microsoft.com>
Add the CDX transport as mana_cdx.ko for device ID 0x00C2, using the shared
gdma_core.ko. Allocate interrupts at probe, limit queues to available
vectors, use 32-bit DMA, and keep CDX auxiliary devices separate from PCI.
Signed-off-by: Manish Awasthi <mawasthi@linux.microsoft.com>
---
drivers/net/ethernet/microsoft/Kconfig | 14 +
drivers/net/ethernet/microsoft/mana/Makefile | 3 +
.../net/ethernet/microsoft/mana/gdma_cdx.c | 340 ++++++++++++++++++
.../net/ethernet/microsoft/mana/gdma_pci.c | 1 +
drivers/net/ethernet/microsoft/mana/mana_en.c | 5 +-
include/net/mana/gdma.h | 4 +
6 files changed, 365 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/ethernet/microsoft/mana/gdma_cdx.c
diff --git a/drivers/net/ethernet/microsoft/Kconfig b/drivers/net/ethernet/microsoft/Kconfig
index ee5bc1c1bf59..7e4b77f7f29c 100644
--- a/drivers/net/ethernet/microsoft/Kconfig
+++ b/drivers/net/ethernet/microsoft/Kconfig
@@ -35,4 +35,18 @@ config MICROSOFT_MANA
To compile this driver as a module, choose M here.
The module will be called mana.
+config MICROSOFT_MANA_CDX
+ tristate "Microsoft Azure Network Adapter (MANA) support for the CDX bus"
+ depends on CDX_BUS
+ depends on GENERIC_MSI_IRQ
+ depends on 64BIT && !CPU_BIG_ENDIAN
+ select MICROSOFT_GDMA_CORE
+ help
+ This driver supports the Microsoft Azure Network Adapter (MANA) on
+ systems where it is integrated into the SoC and presented on the CDX
+ bus rather than discovered over PCI.
+
+ To compile this driver as a module, choose M here.
+ The module will be called mana_cdx.
+
endif #NET_VENDOR_MICROSOFT
diff --git a/drivers/net/ethernet/microsoft/mana/Makefile b/drivers/net/ethernet/microsoft/mana/Makefile
index 72c03fb6e441..64926015f734 100644
--- a/drivers/net/ethernet/microsoft/mana/Makefile
+++ b/drivers/net/ethernet/microsoft/mana/Makefile
@@ -8,3 +8,6 @@ gdma_core-y := gdma_main.o shm_channel.o hw_channel.o mana_en.o mana_ethtool.o \
obj-$(CONFIG_MICROSOFT_MANA) += mana.o
mana-y := gdma_pci.o
+
+obj-$(CONFIG_MICROSOFT_MANA_CDX) += mana_cdx.o
+mana_cdx-y := gdma_cdx.o
diff --git a/drivers/net/ethernet/microsoft/mana/gdma_cdx.c b/drivers/net/ethernet/microsoft/mana/gdma_cdx.c
new file mode 100644
index 000000000000..0d01e3d2f0d9
--- /dev/null
+++ b/drivers/net/ethernet/microsoft/mana/gdma_cdx.c
@@ -0,0 +1,340 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/* Copyright (c) 2025, Microsoft Corporation. */
+#include <linux/module.h>
+#include <linux/bitmap.h>
+#include <linux/cdx/cdx_bus.h>
+#include <linux/msi.h>
+#include <linux/xarray.h>
+
+#include <net/mana/mana.h>
+
+#define MANA_CDX_GDMA_REGS_SIZE (GDMA_REG_SHM_OFFSET + sizeof(u64))
+
+static int mana_cdx_msix_virq(struct gdma_context *gc, int msi)
+{
+ unsigned int virq = msi_get_virq(gc->dev, msi);
+
+ /* CDX allocates its whole vector pool in mana_cdx_setup_hwc_irqs(),
+ * so a vector with no Linux IRQ was never part of that pool.
+ */
+ return virq ? virq : -EINVAL;
+}
+
+static int mana_cdx_dev_reset(struct gdma_context *gc)
+{
+ return cdx_dev_reset(gc->dev);
+}
+
+static int mana_cdx_setup_hwc_irqs(struct gdma_context *gc)
+{
+ struct cdx_device *cdx_dev = to_cdx_device(gc->dev);
+ struct gdma_irq_context *gic;
+ unsigned int max_irqs;
+ int nvec;
+ int err, i = 0, j;
+
+ max_irqs = cdx_dev->num_msi;
+
+ /* Need 1 IRQ for HWC and at least 1 for the data path queues */
+ if (max_irqs < 2) {
+ dev_err(&cdx_dev->dev, "Not enough MSI vectors: %u\n",
+ max_irqs);
+ return -ENOSPC;
+ }
+
+ /* Constrain the device to 32-bit DMA addresses, for both the MSI
+ * doorbells and the data path buffers, and never widen it afterwards.
+ *
+ * The MSI doorbell address has to land within the low 4GB. The data
+ * path carries a second constraint: the device does not perform
+ * writes to the final page of the 48-bit IOVA window, and
+ * iommu_dma_alloc_iova() allocates downwards from the top of that
+ * window, so the first queue created lands on the unusable page and
+ * its event queue stalls permanently. PCI devices are shielded from
+ * this by the low-4GB first attempt in iommu_dma_alloc_iova(), but
+ * that attempt is gated on dev_is_pci() and CDX devices do not
+ * qualify.
+ */
+ err = dma_set_mask_and_coherent(gc->dev, DMA_BIT_MASK(32));
+ if (err) {
+ dev_err(&cdx_dev->dev, "Failed to set 32-bit DMA mask\n");
+ return err;
+ }
+
+ /* The PCI path also calls dma_set_max_seg_size(), but that is
+ * deliberately omitted here: the CDX core does not attach a
+ * dma_parms to the device, so the helper would only WARN, and MANA
+ * never builds scatter-gather lists, so the limit is never read.
+ */
+
+ err = cdx_enable_msi(cdx_dev);
+ if (err) {
+ dev_err(&cdx_dev->dev, "Failed to enable MSI\n");
+ return err;
+ }
+
+ err = msi_domain_alloc_irqs(gc->dev, MSI_DEFAULT_DOMAIN, max_irqs);
+ if (err) {
+ dev_err(&cdx_dev->dev, "Failed to alloc MSI IRQs\n");
+ cdx_disable_msi(cdx_dev);
+ return err;
+ }
+
+ nvec = max_irqs;
+
+ xa_init(&gc->irq_contexts);
+
+ /* No IRQ affinity hint is applied here. The PCI transport spreads its
+ * vectors over the NUMA node local to the device; the CDX platforms
+ * this driver targets are single-node, so there is nothing to spread
+ * over. Affinity management can be added when a multi-node CDX host
+ * exists to validate it against.
+ */
+ for (i = 0; i < nvec; i++) {
+ int msi = i;
+
+ gic = mana_gd_get_gic(gc, false, &msi);
+ if (IS_ERR(gic)) {
+ err = PTR_ERR(gic);
+ goto free_irq;
+ }
+ }
+
+ gc->max_num_msix = nvec;
+ gc->num_msix_usable = nvec;
+
+ /* CDX sizes its MSI pool at probe time and cannot grow it later, so
+ * never share vectors: vector 0 is reserved for the HWC and each of
+ * the remaining nvec - 1 vectors backs exactly one EQ. That bounds
+ * the queue count at nvec - 1 and guarantees the HWC vector is never
+ * handed out to a data queue.
+ */
+ gc->msi_sharing = false;
+
+ gc->msi_bitmap = bitmap_zalloc(nvec, GFP_KERNEL);
+ if (!gc->msi_bitmap) {
+ err = -ENOMEM;
+ goto free_irq;
+ }
+
+ /* Reserve the HWC vector */
+ set_bit(0, gc->msi_bitmap);
+
+ return 0;
+
+free_irq:
+ for (j = i - 1; j >= 0; j--)
+ mana_gd_put_gic(gc, false, j);
+
+ xa_destroy(&gc->irq_contexts);
+ msi_domain_free_irqs_all(gc->dev, MSI_DEFAULT_DOMAIN);
+ cdx_disable_msi(cdx_dev);
+ return err;
+}
+
+static void mana_cdx_remove_irqs(struct gdma_context *gc)
+{
+ struct cdx_device *cdx_dev = to_cdx_device(gc->dev);
+ int i;
+
+ if (gc->max_num_msix < 1)
+ return;
+
+ for (i = 0; i < gc->max_num_msix; i++) {
+ if (!xa_load(&gc->irq_contexts, i))
+ continue;
+
+ mana_gd_put_gic(gc, false, i);
+ }
+
+ WARN_ON(!xa_empty(&gc->irq_contexts));
+
+ xa_destroy(&gc->irq_contexts);
+ msi_domain_free_irqs_all(gc->dev, MSI_DEFAULT_DOMAIN);
+ cdx_disable_msi(cdx_dev);
+
+ bitmap_free(gc->msi_bitmap);
+ gc->msi_bitmap = NULL;
+ gc->max_num_msix = 0;
+ gc->num_msix_usable = 0;
+}
+
+static int mana_cdx_setup_remaining_irqs(struct gdma_context *gc)
+{
+ unsigned int max_queues_vport;
+
+ /* mana_gd_query_max_resources() may turn MSI sharing back on and round
+ * the per-vPort queue count up to MANA_DEF_NUM_QUEUES. CDX sizes its
+ * vector pool at probe time and cannot grow it later, and the HWC
+ * vector must stay private, so give every vPort a private slice of the
+ * remaining vectors instead. gc->max_num_queues is already capped at
+ * num_msix_usable - 1 by the core.
+ */
+ gc->msi_sharing = false;
+ max_queues_vport = (gc->num_msix_usable - 1) / gc->num_ports;
+ if (!max_queues_vport) {
+ dev_err(gc->dev, "%u MSI vectors cannot serve %u vPorts\n",
+ gc->num_msix_usable, gc->num_ports);
+ return -ENOSPC;
+ }
+
+ gc->max_num_queues_vport = min(gc->max_num_queues, max_queues_vport);
+
+ dev_dbg(gc->dev, "%u MSI vectors, %u vPorts, %u queues, no MSI sharing\n",
+ gc->num_msix_usable, gc->num_ports, gc->max_num_queues_vport);
+
+ return 0;
+}
+
+static const struct gdma_bus_ops mana_cdx_bus_ops = {
+ .bus_name = "cdx",
+ .adev_prefix = "mana_cdx",
+ .msix_virq = mana_cdx_msix_virq,
+ .setup_hwc_irqs = mana_cdx_setup_hwc_irqs,
+ .setup_remaining_irqs = mana_cdx_setup_remaining_irqs,
+ .remove_irqs = mana_cdx_remove_irqs,
+ .dev_reset = mana_cdx_dev_reset,
+};
+
+static int mana_cdx_gd_probe(struct cdx_device *cdx_dev)
+{
+ struct gdma_context *gc;
+ void __iomem *bar0_va;
+ int err;
+
+ /* Each port has 2 CQs, each CQ has at most 1 EQE at a time */
+ BUILD_BUG_ON(2 * MAX_PORTS_IN_MANA_DEV * GDMA_EQE_SIZE > EQ_SIZE);
+
+ err = cdx_dev_reset(&cdx_dev->dev);
+ if (err)
+ return err;
+
+ err = cdx_set_master(cdx_dev);
+ if (err)
+ return err;
+
+ gc = vzalloc(sizeof(*gc));
+ if (!gc) {
+ err = -ENOMEM;
+ goto clear_master;
+ }
+
+ mutex_init(&gc->eq_test_event_mutex);
+ mutex_init(&gc->gic_mutex);
+ dev_set_drvdata(&cdx_dev->dev, gc);
+ gc->bar0_pa = cdx_resource_start(cdx_dev, 0);
+ gc->bar0_size = cdx_resource_len(cdx_dev, 0);
+ if (gc->bar0_size < MANA_CDX_GDMA_REGS_SIZE) {
+ dev_err(&cdx_dev->dev, "BAR0 size %#llx is too small\n",
+ (u64)gc->bar0_size);
+ err = -EINVAL;
+ goto free_gc;
+ }
+
+ bar0_va = ioremap(gc->bar0_pa, gc->bar0_size);
+ if (!bar0_va) {
+ err = -ENOMEM;
+ goto free_gc;
+ }
+
+ gc->numa_node = dev_to_node(&cdx_dev->dev);
+ gc->bar0_va = bar0_va;
+ gc->dev = &cdx_dev->dev;
+ gc->bus_ops = &mana_cdx_bus_ops;
+
+ /* gc->is_pf is intentionally left clear: this device uses the VF
+ * register layout, and the vPort and MAC filter registration that
+ * is_pf selects is not required on this bus.
+ */
+
+ err = mana_gd_setup(gc);
+ if (err)
+ goto unmap_bar;
+
+ err = mana_probe(&gc->mana, false);
+ if (err)
+ goto cleanup_gd;
+
+ err = mana_rdma_probe(&gc->mana_ib);
+ if (err)
+ goto remove_mana;
+
+ /* If a hardware reset event arrived over HWC during probe, roll back:
+ * the device state the rest of probe observed is no longer valid.
+ */
+ if (test_and_set_bit(GC_PROBE_SUCCEEDED, &gc->flags)) {
+ err = -EPROTO;
+ goto remove_rdma;
+ }
+
+ return 0;
+
+remove_rdma:
+ mana_rdma_remove(&gc->mana_ib);
+remove_mana:
+ mana_remove(&gc->mana, false);
+cleanup_gd:
+ mana_gd_cleanup(gc);
+unmap_bar:
+ iounmap(bar0_va);
+free_gc:
+ dev_set_drvdata(&cdx_dev->dev, NULL);
+ vfree(gc);
+clear_master:
+ cdx_clear_master(cdx_dev);
+ return err;
+}
+
+static int mana_cdx_gd_remove(struct cdx_device *cdx_dev)
+{
+ struct gdma_context *gc = dev_get_drvdata(&cdx_dev->dev);
+
+ mana_rdma_remove(&gc->mana_ib);
+ mana_remove(&gc->mana, false);
+
+ mana_gd_cleanup(gc);
+ cdx_clear_master(cdx_dev);
+
+ iounmap(gc->bar0_va);
+
+ dev_set_drvdata(&cdx_dev->dev, NULL);
+ vfree(gc);
+ return 0;
+}
+
+/* Quiesce the device for kexec. This is also called upon reboot/shutdown. */
+static void mana_cdx_gd_shutdown(struct cdx_device *cdx_dev)
+{
+ struct gdma_context *gc = dev_get_drvdata(&cdx_dev->dev);
+
+ mana_rdma_remove(&gc->mana_ib);
+ mana_remove(&gc->mana, true);
+
+ mana_gd_cleanup(gc);
+ cdx_clear_master(cdx_dev);
+}
+
+#define CDX_VENDOR_ID_MICROSOFT 0x1414
+static const struct cdx_device_id mana_cdx_table[] = {
+ { CDX_DEVICE(CDX_VENDOR_ID_MICROSOFT, MANA_CDX_DEVICE_ID) },
+ {}
+};
+
+MODULE_DEVICE_TABLE(cdx, mana_cdx_table);
+
+static struct cdx_driver gdma_cdx_driver = {
+ .match_id_table = mana_cdx_table,
+ .probe = mana_cdx_gd_probe,
+ .remove = mana_cdx_gd_remove,
+ .shutdown = mana_cdx_gd_shutdown,
+ .driver = {
+ .name = "mana_cdx",
+ },
+};
+
+module_driver(gdma_cdx_driver, cdx_driver_register, cdx_driver_unregister);
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("Microsoft Azure Network Adapter driver for the CDX bus");
+MODULE_IMPORT_NS("CDX_BUS");
+MODULE_IMPORT_NS("NET_MANA");
diff --git a/drivers/net/ethernet/microsoft/mana/gdma_pci.c b/drivers/net/ethernet/microsoft/mana/gdma_pci.c
index 92a1e66e18b7..ed8925296c8a 100644
--- a/drivers/net/ethernet/microsoft/mana/gdma_pci.c
+++ b/drivers/net/ethernet/microsoft/mana/gdma_pci.c
@@ -619,6 +619,7 @@ static void mana_pci_remove_irqs(struct gdma_context *gc)
static const struct gdma_bus_ops mana_pci_bus_ops = {
.bus_name = "pci",
+ .adev_prefix = "mana",
.msix_can_alloc_dyn = mana_pci_msix_can_alloc_dyn,
.msix_virq = mana_pci_msix_virq,
.msix_alloc_at = mana_pci_msix_alloc_at,
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 16a9d192c099..2ba48a1c4b15 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -3957,8 +3957,9 @@ static int add_adev(struct gdma_dev *gd, const char *name)
/* madev is owned by the auxiliary device */
madev = NULL;
- /* Keep the established mana.{eth,rdma} auxiliary match names. */
- ret = __auxiliary_device_add(adev, "mana");
+ /* Keep match names independent of the common module's name. */
+ ret = __auxiliary_device_add(adev,
+ gd->gdma_context->bus_ops->adev_prefix);
if (ret)
goto add_fail;
diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h
index cdec5558304f..c610fc1067e0 100644
--- a/include/net/mana/gdma.h
+++ b/include/net/mana/gdma.h
@@ -432,6 +432,7 @@ struct gdma_context;
* instance in gdma_context.bus_ops at probe time.
*
* @bus_name: Bus token used to build the per-vector IRQ names.
+ * @adev_prefix: Prefix used for auxiliary-device match names.
* @msix_can_alloc_dyn: True if the bus can allocate MSI-X vectors after
* probe time. Buses that size their vector pool at probe and cannot
* grow it later leave this NULL.
@@ -459,6 +460,7 @@ struct gdma_context;
*/
struct gdma_bus_ops {
const char *bus_name;
+ const char *adev_prefix;
bool (*msix_can_alloc_dyn)(struct gdma_context *gc);
int (*msix_virq)(struct gdma_context *gc, int msi);
int (*msix_alloc_at)(struct gdma_context *gc, int *msi);
@@ -684,6 +686,8 @@ struct gdma_eqe {
#define MANA_PF2_DEVICE_ID 0x00C1
#define MANA_VF_DEVICE_ID 0x00BA
+#define MANA_CDX_DEVICE_ID 0x00C2
+
struct gdma_posted_wqe_info {
u32 wqe_size_in_bu;
};
--
2.54.0
prev parent reply other threads:[~2026-09-24 17:31 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-24 17:30 [PATCH net-next 0/4] net: mana: Add support for the CDX bus Manish Awasthi
2026-09-24 17:30 ` [PATCH net-next 1/4] net: mana: Introduce gdma_bus_ops for bus-specific operations Manish Awasthi
2026-09-24 17:30 ` [PATCH net-next 2/4] net: mana: Move PCI transport code into gdma_pci.c Manish Awasthi
2026-09-24 17:30 ` [PATCH net-next 3/4] net: mana: Build the PCI transport as a separate module Manish Awasthi
2026-09-24 17:30 ` Manish Awasthi [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260924173054.589291-5-mawasthi@linux.microsoft.com \
--to=mawasthi@linux.microsoft.com \
--cc=andrew+netdev@lunn.ch \
--cc=bpf@vger.kernel.org \
--cc=davem@davemloft.net \
--cc=decui@microsoft.com \
--cc=edumazet@google.com \
--cc=ernis@linux.microsoft.com \
--cc=gargaditya@linux.microsoft.com \
--cc=haiyangz@microsoft.com \
--cc=horms@kernel.org \
--cc=kees@kernel.org \
--cc=kotaranov@microsoft.com \
--cc=kuba@kernel.org \
--cc=kys@microsoft.com \
--cc=linux-hyperv@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-rdma@vger.kernel.org \
--cc=longli@microsoft.com \
--cc=mawasthi@microsoft.com \
--cc=netdev@vger.kernel.org \
--cc=nikhil.agarwal@amd.com \
--cc=nipun.gupta@amd.com \
--cc=pabeni@redhat.com \
--cc=paulros@microsoft.com \
--cc=wei.liu@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®