Skip to content

Commit 129f6af

Browse files
floatiouskwilczynski
authored andcommitted
PCI: dwc: ep: Add 'address' alignment to 'size' check in dw_pcie_prog_ep_inbound_atu()
dw_pcie_prog_ep_inbound_atu() is used to program an inbound iATU in "BAR Match Mode". A memory address returned by e.g. kmalloc() is guaranteed to have natural alignment (aligned to the size of the allocation). It is however not guaranteed that pci_epc_set_bar() (and thus dw_pcie_prog_ep_inbound_atu()) is supplied an address that has natural alignment. (An EPF driver can send in an arbitrary physical address to pci_epc_set_bar().) The DWC Databook description for the LWR_TARGET_RW and LWR_TARGET_HW fields in the IATU_LWR_TARGET_ADDR_OFF_INBOUND_i registers state that: "Field size depends on log2(BAR_MASK+1) in BAR match mode." I.e. only the upper bits are writable, and the number of writable bits is dependent on the configured BAR_MASK. Add a check to ensure that the physical address programmed in the iATU is aligned to the size of the BAR (BAR_MASK+1), as without this, we can get hard to debug errors, as we could write to bits that are read-only (without getting a write error), which could cause the iATU to end up redirecting to a physical address that is different from the address that we intended. Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Niklas Cassel <[email protected]> Signed-off-by: Krzysztof Wilczyński <[email protected]> Reviewed-by: Manivannan Sadhasivam <[email protected]>
1 parent 3708acb commit 129f6af

File tree

3 files changed

+9
-6
lines changed

3 files changed

+9
-6
lines changed

drivers/pci/controller/dwc/pcie-designware-ep.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
128128
}
129129

130130
static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no, int type,
131-
dma_addr_t cpu_addr, enum pci_barno bar)
131+
dma_addr_t cpu_addr, enum pci_barno bar,
132+
size_t size)
132133
{
133134
int ret;
134135
u32 free_win;
@@ -145,7 +146,7 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, u8 func_no, int type,
145146
}
146147

147148
ret = dw_pcie_prog_ep_inbound_atu(pci, func_no, free_win, type,
148-
cpu_addr, bar);
149+
cpu_addr, bar, size);
149150
if (ret < 0) {
150151
dev_err(pci->dev, "Failed to program IB window\n");
151152
return ret;
@@ -265,7 +266,8 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
265266
else
266267
type = PCIE_ATU_TYPE_IO;
267268

268-
ret = dw_pcie_ep_inbound_atu(ep, func_no, type, epf_bar->phys_addr, bar);
269+
ret = dw_pcie_ep_inbound_atu(ep, func_no, type, epf_bar->phys_addr, bar,
270+
size);
269271
if (ret)
270272
return ret;
271273

drivers/pci/controller/dwc/pcie-designware.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -597,11 +597,12 @@ int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int type,
597597
}
598598

599599
int dw_pcie_prog_ep_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
600-
int type, u64 cpu_addr, u8 bar)
600+
int type, u64 cpu_addr, u8 bar, size_t size)
601601
{
602602
u32 retries, val;
603603

604-
if (!IS_ALIGNED(cpu_addr, pci->region_align))
604+
if (!IS_ALIGNED(cpu_addr, pci->region_align) ||
605+
!IS_ALIGNED(cpu_addr, size))
605606
return -EINVAL;
606607

607608
dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_TARGET,

drivers/pci/controller/dwc/pcie-designware.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -491,7 +491,7 @@ int dw_pcie_prog_outbound_atu(struct dw_pcie *pci,
491491
int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int type,
492492
u64 cpu_addr, u64 pci_addr, u64 size);
493493
int dw_pcie_prog_ep_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
494-
int type, u64 cpu_addr, u8 bar);
494+
int type, u64 cpu_addr, u8 bar, size_t size);
495495
void dw_pcie_disable_atu(struct dw_pcie *pci, u32 dir, int index);
496496
void dw_pcie_setup(struct dw_pcie *pci);
497497
void dw_pcie_iatu_detect(struct dw_pcie *pci);

0 commit comments

Comments
 (0)