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

Koichiro Den posted 15 patches 3 weeks, 4 days ago
[PATCH 12/15] NTB: hw: epf: Enumerate auxiliary child for DMA ABI v1
Posted by Koichiro Den 3 weeks, 4 days ago
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@valinux.co.jp>
---
 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