Skip to content

Commit 33a6938

Browse files
floatiouskwilczynski
authored andcommitted
PCI: dwc: ep: Write BAR_MASK before iATU registers in pci_epc_set_bar()
The "DesignWare Cores PCI Express Controller Register Descriptions, Version 4.60a", section "1.21.70 IATU_LWR_TARGET_ADDR_OFF_INBOUND_i", fields LWR_TARGET_RW and LWR_TARGET_HW both 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. If we do not write the BAR_MASK before writing the iATU registers, we are relying the reset value of the BAR_MASK being larger than the requested BAR size (which is supplied in the struct pci_epf_bar which is passed to pci_epc_set_bar()). The reset value of the BAR_MASK is SoC dependent. Thus, if the struct pci_epf_bar requests a BAR size that is larger than the reset value of the BAR_MASK, the iATU will try to write to read-only bits, which will cause the iATU to end up redirecting to a physical address that is different from the address that was intended. Thus, we should always write the iATU registers after writing the BAR_MASK. Fixes: f8aed6e ("PCI: dwc: designware: Add EP mode support") 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]> Cc: [email protected]
1 parent 3b9f942 commit 33a6938

File tree

1 file changed

+15
-13
lines changed

1 file changed

+15
-13
lines changed

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

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -222,19 +222,10 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
222222
if ((flags & PCI_BASE_ADDRESS_MEM_TYPE_64) && (bar & 1))
223223
return -EINVAL;
224224

225-
reg = PCI_BASE_ADDRESS_0 + (4 * bar);
226-
227-
if (!(flags & PCI_BASE_ADDRESS_SPACE))
228-
type = PCIE_ATU_TYPE_MEM;
229-
else
230-
type = PCIE_ATU_TYPE_IO;
231-
232-
ret = dw_pcie_ep_inbound_atu(ep, func_no, type, epf_bar->phys_addr, bar);
233-
if (ret)
234-
return ret;
235-
236225
if (ep->epf_bar[bar])
237-
return 0;
226+
goto config_atu;
227+
228+
reg = PCI_BASE_ADDRESS_0 + (4 * bar);
238229

239230
dw_pcie_dbi_ro_wr_en(pci);
240231

@@ -246,9 +237,20 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
246237
dw_pcie_ep_writel_dbi(ep, func_no, reg + 4, 0);
247238
}
248239

249-
ep->epf_bar[bar] = epf_bar;
250240
dw_pcie_dbi_ro_wr_dis(pci);
251241

242+
config_atu:
243+
if (!(flags & PCI_BASE_ADDRESS_SPACE))
244+
type = PCIE_ATU_TYPE_MEM;
245+
else
246+
type = PCIE_ATU_TYPE_IO;
247+
248+
ret = dw_pcie_ep_inbound_atu(ep, func_no, type, epf_bar->phys_addr, bar);
249+
if (ret)
250+
return ret;
251+
252+
ep->epf_bar[bar] = epf_bar;
253+
252254
return 0;
253255
}
254256

0 commit comments

Comments
 (0)