public inbox for dmaengine@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 00/11] dmaengine, PCI: endpoint: Enable remote use of integrated DesignWare eDMA
@ 2026-02-04 14:54 Koichiro Den
  2026-02-04 14:54 ` [PATCH v3 01/11] dmaengine: Add hw_id to dma_slave_caps Koichiro Den
                   ` (10 more replies)
  0 siblings, 11 replies; 32+ messages in thread
From: Koichiro Den @ 2026-02-04 14:54 UTC (permalink / raw)
  To: vkoul, mani, Frank.Li, jingoohan1, lpieralisi, kwilczynski, robh,
	bhelgaas
  Cc: dmaengine, linux-pci, linux-kernel

Hi,

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:

    1. Add dma_slave_caps.hw_id and report it from dw-edma so clients can
       correlate a dma_chan obtained via dma_request_channel() with
       hardware-specific resources (e.g. per-channel LL regions) returned
       by pci_epc_get_remote_resources().
       => Patch 01/11 - 02/11

    2. Add dw-edma-specific per-channel interrupt routing control via
       dma_slave_config.peripheral_config.
       => Patch 03/11

    3. Add dmaengine_(un)register_selfirq() API, and implement it for
       dw-edma. For dw-edma, a write to WR/RD_DONE_INT_STATUS can raise an
       interrupt without setting DONE/ABORT status bits, and dw-edma uses
       this behaviour.
       => Patch 04/11 - 05/11

  * pci/endpoint:

    1. Add a generic remote resource enumeration API
       (pci_epc_get_remote_resources()) for EPF drivers to discover
       controller-owned resources that can be mapped into BAR space (e.g.
       an integrated DMA MMIO window and per-channel LL regions). Implement
       it for dwc.
       => Patch 06/11 - 08/11

    2. Add a smoke test for the new EPC API.
       => Patch 09/11 - 11/11

This series evolved out of:
https://lore.kernel.org/linux-pci/20260118135440.1958279-1-den@valinux.co.jp/


Kernel base
===========

Patches 1-5 cleanly apply to dmaengine.git 'next':
Commit 3c8a86ed002a ("dmaengine: xilinx: xdma: use sg_nents_for_dma() helper")

Patches 6-11 cleanly apply to pci.git 'controller/dwc':
Commit e3c3a5d25dc0 ("PCI: dwc: ep: Add comment explaining controller level PTM access in multi PF setup")

If preferred, I can split the series into two.

Changelog
=========

* v2->v3 changes:
  - Replace DWC-specific helpers with a generic EPC remote resource query API.
  - Add pci-epf-test smoke test and host/kselftest support for the new API.
  - Drop the dw-edma-specific notify-only channel and polling approach
    ([PATCH v2 4/7] and [PATCH v2 5/7]), and rework notification handling
    around a generic dmaengine_(un)register_selfirq() API implemented
    by dw-edma.

* v1->v2 changes:
  - 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.

v2: https://lore.kernel.org/all/20260127033420.3460579-1-den@valinux.co.jp/
v1: https://lore.kernel.org/dmaengine/20260126073652.3293564-1-den@valinux.co.jp/
    +
    https://lore.kernel.org/linux-pci/20260126071550.3233631-1-den@valinux.co.jp/

Thanks for reviewing,


Koichiro Den (11):
  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: Add selfirq callback registration API
  dmaengine: dw-edma: Implement dmaengine selfirq callbacks using
    interrupt emulation
  PCI: endpoint: Add remote resource query API
  PCI: dwc: Record integrated eDMA register window
  PCI: dwc: ep: Report integrated DWC eDMA remote resources
  PCI: endpoint: pci-epf-test: Add smoke test for EPC remote resource
    API
  misc: pci_endpoint_test: Add EPC remote resource API test ioctl
  selftests: pci_endpoint: Add EPC remote resource API test

 drivers/dma/dmaengine.c                       |   1 +
 drivers/dma/dw-edma/dw-edma-core.c            | 143 +++++++++++++++++-
 drivers/dma/dw-edma/dw-edma-core.h            |  30 ++++
 drivers/dma/dw-edma/dw-edma-v0-core.c         |  37 ++++-
 drivers/misc/pci_endpoint_test.c              |  49 ++++++
 .../pci/controller/dwc/pcie-designware-ep.c   |  74 +++++++++
 drivers/pci/controller/dwc/pcie-designware.c  |   4 +
 drivers/pci/controller/dwc/pcie-designware.h  |   2 +
 drivers/pci/endpoint/functions/pci-epf-test.c |  88 +++++++++++
 drivers/pci/endpoint/pci-epc-core.c           |  41 +++++
 include/linux/dma/edma.h                      |  28 ++++
 include/linux/dmaengine.h                     |  72 +++++++++
 include/linux/pci-epc.h                       |  46 ++++++
 include/uapi/linux/pcitest.h                  |   1 +
 .../pci_endpoint/pci_endpoint_test.c          |  28 ++++
 15 files changed, 631 insertions(+), 13 deletions(-)

-- 
2.51.0


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

* [PATCH v3 01/11] dmaengine: Add hw_id to dma_slave_caps
  2026-02-04 14:54 [PATCH v3 00/11] dmaengine, PCI: endpoint: Enable remote use of integrated DesignWare eDMA Koichiro Den
@ 2026-02-04 14:54 ` Koichiro Den
  2026-02-04 19:39   ` Frank Li
  2026-02-04 14:54 ` [PATCH v3 02/11] dmaengine: dw-edma: Report channel hw_id in dma_slave_caps Koichiro Den
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 32+ messages in thread
From: Koichiro Den @ 2026-02-04 14:54 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 related	[flat|nested] 32+ messages in thread

* [PATCH v3 02/11] dmaengine: dw-edma: Report channel hw_id in dma_slave_caps
  2026-02-04 14:54 [PATCH v3 00/11] dmaengine, PCI: endpoint: Enable remote use of integrated DesignWare eDMA Koichiro Den
  2026-02-04 14:54 ` [PATCH v3 01/11] dmaengine: Add hw_id to dma_slave_caps Koichiro Den
@ 2026-02-04 14:54 ` Koichiro Den
  2026-02-04 14:54 ` [PATCH v3 03/11] dmaengine: dw-edma: Add per-channel interrupt routing control Koichiro Den
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 32+ messages in thread
From: Koichiro Den @ 2026-02-04 14:54 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 related	[flat|nested] 32+ messages in thread

* [PATCH v3 03/11] dmaengine: dw-edma: Add per-channel interrupt routing control
  2026-02-04 14:54 [PATCH v3 00/11] dmaengine, PCI: endpoint: Enable remote use of integrated DesignWare eDMA Koichiro Den
  2026-02-04 14:54 ` [PATCH v3 01/11] dmaengine: Add hw_id to dma_slave_caps Koichiro Den
  2026-02-04 14:54 ` [PATCH v3 02/11] dmaengine: dw-edma: Report channel hw_id in dma_slave_caps Koichiro Den
@ 2026-02-04 14:54 ` Koichiro Den
  2026-02-04 17:42   ` Frank Li
  2026-02-04 14:54 ` [PATCH v3 04/11] dmaengine: Add selfirq callback registration API Koichiro Den
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 32+ messages in thread
From: Koichiro Den @ 2026-02-04 14:54 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.

For now, HDMA is not supported for the peripheral_config. Until the
support is implemented and validated, explicitly reject it for HDMA to
avoid silently misconfiguring interrupt routing.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
 drivers/dma/dw-edma/dw-edma-core.c    | 24 +++++++++++++++++++++++
 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, 83 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..b4cb02d545bd 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -224,6 +224,29 @@ 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 (chan->dw->chip->mf == EDMA_MF_HDMA_NATIVE)
+			return -EOPNOTSUPP;
+
+		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 +773,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 related	[flat|nested] 32+ messages in thread

* [PATCH v3 04/11] dmaengine: Add selfirq callback registration API
  2026-02-04 14:54 [PATCH v3 00/11] dmaengine, PCI: endpoint: Enable remote use of integrated DesignWare eDMA Koichiro Den
                   ` (2 preceding siblings ...)
  2026-02-04 14:54 ` [PATCH v3 03/11] dmaengine: dw-edma: Add per-channel interrupt routing control Koichiro Den
@ 2026-02-04 14:54 ` Koichiro Den
  2026-02-04 17:46   ` Frank Li
  2026-02-04 14:54 ` [PATCH v3 05/11] dmaengine: dw-edma: Implement dmaengine selfirq callbacks using interrupt emulation Koichiro Den
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 32+ messages in thread
From: Koichiro Den @ 2026-02-04 14:54 UTC (permalink / raw)
  To: vkoul, mani, Frank.Li, jingoohan1, lpieralisi, kwilczynski, robh,
	bhelgaas
  Cc: dmaengine, linux-pci, linux-kernel

Some DMA controllers can generate an interrupt by software writing to a
register, without updating the normal interrupt status bits. This can be
used as a doorbell mechanism when the DMA engine is remotely programmed,
or for self-tests.

Add an optional per-DMA-device API to register/unregister callbacks for
such "selfirq" events. Providers may invoke these callbacks from their
interrupt handler when they detect an emulated interrupt.

Callbacks are invoked in hardirq context and must not sleep.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
 include/linux/dmaengine.h | 70 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)

diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
index 71bc2674567f..9c6194e8bfe1 100644
--- a/include/linux/dmaengine.h
+++ b/include/linux/dmaengine.h
@@ -785,6 +785,17 @@ struct dma_filter {
 	const struct dma_slave_map *map;
 };
 
+/**
+ * dma_selfirq_fn - callback for emulated/self IRQ events
+ * @dev: DMA device invoking the callback
+ * @data: opaque pointer provided at registration time
+ *
+ * Providers may invoke this callback from their interrupt handler when an
+ * emulated interrupt ("selfirq") might have occurred. The callback runs in
+ * hardirq context and must not sleep.
+ */
+typedef void (*dma_selfirq_fn)(struct dma_device *dev, void *data);
+
 /**
  * struct dma_device - info on the entity supplying DMA services
  * @ref: reference is taken and put every time a channel is allocated or freed
@@ -853,6 +864,10 @@ struct dma_filter {
  *	or an error code
  * @device_synchronize: Synchronizes the termination of a transfers to the
  *  current context.
+ * @device_register_selfirq: optional callback registration for
+ *	emulated/self IRQ events
+ * @device_unregister_selfirq: unregister previously registered selfirq
+ *	callback
  * @device_tx_status: poll for transaction completion, the optional
  *	txstate parameter can be supplied with a pointer to get a
  *	struct with auxiliary transfer status information, otherwise the call
@@ -951,6 +966,11 @@ struct dma_device {
 	int (*device_terminate_all)(struct dma_chan *chan);
 	void (*device_synchronize)(struct dma_chan *chan);
 
+	int (*device_register_selfirq)(struct dma_device *dev,
+				       dma_selfirq_fn fn, void *data);
+	void (*device_unregister_selfirq)(struct dma_device *dev,
+					  dma_selfirq_fn fn, void *data);
+
 	enum dma_status (*device_tx_status)(struct dma_chan *chan,
 					    dma_cookie_t cookie,
 					    struct dma_tx_state *txstate);
@@ -1197,6 +1217,56 @@ static inline void dmaengine_synchronize(struct dma_chan *chan)
 		chan->device->device_synchronize(chan);
 }
 
+/**
+ * dmaengine_register_selfirq() - Register a callback for emulated/self IRQ
+ *                                events
+ * @dev: DMA device
+ * @fn: callback invoked from the provider's IRQ handler
+ * @data: opaque callback data
+ *
+ * Some DMA controllers can raise an interrupt by software writing to a
+ * register without updating normal status bits. Providers may call
+ * registered callbacks from their interrupt handler when such events may
+ * have occurred.
+ * Callbacks are invoked in hardirq context and must not sleep.
+ *
+ * Return: 0 on success, -EOPNOTSUPP if unsupported, -EINVAL on bad args,
+ * or provider-specific -errno.
+ */
+static inline int dmaengine_register_selfirq(struct dma_device *dev,
+					     dma_selfirq_fn fn, void *data)
+{
+	if (!dev || !fn)
+		return -EINVAL;
+	if (!dev->device_register_selfirq)
+		return -EOPNOTSUPP;
+
+	return dev->device_register_selfirq(dev, fn, data);
+}
+
+/**
+ * dmaengine_unregister_selfirq() - Unregister a previously registered
+ *                                  selfirq callback
+ * @dev: DMA device
+ * @fn: callback pointer used at registration time
+ * @data: opaque pointer used at registration time
+ *
+ * Unregister a callback previously registered via
+ * dmaengine_register_selfirq(). Providers may synchronize against
+ * in-flight callbacks, therefore this function may sleep and must not be
+ * called from atomic context.
+ */
+static inline void dmaengine_unregister_selfirq(struct dma_device *dev,
+						dma_selfirq_fn fn, void *data)
+{
+	if (!dev || !fn)
+		return;
+	if (!dev->device_unregister_selfirq)
+		return;
+
+	dev->device_unregister_selfirq(dev, fn, data);
+}
+
 /**
  * dmaengine_terminate_sync() - Terminate all active DMA transfers
  * @chan: The channel for which to terminate the transfers
-- 
2.51.0


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

* [PATCH v3 05/11] dmaengine: dw-edma: Implement dmaengine selfirq callbacks using interrupt emulation
  2026-02-04 14:54 [PATCH v3 00/11] dmaengine, PCI: endpoint: Enable remote use of integrated DesignWare eDMA Koichiro Den
                   ` (3 preceding siblings ...)
  2026-02-04 14:54 ` [PATCH v3 04/11] dmaengine: Add selfirq callback registration API Koichiro Den
@ 2026-02-04 14:54 ` Koichiro Den
  2026-02-04 14:54 ` [PATCH v3 06/11] PCI: endpoint: Add remote resource query API Koichiro Den
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 32+ messages in thread
From: Koichiro Den @ 2026-02-04 14:54 UTC (permalink / raw)
  To: vkoul, mani, Frank.Li, jingoohan1, lpieralisi, kwilczynski, robh,
	bhelgaas
  Cc: dmaengine, linux-pci, linux-kernel

DesignWare eDMA can generate an interrupt when software writes to the
WR_DONE_INT_STATUS / RD_DONE_INT_STATUS registers without setting the
normal DONE/ABORT status bits. This behavior can be used as a
lightweight doorbell for remote DMA use cases.

Implement the dmaengine selfirq registration callbacks for dw-edma, and
ACK emulated interrupts in the eDMA v0 core by writing 0 to INT_CLEAR.

Because interrupt emulation does not set any DONE/ABORT status bits,
dw-edma cannot reliably tell whether an IRQ was raised solely due to
normal DMA completion or whether an emulated selfirq was also raised
around the same time. As a result, selfirq callbacks are invoked on
every IRQ.

Note that dw-hdma-v0 does not implement the ACK path yet due to lack of
hardware access.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
 drivers/dma/dw-edma/dw-edma-core.c    | 118 ++++++++++++++++++++++++--
 drivers/dma/dw-edma/dw-edma-core.h    |  17 ++++
 drivers/dma/dw-edma/dw-edma-v0-core.c |  11 +++
 3 files changed, 141 insertions(+), 5 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index b4cb02d545bd..398328b0a753 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -15,6 +15,7 @@
 #include <linux/irq.h>
 #include <linux/dma/edma.h>
 #include <linux/dma-mapping.h>
+#include <linux/rculist.h>
 #include <linux/string_choices.h>
 
 #include "dw-edma-core.h"
@@ -687,7 +688,30 @@ static void dw_edma_abort_interrupt(struct dw_edma_chan *chan)
 	chan->status = EDMA_ST_IDLE;
 }
 
-static inline irqreturn_t dw_edma_interrupt_write(int irq, void *data)
+static inline irqreturn_t dw_edma_interrupt_emulated(void *data)
+{
+	struct dw_edma_irq *dw_irq = data;
+	struct dw_edma *dw = dw_irq->dw;
+	struct dw_edma_selfirq *h;
+
+	/*
+	 * eDMA interrupt emulation does not set DONE/ABORT status bits, so
+	 * a shared IRQ handler cannot reliably tell whether or not the
+	 * emulated interrupt has been raised when the status bits are
+	 * non-zero. Invoke selfirq callbacks on every IRQ and always claim
+	 * the interrupt.
+	 */
+	dw_edma_core_ack_selfirq(dw);
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(h, &dw->selfirq_handlers, node)
+		h->fn(&dw->dma, h->data);
+	rcu_read_unlock();
+
+	return IRQ_HANDLED;
+}
+
+static inline irqreturn_t dw_edma_interrupt_write_inner(int irq, void *data)
 {
 	struct dw_edma_irq *dw_irq = data;
 
@@ -696,7 +720,7 @@ static inline irqreturn_t dw_edma_interrupt_write(int irq, void *data)
 				       dw_edma_abort_interrupt);
 }
 
-static inline irqreturn_t dw_edma_interrupt_read(int irq, void *data)
+static inline irqreturn_t dw_edma_interrupt_read_inner(int irq, void *data)
 {
 	struct dw_edma_irq *dw_irq = data;
 
@@ -705,12 +729,33 @@ static inline irqreturn_t dw_edma_interrupt_read(int irq, void *data)
 				       dw_edma_abort_interrupt);
 }
 
-static irqreturn_t dw_edma_interrupt_common(int irq, void *data)
+static inline irqreturn_t dw_edma_interrupt_write(int irq, void *data)
+{
+	irqreturn_t ret = IRQ_NONE;
+
+	ret |= dw_edma_interrupt_write_inner(irq, data);
+	ret |= dw_edma_interrupt_emulated(data);
+
+	return ret;
+}
+
+static inline irqreturn_t dw_edma_interrupt_read(int irq, void *data)
+{
+	irqreturn_t ret = IRQ_NONE;
+
+	ret |= dw_edma_interrupt_read_inner(irq, data);
+	ret |= dw_edma_interrupt_emulated(data);
+
+	return ret;
+}
+
+static inline irqreturn_t dw_edma_interrupt_common(int irq, void *data)
 {
 	irqreturn_t ret = IRQ_NONE;
 
-	ret |= dw_edma_interrupt_write(irq, data);
-	ret |= dw_edma_interrupt_read(irq, data);
+	ret |= dw_edma_interrupt_write_inner(irq, data);
+	ret |= dw_edma_interrupt_read_inner(irq, data);
+	ret |= dw_edma_interrupt_emulated(data);
 
 	return ret;
 }
@@ -742,6 +787,63 @@ static void dw_edma_free_chan_resources(struct dma_chan *dchan)
 	}
 }
 
+static inline struct dw_edma *to_dw_edma(struct dma_device *ddev)
+{
+	return container_of(ddev, struct dw_edma, dma);
+}
+
+static int dw_edma_register_selfirq(struct dma_device *ddev, dma_selfirq_fn fn,
+				    void *data)
+{
+	struct dw_edma *dw = to_dw_edma(ddev);
+	struct dw_edma_selfirq *h, *iter;
+	unsigned long flags;
+
+	if (!dw || !fn)
+		return -EINVAL;
+
+	h = kzalloc(sizeof(*h), GFP_KERNEL);
+	if (!h)
+		return -ENOMEM;
+	h->fn = fn;
+	h->data = data;
+
+	spin_lock_irqsave(&dw->selfirq_lock, flags);
+	list_for_each_entry(iter, &dw->selfirq_handlers, node) {
+		if (iter->fn == fn && iter->data == data) {
+			spin_unlock_irqrestore(&dw->selfirq_lock, flags);
+			kfree(h);
+			return -EEXIST;
+		}
+	}
+	list_add_tail_rcu(&h->node, &dw->selfirq_handlers);
+	spin_unlock_irqrestore(&dw->selfirq_lock, flags);
+	return 0;
+}
+
+static void dw_edma_unregister_selfirq(struct dma_device *ddev, dma_selfirq_fn fn,
+				       void *data)
+{
+	struct dw_edma *dw = to_dw_edma(ddev);
+	struct dw_edma_selfirq *h;
+	unsigned long flags;
+
+	if (!dw || !fn)
+		return;
+
+	spin_lock_irqsave(&dw->selfirq_lock, flags);
+	list_for_each_entry(h, &dw->selfirq_handlers, node) {
+		if (h->fn == fn && h->data == data) {
+			list_del_rcu(&h->node);
+			spin_unlock_irqrestore(&dw->selfirq_lock, flags);
+			synchronize_rcu();
+			kfree(h);
+			return;
+		}
+	}
+	spin_unlock_irqrestore(&dw->selfirq_lock, flags);
+}
+
 static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)
 {
 	struct dw_edma_chip *chip = dw->chip;
@@ -846,6 +948,10 @@ static int dw_edma_channel_setup(struct dw_edma *dw, u32 wr_alloc, u32 rd_alloc)
 
 	dma_set_max_seg_size(dma->dev, U32_MAX);
 
+	/* Set DMA device callbacks */
+	dma->device_register_selfirq = dw_edma_register_selfirq;
+	dma->device_unregister_selfirq = dw_edma_unregister_selfirq;
+
 	/* Register DMA device */
 	return dma_async_device_register(dma);
 }
@@ -959,6 +1065,8 @@ int dw_edma_probe(struct dw_edma_chip *chip)
 		return -ENOMEM;
 
 	dw->chip = chip;
+	INIT_LIST_HEAD(&dw->selfirq_handlers);
+	spin_lock_init(&dw->selfirq_lock);
 
 	if (dw->chip->mf == EDMA_MF_HDMA_NATIVE)
 		dw_hdma_v0_core_register(dw);
diff --git a/drivers/dma/dw-edma/dw-edma-core.h b/drivers/dma/dw-edma/dw-edma-core.h
index 0608b9044a08..4b9c4b28b49b 100644
--- a/drivers/dma/dw-edma/dw-edma-core.h
+++ b/drivers/dma/dw-edma/dw-edma-core.h
@@ -97,6 +97,12 @@ struct dw_edma_irq {
 	struct dw_edma			*dw;
 };
 
+struct dw_edma_selfirq {
+	struct list_head		node;
+	dma_selfirq_fn			fn;
+	void				*data;
+};
+
 struct dw_edma {
 	char				name[32];
 
@@ -115,6 +121,9 @@ struct dw_edma {
 	struct dw_edma_chip             *chip;
 
 	const struct dw_edma_core_ops	*core;
+
+	struct list_head		selfirq_handlers;
+	spinlock_t			selfirq_lock;
 };
 
 typedef void (*dw_edma_handler_t)(struct dw_edma_chan *);
@@ -128,6 +137,7 @@ struct dw_edma_core_ops {
 	void (*start)(struct dw_edma_chunk *chunk, bool first);
 	void (*ch_config)(struct dw_edma_chan *chan);
 	void (*debugfs_on)(struct dw_edma *dw);
+	void (*ack_selfirq)(struct dw_edma *dw);
 };
 
 struct dw_edma_sg {
@@ -208,6 +218,13 @@ void dw_edma_core_debugfs_on(struct dw_edma *dw)
 	dw->core->debugfs_on(dw);
 }
 
+static inline
+void dw_edma_core_ack_selfirq(struct dw_edma *dw)
+{
+	if (dw->core->ack_selfirq)
+		dw->core->ack_selfirq(dw);
+}
+
 static inline
 bool dw_edma_core_ch_ignore_irq(struct dw_edma_chan *chan)
 {
diff --git a/drivers/dma/dw-edma/dw-edma-v0-core.c b/drivers/dma/dw-edma/dw-edma-v0-core.c
index a0441e8aa3b3..68e0d088570d 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
@@ -519,6 +519,16 @@ static void dw_edma_v0_core_debugfs_on(struct dw_edma *dw)
 	dw_edma_v0_debugfs_on(dw);
 }
 
+static void dw_edma_v0_core_ack_selfirq(struct dw_edma *dw)
+{
+	/*
+	 * Interrupt emulation may assert the IRQ without setting
+	 * DONE/ABORT status bits. A zero write to INT_CLEAR deasserts the
+	 * emulated IRQ, while being a no-op for real interrupts.
+	 */
+	SET_BOTH_32(dw, int_clear, 0);
+}
+
 static const struct dw_edma_core_ops dw_edma_v0_core = {
 	.off = dw_edma_v0_core_off,
 	.ch_count = dw_edma_v0_core_ch_count,
@@ -527,6 +537,7 @@ static const struct dw_edma_core_ops dw_edma_v0_core = {
 	.start = dw_edma_v0_core_start,
 	.ch_config = dw_edma_v0_core_ch_config,
 	.debugfs_on = dw_edma_v0_core_debugfs_on,
+	.ack_selfirq = dw_edma_v0_core_ack_selfirq,
 };
 
 void dw_edma_v0_core_register(struct dw_edma *dw)
-- 
2.51.0


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

* [PATCH v3 06/11] PCI: endpoint: Add remote resource query API
  2026-02-04 14:54 [PATCH v3 00/11] dmaengine, PCI: endpoint: Enable remote use of integrated DesignWare eDMA Koichiro Den
                   ` (4 preceding siblings ...)
  2026-02-04 14:54 ` [PATCH v3 05/11] dmaengine: dw-edma: Implement dmaengine selfirq callbacks using interrupt emulation Koichiro Den
@ 2026-02-04 14:54 ` Koichiro Den
  2026-02-04 17:55   ` Frank Li
  2026-02-04 14:54 ` [PATCH v3 07/11] PCI: dwc: Record integrated eDMA register window Koichiro Den
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 32+ messages in thread
From: Koichiro Den @ 2026-02-04 14:54 UTC (permalink / raw)
  To: vkoul, mani, Frank.Li, jingoohan1, lpieralisi, kwilczynski, robh,
	bhelgaas
  Cc: dmaengine, linux-pci, linux-kernel

Endpoint controller drivers may integrate auxiliary blocks (e.g. DMA
engines) whose register windows and descriptor memories metadata need to
be exposed to a remote peer. Endpoint function drivers need a generic
way to discover such resources without hard-coding controller-specific
helpers.

Add pci_epc_get_remote_resources() and the corresponding pci_epc_ops
get_remote_resources() callback. The API returns a list of resources
described by type, physical address and size, plus type-specific
metadata.

Passing resources == NULL (or num_resources == 0) returns the required
number of entries.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
 drivers/pci/endpoint/pci-epc-core.c | 41 +++++++++++++++++++++++++
 include/linux/pci-epc.h             | 46 +++++++++++++++++++++++++++++
 2 files changed, 87 insertions(+)

diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
index 068155819c57..fa161113e24c 100644
--- a/drivers/pci/endpoint/pci-epc-core.c
+++ b/drivers/pci/endpoint/pci-epc-core.c
@@ -155,6 +155,47 @@ const struct pci_epc_features *pci_epc_get_features(struct pci_epc *epc,
 }
 EXPORT_SYMBOL_GPL(pci_epc_get_features);
 
+/**
+ * pci_epc_get_remote_resources() - query EPC-provided remote resources
+ * @epc: EPC device
+ * @func_no: function number
+ * @vfunc_no: virtual function number
+ * @resources: output array (may be NULL to query required count)
+ * @num_resources: size of @resources array in entries (0 when querying count)
+ *
+ * Some EPC backends integrate auxiliary blocks (e.g. DMA engines) whose control
+ * registers and/or descriptor memories can be exposed to the host by mapping
+ * them into BAR space. This helper queries the backend for such resources.
+ *
+ * Return:
+ *   * >= 0: number of resources returned (or required, if @resources is NULL)
+ *   * -EOPNOTSUPP: backend does not support remote resource queries
+ *   * other -errno on failure
+ */
+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)
+{
+	int ret;
+
+	if (!epc || !epc->ops)
+		return -EINVAL;
+
+	if (func_no >= epc->max_functions)
+		return -EINVAL;
+
+	if (!epc->ops->get_remote_resources)
+		return -EOPNOTSUPP;
+
+	mutex_lock(&epc->lock);
+	ret = epc->ops->get_remote_resources(epc, func_no, vfunc_no,
+					     resources, num_resources);
+	mutex_unlock(&epc->lock);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(pci_epc_get_remote_resources);
+
 /**
  * pci_epc_stop() - stop the PCI link
  * @epc: the link of the EPC device that has to be stopped
diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
index c021c7af175f..af60d4ad2f0e 100644
--- a/include/linux/pci-epc.h
+++ b/include/linux/pci-epc.h
@@ -61,6 +61,44 @@ struct pci_epc_map {
 	void __iomem	*virt_addr;
 };
 
+/**
+ * enum pci_epc_remote_resource_type - remote resource type identifiers
+ * @PCI_EPC_RR_DMA_CTRL_MMIO: Integrated DMA controller register window (MMIO)
+ * @PCI_EPC_RR_DMA_CHAN_DESC: Per-channel DMA descriptor
+ *
+ * EPC backends may expose auxiliary blocks (e.g. DMA engines) by mapping their
+ * register windows and descriptor memories into BAR space. This enum
+ * identifies the type of each exposable resource.
+ */
+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
+ *
+ * For @PCI_EPC_RR_DMA_CHAN_DESC, @u.dma_chan_desc provides per-channel
+ * information.
+ */
+struct pci_epc_remote_resource {
+	enum pci_epc_remote_resource_type type;
+	phys_addr_t phys_addr;
+	resource_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 +122,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 +155,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 +352,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
-- 
2.51.0


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

* [PATCH v3 07/11] PCI: dwc: Record integrated eDMA register window
  2026-02-04 14:54 [PATCH v3 00/11] dmaengine, PCI: endpoint: Enable remote use of integrated DesignWare eDMA Koichiro Den
                   ` (5 preceding siblings ...)
  2026-02-04 14:54 ` [PATCH v3 06/11] PCI: endpoint: Add remote resource query API Koichiro Den
@ 2026-02-04 14:54 ` Koichiro Den
  2026-02-04 17:57   ` Frank Li
  2026-02-04 14:54 ` [PATCH v3 08/11] PCI: dwc: ep: Report integrated DWC eDMA remote resources Koichiro Den
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 32+ messages in thread
From: Koichiro Den @ 2026-02-04 14:54 UTC (permalink / raw)
  To: vkoul, mani, Frank.Li, jingoohan1, lpieralisi, kwilczynski, robh,
	bhelgaas
  Cc: dmaengine, linux-pci, linux-kernel

Some DesignWare PCIe controllers integrate an eDMA block whose registers
are located in a dedicated register window. Endpoint function drivers
may need the physical base and size of this window to map/expose it to a
peer.

Record the physical base and size of the integrated eDMA register window
in struct dw_pcie.

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

diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index 18331d9e85be..d97ad9d2aa9b 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -162,8 +162,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;
 		}
 	}
 
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 43d7606bc987..88e4a9e514e8 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -542,6 +542,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];
-- 
2.51.0


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

* [PATCH v3 08/11] PCI: dwc: ep: Report integrated DWC eDMA remote resources
  2026-02-04 14:54 [PATCH v3 00/11] dmaengine, PCI: endpoint: Enable remote use of integrated DesignWare eDMA Koichiro Den
                   ` (6 preceding siblings ...)
  2026-02-04 14:54 ` [PATCH v3 07/11] PCI: dwc: Record integrated eDMA register window Koichiro Den
@ 2026-02-04 14:54 ` Koichiro Den
  2026-02-04 18:06   ` Frank Li
  2026-02-04 14:54 ` [PATCH v3 09/11] PCI: endpoint: pci-epf-test: Add smoke test for EPC remote resource API Koichiro Den
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 32+ messages in thread
From: Koichiro Den @ 2026-02-04 14:54 UTC (permalink / raw)
  To: vkoul, mani, Frank.Li, jingoohan1, lpieralisi, kwilczynski, robh,
	bhelgaas
  Cc: dmaengine, linux-pci, linux-kernel

Implement pci_epc_ops.get_remote_resources() for the DesignWare PCIe
endpoint controller. Report:
- the integrated eDMA control MMIO window
- the per-channel linked-list regions for read/write engines

This allows endpoint function drivers to discover and map or inform
these resources to a remote peer using the generic EPC API.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
 .../pci/controller/dwc/pcie-designware-ep.c   | 74 +++++++++++++++++++
 1 file changed, 74 insertions(+)

diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
index 7e7844ff0f7e..5c0dcbf18d07 100644
--- a/drivers/pci/controller/dwc/pcie-designware-ep.c
+++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
@@ -808,6 +808,79 @@ dw_pcie_ep_get_features(struct pci_epc *epc, u8 func_no, u8 vfunc_no)
 	return ep->ops->get_features(ep);
 }
 
+static int
+dw_pcie_ep_get_remote_resources(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
+				struct pci_epc_remote_resource *resources,
+				int num_resources)
+{
+	struct dw_pcie_ep *ep = epc_get_drvdata(epc);
+	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
+	struct dw_edma_chip *edma = &pci->edma;
+	int ll_cnt = 0, needed, idx = 0;
+	resource_size_t dma_size;
+	phys_addr_t dma_phys;
+	unsigned int i;
+
+	if (!pci->edma_reg_size)
+		return 0;
+
+	dma_phys = pci->edma_reg_phys;
+	dma_size = pci->edma_reg_size;
+
+	for (i = 0; i < edma->ll_wr_cnt; i++)
+		if (edma->ll_region_wr[i].sz)
+			ll_cnt++;
+
+	for (i = 0; i < edma->ll_rd_cnt; i++)
+		if (edma->ll_region_rd[i].sz)
+			ll_cnt++;
+
+	needed = 1 + ll_cnt;
+
+	/* Count query mode */
+	if (!resources || !num_resources)
+		return needed;
+
+	if (num_resources < needed)
+		return -ENOSPC;
+
+	resources[idx++] = (struct pci_epc_remote_resource) {
+		.type = PCI_EPC_RR_DMA_CTRL_MMIO,
+		.phys_addr = dma_phys,
+		.size = dma_size,
+	};
+
+	/* One LL region per write channel */
+	for (i = 0; i < edma->ll_wr_cnt; i++) {
+		if (!edma->ll_region_wr[i].sz)
+			continue;
+
+		resources[idx++] = (struct pci_epc_remote_resource) {
+			.type = PCI_EPC_RR_DMA_CHAN_DESC,
+			.phys_addr = edma->ll_region_wr[i].paddr,
+			.size = edma->ll_region_wr[i].sz,
+			.u.dma_chan_desc.hw_chan_id = i,
+			.u.dma_chan_desc.ep2rc = true,
+		};
+	}
+
+	/* One LL region per read channel */
+	for (i = 0; i < edma->ll_rd_cnt; i++) {
+		if (!edma->ll_region_rd[i].sz)
+			continue;
+
+		resources[idx++] = (struct pci_epc_remote_resource) {
+			.type = PCI_EPC_RR_DMA_CHAN_DESC,
+			.phys_addr = edma->ll_region_rd[i].paddr,
+			.size = edma->ll_region_rd[i].sz,
+			.u.dma_chan_desc.hw_chan_id = i,
+			.u.dma_chan_desc.ep2rc = false,
+		};
+	}
+
+	return idx;
+}
+
 static const struct pci_epc_ops epc_ops = {
 	.write_header		= dw_pcie_ep_write_header,
 	.set_bar		= dw_pcie_ep_set_bar,
@@ -823,6 +896,7 @@ static const struct pci_epc_ops epc_ops = {
 	.start			= dw_pcie_ep_start,
 	.stop			= dw_pcie_ep_stop,
 	.get_features		= dw_pcie_ep_get_features,
+	.get_remote_resources	= dw_pcie_ep_get_remote_resources,
 };
 
 /**
-- 
2.51.0


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

* [PATCH v3 09/11] PCI: endpoint: pci-epf-test: Add smoke test for EPC remote resource API
  2026-02-04 14:54 [PATCH v3 00/11] dmaengine, PCI: endpoint: Enable remote use of integrated DesignWare eDMA Koichiro Den
                   ` (7 preceding siblings ...)
  2026-02-04 14:54 ` [PATCH v3 08/11] PCI: dwc: ep: Report integrated DWC eDMA remote resources Koichiro Den
@ 2026-02-04 14:54 ` Koichiro Den
  2026-02-04 19:37   ` Frank Li
                     ` (2 more replies)
  2026-02-04 14:54 ` [PATCH v3 10/11] misc: pci_endpoint_test: Add EPC remote resource API test ioctl Koichiro Den
  2026-02-04 14:54 ` [PATCH v3 11/11] selftests: pci_endpoint: Add EPC remote resource API test Koichiro Den
  10 siblings, 3 replies; 32+ messages in thread
From: Koichiro Den @ 2026-02-04 14:54 UTC (permalink / raw)
  To: vkoul, mani, Frank.Li, jingoohan1, lpieralisi, kwilczynski, robh,
	bhelgaas
  Cc: dmaengine, linux-pci, linux-kernel

Add a new pci-epf-test command that exercises the newly added EPC API
pci_epc_get_remote_resources().

The test is intentionally a smoke test. It verifies that the API either
returns -EOPNOTSUPP or a well-formed resource list (non-zero phys/size
and known resource types). The result is reported to the host via a
status bit and an interrupt, consistent with existing pci-epf-test
commands.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
 drivers/pci/endpoint/functions/pci-epf-test.c | 88 +++++++++++++++++++
 1 file changed, 88 insertions(+)

diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index 6952ee418622..6446a0a23865 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -35,6 +35,7 @@
 #define COMMAND_DISABLE_DOORBELL	BIT(7)
 #define COMMAND_BAR_SUBRANGE_SETUP	BIT(8)
 #define COMMAND_BAR_SUBRANGE_CLEAR	BIT(9)
+#define COMMAND_EPC_API			BIT(10)
 
 #define STATUS_READ_SUCCESS		BIT(0)
 #define STATUS_READ_FAIL		BIT(1)
@@ -54,6 +55,8 @@
 #define STATUS_BAR_SUBRANGE_SETUP_FAIL		BIT(15)
 #define STATUS_BAR_SUBRANGE_CLEAR_SUCCESS	BIT(16)
 #define STATUS_BAR_SUBRANGE_CLEAR_FAIL		BIT(17)
+#define STATUS_EPC_API_SUCCESS		BIT(18)
+#define STATUS_EPC_API_FAIL		BIT(19)
 
 #define FLAG_USE_DMA			BIT(0)
 
@@ -967,6 +970,87 @@ static void pci_epf_test_bar_subrange_clear(struct pci_epf_test *epf_test,
 	reg->status = cpu_to_le32(status);
 }
 
+static void pci_epf_test_epc_api(struct pci_epf_test *epf_test,
+				 struct pci_epf_test_reg *reg)
+{
+	struct pci_epc_remote_resource *resources = NULL;
+	u32 status = le32_to_cpu(reg->status);
+	struct pci_epf *epf = epf_test->epf;
+	struct device *dev = &epf->dev;
+	struct pci_epc *epc = epf->epc;
+	int num_resources;
+	int ret, i;
+
+	num_resources = pci_epc_get_remote_resources(epc, epf->func_no,
+						     epf->vfunc_no, NULL, 0);
+	if (num_resources == -EOPNOTSUPP || num_resources == 0)
+		goto out_success;
+	if (num_resources < 0)
+		goto err;
+
+	resources = kcalloc(num_resources, sizeof(*resources), GFP_KERNEL);
+	if (!resources)
+		goto err;
+
+	ret = pci_epc_get_remote_resources(epc, epf->func_no, epf->vfunc_no,
+					   resources, num_resources);
+	if (ret < 0) {
+		dev_err(dev, "EPC remote resource query failed: %d\n", ret);
+		goto err_free;
+	}
+	if (ret > num_resources) {
+		dev_err(dev, "EPC API returned %d resources (max %d)\n",
+			ret, num_resources);
+		goto err_free;
+	}
+
+	for (i = 0; i < ret; i++) {
+		struct pci_epc_remote_resource *res = &resources[i];
+
+		if (!res->phys_addr || !res->size) {
+			dev_err(dev,
+				"Invalid remote resource[%d] (type=%d phys=%pa size=%llu)\n",
+				i, res->type, &res->phys_addr, res->size);
+			goto err_free;
+		}
+
+		/* Guard against address overflow */
+		if (res->phys_addr + res->size < res->phys_addr) {
+			dev_err(dev,
+				"Remote resource[%d] overflow (phys=%pa size=%llu)\n",
+				i, &res->phys_addr, res->size);
+			goto err_free;
+		}
+
+		switch (res->type) {
+		case PCI_EPC_RR_DMA_CTRL_MMIO:
+			/* Generic checks above are sufficient. */
+			break;
+		case PCI_EPC_RR_DMA_CHAN_DESC:
+			/*
+			 * hw_chan_id and ep2rc are informational. No extra validation
+			 * beyond the generic checks above is needed.
+			 */
+			break;
+		default:
+			dev_err(dev, "Unknown remote resource type %d\n", res->type);
+			goto err_free;
+		}
+	}
+
+out_success:
+	kfree(resources);
+	status |= STATUS_EPC_API_SUCCESS;
+	reg->status = cpu_to_le32(status);
+	return;
+
+err_free:
+	kfree(resources);
+err:
+	status |= STATUS_EPC_API_FAIL;
+	reg->status = cpu_to_le32(status);
+}
+
 static void pci_epf_test_cmd_handler(struct work_struct *work)
 {
 	u32 command;
@@ -1030,6 +1114,10 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
 		pci_epf_test_bar_subrange_clear(epf_test, reg);
 		pci_epf_test_raise_irq(epf_test, reg);
 		break;
+	case COMMAND_EPC_API:
+		pci_epf_test_epc_api(epf_test, reg);
+		pci_epf_test_raise_irq(epf_test, reg);
+		break;
 	default:
 		dev_err(dev, "Invalid command 0x%x\n", command);
 		break;
-- 
2.51.0


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

* [PATCH v3 10/11] misc: pci_endpoint_test: Add EPC remote resource API test ioctl
  2026-02-04 14:54 [PATCH v3 00/11] dmaengine, PCI: endpoint: Enable remote use of integrated DesignWare eDMA Koichiro Den
                   ` (8 preceding siblings ...)
  2026-02-04 14:54 ` [PATCH v3 09/11] PCI: endpoint: pci-epf-test: Add smoke test for EPC remote resource API Koichiro Den
@ 2026-02-04 14:54 ` Koichiro Den
  2026-02-04 14:54 ` [PATCH v3 11/11] selftests: pci_endpoint: Add EPC remote resource API test Koichiro Den
  10 siblings, 0 replies; 32+ messages in thread
From: Koichiro Den @ 2026-02-04 14:54 UTC (permalink / raw)
  To: vkoul, mani, Frank.Li, jingoohan1, lpieralisi, kwilczynski, robh,
	bhelgaas
  Cc: dmaengine, linux-pci, linux-kernel

Add a new PCI endpoint test ioctl, PCITEST_EPC_API, to trigger the
pci-epf-test EPC API smoke test from the host.

The ioctl requests the endpoint to run the test, waits for completion,
and returns success/failure to userspace. This is used by kselftests.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
 drivers/misc/pci_endpoint_test.c | 49 ++++++++++++++++++++++++++++++++
 include/uapi/linux/pcitest.h     |  1 +
 2 files changed, 50 insertions(+)

diff --git a/drivers/misc/pci_endpoint_test.c b/drivers/misc/pci_endpoint_test.c
index 74ab5b5b9011..4be21e37353b 100644
--- a/drivers/misc/pci_endpoint_test.c
+++ b/drivers/misc/pci_endpoint_test.c
@@ -41,6 +41,7 @@
 #define COMMAND_DISABLE_DOORBELL		BIT(7)
 #define COMMAND_BAR_SUBRANGE_SETUP		BIT(8)
 #define COMMAND_BAR_SUBRANGE_CLEAR		BIT(9)
+#define COMMAND_EPC_API				BIT(10)
 
 #define PCI_ENDPOINT_TEST_STATUS		0x8
 #define STATUS_READ_SUCCESS			BIT(0)
@@ -61,6 +62,8 @@
 #define STATUS_BAR_SUBRANGE_SETUP_FAIL		BIT(15)
 #define STATUS_BAR_SUBRANGE_CLEAR_SUCCESS	BIT(16)
 #define STATUS_BAR_SUBRANGE_CLEAR_FAIL		BIT(17)
+#define STATUS_EPC_API_SUCCESS			BIT(18)
+#define STATUS_EPC_API_FAIL			BIT(19)
 
 #define PCI_ENDPOINT_TEST_LOWER_SRC_ADDR	0x0c
 #define PCI_ENDPOINT_TEST_UPPER_SRC_ADDR	0x10
@@ -1117,6 +1120,49 @@ static int pci_endpoint_test_doorbell(struct pci_endpoint_test *test)
 	return 0;
 }
 
+static int pci_endpoint_test_epc_api(struct pci_endpoint_test *test)
+{
+	struct pci_dev *pdev = test->pdev;
+	struct device *dev = &pdev->dev;
+	int irq_type = test->irq_type;
+	u32 status;
+
+	if (irq_type < PCITEST_IRQ_TYPE_INTX ||
+	    irq_type > PCITEST_IRQ_TYPE_MSIX) {
+		dev_err(dev, "Invalid IRQ type\n");
+		return -EINVAL;
+	}
+
+	reinit_completion(&test->irq_raised);
+	/* EPC API smoke test is executed on the endpoint side. */
+	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_STATUS, 0);
+	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE, irq_type);
+	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 1);
+	pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
+				 COMMAND_EPC_API);
+
+	if (!wait_for_completion_timeout(&test->irq_raised,
+					 msecs_to_jiffies(1000))) {
+		dev_err(dev, "Timed out waiting for EPC API test\n");
+		return -ETIMEDOUT;
+	}
+
+	status = pci_endpoint_test_readl(test, PCI_ENDPOINT_TEST_STATUS);
+	if (status & STATUS_EPC_API_FAIL) {
+		dev_err(dev, "EPC API test failed (status=%#x)\n", status);
+		return -EIO;
+	}
+
+	if (!(status & STATUS_EPC_API_SUCCESS)) {
+		dev_err(dev,
+			"EPC API test did not report success (status=%#x)\n",
+			status);
+		return -EIO;
+	}
+
+	return 0;
+}
+
 static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
 				    unsigned long arg)
 {
@@ -1175,6 +1221,9 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
 	case PCITEST_DOORBELL:
 		ret = pci_endpoint_test_doorbell(test);
 		break;
+	case PCITEST_EPC_API:
+		ret = pci_endpoint_test_epc_api(test);
+		break;
 	}
 
 ret:
diff --git a/include/uapi/linux/pcitest.h b/include/uapi/linux/pcitest.h
index 710f8842223f..29491f85b964 100644
--- a/include/uapi/linux/pcitest.h
+++ b/include/uapi/linux/pcitest.h
@@ -23,6 +23,7 @@
 #define PCITEST_BARS		_IO('P', 0xa)
 #define PCITEST_DOORBELL	_IO('P', 0xb)
 #define PCITEST_BAR_SUBRANGE	_IO('P', 0xc)
+#define PCITEST_EPC_API		_IO('P', 0xd)
 #define PCITEST_CLEAR_IRQ	_IO('P', 0x10)
 
 #define PCITEST_IRQ_TYPE_UNDEFINED	-1
-- 
2.51.0


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

* [PATCH v3 11/11] selftests: pci_endpoint: Add EPC remote resource API test
  2026-02-04 14:54 [PATCH v3 00/11] dmaengine, PCI: endpoint: Enable remote use of integrated DesignWare eDMA Koichiro Den
                   ` (9 preceding siblings ...)
  2026-02-04 14:54 ` [PATCH v3 10/11] misc: pci_endpoint_test: Add EPC remote resource API test ioctl Koichiro Den
@ 2026-02-04 14:54 ` Koichiro Den
  10 siblings, 0 replies; 32+ messages in thread
From: Koichiro Den @ 2026-02-04 14:54 UTC (permalink / raw)
  To: vkoul, mani, Frank.Li, jingoohan1, lpieralisi, kwilczynski, robh,
	bhelgaas
  Cc: dmaengine, linux-pci, linux-kernel

Add a new pci_endpoint kselftest that runs the EPC remote resource API
smoke test through PCITEST_EPC_API.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
 .../pci_endpoint/pci_endpoint_test.c          | 28 +++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/tools/testing/selftests/pci_endpoint/pci_endpoint_test.c b/tools/testing/selftests/pci_endpoint/pci_endpoint_test.c
index eecb776c33af..0904d262c084 100644
--- a/tools/testing/selftests/pci_endpoint/pci_endpoint_test.c
+++ b/tools/testing/selftests/pci_endpoint/pci_endpoint_test.c
@@ -278,4 +278,32 @@ TEST_F(pcie_ep_doorbell, DOORBELL_TEST)
 	pci_ep_ioctl(PCITEST_DOORBELL, 0);
 	EXPECT_FALSE(ret) TH_LOG("Test failed for Doorbell\n");
 }
+
+FIXTURE(pci_ep_api)
+{
+	int fd;
+};
+
+FIXTURE_SETUP(pci_ep_api)
+{
+	self->fd = open(test_device, O_RDWR);
+
+	ASSERT_NE(-1, self->fd) TH_LOG("Can't open PCI Endpoint Test device");
+}
+
+FIXTURE_TEARDOWN(pci_ep_api)
+{
+	close(self->fd);
+}
+
+TEST_F(pci_ep_api, EPC_API_TEST)
+{
+	int ret;
+
+	pci_ep_ioctl(PCITEST_SET_IRQTYPE, PCITEST_IRQ_TYPE_AUTO);
+	ASSERT_EQ(0, ret) TH_LOG("Can't set AUTO IRQ type");
+
+	pci_ep_ioctl(PCITEST_EPC_API, 0);
+	EXPECT_FALSE(ret) TH_LOG("EPC API test failed");
+}
 TEST_HARNESS_MAIN
-- 
2.51.0


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

* Re: [PATCH v3 03/11] dmaengine: dw-edma: Add per-channel interrupt routing control
  2026-02-04 14:54 ` [PATCH v3 03/11] dmaengine: dw-edma: Add per-channel interrupt routing control Koichiro Den
@ 2026-02-04 17:42   ` Frank Li
  2026-02-05  6:48     ` Koichiro Den
  0 siblings, 1 reply; 32+ messages in thread
From: Frank Li @ 2026-02-04 17:42 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 11:54:31PM +0900, Koichiro Den wrote:
> 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.
>
> For now, HDMA is not supported for the peripheral_config. Until the
> support is implemented and validated, explicitly reject it for HDMA to
> avoid silently misconfiguring interrupt routing.
>
> Signed-off-by: Koichiro Den <den@valinux.co.jp>
> ---
>  drivers/dma/dw-edma/dw-edma-core.c    | 24 +++++++++++++++++++++++
>  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, 83 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..b4cb02d545bd 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -224,6 +224,29 @@ 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 (chan->dw->chip->mf == EDMA_MF_HDMA_NATIVE)
> +			return -EOPNOTSUPP;
> +
> +		if (config->peripheral_size < sizeof(*pcfg))
> +			return -EINVAL;

It is good to check here.

> +
> +		pcfg = config->peripheral_config;

save whole peripheral_config in case need more special peripheral
configuration in future.

> +		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;
> +		}
> +	}

use helper function to get irq_mode. I posted combine config and prep by
one call.

https://lore.kernel.org/dmaengine/20260105-dma_prep_config-v3-0-a8480362fd42@nxp.com/

So we use such helper to get irq node after above patch merge. It is not
big deal, I can change it later. If provide helper funtions, it will be
slice better.

>
>  	memcpy(&chan->config, config, sizeof(*config));
>  	chan->configured = true;
> @@ -750,6 +773,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);
...
>
> +/*
> + * 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

keep consistent after "," for each enum

Frank

> + * @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] 32+ messages in thread

* Re: [PATCH v3 04/11] dmaengine: Add selfirq callback registration API
  2026-02-04 14:54 ` [PATCH v3 04/11] dmaengine: Add selfirq callback registration API Koichiro Den
@ 2026-02-04 17:46   ` Frank Li
  2026-02-05  6:50     ` Koichiro Den
  0 siblings, 1 reply; 32+ messages in thread
From: Frank Li @ 2026-02-04 17:46 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 11:54:32PM +0900, Koichiro Den wrote:
> Some DMA controllers can generate an interrupt by software writing to a
> register, without updating the normal interrupt status bits. This can be
> used as a doorbell mechanism when the DMA engine is remotely programmed,
> or for self-tests.
>
> Add an optional per-DMA-device API to register/unregister callbacks for
> such "selfirq" events. Providers may invoke these callbacks from their
> interrupt handler when they detect an emulated interrupt.
>
> Callbacks are invoked in hardirq context and must not sleep.

Is it possible register shared irq handle with the same channel's irq
number?

Frank

>
> Signed-off-by: Koichiro Den <den@valinux.co.jp>
> ---
>  include/linux/dmaengine.h | 70 +++++++++++++++++++++++++++++++++++++++
>  1 file changed, 70 insertions(+)
>
> diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> index 71bc2674567f..9c6194e8bfe1 100644
> --- a/include/linux/dmaengine.h
> +++ b/include/linux/dmaengine.h
> @@ -785,6 +785,17 @@ struct dma_filter {
>  	const struct dma_slave_map *map;
>  };
>
> +/**
> + * dma_selfirq_fn - callback for emulated/self IRQ events
> + * @dev: DMA device invoking the callback
> + * @data: opaque pointer provided at registration time
> + *
> + * Providers may invoke this callback from their interrupt handler when an
> + * emulated interrupt ("selfirq") might have occurred. The callback runs in
> + * hardirq context and must not sleep.
> + */
> +typedef void (*dma_selfirq_fn)(struct dma_device *dev, void *data);
> +
>  /**
>   * struct dma_device - info on the entity supplying DMA services
>   * @ref: reference is taken and put every time a channel is allocated or freed
> @@ -853,6 +864,10 @@ struct dma_filter {
>   *	or an error code
>   * @device_synchronize: Synchronizes the termination of a transfers to the
>   *  current context.
> + * @device_register_selfirq: optional callback registration for
> + *	emulated/self IRQ events
> + * @device_unregister_selfirq: unregister previously registered selfirq
> + *	callback
>   * @device_tx_status: poll for transaction completion, the optional
>   *	txstate parameter can be supplied with a pointer to get a
>   *	struct with auxiliary transfer status information, otherwise the call
> @@ -951,6 +966,11 @@ struct dma_device {
>  	int (*device_terminate_all)(struct dma_chan *chan);
>  	void (*device_synchronize)(struct dma_chan *chan);
>
> +	int (*device_register_selfirq)(struct dma_device *dev,
> +				       dma_selfirq_fn fn, void *data);
> +	void (*device_unregister_selfirq)(struct dma_device *dev,
> +					  dma_selfirq_fn fn, void *data);
> +
>  	enum dma_status (*device_tx_status)(struct dma_chan *chan,
>  					    dma_cookie_t cookie,
>  					    struct dma_tx_state *txstate);
> @@ -1197,6 +1217,56 @@ static inline void dmaengine_synchronize(struct dma_chan *chan)
>  		chan->device->device_synchronize(chan);
>  }
>
> +/**
> + * dmaengine_register_selfirq() - Register a callback for emulated/self IRQ
> + *                                events
> + * @dev: DMA device
> + * @fn: callback invoked from the provider's IRQ handler
> + * @data: opaque callback data
> + *
> + * Some DMA controllers can raise an interrupt by software writing to a
> + * register without updating normal status bits. Providers may call
> + * registered callbacks from their interrupt handler when such events may
> + * have occurred.
> + * Callbacks are invoked in hardirq context and must not sleep.
> + *
> + * Return: 0 on success, -EOPNOTSUPP if unsupported, -EINVAL on bad args,
> + * or provider-specific -errno.
> + */
> +static inline int dmaengine_register_selfirq(struct dma_device *dev,
> +					     dma_selfirq_fn fn, void *data)
> +{
> +	if (!dev || !fn)
> +		return -EINVAL;
> +	if (!dev->device_register_selfirq)
> +		return -EOPNOTSUPP;
> +
> +	return dev->device_register_selfirq(dev, fn, data);
> +}
> +
> +/**
> + * dmaengine_unregister_selfirq() - Unregister a previously registered
> + *                                  selfirq callback
> + * @dev: DMA device
> + * @fn: callback pointer used at registration time
> + * @data: opaque pointer used at registration time
> + *
> + * Unregister a callback previously registered via
> + * dmaengine_register_selfirq(). Providers may synchronize against
> + * in-flight callbacks, therefore this function may sleep and must not be
> + * called from atomic context.
> + */
> +static inline void dmaengine_unregister_selfirq(struct dma_device *dev,
> +						dma_selfirq_fn fn, void *data)
> +{
> +	if (!dev || !fn)
> +		return;
> +	if (!dev->device_unregister_selfirq)
> +		return;
> +
> +	dev->device_unregister_selfirq(dev, fn, data);
> +}
> +
>  /**
>   * dmaengine_terminate_sync() - Terminate all active DMA transfers
>   * @chan: The channel for which to terminate the transfers
> --
> 2.51.0
>

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

* Re: [PATCH v3 06/11] PCI: endpoint: Add remote resource query API
  2026-02-04 14:54 ` [PATCH v3 06/11] PCI: endpoint: Add remote resource query API Koichiro Den
@ 2026-02-04 17:55   ` Frank Li
  2026-02-05  6:53     ` Koichiro Den
  0 siblings, 1 reply; 32+ messages in thread
From: Frank Li @ 2026-02-04 17:55 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 11:54:34PM +0900, Koichiro Den wrote:
> Endpoint controller drivers may integrate auxiliary blocks (e.g. DMA
> engines) whose register windows and descriptor memories metadata need to
> be exposed to a remote peer. Endpoint function drivers need a generic
> way to discover such resources without hard-coding controller-specific
> helpers.
>
> Add pci_epc_get_remote_resources() and the corresponding pci_epc_ops
> get_remote_resources() callback. The API returns a list of resources
> described by type, physical address and size, plus type-specific
> metadata.
>
> Passing resources == NULL (or num_resources == 0) returns the required
> number of entries.
>
> Signed-off-by: Koichiro Den <den@valinux.co.jp>
> ---
>  drivers/pci/endpoint/pci-epc-core.c | 41 +++++++++++++++++++++++++
>  include/linux/pci-epc.h             | 46 +++++++++++++++++++++++++++++
>  2 files changed, 87 insertions(+)
>
> diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
> index 068155819c57..fa161113e24c 100644
> --- a/drivers/pci/endpoint/pci-epc-core.c
> +++ b/drivers/pci/endpoint/pci-epc-core.c
> @@ -155,6 +155,47 @@ const struct pci_epc_features *pci_epc_get_features(struct pci_epc *epc,
>  }
>  EXPORT_SYMBOL_GPL(pci_epc_get_features);
>
> +/**
> + * pci_epc_get_remote_resources() - query EPC-provided remote resources
> + * @epc: EPC device
> + * @func_no: function number
> + * @vfunc_no: virtual function number
> + * @resources: output array (may be NULL to query required count)
> + * @num_resources: size of @resources array in entries (0 when querying count)
> + *
> + * Some EPC backends integrate auxiliary blocks (e.g. DMA engines) whose control
> + * registers and/or descriptor memories can be exposed to the host by mapping
> + * them into BAR space. This helper queries the backend for such resources.
> + *
> + * Return:
> + *   * >= 0: number of resources returned (or required, if @resources is NULL)
> + *   * -EOPNOTSUPP: backend does not support remote resource queries
> + *   * other -errno on failure
> + */
> +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)
> +{
> +	int ret;
> +
> +	if (!epc || !epc->ops)
> +		return -EINVAL;
> +
> +	if (func_no >= epc->max_functions)
> +		return -EINVAL;
> +
> +	if (!epc->ops->get_remote_resources)
> +		return -EOPNOTSUPP;
> +
> +	mutex_lock(&epc->lock);
> +	ret = epc->ops->get_remote_resources(epc, func_no, vfunc_no,
> +					     resources, num_resources);
> +	mutex_unlock(&epc->lock);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(pci_epc_get_remote_resources);
> +
>  /**
>   * pci_epc_stop() - stop the PCI link
>   * @epc: the link of the EPC device that has to be stopped
> diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
> index c021c7af175f..af60d4ad2f0e 100644
> --- a/include/linux/pci-epc.h
> +++ b/include/linux/pci-epc.h
> @@ -61,6 +61,44 @@ struct pci_epc_map {
>  	void __iomem	*virt_addr;
>  };
>
> +/**
> + * enum pci_epc_remote_resource_type - remote resource type identifiers
> + * @PCI_EPC_RR_DMA_CTRL_MMIO: Integrated DMA controller register window (MMIO)
> + * @PCI_EPC_RR_DMA_CHAN_DESC: Per-channel DMA descriptor
> + *
> + * EPC backends may expose auxiliary blocks (e.g. DMA engines) by mapping their
> + * register windows and descriptor memories into BAR space. This enum
> + * identifies the type of each exposable resource.
> + */
> +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
> + *
> + * For @PCI_EPC_RR_DMA_CHAN_DESC, @u.dma_chan_desc provides per-channel
> + * information.
> + */
> +struct pci_epc_remote_resource {
> +	enum pci_epc_remote_resource_type type;
> +	phys_addr_t phys_addr;
> +	resource_size_t size;

is it good use struct resource?

> +
> +	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 +122,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)

Add comments, must set 'type' of pci_epc_remote_resource.

Over all it is good.

Frank
>   * @owner: the module owner containing the ops
>   */
>  struct pci_epc_ops {
> @@ -115,6 +155,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 +352,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
> --
> 2.51.0
>

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

* Re: [PATCH v3 07/11] PCI: dwc: Record integrated eDMA register window
  2026-02-04 14:54 ` [PATCH v3 07/11] PCI: dwc: Record integrated eDMA register window Koichiro Den
@ 2026-02-04 17:57   ` Frank Li
  0 siblings, 0 replies; 32+ messages in thread
From: Frank Li @ 2026-02-04 17:57 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 11:54:35PM +0900, Koichiro Den wrote:
> Some DesignWare PCIe controllers integrate an eDMA block whose registers
> are located in a dedicated register window. Endpoint function drivers
> may need the physical base and size of this window to map/expose it to a
> peer.
>
> Record the physical base and size of the integrated eDMA register window
> in struct dw_pcie.
>
> Signed-off-by: Koichiro Den <den@valinux.co.jp>
> ---

Reviewed-by: Frank Li <Frank.Li@nxp.com>

>  drivers/pci/controller/dwc/pcie-designware.c | 4 ++++
>  drivers/pci/controller/dwc/pcie-designware.h | 2 ++
>  2 files changed, 6 insertions(+)
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> index 18331d9e85be..d97ad9d2aa9b 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.c
> +++ b/drivers/pci/controller/dwc/pcie-designware.c
> @@ -162,8 +162,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;
>  		}
>  	}
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
> index 43d7606bc987..88e4a9e514e8 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.h
> +++ b/drivers/pci/controller/dwc/pcie-designware.h
> @@ -542,6 +542,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];
> --
> 2.51.0
>

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

* Re: [PATCH v3 08/11] PCI: dwc: ep: Report integrated DWC eDMA remote resources
  2026-02-04 14:54 ` [PATCH v3 08/11] PCI: dwc: ep: Report integrated DWC eDMA remote resources Koichiro Den
@ 2026-02-04 18:06   ` Frank Li
  2026-02-05  6:58     ` Koichiro Den
  0 siblings, 1 reply; 32+ messages in thread
From: Frank Li @ 2026-02-04 18:06 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 11:54:36PM +0900, Koichiro Den wrote:
> Implement pci_epc_ops.get_remote_resources() for the DesignWare PCIe
> endpoint controller. Report:
> - the integrated eDMA control MMIO window
> - the per-channel linked-list regions for read/write engines
>
> This allows endpoint function drivers to discover and map or inform
> these resources to a remote peer using the generic EPC API.
>
> Signed-off-by: Koichiro Den <den@valinux.co.jp>
> ---
>  .../pci/controller/dwc/pcie-designware-ep.c   | 74 +++++++++++++++++++
>  1 file changed, 74 insertions(+)
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> index 7e7844ff0f7e..5c0dcbf18d07 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> @@ -808,6 +808,79 @@ dw_pcie_ep_get_features(struct pci_epc *epc, u8 func_no, u8 vfunc_no)
>  	return ep->ops->get_features(ep);
>  }
>
> +static int
> +dw_pcie_ep_get_remote_resources(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
> +				struct pci_epc_remote_resource *resources,
> +				int num_resources)
> +{
> +	struct dw_pcie_ep *ep = epc_get_drvdata(epc);
> +	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> +	struct dw_edma_chip *edma = &pci->edma;
> +	int ll_cnt = 0, needed, idx = 0;
> +	resource_size_t dma_size;
> +	phys_addr_t dma_phys;
> +	unsigned int i;
> +
> +	if (!pci->edma_reg_size)
> +		return 0;
> +
> +	dma_phys = pci->edma_reg_phys;
> +	dma_size = pci->edma_reg_size;
> +
> +	for (i = 0; i < edma->ll_wr_cnt; i++)
> +		if (edma->ll_region_wr[i].sz)
> +			ll_cnt++;
> +
> +	for (i = 0; i < edma->ll_rd_cnt; i++)
> +		if (edma->ll_region_rd[i].sz)
> +			ll_cnt++;
> +
> +	needed = 1 + ll_cnt;
> +
> +	/* Count query mode */
> +	if (!resources || !num_resources)
> +		return needed;
> +
> +	if (num_resources < needed)
> +		return -ENOSPC;

How to predict how many 'num_resources' needs?  provide
dw_pcie_ep_get_resource_number()?

Or dw_pcie_ep_get_remote_resources(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
                             struct pci_epc_remote_resource *resources,
                             int *num_resources)

return number_resource validate.  if resources is NULL, just return how
many resource needed.

Frank
> +
> +	resources[idx++] = (struct pci_epc_remote_resource) {
> +		.type = PCI_EPC_RR_DMA_CTRL_MMIO,
> +		.phys_addr = dma_phys,
> +		.size = dma_size,
> +	};
> +
> +	/* One LL region per write channel */
> +	for (i = 0; i < edma->ll_wr_cnt; i++) {
> +		if (!edma->ll_region_wr[i].sz)
> +			continue;
> +
> +		resources[idx++] = (struct pci_epc_remote_resource) {
> +			.type = PCI_EPC_RR_DMA_CHAN_DESC,
> +			.phys_addr = edma->ll_region_wr[i].paddr,
> +			.size = edma->ll_region_wr[i].sz,
> +			.u.dma_chan_desc.hw_chan_id = i,
> +			.u.dma_chan_desc.ep2rc = true,
> +		};
> +	}
> +
> +	/* One LL region per read channel */
> +	for (i = 0; i < edma->ll_rd_cnt; i++) {
> +		if (!edma->ll_region_rd[i].sz)
> +			continue;
> +
> +		resources[idx++] = (struct pci_epc_remote_resource) {
> +			.type = PCI_EPC_RR_DMA_CHAN_DESC,
> +			.phys_addr = edma->ll_region_rd[i].paddr,
> +			.size = edma->ll_region_rd[i].sz,
> +			.u.dma_chan_desc.hw_chan_id = i,
> +			.u.dma_chan_desc.ep2rc = false,
> +		};
> +	}
> +
> +	return idx;
> +}
> +
>  static const struct pci_epc_ops epc_ops = {
>  	.write_header		= dw_pcie_ep_write_header,
>  	.set_bar		= dw_pcie_ep_set_bar,
> @@ -823,6 +896,7 @@ static const struct pci_epc_ops epc_ops = {
>  	.start			= dw_pcie_ep_start,
>  	.stop			= dw_pcie_ep_stop,
>  	.get_features		= dw_pcie_ep_get_features,
> +	.get_remote_resources	= dw_pcie_ep_get_remote_resources,
>  };
>
>  /**
> --
> 2.51.0
>

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

* Re: [PATCH v3 09/11] PCI: endpoint: pci-epf-test: Add smoke test for EPC remote resource API
  2026-02-04 14:54 ` [PATCH v3 09/11] PCI: endpoint: pci-epf-test: Add smoke test for EPC remote resource API Koichiro Den
@ 2026-02-04 19:37   ` Frank Li
  2026-02-05  7:01     ` Koichiro Den
  2026-02-05  0:01   ` kernel test robot
  2026-02-05  2:37   ` kernel test robot
  2 siblings, 1 reply; 32+ messages in thread
From: Frank Li @ 2026-02-04 19:37 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 11:54:37PM +0900, Koichiro Den wrote:
> Add a new pci-epf-test command that exercises the newly added EPC API
> pci_epc_get_remote_resources().
>
> The test is intentionally a smoke test. It verifies that the API either
> returns -EOPNOTSUPP or a well-formed resource list (non-zero phys/size
> and known resource types). The result is reported to the host via a
> status bit and an interrupt, consistent with existing pci-epf-test
> commands.
>
> Signed-off-by: Koichiro Den <den@valinux.co.jp>
> ---
>  drivers/pci/endpoint/functions/pci-epf-test.c | 88 +++++++++++++++++++
>  1 file changed, 88 insertions(+)
>
> diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
> index 6952ee418622..6446a0a23865 100644
> --- a/drivers/pci/endpoint/functions/pci-epf-test.c
> +++ b/drivers/pci/endpoint/functions/pci-epf-test.c
> @@ -35,6 +35,7 @@
>  #define COMMAND_DISABLE_DOORBELL	BIT(7)
>  #define COMMAND_BAR_SUBRANGE_SETUP	BIT(8)
>  #define COMMAND_BAR_SUBRANGE_CLEAR	BIT(9)
> +#define COMMAND_EPC_API			BIT(10)
>
>  #define STATUS_READ_SUCCESS		BIT(0)
>  #define STATUS_READ_FAIL		BIT(1)
> @@ -54,6 +55,8 @@
>  #define STATUS_BAR_SUBRANGE_SETUP_FAIL		BIT(15)
>  #define STATUS_BAR_SUBRANGE_CLEAR_SUCCESS	BIT(16)
>  #define STATUS_BAR_SUBRANGE_CLEAR_FAIL		BIT(17)
> +#define STATUS_EPC_API_SUCCESS		BIT(18)
> +#define STATUS_EPC_API_FAIL		BIT(19)
>
>  #define FLAG_USE_DMA			BIT(0)
>
> @@ -967,6 +970,87 @@ static void pci_epf_test_bar_subrange_clear(struct pci_epf_test *epf_test,
>  	reg->status = cpu_to_le32(status);
>  }
>
> +static void pci_epf_test_epc_api(struct pci_epf_test *epf_test,
> +				 struct pci_epf_test_reg *reg)
> +{
> +	struct pci_epc_remote_resource *resources = NULL;
> +	u32 status = le32_to_cpu(reg->status);
> +	struct pci_epf *epf = epf_test->epf;
> +	struct device *dev = &epf->dev;
> +	struct pci_epc *epc = epf->epc;
> +	int num_resources;
> +	int ret, i;
> +
> +	num_resources = pci_epc_get_remote_resources(epc, epf->func_no,
> +						     epf->vfunc_no, NULL, 0);
> +	if (num_resources == -EOPNOTSUPP || num_resources == 0)
> +		goto out_success;
> +	if (num_resources < 0)
> +		goto err;
> +
> +	resources = kcalloc(num_resources, sizeof(*resources), GFP_KERNEL);

use auto cleanup
	struct pci_epc_remote_resource *resources __free(kfree) =
		kcalloc(num_resources, sizeof(*resources), GFP_KERNEL);

> +	if (!resources)
> +		goto err;
> +
> +	ret = pci_epc_get_remote_resources(epc, epf->func_no, epf->vfunc_no,
> +					   resources, num_resources);
> +	if (ret < 0) {
> +		dev_err(dev, "EPC remote resource query failed: %d\n", ret);
> +		goto err_free;
> +	}
> +	if (ret > num_resources) {
> +		dev_err(dev, "EPC API returned %d resources (max %d)\n",
> +			ret, num_resources);
> +		goto err_free;
> +	}
> +
> +	for (i = 0; i < ret; i++) {
> +		struct pci_epc_remote_resource *res = &resources[i];
> +
> +		if (!res->phys_addr || !res->size) {
> +			dev_err(dev,
> +				"Invalid remote resource[%d] (type=%d phys=%pa size=%llu)\n",
> +				i, res->type, &res->phys_addr, res->size);
> +			goto err_free;
> +		}
> +
> +		/* Guard against address overflow */
> +		if (res->phys_addr + res->size < res->phys_addr) {
> +			dev_err(dev,
> +				"Remote resource[%d] overflow (phys=%pa size=%llu)\n",
> +				i, &res->phys_addr, res->size);
> +			goto err_free;
> +		}
> +
> +		switch (res->type) {
> +		case PCI_EPC_RR_DMA_CTRL_MMIO:
> +			/* Generic checks above are sufficient. */
> +			break;
> +		case PCI_EPC_RR_DMA_CHAN_DESC:
> +			/*
> +			 * hw_chan_id and ep2rc are informational. No extra validation
> +			 * beyond the generic checks above is needed.
> +			 */
> +			break;
> +		default:
> +			dev_err(dev, "Unknown remote resource type %d\n", res->type);
> +			goto err_free;

can you call subrange to map to one of bar?

Frank
> +		}
> +	}
> +
> +out_success:
> +	kfree(resources);
> +	status |= STATUS_EPC_API_SUCCESS;
> +	reg->status = cpu_to_le32(status);
> +	return;
> +
> +err_free:
> +	kfree(resources);
> +err:
> +	status |= STATUS_EPC_API_FAIL;
> +	reg->status = cpu_to_le32(status);
> +}
> +
>  static void pci_epf_test_cmd_handler(struct work_struct *work)
>  {
>  	u32 command;
> @@ -1030,6 +1114,10 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
>  		pci_epf_test_bar_subrange_clear(epf_test, reg);
>  		pci_epf_test_raise_irq(epf_test, reg);
>  		break;
> +	case COMMAND_EPC_API:
> +		pci_epf_test_epc_api(epf_test, reg);
> +		pci_epf_test_raise_irq(epf_test, reg);
> +		break;
>  	default:
>  		dev_err(dev, "Invalid command 0x%x\n", command);
>  		break;
> --
> 2.51.0
>

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

* Re: [PATCH v3 01/11] dmaengine: Add hw_id to dma_slave_caps
  2026-02-04 14:54 ` [PATCH v3 01/11] dmaengine: Add hw_id to dma_slave_caps Koichiro Den
@ 2026-02-04 19:39   ` Frank Li
  2026-02-05  6:46     ` Koichiro Den
  0 siblings, 1 reply; 32+ messages in thread
From: Frank Li @ 2026-02-04 19:39 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 11:54:29PM +0900, Koichiro Den wrote:
> 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;

I have not see where use it? Does src_id of struct dma_chan work?

Frank

>  };
>
>  static inline const char *dma_chan_name(struct dma_chan *chan)
> --
> 2.51.0
>

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

* Re: [PATCH v3 09/11] PCI: endpoint: pci-epf-test: Add smoke test for EPC remote resource API
  2026-02-04 14:54 ` [PATCH v3 09/11] PCI: endpoint: pci-epf-test: Add smoke test for EPC remote resource API Koichiro Den
  2026-02-04 19:37   ` Frank Li
@ 2026-02-05  0:01   ` kernel test robot
  2026-02-05  2:37   ` kernel test robot
  2 siblings, 0 replies; 32+ messages in thread
From: kernel test robot @ 2026-02-05  0:01 UTC (permalink / raw)
  To: Koichiro Den, vkoul, mani, Frank.Li, jingoohan1, lpieralisi,
	kwilczynski, robh, bhelgaas
  Cc: oe-kbuild-all, dmaengine, linux-pci, linux-kernel

Hi Koichiro,

kernel test robot noticed the following build warnings:

[auto build test WARNING on pci/next]
[also build test WARNING on next-20260204]
[cannot apply to vkoul-dmaengine/next pci/for-linus linus/master v6.19-rc8]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Koichiro-Den/dmaengine-Add-hw_id-to-dma_slave_caps/20260204-230604
base:   https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git next
patch link:    https://lore.kernel.org/r/20260204145440.950609-10-den%40valinux.co.jp
patch subject: [PATCH v3 09/11] PCI: endpoint: pci-epf-test: Add smoke test for EPC remote resource API
config: i386-randconfig-003-20260205 (https://download.01.org/0day-ci/archive/20260205/202602050741.nyI2oa7X-lkp@intel.com/config)
compiler: gcc-13 (Debian 13.3.0-16) 13.3.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260205/202602050741.nyI2oa7X-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602050741.nyI2oa7X-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from include/linux/device.h:15,
                    from include/linux/dmaengine.h:8,
                    from drivers/pci/endpoint/functions/pci-epf-test.c:11:
   drivers/pci/endpoint/functions/pci-epf-test.c: In function 'pci_epf_test_epc_api':
>> drivers/pci/endpoint/functions/pci-epf-test.c:1012:33: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 6 has type 'resource_size_t' {aka 'unsigned int'} [-Wformat=]
    1012 |                                 "Invalid remote resource[%d] (type=%d phys=%pa size=%llu)\n",
         |                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:110:30: note: in definition of macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ^~~
   include/linux/dev_printk.h:154:56: note: in expansion of macro 'dev_fmt'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                        ^~~~~~~
   drivers/pci/endpoint/functions/pci-epf-test.c:1011:25: note: in expansion of macro 'dev_err'
    1011 |                         dev_err(dev,
         |                         ^~~~~~~
   drivers/pci/endpoint/functions/pci-epf-test.c:1012:88: note: format string is defined here
    1012 |                                 "Invalid remote resource[%d] (type=%d phys=%pa size=%llu)\n",
         |                                                                                     ~~~^
         |                                                                                        |
         |                                                                                        long long unsigned int
         |                                                                                     %u
   drivers/pci/endpoint/functions/pci-epf-test.c:1020:33: warning: format '%llu' expects argument of type 'long long unsigned int', but argument 5 has type 'resource_size_t' {aka 'unsigned int'} [-Wformat=]
    1020 |                                 "Remote resource[%d] overflow (phys=%pa size=%llu)\n",
         |                                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   include/linux/dev_printk.h:110:30: note: in definition of macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ^~~
   include/linux/dev_printk.h:154:56: note: in expansion of macro 'dev_fmt'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                        ^~~~~~~
   drivers/pci/endpoint/functions/pci-epf-test.c:1019:25: note: in expansion of macro 'dev_err'
    1019 |                         dev_err(dev,
         |                         ^~~~~~~
   drivers/pci/endpoint/functions/pci-epf-test.c:1020:81: note: format string is defined here
    1020 |                                 "Remote resource[%d] overflow (phys=%pa size=%llu)\n",
         |                                                                              ~~~^
         |                                                                                 |
         |                                                                                 long long unsigned int
         |                                                                              %u


vim +1012 drivers/pci/endpoint/functions/pci-epf-test.c

   972	
   973	static void pci_epf_test_epc_api(struct pci_epf_test *epf_test,
   974					 struct pci_epf_test_reg *reg)
   975	{
   976		struct pci_epc_remote_resource *resources = NULL;
   977		u32 status = le32_to_cpu(reg->status);
   978		struct pci_epf *epf = epf_test->epf;
   979		struct device *dev = &epf->dev;
   980		struct pci_epc *epc = epf->epc;
   981		int num_resources;
   982		int ret, i;
   983	
   984		num_resources = pci_epc_get_remote_resources(epc, epf->func_no,
   985							     epf->vfunc_no, NULL, 0);
   986		if (num_resources == -EOPNOTSUPP || num_resources == 0)
   987			goto out_success;
   988		if (num_resources < 0)
   989			goto err;
   990	
   991		resources = kcalloc(num_resources, sizeof(*resources), GFP_KERNEL);
   992		if (!resources)
   993			goto err;
   994	
   995		ret = pci_epc_get_remote_resources(epc, epf->func_no, epf->vfunc_no,
   996						   resources, num_resources);
   997		if (ret < 0) {
   998			dev_err(dev, "EPC remote resource query failed: %d\n", ret);
   999			goto err_free;
  1000		}
  1001		if (ret > num_resources) {
  1002			dev_err(dev, "EPC API returned %d resources (max %d)\n",
  1003				ret, num_resources);
  1004			goto err_free;
  1005		}
  1006	
  1007		for (i = 0; i < ret; i++) {
  1008			struct pci_epc_remote_resource *res = &resources[i];
  1009	
  1010			if (!res->phys_addr || !res->size) {
  1011				dev_err(dev,
> 1012					"Invalid remote resource[%d] (type=%d phys=%pa size=%llu)\n",
  1013					i, res->type, &res->phys_addr, res->size);
  1014				goto err_free;
  1015			}
  1016	
  1017			/* Guard against address overflow */
  1018			if (res->phys_addr + res->size < res->phys_addr) {
  1019				dev_err(dev,
  1020					"Remote resource[%d] overflow (phys=%pa size=%llu)\n",
  1021					i, &res->phys_addr, res->size);
  1022				goto err_free;
  1023			}
  1024	
  1025			switch (res->type) {
  1026			case PCI_EPC_RR_DMA_CTRL_MMIO:
  1027				/* Generic checks above are sufficient. */
  1028				break;
  1029			case PCI_EPC_RR_DMA_CHAN_DESC:
  1030				/*
  1031				 * hw_chan_id and ep2rc are informational. No extra validation
  1032				 * beyond the generic checks above is needed.
  1033				 */
  1034				break;
  1035			default:
  1036				dev_err(dev, "Unknown remote resource type %d\n", res->type);
  1037				goto err_free;
  1038			}
  1039		}
  1040	
  1041	out_success:
  1042		kfree(resources);
  1043		status |= STATUS_EPC_API_SUCCESS;
  1044		reg->status = cpu_to_le32(status);
  1045		return;
  1046	
  1047	err_free:
  1048		kfree(resources);
  1049	err:
  1050		status |= STATUS_EPC_API_FAIL;
  1051		reg->status = cpu_to_le32(status);
  1052	}
  1053	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

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

* Re: [PATCH v3 09/11] PCI: endpoint: pci-epf-test: Add smoke test for EPC remote resource API
  2026-02-04 14:54 ` [PATCH v3 09/11] PCI: endpoint: pci-epf-test: Add smoke test for EPC remote resource API Koichiro Den
  2026-02-04 19:37   ` Frank Li
  2026-02-05  0:01   ` kernel test robot
@ 2026-02-05  2:37   ` kernel test robot
  2 siblings, 0 replies; 32+ messages in thread
From: kernel test robot @ 2026-02-05  2:37 UTC (permalink / raw)
  To: Koichiro Den, vkoul, mani, Frank.Li, jingoohan1, lpieralisi,
	kwilczynski, robh, bhelgaas
  Cc: llvm, oe-kbuild-all, dmaengine, linux-pci, linux-kernel

Hi Koichiro,

kernel test robot noticed the following build warnings:

[auto build test WARNING on pci/next]
[also build test WARNING on next-20260204]
[cannot apply to vkoul-dmaengine/next pci/for-linus linus/master v6.19-rc8]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Koichiro-Den/dmaengine-Add-hw_id-to-dma_slave_caps/20260204-230604
base:   https://git.kernel.org/pub/scm/linux/kernel/git/pci/pci.git next
patch link:    https://lore.kernel.org/r/20260204145440.950609-10-den%40valinux.co.jp
patch subject: [PATCH v3 09/11] PCI: endpoint: pci-epf-test: Add smoke test for EPC remote resource API
config: um-randconfig-001-20260205 (https://download.01.org/0day-ci/archive/20260205/202602051059.2bwjcYJE-lkp@intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 9b8addffa70cee5b2acc5454712d9cf78ce45710)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260205/202602051059.2bwjcYJE-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602051059.2bwjcYJE-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from drivers/pci/endpoint/functions/pci-epf-test.c:11:
   In file included from include/linux/dmaengine.h:12:
   In file included from include/linux/scatterlist.h:9:
   In file included from arch/um/include/asm/io.h:24:
   include/asm-generic/io.h:1209:55: warning: performing pointer arithmetic on a null pointer has undefined behavior [-Wnull-pointer-arithmetic]
    1209 |         return (port > MMIO_UPPER_LIMIT) ? NULL : PCI_IOBASE + port;
         |                                                   ~~~~~~~~~~ ^
>> drivers/pci/endpoint/functions/pci-epf-test.c:1013:36: warning: format specifies type 'unsigned long long' but the argument has type 'resource_size_t' (aka 'unsigned int') [-Wformat]
    1012 |                                 "Invalid remote resource[%d] (type=%d phys=%pa size=%llu)\n",
         |                                                                                     ~~~~
         |                                                                                     %u
    1013 |                                 i, res->type, &res->phys_addr, res->size);
         |                                                                ^~~~~~~~~
   include/linux/dev_printk.h:154:65: note: expanded from macro 'dev_err'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                                ~~~     ^~~~~~~~~~~
   include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ~~~    ^~~~~~~~~~~
   drivers/pci/endpoint/functions/pci-epf-test.c:1021:25: warning: format specifies type 'unsigned long long' but the argument has type 'resource_size_t' (aka 'unsigned int') [-Wformat]
    1020 |                                 "Remote resource[%d] overflow (phys=%pa size=%llu)\n",
         |                                                                              ~~~~
         |                                                                              %u
    1021 |                                 i, &res->phys_addr, res->size);
         |                                                     ^~~~~~~~~
   include/linux/dev_printk.h:154:65: note: expanded from macro 'dev_err'
     154 |         dev_printk_index_wrap(_dev_err, KERN_ERR, dev, dev_fmt(fmt), ##__VA_ARGS__)
         |                                                                ~~~     ^~~~~~~~~~~
   include/linux/dev_printk.h:110:23: note: expanded from macro 'dev_printk_index_wrap'
     110 |                 _p_func(dev, fmt, ##__VA_ARGS__);                       \
         |                              ~~~    ^~~~~~~~~~~
   3 warnings generated.


vim +1013 drivers/pci/endpoint/functions/pci-epf-test.c

   972	
   973	static void pci_epf_test_epc_api(struct pci_epf_test *epf_test,
   974					 struct pci_epf_test_reg *reg)
   975	{
   976		struct pci_epc_remote_resource *resources = NULL;
   977		u32 status = le32_to_cpu(reg->status);
   978		struct pci_epf *epf = epf_test->epf;
   979		struct device *dev = &epf->dev;
   980		struct pci_epc *epc = epf->epc;
   981		int num_resources;
   982		int ret, i;
   983	
   984		num_resources = pci_epc_get_remote_resources(epc, epf->func_no,
   985							     epf->vfunc_no, NULL, 0);
   986		if (num_resources == -EOPNOTSUPP || num_resources == 0)
   987			goto out_success;
   988		if (num_resources < 0)
   989			goto err;
   990	
   991		resources = kcalloc(num_resources, sizeof(*resources), GFP_KERNEL);
   992		if (!resources)
   993			goto err;
   994	
   995		ret = pci_epc_get_remote_resources(epc, epf->func_no, epf->vfunc_no,
   996						   resources, num_resources);
   997		if (ret < 0) {
   998			dev_err(dev, "EPC remote resource query failed: %d\n", ret);
   999			goto err_free;
  1000		}
  1001		if (ret > num_resources) {
  1002			dev_err(dev, "EPC API returned %d resources (max %d)\n",
  1003				ret, num_resources);
  1004			goto err_free;
  1005		}
  1006	
  1007		for (i = 0; i < ret; i++) {
  1008			struct pci_epc_remote_resource *res = &resources[i];
  1009	
  1010			if (!res->phys_addr || !res->size) {
  1011				dev_err(dev,
  1012					"Invalid remote resource[%d] (type=%d phys=%pa size=%llu)\n",
> 1013					i, res->type, &res->phys_addr, res->size);
  1014				goto err_free;
  1015			}
  1016	
  1017			/* Guard against address overflow */
  1018			if (res->phys_addr + res->size < res->phys_addr) {
  1019				dev_err(dev,
  1020					"Remote resource[%d] overflow (phys=%pa size=%llu)\n",
  1021					i, &res->phys_addr, res->size);
  1022				goto err_free;
  1023			}
  1024	
  1025			switch (res->type) {
  1026			case PCI_EPC_RR_DMA_CTRL_MMIO:
  1027				/* Generic checks above are sufficient. */
  1028				break;
  1029			case PCI_EPC_RR_DMA_CHAN_DESC:
  1030				/*
  1031				 * hw_chan_id and ep2rc are informational. No extra validation
  1032				 * beyond the generic checks above is needed.
  1033				 */
  1034				break;
  1035			default:
  1036				dev_err(dev, "Unknown remote resource type %d\n", res->type);
  1037				goto err_free;
  1038			}
  1039		}
  1040	
  1041	out_success:
  1042		kfree(resources);
  1043		status |= STATUS_EPC_API_SUCCESS;
  1044		reg->status = cpu_to_le32(status);
  1045		return;
  1046	
  1047	err_free:
  1048		kfree(resources);
  1049	err:
  1050		status |= STATUS_EPC_API_FAIL;
  1051		reg->status = cpu_to_le32(status);
  1052	}
  1053	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

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

* Re: [PATCH v3 01/11] dmaengine: Add hw_id to dma_slave_caps
  2026-02-04 19:39   ` Frank Li
@ 2026-02-05  6:46     ` Koichiro Den
  2026-02-05 16:04       ` Frank Li
  0 siblings, 1 reply; 32+ messages in thread
From: Koichiro Den @ 2026-02-05  6:46 UTC (permalink / raw)
  To: Frank Li
  Cc: vkoul, mani, jingoohan1, lpieralisi, kwilczynski, robh, bhelgaas,
	dmaengine, linux-pci, linux-kernel

On Wed, Feb 04, 2026 at 02:39:03PM -0500, Frank Li wrote:
> On Wed, Feb 04, 2026 at 11:54:29PM +0900, Koichiro Den wrote:
> > 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;
> 
> I have not see where use it? Does src_id of struct dma_chan work?

There is no direct user of hw_id in this series. The intended flow is:
  1. obtain dma channels to expose via the standard dma_request_channel()
  2. get 'hw_id' for each obtained channel (with this patch, Patch v3 1/11)
  3. call the pci_epc_get_remote_resources() API (introduced in Patch v3 6/11)
  4. iterate the resource list obtained in step 3, and find a resource whose
     .type is PCI_EPC_RR_DMA_CHAN_DESC and .u.dma_chan_desc.hw_chan_id
     matches 'hw_id' obtained in step 2.

By the way, I couldn't find any 'src_id' field in struct dma_chan.
Did you mean dma_chan.chan_id? If so, it's explicitly a sysfs ID and is
allocated by the dmaengine core (from dma_device->chan_ida), so it doesn't
correlate with the provider's HW channel numbering.

(Also, correction to my note in the previous v2 thread:
 https://lore.kernel.org/all/zqcu3awadvqbtil3vudcmgjyjpku7divrhqyox72k43nfzcoo7@hflaengfjy27/
 There I wrote that the low-level dma channel id would become unnecessary,
 but that was incorrect because dma_request_channel() does not provide any
 guarantee that channels are allocated in hw channel order: other,
 unrelated components may have requested dma channels earlier or in
 parallel, so the set of channels obtained by a given user cannot be
 assumed to map cleanly to hw-level channel IDs starting from 0. So this v3 still
 includes this patch. That said, since there are no direct users in this
 series, I am open to dropping Patch v3 1/11-2/11 if you think that would
 be preferable.)

Thanks,
Koichiro

> 
> Frank
> 
> >  };
> >
> >  static inline const char *dma_chan_name(struct dma_chan *chan)
> > --
> > 2.51.0
> >

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

* Re: [PATCH v3 03/11] dmaengine: dw-edma: Add per-channel interrupt routing control
  2026-02-04 17:42   ` Frank Li
@ 2026-02-05  6:48     ` Koichiro Den
  2026-02-05 16:05       ` Frank Li
  0 siblings, 1 reply; 32+ messages in thread
From: Koichiro Den @ 2026-02-05  6:48 UTC (permalink / raw)
  To: Frank Li
  Cc: vkoul, mani, jingoohan1, lpieralisi, kwilczynski, robh, bhelgaas,
	dmaengine, linux-pci, linux-kernel

On Wed, Feb 04, 2026 at 12:42:41PM -0500, Frank Li wrote:
> On Wed, Feb 04, 2026 at 11:54:31PM +0900, Koichiro Den wrote:
> > 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.
> >
> > For now, HDMA is not supported for the peripheral_config. Until the
> > support is implemented and validated, explicitly reject it for HDMA to
> > avoid silently misconfiguring interrupt routing.
> >
> > Signed-off-by: Koichiro Den <den@valinux.co.jp>
> > ---
> >  drivers/dma/dw-edma/dw-edma-core.c    | 24 +++++++++++++++++++++++
> >  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, 83 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..b4cb02d545bd 100644
> > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > @@ -224,6 +224,29 @@ 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 (chan->dw->chip->mf == EDMA_MF_HDMA_NATIVE)
> > +			return -EOPNOTSUPP;
> > +
> > +		if (config->peripheral_size < sizeof(*pcfg))
> > +			return -EINVAL;
> 
> It is good to check here.
> 
> > +
> > +		pcfg = config->peripheral_config;
> 
> save whole peripheral_config in case need more special peripheral
> configuration in future.

Ok, while I initially thought a deep copy (snapshot) was unnecessary for
now, I agree it makes future extensions easier. I'll do so.

> 
> > +		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;
> > +		}
> > +	}
> 
> use helper function to get irq_mode. [...]

Ok, my current plan is to keep chan->irq_mode as sticky per-channel state,
and factor out the parsing/validation of irq_mode (from
config->peripheral_config) into a small helper used by
dw_edma_device_config() and the new prep_config path.

Does this match what you meant by "helper function"?

> [...] I posted combine config and prep by
> one call.
> 
> https://lore.kernel.org/dmaengine/20260105-dma_prep_config-v3-0-a8480362fd42@nxp.com/
> 
> So we use such helper to get irq node after above patch merge. It is not
> big deal, I can change it later. If provide helper funtions, it will be
> slice better.
> 
> >
> >  	memcpy(&chan->config, config, sizeof(*config));
> >  	chan->configured = true;
> > @@ -750,6 +773,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);
> ...
> >
> > +/*
> > + * 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
> 
> keep consistent after "," for each enum

Ok, will add ", local interrupt unmasked" for it.

Thanks for the review,
Koichiro

> 
> Frank
> 
> > + * @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] 32+ messages in thread

* Re: [PATCH v3 04/11] dmaengine: Add selfirq callback registration API
  2026-02-04 17:46   ` Frank Li
@ 2026-02-05  6:50     ` Koichiro Den
  2026-02-05 16:07       ` Frank Li
  0 siblings, 1 reply; 32+ messages in thread
From: Koichiro Den @ 2026-02-05  6:50 UTC (permalink / raw)
  To: Frank Li
  Cc: vkoul, mani, jingoohan1, lpieralisi, kwilczynski, robh, bhelgaas,
	dmaengine, linux-pci, linux-kernel

On Wed, Feb 04, 2026 at 12:46:36PM -0500, Frank Li wrote:
> On Wed, Feb 04, 2026 at 11:54:32PM +0900, Koichiro Den wrote:
> > Some DMA controllers can generate an interrupt by software writing to a
> > register, without updating the normal interrupt status bits. This can be
> > used as a doorbell mechanism when the DMA engine is remotely programmed,
> > or for self-tests.
> >
> > Add an optional per-DMA-device API to register/unregister callbacks for
> > such "selfirq" events. Providers may invoke these callbacks from their
> > interrupt handler when they detect an emulated interrupt.
> >
> > Callbacks are invoked in hardirq context and must not sleep.
> 
> Is it possible register shared irq handle with the same channel's irq
> number?

The proposed dmaengine_{register,unregister}_selfirq() APIs are device-wide
(i.e. not per channel), so I'm not sure which "channel" you refer to here.
Also, when chip->nr_irqs > 1 on EP, dw-edma distributes channels across
multiple IRQ vectors, and it's unclear (at least to me) which IRQ vector
the emulated interrupt ("fake irq") is expected to be delivered on.

That said, technically, yes I agree adding another handler should be
possible, as dw-edma currently requests its irq(s) with IRQF_SHARED.
However, for a consumer driver to do request_irq() on its own, I think it
would need a stable way to obtain the irq number. Today that mapping seems
platform-specific and hidden behind dw_edma_plat_ops->irq_vector().

Would you prefer exposing a helper for obtaining the irq number (or
exporting the mapping in some form) instead of adding the dmaengine selfirq
API, or did you have another approach in mind?

Thanks for the review,
Koichiro

> 
> Frank
> 
> >
> > Signed-off-by: Koichiro Den <den@valinux.co.jp>
> > ---
> >  include/linux/dmaengine.h | 70 +++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 70 insertions(+)
> >
> > diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> > index 71bc2674567f..9c6194e8bfe1 100644
> > --- a/include/linux/dmaengine.h
> > +++ b/include/linux/dmaengine.h
> > @@ -785,6 +785,17 @@ struct dma_filter {
> >  	const struct dma_slave_map *map;
> >  };
> >
> > +/**
> > + * dma_selfirq_fn - callback for emulated/self IRQ events
> > + * @dev: DMA device invoking the callback
> > + * @data: opaque pointer provided at registration time
> > + *
> > + * Providers may invoke this callback from their interrupt handler when an
> > + * emulated interrupt ("selfirq") might have occurred. The callback runs in
> > + * hardirq context and must not sleep.
> > + */
> > +typedef void (*dma_selfirq_fn)(struct dma_device *dev, void *data);
> > +
> >  /**
> >   * struct dma_device - info on the entity supplying DMA services
> >   * @ref: reference is taken and put every time a channel is allocated or freed
> > @@ -853,6 +864,10 @@ struct dma_filter {
> >   *	or an error code
> >   * @device_synchronize: Synchronizes the termination of a transfers to the
> >   *  current context.
> > + * @device_register_selfirq: optional callback registration for
> > + *	emulated/self IRQ events
> > + * @device_unregister_selfirq: unregister previously registered selfirq
> > + *	callback
> >   * @device_tx_status: poll for transaction completion, the optional
> >   *	txstate parameter can be supplied with a pointer to get a
> >   *	struct with auxiliary transfer status information, otherwise the call
> > @@ -951,6 +966,11 @@ struct dma_device {
> >  	int (*device_terminate_all)(struct dma_chan *chan);
> >  	void (*device_synchronize)(struct dma_chan *chan);
> >
> > +	int (*device_register_selfirq)(struct dma_device *dev,
> > +				       dma_selfirq_fn fn, void *data);
> > +	void (*device_unregister_selfirq)(struct dma_device *dev,
> > +					  dma_selfirq_fn fn, void *data);
> > +
> >  	enum dma_status (*device_tx_status)(struct dma_chan *chan,
> >  					    dma_cookie_t cookie,
> >  					    struct dma_tx_state *txstate);
> > @@ -1197,6 +1217,56 @@ static inline void dmaengine_synchronize(struct dma_chan *chan)
> >  		chan->device->device_synchronize(chan);
> >  }
> >
> > +/**
> > + * dmaengine_register_selfirq() - Register a callback for emulated/self IRQ
> > + *                                events
> > + * @dev: DMA device
> > + * @fn: callback invoked from the provider's IRQ handler
> > + * @data: opaque callback data
> > + *
> > + * Some DMA controllers can raise an interrupt by software writing to a
> > + * register without updating normal status bits. Providers may call
> > + * registered callbacks from their interrupt handler when such events may
> > + * have occurred.
> > + * Callbacks are invoked in hardirq context and must not sleep.
> > + *
> > + * Return: 0 on success, -EOPNOTSUPP if unsupported, -EINVAL on bad args,
> > + * or provider-specific -errno.
> > + */
> > +static inline int dmaengine_register_selfirq(struct dma_device *dev,
> > +					     dma_selfirq_fn fn, void *data)
> > +{
> > +	if (!dev || !fn)
> > +		return -EINVAL;
> > +	if (!dev->device_register_selfirq)
> > +		return -EOPNOTSUPP;
> > +
> > +	return dev->device_register_selfirq(dev, fn, data);
> > +}
> > +
> > +/**
> > + * dmaengine_unregister_selfirq() - Unregister a previously registered
> > + *                                  selfirq callback
> > + * @dev: DMA device
> > + * @fn: callback pointer used at registration time
> > + * @data: opaque pointer used at registration time
> > + *
> > + * Unregister a callback previously registered via
> > + * dmaengine_register_selfirq(). Providers may synchronize against
> > + * in-flight callbacks, therefore this function may sleep and must not be
> > + * called from atomic context.
> > + */
> > +static inline void dmaengine_unregister_selfirq(struct dma_device *dev,
> > +						dma_selfirq_fn fn, void *data)
> > +{
> > +	if (!dev || !fn)
> > +		return;
> > +	if (!dev->device_unregister_selfirq)
> > +		return;
> > +
> > +	dev->device_unregister_selfirq(dev, fn, data);
> > +}
> > +
> >  /**
> >   * dmaengine_terminate_sync() - Terminate all active DMA transfers
> >   * @chan: The channel for which to terminate the transfers
> > --
> > 2.51.0
> >

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

* Re: [PATCH v3 06/11] PCI: endpoint: Add remote resource query API
  2026-02-04 17:55   ` Frank Li
@ 2026-02-05  6:53     ` Koichiro Den
  2026-02-05 16:10       ` Frank Li
  0 siblings, 1 reply; 32+ messages in thread
From: Koichiro Den @ 2026-02-05  6:53 UTC (permalink / raw)
  To: Frank Li
  Cc: vkoul, mani, jingoohan1, lpieralisi, kwilczynski, robh, bhelgaas,
	dmaengine, linux-pci, linux-kernel

On Wed, Feb 04, 2026 at 12:55:58PM -0500, Frank Li wrote:
> On Wed, Feb 04, 2026 at 11:54:34PM +0900, Koichiro Den wrote:
> > Endpoint controller drivers may integrate auxiliary blocks (e.g. DMA
> > engines) whose register windows and descriptor memories metadata need to
> > be exposed to a remote peer. Endpoint function drivers need a generic
> > way to discover such resources without hard-coding controller-specific
> > helpers.
> >
> > Add pci_epc_get_remote_resources() and the corresponding pci_epc_ops
> > get_remote_resources() callback. The API returns a list of resources
> > described by type, physical address and size, plus type-specific
> > metadata.
> >
> > Passing resources == NULL (or num_resources == 0) returns the required
> > number of entries.
> >
> > Signed-off-by: Koichiro Den <den@valinux.co.jp>
> > ---
> >  drivers/pci/endpoint/pci-epc-core.c | 41 +++++++++++++++++++++++++
> >  include/linux/pci-epc.h             | 46 +++++++++++++++++++++++++++++
> >  2 files changed, 87 insertions(+)
> >
> > diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
> > index 068155819c57..fa161113e24c 100644
> > --- a/drivers/pci/endpoint/pci-epc-core.c
> > +++ b/drivers/pci/endpoint/pci-epc-core.c
> > @@ -155,6 +155,47 @@ const struct pci_epc_features *pci_epc_get_features(struct pci_epc *epc,
> >  }
> >  EXPORT_SYMBOL_GPL(pci_epc_get_features);
> >
> > +/**
> > + * pci_epc_get_remote_resources() - query EPC-provided remote resources
> > + * @epc: EPC device
> > + * @func_no: function number
> > + * @vfunc_no: virtual function number
> > + * @resources: output array (may be NULL to query required count)
> > + * @num_resources: size of @resources array in entries (0 when querying count)
> > + *
> > + * Some EPC backends integrate auxiliary blocks (e.g. DMA engines) whose control
> > + * registers and/or descriptor memories can be exposed to the host by mapping
> > + * them into BAR space. This helper queries the backend for such resources.
> > + *
> > + * Return:
> > + *   * >= 0: number of resources returned (or required, if @resources is NULL)
> > + *   * -EOPNOTSUPP: backend does not support remote resource queries
> > + *   * other -errno on failure
> > + */
> > +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)
> > +{
> > +	int ret;
> > +
> > +	if (!epc || !epc->ops)
> > +		return -EINVAL;
> > +
> > +	if (func_no >= epc->max_functions)
> > +		return -EINVAL;
> > +
> > +	if (!epc->ops->get_remote_resources)
> > +		return -EOPNOTSUPP;
> > +
> > +	mutex_lock(&epc->lock);
> > +	ret = epc->ops->get_remote_resources(epc, func_no, vfunc_no,
> > +					     resources, num_resources);
> > +	mutex_unlock(&epc->lock);
> > +
> > +	return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(pci_epc_get_remote_resources);
> > +
> >  /**
> >   * pci_epc_stop() - stop the PCI link
> >   * @epc: the link of the EPC device that has to be stopped
> > diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
> > index c021c7af175f..af60d4ad2f0e 100644
> > --- a/include/linux/pci-epc.h
> > +++ b/include/linux/pci-epc.h
> > @@ -61,6 +61,44 @@ struct pci_epc_map {
> >  	void __iomem	*virt_addr;
> >  };
> >
> > +/**
> > + * enum pci_epc_remote_resource_type - remote resource type identifiers
> > + * @PCI_EPC_RR_DMA_CTRL_MMIO: Integrated DMA controller register window (MMIO)
> > + * @PCI_EPC_RR_DMA_CHAN_DESC: Per-channel DMA descriptor
> > + *
> > + * EPC backends may expose auxiliary blocks (e.g. DMA engines) by mapping their
> > + * register windows and descriptor memories into BAR space. This enum
> > + * identifies the type of each exposable resource.
> > + */
> > +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
> > + *
> > + * For @PCI_EPC_RR_DMA_CHAN_DESC, @u.dma_chan_desc provides per-channel
> > + * information.
> > + */
> > +struct pci_epc_remote_resource {
> > +	enum pci_epc_remote_resource_type type;
> > +	phys_addr_t phys_addr;
> > +	resource_size_t size;
> 
> is it good use struct resource?

Personally I don't think it's the best fit here, since these remote
resources are not meant to participate in the global resource tree or
managed by the resource management framework. And most of struct resource
fields (name/flags and the links) does not make sense in this context.

> 
> > +
> > +	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 +122,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)
> 
> Add comments, must set 'type' of pci_epc_remote_resource.

Would something like the following address your concern?

    * @get_remote_resources: ops to retrieve controller-owned resources that can be
    *                        exposed to the remote host (optional)
  + *                        The callback fills @resources (up to @num_resources entries)
  + *                        and returns the number of valid entries. Each returned entry
  + *                        must have @type set (which selects the valid union member in @u)
  + *                        and provide valid @phys_addr/@size.

Thanks for the review,
Koichiro

> 
> Over all it is good.
> 
> Frank
> >   * @owner: the module owner containing the ops
> >   */
> >  struct pci_epc_ops {
> > @@ -115,6 +155,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 +352,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
> > --
> > 2.51.0
> >

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

* Re: [PATCH v3 08/11] PCI: dwc: ep: Report integrated DWC eDMA remote resources
  2026-02-04 18:06   ` Frank Li
@ 2026-02-05  6:58     ` Koichiro Den
  2026-02-05 16:11       ` Frank Li
  0 siblings, 1 reply; 32+ messages in thread
From: Koichiro Den @ 2026-02-05  6:58 UTC (permalink / raw)
  To: Frank Li
  Cc: vkoul, mani, jingoohan1, lpieralisi, kwilczynski, robh, bhelgaas,
	dmaengine, linux-pci, linux-kernel

On Wed, Feb 04, 2026 at 01:06:27PM -0500, Frank Li wrote:
> On Wed, Feb 04, 2026 at 11:54:36PM +0900, Koichiro Den wrote:
> > Implement pci_epc_ops.get_remote_resources() for the DesignWare PCIe
> > endpoint controller. Report:
> > - the integrated eDMA control MMIO window
> > - the per-channel linked-list regions for read/write engines
> >
> > This allows endpoint function drivers to discover and map or inform
> > these resources to a remote peer using the generic EPC API.
> >
> > Signed-off-by: Koichiro Den <den@valinux.co.jp>
> > ---
> >  .../pci/controller/dwc/pcie-designware-ep.c   | 74 +++++++++++++++++++
> >  1 file changed, 74 insertions(+)
> >
> > diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > index 7e7844ff0f7e..5c0dcbf18d07 100644
> > --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> > +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > @@ -808,6 +808,79 @@ dw_pcie_ep_get_features(struct pci_epc *epc, u8 func_no, u8 vfunc_no)
> >  	return ep->ops->get_features(ep);
> >  }
> >
> > +static int
> > +dw_pcie_ep_get_remote_resources(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
> > +				struct pci_epc_remote_resource *resources,
> > +				int num_resources)
> > +{
> > +	struct dw_pcie_ep *ep = epc_get_drvdata(epc);
> > +	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> > +	struct dw_edma_chip *edma = &pci->edma;
> > +	int ll_cnt = 0, needed, idx = 0;
> > +	resource_size_t dma_size;
> > +	phys_addr_t dma_phys;
> > +	unsigned int i;
> > +
> > +	if (!pci->edma_reg_size)
> > +		return 0;
> > +
> > +	dma_phys = pci->edma_reg_phys;
> > +	dma_size = pci->edma_reg_size;
> > +
> > +	for (i = 0; i < edma->ll_wr_cnt; i++)
> > +		if (edma->ll_region_wr[i].sz)
> > +			ll_cnt++;
> > +
> > +	for (i = 0; i < edma->ll_rd_cnt; i++)
> > +		if (edma->ll_region_rd[i].sz)
> > +			ll_cnt++;
> > +
> > +	needed = 1 + ll_cnt;
> > +
> > +	/* Count query mode */
> > +	if (!resources || !num_resources)
> > +		return needed;

^[1] count-query implementation

> > +
> > +	if (num_resources < needed)
> > +		return -ENOSPC;
> 
> How to predict how many 'num_resources' needs?  provide
> dw_pcie_ep_get_resource_number()?
> 
> Or dw_pcie_ep_get_remote_resources(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
>                              struct pci_epc_remote_resource *resources,
>                              int *num_resources)
> 
> return number_resource validate.  if resources is NULL, just return how
> many resource needed.

This is already supported by the current implementation: in
dw_pcie_ep_get_remote_resources(), if resources is NULL (or num_resources
is 0), it returns the number of entries required (see [1] above). Callers
can therefore first query the count and then call again with a properly
sized array.

This behavior is also documented in the core API added in [PATCH v3 06/11]
(pci_epc_get_remote_resources()).

    + * Return:
  > + *   * >= 0: number of resources returned (or required, if @resources is NULL)
    + *   * -EOPNOTSUPP: backend does not support remote resource queries
    + *   * other -errno on failure
    + */
    +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)

Thanks,
Koichiro

> 
> Frank
> > +
> > +	resources[idx++] = (struct pci_epc_remote_resource) {
> > +		.type = PCI_EPC_RR_DMA_CTRL_MMIO,
> > +		.phys_addr = dma_phys,
> > +		.size = dma_size,
> > +	};
> > +
> > +	/* One LL region per write channel */
> > +	for (i = 0; i < edma->ll_wr_cnt; i++) {
> > +		if (!edma->ll_region_wr[i].sz)
> > +			continue;
> > +
> > +		resources[idx++] = (struct pci_epc_remote_resource) {
> > +			.type = PCI_EPC_RR_DMA_CHAN_DESC,
> > +			.phys_addr = edma->ll_region_wr[i].paddr,
> > +			.size = edma->ll_region_wr[i].sz,
> > +			.u.dma_chan_desc.hw_chan_id = i,
> > +			.u.dma_chan_desc.ep2rc = true,
> > +		};
> > +	}
> > +
> > +	/* One LL region per read channel */
> > +	for (i = 0; i < edma->ll_rd_cnt; i++) {
> > +		if (!edma->ll_region_rd[i].sz)
> > +			continue;
> > +
> > +		resources[idx++] = (struct pci_epc_remote_resource) {
> > +			.type = PCI_EPC_RR_DMA_CHAN_DESC,
> > +			.phys_addr = edma->ll_region_rd[i].paddr,
> > +			.size = edma->ll_region_rd[i].sz,
> > +			.u.dma_chan_desc.hw_chan_id = i,
> > +			.u.dma_chan_desc.ep2rc = false,
> > +		};
> > +	}
> > +
> > +	return idx;
> > +}
> > +
> >  static const struct pci_epc_ops epc_ops = {
> >  	.write_header		= dw_pcie_ep_write_header,
> >  	.set_bar		= dw_pcie_ep_set_bar,
> > @@ -823,6 +896,7 @@ static const struct pci_epc_ops epc_ops = {
> >  	.start			= dw_pcie_ep_start,
> >  	.stop			= dw_pcie_ep_stop,
> >  	.get_features		= dw_pcie_ep_get_features,
> > +	.get_remote_resources	= dw_pcie_ep_get_remote_resources,
> >  };
> >
> >  /**
> > --
> > 2.51.0
> >

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

* Re: [PATCH v3 09/11] PCI: endpoint: pci-epf-test: Add smoke test for EPC remote resource API
  2026-02-04 19:37   ` Frank Li
@ 2026-02-05  7:01     ` Koichiro Den
  0 siblings, 0 replies; 32+ messages in thread
From: Koichiro Den @ 2026-02-05  7:01 UTC (permalink / raw)
  To: Frank Li
  Cc: vkoul, mani, jingoohan1, lpieralisi, kwilczynski, robh, bhelgaas,
	dmaengine, linux-pci, linux-kernel

On Wed, Feb 04, 2026 at 02:37:08PM -0500, Frank Li wrote:
> On Wed, Feb 04, 2026 at 11:54:37PM +0900, Koichiro Den wrote:
> > Add a new pci-epf-test command that exercises the newly added EPC API
> > pci_epc_get_remote_resources().
> >
> > The test is intentionally a smoke test. It verifies that the API either
> > returns -EOPNOTSUPP or a well-formed resource list (non-zero phys/size
> > and known resource types). The result is reported to the host via a
> > status bit and an interrupt, consistent with existing pci-epf-test
> > commands.
> >
> > Signed-off-by: Koichiro Den <den@valinux.co.jp>
> > ---
> >  drivers/pci/endpoint/functions/pci-epf-test.c | 88 +++++++++++++++++++
> >  1 file changed, 88 insertions(+)
> >
> > diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
> > index 6952ee418622..6446a0a23865 100644
> > --- a/drivers/pci/endpoint/functions/pci-epf-test.c
> > +++ b/drivers/pci/endpoint/functions/pci-epf-test.c
> > @@ -35,6 +35,7 @@
> >  #define COMMAND_DISABLE_DOORBELL	BIT(7)
> >  #define COMMAND_BAR_SUBRANGE_SETUP	BIT(8)
> >  #define COMMAND_BAR_SUBRANGE_CLEAR	BIT(9)
> > +#define COMMAND_EPC_API			BIT(10)
> >
> >  #define STATUS_READ_SUCCESS		BIT(0)
> >  #define STATUS_READ_FAIL		BIT(1)
> > @@ -54,6 +55,8 @@
> >  #define STATUS_BAR_SUBRANGE_SETUP_FAIL		BIT(15)
> >  #define STATUS_BAR_SUBRANGE_CLEAR_SUCCESS	BIT(16)
> >  #define STATUS_BAR_SUBRANGE_CLEAR_FAIL		BIT(17)
> > +#define STATUS_EPC_API_SUCCESS		BIT(18)
> > +#define STATUS_EPC_API_FAIL		BIT(19)
> >
> >  #define FLAG_USE_DMA			BIT(0)
> >
> > @@ -967,6 +970,87 @@ static void pci_epf_test_bar_subrange_clear(struct pci_epf_test *epf_test,
> >  	reg->status = cpu_to_le32(status);
> >  }
> >
> > +static void pci_epf_test_epc_api(struct pci_epf_test *epf_test,
> > +				 struct pci_epf_test_reg *reg)
> > +{
> > +	struct pci_epc_remote_resource *resources = NULL;
> > +	u32 status = le32_to_cpu(reg->status);
> > +	struct pci_epf *epf = epf_test->epf;
> > +	struct device *dev = &epf->dev;
> > +	struct pci_epc *epc = epf->epc;
> > +	int num_resources;
> > +	int ret, i;
> > +
> > +	num_resources = pci_epc_get_remote_resources(epc, epf->func_no,
> > +						     epf->vfunc_no, NULL, 0);
> > +	if (num_resources == -EOPNOTSUPP || num_resources == 0)
> > +		goto out_success;
> > +	if (num_resources < 0)
> > +		goto err;
> > +
> > +	resources = kcalloc(num_resources, sizeof(*resources), GFP_KERNEL);
> 
> use auto cleanup
> 	struct pci_epc_remote_resource *resources __free(kfree) =
> 		kcalloc(num_resources, sizeof(*resources), GFP_KERNEL);

I'll update it, thanks for pointing that out.
> 
> > +	if (!resources)
> > +		goto err;
> > +
> > +	ret = pci_epc_get_remote_resources(epc, epf->func_no, epf->vfunc_no,
> > +					   resources, num_resources);
> > +	if (ret < 0) {
> > +		dev_err(dev, "EPC remote resource query failed: %d\n", ret);
> > +		goto err_free;
> > +	}
> > +	if (ret > num_resources) {
> > +		dev_err(dev, "EPC API returned %d resources (max %d)\n",
> > +			ret, num_resources);
> > +		goto err_free;
> > +	}
> > +
> > +	for (i = 0; i < ret; i++) {
> > +		struct pci_epc_remote_resource *res = &resources[i];
> > +
> > +		if (!res->phys_addr || !res->size) {
> > +			dev_err(dev,
> > +				"Invalid remote resource[%d] (type=%d phys=%pa size=%llu)\n",
> > +				i, res->type, &res->phys_addr, res->size);
> > +			goto err_free;
> > +		}
> > +
> > +		/* Guard against address overflow */
> > +		if (res->phys_addr + res->size < res->phys_addr) {
> > +			dev_err(dev,
> > +				"Remote resource[%d] overflow (phys=%pa size=%llu)\n",
> > +				i, &res->phys_addr, res->size);
> > +			goto err_free;
> > +		}
> > +
> > +		switch (res->type) {
> > +		case PCI_EPC_RR_DMA_CTRL_MMIO:
> > +			/* Generic checks above are sufficient. */
> > +			break;
> > +		case PCI_EPC_RR_DMA_CHAN_DESC:
> > +			/*
> > +			 * hw_chan_id and ep2rc are informational. No extra validation
> > +			 * beyond the generic checks above is needed.
> > +			 */
> > +			break;
> > +		default:
> > +			dev_err(dev, "Unknown remote resource type %d\n", res->type);
> > +			goto err_free;
> 
> can you call subrange to map to one of bar?

Just for the record, BAR_SUBRANGE_TEST has already landed into the tree and
excercises BAR subrange mapping end-to-end.

In my opinion, simply mapping the returned resources into BAR subranges
here would mostly duplicate the existing subrange test unless we also add
host side validation, and some resource types may be MMIO, so I'd prefer to
keep this as a smoke test. If you had a specific failure mode in mind that
is not covered by BAR_SUBRANGE_TEST, please let me know, I can try to add a
targeted check.

Thanks for the review,
Koichiro

> 
> Frank
> > +		}
> > +	}
> > +
> > +out_success:
> > +	kfree(resources);
> > +	status |= STATUS_EPC_API_SUCCESS;
> > +	reg->status = cpu_to_le32(status);
> > +	return;
> > +
> > +err_free:
> > +	kfree(resources);
> > +err:
> > +	status |= STATUS_EPC_API_FAIL;
> > +	reg->status = cpu_to_le32(status);
> > +}
> > +
> >  static void pci_epf_test_cmd_handler(struct work_struct *work)
> >  {
> >  	u32 command;
> > @@ -1030,6 +1114,10 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
> >  		pci_epf_test_bar_subrange_clear(epf_test, reg);
> >  		pci_epf_test_raise_irq(epf_test, reg);
> >  		break;
> > +	case COMMAND_EPC_API:
> > +		pci_epf_test_epc_api(epf_test, reg);
> > +		pci_epf_test_raise_irq(epf_test, reg);
> > +		break;
> >  	default:
> >  		dev_err(dev, "Invalid command 0x%x\n", command);
> >  		break;
> > --
> > 2.51.0
> >

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

* Re: [PATCH v3 01/11] dmaengine: Add hw_id to dma_slave_caps
  2026-02-05  6:46     ` Koichiro Den
@ 2026-02-05 16:04       ` Frank Li
  0 siblings, 0 replies; 32+ messages in thread
From: Frank Li @ 2026-02-05 16:04 UTC (permalink / raw)
  To: Koichiro Den
  Cc: vkoul, mani, jingoohan1, lpieralisi, kwilczynski, robh, bhelgaas,
	dmaengine, linux-pci, linux-kernel

On Thu, Feb 05, 2026 at 03:46:37PM +0900, Koichiro Den wrote:
> On Wed, Feb 04, 2026 at 02:39:03PM -0500, Frank Li wrote:
> > On Wed, Feb 04, 2026 at 11:54:29PM +0900, Koichiro Den wrote:
> > > 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;
> >
> > I have not see where use it? Does src_id of struct dma_chan work?
>
> There is no direct user of hw_id in this series. The intended flow is:
>   1. obtain dma channels to expose via the standard dma_request_channel()
>   2. get 'hw_id' for each obtained channel (with this patch, Patch v3 1/11)
>   3. call the pci_epc_get_remote_resources() API (introduced in Patch v3 6/11)
>   4. iterate the resource list obtained in step 3, and find a resource whose
>      .type is PCI_EPC_RR_DMA_CHAN_DESC and .u.dma_chan_desc.hw_chan_id
>      matches 'hw_id' obtained in step 2.
>
> By the way, I couldn't find any 'src_id' field in struct dma_chan.
> Did you mean dma_chan.chan_id? If so, it's explicitly a sysfs ID and is
> allocated by the dmaengine core (from dma_device->chan_ida), so it doesn't
> correlate with the provider's HW channel numbering.

Yes, I think it'd better to align HW channel numberring, we should extent
API to allow set it to hardware id or add hw_id in struct dma_chan.

hw_id is not caps.

>
> (Also, correction to my note in the previous v2 thread:
>  https://lore.kernel.org/all/zqcu3awadvqbtil3vudcmgjyjpku7divrhqyox72k43nfzcoo7@hflaengfjy27/
>  There I wrote that the low-level dma channel id would become unnecessary,
>  but that was incorrect because dma_request_channel() does not provide any
>  guarantee that channels are allocated in hw channel order: other,
>  unrelated components may have requested dma channels earlier or in
>  parallel, so the set of channels obtained by a given user cannot be
>  assumed to map cleanly to hw-level channel IDs starting from 0. So this v3 still
>  includes this patch. That said, since there are no direct users in this
>  series, I am open to dropping Patch v3 1/11-2/11 if you think that would
>  be preferable.)

I think struct dma_chan should carry hardware id information.

Frank
>
> Thanks,
> Koichiro
>
> >
> > Frank
> >
> > >  };
> > >
> > >  static inline const char *dma_chan_name(struct dma_chan *chan)
> > > --
> > > 2.51.0
> > >

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

* Re: [PATCH v3 03/11] dmaengine: dw-edma: Add per-channel interrupt routing control
  2026-02-05  6:48     ` Koichiro Den
@ 2026-02-05 16:05       ` Frank Li
  0 siblings, 0 replies; 32+ messages in thread
From: Frank Li @ 2026-02-05 16:05 UTC (permalink / raw)
  To: Koichiro Den
  Cc: vkoul, mani, jingoohan1, lpieralisi, kwilczynski, robh, bhelgaas,
	dmaengine, linux-pci, linux-kernel

On Thu, Feb 05, 2026 at 03:48:30PM +0900, Koichiro Den wrote:
> On Wed, Feb 04, 2026 at 12:42:41PM -0500, Frank Li wrote:
> > On Wed, Feb 04, 2026 at 11:54:31PM +0900, Koichiro Den wrote:
> > > 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.
> > >
> > > For now, HDMA is not supported for the peripheral_config. Until the
> > > support is implemented and validated, explicitly reject it for HDMA to
> > > avoid silently misconfiguring interrupt routing.
> > >
> > > Signed-off-by: Koichiro Den <den@valinux.co.jp>
> > > ---
> > >  drivers/dma/dw-edma/dw-edma-core.c    | 24 +++++++++++++++++++++++
> > >  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, 83 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..b4cb02d545bd 100644
> > > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > > @@ -224,6 +224,29 @@ 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 (chan->dw->chip->mf == EDMA_MF_HDMA_NATIVE)
> > > +			return -EOPNOTSUPP;
> > > +
> > > +		if (config->peripheral_size < sizeof(*pcfg))
> > > +			return -EINVAL;
> >
> > It is good to check here.
> >
> > > +
> > > +		pcfg = config->peripheral_config;
> >
> > save whole peripheral_config in case need more special peripheral
> > configuration in future.
>
> Ok, while I initially thought a deep copy (snapshot) was unnecessary for
> now, I agree it makes future extensions easier. I'll do so.


>
> >
> > > +		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;
> > > +		}
> > > +	}
> >
> > use helper function to get irq_mode. [...]
>
> Ok, my current plan is to keep chan->irq_mode as sticky per-channel state,
> and factor out the parsing/validation of irq_mode (from
> config->peripheral_config) into a small helper used by
> dw_edma_device_config() and the new prep_config path.
>
> Does this match what you meant by "helper function"?

yes.

Frank
>
> > [...] I posted combine config and prep by
> > one call.
> >
> > https://lore.kernel.org/dmaengine/20260105-dma_prep_config-v3-0-a8480362fd42@nxp.com/
> >
> > So we use such helper to get irq node after above patch merge. It is not
> > big deal, I can change it later. If provide helper funtions, it will be
> > slice better.
> >
> > >
> > >  	memcpy(&chan->config, config, sizeof(*config));
> > >  	chan->configured = true;
> > > @@ -750,6 +773,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);
> > ...
> > >
> > > +/*
> > > + * 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
> >
> > keep consistent after "," for each enum
>
> Ok, will add ", local interrupt unmasked" for it.
>
> Thanks for the review,
> Koichiro
>
> >
> > Frank
> >
> > > + * @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] 32+ messages in thread

* Re: [PATCH v3 04/11] dmaengine: Add selfirq callback registration API
  2026-02-05  6:50     ` Koichiro Den
@ 2026-02-05 16:07       ` Frank Li
  0 siblings, 0 replies; 32+ messages in thread
From: Frank Li @ 2026-02-05 16:07 UTC (permalink / raw)
  To: Koichiro Den
  Cc: vkoul, mani, jingoohan1, lpieralisi, kwilczynski, robh, bhelgaas,
	dmaengine, linux-pci, linux-kernel

On Thu, Feb 05, 2026 at 03:50:59PM +0900, Koichiro Den wrote:
> On Wed, Feb 04, 2026 at 12:46:36PM -0500, Frank Li wrote:
> > On Wed, Feb 04, 2026 at 11:54:32PM +0900, Koichiro Den wrote:
> > > Some DMA controllers can generate an interrupt by software writing to a
> > > register, without updating the normal interrupt status bits. This can be
> > > used as a doorbell mechanism when the DMA engine is remotely programmed,
> > > or for self-tests.
> > >
> > > Add an optional per-DMA-device API to register/unregister callbacks for
> > > such "selfirq" events. Providers may invoke these callbacks from their
> > > interrupt handler when they detect an emulated interrupt.
> > >
> > > Callbacks are invoked in hardirq context and must not sleep.
> >
> > Is it possible register shared irq handle with the same channel's irq
> > number?
>
> The proposed dmaengine_{register,unregister}_selfirq() APIs are device-wide
> (i.e. not per channel), so I'm not sure which "channel" you refer to here.
> Also, when chip->nr_irqs > 1 on EP, dw-edma distributes channels across
> multiple IRQ vectors, and it's unclear (at least to me) which IRQ vector
> the emulated interrupt ("fake irq") is expected to be delivered on.
>
> That said, technically, yes I agree adding another handler should be
> possible, as dw-edma currently requests its irq(s) with IRQF_SHARED.
> However, for a consumer driver to do request_irq() on its own, I think it
> would need a stable way to obtain the irq number. Today that mapping seems
> platform-specific and hidden behind dw_edma_plat_ops->irq_vector().

next patch, you add API to get resource, irq number should be one type of
resource.

Frank

>
> Would you prefer exposing a helper for obtaining the irq number (or
> exporting the mapping in some form) instead of adding the dmaengine selfirq
> API, or did you have another approach in mind?
>
> Thanks for the review,
> Koichiro
>
> >
> > Frank
> >
> > >
> > > Signed-off-by: Koichiro Den <den@valinux.co.jp>
> > > ---
> > >  include/linux/dmaengine.h | 70 +++++++++++++++++++++++++++++++++++++++
> > >  1 file changed, 70 insertions(+)
> > >
> > > diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h
> > > index 71bc2674567f..9c6194e8bfe1 100644
> > > --- a/include/linux/dmaengine.h
> > > +++ b/include/linux/dmaengine.h
> > > @@ -785,6 +785,17 @@ struct dma_filter {
> > >  	const struct dma_slave_map *map;
> > >  };
> > >
> > > +/**
> > > + * dma_selfirq_fn - callback for emulated/self IRQ events
> > > + * @dev: DMA device invoking the callback
> > > + * @data: opaque pointer provided at registration time
> > > + *
> > > + * Providers may invoke this callback from their interrupt handler when an
> > > + * emulated interrupt ("selfirq") might have occurred. The callback runs in
> > > + * hardirq context and must not sleep.
> > > + */
> > > +typedef void (*dma_selfirq_fn)(struct dma_device *dev, void *data);
> > > +
> > >  /**
> > >   * struct dma_device - info on the entity supplying DMA services
> > >   * @ref: reference is taken and put every time a channel is allocated or freed
> > > @@ -853,6 +864,10 @@ struct dma_filter {
> > >   *	or an error code
> > >   * @device_synchronize: Synchronizes the termination of a transfers to the
> > >   *  current context.
> > > + * @device_register_selfirq: optional callback registration for
> > > + *	emulated/self IRQ events
> > > + * @device_unregister_selfirq: unregister previously registered selfirq
> > > + *	callback
> > >   * @device_tx_status: poll for transaction completion, the optional
> > >   *	txstate parameter can be supplied with a pointer to get a
> > >   *	struct with auxiliary transfer status information, otherwise the call
> > > @@ -951,6 +966,11 @@ struct dma_device {
> > >  	int (*device_terminate_all)(struct dma_chan *chan);
> > >  	void (*device_synchronize)(struct dma_chan *chan);
> > >
> > > +	int (*device_register_selfirq)(struct dma_device *dev,
> > > +				       dma_selfirq_fn fn, void *data);
> > > +	void (*device_unregister_selfirq)(struct dma_device *dev,
> > > +					  dma_selfirq_fn fn, void *data);
> > > +
> > >  	enum dma_status (*device_tx_status)(struct dma_chan *chan,
> > >  					    dma_cookie_t cookie,
> > >  					    struct dma_tx_state *txstate);
> > > @@ -1197,6 +1217,56 @@ static inline void dmaengine_synchronize(struct dma_chan *chan)
> > >  		chan->device->device_synchronize(chan);
> > >  }
> > >
> > > +/**
> > > + * dmaengine_register_selfirq() - Register a callback for emulated/self IRQ
> > > + *                                events
> > > + * @dev: DMA device
> > > + * @fn: callback invoked from the provider's IRQ handler
> > > + * @data: opaque callback data
> > > + *
> > > + * Some DMA controllers can raise an interrupt by software writing to a
> > > + * register without updating normal status bits. Providers may call
> > > + * registered callbacks from their interrupt handler when such events may
> > > + * have occurred.
> > > + * Callbacks are invoked in hardirq context and must not sleep.
> > > + *
> > > + * Return: 0 on success, -EOPNOTSUPP if unsupported, -EINVAL on bad args,
> > > + * or provider-specific -errno.
> > > + */
> > > +static inline int dmaengine_register_selfirq(struct dma_device *dev,
> > > +					     dma_selfirq_fn fn, void *data)
> > > +{
> > > +	if (!dev || !fn)
> > > +		return -EINVAL;
> > > +	if (!dev->device_register_selfirq)
> > > +		return -EOPNOTSUPP;
> > > +
> > > +	return dev->device_register_selfirq(dev, fn, data);
> > > +}
> > > +
> > > +/**
> > > + * dmaengine_unregister_selfirq() - Unregister a previously registered
> > > + *                                  selfirq callback
> > > + * @dev: DMA device
> > > + * @fn: callback pointer used at registration time
> > > + * @data: opaque pointer used at registration time
> > > + *
> > > + * Unregister a callback previously registered via
> > > + * dmaengine_register_selfirq(). Providers may synchronize against
> > > + * in-flight callbacks, therefore this function may sleep and must not be
> > > + * called from atomic context.
> > > + */
> > > +static inline void dmaengine_unregister_selfirq(struct dma_device *dev,
> > > +						dma_selfirq_fn fn, void *data)
> > > +{
> > > +	if (!dev || !fn)
> > > +		return;
> > > +	if (!dev->device_unregister_selfirq)
> > > +		return;
> > > +
> > > +	dev->device_unregister_selfirq(dev, fn, data);
> > > +}
> > > +
> > >  /**
> > >   * dmaengine_terminate_sync() - Terminate all active DMA transfers
> > >   * @chan: The channel for which to terminate the transfers
> > > --
> > > 2.51.0
> > >

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

* Re: [PATCH v3 06/11] PCI: endpoint: Add remote resource query API
  2026-02-05  6:53     ` Koichiro Den
@ 2026-02-05 16:10       ` Frank Li
  0 siblings, 0 replies; 32+ messages in thread
From: Frank Li @ 2026-02-05 16:10 UTC (permalink / raw)
  To: Koichiro Den
  Cc: vkoul, mani, jingoohan1, lpieralisi, kwilczynski, robh, bhelgaas,
	dmaengine, linux-pci, linux-kernel

On Thu, Feb 05, 2026 at 03:53:52PM +0900, Koichiro Den wrote:
> On Wed, Feb 04, 2026 at 12:55:58PM -0500, Frank Li wrote:
> > On Wed, Feb 04, 2026 at 11:54:34PM +0900, Koichiro Den wrote:
> > > Endpoint controller drivers may integrate auxiliary blocks (e.g. DMA
> > > engines) whose register windows and descriptor memories metadata need to
> > > be exposed to a remote peer. Endpoint function drivers need a generic
> > > way to discover such resources without hard-coding controller-specific
> > > helpers.
> > >
> > > Add pci_epc_get_remote_resources() and the corresponding pci_epc_ops
> > > get_remote_resources() callback. The API returns a list of resources
> > > described by type, physical address and size, plus type-specific
> > > metadata.
> > >
> > > Passing resources == NULL (or num_resources == 0) returns the required
> > > number of entries.
> > >
> > > Signed-off-by: Koichiro Den <den@valinux.co.jp>
> > > ---
> > >  drivers/pci/endpoint/pci-epc-core.c | 41 +++++++++++++++++++++++++
> > >  include/linux/pci-epc.h             | 46 +++++++++++++++++++++++++++++
> > >  2 files changed, 87 insertions(+)
> > >
> > > diff --git a/drivers/pci/endpoint/pci-epc-core.c b/drivers/pci/endpoint/pci-epc-core.c
> > > index 068155819c57..fa161113e24c 100644
> > > --- a/drivers/pci/endpoint/pci-epc-core.c
> > > +++ b/drivers/pci/endpoint/pci-epc-core.c
> > > @@ -155,6 +155,47 @@ const struct pci_epc_features *pci_epc_get_features(struct pci_epc *epc,
> > >  }
> > >  EXPORT_SYMBOL_GPL(pci_epc_get_features);
> > >
> > > +/**
> > > + * pci_epc_get_remote_resources() - query EPC-provided remote resources
> > > + * @epc: EPC device
> > > + * @func_no: function number
> > > + * @vfunc_no: virtual function number
> > > + * @resources: output array (may be NULL to query required count)
> > > + * @num_resources: size of @resources array in entries (0 when querying count)
> > > + *
> > > + * Some EPC backends integrate auxiliary blocks (e.g. DMA engines) whose control
> > > + * registers and/or descriptor memories can be exposed to the host by mapping
> > > + * them into BAR space. This helper queries the backend for such resources.
> > > + *
> > > + * Return:
> > > + *   * >= 0: number of resources returned (or required, if @resources is NULL)
> > > + *   * -EOPNOTSUPP: backend does not support remote resource queries
> > > + *   * other -errno on failure
> > > + */
> > > +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)
> > > +{
> > > +	int ret;
> > > +
> > > +	if (!epc || !epc->ops)
> > > +		return -EINVAL;
> > > +
> > > +	if (func_no >= epc->max_functions)
> > > +		return -EINVAL;
> > > +
> > > +	if (!epc->ops->get_remote_resources)
> > > +		return -EOPNOTSUPP;
> > > +
> > > +	mutex_lock(&epc->lock);
> > > +	ret = epc->ops->get_remote_resources(epc, func_no, vfunc_no,
> > > +					     resources, num_resources);
> > > +	mutex_unlock(&epc->lock);
> > > +
> > > +	return ret;
> > > +}
> > > +EXPORT_SYMBOL_GPL(pci_epc_get_remote_resources);
> > > +
> > >  /**
> > >   * pci_epc_stop() - stop the PCI link
> > >   * @epc: the link of the EPC device that has to be stopped
> > > diff --git a/include/linux/pci-epc.h b/include/linux/pci-epc.h
> > > index c021c7af175f..af60d4ad2f0e 100644
> > > --- a/include/linux/pci-epc.h
> > > +++ b/include/linux/pci-epc.h
> > > @@ -61,6 +61,44 @@ struct pci_epc_map {
> > >  	void __iomem	*virt_addr;
> > >  };
> > >
> > > +/**
> > > + * enum pci_epc_remote_resource_type - remote resource type identifiers
> > > + * @PCI_EPC_RR_DMA_CTRL_MMIO: Integrated DMA controller register window (MMIO)
> > > + * @PCI_EPC_RR_DMA_CHAN_DESC: Per-channel DMA descriptor
> > > + *
> > > + * EPC backends may expose auxiliary blocks (e.g. DMA engines) by mapping their
> > > + * register windows and descriptor memories into BAR space. This enum
> > > + * identifies the type of each exposable resource.
> > > + */
> > > +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
> > > + *
> > > + * For @PCI_EPC_RR_DMA_CHAN_DESC, @u.dma_chan_desc provides per-channel
> > > + * information.
> > > + */
> > > +struct pci_epc_remote_resource {
> > > +	enum pci_epc_remote_resource_type type;
> > > +	phys_addr_t phys_addr;
> > > +	resource_size_t size;
> >
> > is it good use struct resource?
>
> Personally I don't think it's the best fit here, since these remote
> resources are not meant to participate in the global resource tree or
> managed by the resource management framework. And most of struct resource
> fields (name/flags and the links) does not make sense in this context.
>
> >
> > > +
> > > +	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 +122,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)
> >
> > Add comments, must set 'type' of pci_epc_remote_resource.
>
> Would something like the following address your concern?
>
>     * @get_remote_resources: ops to retrieve controller-owned resources that can be
>     *                        exposed to the remote host (optional)
>   + *                        The callback fills @resources (up to @num_resources entries)
>   + *                        and returns the number of valid entries. Each returned entry
>   + *                        must have @type set (which selects the valid union member in @u)
>   + *                        and provide valid @phys_addr/@sizei.

After I review your next patch, I understand API here. It is good.

Frank

>
> Thanks for the review,
> Koichiro
>
> >
> > Over all it is good.
> >
> > Frank
> > >   * @owner: the module owner containing the ops
> > >   */
> > >  struct pci_epc_ops {
> > > @@ -115,6 +155,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 +352,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
> > > --
> > > 2.51.0
> > >

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

* Re: [PATCH v3 08/11] PCI: dwc: ep: Report integrated DWC eDMA remote resources
  2026-02-05  6:58     ` Koichiro Den
@ 2026-02-05 16:11       ` Frank Li
  0 siblings, 0 replies; 32+ messages in thread
From: Frank Li @ 2026-02-05 16:11 UTC (permalink / raw)
  To: Koichiro Den
  Cc: vkoul, mani, jingoohan1, lpieralisi, kwilczynski, robh, bhelgaas,
	dmaengine, linux-pci, linux-kernel

On Thu, Feb 05, 2026 at 03:58:35PM +0900, Koichiro Den wrote:
> On Wed, Feb 04, 2026 at 01:06:27PM -0500, Frank Li wrote:
> > On Wed, Feb 04, 2026 at 11:54:36PM +0900, Koichiro Den wrote:
> > > Implement pci_epc_ops.get_remote_resources() for the DesignWare PCIe
> > > endpoint controller. Report:
> > > - the integrated eDMA control MMIO window
> > > - the per-channel linked-list regions for read/write engines
> > >
> > > This allows endpoint function drivers to discover and map or inform
> > > these resources to a remote peer using the generic EPC API.
> > >
> > > Signed-off-by: Koichiro Den <den@valinux.co.jp>
> > > ---
> > >  .../pci/controller/dwc/pcie-designware-ep.c   | 74 +++++++++++++++++++
> > >  1 file changed, 74 insertions(+)
> > >
> > > diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > > index 7e7844ff0f7e..5c0dcbf18d07 100644
> > > --- a/drivers/pci/controller/dwc/pcie-designware-ep.c
> > > +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c
> > > @@ -808,6 +808,79 @@ dw_pcie_ep_get_features(struct pci_epc *epc, u8 func_no, u8 vfunc_no)
> > >  	return ep->ops->get_features(ep);
> > >  }
> > >
> > > +static int
> > > +dw_pcie_ep_get_remote_resources(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
> > > +				struct pci_epc_remote_resource *resources,
> > > +				int num_resources)
> > > +{
> > > +	struct dw_pcie_ep *ep = epc_get_drvdata(epc);
> > > +	struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
> > > +	struct dw_edma_chip *edma = &pci->edma;
> > > +	int ll_cnt = 0, needed, idx = 0;
> > > +	resource_size_t dma_size;
> > > +	phys_addr_t dma_phys;
> > > +	unsigned int i;
> > > +
> > > +	if (!pci->edma_reg_size)
> > > +		return 0;
> > > +
> > > +	dma_phys = pci->edma_reg_phys;
> > > +	dma_size = pci->edma_reg_size;
> > > +
> > > +	for (i = 0; i < edma->ll_wr_cnt; i++)
> > > +		if (edma->ll_region_wr[i].sz)
> > > +			ll_cnt++;
> > > +
> > > +	for (i = 0; i < edma->ll_rd_cnt; i++)
> > > +		if (edma->ll_region_rd[i].sz)
> > > +			ll_cnt++;
> > > +
> > > +	needed = 1 + ll_cnt;
> > > +
> > > +	/* Count query mode */
> > > +	if (!resources || !num_resources)
> > > +		return needed;
>
> ^[1] count-query implementation
>
> > > +
> > > +	if (num_resources < needed)
> > > +		return -ENOSPC;
> >
> > How to predict how many 'num_resources' needs?  provide
> > dw_pcie_ep_get_resource_number()?
> >
> > Or dw_pcie_ep_get_remote_resources(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
> >                              struct pci_epc_remote_resource *resources,
> >                              int *num_resources)
> >
> > return number_resource validate.  if resources is NULL, just return how
> > many resource needed.
>
> This is already supported by the current implementation: in
> dw_pcie_ep_get_remote_resources(), if resources is NULL (or num_resources
> is 0), it returns the number of entries required (see [1] above). Callers
> can therefore first query the count and then call again with a properly
> sized array.
>
> This behavior is also documented in the core API added in [PATCH v3 06/11]
> (pci_epc_get_remote_resources()).
>
>     + * Return:
>   > + *   * >= 0: number of resources returned (or required, if @resources is NULL)
>     + *   * -EOPNOTSUPP: backend does not support remote resource queries
>     + *   * other -errno on failure
>     + */
>     +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)

Sorry, I missed it.

Frank

>
> Thanks,
> Koichiro
>
> >
> > Frank
> > > +
> > > +	resources[idx++] = (struct pci_epc_remote_resource) {
> > > +		.type = PCI_EPC_RR_DMA_CTRL_MMIO,
> > > +		.phys_addr = dma_phys,
> > > +		.size = dma_size,
> > > +	};
> > > +
> > > +	/* One LL region per write channel */
> > > +	for (i = 0; i < edma->ll_wr_cnt; i++) {
> > > +		if (!edma->ll_region_wr[i].sz)
> > > +			continue;
> > > +
> > > +		resources[idx++] = (struct pci_epc_remote_resource) {
> > > +			.type = PCI_EPC_RR_DMA_CHAN_DESC,
> > > +			.phys_addr = edma->ll_region_wr[i].paddr,
> > > +			.size = edma->ll_region_wr[i].sz,
> > > +			.u.dma_chan_desc.hw_chan_id = i,
> > > +			.u.dma_chan_desc.ep2rc = true,
> > > +		};
> > > +	}
> > > +
> > > +	/* One LL region per read channel */
> > > +	for (i = 0; i < edma->ll_rd_cnt; i++) {
> > > +		if (!edma->ll_region_rd[i].sz)
> > > +			continue;
> > > +
> > > +		resources[idx++] = (struct pci_epc_remote_resource) {
> > > +			.type = PCI_EPC_RR_DMA_CHAN_DESC,
> > > +			.phys_addr = edma->ll_region_rd[i].paddr,
> > > +			.size = edma->ll_region_rd[i].sz,
> > > +			.u.dma_chan_desc.hw_chan_id = i,
> > > +			.u.dma_chan_desc.ep2rc = false,
> > > +		};
> > > +	}
> > > +
> > > +	return idx;
> > > +}
> > > +
> > >  static const struct pci_epc_ops epc_ops = {
> > >  	.write_header		= dw_pcie_ep_write_header,
> > >  	.set_bar		= dw_pcie_ep_set_bar,
> > > @@ -823,6 +896,7 @@ static const struct pci_epc_ops epc_ops = {
> > >  	.start			= dw_pcie_ep_start,
> > >  	.stop			= dw_pcie_ep_stop,
> > >  	.get_features		= dw_pcie_ep_get_features,
> > > +	.get_remote_resources	= dw_pcie_ep_get_remote_resources,
> > >  };
> > >
> > >  /**
> > > --
> > > 2.51.0
> > >

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

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

Thread overview: 32+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-04 14:54 [PATCH v3 00/11] dmaengine, PCI: endpoint: Enable remote use of integrated DesignWare eDMA Koichiro Den
2026-02-04 14:54 ` [PATCH v3 01/11] dmaengine: Add hw_id to dma_slave_caps Koichiro Den
2026-02-04 19:39   ` Frank Li
2026-02-05  6:46     ` Koichiro Den
2026-02-05 16:04       ` Frank Li
2026-02-04 14:54 ` [PATCH v3 02/11] dmaengine: dw-edma: Report channel hw_id in dma_slave_caps Koichiro Den
2026-02-04 14:54 ` [PATCH v3 03/11] dmaengine: dw-edma: Add per-channel interrupt routing control Koichiro Den
2026-02-04 17:42   ` Frank Li
2026-02-05  6:48     ` Koichiro Den
2026-02-05 16:05       ` Frank Li
2026-02-04 14:54 ` [PATCH v3 04/11] dmaengine: Add selfirq callback registration API Koichiro Den
2026-02-04 17:46   ` Frank Li
2026-02-05  6:50     ` Koichiro Den
2026-02-05 16:07       ` Frank Li
2026-02-04 14:54 ` [PATCH v3 05/11] dmaengine: dw-edma: Implement dmaengine selfirq callbacks using interrupt emulation Koichiro Den
2026-02-04 14:54 ` [PATCH v3 06/11] PCI: endpoint: Add remote resource query API Koichiro Den
2026-02-04 17:55   ` Frank Li
2026-02-05  6:53     ` Koichiro Den
2026-02-05 16:10       ` Frank Li
2026-02-04 14:54 ` [PATCH v3 07/11] PCI: dwc: Record integrated eDMA register window Koichiro Den
2026-02-04 17:57   ` Frank Li
2026-02-04 14:54 ` [PATCH v3 08/11] PCI: dwc: ep: Report integrated DWC eDMA remote resources Koichiro Den
2026-02-04 18:06   ` Frank Li
2026-02-05  6:58     ` Koichiro Den
2026-02-05 16:11       ` Frank Li
2026-02-04 14:54 ` [PATCH v3 09/11] PCI: endpoint: pci-epf-test: Add smoke test for EPC remote resource API Koichiro Den
2026-02-04 19:37   ` Frank Li
2026-02-05  7:01     ` Koichiro Den
2026-02-05  0:01   ` kernel test robot
2026-02-05  2:37   ` kernel test robot
2026-02-04 14:54 ` [PATCH v3 10/11] misc: pci_endpoint_test: Add EPC remote resource API test ioctl Koichiro Den
2026-02-04 14:54 ` [PATCH v3 11/11] selftests: pci_endpoint: Add EPC remote resource API test Koichiro Den

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox