[Skiboot] [PATCH 6/9] npu2-hw-procedures: Add support for OpenCAPI PHY link training

Frederic Barrat fbarrat at linux.vnet.ibm.com
Fri Jan 12 00:39:50 AEDT 2018



Le 18/12/2017 à 08:07, Andrew Donnellan a écrit :
> Unlike NVLink, which uses the pci-virt framework to fake a PCI
> configuration space for NVLink devices, the OpenCAPI device model presents
> us with a real configuration space handled by the device over the OpenCAPI
> link.
> 
> As a result, we have to train the OpenCAPI link in skiboot before we do PCI
> probing, so that config space can be accessed, rather than having link
> training being triggered by the Linux driver.
> 
> Add some helper functions to wrap the existing NVLink PHY training sequence
> so we can easily run it within skiboot.
> 
> Additionally, we add OpenCAPI-specific lane settings, and a function to
> "bump" lanes that haven't trained properly (this process isn't documented
> in the workbook, but the hardware experts assure us that this improves link
> training reliability...)
> 
> Signed-off-by: Andrew Donnellan <andrew.donnellan at au1.ibm.com>
> ---

Reviewed-by: Frederic Barrat <fbarrat at linux.vnet.ibm.com>


>   hw/npu2-hw-procedures.c | 77 ++++++++++++++++++++++++++++++++++++++++++-
>   include/npu2-regs.h     |  6 +++-
>   include/npu2.h          |  3 ++-
>   3 files changed, 86 insertions(+)
> 
> diff --git a/hw/npu2-hw-procedures.c b/hw/npu2-hw-procedures.c
> index 8daadde..d1ede56 100644
> --- a/hw/npu2-hw-procedures.c
> +++ b/hw/npu2-hw-procedures.c
> @@ -60,6 +60,7 @@ struct npu2_phy_reg NPU2_PHY_TX_FIFO_INIT		= {0x105, 53, 1};
>   struct npu2_phy_reg NPU2_PHY_TX_RXCAL			= {0x103, 57, 1};
>   struct npu2_phy_reg NPU2_PHY_RX_INIT_DONE		= {0x0ca, 48, 1};
>   struct npu2_phy_reg NPU2_PHY_RX_PR_EDGE_TRACK_CNTL	= {0x092, 48, 2};
> +struct npu2_phy_reg NPU2_PHY_RX_PR_BUMP_SL_1UI		= {0x092, 57, 1};
>   struct npu2_phy_reg NPU2_PHY_RX_PR_FW_OFF		= {0x08a, 56, 1};
>   struct npu2_phy_reg NPU2_PHY_RX_PR_FW_INERTIA_AMT	= {0x08a, 57, 3};
>   struct npu2_phy_reg NPU2_PHY_RX_CFG_LTE_MC		= {0x000, 60, 4};
> @@ -68,6 +69,8 @@ struct npu2_phy_reg NPU2_PHY_RX_B_INTEG_COARSE_GAIN	= {0x026, 48, 4};
>   struct npu2_phy_reg NPU2_PHY_RX_E_INTEG_COARSE_GAIN	= {0x030, 48, 4};
> 
>   /* These registers are per-PHY, not per lane */
> +struct npu2_phy_reg NPU2_PHY_RX_SPEED_SELECT		= {0x262, 51, 2};
> +struct npu2_phy_reg NPU2_PHY_RX_AC_COUPLED		= {0x262, 53, 1};
>   struct npu2_phy_reg NPU2_PHY_TX_ZCAL_SWO_EN		= {0x3c9, 48, 1};
>   struct npu2_phy_reg NPU2_PHY_TX_ZCAL_REQ		= {0x3c1, 49, 1};
>   struct npu2_phy_reg NPU2_PHY_TX_ZCAL_DONE		= {0x3c1, 50, 1};
> @@ -365,6 +368,11 @@ static uint32_t phy_reset_complete(struct npu2_dev *ndev)
>   {
>   	int lane;
> 
> +	if (ndev->type == NPU2_DEV_TYPE_OPENCAPI) {
> +		phy_write(ndev, &NPU2_PHY_RX_AC_COUPLED, 1);
> +		phy_write(ndev, &NPU2_PHY_RX_SPEED_SELECT, 1);
> +	}
> +
>   	FOR_EACH_LANE(ndev, lane) {
>   		phy_write_lane(ndev, &NPU2_PHY_RX_LANE_ANA_PDWN, lane, 0);
>   		phy_write_lane(ndev, &NPU2_PHY_RX_LANE_DIG_PDWN, lane, 0);
> @@ -874,3 +882,72 @@ void npu2_dev_procedure_reset(struct npu2_dev *dev)
>   {
>   	npu2_clear_link_flag(dev, NPU2_DEV_DL_RESET);
>   }
> +
> +static uint32_t run_procedure(struct npu2_dev *dev, uint16_t procedure_number)
> +{
> +	struct procedure *proc;
> +	const char *name;
> +	uint32_t result;
> +
> +	assert(procedure_number <= ARRAY_SIZE(npu_procedures));
> +	proc = npu_procedures[procedure_number];
> +	assert(proc);
> +
> +	name = proc->name;
> +	NPU2DEVINF(dev, "Running procedure %s\n", name);
> +	dev->procedure_status = PROCEDURE_INPROGRESS;
> +	dev->procedure_number = procedure_number;
> +	dev->procedure_step = 0;
> +	dev->procedure_data = 0;
> +	dev->procedure_tb = mftb();
> +
> +	result = get_procedure_status(dev);
> +	while (!(result & PROCEDURE_COMPLETE)) {
> +		time_wait_ms(1);
> +		result = get_procedure_status(dev);
> +	}
> +	return result;
> +}
> +
> +void npu2_opencapi_bump_ui_lane(struct npu2_dev *dev)
> +{
> +	uint64_t reg;
> +	uint64_t status_xscom;
> +	int lane, bit = 7;
> +
> +	switch (dev->index) {
> +	case 2:
> +		status_xscom = OB0_ODL0_TRAINING_STATUS;
> +		break;
> +	case 3:
> +		status_xscom = OB0_ODL1_TRAINING_STATUS;
> +		break;
> +	case 4:
> +		status_xscom = OB3_ODL0_TRAINING_STATUS;
> +		break;
> +	case 5:
> +		status_xscom = OB3_ODL1_TRAINING_STATUS;
> +		break;
> +	default:
> +		assert(false);
> +	}
> +	xscom_read(dev->npu->chip_id, status_xscom, &reg);
> +	reg = GETFIELD(OB_ODL_TRAINING_STATUS_STS_RX_PATTERN_B, reg);
> +
> +	FOR_EACH_LANE(dev, lane) {
> +		if (reg & (1 << bit--))
> +			continue;
> +		prlog(PR_TRACE, "OCAPI: bumpui bumping lane %d\n", lane);
> +		for (int i = 0; i < 4; i++) {
> +			phy_write_lane(dev, &NPU2_PHY_RX_PR_BUMP_SL_1UI, lane, 1);
> +			phy_write_lane(dev, &NPU2_PHY_RX_PR_BUMP_SL_1UI, lane, 0);
> +		}
> +	}
> +}
> +
> +void npu2_opencapi_phy_setup(struct npu2_dev *dev)
> +{
> +	run_procedure(dev, 4); /* procedure_phy_reset */
> +	run_procedure(dev, 5); /* procedure_phy_tx_zcal */
> +	run_procedure(dev, 6); /* procedure_phy_rx_dccal */
> +}
> diff --git a/include/npu2-regs.h b/include/npu2-regs.h
> index b2812d5..77b1529 100644
> --- a/include/npu2-regs.h
> +++ b/include/npu2-regs.h
> @@ -566,4 +566,10 @@ void npu2_scom_write(uint64_t gcid, uint64_t scom_base,
>   #define    PU_IOE_PB_FP_CFG_FP1_FMR_DISABLE	PPC_BIT(52)
>   #define    PU_IOE_PB_FP_CFG_FP1_PRS_DISABLE	PPC_BIT(57)
> 
> +#define OB0_ODL0_TRAINING_STATUS		0x901082E
> +#define OB0_ODL1_TRAINING_STATUS		0x901082F
> +#define OB3_ODL0_TRAINING_STATUS		0xC01082E
> +#define OB3_ODL1_TRAINING_STATUS		0xC01082F
> +#define   OB_ODL_TRAINING_STATUS_STS_RX_PATTERN_B PPC_BITMASK(8, 15)
> +
>   #endif /* __NPU2_REGS_H */
> diff --git a/include/npu2.h b/include/npu2.h
> index b28f91b..1f46bca 100644
> --- a/include/npu2.h
> +++ b/include/npu2.h
> @@ -195,9 +195,12 @@ int64_t npu2_dev_procedure(void *dev, struct pci_cfg_reg_filter *pcrf,
>   			   uint32_t offset, uint32_t len, uint32_t *data,
>   			   bool write);
>   void npu2_dev_procedure_reset(struct npu2_dev *dev);
> +
>   void npu2_set_link_flag(struct npu2_dev *ndev, uint8_t flag);
>   void npu2_clear_link_flag(struct npu2_dev *ndev, uint8_t flag);
>   extern int nv_zcal_nominal;
>   bool is_p9dd1(void);
> +void npu2_opencapi_phy_setup(struct npu2_dev *dev);
> +void npu2_opencapi_bump_ui_lane(struct npu2_dev *dev);
> 
>   #endif /* __NPU2_H */
> 



More information about the Skiboot mailing list