mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2 0/7] dmaengine: dw-edma, PCI: dwc: Enable remote use of integrated DesignWare eDMA
@ 2026-01-27  3:34 Koichiro Den
  2026-01-27  3:34 ` [PATCH v2 1/7] dmaengine: Add hw_id to dma_slave_caps Koichiro Den
                   ` (7 more replies)
  0 siblings, 8 replies; 20+ messages in thread
From: Koichiro Den @ 2026-01-27  3:34 UTC (permalink / raw)
  To: vkoul, mani, Frank.Li, jingoohan1, lpieralisi, kwilczynski, robh,
	bhelgaas
  Cc: dmaengine, linux-pci, linux-kernel

Hi,

Per Frank Li's suggestion [1], this revision combines the previously posted
PCI/dwc helper series and the dmaengine/dw-edma series into a single
7-patch set. This series therefore supersedes the two earlier postings:

  - [PATCH 0/5] dmaengine: dw-edma: Add helpers for remote eDMA use scenarios
    https://lore.kernel.org/dmaengine/20260126073652.3293564-1-den@valinux.co.jp/
  - [PATCH 0/2] PCI: dwc: Expose integrated DesignWare eDMA windows
    https://lore.kernel.org/linux-pci/20260126071550.3233631-1-den@valinux.co.jp/

[1] https://lore.kernel.org/linux-pci/aXeoxxG+9cFML1sx@lizhi-Precision-Tower-5810/

Some DesignWare PCIe endpoint platforms integrate a DesignWare eDMA
instance alongside the PCIe controller. In remote eDMA use cases, the host
needs access to the eDMA register block and the per-channel linked-list
(LL) regions via PCIe BARs, while the endpoint may still boot with a
standard EP configuration (and may also use dw-edma locally).

This series provides the following building blocks:

  * dmaengine: Add an optional dma_slave_caps.hw_id so DMA providers can expose
    a provider-defined hardware channel identifier to clients, and report it
    from dw-edma. This allows users to correlate a DMA channel with
    hardware-specific resources such as per-channel LL regions.

  * dmaengine/dw-edma: Add features useful for remote-controlled EP eDMA usage:
      - per-channel interrupt routing control (configured via dmaengine_slave_config(),
        passing a small dw-edma-specific structure through
        dma_slave_config.peripheral_config / dma_slave_config.peripheral_size),
      - optional completion polling when local IRQ handling is disabled, and
      - notify-only channels for cases where the local side needs interrupt
	notification without cookie-based accounting (i.e. its peer
	prepares and submits the descriptors), useful when host-to-endpoint
	interrupt delivery is difficult or unavailable without it.

  * PCI: dwc: Add query-only helper APIs to expose resources of an integrated
    DesignWare eDMA instance:
      - the physical base/size of the eDMA register window, and
      - the per-channel LL region base/size, keyed by transfer direction and
        the hardware channel identifier (hw_id).

The first real user will likely be the DesignWare backend in the NTB transport work:

  [RFC PATCH v4 25/38] NTB: hw: Add remote eDMA backend registry and DesignWare backend
  https://lore.kernel.org/linux-pci/20260118135440.1958279-26-den@valinux.co.jp/

    (Note: the implementation in this series has been updated since that
    RFC v4, so the RFC series will also need some adjustments. I have an
    updated RFC series locally and can post an RFC v5 if that would help
    review/testing.)

Apply/merge notes:
  - Patches 1-5 apply cleanly on dmaengine.git next.
  - Patches 6-7 apply cleanly on pci.git controller/dwc.

Changes in v2:
  - Combine the two previously posted series into a single set (per Frank's
    suggestion). Order dmaengine/dw-edma patches first so hw_id support
    lands before the PCI LL-region helper, which assumes
    dma_slave_caps.hw_id availability.

Thanks for reviewing,


Koichiro Den (7):
  dmaengine: Add hw_id to dma_slave_caps
  dmaengine: dw-edma: Report channel hw_id in dma_slave_caps
  dmaengine: dw-edma: Add per-channel interrupt routing control
  dmaengine: dw-edma: Poll completion when local IRQ handling is
    disabled
  dmaengine: dw-edma: Add notify-only channels support
  PCI: dwc: Add helper to query integrated dw-edma register window
  PCI: dwc: Add helper to query integrated dw-edma linked-list region

 MAINTAINERS                                  |   2 +-
 drivers/dma/dmaengine.c                      |   1 +
 drivers/dma/dw-edma/dw-edma-core.c           | 167 +++++++++++++++++--
 drivers/dma/dw-edma/dw-edma-core.h           |  21 +++
 drivers/dma/dw-edma/dw-edma-v0-core.c        |  26 ++-
 drivers/pci/controller/dwc/pcie-designware.c |  74 ++++++++
 drivers/pci/controller/dwc/pcie-designware.h |   2 +
 include/linux/dma/edma.h                     |  57 +++++++
 include/linux/dmaengine.h                    |   2 +
 include/linux/pcie-dwc-edma.h                |  72 ++++++++
 10 files changed, 398 insertions(+), 26 deletions(-)
 create mode 100644 include/linux/pcie-dwc-edma.h

-- 
2.51.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 1/7] dmaengine: Add hw_id to dma_slave_caps
  2026-01-27  3:34 [PATCH v2 0/7] dmaengine: dw-edma, PCI: dwc: Enable remote use of integrated DesignWare eDMA Koichiro Den
@ 2026-01-27  3:34 ` Koichiro Den
  2026-01-27  3:34 ` [PATCH v2 2/7] dmaengine: dw-edma: Report channel hw_id in dma_slave_caps Koichiro Den
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 20+ messages in thread
From: Koichiro Den @ 2026-01-27  3:34 UTC (permalink / raw)
  To: vkoul, mani, Frank.Li, jingoohan1, lpieralisi, kwilczynski, robh,
	bhelgaas
  Cc: dmaengine, linux-pci, linux-kernel

Remote DMA users may need to map or otherwise correlate DMA resources on
a per-hardware-channel basis (e.g. DWC EP eDMA linked-list windows).
However, struct dma_chan does not expose a provider-defined hardware
channel identifier.

Add an optional dma_slave_caps.hw_id field to allow DMA engine drivers
to report a provider-specific hardware channel identifier to clients.
Initialize the field to -1 in dma_get_slave_caps() so drivers that do
not populate it continue to behave as before.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
 drivers/dma/dmaengine.c   | 1 +
 include/linux/dmaengine.h | 2 ++
 2 files changed, 3 insertions(+)

diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index ca13cd39330b..b544eb99359d 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -603,6 +603,7 @@ int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
 	caps->cmd_pause = !!device->device_pause;
 	caps->cmd_resume = !!device->device_resume;
 	caps->cmd_terminate = !!device->device_terminate_all;
+	caps->hw_id = -1;
 
 	/*
 	 * DMA engine device might be configured with non-uniformly
diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 99efe2b9b4ea..71bc2674567f 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -507,6 +507,7 @@ enum dma_residue_granularity {
  * @residue_granularity: granularity of the reported transfer residue
  * @descriptor_reuse: if a descriptor can be reused by client and
  * resubmitted multiple times
+ * @hw_id: provider-specific hardware channel identifier (-1 if unknown)
  */
 struct dma_slave_caps {
 	u32 src_addr_widths;
@@ -520,6 +521,7 @@ struct dma_slave_caps {
 	bool cmd_terminate;
 	enum dma_residue_granularity residue_granularity;
 	bool descriptor_reuse;
+	int hw_id;
 };
 
 static inline const char *dma_chan_name(struct dma_chan *chan)
-- 
2.51.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 2/7] dmaengine: dw-edma: Report channel hw_id in dma_slave_caps
  2026-01-27  3:34 [PATCH v2 0/7] dmaengine: dw-edma, PCI: dwc: Enable remote use of integrated DesignWare eDMA Koichiro Den
  2026-01-27  3:34 ` [PATCH v2 1/7] dmaengine: Add hw_id to dma_slave_caps Koichiro Den
@ 2026-01-27  3:34 ` Koichiro Den
  2026-01-27  3:34 ` [PATCH v2 3/7] dmaengine: dw-edma: Add per-channel interrupt routing control Koichiro Den
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 20+ messages in thread
From: Koichiro Den @ 2026-01-27  3:34 UTC (permalink / raw)
  To: vkoul, mani, Frank.Li, jingoohan1, lpieralisi, kwilczynski, robh,
	bhelgaas
  Cc: dmaengine, linux-pci, linux-kernel

Expose the DesignWare eDMA per-channel identifier (chan->id) via
dma_get_slave_caps(). Note that the id space is separated for each read
or write channels.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
 drivers/dma/dw-edma/dw-edma-core.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 8e5f7defa6b6..38832d9447fd 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -217,6 +217,7 @@ static void dw_edma_device_caps(struct dma_chan *dchan,
 		else
 			caps->directions = BIT(DMA_MEM_TO_DEV);
 	}
+	caps->hw_id = chan->id;
 }
 
 static int dw_edma_device_config(struct dma_chan *dchan,
-- 
2.51.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 3/7] dmaengine: dw-edma: Add per-channel interrupt routing control
  2026-01-27  3:34 [PATCH v2 0/7] dmaengine: dw-edma, PCI: dwc: Enable remote use of integrated DesignWare eDMA Koichiro Den
  2026-01-27  3:34 ` [PATCH v2 1/7] dmaengine: Add hw_id to dma_slave_caps Koichiro Den
  2026-01-27  3:34 ` [PATCH v2 2/7] dmaengine: dw-edma: Report channel hw_id in dma_slave_caps Koichiro Den
@ 2026-01-27  3:34 ` Koichiro Den
  2026-01-27  3:34 ` [PATCH v2 4/7] dmaengine: dw-edma: Poll completion when local IRQ handling is disabled Koichiro Den
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 20+ messages in thread
From: Koichiro Den @ 2026-01-27  3:34 UTC (permalink / raw)
  To: vkoul, mani, Frank.Li, jingoohan1, lpieralisi, kwilczynski, robh,
	bhelgaas
  Cc: dmaengine, linux-pci, linux-kernel

DesignWare EP eDMA can generate interrupts both locally and remotely
(LIE/RIE). Remote eDMA users need to decide, per channel, whether
completions should be handled locally, remotely, or both. Unless
carefully configured, the endpoint and host would race to ack the
interrupt.

Introduce a dw_edma_peripheral_config that holds per-channel interrupt
routing mode. Update v0 programming so that RIE and local done/abort
interrupt masking follow the selected mode. The default mode keeps the
original behavior, so unless the new peripheral_config is explicitly
used and set, no functional changes.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
 drivers/dma/dw-edma/dw-edma-core.c    | 21 ++++++++++++++++++++
 drivers/dma/dw-edma/dw-edma-core.h    | 13 +++++++++++++
 drivers/dma/dw-edma/dw-edma-v0-core.c | 26 +++++++++++++++++--------
 include/linux/dma/edma.h              | 28 +++++++++++++++++++++++++++
 4 files changed, 80 insertions(+), 8 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 38832d9447fd..e006f1fa2ee5 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -224,6 +224,26 @@ static int dw_edma_device_config(struct dma_chan *dchan,
 				 struct dma_slave_config *config)
 {
 	struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+	const struct dw_edma_peripheral_config *pcfg;
+
+	/* peripheral_config is optional, default keeps legacy behaviour. */
+	chan->irq_mode = DW_EDMA_CH_IRQ_DEFAULT;
+
+	if (config->peripheral_config) {
+		if (config->peripheral_size < sizeof(*pcfg))
+			return -EINVAL;
+
+		pcfg = config->peripheral_config;
+		switch (pcfg->irq_mode) {
+		case DW_EDMA_CH_IRQ_DEFAULT:
+		case DW_EDMA_CH_IRQ_LOCAL:
+		case DW_EDMA_CH_IRQ_REMOTE:
+			chan->irq_mode = pcfg->irq_mode;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
 
 	memcpy(&chan->config, config, sizeof(*config));
 	chan->configured = true;
@@ -750,6 +770,7 @@ static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)
 		chan->configured = false;
 		chan->request = EDMA_REQ_NONE;
 		chan->status = EDMA_ST_IDLE;
+		chan->irq_mode = DW_EDMA_CH_IRQ_DEFAULT;
 
 		if (chan->dir == EDMA_DIR_WRITE)
 			chan->ll_max = (chip->ll_region_wr[chan->id].sz / EDMA_LL_SZ);
diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
index 71894b9e0b15..0608b9044a08 100644
--- a/drivers/dma/dw-edma/dw-edma-core.h
+++ b/drivers/dma/dw-edma/dw-edma-core.h
@@ -81,6 +81,8 @@ struct dw_edma_chan {
 
 	struct msi_msg			msi;
 
+	enum dw_edma_ch_irq_mode	irq_mode;
+
 	enum dw_edma_request		request;
 	enum dw_edma_status		status;
 	u8				configured;
@@ -206,4 +208,15 @@ void dw_edma_core_debugfs_on(struct dw_edma *dw)
 	dw->core->debugfs_on(dw);
 }
 
+static inline
+bool dw_edma_core_ch_ignore_irq(struct dw_edma_chan *chan)
+{
+	struct dw_edma *dw = chan->dw;
+
+	if (dw->chip->flags & DW_EDMA_CHIP_LOCAL)
+		return chan->irq_mode == DW_EDMA_CH_IRQ_REMOTE;
+	else
+		return chan->irq_mode == DW_EDMA_CH_IRQ_LOCAL;
+}
+
 #endif /* _DW_EDMA_CORE_H */
diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
index b75fdaffad9a..a0441e8aa3b3 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
@@ -256,8 +256,10 @@ dw_edma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
 	for_each_set_bit(pos, &val, total) {
 		chan = &dw->chan[pos + off];
 
-		dw_edma_v0_core_clear_done_int(chan);
-		done(chan);
+		if (!dw_edma_core_ch_ignore_irq(chan)) {
+			dw_edma_v0_core_clear_done_int(chan);
+			done(chan);
+		}
 
 		ret = IRQ_HANDLED;
 	}
@@ -267,8 +269,10 @@ dw_edma_v0_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir,
 	for_each_set_bit(pos, &val, total) {
 		chan = &dw->chan[pos + off];
 
-		dw_edma_v0_core_clear_abort_int(chan);
-		abort(chan);
+		if (!dw_edma_core_ch_ignore_irq(chan)) {
+			dw_edma_v0_core_clear_abort_int(chan);
+			abort(chan);
+		}
 
 		ret = IRQ_HANDLED;
 	}
@@ -331,7 +335,8 @@ static void dw_edma_v0_core_write_chunk(struct dw_edma_chunk *chunk)
 		j--;
 		if (!j) {
 			control |= DW_EDMA_V0_LIE;
-			if (!(chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL))
+			if (!(chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL) &&
+			    chan->irq_mode != DW_EDMA_CH_IRQ_LOCAL)
 				control |= DW_EDMA_V0_RIE;
 		}
 
@@ -407,10 +412,15 @@ static void dw_edma_v0_core_start(struct dw_edma_chunk *chunk, bool first)
 				break;
 			}
 		}
-		/* Interrupt unmask - done, abort */
+		/* Interrupt mask/unmask - done, abort */
 		tmp = GET_RW_32(dw, chan->dir, int_mask);
-		tmp &= ~FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id));
-		tmp &= ~FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id));
+		if (chan->irq_mode == DW_EDMA_CH_IRQ_REMOTE) {
+			tmp |= FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id));
+			tmp |= FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id));
+		} else {
+			tmp &= ~FIELD_PREP(EDMA_V0_DONE_INT_MASK, BIT(chan->id));
+			tmp &= ~FIELD_PREP(EDMA_V0_ABORT_INT_MASK, BIT(chan->id));
+		}
 		SET_RW_32(dw, chan->dir, int_mask, tmp);
 		/* Linked list error */
 		tmp = GET_RW_32(dw, chan->dir, linked_list_err_en);
diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
index 3080747689f6..16e9adc60eb8 100644
--- a/include/linux/dma/edma.h
+++ b/include/linux/dma/edma.h
@@ -60,6 +60,34 @@ enum dw_edma_chip_flags {
 	DW_EDMA_CHIP_LOCAL	= BIT(0),
 };
 
+/*
+ * enum dw_edma_ch_irq_mode - per-channel interrupt routing control
+ * @DW_EDMA_CH_IRQ_DEFAULT:   LIE=1/RIE=1, local interrupt unmasked
+ * @DW_EDMA_CH_IRQ_LOCAL:     LIE=1/RIE=0
+ * @DW_EDMA_CH_IRQ_REMOTE:    LIE=1/RIE=1, local interrupt masked
+ *
+ * Some implementations require using LIE=1/RIE=1 with the local interrupt
+ * masked to generate a remote-only interrupt (rather than LIE=0/RIE=1).
+ * See the DesignWare endpoint databook 5.40, "Hint" below "Figure 8-22
+ * Write Interrupt Generation".
+ */
+enum dw_edma_ch_irq_mode {
+	DW_EDMA_CH_IRQ_DEFAULT	= 0,
+	DW_EDMA_CH_IRQ_LOCAL,
+	DW_EDMA_CH_IRQ_REMOTE,
+};
+
+/**
+ * struct dw_edma_peripheral_config - dw-edma specific slave configuration
+ * @irq_mode: per-channel interrupt routing control.
+ *
+ * Pass this structure via dma_slave_config.peripheral_config and
+ * dma_slave_config.peripheral_size.
+ */
+struct dw_edma_peripheral_config {
+	enum dw_edma_ch_irq_mode irq_mode;
+};
+
 /**
  * struct dw_edma_chip - representation of DesignWare eDMA controller hardware
  * @dev:		 struct device of the eDMA controller
-- 
2.51.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 4/7] dmaengine: dw-edma: Poll completion when local IRQ handling is disabled
  2026-01-27  3:34 [PATCH v2 0/7] dmaengine: dw-edma, PCI: dwc: Enable remote use of integrated DesignWare eDMA Koichiro Den
                   ` (2 preceding siblings ...)
  2026-01-27  3:34 ` [PATCH v2 3/7] dmaengine: dw-edma: Add per-channel interrupt routing control Koichiro Den
@ 2026-01-27  3:34 ` Koichiro Den
  2026-01-27  3:34 ` [PATCH v2 5/7] dmaengine: dw-edma: Add notify-only channels support Koichiro Den
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 20+ messages in thread
From: Koichiro Den @ 2026-01-27  3:34 UTC (permalink / raw)
  To: vkoul, mani, Frank.Li, jingoohan1, lpieralisi, kwilczynski, robh,
	bhelgaas
  Cc: dmaengine, linux-pci, linux-kernel

Poll completion for channels where local done/abort IRQ handling is
disabled (e.g. remote ACK scenarios).

This is useful when transaction descriptor is prepared and submitted
locally, while irq_mode is configured so that the peer is supposed to
ack the interrupts. Without polling mechanism, locally submitted
transaction would never complete and would stuck.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
 drivers/dma/dw-edma/dw-edma-core.c | 104 ++++++++++++++++++++++++-----
 drivers/dma/dw-edma/dw-edma-core.h |   4 ++
 2 files changed, 91 insertions(+), 17 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index e006f1fa2ee5..910a4d516c3a 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -6,6 +6,7 @@
  * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
  */
 
+#include <linux/cleanup.h>
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/kernel.h>
@@ -312,24 +313,9 @@ static int dw_edma_device_terminate_all(struct dma_chan *dchan)
 		chan->request = EDMA_REQ_STOP;
 	}
 
-	return err;
-}
-
-static void dw_edma_device_issue_pending(struct dma_chan *dchan)
-{
-	struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
-	unsigned long flags;
-
-	if (!chan->configured)
-		return;
+	cancel_delayed_work_sync(&chan->poll_work);
 
-	spin_lock_irqsave(&chan->vc.lock, flags);
-	if (vchan_issue_pending(&chan->vc) && chan->request == EDMA_REQ_NONE &&
-	    chan->status == EDMA_ST_IDLE) {
-		chan->status = EDMA_ST_BUSY;
-		dw_edma_start_transfer(chan);
-	}
-	spin_unlock_irqrestore(&chan->vc.lock, flags);
+	return err;
 }
 
 static enum dma_status
@@ -712,6 +698,70 @@ static irqreturn_t dw_edma_interrupt_common(int irq, void *data)
 	return ret;
 }
 
+static void dw_edma_done_arm(struct dw_edma_chan *chan)
+{
+	if (!dw_edma_core_ch_ignore_irq(chan))
+		/* Local side handles IRQs so polling is not needed */
+		return;
+
+	queue_delayed_work(system_wq, &chan->poll_work, 1);
+}
+
+static void dw_edma_chan_poll_done(struct dma_chan *dchan)
+{
+	struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+	enum dma_status st;
+
+	if (!dw_edma_core_ch_ignore_irq(chan))
+		/* Local side handles IRQs so polling is not needed */
+		return;
+
+	guard(spinlock_irqsave)(&chan->poll_lock);
+
+	if (chan->status != EDMA_ST_BUSY)
+		return;
+
+	st = dw_edma_core_ch_status(chan);
+
+	switch (st) {
+	case DMA_COMPLETE:
+		dw_edma_done_interrupt(chan);
+		if (chan->status == EDMA_ST_BUSY)
+			dw_edma_done_arm(chan);
+		break;
+	case DMA_IN_PROGRESS:
+		dw_edma_done_arm(chan);
+		break;
+	case DMA_ERROR:
+		dw_edma_abort_interrupt(chan);
+		break;
+	default:
+		break;
+	}
+}
+
+static void dw_edma_device_issue_pending(struct dma_chan *dchan)
+{
+	struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+	unsigned long flags;
+
+	if (!chan->configured)
+		return;
+
+	dw_edma_chan_poll_done(dchan);
+
+	spin_lock_irqsave(&chan->vc.lock, flags);
+	if (vchan_issue_pending(&chan->vc) && chan->request == EDMA_REQ_NONE &&
+	    chan->status == EDMA_ST_IDLE) {
+		chan->status = EDMA_ST_BUSY;
+		dw_edma_start_transfer(chan);
+	}
+
+	dw_edma_done_arm(chan);
+
+	spin_unlock_irqrestore(&chan->vc.lock, flags);
+}
+
 static int dw_edma_alloc_chan_resources(struct dma_chan *dchan)
 {
 	struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
@@ -739,6 +789,19 @@ static void dw_edma_free_chan_resources(struct dma_chan *dchan)
 	}
 }
 
+static void dw_edma_poll_work(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct dw_edma_chan *chan =
+		container_of(dwork, struct dw_edma_chan, poll_work);
+	struct dma_chan *dchan = &chan->vc.chan;
+
+	if (!chan->configured)
+		return;
+
+	dw_edma_chan_poll_done(dchan);
+}
+
 static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)
 {
 	struct dw_edma_chip *chip = dw->chip;
@@ -772,6 +835,9 @@ static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)
 		chan->status = EDMA_ST_IDLE;
 		chan->irq_mode = DW_EDMA_CH_IRQ_DEFAULT;
 
+		spin_lock_init(&chan->poll_lock);
+		INIT_DELAYED_WORK(&chan->poll_work, dw_edma_poll_work);
+
 		if (chan->dir == EDMA_DIR_WRITE)
 			chan->ll_max = (chip->ll_region_wr[chan->id].sz / EDMA_LL_SZ);
 		else
@@ -1026,6 +1092,10 @@ int dw_edma_remove(struct dw_edma_chip *chip)
 	if (!dw)
 		return -ENODEV;
 
+	/* Poll work can re-arm itself. Disable and drain. */
+	list_for_each_entry(chan, &dw->dma.channels, vc.chan.device_node)
+		disable_delayed_work_sync(&chan->poll_work);
+
 	/* Disable eDMA */
 	dw_edma_core_off(dw);
 
diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
index 0608b9044a08..560a2d2fea86 100644
--- a/drivers/dma/dw-edma/dw-edma-core.h
+++ b/drivers/dma/dw-edma/dw-edma-core.h
@@ -11,6 +11,7 @@
 
 #include <linux/msi.h>
 #include <linux/dma/edma.h>
+#include <linux/workqueue.h>
 
 #include "../virt-dma.h"
 
@@ -83,6 +84,9 @@ struct dw_edma_chan {
 
 	enum dw_edma_ch_irq_mode	irq_mode;
 
+	struct delayed_work		poll_work;
+	spinlock_t			poll_lock;
+
 	enum dw_edma_request		request;
 	enum dw_edma_status		status;
 	u8				configured;
-- 
2.51.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 5/7] dmaengine: dw-edma: Add notify-only channels support
  2026-01-27  3:34 [PATCH v2 0/7] dmaengine: dw-edma, PCI: dwc: Enable remote use of integrated DesignWare eDMA Koichiro Den
                   ` (3 preceding siblings ...)
  2026-01-27  3:34 ` [PATCH v2 4/7] dmaengine: dw-edma: Poll completion when local IRQ handling is disabled Koichiro Den
@ 2026-01-27  3:34 ` Koichiro Den
  2026-01-27  3:34 ` [PATCH v2 6/7] PCI: dwc: Add helper to query integrated dw-edma register window Koichiro Den
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 20+ messages in thread
From: Koichiro Den @ 2026-01-27  3:34 UTC (permalink / raw)
  To: vkoul, mani, Frank.Li, jingoohan1, lpieralisi, kwilczynski, robh,
	bhelgaas
  Cc: dmaengine, linux-pci, linux-kernel

Remote eDMA users may want to prepare descriptors on the remote side while
the local side only needs completion notifications.

Provide a lightweight per-channel notification callback infrastructure.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
 drivers/dma/dw-edma/dw-edma-core.c | 41 ++++++++++++++++++++++++++++++
 drivers/dma/dw-edma/dw-edma-core.h |  4 +++
 include/linux/dma/edma.h           | 29 +++++++++++++++++++++
 3 files changed, 74 insertions(+)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 910a4d516c3a..3396849d0606 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -616,6 +616,13 @@ static void dw_edma_done_interrupt(struct dw_edma_chan *chan)
 	struct virt_dma_desc *vd;
 	unsigned long flags;
 
+	if (chan->notify_only) {
+		if (chan->notify_cb)
+			chan->notify_cb(&chan->vc.chan, chan->notify_cb_param);
+		/* no cookie on this side, just return */
+		return;
+	}
+
 	spin_lock_irqsave(&chan->vc.lock, flags);
 	vd = vchan_next_desc(&chan->vc);
 	if (vd) {
@@ -834,6 +841,9 @@ static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)
 		chan->request = EDMA_REQ_NONE;
 		chan->status = EDMA_ST_IDLE;
 		chan->irq_mode = DW_EDMA_CH_IRQ_DEFAULT;
+		chan->notify_cb = NULL;
+		chan->notify_cb_param = NULL;
+		chan->notify_only = false;
 
 		spin_lock_init(&chan->poll_lock);
 		INIT_DELAYED_WORK(&chan->poll_work, dw_edma_poll_work);
@@ -1115,6 +1125,37 @@ int dw_edma_remove(struct dw_edma_chip *chip)
 }
 EXPORT_SYMBOL_GPL(dw_edma_remove);
 
+int dw_edma_chan_register_notify(struct dma_chan *dchan,
+				 void (*cb)(struct dma_chan *chan, void *data),
+				 void *data)
+{
+	struct dw_edma_chan *chan;
+
+	if (!dchan || !dchan->device ||
+	    dchan->device->device_config != dw_edma_device_config)
+		return -ENODEV;
+
+	chan = dchan2dw_edma_chan(dchan);
+
+	/*
+	 * Reject the operation while the channel is active or has queued
+	 * descriptors.
+	 */
+	scoped_guard(spinlock_irqsave, &chan->vc.lock) {
+		if (chan->request != EDMA_REQ_NONE ||
+		    chan->status != EDMA_ST_IDLE ||
+		    !list_empty(&chan->vc.desc_submitted) ||
+		    !list_empty(&chan->vc.desc_issued))
+			return -EBUSY;
+	}
+
+	chan->notify_cb = cb;
+	chan->notify_cb_param = data;
+	chan->notify_only = !!cb;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(dw_edma_chan_register_notify);
+
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Synopsys DesignWare eDMA controller core driver");
 MODULE_AUTHOR("Gustavo Pimentel <gustavo.pimentel@synopsys.com>");
diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
index 560a2d2fea86..d5ee8330a6cb 100644
--- a/drivers/dma/dw-edma/dw-edma-core.h
+++ b/drivers/dma/dw-edma/dw-edma-core.h
@@ -84,6 +84,10 @@ struct dw_edma_chan {
 
 	enum dw_edma_ch_irq_mode	irq_mode;
 
+	void (*notify_cb)(struct dma_chan *chan, void *data);
+	void *notify_cb_param;
+	bool notify_only;
+
 	struct delayed_work		poll_work;
 	spinlock_t			poll_lock;
 
diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
index 16e9adc60eb8..35275576f273 100644
--- a/include/linux/dma/edma.h
+++ b/include/linux/dma/edma.h
@@ -133,6 +133,27 @@ struct dw_edma_chip {
 #if IS_REACHABLE(CONFIG_DW_EDMA)
 int dw_edma_probe(struct dw_edma_chip *chip);
 int dw_edma_remove(struct dw_edma_chip *chip);
+
+/**
+ * dw_edma_chan_register_notify - register completion notification callback
+ * @chan: DMA channel obtained from dma_request_channel()
+ * @cb:   callback invoked when a completion is detected on @chan (NULL to
+ *        unregister)
+ * @data: opaque pointer passed back to @cb
+ *
+ * This is a lightweight notification mechanism intended for channels whose
+ * descriptors are managed externally (e.g. remote eDMA). When enabled, the
+ * local dw-edma instance does not perform cookie accounting for completions,
+ * because the corresponding descriptor is not tracked locally.
+ *
+ * The callback may be invoked from atomic context and must not sleep.
+ *
+ * Return: 0 on success, -ENODEV if @chan is not a dw-edma channel,
+ *         -EBUSY if the channel is active or has queued descriptors.
+ */
+int dw_edma_chan_register_notify(struct dma_chan *chan,
+				 void (*cb)(struct dma_chan *chan, void *data),
+				 void *data);
 #else
 static inline int dw_edma_probe(struct dw_edma_chip *chip)
 {
@@ -143,6 +164,14 @@ static inline int dw_edma_remove(struct dw_edma_chip *chip)
 {
 	return 0;
 }
+
+static inline int dw_edma_chan_register_notify(struct dma_chan *chan,
+					       void (*cb)(struct dma_chan *chan,
+							  void *data),
+					       void *data)
+{
+	return -ENODEV;
+}
 #endif /* CONFIG_DW_EDMA */
 
 #endif /* _DW_EDMA_H */
-- 
2.51.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 6/7] PCI: dwc: Add helper to query integrated dw-edma register window
  2026-01-27  3:34 [PATCH v2 0/7] dmaengine: dw-edma, PCI: dwc: Enable remote use of integrated DesignWare eDMA Koichiro Den
                   ` (4 preceding siblings ...)
  2026-01-27  3:34 ` [PATCH v2 5/7] dmaengine: dw-edma: Add notify-only channels support Koichiro Den
@ 2026-01-27  3:34 ` Koichiro Den
  2026-01-27  3:34 ` [PATCH v2 7/7] PCI: dwc: Add helper to query integrated dw-edma linked-list region Koichiro Den
  2026-02-01  2:32 ` [PATCH v2 0/7] dmaengine: dw-edma, PCI: dwc: Enable remote use of integrated DesignWare eDMA Koichiro Den
  7 siblings, 0 replies; 20+ messages in thread
From: Koichiro Den @ 2026-01-27  3:34 UTC (permalink / raw)
  To: vkoul, mani, Frank.Li, jingoohan1, lpieralisi, kwilczynski, robh,
	bhelgaas
  Cc: dmaengine, linux-pci, linux-kernel

Some DesignWare PCIe endpoint controllers integrate a DesignWare eDMA
instance. Remote-eDMA providers (e.g. vNTB) need to expose the eDMA
register block to the host through a memory window so the host can
ioremap it and run dw_edma_probe() against the remote view.

Record the physical base and size of the eDMA register aperture and
export dwc_pcie_edma_get_reg_window() so higher-level code can query the
register window associated with a given PCI EPC device.

Keep the controller-side helper declarations in a dedicated header to
avoid pulling eDMA/dmaengine-specific interfaces into the generic
DesignWare PCIe header (include/linux/pcie-dwc.h).

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
 MAINTAINERS                                  |  2 +-
 drivers/pci/controller/dwc/pcie-designware.c | 29 +++++++++++++++
 drivers/pci/controller/dwc/pcie-designware.h |  2 +
 include/linux/pcie-dwc-edma.h                | 39 ++++++++++++++++++++
 4 files changed, 71 insertions(+), 1 deletion(-)
 create mode 100644 include/linux/pcie-dwc-edma.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 5b11839cba9d..fa0cb454744c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20066,7 +20066,7 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/pci/snps,dw-pcie-ep.yaml
 F:	Documentation/devicetree/bindings/pci/snps,dw-pcie.yaml
 F:	drivers/pci/controller/dwc/*designware*
-F:	include/linux/pcie-dwc.h
+F:	include/linux/pcie-dwc*.h
 
 PCI DRIVER FOR TI DRA7XX/J721E
 M:	Vignesh Raghavendra <vigneshr@ti.com>
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index 18331d9e85be..bbaeecce199a 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -18,6 +18,7 @@
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/pcie-dwc.h>
+#include <linux/pcie-dwc-edma.h>
 #include <linux/platform_device.h>
 #include <linux/sizes.h>
 #include <linux/types.h>
@@ -162,8 +163,12 @@ int dw_pcie_get_resources(struct dw_pcie *pci)
 			pci->edma.reg_base = devm_ioremap_resource(pci->dev, res);
 			if (IS_ERR(pci->edma.reg_base))
 				return PTR_ERR(pci->edma.reg_base);
+			pci->edma_reg_phys = res->start;
+			pci->edma_reg_size = resource_size(res);
 		} else if (pci->atu_size >= 2 * DEFAULT_DBI_DMA_OFFSET) {
 			pci->edma.reg_base = pci->atu_base + DEFAULT_DBI_DMA_OFFSET;
+			pci->edma_reg_phys = pci->atu_phys_addr + DEFAULT_DBI_DMA_OFFSET;
+			pci->edma_reg_size = pci->atu_size - DEFAULT_DBI_DMA_OFFSET;
 		}
 	}
 
@@ -1340,3 +1345,27 @@ resource_size_t dw_pcie_parent_bus_offset(struct dw_pcie *pci,
 
 	return cpu_phys_addr - reg_addr;
 }
+
+int dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
+				 resource_size_t *sz)
+{
+	struct dw_pcie_ep *ep;
+	struct dw_pcie *pci;
+
+	if (!epc || !phys || !sz)
+		return -EINVAL;
+
+	ep = epc_get_drvdata(epc);
+	if (!ep)
+		return -ENODEV;
+
+	pci = to_dw_pcie_from_ep(ep);
+	if (!pci->edma_reg_size)
+		return -ENODEV;
+
+	*phys = pci->edma_reg_phys;
+	*sz = pci->edma_reg_size;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(dwc_pcie_edma_get_reg_window);
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index c3301b3aedb7..cd38147443bf 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -534,6 +534,8 @@ struct dw_pcie {
 	int			max_link_speed;
 	u8			n_fts[2];
 	struct dw_edma_chip	edma;
+	phys_addr_t		edma_reg_phys;
+	resource_size_t		edma_reg_size;
 	bool			l1ss_support;	/* L1 PM Substates support */
 	struct clk_bulk_data	app_clks[DW_PCIE_NUM_APP_CLKS];
 	struct clk_bulk_data	core_clks[DW_PCIE_NUM_CORE_CLKS];
diff --git a/include/linux/pcie-dwc-edma.h b/include/linux/pcie-dwc-edma.h
new file mode 100644
index 000000000000..a5b0595603f4
--- /dev/null
+++ b/include/linux/pcie-dwc-edma.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * DesignWare PCIe controller helpers for integrated DesignWare eDMA.
+ */
+
+#ifndef LINUX_PCIE_DWC_EDMA_H
+#define LINUX_PCIE_DWC_EDMA_H
+
+#include <linux/errno.h>
+#include <linux/kconfig.h>
+#include <linux/pci-epc.h>
+#include <linux/types.h>
+
+#ifdef CONFIG_PCIE_DW
+/**
+ * dwc_pcie_edma_get_reg_window() - get integrated DW eDMA register window
+ * @epc:  EPC device associated with the integrated eDMA instance
+ * @phys: pointer to receive the CPU-physical base address
+ * @sz:   pointer to receive the size in bytes
+ *
+ * Some DesignWare PCIe endpoint controllers integrate a DesignWare eDMA
+ * instance. Higher-level code (e.g. BAR/window setup for remote use) may
+ * need the CPU-physical base and size of the eDMA register aperture.
+ *
+ * Return: 0 on success, -ENODEV if the EPC has no integrated eDMA register
+ *         window, or -EINVAL if @epc is %NULL.
+ */
+int dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
+				 resource_size_t *sz);
+#else
+static inline int
+dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
+			     resource_size_t *sz)
+{
+	return -ENODEV;
+}
+#endif /* CONFIG_PCIE_DW */
+
+#endif /* LINUX_PCIE_DWC_EDMA_H */
-- 
2.51.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 7/7] PCI: dwc: Add helper to query integrated dw-edma linked-list region
  2026-01-27  3:34 [PATCH v2 0/7] dmaengine: dw-edma, PCI: dwc: Enable remote use of integrated DesignWare eDMA Koichiro Den
                   ` (5 preceding siblings ...)
  2026-01-27  3:34 ` [PATCH v2 6/7] PCI: dwc: Add helper to query integrated dw-edma register window Koichiro Den
@ 2026-01-27  3:34 ` Koichiro Den
  2026-01-28 15:48   ` Frank Li
  2026-02-01  2:32 ` [PATCH v2 0/7] dmaengine: dw-edma, PCI: dwc: Enable remote use of integrated DesignWare eDMA Koichiro Den
  7 siblings, 1 reply; 20+ messages in thread
From: Koichiro Den @ 2026-01-27  3:34 UTC (permalink / raw)
  To: vkoul, mani, Frank.Li, jingoohan1, lpieralisi, kwilczynski, robh,
	bhelgaas
  Cc: dmaengine, linux-pci, linux-kernel

Some DesignWare PCIe endpoint controllers integrate a DesignWare eDMA
instance and allocate per-channel linked-list (LL) regions. Remote eDMA
providers may need to expose those LL regions to the host so it can
build descriptors against the remote view.

Export dwc_pcie_edma_get_ll_region() to allow higher-level code to query
the LL region (base/size) for a given EPC, transfer direction
(DMA_DEV_TO_MEM / DMA_MEM_TO_DEV) and hardware channel identifier. The
helper maps the request to the appropriate read/write LL region
depending on whether the integrated eDMA is the local or the remote
view.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
 drivers/pci/controller/dwc/pcie-designware.c | 45 ++++++++++++++++++++
 include/linux/pcie-dwc-edma.h                | 33 ++++++++++++++
 2 files changed, 78 insertions(+)

diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index bbaeecce199a..e8617873e832 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -1369,3 +1369,48 @@ int dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
 	return 0;
 }
 EXPORT_SYMBOL_GPL(dwc_pcie_edma_get_reg_window);
+
+int dwc_pcie_edma_get_ll_region(struct pci_epc *epc,
+				enum dma_transfer_direction dir, int hw_id,
+				struct dw_edma_region *region)
+{
+	struct dw_edma_chip *chip;
+	struct dw_pcie_ep *ep;
+	struct dw_pcie *pci;
+	bool dir_read;
+
+	if (!epc || !region)
+		return -EINVAL;
+	if (dir != DMA_DEV_TO_MEM && dir != DMA_MEM_TO_DEV)
+		return -EINVAL;
+	if (hw_id < 0)
+		return -EINVAL;
+
+	ep = epc_get_drvdata(epc);
+	if (!ep)
+		return -ENODEV;
+
+	pci = to_dw_pcie_from_ep(ep);
+	chip = &pci->edma;
+
+	if (!chip->dev)
+		return -ENODEV;
+
+	if (chip->flags & DW_EDMA_CHIP_LOCAL)
+		dir_read = (dir == DMA_DEV_TO_MEM);
+	else
+		dir_read = (dir == DMA_MEM_TO_DEV);
+
+	if (dir_read) {
+		if (hw_id >= chip->ll_rd_cnt)
+			return -EINVAL;
+		*region = chip->ll_region_rd[hw_id];
+	} else {
+		if (hw_id >= chip->ll_wr_cnt)
+			return -EINVAL;
+		*region = chip->ll_region_wr[hw_id];
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(dwc_pcie_edma_get_ll_region);
diff --git a/include/linux/pcie-dwc-edma.h b/include/linux/pcie-dwc-edma.h
index a5b0595603f4..36afb4df1998 100644
--- a/include/linux/pcie-dwc-edma.h
+++ b/include/linux/pcie-dwc-edma.h
@@ -6,6 +6,8 @@
 #ifndef LINUX_PCIE_DWC_EDMA_H
 #define LINUX_PCIE_DWC_EDMA_H
 
+#include <linux/dma/edma.h>
+#include <linux/dmaengine.h>
 #include <linux/errno.h>
 #include <linux/kconfig.h>
 #include <linux/pci-epc.h>
@@ -27,6 +29,29 @@
  */
 int dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
 				 resource_size_t *sz);
+
+/**
+ * dwc_pcie_edma_get_ll_region() - get linked-list (LL) region for a HW channel
+ * @epc:    EPC device associated with the integrated eDMA instance
+ * @dir:    DMA transfer direction (%DMA_DEV_TO_MEM or %DMA_MEM_TO_DEV)
+ * @hw_id:  hardware channel identifier (equals to dw_edma_chan.id)
+ * @region: pointer to a region descriptor to fill in
+ *
+ * Some integrated DesignWare eDMA instances allocate per-channel linked-list
+ * (LL) regions for descriptor storage. This helper returns the LL region
+ * corresponding to @dir and @hw_id.
+ *
+ * The mapping between @dir and the underlying eDMA read/write LL region
+ * depends on whether the integrated eDMA instance represents a local or a
+ * remote view.
+ *
+ * Return: 0 on success, -EINVAL on invalid arguments (including out-of-range
+ *         @hw_id), or -ENODEV if the integrated eDMA instance is not present
+ *         or not initialized.
+ */
+int dwc_pcie_edma_get_ll_region(struct pci_epc *epc,
+				enum dma_transfer_direction dir, int hw_id,
+				struct dw_edma_region *region);
 #else
 static inline int
 dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
@@ -34,6 +59,14 @@ dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
 {
 	return -ENODEV;
 }
+
+static inline int
+dwc_pcie_edma_get_ll_region(struct pci_epc *epc,
+			    enum dma_transfer_direction dir, int hw_id,
+			    struct dw_edma_region *region)
+{
+	return -ENODEV;
+}
 #endif /* CONFIG_PCIE_DW */
 
 #endif /* LINUX_PCIE_DWC_EDMA_H */
-- 
2.51.0


^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 7/7] PCI: dwc: Add helper to query integrated dw-edma linked-list region
  2026-01-27  3:34 ` [PATCH v2 7/7] PCI: dwc: Add helper to query integrated dw-edma linked-list region Koichiro Den
@ 2026-01-28 15:48   ` Frank Li
  2026-01-28 16:25     ` Koichiro Den
  0 siblings, 1 reply; 20+ messages in thread
From: Frank Li @ 2026-01-28 15:48 UTC (permalink / raw)
  To: Koichiro Den
  Cc: vkoul, mani, jingoohan1, lpieralisi, kwilczynski, robh, bhelgaas,
	dmaengine, linux-pci, linux-kernel

On Tue, Jan 27, 2026 at 12:34:20PM +0900, Koichiro Den wrote:
> Some DesignWare PCIe endpoint controllers integrate a DesignWare eDMA
> instance and allocate per-channel linked-list (LL) regions. Remote eDMA
> providers may need to expose those LL regions to the host so it can
> build descriptors against the remote view.
>
> Export dwc_pcie_edma_get_ll_region() to allow higher-level code to query
> the LL region (base/size) for a given EPC, transfer direction
> (DMA_DEV_TO_MEM / DMA_MEM_TO_DEV) and hardware channel identifier. The
> helper maps the request to the appropriate read/write LL region
> depending on whether the integrated eDMA is the local or the remote
> view.
>
> Signed-off-by: Koichiro Den <den@valinux.co.jp>
> ---
>  drivers/pci/controller/dwc/pcie-designware.c | 45 ++++++++++++++++++++
>  include/linux/pcie-dwc-edma.h                | 33 ++++++++++++++
>  2 files changed, 78 insertions(+)
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> index bbaeecce199a..e8617873e832 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.c
> +++ b/drivers/pci/controller/dwc/pcie-designware.c
> @@ -1369,3 +1369,48 @@ int dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
>  	return 0;
>  }
>  EXPORT_SYMBOL_GPL(dwc_pcie_edma_get_reg_window);
> +
> +int dwc_pcie_edma_get_ll_region(struct pci_epc *epc,
> +				enum dma_transfer_direction dir, int hw_id,
> +				struct dw_edma_region *region)

These APIs need an user, A simple method is that add one test case in
pci-epf-test.

Frank

> +{
> +	struct dw_edma_chip *chip;
> +	struct dw_pcie_ep *ep;
> +	struct dw_pcie *pci;
> +	bool dir_read;
> +
> +	if (!epc || !region)
> +		return -EINVAL;
> +	if (dir != DMA_DEV_TO_MEM && dir != DMA_MEM_TO_DEV)
> +		return -EINVAL;
> +	if (hw_id < 0)
> +		return -EINVAL;
> +
> +	ep = epc_get_drvdata(epc);
> +	if (!ep)
> +		return -ENODEV;
> +
> +	pci = to_dw_pcie_from_ep(ep);
> +	chip = &pci->edma;
> +
> +	if (!chip->dev)
> +		return -ENODEV;
> +
> +	if (chip->flags & DW_EDMA_CHIP_LOCAL)
> +		dir_read = (dir == DMA_DEV_TO_MEM);
> +	else
> +		dir_read = (dir == DMA_MEM_TO_DEV);
> +
> +	if (dir_read) {
> +		if (hw_id >= chip->ll_rd_cnt)
> +			return -EINVAL;
> +		*region = chip->ll_region_rd[hw_id];
> +	} else {
> +		if (hw_id >= chip->ll_wr_cnt)
> +			return -EINVAL;
> +		*region = chip->ll_region_wr[hw_id];
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(dwc_pcie_edma_get_ll_region);
> diff --git a/include/linux/pcie-dwc-edma.h b/include/linux/pcie-dwc-edma.h
> index a5b0595603f4..36afb4df1998 100644
> --- a/include/linux/pcie-dwc-edma.h
> +++ b/include/linux/pcie-dwc-edma.h
> @@ -6,6 +6,8 @@
>  #ifndef LINUX_PCIE_DWC_EDMA_H
>  #define LINUX_PCIE_DWC_EDMA_H
>
> +#include <linux/dma/edma.h>
> +#include <linux/dmaengine.h>
>  #include <linux/errno.h>
>  #include <linux/kconfig.h>
>  #include <linux/pci-epc.h>
> @@ -27,6 +29,29 @@
>   */
>  int dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
>  				 resource_size_t *sz);
> +
> +/**
> + * dwc_pcie_edma_get_ll_region() - get linked-list (LL) region for a HW channel
> + * @epc:    EPC device associated with the integrated eDMA instance
> + * @dir:    DMA transfer direction (%DMA_DEV_TO_MEM or %DMA_MEM_TO_DEV)
> + * @hw_id:  hardware channel identifier (equals to dw_edma_chan.id)
> + * @region: pointer to a region descriptor to fill in
> + *
> + * Some integrated DesignWare eDMA instances allocate per-channel linked-list
> + * (LL) regions for descriptor storage. This helper returns the LL region
> + * corresponding to @dir and @hw_id.
> + *
> + * The mapping between @dir and the underlying eDMA read/write LL region
> + * depends on whether the integrated eDMA instance represents a local or a
> + * remote view.
> + *
> + * Return: 0 on success, -EINVAL on invalid arguments (including out-of-range
> + *         @hw_id), or -ENODEV if the integrated eDMA instance is not present
> + *         or not initialized.
> + */
> +int dwc_pcie_edma_get_ll_region(struct pci_epc *epc,
> +				enum dma_transfer_direction dir, int hw_id,
> +				struct dw_edma_region *region);
>  #else
>  static inline int
>  dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
> @@ -34,6 +59,14 @@ dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
>  {
>  	return -ENODEV;
>  }
> +
> +static inline int
> +dwc_pcie_edma_get_ll_region(struct pci_epc *epc,
> +			    enum dma_transfer_direction dir, int hw_id,
> +			    struct dw_edma_region *region)
> +{
> +	return -ENODEV;
> +}
>  #endif /* CONFIG_PCIE_DW */
>
>  #endif /* LINUX_PCIE_DWC_EDMA_H */
> --
> 2.51.0
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 7/7] PCI: dwc: Add helper to query integrated dw-edma linked-list region
  2026-01-28 15:48   ` Frank Li
@ 2026-01-28 16:25     ` Koichiro Den
  2026-01-29  3:42       ` Frank Li
  0 siblings, 1 reply; 20+ messages in thread
From: Koichiro Den @ 2026-01-28 16:25 UTC (permalink / raw)
  To: Frank Li, mani
  Cc: vkoul, jingoohan1, lpieralisi, kwilczynski, robh, bhelgaas,
	dmaengine, linux-pci, linux-kernel

On Wed, Jan 28, 2026 at 10:48:04AM -0500, Frank Li wrote:
> On Tue, Jan 27, 2026 at 12:34:20PM +0900, Koichiro Den wrote:
> > Some DesignWare PCIe endpoint controllers integrate a DesignWare eDMA
> > instance and allocate per-channel linked-list (LL) regions. Remote eDMA
> > providers may need to expose those LL regions to the host so it can
> > build descriptors against the remote view.
> >
> > Export dwc_pcie_edma_get_ll_region() to allow higher-level code to query
> > the LL region (base/size) for a given EPC, transfer direction
> > (DMA_DEV_TO_MEM / DMA_MEM_TO_DEV) and hardware channel identifier. The
> > helper maps the request to the appropriate read/write LL region
> > depending on whether the integrated eDMA is the local or the remote
> > view.
> >
> > Signed-off-by: Koichiro Den <den@valinux.co.jp>
> > ---
> >  drivers/pci/controller/dwc/pcie-designware.c | 45 ++++++++++++++++++++
> >  include/linux/pcie-dwc-edma.h                | 33 ++++++++++++++
> >  2 files changed, 78 insertions(+)
> >
> > diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> > index bbaeecce199a..e8617873e832 100644
> > --- a/drivers/pci/controller/dwc/pcie-designware.c
> > +++ b/drivers/pci/controller/dwc/pcie-designware.c
> > @@ -1369,3 +1369,48 @@ int dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
> >  	return 0;
> >  }
> >  EXPORT_SYMBOL_GPL(dwc_pcie_edma_get_reg_window);
> > +
> > +int dwc_pcie_edma_get_ll_region(struct pci_epc *epc,
> > +				enum dma_transfer_direction dir, int hw_id,
> > +				struct dw_edma_region *region)
> 
> These APIs need an user, A simple method is that add one test case in
> pci-epf-test.

Thanks for the feedback.

I'm unsure whether adding DesignWare-specific coverage to pci-epf-test
would be acceptable. I'd appreciate your guidance on the preferred
approach.

One possible direction I had in mind is to keep pci-epf-test.c generic and
add an optional DesignWare-specific extension, selected via Kconfig, to
exercise these helpers. Likewise on the host side
(drivers/misc/pci_endpoint_test.c and kselftest pci_endpoint_test.c).

Koichiro

> 
> Frank
> 
> > +{
> > +	struct dw_edma_chip *chip;
> > +	struct dw_pcie_ep *ep;
> > +	struct dw_pcie *pci;
> > +	bool dir_read;
> > +
> > +	if (!epc || !region)
> > +		return -EINVAL;
> > +	if (dir != DMA_DEV_TO_MEM && dir != DMA_MEM_TO_DEV)
> > +		return -EINVAL;
> > +	if (hw_id < 0)
> > +		return -EINVAL;
> > +
> > +	ep = epc_get_drvdata(epc);
> > +	if (!ep)
> > +		return -ENODEV;
> > +
> > +	pci = to_dw_pcie_from_ep(ep);
> > +	chip = &pci->edma;
> > +
> > +	if (!chip->dev)
> > +		return -ENODEV;
> > +
> > +	if (chip->flags & DW_EDMA_CHIP_LOCAL)
> > +		dir_read = (dir == DMA_DEV_TO_MEM);
> > +	else
> > +		dir_read = (dir == DMA_MEM_TO_DEV);
> > +
> > +	if (dir_read) {
> > +		if (hw_id >= chip->ll_rd_cnt)
> > +			return -EINVAL;
> > +		*region = chip->ll_region_rd[hw_id];
> > +	} else {
> > +		if (hw_id >= chip->ll_wr_cnt)
> > +			return -EINVAL;
> > +		*region = chip->ll_region_wr[hw_id];
> > +	}
> > +
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(dwc_pcie_edma_get_ll_region);
> > diff --git a/include/linux/pcie-dwc-edma.h b/include/linux/pcie-dwc-edma.h
> > index a5b0595603f4..36afb4df1998 100644
> > --- a/include/linux/pcie-dwc-edma.h
> > +++ b/include/linux/pcie-dwc-edma.h
> > @@ -6,6 +6,8 @@
> >  #ifndef LINUX_PCIE_DWC_EDMA_H
> >  #define LINUX_PCIE_DWC_EDMA_H
> >
> > +#include <linux/dma/edma.h>
> > +#include <linux/dmaengine.h>
> >  #include <linux/errno.h>
> >  #include <linux/kconfig.h>
> >  #include <linux/pci-epc.h>
> > @@ -27,6 +29,29 @@
> >   */
> >  int dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
> >  				 resource_size_t *sz);
> > +
> > +/**
> > + * dwc_pcie_edma_get_ll_region() - get linked-list (LL) region for a HW channel
> > + * @epc:    EPC device associated with the integrated eDMA instance
> > + * @dir:    DMA transfer direction (%DMA_DEV_TO_MEM or %DMA_MEM_TO_DEV)
> > + * @hw_id:  hardware channel identifier (equals to dw_edma_chan.id)
> > + * @region: pointer to a region descriptor to fill in
> > + *
> > + * Some integrated DesignWare eDMA instances allocate per-channel linked-list
> > + * (LL) regions for descriptor storage. This helper returns the LL region
> > + * corresponding to @dir and @hw_id.
> > + *
> > + * The mapping between @dir and the underlying eDMA read/write LL region
> > + * depends on whether the integrated eDMA instance represents a local or a
> > + * remote view.
> > + *
> > + * Return: 0 on success, -EINVAL on invalid arguments (including out-of-range
> > + *         @hw_id), or -ENODEV if the integrated eDMA instance is not present
> > + *         or not initialized.
> > + */
> > +int dwc_pcie_edma_get_ll_region(struct pci_epc *epc,
> > +				enum dma_transfer_direction dir, int hw_id,
> > +				struct dw_edma_region *region);
> >  #else
> >  static inline int
> >  dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
> > @@ -34,6 +59,14 @@ dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
> >  {
> >  	return -ENODEV;
> >  }
> > +
> > +static inline int
> > +dwc_pcie_edma_get_ll_region(struct pci_epc *epc,
> > +			    enum dma_transfer_direction dir, int hw_id,
> > +			    struct dw_edma_region *region)
> > +{
> > +	return -ENODEV;
> > +}
> >  #endif /* CONFIG_PCIE_DW */
> >
> >  #endif /* LINUX_PCIE_DWC_EDMA_H */
> > --
> > 2.51.0
> >

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 7/7] PCI: dwc: Add helper to query integrated dw-edma linked-list region
  2026-01-28 16:25     ` Koichiro Den
@ 2026-01-29  3:42       ` Frank Li
  2026-01-30  7:16         ` Koichiro Den
  0 siblings, 1 reply; 20+ messages in thread
From: Frank Li @ 2026-01-29  3:42 UTC (permalink / raw)
  To: Koichiro Den
  Cc: mani, vkoul, jingoohan1, lpieralisi, kwilczynski, robh, bhelgaas,
	dmaengine, linux-pci, linux-kernel

On Thu, Jan 29, 2026 at 01:25:30AM +0900, Koichiro Den wrote:
> On Wed, Jan 28, 2026 at 10:48:04AM -0500, Frank Li wrote:
> > On Tue, Jan 27, 2026 at 12:34:20PM +0900, Koichiro Den wrote:
> > > Some DesignWare PCIe endpoint controllers integrate a DesignWare eDMA
> > > instance and allocate per-channel linked-list (LL) regions. Remote eDMA
> > > providers may need to expose those LL regions to the host so it can
> > > build descriptors against the remote view.
> > >
> > > Export dwc_pcie_edma_get_ll_region() to allow higher-level code to query
> > > the LL region (base/size) for a given EPC, transfer direction
> > > (DMA_DEV_TO_MEM / DMA_MEM_TO_DEV) and hardware channel identifier. The
> > > helper maps the request to the appropriate read/write LL region
> > > depending on whether the integrated eDMA is the local or the remote
> > > view.
> > >
> > > Signed-off-by: Koichiro Den <den@valinux.co.jp>
> > > ---
> > >  drivers/pci/controller/dwc/pcie-designware.c | 45 ++++++++++++++++++++
> > >  include/linux/pcie-dwc-edma.h                | 33 ++++++++++++++
> > >  2 files changed, 78 insertions(+)
> > >
> > > diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> > > index bbaeecce199a..e8617873e832 100644
> > > --- a/drivers/pci/controller/dwc/pcie-designware.c
> > > +++ b/drivers/pci/controller/dwc/pcie-designware.c
> > > @@ -1369,3 +1369,48 @@ int dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
> > >  	return 0;
> > >  }
> > >  EXPORT_SYMBOL_GPL(dwc_pcie_edma_get_reg_window);
> > > +
> > > +int dwc_pcie_edma_get_ll_region(struct pci_epc *epc,
> > > +				enum dma_transfer_direction dir, int hw_id,
> > > +				struct dw_edma_region *region)
> >
> > These APIs need an user, A simple method is that add one test case in
> > pci-epf-test.
>
> Thanks for the feedback.
>
> I'm unsure whether adding DesignWare-specific coverage to pci-epf-test
> would be acceptable. I'd appreciate your guidance on the preferred
> approach.
>
> One possible direction I had in mind is to keep pci-epf-test.c generic and

Add a EPC/EPF API, so dynatmic check if support DMA region or other feature.

Frank

> add an optional DesignWare-specific extension, selected via Kconfig, to
> exercise these helpers. Likewise on the host side
> (drivers/misc/pci_endpoint_test.c and kselftest pci_endpoint_test.c).
>
> Koichiro
>
> >
> > Frank
> >
> > > +{
> > > +	struct dw_edma_chip *chip;
> > > +	struct dw_pcie_ep *ep;
> > > +	struct dw_pcie *pci;
> > > +	bool dir_read;
> > > +
> > > +	if (!epc || !region)
> > > +		return -EINVAL;
> > > +	if (dir != DMA_DEV_TO_MEM && dir != DMA_MEM_TO_DEV)
> > > +		return -EINVAL;
> > > +	if (hw_id < 0)
> > > +		return -EINVAL;
> > > +
> > > +	ep = epc_get_drvdata(epc);
> > > +	if (!ep)
> > > +		return -ENODEV;
> > > +
> > > +	pci = to_dw_pcie_from_ep(ep);
> > > +	chip = &pci->edma;
> > > +
> > > +	if (!chip->dev)
> > > +		return -ENODEV;
> > > +
> > > +	if (chip->flags & DW_EDMA_CHIP_LOCAL)
> > > +		dir_read = (dir == DMA_DEV_TO_MEM);
> > > +	else
> > > +		dir_read = (dir == DMA_MEM_TO_DEV);
> > > +
> > > +	if (dir_read) {
> > > +		if (hw_id >= chip->ll_rd_cnt)
> > > +			return -EINVAL;
> > > +		*region = chip->ll_region_rd[hw_id];
> > > +	} else {
> > > +		if (hw_id >= chip->ll_wr_cnt)
> > > +			return -EINVAL;
> > > +		*region = chip->ll_region_wr[hw_id];
> > > +	}
> > > +
> > > +	return 0;
> > > +}
> > > +EXPORT_SYMBOL_GPL(dwc_pcie_edma_get_ll_region);
> > > diff --git a/include/linux/pcie-dwc-edma.h b/include/linux/pcie-dwc-edma.h
> > > index a5b0595603f4..36afb4df1998 100644
> > > --- a/include/linux/pcie-dwc-edma.h
> > > +++ b/include/linux/pcie-dwc-edma.h
> > > @@ -6,6 +6,8 @@
> > >  #ifndef LINUX_PCIE_DWC_EDMA_H
> > >  #define LINUX_PCIE_DWC_EDMA_H
> > >
> > > +#include <linux/dma/edma.h>
> > > +#include <linux/dmaengine.h>
> > >  #include <linux/errno.h>
> > >  #include <linux/kconfig.h>
> > >  #include <linux/pci-epc.h>
> > > @@ -27,6 +29,29 @@
> > >   */
> > >  int dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
> > >  				 resource_size_t *sz);
> > > +
> > > +/**
> > > + * dwc_pcie_edma_get_ll_region() - get linked-list (LL) region for a HW channel
> > > + * @epc:    EPC device associated with the integrated eDMA instance
> > > + * @dir:    DMA transfer direction (%DMA_DEV_TO_MEM or %DMA_MEM_TO_DEV)
> > > + * @hw_id:  hardware channel identifier (equals to dw_edma_chan.id)
> > > + * @region: pointer to a region descriptor to fill in
> > > + *
> > > + * Some integrated DesignWare eDMA instances allocate per-channel linked-list
> > > + * (LL) regions for descriptor storage. This helper returns the LL region
> > > + * corresponding to @dir and @hw_id.
> > > + *
> > > + * The mapping between @dir and the underlying eDMA read/write LL region
> > > + * depends on whether the integrated eDMA instance represents a local or a
> > > + * remote view.
> > > + *
> > > + * Return: 0 on success, -EINVAL on invalid arguments (including out-of-range
> > > + *         @hw_id), or -ENODEV if the integrated eDMA instance is not present
> > > + *         or not initialized.
> > > + */
> > > +int dwc_pcie_edma_get_ll_region(struct pci_epc *epc,
> > > +				enum dma_transfer_direction dir, int hw_id,
> > > +				struct dw_edma_region *region);
> > >  #else
> > >  static inline int
> > >  dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
> > > @@ -34,6 +59,14 @@ dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
> > >  {
> > >  	return -ENODEV;
> > >  }
> > > +
> > > +static inline int
> > > +dwc_pcie_edma_get_ll_region(struct pci_epc *epc,
> > > +			    enum dma_transfer_direction dir, int hw_id,
> > > +			    struct dw_edma_region *region)
> > > +{
> > > +	return -ENODEV;
> > > +}
> > >  #endif /* CONFIG_PCIE_DW */
> > >
> > >  #endif /* LINUX_PCIE_DWC_EDMA_H */
> > > --
> > > 2.51.0
> > >

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 7/7] PCI: dwc: Add helper to query integrated dw-edma linked-list region
  2026-01-29  3:42       ` Frank Li
@ 2026-01-30  7:16         ` Koichiro Den
  2026-01-30 15:07           ` Frank Li
  0 siblings, 1 reply; 20+ messages in thread
From: Koichiro Den @ 2026-01-30  7:16 UTC (permalink / raw)
  To: Frank Li
  Cc: mani, vkoul, jingoohan1, lpieralisi, kwilczynski, robh, bhelgaas,
	dmaengine, linux-pci, linux-kernel

On Wed, Jan 28, 2026 at 10:42:29PM -0500, Frank Li wrote:
> On Thu, Jan 29, 2026 at 01:25:30AM +0900, Koichiro Den wrote:
> > On Wed, Jan 28, 2026 at 10:48:04AM -0500, Frank Li wrote:
> > > On Tue, Jan 27, 2026 at 12:34:20PM +0900, Koichiro Den wrote:
> > > > Some DesignWare PCIe endpoint controllers integrate a DesignWare eDMA
> > > > instance and allocate per-channel linked-list (LL) regions. Remote eDMA
> > > > providers may need to expose those LL regions to the host so it can
> > > > build descriptors against the remote view.
> > > >
> > > > Export dwc_pcie_edma_get_ll_region() to allow higher-level code to query
> > > > the LL region (base/size) for a given EPC, transfer direction
> > > > (DMA_DEV_TO_MEM / DMA_MEM_TO_DEV) and hardware channel identifier. The
> > > > helper maps the request to the appropriate read/write LL region
> > > > depending on whether the integrated eDMA is the local or the remote
> > > > view.
> > > >
> > > > Signed-off-by: Koichiro Den <den@valinux.co.jp>
> > > > ---
> > > >  drivers/pci/controller/dwc/pcie-designware.c | 45 ++++++++++++++++++++
> > > >  include/linux/pcie-dwc-edma.h                | 33 ++++++++++++++
> > > >  2 files changed, 78 insertions(+)
> > > >
> > > > diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> > > > index bbaeecce199a..e8617873e832 100644
> > > > --- a/drivers/pci/controller/dwc/pcie-designware.c
> > > > +++ b/drivers/pci/controller/dwc/pcie-designware.c
> > > > @@ -1369,3 +1369,48 @@ int dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
> > > >  	return 0;
> > > >  }
> > > >  EXPORT_SYMBOL_GPL(dwc_pcie_edma_get_reg_window);
> > > > +
> > > > +int dwc_pcie_edma_get_ll_region(struct pci_epc *epc,
> > > > +				enum dma_transfer_direction dir, int hw_id,
> > > > +				struct dw_edma_region *region)
> > >
> > > These APIs need an user, A simple method is that add one test case in
> > > pci-epf-test.
> >
> > Thanks for the feedback.
> >
> > I'm unsure whether adding DesignWare-specific coverage to pci-epf-test
> > would be acceptable. I'd appreciate your guidance on the preferred
> > approach.
> >
> > One possible direction I had in mind is to keep pci-epf-test.c generic and
> 
> Add a EPC/EPF API, so dynatmic check if support DMA region or other feature.

Thank you for the comment.

Ok, I have drafted an API ([1] below).

One thing I'm unsure about is how far the pci-epf-test validation should
go. Since the API (pci_epc_get_remote_resources() in [1]) is generic and
only returns a list of (type, phys_addr, size, and type-specific fields), a
fully end-to-end validation (i.e. "are these resources actually usable from
the host?") would require controller-specific (DW-eDMA-specific) knowledge
and also depends on how those resources are exposed (e.g. for a eDMA LL
region, it may be sufficient to inform the host of EP-local address, while
the eDMA register block would need to be fully exposed via BAR mapping).

Do you think a "smoke test" would be sufficient for now (e.g. testing
whether the new API returns a sane / well-formed list of resources), or are
you expecting the test to actually program the DMA eingine from the host?
Personally, I think the former would suffice, since the latter would be
very close to re-implementing the real user (e.g. ntb_dw_edma [2]) itself.

[1]:

diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index c021c7af175f..4cb5e634daba 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -61,6 +61,35 @@ struct pci_epc_map {
        void __iomem    *virt_addr;
 };

+/**
+ * enum pci_epc_remote_resource_type - remote resource type identifiers
+ */
+enum pci_epc_remote_resource_type {
+       PCI_EPC_RR_DMA_CTRL_MMIO,
+       PCI_EPC_RR_DMA_CHAN_DESC,
+};
+
+/**
+ * struct pci_epc_remote_resource - a physical resource that can be exposed
+ * @type:      resource type, see enum pci_epc_remote_resource_type
+ * @phys_addr: physical base address of the resource
+ * @size:      size of the resource in bytes
+ * @u:         type-specific metadata
+ */
+struct pci_epc_remote_resource {
+       enum pci_epc_remote_resource_type type;
+       phys_addr_t phys_addr;
+       size_t size;
+
+       union {
+               /* PCI_EPC_RR_DMA_CHAN_DESC */
+               struct {
+                       u16 hw_chan_id;
+                       bool ep2rc;
+               } dma_chan_desc;
+       } u;
+};
+
 /**
  * struct pci_epc_ops - set of function pointers for performing EPC operations
  * @write_header: ops to populate configuration space header
@@ -84,6 +113,8 @@ struct pci_epc_map {
  * @start: ops to start the PCI link
  * @stop: ops to stop the PCI link
  * @get_features: ops to get the features supported by the EPC
+ * @get_remote_resources: ops to retrieve controller-owned resources that can be
+ *                       exposed to the remote host (optional)
  * @owner: the module owner containing the ops
  */
 struct pci_epc_ops {
@@ -115,6 +146,9 @@ struct pci_epc_ops {
        void    (*stop)(struct pci_epc *epc);
        const struct pci_epc_features* (*get_features)(struct pci_epc *epc,
                                                       u8 func_no, u8 vfunc_no);
+       int     (*get_remote_resources)(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
+                                       struct pci_epc_remote_resource *resources,
+                                       int num_resources);
        struct module *owner;
 };

@@ -309,6 +343,9 @@ int pci_epc_start(struct pci_epc *epc);
 void pci_epc_stop(struct pci_epc *epc);
 const struct pci_epc_features *pci_epc_get_features(struct pci_epc *epc,
                                                    u8 func_no, u8 vfunc_no);
+int pci_epc_get_remote_resources(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
+                                struct pci_epc_remote_resource *resources,
+                                int num_resources);
 enum pci_barno
 pci_epc_get_first_free_bar(const struct pci_epc_features *epc_features);
 enum pci_barno pci_epc_get_next_free_bar(const struct pci_epc_features

---8<---

Notes:
* The naming ("pci_epc_get_remote_resources") is still TBD, but the intent
  is to return everything needed to support remote use of an EPC-integraed
  DMA engine.
* With this API, [PATCH v2 1/7] and [PATCH v2 2/7] are no longer needed,
  since API caller does not need to know the low-level DMA channel id
  (hw_id).

[2] https://lore.kernel.org/all/20260118135440.1958279-26-den@valinux.co.jp/

Thanks for the review,
Koichiro

> 
> Frank
> 
> > add an optional DesignWare-specific extension, selected via Kconfig, to
> > exercise these helpers. Likewise on the host side
> > (drivers/misc/pci_endpoint_test.c and kselftest pci_endpoint_test.c).
> >
> > Koichiro
> >
> > >
> > > Frank
> > >
> > > > +{
> > > > +	struct dw_edma_chip *chip;
> > > > +	struct dw_pcie_ep *ep;
> > > > +	struct dw_pcie *pci;
> > > > +	bool dir_read;
> > > > +
> > > > +	if (!epc || !region)
> > > > +		return -EINVAL;
> > > > +	if (dir != DMA_DEV_TO_MEM && dir != DMA_MEM_TO_DEV)
> > > > +		return -EINVAL;
> > > > +	if (hw_id < 0)
> > > > +		return -EINVAL;
> > > > +
> > > > +	ep = epc_get_drvdata(epc);
> > > > +	if (!ep)
> > > > +		return -ENODEV;
> > > > +
> > > > +	pci = to_dw_pcie_from_ep(ep);
> > > > +	chip = &pci->edma;
> > > > +
> > > > +	if (!chip->dev)
> > > > +		return -ENODEV;
> > > > +
> > > > +	if (chip->flags & DW_EDMA_CHIP_LOCAL)
> > > > +		dir_read = (dir == DMA_DEV_TO_MEM);
> > > > +	else
> > > > +		dir_read = (dir == DMA_MEM_TO_DEV);
> > > > +
> > > > +	if (dir_read) {
> > > > +		if (hw_id >= chip->ll_rd_cnt)
> > > > +			return -EINVAL;
> > > > +		*region = chip->ll_region_rd[hw_id];
> > > > +	} else {
> > > > +		if (hw_id >= chip->ll_wr_cnt)
> > > > +			return -EINVAL;
> > > > +		*region = chip->ll_region_wr[hw_id];
> > > > +	}
> > > > +
> > > > +	return 0;
> > > > +}
> > > > +EXPORT_SYMBOL_GPL(dwc_pcie_edma_get_ll_region);
> > > > diff --git a/include/linux/pcie-dwc-edma.h b/include/linux/pcie-dwc-edma.h
> > > > index a5b0595603f4..36afb4df1998 100644
> > > > --- a/include/linux/pcie-dwc-edma.h
> > > > +++ b/include/linux/pcie-dwc-edma.h
> > > > @@ -6,6 +6,8 @@
> > > >  #ifndef LINUX_PCIE_DWC_EDMA_H
> > > >  #define LINUX_PCIE_DWC_EDMA_H
> > > >
> > > > +#include <linux/dma/edma.h>
> > > > +#include <linux/dmaengine.h>
> > > >  #include <linux/errno.h>
> > > >  #include <linux/kconfig.h>
> > > >  #include <linux/pci-epc.h>
> > > > @@ -27,6 +29,29 @@
> > > >   */
> > > >  int dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
> > > >  				 resource_size_t *sz);
> > > > +
> > > > +/**
> > > > + * dwc_pcie_edma_get_ll_region() - get linked-list (LL) region for a HW channel
> > > > + * @epc:    EPC device associated with the integrated eDMA instance
> > > > + * @dir:    DMA transfer direction (%DMA_DEV_TO_MEM or %DMA_MEM_TO_DEV)
> > > > + * @hw_id:  hardware channel identifier (equals to dw_edma_chan.id)
> > > > + * @region: pointer to a region descriptor to fill in
> > > > + *
> > > > + * Some integrated DesignWare eDMA instances allocate per-channel linked-list
> > > > + * (LL) regions for descriptor storage. This helper returns the LL region
> > > > + * corresponding to @dir and @hw_id.
> > > > + *
> > > > + * The mapping between @dir and the underlying eDMA read/write LL region
> > > > + * depends on whether the integrated eDMA instance represents a local or a
> > > > + * remote view.
> > > > + *
> > > > + * Return: 0 on success, -EINVAL on invalid arguments (including out-of-range
> > > > + *         @hw_id), or -ENODEV if the integrated eDMA instance is not present
> > > > + *         or not initialized.
> > > > + */
> > > > +int dwc_pcie_edma_get_ll_region(struct pci_epc *epc,
> > > > +				enum dma_transfer_direction dir, int hw_id,
> > > > +				struct dw_edma_region *region);
> > > >  #else
> > > >  static inline int
> > > >  dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
> > > > @@ -34,6 +59,14 @@ dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
> > > >  {
> > > >  	return -ENODEV;
> > > >  }
> > > > +
> > > > +static inline int
> > > > +dwc_pcie_edma_get_ll_region(struct pci_epc *epc,
> > > > +			    enum dma_transfer_direction dir, int hw_id,
> > > > +			    struct dw_edma_region *region)
> > > > +{
> > > > +	return -ENODEV;
> > > > +}
> > > >  #endif /* CONFIG_PCIE_DW */
> > > >
> > > >  #endif /* LINUX_PCIE_DWC_EDMA_H */
> > > > --
> > > > 2.51.0
> > > >

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 7/7] PCI: dwc: Add helper to query integrated dw-edma linked-list region
  2026-01-30  7:16         ` Koichiro Den
@ 2026-01-30 15:07           ` Frank Li
  2026-01-30 17:27             ` Koichiro Den
  0 siblings, 1 reply; 20+ messages in thread
From: Frank Li @ 2026-01-30 15:07 UTC (permalink / raw)
  To: Koichiro Den
  Cc: mani, vkoul, jingoohan1, lpieralisi, kwilczynski, robh, bhelgaas,
	dmaengine, linux-pci, linux-kernel

On Fri, Jan 30, 2026 at 04:16:11PM +0900, Koichiro Den wrote:
> On Wed, Jan 28, 2026 at 10:42:29PM -0500, Frank Li wrote:
> > On Thu, Jan 29, 2026 at 01:25:30AM +0900, Koichiro Den wrote:
> > > On Wed, Jan 28, 2026 at 10:48:04AM -0500, Frank Li wrote:
> > > > On Tue, Jan 27, 2026 at 12:34:20PM +0900, Koichiro Den wrote:
> > > > > Some DesignWare PCIe endpoint controllers integrate a DesignWare eDMA
> > > > > instance and allocate per-channel linked-list (LL) regions. Remote eDMA
> > > > > providers may need to expose those LL regions to the host so it can
> > > > > build descriptors against the remote view.
> > > > >
> > > > > Export dwc_pcie_edma_get_ll_region() to allow higher-level code to query
> > > > > the LL region (base/size) for a given EPC, transfer direction
> > > > > (DMA_DEV_TO_MEM / DMA_MEM_TO_DEV) and hardware channel identifier. The
> > > > > helper maps the request to the appropriate read/write LL region
> > > > > depending on whether the integrated eDMA is the local or the remote
> > > > > view.
> > > > >
> > > > > Signed-off-by: Koichiro Den <den@valinux.co.jp>
> > > > > ---
> > > > >  drivers/pci/controller/dwc/pcie-designware.c | 45 ++++++++++++++++++++
> > > > >  include/linux/pcie-dwc-edma.h                | 33 ++++++++++++++
> > > > >  2 files changed, 78 insertions(+)
> > > > >
> > > > > diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> > > > > index bbaeecce199a..e8617873e832 100644
> > > > > --- a/drivers/pci/controller/dwc/pcie-designware.c
> > > > > +++ b/drivers/pci/controller/dwc/pcie-designware.c
> > > > > @@ -1369,3 +1369,48 @@ int dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
> > > > >  	return 0;
> > > > >  }
> > > > >  EXPORT_SYMBOL_GPL(dwc_pcie_edma_get_reg_window);
> > > > > +
> > > > > +int dwc_pcie_edma_get_ll_region(struct pci_epc *epc,
> > > > > +				enum dma_transfer_direction dir, int hw_id,
> > > > > +				struct dw_edma_region *region)
> > > >
> > > > These APIs need an user, A simple method is that add one test case in
> > > > pci-epf-test.
> > >
> > > Thanks for the feedback.
> > >
> > > I'm unsure whether adding DesignWare-specific coverage to pci-epf-test
> > > would be acceptable. I'd appreciate your guidance on the preferred
> > > approach.
> > >
> > > One possible direction I had in mind is to keep pci-epf-test.c generic and
> >
> > Add a EPC/EPF API, so dynatmic check if support DMA region or other feature.
>
> Thank you for the comment.
>
> Ok, I have drafted an API ([1] below).
>
> One thing I'm unsure about is how far the pci-epf-test validation should
> go. Since the API (pci_epc_get_remote_resources() in [1]) is generic and
> only returns a list of (type, phys_addr, size, and type-specific fields), a
> fully end-to-end validation (i.e. "are these resources actually usable from
> the host?") would require controller-specific (DW-eDMA-specific) knowledge
> and also depends on how those resources are exposed (e.g. for a eDMA LL
> region, it may be sufficient to inform the host of EP-local address, while
> the eDMA register block would need to be fully exposed via BAR mapping).
>
> Do you think a "smoke test" would be sufficient for now (e.g. testing
> whether the new API returns a sane / well-formed list of resources),
> or are
> you expecting the test to actually program the DMA eingine from the host?
> Personally, I think the former would suffice, since the latter would be
> very close to re-implementing the real user (e.g. ntb_dw_edma [2]) itself.

Smoke test should be enough now.

Frank
>
> [1]:
>
> diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
> index c021c7af175f..4cb5e634daba 100644
> --- a/include/linux/pci-epc.h
> +++ b/include/linux/pci-epc.h
> @@ -61,6 +61,35 @@ struct pci_epc_map {
>         void __iomem    *virt_addr;
>  };
>
> +/**
> + * enum pci_epc_remote_resource_type - remote resource type identifiers
> + */
> +enum pci_epc_remote_resource_type {
> +       PCI_EPC_RR_DMA_CTRL_MMIO,
> +       PCI_EPC_RR_DMA_CHAN_DESC,
> +};
> +
> +/**
> + * struct pci_epc_remote_resource - a physical resource that can be exposed
> + * @type:      resource type, see enum pci_epc_remote_resource_type
> + * @phys_addr: physical base address of the resource
> + * @size:      size of the resource in bytes
> + * @u:         type-specific metadata
> + */
> +struct pci_epc_remote_resource {
> +       enum pci_epc_remote_resource_type type;
> +       phys_addr_t phys_addr;
> +       size_t size;
> +
> +       union {
> +               /* PCI_EPC_RR_DMA_CHAN_DESC */
> +               struct {
> +                       u16 hw_chan_id;
> +                       bool ep2rc;
> +               } dma_chan_desc;
> +       } u;
> +};
> +
>  /**
>   * struct pci_epc_ops - set of function pointers for performing EPC operations
>   * @write_header: ops to populate configuration space header
> @@ -84,6 +113,8 @@ struct pci_epc_map {
>   * @start: ops to start the PCI link
>   * @stop: ops to stop the PCI link
>   * @get_features: ops to get the features supported by the EPC
> + * @get_remote_resources: ops to retrieve controller-owned resources that can be
> + *                       exposed to the remote host (optional)
>   * @owner: the module owner containing the ops
>   */
>  struct pci_epc_ops {
> @@ -115,6 +146,9 @@ struct pci_epc_ops {
>         void    (*stop)(struct pci_epc *epc);
>         const struct pci_epc_features* (*get_features)(struct pci_epc *epc,
>                                                        u8 func_no, u8 vfunc_no);
> +       int     (*get_remote_resources)(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
> +                                       struct pci_epc_remote_resource *resources,
> +                                       int num_resources);
>         struct module *owner;
>  };
>
> @@ -309,6 +343,9 @@ int pci_epc_start(struct pci_epc *epc);
>  void pci_epc_stop(struct pci_epc *epc);
>  const struct pci_epc_features *pci_epc_get_features(struct pci_epc *epc,
>                                                     u8 func_no, u8 vfunc_no);
> +int pci_epc_get_remote_resources(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
> +                                struct pci_epc_remote_resource *resources,
> +                                int num_resources);
>  enum pci_barno
>  pci_epc_get_first_free_bar(const struct pci_epc_features *epc_features);
>  enum pci_barno pci_epc_get_next_free_bar(const struct pci_epc_features
>
> ---8<---
>
> Notes:
> * The naming ("pci_epc_get_remote_resources") is still TBD, but the intent
>   is to return everything needed to support remote use of an EPC-integraed
>   DMA engine.
> * With this API, [PATCH v2 1/7] and [PATCH v2 2/7] are no longer needed,
>   since API caller does not need to know the low-level DMA channel id
>   (hw_id).
>
> [2] https://lore.kernel.org/all/20260118135440.1958279-26-den@valinux.co.jp/
>
> Thanks for the review,
> Koichiro
>
> >
> > Frank
> >
> > > add an optional DesignWare-specific extension, selected via Kconfig, to
> > > exercise these helpers. Likewise on the host side
> > > (drivers/misc/pci_endpoint_test.c and kselftest pci_endpoint_test.c).
> > >
> > > Koichiro
> > >
> > > >
> > > > Frank
> > > >
> > > > > +{
> > > > > +	struct dw_edma_chip *chip;
> > > > > +	struct dw_pcie_ep *ep;
> > > > > +	struct dw_pcie *pci;
> > > > > +	bool dir_read;
> > > > > +
> > > > > +	if (!epc || !region)
> > > > > +		return -EINVAL;
> > > > > +	if (dir != DMA_DEV_TO_MEM && dir != DMA_MEM_TO_DEV)
> > > > > +		return -EINVAL;
> > > > > +	if (hw_id < 0)
> > > > > +		return -EINVAL;
> > > > > +
> > > > > +	ep = epc_get_drvdata(epc);
> > > > > +	if (!ep)
> > > > > +		return -ENODEV;
> > > > > +
> > > > > +	pci = to_dw_pcie_from_ep(ep);
> > > > > +	chip = &pci->edma;
> > > > > +
> > > > > +	if (!chip->dev)
> > > > > +		return -ENODEV;
> > > > > +
> > > > > +	if (chip->flags & DW_EDMA_CHIP_LOCAL)
> > > > > +		dir_read = (dir == DMA_DEV_TO_MEM);
> > > > > +	else
> > > > > +		dir_read = (dir == DMA_MEM_TO_DEV);
> > > > > +
> > > > > +	if (dir_read) {
> > > > > +		if (hw_id >= chip->ll_rd_cnt)
> > > > > +			return -EINVAL;
> > > > > +		*region = chip->ll_region_rd[hw_id];
> > > > > +	} else {
> > > > > +		if (hw_id >= chip->ll_wr_cnt)
> > > > > +			return -EINVAL;
> > > > > +		*region = chip->ll_region_wr[hw_id];
> > > > > +	}
> > > > > +
> > > > > +	return 0;
> > > > > +}
> > > > > +EXPORT_SYMBOL_GPL(dwc_pcie_edma_get_ll_region);
> > > > > diff --git a/include/linux/pcie-dwc-edma.h b/include/linux/pcie-dwc-edma.h
> > > > > index a5b0595603f4..36afb4df1998 100644
> > > > > --- a/include/linux/pcie-dwc-edma.h
> > > > > +++ b/include/linux/pcie-dwc-edma.h
> > > > > @@ -6,6 +6,8 @@
> > > > >  #ifndef LINUX_PCIE_DWC_EDMA_H
> > > > >  #define LINUX_PCIE_DWC_EDMA_H
> > > > >
> > > > > +#include <linux/dma/edma.h>
> > > > > +#include <linux/dmaengine.h>
> > > > >  #include <linux/errno.h>
> > > > >  #include <linux/kconfig.h>
> > > > >  #include <linux/pci-epc.h>
> > > > > @@ -27,6 +29,29 @@
> > > > >   */
> > > > >  int dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
> > > > >  				 resource_size_t *sz);
> > > > > +
> > > > > +/**
> > > > > + * dwc_pcie_edma_get_ll_region() - get linked-list (LL) region for a HW channel
> > > > > + * @epc:    EPC device associated with the integrated eDMA instance
> > > > > + * @dir:    DMA transfer direction (%DMA_DEV_TO_MEM or %DMA_MEM_TO_DEV)
> > > > > + * @hw_id:  hardware channel identifier (equals to dw_edma_chan.id)
> > > > > + * @region: pointer to a region descriptor to fill in
> > > > > + *
> > > > > + * Some integrated DesignWare eDMA instances allocate per-channel linked-list
> > > > > + * (LL) regions for descriptor storage. This helper returns the LL region
> > > > > + * corresponding to @dir and @hw_id.
> > > > > + *
> > > > > + * The mapping between @dir and the underlying eDMA read/write LL region
> > > > > + * depends on whether the integrated eDMA instance represents a local or a
> > > > > + * remote view.
> > > > > + *
> > > > > + * Return: 0 on success, -EINVAL on invalid arguments (including out-of-range
> > > > > + *         @hw_id), or -ENODEV if the integrated eDMA instance is not present
> > > > > + *         or not initialized.
> > > > > + */
> > > > > +int dwc_pcie_edma_get_ll_region(struct pci_epc *epc,
> > > > > +				enum dma_transfer_direction dir, int hw_id,
> > > > > +				struct dw_edma_region *region);
> > > > >  #else
> > > > >  static inline int
> > > > >  dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
> > > > > @@ -34,6 +59,14 @@ dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
> > > > >  {
> > > > >  	return -ENODEV;
> > > > >  }
> > > > > +
> > > > > +static inline int
> > > > > +dwc_pcie_edma_get_ll_region(struct pci_epc *epc,
> > > > > +			    enum dma_transfer_direction dir, int hw_id,
> > > > > +			    struct dw_edma_region *region)
> > > > > +{
> > > > > +	return -ENODEV;
> > > > > +}
> > > > >  #endif /* CONFIG_PCIE_DW */
> > > > >
> > > > >  #endif /* LINUX_PCIE_DWC_EDMA_H */
> > > > > --
> > > > > 2.51.0
> > > > >

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 7/7] PCI: dwc: Add helper to query integrated dw-edma linked-list region
  2026-01-30 15:07           ` Frank Li
@ 2026-01-30 17:27             ` Koichiro Den
  0 siblings, 0 replies; 20+ messages in thread
From: Koichiro Den @ 2026-01-30 17:27 UTC (permalink / raw)
  To: Frank Li
  Cc: mani, vkoul, jingoohan1, lpieralisi, kwilczynski, robh, bhelgaas,
	dmaengine, linux-pci, linux-kernel

On Fri, Jan 30, 2026 at 10:07:02AM -0500, Frank Li wrote:
> On Fri, Jan 30, 2026 at 04:16:11PM +0900, Koichiro Den wrote:
> > On Wed, Jan 28, 2026 at 10:42:29PM -0500, Frank Li wrote:
> > > On Thu, Jan 29, 2026 at 01:25:30AM +0900, Koichiro Den wrote:
> > > > On Wed, Jan 28, 2026 at 10:48:04AM -0500, Frank Li wrote:
> > > > > On Tue, Jan 27, 2026 at 12:34:20PM +0900, Koichiro Den wrote:
> > > > > > Some DesignWare PCIe endpoint controllers integrate a DesignWare eDMA
> > > > > > instance and allocate per-channel linked-list (LL) regions. Remote eDMA
> > > > > > providers may need to expose those LL regions to the host so it can
> > > > > > build descriptors against the remote view.
> > > > > >
> > > > > > Export dwc_pcie_edma_get_ll_region() to allow higher-level code to query
> > > > > > the LL region (base/size) for a given EPC, transfer direction
> > > > > > (DMA_DEV_TO_MEM / DMA_MEM_TO_DEV) and hardware channel identifier. The
> > > > > > helper maps the request to the appropriate read/write LL region
> > > > > > depending on whether the integrated eDMA is the local or the remote
> > > > > > view.
> > > > > >
> > > > > > Signed-off-by: Koichiro Den <den@valinux.co.jp>
> > > > > > ---
> > > > > >  drivers/pci/controller/dwc/pcie-designware.c | 45 ++++++++++++++++++++
> > > > > >  include/linux/pcie-dwc-edma.h                | 33 ++++++++++++++
> > > > > >  2 files changed, 78 insertions(+)
> > > > > >
> > > > > > diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> > > > > > index bbaeecce199a..e8617873e832 100644
> > > > > > --- a/drivers/pci/controller/dwc/pcie-designware.c
> > > > > > +++ b/drivers/pci/controller/dwc/pcie-designware.c
> > > > > > @@ -1369,3 +1369,48 @@ int dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
> > > > > >  	return 0;
> > > > > >  }
> > > > > >  EXPORT_SYMBOL_GPL(dwc_pcie_edma_get_reg_window);
> > > > > > +
> > > > > > +int dwc_pcie_edma_get_ll_region(struct pci_epc *epc,
> > > > > > +				enum dma_transfer_direction dir, int hw_id,
> > > > > > +				struct dw_edma_region *region)
> > > > >
> > > > > These APIs need an user, A simple method is that add one test case in
> > > > > pci-epf-test.
> > > >
> > > > Thanks for the feedback.
> > > >
> > > > I'm unsure whether adding DesignWare-specific coverage to pci-epf-test
> > > > would be acceptable. I'd appreciate your guidance on the preferred
> > > > approach.
> > > >
> > > > One possible direction I had in mind is to keep pci-epf-test.c generic and
> > >
> > > Add a EPC/EPF API, so dynatmic check if support DMA region or other feature.
> >
> > Thank you for the comment.
> >
> > Ok, I have drafted an API ([1] below).
> >
> > One thing I'm unsure about is how far the pci-epf-test validation should
> > go. Since the API (pci_epc_get_remote_resources() in [1]) is generic and
> > only returns a list of (type, phys_addr, size, and type-specific fields), a
> > fully end-to-end validation (i.e. "are these resources actually usable from
> > the host?") would require controller-specific (DW-eDMA-specific) knowledge
> > and also depends on how those resources are exposed (e.g. for a eDMA LL
> > region, it may be sufficient to inform the host of EP-local address, while
> > the eDMA register block would need to be fully exposed via BAR mapping).
> >
> > Do you think a "smoke test" would be sufficient for now (e.g. testing
> > whether the new API returns a sane / well-formed list of resources),
> > or are
> > you expecting the test to actually program the DMA eingine from the host?
> > Personally, I think the former would suffice, since the latter would be
> > very close to re-implementing the real user (e.g. ntb_dw_edma [2]) itself.
> 
> Smoke test should be enough now.

I'll prepare v3 accordingly. Thanks.

Koichiro

> 
> Frank
> >
> > [1]:
> >
> > diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
> > index c021c7af175f..4cb5e634daba 100644
> > --- a/include/linux/pci-epc.h
> > +++ b/include/linux/pci-epc.h
> > @@ -61,6 +61,35 @@ struct pci_epc_map {
> >         void __iomem    *virt_addr;
> >  };
> >
> > +/**
> > + * enum pci_epc_remote_resource_type - remote resource type identifiers
> > + */
> > +enum pci_epc_remote_resource_type {
> > +       PCI_EPC_RR_DMA_CTRL_MMIO,
> > +       PCI_EPC_RR_DMA_CHAN_DESC,
> > +};
> > +
> > +/**
> > + * struct pci_epc_remote_resource - a physical resource that can be exposed
> > + * @type:      resource type, see enum pci_epc_remote_resource_type
> > + * @phys_addr: physical base address of the resource
> > + * @size:      size of the resource in bytes
> > + * @u:         type-specific metadata
> > + */
> > +struct pci_epc_remote_resource {
> > +       enum pci_epc_remote_resource_type type;
> > +       phys_addr_t phys_addr;
> > +       size_t size;
> > +
> > +       union {
> > +               /* PCI_EPC_RR_DMA_CHAN_DESC */
> > +               struct {
> > +                       u16 hw_chan_id;
> > +                       bool ep2rc;
> > +               } dma_chan_desc;
> > +       } u;
> > +};
> > +
> >  /**
> >   * struct pci_epc_ops - set of function pointers for performing EPC operations
> >   * @write_header: ops to populate configuration space header
> > @@ -84,6 +113,8 @@ struct pci_epc_map {
> >   * @start: ops to start the PCI link
> >   * @stop: ops to stop the PCI link
> >   * @get_features: ops to get the features supported by the EPC
> > + * @get_remote_resources: ops to retrieve controller-owned resources that can be
> > + *                       exposed to the remote host (optional)
> >   * @owner: the module owner containing the ops
> >   */
> >  struct pci_epc_ops {
> > @@ -115,6 +146,9 @@ struct pci_epc_ops {
> >         void    (*stop)(struct pci_epc *epc);
> >         const struct pci_epc_features* (*get_features)(struct pci_epc *epc,
> >                                                        u8 func_no, u8 vfunc_no);
> > +       int     (*get_remote_resources)(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
> > +                                       struct pci_epc_remote_resource *resources,
> > +                                       int num_resources);
> >         struct module *owner;
> >  };
> >
> > @@ -309,6 +343,9 @@ int pci_epc_start(struct pci_epc *epc);
> >  void pci_epc_stop(struct pci_epc *epc);
> >  const struct pci_epc_features *pci_epc_get_features(struct pci_epc *epc,
> >                                                     u8 func_no, u8 vfunc_no);
> > +int pci_epc_get_remote_resources(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
> > +                                struct pci_epc_remote_resource *resources,
> > +                                int num_resources);
> >  enum pci_barno
> >  pci_epc_get_first_free_bar(const struct pci_epc_features *epc_features);
> >  enum pci_barno pci_epc_get_next_free_bar(const struct pci_epc_features
> >
> > ---8<---
> >
> > Notes:
> > * The naming ("pci_epc_get_remote_resources") is still TBD, but the intent
> >   is to return everything needed to support remote use of an EPC-integraed
> >   DMA engine.
> > * With this API, [PATCH v2 1/7] and [PATCH v2 2/7] are no longer needed,
> >   since API caller does not need to know the low-level DMA channel id
> >   (hw_id).
> >
> > [2] https://lore.kernel.org/all/20260118135440.1958279-26-den@valinux.co.jp/
> >
> > Thanks for the review,
> > Koichiro
> >
> > >
> > > Frank
> > >
> > > > add an optional DesignWare-specific extension, selected via Kconfig, to
> > > > exercise these helpers. Likewise on the host side
> > > > (drivers/misc/pci_endpoint_test.c and kselftest pci_endpoint_test.c).
> > > >
> > > > Koichiro
> > > >
> > > > >
> > > > > Frank
> > > > >
> > > > > > +{
> > > > > > +	struct dw_edma_chip *chip;
> > > > > > +	struct dw_pcie_ep *ep;
> > > > > > +	struct dw_pcie *pci;
> > > > > > +	bool dir_read;
> > > > > > +
> > > > > > +	if (!epc || !region)
> > > > > > +		return -EINVAL;
> > > > > > +	if (dir != DMA_DEV_TO_MEM && dir != DMA_MEM_TO_DEV)
> > > > > > +		return -EINVAL;
> > > > > > +	if (hw_id < 0)
> > > > > > +		return -EINVAL;
> > > > > > +
> > > > > > +	ep = epc_get_drvdata(epc);
> > > > > > +	if (!ep)
> > > > > > +		return -ENODEV;
> > > > > > +
> > > > > > +	pci = to_dw_pcie_from_ep(ep);
> > > > > > +	chip = &pci->edma;
> > > > > > +
> > > > > > +	if (!chip->dev)
> > > > > > +		return -ENODEV;
> > > > > > +
> > > > > > +	if (chip->flags & DW_EDMA_CHIP_LOCAL)
> > > > > > +		dir_read = (dir == DMA_DEV_TO_MEM);
> > > > > > +	else
> > > > > > +		dir_read = (dir == DMA_MEM_TO_DEV);
> > > > > > +
> > > > > > +	if (dir_read) {
> > > > > > +		if (hw_id >= chip->ll_rd_cnt)
> > > > > > +			return -EINVAL;
> > > > > > +		*region = chip->ll_region_rd[hw_id];
> > > > > > +	} else {
> > > > > > +		if (hw_id >= chip->ll_wr_cnt)
> > > > > > +			return -EINVAL;
> > > > > > +		*region = chip->ll_region_wr[hw_id];
> > > > > > +	}
> > > > > > +
> > > > > > +	return 0;
> > > > > > +}
> > > > > > +EXPORT_SYMBOL_GPL(dwc_pcie_edma_get_ll_region);
> > > > > > diff --git a/include/linux/pcie-dwc-edma.h b/include/linux/pcie-dwc-edma.h
> > > > > > index a5b0595603f4..36afb4df1998 100644
> > > > > > --- a/include/linux/pcie-dwc-edma.h
> > > > > > +++ b/include/linux/pcie-dwc-edma.h
> > > > > > @@ -6,6 +6,8 @@
> > > > > >  #ifndef LINUX_PCIE_DWC_EDMA_H
> > > > > >  #define LINUX_PCIE_DWC_EDMA_H
> > > > > >
> > > > > > +#include <linux/dma/edma.h>
> > > > > > +#include <linux/dmaengine.h>
> > > > > >  #include <linux/errno.h>
> > > > > >  #include <linux/kconfig.h>
> > > > > >  #include <linux/pci-epc.h>
> > > > > > @@ -27,6 +29,29 @@
> > > > > >   */
> > > > > >  int dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
> > > > > >  				 resource_size_t *sz);
> > > > > > +
> > > > > > +/**
> > > > > > + * dwc_pcie_edma_get_ll_region() - get linked-list (LL) region for a HW channel
> > > > > > + * @epc:    EPC device associated with the integrated eDMA instance
> > > > > > + * @dir:    DMA transfer direction (%DMA_DEV_TO_MEM or %DMA_MEM_TO_DEV)
> > > > > > + * @hw_id:  hardware channel identifier (equals to dw_edma_chan.id)
> > > > > > + * @region: pointer to a region descriptor to fill in
> > > > > > + *
> > > > > > + * Some integrated DesignWare eDMA instances allocate per-channel linked-list
> > > > > > + * (LL) regions for descriptor storage. This helper returns the LL region
> > > > > > + * corresponding to @dir and @hw_id.
> > > > > > + *
> > > > > > + * The mapping between @dir and the underlying eDMA read/write LL region
> > > > > > + * depends on whether the integrated eDMA instance represents a local or a
> > > > > > + * remote view.
> > > > > > + *
> > > > > > + * Return: 0 on success, -EINVAL on invalid arguments (including out-of-range
> > > > > > + *         @hw_id), or -ENODEV if the integrated eDMA instance is not present
> > > > > > + *         or not initialized.
> > > > > > + */
> > > > > > +int dwc_pcie_edma_get_ll_region(struct pci_epc *epc,
> > > > > > +				enum dma_transfer_direction dir, int hw_id,
> > > > > > +				struct dw_edma_region *region);
> > > > > >  #else
> > > > > >  static inline int
> > > > > >  dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
> > > > > > @@ -34,6 +59,14 @@ dwc_pcie_edma_get_reg_window(struct pci_epc *epc, phys_addr_t *phys,
> > > > > >  {
> > > > > >  	return -ENODEV;
> > > > > >  }
> > > > > > +
> > > > > > +static inline int
> > > > > > +dwc_pcie_edma_get_ll_region(struct pci_epc *epc,
> > > > > > +			    enum dma_transfer_direction dir, int hw_id,
> > > > > > +			    struct dw_edma_region *region)
> > > > > > +{
> > > > > > +	return -ENODEV;
> > > > > > +}
> > > > > >  #endif /* CONFIG_PCIE_DW */
> > > > > >
> > > > > >  #endif /* LINUX_PCIE_DWC_EDMA_H */
> > > > > > --
> > > > > > 2.51.0
> > > > > >

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 0/7] dmaengine: dw-edma, PCI: dwc: Enable remote use of integrated DesignWare eDMA
  2026-01-27  3:34 [PATCH v2 0/7] dmaengine: dw-edma, PCI: dwc: Enable remote use of integrated DesignWare eDMA Koichiro Den
                   ` (6 preceding siblings ...)
  2026-01-27  3:34 ` [PATCH v2 7/7] PCI: dwc: Add helper to query integrated dw-edma linked-list region Koichiro Den
@ 2026-02-01  2:32 ` Koichiro Den
  2026-02-02 16:59   ` Frank Li
  7 siblings, 1 reply; 20+ messages in thread
From: Koichiro Den @ 2026-02-01  2:32 UTC (permalink / raw)
  To: vkoul, mani, Frank.Li, jingoohan1, lpieralisi, kwilczynski, robh,
	bhelgaas
  Cc: dmaengine, linux-pci, linux-kernel

On Tue, Jan 27, 2026 at 12:34:13PM +0900, Koichiro Den wrote:
> Hi,
> 
> Per Frank Li's suggestion [1], this revision combines the previously posted
> PCI/dwc helper series and the dmaengine/dw-edma series into a single
> 7-patch set. This series therefore supersedes the two earlier postings:
> 
>   - [PATCH 0/5] dmaengine: dw-edma: Add helpers for remote eDMA use scenarios
>     https://lore.kernel.org/dmaengine/20260126073652.3293564-1-den@valinux.co.jp/
>   - [PATCH 0/2] PCI: dwc: Expose integrated DesignWare eDMA windows
>     https://lore.kernel.org/linux-pci/20260126071550.3233631-1-den@valinux.co.jp/
> 
> [1] https://lore.kernel.org/linux-pci/aXeoxxG+9cFML1sx@lizhi-Precision-Tower-5810/
> 
> Some DesignWare PCIe endpoint platforms integrate a DesignWare eDMA
> instance alongside the PCIe controller. In remote eDMA use cases, the host
> needs access to the eDMA register block and the per-channel linked-list
> (LL) regions via PCIe BARs, while the endpoint may still boot with a
> standard EP configuration (and may also use dw-edma locally).
> 
> This series provides the following building blocks:
> 
>   * dmaengine: Add an optional dma_slave_caps.hw_id so DMA providers can expose
>     a provider-defined hardware channel identifier to clients, and report it
>     from dw-edma. This allows users to correlate a DMA channel with
>     hardware-specific resources such as per-channel LL regions.
> 
>   * dmaengine/dw-edma: Add features useful for remote-controlled EP eDMA usage:
>       - per-channel interrupt routing control (configured via dmaengine_slave_config(),
>         passing a small dw-edma-specific structure through
>         dma_slave_config.peripheral_config / dma_slave_config.peripheral_size),
>       - optional completion polling when local IRQ handling is disabled, and
>       - notify-only channels for cases where the local side needs interrupt
> 	notification without cookie-based accounting (i.e. its peer
> 	prepares and submits the descriptors), useful when host-to-endpoint
> 	interrupt delivery is difficult or unavailable without it.
> 
>   * PCI: dwc: Add query-only helper APIs to expose resources of an integrated
>     DesignWare eDMA instance:
>       - the physical base/size of the eDMA register window, and
>       - the per-channel LL region base/size, keyed by transfer direction and
>         the hardware channel identifier (hw_id).
> 
> The first real user will likely be the DesignWare backend in the NTB transport work:
> 
>   [RFC PATCH v4 25/38] NTB: hw: Add remote eDMA backend registry and DesignWare backend
>   https://lore.kernel.org/linux-pci/20260118135440.1958279-26-den@valinux.co.jp/
> 
>     (Note: the implementation in this series has been updated since that
>     RFC v4, so the RFC series will also need some adjustments. I have an
>     updated RFC series locally and can post an RFC v5 if that would help
>     review/testing.)
> 
> Apply/merge notes:
>   - Patches 1-5 apply cleanly on dmaengine.git next.
>   - Patches 6-7 apply cleanly on pci.git controller/dwc.
> 
> Changes in v2:
>   - Combine the two previously posted series into a single set (per Frank's
>     suggestion). Order dmaengine/dw-edma patches first so hw_id support
>     lands before the PCI LL-region helper, which assumes
>     dma_slave_caps.hw_id availability.
> 
> Thanks for reviewing,
> 
> 
> Koichiro Den (7):
>   dmaengine: Add hw_id to dma_slave_caps
>   dmaengine: dw-edma: Report channel hw_id in dma_slave_caps
>   dmaengine: dw-edma: Add per-channel interrupt routing control
>   dmaengine: dw-edma: Poll completion when local IRQ handling is
>     disabled
>   dmaengine: dw-edma: Add notify-only channels support
>   PCI: dwc: Add helper to query integrated dw-edma register window
>   PCI: dwc: Add helper to query integrated dw-edma linked-list region


Hi Mani, Vinod (and others),

I'd appreciate your thoughts on the overall design of patches 3–5/7 when
you have a moment.

  - [PATCH v2 3/7] dmaengine: dw-edma: Add per-channel interrupt routing control
    https://lore.kernel.org/dmaengine/20260127033420.3460579-4-den@valinux.co.jp/
  - [PATCH v2 4/7] dmaengine: dw-edma: Poll completion when local IRQ handling is disabled
    https://lore.kernel.org/dmaengine/20260127033420.3460579-5-den@valinux.co.jp/
  - [PATCH v2 5/7] dmaengine: dw-edma: Add notify-only channels support
    https://lore.kernel.org/dmaengine/20260127033420.3460579-6-den@valinux.co.jp/

My cover letter might have been too terse, so let me add a bit more context
and two questions at the end.

(Frank already provided helpful feedback on v1/RFC for Patch 3/7. Thanks, Frank.)


Motivation for these three patches
----------------------------------

  For remote use of a DMA channel (i.e. the host drives a channel that
  resides in the endpoint (EP)):

  * The EP initializes its DMA channels during the normal SoC glue
    driver probe.
  * It obtains a dma_chan to delegate to the host via the standard
    dma_request_channel().
  * It exposes the underlying HW resources to the host ("delegation").
  * The host also acquires a channel via the standard
    dma_request_channel(). The underlying HW resource is the same as on the
    EP side, but it's driven remotely from the host.

  and I'm targeting two operating modes:

  1). Standard use of the remote channel

    * The host submits a transaction and handles its completion, just
      like a local dmaengine client would. Under the hood, the HW channel
      resides in the remote EP.
    * In this scenario, we need to ensure:
      (a). completion interrupts are delivered only to the host. Or,
      (b). even if (a) is not possible (i.e. the EP also gets interrupted),
           the EP must not acknowledge/clear the interrupt status in a way
           that would race with host.

                                  dmaengine_submit()
                                          :
                                          v
       +----------+                 +----------+
       | dma_chan |--(delegate)--->: dma_chan :
       +----------+                 +----------+
      EP (delegator)              Host (delegatee)
                                          ^
                                          :
                                completion interrupt

  2). Notify-only channel

    * The host submits a transaction, and the EP gets the interrupt
      and runs any registered callbacks.
    * In this scenario, we need to ensure:
      (a). completion interrupts are delivered only to the EP. Or,
      (b). even if (a) is not possible (i.e. the host also gets
           interrupted), the host must not acknowledge/clear the interrupt
           status in a way that would race with the EP.
      (c). repeated dmaengine_submit() calls must not get stuck, even
           though it cannot rely on interrupt-driven transaction status
           management.
      (d). callback can be registered for the dma_chan on the EP.

                                  dmaengine_submit()
                                          :
                                          v
       +----------+                 +----------+
       | dma_chan |--(delegate)--->: dma_chan :
       +----------+                 +----------+
      EP (delegator)              Host (delegatee)
             ^
             :
      completion interrupt


  Patch mapping:
    - (a)(b) are addressed by [PATCH v2 3/7].
    - (c) is addressed by [PATCH v2 4/7].
    - (d) is addressed by [PATCH v2 5/7].


Questions
---------

  1. Are these two use cases (1) and (2) acceptable?
  2. To support (1) and (2), is the current implementation direction acceptable?
     Or should this be generalized into a dmaengine API rather than being a
     dw-edma-core-specific extension?


Any feedback would be appreciated.

Kind regards,
Koichiro


> 
>  MAINTAINERS                                  |   2 +-
>  drivers/dma/dmaengine.c                      |   1 +
>  drivers/dma/dw-edma/dw-edma-core.c           | 167 +++++++++++++++++--
>  drivers/dma/dw-edma/dw-edma-core.h           |  21 +++
>  drivers/dma/dw-edma/dw-edma-v0-core.c        |  26 ++-
>  drivers/pci/controller/dwc/pcie-designware.c |  74 ++++++++
>  drivers/pci/controller/dwc/pcie-designware.h |   2 +
>  include/linux/dma/edma.h                     |  57 +++++++
>  include/linux/dmaengine.h                    |   2 +
>  include/linux/pcie-dwc-edma.h                |  72 ++++++++
>  10 files changed, 398 insertions(+), 26 deletions(-)
>  create mode 100644 include/linux/pcie-dwc-edma.h
> 
> -- 
> 2.51.0
> 

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 0/7] dmaengine: dw-edma, PCI: dwc: Enable remote use of integrated DesignWare eDMA
  2026-02-01  2:32 ` [PATCH v2 0/7] dmaengine: dw-edma, PCI: dwc: Enable remote use of integrated DesignWare eDMA Koichiro Den
@ 2026-02-02 16:59   ` Frank Li
  2026-02-03  1:59     ` Koichiro Den
  0 siblings, 1 reply; 20+ messages in thread
From: Frank Li @ 2026-02-02 16:59 UTC (permalink / raw)
  To: Koichiro Den
  Cc: vkoul, mani, jingoohan1, lpieralisi, kwilczynski, robh, bhelgaas,
	dmaengine, linux-pci, linux-kernel

On Sun, Feb 01, 2026 at 11:32:23AM +0900, Koichiro Den wrote:
> On Tue, Jan 27, 2026 at 12:34:13PM +0900, Koichiro Den wrote:
> > Hi,
> >
> > Per Frank Li's suggestion [1], this revision combines the previously posted
> > PCI/dwc helper series and the dmaengine/dw-edma series into a single
> > 7-patch set. This series therefore supersedes the two earlier postings:
> >
> >   - [PATCH 0/5] dmaengine: dw-edma: Add helpers for remote eDMA use scenarios
> >     https://lore.kernel.org/dmaengine/20260126073652.3293564-1-den@valinux.co.jp/
> >   - [PATCH 0/2] PCI: dwc: Expose integrated DesignWare eDMA windows
> >     https://lore.kernel.org/linux-pci/20260126071550.3233631-1-den@valinux.co.jp/
> >
> > [1] https://lore.kernel.org/linux-pci/aXeoxxG+9cFML1sx@lizhi-Precision-Tower-5810/
> >
> > Some DesignWare PCIe endpoint platforms integrate a DesignWare eDMA
> > instance alongside the PCIe controller. In remote eDMA use cases, the host
> > needs access to the eDMA register block and the per-channel linked-list
> > (LL) regions via PCIe BARs, while the endpoint may still boot with a
> > standard EP configuration (and may also use dw-edma locally).
> >
> > This series provides the following building blocks:
> >
> >   * dmaengine: Add an optional dma_slave_caps.hw_id so DMA providers can expose
> >     a provider-defined hardware channel identifier to clients, and report it
> >     from dw-edma. This allows users to correlate a DMA channel with
> >     hardware-specific resources such as per-channel LL regions.
> >
> >   * dmaengine/dw-edma: Add features useful for remote-controlled EP eDMA usage:
> >       - per-channel interrupt routing control (configured via dmaengine_slave_config(),
> >         passing a small dw-edma-specific structure through
> >         dma_slave_config.peripheral_config / dma_slave_config.peripheral_size),
> >       - optional completion polling when local IRQ handling is disabled, and
> >       - notify-only channels for cases where the local side needs interrupt
> > 	notification without cookie-based accounting (i.e. its peer
> > 	prepares and submits the descriptors), useful when host-to-endpoint
> > 	interrupt delivery is difficult or unavailable without it.
> >
> >   * PCI: dwc: Add query-only helper APIs to expose resources of an integrated
> >     DesignWare eDMA instance:
> >       - the physical base/size of the eDMA register window, and
> >       - the per-channel LL region base/size, keyed by transfer direction and
> >         the hardware channel identifier (hw_id).
> >
> > The first real user will likely be the DesignWare backend in the NTB transport work:
> >
> >   [RFC PATCH v4 25/38] NTB: hw: Add remote eDMA backend registry and DesignWare backend
> >   https://lore.kernel.org/linux-pci/20260118135440.1958279-26-den@valinux.co.jp/
> >
> >     (Note: the implementation in this series has been updated since that
> >     RFC v4, so the RFC series will also need some adjustments. I have an
> >     updated RFC series locally and can post an RFC v5 if that would help
> >     review/testing.)
> >
> > Apply/merge notes:
> >   - Patches 1-5 apply cleanly on dmaengine.git next.
> >   - Patches 6-7 apply cleanly on pci.git controller/dwc.
> >
> > Changes in v2:
> >   - Combine the two previously posted series into a single set (per Frank's
> >     suggestion). Order dmaengine/dw-edma patches first so hw_id support
> >     lands before the PCI LL-region helper, which assumes
> >     dma_slave_caps.hw_id availability.
> >
> > Thanks for reviewing,
> >
> >
> > Koichiro Den (7):
> >   dmaengine: Add hw_id to dma_slave_caps
> >   dmaengine: dw-edma: Report channel hw_id in dma_slave_caps
> >   dmaengine: dw-edma: Add per-channel interrupt routing control
> >   dmaengine: dw-edma: Poll completion when local IRQ handling is
> >     disabled
> >   dmaengine: dw-edma: Add notify-only channels support
> >   PCI: dwc: Add helper to query integrated dw-edma register window
> >   PCI: dwc: Add helper to query integrated dw-edma linked-list region
>
>
> Hi Mani, Vinod (and others),
>
> I'd appreciate your thoughts on the overall design of patches 3–5/7 when
> you have a moment.
>
>   - [PATCH v2 3/7] dmaengine: dw-edma: Add per-channel interrupt routing control
>     https://lore.kernel.org/dmaengine/20260127033420.3460579-4-den@valinux.co.jp/
>   - [PATCH v2 4/7] dmaengine: dw-edma: Poll completion when local IRQ handling is disabled
>     https://lore.kernel.org/dmaengine/20260127033420.3460579-5-den@valinux.co.jp/
>   - [PATCH v2 5/7] dmaengine: dw-edma: Add notify-only channels support
>     https://lore.kernel.org/dmaengine/20260127033420.3460579-6-den@valinux.co.jp/
>
> My cover letter might have been too terse, so let me add a bit more context
> and two questions at the end.
>
> (Frank already provided helpful feedback on v1/RFC for Patch 3/7. Thanks, Frank.)
>
>
> Motivation for these three patches
> ----------------------------------
>
>   For remote use of a DMA channel (i.e. the host drives a channel that
>   resides in the endpoint (EP)):
>
>   * The EP initializes its DMA channels during the normal SoC glue
>     driver probe.
>   * It obtains a dma_chan to delegate to the host via the standard
>     dma_request_channel().
>   * It exposes the underlying HW resources to the host ("delegation").
>   * The host also acquires a channel via the standard
>     dma_request_channel(). The underlying HW resource is the same as on the
>     EP side, but it's driven remotely from the host.
>
>   and I'm targeting two operating modes:
>
>   1). Standard use of the remote channel
>
>     * The host submits a transaction and handles its completion, just
>       like a local dmaengine client would. Under the hood, the HW channel
>       resides in the remote EP.
>     * In this scenario, we need to ensure:
>       (a). completion interrupts are delivered only to the host. Or,
>       (b). even if (a) is not possible (i.e. the EP also gets interrupted),
>            the EP must not acknowledge/clear the interrupt status in a way
>            that would race with host.
>
>                                   dmaengine_submit()
>                                           :
>                                           v
>        +----------+                 +----------+
>        | dma_chan |--(delegate)--->: dma_chan :
>        +----------+                 +----------+
>       EP (delegator)              Host (delegatee)
>                                           ^
>                                           :
>                                 completion interrupt
>
>   2). Notify-only channel
>
>     * The host submits a transaction, and the EP gets the interrupt
>       and runs any registered callbacks.
>     * In this scenario, we need to ensure:
>       (a). completion interrupts are delivered only to the EP. Or,
>       (b). even if (a) is not possible (i.e. the host also gets
>            interrupted), the host must not acknowledge/clear the interrupt
>            status in a way that would race with the EP.
>       (c). repeated dmaengine_submit() calls must not get stuck, even
>            though it cannot rely on interrupt-driven transaction status
>            management.

According to RM:

WR_DONE_INT_STATUS
Done Interrupt Status. The DMA write channel has successfully completed the DMA transfer. For
more information, see "Interrupts and Error Handling". Each bit corresponds to a DMA channel. Bit
[0] corresponds to channel 0.
- Enabling: For more information, see "Interrupts and Error Handling".
- Masking: The DMA write interrupt Mask register has no effect on this register.
- Clearing: You must write a 1'b1 to the corresponding channel bit in the DMA write interrupt Clear register
to clear this interrupt bit.

Note: You can write to this register to emulate interrupt generation, during software or hardware testing. A
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
write to the address triggers an interrupt, but the DMA does not set the Done or Abort bits in this register.


So you just need write this register to trigger a fake irq. needn't do
data transfer.

Frank

>       (d). callback can be registered for the dma_chan on the EP.
>
>                                   dmaengine_submit()
>                                           :
>                                           v
>        +----------+                 +----------+
>        | dma_chan |--(delegate)--->: dma_chan :
>        +----------+                 +----------+
>       EP (delegator)              Host (delegatee)
>              ^
>              :
>       completion interrupt
>
>
>   Patch mapping:
>     - (a)(b) are addressed by [PATCH v2 3/7].
>     - (c) is addressed by [PATCH v2 4/7].
>     - (d) is addressed by [PATCH v2 5/7].
>
>
> Questions
> ---------
>
>   1. Are these two use cases (1) and (2) acceptable?
>   2. To support (1) and (2), is the current implementation direction acceptable?
>      Or should this be generalized into a dmaengine API rather than being a
>      dw-edma-core-specific extension?
>
>
> Any feedback would be appreciated.
>
> Kind regards,
> Koichiro
>
>
> >
> >  MAINTAINERS                                  |   2 +-
> >  drivers/dma/dmaengine.c                      |   1 +
> >  drivers/dma/dw-edma/dw-edma-core.c           | 167 +++++++++++++++++--
> >  drivers/dma/dw-edma/dw-edma-core.h           |  21 +++
> >  drivers/dma/dw-edma/dw-edma-v0-core.c        |  26 ++-
> >  drivers/pci/controller/dwc/pcie-designware.c |  74 ++++++++
> >  drivers/pci/controller/dwc/pcie-designware.h |   2 +
> >  include/linux/dma/edma.h                     |  57 +++++++
> >  include/linux/dmaengine.h                    |   2 +
> >  include/linux/pcie-dwc-edma.h                |  72 ++++++++
> >  10 files changed, 398 insertions(+), 26 deletions(-)
> >  create mode 100644 include/linux/pcie-dwc-edma.h
> >
> > --
> > 2.51.0
> >

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 0/7] dmaengine: dw-edma, PCI: dwc: Enable remote use of integrated DesignWare eDMA
  2026-02-02 16:59   ` Frank Li
@ 2026-02-03  1:59     ` Koichiro Den
  2026-02-03 17:26       ` Frank Li
  0 siblings, 1 reply; 20+ messages in thread
From: Koichiro Den @ 2026-02-03  1:59 UTC (permalink / raw)
  To: Frank Li
  Cc: vkoul, mani, jingoohan1, lpieralisi, kwilczynski, robh, bhelgaas,
	dmaengine, linux-pci, linux-kernel

On Mon, Feb 02, 2026 at 11:59:05AM -0500, Frank Li wrote:
> On Sun, Feb 01, 2026 at 11:32:23AM +0900, Koichiro Den wrote:
> > On Tue, Jan 27, 2026 at 12:34:13PM +0900, Koichiro Den wrote:
> > > Hi,
> > >
> > > Per Frank Li's suggestion [1], this revision combines the previously posted
> > > PCI/dwc helper series and the dmaengine/dw-edma series into a single
> > > 7-patch set. This series therefore supersedes the two earlier postings:
> > >
> > >   - [PATCH 0/5] dmaengine: dw-edma: Add helpers for remote eDMA use scenarios
> > >     https://lore.kernel.org/dmaengine/20260126073652.3293564-1-den@valinux.co.jp/
> > >   - [PATCH 0/2] PCI: dwc: Expose integrated DesignWare eDMA windows
> > >     https://lore.kernel.org/linux-pci/20260126071550.3233631-1-den@valinux.co.jp/
> > >
> > > [1] https://lore.kernel.org/linux-pci/aXeoxxG+9cFML1sx@lizhi-Precision-Tower-5810/
> > >
> > > Some DesignWare PCIe endpoint platforms integrate a DesignWare eDMA
> > > instance alongside the PCIe controller. In remote eDMA use cases, the host
> > > needs access to the eDMA register block and the per-channel linked-list
> > > (LL) regions via PCIe BARs, while the endpoint may still boot with a
> > > standard EP configuration (and may also use dw-edma locally).
> > >
> > > This series provides the following building blocks:
> > >
> > >   * dmaengine: Add an optional dma_slave_caps.hw_id so DMA providers can expose
> > >     a provider-defined hardware channel identifier to clients, and report it
> > >     from dw-edma. This allows users to correlate a DMA channel with
> > >     hardware-specific resources such as per-channel LL regions.
> > >
> > >   * dmaengine/dw-edma: Add features useful for remote-controlled EP eDMA usage:
> > >       - per-channel interrupt routing control (configured via dmaengine_slave_config(),
> > >         passing a small dw-edma-specific structure through
> > >         dma_slave_config.peripheral_config / dma_slave_config.peripheral_size),
> > >       - optional completion polling when local IRQ handling is disabled, and
> > >       - notify-only channels for cases where the local side needs interrupt
> > > 	notification without cookie-based accounting (i.e. its peer
> > > 	prepares and submits the descriptors), useful when host-to-endpoint
> > > 	interrupt delivery is difficult or unavailable without it.
> > >
> > >   * PCI: dwc: Add query-only helper APIs to expose resources of an integrated
> > >     DesignWare eDMA instance:
> > >       - the physical base/size of the eDMA register window, and
> > >       - the per-channel LL region base/size, keyed by transfer direction and
> > >         the hardware channel identifier (hw_id).
> > >
> > > The first real user will likely be the DesignWare backend in the NTB transport work:
> > >
> > >   [RFC PATCH v4 25/38] NTB: hw: Add remote eDMA backend registry and DesignWare backend
> > >   https://lore.kernel.org/linux-pci/20260118135440.1958279-26-den@valinux.co.jp/
> > >
> > >     (Note: the implementation in this series has been updated since that
> > >     RFC v4, so the RFC series will also need some adjustments. I have an
> > >     updated RFC series locally and can post an RFC v5 if that would help
> > >     review/testing.)
> > >
> > > Apply/merge notes:
> > >   - Patches 1-5 apply cleanly on dmaengine.git next.
> > >   - Patches 6-7 apply cleanly on pci.git controller/dwc.
> > >
> > > Changes in v2:
> > >   - Combine the two previously posted series into a single set (per Frank's
> > >     suggestion). Order dmaengine/dw-edma patches first so hw_id support
> > >     lands before the PCI LL-region helper, which assumes
> > >     dma_slave_caps.hw_id availability.
> > >
> > > Thanks for reviewing,
> > >
> > >
> > > Koichiro Den (7):
> > >   dmaengine: Add hw_id to dma_slave_caps
> > >   dmaengine: dw-edma: Report channel hw_id in dma_slave_caps
> > >   dmaengine: dw-edma: Add per-channel interrupt routing control
> > >   dmaengine: dw-edma: Poll completion when local IRQ handling is
> > >     disabled
> > >   dmaengine: dw-edma: Add notify-only channels support
> > >   PCI: dwc: Add helper to query integrated dw-edma register window
> > >   PCI: dwc: Add helper to query integrated dw-edma linked-list region
> >
> >
> > Hi Mani, Vinod (and others),
> >
> > I'd appreciate your thoughts on the overall design of patches 3–5/7 when
> > you have a moment.
> >
> >   - [PATCH v2 3/7] dmaengine: dw-edma: Add per-channel interrupt routing control
> >     https://lore.kernel.org/dmaengine/20260127033420.3460579-4-den@valinux.co.jp/
> >   - [PATCH v2 4/7] dmaengine: dw-edma: Poll completion when local IRQ handling is disabled
> >     https://lore.kernel.org/dmaengine/20260127033420.3460579-5-den@valinux.co.jp/
> >   - [PATCH v2 5/7] dmaengine: dw-edma: Add notify-only channels support
> >     https://lore.kernel.org/dmaengine/20260127033420.3460579-6-den@valinux.co.jp/
> >
> > My cover letter might have been too terse, so let me add a bit more context
> > and two questions at the end.
> >
> > (Frank already provided helpful feedback on v1/RFC for Patch 3/7. Thanks, Frank.)
> >
> >
> > Motivation for these three patches
> > ----------------------------------
> >
> >   For remote use of a DMA channel (i.e. the host drives a channel that
> >   resides in the endpoint (EP)):
> >
> >   * The EP initializes its DMA channels during the normal SoC glue
> >     driver probe.
> >   * It obtains a dma_chan to delegate to the host via the standard
> >     dma_request_channel().
> >   * It exposes the underlying HW resources to the host ("delegation").
> >   * The host also acquires a channel via the standard
> >     dma_request_channel(). The underlying HW resource is the same as on the
> >     EP side, but it's driven remotely from the host.
> >
> >   and I'm targeting two operating modes:
> >
> >   1). Standard use of the remote channel
> >
> >     * The host submits a transaction and handles its completion, just
> >       like a local dmaengine client would. Under the hood, the HW channel
> >       resides in the remote EP.
> >     * In this scenario, we need to ensure:
> >       (a). completion interrupts are delivered only to the host. Or,
> >       (b). even if (a) is not possible (i.e. the EP also gets interrupted),
> >            the EP must not acknowledge/clear the interrupt status in a way
> >            that would race with host.
> >
> >                                   dmaengine_submit()
> >                                           :
> >                                           v
> >        +----------+                 +----------+
> >        | dma_chan |--(delegate)--->: dma_chan :
> >        +----------+                 +----------+
> >       EP (delegator)              Host (delegatee)
> >                                           ^
> >                                           :
> >                                 completion interrupt
> >
> >   2). Notify-only channel
> >
> >     * The host submits a transaction, and the EP gets the interrupt
> >       and runs any registered callbacks.
> >     * In this scenario, we need to ensure:
> >       (a). completion interrupts are delivered only to the EP. Or,
> >       (b). even if (a) is not possible (i.e. the host also gets
> >            interrupted), the host must not acknowledge/clear the interrupt
> >            status in a way that would race with the EP.
> >       (c). repeated dmaengine_submit() calls must not get stuck, even
> >            though it cannot rely on interrupt-driven transaction status
> >            management.
> 
> According to RM:
> 
> WR_DONE_INT_STATUS
> Done Interrupt Status. The DMA write channel has successfully completed the DMA transfer. For
> more information, see "Interrupts and Error Handling". Each bit corresponds to a DMA channel. Bit
> [0] corresponds to channel 0.
> - Enabling: For more information, see "Interrupts and Error Handling".
> - Masking: The DMA write interrupt Mask register has no effect on this register.
> - Clearing: You must write a 1'b1 to the corresponding channel bit in the DMA write interrupt Clear register
> to clear this interrupt bit.
> 
> Note: You can write to this register to emulate interrupt generation, during software or hardware testing. A
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> write to the address triggers an interrupt, but the DMA does not set the Done or Abort bits in this register.
> 
> 
> So you just need write this register to trigger a fake irq. needn't do
> data transfer.

Thanks for the comment.

One concern I have with using the fake interrupt mechanism is that it is
effectively channel-less, while the only documented acknowledgment path is
via {WR,RD}_DONE_INT_CLEAR[x], which is strictly channel-based. The RM does
not describe how a channel-less, emulated interrupt is associated with (or
cleared by) a specific channel's INT_CLEAR bit.

Because of that, I don't think there is a spec-backed guarantee that
writing INT_CLEAR for an arbitrary (even if reserved) channel will reliably
clear a fake interrupt, though I might be missing something. In the very
first RFC v1 series [1], I ended up writing 1 to all enabled channels
simply as the most defensive approach. However, that clearly does not
compose well once the same eDMA instance is used for real data transfers,
since it risks clearing real completion events.

What's your view on this?

[1] https://lore.kernel.org/all/20251023071916.901355-16-den@valinux.co.jp/

Thanks again for taking a close look at this.

Koichiro

> 
> Frank
> 
> >       (d). callback can be registered for the dma_chan on the EP.
> >
> >                                   dmaengine_submit()
> >                                           :
> >                                           v
> >        +----------+                 +----------+
> >        | dma_chan |--(delegate)--->: dma_chan :
> >        +----------+                 +----------+
> >       EP (delegator)              Host (delegatee)
> >              ^
> >              :
> >       completion interrupt
> >
> >
> >   Patch mapping:
> >     - (a)(b) are addressed by [PATCH v2 3/7].
> >     - (c) is addressed by [PATCH v2 4/7].
> >     - (d) is addressed by [PATCH v2 5/7].
> >
> >
> > Questions
> > ---------
> >
> >   1. Are these two use cases (1) and (2) acceptable?
> >   2. To support (1) and (2), is the current implementation direction acceptable?
> >      Or should this be generalized into a dmaengine API rather than being a
> >      dw-edma-core-specific extension?
> >
> >
> > Any feedback would be appreciated.
> >
> > Kind regards,
> > Koichiro
> >
> >
> > >
> > >  MAINTAINERS                                  |   2 +-
> > >  drivers/dma/dmaengine.c                      |   1 +
> > >  drivers/dma/dw-edma/dw-edma-core.c           | 167 +++++++++++++++++--
> > >  drivers/dma/dw-edma/dw-edma-core.h           |  21 +++
> > >  drivers/dma/dw-edma/dw-edma-v0-core.c        |  26 ++-
> > >  drivers/pci/controller/dwc/pcie-designware.c |  74 ++++++++
> > >  drivers/pci/controller/dwc/pcie-designware.h |   2 +
> > >  include/linux/dma/edma.h                     |  57 +++++++
> > >  include/linux/dmaengine.h                    |   2 +
> > >  include/linux/pcie-dwc-edma.h                |  72 ++++++++
> > >  10 files changed, 398 insertions(+), 26 deletions(-)
> > >  create mode 100644 include/linux/pcie-dwc-edma.h
> > >
> > > --
> > > 2.51.0
> > >

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 0/7] dmaengine: dw-edma, PCI: dwc: Enable remote use of integrated DesignWare eDMA
  2026-02-03  1:59     ` Koichiro Den
@ 2026-02-03 17:26       ` Frank Li
  2026-02-04  7:27         ` Koichiro Den
  0 siblings, 1 reply; 20+ messages in thread
From: Frank Li @ 2026-02-03 17:26 UTC (permalink / raw)
  To: Koichiro Den
  Cc: vkoul, mani, jingoohan1, lpieralisi, kwilczynski, robh, bhelgaas,
	dmaengine, linux-pci, linux-kernel

On Tue, Feb 03, 2026 at 10:59:10AM +0900, Koichiro Den wrote:
> On Mon, Feb 02, 2026 at 11:59:05AM -0500, Frank Li wrote:
> > On Sun, Feb 01, 2026 at 11:32:23AM +0900, Koichiro Den wrote:
> > > On Tue, Jan 27, 2026 at 12:34:13PM +0900, Koichiro Den wrote:
> > > > Hi,
> > > >
> > > > Per Frank Li's suggestion [1], this revision combines the previously posted
> > > > PCI/dwc helper series and the dmaengine/dw-edma series into a single
> > > > 7-patch set. This series therefore supersedes the two earlier postings:
> > > >
> > > >   - [PATCH 0/5] dmaengine: dw-edma: Add helpers for remote eDMA use scenarios
> > > >     https://lore.kernel.org/dmaengine/20260126073652.3293564-1-den@valinux.co.jp/
> > > >   - [PATCH 0/2] PCI: dwc: Expose integrated DesignWare eDMA windows
> > > >     https://lore.kernel.org/linux-pci/20260126071550.3233631-1-den@valinux.co.jp/
> > > >
> > > > [1] https://lore.kernel.org/linux-pci/aXeoxxG+9cFML1sx@lizhi-Precision-Tower-5810/
> > > >
> > > > Some DesignWare PCIe endpoint platforms integrate a DesignWare eDMA
> > > > instance alongside the PCIe controller. In remote eDMA use cases, the host
> > > > needs access to the eDMA register block and the per-channel linked-list
> > > > (LL) regions via PCIe BARs, while the endpoint may still boot with a
> > > > standard EP configuration (and may also use dw-edma locally).
> > > >
> > > > This series provides the following building blocks:
> > > >
> > > >   * dmaengine: Add an optional dma_slave_caps.hw_id so DMA providers can expose
> > > >     a provider-defined hardware channel identifier to clients, and report it
> > > >     from dw-edma. This allows users to correlate a DMA channel with
> > > >     hardware-specific resources such as per-channel LL regions.
> > > >
> > > >   * dmaengine/dw-edma: Add features useful for remote-controlled EP eDMA usage:
> > > >       - per-channel interrupt routing control (configured via dmaengine_slave_config(),
> > > >         passing a small dw-edma-specific structure through
> > > >         dma_slave_config.peripheral_config / dma_slave_config.peripheral_size),
> > > >       - optional completion polling when local IRQ handling is disabled, and
> > > >       - notify-only channels for cases where the local side needs interrupt
> > > > 	notification without cookie-based accounting (i.e. its peer
> > > > 	prepares and submits the descriptors), useful when host-to-endpoint
> > > > 	interrupt delivery is difficult or unavailable without it.
> > > >
> > > >   * PCI: dwc: Add query-only helper APIs to expose resources of an integrated
> > > >     DesignWare eDMA instance:
> > > >       - the physical base/size of the eDMA register window, and
> > > >       - the per-channel LL region base/size, keyed by transfer direction and
> > > >         the hardware channel identifier (hw_id).
> > > >
> > > > The first real user will likely be the DesignWare backend in the NTB transport work:
> > > >
> > > >   [RFC PATCH v4 25/38] NTB: hw: Add remote eDMA backend registry and DesignWare backend
> > > >   https://lore.kernel.org/linux-pci/20260118135440.1958279-26-den@valinux.co.jp/
> > > >
> > > >     (Note: the implementation in this series has been updated since that
> > > >     RFC v4, so the RFC series will also need some adjustments. I have an
> > > >     updated RFC series locally and can post an RFC v5 if that would help
> > > >     review/testing.)
> > > >
> > > > Apply/merge notes:
> > > >   - Patches 1-5 apply cleanly on dmaengine.git next.
> > > >   - Patches 6-7 apply cleanly on pci.git controller/dwc.
> > > >
> > > > Changes in v2:
> > > >   - Combine the two previously posted series into a single set (per Frank's
> > > >     suggestion). Order dmaengine/dw-edma patches first so hw_id support
> > > >     lands before the PCI LL-region helper, which assumes
> > > >     dma_slave_caps.hw_id availability.
> > > >
> > > > Thanks for reviewing,
> > > >
> > > >
> > > > Koichiro Den (7):
> > > >   dmaengine: Add hw_id to dma_slave_caps
> > > >   dmaengine: dw-edma: Report channel hw_id in dma_slave_caps
> > > >   dmaengine: dw-edma: Add per-channel interrupt routing control
> > > >   dmaengine: dw-edma: Poll completion when local IRQ handling is
> > > >     disabled
> > > >   dmaengine: dw-edma: Add notify-only channels support
> > > >   PCI: dwc: Add helper to query integrated dw-edma register window
> > > >   PCI: dwc: Add helper to query integrated dw-edma linked-list region
> > >
> > >
> > > Hi Mani, Vinod (and others),
> > >
> > > I'd appreciate your thoughts on the overall design of patches 3–5/7 when
> > > you have a moment.
> > >
> > >   - [PATCH v2 3/7] dmaengine: dw-edma: Add per-channel interrupt routing control
> > >     https://lore.kernel.org/dmaengine/20260127033420.3460579-4-den@valinux.co.jp/
> > >   - [PATCH v2 4/7] dmaengine: dw-edma: Poll completion when local IRQ handling is disabled
> > >     https://lore.kernel.org/dmaengine/20260127033420.3460579-5-den@valinux.co.jp/
> > >   - [PATCH v2 5/7] dmaengine: dw-edma: Add notify-only channels support
> > >     https://lore.kernel.org/dmaengine/20260127033420.3460579-6-den@valinux.co.jp/
> > >
> > > My cover letter might have been too terse, so let me add a bit more context
> > > and two questions at the end.
> > >
> > > (Frank already provided helpful feedback on v1/RFC for Patch 3/7. Thanks, Frank.)
> > >
> > >
> > > Motivation for these three patches
> > > ----------------------------------
> > >
> > >   For remote use of a DMA channel (i.e. the host drives a channel that
> > >   resides in the endpoint (EP)):
> > >
> > >   * The EP initializes its DMA channels during the normal SoC glue
> > >     driver probe.
> > >   * It obtains a dma_chan to delegate to the host via the standard
> > >     dma_request_channel().
> > >   * It exposes the underlying HW resources to the host ("delegation").
> > >   * The host also acquires a channel via the standard
> > >     dma_request_channel(). The underlying HW resource is the same as on the
> > >     EP side, but it's driven remotely from the host.
> > >
> > >   and I'm targeting two operating modes:
> > >
> > >   1). Standard use of the remote channel
> > >
> > >     * The host submits a transaction and handles its completion, just
> > >       like a local dmaengine client would. Under the hood, the HW channel
> > >       resides in the remote EP.
> > >     * In this scenario, we need to ensure:
> > >       (a). completion interrupts are delivered only to the host. Or,
> > >       (b). even if (a) is not possible (i.e. the EP also gets interrupted),
> > >            the EP must not acknowledge/clear the interrupt status in a way
> > >            that would race with host.
> > >
> > >                                   dmaengine_submit()
> > >                                           :
> > >                                           v
> > >        +----------+                 +----------+
> > >        | dma_chan |--(delegate)--->: dma_chan :
> > >        +----------+                 +----------+
> > >       EP (delegator)              Host (delegatee)
> > >                                           ^
> > >                                           :
> > >                                 completion interrupt
> > >
> > >   2). Notify-only channel
> > >
> > >     * The host submits a transaction, and the EP gets the interrupt
> > >       and runs any registered callbacks.
> > >     * In this scenario, we need to ensure:
> > >       (a). completion interrupts are delivered only to the EP. Or,
> > >       (b). even if (a) is not possible (i.e. the host also gets
> > >            interrupted), the host must not acknowledge/clear the interrupt
> > >            status in a way that would race with the EP.
> > >       (c). repeated dmaengine_submit() calls must not get stuck, even
> > >            though it cannot rely on interrupt-driven transaction status
> > >            management.
> >
> > According to RM:
> >
> > WR_DONE_INT_STATUS
> > Done Interrupt Status. The DMA write channel has successfully completed the DMA transfer. For
> > more information, see "Interrupts and Error Handling". Each bit corresponds to a DMA channel. Bit
> > [0] corresponds to channel 0.
> > - Enabling: For more information, see "Interrupts and Error Handling".
> > - Masking: The DMA write interrupt Mask register has no effect on this register.
> > - Clearing: You must write a 1'b1 to the corresponding channel bit in the DMA write interrupt Clear register
> > to clear this interrupt bit.
> >
> > Note: You can write to this register to emulate interrupt generation, during software or hardware testing. A
> > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > write to the address triggers an interrupt, but the DMA does not set the Done or Abort bits in this register.
> >
> >
> > So you just need write this register to trigger a fake irq. needn't do
> > data transfer.
>
> Thanks for the comment.
>
> One concern I have with using the fake interrupt mechanism is that it is
> effectively channel-less, while the only documented acknowledgment path is
> via {WR,RD}_DONE_INT_CLEAR[x], which is strictly channel-based. The RM does
> not describe how a channel-less, emulated interrupt is associated with (or
> cleared by) a specific channel's INT_CLEAR bit.

According to spec, it should only generate a irq, but no bit set at status.
so needn't clean.

>
> Because of that, I don't think there is a spec-backed guarantee that
> writing INT_CLEAR for an arbitrary (even if reserved) channel will reliably
> clear a fake interrupt, though I might be missing something. In the very
> first RFC v1 series [1], I ended up writing 1 to all enabled channels
> simply as the most defensive approach. However, that clearly does not
> compose well once the same eDMA instance is used for real data transfers,
> since it risks clearing real completion events.

Transfer a dummy data is not big issue. Only have to write at least 2
register to finish a data transfer to trigger remote doorbell.

If write INT_STATUS work, which will most likely push doorbell. I have not
did test, dose write INT_STATUS work?

Frank

>
> What's your view on this?
>
> [1] https://lore.kernel.org/all/20251023071916.901355-16-den@valinux.co.jp/
>
> Thanks again for taking a close look at this.
>
> Koichiro
>
> >
> > Frank
> >
> > >       (d). callback can be registered for the dma_chan on the EP.
> > >
> > >                                   dmaengine_submit()
> > >                                           :
> > >                                           v
> > >        +----------+                 +----------+
> > >        | dma_chan |--(delegate)--->: dma_chan :
> > >        +----------+                 +----------+
> > >       EP (delegator)              Host (delegatee)
> > >              ^
> > >              :
> > >       completion interrupt
> > >
> > >
> > >   Patch mapping:
> > >     - (a)(b) are addressed by [PATCH v2 3/7].
> > >     - (c) is addressed by [PATCH v2 4/7].
> > >     - (d) is addressed by [PATCH v2 5/7].
> > >
> > >
> > > Questions
> > > ---------
> > >
> > >   1. Are these two use cases (1) and (2) acceptable?
> > >   2. To support (1) and (2), is the current implementation direction acceptable?
> > >      Or should this be generalized into a dmaengine API rather than being a
> > >      dw-edma-core-specific extension?
> > >
> > >
> > > Any feedback would be appreciated.
> > >
> > > Kind regards,
> > > Koichiro
> > >
> > >
> > > >
> > > >  MAINTAINERS                                  |   2 +-
> > > >  drivers/dma/dmaengine.c                      |   1 +
> > > >  drivers/dma/dw-edma/dw-edma-core.c           | 167 +++++++++++++++++--
> > > >  drivers/dma/dw-edma/dw-edma-core.h           |  21 +++
> > > >  drivers/dma/dw-edma/dw-edma-v0-core.c        |  26 ++-
> > > >  drivers/pci/controller/dwc/pcie-designware.c |  74 ++++++++
> > > >  drivers/pci/controller/dwc/pcie-designware.h |   2 +
> > > >  include/linux/dma/edma.h                     |  57 +++++++
> > > >  include/linux/dmaengine.h                    |   2 +
> > > >  include/linux/pcie-dwc-edma.h                |  72 ++++++++
> > > >  10 files changed, 398 insertions(+), 26 deletions(-)
> > > >  create mode 100644 include/linux/pcie-dwc-edma.h
> > > >
> > > > --
> > > > 2.51.0
> > > >

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 0/7] dmaengine: dw-edma, PCI: dwc: Enable remote use of integrated DesignWare eDMA
  2026-02-03 17:26       ` Frank Li
@ 2026-02-04  7:27         ` Koichiro Den
  2026-02-04 16:17           ` Frank Li
  0 siblings, 1 reply; 20+ messages in thread
From: Koichiro Den @ 2026-02-04  7:27 UTC (permalink / raw)
  To: Frank Li
  Cc: vkoul, mani, jingoohan1, lpieralisi, kwilczynski, robh, bhelgaas,
	dmaengine, linux-pci, linux-kernel

On Tue, Feb 03, 2026 at 12:26:34PM -0500, Frank Li wrote:
> On Tue, Feb 03, 2026 at 10:59:10AM +0900, Koichiro Den wrote:
> > On Mon, Feb 02, 2026 at 11:59:05AM -0500, Frank Li wrote:
> > > On Sun, Feb 01, 2026 at 11:32:23AM +0900, Koichiro Den wrote:
> > > > On Tue, Jan 27, 2026 at 12:34:13PM +0900, Koichiro Den wrote:
> > > > > Hi,
> > > > >
> > > > > Per Frank Li's suggestion [1], this revision combines the previously posted
> > > > > PCI/dwc helper series and the dmaengine/dw-edma series into a single
> > > > > 7-patch set. This series therefore supersedes the two earlier postings:
> > > > >
> > > > >   - [PATCH 0/5] dmaengine: dw-edma: Add helpers for remote eDMA use scenarios
> > > > >     https://lore.kernel.org/dmaengine/20260126073652.3293564-1-den@valinux.co.jp/
> > > > >   - [PATCH 0/2] PCI: dwc: Expose integrated DesignWare eDMA windows
> > > > >     https://lore.kernel.org/linux-pci/20260126071550.3233631-1-den@valinux.co.jp/
> > > > >
> > > > > [1] https://lore.kernel.org/linux-pci/aXeoxxG+9cFML1sx@lizhi-Precision-Tower-5810/
> > > > >
> > > > > Some DesignWare PCIe endpoint platforms integrate a DesignWare eDMA
> > > > > instance alongside the PCIe controller. In remote eDMA use cases, the host
> > > > > needs access to the eDMA register block and the per-channel linked-list
> > > > > (LL) regions via PCIe BARs, while the endpoint may still boot with a
> > > > > standard EP configuration (and may also use dw-edma locally).
> > > > >
> > > > > This series provides the following building blocks:
> > > > >
> > > > >   * dmaengine: Add an optional dma_slave_caps.hw_id so DMA providers can expose
> > > > >     a provider-defined hardware channel identifier to clients, and report it
> > > > >     from dw-edma. This allows users to correlate a DMA channel with
> > > > >     hardware-specific resources such as per-channel LL regions.
> > > > >
> > > > >   * dmaengine/dw-edma: Add features useful for remote-controlled EP eDMA usage:
> > > > >       - per-channel interrupt routing control (configured via dmaengine_slave_config(),
> > > > >         passing a small dw-edma-specific structure through
> > > > >         dma_slave_config.peripheral_config / dma_slave_config.peripheral_size),
> > > > >       - optional completion polling when local IRQ handling is disabled, and
> > > > >       - notify-only channels for cases where the local side needs interrupt
> > > > > 	notification without cookie-based accounting (i.e. its peer
> > > > > 	prepares and submits the descriptors), useful when host-to-endpoint
> > > > > 	interrupt delivery is difficult or unavailable without it.
> > > > >
> > > > >   * PCI: dwc: Add query-only helper APIs to expose resources of an integrated
> > > > >     DesignWare eDMA instance:
> > > > >       - the physical base/size of the eDMA register window, and
> > > > >       - the per-channel LL region base/size, keyed by transfer direction and
> > > > >         the hardware channel identifier (hw_id).
> > > > >
> > > > > The first real user will likely be the DesignWare backend in the NTB transport work:
> > > > >
> > > > >   [RFC PATCH v4 25/38] NTB: hw: Add remote eDMA backend registry and DesignWare backend
> > > > >   https://lore.kernel.org/linux-pci/20260118135440.1958279-26-den@valinux.co.jp/
> > > > >
> > > > >     (Note: the implementation in this series has been updated since that
> > > > >     RFC v4, so the RFC series will also need some adjustments. I have an
> > > > >     updated RFC series locally and can post an RFC v5 if that would help
> > > > >     review/testing.)
> > > > >
> > > > > Apply/merge notes:
> > > > >   - Patches 1-5 apply cleanly on dmaengine.git next.
> > > > >   - Patches 6-7 apply cleanly on pci.git controller/dwc.
> > > > >
> > > > > Changes in v2:
> > > > >   - Combine the two previously posted series into a single set (per Frank's
> > > > >     suggestion). Order dmaengine/dw-edma patches first so hw_id support
> > > > >     lands before the PCI LL-region helper, which assumes
> > > > >     dma_slave_caps.hw_id availability.
> > > > >
> > > > > Thanks for reviewing,
> > > > >
> > > > >
> > > > > Koichiro Den (7):
> > > > >   dmaengine: Add hw_id to dma_slave_caps
> > > > >   dmaengine: dw-edma: Report channel hw_id in dma_slave_caps
> > > > >   dmaengine: dw-edma: Add per-channel interrupt routing control
> > > > >   dmaengine: dw-edma: Poll completion when local IRQ handling is
> > > > >     disabled
> > > > >   dmaengine: dw-edma: Add notify-only channels support
> > > > >   PCI: dwc: Add helper to query integrated dw-edma register window
> > > > >   PCI: dwc: Add helper to query integrated dw-edma linked-list region
> > > >
> > > >
> > > > Hi Mani, Vinod (and others),
> > > >
> > > > I'd appreciate your thoughts on the overall design of patches 3–5/7 when
> > > > you have a moment.
> > > >
> > > >   - [PATCH v2 3/7] dmaengine: dw-edma: Add per-channel interrupt routing control
> > > >     https://lore.kernel.org/dmaengine/20260127033420.3460579-4-den@valinux.co.jp/
> > > >   - [PATCH v2 4/7] dmaengine: dw-edma: Poll completion when local IRQ handling is disabled
> > > >     https://lore.kernel.org/dmaengine/20260127033420.3460579-5-den@valinux.co.jp/
> > > >   - [PATCH v2 5/7] dmaengine: dw-edma: Add notify-only channels support
> > > >     https://lore.kernel.org/dmaengine/20260127033420.3460579-6-den@valinux.co.jp/
> > > >
> > > > My cover letter might have been too terse, so let me add a bit more context
> > > > and two questions at the end.
> > > >
> > > > (Frank already provided helpful feedback on v1/RFC for Patch 3/7. Thanks, Frank.)
> > > >
> > > >
> > > > Motivation for these three patches
> > > > ----------------------------------
> > > >
> > > >   For remote use of a DMA channel (i.e. the host drives a channel that
> > > >   resides in the endpoint (EP)):
> > > >
> > > >   * The EP initializes its DMA channels during the normal SoC glue
> > > >     driver probe.
> > > >   * It obtains a dma_chan to delegate to the host via the standard
> > > >     dma_request_channel().
> > > >   * It exposes the underlying HW resources to the host ("delegation").
> > > >   * The host also acquires a channel via the standard
> > > >     dma_request_channel(). The underlying HW resource is the same as on the
> > > >     EP side, but it's driven remotely from the host.
> > > >
> > > >   and I'm targeting two operating modes:
> > > >
> > > >   1). Standard use of the remote channel
> > > >
> > > >     * The host submits a transaction and handles its completion, just
> > > >       like a local dmaengine client would. Under the hood, the HW channel
> > > >       resides in the remote EP.
> > > >     * In this scenario, we need to ensure:
> > > >       (a). completion interrupts are delivered only to the host. Or,
> > > >       (b). even if (a) is not possible (i.e. the EP also gets interrupted),
> > > >            the EP must not acknowledge/clear the interrupt status in a way
> > > >            that would race with host.
> > > >
> > > >                                   dmaengine_submit()
> > > >                                           :
> > > >                                           v
> > > >        +----------+                 +----------+
> > > >        | dma_chan |--(delegate)--->: dma_chan :
> > > >        +----------+                 +----------+
> > > >       EP (delegator)              Host (delegatee)
> > > >                                           ^
> > > >                                           :
> > > >                                 completion interrupt
> > > >
> > > >   2). Notify-only channel
> > > >
> > > >     * The host submits a transaction, and the EP gets the interrupt
> > > >       and runs any registered callbacks.
> > > >     * In this scenario, we need to ensure:
> > > >       (a). completion interrupts are delivered only to the EP. Or,
> > > >       (b). even if (a) is not possible (i.e. the host also gets
> > > >            interrupted), the host must not acknowledge/clear the interrupt
> > > >            status in a way that would race with the EP.
> > > >       (c). repeated dmaengine_submit() calls must not get stuck, even
> > > >            though it cannot rely on interrupt-driven transaction status
> > > >            management.
> > >
> > > According to RM:
> > >
> > > WR_DONE_INT_STATUS
> > > Done Interrupt Status. The DMA write channel has successfully completed the DMA transfer. For
> > > more information, see "Interrupts and Error Handling". Each bit corresponds to a DMA channel. Bit
> > > [0] corresponds to channel 0.
> > > - Enabling: For more information, see "Interrupts and Error Handling".
> > > - Masking: The DMA write interrupt Mask register has no effect on this register.
> > > - Clearing: You must write a 1'b1 to the corresponding channel bit in the DMA write interrupt Clear register
> > > to clear this interrupt bit.
> > >
> > > Note: You can write to this register to emulate interrupt generation, during software or hardware testing. A
> > > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > > write to the address triggers an interrupt, but the DMA does not set the Done or Abort bits in this register.
> > >
> > >
> > > So you just need write this register to trigger a fake irq. needn't do
> > > data transfer.
> >
> > Thanks for the comment.
> >
> > One concern I have with using the fake interrupt mechanism is that it is
> > effectively channel-less, while the only documented acknowledgment path is
> > via {WR,RD}_DONE_INT_CLEAR[x], which is strictly channel-based. The RM does
> > not describe how a channel-less, emulated interrupt is associated with (or
> > cleared by) a specific channel's INT_CLEAR bit.
> 
> According to spec, it should only generate a irq, but no bit set at status.
> so needn't clean.
> 
> >
> > Because of that, I don't think there is a spec-backed guarantee that
> > writing INT_CLEAR for an arbitrary (even if reserved) channel will reliably
> > clear a fake interrupt, though I might be missing something. In the very
> > first RFC v1 series [1], I ended up writing 1 to all enabled channels
> > simply as the most defensive approach. However, that clearly does not
> > compose well once the same eDMA instance is used for real data transfers,
> > since it risks clearing real completion events.
> 
> Transfer a dummy data is not big issue. Only have to write at least 2
> register to finish a data transfer to trigger remote doorbell.
> 
> If write INT_STATUS work, which will most likely push doorbell. I have not
> did test, dose write INT_STATUS work?

In the RM, WR_DONE_INT_CLEAR has the description:

    Done Interrupt Clear. You must write a 1'b1 to clear the
    corresponding bit in the Done interrupt status field of the
    DMA write interrupt status register. Each bit corresponds to a
    DMA channel. Bit [0] corresponds to channel 0.
    Note: Reading from this self-clearing register field always
    returns a '0'.

Based on this, I originally assumed that writing a 1 to at least one
channel bit was required. However, after reading your comment, I tested
this on R-Car S4 Spider (eDMA) and verified that writing all 0s to
INT_CLEAR is sufficient to deassert a raised fake irq. This means the fake
irq can be acked without interfering with ongoing real DMA transfers on any
channel.

For HDMA, I do not currently have access to suitable hardware, so I have
not been able to validate the same behavior. I guess something like this
might work:

    SET_BOTH_CH_32(dw, 0, int_clear, 0) // channel 0 chosen arbitrarily

Anyway, based on the above, I have prepared v3 of the series and also
locally updated my RFC series ("[RFC PATCH v4 00/38] NTB transport backed
by PCI EP embedded DMA") accordingly. This fake irq approach has been
working well in my testing, so I plan to send v3 shortly.

Thanks for the review, it helped a lot,
Koichiro

> 
> Frank
> 
> >
> > What's your view on this?
> >
> > [1] https://lore.kernel.org/all/20251023071916.901355-16-den@valinux.co.jp/
> >
> > Thanks again for taking a close look at this.
> >
> > Koichiro
> >
> > >
> > > Frank
> > >
> > > >       (d). callback can be registered for the dma_chan on the EP.
> > > >
> > > >                                   dmaengine_submit()
> > > >                                           :
> > > >                                           v
> > > >        +----------+                 +----------+
> > > >        | dma_chan |--(delegate)--->: dma_chan :
> > > >        +----------+                 +----------+
> > > >       EP (delegator)              Host (delegatee)
> > > >              ^
> > > >              :
> > > >       completion interrupt
> > > >
> > > >
> > > >   Patch mapping:
> > > >     - (a)(b) are addressed by [PATCH v2 3/7].
> > > >     - (c) is addressed by [PATCH v2 4/7].
> > > >     - (d) is addressed by [PATCH v2 5/7].
> > > >
> > > >
> > > > Questions
> > > > ---------
> > > >
> > > >   1. Are these two use cases (1) and (2) acceptable?
> > > >   2. To support (1) and (2), is the current implementation direction acceptable?
> > > >      Or should this be generalized into a dmaengine API rather than being a
> > > >      dw-edma-core-specific extension?
> > > >
> > > >
> > > > Any feedback would be appreciated.
> > > >
> > > > Kind regards,
> > > > Koichiro
> > > >
> > > >
> > > > >
> > > > >  MAINTAINERS                                  |   2 +-
> > > > >  drivers/dma/dmaengine.c                      |   1 +
> > > > >  drivers/dma/dw-edma/dw-edma-core.c           | 167 +++++++++++++++++--
> > > > >  drivers/dma/dw-edma/dw-edma-core.h           |  21 +++
> > > > >  drivers/dma/dw-edma/dw-edma-v0-core.c        |  26 ++-
> > > > >  drivers/pci/controller/dwc/pcie-designware.c |  74 ++++++++
> > > > >  drivers/pci/controller/dwc/pcie-designware.h |   2 +
> > > > >  include/linux/dma/edma.h                     |  57 +++++++
> > > > >  include/linux/dmaengine.h                    |   2 +
> > > > >  include/linux/pcie-dwc-edma.h                |  72 ++++++++
> > > > >  10 files changed, 398 insertions(+), 26 deletions(-)
> > > > >  create mode 100644 include/linux/pcie-dwc-edma.h
> > > > >
> > > > > --
> > > > > 2.51.0
> > > > >

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v2 0/7] dmaengine: dw-edma, PCI: dwc: Enable remote use of integrated DesignWare eDMA
  2026-02-04  7:27         ` Koichiro Den
@ 2026-02-04 16:17           ` Frank Li
  0 siblings, 0 replies; 20+ messages in thread
From: Frank Li @ 2026-02-04 16:17 UTC (permalink / raw)
  To: Koichiro Den
  Cc: vkoul, mani, jingoohan1, lpieralisi, kwilczynski, robh, bhelgaas,
	dmaengine, linux-pci, linux-kernel

On Wed, Feb 04, 2026 at 04:27:46PM +0900, Koichiro Den wrote:
> On Tue, Feb 03, 2026 at 12:26:34PM -0500, Frank Li wrote:
> > On Tue, Feb 03, 2026 at 10:59:10AM +0900, Koichiro Den wrote:
> > > On Mon, Feb 02, 2026 at 11:59:05AM -0500, Frank Li wrote:
> > > > On Sun, Feb 01, 2026 at 11:32:23AM +0900, Koichiro Den wrote:
> > > > > On Tue, Jan 27, 2026 at 12:34:13PM +0900, Koichiro Den wrote:
> > > > > > Hi,
> > > > > >
> > > > > > Per Frank Li's suggestion [1], this revision combines the previously posted
> > > > > > PCI/dwc helper series and the dmaengine/dw-edma series into a single
> > > > > > 7-patch set. This series therefore supersedes the two earlier postings:
> > > > > >
> > > > > >   - [PATCH 0/5] dmaengine: dw-edma: Add helpers for remote eDMA use scenarios
> > > > > >     https://lore.kernel.org/dmaengine/20260126073652.3293564-1-den@valinux.co.jp/
> > > > > >   - [PATCH 0/2] PCI: dwc: Expose integrated DesignWare eDMA windows
> > > > > >     https://lore.kernel.org/linux-pci/20260126071550.3233631-1-den@valinux.co.jp/
> > > > > >
> > > > > > [1] https://lore.kernel.org/linux-pci/aXeoxxG+9cFML1sx@lizhi-Precision-Tower-5810/
> > > > > >
> > > > > > Some DesignWare PCIe endpoint platforms integrate a DesignWare eDMA
> > > > > > instance alongside the PCIe controller. In remote eDMA use cases, the host
> > > > > > needs access to the eDMA register block and the per-channel linked-list
> > > > > > (LL) regions via PCIe BARs, while the endpoint may still boot with a
> > > > > > standard EP configuration (and may also use dw-edma locally).
> > > > > >
> > > > > > This series provides the following building blocks:
> > > > > >
> > > > > >   * dmaengine: Add an optional dma_slave_caps.hw_id so DMA providers can expose
> > > > > >     a provider-defined hardware channel identifier to clients, and report it
> > > > > >     from dw-edma. This allows users to correlate a DMA channel with
> > > > > >     hardware-specific resources such as per-channel LL regions.
> > > > > >
> > > > > >   * dmaengine/dw-edma: Add features useful for remote-controlled EP eDMA usage:
> > > > > >       - per-channel interrupt routing control (configured via dmaengine_slave_config(),
> > > > > >         passing a small dw-edma-specific structure through
> > > > > >         dma_slave_config.peripheral_config / dma_slave_config.peripheral_size),
> > > > > >       - optional completion polling when local IRQ handling is disabled, and
> > > > > >       - notify-only channels for cases where the local side needs interrupt
> > > > > > 	notification without cookie-based accounting (i.e. its peer
> > > > > > 	prepares and submits the descriptors), useful when host-to-endpoint
> > > > > > 	interrupt delivery is difficult or unavailable without it.
> > > > > >
> > > > > >   * PCI: dwc: Add query-only helper APIs to expose resources of an integrated
> > > > > >     DesignWare eDMA instance:
> > > > > >       - the physical base/size of the eDMA register window, and
> > > > > >       - the per-channel LL region base/size, keyed by transfer direction and
> > > > > >         the hardware channel identifier (hw_id).
> > > > > >
> > > > > > The first real user will likely be the DesignWare backend in the NTB transport work:
> > > > > >
> > > > > >   [RFC PATCH v4 25/38] NTB: hw: Add remote eDMA backend registry and DesignWare backend
> > > > > >   https://lore.kernel.org/linux-pci/20260118135440.1958279-26-den@valinux.co.jp/
> > > > > >
> > > > > >     (Note: the implementation in this series has been updated since that
> > > > > >     RFC v4, so the RFC series will also need some adjustments. I have an
> > > > > >     updated RFC series locally and can post an RFC v5 if that would help
> > > > > >     review/testing.)
> > > > > >
> > > > > > Apply/merge notes:
> > > > > >   - Patches 1-5 apply cleanly on dmaengine.git next.
> > > > > >   - Patches 6-7 apply cleanly on pci.git controller/dwc.
> > > > > >
> > > > > > Changes in v2:
> > > > > >   - Combine the two previously posted series into a single set (per Frank's
> > > > > >     suggestion). Order dmaengine/dw-edma patches first so hw_id support
> > > > > >     lands before the PCI LL-region helper, which assumes
> > > > > >     dma_slave_caps.hw_id availability.
> > > > > >
> > > > > > Thanks for reviewing,
> > > > > >
> > > > > >
> > > > > > Koichiro Den (7):
> > > > > >   dmaengine: Add hw_id to dma_slave_caps
> > > > > >   dmaengine: dw-edma: Report channel hw_id in dma_slave_caps
> > > > > >   dmaengine: dw-edma: Add per-channel interrupt routing control
> > > > > >   dmaengine: dw-edma: Poll completion when local IRQ handling is
> > > > > >     disabled
> > > > > >   dmaengine: dw-edma: Add notify-only channels support
> > > > > >   PCI: dwc: Add helper to query integrated dw-edma register window
> > > > > >   PCI: dwc: Add helper to query integrated dw-edma linked-list region
> > > > >
> > > > >
> > > > > Hi Mani, Vinod (and others),
> > > > >
> > > > > I'd appreciate your thoughts on the overall design of patches 3–5/7 when
> > > > > you have a moment.
> > > > >
> > > > >   - [PATCH v2 3/7] dmaengine: dw-edma: Add per-channel interrupt routing control
> > > > >     https://lore.kernel.org/dmaengine/20260127033420.3460579-4-den@valinux.co.jp/
> > > > >   - [PATCH v2 4/7] dmaengine: dw-edma: Poll completion when local IRQ handling is disabled
> > > > >     https://lore.kernel.org/dmaengine/20260127033420.3460579-5-den@valinux.co.jp/
> > > > >   - [PATCH v2 5/7] dmaengine: dw-edma: Add notify-only channels support
> > > > >     https://lore.kernel.org/dmaengine/20260127033420.3460579-6-den@valinux.co.jp/
> > > > >
> > > > > My cover letter might have been too terse, so let me add a bit more context
> > > > > and two questions at the end.
> > > > >
> > > > > (Frank already provided helpful feedback on v1/RFC for Patch 3/7. Thanks, Frank.)
> > > > >
> > > > >
> > > > > Motivation for these three patches
> > > > > ----------------------------------
> > > > >
> > > > >   For remote use of a DMA channel (i.e. the host drives a channel that
> > > > >   resides in the endpoint (EP)):
> > > > >
> > > > >   * The EP initializes its DMA channels during the normal SoC glue
> > > > >     driver probe.
> > > > >   * It obtains a dma_chan to delegate to the host via the standard
> > > > >     dma_request_channel().
> > > > >   * It exposes the underlying HW resources to the host ("delegation").
> > > > >   * The host also acquires a channel via the standard
> > > > >     dma_request_channel(). The underlying HW resource is the same as on the
> > > > >     EP side, but it's driven remotely from the host.
> > > > >
> > > > >   and I'm targeting two operating modes:
> > > > >
> > > > >   1). Standard use of the remote channel
> > > > >
> > > > >     * The host submits a transaction and handles its completion, just
> > > > >       like a local dmaengine client would. Under the hood, the HW channel
> > > > >       resides in the remote EP.
> > > > >     * In this scenario, we need to ensure:
> > > > >       (a). completion interrupts are delivered only to the host. Or,
> > > > >       (b). even if (a) is not possible (i.e. the EP also gets interrupted),
> > > > >            the EP must not acknowledge/clear the interrupt status in a way
> > > > >            that would race with host.
> > > > >
> > > > >                                   dmaengine_submit()
> > > > >                                           :
> > > > >                                           v
> > > > >        +----------+                 +----------+
> > > > >        | dma_chan |--(delegate)--->: dma_chan :
> > > > >        +----------+                 +----------+
> > > > >       EP (delegator)              Host (delegatee)
> > > > >                                           ^
> > > > >                                           :
> > > > >                                 completion interrupt
> > > > >
> > > > >   2). Notify-only channel
> > > > >
> > > > >     * The host submits a transaction, and the EP gets the interrupt
> > > > >       and runs any registered callbacks.
> > > > >     * In this scenario, we need to ensure:
> > > > >       (a). completion interrupts are delivered only to the EP. Or,
> > > > >       (b). even if (a) is not possible (i.e. the host also gets
> > > > >            interrupted), the host must not acknowledge/clear the interrupt
> > > > >            status in a way that would race with the EP.
> > > > >       (c). repeated dmaengine_submit() calls must not get stuck, even
> > > > >            though it cannot rely on interrupt-driven transaction status
> > > > >            management.
> > > >
> > > > According to RM:
> > > >
> > > > WR_DONE_INT_STATUS
> > > > Done Interrupt Status. The DMA write channel has successfully completed the DMA transfer. For
> > > > more information, see "Interrupts and Error Handling". Each bit corresponds to a DMA channel. Bit
> > > > [0] corresponds to channel 0.
> > > > - Enabling: For more information, see "Interrupts and Error Handling".
> > > > - Masking: The DMA write interrupt Mask register has no effect on this register.
> > > > - Clearing: You must write a 1'b1 to the corresponding channel bit in the DMA write interrupt Clear register
> > > > to clear this interrupt bit.
> > > >
> > > > Note: You can write to this register to emulate interrupt generation, during software or hardware testing. A
> > > > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> > > > write to the address triggers an interrupt, but the DMA does not set the Done or Abort bits in this register.
> > > >
> > > >
> > > > So you just need write this register to trigger a fake irq. needn't do
> > > > data transfer.
> > >
> > > Thanks for the comment.
> > >
> > > One concern I have with using the fake interrupt mechanism is that it is
> > > effectively channel-less, while the only documented acknowledgment path is
> > > via {WR,RD}_DONE_INT_CLEAR[x], which is strictly channel-based. The RM does
> > > not describe how a channel-less, emulated interrupt is associated with (or
> > > cleared by) a specific channel's INT_CLEAR bit.
> >
> > According to spec, it should only generate a irq, but no bit set at status.
> > so needn't clean.
> >
> > >
> > > Because of that, I don't think there is a spec-backed guarantee that
> > > writing INT_CLEAR for an arbitrary (even if reserved) channel will reliably
> > > clear a fake interrupt, though I might be missing something. In the very
> > > first RFC v1 series [1], I ended up writing 1 to all enabled channels
> > > simply as the most defensive approach. However, that clearly does not
> > > compose well once the same eDMA instance is used for real data transfers,
> > > since it risks clearing real completion events.
> >
> > Transfer a dummy data is not big issue. Only have to write at least 2
> > register to finish a data transfer to trigger remote doorbell.
> >
> > If write INT_STATUS work, which will most likely push doorbell. I have not
> > did test, dose write INT_STATUS work?
>
> In the RM, WR_DONE_INT_CLEAR has the description:
>
>     Done Interrupt Clear. You must write a 1'b1 to clear the
>     corresponding bit in the Done interrupt status field of the
>     DMA write interrupt status register. Each bit corresponds to a
>     DMA channel. Bit [0] corresponds to channel 0.
>     Note: Reading from this self-clearing register field always
>     returns a '0'.
>
> Based on this, I originally assumed that writing a 1 to at least one
> channel bit was required. However, after reading your comment, I tested
> this on R-Car S4 Spider (eDMA) and verified that writing all 0s to
> INT_CLEAR is sufficient to deassert a raised fake irq. This means the fake
> irq can be acked without interfering with ongoing real DMA transfers on any
> channel.
>
> For HDMA, I do not currently have access to suitable hardware, so I have
> not been able to validate the same behavior. I guess something like this
> might work:
>
>     SET_BOTH_CH_32(dw, 0, int_clear, 0) // channel 0 chosen arbitrarily
>
> Anyway, based on the above, I have prepared v3 of the series and also
> locally updated my RFC series ("[RFC PATCH v4 00/38] NTB transport backed
> by PCI EP embedded DMA") accordingly. This fake irq approach has been
> working well in my testing, so I plan to send v3 shortly.

RFC is too bigger, can you do small one for epf_endpont_test(), which
already used MSI its as doorbell?  you can provide althernate method to do
doorbell, it will go quick to be merged.

Most DWC controller included DMA suppport, it will beneafit more than MSI
ITS because not all chips have its or there are other limiation.

Frank

>
> Thanks for the review, it helped a lot,
> Koichiro
>
> >
> > Frank
> >
> > >
> > > What's your view on this?
> > >
> > > [1] https://lore.kernel.org/all/20251023071916.901355-16-den@valinux.co.jp/
> > >
> > > Thanks again for taking a close look at this.
> > >
> > > Koichiro
> > >
> > > >
> > > > Frank
> > > >
> > > > >       (d). callback can be registered for the dma_chan on the EP.
> > > > >
> > > > >                                   dmaengine_submit()
> > > > >                                           :
> > > > >                                           v
> > > > >        +----------+                 +----------+
> > > > >        | dma_chan |--(delegate)--->: dma_chan :
> > > > >        +----------+                 +----------+
> > > > >       EP (delegator)              Host (delegatee)
> > > > >              ^
> > > > >              :
> > > > >       completion interrupt
> > > > >
> > > > >
> > > > >   Patch mapping:
> > > > >     - (a)(b) are addressed by [PATCH v2 3/7].
> > > > >     - (c) is addressed by [PATCH v2 4/7].
> > > > >     - (d) is addressed by [PATCH v2 5/7].
> > > > >
> > > > >
> > > > > Questions
> > > > > ---------
> > > > >
> > > > >   1. Are these two use cases (1) and (2) acceptable?
> > > > >   2. To support (1) and (2), is the current implementation direction acceptable?
> > > > >      Or should this be generalized into a dmaengine API rather than being a
> > > > >      dw-edma-core-specific extension?
> > > > >
> > > > >
> > > > > Any feedback would be appreciated.
> > > > >
> > > > > Kind regards,
> > > > > Koichiro
> > > > >
> > > > >
> > > > > >
> > > > > >  MAINTAINERS                                  |   2 +-
> > > > > >  drivers/dma/dmaengine.c                      |   1 +
> > > > > >  drivers/dma/dw-edma/dw-edma-core.c           | 167 +++++++++++++++++--
> > > > > >  drivers/dma/dw-edma/dw-edma-core.h           |  21 +++
> > > > > >  drivers/dma/dw-edma/dw-edma-v0-core.c        |  26 ++-
> > > > > >  drivers/pci/controller/dwc/pcie-designware.c |  74 ++++++++
> > > > > >  drivers/pci/controller/dwc/pcie-designware.h |   2 +
> > > > > >  include/linux/dma/edma.h                     |  57 +++++++
> > > > > >  include/linux/dmaengine.h                    |   2 +
> > > > > >  include/linux/pcie-dwc-edma.h                |  72 ++++++++
> > > > > >  10 files changed, 398 insertions(+), 26 deletions(-)
> > > > > >  create mode 100644 include/linux/pcie-dwc-edma.h
> > > > > >
> > > > > > --
> > > > > > 2.51.0
> > > > > >

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2026-02-04 16:17 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-01-27  3:34 [PATCH v2 0/7] dmaengine: dw-edma, PCI: dwc: Enable remote use of integrated DesignWare eDMA Koichiro Den
2026-01-27  3:34 ` [PATCH v2 1/7] dmaengine: Add hw_id to dma_slave_caps Koichiro Den
2026-01-27  3:34 ` [PATCH v2 2/7] dmaengine: dw-edma: Report channel hw_id in dma_slave_caps Koichiro Den
2026-01-27  3:34 ` [PATCH v2 3/7] dmaengine: dw-edma: Add per-channel interrupt routing control Koichiro Den
2026-01-27  3:34 ` [PATCH v2 4/7] dmaengine: dw-edma: Poll completion when local IRQ handling is disabled Koichiro Den
2026-01-27  3:34 ` [PATCH v2 5/7] dmaengine: dw-edma: Add notify-only channels support Koichiro Den
2026-01-27  3:34 ` [PATCH v2 6/7] PCI: dwc: Add helper to query integrated dw-edma register window Koichiro Den
2026-01-27  3:34 ` [PATCH v2 7/7] PCI: dwc: Add helper to query integrated dw-edma linked-list region Koichiro Den
2026-01-28 15:48   ` Frank Li
2026-01-28 16:25     ` Koichiro Den
2026-01-29  3:42       ` Frank Li
2026-01-30  7:16         ` Koichiro Den
2026-01-30 15:07           ` Frank Li
2026-01-30 17:27             ` Koichiro Den
2026-02-01  2:32 ` [PATCH v2 0/7] dmaengine: dw-edma, PCI: dwc: Enable remote use of integrated DesignWare eDMA Koichiro Den
2026-02-02 16:59   ` Frank Li
2026-02-03  1:59     ` Koichiro Den
2026-02-03 17:26       ` Frank Li
2026-02-04  7:27         ` Koichiro Den
2026-02-04 16:17           ` Frank Li

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®