From: Aksh Garg Date: Tue, 24 Feb 2026 08:38:17 +0000 (+0530) Subject: PCI: dwc: ep: Mirror the max link width and speed fields to all functions X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=94cbea0f636b55602a9a10583670976680ecea67;p=thirdparty%2Fkernel%2Flinux.git PCI: dwc: ep: Mirror the max link width and speed fields to all functions PCIe r7.0, section 7.5.3.6 states that for multi-function devices, the Max Link Width and Max Link Speed fields in the Link Capabilities Register must report the same values for all functions. Currently, dw_pcie_setup() programs these fields only for Function 0 via dw_pcie_link_set_max_speed() and dw_pcie_link_set_max_link_width(). For multi-function endpoint configurations, Function 1 and beyond retain their default values, violating the PCIe specification. Fix this by reading the Max Link Width and Max Link Speed fields from Link Capabilities Register of Function 0 after dw_pcie_setup() completes, then mirroring these values to all other functions. Fixes: 24ede430fa49 ("PCI: designware-ep: Add multiple PFs support for DWC") Fixes: 89db0793c9f2 ("PCI: dwc: Add missing PCI_EXP_LNKCAP_MLW handling") Signed-off-by: Aksh Garg [mani: renamed ref_lnkcap to func0_lnkcap] Signed-off-by: Manivannan Sadhasivam Link: https://patch.msgid.link/20260224083817.916782-3-a-garg7@ti.com --- diff --git a/drivers/pci/controller/dwc/pcie-designware-ep.c b/drivers/pci/controller/dwc/pcie-designware-ep.c index 709ab60c9e398..21b6f4eb24cda 100644 --- a/drivers/pci/controller/dwc/pcie-designware-ep.c +++ b/drivers/pci/controller/dwc/pcie-designware-ep.c @@ -1103,7 +1103,8 @@ static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci) { struct dw_pcie_ep *ep = &pci->ep; u8 funcs = ep->epc->max_functions; - u8 func_no; + u32 func0_lnkcap, lnkcap; + u8 func_no, offset; dw_pcie_dbi_ro_wr_en(pci); @@ -1111,6 +1112,32 @@ static void dw_pcie_ep_init_non_sticky_registers(struct dw_pcie *pci) dw_pcie_ep_init_rebar_registers(ep, func_no); dw_pcie_setup(pci); + + /* + * PCIe r7.0, section 7.5.3.6 states that for multi-function + * endpoints, max link width and speed fields must report same + * values for all functions. However, dw_pcie_setup() programs + * these fields only for function 0. Hence, mirror these fields + * to all other functions as well. + */ + if (funcs > 1) { + offset = dw_pcie_find_capability(pci, PCI_CAP_ID_EXP); + func0_lnkcap = dw_pcie_readl_dbi(pci, offset + PCI_EXP_LNKCAP); + func0_lnkcap = FIELD_GET(PCI_EXP_LNKCAP_MLW | + PCI_EXP_LNKCAP_SLS, func0_lnkcap); + + for (func_no = 1; func_no < funcs; func_no++) { + offset = dw_pcie_ep_find_capability(ep, func_no, + PCI_CAP_ID_EXP); + lnkcap = dw_pcie_ep_readl_dbi(ep, func_no, + offset + PCI_EXP_LNKCAP); + FIELD_MODIFY(PCI_EXP_LNKCAP_MLW | PCI_EXP_LNKCAP_SLS, + &lnkcap, func0_lnkcap); + dw_pcie_ep_writel_dbi(ep, func_no, + offset + PCI_EXP_LNKCAP, lnkcap); + } + } + dw_pcie_dbi_ro_wr_dis(pci); }