Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

PCI: cadence: Clear FLR in device capabilities register

Clear FLR (Function Level Reset) from device capabilities
registers for all physical functions.

During FLR, the Margining Lane Status and Margining Lane Control
registers should not be reset, as per PCIe specification.
However, the controller incorrectly resets these registers upon FLR.
This causes PCISIG compliance FLR test to fail. Hence preventing
all functions from advertising FLR support if flag quirk_disable_flr
is set.

Link: https://lore.kernel.org/r/1635165075-89864-1-git-send-email-pthombar@cadence.com
Signed-off-by: Parshuram Thombare <pthombar@cadence.com>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>

authored by

Parshuram Thombare and committed by
Lorenzo Pieralisi
95b00f68 a1f67bc1

+23 -1
+3
drivers/pci/controller/cadence/pci-j721e.c
··· 69 69 enum j721e_pcie_mode mode; 70 70 unsigned int quirk_retrain_flag:1; 71 71 unsigned int quirk_detect_quiet_flag:1; 72 + unsigned int quirk_disable_flr:1; 72 73 u32 linkdown_irq_regfield; 73 74 unsigned int byte_access_allowed:1; 74 75 }; ··· 308 307 static const struct j721e_pcie_data j7200_pcie_ep_data = { 309 308 .mode = PCI_MODE_EP, 310 309 .quirk_detect_quiet_flag = true, 310 + .quirk_disable_flr = true, 311 311 }; 312 312 313 313 static const struct j721e_pcie_data am64_pcie_rc_data = { ··· 407 405 return -ENOMEM; 408 406 409 407 ep->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag; 408 + ep->quirk_disable_flr = data->quirk_disable_flr; 410 409 411 410 cdns_pcie = &ep->pcie; 412 411 cdns_pcie->dev = dev;
+17 -1
drivers/pci/controller/cadence/pcie-cadence-ep.c
··· 564 564 struct cdns_pcie_ep *ep = epc_get_drvdata(epc); 565 565 struct cdns_pcie *pcie = &ep->pcie; 566 566 struct device *dev = pcie->dev; 567 - int ret; 567 + int max_epfs = sizeof(epc->function_num_map) * 8; 568 + int ret, value, epf; 568 569 569 570 /* 570 571 * BIT(0) is hardwired to 1, hence function 0 is always enabled 571 572 * and can't be disabled anyway. 572 573 */ 573 574 cdns_pcie_writel(pcie, CDNS_PCIE_LM_EP_FUNC_CFG, epc->function_num_map); 575 + 576 + if (ep->quirk_disable_flr) { 577 + for (epf = 0; epf < max_epfs; epf++) { 578 + if (!(epc->function_num_map & BIT(epf))) 579 + continue; 580 + 581 + value = cdns_pcie_ep_fn_readl(pcie, epf, 582 + CDNS_PCIE_EP_FUNC_DEV_CAP_OFFSET + 583 + PCI_EXP_DEVCAP); 584 + value &= ~PCI_EXP_DEVCAP_FLR; 585 + cdns_pcie_ep_fn_writel(pcie, epf, 586 + CDNS_PCIE_EP_FUNC_DEV_CAP_OFFSET + 587 + PCI_EXP_DEVCAP, value); 588 + } 589 + } 574 590 575 591 ret = cdns_pcie_start_link(pcie); 576 592 if (ret) {
+3
drivers/pci/controller/cadence/pcie-cadence.h
··· 127 127 128 128 #define CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET 0x90 129 129 #define CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET 0xb0 130 + #define CDNS_PCIE_EP_FUNC_DEV_CAP_OFFSET 0xc0 130 131 #define CDNS_PCIE_EP_FUNC_SRIOV_CAP_OFFSET 0x200 131 132 132 133 /* ··· 362 361 * minimize time between read and write 363 362 * @epf: Structure to hold info about endpoint function 364 363 * @quirk_detect_quiet_flag: LTSSM Detect Quiet min delay set as quirk 364 + * @quirk_disable_flr: Disable FLR (Function Level Reset) quirk flag 365 365 */ 366 366 struct cdns_pcie_ep { 367 367 struct cdns_pcie pcie; ··· 378 376 spinlock_t lock; 379 377 struct cdns_pcie_epf *epf; 380 378 unsigned int quirk_detect_quiet_flag:1; 379 + unsigned int quirk_disable_flr:1; 381 380 }; 382 381 383 382