[Skiboot] [PATCH V2] Retry link training at PCIe GEN1 if presence detected but

Timothy Pearson tpearson at raptorengineering.com
Thu Dec 13 15:26:13 AEDT 2018


 training repeatedly failed

Certain older PCIe 1.0 devices will not train unless the training process starts at GEN1 speeds.
As a last resort when a device will not train, fall back to GEN1 speed for the last training attempt.

This is verified to fix devices based on the Conexant CX23888 on the Talos II platform.

Signed-off-by: Timothy Pearson <tpearson at raptorengineering.com>
---
 hw/phb4.c      | 63 ++++++++++++++++++++++++++++++++++++++------------
 include/phb4.h |  2 +-
 2 files changed, 49 insertions(+), 16 deletions(-)

diff --git a/hw/phb4.c b/hw/phb4.c
index 50e1be1c..1a07b772 100644
--- a/hw/phb4.c
+++ b/hw/phb4.c
@@ -1,4 +1,5 @@
 /* Copyright 2013-2016 IBM Corp.
+ * Copyright 2018 Raptor Engineering, LLC
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -2269,6 +2270,14 @@ static int64_t phb4_retry_state(struct pci_slot *slot)
 	/* Mark link as down */
 	phb4_prepare_link_change(slot, false);
 
+	/* Last attempt to activate link */
+	if (slot->link_retries == 1) {
+		if (slot->state == PHB4_SLOT_LINK_WAIT) {
+			PHBERR(p, "Falling back to GEN1 training\n");
+			p->max_link_speed = 1;
+		}
+	}
+
 	if (!slot->link_retries--) {
 		switch (slot->state) {
 		case PHB4_SLOT_LINK_WAIT_ELECTRICAL:
@@ -2715,6 +2724,41 @@ static int64_t phb4_poll_link(struct pci_slot *slot)
 	return OPAL_HARDWARE;
 }
 
+static unsigned int phb4_get_max_link_speed(struct phb4 *p, struct dt_node *np)
+{
+	unsigned int max_link_speed;
+	struct proc_chip *chip;
+	chip = get_chip(p->chip_id);
+
+	/* Priority order: NVRAM -> dt -> GEN2 dd1 -> GEN3 dd2.00 -> GEN4 */
+	max_link_speed = 4;
+	if (p->rev == PHB4_REV_NIMBUS_DD10)
+		max_link_speed = 2;
+	if (p->rev == PHB4_REV_NIMBUS_DD20 &&
+	    ((0xf & chip->ec_level) == 0) && chip->ec_rev == 0)
+		max_link_speed = 3;
+	if (np) {
+		if (dt_has_node_property(np, "ibm,max-link-speed", NULL)) {
+			max_link_speed = dt_prop_get_u32(np, "ibm,max-link-speed");
+			p->dt_max_link_speed = max_link_speed;
+		}
+		else {
+			p->dt_max_link_speed = 0;
+		}
+	}
+	else {
+		if (p->dt_max_link_speed > 0) {
+			max_link_speed = p->dt_max_link_speed;
+		}
+	}
+	if (pcie_max_link_speed)
+		max_link_speed = pcie_max_link_speed;
+	if (max_link_speed > 4) /* clamp to 4 */
+		max_link_speed = 4;
+
+	return max_link_speed;
+}
+
 static int64_t phb4_hreset(struct pci_slot *slot)
 {
 	struct phb4 *p = phb_to_phb4(slot->phb);
@@ -2783,6 +2827,9 @@ static int64_t phb4_freset(struct pci_slot *slot)
 	case PHB4_SLOT_NORMAL:
 		PHBDBG(p, "FRESET: Starts\n");
 
+		/* Reset max link speed for training */
+		p->max_link_speed = phb4_get_max_link_speed(p, NULL);
+
 		/* Nothing to do without adapter connected */
 		if (slot->ops.get_presence_state)
 			slot->ops.get_presence_state(slot, &presence);
@@ -5081,14 +5128,12 @@ static void phb4_create(struct dt_node *np)
 	char *path;
 	uint32_t irq_base, irq_flags;
 	int i;
-	struct proc_chip *chip;
 
 	assert(p);
 
 	/* Populate base stuff */
 	p->index = dt_prop_get_u32(np, "ibm,phb-index");
 	p->chip_id = dt_prop_get_u32(np, "ibm,chip-id");
-	chip = get_chip(p->chip_id);
 	p->regs = (void *)dt_get_address(np, 0, NULL);
 	p->int_mmio = (void *)dt_get_address(np, 1, NULL);
 	p->phb.dt_node = np;
@@ -5170,19 +5215,7 @@ static void phb4_create(struct dt_node *np)
 	if (!phb4_read_capabilities(p))
 		goto failed;
 
-	/* Priority order: NVRAM -> dt -> GEN2 dd1 -> GEN3 dd2.00 -> GEN4 */
-	p->max_link_speed = 4;
-	if (p->rev == PHB4_REV_NIMBUS_DD10)
-		p->max_link_speed = 2;
-	if (p->rev == PHB4_REV_NIMBUS_DD20 &&
-	    ((0xf & chip->ec_level) == 0) && chip->ec_rev == 0)
-		p->max_link_speed = 3;
-	if (dt_has_node_property(np, "ibm,max-link-speed", NULL))
-		p->max_link_speed = dt_prop_get_u32(np, "ibm,max-link-speed");
-	if (pcie_max_link_speed)
-		p->max_link_speed = pcie_max_link_speed;
-	if (p->max_link_speed > 4) /* clamp to 4 */
-		p->max_link_speed = 4;
+	p->max_link_speed = phb4_get_max_link_speed(p, np);
 	PHBINF(p, "Max link speed: GEN%i\n", p->max_link_speed);
 
 	/* Check for lane equalization values from HB or HDAT */
diff --git a/include/phb4.h b/include/phb4.h
index c04b594d..79bfa416 100644
--- a/include/phb4.h
+++ b/include/phb4.h
@@ -154,7 +154,7 @@ struct phb4_err {
 	uint32_t err_bit;
 };
 
-#define PHB4_LINK_LINK_RETRIES		3
+#define PHB4_LINK_LINK_RETRIES		4
 /* Link timeouts, increments of 10ms */
 #define PHB4_LINK_ELECTRICAL_RETRIES	100
 #define PHB4_LINK_WAIT_RETRIES		200
-- 
2.18.0



More information about the Skiboot mailing list