Commit edf408b9 authored by Serge Semin's avatar Serge Semin Committed by Bjorn Helgaas

PCI: dwc: Validate iATU outbound mappings against hardware constraints

Make __dw_pcie_prog_outbound_atu() check the requested region base and size
against what the hardware can support.  Return error if the region is not
correctly aligned or of a supported size.

[bhelgaas: commit log]
Link: https://lore.kernel.org/r/20220624143947.8991-14-Sergey.Semin@baikalelectronics.ruSigned-off-by: default avatarSerge Semin <Sergey.Semin@baikalelectronics.ru>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarRob Herring <robh@kernel.org>
Reviewed-by: default avatarManivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
parent 89473aa9
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
* Author: Jingoo Han <jg1.han@samsung.com> * Author: Jingoo Han <jg1.han@samsung.com>
*/ */
#include <linux/align.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/of.h> #include <linux/of.h>
...@@ -305,9 +306,9 @@ static inline u32 dw_pcie_enable_ecrc(u32 val) ...@@ -305,9 +306,9 @@ static inline u32 dw_pcie_enable_ecrc(u32 val)
return val | PCIE_ATU_TD; return val | PCIE_ATU_TD;
} }
static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no, static int __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
int index, int type, u64 cpu_addr, int index, int type, u64 cpu_addr,
u64 pci_addr, u64 size) u64 pci_addr, u64 size)
{ {
u32 retries, val; u32 retries, val;
u64 limit_addr; u64 limit_addr;
...@@ -317,6 +318,12 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no, ...@@ -317,6 +318,12 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
limit_addr = cpu_addr + size - 1; limit_addr = cpu_addr + size - 1;
if ((limit_addr & ~pci->region_limit) != (cpu_addr & ~pci->region_limit) ||
!IS_ALIGNED(cpu_addr, pci->region_align) ||
!IS_ALIGNED(pci_addr, pci->region_align) || !size) {
return -EINVAL;
}
dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_LOWER_BASE, dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_LOWER_BASE,
lower_32_bits(cpu_addr)); lower_32_bits(cpu_addr));
dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_UPPER_BASE, dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_UPPER_BASE,
...@@ -350,27 +357,29 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no, ...@@ -350,27 +357,29 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) { for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
val = dw_pcie_readl_atu_ob(pci, index, PCIE_ATU_REGION_CTRL2); val = dw_pcie_readl_atu_ob(pci, index, PCIE_ATU_REGION_CTRL2);
if (val & PCIE_ATU_ENABLE) if (val & PCIE_ATU_ENABLE)
return; return 0;
mdelay(LINK_WAIT_IATU); mdelay(LINK_WAIT_IATU);
} }
dev_err(pci->dev, "Outbound iATU is not being enabled\n"); dev_err(pci->dev, "Outbound iATU is not being enabled\n");
return -ETIMEDOUT;
} }
void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type, int dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
u64 cpu_addr, u64 pci_addr, u64 size) u64 cpu_addr, u64 pci_addr, u64 size)
{ {
__dw_pcie_prog_outbound_atu(pci, 0, index, type, return __dw_pcie_prog_outbound_atu(pci, 0, index, type,
cpu_addr, pci_addr, size); cpu_addr, pci_addr, size);
} }
void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index, int dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
int type, u64 cpu_addr, u64 pci_addr, int type, u64 cpu_addr, u64 pci_addr,
u64 size) u64 size)
{ {
__dw_pcie_prog_outbound_atu(pci, func_no, index, type, return __dw_pcie_prog_outbound_atu(pci, func_no, index, type,
cpu_addr, pci_addr, size); cpu_addr, pci_addr, size);
} }
static inline u32 dw_pcie_readl_atu_ib(struct dw_pcie *pci, u32 index, u32 reg) static inline u32 dw_pcie_readl_atu_ib(struct dw_pcie *pci, u32 index, u32 reg)
...@@ -389,6 +398,9 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index, ...@@ -389,6 +398,9 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
{ {
u32 retries, val; u32 retries, val;
if (!IS_ALIGNED(cpu_addr, pci->region_align))
return -EINVAL;
dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_TARGET, dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_TARGET,
lower_32_bits(cpu_addr)); lower_32_bits(cpu_addr));
dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_TARGET, dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_TARGET,
......
...@@ -304,12 +304,10 @@ void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val); ...@@ -304,12 +304,10 @@ void dw_pcie_write_dbi2(struct dw_pcie *pci, u32 reg, size_t size, u32 val);
int dw_pcie_link_up(struct dw_pcie *pci); int dw_pcie_link_up(struct dw_pcie *pci);
void dw_pcie_upconfig_setup(struct dw_pcie *pci); void dw_pcie_upconfig_setup(struct dw_pcie *pci);
int dw_pcie_wait_for_link(struct dw_pcie *pci); int dw_pcie_wait_for_link(struct dw_pcie *pci);
void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
int type, u64 cpu_addr, u64 pci_addr, u64 cpu_addr, u64 pci_addr, u64 size);
u64 size); int dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index,
void dw_pcie_prog_ep_outbound_atu(struct dw_pcie *pci, u8 func_no, int index, int type, u64 cpu_addr, u64 pci_addr, u64 size);
int type, u64 cpu_addr, u64 pci_addr,
u64 size);
int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index, int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
int type, u64 cpu_addr, u8 bar); int type, u64 cpu_addr, u8 bar);
void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index); void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment