mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
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

      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®