[Skiboot] [PATCH v5] hw/npu2-opencapi: Add initial support for allocating OpenCAPI LPC memory

Frederic Barrat fbarrat at linux.ibm.com
Tue May 14 17:44:31 AEST 2019



Le 14/05/2019 à 03:10, Andrew Donnellan a écrit :
> Lowest Point of Coherency (LPC) memory allows the host to access memory on
> an OpenCAPI device.
> 
> Define 2 OPAL calls, OPAL_NPU_MEM_ALLOC and OPAL_NPU_MEM_RELEASE, for
> assigning and clearing the memory BAR. (We try to avoid using the term
> "LPC" to avoid confusion with Low Pin Count.)
> 
> At present, we use a fixed location in the address space, which means we
> are restricted to a single range of 4TB, on a single OpenCAPI device per
> chip. In future, we'll use some chip ID extension magic to give us more
> space, and some sort of allocator to assign ranges to more than one device.
> 
> Signed-off-by: Andrew Donnellan <ajd at linux.ibm.com>
> 
> ---


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


> 
> This code is currently being used for some internal testing of LPC memory
> devices and seems to work acceptably for that purpose. We haven't tested
> all the corner cases... this is really just intended to enable prototyping
> and bringup at this stage.
> 
> v1->v2:
> - Comments from Fred
> - Simplify BAR release
> - Make the BAR maths more sensible
> - Use OCAPI log macro
> 
> v2->v3:
> - Add documentation
> - got rid of a spurious TODO
> 
> v3->v4:
> - Add locking (Fred)
> 
> v4->v5:
> - Fix return code (Fred)
> ---
>   ...pal-npu2-opencapi-159-160-161-171-172.rst} |  77 ++++++++
>   hw/npu2-opencapi.c                            | 181 ++++++++++++++++++
>   hw/phys-map.c                                 |  11 ++
>   include/npu2-regs.h                           |   7 +
>   include/npu2.h                                |  11 +-
>   include/opal-api.h                            |   4 +-
>   include/phys-map.h                            |   1 +
>   7 files changed, 288 insertions(+), 4 deletions(-)
>   rename doc/opal-api/{opal-npu2-opencapi-159-160-161.rst => opal-npu2-opencapi-159-160-161-171-172.rst} (64%)
> 
> diff --git a/doc/opal-api/opal-npu2-opencapi-159-160-161.rst b/doc/opal-api/opal-npu2-opencapi-159-160-161-171-172.rst
> similarity index 64%
> rename from doc/opal-api/opal-npu2-opencapi-159-160-161.rst
> rename to doc/opal-api/opal-npu2-opencapi-159-160-161-171-172.rst
> index 4db3d3e8961e..6d603f173a4b 100644
> --- a/doc/opal-api/opal-npu2-opencapi-159-160-161.rst
> +++ b/doc/opal-api/opal-npu2-opencapi-159-160-161-171-172.rst
> @@ -124,3 +124,80 @@ OPAL_SUCCESS
>   
>   OPAL_PARAMETER
>      A provided parameter was invalid
> +
> + .. _OPAL_NPU_MEM_ALLOC:
> +
> +OPAL_NPU_MEM_ALLOC
> +==================
> +
> +OpenCAPI devices only.
> +
> +Sets up the NPU memory BAR for Lowest Point of Coherency (LPC) memory.
> +
> +At present, only one device per CPU can use LPC memory, and a maximum of 4TB
> +can be allocated.
> +
> +Parameters
> +----------
> +::
> +
> +   uint64_t phb_id
> +   uint32_t bdfn
> +   uint64_t size
> +   uint64_t *bar
> +
> +``phb_id``
> +   OPAL ID of PHB
> +
> +``bdfn``
> +   Bus-Device-Function number of OpenCAPI AFU
> +
> +``size``
> +   Size of requested LPC memory area in bytes
> +
> +``bar``
> +   Pointer to variable where base of LPC memory area will be returned
> +
> +Return Values
> +-------------
> +
> +OPAL_SUCCESS
> +   BAR setup completed successfully
> +
> +OPAL_PARAMETER
> +   A provided parameter was invalid
> +
> +OPAL_RESOURCE
> +   The BAR could not be assigned due to limitations
> +
> +.. _OPAL_NPU_MEM_RELEASE:
> +
> +OPAL_NPU_MEM_RELEASE
> +====================
> +
> +OpenCAPI devices only.
> +
> +Releases NPU memory BAR.
> +
> +Parameters
> +----------
> +::
> +
> +   uint64_t phb_id
> +   uint32_t bdfn
> +
> +``phb_id``
> +   OPAL ID of PHB
> +
> +``bdfn``
> +   Bus-Device-Function number of OpenCAPI AFU
> +
> +Return Values
> +-------------
> +
> +OPAL_SUCCESS
> +   BAR setup completed successfully
> +
> +OPAL_PARAMETER
> +   A provided parameter was invalid, or the specified device does not currently
> +   have LPC memory assigned
> diff --git a/hw/npu2-opencapi.c b/hw/npu2-opencapi.c
> index 9df51b22eda5..fb87b6ca3c71 100644
> --- a/hw/npu2-opencapi.c
> +++ b/hw/npu2-opencapi.c
> @@ -2025,3 +2025,184 @@ static int64_t opal_npu_tl_set(uint64_t phb_id, uint32_t __unused bdfn,
>   	return OPAL_SUCCESS;
>   }
>   opal_call(OPAL_NPU_TL_SET, opal_npu_tl_set, 5);
> +
> +static void set_mem_bar(struct npu2_dev *dev, uint64_t base, uint64_t size)
> +{
> +	uint64_t stack, val, reg, bar_offset, pa_config_offset;
> +	uint8_t memsel;
> +
> +	stack = index_to_stack(dev->brick_index);
> +	switch (dev->brick_index) {
> +	case 2:
> +	case 4:
> +		bar_offset = NPU2_GPU0_MEM_BAR;
> +		pa_config_offset = NPU2_CQ_CTL_MISC_PA0_CONFIG;
> +		break;
> +	case 3:
> +	case 5:
> +		bar_offset = NPU2_GPU1_MEM_BAR;
> +		pa_config_offset = NPU2_CQ_CTL_MISC_PA1_CONFIG;
> +		break;
> +	default:
> +		assert(false);
> +	}
> +
> +	assert((!size && !base) || (size && base));
> +
> +	/*
> +	 * Memory select configuration:
> +	 * - 0b000 - BAR disabled
> +	 * - 0b001 - match 0b00, 0b01
> +	 * - 0b010 - match 0b01, 0b10
> +	 * - 0b011 - match 0b00, 0b10
> +	 * - 0b100 - match 0b00
> +	 * - 0b101 - match 0b01
> +	 * - 0b110 - match 0b10
> +	 * - 0b111 - match 0b00, 0b01, 0b10
> +	 */
> +	memsel = GETFIELD(PPC_BITMASK(13, 14), base);
> +	if (size)
> +		val = SETFIELD(NPU2_MEM_BAR_EN | NPU2_MEM_BAR_SEL_MEM, 0ULL, 0b100 + memsel);
> +	else
> +		val = 0;
> +
> +	/* Base address - 12 bits, 1G aligned */
> +	val = SETFIELD(NPU2_MEM_BAR_NODE_ADDR, val, GETFIELD(PPC_BITMASK(22, 33), base));
> +
> +	/* GCID */
> +	val = SETFIELD(NPU2_MEM_BAR_GROUP, val, GETFIELD(PPC_BITMASK(15, 18), base));
> +	val = SETFIELD(NPU2_MEM_BAR_CHIP, val, GETFIELD(PPC_BITMASK(19, 21), base));
> +
> +	/* Other settings */
> +	val = SETFIELD(NPU2_MEM_BAR_POISON, val, 1);
> +	val = SETFIELD(NPU2_MEM_BAR_GRANULE, val, 0);
> +	val = SETFIELD(NPU2_MEM_BAR_BAR_SIZE, val, ilog2(size >> 30));
> +	val = SETFIELD(NPU2_MEM_BAR_MODE, val, 0);
> +
> +	for (int block = NPU2_BLOCK_SM_0; block <= NPU2_BLOCK_SM_3; block++) {
> +		reg = NPU2_REG_OFFSET(stack, block, bar_offset);
> +		npu2_write(dev->npu, reg, val);
> +	}
> +
> +	/* Set PA config */
> +	if (size)
> +		val = SETFIELD(NPU2_CQ_CTL_MISC_PA_CONFIG_MEMSELMATCH, 0ULL, 0b100 + memsel);
> +	else
> +		val = 0;
> +	val = SETFIELD(NPU2_CQ_CTL_MISC_PA_CONFIG_GRANULE, val, 0);
> +	val = SETFIELD(NPU2_CQ_CTL_MISC_PA_CONFIG_SIZE, val, ilog2(size >> 30));
> +	val = SETFIELD(NPU2_CQ_CTL_MISC_PA_CONFIG_MODE, val, 0);
> +	val = SETFIELD(NPU2_CQ_CTL_MISC_PA_CONFIG_MASK, val, 0);
> +	reg = NPU2_REG_OFFSET(stack, NPU2_BLOCK_CTL, pa_config_offset);
> +	npu2_write(dev->npu, reg, val);
> +}
> +
> +static int64_t alloc_mem_bar(struct npu2_dev *dev, uint64_t size, uint64_t *bar)
> +{
> +	uint64_t phys_map_base, phys_map_size;
> +	int rc = OPAL_SUCCESS;
> +
> +	lock(&dev->npu->lock);
> +
> +	/*
> +	 * Right now, we support 1 allocation per chip, of up to 4TB.
> +	 *
> +	 * In future, we will use chip address extension to support
> +	 * >4TB ranges, and we will implement a more sophisticated
> +	 * allocator to allow an allocation for every link on a chip.
> +	 */
> +
> +	if (dev->npu->lpc_mem_allocated) {
> +		rc = OPAL_RESOURCE;
> +		goto out;
> +	}
> +
> +	phys_map_get(dev->npu->chip_id, OCAPI_MEM, 0, &phys_map_base, &phys_map_size);
> +
> +	if (size > phys_map_size) {
> +		/**
> +		 * @fwts-label OCAPIInvalidLPCMemoryBARSize
> +		 * @fwts-advice The operating system requested an unsupported
> +		 * amount of OpenCAPI LPC memory. This is possibly a kernel
> +		 * bug, or you may need to upgrade your firmware.
> +		 */
> +		OCAPIERR(dev, "Invalid LPC memory BAR allocation size requested: 0x%llx bytes (limit 0x%llx)\n",
> +			 size, phys_map_size);
> +		rc = OPAL_PARAMETER;
> +		goto out;
> +	}
> +
> +	/* Minimum BAR size is 1 GB */
> +	if (size < (1 << 30)) {
> +		size = 1 << 30;
> +	}
> +
> +	if (!is_pow2(size)) {
> +		size = 1 << (ilog2(size) + 1);
> +	}
> +
> +	set_mem_bar(dev, phys_map_base, size);
> +	*bar = phys_map_base;
> +	dev->npu->lpc_mem_allocated = dev;
> +
> +out:
> +	unlock(&dev->npu->lock);
> +	return rc;
> +}
> +
> +static int64_t release_mem_bar(struct npu2_dev *dev)
> +{
> +	int rc = OPAL_SUCCESS;
> +
> +	lock(&dev->npu->lock);
> +
> +	if (dev->npu->lpc_mem_allocated != dev) {
> +		rc = OPAL_PARAMETER;
> +		goto out;
> +	}
> +
> +	set_mem_bar(dev, 0, 0);
> +	dev->npu->lpc_mem_allocated = NULL;
> +
> +out:
> +	unlock(&dev->npu->lock);
> +	return rc;
> +}
> +
> +static int64_t opal_npu_mem_alloc(uint64_t phb_id, uint32_t __unused bdfn,
> +				  uint64_t size, uint64_t *bar)
> +{
> +	struct phb *phb = pci_get_phb(phb_id);
> +	struct npu2_dev *dev;
> +
> +
> +	if (!phb || phb->phb_type != phb_type_npu_v2_opencapi)
> +		return OPAL_PARAMETER;
> +
> +	dev = phb_to_npu2_dev_ocapi(phb);
> +	if (!dev)
> +		return OPAL_PARAMETER;
> +
> +	if (!opal_addr_valid(bar))
> +		return OPAL_PARAMETER;
> +
> +	return alloc_mem_bar(dev, size, bar);
> +}
> +opal_call(OPAL_NPU_MEM_ALLOC, opal_npu_mem_alloc, 4);
> +
> +static int64_t opal_npu_mem_release(uint64_t phb_id, uint32_t __unused bdfn)
> +{
> +	struct phb *phb = pci_get_phb(phb_id);
> +	struct npu2_dev *dev;
> +
> +
> +	if (!phb || phb->phb_type != phb_type_npu_v2_opencapi)
> +		return OPAL_PARAMETER;
> +
> +	dev = phb_to_npu2_dev_ocapi(phb);
> +	if (!dev)
> +		return OPAL_PARAMETER;
> +
> +	return release_mem_bar(dev);
> +}
> +opal_call(OPAL_NPU_MEM_RELEASE, opal_npu_mem_release, 2);
> diff --git a/hw/phys-map.c b/hw/phys-map.c
> index fe949e4043ff..75836297c2f9 100644
> --- a/hw/phys-map.c
> +++ b/hw/phys-map.c
> @@ -52,6 +52,17 @@ static const struct phys_map_entry phys_map_table_nimbus[] = {
>   	{ GPU_MEM_4T_UP,   2, 0x0000044000000000ull, 0x0000002000000000ull },
>   	{ GPU_MEM_4T_UP,   3, 0x0000046000000000ull, 0x0000002000000000ull },
>   
> +	/*
> +	 * OpenCAPI LPC Memory - single 4TB range per chip, fills
> +	 * whole second non-mirrored region.
> +	 *
> +	 * Longer term, we're going to use chip address extension to
> +	 * enable >4TB to be allocated per chip.  At that point, we
> +	 * may have to find another way of assigning these ranges
> +	 * outside of phys-map.
> +	 */
> +	{ OCAPI_MEM,	   0, 0x0002000000000000ull, 0x0000040000000000ull },
> +
>   	/* 0 TB offset @ MMIO 0x0006000000000000ull */
>   	{ PHB4_64BIT_MMIO, 0, 0x0006000000000000ull, 0x0000004000000000ull },
>   	{ PHB4_64BIT_MMIO, 1, 0x0006004000000000ull, 0x0000004000000000ull },
> diff --git a/include/npu2-regs.h b/include/npu2-regs.h
> index 61e8ea8615f8..3cb587adc354 100644
> --- a/include/npu2-regs.h
> +++ b/include/npu2-regs.h
> @@ -239,6 +239,13 @@ void npu2_scom_write(uint64_t gcid, uint64_t scom_base,
>   #define NPU2_CQ_CTL_STATUS			0x090
>   #define   NPU2_CQ_CTL_STATUS_BRK0_AM_FENCED	PPC_BITMASK(48, 49)
>   #define   NPU2_CQ_CTL_STATUS_BRK1_AM_FENCED	PPC_BITMASK(50, 51)
> +#define NPU2_CQ_CTL_MISC_PA0_CONFIG		0x0A0 /* or should that be CS */
> +#define NPU2_CQ_CTL_MISC_PA1_CONFIG		0x0A8 /* or should that be CS */
> +#define   NPU2_CQ_CTL_MISC_PA_CONFIG_MEMSELMATCH PPC_BITMASK(0,2)
> +#define   NPU2_CQ_CTL_MISC_PA_CONFIG_GRANULE	PPC_BIT(3)
> +#define   NPU2_CQ_CTL_MISC_PA_CONFIG_SIZE	PPC_BITMASK(4,7)
> +#define   NPU2_CQ_CTL_MISC_PA_CONFIG_MODE	PPC_BITMASK(8,11)
> +#define   NPU2_CQ_CTL_MISC_PA_CONFIG_MASK	PPC_BITMASK(13,19)
>   #define NPU2_CQ_C_ERR_RPT_MSG0			0x0C0
>   #define NPU2_CQ_C_ERR_RPT_MSG1			0x0C8
>   #define NPU2_CQ_C_ERR_RPT_FIRST0		0x0D0
> diff --git a/include/npu2.h b/include/npu2.h
> index d58aab47bb30..5b2a436bda06 100644
> --- a/include/npu2.h
> +++ b/include/npu2.h
> @@ -180,8 +180,10 @@ struct npu2 {
>   	uint64_t	tve_cache[16];
>   	bool		tx_zcal_complete[2];
>   
> -	/* Used to protect global MMIO space, in particular the XTS
> -	 * tables. */
> +	/*
> +	 * Used to protect global MMIO space, in particular the XTS
> +	 * tables, and LPC allocation
> +	 */
>   	struct lock	lock;
>   
>   	/* NVLink */
> @@ -193,6 +195,11 @@ struct npu2 {
>   	struct lock	i2c_lock;
>   	uint8_t		i2c_pin_mode;
>   	uint8_t		i2c_pin_wr_state;
> +	/*
> +	 * Which device currently has an LPC allocation.
> +	 * Temporary as long as we only support 1 LPC alloc per chip.
> +	 */
> +	struct npu2_dev	*lpc_mem_allocated;
>   };
>   
>   static inline struct npu2 *phb_to_npu2_nvlink(struct phb *phb)
> diff --git a/include/opal-api.h b/include/opal-api.h
> index e461c9d278c2..b0ad435539fb 100644
> --- a/include/opal-api.h
> +++ b/include/opal-api.h
> @@ -227,8 +227,8 @@
>   #define OPAL_NPU_SET_RELAXED_ORDER		168
>   #define OPAL_NPU_GET_RELAXED_ORDER		169
>   #define OPAL_XIVE_GET_VP_STATE			170 /* Get NVT state */
> -#define OPAL_NPU_RESERVED1			171  /* LPC Allocate */
> -#define OPAL_NPU_RESERVED2			172  /* LPC Release */
> +#define OPAL_NPU_MEM_ALLOC			171
> +#define OPAL_NPU_MEM_RELEASE			172
>   #define OPAL_LAST				172
>   
>   #define QUIESCE_HOLD			1 /* Spin all calls at entry */
> diff --git a/include/phys-map.h b/include/phys-map.h
> index 73adda079e23..0cf48b6628af 100644
> --- a/include/phys-map.h
> +++ b/include/phys-map.h
> @@ -28,6 +28,7 @@ enum phys_map_type {
>   	SYSTEM_MEM,
>   	GPU_MEM_4T_DOWN,
>   	GPU_MEM_4T_UP,
> +	OCAPI_MEM,
>   	PHB4_64BIT_MMIO,
>   	PHB4_32BIT_MMIO,
>   	PHB4_XIVE_ESB,
> 



More information about the Skiboot mailing list