PCI: aardvark: Fix reporting Data Link Layer Link Active

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: 8a3ebd8de3 ("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
This commit is contained in:
Pali Rohár 2021-10-05 20:09:52 +02:00 committed by Lorenzo Pieralisi
parent 661c399a65
commit 2b650b7ff2
1 changed files with 28 additions and 1 deletions

View 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: