5075 lines · 137.2 KB · C
RawDownload
/* * Copyright 2016 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Author: Huang Rui * */ #include <linux/firmware.h>#include <drm/drm_drv.h> #include "amdgpu.h"#include "amdgpu_psp.h"#include "amdgpu_ucode.h"#include "amdgpu_xgmi.h"#include "soc15_common.h"#include "psp_v3_1.h"#include "psp_v10_0.h"#include "psp_v11_0.h"#include "psp_v11_0_8.h"#include "psp_v12_0.h"#include "psp_v13_0.h"#include "psp_v13_0_4.h"#include "psp_v14_0.h"#include "psp_v15_0.h"#include "psp_v15_0_8.h" #include "amdgpu_ras.h"#include "amdgpu_securedisplay.h"#include "amdgpu_atomfirmware.h" #define AMD_VBIOS_FILE_MAX_SIZE_B      (1024*1024*16) static int psp_load_smu_fw(struct psp_context *psp);static int psp_rap_terminate(struct psp_context *psp);static int psp_securedisplay_terminate(struct psp_context *psp); static const char * const amdgpu_ptl_fmt_str[] = {	[AMDGPU_PTL_FMT_I8]      = "I8",	[AMDGPU_PTL_FMT_F16]     = "F16",	[AMDGPU_PTL_FMT_BF16]    = "BF16",	[AMDGPU_PTL_FMT_F32]     = "F32",	[AMDGPU_PTL_FMT_F64]     = "F64",	[AMDGPU_PTL_FMT_F8]      = "F8",	[AMDGPU_PTL_FMT_VECTOR]  = "VECTOR",	[AMDGPU_PTL_FMT_INVALID] = "INVALID",}; static int psp_ring_init(struct psp_context *psp,			 enum psp_ring_type ring_type){	int ret = 0;	struct psp_ring *ring;	struct amdgpu_device *adev = psp->adev; 	ring = &psp->km_ring; 	ring->ring_type = ring_type; 	/* allocate 4k Page of Local Frame Buffer memory for ring */	ring->ring_size = 0x1000;	ret = amdgpu_bo_create_kernel(adev, ring->ring_size, PAGE_SIZE,				      AMDGPU_GEM_DOMAIN_VRAM |				      AMDGPU_GEM_DOMAIN_GTT,				      &adev->firmware.rbuf,				      &ring->ring_mem_mc_addr,				      (void **)&ring->ring_mem);	if (ret) {		ring->ring_size = 0;		return ret;	} 	return 0;} /* * Due to DF Cstate management centralized to PMFW, the firmware * loading sequence will be updated as below: *   - Load KDB *   - Load SYS_DRV *   - Load tOS *   - Load PMFW *   - Setup TMR *   - Load other non-psp fw *   - Load ASD *   - Load XGMI/RAS/HDCP/DTM TA if any * * This new sequence is required for *   - Arcturus and onwards */static void psp_check_pmfw_centralized_cstate_management(struct psp_context *psp){	struct amdgpu_device *adev = psp->adev; 	if (amdgpu_sriov_vf(adev)) {		psp->pmfw_centralized_cstate_management = false;		return;	} 	switch (amdgpu_ip_version(adev, MP0_HWIP, 0)) {	case IP_VERSION(11, 0, 0):	case IP_VERSION(11, 0, 4):	case IP_VERSION(11, 0, 5):	case IP_VERSION(11, 0, 7):	case IP_VERSION(11, 0, 9):	case IP_VERSION(11, 0, 11):	case IP_VERSION(11, 0, 12):	case IP_VERSION(11, 0, 13):	case IP_VERSION(13, 0, 0):	case IP_VERSION(13, 0, 2):	case IP_VERSION(13, 0, 7):		psp->pmfw_centralized_cstate_management = true;		break;	default:		psp->pmfw_centralized_cstate_management = false;		break;	}} static int psp_init_sriov_microcode(struct psp_context *psp){	struct amdgpu_device *adev = psp->adev;	char ucode_prefix[30];	int ret = 0; 	amdgpu_ucode_ip_version_decode(adev, MP0_HWIP, ucode_prefix, sizeof(ucode_prefix)); 	switch (amdgpu_ip_version(adev, MP0_HWIP, 0)) {	case IP_VERSION(9, 0, 0):	case IP_VERSION(11, 0, 7):	case IP_VERSION(11, 0, 9):		adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MEC2;		ret = psp_init_cap_microcode(psp, ucode_prefix);		break;	case IP_VERSION(13, 0, 2):		adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MEC2;		ret = psp_init_cap_microcode(psp, ucode_prefix);		ret &= psp_init_ta_microcode(psp, ucode_prefix);		break;	case IP_VERSION(13, 0, 0):		adev->virt.autoload_ucode_id = 0;		break;	case IP_VERSION(13, 0, 6):	case IP_VERSION(13, 0, 14):	case IP_VERSION(13, 0, 15):		ret = psp_init_cap_microcode(psp, ucode_prefix);		ret &= psp_init_ta_microcode(psp, ucode_prefix);		break;	case IP_VERSION(13, 0, 10):		adev->virt.autoload_ucode_id = AMDGPU_UCODE_ID_CP_MES1_DATA;		ret = psp_init_cap_microcode(psp, ucode_prefix);		break;	case IP_VERSION(13, 0, 12):		ret = psp_init_ta_microcode(psp, ucode_prefix);		break;	default:		return -EINVAL;	}	return ret;} static int psp_early_init(struct amdgpu_ip_block *ip_block){	struct amdgpu_device *adev = ip_block->adev;	struct psp_context *psp = &adev->psp; 	psp->autoload_supported = true;	psp->boot_time_tmr = true; 	switch (amdgpu_ip_version(adev, MP0_HWIP, 0)) {	case IP_VERSION(9, 0, 0):		psp_v3_1_set_psp_funcs(psp);		psp->autoload_supported = false;		psp->boot_time_tmr = false;		break;	case IP_VERSION(10, 0, 0):	case IP_VERSION(10, 0, 1):		psp_v10_0_set_psp_funcs(psp);		psp->autoload_supported = false;		psp->boot_time_tmr = false;		break;	case IP_VERSION(11, 0, 2):	case IP_VERSION(11, 0, 4):		psp_v11_0_set_psp_funcs(psp);		psp->autoload_supported = false;		psp->boot_time_tmr = false;		break;	case IP_VERSION(11, 0, 0):	case IP_VERSION(11, 0, 7):		adev->psp.sup_pd_fw_up = !amdgpu_sriov_vf(adev);		fallthrough;	case IP_VERSION(11, 0, 5):	case IP_VERSION(11, 0, 9):	case IP_VERSION(11, 0, 11):	case IP_VERSION(11, 5, 0):	case IP_VERSION(11, 5, 2):	case IP_VERSION(11, 0, 12):	case IP_VERSION(11, 0, 13):		psp_v11_0_set_psp_funcs(psp);		psp->boot_time_tmr = false;		break;	case IP_VERSION(11, 0, 3):	case IP_VERSION(12, 0, 1):		psp_v12_0_set_psp_funcs(psp);		psp->autoload_supported = false;		psp->boot_time_tmr = false;		break;	case IP_VERSION(13, 0, 2):		psp->boot_time_tmr = false;		fallthrough;	case IP_VERSION(13, 0, 6):	case IP_VERSION(13, 0, 14):		psp_v13_0_set_psp_funcs(psp);		psp->autoload_supported = false;		break;	case IP_VERSION(13, 0, 12):	case IP_VERSION(13, 0, 15):		psp_v13_0_set_psp_funcs(psp);		psp->autoload_supported = false;		adev->psp.sup_ifwi_up = !amdgpu_sriov_vf(adev);		break;	case IP_VERSION(13, 0, 1):	case IP_VERSION(13, 0, 3):	case IP_VERSION(13, 0, 5):	case IP_VERSION(13, 0, 8):	case IP_VERSION(13, 0, 11):	case IP_VERSION(14, 0, 0):	case IP_VERSION(14, 0, 1):	case IP_VERSION(14, 0, 4):		psp_v13_0_set_psp_funcs(psp);		psp->boot_time_tmr = false;		break;	case IP_VERSION(11, 0, 8):		if (adev->apu_flags & AMD_APU_IS_CYAN_SKILLFISH2) {			psp_v11_0_8_set_psp_funcs(psp);		}		psp->autoload_supported = false;		psp->boot_time_tmr = false;		break;	case IP_VERSION(13, 0, 0):	case IP_VERSION(13, 0, 7):	case IP_VERSION(13, 0, 10):		psp_v13_0_set_psp_funcs(psp);		adev->psp.sup_ifwi_up = !amdgpu_sriov_vf(adev);		psp->boot_time_tmr = false;		break;	case IP_VERSION(13, 0, 4):		psp_v13_0_4_set_psp_funcs(psp);		psp->boot_time_tmr = false;		break;	case IP_VERSION(14, 0, 2):	case IP_VERSION(14, 0, 3):		adev->psp.sup_ifwi_up = !amdgpu_sriov_vf(adev);		psp_v14_0_set_psp_funcs(psp);		break;	case IP_VERSION(14, 0, 5):		psp_v14_0_set_psp_funcs(psp);		psp->boot_time_tmr = false;		break;	case IP_VERSION(15, 0, 0):	case IP_VERSION(15, 0, 5):	case IP_VERSION(15, 0, 9):		psp_v15_0_0_set_psp_funcs(psp);		psp->boot_time_tmr = false;		break;	case IP_VERSION(15, 0, 8):		psp_v15_0_8_set_psp_funcs(psp);		break;	default:		return -EINVAL;	} 	psp->adev = adev; 	adev->psp_timeout = 20000; 	psp_check_pmfw_centralized_cstate_management(psp); 	if (amdgpu_sriov_vf(adev))		return psp_init_sriov_microcode(psp);	else		return psp_init_microcode(psp);} void psp_ta_free_shared_buf(struct ta_mem_context *mem_ctx){	amdgpu_bo_free_kernel(&mem_ctx->shared_bo, &mem_ctx->shared_mc_addr,			      &mem_ctx->shared_buf);	mem_ctx->shared_bo = NULL;} static void psp_free_shared_bufs(struct psp_context *psp){	void *tmr_buf;	void **pptr; 	/* free TMR memory buffer */	pptr = amdgpu_sriov_vf(psp->adev) ? &tmr_buf : NULL;	amdgpu_bo_free_kernel(&psp->tmr_bo, &psp->tmr_mc_addr, pptr);	psp->tmr_bo = NULL; 	/* free xgmi shared memory */	psp_ta_free_shared_buf(&psp->xgmi_context.context.mem_context); 	/* free ras shared memory */	psp_ta_free_shared_buf(&psp->ras_context.context.mem_context); 	/* free hdcp shared memory */	psp_ta_free_shared_buf(&psp->hdcp_context.context.mem_context); 	/* free dtm shared memory */	psp_ta_free_shared_buf(&psp->dtm_context.context.mem_context); 	/* free rap shared memory */	psp_ta_free_shared_buf(&psp->rap_context.context.mem_context); 	/* free securedisplay shared memory */	psp_ta_free_shared_buf(&psp->securedisplay_context.context.mem_context);  } static void psp_memory_training_fini(struct psp_context *psp){	struct psp_memory_training_context *ctx = &psp->mem_train_ctx; 	ctx->init = PSP_MEM_TRAIN_NOT_SUPPORT;	kfree(ctx->sys_cache);	ctx->sys_cache = NULL;} static int psp_memory_training_init(struct psp_context *psp){	int ret;	struct psp_memory_training_context *ctx = &psp->mem_train_ctx; 	if (ctx->init != PSP_MEM_TRAIN_RESERVE_SUCCESS) {		dev_dbg(psp->adev->dev, "memory training is not supported!\n");		return 0;	} 	ctx->sys_cache = kzalloc(ctx->train_data_size, GFP_KERNEL);	if (ctx->sys_cache == NULL) {		dev_err(psp->adev->dev, "alloc mem_train_ctx.sys_cache failed!\n");		ret = -ENOMEM;		goto Err_out;	} 	dev_dbg(psp->adev->dev,		"train_data_size:%llx,p2c_train_data_offset:%llx,c2p_train_data_offset:%llx.\n",		ctx->train_data_size,		ctx->p2c_train_data_offset,		ctx->c2p_train_data_offset);	ctx->init = PSP_MEM_TRAIN_INIT_SUCCESS;	return 0; Err_out:	psp_memory_training_fini(psp);	return ret;} /* * Helper funciton to query psp runtime database entry * * @adev: amdgpu_device pointer * @entry_type: the type of psp runtime database entry * @db_entry: runtime database entry pointer * * Return false if runtime database doesn't exit or entry is invalid * or true if the specific database entry is found, and copy to @db_entry */static bool psp_get_runtime_db_entry(struct amdgpu_device *adev,				     enum psp_runtime_entry_type entry_type,				     void *db_entry){	uint64_t db_header_pos, db_dir_pos;	struct psp_runtime_data_header db_header = {0};	struct psp_runtime_data_directory db_dir = {0};	bool ret = false;	int i; 	/*	 * Runtime DB is for dGPUs only.	 */	if (adev->flags & AMD_IS_APU)		return false; 	if (amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 6) ||	    amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 12) ||	    amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 14) ||		amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 15))		return false; 	db_header_pos = adev->gmc.mc_vram_size - PSP_RUNTIME_DB_OFFSET;	db_dir_pos = db_header_pos + sizeof(struct psp_runtime_data_header); 	/* read runtime db header from vram */	amdgpu_device_vram_access(adev, db_header_pos, (uint32_t *)&db_header,			sizeof(struct psp_runtime_data_header), false); 	if (db_header.cookie != PSP_RUNTIME_DB_COOKIE_ID) {		/* runtime db doesn't exist, exit */		dev_dbg(adev->dev, "PSP runtime database doesn't exist\n");		return false;	} 	/* read runtime database entry from vram */	amdgpu_device_vram_access(adev, db_dir_pos, (uint32_t *)&db_dir,			sizeof(struct psp_runtime_data_directory), false); 	if (db_dir.entry_count >= PSP_RUNTIME_DB_DIAG_ENTRY_MAX_COUNT) {		/* invalid db entry count, exit */		dev_warn(adev->dev, "Invalid PSP runtime database entry count\n");		return false;	} 	/* look up for requested entry type */	for (i = 0; i < db_dir.entry_count && !ret; i++) {		if (db_dir.entry_list[i].entry_type == entry_type) {			switch (entry_type) {			case PSP_RUNTIME_ENTRY_TYPE_BOOT_CONFIG:				if (db_dir.entry_list[i].size < sizeof(struct psp_runtime_boot_cfg_entry)) {					/* invalid db entry size */					dev_warn(adev->dev, "Invalid PSP runtime database boot cfg entry size\n");					return false;				}				/* read runtime database entry */				amdgpu_device_vram_access(adev, db_header_pos + db_dir.entry_list[i].offset,							  (uint32_t *)db_entry, sizeof(struct psp_runtime_boot_cfg_entry), false);				ret = true;				break;			case PSP_RUNTIME_ENTRY_TYPE_PPTABLE_ERR_STATUS:				if (db_dir.entry_list[i].size < sizeof(struct psp_runtime_scpm_entry)) {					/* invalid db entry size */					dev_warn(adev->dev, "Invalid PSP runtime database scpm entry size\n");					return false;				}				/* read runtime database entry */				amdgpu_device_vram_access(adev, db_header_pos + db_dir.entry_list[i].offset,							  (uint32_t *)db_entry, sizeof(struct psp_runtime_scpm_entry), false);				ret = true;				break;			default:				ret = false;				break;			}		}	} 	return ret;} static int psp_sw_init(struct amdgpu_ip_block *ip_block){	struct amdgpu_device *adev = ip_block->adev;	struct psp_context *psp = &adev->psp;	int ret;	struct psp_runtime_boot_cfg_entry boot_cfg_entry;	struct psp_memory_training_context *mem_training_ctx = &psp->mem_train_ctx;	struct psp_runtime_scpm_entry scpm_entry; 	psp->cmd = kzalloc_obj(struct psp_gfx_cmd_resp);	if (!psp->cmd) {		dev_err(adev->dev, "Failed to allocate memory to command buffer!\n");		return -ENOMEM;	} 	adev->psp.xgmi_context.supports_extended_data =		!adev->gmc.xgmi.connected_to_cpu &&		amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 2); 	memset(&scpm_entry, 0, sizeof(scpm_entry));	if ((psp_get_runtime_db_entry(adev,				PSP_RUNTIME_ENTRY_TYPE_PPTABLE_ERR_STATUS,				&scpm_entry)) &&	    (scpm_entry.scpm_status != SCPM_DISABLE)) {		adev->scpm_enabled = true;		adev->scpm_status = scpm_entry.scpm_status;	} else {		adev->scpm_enabled = false;		adev->scpm_status = SCPM_DISABLE;	} 

Lines 1–500 of 5075.