]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
Merge branch 'remotes/lorenzo/pci/cadence'
authorBjorn Helgaas <bhelgaas@google.com>
Wed, 24 Feb 2021 20:59:21 +0000 (14:59 -0600)
committerBjorn Helgaas <bhelgaas@google.com>
Wed, 24 Feb 2021 20:59:21 +0000 (14:59 -0600)
- Retrain Link to work around Gen2 training defect (Nadeem Athani)

* remotes/lorenzo/pci/cadence:
  PCI: cadence: Retrain Link to work around Gen2 training defect

1  2 
drivers/pci/controller/cadence/pcie-cadence-host.c

index 1cb7cfc75d6e453630ca6a94d0eec1281c4725dd,6f591d38257851380daf89315c18fa7ee32fc7b2..73dcf8cf98fbf43efeeb6e54001ee25bb1b757bb
@@@ -77,6 -77,68 +77,68 @@@ static struct pci_ops cdns_pcie_host_op
        .write          = pci_generic_config_write,
  };
  
+ static int cdns_pcie_host_wait_for_link(struct cdns_pcie *pcie)
+ {
+       struct device *dev = pcie->dev;
+       int retries;
+       /* Check if the link is up or not */
+       for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
+               if (cdns_pcie_link_up(pcie)) {
+                       dev_info(dev, "Link up\n");
+                       return 0;
+               }
+               usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
+       }
+       return -ETIMEDOUT;
+ }
+ static int cdns_pcie_retrain(struct cdns_pcie *pcie)
+ {
+       u32 lnk_cap_sls, pcie_cap_off = CDNS_PCIE_RP_CAP_OFFSET;
+       u16 lnk_stat, lnk_ctl;
+       int ret = 0;
+       /*
+        * Set retrain bit if current speed is 2.5 GB/s,
+        * but the PCIe root port support is > 2.5 GB/s.
+        */
+       lnk_cap_sls = cdns_pcie_readl(pcie, (CDNS_PCIE_RP_BASE + pcie_cap_off +
+                                            PCI_EXP_LNKCAP));
+       if ((lnk_cap_sls & PCI_EXP_LNKCAP_SLS) <= PCI_EXP_LNKCAP_SLS_2_5GB)
+               return ret;
+       lnk_stat = cdns_pcie_rp_readw(pcie, pcie_cap_off + PCI_EXP_LNKSTA);
+       if ((lnk_stat & PCI_EXP_LNKSTA_CLS) == PCI_EXP_LNKSTA_CLS_2_5GB) {
+               lnk_ctl = cdns_pcie_rp_readw(pcie,
+                                            pcie_cap_off + PCI_EXP_LNKCTL);
+               lnk_ctl |= PCI_EXP_LNKCTL_RL;
+               cdns_pcie_rp_writew(pcie, pcie_cap_off + PCI_EXP_LNKCTL,
+                                   lnk_ctl);
+               ret = cdns_pcie_host_wait_for_link(pcie);
+       }
+       return ret;
+ }
+ static int cdns_pcie_host_start_link(struct cdns_pcie_rc *rc)
+ {
+       struct cdns_pcie *pcie = &rc->pcie;
+       int ret;
+       ret = cdns_pcie_host_wait_for_link(pcie);
+       /*
+        * Retrain link for Gen2 training defect
+        * if quirk flag is set.
+        */
+       if (!ret && rc->quirk_retrain_flag)
+               ret = cdns_pcie_retrain(pcie);
+       return ret;
+ }
  
  static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
  {
@@@ -321,10 -383,9 +383,10 @@@ static int cdns_pcie_host_map_dma_range
  
        resource_list_for_each_entry(entry, &bridge->dma_ranges) {
                err = cdns_pcie_host_bar_config(rc, entry);
 -              if (err)
 +              if (err) {
                        dev_err(dev, "Fail to configure IB using dma-ranges\n");
 -              return err;
 +                      return err;
 +              }
        }
  
        return 0;
@@@ -399,23 -460,6 +461,6 @@@ static int cdns_pcie_host_init(struct d
        return cdns_pcie_host_init_address_translation(rc);
  }
  
- static int cdns_pcie_host_wait_for_link(struct cdns_pcie *pcie)
- {
-       struct device *dev = pcie->dev;
-       int retries;
-       /* Check if the link is up or not */
-       for (retries = 0; retries < LINK_WAIT_MAX_RETRIES; retries++) {
-               if (cdns_pcie_link_up(pcie)) {
-                       dev_info(dev, "Link up\n");
-                       return 0;
-               }
-               usleep_range(LINK_WAIT_USLEEP_MIN, LINK_WAIT_USLEEP_MAX);
-       }
-       return -ETIMEDOUT;
- }
  int cdns_pcie_host_setup(struct cdns_pcie_rc *rc)
  {
        struct device *dev = rc->pcie.dev;
                return ret;
        }
  
-       ret = cdns_pcie_host_wait_for_link(pcie);
+       ret = cdns_pcie_host_start_link(rc);
        if (ret)
                dev_dbg(dev, "PCIe link never came up\n");