PCI: aardvark: Fix checking for link up via LTSSM state
authorPali Rohár <pali@kernel.org>
Wed, 24 Nov 2021 22:49:28 +0000 (23:49 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 8 Dec 2021 07:46:51 +0000 (08:46 +0100)
commit 661c399a651c11aaf83c45cbfe0b4a1fb7bc3179 upstream.

Current implementation of advk_pcie_link_up() is wrong as it marks also
link disabled or hot reset states as link up.

Fix it by marking link up only to those states which are defined in PCIe
Base specification 3.0, Table 4-14: Link Status Mapped to the LTSSM.

To simplify implementation, Define macros for every LTSSM state which
aardvark hardware can return in CFG_REG register.

Fix also checking for link training according to the same Table 4-14.
Define a new function advk_pcie_link_training() for this purpose.

Link: https://lore.kernel.org/r/20211005180952.6812-13-kabel@kernel.org
Fixes: 8c39d710363c ("PCI: aardvark: Add Aardvark PCI host controller driver")
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
Cc: Remi Pommarel <repk@triplefau.lt>
Signed-off-by: Marek Behún <kabel@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/pci/host/pci-aardvark.c

index 7c3369726c876ed43f356953bc43a0135ed3e27c..9ae544e113dc269bc893013f65108b94ccecd188 100644 (file)
 #define CFG_REG                                        (LMI_BASE_ADDR + 0x0)
 #define     LTSSM_SHIFT                                24
 #define     LTSSM_MASK                         0x3f
-#define     LTSSM_L0                           0x10
 #define     RC_BAR_CONFIG                      0x300
 
+/* LTSSM values in CFG_REG */
+enum {
+       LTSSM_DETECT_QUIET                      = 0x0,
+       LTSSM_DETECT_ACTIVE                     = 0x1,
+       LTSSM_POLLING_ACTIVE                    = 0x2,
+       LTSSM_POLLING_COMPLIANCE                = 0x3,
+       LTSSM_POLLING_CONFIGURATION             = 0x4,
+       LTSSM_CONFIG_LINKWIDTH_START            = 0x5,
+       LTSSM_CONFIG_LINKWIDTH_ACCEPT           = 0x6,
+       LTSSM_CONFIG_LANENUM_ACCEPT             = 0x7,
+       LTSSM_CONFIG_LANENUM_WAIT               = 0x8,
+       LTSSM_CONFIG_COMPLETE                   = 0x9,
+       LTSSM_CONFIG_IDLE                       = 0xa,
+       LTSSM_RECOVERY_RCVR_LOCK                = 0xb,
+       LTSSM_RECOVERY_SPEED                    = 0xc,
+       LTSSM_RECOVERY_RCVR_CFG                 = 0xd,
+       LTSSM_RECOVERY_IDLE                     = 0xe,
+       LTSSM_L0                                = 0x10,
+       LTSSM_RX_L0S_ENTRY                      = 0x11,
+       LTSSM_RX_L0S_IDLE                       = 0x12,
+       LTSSM_RX_L0S_FTS                        = 0x13,
+       LTSSM_TX_L0S_ENTRY                      = 0x14,
+       LTSSM_TX_L0S_IDLE                       = 0x15,
+       LTSSM_TX_L0S_FTS                        = 0x16,
+       LTSSM_L1_ENTRY                          = 0x17,
+       LTSSM_L1_IDLE                           = 0x18,
+       LTSSM_L2_IDLE                           = 0x19,
+       LTSSM_L2_TRANSMIT_WAKE                  = 0x1a,
+       LTSSM_DISABLED                          = 0x20,
+       LTSSM_LOOPBACK_ENTRY_MASTER             = 0x21,
+       LTSSM_LOOPBACK_ACTIVE_MASTER            = 0x22,
+       LTSSM_LOOPBACK_EXIT_MASTER              = 0x23,
+       LTSSM_LOOPBACK_ENTRY_SLAVE              = 0x24,
+       LTSSM_LOOPBACK_ACTIVE_SLAVE             = 0x25,
+       LTSSM_LOOPBACK_EXIT_SLAVE               = 0x26,
+       LTSSM_HOT_RESET                         = 0x27,
+       LTSSM_RECOVERY_EQUALIZATION_PHASE0      = 0x28,
+       LTSSM_RECOVERY_EQUALIZATION_PHASE1      = 0x29,
+       LTSSM_RECOVERY_EQUALIZATION_PHASE2      = 0x2a,
+       LTSSM_RECOVERY_EQUALIZATION_PHASE3      = 0x2b,
+};
+
 /* PCIe core controller registers */
 #define CTRL_CORE_BASE_ADDR                    0x18000
 #define CTRL_CONFIG_REG                                (CTRL_CORE_BASE_ADDR + 0x0)
@@ -248,13 +289,35 @@ static inline u32 advk_readl(struct advk_pcie *pcie, u64 reg)
        return readl(pcie->base + reg);
 }
 
-static int advk_pcie_link_up(struct advk_pcie *pcie)
+static u8 advk_pcie_ltssm_state(struct advk_pcie *pcie)
 {
-       u32 val, ltssm_state;
+       u32 val;
+       u8 ltssm_state;
 
        val = advk_readl(pcie, CFG_REG);
        ltssm_state = (val >> LTSSM_SHIFT) & LTSSM_MASK;
-       return ltssm_state >= LTSSM_L0;
+       return ltssm_state;
+}
+
+static inline bool advk_pcie_link_up(struct advk_pcie *pcie)
+{
+       /* check if LTSSM is in normal operation - some L* state */
+       u8 ltssm_state = advk_pcie_ltssm_state(pcie);
+       return ltssm_state >= LTSSM_L0 && ltssm_state < LTSSM_DISABLED;
+}
+
+static inline bool advk_pcie_link_training(struct advk_pcie *pcie)
+{
+       /*
+         * According to PCIe Base specification 3.0, Table 4-14: Link
+         * Status Mapped to the LTSSM is Link Training mapped to LTSSM
+         * Configuration and Recovery states.
+         */
+       u8 ltssm_state = advk_pcie_ltssm_state(pcie);
+       return ((ltssm_state >= LTSSM_CONFIG_LINKWIDTH_START &&
+                 ltssm_state < LTSSM_L0) ||
+               (ltssm_state >= LTSSM_RECOVERY_EQUALIZATION_PHASE0 &&
+                 ltssm_state <= LTSSM_RECOVERY_EQUALIZATION_PHASE3));
 }
 
 static int advk_pcie_wait_for_link(struct advk_pcie *pcie)