aboutsummaryrefslogtreecommitdiff
path: root/hw/phb4.c
diff options
context:
space:
mode:
authorOliver O'Halloran <oohall@gmail.com>2019-05-30 13:20:56 +1000
committerStewart Smith <stewart@linux.ibm.com>2019-06-03 10:28:57 +1000
commit6c0a6612f4920438e19d68e0c7146a5ef5fec877 (patch)
tree4027af300fa30107c977545bc77b7bdd0dcc7bf7 /hw/phb4.c
parent4760818d7c78f9f9b6d6980ece336183cedb92d9 (diff)
downloadskiboot-6c0a6612f4920438e19d68e0c7146a5ef5fec877.zip
skiboot-6c0a6612f4920438e19d68e0c7146a5ef5fec877.tar.gz
skiboot-6c0a6612f4920438e19d68e0c7146a5ef5fec877.tar.bz2
hw/phb4: Make phb4_training_trace() more general
phb4_training_trace() is used to monitor the Link Training Status State Machine (LTSSM) of the PHB's data link layer. Currently it is only used to observe the LTSSM while bringing up the link, but sometimes it's useful to see what's occurring in other situations (e.g. link disable, or secondary bus reset). This patch renames it to phb4_link_trace() and allows the target LTSSM state and a flexible timeout to help in these situations. Signed-off-by: Oliver O'Halloran <oohall@gmail.com> Signed-off-by: Stewart Smith <stewart@linux.ibm.com>
Diffstat (limited to 'hw/phb4.c')
-rw-r--r--hw/phb4.c44
1 files changed, 25 insertions, 19 deletions
diff --git a/hw/phb4.c b/hw/phb4.c
index 0689563..9a38dc7 100644
--- a/hw/phb4.c
+++ b/hw/phb4.c
@@ -2337,12 +2337,13 @@ static int64_t phb4_retry_state(struct pci_slot *slot)
return pci_slot_set_sm_timeout(slot, msecs_to_tb(1));
}
-static void phb4_train_info(struct phb4 *p, uint64_t reg, unsigned long time)
+static uint64_t phb4_train_info(struct phb4 *p, uint64_t reg, unsigned long dt)
{
+ uint64_t ltssm_state = GETFIELD(PHB_PCIE_DLP_LTSSM_TRC, reg);
char s[80];
snprintf(s, sizeof(s), "TRACE:0x%016llx % 2lims",
- reg, tb_to_msecs(time));
+ reg, tb_to_msecs(dt));
if (reg & PHB_PCIE_DLP_TL_LINKACT)
snprintf(s, sizeof(s), "%s trained ", s);
@@ -2357,7 +2358,7 @@ static void phb4_train_info(struct phb4 *p, uint64_t reg, unsigned long time)
GETFIELD(PHB_PCIE_DLP_LINK_SPEED, reg),
GETFIELD(PHB_PCIE_DLP_LINK_WIDTH, reg));
- switch (GETFIELD(PHB_PCIE_DLP_LTSSM_TRC, reg)) {
+ switch (ltssm_state) {
case PHB_PCIE_DLP_LTSSM_RESET:
snprintf(s, sizeof(s), "%sreset", s);
break;
@@ -2395,6 +2396,8 @@ static void phb4_train_info(struct phb4 *p, uint64_t reg, unsigned long time)
snprintf(s, sizeof(s), "%sunvalid", s);
}
PHBNOTICE(p, "%s\n", s);
+
+ return ltssm_state;
}
static void phb4_dump_pec_err_regs(struct phb4 *p)
@@ -2656,10 +2659,10 @@ static bool phb4_link_optimal(struct pci_slot *slot, uint32_t *vdid)
* training. If any errors are detected it simply returns so the
* normal code can deal with it.
*/
-static void phb4_training_trace(struct phb4 *p)
+static void phb4_link_trace(struct phb4 *p, uint64_t target_state, int max_ms)
{
+ unsigned long now, end, start = mftb(), state = 0;
uint64_t trwctl, reg, reglast = -1;
- unsigned long now, start = mftb();
bool enabled;
/*
@@ -2673,28 +2676,31 @@ static void phb4_training_trace(struct phb4 *p)
trwctl | PHB_PCIE_DLP_TRWCTL_EN);
}
+ end = start + msecs_to_tb(max_ms);
+ now = start;
- while(1) {
- now = mftb();
+ do {
reg = in_be64(p->regs + PHB_PCIE_DLP_TRAIN_CTL);
if (reg != reglast)
- phb4_train_info(p, reg, now - start);
+ state = phb4_train_info(p, reg, now - start);
reglast = reg;
if (!phb4_check_reg(p, reg)) {
- PHBNOTICE(p, "TRACE: PHB fence waiting link.\n");
- break;
- }
- if (reg & PHB_PCIE_DLP_TL_LINKACT) {
- PHBNOTICE(p, "TRACE: Link trained.\n");
- break;
+ PHBNOTICE(p, "TRACE: PHB fenced.\n");
+ goto out;
}
- if ((now - start) > secs_to_tb(3)) {
- PHBNOTICE(p, "TRACE: Timeout waiting for link up.\n");
- break;
+
+ if (tb_compare(now, end) == TB_AAFTERB) {
+ PHBNOTICE(p, "TRACE: Timed out after %dms\n", max_ms);
+ goto out;
}
- }
+ now = mftb();
+ } while (state != target_state);
+
+ PHBNOTICE(p, "TRACE: Reached target state\n");
+
+out:
/*
* The trace enable bit is a clock gate for the tracing logic. Turn
* it off to save power if we're not using it otherwise.
@@ -3027,7 +3033,7 @@ static int64_t phb4_freset(struct pci_slot *slot)
phb4_assert_perst(slot, false);
if (pci_tracing)
- phb4_training_trace(p)
+ phb4_link_trace(p, PHB_PCIE_DLP_LTSSM_L0, 3000);
pci_slot_set_state(slot, PHB4_SLOT_LINK_START);
return slot->ops.poll_link(slot);