PCI: aardvark: Fix reporting Data Link Layer Link Active
authorPali Rohár <pali@kernel.org>
Tue, 5 Oct 2021 18:09:52 +0000 (20:09 +0200)
committerLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Thu, 7 Oct 2021 13:27:59 +0000 (14:27 +0100)
Add support for reporting PCI_EXP_LNKSTA_DLLLA bit in Link Control register
on emulated bridge via current LTSSM state. Also correctly indicate DLLLA
capability via PCI_EXP_LNKCAP_DLLLARC bit in Link Control Capability
register.

Link: https://lore.kernel.org/r/20211005180952.6812-14-kabel@kernel.org
Fixes: 8a3ebd8de328 ("PCI: aardvark: Implement emulated root PCI bridge config space")
Signed-off-by: Pali Rohár <pali@kernel.org>
Signed-off-by: Marek Behún <kabel@kernel.org>
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: Marek Behún <kabel@kernel.org>
Cc: stable@vger.kernel.org
drivers/pci/controller/pci-aardvark.c

index f831f7d..10476c0 100644 (file)
@@ -317,6 +317,20 @@ static inline bool advk_pcie_link_up(struct advk_pcie *pcie)
        return ltssm_state >= LTSSM_L0 && ltssm_state < LTSSM_DISABLED;
 }
 
+static inline bool advk_pcie_link_active(struct advk_pcie *pcie)
+{
+       /*
+        * According to PCIe Base specification 3.0, Table 4-14: Link
+        * Status Mapped to the LTSSM, and 4.2.6.3.6 Configuration.Idle
+        * is Link Up mapped to LTSSM Configuration.Idle, Recovery, L0,
+        * L0s, L1 and L2 states. And according to 3.2.1. Data Link
+        * Control and Management State Machine Rules is DL Up status
+        * reported in DL Active state.
+        */
+       u8 ltssm_state = advk_pcie_ltssm_state(pcie);
+       return ltssm_state >= LTSSM_CONFIG_IDLE && ltssm_state < LTSSM_DISABLED;
+}
+
 static inline bool advk_pcie_link_training(struct advk_pcie *pcie)
 {
        /*
@@ -766,12 +780,26 @@ advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
                return PCI_BRIDGE_EMUL_HANDLED;
        }
 
+       case PCI_EXP_LNKCAP: {
+               u32 val = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg);
+               /*
+                * PCI_EXP_LNKCAP_DLLLARC bit is hardwired in aardvark HW to 0.
+                * But support for PCI_EXP_LNKSTA_DLLLA is emulated via ltssm
+                * state so explicitly enable PCI_EXP_LNKCAP_DLLLARC flag.
+                */
+               val |= PCI_EXP_LNKCAP_DLLLARC;
+               *value = val;
+               return PCI_BRIDGE_EMUL_HANDLED;
+       }
+
        case PCI_EXP_LNKCTL: {
                /* u32 contains both PCI_EXP_LNKCTL and PCI_EXP_LNKSTA */
                u32 val = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg) &
                        ~(PCI_EXP_LNKSTA_LT << 16);
                if (advk_pcie_link_training(pcie))
                        val |= (PCI_EXP_LNKSTA_LT << 16);
+               if (advk_pcie_link_active(pcie))
+                       val |= (PCI_EXP_LNKSTA_DLLLA << 16);
                *value = val;
                return PCI_BRIDGE_EMUL_HANDLED;
        }
@@ -779,7 +807,6 @@ advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
        case PCI_CAP_LIST_ID:
        case PCI_EXP_DEVCAP:
        case PCI_EXP_DEVCTL:
-       case PCI_EXP_LNKCAP:
                *value = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg);
                return PCI_BRIDGE_EMUL_HANDLED;
        default: