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

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.ru


Signed-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
Loading
Loading
Loading
Loading
+25 −13
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
 * Author: Jingoo Han <jg1.han@samsung.com>
 */

#include <linux/align.h>
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/of.h>
@@ -305,7 +306,7 @@ static inline u32 dw_pcie_enable_ecrc(u32 val)
	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,
				       u64 pci_addr, u64 size)
{
@@ -317,6 +318,12 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,

	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,
			      lower_32_bits(cpu_addr));
	dw_pcie_writel_atu_ob(pci, index, PCIE_ATU_UPPER_BASE,
@@ -350,26 +357,28 @@ static void __dw_pcie_prog_outbound_atu(struct dw_pcie *pci, u8 func_no,
	for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
		val = dw_pcie_readl_atu_ob(pci, index, PCIE_ATU_REGION_CTRL2);
		if (val & PCIE_ATU_ENABLE)
			return;
			return 0;

		mdelay(LINK_WAIT_IATU);
	}

	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)
{
	__dw_pcie_prog_outbound_atu(pci, 0, index, type,
	return __dw_pcie_prog_outbound_atu(pci, 0, index, type,
					   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,
				 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);
}

@@ -389,6 +398,9 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
{
	u32 retries, val;

	if (!IS_ALIGNED(cpu_addr, pci->region_align))
		return -EINVAL;

	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_TARGET,
			      lower_32_bits(cpu_addr));
	dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_TARGET,
+4 −6
Original line number Diff line number Diff line
@@ -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);
void dw_pcie_upconfig_setup(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 type, u64 cpu_addr, u64 pci_addr,
			       u64 size);
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 dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
			      u64 cpu_addr, u64 pci_addr, u64 size);
int 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 dw_pcie_prog_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
			     int type, u64 cpu_addr, u8 bar);
void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index);