[PATCH AUTOSEL 6.19] PCI: cadence: Avoid signed 64-bit truncation and invalid sort

Sasha Levin
2026-02-14T21:26:26Z

From: Ian Rogers <irogers@google.com>

[ Upstream commit 0297dce758a021ccf2c0f4e164d5403ef722961c ]

The cdns_pcie_host_dma_ranges_cmp() element comparison function used by
list_sort() is of type list_cmp_func_t, so it returns a 32-bit int.

cdns_pcie_host_dma_ranges_cmp() computes a resource_size_t difference that
may be a 64-bit value, and truncating that difference to a 32-bit return
value may change the sign and result in an invalid sort order.

Avoid the truncation and invalid sort order by returning -1, 0, or 1.

Signed-off-by: Ian Rogers <irogers@google.com>
Signed-off-by: Manivannan Sadhasivam <mani@kernel.org>
[bhelgaas: commit log]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Link: https://patch.msgid.link/20251209223756.2321578-1-irogers@google.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

## Analysis of PCI: cadence: Avoid signed 64-bit truncation and invalid
sort

### Commit Message Analysis

The commit message clearly describes a bug: the comparison function
`cdns_pcie_host_dma_ranges_cmp()` returns a 32-bit `int`, but it
computes a difference of `resource_size_t` values which can be 64-bit.
Truncating a 64-bit difference to 32 bits can change the sign, resulting
in an **invalid sort order**. This is a classic integer truncation bug
in comparison functions.

### Code Change Analysis

**Before (buggy):**
```c
return resource_size(entry2->res) - resource_size(entry1->res);
```

This subtracts two `resource_size_t` (which is `u64` on 64-bit systems)
values and returns the result as an `int` (32-bit). If the difference
exceeds `INT_MAX` or the subtraction wraps around (since
`resource_size_t` is unsigned), the truncated 32-bit value can have the
wrong sign.

**After (fixed):**
```c
size1 = resource_size(entry1->res);
size2 = resource_size(entry2->res);

if (size1 > size2)
return -1;
if (size1 < size2)
return 1;
return 0;
```

This is the canonical safe way to write a comparison function, returning
-1, 0, or 1 directly.

### Bug Impact

This function is used by `list_sort()` to sort DMA ranges by size
(descending order). An invalid sort order means:

1. **DMA ranges may not be sorted correctly**, which affects BAR
configuration in `cdns_pcie_host_bar_config()`.
2. The Cadence PCIe host controller relies on this sorting to assign
BARs to inbound memory regions. If large regions are not processed
first (as intended by the descending sort), BAR assignment could fail
or produce suboptimal/incorrect mappings.
3. This could lead to **PCIe enumeration failures** or **incorrect
memory mappings** on systems using the Cadence PCIe controller
(common in embedded/SoC platforms).

The bug is triggered when resource sizes differ by more than 2^31 bytes
(2 GiB), which is realistic for modern systems with large DMA regions.

### Stable Criteria Check

1. **Obviously correct and tested**: Yes - the fix is a textbook
correction of an integer truncation bug in a comparator. Reviewed and
merged by the PCI subsystem maintainer (Bjorn Helgaas).
2. **Fixes a real bug**: Yes - integer truncation causing invalid sort
order is a real bug that can cause incorrect BAR configuration.
3. **Important issue**: Moderate - incorrect PCIe BAR configuration can
cause device failures on affected platforms.
4. **Small and contained**: Yes - the change is minimal (about 10 lines
changed in a single function), localized to one comparator function.
5. **No new features**: Correct - this is purely a bug fix.
6. **Applies cleanly**: The change is self-contained with no
dependencies.

### Risk Assessment

- **Risk**: Very low. The change replaces an incorrect arithmetic
comparison with the standard -1/0/1 pattern. There's no way this can
introduce a regression.
- **Scope**: Single function in a single file, affecting only the
Cadence PCIe host controller driver.
- **Benefit**: Correct DMA range sorting for systems with large memory
regions using Cadence PCIe.

### Subsystem Relevance

The Cadence PCIe controller IP is used in several SoCs (TI, Renesas,
etc.), so this affects real embedded/industrial platforms that are
likely running stable kernels.

### Conclusion

This is a clear, small, obviously correct bug fix for an integer
truncation issue that can cause incorrect PCI BAR configuration. It
meets all stable kernel criteria with minimal risk.

**YES**

.../controller/cadence/pcie-cadence-host-common.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/pci/controller/cadence/pcie-cadence-host-common.c b/drivers/pci/controller/cadence/pcie-cadence-host-common.c
index 15415d7f35ee9..2b0211870f02a 100644
--- a/drivers/pci/controller/cadence/pcie-cadence-host-common.c
+++ b/drivers/pci/controller/cadence/pcie-cadence-host-common.c
@@ -173,11 +173,21 @@ int cdns_pcie_host_dma_ranges_cmp(void *priv, const struct list_head *a,
const struct list_head *b)
{
struct resource_entry *entry1, *entry2;
+ u64 size1, size2;

entry1 = container_of(a, struct resource_entry, node);
entry2 = container_of(b, struct resource_entry, node);

- return resource_size(entry2->res) - resource_size(entry1->res);
+ size1 = resource_size(entry1->res);
+ size2 = resource_size(entry2->res);
+
+ if (size1 > size2)
+ return -1;
+
+ if (size1 < size2)
+ return 1;
+
+ return 0;
}
EXPORT_SYMBOL_GPL(cdns_pcie_host_dma_ranges_cmp);

--
2.51.0