* [PATCH v4 1/4] PCI: dwc: Fix msg_atu_index assignment
2026-01-23 18:28 [PATCH v4 0/4] PCI: dwc: Clean up iATU index mess Niklas Cassel
@ 2026-01-23 18:28 ` Niklas Cassel
2026-01-23 18:46 ` Damien Le Moal
2026-01-23 18:28 ` [PATCH v4 2/4] PCI: dwc: Improve msg_atu_index error handling Niklas Cassel
` (2 subsequent siblings)
3 siblings, 1 reply; 10+ messages in thread
From: Niklas Cassel @ 2026-01-23 18:28 UTC (permalink / raw)
To: Jingoo Han, Manivannan Sadhasivam, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas, Frank Li
Cc: Randolph Lin, Samuel Holland, Charles Mirabile, tim609,
Krishna Chaitanya Chundru, dlemoal, Maciej W. Rozycki,
Niklas Cassel, stable, Shawn Lin, Hans Zhang, linux-pci
When dw_pcie_iatu_setup() configures outbound address translation
for both type PCIE_ATU_TYPE_MEM and PCIE_ATU_TYPE_IO, the iATU index
to use is incremented before calling dw_pcie_prog_outbound_atu().
However, for msg_atu_index the index is not incremented before use,
causing the iATU index to be the same as the last configured iATU
index, which means that it will incorrectly use the same iATU index
that is already in use, breaking outbound address translation.
Fixes: e1a4ec1a9520 ("PCI: dwc: Add generic MSG TLP support for sending PME_Turn_Off when system suspend")
Cc: stable@vger.kernel.org
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>
Reviewed-by: Hans Zhang <zhanghuabing@ecosda.com>
Signed-off-by: Niklas Cassel <cassel@kernel.org>
---
drivers/pci/controller/dwc/pcie-designware-host.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index b3d6a474fd16..ae5f2d8a3857 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -982,7 +982,7 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp)
dev_warn(pci->dev, "Ranges exceed outbound iATU size (%d)\n",
pci->num_ob_windows);
- pp->msg_atu_index = i;
+ pp->msg_atu_index = ++i;
i = 0;
resource_list_for_each_entry(entry, &pp->bridge->dma_ranges) {
--
2.52.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH v4 1/4] PCI: dwc: Fix msg_atu_index assignment
2026-01-23 18:28 ` [PATCH v4 1/4] PCI: dwc: Fix msg_atu_index assignment Niklas Cassel
@ 2026-01-23 18:46 ` Damien Le Moal
0 siblings, 0 replies; 10+ messages in thread
From: Damien Le Moal @ 2026-01-23 18:46 UTC (permalink / raw)
To: Niklas Cassel, Jingoo Han, Manivannan Sadhasivam,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Frank Li
Cc: Randolph Lin, Samuel Holland, Charles Mirabile, tim609,
Krishna Chaitanya Chundru, Maciej W. Rozycki, stable, Shawn Lin,
Hans Zhang, linux-pci
On 2026/01/24 5:28, Niklas Cassel wrote:
> When dw_pcie_iatu_setup() configures outbound address translation
> for both type PCIE_ATU_TYPE_MEM and PCIE_ATU_TYPE_IO, the iATU index
> to use is incremented before calling dw_pcie_prog_outbound_atu().
>
> However, for msg_atu_index the index is not incremented before use,
> causing the iATU index to be the same as the last configured iATU
> index, which means that it will incorrectly use the same iATU index
> that is already in use, breaking outbound address translation.
>
> Fixes: e1a4ec1a9520 ("PCI: dwc: Add generic MSG TLP support for sending PME_Turn_Off when system suspend")
> Cc: stable@vger.kernel.org
> Reviewed-by: Frank Li <Frank.Li@nxp.com>
> Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>
> Reviewed-by: Hans Zhang <zhanghuabing@ecosda.com>
> Signed-off-by: Niklas Cassel <cassel@kernel.org>
> ---
> drivers/pci/controller/dwc/pcie-designware-host.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> index b3d6a474fd16..ae5f2d8a3857 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> @@ -982,7 +982,7 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp)
> dev_warn(pci->dev, "Ranges exceed outbound iATU size (%d)\n",
> pci->num_ob_windows);
>
> - pp->msg_atu_index = i;
> + pp->msg_atu_index = ++i;
pp->msg_atu_index = i + 1;
is a lot more readable in my opinion. Changing i itself is useless since it is
reset to 0 below.
>
> i = 0;
> resource_list_for_each_entry(entry, &pp->bridge->dma_ranges) {
--
Damien Le Moal
Western Digital Research
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 2/4] PCI: dwc: Improve msg_atu_index error handling
2026-01-23 18:28 [PATCH v4 0/4] PCI: dwc: Clean up iATU index mess Niklas Cassel
2026-01-23 18:28 ` [PATCH v4 1/4] PCI: dwc: Fix msg_atu_index assignment Niklas Cassel
@ 2026-01-23 18:28 ` Niklas Cassel
2026-01-23 18:50 ` Damien Le Moal
2026-01-23 18:28 ` [PATCH v4 3/4] PCI: dwc: Clean up iATU index usage in dw_pcie_iatu_setup() Niklas Cassel
2026-01-23 18:28 ` [PATCH v4 4/4] PCI: dwc: Fix missing iATU setup when ECAM is enabled Niklas Cassel
3 siblings, 1 reply; 10+ messages in thread
From: Niklas Cassel @ 2026-01-23 18:28 UTC (permalink / raw)
To: Jingoo Han, Manivannan Sadhasivam, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas, Frank Li
Cc: Randolph Lin, Samuel Holland, Charles Mirabile, tim609,
Krishna Chaitanya Chundru, dlemoal, Maciej W. Rozycki,
Niklas Cassel, Shawn Lin, linux-pci
Only try to dedicate an outbound iATU to MSG TLP if use_atu_msg is set.
If use_atu_msg is not set, it is completely useless to bump the index.
Additionally, if use_atu_msg is set, and there is no outbound iATU
available, return an error.
Fixes: e1a4ec1a9520 ("PCI: dwc: Add generic MSG TLP support for sending PME_Turn_Off when system suspend")
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>
Signed-off-by: Niklas Cassel <cassel@kernel.org>
---
drivers/pci/controller/dwc/pcie-designware-host.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index ae5f2d8a3857..d7f57d77bdf5 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -982,7 +982,14 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp)
dev_warn(pci->dev, "Ranges exceed outbound iATU size (%d)\n",
pci->num_ob_windows);
- pp->msg_atu_index = ++i;
+ if (pp->use_atu_msg) {
+ if (pci->num_ob_windows > ++i) {
+ pp->msg_atu_index = i;
+ } else {
+ dev_err(pci->dev, "Cannot add outbound window for MSG TLP\n");
+ return -ENOMEM;
+ }
+ }
i = 0;
resource_list_for_each_entry(entry, &pp->bridge->dma_ranges) {
--
2.52.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH v4 2/4] PCI: dwc: Improve msg_atu_index error handling
2026-01-23 18:28 ` [PATCH v4 2/4] PCI: dwc: Improve msg_atu_index error handling Niklas Cassel
@ 2026-01-23 18:50 ` Damien Le Moal
2026-01-27 15:03 ` Niklas Cassel
0 siblings, 1 reply; 10+ messages in thread
From: Damien Le Moal @ 2026-01-23 18:50 UTC (permalink / raw)
To: Niklas Cassel, Jingoo Han, Manivannan Sadhasivam,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Frank Li
Cc: Randolph Lin, Samuel Holland, Charles Mirabile, tim609,
Krishna Chaitanya Chundru, Maciej W. Rozycki, Shawn Lin,
linux-pci
On 2026/01/24 5:28, Niklas Cassel wrote:
> Only try to dedicate an outbound iATU to MSG TLP if use_atu_msg is set.
> If use_atu_msg is not set, it is completely useless to bump the index.
>
> Additionally, if use_atu_msg is set, and there is no outbound iATU
> available, return an error.
>
> Fixes: e1a4ec1a9520 ("PCI: dwc: Add generic MSG TLP support for sending PME_Turn_Off when system suspend")
> Reviewed-by: Frank Li <Frank.Li@nxp.com>
> Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>
> Signed-off-by: Niklas Cassel <cassel@kernel.org>
> ---
> drivers/pci/controller/dwc/pcie-designware-host.c | 9 ++++++++-
> 1 file changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> index ae5f2d8a3857..d7f57d77bdf5 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> @@ -982,7 +982,14 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp)
> dev_warn(pci->dev, "Ranges exceed outbound iATU size (%d)\n",
> pci->num_ob_windows);
>
> - pp->msg_atu_index = ++i;
> + if (pp->use_atu_msg) {
> + if (pci->num_ob_windows > ++i) {
if (pp->use_atu_msg) {
i++;
if (pci->num_ob_windows > i) {
is far more readable in my opinion.
> + pp->msg_atu_index = i;
> + } else {
> + dev_err(pci->dev, "Cannot add outbound window for MSG TLP\n");
> + return -ENOMEM;
> + }
> + }
Seeing this, I do not really see the point of the previous patch since you
completely nuke that change here. So maybe drop patch 1 ?
>
> i = 0;
> resource_list_for_each_entry(entry, &pp->bridge->dma_ranges) {
--
Damien Le Moal
Western Digital Research
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v4 2/4] PCI: dwc: Improve msg_atu_index error handling
2026-01-23 18:50 ` Damien Le Moal
@ 2026-01-27 15:03 ` Niklas Cassel
0 siblings, 0 replies; 10+ messages in thread
From: Niklas Cassel @ 2026-01-27 15:03 UTC (permalink / raw)
To: Damien Le Moal
Cc: Jingoo Han, Manivannan Sadhasivam, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas, Frank Li,
Randolph Lin, Samuel Holland, Charles Mirabile, tim609,
Krishna Chaitanya Chundru, Maciej W. Rozycki, Shawn Lin,
linux-pci
On Sat, Jan 24, 2026 at 05:50:06AM +1100, Damien Le Moal wrote:
> On 2026/01/24 5:28, Niklas Cassel wrote:
> > Only try to dedicate an outbound iATU to MSG TLP if use_atu_msg is set.
> > If use_atu_msg is not set, it is completely useless to bump the index.
> >
> > Additionally, if use_atu_msg is set, and there is no outbound iATU
> > available, return an error.
> >
> > Fixes: e1a4ec1a9520 ("PCI: dwc: Add generic MSG TLP support for sending PME_Turn_Off when system suspend")
> > Reviewed-by: Frank Li <Frank.Li@nxp.com>
> > Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>
> > Signed-off-by: Niklas Cassel <cassel@kernel.org>
> > ---
> > drivers/pci/controller/dwc/pcie-designware-host.c | 9 ++++++++-
> > 1 file changed, 8 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> > index ae5f2d8a3857..d7f57d77bdf5 100644
> > --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> > +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> > @@ -982,7 +982,14 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp)
> > dev_warn(pci->dev, "Ranges exceed outbound iATU size (%d)\n",
> > pci->num_ob_windows);
> >
> > - pp->msg_atu_index = ++i;
> > + if (pp->use_atu_msg) {
> > + if (pci->num_ob_windows > ++i) {
>
> if (pp->use_atu_msg) {
> i++;
> if (pci->num_ob_windows > i) {
>
> is far more readable in my opinion.
Yes, I agree that it is more readable.
However, in patch 3/4 in series, I'm do a cleanup of this whole function,
not just this statement.
This patch changes the code in a way that is consistent with the existing
coding style of this function, see e.g.:
https://github.com/torvalds/linux/blob/v6.19-rc7/drivers/pci/controller/dwc/pcie-designware-host.c#L932-L934
Then patch 3/4 modifies the whole function to be more readable.
So I prefer to still keep this patch as is, such the code is always in a
"consistent coding style".
And then do all cleanups in the cleanup patch.
>
> > + pp->msg_atu_index = i;
> > + } else {
> > + dev_err(pci->dev, "Cannot add outbound window for MSG TLP\n");
> > + return -ENOMEM;
> > + }
> > + }
>
> Seeing this, I do not really see the point of the previous patch since you
> completely nuke that change here. So maybe drop patch 1 ?
My thinking was that the previous patch has
CC: stable, so I wanted the smallest viable backportable fix.
But, I guess that the "if (pp->use_atu_msg) {" guard makes sense even for a
backported fix, as it is pointless to increment the counter if use_atu_msg
is not set, so sure, I can squash patch 1 and 2.
Kind regards,
Niklas
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v4 3/4] PCI: dwc: Clean up iATU index usage in dw_pcie_iatu_setup()
2026-01-23 18:28 [PATCH v4 0/4] PCI: dwc: Clean up iATU index mess Niklas Cassel
2026-01-23 18:28 ` [PATCH v4 1/4] PCI: dwc: Fix msg_atu_index assignment Niklas Cassel
2026-01-23 18:28 ` [PATCH v4 2/4] PCI: dwc: Improve msg_atu_index error handling Niklas Cassel
@ 2026-01-23 18:28 ` Niklas Cassel
2026-01-23 18:28 ` [PATCH v4 4/4] PCI: dwc: Fix missing iATU setup when ECAM is enabled Niklas Cassel
3 siblings, 0 replies; 10+ messages in thread
From: Niklas Cassel @ 2026-01-23 18:28 UTC (permalink / raw)
To: Jingoo Han, Manivannan Sadhasivam, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas
Cc: Randolph Lin, Samuel Holland, Frank Li, Charles Mirabile, tim609,
Krishna Chaitanya Chundru, dlemoal, Maciej W. Rozycki,
Niklas Cassel, linux-pci
The current iATU index usage in dw_pcie_iatu_setup() is a mess.
For outbound address translation the index is incremented before usage.
For inbound address translation the index is incremented after usage.
Incrementing the index after usage make much more sense, and make the
index usage consistent for both outbound and inbound address translation.
Most likely, the overly complicated logic for the outbound address
translation is because the iATU at index 0 is reserved for CFG IOs
(dw_pcie_other_conf_map_bus()), however, we should be able to use the
exact same logic for the indexing of the outbound and inbound iATUs.
(Only the starting index should be different.)
Create two new variables ob_iatu_index and ib_iatu_index, which makes
it more clear from the name itself that it is a zeroes based index,
and only increment the index if the iATU configuration call succeeded.
Since we always check if there is an index available immediately before
programming the iATU, we can remove the useless "ranges exceed outbound
iATU size" warnings, as the code is already unreachable. For the same
reason, we can also remove the useless breaks outside of the while loops.
No functional changes intended.
Signed-off-by: Niklas Cassel <cassel@kernel.org>
---
.../pci/controller/dwc/pcie-designware-host.c | 59 ++++++++++---------
1 file changed, 31 insertions(+), 28 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index d7f57d77bdf5..87e6a32dbb9a 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -892,9 +892,10 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp)
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
struct dw_pcie_ob_atu_cfg atu = { 0 };
struct resource_entry *entry;
+ int ob_iatu_index;
+ int ib_iatu_index;
int i, ret;
- /* Note the very first outbound ATU is used for CFG IOs */
if (!pci->num_ob_windows) {
dev_err(pci->dev, "No outbound iATU found\n");
return -EINVAL;
@@ -910,16 +911,18 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp)
for (i = 0; i < pci->num_ib_windows; i++)
dw_pcie_disable_atu(pci, PCIE_ATU_REGION_DIR_IB, i);
- i = 0;
+ /*
+ * NOTE: For outbound address translation, outbound iATU at index 0 is
+ * reserved for CFG IOs (dw_pcie_other_conf_map_bus()), thus start at
+ * index 1.
+ */
+ ob_iatu_index = 1;
resource_list_for_each_entry(entry, &pp->bridge->windows) {
resource_size_t res_size;
if (resource_type(entry->res) != IORESOURCE_MEM)
continue;
- if (pci->num_ob_windows <= i + 1)
- break;
-
atu.type = PCIE_ATU_TYPE_MEM;
atu.parent_bus_addr = entry->res->start - pci->parent_bus_offset;
atu.pci_addr = entry->res->start - entry->offset;
@@ -937,13 +940,13 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp)
* middle. Otherwise, we would end up only partially
* mapping a single resource.
*/
- if (pci->num_ob_windows <= ++i) {
- dev_err(pci->dev, "Exhausted outbound windows for region: %pr\n",
+ if (ob_iatu_index >= pci->num_ob_windows) {
+ dev_err(pci->dev, "Cannot add outbound window for region: %pr\n",
entry->res);
return -ENOMEM;
}
- atu.index = i;
+ atu.index = ob_iatu_index;
atu.size = MIN(pci->region_limit + 1, res_size);
ret = dw_pcie_prog_outbound_atu(pci, &atu);
@@ -953,6 +956,7 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp)
return ret;
}
+ ob_iatu_index++;
atu.parent_bus_addr += atu.size;
atu.pci_addr += atu.size;
res_size -= atu.size;
@@ -960,8 +964,8 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp)
}
if (pp->io_size) {
- if (pci->num_ob_windows > ++i) {
- atu.index = i;
+ if (ob_iatu_index < pci->num_ob_windows) {
+ atu.index = ob_iatu_index;
atu.type = PCIE_ATU_TYPE_IO;
atu.parent_bus_addr = pp->io_base - pci->parent_bus_offset;
atu.pci_addr = pp->io_bus_addr;
@@ -973,34 +977,35 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp)
entry->res);
return ret;
}
+ ob_iatu_index++;
} else {
+ /*
+ * If there are not enough outbound windows to give I/O
+ * space its own iATU, the outbound iATU at index 0 will
+ * be shared between I/O space and CFG IOs, by
+ * temporarily reconfiguring the iATU to CFG space, in
+ * order to do a CFG IO, and then immediately restoring
+ * it to I/O space.
+ */
pp->cfg0_io_shared = true;
}
}
- if (pci->num_ob_windows <= i)
- dev_warn(pci->dev, "Ranges exceed outbound iATU size (%d)\n",
- pci->num_ob_windows);
-
if (pp->use_atu_msg) {
- if (pci->num_ob_windows > ++i) {
- pp->msg_atu_index = i;
- } else {
+ if (ob_iatu_index >= pci->num_ob_windows) {
dev_err(pci->dev, "Cannot add outbound window for MSG TLP\n");
return -ENOMEM;
}
+ pp->msg_atu_index = ob_iatu_index++;
}
- i = 0;
+ ib_iatu_index = 0;
resource_list_for_each_entry(entry, &pp->bridge->dma_ranges) {
resource_size_t res_start, res_size, window_size;
if (resource_type(entry->res) != IORESOURCE_MEM)
continue;
- if (pci->num_ib_windows <= i)
- break;
-
res_size = resource_size(entry->res);
res_start = entry->res->start;
while (res_size > 0) {
@@ -1009,14 +1014,15 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp)
* middle. Otherwise, we would end up only partially
* mapping a single resource.
*/
- if (pci->num_ib_windows <= i) {
- dev_err(pci->dev, "Exhausted inbound windows for region: %pr\n",
+ if (ib_iatu_index >= pci->num_ib_windows) {
+ dev_err(pci->dev, "Cannot add inbound window for region: %pr\n",
entry->res);
return -ENOMEM;
}
window_size = MIN(pci->region_limit + 1, res_size);
- ret = dw_pcie_prog_inbound_atu(pci, i++, PCIE_ATU_TYPE_MEM, res_start,
+ ret = dw_pcie_prog_inbound_atu(pci, ib_iatu_index,
+ PCIE_ATU_TYPE_MEM, res_start,
res_start - entry->offset, window_size);
if (ret) {
dev_err(pci->dev, "Failed to set DMA range %pr\n",
@@ -1024,15 +1030,12 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp)
return ret;
}
+ ib_iatu_index++;
res_start += window_size;
res_size -= window_size;
}
}
- if (pci->num_ib_windows <= i)
- dev_warn(pci->dev, "Dma-ranges exceed inbound iATU size (%u)\n",
- pci->num_ib_windows);
-
return 0;
}
--
2.52.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v4 4/4] PCI: dwc: Fix missing iATU setup when ECAM is enabled
2026-01-23 18:28 [PATCH v4 0/4] PCI: dwc: Clean up iATU index mess Niklas Cassel
` (2 preceding siblings ...)
2026-01-23 18:28 ` [PATCH v4 3/4] PCI: dwc: Clean up iATU index usage in dw_pcie_iatu_setup() Niklas Cassel
@ 2026-01-23 18:28 ` Niklas Cassel
2026-01-23 18:53 ` Damien Le Moal
3 siblings, 1 reply; 10+ messages in thread
From: Niklas Cassel @ 2026-01-23 18:28 UTC (permalink / raw)
To: Jingoo Han, Manivannan Sadhasivam, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krishna Chaitanya Chundru
Cc: Randolph Lin, Samuel Holland, Frank Li, Charles Mirabile, tim609,
dlemoal, Maciej W. Rozycki, Niklas Cassel, linux-pci
From: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
When ECAM is enabled, the driver skipped calling dw_pcie_iatu_setup()
before configuring ECAM iATU entries. This left IO and MEM outbound
windows unprogrammed, resulting in broken IO transactions. Additionally,
dw_pcie_config_ecam_iatu() was only called during host initialization,
so ECAM-related iATU entries were not restored after suspend/resume,
leading to failures in configuration space access
To resolve these issues, the ECAM iATU configuration is moved into
dw_pcie_iatu_setup(), and dw_pcie_iatu_setup() is invoked when ECAM is
enabled.
Furthermore, error checks are added in dw_pcie_prog_outbound_atu() and
dw_pcie_prog_inbound_atu() such that an error is returned if trying to
program an iATU that is outside the number of iATUs provided by the
controller.
Fixes: f6fd357f7afb ("PCI: dwc: Prepare the driver for enabling ECAM mechanism using iATU 'CFG Shift Feature'")
Reported-by: Maciej W. Rozycki <macro@orcam.me.uk>
Closes: https://lore.kernel.org/all/alpine.DEB.2.21.2511280256260.36486@angie.orcam.me.uk/
Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
Co-developed-by: Niklas Cassel <cassel@kernel.org>
Signed-off-by: Niklas Cassel <cassel@kernel.org>
---
.../pci/controller/dwc/pcie-designware-host.c | 33 ++++++++++++-------
drivers/pci/controller/dwc/pcie-designware.c | 6 ++++
2 files changed, 28 insertions(+), 11 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
index 87e6a32dbb9a..bc2e08ec515e 100644
--- a/drivers/pci/controller/dwc/pcie-designware-host.c
+++ b/drivers/pci/controller/dwc/pcie-designware-host.c
@@ -641,14 +641,6 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
if (ret)
goto err_free_msi;
- if (pp->ecam_enabled) {
- ret = dw_pcie_config_ecam_iatu(pp);
- if (ret) {
- dev_err(dev, "Failed to configure iATU in ECAM mode\n");
- goto err_free_msi;
- }
- }
-
/*
* Allocate the resource for MSG TLP before programming the iATU
* outbound window in dw_pcie_setup_rc(). Since the allocation depends
@@ -915,8 +907,21 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp)
* NOTE: For outbound address translation, outbound iATU at index 0 is
* reserved for CFG IOs (dw_pcie_other_conf_map_bus()), thus start at
* index 1.
+ *
+ * If using ECAM, outbound iATU at index 0 and index 1 is reserved for
+ * CFG IOs.
*/
- ob_iatu_index = 1;
+ if (pp->ecam_enabled) {
+ ob_iatu_index = 2;
+ ret = dw_pcie_config_ecam_iatu(pp);
+ if (ret) {
+ dev_err(pci->dev, "Failed to configure iATU in ECAM mode\n");
+ return ret;
+ }
+ } else {
+ ob_iatu_index = 1;
+ }
+
resource_list_for_each_entry(entry, &pp->bridge->windows) {
resource_size_t res_size;
@@ -985,8 +990,14 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp)
* be shared between I/O space and CFG IOs, by
* temporarily reconfiguring the iATU to CFG space, in
* order to do a CFG IO, and then immediately restoring
- * it to I/O space.
+ * it to I/O space. This is only implemented when using
+ * dw_pcie_other_conf_map_bus(), which is not the case
+ * when using ECAM.
*/
+ if (pp->ecam_enabled) {
+ dev_err(pci->dev, "Cannot add outbound window for I/O\n");
+ return -ENOMEM;
+ }
pp->cfg0_io_shared = true;
}
}
@@ -1157,7 +1168,7 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
* the platform uses its own address translation component rather than
* ATU, so we should not program the ATU here.
*/
- if (pp->bridge->child_ops == &dw_child_pcie_ops) {
+ if (pp->bridge->child_ops == &dw_child_pcie_ops || pp->ecam_enabled) {
ret = dw_pcie_iatu_setup(pp);
if (ret)
return ret;
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index 18331d9e85be..5741c09dde7f 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -532,6 +532,9 @@ int dw_pcie_prog_outbound_atu(struct dw_pcie *pci,
u32 retries, val;
u64 limit_addr;
+ if (atu->index >= pci->num_ob_windows)
+ return -ENOSPC;
+
limit_addr = parent_bus_addr + atu->size - 1;
if ((limit_addr & ~pci->region_limit) != (parent_bus_addr & ~pci->region_limit) ||
@@ -605,6 +608,9 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int type,
u64 limit_addr = pci_addr + size - 1;
u32 retries, val;
+ if (index >= pci->num_ib_windows)
+ return -ENOSPC;
+
if ((limit_addr & ~pci->region_limit) != (pci_addr & ~pci->region_limit) ||
!IS_ALIGNED(parent_bus_addr, pci->region_align) ||
!IS_ALIGNED(pci_addr, pci->region_align) || !size) {
--
2.52.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* Re: [PATCH v4 4/4] PCI: dwc: Fix missing iATU setup when ECAM is enabled
2026-01-23 18:28 ` [PATCH v4 4/4] PCI: dwc: Fix missing iATU setup when ECAM is enabled Niklas Cassel
@ 2026-01-23 18:53 ` Damien Le Moal
2026-01-27 15:02 ` Niklas Cassel
0 siblings, 1 reply; 10+ messages in thread
From: Damien Le Moal @ 2026-01-23 18:53 UTC (permalink / raw)
To: Niklas Cassel, Jingoo Han, Manivannan Sadhasivam,
Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring,
Bjorn Helgaas, Krishna Chaitanya Chundru
Cc: Randolph Lin, Samuel Holland, Frank Li, Charles Mirabile, tim609,
Maciej W. Rozycki, linux-pci
On 2026/01/24 5:28, Niklas Cassel wrote:
> From: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
>
> When ECAM is enabled, the driver skipped calling dw_pcie_iatu_setup()
> before configuring ECAM iATU entries. This left IO and MEM outbound
> windows unprogrammed, resulting in broken IO transactions. Additionally,
> dw_pcie_config_ecam_iatu() was only called during host initialization,
> so ECAM-related iATU entries were not restored after suspend/resume,
> leading to failures in configuration space access
>
> To resolve these issues, the ECAM iATU configuration is moved into
> dw_pcie_iatu_setup(), and dw_pcie_iatu_setup() is invoked when ECAM is
> enabled.
>
> Furthermore, error checks are added in dw_pcie_prog_outbound_atu() and
> dw_pcie_prog_inbound_atu() such that an error is returned if trying to
> program an iATU that is outside the number of iATUs provided by the
> controller.
>
> Fixes: f6fd357f7afb ("PCI: dwc: Prepare the driver for enabling ECAM mechanism using iATU 'CFG Shift Feature'")
> Reported-by: Maciej W. Rozycki <macro@orcam.me.uk>
> Closes: https://lore.kernel.org/all/alpine.DEB.2.21.2511280256260.36486@angie.orcam.me.uk/
> Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
> Co-developed-by: Niklas Cassel <cassel@kernel.org>
> Signed-off-by: Niklas Cassel <cassel@kernel.org>
It looks like this patch depends on patch 3, which does not have a Fixes tag. So
why not squash together patches 3 and 4 ?
> ---
> .../pci/controller/dwc/pcie-designware-host.c | 33 ++++++++++++-------
> drivers/pci/controller/dwc/pcie-designware.c | 6 ++++
> 2 files changed, 28 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c
> index 87e6a32dbb9a..bc2e08ec515e 100644
> --- a/drivers/pci/controller/dwc/pcie-designware-host.c
> +++ b/drivers/pci/controller/dwc/pcie-designware-host.c
> @@ -641,14 +641,6 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp)
> if (ret)
> goto err_free_msi;
>
> - if (pp->ecam_enabled) {
> - ret = dw_pcie_config_ecam_iatu(pp);
> - if (ret) {
> - dev_err(dev, "Failed to configure iATU in ECAM mode\n");
> - goto err_free_msi;
> - }
> - }
> -
> /*
> * Allocate the resource for MSG TLP before programming the iATU
> * outbound window in dw_pcie_setup_rc(). Since the allocation depends
> @@ -915,8 +907,21 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp)
> * NOTE: For outbound address translation, outbound iATU at index 0 is
> * reserved for CFG IOs (dw_pcie_other_conf_map_bus()), thus start at
> * index 1.
> + *
> + * If using ECAM, outbound iATU at index 0 and index 1 is reserved for
> + * CFG IOs.
> */
> - ob_iatu_index = 1;
> + if (pp->ecam_enabled) {
> + ob_iatu_index = 2;
> + ret = dw_pcie_config_ecam_iatu(pp);
> + if (ret) {
> + dev_err(pci->dev, "Failed to configure iATU in ECAM mode\n");
> + return ret;
> + }
> + } else {
> + ob_iatu_index = 1;
> + }
> +
> resource_list_for_each_entry(entry, &pp->bridge->windows) {
> resource_size_t res_size;
>
> @@ -985,8 +990,14 @@ static int dw_pcie_iatu_setup(struct dw_pcie_rp *pp)
> * be shared between I/O space and CFG IOs, by
> * temporarily reconfiguring the iATU to CFG space, in
> * order to do a CFG IO, and then immediately restoring
> - * it to I/O space.
> + * it to I/O space. This is only implemented when using
> + * dw_pcie_other_conf_map_bus(), which is not the case
> + * when using ECAM.
> */
> + if (pp->ecam_enabled) {
> + dev_err(pci->dev, "Cannot add outbound window for I/O\n");
> + return -ENOMEM;
> + }
> pp->cfg0_io_shared = true;
> }
> }
> @@ -1157,7 +1168,7 @@ int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
> * the platform uses its own address translation component rather than
> * ATU, so we should not program the ATU here.
> */
> - if (pp->bridge->child_ops == &dw_child_pcie_ops) {
> + if (pp->bridge->child_ops == &dw_child_pcie_ops || pp->ecam_enabled) {
> ret = dw_pcie_iatu_setup(pp);
> if (ret)
> return ret;
> diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
> index 18331d9e85be..5741c09dde7f 100644
> --- a/drivers/pci/controller/dwc/pcie-designware.c
> +++ b/drivers/pci/controller/dwc/pcie-designware.c
> @@ -532,6 +532,9 @@ int dw_pcie_prog_outbound_atu(struct dw_pcie *pci,
> u32 retries, val;
> u64 limit_addr;
>
> + if (atu->index >= pci->num_ob_windows)
> + return -ENOSPC;
> +
> limit_addr = parent_bus_addr + atu->size - 1;
>
> if ((limit_addr & ~pci->region_limit) != (parent_bus_addr & ~pci->region_limit) ||
> @@ -605,6 +608,9 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int type,
> u64 limit_addr = pci_addr + size - 1;
> u32 retries, val;
>
> + if (index >= pci->num_ib_windows)
> + return -ENOSPC;
> +
> if ((limit_addr & ~pci->region_limit) != (pci_addr & ~pci->region_limit) ||
> !IS_ALIGNED(parent_bus_addr, pci->region_align) ||
> !IS_ALIGNED(pci_addr, pci->region_align) || !size) {
--
Damien Le Moal
Western Digital Research
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH v4 4/4] PCI: dwc: Fix missing iATU setup when ECAM is enabled
2026-01-23 18:53 ` Damien Le Moal
@ 2026-01-27 15:02 ` Niklas Cassel
0 siblings, 0 replies; 10+ messages in thread
From: Niklas Cassel @ 2026-01-27 15:02 UTC (permalink / raw)
To: Damien Le Moal
Cc: Jingoo Han, Manivannan Sadhasivam, Lorenzo Pieralisi,
Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas,
Krishna Chaitanya Chundru, Randolph Lin, Samuel Holland, Frank Li,
Charles Mirabile, tim609, Maciej W. Rozycki, linux-pci
On Sat, Jan 24, 2026 at 05:53:36AM +1100, Damien Le Moal wrote:
> On 2026/01/24 5:28, Niklas Cassel wrote:
> > From: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
> >
> > When ECAM is enabled, the driver skipped calling dw_pcie_iatu_setup()
> > before configuring ECAM iATU entries. This left IO and MEM outbound
> > windows unprogrammed, resulting in broken IO transactions. Additionally,
> > dw_pcie_config_ecam_iatu() was only called during host initialization,
> > so ECAM-related iATU entries were not restored after suspend/resume,
> > leading to failures in configuration space access
> >
> > To resolve these issues, the ECAM iATU configuration is moved into
> > dw_pcie_iatu_setup(), and dw_pcie_iatu_setup() is invoked when ECAM is
> > enabled.
> >
> > Furthermore, error checks are added in dw_pcie_prog_outbound_atu() and
> > dw_pcie_prog_inbound_atu() such that an error is returned if trying to
> > program an iATU that is outside the number of iATUs provided by the
> > controller.
> >
> > Fixes: f6fd357f7afb ("PCI: dwc: Prepare the driver for enabling ECAM mechanism using iATU 'CFG Shift Feature'")
> > Reported-by: Maciej W. Rozycki <macro@orcam.me.uk>
> > Closes: https://lore.kernel.org/all/alpine.DEB.2.21.2511280256260.36486@angie.orcam.me.uk/
> > Signed-off-by: Krishna Chaitanya Chundru <krishna.chundru@oss.qualcomm.com>
> > Co-developed-by: Niklas Cassel <cassel@kernel.org>
> > Signed-off-by: Niklas Cassel <cassel@kernel.org>
>
> It looks like this patch depends on patch 3, which does not have a Fixes tag. So
> why not squash together patches 3 and 4 ?
I think it would be wrong to squash the patches.
This patch is mostly written by Krishna, and I think it is wrong to squash
a cleanup patch with a fix patch.
It is okay to have a fix patch that is done on top of a cleanup patch.
(It would require a lot more effort to write a fix without the cleanup
having been done first.)
Therefore, I will simply add:
Cc: stable+noautosel@kernel.org # depends on Clean up iATU index usage in dw_pcie_iatu_setup()
Such that stable will see that this patch requires a small dependency.
Kind regards,
Niklas
^ permalink raw reply [flat|nested] 10+ messages in thread