[PATCH 12/15] NTB: hw: epf: Enumerate auxiliary child for DMA ABI v1
Koichiro Den <[email protected]> Fri, 13 Mar 2026 01:50:02 +0900
| Newsgroups | dev.linux.lists.ntb,org.kernel.vger.dmaengine,org.kernel.vger.linux-doc,org.kernel.vger.linux-kernel,org.kernel.vger.linux-pci |
|---|---|
| Message-ID | <[email protected]> |
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 <[email protected]> --- 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