Commit 240c811c authored by Tianci.Yin's avatar Tianci.Yin Committed by Alex Deucher
Browse files

drm/amdgpu: fix VRAM partially encroached issue in GDDR6 memory training(V2)



[why]
In GDDR6 BIST training, a certain mount of bottom VRAM will be encroached by
UMC, that causes problems(like GTT corrupted and page fault observed).

[how]
Saving the content of this bottom VRAM to system memory before training, and
restoring it after training to avoid VRAM corruption.

Acked-by: default avatarChristian König <christian.koenig@amd.com>
Signed-off-by: default avatarTianci.Yin <tianci.yin@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent a9d4fe2f
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -172,6 +172,8 @@ struct psp_dtm_context {
#define MEM_TRAIN_SYSTEM_SIGNATURE		0x54534942
#define GDDR6_MEM_TRAINING_DATA_SIZE_IN_BYTES	0x1000
#define GDDR6_MEM_TRAINING_OFFSET		0x8000
/*Define the VRAM size that will be encroached by BIST training.*/
#define GDDR6_MEM_TRAINING_ENCROACHED_SIZE	0x2000000

enum psp_memory_training_init_flag {
	PSP_MEM_TRAIN_NOT_SUPPORT	= 0x0,
+33 −3
Original line number Diff line number Diff line
@@ -971,10 +971,13 @@ Err_out:
 */
static int psp_v11_0_memory_training(struct psp_context *psp, uint32_t ops)
{
	int ret;
	uint32_t p2c_header[4];
	struct psp_memory_training_context *ctx = &psp->mem_train_ctx;
	uint32_t *pcache = (uint32_t*)ctx->sys_cache;
	struct amdgpu_device *adev = psp->adev;
	uint32_t p2c_header[4];
	uint32_t sz;
	void *buf;
	int ret;

	if (ctx->init == PSP_MEM_TRAIN_NOT_SUPPORT) {
		DRM_DEBUG("Memory training is not supported.\n");
@@ -989,7 +992,7 @@ static int psp_v11_0_memory_training(struct psp_context *psp, uint32_t ops)
		return 0;
	}

	amdgpu_device_vram_access(psp->adev, ctx->p2c_train_data_offset, p2c_header, sizeof(p2c_header), false);
	amdgpu_device_vram_access(adev, ctx->p2c_train_data_offset, p2c_header, sizeof(p2c_header), false);
	DRM_DEBUG("sys_cache[%08x,%08x,%08x,%08x] p2c_header[%08x,%08x,%08x,%08x]\n",
		  pcache[0], pcache[1], pcache[2], pcache[3],
		  p2c_header[0], p2c_header[1], p2c_header[2], p2c_header[3]);
@@ -1026,11 +1029,38 @@ static int psp_v11_0_memory_training(struct psp_context *psp, uint32_t ops)
	DRM_DEBUG("Memory training ops:%x.\n", ops);

	if (ops & PSP_MEM_TRAIN_SEND_LONG_MSG) {
		/*
		 * Long traing will encroach certain mount of bottom VRAM,
		 * saving the content of this bottom VRAM to system memory
		 * before training, and restoring it after training to avoid
		 * VRAM corruption.
		 */
		sz = GDDR6_MEM_TRAINING_ENCROACHED_SIZE;

		if (adev->gmc.visible_vram_size < sz || !adev->mman.aper_base_kaddr) {
			DRM_ERROR("visible_vram_size %llx or aper_base_kaddr %p is not initialized.\n",
				  adev->gmc.visible_vram_size,
				  adev->mman.aper_base_kaddr);
			return -EINVAL;
		}

		buf = vmalloc(sz);
		if (!buf) {
			DRM_ERROR("failed to allocate system memory.\n");
			return -ENOMEM;
		}

		memcpy_fromio(buf, adev->mman.aper_base_kaddr, sz);
		ret = psp_v11_0_memory_training_send_msg(psp, PSP_BL__DRAM_LONG_TRAIN);
		if (ret) {
			DRM_ERROR("Send long training msg failed.\n");
			vfree(buf);
			return ret;
		}

		memcpy_toio(adev->mman.aper_base_kaddr, buf, sz);
		adev->nbio.funcs->hdp_flush(adev, NULL);
		vfree(buf);
	}

	if (ops & PSP_MEM_TRAIN_SAVE) {