drm/amdgpu: added support for psp fw attestation
[linux-2.6-microblaze.git] / drivers / gpu / drm / amd / amdgpu / amdgpu_psp.c
index d8c6520..487961e 100644 (file)
@@ -100,6 +100,8 @@ static int psp_early_init(void *handle)
        case CHIP_NAVI12:
        case CHIP_SIENNA_CICHLID:
        case CHIP_NAVY_FLOUNDER:
+       case CHIP_VANGOGH:
+       case CHIP_DIMGREY_CAVEFISH:
                psp_v11_0_set_psp_funcs(psp);
                psp->autoload_supported = true;
                break;
@@ -161,10 +163,12 @@ static int psp_sw_init(void *handle)
        struct psp_context *psp = &adev->psp;
        int ret;
 
-       ret = psp_init_microcode(psp);
-       if (ret) {
-               DRM_ERROR("Failed to load psp firmware!\n");
-               return ret;
+       if (!amdgpu_sriov_vf(adev)) {
+               ret = psp_init_microcode(psp);
+               if (ret) {
+                       DRM_ERROR("Failed to load psp firmware!\n");
+                       return ret;
+               }
        }
 
        ret = psp_memory_training_init(psp);
@@ -178,7 +182,7 @@ static int psp_sw_init(void *handle)
                return ret;
        }
 
-       if (adev->asic_type == CHIP_NAVI10) {
+       if (adev->asic_type == CHIP_NAVI10 || adev->asic_type == CHIP_SIENNA_CICHLID) {
                ret= psp_sysfs_init(adev);
                if (ret) {
                        return ret;
@@ -206,7 +210,8 @@ static int psp_sw_fini(void *handle)
                adev->psp.ta_fw = NULL;
        }
 
-       if (adev->asic_type == CHIP_NAVI10)
+       if (adev->asic_type == CHIP_NAVI10 ||
+           adev->asic_type == CHIP_SIENNA_CICHLID)
                psp_sysfs_fini(adev);
 
        return 0;
@@ -219,6 +224,9 @@ int psp_wait_for(struct psp_context *psp, uint32_t reg_index,
        int i;
        struct amdgpu_device *adev = psp->adev;
 
+       if (psp->adev->in_pci_err_recovery)
+               return 0;
+
        for (i = 0; i < adev->usec_timeout; i++) {
                val = RREG32(reg_index);
                if (check_changed) {
@@ -245,6 +253,9 @@ psp_cmd_submit_buf(struct psp_context *psp,
        bool ras_intr = false;
        bool skip_unsupport = false;
 
+       if (psp->adev->in_pci_err_recovery)
+               return 0;
+
        mutex_lock(&psp->mutex);
 
        memset(psp->cmd_buf_mem, 0, PSP_CMD_BUFFER_SIZE);
@@ -279,6 +290,8 @@ psp_cmd_submit_buf(struct psp_context *psp,
        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((void*)&cmd->resp, (void*)&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.
@@ -299,9 +312,6 @@ psp_cmd_submit_buf(struct psp_context *psp,
                }
        }
 
-       /* get xGMI session id from response buffer */
-       cmd->resp.session_id = psp->cmd_buf_mem->resp.session_id;
-
        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;
@@ -500,6 +510,37 @@ static int psp_tmr_terminate(struct psp_context *psp)
        return 0;
 }
 
+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 = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       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);
+       }
+
+       kfree(cmd);
+
+       return ret;
+}
+
 static void psp_prep_asd_load_cmd_buf(struct psp_gfx_cmd_resp *cmd,
                                uint64_t asd_mc, uint32_t size)
 {
@@ -929,6 +970,7 @@ static int psp_ras_load(struct psp_context *psp)
 {
        int ret;
        struct psp_gfx_cmd_resp *cmd;
+       struct ta_ras_shared_memory *ras_cmd;
 
        /*
         * TODO: bypass the loading in sriov for now
@@ -952,11 +994,20 @@ static int psp_ras_load(struct psp_context *psp)
        ret = psp_cmd_submit_buf(psp, NULL, cmd,
                        psp->fence_buf_mc_addr);
 
+       ras_cmd = (struct ta_ras_shared_memory*)psp->ras.ras_shared_buf;
+
        if (!ret) {
-               psp->ras.ras_initialized = true;
                psp->ras.session_id = cmd->resp.session_id;
+
+               if (!ras_cmd->ras_status)
+                       psp->ras.ras_initialized = true;
+               else
+                       dev_warn(psp->adev->dev, "RAS Init Status: 0x%X\n", ras_cmd->ras_status);
        }
 
+       if (ret || ras_cmd->ras_status)
+               amdgpu_ras_fini(psp->adev);
+
        kfree(cmd);
 
        return ret;
@@ -1429,6 +1480,168 @@ static int psp_dtm_terminate(struct psp_context *psp)
 }
 // DTM end
 
+// RAP start
+static int psp_rap_init_shared_buf(struct psp_context *psp)
+{
+       int ret;
+
+       /*
+        * Allocate 16k memory aligned to 4k from Frame Buffer (local
+        * physical) for rap ta <-> Driver
+        */
+       ret = amdgpu_bo_create_kernel(psp->adev, PSP_RAP_SHARED_MEM_SIZE,
+                                     PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM,
+                                     &psp->rap_context.rap_shared_bo,
+                                     &psp->rap_context.rap_shared_mc_addr,
+                                     &psp->rap_context.rap_shared_buf);
+
+       return ret;
+}
+
+static int psp_rap_load(struct psp_context *psp)
+{
+       int ret;
+       struct psp_gfx_cmd_resp *cmd;
+
+       cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       memset(psp->fw_pri_buf, 0, PSP_1_MEG);
+       memcpy(psp->fw_pri_buf, psp->ta_rap_start_addr, psp->ta_rap_ucode_size);
+
+       psp_prep_ta_load_cmd_buf(cmd,
+                                psp->fw_pri_mc_addr,
+                                psp->ta_rap_ucode_size,
+                                psp->rap_context.rap_shared_mc_addr,
+                                PSP_RAP_SHARED_MEM_SIZE);
+
+       ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
+
+       if (!ret) {
+               psp->rap_context.rap_initialized = true;
+               psp->rap_context.session_id = cmd->resp.session_id;
+               mutex_init(&psp->rap_context.mutex);
+       }
+
+       kfree(cmd);
+
+       return ret;
+}
+
+static int psp_rap_unload(struct psp_context *psp)
+{
+       int ret;
+       struct psp_gfx_cmd_resp *cmd;
+
+       cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       psp_prep_ta_unload_cmd_buf(cmd, psp->rap_context.session_id);
+
+       ret = psp_cmd_submit_buf(psp, NULL, cmd, psp->fence_buf_mc_addr);
+
+       kfree(cmd);
+
+       return ret;
+}
+
+static int psp_rap_initialize(struct psp_context *psp)
+{
+       int ret;
+
+       /*
+        * TODO: bypass the initialize in sriov for now
+        */
+       if (amdgpu_sriov_vf(psp->adev))
+               return 0;
+
+       if (!psp->adev->psp.ta_rap_ucode_size ||
+           !psp->adev->psp.ta_rap_start_addr) {
+               dev_info(psp->adev->dev, "RAP: optional rap ta ucode is not available\n");
+               return 0;
+       }
+
+       if (!psp->rap_context.rap_initialized) {
+               ret = psp_rap_init_shared_buf(psp);
+               if (ret)
+                       return ret;
+       }
+
+       ret = psp_rap_load(psp);
+       if (ret)
+               return ret;
+
+       ret = psp_rap_invoke(psp, TA_CMD_RAP__INITIALIZE);
+       if (ret != TA_RAP_STATUS__SUCCESS) {
+               psp_rap_unload(psp);
+
+               amdgpu_bo_free_kernel(&psp->rap_context.rap_shared_bo,
+                             &psp->rap_context.rap_shared_mc_addr,
+                             &psp->rap_context.rap_shared_buf);
+
+               psp->rap_context.rap_initialized = false;
+
+               dev_warn(psp->adev->dev, "RAP TA initialize fail.\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int psp_rap_terminate(struct psp_context *psp)
+{
+       int ret;
+
+       if (!psp->rap_context.rap_initialized)
+               return 0;
+
+       ret = psp_rap_unload(psp);
+
+       psp->rap_context.rap_initialized = false;
+
+       /* free rap shared memory */
+       amdgpu_bo_free_kernel(&psp->rap_context.rap_shared_bo,
+                             &psp->rap_context.rap_shared_mc_addr,
+                             &psp->rap_context.rap_shared_buf);
+
+       return ret;
+}
+
+int psp_rap_invoke(struct psp_context *psp, uint32_t ta_cmd_id)
+{
+       struct ta_rap_shared_memory *rap_cmd;
+       int ret;
+
+       if (!psp->rap_context.rap_initialized)
+               return -EINVAL;
+
+       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.rap_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.session_id);
+       if (ret) {
+               mutex_unlock(&psp->rap_context.mutex);
+               return ret;
+       }
+
+       mutex_unlock(&psp->rap_context.mutex);
+
+       return rap_cmd->rap_status;
+}
+// RAP end
+
 static int psp_hw_start(struct psp_context *psp)
 {
        struct amdgpu_device *adev = psp->adev;
@@ -1570,6 +1783,12 @@ static int psp_get_fw_type(struct amdgpu_firmware_info *ucode,
        case AMDGPU_UCODE_ID_RLC_RESTORE_LIST_SRM_MEM:
                *type = GFX_FW_TYPE_RLC_RESTORE_LIST_SRM_MEM;
                break;
+       case AMDGPU_UCODE_ID_RLC_IRAM:
+               *type = GFX_FW_TYPE_RLC_IRAM;
+               break;
+       case AMDGPU_UCODE_ID_RLC_DRAM:
+               *type = GFX_FW_TYPE_RLC_DRAM_BOOT;
+               break;
        case AMDGPU_UCODE_ID_SMC:
                *type = GFX_FW_TYPE_SMU;
                break;
@@ -1706,7 +1925,7 @@ static int psp_load_smu_fw(struct psp_context *psp)
                return 0;
 
 
-       if (adev->in_gpu_reset && ras && ras->supported) {
+       if (amdgpu_in_reset(adev) && ras && ras->supported) {
                ret = amdgpu_dpm_set_mp1_state(adev, PP_MP1_STATE_UNLOAD);
                if (ret) {
                        DRM_WARN("Failed to set MP1 state prepare for reload\n");
@@ -1787,8 +2006,8 @@ static int psp_np_fw_load(struct psp_context *psp)
                        continue;
 
                if (psp->autoload_supported &&
-                   (adev->asic_type == CHIP_SIENNA_CICHLID ||
-                    adev->asic_type == CHIP_NAVY_FLOUNDER) &&
+                   (adev->asic_type >= CHIP_SIENNA_CICHLID &&
+                    adev->asic_type <= CHIP_DIMGREY_CAVEFISH) &&
                    (ucode->ucode_id == AMDGPU_UCODE_ID_SDMA1 ||
                     ucode->ucode_id == AMDGPU_UCODE_ID_SDMA2 ||
                     ucode->ucode_id == AMDGPU_UCODE_ID_SDMA3))
@@ -1821,7 +2040,7 @@ static int psp_load_fw(struct amdgpu_device *adev)
        int ret;
        struct psp_context *psp = &adev->psp;
 
-       if (amdgpu_sriov_vf(adev) && adev->in_gpu_reset) {
+       if (amdgpu_sriov_vf(adev) && amdgpu_in_reset(adev)) {
                psp_ring_stop(psp, PSP_RING_TYPE__KM); /* should not destroy ring, only stop */
                goto skip_memalloc;
        }
@@ -1891,6 +2110,11 @@ skip_memalloc:
                if (ret)
                        dev_err(psp->adev->dev,
                                "DTM: Failed to initialize DTM\n");
+
+               ret = psp_rap_initialize(psp);
+               if (ret)
+                       dev_err(psp->adev->dev,
+                               "RAP: Failed to initialize RAP\n");
        }
 
        return 0;
@@ -1941,6 +2165,7 @@ static int psp_hw_fini(void *handle)
 
        if (psp->adev->psp.ta_fw) {
                psp_ras_terminate(psp);
+               psp_rap_terminate(psp);
                psp_dtm_terminate(psp);
                psp_hdcp_terminate(psp);
        }
@@ -1999,6 +2224,11 @@ static int psp_suspend(void *handle)
                        DRM_ERROR("Failed to terminate dtm ta\n");
                        return ret;
                }
+               ret = psp_rap_terminate(psp);
+               if (ret) {
+                       DRM_ERROR("Failed to terminate rap ta\n");
+                       return ret;
+               }
        }
 
        ret = psp_asd_unload(psp);
@@ -2077,6 +2307,11 @@ static int psp_resume(void *handle)
                if (ret)
                        dev_err(psp->adev->dev,
                                "DTM: Failed to initialize DTM\n");
+
+               ret = psp_rap_initialize(psp);
+               if (ret)
+                       dev_err(psp->adev->dev,
+                               "RAP: Failed to initialize RAP\n");
        }
 
        mutex_unlock(&adev->firmware.mutex);
@@ -2187,7 +2422,7 @@ int psp_init_asd_microcode(struct psp_context *psp,
                           const char *chip_name)
 {
        struct amdgpu_device *adev = psp->adev;
-       char fw_name[30];
+       char fw_name[PSP_FW_NAME_LEN];
        const struct psp_firmware_header_v1_0 *asd_hdr;
        int err = 0;
 
@@ -2219,11 +2454,47 @@ out:
        return err;
 }
 
-int psp_init_sos_microcode(struct psp_context *psp,
+int psp_init_toc_microcode(struct psp_context *psp,
                           const char *chip_name)
 {
        struct amdgpu_device *adev = psp->adev;
        char fw_name[30];
+       const struct psp_firmware_header_v1_0 *toc_hdr;
+       int err = 0;
+
+       if (!chip_name) {
+               dev_err(adev->dev, "invalid chip name for toc microcode\n");
+               return -EINVAL;
+       }
+
+       snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_toc.bin", chip_name);
+       err = request_firmware(&adev->psp.toc_fw, fw_name, adev->dev);
+       if (err)
+               goto out;
+
+       err = amdgpu_ucode_validate(adev->psp.toc_fw);
+       if (err)
+               goto out;
+
+       toc_hdr = (const struct psp_firmware_header_v1_0 *)adev->psp.toc_fw->data;
+       adev->psp.toc_fw_version = le32_to_cpu(toc_hdr->header.ucode_version);
+       adev->psp.toc_feature_version = le32_to_cpu(toc_hdr->ucode_feature_version);
+       adev->psp.toc_bin_size = le32_to_cpu(toc_hdr->header.ucode_size_bytes);
+       adev->psp.toc_start_addr = (uint8_t *)toc_hdr +
+                               le32_to_cpu(toc_hdr->header.ucode_array_offset_bytes);
+       return 0;
+out:
+       dev_err(adev->dev, "fail to request/validate toc microcode\n");
+       release_firmware(adev->psp.toc_fw);
+       adev->psp.toc_fw = NULL;
+       return err;
+}
+
+int psp_init_sos_microcode(struct psp_context *psp,
+                          const char *chip_name)
+{
+       struct amdgpu_device *adev = psp->adev;
+       char fw_name[PSP_FW_NAME_LEN];
        const struct psp_firmware_header_v1_0 *sos_hdr;
        const struct psp_firmware_header_v1_1 *sos_hdr_v1_1;
        const struct psp_firmware_header_v1_2 *sos_hdr_v1_2;
@@ -2342,6 +2613,11 @@ int parse_ta_bin_descriptor(struct psp_context *psp,
                psp->ta_dtm_ucode_size     = le32_to_cpu(desc->size_bytes);
                psp->ta_dtm_start_addr     = ucode_start_addr;
                break;
+       case TA_FW_TYPE_PSP_RAP:
+               psp->ta_rap_ucode_version  = le32_to_cpu(desc->fw_version);
+               psp->ta_rap_ucode_size     = le32_to_cpu(desc->size_bytes);
+               psp->ta_rap_start_addr     = ucode_start_addr;
+               break;
        default:
                dev_warn(psp->adev->dev, "Unsupported TA type: %d\n", desc->fw_type);
                break;
@@ -2420,7 +2696,7 @@ static ssize_t psp_usbc_pd_fw_sysfs_read(struct device *dev,
                                         char *buf)
 {
        struct drm_device *ddev = dev_get_drvdata(dev);
-       struct amdgpu_device *adev = ddev->dev_private;
+       struct amdgpu_device *adev = drm_to_adev(ddev);
        uint32_t fw_ver;
        int ret;
 
@@ -2447,7 +2723,7 @@ static ssize_t psp_usbc_pd_fw_sysfs_write(struct device *dev,
                                                       size_t count)
 {
        struct drm_device *ddev = dev_get_drvdata(dev);
-       struct amdgpu_device *adev = ddev->dev_private;
+       struct amdgpu_device *adev = drm_to_adev(ddev);
        void *cpu_addr;
        dma_addr_t dma_addr;
        int ret;