drm/amd/powerplay: bug fix for pcie parameters override
authorKenneth Feng <kenneth.feng@amd.com>
Fri, 11 Oct 2019 09:51:34 +0000 (17:51 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 15 Oct 2019 19:50:37 +0000 (15:50 -0400)
Bug fix for pcie paramerers override on swsmu.
Below is a scenario to have this problem.
pptable definition on pcie dpm:
0 -> pcie gen speed:1, pcie lanes: *16
1 -> pcie gen speed:4, pcie lanes: *16
Then if we have a system only have the capbility:
pcie gen speed: 3, pcie lanes: *8,
we will override dpm 1 to pcie gen speed 3, pcie lanes *8.
But the code skips the dpm 0 configuration.
So the real pcie dpm parameters are:
0 -> pcie gen speed:1, pcie lanes: *16
1 -> pcie gen speed:3, pcie lanes: *8
Then the wrong pcie lanes will be toggled.

Signed-off-by: Kenneth Feng <kenneth.feng@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: Evan Quan <evan.quan@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/powerplay/amdgpu_smu.c
drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h
drivers/gpu/drm/amd/powerplay/navi10_ppt.c
drivers/gpu/drm/amd/powerplay/smu_v11_0.c
drivers/gpu/drm/amd/powerplay/vega20_ppt.c

index 8bb5287fe711f51fdf4920f71dcd16eb76d12007..6cb52881e95518597c6ce4108bae099aa1059b07 100644 (file)
@@ -945,50 +945,6 @@ static int smu_fini_fb_allocations(struct smu_context *smu)
        return 0;
 }
 
-static int smu_override_pcie_parameters(struct smu_context *smu)
-{
-       struct amdgpu_device *adev = smu->adev;
-       uint32_t pcie_gen = 0, pcie_width = 0, smu_pcie_arg;
-       int ret;
-
-       if (adev->flags & AMD_IS_APU)
-               return 0;
-
-       if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4)
-               pcie_gen = 3;
-       else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
-               pcie_gen = 2;
-       else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2)
-               pcie_gen = 1;
-       else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1)
-               pcie_gen = 0;
-
-       /* Bit 31:16: LCLK DPM level. 0 is DPM0, and 1 is DPM1
-        * Bit 15:8:  PCIE GEN, 0 to 3 corresponds to GEN1 to GEN4
-        * Bit 7:0:   PCIE lane width, 1 to 7 corresponds is x1 to x32
-        */
-       if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X16)
-               pcie_width = 6;
-       else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X12)
-               pcie_width = 5;
-       else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X8)
-               pcie_width = 4;
-       else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X4)
-               pcie_width = 3;
-       else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X2)
-               pcie_width = 2;
-       else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X1)
-               pcie_width = 1;
-
-       smu_pcie_arg = (1 << 16) | (pcie_gen << 8) | pcie_width;
-       ret = smu_send_smc_msg_with_param(smu,
-                                         SMU_MSG_OverridePcieParameters,
-                                         smu_pcie_arg);
-       if (ret)
-               pr_err("[%s] Attempt to override pcie params failed!\n", __func__);
-       return ret;
-}
-
 static int smu_smc_table_hw_init(struct smu_context *smu,
                                 bool initialize)
 {
index 401affdee49dce6964da14aa58314a15396bab92..cdb845f5f23e70d03dcb51c293a2cbedb1deebf1 100644 (file)
@@ -469,6 +469,7 @@ struct pptable_funcs {
        int (*get_dpm_clk_limited)(struct smu_context *smu, enum smu_clk_type clk_type,
                                   uint32_t dpm_level, uint32_t *freq);
        int (*set_df_cstate)(struct smu_context *smu, enum pp_df_cstate state);
+       int (*update_pcie_parameters)(struct smu_context *smu, uint32_t pcie_gen_cap, uint32_t pcie_width_cap);
 };
 
 struct smu_funcs
@@ -551,6 +552,7 @@ struct smu_funcs
        int (*mode2_reset)(struct smu_context *smu);
        int (*get_dpm_ultimate_freq)(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t *min, uint32_t *max);
        int (*set_soft_freq_limited_range)(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t min, uint32_t max);
+       int (*override_pcie_parameters)(struct smu_context *smu);
 };
 
 #define smu_init_microcode(smu) \
@@ -783,6 +785,12 @@ struct smu_funcs
 #define smu_set_soft_freq_limited_range(smu, clk_type, min, max) \
                ((smu)->funcs->set_soft_freq_limited_range ? (smu)->funcs->set_soft_freq_limited_range((smu), (clk_type), (min), (max)) : -EINVAL)
 
+#define smu_override_pcie_parameters(smu) \
+               ((smu)->funcs->override_pcie_parameters ? (smu)->funcs->override_pcie_parameters((smu)) : 0)
+
+#define smu_update_pcie_parameters(smu, pcie_gen_cap, pcie_width_cap) \
+               ((smu)->ppt_funcs->update_pcie_parameters ? (smu)->ppt_funcs->update_pcie_parameters((smu), (pcie_gen_cap), (pcie_width_cap)) : 0)
+
 extern int smu_get_atom_data_table(struct smu_context *smu, uint32_t table,
                                   uint16_t *size, uint8_t *frev, uint8_t *crev,
                                   uint8_t **addr);
index 22be714ab222c9f4756e938a33edab56c4e9aae9..d59ec114f824ab14650250bbb5636a838bb318cb 100644 (file)
@@ -1629,6 +1629,28 @@ static int navi10_get_power_limit(struct smu_context *smu,
        return 0;
 }
 
+static int navi10_update_pcie_parameters(struct smu_context *smu,
+                                    uint32_t pcie_gen_cap,
+                                    uint32_t pcie_width_cap)
+{
+       PPTable_t *pptable = smu->smu_table.driver_pptable;
+       int ret, i;
+       uint32_t smu_pcie_arg;
+
+       for (i = 0; i < NUM_LINK_LEVELS; i++) {
+               smu_pcie_arg = (i << 16) |
+                       ((pptable->PcieGenSpeed[i] <= pcie_gen_cap) ? (pptable->PcieGenSpeed[i] << 8) :
+                               (pcie_gen_cap << 8)) | ((pptable->PcieLaneCount[i] <= pcie_width_cap) ?
+                                       pptable->PcieLaneCount[i] : pcie_width_cap);
+               ret = smu_send_smc_msg_with_param(smu,
+                                         SMU_MSG_OverridePcieParameters,
+                                         smu_pcie_arg);
+       }
+
+       return ret;
+}
+
+
 static const struct pptable_funcs navi10_ppt_funcs = {
        .tables_init = navi10_tables_init,
        .alloc_dpm_context = navi10_allocate_dpm_context,
@@ -1667,6 +1689,7 @@ static const struct pptable_funcs navi10_ppt_funcs = {
        .get_thermal_temperature_range = navi10_get_thermal_temperature_range,
        .display_disable_memory_clock_switch = navi10_display_disable_memory_clock_switch,
        .get_power_limit = navi10_get_power_limit,
+       .update_pcie_parameters = navi10_update_pcie_parameters,
 };
 
 void navi10_set_ppt_funcs(struct smu_context *smu)
index c9e90d59a6b8f1a03c271a9bbdd4620d11e71bcf..a812ae59a94b122c21f6a22afdd5ee1de10287b0 100644 (file)
@@ -35,6 +35,7 @@
 #include "vega20_ppt.h"
 #include "arcturus_ppt.h"
 #include "navi10_ppt.h"
+#include "amd_pcie.h"
 
 #include "asic_reg/thm/thm_11_0_2_offset.h"
 #include "asic_reg/thm/thm_11_0_2_sh_mask.h"
@@ -1792,6 +1793,48 @@ static int smu_v11_0_set_soft_freq_limited_range(struct smu_context *smu, enum s
        return ret;
 }
 
+static int smu_v11_0_override_pcie_parameters(struct smu_context *smu)
+{
+       struct amdgpu_device *adev = smu->adev;
+       uint32_t pcie_gen = 0, pcie_width = 0;
+       int ret;
+
+       if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4)
+               pcie_gen = 3;
+       else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
+               pcie_gen = 2;
+       else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2)
+               pcie_gen = 1;
+       else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1)
+               pcie_gen = 0;
+
+       /* Bit 31:16: LCLK DPM level. 0 is DPM0, and 1 is DPM1
+        * Bit 15:8:  PCIE GEN, 0 to 3 corresponds to GEN1 to GEN4
+        * Bit 7:0:   PCIE lane width, 1 to 7 corresponds is x1 to x32
+        */
+       if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X16)
+               pcie_width = 6;
+       else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X12)
+               pcie_width = 5;
+       else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X8)
+               pcie_width = 4;
+       else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X4)
+               pcie_width = 3;
+       else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X2)
+               pcie_width = 2;
+       else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X1)
+               pcie_width = 1;
+
+       ret = smu_update_pcie_parameters(smu, pcie_gen, pcie_width);
+
+       if (ret)
+               pr_err("[%s] Attempt to override pcie params failed!\n", __func__);
+
+       return ret;
+
+}
+
+
 static const struct smu_funcs smu_v11_0_funcs = {
        .init_microcode = smu_v11_0_init_microcode,
        .load_microcode = smu_v11_0_load_microcode,
@@ -1844,6 +1887,7 @@ static const struct smu_funcs smu_v11_0_funcs = {
        .baco_reset = smu_v11_0_baco_reset,
        .get_dpm_ultimate_freq = smu_v11_0_get_dpm_ultimate_freq,
        .set_soft_freq_limited_range = smu_v11_0_set_soft_freq_limited_range,
+       .override_pcie_parameters = smu_v11_0_override_pcie_parameters,
 };
 
 void smu_v11_0_set_smu_funcs(struct smu_context *smu)
index 3fc6ad088e195e3715ce114dc5f815ae5955e717..bebf38ca4be7e6d5576feccea2340c97962989d7 100644 (file)
@@ -3157,6 +3157,28 @@ static int vega20_set_df_cstate(struct smu_context *smu,
        return smu_send_smc_msg_with_param(smu, SMU_MSG_DFCstateControl, state);
 }
 
+static int vega20_update_pcie_parameters(struct smu_context *smu,
+                                    uint32_t pcie_gen_cap,
+                                    uint32_t pcie_width_cap)
+{
+       PPTable_t *pptable = smu->smu_table.driver_pptable;
+       int ret, i;
+       uint32_t smu_pcie_arg;
+
+       for (i = 0; i < NUM_LINK_LEVELS; i++) {
+               smu_pcie_arg = (i << 16) |
+                       ((pptable->PcieGenSpeed[i] <= pcie_gen_cap) ? (pptable->PcieGenSpeed[i] << 8) :
+                               (pcie_gen_cap << 8)) | ((pptable->PcieLaneCount[i] <= pcie_width_cap) ?
+                                       pptable->PcieLaneCount[i] : pcie_width_cap);
+               ret = smu_send_smc_msg_with_param(smu,
+                                         SMU_MSG_OverridePcieParameters,
+                                         smu_pcie_arg);
+       }
+
+       return ret;
+}
+
+
 static const struct pptable_funcs vega20_ppt_funcs = {
        .tables_init = vega20_tables_init,
        .alloc_dpm_context = vega20_allocate_dpm_context,
@@ -3201,6 +3223,7 @@ static const struct pptable_funcs vega20_ppt_funcs = {
        .set_watermarks_table = vega20_set_watermarks_table,
        .get_thermal_temperature_range = vega20_get_thermal_temperature_range,
        .set_df_cstate = vega20_set_df_cstate,
+       .update_pcie_parameters = vega20_update_pcie_parameters
 };
 
 void vega20_set_ppt_funcs(struct smu_context *smu)