Thread (13 messages) 13 messages, 4 authors, 2025-09-18
STALE306d
Revisions (10)
  1. v1 [diff vs current]
  2. v2 current
  3. v4 [diff vs current]
  4. v5 [diff vs current]
  5. v6 [diff vs current]
  6. v7 [diff vs current]
  7. v8 [diff vs current]
  8. v9 [diff vs current]
  9. v10 [diff vs current]
  10. v11 [diff vs current]

[PATCH v2 1/5] PCI: dwc: Add outbound ATU address range validation callback

From: Randolph Lin <randolph@andestech.com>
Date: 2025-09-16 10:04:44
Also in: linux-pci, linux-riscv, lkml
Subsystem: pci driver for synopsys designware, pci native host bridge and endpoint drivers, pci subsystem, the rest · Maintainers: Jingoo Han, Manivannan Sadhasivam, Lorenzo Pieralisi, Krzysztof Wilczyński, Bjorn Helgaas, Linus Torvalds

Introduce an optional callback for outbound ATU address range
validation to handle cases that deviate from the generic check.

Signed-off-by: Randolph Lin <randolph@andestech.com>
---
 drivers/pci/controller/dwc/pcie-designware.c | 29 ++++++++++++++++----
 drivers/pci/controller/dwc/pcie-designware.h |  3 ++
 2 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index 89aad5a08928..087f9077cf21 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -528,6 +528,28 @@ static inline u32 dw_pcie_enable_ecrc(u32 val)
 	return val | PCIE_ATU_TD;
 }
 
+static
+bool dw_pcie_outbound_atu_addr_valid(struct dw_pcie *pci,
+				     const struct dw_pcie_ob_atu_cfg *atu,
+				     u64 *limit_addr)
+{
+	u64 parent_bus_addr = atu->parent_bus_addr;
+
+	if (pci->ops && pci->ops->outbound_atu_addr_valid)
+		return pci->ops->outbound_atu_addr_valid(pci, atu, limit_addr);
+
+	*limit_addr = parent_bus_addr + atu->size - 1;
+
+	if ((*limit_addr & ~pci->region_limit) !=
+	    (parent_bus_addr & ~pci->region_limit) ||
+	    !IS_ALIGNED(parent_bus_addr, pci->region_align) ||
+	    !IS_ALIGNED(atu->pci_addr, pci->region_align) ||
+	    !atu->size)
+		return false;
+
+	return true;
+}
+
 int dw_pcie_prog_outbound_atu(struct dw_pcie *pci,
 			      const struct dw_pcie_ob_atu_cfg *atu)
 {
@@ -535,13 +557,8 @@ int dw_pcie_prog_outbound_atu(struct dw_pcie *pci,
 	u32 retries, val;
 	u64 limit_addr;
 
-	limit_addr = parent_bus_addr + atu->size - 1;
-
-	if ((limit_addr & ~pci->region_limit) != (parent_bus_addr & ~pci->region_limit) ||
-	    !IS_ALIGNED(parent_bus_addr, pci->region_align) ||
-	    !IS_ALIGNED(atu->pci_addr, pci->region_align) || !atu->size) {
+	if (!dw_pcie_outbound_atu_addr_valid(pci, atu, &limit_addr))
 		return -EINVAL;
-	}
 
 	dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_LOWER_BASE,
 			      lower_32_bits(parent_bus_addr));
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index 00f52d472dcd..6d4805048048 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -469,6 +469,9 @@ struct dw_pcie_ep {
 
 struct dw_pcie_ops {
 	u64	(*cpu_addr_fixup)(struct dw_pcie *pcie, u64 cpu_addr);
+	bool	(*outbound_atu_addr_valid)(struct dw_pcie *pcie,
+					   const struct dw_pcie_ob_atu_cfg *atu,
+					   u64 *limit_addr);
 	u32	(*read_dbi)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
 			    size_t size);
 	void	(*write_dbi)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
-- 
2.34.1
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help