Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/gpu/drm/amd/amdgpu/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 123 kB image not shown  

Quelle  amdgpu_psp.c   Sprache: C

 
/*
 * 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 "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 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):
  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):
  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;
 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;

 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))
  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(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL);
 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;
 }

 /* TODO: stop gpu driver services and print alarm if scpm is enabled with error status */

 memset(&boot_cfg_entry, 0, sizeof(boot_cfg_entry));
 if (psp_get_runtime_db_entry(adev,
    PSP_RUNTIME_ENTRY_TYPE_BOOT_CONFIG,
    &boot_cfg_entry)) {
  psp->boot_cfg_bitmask = boot_cfg_entry.boot_cfg_bitmask;
  if ((psp->boot_cfg_bitmask) &
      BOOT_CFG_FEATURE_TWO_STAGE_DRAM_TRAINING) {
   /* If psp runtime database exists, then
 * only enable two stage memory training
 * when TWO_STAGE_DRAM_TRAINING bit is set
 * in runtime database
 */

   mem_training_ctx->enable_mem_training = true;
  }

 } else {
  /* If psp runtime database doesn't exist or is
 * invalid, force enable two stage memory training
 */

  mem_training_ctx->enable_mem_training = true;
 }

 if (mem_training_ctx->enable_mem_training) {
  ret = psp_memory_training_init(psp);
  if (ret) {
   dev_err(adev->dev, "Failed to initialize memory training!\n");
   return ret;
  }

  ret = psp_mem_training(psp, PSP_MEM_TRAIN_COLD_BOOT);
  if (ret) {
   dev_err(adev->dev, "Failed to process memory training!\n");
   return ret;
  }
 }

 ret = amdgpu_bo_create_kernel(adev, PSP_1_MEG, PSP_1_MEG,
          (amdgpu_sriov_vf(adev) || adev->debug_use_vram_fw_buf) ?
          AMDGPU_GEM_DOMAIN_VRAM : AMDGPU_GEM_DOMAIN_GTT,
          &psp->fw_pri_bo,
          &psp->fw_pri_mc_addr,
          &psp->fw_pri_buf);
 if (ret)
  return ret;

 ret = amdgpu_bo_create_kernel(adev, PSP_FENCE_BUFFER_SIZE, PAGE_SIZE,
          AMDGPU_GEM_DOMAIN_VRAM |
          AMDGPU_GEM_DOMAIN_GTT,
          &psp->fence_buf_bo,
          &psp->fence_buf_mc_addr,
          &psp->fence_buf);
 if (ret)
  goto failed1;

 ret = amdgpu_bo_create_kernel(adev, PSP_CMD_BUFFER_SIZE, PAGE_SIZE,
          AMDGPU_GEM_DOMAIN_VRAM |
          AMDGPU_GEM_DOMAIN_GTT,
          &psp->cmd_buf_bo, &psp->cmd_buf_mc_addr,
          (void **)&psp->cmd_buf_mem);
 if (ret)
  goto failed2;

 return 0;

failed2:
 amdgpu_bo_free_kernel(&psp->fence_buf_bo,
         &psp->fence_buf_mc_addr, &psp->fence_buf);
failed1:
 amdgpu_bo_free_kernel(&psp->fw_pri_bo,
         &psp->fw_pri_mc_addr, &psp->fw_pri_buf);
 return ret;
}

static int psp_sw_fini(struct amdgpu_ip_block *ip_block)
{
 struct amdgpu_device *adev = ip_block->adev;
 struct psp_context *psp = &adev->psp;

 psp_memory_training_fini(psp);

 amdgpu_ucode_release(&psp->sos_fw);
 amdgpu_ucode_release(&psp->asd_fw);
 amdgpu_ucode_release(&psp->ta_fw);
 amdgpu_ucode_release(&psp->cap_fw);
 amdgpu_ucode_release(&psp->toc_fw);

 kfree(psp->cmd);
 psp->cmd = NULL;

 psp_free_shared_bufs(psp);

 if (psp->km_ring.ring_mem)
  amdgpu_bo_free_kernel(&adev->firmware.rbuf,
          &psp->km_ring.ring_mem_mc_addr,
          (void **)&psp->km_ring.ring_mem);

 amdgpu_bo_free_kernel(&psp->fw_pri_bo,
         &psp->fw_pri_mc_addr, &psp->fw_pri_buf);
 amdgpu_bo_free_kernel(&psp->fence_buf_bo,
         &psp->fence_buf_mc_addr, &psp->fence_buf);
 amdgpu_bo_free_kernel(&psp->cmd_buf_bo, &psp->cmd_buf_mc_addr,
         (void **)&psp->cmd_buf_mem);

 return 0;
}

int psp_wait_for(struct psp_context *psp, uint32_t reg_index, uint32_t reg_val,
   uint32_t mask, uint32_t flags)
{
 bool check_changed = flags & PSP_WAITREG_CHANGED;
 bool verbose = !(flags & PSP_WAITREG_NOVERBOSE);
 uint32_t val;
 int i;
 struct amdgpu_device *adev = psp->adev;

 if (psp->adev->no_hw_access)
  return 0;

 for (i = 0; i < adev->usec_timeout; i++) {
  val = RREG32(reg_index);
  if (check_changed) {
   if (val != reg_val)
    return 0;
  } else {
   if ((val & mask) == reg_val)
    return 0;
  }
  udelay(1);
 }

 if (verbose)
  dev_err(adev->dev,
   "psp reg (0x%x) wait timed out, mask: %x, read: %x exp: %x",
   reg_index, mask, val, reg_val);

 return -ETIME;
}

int psp_wait_for_spirom_update(struct psp_context *psp, uint32_t reg_index,
          uint32_t reg_val, uint32_t mask, uint32_t msec_timeout)
{
 uint32_t val;
 int i;
 struct amdgpu_device *adev = psp->adev;

 if (psp->adev->no_hw_access)
  return 0;

 for (i = 0; i < msec_timeout; i++) {
  val = RREG32(reg_index);
  if ((val & mask) == reg_val)
   return 0;
  msleep(1);
 }

 return -ETIME;
}

static const char *psp_gfx_cmd_name(enum psp_gfx_cmd_id cmd_id)
{
 switch (cmd_id) {
 case GFX_CMD_ID_LOAD_TA:
  return "LOAD_TA";
 case GFX_CMD_ID_UNLOAD_TA:
  return "UNLOAD_TA";
 case GFX_CMD_ID_INVOKE_CMD:
  return "INVOKE_CMD";
 case GFX_CMD_ID_LOAD_ASD:
  return "LOAD_ASD";
 case GFX_CMD_ID_SETUP_TMR:
  return "SETUP_TMR";
 case GFX_CMD_ID_LOAD_IP_FW:
  return "LOAD_IP_FW";
 case GFX_CMD_ID_DESTROY_TMR:
  return "DESTROY_TMR";
 case GFX_CMD_ID_SAVE_RESTORE:
  return "SAVE_RESTORE_IP_FW";
 case GFX_CMD_ID_SETUP_VMR:
  return "SETUP_VMR";
 case GFX_CMD_ID_DESTROY_VMR:
  return "DESTROY_VMR";
 case GFX_CMD_ID_PROG_REG:
  return "PROG_REG";
 case GFX_CMD_ID_GET_FW_ATTESTATION:
  return "GET_FW_ATTESTATION";
 case GFX_CMD_ID_LOAD_TOC:
  return "ID_LOAD_TOC";
 case GFX_CMD_ID_AUTOLOAD_RLC:
  return "AUTOLOAD_RLC";
 case GFX_CMD_ID_BOOT_CFG:
  return "BOOT_CFG";
 case GFX_CMD_ID_CONFIG_SQ_PERFMON:
  return "CONFIG_SQ_PERFMON";
 case GFX_CMD_ID_FB_FW_RESERV_ADDR:
  return "FB_FW_RESERV_ADDR";
 case GFX_CMD_ID_FB_FW_RESERV_EXT_ADDR:
  return "FB_FW_RESERV_EXT_ADDR";
 default:
  return "UNKNOWN CMD";
 }
}

static bool psp_err_warn(struct psp_context *psp)
{
 struct psp_gfx_cmd_resp *cmd = psp->cmd_buf_mem;

 /* This response indicates reg list is already loaded */
 if (amdgpu_ip_version(psp->adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 2) &&
     cmd->cmd_id == GFX_CMD_ID_LOAD_IP_FW &&
     cmd->cmd.cmd_load_ip_fw.fw_type == GFX_FW_TYPE_REG_LIST &&
     cmd->resp.status == TEE_ERROR_CANCEL)
  return false;

 return true;
}

static int
psp_cmd_submit_buf(struct psp_context *psp,
     struct amdgpu_firmware_info *ucode,
     struct psp_gfx_cmd_resp *cmd, uint64_t fence_mc_addr)
{
 int ret;
 int index;
 int timeout = psp->adev->psp_timeout;
 bool ras_intr = false;
 bool skip_unsupport = false;

 if (psp->adev->no_hw_access)
  return 0;

 memset(psp->cmd_buf_mem, 0, PSP_CMD_BUFFER_SIZE);

 memcpy(psp->cmd_buf_mem, cmd, sizeof(struct psp_gfx_cmd_resp));

 index = atomic_inc_return(&psp->fence_value);
 ret = psp_ring_cmd_submit(psp, psp->cmd_buf_mc_addr, fence_mc_addr, index);
 if (ret) {
  atomic_dec(&psp->fence_value);
  goto exit;
 }

 amdgpu_device_invalidate_hdp(psp->adev, NULL);
 while (*((unsigned int *)psp->fence_buf) != index) {
  if (--timeout == 0)
   break;
  /*
 * Shouldn't wait for timeout when err_event_athub occurs,
 * because gpu reset thread triggered and lock resource should
 * be released for psp resume sequence.
 */

  ras_intr = amdgpu_ras_intr_triggered();
  if (ras_intr)
   break;
  usleep_range(10, 100);
  amdgpu_device_invalidate_hdp(psp->adev, NULL);
 }

 /* We allow TEE_ERROR_NOT_SUPPORTED for VMR command and PSP_ERR_UNKNOWN_COMMAND in SRIOV */
 skip_unsupport = (psp->cmd_buf_mem->resp.status == TEE_ERROR_NOT_SUPPORTED ||
  psp->cmd_buf_mem->resp.status == PSP_ERR_UNKNOWN_COMMAND) && amdgpu_sriov_vf(psp->adev);

 memcpy(&cmd->resp, &psp->cmd_buf_mem->resp, sizeof(struct psp_gfx_resp));

 /* In some cases, psp response status is not 0 even there is no
 * problem while the command is submitted. Some version of PSP FW
 * doesn't write 0 to that field.
 * So here we would like to only print a warning instead of an error
 * during psp initialization to avoid breaking hw_init and it doesn't
 * return -EINVAL.
 */

 if (!skip_unsupport && (psp->cmd_buf_mem->resp.status || !timeout) && !ras_intr) {
  if (ucode)
   dev_warn(psp->adev->dev,
     "failed to load ucode %s(0x%X) ",
     amdgpu_ucode_name(ucode->ucode_id), ucode->ucode_id);
  if (psp_err_warn(psp))
   dev_warn(
    psp->adev->dev,
    "psp gfx command %s(0x%X) failed and response status is (0x%X)\n",
    psp_gfx_cmd_name(psp->cmd_buf_mem->cmd_id),
    psp->cmd_buf_mem->cmd_id,
    psp->cmd_buf_mem->resp.status);
  /* If any firmware (including CAP) load fails under SRIOV, it should
 * return failure to stop the VF from initializing.
 * Also return failure in case of timeout
 */

  if ((ucode && amdgpu_sriov_vf(psp->adev)) || !timeout) {
   ret = -EINVAL;
   goto exit;
  }
 }

 if (ucode) {
  ucode->tmr_mc_addr_lo = psp->cmd_buf_mem->resp.fw_addr_lo;
  ucode->tmr_mc_addr_hi = psp->cmd_buf_mem->resp.fw_addr_hi;
 }

exit:
 return ret;
}

static struct psp_gfx_cmd_resp *acquire_psp_cmd_buf(struct psp_context *psp)
{
 struct psp_gfx_cmd_resp *cmd = psp->cmd;

 mutex_lock(&psp->mutex);

 memset(cmd, 0, sizeof(struct psp_gfx_cmd_resp));

 return cmd;
}

static void release_psp_cmd_buf(struct psp_context *psp)
{
 mutex_unlock(&psp->mutex);
}

static void psp_prep_tmr_cmd_buf(struct psp_context *psp,
     struct psp_gfx_cmd_resp *cmd,
     uint64_t tmr_mc, struct amdgpu_bo *tmr_bo)
{
 struct amdgpu_device *adev = psp->adev;
 uint32_t size = 0;
 uint64_t tmr_pa = 0;

 if (tmr_bo) {
  size = amdgpu_bo_size(tmr_bo);
  tmr_pa = amdgpu_gmc_vram_pa(adev, tmr_bo);
 }

 if (amdgpu_sriov_vf(psp->adev))
  cmd->cmd_id = GFX_CMD_ID_SETUP_VMR;
 else
  cmd->cmd_id = GFX_CMD_ID_SETUP_TMR;
 cmd->cmd.cmd_setup_tmr.buf_phy_addr_lo = lower_32_bits(tmr_mc);
 cmd->cmd.cmd_setup_tmr.buf_phy_addr_hi = upper_32_bits(tmr_mc);
 cmd->cmd.cmd_setup_tmr.buf_size = size;
 cmd->cmd.cmd_setup_tmr.bitfield.virt_phy_addr = 1;
 cmd->cmd.cmd_setup_tmr.system_phy_addr_lo = lower_32_bits(tmr_pa);
 cmd->cmd.cmd_setup_tmr.system_phy_addr_hi = upper_32_bits(tmr_pa);
}

static void psp_prep_load_toc_cmd_buf(struct psp_gfx_cmd_resp *cmd,
          uint64_t pri_buf_mc, uint32_t size)
{
 cmd->cmd_id = GFX_CMD_ID_LOAD_TOC;
 cmd->cmd.cmd_load_toc.toc_phy_addr_lo = lower_32_bits(pri_buf_mc);
 cmd->cmd.cmd_load_toc.toc_phy_addr_hi = upper_32_bits(pri_buf_mc);
 cmd->cmd.cmd_load_toc.toc_size = size;
}

/* Issue LOAD TOC cmd to PSP to part toc and calculate tmr size needed */
static int psp_load_toc(struct psp_context *psp,
   uint32_t *tmr_size)
{
 int ret;
 struct psp_gfx_cmd_resp *cmd = acquire_psp_cmd_buf(psp);

 /* Copy toc to psp firmware private buffer */
 psp_copy_fw(psp, psp->toc.start_addr, psp->toc.size_bytes);

 psp_prep_load_toc_cmd_buf(cmd, psp->fw_pri_mc_addr, psp->toc.size_bytes);

 ret = psp_cmd_submit_buf(psp, NULL, cmd,
     psp->fence_buf_mc_addr);
 if (!ret)
  *tmr_size = psp->cmd_buf_mem->resp.tmr_size;

 release_psp_cmd_buf(psp);

 return ret;
}

/* Set up Trusted Memory Region */
static int psp_tmr_init(struct psp_context *psp)
{
 int ret = 0;
 int tmr_size;
 void *tmr_buf;
 void **pptr;

 /*
  * According to HW engineer, they prefer the TMR address be "naturally
  * aligned" , e.g. the start address be an integer divide of TMR size.
  *
  * Note: this memory need be reserved till the driver
  * uninitializes.
  */
 tmr_size = PSP_TMR_SIZE(psp->adev);

 /* For ASICs support RLC autoload, psp will parse the toc
  * and calculate the total size of TMR needed
  */
 if (!amdgpu_sriov_vf(psp->adev) &&
     psp->toc.start_addr &&
     psp->toc.size_bytes &&
     psp->fw_pri_buf) {
  ret = psp_load_toc(psp, &tmr_size);
  if (ret) {
   dev_err(psp->adev->dev, "Failed to load toc\n");
   return ret;
  }
 }

 if (!psp->tmr_bo && !psp->boot_time_tmr) {
  pptr = amdgpu_sriov_vf(psp->adev) ? &tmr_buf : NULL;
  ret = amdgpu_bo_create_kernel(psp->adev, tmr_size,
           PSP_TMR_ALIGNMENT,
           AMDGPU_HAS_VRAM(psp->adev) ?
           AMDGPU_GEM_DOMAIN_VRAM :
           AMDGPU_GEM_DOMAIN_GTT,
           &psp->tmr_bo, &psp->tmr_mc_addr,
           pptr);
 }
 if (amdgpu_virt_xgmi_migrate_enabled(psp->adev) && psp->tmr_bo)
  psp->tmr_mc_addr = amdgpu_bo_fb_aper_addr(psp->tmr_bo);

 return ret;
}

static bool psp_skip_tmr(struct psp_context *psp)
{
 switch (amdgpu_ip_version(psp->adev, MP0_HWIP, 0)) {
 case IP_VERSION(11, 0, 9):
 case IP_VERSION(11, 0, 7):
 case IP_VERSION(13, 0, 2):
 case IP_VERSION(13, 0, 6):
 case IP_VERSION(13, 0, 10):
 case IP_VERSION(13, 0, 12):
 case IP_VERSION(13, 0, 14):
  return true;
 default:
  return false;
 }
}

static int psp_tmr_load(struct psp_context *psp)
{
 int ret;
 struct psp_gfx_cmd_resp *cmd;

 /* For Navi12 and CHIP_SIENNA_CICHLID SRIOV, do not set up TMR.
  * Already set up by host driver.
  */
 if (amdgpu_sriov_vf(psp->adev) && psp_skip_tmr(psp))
  return 0;

 cmd = acquire_psp_cmd_buf(psp);

 psp_prep_tmr_cmd_buf(psp, cmd, psp->tmr_mc_addr, psp->tmr_bo);
 if (psp->tmr_bo)
  dev_info(psp->adev->dev, "reserve 0x%lx from 0x%llx for PSP TMR\n",
    amdgpu_bo_size(psp->tmr_bo), psp->tmr_mc_addr);

 ret = psp_cmd_submit_buf(psp, NULL, cmd,
     psp->fence_buf_mc_addr);

 release_psp_cmd_buf(psp);

 return ret;
}

static void psp_prep_tmr_unload_cmd_buf(struct psp_context *psp,
     struct psp_gfx_cmd_resp *cmd)
{
 if (amdgpu_sriov_vf(psp->adev))
  cmd->cmd_id = GFX_CMD_ID_DESTROY_VMR;
 else
  cmd->cmd_id = GFX_CMD_ID_DESTROY_TMR;
}

static int psp_tmr_unload(struct psp_context *psp)
{
 int ret;
 struct psp_gfx_cmd_resp *cmd;

 /* skip TMR unload for Navi12 and CHIP_SIENNA_CICHLID SRIOV,
  * as TMR is not loaded at all
  */
 if (amdgpu_sriov_vf(psp->adev) && psp_skip_tmr(psp))
  return 0;

 cmd = acquire_psp_cmd_buf(psp);

 psp_prep_tmr_unload_cmd_buf(psp, cmd);
 dev_dbg(psp->adev->dev, "free PSP TMR buffer\n");

 ret = psp_cmd_submit_buf(psp, NULL, cmd,
     psp->fence_buf_mc_addr);

 release_psp_cmd_buf(psp);

 return ret;
}

static int psp_tmr_terminate(struct psp_context *psp)
{
 return psp_tmr_unload(psp);
}

int psp_get_fw_attestation_records_addr(struct psp_context *psp,
     uint64_t *output_ptr)
{
 int ret;
 struct psp_gfx_cmd_resp *cmd;

 if (!output_ptr)
  return -EINVAL;

 if (amdgpu_sriov_vf(psp->adev))
  return 0;

 cmd = acquire_psp_cmd_buf(psp);

 cmd->cmd_id = GFX_CMD_ID_GET_FW_ATTESTATION;

 ret = psp_cmd_submit_buf(psp, NULL, cmd,
     psp->fence_buf_mc_addr);

 if (!ret) {
  *output_ptr = ((uint64_t)cmd->resp.uresp.fwar_db_info.fwar_db_addr_lo) +
         ((uint64_t)cmd->resp.uresp.fwar_db_info.fwar_db_addr_hi << 32);
 }

 release_psp_cmd_buf(psp);

 return ret;
}

static int psp_get_fw_reservation_info(struct psp_context *psp,
         uint32_t cmd_id,
         uint64_t *addr,
         uint32_t *size)
{
 int ret;
 uint32_t status;
 struct psp_gfx_cmd_resp *cmd;

 cmd = acquire_psp_cmd_buf(psp);

 cmd->cmd_id = cmd_id;

 ret = psp_cmd_submit_buf(psp, NULL, cmd,
     psp->fence_buf_mc_addr);
 if (ret) {
  release_psp_cmd_buf(psp);
  return ret;
 }

 status = cmd->resp.status;
 if (status == PSP_ERR_UNKNOWN_COMMAND) {
  release_psp_cmd_buf(psp);
  *addr = 0;
  *size = 0;
  return 0;
 }

 *addr = (uint64_t)cmd->resp.uresp.fw_reserve_info.reserve_base_address_hi << 32 |
  cmd->resp.uresp.fw_reserve_info.reserve_base_address_lo;
 *size = cmd->resp.uresp.fw_reserve_info.reserve_size;

 release_psp_cmd_buf(psp);

 return 0;
}

int psp_update_fw_reservation(struct psp_context *psp)
{
 int ret;
 uint64_t reserv_addr, reserv_addr_ext;
 uint32_t reserv_size, reserv_size_ext, mp0_ip_ver;
 struct amdgpu_device *adev = psp->adev;

 mp0_ip_ver = amdgpu_ip_version(adev, MP0_HWIP, 0);

 if (amdgpu_sriov_vf(psp->adev))
  return 0;

 switch (mp0_ip_ver) {
 case IP_VERSION(14, 0, 2):
  if (adev->psp.sos.fw_version < 0x3b0e0d)
   return 0;
  break;

 case IP_VERSION(14, 0, 3):
  if (adev->psp.sos.fw_version < 0x3a0e14)
   return 0;
  break;

 default:
  return 0;
 }

 ret = psp_get_fw_reservation_info(psp, GFX_CMD_ID_FB_FW_RESERV_ADDR, &reserv_addr, &reserv_size);
 if (ret)
  return ret;
 ret = psp_get_fw_reservation_info(psp, GFX_CMD_ID_FB_FW_RESERV_EXT_ADDR, &reserv_addr_ext, &reserv_size_ext);
 if (ret)
  return ret;

 if (reserv_addr != adev->gmc.real_vram_size - reserv_size) {
  dev_warn(adev->dev, "reserve fw region is not valid!\n");
  return 0;
 }

 amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory, NULL, NULL);

 reserv_size = roundup(reserv_size, SZ_1M);

 ret = amdgpu_bo_create_kernel_at(adev, reserv_addr, reserv_size, &adev->mman.fw_reserved_memory, NULL);
 if (ret) {
  dev_err(adev->dev, "reserve fw region failed(%d)!\n", ret);
  amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory, NULL, NULL);
  return ret;
 }

 reserv_size_ext = roundup(reserv_size_ext, SZ_1M);

 ret = amdgpu_bo_create_kernel_at(adev, reserv_addr_ext, reserv_size_ext,
      &adev->mman.fw_reserved_memory_extend, NULL);
 if (ret) {
  dev_err(adev->dev, "reserve extend fw region failed(%d)!\n", ret);
  amdgpu_bo_free_kernel(&adev->mman.fw_reserved_memory_extend, NULL, NULL);
  return ret;
 }

 return 0;
}

static int psp_boot_config_get(struct amdgpu_device *adev, uint32_t *boot_cfg)
{
 struct psp_context *psp = &adev->psp;
 struct psp_gfx_cmd_resp *cmd;
 int ret;

 if (amdgpu_sriov_vf(adev))
  return 0;

 cmd = acquire_psp_cmd_buf(psp);

 cmd->cmd_id = GFX_CMD_ID_BOOT_CFG;
 cmd->cmd.boot_cfg.sub_cmd = BOOTCFG_CMD_GET;

 ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
 if (!ret) {
  *boot_cfg =
   (cmd->resp.uresp.boot_cfg.boot_cfg & BOOT_CONFIG_GECC) ? 1 : 0;
 }

 release_psp_cmd_buf(psp);

 return ret;
}

static int psp_boot_config_set(struct amdgpu_device *adev, uint32_t boot_cfg)
{
 int ret;
 struct psp_context *psp = &adev->psp;
 struct psp_gfx_cmd_resp *cmd;

 if (amdgpu_sriov_vf(adev))
  return 0;

 cmd = acquire_psp_cmd_buf(psp);

 cmd->cmd_id = GFX_CMD_ID_BOOT_CFG;
 cmd->cmd.boot_cfg.sub_cmd = BOOTCFG_CMD_SET;
 cmd->cmd.boot_cfg.boot_config = boot_cfg;
 cmd->cmd.boot_cfg.boot_config_valid = boot_cfg;

 ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);

 release_psp_cmd_buf(psp);

 return ret;
}

static int psp_rl_load(struct amdgpu_device *adev)
{
 int ret;
 struct psp_context *psp = &adev->psp;
 struct psp_gfx_cmd_resp *cmd;

 if (!is_psp_fw_valid(psp->rl))
  return 0;

 cmd = acquire_psp_cmd_buf(psp);

 memset(psp->fw_pri_buf, 0, PSP_1_MEG);
 memcpy(psp->fw_pri_buf, psp->rl.start_addr, psp->rl.size_bytes);

 cmd->cmd_id = GFX_CMD_ID_LOAD_IP_FW;
 cmd->cmd.cmd_load_ip_fw.fw_phy_addr_lo = lower_32_bits(psp->fw_pri_mc_addr);
 cmd->cmd.cmd_load_ip_fw.fw_phy_addr_hi = upper_32_bits(psp->fw_pri_mc_addr);
 cmd->cmd.cmd_load_ip_fw.fw_size = psp->rl.size_bytes;
 cmd->cmd.cmd_load_ip_fw.fw_type = GFX_FW_TYPE_REG_LIST;

 ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);

 release_psp_cmd_buf(psp);

 return ret;
}

int psp_memory_partition(struct psp_context *psp, int mode)
{
 struct psp_gfx_cmd_resp *cmd;
 int ret;

 if (amdgpu_sriov_vf(psp->adev))
  return 0;

 cmd = acquire_psp_cmd_buf(psp);

 cmd->cmd_id = GFX_CMD_ID_FB_NPS_MODE;
 cmd->cmd.cmd_memory_part.mode = mode;

 dev_info(psp->adev->dev,
   "Requesting %d memory partition change through PSP", mode);
 ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
 if (ret)
  dev_err(psp->adev->dev,
   "PSP request failed to change to NPS%d mode\n", mode);

 release_psp_cmd_buf(psp);

 return ret;
}

int psp_spatial_partition(struct psp_context *psp, int mode)
{
 struct psp_gfx_cmd_resp *cmd;
 int ret;

 if (amdgpu_sriov_vf(psp->adev))
  return 0;

 cmd = acquire_psp_cmd_buf(psp);

 cmd->cmd_id = GFX_CMD_ID_SRIOV_SPATIAL_PART;
 cmd->cmd.cmd_spatial_part.mode = mode;

 dev_info(psp->adev->dev, "Requesting %d partitions through PSP", mode);
 ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);

 release_psp_cmd_buf(psp);

 return ret;
}

static int psp_asd_initialize(struct psp_context *psp)
{
 int ret;

 /* If PSP version doesn't match ASD version, asd loading will be failed.
  * add workaround to bypass it for sriov now.
  * TODO: add version check to make it common
  */
 if (amdgpu_sriov_vf(psp->adev) || !psp->asd_context.bin_desc.size_bytes)
  return 0;

 /* bypass asd if display hardware is not available */
 if (!amdgpu_device_has_display_hardware(psp->adev) &&
     amdgpu_ip_version(psp->adev, MP0_HWIP, 0) >= IP_VERSION(13, 0, 10))
  return 0;

 psp->asd_context.mem_context.shared_mc_addr  = 0;
 psp->asd_context.mem_context.shared_mem_size = PSP_ASD_SHARED_MEM_SIZE;
 psp->asd_context.ta_load_type                = GFX_CMD_ID_LOAD_ASD;

 ret = psp_ta_load(psp, &psp->asd_context);
 if (!ret)
  psp->asd_context.initialized = true;

 return ret;
}

static void psp_prep_ta_unload_cmd_buf(struct psp_gfx_cmd_resp *cmd,
           uint32_t session_id)
{
 cmd->cmd_id = GFX_CMD_ID_UNLOAD_TA;
 cmd->cmd.cmd_unload_ta.session_id = session_id;
}

int psp_ta_unload(struct psp_context *psp, struct ta_context *context)
{
 int ret;
 struct psp_gfx_cmd_resp *cmd = acquire_psp_cmd_buf(psp);

 psp_prep_ta_unload_cmd_buf(cmd, context->session_id);

 ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);

 context->resp_status = cmd->resp.status;

 release_psp_cmd_buf(psp);

 return ret;
}

static int psp_asd_terminate(struct psp_context *psp)
{
 int ret;

 if (amdgpu_sriov_vf(psp->adev))
  return 0;

 if (!psp->asd_context.initialized)
  return 0;

 ret = psp_ta_unload(psp, &psp->asd_context);
 if (!ret)
  psp->asd_context.initialized = false;

 return ret;
}

static void psp_prep_reg_prog_cmd_buf(struct psp_gfx_cmd_resp *cmd,
  uint32_t id, uint32_t value)
{
 cmd->cmd_id = GFX_CMD_ID_PROG_REG;
 cmd->cmd.cmd_setup_reg_prog.reg_value = value;
 cmd->cmd.cmd_setup_reg_prog.reg_id = id;
}

int psp_reg_program(struct psp_context *psp, enum psp_reg_prog_id reg,
  uint32_t value)
{
 struct psp_gfx_cmd_resp *cmd;
 int ret = 0;

 if (reg >= PSP_REG_LAST)
  return -EINVAL;

 cmd = acquire_psp_cmd_buf(psp);

 psp_prep_reg_prog_cmd_buf(cmd, reg, value);
 ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
 if (ret)
  dev_err(psp->adev->dev, "PSP failed to program reg id %d\n", reg);

 release_psp_cmd_buf(psp);

 return ret;
}

static void psp_prep_ta_load_cmd_buf(struct psp_gfx_cmd_resp *cmd,
         uint64_t ta_bin_mc,
         struct ta_context *context)
{
 cmd->cmd_id    = context->ta_load_type;
 cmd->cmd.cmd_load_ta.app_phy_addr_lo = lower_32_bits(ta_bin_mc);
 cmd->cmd.cmd_load_ta.app_phy_addr_hi = upper_32_bits(ta_bin_mc);
 cmd->cmd.cmd_load_ta.app_len  = context->bin_desc.size_bytes;

 cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_lo =
  lower_32_bits(context->mem_context.shared_mc_addr);
 cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_hi =
  upper_32_bits(context->mem_context.shared_mc_addr);
 cmd->cmd.cmd_load_ta.cmd_buf_len = context->mem_context.shared_mem_size;
}

int psp_ta_init_shared_buf(struct psp_context *psp,
      struct ta_mem_context *mem_ctx)
{
 /*
  * Allocate 16k memory aligned to 4k from Frame Buffer (local
  * physical) for ta to host memory
  */
 return amdgpu_bo_create_kernel(psp->adev, mem_ctx->shared_mem_size,
          PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM |
          AMDGPU_GEM_DOMAIN_GTT,
          &mem_ctx->shared_bo,
          &mem_ctx->shared_mc_addr,
          &mem_ctx->shared_buf);
}

static void psp_prep_ta_invoke_cmd_buf(struct psp_gfx_cmd_resp *cmd,
           uint32_t ta_cmd_id,
           uint32_t session_id)
{
 cmd->cmd_id    = GFX_CMD_ID_INVOKE_CMD;
 cmd->cmd.cmd_invoke_cmd.session_id = session_id;
 cmd->cmd.cmd_invoke_cmd.ta_cmd_id = ta_cmd_id;
}

int psp_ta_invoke(struct psp_context *psp,
    uint32_t ta_cmd_id,
    struct ta_context *context)
{
 int ret;
 struct psp_gfx_cmd_resp *cmd = acquire_psp_cmd_buf(psp);

 psp_prep_ta_invoke_cmd_buf(cmd, ta_cmd_id, context->session_id);

 ret = psp_cmd_submit_buf(psp, NULL, cmd,
     psp->fence_buf_mc_addr);

 context->resp_status = cmd->resp.status;

 release_psp_cmd_buf(psp);

 return ret;
}

int psp_ta_load(struct psp_context *psp, struct ta_context *context)
{
 int ret;
 struct psp_gfx_cmd_resp *cmd;

 cmd = acquire_psp_cmd_buf(psp);

 psp_copy_fw(psp, context->bin_desc.start_addr,
      context->bin_desc.size_bytes);

 if (amdgpu_virt_xgmi_migrate_enabled(psp->adev) &&
  context->mem_context.shared_bo)
  context->mem_context.shared_mc_addr =
   amdgpu_bo_fb_aper_addr(context->mem_context.shared_bo);

 psp_prep_ta_load_cmd_buf(cmd, psp->fw_pri_mc_addr, context);

 ret = psp_cmd_submit_buf(psp, NULL, cmd,
     psp->fence_buf_mc_addr);

 context->resp_status = cmd->resp.status;

 if (!ret)
  context->session_id = cmd->resp.session_id;

 release_psp_cmd_buf(psp);

 return ret;
}

int psp_xgmi_invoke(struct psp_context *psp, uint32_t ta_cmd_id)
{
 return psp_ta_invoke(psp, ta_cmd_id, &psp->xgmi_context.context);
}

int psp_xgmi_terminate(struct psp_context *psp)
{
 int ret;
 struct amdgpu_device *adev = psp->adev;

 /* XGMI TA unload currently is not supported on Arcturus/Aldebaran A+A */
 if (amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(11, 0, 4) ||
     (amdgpu_ip_version(adev, MP0_HWIP, 0) == IP_VERSION(13, 0, 2) &&
      adev->gmc.xgmi.connected_to_cpu))
  return 0;

 if (!psp->xgmi_context.context.initialized)
  return 0;

 ret = psp_ta_unload(psp, &psp->xgmi_context.context);

 psp->xgmi_context.context.initialized = false;

 return ret;
}

int psp_xgmi_initialize(struct psp_context *psp, bool set_extended_data, bool load_ta)
{
 struct ta_xgmi_shared_memory *xgmi_cmd;
 int ret;

 if (!psp->ta_fw ||
     !psp->xgmi_context.context.bin_desc.size_bytes ||
     !psp->xgmi_context.context.bin_desc.start_addr)
  return -ENOENT;

 if (!load_ta)
  goto invoke;

 psp->xgmi_context.context.mem_context.shared_mem_size = PSP_XGMI_SHARED_MEM_SIZE;
 psp->xgmi_context.context.ta_load_type = GFX_CMD_ID_LOAD_TA;

 if (!psp->xgmi_context.context.mem_context.shared_buf) {
  ret = psp_ta_init_shared_buf(psp, &psp->xgmi_context.context.mem_context);
  if (ret)
   return ret;
 }

 /* Load XGMI TA */
 ret = psp_ta_load(psp, &psp->xgmi_context.context);
 if (!ret)
  psp->xgmi_context.context.initialized = true;
 else
  return ret;

invoke:
 /* Initialize XGMI session */
 xgmi_cmd = (struct ta_xgmi_shared_memory *)(psp->xgmi_context.context.mem_context.shared_buf);
 memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory));
 xgmi_cmd->flag_extend_link_record = set_extended_data;
 xgmi_cmd->cmd_id = TA_COMMAND_XGMI__INITIALIZE;

 ret = psp_xgmi_invoke(psp, xgmi_cmd->cmd_id);
 /* note down the capbility flag for XGMI TA */
 psp->xgmi_context.xgmi_ta_caps = xgmi_cmd->caps_flag;

 return ret;
}

int psp_xgmi_get_hive_id(struct psp_context *psp, uint64_t *hive_id)
{
 struct ta_xgmi_shared_memory *xgmi_cmd;
 int ret;

 xgmi_cmd = (struct ta_xgmi_shared_memory *)psp->xgmi_context.context.mem_context.shared_buf;
 memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory));

 xgmi_cmd->cmd_id = TA_COMMAND_XGMI__GET_HIVE_ID;

 /* Invoke xgmi ta to get hive id */
 ret = psp_xgmi_invoke(psp, xgmi_cmd->cmd_id);
 if (ret)
  return ret;

 *hive_id = xgmi_cmd->xgmi_out_message.get_hive_id.hive_id;

 return 0;
}

int psp_xgmi_get_node_id(struct psp_context *psp, uint64_t *node_id)
{
 struct ta_xgmi_shared_memory *xgmi_cmd;
 int ret;

 xgmi_cmd = (struct ta_xgmi_shared_memory *)psp->xgmi_context.context.mem_context.shared_buf;
 memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory));

 xgmi_cmd->cmd_id = TA_COMMAND_XGMI__GET_NODE_ID;

 /* Invoke xgmi ta to get the node id */
 ret = psp_xgmi_invoke(psp, xgmi_cmd->cmd_id);
 if (ret)
  return ret;

 *node_id = xgmi_cmd->xgmi_out_message.get_node_id.node_id;

 return 0;
}

static bool psp_xgmi_peer_link_info_supported(struct psp_context *psp)
{
 return (amdgpu_ip_version(psp->adev, MP0_HWIP, 0) ==
   IP_VERSION(13, 0, 2) &&
  psp->xgmi_context.context.bin_desc.fw_version >= 0x2000000b) ||
        amdgpu_ip_version(psp->adev, MP0_HWIP, 0) >=
         IP_VERSION(13, 0, 6);
}

/*
 * Chips that support extended topology information require the driver to
 * reflect topology information in the opposite direction.  This is
 * because the TA has already exceeded its link record limit and if the
 * TA holds bi-directional information, the driver would have to do
 * multiple fetches instead of just two.
 */
static void psp_xgmi_reflect_topology_info(struct psp_context *psp,
     struct psp_xgmi_node_info node_info)
{
 struct amdgpu_device *mirror_adev;
 struct amdgpu_hive_info *hive;
 uint64_t src_node_id = psp->adev->gmc.xgmi.node_id;
 uint64_t dst_node_id = node_info.node_id;
 uint8_t dst_num_hops = node_info.num_hops;
 uint8_t dst_num_links = node_info.num_links;

 hive = amdgpu_get_xgmi_hive(psp->adev);
 if (WARN_ON(!hive))
  return;

 list_for_each_entry(mirror_adev, &hive->device_list, gmc.xgmi.head) {
  struct psp_xgmi_topology_info *mirror_top_info;
  int j;

  if (mirror_adev->gmc.xgmi.node_id != dst_node_id)
   continue;

  mirror_top_info = &mirror_adev->psp.xgmi_context.top_info;
  for (j = 0; j < mirror_top_info->num_nodes; j++) {
   if (mirror_top_info->nodes[j].node_id != src_node_id)
    continue;

   mirror_top_info->nodes[j].num_hops = dst_num_hops;
   /*
    * prevent 0 num_links value re-reflection since reflection
    * criteria is based on num_hops (direct or indirect).
    *
    */
   if (dst_num_links)
    mirror_top_info->nodes[j].num_links = dst_num_links;

   break;
  }

  break;
 }

 amdgpu_put_xgmi_hive(hive);
}

int psp_xgmi_get_topology_info(struct psp_context *psp,
          int number_devices,
          struct psp_xgmi_topology_info *topology,
          bool get_extended_data)
{
 struct ta_xgmi_shared_memory *xgmi_cmd;
 struct ta_xgmi_cmd_get_topology_info_input *topology_info_input;
 struct ta_xgmi_cmd_get_topology_info_output *topology_info_output;
 int i;
 int ret;

 if (!topology || topology->num_nodes > TA_XGMI__MAX_CONNECTED_NODES)
  return -EINVAL;

 xgmi_cmd = (struct ta_xgmi_shared_memory *)psp->xgmi_context.context.mem_context.shared_buf;
 memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory));
 xgmi_cmd->flag_extend_link_record = get_extended_data;

 /* Fill in the shared memory with topology information as input */
 topology_info_input = &xgmi_cmd->xgmi_in_message.get_topology_info;
 xgmi_cmd->cmd_id = TA_COMMAND_XGMI__GET_TOPOLOGY_INFO;
 topology_info_input->num_nodes = number_devices;

 for (i = 0; i < topology_info_input->num_nodes; i++) {
  topology_info_input->nodes[i].node_id = topology->nodes[i].node_id;
  topology_info_input->nodes[i].num_hops = topology->nodes[i].num_hops;
  topology_info_input->nodes[i].is_sharing_enabled = topology->nodes[i].is_sharing_enabled;
  topology_info_input->nodes[i].sdma_engine = topology->nodes[i].sdma_engine;
 }

 /* Invoke xgmi ta to get the topology information */
 ret = psp_xgmi_invoke(psp, TA_COMMAND_XGMI__GET_TOPOLOGY_INFO);
 if (ret)
  return ret;

 /* Read the output topology information from the shared memory */
 topology_info_output = &xgmi_cmd->xgmi_out_message.get_topology_info;
 topology->num_nodes = xgmi_cmd->xgmi_out_message.get_topology_info.num_nodes;
 for (i = 0; i < topology->num_nodes; i++) {
  /* extended data will either be 0 or equal to non-extended data */
  if (topology_info_output->nodes[i].num_hops)
   topology->nodes[i].num_hops = topology_info_output->nodes[i].num_hops;

  /* non-extended data gets everything here so no need to update */
  if (!get_extended_data) {
   topology->nodes[i].node_id = topology_info_output->nodes[i].node_id;
   topology->nodes[i].is_sharing_enabled =
     topology_info_output->nodes[i].is_sharing_enabled;
   topology->nodes[i].sdma_engine =
     topology_info_output->nodes[i].sdma_engine;
  }

 }

 /* Invoke xgmi ta again to get the link information */
 if (psp_xgmi_peer_link_info_supported(psp)) {
  struct ta_xgmi_cmd_get_peer_link_info *link_info_output;
  struct ta_xgmi_cmd_get_extend_peer_link_info *link_extend_info_output;
  bool requires_reflection =
   (psp->xgmi_context.supports_extended_data &&
    get_extended_data) ||
   amdgpu_ip_version(psp->adev, MP0_HWIP, 0) ==
    IP_VERSION(13, 0, 6) ||
   amdgpu_ip_version(psp->adev, MP0_HWIP, 0) ==
    IP_VERSION(13, 0, 14);
  bool ta_port_num_support = amdgpu_sriov_vf(psp->adev) ? 0 :
    psp->xgmi_context.xgmi_ta_caps & EXTEND_PEER_LINK_INFO_CMD_FLAG;

  /* popluate the shared output buffer rather than the cmd input buffer
   * with node_ids as the input for GET_PEER_LINKS command execution.
   * This is required for GET_PEER_LINKS per xgmi ta implementation.
   * The same requirement for GET_EXTEND_PEER_LINKS command.
   */
  if (ta_port_num_support) {
   link_extend_info_output = &xgmi_cmd->xgmi_out_message.get_extend_link_info;

   for (i = 0; i < topology->num_nodes; i++)
    link_extend_info_output->nodes[i].node_id = topology->nodes[i].node_id;

   link_extend_info_output->num_nodes = topology->num_nodes;
   xgmi_cmd->cmd_id = TA_COMMAND_XGMI__GET_EXTEND_PEER_LINKS;
  } else {
   link_info_output = &xgmi_cmd->xgmi_out_message.get_link_info;

   for (i = 0; i < topology->num_nodes; i++)
    link_info_output->nodes[i].node_id = topology->nodes[i].node_id;

   link_info_output->num_nodes = topology->num_nodes;
   xgmi_cmd->cmd_id = TA_COMMAND_XGMI__GET_PEER_LINKS;
  }

  ret = psp_xgmi_invoke(psp, xgmi_cmd->cmd_id);
  if (ret)
   return ret;

  for (i = 0; i < topology->num_nodes; i++) {
   uint8_t node_num_links = ta_port_num_support ?
    link_extend_info_output->nodes[i].num_links : link_info_output->nodes[i].num_links;
   /* accumulate num_links on extended data */
   if (get_extended_data) {
    topology->nodes[i].num_links = topology->nodes[i].num_links + node_num_links;
   } else {
    topology->nodes[i].num_links = (requires_reflection && topology->nodes[i].num_links) ?
        topology->nodes[i].num_links : node_num_links;
   }
   /* popluate the connected port num info if supported and available */
   if (ta_port_num_support && topology->nodes[i].num_links) {
    memcpy(topology->nodes[i].port_num, link_extend_info_output->nodes[i].port_num,
           sizeof(struct xgmi_connected_port_num) * TA_XGMI__MAX_PORT_NUM);
   }

   /* reflect the topology information for bi-directionality */
   if (requires_reflection && topology->nodes[i].num_hops)
    psp_xgmi_reflect_topology_info(psp, topology->nodes[i]);
  }
 }

 return 0;
}

int psp_xgmi_set_topology_info(struct psp_context *psp,
          int number_devices,
          struct psp_xgmi_topology_info *topology)
{
 struct ta_xgmi_shared_memory *xgmi_cmd;
 struct ta_xgmi_cmd_get_topology_info_input *topology_info_input;
 int i;

 if (!topology || topology->num_nodes > TA_XGMI__MAX_CONNECTED_NODES)
  return -EINVAL;

 xgmi_cmd = (struct ta_xgmi_shared_memory *)psp->xgmi_context.context.mem_context.shared_buf;
 memset(xgmi_cmd, 0, sizeof(struct ta_xgmi_shared_memory));

 topology_info_input = &xgmi_cmd->xgmi_in_message.get_topology_info;
 xgmi_cmd->cmd_id = TA_COMMAND_XGMI__SET_TOPOLOGY_INFO;
 topology_info_input->num_nodes = number_devices;

 for (i = 0; i < topology_info_input->num_nodes; i++) {
  topology_info_input->nodes[i].node_id = topology->nodes[i].node_id;
  topology_info_input->nodes[i].num_hops = topology->nodes[i].num_hops;
  topology_info_input->nodes[i].is_sharing_enabled = 1;
  topology_info_input->nodes[i].sdma_engine = topology->nodes[i].sdma_engine;
 }

 /* Invoke xgmi ta to set topology information */
 return psp_xgmi_invoke(psp, TA_COMMAND_XGMI__SET_TOPOLOGY_INFO);
}

// ras begin
static void psp_ras_ta_check_status(struct psp_context *psp)
{
 struct ta_ras_shared_memory *ras_cmd =
  (struct ta_ras_shared_memory *)psp->ras_context.context.mem_context.shared_buf;

 switch (ras_cmd->ras_status) {
 case TA_RAS_STATUS__ERROR_UNSUPPORTED_IP:
  dev_warn(psp->adev->dev,
    "RAS WARNING: cmd failed due to unsupported ip\n");
  break;
 case TA_RAS_STATUS__ERROR_UNSUPPORTED_ERROR_INJ:
  dev_warn(psp->adev->dev,
    "RAS WARNING: cmd failed due to unsupported error injection\n");
  break;
 case TA_RAS_STATUS__SUCCESS:
  break;
 case TA_RAS_STATUS__TEE_ERROR_ACCESS_DENIED:
  if (ras_cmd->cmd_id == TA_RAS_COMMAND__TRIGGER_ERROR)
   dev_warn(psp->adev->dev,
     "RAS WARNING: Inject error to critical region is not allowed\n");
  break;
 default:
  dev_warn(psp->adev->dev,
    "RAS WARNING: ras status = 0x%X\n", ras_cmd->ras_status);
  break;
 }
}

static int psp_ras_send_cmd(struct psp_context *psp,
  enum ras_command cmd_id, void *in, void *out)
{
 struct ta_ras_shared_memory *ras_cmd;
 uint32_t cmd = cmd_id;
 int ret = 0;

 if (!in)
  return -EINVAL;

 mutex_lock(&psp->ras_context.mutex);
 ras_cmd = (struct ta_ras_shared_memory *)psp->ras_context.context.mem_context.shared_buf;
 memset(ras_cmd, 0, sizeof(struct ta_ras_shared_memory));

 switch (cmd) {
 case TA_RAS_COMMAND__ENABLE_FEATURES:
 case TA_RAS_COMMAND__DISABLE_FEATURES:
  memcpy(&ras_cmd->ras_in_message,
   in, sizeof(ras_cmd->ras_in_message));
  break;
 case TA_RAS_COMMAND__TRIGGER_ERROR:
  memcpy(&ras_cmd->ras_in_message.trigger_error,
   in, sizeof(ras_cmd->ras_in_message.trigger_error));
  break;
 case TA_RAS_COMMAND__QUERY_ADDRESS:
  memcpy(&ras_cmd->ras_in_message.address,
   in, sizeof(ras_cmd->ras_in_message.address));
  break;
 default:
  dev_err(psp->adev->dev, "Invalid ras cmd id: %u\n", cmd);
  ret = -EINVAL;
  goto err_out;
 }

 ras_cmd->cmd_id = cmd;
 ret = psp_ras_invoke(psp, ras_cmd->cmd_id);

 switch (cmd) {
 case TA_RAS_COMMAND__TRIGGER_ERROR:
  if (!ret && out)
   memcpy(out, &ras_cmd->ras_status, sizeof(ras_cmd->ras_status));
  break;
 case TA_RAS_COMMAND__QUERY_ADDRESS:
  if (ret || ras_cmd->ras_status || psp->cmd_buf_mem->resp.status)
   ret = -EINVAL;
  else if (out)
   memcpy(out,
    &ras_cmd->ras_out_message.address,
    sizeof(ras_cmd->ras_out_message.address));
  break;
 default:
  break;
 }

err_out:
 mutex_unlock(&psp->ras_context.mutex);

 return ret;
}

int psp_ras_invoke(struct psp_context *psp, uint32_t ta_cmd_id)
{
 struct ta_ras_shared_memory *ras_cmd;
 int ret;

 ras_cmd = (struct ta_ras_shared_memory *)psp->ras_context.context.mem_context.shared_buf;

 /*
  * TODO: bypass the loading in sriov for now
  */
 if (amdgpu_sriov_vf(psp->adev))
  return 0;

 ret = psp_ta_invoke(psp, ta_cmd_id, &psp->ras_context.context);

 if (amdgpu_ras_intr_triggered())
  return ret;

 if (ras_cmd->if_version > RAS_TA_HOST_IF_VER) {
  dev_warn(psp->adev->dev, "RAS: Unsupported Interface\n");
  return -EINVAL;
 }

 if (!ret) {
  if (ras_cmd->ras_out_message.flags.err_inject_switch_disable_flag) {
   dev_warn(psp->adev->dev, "ECC switch disabled\n");

   ras_cmd->ras_status = TA_RAS_STATUS__ERROR_RAS_NOT_AVAILABLE;
  } else if (ras_cmd->ras_out_message.flags.reg_access_failure_flag)
   dev_warn(psp->adev->dev,
     "RAS internal register access blocked\n");

  psp_ras_ta_check_status(psp);
 }

 return ret;
}

int psp_ras_enable_features(struct psp_context *psp,
  union ta_ras_cmd_input *info, bool enable)
{
 enum ras_command cmd_id;
 int ret;

 if (!psp->ras_context.context.initialized || !info)
  return -EINVAL;

 cmd_id = enable ?
  TA_RAS_COMMAND__ENABLE_FEATURES : TA_RAS_COMMAND__DISABLE_FEATURES;
 ret = psp_ras_send_cmd(psp, cmd_id, info, NULL);
 if (ret)
  return -EINVAL;

 return 0;
}

int psp_ras_terminate(struct psp_context *psp)
{
 int ret;

 /*
  * TODO: bypass the terminate in sriov for now
  */
 if (amdgpu_sriov_vf(psp->adev))
  return 0;

 if (!psp->ras_context.context.initialized)
  return 0;

 ret = psp_ta_unload(psp, &psp->ras_context.context);

 psp->ras_context.context.initialized = false;

 mutex_destroy(&psp->ras_context.mutex);

 return ret;
}

int psp_ras_initialize(struct psp_context *psp)
{
 int ret;
 uint32_t boot_cfg = 0xFF;
 struct amdgpu_device *adev = psp->adev;
 struct ta_ras_shared_memory *ras_cmd;

 /*
  * TODO: bypass the initialize in sriov for now
  */
 if (amdgpu_sriov_vf(adev))
  return 0;

 if (!adev->psp.ras_context.context.bin_desc.size_bytes ||
     !adev->psp.ras_context.context.bin_desc.start_addr) {
  dev_info(adev->dev, "RAS: optional ras ta ucode is not available\n");
  return 0;
 }

 if (amdgpu_atomfirmware_dynamic_boot_config_supported(adev)) {
  /* query GECC enablement status from boot config
   * boot_cfg: 1: GECC is enabled or 0: GECC is disabled
   */
  ret = psp_boot_config_get(adev, &boot_cfg);
  if (ret)
   dev_warn(adev->dev, "PSP get boot config failed\n");

  if (boot_cfg == 1 && !adev->ras_default_ecc_enabled &&
      amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__UMC)) {
   dev_warn(adev->dev, "GECC is currently enabled, which may affect performance\n");
   dev_warn(adev->dev,
    "To disable GECC, please reboot the system and load the amdgpu driver with the parameter amdgpu_ras_enable=0\n");
  } else {
   if ((adev->ras_default_ecc_enabled || amdgpu_ras_enable == 1) &&
    amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__UMC)) {
    if (boot_cfg == 1) {
     dev_info(adev->dev, "GECC is enabled\n");
    } else {
     /* enable GECC in next boot cycle if it is disabled
      * in boot config, or force enable GECC if failed to
      * get boot configuration
      */
     ret = psp_boot_config_set(adev, BOOT_CONFIG_GECC);
     if (ret)
      dev_warn(adev->dev, "PSP set boot config failed\n");
     else
      dev_warn(adev->dev, "GECC will be enabled in next boot cycle\n");
    }
   } else {
    if (!boot_cfg) {
     if (!adev->ras_default_ecc_enabled &&
         amdgpu_ras_enable != 1 &&
         amdgpu_ras_is_supported(adev, AMDGPU_RAS_BLOCK__UMC))
      dev_warn(adev->dev, "GECC is disabled, set amdgpu_ras_enable=1 to enable GECC in next boot cycle if needed\n");
     else
      dev_info(adev->dev, "GECC is disabled\n");
    } else {
     /* disable GECC in next boot cycle if ras is
      * disabled by module parameter amdgpu_ras_enable
      * and/or amdgpu_ras_mask, or boot_config_get call
      * is failed
      */
     ret = psp_boot_config_set(adev, 0);
     if (ret)
      dev_warn(adev->dev, "PSP set boot config failed\n");
     else
      dev_warn(adev->dev, "GECC will be disabled in next boot cycle if set amdgpu_ras_enable and/or amdgpu_ras_mask to 0x0\n");
    }
   }
  }
 }

 psp->ras_context.context.mem_context.shared_mem_size = PSP_RAS_SHARED_MEM_SIZE;
 psp->ras_context.context.ta_load_type = GFX_CMD_ID_LOAD_TA;

 if (!psp->ras_context.context.mem_context.shared_buf) {
  ret = psp_ta_init_shared_buf(psp, &psp->ras_context.context.mem_context);
  if (ret)
   return ret;
 }

 ras_cmd = (struct ta_ras_shared_memory *)psp->ras_context.context.mem_context.shared_buf;
 memset(ras_cmd, 0, sizeof(struct ta_ras_shared_memory));

 if (amdgpu_ras_is_poison_mode_supported(adev))
  ras_cmd->ras_in_message.init_flags.poison_mode_en = 1;
 if (!adev->gmc.xgmi.connected_to_cpu && !adev->gmc.is_app_apu)
  ras_cmd->ras_in_message.init_flags.dgpu_mode = 1;
 ras_cmd->ras_in_message.init_flags.xcc_mask =
  adev->gfx.xcc_mask;
 ras_cmd->ras_in_message.init_flags.channel_dis_num = hweight32(adev->gmc.m_half_use) * 2;
 if (adev->gmc.gmc_funcs->query_mem_partition_mode)
  ras_cmd->ras_in_message.init_flags.nps_mode =
   adev->gmc.gmc_funcs->query_mem_partition_mode(adev);
 ras_cmd->ras_in_message.init_flags.active_umc_mask = adev->umc.active_mask;

 ret = psp_ta_load(psp, &psp->ras_context.context);

 if (!ret && !ras_cmd->ras_status) {
  psp->ras_context.context.initialized = true;
  mutex_init(&psp->ras_context.mutex);
 } else {
  if (ras_cmd->ras_status)
   dev_warn(adev->dev, "RAS Init Status: 0x%X\n", ras_cmd->ras_status);

  /* fail to load RAS TA */
  psp->ras_context.context.initialized = false;
 }

 return ret;
}

int psp_ras_trigger_error(struct psp_context *psp,
     struct ta_ras_trigger_error_input *info, uint32_t instance_mask)
{
 struct amdgpu_device *adev = psp->adev;
 int ret;
 uint32_t dev_mask;
 uint32_t ras_status = 0;

 if (!psp->ras_context.context.initialized || !info)
  return -EINVAL;

 switch (info->block_id) {
 case TA_RAS_BLOCK__GFX:
  dev_mask = GET_MASK(GC, instance_mask);
  break;
 case TA_RAS_BLOCK__SDMA:
  dev_mask = GET_MASK(SDMA0, instance_mask);
  break;
 case TA_RAS_BLOCK__VCN:
 case TA_RAS_BLOCK__JPEG:
  dev_mask = GET_MASK(VCN, instance_mask);
  break;
 default:
  dev_mask = instance_mask;
  break;
 }

 /* reuse sub_block_index for backward compatibility */
 dev_mask <<= AMDGPU_RAS_INST_SHIFT;
 dev_mask &= AMDGPU_RAS_INST_MASK;
 info->sub_block_index |= dev_mask;

 ret = psp_ras_send_cmd(psp,
   TA_RAS_COMMAND__TRIGGER_ERROR, info, &ras_status);
 if (ret)
  return -EINVAL;

 /* If err_event_athub occurs error inject was successful, however
  *  return status from TA is no long reliable
  */
 if (amdgpu_ras_intr_triggered())
  return 0;

 if (ras_status == TA_RAS_STATUS__TEE_ERROR_ACCESS_DENIED)
  return -EACCES;
 else if (ras_status)
  return -EINVAL;

 return 0;
}

int psp_ras_query_address(struct psp_context *psp,
     struct ta_ras_query_address_input *addr_in,
     struct ta_ras_query_address_output *addr_out)
{
 int ret;

 if (!psp->ras_context.context.initialized ||
  !addr_in || !addr_out)
  return -EINVAL;

 ret = psp_ras_send_cmd(psp,
   TA_RAS_COMMAND__QUERY_ADDRESS, addr_in, addr_out);

 return ret;
}
// ras end

// HDCP start
static int psp_hdcp_initialize(struct psp_context *psp)
{
 int ret;

 /*
  * TODO: bypass the initialize in sriov for now
  */
 if (amdgpu_sriov_vf(psp->adev))
  return 0;

 /* bypass hdcp initialization if dmu is harvested */
 if (!amdgpu_device_has_display_hardware(psp->adev))
  return 0;

 if (!psp->hdcp_context.context.bin_desc.size_bytes ||
     !psp->hdcp_context.context.bin_desc.start_addr) {
  dev_info(psp->adev->dev, "HDCP: optional hdcp ta ucode is not available\n");
  return 0;
 }

 psp->hdcp_context.context.mem_context.shared_mem_size = PSP_HDCP_SHARED_MEM_SIZE;
 psp->hdcp_context.context.ta_load_type = GFX_CMD_ID_LOAD_TA;

 if (!psp->hdcp_context.context.mem_context.shared_buf) {
  ret = psp_ta_init_shared_buf(psp, &psp->hdcp_context.context.mem_context);
  if (ret)
   return ret;
 }

 ret = psp_ta_load(psp, &psp->hdcp_context.context);
 if (!ret) {
  psp->hdcp_context.context.initialized = true;
  mutex_init(&psp->hdcp_context.mutex);
 }

 return ret;
}

int psp_hdcp_invoke(struct psp_context *psp, uint32_t ta_cmd_id)
{
 /*
  * TODO: bypass the loading in sriov for now
  */
 if (amdgpu_sriov_vf(psp->adev))
  return 0;

 if (!psp->hdcp_context.context.initialized)
  return 0;

 return psp_ta_invoke(psp, ta_cmd_id, &psp->hdcp_context.context);
}

static int psp_hdcp_terminate(struct psp_context *psp)
{
 int ret;

 /*
  * TODO: bypass the terminate in sriov for now
  */
 if (amdgpu_sriov_vf(psp->adev))
  return 0;

 if (!psp->hdcp_context.context.initialized)
  return 0;

 ret = psp_ta_unload(psp, &psp->hdcp_context.context);

 psp->hdcp_context.context.initialized = false;

 return ret;
}
// HDCP end

// DTM start
static int psp_dtm_initialize(struct psp_context *psp)
{
 int ret;

 /*
  * TODO: bypass the initialize in sriov for now
  */
 if (amdgpu_sriov_vf(psp->adev))
  return 0;

 /* bypass dtm initialization if dmu is harvested */
 if (!amdgpu_device_has_display_hardware(psp->adev))
  return 0;

 if (!psp->dtm_context.context.bin_desc.size_bytes ||
     !psp->dtm_context.context.bin_desc.start_addr) {
  dev_info(psp->adev->dev, "DTM: optional dtm ta ucode is not available\n");
  return 0;
 }

 psp->dtm_context.context.mem_context.shared_mem_size = PSP_DTM_SHARED_MEM_SIZE;
 psp->dtm_context.context.ta_load_type = GFX_CMD_ID_LOAD_TA;

 if (!psp->dtm_context.context.mem_context.shared_buf) {
  ret = psp_ta_init_shared_buf(psp, &psp->dtm_context.context.mem_context);
  if (ret)
   return ret;
 }

 ret = psp_ta_load(psp, &psp->dtm_context.context);
 if (!ret) {
  psp->dtm_context.context.initialized = true;
  mutex_init(&psp->dtm_context.mutex);
 }

 return ret;
}

int psp_dtm_invoke(struct psp_context *psp, uint32_t ta_cmd_id)
{
 /*
  * TODO: bypass the loading in sriov for now
  */
 if (amdgpu_sriov_vf(psp->adev))
  return 0;

 if (!psp->dtm_context.context.initialized)
  return 0;

 return psp_ta_invoke(psp, ta_cmd_id, &psp->dtm_context.context);
}

static int psp_dtm_terminate(struct psp_context *psp)
{
 int ret;

 /*
  * TODO: bypass the terminate in sriov for now
  */
 if (amdgpu_sriov_vf(psp->adev))
  return 0;

 if (!psp->dtm_context.context.initialized)
  return 0;

 ret = psp_ta_unload(psp, &psp->dtm_context.context);

 psp->dtm_context.context.initialized = false;

 return ret;
}
// DTM end

// RAP start
static int psp_rap_initialize(struct psp_context *psp)
{
 int ret;
 enum ta_rap_status status = TA_RAP_STATUS__SUCCESS;

 /*
  * TODO: bypass the initialize in sriov for now
  */
 if (amdgpu_sriov_vf(psp->adev))
  return 0;

 if (!psp->rap_context.context.bin_desc.size_bytes ||
     !psp->rap_context.context.bin_desc.start_addr) {
  dev_info(psp->adev->dev, "RAP: optional rap ta ucode is not available\n");
  return 0;
 }

 psp->rap_context.context.mem_context.shared_mem_size = PSP_RAP_SHARED_MEM_SIZE;
 psp->rap_context.context.ta_load_type = GFX_CMD_ID_LOAD_TA;

 if (!psp->rap_context.context.mem_context.shared_buf) {
  ret = psp_ta_init_shared_buf(psp, &psp->rap_context.context.mem_context);
  if (ret)
   return ret;
 }

 ret = psp_ta_load(psp, &psp->rap_context.context);
 if (!ret) {
  psp->rap_context.context.initialized = true;
  mutex_init(&psp->rap_context.mutex);
 } else
  return ret;

 ret = psp_rap_invoke(psp, TA_CMD_RAP__INITIALIZE, &status);
 if (ret || status != TA_RAP_STATUS__SUCCESS) {
  psp_rap_terminate(psp);
  /* free rap shared memory */
  psp_ta_free_shared_buf(&psp->rap_context.context.mem_context);

  dev_warn(psp->adev->dev, "RAP TA initialize fail (%d) status %d.\n",
    ret, status);

  return ret;
 }

 return 0;
}

static int psp_rap_terminate(struct psp_context *psp)
{
 int ret;

 if (!psp->rap_context.context.initialized)
  return 0;

 ret = psp_ta_unload(psp, &psp->rap_context.context);

 psp->rap_context.context.initialized = false;

 return ret;
}

int psp_rap_invoke(struct psp_context *psp, uint32_t ta_cmd_id, enum ta_rap_status *status)
{
 struct ta_rap_shared_memory *rap_cmd;
 int ret = 0;

 if (!psp->rap_context.context.initialized)
  return 0;

 if (ta_cmd_id != TA_CMD_RAP__INITIALIZE &&
     ta_cmd_id != TA_CMD_RAP__VALIDATE_L0)
  return -EINVAL;

 mutex_lock(&psp->rap_context.mutex);

 rap_cmd = (struct ta_rap_shared_memory *)
    psp->rap_context.context.mem_context.shared_buf;
 memset(rap_cmd, 0, sizeof(struct ta_rap_shared_memory));

 rap_cmd->cmd_id = ta_cmd_id;
 rap_cmd->validation_method_id = METHOD_A;

 ret = psp_ta_invoke(psp, rap_cmd->cmd_id, &psp->rap_context.context);
 if (ret)
  goto out_unlock;

 if (status)
  *status = rap_cmd->rap_status;

out_unlock:
 mutex_unlock(&psp->rap_context.mutex);

 return ret;
}
// RAP end

/* securedisplay start */
static int psp_securedisplay_initialize(struct psp_context *psp)
{
 int ret;
 struct ta_securedisplay_cmd *securedisplay_cmd;

 /*
  * TODO: bypass the initialize in sriov for now
  */
 if (amdgpu_sriov_vf(psp->adev))
  return 0;

 /* bypass securedisplay initialization if dmu is harvested */
 if (!amdgpu_device_has_display_hardware(psp->adev))
  return 0;

 if (!psp->securedisplay_context.context.bin_desc.size_bytes ||
     !psp->securedisplay_context.context.bin_desc.start_addr) {
  dev_info(psp->adev->dev,
    "SECUREDISPLAY: optional securedisplay ta ucode is not available\n");
  return 0;
 }

 psp->securedisplay_context.context.mem_context.shared_mem_size =
  PSP_SECUREDISPLAY_SHARED_MEM_SIZE;
 psp->securedisplay_context.context.ta_load_type = GFX_CMD_ID_LOAD_TA;

 if (!psp->securedisplay_context.context.initialized) {
  ret = psp_ta_init_shared_buf(psp,
          &psp->securedisplay_context.context.mem_context);
  if (ret)
   return ret;
 }

 ret = psp_ta_load(psp, &psp->securedisplay_context.context);
 if (!ret && !psp->securedisplay_context.context.resp_status) {
  psp->securedisplay_context.context.initialized = true;
  mutex_init(&psp->securedisplay_context.mutex);
 } else {
  /* don't try again */
  psp->securedisplay_context.context.bin_desc.size_bytes = 0;
  return ret;
 }

 mutex_lock(&psp->securedisplay_context.mutex);

 psp_prep_securedisplay_cmd_buf(psp, &securedisplay_cmd,
   TA_SECUREDISPLAY_COMMAND__QUERY_TA);

 ret = psp_securedisplay_invoke(psp, TA_SECUREDISPLAY_COMMAND__QUERY_TA);

 mutex_unlock(&psp->securedisplay_context.mutex);

 if (ret) {
  psp_securedisplay_terminate(psp);
  /* free securedisplay shared memory */
  psp_ta_free_shared_buf(&psp->securedisplay_context.context.mem_context);
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=98 H=96 G=96

¤ Dauer der Verarbeitung: 0.57 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.