Skip to content

Commit 364b3f1

Browse files
repkLorenzo Pieralisi
authored andcommitted
PCI: aardvark: Use LTSSM state to build link training flag
Aardvark's PCI_EXP_LNKSTA_LT flag in its link status register is not implemented and does not reflect the actual link training state (the flag is always set to 0). In order to support link re-training feature this flag has to be emulated. The Link Training and Status State Machine (LTSSM) flag in Aardvark LMI config register could be used as a link training indicator. Indeed if the LTSSM is in L0 or upper state then link training has completed (see [1]). Unfortunately because after asking a link retraining it takes a while for the LTSSM state to become less than 0x10 (due to L0s to recovery state transition delays), LTSSM can still be in L0 while link training has not finished yet. So this waits for link to be in recovery or lesser state before returning after asking for a link retrain. [1] "PCI Express Base Specification", REV. 4.0 PCI Express, February 19 2014, Table 4-14 Fixes: 8a3ebd8 ("PCI: aardvark: Implement emulated root PCI bridge config space") Tested-by: Marc Zyngier <[email protected]> Signed-off-by: Remi Pommarel <[email protected]> Signed-off-by: Lorenzo Pieralisi <[email protected]> Reviewed-by: Andrew Murray <[email protected]> Acked-by: Thomas Petazzoni <[email protected]>
1 parent 54ecb8f commit 364b3f1

File tree

1 file changed

+28
-1
lines changed

1 file changed

+28
-1
lines changed

drivers/pci/controller/pci-aardvark.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@
180180
#define LINK_WAIT_MAX_RETRIES 10
181181
#define LINK_WAIT_USLEEP_MIN 90000
182182
#define LINK_WAIT_USLEEP_MAX 100000
183+
#define RETRAIN_WAIT_MAX_RETRIES 10
184+
#define RETRAIN_WAIT_USLEEP_US 2000
183185

184186
#define MSI_IRQ_NUM 32
185187

@@ -239,6 +241,17 @@ static int advk_pcie_wait_for_link(struct advk_pcie *pcie)
239241
return -ETIMEDOUT;
240242
}
241243

244+
static void advk_pcie_wait_for_retrain(struct advk_pcie *pcie)
245+
{
246+
size_t retries;
247+
248+
for (retries = 0; retries < RETRAIN_WAIT_MAX_RETRIES; ++retries) {
249+
if (!advk_pcie_link_up(pcie))
250+
break;
251+
udelay(RETRAIN_WAIT_USLEEP_US);
252+
}
253+
}
254+
242255
static void advk_pcie_setup_hw(struct advk_pcie *pcie)
243256
{
244257
u32 reg;
@@ -426,11 +439,20 @@ advk_pci_bridge_emul_pcie_conf_read(struct pci_bridge_emul *bridge,
426439
return PCI_BRIDGE_EMUL_HANDLED;
427440
}
428441

442+
case PCI_EXP_LNKCTL: {
443+
/* u32 contains both PCI_EXP_LNKCTL and PCI_EXP_LNKSTA */
444+
u32 val = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg) &
445+
~(PCI_EXP_LNKSTA_LT << 16);
446+
if (!advk_pcie_link_up(pcie))
447+
val |= (PCI_EXP_LNKSTA_LT << 16);
448+
*value = val;
449+
return PCI_BRIDGE_EMUL_HANDLED;
450+
}
451+
429452
case PCI_CAP_LIST_ID:
430453
case PCI_EXP_DEVCAP:
431454
case PCI_EXP_DEVCTL:
432455
case PCI_EXP_LNKCAP:
433-
case PCI_EXP_LNKCTL:
434456
*value = advk_readl(pcie, PCIE_CORE_PCIEXP_CAP + reg);
435457
return PCI_BRIDGE_EMUL_HANDLED;
436458
default:
@@ -447,8 +469,13 @@ advk_pci_bridge_emul_pcie_conf_write(struct pci_bridge_emul *bridge,
447469

448470
switch (reg) {
449471
case PCI_EXP_DEVCTL:
472+
advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg);
473+
break;
474+
450475
case PCI_EXP_LNKCTL:
451476
advk_writel(pcie, new, PCIE_CORE_PCIEXP_CAP + reg);
477+
if (new & PCI_EXP_LNKCTL_RL)
478+
advk_pcie_wait_for_retrain(pcie);
452479
break;
453480

454481
case PCI_EXP_RTCTL:

0 commit comments

Comments
 (0)