drm/amdgpu: Add interface to load SRIOV cap FW
authorBokun Zhang <Bokun.Zhang@amd.com>
Wed, 12 Jan 2022 15:34:11 +0000 (10:34 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 14 Jan 2022 22:52:00 +0000 (17:52 -0500)
- Add interface to load SRIOV cap FW. If the FW does not
  exist, simply skip this FW loading routine.
  This FW will only be loaded under SRIOV. Other driver
  configuration will not be affected.
  By adding this interface, it will make us easier to
  prepare SRIOV Linux guest driver for different users.

- Update sysfs interface to read cap FW version.

- Refactor PSP FW loading routine under SRIOV to use a
  unified SWITCH statement instead of using IF statement

- Remove redundant amdgpu_sriov_vf() check in FW loading
  routine

Acked-by: Monk Liu <monk.liu@amd.com>
Acked-by: Guchun Chen <guchun.chen@amd.com>
Signed-off-by: Bokun Zhang <Bokun.Zhang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h
drivers/gpu/drm/amd/amdgpu/amdgpu_ucode.h
drivers/gpu/drm/amd/amdgpu/psp_gfx_if.h
drivers/gpu/drm/amd/amdgpu/psp_v11_0.c
drivers/gpu/drm/amd/amdgpu/psp_v3_1.c
include/uapi/drm/amdgpu_drm.h

index 289521aafb794f1d335e9be77a502e8cd7a90d4e..85f06396d18470ec013948faabf1fcb3c0bad7c4 100644 (file)
@@ -400,6 +400,10 @@ static int amdgpu_firmware_info(struct drm_amdgpu_info_firmware *fw_info,
                fw_info->ver = adev->psp.toc.fw_version;
                fw_info->feature = adev->psp.toc.feature_version;
                break;
+       case AMDGPU_INFO_FW_CAP:
+               fw_info->ver = adev->psp.cap_fw_version;
+               fw_info->feature = adev->psp.cap_feature_version;
+               break;
        default:
                return -EINVAL;
        }
@@ -1617,6 +1621,16 @@ static int amdgpu_debugfs_firmware_info_show(struct seq_file *m, void *unused)
        seq_printf(m, "TOC feature version: %u, firmware version: 0x%08x\n",
                   fw_info.feature, fw_info.ver);
 
+       /* CAP */
+       if (adev->psp.cap_fw) {
+               query_fw.fw_type = AMDGPU_INFO_FW_CAP;
+               ret = amdgpu_firmware_info(&fw_info, &query_fw, adev);
+               if (ret)
+                       return ret;
+               seq_printf(m, "CAP feature version: %u, firmware version: 0x%08x\n",
+                               fw_info.feature, fw_info.ver);
+       }
+
        seq_printf(m, "VBIOS version: %s\n", ctx->vbios_version);
 
        return 0;
index dee17a0e11870618a1277545a68cfc464655a073..c984b5a346798a2fb3c63006956cd7917a09ea5a 100644 (file)
@@ -259,6 +259,32 @@ static bool psp_get_runtime_db_entry(struct amdgpu_device *adev,
        return ret;
 }
 
+static int psp_init_sriov_microcode(struct psp_context *psp)
+{
+       struct amdgpu_device *adev = psp->adev;
+       int ret = 0;
+
+       switch (adev->ip_versions[MP0_HWIP][0]) {
+       case IP_VERSION(9, 0, 0):
+               ret = psp_init_cap_microcode(psp, "vega10");
+               break;
+       case IP_VERSION(11, 0, 9):
+               ret = psp_init_cap_microcode(psp, "navi12");
+               break;
+       case IP_VERSION(11, 0, 7):
+               ret = psp_init_cap_microcode(psp, "sienna_cichlid");
+               break;
+       case IP_VERSION(13, 0, 2):
+               ret = psp_init_ta_microcode(psp, "aldebaran");
+               break;
+       default:
+               BUG();
+               break;
+       }
+
+       return ret;
+}
+
 static int psp_sw_init(void *handle)
 {
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
@@ -273,19 +299,13 @@ static int psp_sw_init(void *handle)
                ret = -ENOMEM;
        }
 
-       if (!amdgpu_sriov_vf(adev)) {
+       if (amdgpu_sriov_vf(adev))
+               ret = psp_init_sriov_microcode(psp);
+       else
                ret = psp_init_microcode(psp);
-               if (ret) {
-                       DRM_ERROR("Failed to load psp firmware!\n");
-                       return ret;
-               }
-       } else if (amdgpu_sriov_vf(adev) &&
-                  adev->ip_versions[MP0_HWIP][0] == IP_VERSION(13, 0, 2)) {
-               ret = psp_init_ta_microcode(psp, "aldebaran");
-               if (ret) {
-                       DRM_ERROR("Failed to initialize ta microcode!\n");
-                       return ret;
-               }
+       if (ret) {
+               DRM_ERROR("Failed to load psp firmware!\n");
+               return ret;
        }
 
        memset(&boot_cfg_entry, 0, sizeof(boot_cfg_entry));
@@ -353,6 +373,10 @@ static int psp_sw_fini(void *handle)
                release_firmware(psp->ta_fw);
                psp->ta_fw = NULL;
        }
+       if (adev->psp.cap_fw) {
+               release_firmware(psp->cap_fw);
+               psp->cap_fw = NULL;
+       }
 
        if (adev->ip_versions[MP0_HWIP][0] == IP_VERSION(11, 0, 0) ||
            adev->ip_versions[MP0_HWIP][0] == IP_VERSION(11, 0, 7))
@@ -491,7 +515,10 @@ psp_cmd_submit_buf(struct psp_context *psp,
                DRM_WARN("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 (!timeout) {
+               /* If we load CAP FW, PSP must return 0 under SRIOV
+                * also return failure in case of timeout
+                */
+               if ((ucode && (ucode->ucode_id == AMDGPU_UCODE_ID_CAP)) || !timeout) {
                        ret = -EINVAL;
                        goto exit;
                }
@@ -2051,6 +2078,9 @@ static int psp_get_fw_type(struct amdgpu_firmware_info *ucode,
                           enum psp_gfx_fw_type *type)
 {
        switch (ucode->ucode_id) {
+       case AMDGPU_UCODE_ID_CAP:
+               *type = GFX_FW_TYPE_CAP;
+               break;
        case AMDGPU_UCODE_ID_SDMA0:
                *type = GFX_FW_TYPE_SDMA0;
                break;
@@ -3217,6 +3247,58 @@ out:
        return err;
 }
 
+int psp_init_cap_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 *cap_hdr_v1_0;
+       struct amdgpu_firmware_info *info = NULL;
+       int err = 0;
+
+       if (!chip_name) {
+               dev_err(adev->dev, "invalid chip name for cap microcode\n");
+               return -EINVAL;
+       }
+
+       if (!amdgpu_sriov_vf(adev)) {
+               dev_err(adev->dev, "cap microcode should only be loaded under SRIOV\n");
+               return -EINVAL;
+       }
+
+       snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_cap.bin", chip_name);
+       err = request_firmware(&adev->psp.cap_fw, fw_name, adev->dev);
+       if (err) {
+               dev_warn(adev->dev, "cap microcode does not exist, skip\n");
+               err = 0;
+               goto out;
+       }
+
+       err = amdgpu_ucode_validate(adev->psp.cap_fw);
+       if (err) {
+               dev_err(adev->dev, "fail to initialize cap microcode\n");
+               goto out;
+       }
+
+       info = &adev->firmware.ucode[AMDGPU_UCODE_ID_CAP];
+       info->ucode_id = AMDGPU_UCODE_ID_CAP;
+       info->fw = adev->psp.cap_fw;
+       cap_hdr_v1_0 = (const struct psp_firmware_header_v1_0 *)
+               adev->psp.cap_fw->data;
+       adev->firmware.fw_size += ALIGN(
+                       le32_to_cpu(cap_hdr_v1_0->header.ucode_size_bytes), PAGE_SIZE);
+       adev->psp.cap_fw_version = le32_to_cpu(cap_hdr_v1_0->header.ucode_version);
+       adev->psp.cap_feature_version = le32_to_cpu(cap_hdr_v1_0->sos.fw_version);
+       adev->psp.cap_ucode_size = le32_to_cpu(cap_hdr_v1_0->header.ucode_size_bytes);
+
+       return 0;
+
+out:
+       release_firmware(adev->psp.cap_fw);
+       adev->psp.cap_fw = NULL;
+       return err;
+}
+
 static int psp_set_clockgating_state(void *handle,
                                     enum amd_clockgating_state state)
 {
index f29afabbff1fbee6509742901466fe57ebc17478..ff7d533eb746ce5f267c9be44dc385d64d32df41 100644 (file)
@@ -306,6 +306,9 @@ struct psp_context
        /* toc firmware */
        const struct firmware           *toc_fw;
 
+       /* cap firmware */
+       const struct firmware           *cap_fw;
+
        /* fence buffer */
        struct amdgpu_bo                *fence_buf_bo;
        uint64_t                        fence_buf_mc_addr;
@@ -327,6 +330,10 @@ struct psp_context
        const struct firmware           *ta_fw;
        uint32_t                        ta_fw_version;
 
+       uint32_t                        cap_fw_version;
+       uint32_t                        cap_feature_version;
+       uint32_t                        cap_ucode_size;
+
        struct ta_context               asd_context;
        struct psp_xgmi_context         xgmi_context;
        struct psp_ras_context          ras_context;
@@ -440,6 +447,8 @@ int psp_init_sos_microcode(struct psp_context *psp,
                           const char *chip_name);
 int psp_init_ta_microcode(struct psp_context *psp,
                          const char *chip_name);
+int psp_init_cap_microcode(struct psp_context *psp,
+                         const char *chip_name);
 int psp_get_fw_attestation_records_addr(struct psp_context *psp,
                                        uint64_t *output_ptr);
 
index 7c2538db3cd52be04f86e8f47d8d0e0813833218..428f4df184d083a219b93437f2f756cb17bb35f6 100644 (file)
@@ -378,6 +378,7 @@ enum AMDGPU_UCODE_ID {
        AMDGPU_UCODE_ID_VCN0_RAM,
        AMDGPU_UCODE_ID_VCN1_RAM,
        AMDGPU_UCODE_ID_DMCUB,
+       AMDGPU_UCODE_ID_CAP,
        AMDGPU_UCODE_ID_MAXIMUM,
 };
 
index dd0dce25490137f1fee57218dafd4c4c074b032f..1f276ddd26e9c2ac25ed28d8eb1d0ad775510ab3 100644 (file)
@@ -258,6 +258,7 @@ enum psp_gfx_fw_type {
        GFX_FW_TYPE_SDMA6                           = 56,   /* SDMA6                    MI      */
        GFX_FW_TYPE_SDMA7                           = 57,   /* SDMA7                    MI      */
        GFX_FW_TYPE_VCN1                            = 58,   /* VCN1                     MI      */
+       GFX_FW_TYPE_CAP                             = 62,   /* CAP_FW                           */
        GFX_FW_TYPE_REG_LIST                        = 67,   /* REG_LIST                 MI      */
        GFX_FW_TYPE_MAX
 };
index d0e76b36d4ab1a5565829592606c957e45be7d20..9518b4394a6e7863a5e9b902ec076870b018b946 100644 (file)
@@ -53,11 +53,13 @@ MODULE_FIRMWARE("amdgpu/navi14_ta.bin");
 MODULE_FIRMWARE("amdgpu/navi12_sos.bin");
 MODULE_FIRMWARE("amdgpu/navi12_asd.bin");
 MODULE_FIRMWARE("amdgpu/navi12_ta.bin");
+MODULE_FIRMWARE("amdgpu/navi12_cap.bin");
 MODULE_FIRMWARE("amdgpu/arcturus_sos.bin");
 MODULE_FIRMWARE("amdgpu/arcturus_asd.bin");
 MODULE_FIRMWARE("amdgpu/arcturus_ta.bin");
 MODULE_FIRMWARE("amdgpu/sienna_cichlid_sos.bin");
 MODULE_FIRMWARE("amdgpu/sienna_cichlid_ta.bin");
+MODULE_FIRMWARE("amdgpu/sienna_cichlid_cap.bin");
 MODULE_FIRMWARE("amdgpu/navy_flounder_sos.bin");
 MODULE_FIRMWARE("amdgpu/navy_flounder_ta.bin");
 MODULE_FIRMWARE("amdgpu/vangogh_asd.bin");
@@ -177,8 +179,6 @@ static int psp_v11_0_init_microcode(struct psp_context *psp)
                err = psp_init_asd_microcode(psp, chip_name);
                if (err)
                        return err;
-               if (amdgpu_sriov_vf(adev))
-                       break;
                snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_ta.bin", chip_name);
                err = request_firmware(&adev->psp.ta_fw, fw_name, adev->dev);
                if (err) {
index 1ed357cb0f49014a18afa78d4b6ad42abe8295bb..01f3bcc62a6c72a927abdfdf621252119803fc95 100644 (file)
@@ -44,6 +44,7 @@
 
 MODULE_FIRMWARE("amdgpu/vega10_sos.bin");
 MODULE_FIRMWARE("amdgpu/vega10_asd.bin");
+MODULE_FIRMWARE("amdgpu/vega10_cap.bin");
 MODULE_FIRMWARE("amdgpu/vega12_sos.bin");
 MODULE_FIRMWARE("amdgpu/vega12_asd.bin");
 
index 0b94ec7b73e78883ad4ef54ccf6842bd19e4c58a..be4f9111f478807c46590941f4fec01ccb865b5c 100644 (file)
@@ -728,6 +728,8 @@ struct drm_amdgpu_cs_chunk_data {
        #define AMDGPU_INFO_FW_DMCUB            0x14
        /* Subquery id: Query TOC firmware version */
        #define AMDGPU_INFO_FW_TOC              0x15
+       /* Subquery id: Query CAP firmware version */
+       #define AMDGPU_INFO_FW_CAP              0x16
 
 /* number of bytes moved for TTM migration */
 #define AMDGPU_INFO_NUM_BYTES_MOVED            0x0f