[Skiboot] [PATCH 2/3] npu2-opencapi: Detect if link trained in degraded mode
Andrew Donnellan
andrew.donnellan at au1.ibm.com
Mon Nov 26 11:02:37 AEDT 2018
On 23/11/18 7:54 pm, Frederic Barrat wrote:
> 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 at linux.ibm.com>
Reviewed-by: Andrew Donnellan <andrew.donnellan at au1.ibm.com>
> ---
> hw/npu2-opencapi.c | 50 ++++++++++++++++++++++++++++-----------------
> include/npu2-regs.h | 2 ++
> 2 files changed, 33 insertions(+), 19 deletions(-)
>
> diff --git a/hw/npu2-opencapi.c b/hw/npu2-opencapi.c
> index c771fae8..da86b46c 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));
> }
> diff --git a/include/npu2-regs.h b/include/npu2-regs.h
> index 165e0b79..c5096dd1 100644
> --- a/include/npu2-regs.h
> +++ b/include/npu2-regs.h
> @@ -741,6 +741,8 @@ void npu2_scom_write(uint64_t gcid, uint64_t scom_base,
> #define OB3_ODL0_STATUS 0xC01082C
> #define OB3_ODL1_STATUS 0xC01082D
> #define OB_ODL_STATUS_TRAINED_MODE PPC_BITMASK(0,3)
> +#define OB_ODL_STATUS_RX_TRAINED_LANES PPC_BITMASK(16, 23)
> +#define OB_ODL_STATUS_TX_TRAINED_LANES PPC_BITMASK(24, 31)
> #define OB_ODL_STATUS_TRAINING_STATE_MACHINE PPC_BITMASK(49, 51)
>
> #define OB0_ODL0_TRAINING_STATUS 0x901082E
>
--
Andrew Donnellan OzLabs, ADL Canberra
andrew.donnellan at au1.ibm.com IBM Australia Limited
More information about the Skiboot
mailing list