drm/amdgpu: add psp ras subsystem infrastructure (v2)
authorxinhui pan <xinhui.pan@amd.com>
Wed, 21 Nov 2018 03:17:49 +0000 (11:17 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 19 Mar 2019 20:36:50 +0000 (15:36 -0500)
Add ras fw loading, init, terminate.
Add ras cmd submit helper.
Add ras feature enable/disable common function.

v2: squash in unused variable warning fix

Signed-off-by: xinhui pan <xinhui.pan@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.h

index 3091488cd8cca9c823ba707c7fa42f48b756b5ca..c1b86201624535652ef965e6d3e1edf7230d0888 100644 (file)
@@ -466,6 +466,206 @@ static int psp_xgmi_initialize(struct psp_context *psp)
        return ret;
 }
 
+// ras begin
+static void psp_prep_ras_ta_load_cmd_buf(struct psp_gfx_cmd_resp *cmd,
+               uint64_t ras_ta_mc, uint64_t ras_mc_shared,
+               uint32_t ras_ta_size, uint32_t shared_size)
+{
+       cmd->cmd_id = GFX_CMD_ID_LOAD_TA;
+       cmd->cmd.cmd_load_ta.app_phy_addr_lo = lower_32_bits(ras_ta_mc);
+       cmd->cmd.cmd_load_ta.app_phy_addr_hi = upper_32_bits(ras_ta_mc);
+       cmd->cmd.cmd_load_ta.app_len = ras_ta_size;
+
+       cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_lo = lower_32_bits(ras_mc_shared);
+       cmd->cmd.cmd_load_ta.cmd_buf_phy_addr_hi = upper_32_bits(ras_mc_shared);
+       cmd->cmd.cmd_load_ta.cmd_buf_len = shared_size;
+}
+
+static int psp_ras_init_shared_buf(struct psp_context *psp)
+{
+       int ret;
+
+       /*
+        * Allocate 16k memory aligned to 4k from Frame Buffer (local
+        * physical) for ras ta <-> Driver
+        */
+       ret = amdgpu_bo_create_kernel(psp->adev, PSP_RAS_SHARED_MEM_SIZE,
+                       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM,
+                       &psp->ras.ras_shared_bo,
+                       &psp->ras.ras_shared_mc_addr,
+                       &psp->ras.ras_shared_buf);
+
+       return ret;
+}
+
+static int psp_ras_load(struct psp_context *psp)
+{
+       int ret;
+       struct psp_gfx_cmd_resp *cmd;
+
+       /*
+        * TODO: bypass the loading in sriov for now
+        */
+       if (amdgpu_sriov_vf(psp->adev))
+               return 0;
+
+       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_ras_start_addr, psp->ta_ras_ucode_size);
+
+       psp_prep_ras_ta_load_cmd_buf(cmd, psp->fw_pri_mc_addr,
+                       psp->ras.ras_shared_mc_addr,
+                       psp->ta_ras_ucode_size, PSP_RAS_SHARED_MEM_SIZE);
+
+       ret = psp_cmd_submit_buf(psp, NULL, cmd,
+                       psp->fence_buf_mc_addr);
+
+       if (!ret) {
+               psp->ras.ras_initialized = 1;
+               psp->ras.session_id = cmd->resp.session_id;
+       }
+
+       kfree(cmd);
+
+       return ret;
+}
+
+static void psp_prep_ras_ta_unload_cmd_buf(struct psp_gfx_cmd_resp *cmd,
+                                               uint32_t ras_session_id)
+{
+       cmd->cmd_id = GFX_CMD_ID_UNLOAD_TA;
+       cmd->cmd.cmd_unload_ta.session_id = ras_session_id;
+}
+
+static int psp_ras_unload(struct psp_context *psp)
+{
+       int ret;
+       struct psp_gfx_cmd_resp *cmd;
+
+       /*
+        * TODO: bypass the unloading in sriov for now
+        */
+       if (amdgpu_sriov_vf(psp->adev))
+               return 0;
+
+       cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       psp_prep_ras_ta_unload_cmd_buf(cmd, psp->ras.session_id);
+
+       ret = psp_cmd_submit_buf(psp, NULL, cmd,
+                       psp->fence_buf_mc_addr);
+
+       kfree(cmd);
+
+       return ret;
+}
+
+static void psp_prep_ras_ta_invoke_cmd_buf(struct psp_gfx_cmd_resp *cmd,
+               uint32_t ta_cmd_id,
+               uint32_t ras_session_id)
+{
+       cmd->cmd_id = GFX_CMD_ID_INVOKE_CMD;
+       cmd->cmd.cmd_invoke_cmd.session_id = ras_session_id;
+       cmd->cmd.cmd_invoke_cmd.ta_cmd_id = ta_cmd_id;
+       /* Note: cmd_invoke_cmd.buf is not used for now */
+}
+
+int psp_ras_invoke(struct psp_context *psp, uint32_t ta_cmd_id)
+{
+       int ret;
+       struct psp_gfx_cmd_resp *cmd;
+
+       /*
+        * TODO: bypass the loading in sriov for now
+        */
+       if (amdgpu_sriov_vf(psp->adev))
+               return 0;
+
+       cmd = kzalloc(sizeof(struct psp_gfx_cmd_resp), GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       psp_prep_ras_ta_invoke_cmd_buf(cmd, ta_cmd_id,
+                       psp->ras.session_id);
+
+       ret = psp_cmd_submit_buf(psp, NULL, cmd,
+                       psp->fence_buf_mc_addr);
+
+       kfree(cmd);
+
+       return ret;
+}
+
+int psp_ras_enable_features(struct psp_context *psp,
+               union ta_ras_cmd_input *info, bool enable)
+{
+       struct ta_ras_shared_memory *ras_cmd;
+       int ret;
+
+       if (!psp->ras.ras_initialized)
+               return -EINVAL;
+
+       ras_cmd = (struct ta_ras_shared_memory *)psp->ras.ras_shared_buf;
+       memset(ras_cmd, 0, sizeof(struct ta_ras_shared_memory));
+
+       if (enable)
+               ras_cmd->cmd_id = TA_RAS_COMMAND__ENABLE_FEATURES;
+       else
+               ras_cmd->cmd_id = TA_RAS_COMMAND__DISABLE_FEATURES;
+
+       ras_cmd->ras_in_message = *info;
+
+       ret = psp_ras_invoke(psp, ras_cmd->cmd_id);
+       if (ret)
+               return -EINVAL;
+
+       return ras_cmd->ras_status;
+}
+
+static int psp_ras_terminate(struct psp_context *psp)
+{
+       int ret;
+
+       if (!psp->ras.ras_initialized)
+               return 0;
+
+       ret = psp_ras_unload(psp);
+       if (ret)
+               return ret;
+
+       psp->ras.ras_initialized = 0;
+
+       /* free ras shared memory */
+       amdgpu_bo_free_kernel(&psp->ras.ras_shared_bo,
+                       &psp->ras.ras_shared_mc_addr,
+                       &psp->ras.ras_shared_buf);
+
+       return 0;
+}
+
+static int psp_ras_initialize(struct psp_context *psp)
+{
+       int ret;
+
+       if (!psp->ras.ras_initialized) {
+               ret = psp_ras_init_shared_buf(psp);
+               if (ret)
+                       return ret;
+       }
+
+       ret = psp_ras_load(psp);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+// ras end
+
 static int psp_hw_start(struct psp_context *psp)
 {
        struct amdgpu_device *adev = psp->adev;
@@ -502,6 +702,12 @@ static int psp_hw_start(struct psp_context *psp)
                        dev_err(psp->adev->dev,
                                "XGMI: Failed to initialize XGMI session\n");
        }
+
+       ret = psp_ras_initialize(psp);
+       if (ret)
+               dev_err(psp->adev->dev,
+                               "RAS: Failed to initialize RAS\n");
+
        return 0;
 }
 
@@ -753,6 +959,8 @@ static int psp_hw_fini(void *handle)
            psp->xgmi_context.initialized == 1)
                 psp_xgmi_terminate(psp);
 
+       psp_ras_terminate(psp);
+
        psp_ring_destroy(psp, PSP_RING_TYPE__KM);
 
        amdgpu_bo_free_kernel(&psp->tmr_bo, &psp->tmr_mc_addr, &psp->tmr_buf);
@@ -786,6 +994,12 @@ static int psp_suspend(void *handle)
                }
        }
 
+       ret = psp_ras_terminate(psp);
+       if (ret) {
+               DRM_ERROR("Failed to terminate ras ta\n");
+               return ret;
+       }
+
        ret = psp_ring_stop(psp, PSP_RING_TYPE__KM);
        if (ret) {
                DRM_ERROR("PSP ring stop failed\n");
index 3e6fcc9cdef014e427832036ca8f3f0c0853fe04..9c067e760a5f4af4522015abf3caf20baafb2161 100644 (file)
@@ -34,6 +34,7 @@
 #define PSP_CMD_BUFFER_SIZE    0x1000
 #define PSP_ASD_SHARED_MEM_SIZE 0x4000
 #define PSP_XGMI_SHARED_MEM_SIZE 0x4000
+#define PSP_RAS_SHARED_MEM_SIZE 0x4000
 #define PSP_1_MEG              0x100000
 #define PSP_TMR_SIZE   0x400000
 
@@ -102,6 +103,15 @@ struct psp_xgmi_context {
        void                            *xgmi_shared_buf;
 };
 
+struct psp_ras_context {
+       /*ras fw*/
+       bool                    ras_initialized;
+       uint32_t                session_id;
+       struct amdgpu_bo        *ras_shared_bo;
+       uint64_t                ras_shared_mc_addr;
+       void                    *ras_shared_buf;
+};
+
 struct psp_context
 {
        struct amdgpu_device            *adev;
@@ -162,6 +172,7 @@ struct psp_context
        uint32_t                        ta_ras_ucode_size;
        uint8_t                         *ta_ras_start_addr;
        struct psp_xgmi_context         xgmi_context;
+       struct psp_ras_context          ras;
 };
 
 struct amdgpu_psp_funcs {
@@ -232,6 +243,11 @@ extern const struct amdgpu_ip_block_version psp_v10_0_ip_block;
 
 int psp_gpu_reset(struct amdgpu_device *adev);
 int psp_xgmi_invoke(struct psp_context *psp, uint32_t ta_cmd_id);
+
+int psp_ras_invoke(struct psp_context *psp, uint32_t ta_cmd_id);
+int psp_ras_enable_features(struct psp_context *psp,
+               union ta_ras_cmd_input *info, bool enable);
+
 extern const struct amdgpu_ip_block_version psp_v11_0_ip_block;
 
 #endif