summaryrefslogtreecommitdiff
path: root/drivers/pci/controller/dwc
diff options
context:
space:
mode:
authorAlan Mikhak <alan.mikhak@sifive.com>2020-04-02 02:58:13 +0300
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>2020-05-22 17:05:23 +0300
commit668b4490a3a56f062172096692ebe9d12e26be5c (patch)
tree4819239ed6954abf07e91d37b9bdf57f379843c0 /drivers/pci/controller/dwc
parent819482a96790d25fca97ec5c752400edbef05753 (diff)
downloadlinux-668b4490a3a56f062172096692ebe9d12e26be5c.tar.xz
PCI: dwc: Program outbound ATU upper limit register
Function dw_pcie_prog_outbound_atu_unroll() does not program the upper 32-bit ATU limit register. Since ATU programming functions limit the size of the translated region to 4GB by using a u32 size parameter, these issues may combine into undefined behavior for resource sizes with non-zero upper 32-bits. For example, a 128GB address space starting at physical CPU address of 0x2000000000 with size of 0x2000000000 needs the following values programmed into the lower and upper 32-bit limit registers: 0x3fffffff in the upper 32-bit limit register 0xffffffff in the lower 32-bit limit register Currently, only the lower 32-bit limit register is programmed with a value of 0xffffffff but the upper 32-bit limit register is not being programmed. As a result, the upper 32-bit limit register remains at its default value after reset of 0x0. These issues may combine to produce undefined behavior since the ATU limit address may be lower than the ATU base address. Programming the upper ATU limit address register prevents such undefined behavior despite the region size getting truncated due to the 32-bit size limit. Link: https://lore.kernel.org/r/1585785493-23210-1-git-send-email-alan.mikhak@sifive.com Signed-off-by: Alan Mikhak <alan.mikhak@sifive.com> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Acked-by: Gustavo Pimentel <gustavo.pimentel@synopsys.com>
Diffstat (limited to 'drivers/pci/controller/dwc')
-rw-r--r--drivers/pci/controller/dwc/pcie-designware.c7
-rw-r--r--drivers/pci/controller/dwc/pcie-designware.h3
2 files changed, 7 insertions, 3 deletions
diff --git a/drivers/pci/controller/dwc/pcie-designware.c b/drivers/pci/controller/dwc/pcie-designware.c
index 681548c88282..c92496e36fd5 100644
--- a/drivers/pci/controller/dwc/pcie-designware.c
+++ b/drivers/pci/controller/dwc/pcie-designware.c
@@ -244,13 +244,16 @@ static void dw_pcie_prog_outbound_atu_unroll(struct dw_pcie *pci, int index,
u64 pci_addr, u32 size)
{
u32 retries, val;
+ u64 limit_addr = cpu_addr + size - 1;
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_BASE,
lower_32_bits(cpu_addr));
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_BASE,
upper_32_bits(cpu_addr));
- dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LIMIT,
- lower_32_bits(cpu_addr + size - 1));
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_LIMIT,
+ lower_32_bits(limit_addr));
+ dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_LIMIT,
+ upper_32_bits(limit_addr));
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_LOWER_TARGET,
lower_32_bits(pci_addr));
dw_pcie_writel_ob_unroll(pci, index, PCIE_ATU_UNR_UPPER_TARGET,
diff --git a/drivers/pci/controller/dwc/pcie-designware.h b/drivers/pci/controller/dwc/pcie-designware.h
index d6e1f397e6b0..656e00f8fbeb 100644
--- a/drivers/pci/controller/dwc/pcie-designware.h
+++ b/drivers/pci/controller/dwc/pcie-designware.h
@@ -112,9 +112,10 @@
#define PCIE_ATU_UNR_REGION_CTRL2 0x04
#define PCIE_ATU_UNR_LOWER_BASE 0x08
#define PCIE_ATU_UNR_UPPER_BASE 0x0C
-#define PCIE_ATU_UNR_LIMIT 0x10
+#define PCIE_ATU_UNR_LOWER_LIMIT 0x10
#define PCIE_ATU_UNR_LOWER_TARGET 0x14
#define PCIE_ATU_UNR_UPPER_TARGET 0x18
+#define PCIE_ATU_UNR_UPPER_LIMIT 0x20
/*
* The default address offset between dbi_base and atu_base. Root controller