Merge tag 'drm-misc-next-fixes-2021-09-09' of git://anongit.freedesktop.org/drm/drm...
[linux-2.6-microblaze.git] / drivers / gpu / drm / amd / pm / swsmu / smu11 / sienna_cichlid_ppt.c
index fb5b3ea..5e292c3 100644 (file)
@@ -353,8 +353,7 @@ static void sienna_cichlid_check_bxco_support(struct smu_context *smu)
        struct amdgpu_device *adev = smu->adev;
        uint32_t val;
 
-       if (powerplay_table->platform_caps & SMU_11_0_7_PP_PLATFORM_CAP_BACO ||
-           powerplay_table->platform_caps & SMU_11_0_7_PP_PLATFORM_CAP_MACO) {
+       if (powerplay_table->platform_caps & SMU_11_0_7_PP_PLATFORM_CAP_BACO) {
                val = RREG32_SOC15(NBIO, 0, mmRCC_BIF_STRAP0);
                smu_baco->platform_support =
                        (val & RCC_BIF_STRAP0__STRAP_PX_CAPABLE_MASK) ? true :
@@ -489,6 +488,26 @@ err0_out:
        return -ENOMEM;
 }
 
+static uint32_t sienna_cichlid_get_throttler_status_locked(struct smu_context *smu)
+{
+       struct smu_table_context *smu_table= &smu->smu_table;
+       SmuMetricsExternal_t *metrics_ext =
+               (SmuMetricsExternal_t *)(smu_table->metrics_table);
+       uint32_t throttler_status = 0;
+       int i;
+
+       if ((smu->adev->asic_type == CHIP_SIENNA_CICHLID) &&
+            (smu->smc_fw_version >= 0x3A4300)) {
+               for (i = 0; i < THROTTLER_COUNT; i++)
+                       throttler_status |=
+                               (metrics_ext->SmuMetrics_V2.ThrottlingPercentage[i] ? 1U << i : 0);
+       } else {
+               throttler_status = metrics_ext->SmuMetrics.ThrottlerStatus;
+       }
+
+       return throttler_status;
+}
+
 static int sienna_cichlid_get_smu_metrics_data(struct smu_context *smu,
                                               MetricsMember_t member,
                                               uint32_t *value)
@@ -496,6 +515,11 @@ static int sienna_cichlid_get_smu_metrics_data(struct smu_context *smu,
        struct smu_table_context *smu_table= &smu->smu_table;
        SmuMetrics_t *metrics =
                &(((SmuMetricsExternal_t *)(smu_table->metrics_table))->SmuMetrics);
+       SmuMetrics_V2_t *metrics_v2 =
+               &(((SmuMetricsExternal_t *)(smu_table->metrics_table))->SmuMetrics_V2);
+       bool use_metrics_v2 = ((smu->adev->asic_type == CHIP_SIENNA_CICHLID) &&
+               (smu->smc_fw_version >= 0x3A4300)) ? true : false;
+       uint16_t average_gfx_activity;
        int ret = 0;
 
        mutex_lock(&smu->metrics_lock);
@@ -510,78 +534,96 @@ static int sienna_cichlid_get_smu_metrics_data(struct smu_context *smu,
 
        switch (member) {
        case METRICS_CURR_GFXCLK:
-               *value = metrics->CurrClock[PPCLK_GFXCLK];
+               *value = use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_GFXCLK] :
+                       metrics->CurrClock[PPCLK_GFXCLK];
                break;
        case METRICS_CURR_SOCCLK:
-               *value = metrics->CurrClock[PPCLK_SOCCLK];
+               *value = use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_SOCCLK] :
+                       metrics->CurrClock[PPCLK_SOCCLK];
                break;
        case METRICS_CURR_UCLK:
-               *value = metrics->CurrClock[PPCLK_UCLK];
+               *value = use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_UCLK] :
+                       metrics->CurrClock[PPCLK_UCLK];
                break;
        case METRICS_CURR_VCLK:
-               *value = metrics->CurrClock[PPCLK_VCLK_0];
+               *value = use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_VCLK_0] :
+                       metrics->CurrClock[PPCLK_VCLK_0];
                break;
        case METRICS_CURR_VCLK1:
-               *value = metrics->CurrClock[PPCLK_VCLK_1];
+               *value = use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_VCLK_1] :
+                       metrics->CurrClock[PPCLK_VCLK_1];
                break;
        case METRICS_CURR_DCLK:
-               *value = metrics->CurrClock[PPCLK_DCLK_0];
+               *value = use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_DCLK_0] :
+                       metrics->CurrClock[PPCLK_DCLK_0];
                break;
        case METRICS_CURR_DCLK1:
-               *value = metrics->CurrClock[PPCLK_DCLK_1];
+               *value = use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_DCLK_1] :
+                       metrics->CurrClock[PPCLK_DCLK_1];
                break;
        case METRICS_CURR_DCEFCLK:
-               *value = metrics->CurrClock[PPCLK_DCEFCLK];
+               *value = use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_DCEFCLK] :
+                       metrics->CurrClock[PPCLK_DCEFCLK];
                break;
        case METRICS_CURR_FCLK:
-               *value = metrics->CurrClock[PPCLK_FCLK];
+               *value = use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_FCLK] :
+                       metrics->CurrClock[PPCLK_FCLK];
                break;
        case METRICS_AVERAGE_GFXCLK:
-               if (metrics->AverageGfxActivity <= SMU_11_0_7_GFX_BUSY_THRESHOLD)
-                       *value = metrics->AverageGfxclkFrequencyPostDs;
+               average_gfx_activity = use_metrics_v2 ? metrics_v2->AverageGfxActivity :
+                       metrics->AverageGfxActivity;
+               if (average_gfx_activity <= SMU_11_0_7_GFX_BUSY_THRESHOLD)
+                       *value = use_metrics_v2 ? metrics_v2->AverageGfxclkFrequencyPostDs :
+                               metrics->AverageGfxclkFrequencyPostDs;
                else
-                       *value = metrics->AverageGfxclkFrequencyPreDs;
+                       *value = use_metrics_v2 ? metrics_v2->AverageGfxclkFrequencyPreDs :
+                               metrics->AverageGfxclkFrequencyPreDs;
                break;
        case METRICS_AVERAGE_FCLK:
-               *value = metrics->AverageFclkFrequencyPostDs;
+               *value = use_metrics_v2 ? metrics_v2->AverageFclkFrequencyPostDs :
+                       metrics->AverageFclkFrequencyPostDs;
                break;
        case METRICS_AVERAGE_UCLK:
-               *value = metrics->AverageUclkFrequencyPostDs;
+               *value = use_metrics_v2 ? metrics_v2->AverageUclkFrequencyPostDs :
+                       metrics->AverageUclkFrequencyPostDs;
                break;
        case METRICS_AVERAGE_GFXACTIVITY:
-               *value = metrics->AverageGfxActivity;
+               *value = use_metrics_v2 ? metrics_v2->AverageGfxActivity :
+                       metrics->AverageGfxActivity;
                break;
        case METRICS_AVERAGE_MEMACTIVITY:
-               *value = metrics->AverageUclkActivity;
+               *value = use_metrics_v2 ? metrics_v2->AverageUclkActivity :
+                       metrics->AverageUclkActivity;
                break;
        case METRICS_AVERAGE_SOCKETPOWER:
-               *value = metrics->AverageSocketPower << 8;
+               *value = use_metrics_v2 ? metrics_v2->AverageSocketPower << 8 :
+                       metrics->AverageSocketPower << 8;
                break;
        case METRICS_TEMPERATURE_EDGE:
-               *value = metrics->TemperatureEdge *
+               *value = (use_metrics_v2 ? metrics_v2->TemperatureEdge : metrics->TemperatureEdge) *
                        SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
                break;
        case METRICS_TEMPERATURE_HOTSPOT:
-               *value = metrics->TemperatureHotspot *
+               *value = (use_metrics_v2 ? metrics_v2->TemperatureHotspot : metrics->TemperatureHotspot) *
                        SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
                break;
        case METRICS_TEMPERATURE_MEM:
-               *value = metrics->TemperatureMem *
+               *value = (use_metrics_v2 ? metrics_v2->TemperatureMem : metrics->TemperatureMem) *
                        SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
                break;
        case METRICS_TEMPERATURE_VRGFX:
-               *value = metrics->TemperatureVrGfx *
+               *value = (use_metrics_v2 ? metrics_v2->TemperatureVrGfx : metrics->TemperatureVrGfx) *
                        SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
                break;
        case METRICS_TEMPERATURE_VRSOC:
-               *value = metrics->TemperatureVrSoc *
+               *value = (use_metrics_v2 ? metrics_v2->TemperatureVrSoc : metrics->TemperatureVrSoc) *
                        SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
                break;
        case METRICS_THROTTLER_STATUS:
-               *value = metrics->ThrottlerStatus;
+               *value = sienna_cichlid_get_throttler_status_locked(smu);
                break;
        case METRICS_CURR_FANSPEED:
-               *value = metrics->CurrFanSpeed;
+               *value = use_metrics_v2 ? metrics_v2->CurrFanSpeed : metrics->CurrFanSpeed;
                break;
        default:
                *value = UINT_MAX;
@@ -1046,7 +1088,7 @@ static int sienna_cichlid_print_clk_levels(struct smu_context *smu,
                                if (ret)
                                        goto print_clk_out;
 
-                               size += sprintf(buf + size, "%d: %uMhz %s\n", i, value,
+                               size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, value,
                                                cur_value == value ? "*" : "");
                        }
                } else {
@@ -1068,7 +1110,7 @@ static int sienna_cichlid_print_clk_levels(struct smu_context *smu,
                        }
 
                        for (i = 0; i < count; i++) {
-                               size += sprintf(buf + size, "%d: %uMhz %s\n", i, freq_values[i],
+                               size += sysfs_emit_at(buf, size, "%d: %uMhz %s\n", i, freq_values[i],
                                                cur_value  == freq_values[i] ? "*" : "");
                        }
 
@@ -1079,7 +1121,7 @@ static int sienna_cichlid_print_clk_levels(struct smu_context *smu,
                lane_width = smu_v11_0_get_current_pcie_link_width_level(smu);
                GET_PPTABLE_MEMBER(LclkFreq, &table_member);
                for (i = 0; i < NUM_LINK_LEVELS; i++)
-                       size += sprintf(buf + size, "%d: %s %s %dMhz %s\n", i,
+                       size += sysfs_emit_at(buf, size, "%d: %s %s %dMhz %s\n", i,
                                        (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 0) ? "2.5GT/s," :
                                        (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 1) ? "5.0GT/s," :
                                        (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 2) ? "8.0GT/s," :
@@ -1102,8 +1144,8 @@ static int sienna_cichlid_print_clk_levels(struct smu_context *smu,
                if (!sienna_cichlid_is_od_feature_supported(od_settings, SMU_11_0_7_ODCAP_GFXCLK_LIMITS))
                        break;
 
-               size += sprintf(buf + size, "OD_SCLK:\n");
-               size += sprintf(buf + size, "0: %uMhz\n1: %uMhz\n", od_table->GfxclkFmin, od_table->GfxclkFmax);
+               size += sysfs_emit_at(buf, size, "OD_SCLK:\n");
+               size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n", od_table->GfxclkFmin, od_table->GfxclkFmax);
                break;
 
        case SMU_OD_MCLK:
@@ -1113,8 +1155,8 @@ static int sienna_cichlid_print_clk_levels(struct smu_context *smu,
                if (!sienna_cichlid_is_od_feature_supported(od_settings, SMU_11_0_7_ODCAP_UCLK_LIMITS))
                        break;
 
-               size += sprintf(buf + size, "OD_MCLK:\n");
-               size += sprintf(buf + size, "0: %uMhz\n1: %uMHz\n", od_table->UclkFmin, od_table->UclkFmax);
+               size += sysfs_emit_at(buf, size, "OD_MCLK:\n");
+               size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMHz\n", od_table->UclkFmin, od_table->UclkFmax);
                break;
 
        case SMU_OD_VDDGFX_OFFSET:
@@ -1130,22 +1172,22 @@ static int sienna_cichlid_print_clk_levels(struct smu_context *smu,
                     (smu_version < 0x003a2900))
                        break;
 
-               size += sprintf(buf + size, "OD_VDDGFX_OFFSET:\n");
-               size += sprintf(buf + size, "%dmV\n", od_table->VddGfxOffset);
+               size += sysfs_emit_at(buf, size, "OD_VDDGFX_OFFSET:\n");
+               size += sysfs_emit_at(buf, size, "%dmV\n", od_table->VddGfxOffset);
                break;
 
        case SMU_OD_RANGE:
                if (!smu->od_enabled || !od_table || !od_settings)
                        break;
 
-               size = sprintf(buf, "%s:\n", "OD_RANGE");
+               size = sysfs_emit(buf, "%s:\n", "OD_RANGE");
 
                if (sienna_cichlid_is_od_feature_supported(od_settings, SMU_11_0_7_ODCAP_GFXCLK_LIMITS)) {
                        sienna_cichlid_get_od_setting_range(od_settings, SMU_11_0_7_ODSETTING_GFXCLKFMIN,
                                                            &min_value, NULL);
                        sienna_cichlid_get_od_setting_range(od_settings, SMU_11_0_7_ODSETTING_GFXCLKFMAX,
                                                            NULL, &max_value);
-                       size += sprintf(buf + size, "SCLK: %7uMhz %10uMhz\n",
+                       size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n",
                                        min_value, max_value);
                }
 
@@ -1154,7 +1196,7 @@ static int sienna_cichlid_print_clk_levels(struct smu_context *smu,
                                                            &min_value, NULL);
                        sienna_cichlid_get_od_setting_range(od_settings, SMU_11_0_7_ODSETTING_UCLKFMAX,
                                                            NULL, &max_value);
-                       size += sprintf(buf + size, "MCLK: %7uMhz %10uMhz\n",
+                       size += sysfs_emit_at(buf, size, "MCLK: %7uMhz %10uMhz\n",
                                        min_value, max_value);
                }
                break;
@@ -1312,27 +1354,20 @@ static bool sienna_cichlid_is_dpm_running(struct smu_context *smu)
        return !!(feature_enabled & SMC_DPM_FEATURE);
 }
 
-static int sienna_cichlid_get_fan_speed_percent(struct smu_context *smu,
-                                               uint32_t *speed)
+static int sienna_cichlid_get_fan_speed_rpm(struct smu_context *smu,
+                                           uint32_t *speed)
 {
-       int ret;
-       u32 rpm;
-
        if (!speed)
                return -EINVAL;
 
-       switch (smu_v11_0_get_fan_control_mode(smu)) {
-       case AMD_FAN_CTRL_AUTO:
-               ret = sienna_cichlid_get_smu_metrics_data(smu,
-                                                         METRICS_CURR_FANSPEED,
-                                                         &rpm);
-               if (!ret && smu->fan_max_rpm)
-                       *speed = rpm * 100 / smu->fan_max_rpm;
-               return ret;
-       default:
-               *speed = smu->user_dpm_profile.fan_speed_percent;
-               return 0;
-       }
+       /*
+        * For Sienna_Cichlid and later, the fan speed(rpm) reported
+        * by pmfw is always trustable(even when the fan control feature
+        * disabled or 0 RPM kicked in).
+        */
+       return sienna_cichlid_get_smu_metrics_data(smu,
+                                                  METRICS_CURR_FANSPEED,
+                                                  speed);
 }
 
 static int sienna_cichlid_get_fan_parameters(struct smu_context *smu)
@@ -1377,7 +1412,7 @@ static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
        if (!buf)
                return -EINVAL;
 
-       size += sprintf(buf + size, "%16s %s %s %s %s %s %s %s %s %s %s\n",
+       size += sysfs_emit_at(buf, size, "%16s %s %s %s %s %s %s %s %s %s %s\n",
                        title[0], title[1], title[2], title[3], title[4], title[5],
                        title[6], title[7], title[8], title[9], title[10]);
 
@@ -1397,10 +1432,10 @@ static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
                        return result;
                }
 
-               size += sprintf(buf + size, "%2d %14s%s:\n",
+               size += sysfs_emit_at(buf, size, "%2d %14s%s:\n",
                        i, profile_name[i], (i == smu->power_profile_mode) ? "*" : " ");
 
-               size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
+               size += sysfs_emit_at(buf, size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
                        " ",
                        0,
                        "GFXCLK",
@@ -1414,7 +1449,7 @@ static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
                        activity_monitor->Gfx_PD_Data_error_coeff,
                        activity_monitor->Gfx_PD_Data_error_rate_coeff);
 
-               size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
+               size += sysfs_emit_at(buf, size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
                        " ",
                        1,
                        "SOCCLK",
@@ -1428,7 +1463,7 @@ static int sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *
                        activity_monitor->Fclk_PD_Data_error_coeff,
                        activity_monitor->Fclk_PD_Data_error_rate_coeff);
 
-               size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
+               size += sysfs_emit_at(buf, size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n",
                        " ",
                        2,
                        "MEMLK",
@@ -1911,18 +1946,29 @@ static int sienna_cichlid_set_default_od_settings(struct smu_context *smu)
                (OverDriveTable_t *)smu->smu_table.overdrive_table;
        OverDriveTable_t *boot_od_table =
                (OverDriveTable_t *)smu->smu_table.boot_overdrive_table;
+       OverDriveTable_t *user_od_table =
+               (OverDriveTable_t *)smu->smu_table.user_overdrive_table;
        int ret = 0;
 
+       /*
+        * For S3/S4/Runpm resume, no need to setup those overdrive tables again as
+        *   - either they already have the default OD settings got during cold bootup
+        *   - or they have some user customized OD settings which cannot be overwritten
+        */
+       if (smu->adev->in_suspend)
+               return 0;
+
        ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE,
-                                  0, (void *)od_table, false);
+                                  0, (void *)boot_od_table, false);
        if (ret) {
                dev_err(smu->adev->dev, "Failed to get overdrive table!\n");
                return ret;
        }
 
-       memcpy(boot_od_table, od_table, sizeof(OverDriveTable_t));
+       sienna_cichlid_dump_od_table(smu, boot_od_table);
 
-       sienna_cichlid_dump_od_table(smu, od_table);
+       memcpy(od_table, boot_od_table, sizeof(OverDriveTable_t));
+       memcpy(user_od_table, boot_od_table, sizeof(OverDriveTable_t));
 
        return 0;
 }
@@ -2085,13 +2131,20 @@ static int sienna_cichlid_od_edit_dpm_table(struct smu_context *smu,
                fallthrough;
 
        case PP_OD_COMMIT_DPM_TABLE:
-               sienna_cichlid_dump_od_table(smu, od_table);
+               if (memcmp(od_table, table_context->user_overdrive_table, sizeof(OverDriveTable_t))) {
+                       sienna_cichlid_dump_od_table(smu, od_table);
+                       ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE, 0, (void *)od_table, true);
+                       if (ret) {
+                               dev_err(smu->adev->dev, "Failed to import overdrive table!\n");
+                               return ret;
+                       }
+                       memcpy(table_context->user_overdrive_table, od_table, sizeof(OverDriveTable_t));
+                       smu->user_dpm_profile.user_od = true;
 
-               ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE,
-                                          0, (void *)od_table, true);
-               if (ret) {
-                       dev_err(smu->adev->dev, "Failed to import overdrive table!\n");
-                       return ret;
+                       if (!memcmp(table_context->user_overdrive_table,
+                                   table_context->boot_overdrive_table,
+                                   sizeof(OverDriveTable_t)))
+                               smu->user_dpm_profile.user_od = false;
                }
                break;
 
@@ -3567,65 +3620,94 @@ static ssize_t sienna_cichlid_get_gpu_metrics(struct smu_context *smu,
        SmuMetricsExternal_t metrics_external;
        SmuMetrics_t *metrics =
                &(metrics_external.SmuMetrics);
+       SmuMetrics_V2_t *metrics_v2 =
+               &(metrics_external.SmuMetrics_V2);
        struct amdgpu_device *adev = smu->adev;
-       uint32_t smu_version;
+       bool use_metrics_v2 = ((adev->asic_type == CHIP_SIENNA_CICHLID) &&
+               (smu->smc_fw_version >= 0x3A4300)) ? true : false;
+       uint16_t average_gfx_activity;
        int ret = 0;
 
-       ret = smu_cmn_get_metrics_table(smu,
-                                       &metrics_external,
-                                       true);
-       if (ret)
+       mutex_lock(&smu->metrics_lock);
+       ret = smu_cmn_get_metrics_table_locked(smu,
+                                              &metrics_external,
+                                              true);
+       if (ret) {
+               mutex_unlock(&smu->metrics_lock);
                return ret;
+       }
 
        smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 3);
 
-       gpu_metrics->temperature_edge = metrics->TemperatureEdge;
-       gpu_metrics->temperature_hotspot = metrics->TemperatureHotspot;
-       gpu_metrics->temperature_mem = metrics->TemperatureMem;
-       gpu_metrics->temperature_vrgfx = metrics->TemperatureVrGfx;
-       gpu_metrics->temperature_vrsoc = metrics->TemperatureVrSoc;
-       gpu_metrics->temperature_vrmem = metrics->TemperatureVrMem0;
-
-       gpu_metrics->average_gfx_activity = metrics->AverageGfxActivity;
-       gpu_metrics->average_umc_activity = metrics->AverageUclkActivity;
-       gpu_metrics->average_mm_activity = metrics->VcnActivityPercentage;
-
-       gpu_metrics->average_socket_power = metrics->AverageSocketPower;
-       gpu_metrics->energy_accumulator = metrics->EnergyAccumulator;
-
-       if (metrics->AverageGfxActivity <= SMU_11_0_7_GFX_BUSY_THRESHOLD)
-               gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPostDs;
+       gpu_metrics->temperature_edge =
+               use_metrics_v2 ? metrics_v2->TemperatureEdge : metrics->TemperatureEdge;
+       gpu_metrics->temperature_hotspot =
+               use_metrics_v2 ? metrics_v2->TemperatureHotspot : metrics->TemperatureHotspot;
+       gpu_metrics->temperature_mem =
+               use_metrics_v2 ? metrics_v2->TemperatureMem : metrics->TemperatureMem;
+       gpu_metrics->temperature_vrgfx =
+               use_metrics_v2 ? metrics_v2->TemperatureVrGfx : metrics->TemperatureVrGfx;
+       gpu_metrics->temperature_vrsoc =
+               use_metrics_v2 ? metrics_v2->TemperatureVrSoc : metrics->TemperatureVrSoc;
+       gpu_metrics->temperature_vrmem =
+               use_metrics_v2 ? metrics_v2->TemperatureVrMem0 : metrics->TemperatureVrMem0;
+
+       gpu_metrics->average_gfx_activity =
+               use_metrics_v2 ? metrics_v2->AverageGfxActivity : metrics->AverageGfxActivity;
+       gpu_metrics->average_umc_activity =
+               use_metrics_v2 ? metrics_v2->AverageUclkActivity : metrics->AverageUclkActivity;
+       gpu_metrics->average_mm_activity =
+               use_metrics_v2 ? metrics_v2->VcnActivityPercentage : metrics->VcnActivityPercentage;
+
+       gpu_metrics->average_socket_power =
+               use_metrics_v2 ? metrics_v2->AverageSocketPower : metrics->AverageSocketPower;
+       gpu_metrics->energy_accumulator =
+               use_metrics_v2 ? metrics_v2->EnergyAccumulator : metrics->EnergyAccumulator;
+
+       average_gfx_activity = use_metrics_v2 ? metrics_v2->AverageGfxActivity : metrics->AverageGfxActivity;
+       if (average_gfx_activity <= SMU_11_0_7_GFX_BUSY_THRESHOLD)
+               gpu_metrics->average_gfxclk_frequency =
+                       use_metrics_v2 ? metrics_v2->AverageGfxclkFrequencyPostDs : metrics->AverageGfxclkFrequencyPostDs;
        else
-               gpu_metrics->average_gfxclk_frequency = metrics->AverageGfxclkFrequencyPreDs;
-       gpu_metrics->average_uclk_frequency = metrics->AverageUclkFrequencyPostDs;
-       gpu_metrics->average_vclk0_frequency = metrics->AverageVclk0Frequency;
-       gpu_metrics->average_dclk0_frequency = metrics->AverageDclk0Frequency;
-       gpu_metrics->average_vclk1_frequency = metrics->AverageVclk1Frequency;
-       gpu_metrics->average_dclk1_frequency = metrics->AverageDclk1Frequency;
-
-       gpu_metrics->current_gfxclk = metrics->CurrClock[PPCLK_GFXCLK];
-       gpu_metrics->current_socclk = metrics->CurrClock[PPCLK_SOCCLK];
-       gpu_metrics->current_uclk = metrics->CurrClock[PPCLK_UCLK];
-       gpu_metrics->current_vclk0 = metrics->CurrClock[PPCLK_VCLK_0];
-       gpu_metrics->current_dclk0 = metrics->CurrClock[PPCLK_DCLK_0];
-       gpu_metrics->current_vclk1 = metrics->CurrClock[PPCLK_VCLK_1];
-       gpu_metrics->current_dclk1 = metrics->CurrClock[PPCLK_DCLK_1];
-
-       gpu_metrics->throttle_status = metrics->ThrottlerStatus;
+               gpu_metrics->average_gfxclk_frequency =
+                       use_metrics_v2 ? metrics_v2->AverageGfxclkFrequencyPreDs : metrics->AverageGfxclkFrequencyPreDs;
+       gpu_metrics->average_uclk_frequency =
+               use_metrics_v2 ? metrics_v2->AverageUclkFrequencyPostDs : metrics->AverageUclkFrequencyPostDs;
+       gpu_metrics->average_vclk0_frequency =
+               use_metrics_v2 ? metrics_v2->AverageVclk0Frequency : metrics->AverageVclk0Frequency;
+       gpu_metrics->average_dclk0_frequency =
+               use_metrics_v2 ? metrics_v2->AverageDclk0Frequency : metrics->AverageDclk0Frequency;
+       gpu_metrics->average_vclk1_frequency =
+               use_metrics_v2 ? metrics_v2->AverageVclk1Frequency : metrics->AverageVclk1Frequency;
+       gpu_metrics->average_dclk1_frequency =
+               use_metrics_v2 ? metrics_v2->AverageDclk1Frequency : metrics->AverageDclk1Frequency;
+
+       gpu_metrics->current_gfxclk =
+               use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_GFXCLK] : metrics->CurrClock[PPCLK_GFXCLK];
+       gpu_metrics->current_socclk =
+               use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_SOCCLK] : metrics->CurrClock[PPCLK_SOCCLK];
+       gpu_metrics->current_uclk =
+               use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_UCLK] : metrics->CurrClock[PPCLK_UCLK];
+       gpu_metrics->current_vclk0 =
+               use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_VCLK_0] : metrics->CurrClock[PPCLK_VCLK_0];
+       gpu_metrics->current_dclk0 =
+               use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_DCLK_0] : metrics->CurrClock[PPCLK_DCLK_0];
+       gpu_metrics->current_vclk1 =
+               use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_VCLK_1] : metrics->CurrClock[PPCLK_VCLK_1];
+       gpu_metrics->current_dclk1 =
+               use_metrics_v2 ? metrics_v2->CurrClock[PPCLK_DCLK_1] : metrics->CurrClock[PPCLK_DCLK_1];
+
+       gpu_metrics->throttle_status = sienna_cichlid_get_throttler_status_locked(smu);
        gpu_metrics->indep_throttle_status =
-                       smu_cmn_get_indep_throttler_status(metrics->ThrottlerStatus,
+                       smu_cmn_get_indep_throttler_status(gpu_metrics->throttle_status,
                                                           sienna_cichlid_throttler_map);
 
-       gpu_metrics->current_fan_speed = metrics->CurrFanSpeed;
+       gpu_metrics->current_fan_speed = use_metrics_v2 ? metrics_v2->CurrFanSpeed : metrics->CurrFanSpeed;
 
-       ret = smu_cmn_get_smc_version(smu, NULL, &smu_version);
-       if (ret)
-               return ret;
-
-       if (((adev->asic_type == CHIP_SIENNA_CICHLID) && smu_version > 0x003A1E00) ||
-             ((adev->asic_type == CHIP_NAVY_FLOUNDER) && smu_version > 0x00410400)) {
-               gpu_metrics->pcie_link_width = metrics->PcieWidth;
-               gpu_metrics->pcie_link_speed = link_speed[metrics->PcieRate];
+       if (((adev->asic_type == CHIP_SIENNA_CICHLID) && smu->smc_fw_version > 0x003A1E00) ||
+             ((adev->asic_type == CHIP_NAVY_FLOUNDER) && smu->smc_fw_version > 0x00410400)) {
+               gpu_metrics->pcie_link_width = use_metrics_v2 ? metrics_v2->PcieWidth : metrics->PcieWidth;
+               gpu_metrics->pcie_link_speed = link_speed[use_metrics_v2 ? metrics_v2->PcieRate : metrics->PcieRate];
        } else {
                gpu_metrics->pcie_link_width =
                                smu_v11_0_get_current_pcie_link_width(smu);
@@ -3633,6 +3715,8 @@ static ssize_t sienna_cichlid_get_gpu_metrics(struct smu_context *smu,
                                smu_v11_0_get_current_pcie_link_speed(smu);
        }
 
+       mutex_unlock(&smu->metrics_lock);
+
        gpu_metrics->system_clock_counter = ktime_get_boottime_ns();
 
        *table = (void *)gpu_metrics;
@@ -3768,7 +3852,8 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
        .display_config_changed = sienna_cichlid_display_config_changed,
        .notify_smc_display_config = sienna_cichlid_notify_smc_display_config,
        .is_dpm_running = sienna_cichlid_is_dpm_running,
-       .get_fan_speed_percent = sienna_cichlid_get_fan_speed_percent,
+       .get_fan_speed_pwm = smu_v11_0_get_fan_speed_pwm,
+       .get_fan_speed_rpm = sienna_cichlid_get_fan_speed_rpm,
        .get_power_profile_mode = sienna_cichlid_get_power_profile_mode,
        .set_power_profile_mode = sienna_cichlid_set_power_profile_mode,
        .set_watermarks_table = sienna_cichlid_set_watermarks_table,
@@ -3811,7 +3896,8 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
        .display_clock_voltage_request = smu_v11_0_display_clock_voltage_request,
        .get_fan_control_mode = smu_v11_0_get_fan_control_mode,
        .set_fan_control_mode = smu_v11_0_set_fan_control_mode,
-       .set_fan_speed_percent = smu_v11_0_set_fan_speed_percent,
+       .set_fan_speed_pwm = smu_v11_0_set_fan_speed_pwm,
+       .set_fan_speed_rpm = smu_v11_0_set_fan_speed_rpm,
        .set_xgmi_pstate = smu_v11_0_set_xgmi_pstate,
        .gfx_off_control = smu_v11_0_gfx_off_control,
        .register_irq_handler = smu_v11_0_register_irq_handler,
@@ -3828,6 +3914,7 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
        .set_soft_freq_limited_range = smu_v11_0_set_soft_freq_limited_range,
        .set_default_od_settings = sienna_cichlid_set_default_od_settings,
        .od_edit_dpm_table = sienna_cichlid_od_edit_dpm_table,
+       .restore_user_od_settings = smu_v11_0_restore_user_od_settings,
        .run_btc = sienna_cichlid_run_btc,
        .set_power_source = smu_v11_0_set_power_source,
        .get_pp_feature_mask = smu_cmn_get_pp_feature_mask,