drm/amd/pm: fix Navi1x runtime resume failure V2
authorEvan Quan <evan.quan@amd.com>
Wed, 17 Mar 2021 04:10:15 +0000 (12:10 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 9 Apr 2021 20:37:53 +0000 (16:37 -0400)
The RLC was put into a wrong state on runtime suspend. Thus the RLC
autoload will fail on the succeeding runtime resume. By adding an
intermediate PPSMC_MSG_PrepareMp1ForUnload(some GC hard reset involved,
designed for PnP), we can bring RLC back into the desired state.

V2: integrate INTERRUPTS_ENABLED flag clearing into current
    mp1 state set routines

Signed-off-by: Evan Quan <evan.quan@amd.com>
Reviewed-by: Lijo Lazar <lijo.lazar@amd.com>
Reviewed-by: Guchun Chen <guchun.chen@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdgpu/amdgpu_psp.c
drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu13/aldebaran_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu_cmn.c
drivers/gpu/drm/amd/pm/swsmu/smu_cmn.h

index bae304b..c2b7ee6 100644 (file)
@@ -2146,9 +2146,12 @@ static int psp_load_smu_fw(struct psp_context *psp)
        if (!ucode->fw || amdgpu_sriov_vf(psp->adev))
                return 0;
 
-
-       if (amdgpu_in_reset(adev) && ras && ras->supported &&
-               adev->asic_type == CHIP_ARCTURUS) {
+       if ((amdgpu_in_reset(adev) &&
+            ras && ras->supported &&
+            adev->asic_type == CHIP_ARCTURUS) ||
+            (adev->in_runpm &&
+             adev->asic_type >= CHIP_NAVI10 &&
+             adev->asic_type <= CHIP_NAVI12)) {
                ret = amdgpu_dpm_set_mp1_state(adev, PP_MP1_STATE_UNLOAD);
                if (ret) {
                        DRM_WARN("Failed to set MP1 state prepare for reload\n");
index 25d5f03..2edb634 100644 (file)
@@ -807,6 +807,13 @@ struct pptable_funcs {
        int (*check_fw_status)(struct smu_context *smu);
 
        /**
+        * @set_mp1_state: put SMU into a correct state for comming
+        *                 resume from runpm or gpu reset.
+        */
+       int (*set_mp1_state)(struct smu_context *smu,
+                            enum pp_mp1_state mp1_state);
+
+       /**
         * @setup_pptable: Initialize the power play table and populate it with
         *                 default values.
         */
index 143e378..05f0090 100644 (file)
@@ -1908,36 +1908,16 @@ int smu_set_mp1_state(void *handle,
                      enum pp_mp1_state mp1_state)
 {
        struct smu_context *smu = handle;
-       uint16_t msg;
-       int ret;
+       int ret = 0;
 
        if (!smu->pm_enabled)
                return -EOPNOTSUPP;
 
        mutex_lock(&smu->mutex);
 
-       switch (mp1_state) {
-       case PP_MP1_STATE_SHUTDOWN:
-               msg = SMU_MSG_PrepareMp1ForShutdown;
-               break;
-       case PP_MP1_STATE_UNLOAD:
-               msg = SMU_MSG_PrepareMp1ForUnload;
-               break;
-       case PP_MP1_STATE_RESET:
-               msg = SMU_MSG_PrepareMp1ForReset;
-               break;
-       case PP_MP1_STATE_NONE:
-       default:
-               mutex_unlock(&smu->mutex);
-               return 0;
-       }
-
-       ret = smu_send_smc_msg(smu, msg, NULL);
-       /* some asics may not support those messages */
-       if (ret == -EINVAL)
-               ret = 0;
-       if (ret)
-               dev_err(smu->adev->dev, "[PrepareMp1] Failed!\n");
+       if (smu->ppt_funcs &&
+           smu->ppt_funcs->set_mp1_state)
+               ret = smu->ppt_funcs->set_mp1_state(smu, mp1_state);
 
        mutex_unlock(&smu->mutex);
 
index bbc0309..77693bf 100644 (file)
@@ -2365,6 +2365,7 @@ static const struct pptable_funcs arcturus_ppt_funcs = {
        .get_fan_parameters = arcturus_get_fan_parameters,
        .interrupt_work = smu_v11_0_interrupt_work,
        .set_light_sbr = smu_v11_0_set_light_sbr,
+       .set_mp1_state = smu_cmn_set_mp1_state,
 };
 
 void arcturus_set_ppt_funcs(struct smu_context *smu)
index 3d0de2c..f827096 100644 (file)
@@ -431,6 +431,30 @@ static int navi10_store_powerplay_table(struct smu_context *smu)
        return 0;
 }
 
+static int navi10_set_mp1_state(struct smu_context *smu,
+                               enum pp_mp1_state mp1_state)
+{
+       struct amdgpu_device *adev = smu->adev;
+       uint32_t mp1_fw_flags;
+       int ret = 0;
+
+       ret = smu_cmn_set_mp1_state(smu, mp1_state);
+       if (ret)
+               return ret;
+
+       if (mp1_state == PP_MP1_STATE_UNLOAD) {
+               mp1_fw_flags = RREG32_PCIE(MP1_Public |
+                                          (smnMP1_FIRMWARE_FLAGS & 0xffffffff));
+
+               mp1_fw_flags &= ~MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK;
+
+               WREG32_PCIE(MP1_Public |
+                           (smnMP1_FIRMWARE_FLAGS & 0xffffffff), mp1_fw_flags);
+       }
+
+       return 0;
+}
+
 static int navi10_setup_pptable(struct smu_context *smu)
 {
        int ret = 0;
@@ -3031,6 +3055,7 @@ static const struct pptable_funcs navi10_ppt_funcs = {
        .get_fan_parameters = navi10_get_fan_parameters,
        .post_init = navi10_post_smu_init,
        .interrupt_work = smu_v11_0_interrupt_work,
+       .set_mp1_state = navi10_set_mp1_state,
 };
 
 void navi10_set_ppt_funcs(struct smu_context *smu)
index 3621884..722fe06 100644 (file)
@@ -3110,6 +3110,19 @@ static int sienna_cichlid_system_features_control(struct smu_context *smu,
        return smu_v11_0_system_features_control(smu, en);
 }
 
+static int sienna_cichlid_set_mp1_state(struct smu_context *smu,
+                                       enum pp_mp1_state mp1_state)
+{
+       switch (mp1_state) {
+       case PP_MP1_STATE_UNLOAD:
+               return smu_cmn_set_mp1_state(smu, mp1_state);
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
        .get_allowed_feature_mask = sienna_cichlid_get_allowed_feature_mask,
        .set_default_dpm_table = sienna_cichlid_set_default_dpm_table,
@@ -3195,6 +3208,7 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
        .get_fan_parameters = sienna_cichlid_get_fan_parameters,
        .interrupt_work = smu_v11_0_interrupt_work,
        .gpo_control = sienna_cichlid_gpo_control,
+       .set_mp1_state = sienna_cichlid_set_mp1_state,
 };
 
 void sienna_cichlid_set_ppt_funcs(struct smu_context *smu)
index 9813a86..7d38b92 100644 (file)
@@ -1460,6 +1460,19 @@ static bool aldebaran_is_mode2_reset_supported(struct smu_context *smu)
        return true;
 }
 
+static int aldebaran_set_mp1_state(struct smu_context *smu,
+                                  enum pp_mp1_state mp1_state)
+{
+       switch (mp1_state) {
+       case PP_MP1_STATE_UNLOAD:
+               return smu_cmn_set_mp1_state(smu, mp1_state);
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static const struct pptable_funcs aldebaran_ppt_funcs = {
        /* init dpm */
        .get_allowed_feature_mask = aldebaran_get_allowed_feature_mask,
@@ -1518,6 +1531,7 @@ static const struct pptable_funcs aldebaran_ppt_funcs = {
        .mode2_reset_is_support = aldebaran_is_mode2_reset_supported,
        .mode1_reset = smu_v13_0_mode1_reset,
        .mode2_reset = smu_v13_0_mode2_reset,
+       .set_mp1_state = aldebaran_set_mp1_state,
 };
 
 void aldebaran_set_ppt_funcs(struct smu_context *smu)
index 4b45953..2d216f5 100644 (file)
@@ -780,3 +780,31 @@ void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev)
        header->structure_size = structure_size;
 
 }
+
+int smu_cmn_set_mp1_state(struct smu_context *smu,
+                         enum pp_mp1_state mp1_state)
+{
+       enum smu_message_type msg;
+       int ret;
+
+       switch (mp1_state) {
+       case PP_MP1_STATE_SHUTDOWN:
+               msg = SMU_MSG_PrepareMp1ForShutdown;
+               break;
+       case PP_MP1_STATE_UNLOAD:
+               msg = SMU_MSG_PrepareMp1ForUnload;
+               break;
+       case PP_MP1_STATE_RESET:
+               msg = SMU_MSG_PrepareMp1ForReset;
+               break;
+       case PP_MP1_STATE_NONE:
+       default:
+               return 0;
+       }
+
+       ret = smu_cmn_send_smc_msg(smu, msg, NULL);
+       if (ret)
+               dev_err(smu->adev->dev, "[PrepareMp1] Failed!\n");
+
+       return ret;
+}
index c692501..155e2a6 100644 (file)
@@ -99,5 +99,8 @@ int smu_cmn_get_metrics_table(struct smu_context *smu,
 
 void smu_cmn_init_soft_gpu_metrics(void *table, uint8_t frev, uint8_t crev);
 
+int smu_cmn_set_mp1_state(struct smu_context *smu,
+                         enum pp_mp1_state mp1_state);
+
 #endif
 #endif