aboutsummaryrefslogtreecommitdiff
path: root/hw/npu2-opencapi.c
diff options
context:
space:
mode:
authorFrederic Barrat <fbarrat@linux.ibm.com>2018-11-23 09:54:38 +0100
committerStewart Smith <stewart@linux.ibm.com>2018-11-28 17:51:58 +1100
commit64d06b1feed160c42d447750b6c5c0601d15487c (patch)
tree41ca95a1a7cf2a5d4cfdb8205372f9f3d647fd2f /hw/npu2-opencapi.c
parentff376805bde5293a034616c75cd572d44ac28de0 (diff)
downloadskiboot-64d06b1feed160c42d447750b6c5c0601d15487c.zip
skiboot-64d06b1feed160c42d447750b6c5c0601d15487c.tar.gz
skiboot-64d06b1feed160c42d447750b6c5c0601d15487c.tar.bz2
npu2-opencapi: Detect if link trained in degraded mode
There's no status readily available to tell the effective link width. Instead, we have to look at the individual status of each lane, on the transmit and receive direction. All relevant information is in the ODL status register. Signed-off-by: Frederic Barrat <fbarrat@linux.ibm.com> Reviewed-by: Andrew Donnellan <andrew.donnellan@au1.ibm.com> Signed-off-by: Stewart Smith <stewart@linux.ibm.com>
Diffstat (limited to 'hw/npu2-opencapi.c')
-rw-r--r--hw/npu2-opencapi.c50
1 files changed, 31 insertions, 19 deletions
diff --git a/hw/npu2-opencapi.c b/hw/npu2-opencapi.c
index c771fae..da86b46 100644
--- a/hw/npu2-opencapi.c
+++ b/hw/npu2-opencapi.c
@@ -1013,32 +1013,43 @@ static int64_t npu2_opencapi_get_presence_state(struct pci_slot __unused *slot,
return OPAL_SUCCESS;
}
+static enum OpalShpcLinkState get_link_width(uint64_t odl_status)
+{
+ uint64_t tx_lanes, rx_lanes, state;
+
+ /*
+ * On P9, the 'trained mode' field of the ODL status is
+ * hard-coded to x8 and is useless for us. We need to look at
+ * the status of the individual lanes.
+ * The link trains at x8, x4 or not at all.
+ */
+ state = GETFIELD(OB_ODL_STATUS_TRAINING_STATE_MACHINE, odl_status);
+ if (state != OCAPI_LINK_STATE_TRAINED)
+ return OPAL_SHPC_LINK_DOWN;
+
+ rx_lanes = GETFIELD(OB_ODL_STATUS_RX_TRAINED_LANES, odl_status);
+ tx_lanes = GETFIELD(OB_ODL_STATUS_TX_TRAINED_LANES, odl_status);
+ if ((rx_lanes != 0xFF) || (tx_lanes != 0xFF))
+ return OPAL_SHPC_LINK_UP_x4;
+ else
+ return OPAL_SHPC_LINK_UP_x8;
+}
+
static int64_t npu2_opencapi_get_link_state(struct pci_slot *slot, uint8_t *val)
{
struct npu2_dev *dev = phb_to_npu2_dev_ocapi(slot->phb);
uint64_t reg;
- int64_t link_width, training_status, rc = OPAL_SUCCESS;
reg = get_odl_status(dev->npu->chip_id, dev->brick_index);
- link_width = GETFIELD(OB_ODL_STATUS_TRAINED_MODE, reg);
- training_status = GETFIELD(OB_ODL_STATUS_TRAINING_STATE_MACHINE, reg);
-
- if (training_status != OCAPI_LINK_STATE_TRAINED) {
- *val = OPAL_SHPC_LINK_DOWN;
- return OPAL_SUCCESS;
- }
+ *val = get_link_width(reg);
+ return OPAL_SUCCESS;
+}
- switch (link_width) {
- case 0b0001:
- *val = OPAL_SHPC_LINK_UP_x4;
- break;
- case 0b0010:
- *val = OPAL_SHPC_LINK_UP_x8;
- break;
- default:
- rc = OPAL_HARDWARE;
- }
- return rc;
+static void check_trained_link(struct npu2_dev *dev, uint64_t odl_status)
+{
+ if (get_link_width(odl_status) != OPAL_SHPC_LINK_UP_x8)
+ OCAPIERR(dev, "Link trained in degraded mode (%016llx)\n",
+ odl_status);
}
static int64_t npu2_opencapi_retry_state(struct pci_slot *slot,
@@ -1089,6 +1100,7 @@ static int64_t npu2_opencapi_poll_link(struct pci_slot *slot)
OCAPI_LINK_STATE_TRAINED) {
OCAPIINF(dev, "link trained in %lld ms\n",
OCAPI_LINK_TRAINING_TIMEOUT - slot->retries);
+ check_trained_link(dev, reg);
pci_slot_set_state(slot, OCAPI_SLOT_LINK_TRAINED);
return pci_slot_set_sm_timeout(slot, msecs_to_tb(1));
}