PCI: cadence: Clear FLR in device capabilities register
authorParshuram Thombare <pthombar@cadence.com>
Mon, 25 Oct 2021 12:31:15 +0000 (05:31 -0700)
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Thu, 12 May 2022 21:19:40 +0000 (22:19 +0100)
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>
drivers/pci/controller/cadence/pci-j721e.c
drivers/pci/controller/cadence/pcie-cadence-ep.c
drivers/pci/controller/cadence/pcie-cadence.h

index 768d33f9ebc87569d4e247bba2588a958e529b40..a82f845cc4b521c9b5410ab226d51a585ab1a261 100644 (file)
@@ -69,6 +69,7 @@ struct j721e_pcie_data {
        enum j721e_pcie_mode    mode;
        unsigned int            quirk_retrain_flag:1;
        unsigned int            quirk_detect_quiet_flag:1;
+       unsigned int            quirk_disable_flr:1;
        u32                     linkdown_irq_regfield;
        unsigned int            byte_access_allowed:1;
 };
@@ -307,6 +308,7 @@ static const struct j721e_pcie_data j7200_pcie_rc_data = {
 static const struct j721e_pcie_data j7200_pcie_ep_data = {
        .mode = PCI_MODE_EP,
        .quirk_detect_quiet_flag = true,
+       .quirk_disable_flr = true,
 };
 
 static const struct j721e_pcie_data am64_pcie_rc_data = {
@@ -405,6 +407,7 @@ static int j721e_pcie_probe(struct platform_device *pdev)
                        return -ENOMEM;
 
                ep->quirk_detect_quiet_flag = data->quirk_detect_quiet_flag;
+               ep->quirk_disable_flr = data->quirk_disable_flr;
 
                cdns_pcie = &ep->pcie;
                cdns_pcie->dev = dev;
index 18e32b8ffd5ef2c76cb55757b2ef7dd67ba03495..b8b655d4047ecafca24fd112882d45a5f6e0f295 100644 (file)
@@ -564,7 +564,8 @@ static int cdns_pcie_ep_start(struct pci_epc *epc)
        struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
        struct cdns_pcie *pcie = &ep->pcie;
        struct device *dev = pcie->dev;
-       int ret;
+       int max_epfs = sizeof(epc->function_num_map) * 8;
+       int ret, value, epf;
 
        /*
         * BIT(0) is hardwired to 1, hence function 0 is always enabled
@@ -572,6 +573,21 @@ static int cdns_pcie_ep_start(struct pci_epc *epc)
         */
        cdns_pcie_writel(pcie, CDNS_PCIE_LM_EP_FUNC_CFG, epc->function_num_map);
 
+       if (ep->quirk_disable_flr) {
+               for (epf = 0; epf < max_epfs; epf++) {
+                       if (!(epc->function_num_map & BIT(epf)))
+                               continue;
+
+                       value = cdns_pcie_ep_fn_readl(pcie, epf,
+                                       CDNS_PCIE_EP_FUNC_DEV_CAP_OFFSET +
+                                       PCI_EXP_DEVCAP);
+                       value &= ~PCI_EXP_DEVCAP_FLR;
+                       cdns_pcie_ep_fn_writel(pcie, epf,
+                                       CDNS_PCIE_EP_FUNC_DEV_CAP_OFFSET +
+                                       PCI_EXP_DEVCAP, value);
+               }
+       }
+
        ret = cdns_pcie_start_link(pcie);
        if (ret) {
                dev_err(dev, "Failed to start link\n");
index 1ffa8fa77a8ac6defbb6a84352dcb7ae8e16eaa9..190786e47df930443acdd578cdc5a04c8dee7ce7 100644 (file)
 
 #define CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET       0x90
 #define CDNS_PCIE_EP_FUNC_MSIX_CAP_OFFSET      0xb0
+#define CDNS_PCIE_EP_FUNC_DEV_CAP_OFFSET       0xc0
 #define CDNS_PCIE_EP_FUNC_SRIOV_CAP_OFFSET     0x200
 
 /*
@@ -361,6 +362,7 @@ struct cdns_pcie_epf {
  *        minimize time between read and write
  * @epf: Structure to hold info about endpoint function
  * @quirk_detect_quiet_flag: LTSSM Detect Quiet min delay set as quirk
+ * @quirk_disable_flr: Disable FLR (Function Level Reset) quirk flag
  */
 struct cdns_pcie_ep {
        struct cdns_pcie        pcie;
@@ -376,6 +378,7 @@ struct cdns_pcie_ep {
        spinlock_t              lock;
        struct cdns_pcie_epf    *epf;
        unsigned int            quirk_detect_quiet_flag:1;
+       unsigned int            quirk_disable_flr:1;
 };