mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v2 00/12] dmaengine: dw-edma: Prepare for PCI EP DMA (part 1/3)
@ 2026-05-25  6:24 Koichiro Den
  2026-05-25  6:24 ` [PATCH v2 01/12] dmaengine: dw-edma: Add hardware channel filter Koichiro Den
                   ` (11 more replies)
  0 siblings, 12 replies; 24+ messages in thread
From: Koichiro Den @ 2026-05-25  6:24 UTC (permalink / raw)
  To: Vinod Koul, Frank Li, Manivannan Sadhasivam
  Cc: Marek Vasut, Yoshihiro Shimoda, dmaengine, linux-kernel

Hi,

This is v2, part 1 of three series for PCI endpoint DMA.

The three series are:

  * part 1: dmaengine: dw-edma: Prepare for PCI EP DMA
  * part 2: PCI: endpoint: Expose endpoint DMA resources
  * part 3: PCI: endpoint: Add PCI DMA endpoint function

This first series contains the dmaengine and dw-edma groundwork needed
to let a PCI endpoint function delegate selected endpoint-integrated DMA
channels to a PCI host. It does not add the endpoint function itself.


Background
==========

I previously posted this RFC:

  [PATCH 00/15] PCI: endpoint: Remote DMA support via vNTB
  https://lore.kernel.org/linux-pci/20260312165005.1148676-1-den@valinux.co.jp/

That design exposed the endpoint-local PCIe DMA engine through
vNTB. This version moves the DMA engine into its own endpoint function
instead. The host then sees a DMA controller PCI function, and vNTB does
not need to carry a DMA-specific ABI.

The immediate motivation is NTB transport between a directly attached EP
and RC. The goal is to use the endpoint-local DMA engine and avoid the
extra CPU copy in both directions.


Scope
=====

This series:

  * adds a dw-edma dma_request_channel() filter for exact hardware channel
    claims,
  * adds per-channel interrupt routing control for delegated channels,
  * adds a partial channel ownership mode for delegated channel sets, and
  * prepares dw-edma-pcie to describe device-specific DMA layouts through
    match data.

The PCI endpoint metadata format, DesignWare endpoint resource exposure,
and the endpoint function driver are added by parts 2 and 3.


Dependencies
============

This series is based on dmaengine/next at:

  362ee0c0dc52 ("dmaengine: Move MODULE_DEVICE_TABLE next to the table itself")

Parts 2 and 3 depend on this series.


Note
====

Pre-existing dw-edma issues flagged by Sashiko during v1 review are
handled separately. See
https://lore.kernel.org/dmaengine/20260521142153.2957432-1-den@valinux.co.jp/


---
Changelog
=========

Changes in v2:
  - Move non-LL state and platform ops into match data. (Frank)
  - Use a named .driver_data initializer for the Xilinx MDB ID entry and
    fix the vsec_data rename patch title. (Frank)
  - Replace the dma_get_slave_channel() export with a dw-edma channel
    filter for dma_request_channel(). (Sashiko)
  - Rework the IRQ-routing config as dw_edma_irq_config, keep HDMA native
    int config separate, and reject remote IRQ mode on local instances.
    (Sashiko)
  - Report IRQ_HANDLED only for status that was actually serviced and drop
    the lockless free_chan_resources() reset. (Sashiko)
  - Tighten partial ownership: reject unsupported map formats early and
    require direction-wide ownership for supported shared-register
    layouts. (Sashiko)

v1: https://lore.kernel.org/dmaengine/20260521063115.2842238-1-den@valinux.co.jp/


Best regards,
Koichiro


Koichiro Den (12):
  dmaengine: dw-edma: Add hardware channel filter
  dmaengine: dw-edma: Add per-channel interrupt routing control
  dmaengine: dw-edma: Add partial channel ownership mode
  dmaengine: dw-edma-pcie: Track non-LL mode in DMA data
  dmaengine: dw-edma-pcie: Add capability match data
  dmaengine: dw-edma-pcie: Rename vsec_data to dma_data
  dmaengine: dw-edma-pcie: Add default IRQ mode to match data
  dmaengine: dw-edma-pcie: Add platform ops to match data
  dmaengine: dw-edma-pcie: Add register offset match flag
  dmaengine: dw-edma-pcie: Factor out descriptor block address lookup
  dmaengine: dw-edma-pcie: Handle optional data blocks
  dmaengine: dw-edma-pcie: Add chip flags to match data

 drivers/dma/dw-edma/dw-edma-core.c    | 128 ++++++++++++--
 drivers/dma/dw-edma/dw-edma-core.h    |  13 ++
 drivers/dma/dw-edma/dw-edma-pcie.c    | 245 +++++++++++++++++---------
 drivers/dma/dw-edma/dw-edma-v0-core.c |  22 ++-
 include/linux/dma/edma.h              |  64 +++++++
 5 files changed, 368 insertions(+), 104 deletions(-)

-- 
2.51.0

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

* [PATCH v2 01/12] dmaengine: dw-edma: Add hardware channel filter
  2026-05-25  6:24 [PATCH v2 00/12] dmaengine: dw-edma: Prepare for PCI EP DMA (part 1/3) Koichiro Den
@ 2026-05-25  6:24 ` Koichiro Den
  2026-06-04 20:40   ` Frank Li
  2026-05-25  6:24 ` [PATCH v2 02/12] dmaengine: dw-edma: Add per-channel interrupt routing control Koichiro Den
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 24+ messages in thread
From: Koichiro Den @ 2026-05-25  6:24 UTC (permalink / raw)
  To: Vinod Koul, Frank Li, Manivannan Sadhasivam
  Cc: Marek Vasut, Yoshihiro Shimoda, dmaengine, linux-kernel

Add a dma_request_channel() filter that matches a DesignWare eDMA
write/read hardware channel by hardware channel number.

PCI endpoint resource enumeration can describe hardware channel metadata
and let consumers claim it through the normal DMAengine request path.
This avoids returning an unclaimed dma_chan pointer to the caller and does
not require making dma_get_slave_channel() public.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
Changes in v2:
  - New patch. Replace the raw channel lookup helper with a
    dma_request_channel() filter.
  - Do not make dma_get_slave_channel() public.
    Patch 01/12 "dmaengine: Make dma_get_slave_channel() public" is
    dropped.

 drivers/dma/dw-edma/dw-edma-core.c | 15 +++++++++++++++
 include/linux/dma/edma.h           | 18 ++++++++++++++++++
 2 files changed, 33 insertions(+)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index c2feb3adc79f..80b4a168225b 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -1189,6 +1189,21 @@ int dw_edma_remove(struct dw_edma_chip *chip)
 }
 EXPORT_SYMBOL_GPL(dw_edma_remove);
 
+bool dw_edma_filter_hw_chan(struct dma_chan *dchan, void *param)
+{
+	struct dw_edma_hw_chan_filter *filter = param;
+	struct dw_edma_chan *chan;
+
+	if (!filter || dchan->device->dev != filter->dma_dev)
+		return false;
+
+	chan = dchan2dw_edma_chan(dchan);
+
+	return chan->dir == (filter->write ? EDMA_DIR_WRITE : EDMA_DIR_READ) &&
+	       chan->id == filter->id;
+}
+EXPORT_SYMBOL_GPL(dw_edma_filter_hw_chan);
+
 MODULE_LICENSE("GPL v2");
 MODULE_DESCRIPTION("Synopsys DesignWare eDMA controller core driver");
 MODULE_AUTHOR("Gustavo Pimentel <gustavo.pimentel@synopsys.com>");
diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
index 1fafd5b0e315..3e15cf83b784 100644
--- a/include/linux/dma/edma.h
+++ b/include/linux/dma/edma.h
@@ -106,10 +106,23 @@ struct dw_edma_chip {
 	bool			cfg_non_ll;
 };
 
+/**
+ * struct dw_edma_hw_chan_filter - DesignWare eDMA hardware channel selector
+ * @dma_dev: DMA controller device to match
+ * @write: true to select a write channel, false to select a read channel
+ * @id: hardware channel number within the selected direction
+ */
+struct dw_edma_hw_chan_filter {
+	struct device	*dma_dev;
+	bool		write;
+	u16		id;
+};
+
 /* Export to the platform drivers */
 #if IS_REACHABLE(CONFIG_DW_EDMA)
 int dw_edma_probe(struct dw_edma_chip *chip);
 int dw_edma_remove(struct dw_edma_chip *chip);
+bool dw_edma_filter_hw_chan(struct dma_chan *chan, void *param);
 #else
 static inline int dw_edma_probe(struct dw_edma_chip *chip)
 {
@@ -120,6 +133,11 @@ static inline int dw_edma_remove(struct dw_edma_chip *chip)
 {
 	return 0;
 }
+
+static inline bool dw_edma_filter_hw_chan(struct dma_chan *chan, void *param)
+{
+	return false;
+}
 #endif /* CONFIG_DW_EDMA */
 
 #endif /* _DW_EDMA_H */
-- 
2.51.0


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

* [PATCH v2 02/12] dmaengine: dw-edma: Add per-channel interrupt routing control
  2026-05-25  6:24 [PATCH v2 00/12] dmaengine: dw-edma: Prepare for PCI EP DMA (part 1/3) Koichiro Den
  2026-05-25  6:24 ` [PATCH v2 01/12] dmaengine: dw-edma: Add hardware channel filter Koichiro Den
@ 2026-05-25  6:24 ` Koichiro Den
  2026-06-04 20:18   ` Frank Li
  2026-05-25  6:24 ` [PATCH v2 03/12] dmaengine: dw-edma: Add partial channel ownership mode Koichiro Den
                   ` (9 subsequent siblings)
  11 siblings, 1 reply; 24+ messages in thread
From: Koichiro Den @ 2026-05-25  6:24 UTC (permalink / raw)
  To: Vinod Koul, Frank Li, Manivannan Sadhasivam
  Cc: Marek Vasut, Yoshihiro Shimoda, dmaengine, linux-kernel

DesignWare eDMA can signal completion locally through edma_int[] and
remotely through IMWr/MSI. When channels are delegated to a remote
frontend, the local endpoint side and the remote host side must not both
service the same DONE/ABORT status.

Add dw_edma_irq_config, carried through dma_slave_config, so a frontend
can choose default, local, or remote IRQ handling per channel. Update the
v0 path so linked-list interrupt generation and DONE/ABORT masking follow
the selected mode. If a frontend does not supply the config, keep the
existing behavior.

HDMA native already uses dma_slave_config.peripheral_config as an int for
non-LL mode selection. Keep that interface unchanged and reject the new
IRQ config there until an IRQ routing model is implemented and validated.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
Changes in v2:
  - Rename dw_edma_peripheral_config to dw_edma_irq_config.
  - Keep the IRQ config distinct from HDMA native's int config.
  - Reject remote-only IRQ mode on local instances.
  - Report IRQ_HANDLED only after servicing non-ignored status.
  - Drop the lockless irq_mode reset in free_chan_resources().
  - Revise the commit message.
  - Drop Frank's Reviewed-by due to the above changes.

 drivers/dma/dw-edma/dw-edma-core.c    | 66 +++++++++++++++++++++++++--
 drivers/dma/dw-edma/dw-edma-core.h    | 13 ++++++
 drivers/dma/dw-edma/dw-edma-v0-core.c | 22 ++++++---
 include/linux/dma/edma.h              | 40 ++++++++++++++++
 4 files changed, 131 insertions(+), 10 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index 80b4a168225b..a70e0640d082 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -219,12 +219,66 @@ static void dw_edma_device_caps(struct dma_chan *dchan,
 	}
 }
 
+static enum dw_edma_ch_irq_mode
+dw_edma_get_default_irq_mode(struct dw_edma_chan *chan)
+{
+	switch (chan->dw->chip->default_irq_mode) {
+	case DW_EDMA_CH_IRQ_DEFAULT:
+	case DW_EDMA_CH_IRQ_LOCAL:
+		return chan->dw->chip->default_irq_mode;
+	case DW_EDMA_CH_IRQ_REMOTE:
+		if (!(chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL))
+			return DW_EDMA_CH_IRQ_REMOTE;
+		return DW_EDMA_CH_IRQ_DEFAULT;
+	default:
+		return DW_EDMA_CH_IRQ_DEFAULT;
+	}
+}
+
+static int dw_edma_parse_irq_mode(struct dw_edma_chan *chan,
+				  const struct dma_slave_config *config,
+				  enum dw_edma_ch_irq_mode *mode)
+{
+	const struct dw_edma_irq_config *pcfg;
+
+	/* peripheral_config is optional, fall back to the frontend default. */
+	*mode = dw_edma_get_default_irq_mode(chan);
+	if (!config || !config->peripheral_config)
+		return 0;
+
+	if (chan->dw->chip->mf == EDMA_MF_HDMA_NATIVE)
+		return -EOPNOTSUPP;
+
+	if (config->peripheral_size != sizeof(*pcfg))
+		return -EINVAL;
+
+	pcfg = config->peripheral_config;
+	if (pcfg->reserved)
+		return -EINVAL;
+
+	switch (pcfg->irq_mode) {
+	case DW_EDMA_CH_IRQ_DEFAULT:
+	case DW_EDMA_CH_IRQ_LOCAL:
+		*mode = pcfg->irq_mode;
+		return 0;
+	case DW_EDMA_CH_IRQ_REMOTE:
+		if (chan->dw->chip->flags & DW_EDMA_CHIP_LOCAL)
+			return -EINVAL;
+		*mode = DW_EDMA_CH_IRQ_REMOTE;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
 static int dw_edma_device_config(struct dma_chan *dchan,
 				 struct dma_slave_config *config)
 {
 	struct dw_edma_chan *chan = dchan2dw_edma_chan(dchan);
+	enum dw_edma_ch_irq_mode mode;
 	bool cfg_non_ll;
 	int non_ll = 0;
+	int ret;
 
 	chan->non_ll = false;
 	if (chan->dw->chip->mf == EDMA_MF_HDMA_NATIVE) {
@@ -255,10 +309,11 @@ static int dw_edma_device_config(struct dma_chan *dchan,
 
 		if (cfg_non_ll || non_ll)
 			chan->non_ll = true;
-	} else if (config->peripheral_config) {
-		dev_err(dchan->device->dev,
-			"peripheral config param applicable only for HDMA\n");
-		return -EINVAL;
+	} else {
+		ret = dw_edma_parse_irq_mode(chan, config, &mode);
+		if (ret)
+			return ret;
+		chan->irq_mode = mode;
 	}
 
 	memcpy(&chan->config, config, sizeof(*config));
@@ -853,6 +908,8 @@ static int dw_edma_alloc_chan_resources(struct dma_chan *dchan)
 	if (chan->status != EDMA_ST_IDLE)
 		return -EBUSY;
 
+	chan->irq_mode = dw_edma_get_default_irq_mode(chan);
+
 	return 0;
 }
 
@@ -904,6 +961,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_get_default_irq_mode(chan);
 
 		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 902574b1ba86..e2aadf0109b6 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;
@@ -224,4 +226,15 @@ dw_edma_core_db_offset(struct dw_edma *dw)
 	return dw->core->db_offset(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 69e8279adec8..08ec2bd7856e 100644
--- a/drivers/dma/dw-edma/dw-edma-v0-core.c
+++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
@@ -256,9 +256,11 @@ 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];
 
+		if (dw_edma_core_ch_ignore_irq(chan))
+			continue;
+
 		dw_edma_v0_core_clear_done_int(chan);
 		done(chan);
-
 		ret = IRQ_HANDLED;
 	}
 
@@ -267,9 +269,11 @@ 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];
 
+		if (dw_edma_core_ch_ignore_irq(chan))
+			continue;
+
 		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 3e15cf83b784..2bf2298711e1 100644
--- a/include/linux/dma/edma.h
+++ b/include/linux/dma/edma.h
@@ -60,6 +60,43 @@ 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:   keep legacy behavior
+ * @DW_EDMA_CH_IRQ_LOCAL:     local interrupt only (edma_int[])
+ * @DW_EDMA_CH_IRQ_REMOTE:    remote interrupt only (IMWr/MSI),
+ *                            while masking local DONE/ABORT output.
+ *
+ * DesignWare EP eDMA can signal interrupts locally through the edma_int[]
+ * bus, and remotely using posted memory writes (IMWr) that may be
+ * interpreted as MSI/MSI-X by the RC.
+ *
+ * For the v0 eDMA programming path, DMA_*_INT_MASK gates the local edma_int[]
+ * assertion, while there is no dedicated per-channel mask for IMWr generation.
+ * To request a remote-only interrupt, Synopsys recommends setting both LIE and
+ * RIE, and masking the local interrupt in DMA_*_INT_MASK (rather than relying
+ * on LIE=0/RIE=1). See the DesignWare endpoint databook 5.40a, Non Linked
+ * List Mode interrupt handling ("Hint").
+ */
+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_irq_config - dw-edma interrupt routing configuration
+ * @irq_mode: per-channel interrupt routing control.
+ * @reserved: must be zero.
+ *
+ * Pass this structure via dma_slave_config.peripheral_config and
+ * dma_slave_config.peripheral_size.
+ */
+struct dw_edma_irq_config {
+	enum dw_edma_ch_irq_mode irq_mode;
+	u32 reserved;
+};
+
 /**
  * struct dw_edma_chip - representation of DesignWare eDMA controller hardware
  * @dev:		 struct device of the eDMA controller
@@ -76,6 +113,8 @@ enum dw_edma_chip_flags {
  * @db_irq:		 Virtual IRQ dedicated to interrupt emulation
  * @db_offset:		 Offset from DMA register base
  * @mf:			 DMA register map format
+ * @default_irq_mode:	 default per-channel interrupt routing when client
+ *			 does not supply dw_edma_irq_config
  * @dw:			 struct dw_edma that is filled by dw_edma_probe()
  */
 struct dw_edma_chip {
@@ -101,6 +140,7 @@ struct dw_edma_chip {
 	resource_size_t		db_offset;
 
 	enum dw_edma_map_format	mf;
+	enum dw_edma_ch_irq_mode	default_irq_mode;
 
 	struct dw_edma		*dw;
 	bool			cfg_non_ll;
-- 
2.51.0


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

* [PATCH v2 03/12] dmaengine: dw-edma: Add partial channel ownership mode
  2026-05-25  6:24 [PATCH v2 00/12] dmaengine: dw-edma: Prepare for PCI EP DMA (part 1/3) Koichiro Den
  2026-05-25  6:24 ` [PATCH v2 01/12] dmaengine: dw-edma: Add hardware channel filter Koichiro Den
  2026-05-25  6:24 ` [PATCH v2 02/12] dmaengine: dw-edma: Add per-channel interrupt routing control Koichiro Den
@ 2026-05-25  6:24 ` Koichiro Den
  2026-06-04 20:24   ` Frank Li
  2026-05-25  6:24 ` [PATCH v2 04/12] dmaengine: dw-edma-pcie: Track non-LL mode in DMA data Koichiro Den
                   ` (8 subsequent siblings)
  11 siblings, 1 reply; 24+ messages in thread
From: Koichiro Den @ 2026-05-25  6:24 UTC (permalink / raw)
  To: Vinod Koul, Frank Li, Manivannan Sadhasivam
  Cc: Marek Vasut, Yoshihiro Shimoda, dmaengine, linux-kernel

Some endpoint DMA frontends expose only a subset of a controller that is
also initialized by the endpoint-side OS. Add a partial ownership flag
so dw-edma does not reset controller-wide state in probe() or remove().

Keep the mode conservative. Do not enable interrupt-emulation doorbells,
and reject partial instances for map formats that this driver cannot safely
share. For EDMA_MF_EDMA_UNROLL and EDMA_MF_HDMA_COMPAT, require ownership
of all channels in each exposed direction. The driver updates registers
shared by all channels in a direction, such as interrupt masks and
linked-list error enables, so two independent OS instances cannot safely
split one direction without a shared locking protocol, which is
unrealistic.

The frontend must still quiesce delegated channels before removing a
partial instance. The flag only keeps probe() and remove() from
resetting controller-wide state that may belong to a peer OS instance.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
Changes in v2:
  - Reject partial ownership for unsupported map formats up front,
    keep direction-granularity validation limited to supported formats.
  - Revise the commit message accordingly.

 drivers/dma/dw-edma/dw-edma-core.c | 47 +++++++++++++++++++++++-------
 include/linux/dma/edma.h           |  6 ++++
 2 files changed, 43 insertions(+), 10 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
index a70e0640d082..fcef9a27b6ce 100644
--- a/drivers/dma/dw-edma/dw-edma-core.c
+++ b/drivers/dma/dw-edma/dw-edma-core.c
@@ -794,6 +794,9 @@ static int dw_edma_emul_irq_alloc(struct dw_edma *dw)
 	chip->db_irq = 0;
 	chip->db_offset = ~0;
 
+	if (chip->flags & DW_EDMA_CHIP_PARTIAL)
+		return 0;
+
 	/*
 	 * Only meaningful when the core provides the deassert sequence
 	 * for interrupt emulation.
@@ -1135,6 +1138,8 @@ int dw_edma_probe(struct dw_edma_chip *chip)
 {
 	struct device *dev;
 	struct dw_edma *dw;
+	u16 hw_wr_ch_cnt;
+	u16 hw_rd_ch_cnt;
 	u32 wr_alloc = 0;
 	u32 rd_alloc = 0;
 	int i, err;
@@ -1146,6 +1151,16 @@ int dw_edma_probe(struct dw_edma_chip *chip)
 	if (!dev || !chip->ops)
 		return -EINVAL;
 
+	if (chip->flags & DW_EDMA_CHIP_PARTIAL) {
+		switch (chip->mf) {
+		case EDMA_MF_EDMA_UNROLL:
+		case EDMA_MF_HDMA_COMPAT:
+			break;
+		default:
+			return -EOPNOTSUPP;
+		}
+	}
+
 	dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL);
 	if (!dw)
 		return -ENOMEM;
@@ -1159,13 +1174,23 @@ int dw_edma_probe(struct dw_edma_chip *chip)
 
 	raw_spin_lock_init(&dw->lock);
 
-	dw->wr_ch_cnt = min_t(u16, chip->ll_wr_cnt,
-			      dw_edma_core_ch_count(dw, EDMA_DIR_WRITE));
-	dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt, EDMA_MAX_WR_CH);
+	hw_wr_ch_cnt = min_t(u16, dw_edma_core_ch_count(dw, EDMA_DIR_WRITE),
+			     EDMA_MAX_WR_CH);
+	hw_rd_ch_cnt = min_t(u16, dw_edma_core_ch_count(dw, EDMA_DIR_READ),
+			     EDMA_MAX_RD_CH);
+
+	if (chip->flags & DW_EDMA_CHIP_PARTIAL) {
+		/*
+		 * Direction-wide registers are shared by all channels in that
+		 * direction, so a direction must have a single owner.
+		 */
+		if ((chip->ll_wr_cnt && chip->ll_wr_cnt != hw_wr_ch_cnt) ||
+		    (chip->ll_rd_cnt && chip->ll_rd_cnt != hw_rd_ch_cnt))
+			return -EOPNOTSUPP;
+	}
 
-	dw->rd_ch_cnt = min_t(u16, chip->ll_rd_cnt,
-			      dw_edma_core_ch_count(dw, EDMA_DIR_READ));
-	dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt, EDMA_MAX_RD_CH);
+	dw->wr_ch_cnt = min_t(u16, chip->ll_wr_cnt, hw_wr_ch_cnt);
+	dw->rd_ch_cnt = min_t(u16, chip->ll_rd_cnt, hw_rd_ch_cnt);
 
 	if (!dw->wr_ch_cnt && !dw->rd_ch_cnt)
 		return -EINVAL;
@@ -1182,8 +1207,10 @@ int dw_edma_probe(struct dw_edma_chip *chip)
 	snprintf(dw->name, sizeof(dw->name), "dw-edma-core:%s",
 		 dev_name(chip->dev));
 
-	/* Disable eDMA, only to establish the ideal initial conditions */
-	dw_edma_core_off(dw);
+	if (!(chip->flags & DW_EDMA_CHIP_PARTIAL)) {
+		/* Disable eDMA only when this instance owns the controller. */
+		dw_edma_core_off(dw);
+	}
 
 	/* Request IRQs */
 	err = dw_edma_irq_request(dw, &wr_alloc, &rd_alloc);
@@ -1227,8 +1254,8 @@ int dw_edma_remove(struct dw_edma_chip *chip)
 	if (!dw)
 		return -ENODEV;
 
-	/* Disable eDMA */
-	dw_edma_core_off(dw);
+	if (!(chip->flags & DW_EDMA_CHIP_PARTIAL))
+		dw_edma_core_off(dw);
 
 	/* Free irqs */
 	for (i = (dw->nr_irqs - 1); i >= 0; i--)
diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
index 2bf2298711e1..84f0e728d300 100644
--- a/include/linux/dma/edma.h
+++ b/include/linux/dma/edma.h
@@ -55,9 +55,15 @@ enum dw_edma_map_format {
 /**
  * enum dw_edma_chip_flags - Flags specific to an eDMA chip
  * @DW_EDMA_CHIP_LOCAL:		eDMA is used locally by an endpoint
+ * @DW_EDMA_CHIP_PARTIAL:	Only channels described by this instance are
+ *				owned by this driver. Controller-wide state
+ *				must be preserved, and layouts with shared
+ *				direction-wide registers must only be shared at
+ *				direction granularity.
  */
 enum dw_edma_chip_flags {
 	DW_EDMA_CHIP_LOCAL	= BIT(0),
+	DW_EDMA_CHIP_PARTIAL	= BIT(1),
 };
 
 /**
-- 
2.51.0


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

* [PATCH v2 04/12] dmaengine: dw-edma-pcie: Track non-LL mode in DMA data
  2026-05-25  6:24 [PATCH v2 00/12] dmaengine: dw-edma: Prepare for PCI EP DMA (part 1/3) Koichiro Den
                   ` (2 preceding siblings ...)
  2026-05-25  6:24 ` [PATCH v2 03/12] dmaengine: dw-edma: Add partial channel ownership mode Koichiro Den
@ 2026-05-25  6:24 ` Koichiro Den
  2026-06-04 20:26   ` Frank Li
  2026-05-25  6:24 ` [PATCH v2 05/12] dmaengine: dw-edma-pcie: Add capability match data Koichiro Den
                   ` (7 subsequent siblings)
  11 siblings, 1 reply; 24+ messages in thread
From: Koichiro Den @ 2026-05-25  6:24 UTC (permalink / raw)
  To: Vinod Koul, Frank Li, Manivannan Sadhasivam
  Cc: Marek Vasut, Yoshihiro Shimoda, dmaengine, linux-kernel

The dw-edma-pcie driver copies static template data into a mutable
dw_edma_pcie_data instance before applying capability-derived updates.
Keep the derived non-LL mode in that copy as well, instead of only
tracking it in a local variable in dw_edma_pcie_probe().

This prepares for keeping capability parsing behind match data without a
separate non-LL output parameter.

No functional change intended.

Suggested-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
Changes in v2:
  - New patch, per Frank's feedback.

 drivers/dma/dw-edma/dw-edma-pcie.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
index 0b30ce138503..e92ff5dc6f67 100644
--- a/drivers/dma/dw-edma/dw-edma-pcie.c
+++ b/drivers/dma/dw-edma/dw-edma-pcie.c
@@ -72,6 +72,7 @@ struct dw_edma_pcie_data {
 	u16				wr_ch_cnt;
 	u16				rd_ch_cnt;
 	u64				devmem_phys_off;
+	bool				cfg_non_ll;
 };
 
 static const struct dw_edma_pcie_data snps_edda_data = {
@@ -312,7 +313,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 	struct dw_edma_chip *chip;
 	int err, nr_irqs;
 	int i, mask;
-	bool non_ll = false;
 
 	struct dw_edma_pcie_data *vsec_data __free(kfree) =
 		kmalloc_obj(*vsec_data);
@@ -344,14 +344,14 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 		 * the HDMA IP.
 		 */
 		if (vsec_data->devmem_phys_off == DW_PCIE_XILINX_MDB_INVALID_ADDR)
-			non_ll = true;
+			vsec_data->cfg_non_ll = true;
 
 		/*
 		 * Configure the channel LL and data blocks if number of
 		 * channels enabled in VSEC capability are more than the
 		 * channels configured in xilinx_mdb_data.
 		 */
-		if (!non_ll)
+		if (!vsec_data->cfg_non_ll)
 			dw_edma_set_chan_region_offset(vsec_data, BAR_2, 0,
 						       DW_PCIE_XILINX_MDB_LL_OFF_GAP,
 						       DW_PCIE_XILINX_MDB_LL_SIZE,
@@ -404,7 +404,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 	chip->mf = vsec_data->mf;
 	chip->nr_irqs = nr_irqs;
 	chip->ops = &dw_edma_pcie_plat_ops;
-	chip->cfg_non_ll = non_ll;
+	chip->cfg_non_ll = vsec_data->cfg_non_ll;
 
 	chip->ll_wr_cnt = vsec_data->wr_ch_cnt;
 	chip->ll_rd_cnt = vsec_data->rd_ch_cnt;
@@ -413,7 +413,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 	if (!chip->reg_base)
 		return -ENOMEM;
 
-	for (i = 0; i < chip->ll_wr_cnt && !non_ll; i++) {
+	for (i = 0; i < chip->ll_wr_cnt && !vsec_data->cfg_non_ll; i++) {
 		struct dw_edma_region *ll_region = &chip->ll_region_wr[i];
 		struct dw_edma_region *dt_region = &chip->dt_region_wr[i];
 		struct dw_edma_block *ll_block = &vsec_data->ll_wr[i];
@@ -440,7 +440,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 		dt_region->sz = dt_block->sz;
 	}
 
-	for (i = 0; i < chip->ll_rd_cnt && !non_ll; i++) {
+	for (i = 0; i < chip->ll_rd_cnt && !vsec_data->cfg_non_ll; i++) {
 		struct dw_edma_region *ll_region = &chip->ll_region_rd[i];
 		struct dw_edma_region *dt_region = &chip->dt_region_rd[i];
 		struct dw_edma_block *ll_block = &vsec_data->ll_rd[i];
-- 
2.51.0


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

* [PATCH v2 05/12] dmaengine: dw-edma-pcie: Add capability match data
  2026-05-25  6:24 [PATCH v2 00/12] dmaengine: dw-edma: Prepare for PCI EP DMA (part 1/3) Koichiro Den
                   ` (3 preceding siblings ...)
  2026-05-25  6:24 ` [PATCH v2 04/12] dmaengine: dw-edma-pcie: Track non-LL mode in DMA data Koichiro Den
@ 2026-05-25  6:24 ` Koichiro Den
  2026-06-04 20:28   ` Frank Li
  2026-05-25  6:24 ` [PATCH v2 06/12] dmaengine: dw-edma-pcie: Rename vsec_data to dma_data Koichiro Den
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 24+ messages in thread
From: Koichiro Den @ 2026-05-25  6:24 UTC (permalink / raw)
  To: Vinod Koul, Frank Li, Manivannan Sadhasivam
  Cc: Marek Vasut, Yoshihiro Shimoda, dmaengine, linux-kernel

Move device-specific capability parsing behind per-device match data.

The existing probe path mixes two decisions: which static template a PCI
ID uses, and which device-specific capability parser adjusts that
template. Split those decisions so device-specific discovery can be
added through match data instead of adding more vendor checks to
dw_edma_pcie_probe().

No functional change is intended for the existing Synopsys EDDA and
AMD/Xilinx MDB matches. They still copy the same static template data and
run the same capability parsing logic before BAR mapping. The MDB entry
also keeps using endpoint memory physical addresses for descriptor
windows through a new match-data flag.

Suggested-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
Changes in v2:
  - Keep non-LL mode in dw_edma_pcie_data instead of a separate
    parse_caps() output parameter.
  - While at here, use a named .driver_data initializer for the Xilinx MDB ID
    entry, per Frank's suggestion.

 drivers/dma/dw-edma/dw-edma-pcie.c | 127 +++++++++++++++++++----------
 1 file changed, 85 insertions(+), 42 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
index e92ff5dc6f67..5a6f5af358d0 100644
--- a/drivers/dma/dw-edma/dw-edma-pcie.c
+++ b/drivers/dma/dw-edma/dw-edma-pcie.c
@@ -75,6 +75,19 @@ struct dw_edma_pcie_data {
 	bool				cfg_non_ll;
 };
 
+struct dw_edma_pcie_match_data {
+	const struct dw_edma_pcie_data *data;
+	/*
+	 * Mandatory callback. It may leave @pdata unchanged when the static
+	 * template already describes the device.
+	 */
+	int (*parse_caps)(struct pci_dev *pdev,
+			  struct dw_edma_pcie_data *pdata);
+	unsigned long flags;
+};
+
+#define DW_EDMA_PCIE_F_DEVMEM_PHYS_OFF	BIT(0)
+
 static const struct dw_edma_pcie_data snps_edda_data = {
 	/* eDMA registers location */
 	.rg.bar				= BAR_0,
@@ -296,19 +309,61 @@ static void dw_edma_pcie_get_xilinx_dma_data(struct pci_dev *pdev,
 	pdata->devmem_phys_off = off;
 }
 
+static int
+dw_edma_pcie_parse_synopsys_caps(struct pci_dev *pdev,
+				 struct dw_edma_pcie_data *pdata)
+{
+	dw_edma_pcie_get_synopsys_dma_data(pdev, pdata);
+
+	return 0;
+}
+
+static int
+dw_edma_pcie_parse_xilinx_caps(struct pci_dev *pdev,
+			       struct dw_edma_pcie_data *pdata)
+{
+	dw_edma_pcie_get_xilinx_dma_data(pdev, pdata);
+
+	/*
+	 * There is no valid address found for the LL memory space on the
+	 * device side. In the absence of LL base address use the non-LL mode or
+	 * simple mode supported by the HDMA IP.
+	 */
+	if (pdata->devmem_phys_off == DW_PCIE_XILINX_MDB_INVALID_ADDR) {
+		pdata->cfg_non_ll = true;
+		return 0;
+	}
+
+	/*
+	 * Configure the channel LL and data blocks if number of channels
+	 * enabled in VSEC capability are more than the channels configured in
+	 * xilinx_mdb_data.
+	 */
+	dw_edma_set_chan_region_offset(pdata, BAR_2, 0,
+				       DW_PCIE_XILINX_MDB_LL_OFF_GAP,
+				       DW_PCIE_XILINX_MDB_LL_SIZE,
+				       DW_PCIE_XILINX_MDB_DT_OFF_GAP,
+				       DW_PCIE_XILINX_MDB_DT_SIZE);
+
+	return 0;
+}
+
 static u64 dw_edma_get_phys_addr(struct pci_dev *pdev,
+				 const struct dw_edma_pcie_match_data *match,
 				 struct dw_edma_pcie_data *pdata,
 				 enum pci_barno bar)
 {
-	if (pdev->vendor == PCI_VENDOR_ID_XILINX)
+	if (match->flags & DW_EDMA_PCIE_F_DEVMEM_PHYS_OFF)
 		return pdata->devmem_phys_off;
+
 	return pci_bus_address(pdev, bar);
 }
 
 static int dw_edma_pcie_probe(struct pci_dev *pdev,
 			      const struct pci_device_id *pid)
 {
-	struct dw_edma_pcie_data *pdata = (void *)pid->driver_data;
+	const struct dw_edma_pcie_match_data *match = (void *)pid->driver_data;
+	const struct dw_edma_pcie_data *pdata = match->data;
 	struct device *dev = &pdev->dev;
 	struct dw_edma_chip *chip;
 	int err, nr_irqs;
@@ -328,36 +383,13 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 
 	memcpy(vsec_data, pdata, sizeof(struct dw_edma_pcie_data));
 
-	/*
-	 * Tries to find if exists a PCIe Vendor-Specific Extended Capability
-	 * for the DMA, if one exists, then reconfigures it.
-	 */
-	dw_edma_pcie_get_synopsys_dma_data(pdev, vsec_data);
-
-	if (pdev->vendor == PCI_VENDOR_ID_XILINX) {
-		dw_edma_pcie_get_xilinx_dma_data(pdev, vsec_data);
-
-		/*
-		 * There is no valid address found for the LL memory
-		 * space on the device side. In the absence of LL base
-		 * address use the non-LL mode or simple mode supported by
-		 * the HDMA IP.
-		 */
-		if (vsec_data->devmem_phys_off == DW_PCIE_XILINX_MDB_INVALID_ADDR)
-			vsec_data->cfg_non_ll = true;
-
-		/*
-		 * Configure the channel LL and data blocks if number of
-		 * channels enabled in VSEC capability are more than the
-		 * channels configured in xilinx_mdb_data.
-		 */
-		if (!vsec_data->cfg_non_ll)
-			dw_edma_set_chan_region_offset(vsec_data, BAR_2, 0,
-						       DW_PCIE_XILINX_MDB_LL_OFF_GAP,
-						       DW_PCIE_XILINX_MDB_LL_SIZE,
-						       DW_PCIE_XILINX_MDB_DT_OFF_GAP,
-						       DW_PCIE_XILINX_MDB_DT_SIZE);
-	}
+	/* Let device-specific discovery override the static template data. */
+	if (!match->parse_caps)
+		return -EINVAL;
+
+	err = match->parse_caps(pdev, vsec_data);
+	if (err)
+		return err;
 
 	/* Mapping PCI BAR regions */
 	mask = BIT(vsec_data->rg.bar);
@@ -424,8 +456,8 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 			return -ENOMEM;
 
 		ll_region->vaddr.io += ll_block->off;
-		ll_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
-							 ll_block->bar);
+		ll_region->paddr = dw_edma_get_phys_addr(pdev, match,
+							 vsec_data, ll_block->bar);
 		ll_region->paddr += ll_block->off;
 		ll_region->sz = ll_block->sz;
 
@@ -434,8 +466,8 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 			return -ENOMEM;
 
 		dt_region->vaddr.io += dt_block->off;
-		dt_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
-							 dt_block->bar);
+		dt_region->paddr = dw_edma_get_phys_addr(pdev, match,
+							 vsec_data, dt_block->bar);
 		dt_region->paddr += dt_block->off;
 		dt_region->sz = dt_block->sz;
 	}
@@ -451,8 +483,8 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 			return -ENOMEM;
 
 		ll_region->vaddr.io += ll_block->off;
-		ll_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
-							 ll_block->bar);
+		ll_region->paddr = dw_edma_get_phys_addr(pdev, match,
+							 vsec_data, ll_block->bar);
 		ll_region->paddr += ll_block->off;
 		ll_region->sz = ll_block->sz;
 
@@ -461,8 +493,8 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 			return -ENOMEM;
 
 		dt_region->vaddr.io += dt_block->off;
-		dt_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
-							 dt_block->bar);
+		dt_region->paddr = dw_edma_get_phys_addr(pdev, match,
+							 vsec_data, dt_block->bar);
 		dt_region->paddr += dt_block->off;
 		dt_region->sz = dt_block->sz;
 	}
@@ -543,10 +575,21 @@ static void dw_edma_pcie_remove(struct pci_dev *pdev)
 	pci_free_irq_vectors(pdev);
 }
 
+static const struct dw_edma_pcie_match_data snps_edda_match_data = {
+	.data = &snps_edda_data,
+	.parse_caps = dw_edma_pcie_parse_synopsys_caps,
+};
+
+static const struct dw_edma_pcie_match_data xilinx_mdb_match_data = {
+	.data = &xilinx_mdb_data,
+	.parse_caps = dw_edma_pcie_parse_xilinx_caps,
+	.flags = DW_EDMA_PCIE_F_DEVMEM_PHYS_OFF,
+};
+
 static const struct pci_device_id dw_edma_pcie_id_table[] = {
-	{ PCI_DEVICE_DATA(SYNOPSYS, EDDA, &snps_edda_data) },
+	{ PCI_DEVICE_DATA(SYNOPSYS, EDDA, &snps_edda_match_data) },
 	{ PCI_VDEVICE(XILINX, PCI_DEVICE_ID_XILINX_B054),
-	  (kernel_ulong_t)&xilinx_mdb_data },
+	  .driver_data = (kernel_ulong_t)&xilinx_mdb_match_data },
 	{ }
 };
 MODULE_DEVICE_TABLE(pci, dw_edma_pcie_id_table);
-- 
2.51.0


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

* [PATCH v2 06/12] dmaengine: dw-edma-pcie: Rename vsec_data to dma_data
  2026-05-25  6:24 [PATCH v2 00/12] dmaengine: dw-edma: Prepare for PCI EP DMA (part 1/3) Koichiro Den
                   ` (4 preceding siblings ...)
  2026-05-25  6:24 ` [PATCH v2 05/12] dmaengine: dw-edma-pcie: Add capability match data Koichiro Den
@ 2026-05-25  6:24 ` Koichiro Den
  2026-06-04 20:35   ` Frank Li
  2026-05-25  6:24 ` [PATCH v2 07/12] dmaengine: dw-edma-pcie: Add default IRQ mode to match data Koichiro Den
                   ` (5 subsequent siblings)
  11 siblings, 1 reply; 24+ messages in thread
From: Koichiro Den @ 2026-05-25  6:24 UTC (permalink / raw)
  To: Vinod Koul, Frank Li, Manivannan Sadhasivam
  Cc: Marek Vasut, Yoshihiro Shimoda, dmaengine, linux-kernel

dw_edma_pcie_probe() now obtains DMA layout data through device-specific
capability callbacks, not only from PCIe Vendor-Specific Extended
Capabilities. Rename the local data copy from vsec_data to dma_data
before adding endpoint DMA BAR metadata discovery, which does not rely
on VSEC.

No functional change intended.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
Changes in v2:
  - Fix the commit title as Frank pointed out.

 drivers/dma/dw-edma/dw-edma-pcie.c | 76 +++++++++++++++---------------
 1 file changed, 37 insertions(+), 39 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
index 5a6f5af358d0..c7362f1bf80c 100644
--- a/drivers/dma/dw-edma/dw-edma-pcie.c
+++ b/drivers/dma/dw-edma/dw-edma-pcie.c
@@ -369,11 +369,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 	int err, nr_irqs;
 	int i, mask;
 
-	struct dw_edma_pcie_data *vsec_data __free(kfree) =
-		kmalloc_obj(*vsec_data);
-	if (!vsec_data)
-		return -ENOMEM;
-
 	/* Enable PCI device */
 	err = pcim_enable_device(pdev);
 	if (err) {
@@ -381,25 +376,28 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 		return err;
 	}
 
-	memcpy(vsec_data, pdata, sizeof(struct dw_edma_pcie_data));
+	struct dw_edma_pcie_data *dma_data __free(kfree) =
+		kmemdup(pdata, sizeof(*dma_data), GFP_KERNEL);
+	if (!dma_data)
+		return -ENOMEM;
 
 	/* Let device-specific discovery override the static template data. */
 	if (!match->parse_caps)
 		return -EINVAL;
 
-	err = match->parse_caps(pdev, vsec_data);
+	err = match->parse_caps(pdev, dma_data);
 	if (err)
 		return err;
 
 	/* Mapping PCI BAR regions */
-	mask = BIT(vsec_data->rg.bar);
-	for (i = 0; i < vsec_data->wr_ch_cnt; i++) {
-		mask |= BIT(vsec_data->ll_wr[i].bar);
-		mask |= BIT(vsec_data->dt_wr[i].bar);
+	mask = BIT(dma_data->rg.bar);
+	for (i = 0; i < dma_data->wr_ch_cnt; i++) {
+		mask |= BIT(dma_data->ll_wr[i].bar);
+		mask |= BIT(dma_data->dt_wr[i].bar);
 	}
-	for (i = 0; i < vsec_data->rd_ch_cnt; i++) {
-		mask |= BIT(vsec_data->ll_rd[i].bar);
-		mask |= BIT(vsec_data->dt_rd[i].bar);
+	for (i = 0; i < dma_data->rd_ch_cnt; i++) {
+		mask |= BIT(dma_data->ll_rd[i].bar);
+		mask |= BIT(dma_data->dt_rd[i].bar);
 	}
 	err = pcim_iomap_regions(pdev, mask, pci_name(pdev));
 	if (err) {
@@ -422,7 +420,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 		return -ENOMEM;
 
 	/* IRQs allocation */
-	nr_irqs = pci_alloc_irq_vectors(pdev, 1, vsec_data->irqs,
+	nr_irqs = pci_alloc_irq_vectors(pdev, 1, dma_data->irqs,
 					PCI_IRQ_MSI | PCI_IRQ_MSIX);
 	if (nr_irqs < 1) {
 		pci_err(pdev, "fail to alloc IRQ vector (number of IRQs=%u)\n",
@@ -433,23 +431,23 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 	/* Data structure initialization */
 	chip->dev = dev;
 
-	chip->mf = vsec_data->mf;
+	chip->mf = dma_data->mf;
 	chip->nr_irqs = nr_irqs;
 	chip->ops = &dw_edma_pcie_plat_ops;
-	chip->cfg_non_ll = vsec_data->cfg_non_ll;
+	chip->cfg_non_ll = dma_data->cfg_non_ll;
 
-	chip->ll_wr_cnt = vsec_data->wr_ch_cnt;
-	chip->ll_rd_cnt = vsec_data->rd_ch_cnt;
+	chip->ll_wr_cnt = dma_data->wr_ch_cnt;
+	chip->ll_rd_cnt = dma_data->rd_ch_cnt;
 
-	chip->reg_base = pcim_iomap_table(pdev)[vsec_data->rg.bar];
+	chip->reg_base = pcim_iomap_table(pdev)[dma_data->rg.bar];
 	if (!chip->reg_base)
 		return -ENOMEM;
 
-	for (i = 0; i < chip->ll_wr_cnt && !vsec_data->cfg_non_ll; i++) {
+	for (i = 0; i < chip->ll_wr_cnt && !dma_data->cfg_non_ll; i++) {
 		struct dw_edma_region *ll_region = &chip->ll_region_wr[i];
 		struct dw_edma_region *dt_region = &chip->dt_region_wr[i];
-		struct dw_edma_block *ll_block = &vsec_data->ll_wr[i];
-		struct dw_edma_block *dt_block = &vsec_data->dt_wr[i];
+		struct dw_edma_block *ll_block = &dma_data->ll_wr[i];
+		struct dw_edma_block *dt_block = &dma_data->dt_wr[i];
 
 		ll_region->vaddr.io = pcim_iomap_table(pdev)[ll_block->bar];
 		if (!ll_region->vaddr.io)
@@ -457,7 +455,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 
 		ll_region->vaddr.io += ll_block->off;
 		ll_region->paddr = dw_edma_get_phys_addr(pdev, match,
-							 vsec_data, ll_block->bar);
+							 dma_data, ll_block->bar);
 		ll_region->paddr += ll_block->off;
 		ll_region->sz = ll_block->sz;
 
@@ -467,16 +465,16 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 
 		dt_region->vaddr.io += dt_block->off;
 		dt_region->paddr = dw_edma_get_phys_addr(pdev, match,
-							 vsec_data, dt_block->bar);
+							 dma_data, dt_block->bar);
 		dt_region->paddr += dt_block->off;
 		dt_region->sz = dt_block->sz;
 	}
 
-	for (i = 0; i < chip->ll_rd_cnt && !vsec_data->cfg_non_ll; i++) {
+	for (i = 0; i < chip->ll_rd_cnt && !dma_data->cfg_non_ll; i++) {
 		struct dw_edma_region *ll_region = &chip->ll_region_rd[i];
 		struct dw_edma_region *dt_region = &chip->dt_region_rd[i];
-		struct dw_edma_block *ll_block = &vsec_data->ll_rd[i];
-		struct dw_edma_block *dt_block = &vsec_data->dt_rd[i];
+		struct dw_edma_block *ll_block = &dma_data->ll_rd[i];
+		struct dw_edma_block *dt_block = &dma_data->dt_rd[i];
 
 		ll_region->vaddr.io = pcim_iomap_table(pdev)[ll_block->bar];
 		if (!ll_region->vaddr.io)
@@ -484,7 +482,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 
 		ll_region->vaddr.io += ll_block->off;
 		ll_region->paddr = dw_edma_get_phys_addr(pdev, match,
-							 vsec_data, ll_block->bar);
+							 dma_data, ll_block->bar);
 		ll_region->paddr += ll_block->off;
 		ll_region->sz = ll_block->sz;
 
@@ -494,7 +492,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 
 		dt_region->vaddr.io += dt_block->off;
 		dt_region->paddr = dw_edma_get_phys_addr(pdev, match,
-							 vsec_data, dt_block->bar);
+							 dma_data, dt_block->bar);
 		dt_region->paddr += dt_block->off;
 		dt_region->sz = dt_block->sz;
 	}
@@ -512,31 +510,31 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 		pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", chip->mf);
 
 	pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p)\n",
-		vsec_data->rg.bar, vsec_data->rg.off, vsec_data->rg.sz,
+		dma_data->rg.bar, dma_data->rg.off, dma_data->rg.sz,
 		chip->reg_base);
 
 
 	for (i = 0; i < chip->ll_wr_cnt; i++) {
 		pci_dbg(pdev, "L. List:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
-			i, vsec_data->ll_wr[i].bar,
-			vsec_data->ll_wr[i].off, chip->ll_region_wr[i].sz,
+			i, dma_data->ll_wr[i].bar,
+			dma_data->ll_wr[i].off, chip->ll_region_wr[i].sz,
 			chip->ll_region_wr[i].vaddr.io, &chip->ll_region_wr[i].paddr);
 
 		pci_dbg(pdev, "Data:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
-			i, vsec_data->dt_wr[i].bar,
-			vsec_data->dt_wr[i].off, chip->dt_region_wr[i].sz,
+			i, dma_data->dt_wr[i].bar,
+			dma_data->dt_wr[i].off, chip->dt_region_wr[i].sz,
 			chip->dt_region_wr[i].vaddr.io, &chip->dt_region_wr[i].paddr);
 	}
 
 	for (i = 0; i < chip->ll_rd_cnt; i++) {
 		pci_dbg(pdev, "L. List:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
-			i, vsec_data->ll_rd[i].bar,
-			vsec_data->ll_rd[i].off, chip->ll_region_rd[i].sz,
+			i, dma_data->ll_rd[i].bar,
+			dma_data->ll_rd[i].off, chip->ll_region_rd[i].sz,
 			chip->ll_region_rd[i].vaddr.io, &chip->ll_region_rd[i].paddr);
 
 		pci_dbg(pdev, "Data:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
-			i, vsec_data->dt_rd[i].bar,
-			vsec_data->dt_rd[i].off, chip->dt_region_rd[i].sz,
+			i, dma_data->dt_rd[i].bar,
+			dma_data->dt_rd[i].off, chip->dt_region_rd[i].sz,
 			chip->dt_region_rd[i].vaddr.io, &chip->dt_region_rd[i].paddr);
 	}
 
-- 
2.51.0


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

* [PATCH v2 07/12] dmaengine: dw-edma-pcie: Add default IRQ mode to match data
  2026-05-25  6:24 [PATCH v2 00/12] dmaengine: dw-edma: Prepare for PCI EP DMA (part 1/3) Koichiro Den
                   ` (5 preceding siblings ...)
  2026-05-25  6:24 ` [PATCH v2 06/12] dmaengine: dw-edma-pcie: Rename vsec_data to dma_data Koichiro Den
@ 2026-05-25  6:24 ` Koichiro Den
  2026-05-25  6:24 ` [PATCH v2 08/12] dmaengine: dw-edma-pcie: Add platform ops " Koichiro Den
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 24+ messages in thread
From: Koichiro Den @ 2026-05-25  6:24 UTC (permalink / raw)
  To: Vinod Koul, Frank Li, Manivannan Sadhasivam
  Cc: Marek Vasut, Yoshihiro Shimoda, dmaengine, linux-kernel

Store the default per-channel interrupt routing mode in dw-edma-pcie
match data and copy it into dw_edma_chip during probe.

No functional change intended. Existing Synopsys EDDA and AMD/Xilinx MDB
matches leave the field zero, which is DW_EDMA_CH_IRQ_DEFAULT.

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
Changes in v2:
  - Refine the commit title.

 drivers/dma/dw-edma/dw-edma-pcie.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
index c7362f1bf80c..9aed1005854d 100644
--- a/drivers/dma/dw-edma/dw-edma-pcie.c
+++ b/drivers/dma/dw-edma/dw-edma-pcie.c
@@ -84,6 +84,7 @@ struct dw_edma_pcie_match_data {
 	int (*parse_caps)(struct pci_dev *pdev,
 			  struct dw_edma_pcie_data *pdata);
 	unsigned long flags;
+	enum dw_edma_ch_irq_mode default_irq_mode;
 };
 
 #define DW_EDMA_PCIE_F_DEVMEM_PHYS_OFF	BIT(0)
@@ -432,6 +433,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 	chip->dev = dev;
 
 	chip->mf = dma_data->mf;
+	chip->default_irq_mode = match->default_irq_mode;
 	chip->nr_irqs = nr_irqs;
 	chip->ops = &dw_edma_pcie_plat_ops;
 	chip->cfg_non_ll = dma_data->cfg_non_ll;
-- 
2.51.0


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

* [PATCH v2 08/12] dmaengine: dw-edma-pcie: Add platform ops to match data
  2026-05-25  6:24 [PATCH v2 00/12] dmaengine: dw-edma: Prepare for PCI EP DMA (part 1/3) Koichiro Den
                   ` (6 preceding siblings ...)
  2026-05-25  6:24 ` [PATCH v2 07/12] dmaengine: dw-edma-pcie: Add default IRQ mode to match data Koichiro Den
@ 2026-05-25  6:24 ` Koichiro Den
  2026-06-04 20:37   ` Frank Li
  2026-05-25  6:24 ` [PATCH v2 09/12] dmaengine: dw-edma-pcie: Add register offset match flag Koichiro Den
                   ` (3 subsequent siblings)
  11 siblings, 1 reply; 24+ messages in thread
From: Koichiro Den @ 2026-05-25  6:24 UTC (permalink / raw)
  To: Vinod Koul, Frank Li, Manivannan Sadhasivam
  Cc: Marek Vasut, Yoshihiro Shimoda, dmaengine, linux-kernel

Move the platform ops pointer into match data. Existing EDDA/MDB matches
keep using dw_edma_pcie_plat_ops.

No functional changes intended.

Suggested-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
Changes in v2:
  - New patch. The original commit
    "dmaengine: dw-edma-pcie: Add raw slave address ops" is dropped
    per Frank's suggestion. DW_EDMA_PCIE_F_RAW_SLAVE_ADDR is no
    longer needed.

 drivers/dma/dw-edma/dw-edma-pcie.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
index 9aed1005854d..1d63b07723f9 100644
--- a/drivers/dma/dw-edma/dw-edma-pcie.c
+++ b/drivers/dma/dw-edma/dw-edma-pcie.c
@@ -77,6 +77,7 @@ struct dw_edma_pcie_data {
 
 struct dw_edma_pcie_match_data {
 	const struct dw_edma_pcie_data *data;
+	const struct dw_edma_plat_ops *plat_ops;
 	/*
 	 * Mandatory callback. It may leave @pdata unchanged when the static
 	 * template already describes the device.
@@ -383,7 +384,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 		return -ENOMEM;
 
 	/* Let device-specific discovery override the static template data. */
-	if (!match->parse_caps)
+	if (!match->parse_caps || !match->plat_ops)
 		return -EINVAL;
 
 	err = match->parse_caps(pdev, dma_data);
@@ -435,7 +436,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 	chip->mf = dma_data->mf;
 	chip->default_irq_mode = match->default_irq_mode;
 	chip->nr_irqs = nr_irqs;
-	chip->ops = &dw_edma_pcie_plat_ops;
+	chip->ops = match->plat_ops;
 	chip->cfg_non_ll = dma_data->cfg_non_ll;
 
 	chip->ll_wr_cnt = dma_data->wr_ch_cnt;
@@ -577,11 +578,13 @@ static void dw_edma_pcie_remove(struct pci_dev *pdev)
 
 static const struct dw_edma_pcie_match_data snps_edda_match_data = {
 	.data = &snps_edda_data,
+	.plat_ops = &dw_edma_pcie_plat_ops,
 	.parse_caps = dw_edma_pcie_parse_synopsys_caps,
 };
 
 static const struct dw_edma_pcie_match_data xilinx_mdb_match_data = {
 	.data = &xilinx_mdb_data,
+	.plat_ops = &dw_edma_pcie_plat_ops,
 	.parse_caps = dw_edma_pcie_parse_xilinx_caps,
 	.flags = DW_EDMA_PCIE_F_DEVMEM_PHYS_OFF,
 };
-- 
2.51.0


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

* [PATCH v2 09/12] dmaengine: dw-edma-pcie: Add register offset match flag
  2026-05-25  6:24 [PATCH v2 00/12] dmaengine: dw-edma: Prepare for PCI EP DMA (part 1/3) Koichiro Den
                   ` (7 preceding siblings ...)
  2026-05-25  6:24 ` [PATCH v2 08/12] dmaengine: dw-edma-pcie: Add platform ops " Koichiro Den
@ 2026-05-25  6:24 ` Koichiro Den
  2026-05-25  6:24 ` [PATCH v2 10/12] dmaengine: dw-edma-pcie: Factor out descriptor block address lookup Koichiro Den
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 24+ messages in thread
From: Koichiro Den @ 2026-05-25  6:24 UTC (permalink / raw)
  To: Vinod Koul, Frank Li, Manivannan Sadhasivam
  Cc: Marek Vasut, Yoshihiro Shimoda, dmaengine, linux-kernel

Add a match-data flag for devices whose DMA register block starts at an
offset inside the mapped BAR. Existing Synopsys EDDA and AMD/Xilinx MDB
matches keep using the BAR mapping base directly.

No functional change intended.

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
 drivers/dma/dw-edma/dw-edma-pcie.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
index 1d63b07723f9..8ba2b3917f05 100644
--- a/drivers/dma/dw-edma/dw-edma-pcie.c
+++ b/drivers/dma/dw-edma/dw-edma-pcie.c
@@ -89,6 +89,7 @@ struct dw_edma_pcie_match_data {
 };
 
 #define DW_EDMA_PCIE_F_DEVMEM_PHYS_OFF	BIT(0)
+#define DW_EDMA_PCIE_F_REG_OFFSET	BIT(1)
 
 static const struct dw_edma_pcie_data snps_edda_data = {
 	/* eDMA registers location */
@@ -445,6 +446,8 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 	chip->reg_base = pcim_iomap_table(pdev)[dma_data->rg.bar];
 	if (!chip->reg_base)
 		return -ENOMEM;
+	if (match->flags & DW_EDMA_PCIE_F_REG_OFFSET)
+		chip->reg_base += dma_data->rg.off;
 
 	for (i = 0; i < chip->ll_wr_cnt && !dma_data->cfg_non_ll; i++) {
 		struct dw_edma_region *ll_region = &chip->ll_region_wr[i];
-- 
2.51.0


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

* [PATCH v2 10/12] dmaengine: dw-edma-pcie: Factor out descriptor block address lookup
  2026-05-25  6:24 [PATCH v2 00/12] dmaengine: dw-edma: Prepare for PCI EP DMA (part 1/3) Koichiro Den
                   ` (8 preceding siblings ...)
  2026-05-25  6:24 ` [PATCH v2 09/12] dmaengine: dw-edma-pcie: Add register offset match flag Koichiro Den
@ 2026-05-25  6:24 ` Koichiro Den
  2026-05-25  6:24 ` [PATCH v2 11/12] dmaengine: dw-edma-pcie: Handle optional data blocks Koichiro Den
  2026-05-25  6:24 ` [PATCH v2 12/12] dmaengine: dw-edma-pcie: Add chip flags to match data Koichiro Den
  11 siblings, 0 replies; 24+ messages in thread
From: Koichiro Den @ 2026-05-25  6:24 UTC (permalink / raw)
  To: Vinod Koul, Frank Li, Manivannan Sadhasivam
  Cc: Marek Vasut, Yoshihiro Shimoda, dmaengine, linux-kernel

Add an optional physical address override to struct dw_edma_block and
use a helper to compute descriptor block addresses.

No functional change intended. Existing EDDA and MDB block descriptors
leave the override unset, so the helper still returns the same
pci_bus_address() plus block offset value.

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
Changes in v2:
  - Refine the commit title.

 drivers/dma/dw-edma/dw-edma-pcie.c | 34 +++++++++++++++++++-----------
 1 file changed, 22 insertions(+), 12 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
index 8ba2b3917f05..c2be43170e02 100644
--- a/drivers/dma/dw-edma/dw-edma-pcie.c
+++ b/drivers/dma/dw-edma/dw-edma-pcie.c
@@ -54,6 +54,8 @@
 struct dw_edma_block {
 	enum pci_barno			bar;
 	off_t				off;
+	u64				paddr;
+	bool				paddr_valid;
 	size_t				sz;
 };
 
@@ -362,6 +364,18 @@ static u64 dw_edma_get_phys_addr(struct pci_dev *pdev,
 	return pci_bus_address(pdev, bar);
 }
 
+static u64 dw_edma_get_block_addr(struct pci_dev *pdev,
+				  const struct dw_edma_pcie_match_data *match,
+				  struct dw_edma_pcie_data *pdata,
+				  const struct dw_edma_block *block)
+{
+	if (block->paddr_valid)
+		return block->paddr;
+
+	return dw_edma_get_phys_addr(pdev, match, pdata, block->bar) +
+	       block->off;
+}
+
 static int dw_edma_pcie_probe(struct pci_dev *pdev,
 			      const struct pci_device_id *pid)
 {
@@ -460,9 +474,8 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 			return -ENOMEM;
 
 		ll_region->vaddr.io += ll_block->off;
-		ll_region->paddr = dw_edma_get_phys_addr(pdev, match,
-							 dma_data, ll_block->bar);
-		ll_region->paddr += ll_block->off;
+		ll_region->paddr = dw_edma_get_block_addr(pdev, match, dma_data,
+							  ll_block);
 		ll_region->sz = ll_block->sz;
 
 		dt_region->vaddr.io = pcim_iomap_table(pdev)[dt_block->bar];
@@ -470,9 +483,8 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 			return -ENOMEM;
 
 		dt_region->vaddr.io += dt_block->off;
-		dt_region->paddr = dw_edma_get_phys_addr(pdev, match,
-							 dma_data, dt_block->bar);
-		dt_region->paddr += dt_block->off;
+		dt_region->paddr = dw_edma_get_block_addr(pdev, match, dma_data,
+							  dt_block);
 		dt_region->sz = dt_block->sz;
 	}
 
@@ -487,9 +499,8 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 			return -ENOMEM;
 
 		ll_region->vaddr.io += ll_block->off;
-		ll_region->paddr = dw_edma_get_phys_addr(pdev, match,
-							 dma_data, ll_block->bar);
-		ll_region->paddr += ll_block->off;
+		ll_region->paddr = dw_edma_get_block_addr(pdev, match, dma_data,
+							  ll_block);
 		ll_region->sz = ll_block->sz;
 
 		dt_region->vaddr.io = pcim_iomap_table(pdev)[dt_block->bar];
@@ -497,9 +508,8 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 			return -ENOMEM;
 
 		dt_region->vaddr.io += dt_block->off;
-		dt_region->paddr = dw_edma_get_phys_addr(pdev, match,
-							 dma_data, dt_block->bar);
-		dt_region->paddr += dt_block->off;
+		dt_region->paddr = dw_edma_get_block_addr(pdev, match, dma_data,
+							  dt_block);
 		dt_region->sz = dt_block->sz;
 	}
 
-- 
2.51.0


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

* [PATCH v2 11/12] dmaengine: dw-edma-pcie: Handle optional data blocks
  2026-05-25  6:24 [PATCH v2 00/12] dmaengine: dw-edma: Prepare for PCI EP DMA (part 1/3) Koichiro Den
                   ` (9 preceding siblings ...)
  2026-05-25  6:24 ` [PATCH v2 10/12] dmaengine: dw-edma-pcie: Factor out descriptor block address lookup Koichiro Den
@ 2026-05-25  6:24 ` Koichiro Den
  2026-05-25  6:24 ` [PATCH v2 12/12] dmaengine: dw-edma-pcie: Add chip flags to match data Koichiro Den
  11 siblings, 0 replies; 24+ messages in thread
From: Koichiro Den @ 2026-05-25  6:24 UTC (permalink / raw)
  To: Vinod Koul, Frank Li, Manivannan Sadhasivam
  Cc: Marek Vasut, Yoshihiro Shimoda, dmaengine, linux-kernel

Skip data block BAR mapping and debug output when a channel has no data
block size. This lets future providers describe channels that only need
descriptor memory exposed.

No functional change intended for existing EDDA and MDB devices. Their
static channel descriptions still provide data block sizes where data
block windows are used. A zero-sized data block now means "not present"
for future metadata providers.

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
 drivers/dma/dw-edma/dw-edma-pcie.c | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
index c2be43170e02..00e9c9775e3e 100644
--- a/drivers/dma/dw-edma/dw-edma-pcie.c
+++ b/drivers/dma/dw-edma/dw-edma-pcie.c
@@ -410,11 +410,13 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 	mask = BIT(dma_data->rg.bar);
 	for (i = 0; i < dma_data->wr_ch_cnt; i++) {
 		mask |= BIT(dma_data->ll_wr[i].bar);
-		mask |= BIT(dma_data->dt_wr[i].bar);
+		if (dma_data->dt_wr[i].sz)
+			mask |= BIT(dma_data->dt_wr[i].bar);
 	}
 	for (i = 0; i < dma_data->rd_ch_cnt; i++) {
 		mask |= BIT(dma_data->ll_rd[i].bar);
-		mask |= BIT(dma_data->dt_rd[i].bar);
+		if (dma_data->dt_rd[i].sz)
+			mask |= BIT(dma_data->dt_rd[i].bar);
 	}
 	err = pcim_iomap_regions(pdev, mask, pci_name(pdev));
 	if (err) {
@@ -478,6 +480,9 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 							  ll_block);
 		ll_region->sz = ll_block->sz;
 
+		if (!dt_block->sz)
+			continue;
+
 		dt_region->vaddr.io = pcim_iomap_table(pdev)[dt_block->bar];
 		if (!dt_region->vaddr.io)
 			return -ENOMEM;
@@ -503,6 +508,9 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 							  ll_block);
 		ll_region->sz = ll_block->sz;
 
+		if (!dt_block->sz)
+			continue;
+
 		dt_region->vaddr.io = pcim_iomap_table(pdev)[dt_block->bar];
 		if (!dt_region->vaddr.io)
 			return -ENOMEM;
@@ -536,10 +544,14 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 			dma_data->ll_wr[i].off, chip->ll_region_wr[i].sz,
 			chip->ll_region_wr[i].vaddr.io, &chip->ll_region_wr[i].paddr);
 
+		if (!dma_data->dt_wr[i].sz)
+			continue;
+
 		pci_dbg(pdev, "Data:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
 			i, dma_data->dt_wr[i].bar,
 			dma_data->dt_wr[i].off, chip->dt_region_wr[i].sz,
-			chip->dt_region_wr[i].vaddr.io, &chip->dt_region_wr[i].paddr);
+			chip->dt_region_wr[i].vaddr.io,
+			&chip->dt_region_wr[i].paddr);
 	}
 
 	for (i = 0; i < chip->ll_rd_cnt; i++) {
@@ -548,10 +560,14 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 			dma_data->ll_rd[i].off, chip->ll_region_rd[i].sz,
 			chip->ll_region_rd[i].vaddr.io, &chip->ll_region_rd[i].paddr);
 
+		if (!dma_data->dt_rd[i].sz)
+			continue;
+
 		pci_dbg(pdev, "Data:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
 			i, dma_data->dt_rd[i].bar,
 			dma_data->dt_rd[i].off, chip->dt_region_rd[i].sz,
-			chip->dt_region_rd[i].vaddr.io, &chip->dt_region_rd[i].paddr);
+			chip->dt_region_rd[i].vaddr.io,
+			&chip->dt_region_rd[i].paddr);
 	}
 
 	pci_dbg(pdev, "Nr. IRQs:\t%u\n", chip->nr_irqs);
-- 
2.51.0


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

* [PATCH v2 12/12] dmaengine: dw-edma-pcie: Add chip flags to match data
  2026-05-25  6:24 [PATCH v2 00/12] dmaengine: dw-edma: Prepare for PCI EP DMA (part 1/3) Koichiro Den
                   ` (10 preceding siblings ...)
  2026-05-25  6:24 ` [PATCH v2 11/12] dmaengine: dw-edma-pcie: Handle optional data blocks Koichiro Den
@ 2026-05-25  6:24 ` Koichiro Den
  11 siblings, 0 replies; 24+ messages in thread
From: Koichiro Den @ 2026-05-25  6:24 UTC (permalink / raw)
  To: Vinod Koul, Frank Li, Manivannan Sadhasivam
  Cc: Marek Vasut, Yoshihiro Shimoda, dmaengine, linux-kernel

Allow PCI ID match data to pass dw_edma_chip flags into dw_edma_probe().
This keeps per-device policy in the match data instead of open-coding it
in probe().

Reviewed-by: Frank Li <Frank.Li@nxp.com>
Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
Changes in v2:
  - Refine the commit title.

 drivers/dma/dw-edma/dw-edma-pcie.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
index 00e9c9775e3e..12229a9301cd 100644
--- a/drivers/dma/dw-edma/dw-edma-pcie.c
+++ b/drivers/dma/dw-edma/dw-edma-pcie.c
@@ -87,6 +87,7 @@ struct dw_edma_pcie_match_data {
 	int (*parse_caps)(struct pci_dev *pdev,
 			  struct dw_edma_pcie_data *pdata);
 	unsigned long flags;
+	u32 chip_flags;
 	enum dw_edma_ch_irq_mode default_irq_mode;
 };
 
@@ -451,6 +452,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
 	chip->dev = dev;
 
 	chip->mf = dma_data->mf;
+	chip->flags = match->chip_flags;
 	chip->default_irq_mode = match->default_irq_mode;
 	chip->nr_irqs = nr_irqs;
 	chip->ops = match->plat_ops;
-- 
2.51.0


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

* Re: [PATCH v2 02/12] dmaengine: dw-edma: Add per-channel interrupt routing control
  2026-05-25  6:24 ` [PATCH v2 02/12] dmaengine: dw-edma: Add per-channel interrupt routing control Koichiro Den
@ 2026-06-04 20:18   ` Frank Li
  2026-06-05  2:36     ` Koichiro Den
  0 siblings, 1 reply; 24+ messages in thread
From: Frank Li @ 2026-06-04 20:18 UTC (permalink / raw)
  To: Koichiro Den
  Cc: Vinod Koul, Frank Li, Manivannan Sadhasivam, Marek Vasut,
	Yoshihiro Shimoda, dmaengine, linux-kernel

On Mon, May 25, 2026 at 03:24:10PM +0900, Koichiro Den wrote:
> DesignWare eDMA can signal completion locally through edma_int[] and
> remotely through IMWr/MSI. When channels are delegated to a remote
> frontend, the local endpoint side and the remote host side must not both
> service the same DONE/ABORT status.
>
> Add dw_edma_irq_config, carried through dma_slave_config, so a frontend
> can choose default, local, or remote IRQ handling per channel. Update the
> v0 path so linked-list interrupt generation and DONE/ABORT masking follow
> the selected mode. If a frontend does not supply the config, keep the
> existing behavior.
>
> HDMA native already uses dma_slave_config.peripheral_config as an int for
> non-LL mode selection. Keep that interface unchanged and reject the new
> IRQ config there until an IRQ routing model is implemented and validated.
>
> Signed-off-by: Koichiro Den <den@valinux.co.jp>
> ---
...
>
> +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)

suppose it should be pre channel config, why need check chip's informaiton?

> +		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 69e8279adec8..08ec2bd7856e 100644
> --- a/drivers/dma/dw-edma/dw-edma-v0-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
> @@ -256,9 +256,11 @@ 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];
>
> +		if (dw_edma_core_ch_ignore_irq(chan))
> +			continue;
> +
>  		dw_edma_v0_core_clear_done_int(chan);
>  		done(chan);
> -
>  		ret = IRQ_HANDLED;
>  	}
>
> @@ -267,9 +269,11 @@ 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];
>
> +		if (dw_edma_core_ch_ignore_irq(chan))
> +			continue;
> +
>  		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 3e15cf83b784..2bf2298711e1 100644
> --- a/include/linux/dma/edma.h
> +++ b/include/linux/dma/edma.h
> @@ -60,6 +60,43 @@ 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:   keep legacy behavior

Feel like it make things complex, most likely use pcie ep probe, it should
be use DW_EDMA_CH_IRQ_LOCAL.

If probe from dw-edma-pcie.c, it should be use DW_EDMA_CH_IRQ_REMOTE.

Add default mode, it make check logic become complex.

Frank

> + * @DW_EDMA_CH_IRQ_LOCAL:     local interrupt only (edma_int[])
> + * @DW_EDMA_CH_IRQ_REMOTE:    remote interrupt only (IMWr/MSI),
> + *                            while masking local DONE/ABORT output.
> + *
> + * DesignWare EP eDMA can signal interrupts locally through the edma_int[]
> + * bus, and remotely using posted memory writes (IMWr) that may be
> + * interpreted as MSI/MSI-X by the RC.
> + *
> + * For the v0 eDMA programming path, DMA_*_INT_MASK gates the local edma_int[]
> + * assertion, while there is no dedicated per-channel mask for IMWr generation.
> + * To request a remote-only interrupt, Synopsys recommends setting both LIE and
> + * RIE, and masking the local interrupt in DMA_*_INT_MASK (rather than relying
> + * on LIE=0/RIE=1). See the DesignWare endpoint databook 5.40a, Non Linked
> + * List Mode interrupt handling ("Hint").
> + */
> +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_irq_config - dw-edma interrupt routing configuration
> + * @irq_mode: per-channel interrupt routing control.
> + * @reserved: must be zero.
> + *
> + * Pass this structure via dma_slave_config.peripheral_config and
> + * dma_slave_config.peripheral_size.
> + */
> +struct dw_edma_irq_config {
> +	enum dw_edma_ch_irq_mode irq_mode;
> +	u32 reserved;
> +};
> +
>  /**
>   * struct dw_edma_chip - representation of DesignWare eDMA controller hardware
>   * @dev:		 struct device of the eDMA controller
> @@ -76,6 +113,8 @@ enum dw_edma_chip_flags {
>   * @db_irq:		 Virtual IRQ dedicated to interrupt emulation
>   * @db_offset:		 Offset from DMA register base
>   * @mf:			 DMA register map format
> + * @default_irq_mode:	 default per-channel interrupt routing when client
> + *			 does not supply dw_edma_irq_config
>   * @dw:			 struct dw_edma that is filled by dw_edma_probe()
>   */
>  struct dw_edma_chip {
> @@ -101,6 +140,7 @@ struct dw_edma_chip {
>  	resource_size_t		db_offset;
>
>  	enum dw_edma_map_format	mf;
> +	enum dw_edma_ch_irq_mode	default_irq_mode;

suppose it is pre-channel config?

Frank
>
>  	struct dw_edma		*dw;
>  	bool			cfg_non_ll;
> --
> 2.51.0
>

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

* Re: [PATCH v2 03/12] dmaengine: dw-edma: Add partial channel ownership mode
  2026-05-25  6:24 ` [PATCH v2 03/12] dmaengine: dw-edma: Add partial channel ownership mode Koichiro Den
@ 2026-06-04 20:24   ` Frank Li
  2026-06-05  2:40     ` Koichiro Den
  0 siblings, 1 reply; 24+ messages in thread
From: Frank Li @ 2026-06-04 20:24 UTC (permalink / raw)
  To: Koichiro Den
  Cc: Vinod Koul, Frank Li, Manivannan Sadhasivam, Marek Vasut,
	Yoshihiro Shimoda, dmaengine, linux-kernel

On Mon, May 25, 2026 at 03:24:11PM +0900, Koichiro Den wrote:
> Some endpoint DMA frontends expose only a subset of a controller that is
> also initialized by the endpoint-side OS. Add a partial ownership flag
> so dw-edma does not reset controller-wide state in probe() or remove().
>
> Keep the mode conservative. Do not enable interrupt-emulation doorbells,
> and reject partial instances for map formats that this driver cannot safely
> share. For EDMA_MF_EDMA_UNROLL and EDMA_MF_HDMA_COMPAT, require ownership
> of all channels in each exposed direction. The driver updates registers
> shared by all channels in a direction, such as interrupt masks and
> linked-list error enables, so two independent OS instances cannot safely
> split one direction without a shared locking protocol, which is
> unrealistic.
>
> The frontend must still quiesce delegated channels before removing a
> partial instance. The flag only keeps probe() and remove() from
> resetting controller-wide state that may belong to a peer OS instance.
>
> Signed-off-by: Koichiro Den <den@valinux.co.jp>
> ---
> Changes in v2:
>   - Reject partial ownership for unsupported map formats up front,
>     keep direction-granularity validation limited to supported formats.
>   - Revise the commit message accordingly.
>
>  drivers/dma/dw-edma/dw-edma-core.c | 47 +++++++++++++++++++++++-------
>  include/linux/dma/edma.h           |  6 ++++
>  2 files changed, 43 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index a70e0640d082..fcef9a27b6ce 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -794,6 +794,9 @@ static int dw_edma_emul_irq_alloc(struct dw_edma *dw)
>  	chip->db_irq = 0;
>  	chip->db_offset = ~0;
>
> +	if (chip->flags & DW_EDMA_CHIP_PARTIAL)
> +		return 0;
> +
>  	/*
>  	 * Only meaningful when the core provides the deassert sequence
>  	 * for interrupt emulation.
> @@ -1135,6 +1138,8 @@ int dw_edma_probe(struct dw_edma_chip *chip)
>  {
>  	struct device *dev;
>  	struct dw_edma *dw;
> +	u16 hw_wr_ch_cnt;
> +	u16 hw_rd_ch_cnt;
>  	u32 wr_alloc = 0;
>  	u32 rd_alloc = 0;
>  	int i, err;
> @@ -1146,6 +1151,16 @@ int dw_edma_probe(struct dw_edma_chip *chip)
>  	if (!dev || !chip->ops)
>  		return -EINVAL;
>
> +	if (chip->flags & DW_EDMA_CHIP_PARTIAL) {
> +		switch (chip->mf) {
> +		case EDMA_MF_EDMA_UNROLL:
> +		case EDMA_MF_HDMA_COMPAT:
> +			break;
> +		default:
> +			return -EOPNOTSUPP;
> +		}
> +	}
> +
>  	dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL);
>  	if (!dw)
>  		return -ENOMEM;
> @@ -1159,13 +1174,23 @@ int dw_edma_probe(struct dw_edma_chip *chip)
>
>  	raw_spin_lock_init(&dw->lock);
>
> -	dw->wr_ch_cnt = min_t(u16, chip->ll_wr_cnt,
> -			      dw_edma_core_ch_count(dw, EDMA_DIR_WRITE));
> -	dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt, EDMA_MAX_WR_CH);
> +	hw_wr_ch_cnt = min_t(u16, dw_edma_core_ch_count(dw, EDMA_DIR_WRITE),
> +			     EDMA_MAX_WR_CH);
> +	hw_rd_ch_cnt = min_t(u16, dw_edma_core_ch_count(dw, EDMA_DIR_READ),
> +			     EDMA_MAX_RD_CH);
> +
> +	if (chip->flags & DW_EDMA_CHIP_PARTIAL) {
> +		/*
> +		 * Direction-wide registers are shared by all channels in that
> +		 * direction, so a direction must have a single owner.
> +		 */
> +		if ((chip->ll_wr_cnt && chip->ll_wr_cnt != hw_wr_ch_cnt) ||
> +		    (chip->ll_rd_cnt && chip->ll_rd_cnt != hw_rd_ch_cnt))
> +			return -EOPNOTSUPP;
> +	}
>
> -	dw->rd_ch_cnt = min_t(u16, chip->ll_rd_cnt,
> -			      dw_edma_core_ch_count(dw, EDMA_DIR_READ));
> -	dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt, EDMA_MAX_RD_CH);
> +	dw->wr_ch_cnt = min_t(u16, chip->ll_wr_cnt, hw_wr_ch_cnt);
> +	dw->rd_ch_cnt = min_t(u16, chip->ll_rd_cnt, hw_rd_ch_cnt);
>
>  	if (!dw->wr_ch_cnt && !dw->rd_ch_cnt)
>  		return -EINVAL;
> @@ -1182,8 +1207,10 @@ int dw_edma_probe(struct dw_edma_chip *chip)
>  	snprintf(dw->name, sizeof(dw->name), "dw-edma-core:%s",
>  		 dev_name(chip->dev));
>
> -	/* Disable eDMA, only to establish the ideal initial conditions */
> -	dw_edma_core_off(dw);
> +	if (!(chip->flags & DW_EDMA_CHIP_PARTIAL)) {
> +		/* Disable eDMA only when this instance owns the controller. */
> +		dw_edma_core_off(dw);
> +	}
>
>  	/* Request IRQs */
>  	err = dw_edma_irq_request(dw, &wr_alloc, &rd_alloc);
> @@ -1227,8 +1254,8 @@ int dw_edma_remove(struct dw_edma_chip *chip)
>  	if (!dw)
>  		return -ENODEV;
>
> -	/* Disable eDMA */
> -	dw_edma_core_off(dw);
> +	if (!(chip->flags & DW_EDMA_CHIP_PARTIAL))
> +		dw_edma_core_off(dw);

Can we simplely prevent dma driver remove? If attached to pci host,
remove edma driver always be risk because RC may write data at any time.

And it doesn't make sense to remove EP and EDMA driver after linkup.

Frank

>
>  	/* Free irqs */
>  	for (i = (dw->nr_irqs - 1); i >= 0; i--)
> diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> index 2bf2298711e1..84f0e728d300 100644
> --- a/include/linux/dma/edma.h
> +++ b/include/linux/dma/edma.h
> @@ -55,9 +55,15 @@ enum dw_edma_map_format {
>  /**
>   * enum dw_edma_chip_flags - Flags specific to an eDMA chip
>   * @DW_EDMA_CHIP_LOCAL:		eDMA is used locally by an endpoint
> + * @DW_EDMA_CHIP_PARTIAL:	Only channels described by this instance are
> + *				owned by this driver. Controller-wide state
> + *				must be preserved, and layouts with shared
> + *				direction-wide registers must only be shared at
> + *				direction granularity.
>   */
>  enum dw_edma_chip_flags {
>  	DW_EDMA_CHIP_LOCAL	= BIT(0),
> +	DW_EDMA_CHIP_PARTIAL	= BIT(1),
>  };
>
>  /**
> --
> 2.51.0
>

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

* Re: [PATCH v2 04/12] dmaengine: dw-edma-pcie: Track non-LL mode in DMA data
  2026-05-25  6:24 ` [PATCH v2 04/12] dmaengine: dw-edma-pcie: Track non-LL mode in DMA data Koichiro Den
@ 2026-06-04 20:26   ` Frank Li
  0 siblings, 0 replies; 24+ messages in thread
From: Frank Li @ 2026-06-04 20:26 UTC (permalink / raw)
  To: Koichiro Den
  Cc: Vinod Koul, Frank Li, Manivannan Sadhasivam, Marek Vasut,
	Yoshihiro Shimoda, dmaengine, linux-kernel

On Mon, May 25, 2026 at 03:24:12PM +0900, Koichiro Den wrote:
> The dw-edma-pcie driver copies static template data into a mutable
> dw_edma_pcie_data instance before applying capability-derived updates.
> Keep the derived non-LL mode in that copy as well, instead of only
> tracking it in a local variable in dw_edma_pcie_probe().
>
> This prepares for keeping capability parsing behind match data without a
> separate non-LL output parameter.
>
> No functional change intended.
>
> Suggested-by: Frank Li <Frank.Li@nxp.com>
> Signed-off-by: Koichiro Den <den@valinux.co.jp>
> ---

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

> Changes in v2:
>   - New patch, per Frank's feedback.
>
>  drivers/dma/dw-edma/dw-edma-pcie.c | 12 ++++++------
>  1 file changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
> index 0b30ce138503..e92ff5dc6f67 100644
> --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> @@ -72,6 +72,7 @@ struct dw_edma_pcie_data {
>  	u16				wr_ch_cnt;
>  	u16				rd_ch_cnt;
>  	u64				devmem_phys_off;
> +	bool				cfg_non_ll;
>  };
>
>  static const struct dw_edma_pcie_data snps_edda_data = {
> @@ -312,7 +313,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  	struct dw_edma_chip *chip;
>  	int err, nr_irqs;
>  	int i, mask;
> -	bool non_ll = false;
>
>  	struct dw_edma_pcie_data *vsec_data __free(kfree) =
>  		kmalloc_obj(*vsec_data);
> @@ -344,14 +344,14 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  		 * the HDMA IP.
>  		 */
>  		if (vsec_data->devmem_phys_off == DW_PCIE_XILINX_MDB_INVALID_ADDR)
> -			non_ll = true;
> +			vsec_data->cfg_non_ll = true;
>
>  		/*
>  		 * Configure the channel LL and data blocks if number of
>  		 * channels enabled in VSEC capability are more than the
>  		 * channels configured in xilinx_mdb_data.
>  		 */
> -		if (!non_ll)
> +		if (!vsec_data->cfg_non_ll)
>  			dw_edma_set_chan_region_offset(vsec_data, BAR_2, 0,
>  						       DW_PCIE_XILINX_MDB_LL_OFF_GAP,
>  						       DW_PCIE_XILINX_MDB_LL_SIZE,
> @@ -404,7 +404,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  	chip->mf = vsec_data->mf;
>  	chip->nr_irqs = nr_irqs;
>  	chip->ops = &dw_edma_pcie_plat_ops;
> -	chip->cfg_non_ll = non_ll;
> +	chip->cfg_non_ll = vsec_data->cfg_non_ll;
>
>  	chip->ll_wr_cnt = vsec_data->wr_ch_cnt;
>  	chip->ll_rd_cnt = vsec_data->rd_ch_cnt;
> @@ -413,7 +413,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  	if (!chip->reg_base)
>  		return -ENOMEM;
>
> -	for (i = 0; i < chip->ll_wr_cnt && !non_ll; i++) {
> +	for (i = 0; i < chip->ll_wr_cnt && !vsec_data->cfg_non_ll; i++) {
>  		struct dw_edma_region *ll_region = &chip->ll_region_wr[i];
>  		struct dw_edma_region *dt_region = &chip->dt_region_wr[i];
>  		struct dw_edma_block *ll_block = &vsec_data->ll_wr[i];
> @@ -440,7 +440,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  		dt_region->sz = dt_block->sz;
>  	}
>
> -	for (i = 0; i < chip->ll_rd_cnt && !non_ll; i++) {
> +	for (i = 0; i < chip->ll_rd_cnt && !vsec_data->cfg_non_ll; i++) {
>  		struct dw_edma_region *ll_region = &chip->ll_region_rd[i];
>  		struct dw_edma_region *dt_region = &chip->dt_region_rd[i];
>  		struct dw_edma_block *ll_block = &vsec_data->ll_rd[i];
> --
> 2.51.0
>

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

* Re: [PATCH v2 05/12] dmaengine: dw-edma-pcie: Add capability match data
  2026-05-25  6:24 ` [PATCH v2 05/12] dmaengine: dw-edma-pcie: Add capability match data Koichiro Den
@ 2026-06-04 20:28   ` Frank Li
  0 siblings, 0 replies; 24+ messages in thread
From: Frank Li @ 2026-06-04 20:28 UTC (permalink / raw)
  To: Koichiro Den
  Cc: Vinod Koul, Frank Li, Manivannan Sadhasivam, Marek Vasut,
	Yoshihiro Shimoda, dmaengine, linux-kernel

On Mon, May 25, 2026 at 03:24:13PM +0900, Koichiro Den wrote:
> Move device-specific capability parsing behind per-device match data.
>
> The existing probe path mixes two decisions: which static template a PCI
> ID uses, and which device-specific capability parser adjusts that
> template. Split those decisions so device-specific discovery can be
> added through match data instead of adding more vendor checks to
> dw_edma_pcie_probe().
>
> No functional change is intended for the existing Synopsys EDDA and
> AMD/Xilinx MDB matches. They still copy the same static template data and
> run the same capability parsing logic before BAR mapping. The MDB entry
> also keeps using endpoint memory physical addresses for descriptor
> windows through a new match-data flag.
>
> Suggested-by: Frank Li <Frank.Li@nxp.com>
> Signed-off-by: Koichiro Den <den@valinux.co.jp>
> ---

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

> Changes in v2:
>   - Keep non-LL mode in dw_edma_pcie_data instead of a separate
>     parse_caps() output parameter.
>   - While at here, use a named .driver_data initializer for the Xilinx MDB ID
>     entry, per Frank's suggestion.
>
>  drivers/dma/dw-edma/dw-edma-pcie.c | 127 +++++++++++++++++++----------
>  1 file changed, 85 insertions(+), 42 deletions(-)
>
> diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
> index e92ff5dc6f67..5a6f5af358d0 100644
> --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> @@ -75,6 +75,19 @@ struct dw_edma_pcie_data {
>  	bool				cfg_non_ll;
>  };
>
> +struct dw_edma_pcie_match_data {
> +	const struct dw_edma_pcie_data *data;
> +	/*
> +	 * Mandatory callback. It may leave @pdata unchanged when the static
> +	 * template already describes the device.
> +	 */
> +	int (*parse_caps)(struct pci_dev *pdev,
> +			  struct dw_edma_pcie_data *pdata);
> +	unsigned long flags;
> +};
> +
> +#define DW_EDMA_PCIE_F_DEVMEM_PHYS_OFF	BIT(0)
> +
>  static const struct dw_edma_pcie_data snps_edda_data = {
>  	/* eDMA registers location */
>  	.rg.bar				= BAR_0,
> @@ -296,19 +309,61 @@ static void dw_edma_pcie_get_xilinx_dma_data(struct pci_dev *pdev,
>  	pdata->devmem_phys_off = off;
>  }
>
> +static int
> +dw_edma_pcie_parse_synopsys_caps(struct pci_dev *pdev,
> +				 struct dw_edma_pcie_data *pdata)
> +{
> +	dw_edma_pcie_get_synopsys_dma_data(pdev, pdata);
> +
> +	return 0;
> +}
> +
> +static int
> +dw_edma_pcie_parse_xilinx_caps(struct pci_dev *pdev,
> +			       struct dw_edma_pcie_data *pdata)
> +{
> +	dw_edma_pcie_get_xilinx_dma_data(pdev, pdata);
> +
> +	/*
> +	 * There is no valid address found for the LL memory space on the
> +	 * device side. In the absence of LL base address use the non-LL mode or
> +	 * simple mode supported by the HDMA IP.
> +	 */
> +	if (pdata->devmem_phys_off == DW_PCIE_XILINX_MDB_INVALID_ADDR) {
> +		pdata->cfg_non_ll = true;
> +		return 0;
> +	}
> +
> +	/*
> +	 * Configure the channel LL and data blocks if number of channels
> +	 * enabled in VSEC capability are more than the channels configured in
> +	 * xilinx_mdb_data.
> +	 */
> +	dw_edma_set_chan_region_offset(pdata, BAR_2, 0,
> +				       DW_PCIE_XILINX_MDB_LL_OFF_GAP,
> +				       DW_PCIE_XILINX_MDB_LL_SIZE,
> +				       DW_PCIE_XILINX_MDB_DT_OFF_GAP,
> +				       DW_PCIE_XILINX_MDB_DT_SIZE);
> +
> +	return 0;
> +}
> +
>  static u64 dw_edma_get_phys_addr(struct pci_dev *pdev,
> +				 const struct dw_edma_pcie_match_data *match,
>  				 struct dw_edma_pcie_data *pdata,
>  				 enum pci_barno bar)
>  {
> -	if (pdev->vendor == PCI_VENDOR_ID_XILINX)
> +	if (match->flags & DW_EDMA_PCIE_F_DEVMEM_PHYS_OFF)
>  		return pdata->devmem_phys_off;
> +
>  	return pci_bus_address(pdev, bar);
>  }
>
>  static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  			      const struct pci_device_id *pid)
>  {
> -	struct dw_edma_pcie_data *pdata = (void *)pid->driver_data;
> +	const struct dw_edma_pcie_match_data *match = (void *)pid->driver_data;
> +	const struct dw_edma_pcie_data *pdata = match->data;
>  	struct device *dev = &pdev->dev;
>  	struct dw_edma_chip *chip;
>  	int err, nr_irqs;
> @@ -328,36 +383,13 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>
>  	memcpy(vsec_data, pdata, sizeof(struct dw_edma_pcie_data));
>
> -	/*
> -	 * Tries to find if exists a PCIe Vendor-Specific Extended Capability
> -	 * for the DMA, if one exists, then reconfigures it.
> -	 */
> -	dw_edma_pcie_get_synopsys_dma_data(pdev, vsec_data);
> -
> -	if (pdev->vendor == PCI_VENDOR_ID_XILINX) {
> -		dw_edma_pcie_get_xilinx_dma_data(pdev, vsec_data);
> -
> -		/*
> -		 * There is no valid address found for the LL memory
> -		 * space on the device side. In the absence of LL base
> -		 * address use the non-LL mode or simple mode supported by
> -		 * the HDMA IP.
> -		 */
> -		if (vsec_data->devmem_phys_off == DW_PCIE_XILINX_MDB_INVALID_ADDR)
> -			vsec_data->cfg_non_ll = true;
> -
> -		/*
> -		 * Configure the channel LL and data blocks if number of
> -		 * channels enabled in VSEC capability are more than the
> -		 * channels configured in xilinx_mdb_data.
> -		 */
> -		if (!vsec_data->cfg_non_ll)
> -			dw_edma_set_chan_region_offset(vsec_data, BAR_2, 0,
> -						       DW_PCIE_XILINX_MDB_LL_OFF_GAP,
> -						       DW_PCIE_XILINX_MDB_LL_SIZE,
> -						       DW_PCIE_XILINX_MDB_DT_OFF_GAP,
> -						       DW_PCIE_XILINX_MDB_DT_SIZE);
> -	}
> +	/* Let device-specific discovery override the static template data. */
> +	if (!match->parse_caps)
> +		return -EINVAL;
> +
> +	err = match->parse_caps(pdev, vsec_data);
> +	if (err)
> +		return err;
>
>  	/* Mapping PCI BAR regions */
>  	mask = BIT(vsec_data->rg.bar);
> @@ -424,8 +456,8 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  			return -ENOMEM;
>
>  		ll_region->vaddr.io += ll_block->off;
> -		ll_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
> -							 ll_block->bar);
> +		ll_region->paddr = dw_edma_get_phys_addr(pdev, match,
> +							 vsec_data, ll_block->bar);
>  		ll_region->paddr += ll_block->off;
>  		ll_region->sz = ll_block->sz;
>
> @@ -434,8 +466,8 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  			return -ENOMEM;
>
>  		dt_region->vaddr.io += dt_block->off;
> -		dt_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
> -							 dt_block->bar);
> +		dt_region->paddr = dw_edma_get_phys_addr(pdev, match,
> +							 vsec_data, dt_block->bar);
>  		dt_region->paddr += dt_block->off;
>  		dt_region->sz = dt_block->sz;
>  	}
> @@ -451,8 +483,8 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  			return -ENOMEM;
>
>  		ll_region->vaddr.io += ll_block->off;
> -		ll_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
> -							 ll_block->bar);
> +		ll_region->paddr = dw_edma_get_phys_addr(pdev, match,
> +							 vsec_data, ll_block->bar);
>  		ll_region->paddr += ll_block->off;
>  		ll_region->sz = ll_block->sz;
>
> @@ -461,8 +493,8 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  			return -ENOMEM;
>
>  		dt_region->vaddr.io += dt_block->off;
> -		dt_region->paddr = dw_edma_get_phys_addr(pdev, vsec_data,
> -							 dt_block->bar);
> +		dt_region->paddr = dw_edma_get_phys_addr(pdev, match,
> +							 vsec_data, dt_block->bar);
>  		dt_region->paddr += dt_block->off;
>  		dt_region->sz = dt_block->sz;
>  	}
> @@ -543,10 +575,21 @@ static void dw_edma_pcie_remove(struct pci_dev *pdev)
>  	pci_free_irq_vectors(pdev);
>  }
>
> +static const struct dw_edma_pcie_match_data snps_edda_match_data = {
> +	.data = &snps_edda_data,
> +	.parse_caps = dw_edma_pcie_parse_synopsys_caps,
> +};
> +
> +static const struct dw_edma_pcie_match_data xilinx_mdb_match_data = {
> +	.data = &xilinx_mdb_data,
> +	.parse_caps = dw_edma_pcie_parse_xilinx_caps,
> +	.flags = DW_EDMA_PCIE_F_DEVMEM_PHYS_OFF,
> +};
> +
>  static const struct pci_device_id dw_edma_pcie_id_table[] = {
> -	{ PCI_DEVICE_DATA(SYNOPSYS, EDDA, &snps_edda_data) },
> +	{ PCI_DEVICE_DATA(SYNOPSYS, EDDA, &snps_edda_match_data) },
>  	{ PCI_VDEVICE(XILINX, PCI_DEVICE_ID_XILINX_B054),
> -	  (kernel_ulong_t)&xilinx_mdb_data },
> +	  .driver_data = (kernel_ulong_t)&xilinx_mdb_match_data },
>  	{ }
>  };
>  MODULE_DEVICE_TABLE(pci, dw_edma_pcie_id_table);
> --
> 2.51.0
>

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

* Re: [PATCH v2 06/12] dmaengine: dw-edma-pcie: Rename vsec_data to dma_data
  2026-05-25  6:24 ` [PATCH v2 06/12] dmaengine: dw-edma-pcie: Rename vsec_data to dma_data Koichiro Den
@ 2026-06-04 20:35   ` Frank Li
  2026-06-05  2:42     ` Koichiro Den
  0 siblings, 1 reply; 24+ messages in thread
From: Frank Li @ 2026-06-04 20:35 UTC (permalink / raw)
  To: Koichiro Den
  Cc: Vinod Koul, Frank Li, Manivannan Sadhasivam, Marek Vasut,
	Yoshihiro Shimoda, dmaengine, linux-kernel

On Mon, May 25, 2026 at 03:24:14PM +0900, Koichiro Den wrote:
> dw_edma_pcie_probe() now obtains DMA layout data through device-specific
> capability callbacks, not only from PCIe Vendor-Specific Extended
> Capabilities. Rename the local data copy from vsec_data to dma_data
> before adding endpoint DMA BAR metadata discovery, which does not rely
> on VSEC.
>
> No functional change intended.
>
> Signed-off-by: Koichiro Den <den@valinux.co.jp>
> ---
> Changes in v2:
>   - Fix the commit title as Frank pointed out.
>
>  drivers/dma/dw-edma/dw-edma-pcie.c | 76 +++++++++++++++---------------
>  1 file changed, 37 insertions(+), 39 deletions(-)
>
> diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
> index 5a6f5af358d0..c7362f1bf80c 100644
> --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> @@ -369,11 +369,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  	int err, nr_irqs;
>  	int i, mask;
>
> -	struct dw_edma_pcie_data *vsec_data __free(kfree) =
> -		kmalloc_obj(*vsec_data);
> -	if (!vsec_data)
> -		return -ENOMEM;
> -
>  	/* Enable PCI device */
>  	err = pcim_enable_device(pdev);
>  	if (err) {
> @@ -381,25 +376,28 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  		return err;
>  	}
>
> -	memcpy(vsec_data, pdata, sizeof(struct dw_edma_pcie_data));
> +	struct dw_edma_pcie_data *dma_data __free(kfree) =
> +		kmemdup(pdata, sizeof(*dma_data), GFP_KERNEL);
> +	if (!dma_data)
> +		return -ENOMEM;
>

This is straigh forward patch, you move this block after pcim_enable_device();
I suggest keep original place for easily review.

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


>  	/* Let device-specific discovery override the static template data. */
>  	if (!match->parse_caps)
>  		return -EINVAL;
>
> -	err = match->parse_caps(pdev, vsec_data);
> +	err = match->parse_caps(pdev, dma_data);
>  	if (err)
>  		return err;
>
>  	/* Mapping PCI BAR regions */
> -	mask = BIT(vsec_data->rg.bar);
> -	for (i = 0; i < vsec_data->wr_ch_cnt; i++) {
> -		mask |= BIT(vsec_data->ll_wr[i].bar);
> -		mask |= BIT(vsec_data->dt_wr[i].bar);
> +	mask = BIT(dma_data->rg.bar);
> +	for (i = 0; i < dma_data->wr_ch_cnt; i++) {
> +		mask |= BIT(dma_data->ll_wr[i].bar);
> +		mask |= BIT(dma_data->dt_wr[i].bar);
>  	}
> -	for (i = 0; i < vsec_data->rd_ch_cnt; i++) {
> -		mask |= BIT(vsec_data->ll_rd[i].bar);
> -		mask |= BIT(vsec_data->dt_rd[i].bar);
> +	for (i = 0; i < dma_data->rd_ch_cnt; i++) {
> +		mask |= BIT(dma_data->ll_rd[i].bar);
> +		mask |= BIT(dma_data->dt_rd[i].bar);
>  	}
>  	err = pcim_iomap_regions(pdev, mask, pci_name(pdev));
>  	if (err) {
> @@ -422,7 +420,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  		return -ENOMEM;
>
>  	/* IRQs allocation */
> -	nr_irqs = pci_alloc_irq_vectors(pdev, 1, vsec_data->irqs,
> +	nr_irqs = pci_alloc_irq_vectors(pdev, 1, dma_data->irqs,
>  					PCI_IRQ_MSI | PCI_IRQ_MSIX);
>  	if (nr_irqs < 1) {
>  		pci_err(pdev, "fail to alloc IRQ vector (number of IRQs=%u)\n",
> @@ -433,23 +431,23 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  	/* Data structure initialization */
>  	chip->dev = dev;
>
> -	chip->mf = vsec_data->mf;
> +	chip->mf = dma_data->mf;
>  	chip->nr_irqs = nr_irqs;
>  	chip->ops = &dw_edma_pcie_plat_ops;
> -	chip->cfg_non_ll = vsec_data->cfg_non_ll;
> +	chip->cfg_non_ll = dma_data->cfg_non_ll;
>
> -	chip->ll_wr_cnt = vsec_data->wr_ch_cnt;
> -	chip->ll_rd_cnt = vsec_data->rd_ch_cnt;
> +	chip->ll_wr_cnt = dma_data->wr_ch_cnt;
> +	chip->ll_rd_cnt = dma_data->rd_ch_cnt;
>
> -	chip->reg_base = pcim_iomap_table(pdev)[vsec_data->rg.bar];
> +	chip->reg_base = pcim_iomap_table(pdev)[dma_data->rg.bar];
>  	if (!chip->reg_base)
>  		return -ENOMEM;
>
> -	for (i = 0; i < chip->ll_wr_cnt && !vsec_data->cfg_non_ll; i++) {
> +	for (i = 0; i < chip->ll_wr_cnt && !dma_data->cfg_non_ll; i++) {
>  		struct dw_edma_region *ll_region = &chip->ll_region_wr[i];
>  		struct dw_edma_region *dt_region = &chip->dt_region_wr[i];
> -		struct dw_edma_block *ll_block = &vsec_data->ll_wr[i];
> -		struct dw_edma_block *dt_block = &vsec_data->dt_wr[i];
> +		struct dw_edma_block *ll_block = &dma_data->ll_wr[i];
> +		struct dw_edma_block *dt_block = &dma_data->dt_wr[i];
>
>  		ll_region->vaddr.io = pcim_iomap_table(pdev)[ll_block->bar];
>  		if (!ll_region->vaddr.io)
> @@ -457,7 +455,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>
>  		ll_region->vaddr.io += ll_block->off;
>  		ll_region->paddr = dw_edma_get_phys_addr(pdev, match,
> -							 vsec_data, ll_block->bar);
> +							 dma_data, ll_block->bar);
>  		ll_region->paddr += ll_block->off;
>  		ll_region->sz = ll_block->sz;
>
> @@ -467,16 +465,16 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>
>  		dt_region->vaddr.io += dt_block->off;
>  		dt_region->paddr = dw_edma_get_phys_addr(pdev, match,
> -							 vsec_data, dt_block->bar);
> +							 dma_data, dt_block->bar);
>  		dt_region->paddr += dt_block->off;
>  		dt_region->sz = dt_block->sz;
>  	}
>
> -	for (i = 0; i < chip->ll_rd_cnt && !vsec_data->cfg_non_ll; i++) {
> +	for (i = 0; i < chip->ll_rd_cnt && !dma_data->cfg_non_ll; i++) {
>  		struct dw_edma_region *ll_region = &chip->ll_region_rd[i];
>  		struct dw_edma_region *dt_region = &chip->dt_region_rd[i];
> -		struct dw_edma_block *ll_block = &vsec_data->ll_rd[i];
> -		struct dw_edma_block *dt_block = &vsec_data->dt_rd[i];
> +		struct dw_edma_block *ll_block = &dma_data->ll_rd[i];
> +		struct dw_edma_block *dt_block = &dma_data->dt_rd[i];
>
>  		ll_region->vaddr.io = pcim_iomap_table(pdev)[ll_block->bar];
>  		if (!ll_region->vaddr.io)
> @@ -484,7 +482,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>
>  		ll_region->vaddr.io += ll_block->off;
>  		ll_region->paddr = dw_edma_get_phys_addr(pdev, match,
> -							 vsec_data, ll_block->bar);
> +							 dma_data, ll_block->bar);
>  		ll_region->paddr += ll_block->off;
>  		ll_region->sz = ll_block->sz;
>
> @@ -494,7 +492,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>
>  		dt_region->vaddr.io += dt_block->off;
>  		dt_region->paddr = dw_edma_get_phys_addr(pdev, match,
> -							 vsec_data, dt_block->bar);
> +							 dma_data, dt_block->bar);
>  		dt_region->paddr += dt_block->off;
>  		dt_region->sz = dt_block->sz;
>  	}
> @@ -512,31 +510,31 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  		pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", chip->mf);
>
>  	pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p)\n",
> -		vsec_data->rg.bar, vsec_data->rg.off, vsec_data->rg.sz,
> +		dma_data->rg.bar, dma_data->rg.off, dma_data->rg.sz,
>  		chip->reg_base);
>
>
>  	for (i = 0; i < chip->ll_wr_cnt; i++) {
>  		pci_dbg(pdev, "L. List:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
> -			i, vsec_data->ll_wr[i].bar,
> -			vsec_data->ll_wr[i].off, chip->ll_region_wr[i].sz,
> +			i, dma_data->ll_wr[i].bar,
> +			dma_data->ll_wr[i].off, chip->ll_region_wr[i].sz,
>  			chip->ll_region_wr[i].vaddr.io, &chip->ll_region_wr[i].paddr);
>
>  		pci_dbg(pdev, "Data:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
> -			i, vsec_data->dt_wr[i].bar,
> -			vsec_data->dt_wr[i].off, chip->dt_region_wr[i].sz,
> +			i, dma_data->dt_wr[i].bar,
> +			dma_data->dt_wr[i].off, chip->dt_region_wr[i].sz,
>  			chip->dt_region_wr[i].vaddr.io, &chip->dt_region_wr[i].paddr);
>  	}
>
>  	for (i = 0; i < chip->ll_rd_cnt; i++) {
>  		pci_dbg(pdev, "L. List:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
> -			i, vsec_data->ll_rd[i].bar,
> -			vsec_data->ll_rd[i].off, chip->ll_region_rd[i].sz,
> +			i, dma_data->ll_rd[i].bar,
> +			dma_data->ll_rd[i].off, chip->ll_region_rd[i].sz,
>  			chip->ll_region_rd[i].vaddr.io, &chip->ll_region_rd[i].paddr);
>
>  		pci_dbg(pdev, "Data:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
> -			i, vsec_data->dt_rd[i].bar,
> -			vsec_data->dt_rd[i].off, chip->dt_region_rd[i].sz,
> +			i, dma_data->dt_rd[i].bar,
> +			dma_data->dt_rd[i].off, chip->dt_region_rd[i].sz,
>  			chip->dt_region_rd[i].vaddr.io, &chip->dt_region_rd[i].paddr);
>  	}
>
> --
> 2.51.0
>

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

* Re: [PATCH v2 08/12] dmaengine: dw-edma-pcie: Add platform ops to match data
  2026-05-25  6:24 ` [PATCH v2 08/12] dmaengine: dw-edma-pcie: Add platform ops " Koichiro Den
@ 2026-06-04 20:37   ` Frank Li
  0 siblings, 0 replies; 24+ messages in thread
From: Frank Li @ 2026-06-04 20:37 UTC (permalink / raw)
  To: Koichiro Den
  Cc: Vinod Koul, Frank Li, Manivannan Sadhasivam, Marek Vasut,
	Yoshihiro Shimoda, dmaengine, linux-kernel

On Mon, May 25, 2026 at 03:24:16PM +0900, Koichiro Den wrote:
> Move the platform ops pointer into match data. Existing EDDA/MDB matches
> keep using dw_edma_pcie_plat_ops.
>
> No functional changes intended.
>
> Suggested-by: Frank Li <Frank.Li@nxp.com>
> Signed-off-by: Koichiro Den <den@valinux.co.jp>
> ---

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

> Changes in v2:
>   - New patch. The original commit
>     "dmaengine: dw-edma-pcie: Add raw slave address ops" is dropped
>     per Frank's suggestion. DW_EDMA_PCIE_F_RAW_SLAVE_ADDR is no
>     longer needed.
>
>  drivers/dma/dw-edma/dw-edma-pcie.c | 7 +++++--
>  1 file changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
> index 9aed1005854d..1d63b07723f9 100644
> --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> @@ -77,6 +77,7 @@ struct dw_edma_pcie_data {
>
>  struct dw_edma_pcie_match_data {
>  	const struct dw_edma_pcie_data *data;
> +	const struct dw_edma_plat_ops *plat_ops;
>  	/*
>  	 * Mandatory callback. It may leave @pdata unchanged when the static
>  	 * template already describes the device.
> @@ -383,7 +384,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  		return -ENOMEM;
>
>  	/* Let device-specific discovery override the static template data. */
> -	if (!match->parse_caps)
> +	if (!match->parse_caps || !match->plat_ops)
>  		return -EINVAL;
>
>  	err = match->parse_caps(pdev, dma_data);
> @@ -435,7 +436,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
>  	chip->mf = dma_data->mf;
>  	chip->default_irq_mode = match->default_irq_mode;
>  	chip->nr_irqs = nr_irqs;
> -	chip->ops = &dw_edma_pcie_plat_ops;
> +	chip->ops = match->plat_ops;
>  	chip->cfg_non_ll = dma_data->cfg_non_ll;
>
>  	chip->ll_wr_cnt = dma_data->wr_ch_cnt;
> @@ -577,11 +578,13 @@ static void dw_edma_pcie_remove(struct pci_dev *pdev)
>
>  static const struct dw_edma_pcie_match_data snps_edda_match_data = {
>  	.data = &snps_edda_data,
> +	.plat_ops = &dw_edma_pcie_plat_ops,
>  	.parse_caps = dw_edma_pcie_parse_synopsys_caps,
>  };
>
>  static const struct dw_edma_pcie_match_data xilinx_mdb_match_data = {
>  	.data = &xilinx_mdb_data,
> +	.plat_ops = &dw_edma_pcie_plat_ops,
>  	.parse_caps = dw_edma_pcie_parse_xilinx_caps,
>  	.flags = DW_EDMA_PCIE_F_DEVMEM_PHYS_OFF,
>  };
> --
> 2.51.0
>

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

* Re: [PATCH v2 01/12] dmaengine: dw-edma: Add hardware channel filter
  2026-05-25  6:24 ` [PATCH v2 01/12] dmaengine: dw-edma: Add hardware channel filter Koichiro Den
@ 2026-06-04 20:40   ` Frank Li
  2026-06-05  2:26     ` Koichiro Den
  0 siblings, 1 reply; 24+ messages in thread
From: Frank Li @ 2026-06-04 20:40 UTC (permalink / raw)
  To: Koichiro Den
  Cc: Vinod Koul, Frank Li, Manivannan Sadhasivam, Marek Vasut,
	Yoshihiro Shimoda, dmaengine, linux-kernel

On Mon, May 25, 2026 at 03:24:09PM +0900, Koichiro Den wrote:
> Add a dma_request_channel() filter that matches a DesignWare eDMA
> write/read hardware channel by hardware channel number.
>
> PCI endpoint resource enumeration can describe hardware channel metadata
> and let consumers claim it through the normal DMAengine request path.
> This avoids returning an unclaimed dma_chan pointer to the caller and does
> not require making dma_get_slave_channel() public.
>
> Signed-off-by: Koichiro Den <den@valinux.co.jp>
> ---
> Changes in v2:
>   - New patch. Replace the raw channel lookup helper with a
>     dma_request_channel() filter.
>   - Do not make dma_get_slave_channel() public.
>     Patch 01/12 "dmaengine: Make dma_get_slave_channel() public" is
>     dropped.
>
>  drivers/dma/dw-edma/dw-edma-core.c | 15 +++++++++++++++
>  include/linux/dma/edma.h           | 18 ++++++++++++++++++
>  2 files changed, 33 insertions(+)
>
> diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> index c2feb3adc79f..80b4a168225b 100644
> --- a/drivers/dma/dw-edma/dw-edma-core.c
> +++ b/drivers/dma/dw-edma/dw-edma-core.c
> @@ -1189,6 +1189,21 @@ int dw_edma_remove(struct dw_edma_chip *chip)
>  }
>  EXPORT_SYMBOL_GPL(dw_edma_remove);
>
> +bool dw_edma_filter_hw_chan(struct dma_chan *dchan, void *param)
> +{
> +	struct dw_edma_hw_chan_filter *filter = param;
> +	struct dw_edma_chan *chan;
> +
> +	if (!filter || dchan->device->dev != filter->dma_dev)
> +		return false;
> +
> +	chan = dchan2dw_edma_chan(dchan);
> +
> +	return chan->dir == (filter->write ? EDMA_DIR_WRITE : EDMA_DIR_READ) &&
> +	       chan->id == filter->id;
> +}
> +EXPORT_SYMBOL_GPL(dw_edma_filter_hw_chan);
> +
>  MODULE_LICENSE("GPL v2");
>  MODULE_DESCRIPTION("Synopsys DesignWare eDMA controller core driver");
>  MODULE_AUTHOR("Gustavo Pimentel <gustavo.pimentel@synopsys.com>");
> diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> index 1fafd5b0e315..3e15cf83b784 100644
> --- a/include/linux/dma/edma.h
> +++ b/include/linux/dma/edma.h
> @@ -106,10 +106,23 @@ struct dw_edma_chip {
>  	bool			cfg_non_ll;
>  };
>
> +/**
> + * struct dw_edma_hw_chan_filter - DesignWare eDMA hardware channel selector
> + * @dma_dev: DMA controller device to match
> + * @write: true to select a write channel, false to select a read channel
> + * @id: hardware channel number within the selected direction
> + */
> +struct dw_edma_hw_chan_filter {
> +	struct device	*dma_dev;
> +	bool		write;
> +	u16		id;
> +};
> +

I have not seen user for this, not sure why it need be in this public header

Frank

>  /* Export to the platform drivers */
>  #if IS_REACHABLE(CONFIG_DW_EDMA)
>  int dw_edma_probe(struct dw_edma_chip *chip);
>  int dw_edma_remove(struct dw_edma_chip *chip);
> +bool dw_edma_filter_hw_chan(struct dma_chan *chan, void *param);
>  #else
>  static inline int dw_edma_probe(struct dw_edma_chip *chip)
>  {
> @@ -120,6 +133,11 @@ static inline int dw_edma_remove(struct dw_edma_chip *chip)
>  {
>  	return 0;
>  }
> +
> +static inline bool dw_edma_filter_hw_chan(struct dma_chan *chan, void *param)
> +{
> +	return false;
> +}
>  #endif /* CONFIG_DW_EDMA */
>
>  #endif /* _DW_EDMA_H */
> --
> 2.51.0
>

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

* Re: [PATCH v2 01/12] dmaengine: dw-edma: Add hardware channel filter
  2026-06-04 20:40   ` Frank Li
@ 2026-06-05  2:26     ` Koichiro Den
  0 siblings, 0 replies; 24+ messages in thread
From: Koichiro Den @ 2026-06-05  2:26 UTC (permalink / raw)
  To: Frank Li
  Cc: Vinod Koul, Frank Li, Manivannan Sadhasivam, Marek Vasut,
	Yoshihiro Shimoda, dmaengine, linux-kernel

On Thu, Jun 04, 2026 at 04:40:06PM -0400, Frank Li wrote:
> On Mon, May 25, 2026 at 03:24:09PM +0900, Koichiro Den wrote:
> > Add a dma_request_channel() filter that matches a DesignWare eDMA
> > write/read hardware channel by hardware channel number.
> >
> > PCI endpoint resource enumeration can describe hardware channel metadata
> > and let consumers claim it through the normal DMAengine request path.
> > This avoids returning an unclaimed dma_chan pointer to the caller and does
> > not require making dma_get_slave_channel() public.
> >
> > Signed-off-by: Koichiro Den <den@valinux.co.jp>
> > ---
> > Changes in v2:
> >   - New patch. Replace the raw channel lookup helper with a
> >     dma_request_channel() filter.
> >   - Do not make dma_get_slave_channel() public.
> >     Patch 01/12 "dmaengine: Make dma_get_slave_channel() public" is
> >     dropped.
> >
> >  drivers/dma/dw-edma/dw-edma-core.c | 15 +++++++++++++++
> >  include/linux/dma/edma.h           | 18 ++++++++++++++++++
> >  2 files changed, 33 insertions(+)
> >
> > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > index c2feb3adc79f..80b4a168225b 100644
> > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > @@ -1189,6 +1189,21 @@ int dw_edma_remove(struct dw_edma_chip *chip)
> >  }
> >  EXPORT_SYMBOL_GPL(dw_edma_remove);
> >
> > +bool dw_edma_filter_hw_chan(struct dma_chan *dchan, void *param)
> > +{
> > +	struct dw_edma_hw_chan_filter *filter = param;
> > +	struct dw_edma_chan *chan;
> > +
> > +	if (!filter || dchan->device->dev != filter->dma_dev)
> > +		return false;
> > +
> > +	chan = dchan2dw_edma_chan(dchan);
> > +
> > +	return chan->dir == (filter->write ? EDMA_DIR_WRITE : EDMA_DIR_READ) &&
> > +	       chan->id == filter->id;
> > +}
> > +EXPORT_SYMBOL_GPL(dw_edma_filter_hw_chan);
> > +
> >  MODULE_LICENSE("GPL v2");
> >  MODULE_DESCRIPTION("Synopsys DesignWare eDMA controller core driver");
> >  MODULE_AUTHOR("Gustavo Pimentel <gustavo.pimentel@synopsys.com>");
> > diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> > index 1fafd5b0e315..3e15cf83b784 100644
> > --- a/include/linux/dma/edma.h
> > +++ b/include/linux/dma/edma.h
> > @@ -106,10 +106,23 @@ struct dw_edma_chip {
> >  	bool			cfg_non_ll;
> >  };
> >
> > +/**
> > + * struct dw_edma_hw_chan_filter - DesignWare eDMA hardware channel selector
> > + * @dma_dev: DMA controller device to match
> > + * @write: true to select a write channel, false to select a read channel
> > + * @id: hardware channel number within the selected direction
> > + */
> > +struct dw_edma_hw_chan_filter {
> > +	struct device	*dma_dev;
> > +	bool		write;
> > +	u16		id;
> > +};
> > +
> 
> I have not seen user for this, not sure why it need be in this public header

Thanks for the review.

It is used by the DesignWare EP resource provider added in part 2:
https://lore.kernel.org/linux-pci/20260525063129.3316894-4-den@valinux.co.jp/
Since that provider lives outside drivers/dma/dw-edma, the filter definition
needs to be visible outside the dw-edma core.

As a side note, this was added in v2, after Sashiko's feedback [1]. The v2 model
is:

  - The PCI aux resource provider describes static HW channel resources, rather
    than potentially unstable dma_chan pointers.
  - When the EPF delegates some of the channels to the peer host, it requests
    the channel by matching the HW channel id.

If the lifetime/removal model changes based on your feedback on [PATCH v2
03/12], we could possibly go back to the v1 model [2], where the PCI aux
resource provider describes channel resources with dma_chan pointers. In that
case, we would need to document that those dma_chan pointers must remain valid
for the lifetime of the aux resource consumer, and this dw_edma_hw_chan_filter
helper would no longer be needed; dw_edma_find_channel() could be revived [3].

[1] https://lore.kernel.org/dmaengine/20260521065525.C65DB1F000E9@smtp.kernel.org/
[2] https://lore.kernel.org/linux-pci/20260521063405.2842644-3-den@valinux.co.jp/
[3] https://lore.kernel.org/dmaengine/20260521063115.2842238-3-den@valinux.co.jp/

Best regards,
Koichiro

> 
> Frank
> 
> >  /* Export to the platform drivers */
> >  #if IS_REACHABLE(CONFIG_DW_EDMA)
> >  int dw_edma_probe(struct dw_edma_chip *chip);
> >  int dw_edma_remove(struct dw_edma_chip *chip);
> > +bool dw_edma_filter_hw_chan(struct dma_chan *chan, void *param);
> >  #else
> >  static inline int dw_edma_probe(struct dw_edma_chip *chip)
> >  {
> > @@ -120,6 +133,11 @@ static inline int dw_edma_remove(struct dw_edma_chip *chip)
> >  {
> >  	return 0;
> >  }
> > +
> > +static inline bool dw_edma_filter_hw_chan(struct dma_chan *chan, void *param)
> > +{
> > +	return false;
> > +}
> >  #endif /* CONFIG_DW_EDMA */
> >
> >  #endif /* _DW_EDMA_H */
> > --
> > 2.51.0
> >

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

* Re: [PATCH v2 02/12] dmaengine: dw-edma: Add per-channel interrupt routing control
  2026-06-04 20:18   ` Frank Li
@ 2026-06-05  2:36     ` Koichiro Den
  0 siblings, 0 replies; 24+ messages in thread
From: Koichiro Den @ 2026-06-05  2:36 UTC (permalink / raw)
  To: Frank Li
  Cc: Vinod Koul, Frank Li, Manivannan Sadhasivam, Marek Vasut,
	Yoshihiro Shimoda, dmaengine, linux-kernel

On Thu, Jun 04, 2026 at 04:18:02PM -0400, Frank Li wrote:
> On Mon, May 25, 2026 at 03:24:10PM +0900, Koichiro Den wrote:
> > DesignWare eDMA can signal completion locally through edma_int[] and
> > remotely through IMWr/MSI. When channels are delegated to a remote
> > frontend, the local endpoint side and the remote host side must not both
> > service the same DONE/ABORT status.
> >
> > Add dw_edma_irq_config, carried through dma_slave_config, so a frontend
> > can choose default, local, or remote IRQ handling per channel. Update the
> > v0 path so linked-list interrupt generation and DONE/ABORT masking follow
> > the selected mode. If a frontend does not supply the config, keep the
> > existing behavior.
> >
> > HDMA native already uses dma_slave_config.peripheral_config as an int for
> > non-LL mode selection. Keep that interface unchanged and reject the new
> > IRQ config there until an IRQ routing model is implemented and validated.
> >
> > Signed-off-by: Koichiro Den <den@valinux.co.jp>
> > ---
> ...
> >
> > +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)
> 
> suppose it should be pre channel config, why need check chip's informaiton?

The irq_mode alone does not tell whether this Linux instance should handle the
channel interrupt. The decision depends on both the per-channel irq_mode and
whether this dw-edma instance is the local or remote.

- For a local instance (i.e. EP Linux), interrupts that are supposed to be
  handled on a remote instance needs to be ignored even if edma_int[*] for that
  is raised.
- For a remote instance (i.e. Host Linux), interrupts that are supposed to be
  handled on a local instance needs to be ignored even if IMWr for that is
  raised.

The both ends sees the same status/clear registers, so the non-owner side must
not clear the done/abort status for a channel that is supposed to be cleared by
the other side.

> 
> > +		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 69e8279adec8..08ec2bd7856e 100644
> > --- a/drivers/dma/dw-edma/dw-edma-v0-core.c
> > +++ b/drivers/dma/dw-edma/dw-edma-v0-core.c
> > @@ -256,9 +256,11 @@ 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];
> >
> > +		if (dw_edma_core_ch_ignore_irq(chan))
> > +			continue;
> > +
> >  		dw_edma_v0_core_clear_done_int(chan);
> >  		done(chan);
> > -
> >  		ret = IRQ_HANDLED;
> >  	}
> >
> > @@ -267,9 +269,11 @@ 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];
> >
> > +		if (dw_edma_core_ch_ignore_irq(chan))
> > +			continue;
> > +
> >  		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 3e15cf83b784..2bf2298711e1 100644
> > --- a/include/linux/dma/edma.h
> > +++ b/include/linux/dma/edma.h
> > @@ -60,6 +60,43 @@ 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:   keep legacy behavior
> 
> Feel like it make things complex, most likely use pcie ep probe, it should
> be use DW_EDMA_CH_IRQ_LOCAL.
> 
> If probe from dw-edma-pcie.c, it should be use DW_EDMA_CH_IRQ_REMOTE.
> 
> Add default mode, it make check logic become complex.

Sounds reasonable. I will drop the DEFAULT mode.

Thanks for reviewing,
Koichiro

> 
> Frank
> 
> > + * @DW_EDMA_CH_IRQ_LOCAL:     local interrupt only (edma_int[])
> > + * @DW_EDMA_CH_IRQ_REMOTE:    remote interrupt only (IMWr/MSI),
> > + *                            while masking local DONE/ABORT output.
> > + *
> > + * DesignWare EP eDMA can signal interrupts locally through the edma_int[]
> > + * bus, and remotely using posted memory writes (IMWr) that may be
> > + * interpreted as MSI/MSI-X by the RC.
> > + *
> > + * For the v0 eDMA programming path, DMA_*_INT_MASK gates the local edma_int[]
> > + * assertion, while there is no dedicated per-channel mask for IMWr generation.
> > + * To request a remote-only interrupt, Synopsys recommends setting both LIE and
> > + * RIE, and masking the local interrupt in DMA_*_INT_MASK (rather than relying
> > + * on LIE=0/RIE=1). See the DesignWare endpoint databook 5.40a, Non Linked
> > + * List Mode interrupt handling ("Hint").
> > + */
> > +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_irq_config - dw-edma interrupt routing configuration
> > + * @irq_mode: per-channel interrupt routing control.
> > + * @reserved: must be zero.
> > + *
> > + * Pass this structure via dma_slave_config.peripheral_config and
> > + * dma_slave_config.peripheral_size.
> > + */
> > +struct dw_edma_irq_config {
> > +	enum dw_edma_ch_irq_mode irq_mode;
> > +	u32 reserved;
> > +};
> > +
> >  /**
> >   * struct dw_edma_chip - representation of DesignWare eDMA controller hardware
> >   * @dev:		 struct device of the eDMA controller
> > @@ -76,6 +113,8 @@ enum dw_edma_chip_flags {
> >   * @db_irq:		 Virtual IRQ dedicated to interrupt emulation
> >   * @db_offset:		 Offset from DMA register base
> >   * @mf:			 DMA register map format
> > + * @default_irq_mode:	 default per-channel interrupt routing when client
> > + *			 does not supply dw_edma_irq_config
> >   * @dw:			 struct dw_edma that is filled by dw_edma_probe()
> >   */
> >  struct dw_edma_chip {
> > @@ -101,6 +140,7 @@ struct dw_edma_chip {
> >  	resource_size_t		db_offset;
> >
> >  	enum dw_edma_map_format	mf;
> > +	enum dw_edma_ch_irq_mode	default_irq_mode;
> 
> suppose it is pre-channel config?
> 
> Frank
> >
> >  	struct dw_edma		*dw;
> >  	bool			cfg_non_ll;
> > --
> > 2.51.0
> >

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

* Re: [PATCH v2 03/12] dmaengine: dw-edma: Add partial channel ownership mode
  2026-06-04 20:24   ` Frank Li
@ 2026-06-05  2:40     ` Koichiro Den
  0 siblings, 0 replies; 24+ messages in thread
From: Koichiro Den @ 2026-06-05  2:40 UTC (permalink / raw)
  To: Frank Li
  Cc: Vinod Koul, Frank Li, Manivannan Sadhasivam, Marek Vasut,
	Yoshihiro Shimoda, dmaengine, linux-kernel

On Thu, Jun 04, 2026 at 04:24:21PM -0400, Frank Li wrote:
> On Mon, May 25, 2026 at 03:24:11PM +0900, Koichiro Den wrote:
> > Some endpoint DMA frontends expose only a subset of a controller that is
> > also initialized by the endpoint-side OS. Add a partial ownership flag
> > so dw-edma does not reset controller-wide state in probe() or remove().
> >
> > Keep the mode conservative. Do not enable interrupt-emulation doorbells,
> > and reject partial instances for map formats that this driver cannot safely
> > share. For EDMA_MF_EDMA_UNROLL and EDMA_MF_HDMA_COMPAT, require ownership
> > of all channels in each exposed direction. The driver updates registers
> > shared by all channels in a direction, such as interrupt masks and
> > linked-list error enables, so two independent OS instances cannot safely
> > split one direction without a shared locking protocol, which is
> > unrealistic.
> >
> > The frontend must still quiesce delegated channels before removing a
> > partial instance. The flag only keeps probe() and remove() from
> > resetting controller-wide state that may belong to a peer OS instance.
> >
> > Signed-off-by: Koichiro Den <den@valinux.co.jp>
> > ---
> > Changes in v2:
> >   - Reject partial ownership for unsupported map formats up front,
> >     keep direction-granularity validation limited to supported formats.
> >   - Revise the commit message accordingly.
> >
> >  drivers/dma/dw-edma/dw-edma-core.c | 47 +++++++++++++++++++++++-------
> >  include/linux/dma/edma.h           |  6 ++++
> >  2 files changed, 43 insertions(+), 10 deletions(-)
> >
> > diff --git a/drivers/dma/dw-edma/dw-edma-core.c b/drivers/dma/dw-edma/dw-edma-core.c
> > index a70e0640d082..fcef9a27b6ce 100644
> > --- a/drivers/dma/dw-edma/dw-edma-core.c
> > +++ b/drivers/dma/dw-edma/dw-edma-core.c
> > @@ -794,6 +794,9 @@ static int dw_edma_emul_irq_alloc(struct dw_edma *dw)
> >  	chip->db_irq = 0;
> >  	chip->db_offset = ~0;
> >
> > +	if (chip->flags & DW_EDMA_CHIP_PARTIAL)
> > +		return 0;
> > +
> >  	/*
> >  	 * Only meaningful when the core provides the deassert sequence
> >  	 * for interrupt emulation.
> > @@ -1135,6 +1138,8 @@ int dw_edma_probe(struct dw_edma_chip *chip)
> >  {
> >  	struct device *dev;
> >  	struct dw_edma *dw;
> > +	u16 hw_wr_ch_cnt;
> > +	u16 hw_rd_ch_cnt;
> >  	u32 wr_alloc = 0;
> >  	u32 rd_alloc = 0;
> >  	int i, err;
> > @@ -1146,6 +1151,16 @@ int dw_edma_probe(struct dw_edma_chip *chip)
> >  	if (!dev || !chip->ops)
> >  		return -EINVAL;
> >
> > +	if (chip->flags & DW_EDMA_CHIP_PARTIAL) {
> > +		switch (chip->mf) {
> > +		case EDMA_MF_EDMA_UNROLL:
> > +		case EDMA_MF_HDMA_COMPAT:
> > +			break;
> > +		default:
> > +			return -EOPNOTSUPP;
> > +		}
> > +	}
> > +
> >  	dw = devm_kzalloc(dev, sizeof(*dw), GFP_KERNEL);
> >  	if (!dw)
> >  		return -ENOMEM;
> > @@ -1159,13 +1174,23 @@ int dw_edma_probe(struct dw_edma_chip *chip)
> >
> >  	raw_spin_lock_init(&dw->lock);
> >
> > -	dw->wr_ch_cnt = min_t(u16, chip->ll_wr_cnt,
> > -			      dw_edma_core_ch_count(dw, EDMA_DIR_WRITE));
> > -	dw->wr_ch_cnt = min_t(u16, dw->wr_ch_cnt, EDMA_MAX_WR_CH);
> > +	hw_wr_ch_cnt = min_t(u16, dw_edma_core_ch_count(dw, EDMA_DIR_WRITE),
> > +			     EDMA_MAX_WR_CH);
> > +	hw_rd_ch_cnt = min_t(u16, dw_edma_core_ch_count(dw, EDMA_DIR_READ),
> > +			     EDMA_MAX_RD_CH);
> > +
> > +	if (chip->flags & DW_EDMA_CHIP_PARTIAL) {
> > +		/*
> > +		 * Direction-wide registers are shared by all channels in that
> > +		 * direction, so a direction must have a single owner.
> > +		 */
> > +		if ((chip->ll_wr_cnt && chip->ll_wr_cnt != hw_wr_ch_cnt) ||
> > +		    (chip->ll_rd_cnt && chip->ll_rd_cnt != hw_rd_ch_cnt))
> > +			return -EOPNOTSUPP;
> > +	}
> >
> > -	dw->rd_ch_cnt = min_t(u16, chip->ll_rd_cnt,
> > -			      dw_edma_core_ch_count(dw, EDMA_DIR_READ));
> > -	dw->rd_ch_cnt = min_t(u16, dw->rd_ch_cnt, EDMA_MAX_RD_CH);
> > +	dw->wr_ch_cnt = min_t(u16, chip->ll_wr_cnt, hw_wr_ch_cnt);
> > +	dw->rd_ch_cnt = min_t(u16, chip->ll_rd_cnt, hw_rd_ch_cnt);
> >
> >  	if (!dw->wr_ch_cnt && !dw->rd_ch_cnt)
> >  		return -EINVAL;
> > @@ -1182,8 +1207,10 @@ int dw_edma_probe(struct dw_edma_chip *chip)
> >  	snprintf(dw->name, sizeof(dw->name), "dw-edma-core:%s",
> >  		 dev_name(chip->dev));
> >
> > -	/* Disable eDMA, only to establish the ideal initial conditions */
> > -	dw_edma_core_off(dw);
> > +	if (!(chip->flags & DW_EDMA_CHIP_PARTIAL)) {
> > +		/* Disable eDMA only when this instance owns the controller. */
> > +		dw_edma_core_off(dw);
> > +	}
> >
> >  	/* Request IRQs */
> >  	err = dw_edma_irq_request(dw, &wr_alloc, &rd_alloc);
> > @@ -1227,8 +1254,8 @@ int dw_edma_remove(struct dw_edma_chip *chip)
> >  	if (!dw)
> >  		return -ENODEV;
> >
> > -	/* Disable eDMA */
> > -	dw_edma_core_off(dw);
> > +	if (!(chip->flags & DW_EDMA_CHIP_PARTIAL))
> > +		dw_edma_core_off(dw);
> 
> Can we simplely prevent dma driver remove? If attached to pci host,
> remove edma driver always be risk because RC may write data at any time.
> 
> And it doesn't make sense to remove EP and EDMA driver after linkup.

Do you mean preventing driver unbind/remove itself regardless of chip->flags,
rather than only avoiding dw_edma_core_off()?

That might be a better direction, but it sounds a broader policy change and I'm
not sure it would not affect existing use cases.

Best regards,
Koichiro

> 
> Frank
> 
> >
> >  	/* Free irqs */
> >  	for (i = (dw->nr_irqs - 1); i >= 0; i--)
> > diff --git a/include/linux/dma/edma.h b/include/linux/dma/edma.h
> > index 2bf2298711e1..84f0e728d300 100644
> > --- a/include/linux/dma/edma.h
> > +++ b/include/linux/dma/edma.h
> > @@ -55,9 +55,15 @@ enum dw_edma_map_format {
> >  /**
> >   * enum dw_edma_chip_flags - Flags specific to an eDMA chip
> >   * @DW_EDMA_CHIP_LOCAL:		eDMA is used locally by an endpoint
> > + * @DW_EDMA_CHIP_PARTIAL:	Only channels described by this instance are
> > + *				owned by this driver. Controller-wide state
> > + *				must be preserved, and layouts with shared
> > + *				direction-wide registers must only be shared at
> > + *				direction granularity.
> >   */
> >  enum dw_edma_chip_flags {
> >  	DW_EDMA_CHIP_LOCAL	= BIT(0),
> > +	DW_EDMA_CHIP_PARTIAL	= BIT(1),
> >  };
> >
> >  /**
> > --
> > 2.51.0
> >

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

* Re: [PATCH v2 06/12] dmaengine: dw-edma-pcie: Rename vsec_data to dma_data
  2026-06-04 20:35   ` Frank Li
@ 2026-06-05  2:42     ` Koichiro Den
  0 siblings, 0 replies; 24+ messages in thread
From: Koichiro Den @ 2026-06-05  2:42 UTC (permalink / raw)
  To: Frank Li
  Cc: Vinod Koul, Frank Li, Manivannan Sadhasivam, Marek Vasut,
	Yoshihiro Shimoda, dmaengine, linux-kernel

On Thu, Jun 04, 2026 at 04:35:47PM -0400, Frank Li wrote:
> On Mon, May 25, 2026 at 03:24:14PM +0900, Koichiro Den wrote:
> > dw_edma_pcie_probe() now obtains DMA layout data through device-specific
> > capability callbacks, not only from PCIe Vendor-Specific Extended
> > Capabilities. Rename the local data copy from vsec_data to dma_data
> > before adding endpoint DMA BAR metadata discovery, which does not rely
> > on VSEC.
> >
> > No functional change intended.
> >
> > Signed-off-by: Koichiro Den <den@valinux.co.jp>
> > ---
> > Changes in v2:
> >   - Fix the commit title as Frank pointed out.
> >
> >  drivers/dma/dw-edma/dw-edma-pcie.c | 76 +++++++++++++++---------------
> >  1 file changed, 37 insertions(+), 39 deletions(-)
> >
> > diff --git a/drivers/dma/dw-edma/dw-edma-pcie.c b/drivers/dma/dw-edma/dw-edma-pcie.c
> > index 5a6f5af358d0..c7362f1bf80c 100644
> > --- a/drivers/dma/dw-edma/dw-edma-pcie.c
> > +++ b/drivers/dma/dw-edma/dw-edma-pcie.c
> > @@ -369,11 +369,6 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> >  	int err, nr_irqs;
> >  	int i, mask;
> >
> > -	struct dw_edma_pcie_data *vsec_data __free(kfree) =
> > -		kmalloc_obj(*vsec_data);
> > -	if (!vsec_data)
> > -		return -ENOMEM;
> > -
> >  	/* Enable PCI device */
> >  	err = pcim_enable_device(pdev);
> >  	if (err) {
> > @@ -381,25 +376,28 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> >  		return err;
> >  	}
> >
> > -	memcpy(vsec_data, pdata, sizeof(struct dw_edma_pcie_data));
> > +	struct dw_edma_pcie_data *dma_data __free(kfree) =
> > +		kmemdup(pdata, sizeof(*dma_data), GFP_KERNEL);
> > +	if (!dma_data)
> > +		return -ENOMEM;
> >
> 
> This is straigh forward patch, you move this block after pcim_enable_device();
> I suggest keep original place for easily review.
> 
> Reviewed-by: Frank Li <Frank.Li@nxp.com>

Agreed. (I placed it there to keep the copy close to the old memcpy point.)
I will move it back.

Thanks for the review,
Koichiro

> 
> 
> >  	/* Let device-specific discovery override the static template data. */
> >  	if (!match->parse_caps)
> >  		return -EINVAL;
> >
> > -	err = match->parse_caps(pdev, vsec_data);
> > +	err = match->parse_caps(pdev, dma_data);
> >  	if (err)
> >  		return err;
> >
> >  	/* Mapping PCI BAR regions */
> > -	mask = BIT(vsec_data->rg.bar);
> > -	for (i = 0; i < vsec_data->wr_ch_cnt; i++) {
> > -		mask |= BIT(vsec_data->ll_wr[i].bar);
> > -		mask |= BIT(vsec_data->dt_wr[i].bar);
> > +	mask = BIT(dma_data->rg.bar);
> > +	for (i = 0; i < dma_data->wr_ch_cnt; i++) {
> > +		mask |= BIT(dma_data->ll_wr[i].bar);
> > +		mask |= BIT(dma_data->dt_wr[i].bar);
> >  	}
> > -	for (i = 0; i < vsec_data->rd_ch_cnt; i++) {
> > -		mask |= BIT(vsec_data->ll_rd[i].bar);
> > -		mask |= BIT(vsec_data->dt_rd[i].bar);
> > +	for (i = 0; i < dma_data->rd_ch_cnt; i++) {
> > +		mask |= BIT(dma_data->ll_rd[i].bar);
> > +		mask |= BIT(dma_data->dt_rd[i].bar);
> >  	}
> >  	err = pcim_iomap_regions(pdev, mask, pci_name(pdev));
> >  	if (err) {
> > @@ -422,7 +420,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> >  		return -ENOMEM;
> >
> >  	/* IRQs allocation */
> > -	nr_irqs = pci_alloc_irq_vectors(pdev, 1, vsec_data->irqs,
> > +	nr_irqs = pci_alloc_irq_vectors(pdev, 1, dma_data->irqs,
> >  					PCI_IRQ_MSI | PCI_IRQ_MSIX);
> >  	if (nr_irqs < 1) {
> >  		pci_err(pdev, "fail to alloc IRQ vector (number of IRQs=%u)\n",
> > @@ -433,23 +431,23 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> >  	/* Data structure initialization */
> >  	chip->dev = dev;
> >
> > -	chip->mf = vsec_data->mf;
> > +	chip->mf = dma_data->mf;
> >  	chip->nr_irqs = nr_irqs;
> >  	chip->ops = &dw_edma_pcie_plat_ops;
> > -	chip->cfg_non_ll = vsec_data->cfg_non_ll;
> > +	chip->cfg_non_ll = dma_data->cfg_non_ll;
> >
> > -	chip->ll_wr_cnt = vsec_data->wr_ch_cnt;
> > -	chip->ll_rd_cnt = vsec_data->rd_ch_cnt;
> > +	chip->ll_wr_cnt = dma_data->wr_ch_cnt;
> > +	chip->ll_rd_cnt = dma_data->rd_ch_cnt;
> >
> > -	chip->reg_base = pcim_iomap_table(pdev)[vsec_data->rg.bar];
> > +	chip->reg_base = pcim_iomap_table(pdev)[dma_data->rg.bar];
> >  	if (!chip->reg_base)
> >  		return -ENOMEM;
> >
> > -	for (i = 0; i < chip->ll_wr_cnt && !vsec_data->cfg_non_ll; i++) {
> > +	for (i = 0; i < chip->ll_wr_cnt && !dma_data->cfg_non_ll; i++) {
> >  		struct dw_edma_region *ll_region = &chip->ll_region_wr[i];
> >  		struct dw_edma_region *dt_region = &chip->dt_region_wr[i];
> > -		struct dw_edma_block *ll_block = &vsec_data->ll_wr[i];
> > -		struct dw_edma_block *dt_block = &vsec_data->dt_wr[i];
> > +		struct dw_edma_block *ll_block = &dma_data->ll_wr[i];
> > +		struct dw_edma_block *dt_block = &dma_data->dt_wr[i];
> >
> >  		ll_region->vaddr.io = pcim_iomap_table(pdev)[ll_block->bar];
> >  		if (!ll_region->vaddr.io)
> > @@ -457,7 +455,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> >
> >  		ll_region->vaddr.io += ll_block->off;
> >  		ll_region->paddr = dw_edma_get_phys_addr(pdev, match,
> > -							 vsec_data, ll_block->bar);
> > +							 dma_data, ll_block->bar);
> >  		ll_region->paddr += ll_block->off;
> >  		ll_region->sz = ll_block->sz;
> >
> > @@ -467,16 +465,16 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> >
> >  		dt_region->vaddr.io += dt_block->off;
> >  		dt_region->paddr = dw_edma_get_phys_addr(pdev, match,
> > -							 vsec_data, dt_block->bar);
> > +							 dma_data, dt_block->bar);
> >  		dt_region->paddr += dt_block->off;
> >  		dt_region->sz = dt_block->sz;
> >  	}
> >
> > -	for (i = 0; i < chip->ll_rd_cnt && !vsec_data->cfg_non_ll; i++) {
> > +	for (i = 0; i < chip->ll_rd_cnt && !dma_data->cfg_non_ll; i++) {
> >  		struct dw_edma_region *ll_region = &chip->ll_region_rd[i];
> >  		struct dw_edma_region *dt_region = &chip->dt_region_rd[i];
> > -		struct dw_edma_block *ll_block = &vsec_data->ll_rd[i];
> > -		struct dw_edma_block *dt_block = &vsec_data->dt_rd[i];
> > +		struct dw_edma_block *ll_block = &dma_data->ll_rd[i];
> > +		struct dw_edma_block *dt_block = &dma_data->dt_rd[i];
> >
> >  		ll_region->vaddr.io = pcim_iomap_table(pdev)[ll_block->bar];
> >  		if (!ll_region->vaddr.io)
> > @@ -484,7 +482,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> >
> >  		ll_region->vaddr.io += ll_block->off;
> >  		ll_region->paddr = dw_edma_get_phys_addr(pdev, match,
> > -							 vsec_data, ll_block->bar);
> > +							 dma_data, ll_block->bar);
> >  		ll_region->paddr += ll_block->off;
> >  		ll_region->sz = ll_block->sz;
> >
> > @@ -494,7 +492,7 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> >
> >  		dt_region->vaddr.io += dt_block->off;
> >  		dt_region->paddr = dw_edma_get_phys_addr(pdev, match,
> > -							 vsec_data, dt_block->bar);
> > +							 dma_data, dt_block->bar);
> >  		dt_region->paddr += dt_block->off;
> >  		dt_region->sz = dt_block->sz;
> >  	}
> > @@ -512,31 +510,31 @@ static int dw_edma_pcie_probe(struct pci_dev *pdev,
> >  		pci_dbg(pdev, "Version:\tUnknown (0x%x)\n", chip->mf);
> >
> >  	pci_dbg(pdev, "Registers:\tBAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p)\n",
> > -		vsec_data->rg.bar, vsec_data->rg.off, vsec_data->rg.sz,
> > +		dma_data->rg.bar, dma_data->rg.off, dma_data->rg.sz,
> >  		chip->reg_base);
> >
> >
> >  	for (i = 0; i < chip->ll_wr_cnt; i++) {
> >  		pci_dbg(pdev, "L. List:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
> > -			i, vsec_data->ll_wr[i].bar,
> > -			vsec_data->ll_wr[i].off, chip->ll_region_wr[i].sz,
> > +			i, dma_data->ll_wr[i].bar,
> > +			dma_data->ll_wr[i].off, chip->ll_region_wr[i].sz,
> >  			chip->ll_region_wr[i].vaddr.io, &chip->ll_region_wr[i].paddr);
> >
> >  		pci_dbg(pdev, "Data:\tWRITE CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
> > -			i, vsec_data->dt_wr[i].bar,
> > -			vsec_data->dt_wr[i].off, chip->dt_region_wr[i].sz,
> > +			i, dma_data->dt_wr[i].bar,
> > +			dma_data->dt_wr[i].off, chip->dt_region_wr[i].sz,
> >  			chip->dt_region_wr[i].vaddr.io, &chip->dt_region_wr[i].paddr);
> >  	}
> >
> >  	for (i = 0; i < chip->ll_rd_cnt; i++) {
> >  		pci_dbg(pdev, "L. List:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
> > -			i, vsec_data->ll_rd[i].bar,
> > -			vsec_data->ll_rd[i].off, chip->ll_region_rd[i].sz,
> > +			i, dma_data->ll_rd[i].bar,
> > +			dma_data->ll_rd[i].off, chip->ll_region_rd[i].sz,
> >  			chip->ll_region_rd[i].vaddr.io, &chip->ll_region_rd[i].paddr);
> >
> >  		pci_dbg(pdev, "Data:\tREAD CH%.2u, BAR=%u, off=0x%.8lx, sz=0x%zx bytes, addr(v=%p, p=%pa)\n",
> > -			i, vsec_data->dt_rd[i].bar,
> > -			vsec_data->dt_rd[i].off, chip->dt_region_rd[i].sz,
> > +			i, dma_data->dt_rd[i].bar,
> > +			dma_data->dt_rd[i].off, chip->dt_region_rd[i].sz,
> >  			chip->dt_region_rd[i].vaddr.io, &chip->dt_region_rd[i].paddr);
> >  	}
> >
> > --
> > 2.51.0
> >

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

end of thread, other threads:[~2026-06-05  2:42 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-05-25  6:24 [PATCH v2 00/12] dmaengine: dw-edma: Prepare for PCI EP DMA (part 1/3) Koichiro Den
2026-05-25  6:24 ` [PATCH v2 01/12] dmaengine: dw-edma: Add hardware channel filter Koichiro Den
2026-06-04 20:40   ` Frank Li
2026-06-05  2:26     ` Koichiro Den
2026-05-25  6:24 ` [PATCH v2 02/12] dmaengine: dw-edma: Add per-channel interrupt routing control Koichiro Den
2026-06-04 20:18   ` Frank Li
2026-06-05  2:36     ` Koichiro Den
2026-05-25  6:24 ` [PATCH v2 03/12] dmaengine: dw-edma: Add partial channel ownership mode Koichiro Den
2026-06-04 20:24   ` Frank Li
2026-06-05  2:40     ` Koichiro Den
2026-05-25  6:24 ` [PATCH v2 04/12] dmaengine: dw-edma-pcie: Track non-LL mode in DMA data Koichiro Den
2026-06-04 20:26   ` Frank Li
2026-05-25  6:24 ` [PATCH v2 05/12] dmaengine: dw-edma-pcie: Add capability match data Koichiro Den
2026-06-04 20:28   ` Frank Li
2026-05-25  6:24 ` [PATCH v2 06/12] dmaengine: dw-edma-pcie: Rename vsec_data to dma_data Koichiro Den
2026-06-04 20:35   ` Frank Li
2026-06-05  2:42     ` Koichiro Den
2026-05-25  6:24 ` [PATCH v2 07/12] dmaengine: dw-edma-pcie: Add default IRQ mode to match data Koichiro Den
2026-05-25  6:24 ` [PATCH v2 08/12] dmaengine: dw-edma-pcie: Add platform ops " Koichiro Den
2026-06-04 20:37   ` Frank Li
2026-05-25  6:24 ` [PATCH v2 09/12] dmaengine: dw-edma-pcie: Add register offset match flag Koichiro Den
2026-05-25  6:24 ` [PATCH v2 10/12] dmaengine: dw-edma-pcie: Factor out descriptor block address lookup Koichiro Den
2026-05-25  6:24 ` [PATCH v2 11/12] dmaengine: dw-edma-pcie: Handle optional data blocks Koichiro Den
2026-05-25  6:24 ` [PATCH v2 12/12] dmaengine: dw-edma-pcie: Add chip flags to match data Koichiro Den

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

all inboxes | Powered by JetHome®