[PATCH 12/15] NTB: hw: epf: Enumerate auxiliary child for DMA ABI v1

From: Koichiro Den

Date: Thu Mar 12 2026 - 12:54:54 EST


When the peer advertises exported DMA ABI v1, create an auxiliary child
device named "ep_dma_v1" and pass the parsed locator and IRQ information
via a software node.

Register the child only after LINK_UP succeeds so the provider is not
probed before the remote BAR layout is live, and tear it down again on
link down or device removal.

This gives controller-specific frontends a clean attachment point
without teaching ntb_hw_epf about any particular DMA engine.

Signed-off-by: Koichiro Den <den@xxxxxxxxxxxxx>
---
drivers/ntb/hw/epf/Kconfig | 1 +
drivers/ntb/hw/epf/ntb_hw_epf.c | 87 +++++++++++++++++++++++++++++++++
2 files changed, 88 insertions(+)

diff --git a/drivers/ntb/hw/epf/Kconfig b/drivers/ntb/hw/epf/Kconfig
index 314485574bf8..03139d6eddc8 100644
--- a/drivers/ntb/hw/epf/Kconfig
+++ b/drivers/ntb/hw/epf/Kconfig
@@ -1,5 +1,6 @@
config NTB_EPF
tristate "Generic EPF Non-Transparent Bridge support"
+ select AUXILIARY_BUS
help
This driver supports EPF NTB on configurable endpoint.
If unsure, say N.
diff --git a/drivers/ntb/hw/epf/ntb_hw_epf.c b/drivers/ntb/hw/epf/ntb_hw_epf.c
index 6b427577b1bd..31f1d3bdffc9 100644
--- a/drivers/ntb/hw/epf/ntb_hw_epf.c
+++ b/drivers/ntb/hw/epf/ntb_hw_epf.c
@@ -7,9 +7,13 @@
*/

#include <linux/atomic.h>
+#include <linux/auxiliary_bus.h>
+#include <linux/cleanup.h>
#include <linux/delay.h>
+#include <linux/idr.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/property.h>
#include <linux/slab.h>
#include <linux/ntb.h>

@@ -75,6 +79,8 @@

#define NTB_EPF_COMMAND_TIMEOUT 1000 /* 1 Sec */

+static DEFINE_IDA(dma_aux_ids);
+
enum pci_barno {
NO_BAR = -1,
BAR_0,
@@ -124,6 +130,8 @@ struct ntb_epf_dev {
u32 dma_irq_count;
enum pci_barno dma_bar;
bool dma_aux_avail;
+ bool dma_aux_added;
+ struct auxiliary_device *dma_auxdev;

void __iomem *ctrl_reg;
void __iomem *db_reg;
@@ -138,6 +146,78 @@ struct ntb_epf_dev {

#define ntb_ndev(__ntb) container_of(__ntb, struct ntb_epf_dev, ntb)

+static void ntb_epf_dma_aux_release(struct device *dev)
+{
+ struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
+
+ kfree(auxdev);
+}
+
+static int ntb_epf_register_dma_auxdev(struct ntb_epf_dev *ndev)
+{
+ const struct property_entry props[] = {
+ PROPERTY_ENTRY_U32("dma-abi", ndev->dma_abi),
+ PROPERTY_ENTRY_U32("dma-bar", ndev->dma_bar),
+ PROPERTY_ENTRY_U32("dma-offset", ndev->dma_offset),
+ PROPERTY_ENTRY_U32("dma-size", ndev->dma_size),
+ PROPERTY_ENTRY_U32("dma-num-chans", ndev->dma_num_chans),
+ PROPERTY_ENTRY_U32("dma-irq-base", ndev->dma_irq_base),
+ PROPERTY_ENTRY_U32("dma-irq-count", ndev->dma_irq_count),
+ { }
+ };
+ int ret;
+
+ if (!ndev->dma_aux_avail || ndev->dma_abi != 1 || ndev->dma_aux_added)
+ return 0;
+
+ struct auxiliary_device *auxdev __free(kfree) = kzalloc_obj(*auxdev);
+ if (!auxdev)
+ return -ENOMEM;
+
+ ret = ida_alloc(&dma_aux_ids, GFP_KERNEL);
+ if (ret < 0)
+ return ret;
+
+ auxdev->name = "ep_dma_v1";
+ auxdev->id = ret;
+ auxdev->dev.parent = ndev->dev;
+ auxdev->dev.release = ntb_epf_dma_aux_release;
+
+ ret = auxiliary_device_init(auxdev);
+ if (ret)
+ goto err_free_id;
+
+ auxdev->dev.dma_parms = ndev->dev->dma_parms;
+
+ ret = device_create_managed_software_node(&auxdev->dev, props, NULL);
+ if (ret)
+ goto err_uninit;
+
+ ret = auxiliary_device_add(auxdev);
+ if (ret)
+ goto err_uninit;
+
+ ndev->dma_aux_added = true;
+ ndev->dma_auxdev = no_free_ptr(auxdev);
+ return 0;
+
+err_uninit:
+ auxiliary_device_uninit(auxdev);
+err_free_id:
+ ida_free(&dma_aux_ids, auxdev->id);
+ return ret;
+}
+
+static void ntb_epf_unregister_dma_auxdev(struct ntb_epf_dev *ndev)
+{
+ if (!ndev->dma_aux_added)
+ return;
+
+ auxiliary_device_delete(ndev->dma_auxdev);
+ auxiliary_device_uninit(ndev->dma_auxdev);
+ ndev->dma_aux_added = false;
+}
+
static int ntb_epf_send_command(struct ntb_epf_dev *ndev, u32 command,
u32 argument)
{
@@ -337,6 +417,10 @@ static int ntb_epf_link_enable(struct ntb_dev *ntb,
return ret;
}

+ ret = ntb_epf_register_dma_auxdev(ndev);
+ if (ret)
+ dev_warn(dev, "Failed to register DMA auxiliary device\n");
+
return 0;
}

@@ -346,6 +430,8 @@ static int ntb_epf_link_disable(struct ntb_dev *ntb)
struct device *dev = ndev->dev;
int ret;

+ ntb_epf_unregister_dma_auxdev(ndev);
+
ret = ntb_epf_send_command(ndev, CMD_LINK_DOWN, 0);
if (ret) {
dev_err(dev, "Fail to disable link\n");
@@ -891,6 +977,7 @@ static void ntb_epf_pci_remove(struct pci_dev *pdev)
{
struct ntb_epf_dev *ndev = pci_get_drvdata(pdev);

+ ntb_epf_unregister_dma_auxdev(ndev);
ntb_unregister_device(&ndev->ntb);
ntb_epf_cleanup_isr(ndev);
ntb_epf_deinit_pci(ndev);
--
2.51.0