[PATCH 5/8] drm/amdgpu/atomfirmware: add memory training related helper functions

Tuikov, Luben Luben.Tuikov at amd.com
Wed Oct 9 03:34:11 UTC 2019


On 2019-10-08 3:29 p.m., Alex Deucher wrote:
> From: "Tianci.Yin" <tianci.yin at amd.com>
> 
> parse firmware to get memory training capability and fb location.
> 
> Change-Id: I147c1d48e255e0191be4beb1ad6b637da607bf75
> Reviewed-by: Alex Deucher <alexander.deucher at amd.com>
> Signed-off-by: Tianci.Yin <tianci.yin at amd.com>
> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu.h           |   7 +
>  drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c  |   5 +
>  .../gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c  | 130 ++++++++++++++++++
>  .../gpu/drm/amd/amdgpu/amdgpu_atomfirmware.h  |   1 +
>  4 files changed, 143 insertions(+)
> 
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> index 0d60c2e6c592..eeb6b6282fce 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h
> @@ -288,6 +288,9 @@ struct amdgpu_ip_block_version {
>  	const struct amd_ip_funcs *funcs;
>  };
>  
> +#define hw_revision(major, minor, revision) \
> +	((((uint32_t) major) << 16) | ((uint32_t) minor << 8) | ((uint32_t) revision))
> +
>  struct amdgpu_ip_block {
>  	struct amdgpu_ip_block_status status;
>  	const struct amdgpu_ip_block_version *version;
> @@ -630,6 +633,10 @@ struct amdgpu_fw_vram_usage {
>  	u64 size;
>  	struct amdgpu_bo *reserved_bo;
>  	void *va;
> +
> +	/*offset on the top of vram, used as c2p write buffer*/
> +	u64 mem_train_fb_loc;
> +	bool mem_train_support;
>  };
>  
>  /*
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
> index 1c9d40f97a9b..5f5a2d3fff9b 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atombios.c
> @@ -2038,6 +2038,11 @@ int amdgpu_atombios_init(struct amdgpu_device *adev)
>  	if (adev->is_atom_fw) {
>  		amdgpu_atomfirmware_scratch_regs_init(adev);
>  		amdgpu_atomfirmware_allocate_fb_scratch(adev);
> +		ret = amdgpu_atomfirmware_get_mem_train_fb_loc(adev);
> +		if(ret) {

Space after a keyword: "if (ret)" according to LKCS.

> +			DRM_ERROR("Failed to get mem train fb location.\n");
> +			return ret;
> +		}
>  	} else {
>  		amdgpu_atombios_scratch_regs_init(adev);
>  		amdgpu_atombios_allocate_fb_scratch(adev);
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c
> index 39fd8ae5a822..dfaebd929332 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.c
> @@ -27,6 +27,7 @@
>  #include "amdgpu_atomfirmware.h"
>  #include "atom.h"
>  #include "atombios.h"
> +#include "soc15_hw_ip.h"
>  
>  bool amdgpu_atomfirmware_gpu_supports_virtualization(struct amdgpu_device *adev)
>  {
> @@ -462,3 +463,132 @@ int amdgpu_atomfirmware_get_gfx_info(struct amdgpu_device *adev)
>  	}
>  	return -EINVAL;
>  }
> +
> +/*
> + * Check if VBIOS supports GDDR6 training data save/restore
> + */
> +static bool gddr6_mem_train_vbios_support(struct amdgpu_device *adev)
> +{
> +	uint16_t data_offset;
> +	int index;
> +
> +	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
> +					    firmwareinfo);
> +	if (amdgpu_atom_parse_data_header(adev->mode_info.atom_context, index, NULL,
> +					  NULL, NULL, &data_offset)) {
> +		struct atom_firmware_info_v3_1 *firmware_info =
> +			(struct atom_firmware_info_v3_1 *)(adev->mode_info.atom_context->bios +
> +							   data_offset);
> +
> +		DRM_DEBUG("atom firmware capability:0x%08x.\n",
> +			  le32_to_cpu(firmware_info->firmware_capability));
> +
> +		if (le32_to_cpu(firmware_info->firmware_capability) &
> +		    ATOM_FIRMWARE_CAP_ENABLE_2STAGE_BIST_TRAINING)
> +			return true;
> +	}
> +
> +	return false;
> +}
> +
> +static int gddr6_mem_train_support(struct amdgpu_device *adev)
> +{
> +	int ret = 0;

int ret;
Don't preinitialize. Instead, explicitly set on all contingencies.
This makes the code more secure. See below.

> +	bool vbios_support = false;
> +	uint32_t major, minor, revision, hw_v;
> +
> +	if (!amdgpu_sriov_vf(adev) &&
> +	    gddr6_mem_train_vbios_support(adev)) {
> +		vbios_support = true;
> +	}
> +
> +	amdgpu_discovery_get_ip_version(adev, MP0_HWID, &major, &minor, &revision);
> +	hw_v = hw_revision(major, minor, revision);
> +	/*
> +	 * treat 0 revision as a special case since register for MP0 and MMHUB is missing
> +	 * for some Navi10 A0, preventing driver from discovering the hwip information since
> +	 * none of the functions will be initialized, it should not cause any problems
> +	 */
> +	switch(hw_v) {

Space after keyword: "switch (hw_v) {" according to LKCS.

> +	case hw_revision(11, 0, 0):
> +	case hw_revision(11, 0, 5):
> +		ret = vbios_support;
> +		break;
> +	default:
> +		if (vbios_support) {
> +			DRM_ERROR("memory training vbios supports but psp hw(%08x)"
> +				  " doesn't support!\n", hw_v);
> +			ret = -1;
> +		}

} else {
	ret = 0;
}
break;

> +		break;
> +	}
> +
> +	DRM_DEBUG("mp0 hw_v %08x, ret:%d.\n", hw_v, ret);
> +	return ret;
> +}
> +
> +int amdgpu_atomfirmware_get_mem_train_fb_loc(struct amdgpu_device *adev)
> +{
> +	struct atom_context *ctx = adev->mode_info.atom_context;
> +	unsigned char *bios = ctx->bios;
> +	struct vram_reserve_block *reserved_block;
> +	int index, block_number;
> +	uint8_t frev, crev;
> +	uint16_t data_offset, size;
> +	uint32_t start_address_in_kb = 0;
> +	uint64_t offset;
> +	int ret = 0;
> +
> +	adev->fw_vram_usage.mem_train_support = false;
> +	ret = gddr6_mem_train_support(adev);
> +	if (ret == -1)
> +		return -EINVAL;
> +	else if (ret == 0)
> +		return 0;
> +
> +	index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
> +					    vram_usagebyfirmware);
> +	ret = amdgpu_atom_parse_data_header(ctx, index, &size, &frev, &crev,
> +					    &data_offset);
> +	if (!ret) {

if (ret == 0)
Since it is an integer and not a pointer--compare to 0 integer.

Regards,
Luben

> +		DRM_ERROR("parse data header failed.\n");
> +		return -EINVAL;
> +	}
> +
> +	DRM_DEBUG("atom firmware common table header size:0x%04x, frev:0x%02x,"
> +		  " crev:0x%02x, data_offset:0x%04x.\n", size, frev, crev, data_offset);
> +	/* only support 2.1+ */
> +	if (((uint16_t)frev << 8 | crev) < 0x0201) {
> +		DRM_ERROR("frev:0x%02x, crev:0x%02x < 2.1 !\n", frev, crev);
> +		return -EINVAL;
> +	}
> +
> +	reserved_block = (struct vram_reserve_block *)
> +		(bios + data_offset + sizeof(struct atom_common_table_header));
> +	block_number = ((unsigned int)size - sizeof(struct atom_common_table_header))
> +		/ sizeof(struct vram_reserve_block);
> +	reserved_block += (block_number > 0) ? block_number-1 : 0;
> +	DRM_DEBUG("block_number:0x%04x, last block: 0x%08xkb sz, %dkb fw, %dkb drv.\n",
> +		  block_number,
> +		  le32_to_cpu(reserved_block->start_address_in_kb),
> +		  le16_to_cpu(reserved_block->used_by_firmware_in_kb),
> +		  le16_to_cpu(reserved_block->used_by_driver_in_kb));
> +	if (reserved_block->used_by_firmware_in_kb > 0) {
> +		start_address_in_kb = le32_to_cpu(reserved_block->start_address_in_kb);
> +		offset = (uint64_t)start_address_in_kb * ONE_K;
> +		if ((offset & (ONE_MEG - 1)) < (4 * ONE_K + 1) ) {
> +			offset -= ONE_MEG;
> +		}
> +
> +		offset &= ~(ONE_MEG - 1);
> +		adev->fw_vram_usage.mem_train_fb_loc = offset;
> +		adev->fw_vram_usage.mem_train_support = true;
> +		DRM_DEBUG("mem_train_fb_loc:0x%09llx.\n", offset);
> +		ret = 0;
> +	} else {
> +		DRM_ERROR("used_by_firmware_in_kb is 0!\n");
> +		ret = -EINVAL;
> +	}
> +
> +	return ret;
> +}
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.h
> index 53449fc7baf4..f871af5ea6f3 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_atomfirmware.h
> @@ -31,6 +31,7 @@ void amdgpu_atomfirmware_scratch_regs_init(struct amdgpu_device *adev);
>  int amdgpu_atomfirmware_allocate_fb_scratch(struct amdgpu_device *adev);
>  int amdgpu_atomfirmware_get_vram_info(struct amdgpu_device *adev,
>  	int *vram_width, int *vram_type, int *vram_vendor);
> +int amdgpu_atomfirmware_get_mem_train_fb_loc(struct amdgpu_device *adev);
>  int amdgpu_atomfirmware_get_clock_info(struct amdgpu_device *adev);
>  int amdgpu_atomfirmware_get_gfx_info(struct amdgpu_device *adev);
>  bool amdgpu_atomfirmware_mem_ecc_supported(struct amdgpu_device *adev);
> 



More information about the amd-gfx mailing list