drm/amd/pm: bump Navi1x driver if version and related data structures V2
authorEvan Quan <evan.quan@amd.com>
Sat, 20 Feb 2021 02:45:32 +0000 (10:45 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 2 Mar 2021 19:05:18 +0000 (14:05 -0500)
New changes were involved for the SmuMetrics structure.

Signed-off-by: Evan Quan <evan.quan@amd.com>
Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/pm/inc/smu11_driver_if_navi10.h
drivers/gpu/drm/amd/pm/inc/smu_v11_0.h
drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c

index 246d3951a78ab471bc7cc9f7bdc293a020755337..04752ade10165f3e23ac1e9b31e665072ad05e36 100644 (file)
@@ -843,11 +843,15 @@ typedef struct {
   uint16_t      FanMaximumRpm;
   uint16_t      FanMinimumPwm;
   uint16_t      FanTargetTemperature; // Degree Celcius 
+  uint16_t      FanMode;
+  uint16_t      FanMaxPwm;
+  uint16_t      FanMinPwm;
+  uint16_t      FanMaxTemp; // Degree Celcius
+  uint16_t      FanMinTemp; // Degree Celcius
   uint16_t      MaxOpTemp;            // Degree Celcius
   uint16_t      FanZeroRpmEnable;
-  uint16_t      Padding;
 
-  uint32_t     MmHubPadding[8]; // SMU internal use  
+  uint32_t     MmHubPadding[6]; // SMU internal use
 
 } OverDriveTable_t; 
 
@@ -880,6 +884,45 @@ typedef struct {
   uint8_t  Padding8_2;
   uint16_t CurrFanSpeed;
 
+  // Padding - ignore
+  uint32_t     MmHubPadding[8]; // SMU internal use
+} SmuMetrics_legacy_t;
+
+typedef struct {
+  uint16_t CurrClock[PPCLK_COUNT];
+  uint16_t AverageGfxclkFrequencyPostDs;
+  uint16_t AverageSocclkFrequency;
+  uint16_t AverageUclkFrequencyPostDs;
+  uint16_t AverageGfxActivity    ;
+  uint16_t AverageUclkActivity   ;
+  uint8_t  CurrSocVoltageOffset  ;
+  uint8_t  CurrGfxVoltageOffset  ;
+  uint8_t  CurrMemVidOffset      ;
+  uint8_t  Padding8              ;
+  uint16_t AverageSocketPower    ;
+  uint16_t TemperatureEdge       ;
+  uint16_t TemperatureHotspot    ;
+  uint16_t TemperatureMem        ;
+  uint16_t TemperatureVrGfx      ;
+  uint16_t TemperatureVrMem0     ;
+  uint16_t TemperatureVrMem1     ;  
+  uint16_t TemperatureVrSoc      ;  
+  uint16_t TemperatureLiquid0    ;
+  uint16_t TemperatureLiquid1    ;  
+  uint16_t TemperaturePlx        ;
+  uint16_t Padding16             ;
+  uint32_t ThrottlerStatus       ; 
+  uint8_t  LinkDpmLevel;
+  uint8_t  Padding8_2;
+  uint16_t CurrFanSpeed;
+
+  uint16_t AverageGfxclkFrequencyPreDs;
+  uint16_t AverageUclkFrequencyPreDs;
+  uint8_t  PcieRate;
+  uint8_t  PcieWidth;
+  uint8_t  Padding8_3[2];
+
   // Padding - ignore
   uint32_t     MmHubPadding[8]; // SMU internal use
 } SmuMetrics_t;
@@ -919,10 +962,61 @@ typedef struct {
   uint16_t VcnActivityPercentage ;
   uint16_t padding16_2;
 
+  // Padding - ignore
+  uint32_t     MmHubPadding[8]; // SMU internal use
+} SmuMetrics_NV12_legacy_t;
+
+typedef struct {
+  uint16_t CurrClock[PPCLK_COUNT];
+  uint16_t AverageGfxclkFrequencyPostDs;
+  uint16_t AverageSocclkFrequency;
+  uint16_t AverageUclkFrequencyPostDs;
+  uint16_t AverageGfxActivity    ;
+  uint16_t AverageUclkActivity   ;
+  uint8_t  CurrSocVoltageOffset  ;
+  uint8_t  CurrGfxVoltageOffset  ;
+  uint8_t  CurrMemVidOffset      ;
+  uint8_t  Padding8              ;
+  uint16_t AverageSocketPower    ;
+  uint16_t TemperatureEdge       ;
+  uint16_t TemperatureHotspot    ;
+  uint16_t TemperatureMem        ;
+  uint16_t TemperatureVrGfx      ;
+  uint16_t TemperatureVrMem0     ;
+  uint16_t TemperatureVrMem1     ;
+  uint16_t TemperatureVrSoc      ;
+  uint16_t TemperatureLiquid0    ;
+  uint16_t TemperatureLiquid1    ;
+  uint16_t TemperaturePlx        ;
+  uint16_t Padding16             ;
+  uint32_t ThrottlerStatus       ;
+
+  uint8_t  LinkDpmLevel;
+  uint8_t  Padding8_2;
+  uint16_t CurrFanSpeed;
+
+  uint16_t AverageVclkFrequency  ;
+  uint16_t AverageDclkFrequency  ;
+  uint16_t VcnActivityPercentage ;
+  uint16_t AverageGfxclkFrequencyPreDs;
+  uint16_t AverageUclkFrequencyPreDs;
+  uint8_t  PcieRate;
+  uint8_t  PcieWidth;
+
+  uint32_t Padding32_1;
+  uint64_t EnergyAccumulator;
+
   // Padding - ignore
   uint32_t     MmHubPadding[8]; // SMU internal use
 } SmuMetrics_NV12_t;
 
+typedef union SmuMetrics {
+       SmuMetrics_legacy_t             nv10_legacy_metrics;
+       SmuMetrics_t                    nv10_metrics;
+       SmuMetrics_NV12_legacy_t        nv12_legacy_metrics;
+       SmuMetrics_NV12_t               nv12_metrics;
+} SmuMetrics_NV1X_t;
+
 typedef struct {
   uint16_t MinClock; // This is either DCEFCLK or SOCCLK (in MHz)
   uint16_t MaxClock; // This is either DCEFCLK or SOCCLK (in MHz)
index d4cddd2390a29d1d54f6003714321791f9bc516f..520979ad2687d6aac80ea7f6a8dbad25ad5b0402 100644 (file)
@@ -27,9 +27,9 @@
 
 #define SMU11_DRIVER_IF_VERSION_INV 0xFFFFFFFF
 #define SMU11_DRIVER_IF_VERSION_ARCT 0x17
-#define SMU11_DRIVER_IF_VERSION_NV10 0x36
-#define SMU11_DRIVER_IF_VERSION_NV12 0x36
-#define SMU11_DRIVER_IF_VERSION_NV14 0x36
+#define SMU11_DRIVER_IF_VERSION_NV10 0x37
+#define SMU11_DRIVER_IF_VERSION_NV12 0x38
+#define SMU11_DRIVER_IF_VERSION_NV14 0x38
 #define SMU11_DRIVER_IF_VERSION_Sienna_Cichlid 0x3D
 #define SMU11_DRIVER_IF_VERSION_Navy_Flounder 0xE
 #define SMU11_DRIVER_IF_VERSION_VANGOGH 0x02
index e609f1e7914b7c431c8bfc52cacfacb9affd0a36..73d7acf388d6b9b71193678d1426ea3b046fc95f 100644 (file)
@@ -70,6 +70,8 @@
        FEATURE_MASK(FEATURE_DPM_LINK_BIT)       | \
        FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT))
 
+#define SMU_11_0_GFX_BUSY_THRESHOLD 15
+
 static struct cmn2asic_msg_mapping navi10_message_map[SMU_MSG_MAX_COUNT] = {
        MSG_MAP(TestMessage,                    PPSMC_MSG_TestMessage,                  1),
        MSG_MAP(GetSmuVersion,                  PPSMC_MSG_GetSmuVersion,                1),
@@ -456,18 +458,13 @@ static int navi10_tables_init(struct smu_context *smu)
 {
        struct smu_table_context *smu_table = &smu->smu_table;
        struct smu_table *tables = smu_table->tables;
-       struct amdgpu_device *adev = smu->adev;
 
        SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t),
                       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
        SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
                       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
-       if (adev->asic_type == CHIP_NAVI12)
-               SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_NV12_t),
-                              PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
-       else
-               SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
-                              PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
+       SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_NV1X_t),
+                      PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
        SMU_TABLE_INIT(tables, SMU_TABLE_I2C_COMMANDS, sizeof(SwI2cRequest_t),
                       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
        SMU_TABLE_INIT(tables, SMU_TABLE_OVERDRIVE, sizeof(OverDriveTable_t),
@@ -478,9 +475,8 @@ static int navi10_tables_init(struct smu_context *smu)
                       sizeof(DpmActivityMonitorCoeffInt_t), PAGE_SIZE,
                       AMDGPU_GEM_DOMAIN_VRAM);
 
-       smu_table->metrics_table = kzalloc(adev->asic_type == CHIP_NAVI12 ?
-                                          sizeof(SmuMetrics_NV12_t) :
-                                          sizeof(SmuMetrics_t), GFP_KERNEL);
+       smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_NV1X_t),
+                                          GFP_KERNEL);
        if (!smu_table->metrics_table)
                goto err0_out;
        smu_table->metrics_time = 0;
@@ -504,17 +500,200 @@ err0_out:
        return -ENOMEM;
 }
 
+static int navi10_get_legacy_smu_metrics_data(struct smu_context *smu,
+                                             MetricsMember_t member,
+                                             uint32_t *value)
+{
+       struct smu_table_context *smu_table= &smu->smu_table;
+       SmuMetrics_legacy_t *metrics =
+               (SmuMetrics_legacy_t *)smu_table->metrics_table;
+       int ret = 0;
+
+       mutex_lock(&smu->metrics_lock);
+
+       ret = smu_cmn_get_metrics_table_locked(smu,
+                                              NULL,
+                                              false);
+       if (ret) {
+               mutex_unlock(&smu->metrics_lock);
+               return ret;
+       }
+
+       switch (member) {
+       case METRICS_CURR_GFXCLK:
+               *value = metrics->CurrClock[PPCLK_GFXCLK];
+               break;
+       case METRICS_CURR_SOCCLK:
+               *value = metrics->CurrClock[PPCLK_SOCCLK];
+               break;
+       case METRICS_CURR_UCLK:
+               *value = metrics->CurrClock[PPCLK_UCLK];
+               break;
+       case METRICS_CURR_VCLK:
+               *value = metrics->CurrClock[PPCLK_VCLK];
+               break;
+       case METRICS_CURR_DCLK:
+               *value = metrics->CurrClock[PPCLK_DCLK];
+               break;
+       case METRICS_CURR_DCEFCLK:
+               *value = metrics->CurrClock[PPCLK_DCEFCLK];
+               break;
+       case METRICS_AVERAGE_GFXCLK:
+               *value = metrics->AverageGfxclkFrequency;
+               break;
+       case METRICS_AVERAGE_SOCCLK:
+               *value = metrics->AverageSocclkFrequency;
+               break;
+       case METRICS_AVERAGE_UCLK:
+               *value = metrics->AverageUclkFrequency;
+               break;
+       case METRICS_AVERAGE_GFXACTIVITY:
+               *value = metrics->AverageGfxActivity;
+               break;
+       case METRICS_AVERAGE_MEMACTIVITY:
+               *value = metrics->AverageUclkActivity;
+               break;
+       case METRICS_AVERAGE_SOCKETPOWER:
+               *value = metrics->AverageSocketPower << 8;
+               break;
+       case METRICS_TEMPERATURE_EDGE:
+               *value = metrics->TemperatureEdge *
+                       SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+               break;
+       case METRICS_TEMPERATURE_HOTSPOT:
+               *value = metrics->TemperatureHotspot *
+                       SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+               break;
+       case METRICS_TEMPERATURE_MEM:
+               *value = metrics->TemperatureMem *
+                       SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+               break;
+       case METRICS_TEMPERATURE_VRGFX:
+               *value = metrics->TemperatureVrGfx *
+                       SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+               break;
+       case METRICS_TEMPERATURE_VRSOC:
+               *value = metrics->TemperatureVrSoc *
+                       SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+               break;
+       case METRICS_THROTTLER_STATUS:
+               *value = metrics->ThrottlerStatus;
+               break;
+       case METRICS_CURR_FANSPEED:
+               *value = metrics->CurrFanSpeed;
+               break;
+       default:
+               *value = UINT_MAX;
+               break;
+       }
+
+       mutex_unlock(&smu->metrics_lock);
+
+       return ret;
+}
+
 static int navi10_get_smu_metrics_data(struct smu_context *smu,
                                       MetricsMember_t member,
                                       uint32_t *value)
 {
        struct smu_table_context *smu_table= &smu->smu_table;
-       /*
-        * This works for NV12 also. As although NV12 uses a different
-        * SmuMetrics structure from other NV1X ASICs, they share the
-        * same offsets for the heading parts(those members used here).
-        */
-       SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table;
+       SmuMetrics_t *metrics =
+               (SmuMetrics_t *)smu_table->metrics_table;
+       int ret = 0;
+
+       mutex_lock(&smu->metrics_lock);
+
+       ret = smu_cmn_get_metrics_table_locked(smu,
+                                              NULL,
+                                              false);
+       if (ret) {
+               mutex_unlock(&smu->metrics_lock);
+               return ret;
+       }
+
+       switch (member) {
+       case METRICS_CURR_GFXCLK:
+               *value = metrics->CurrClock[PPCLK_GFXCLK];
+               break;
+       case METRICS_CURR_SOCCLK:
+               *value = metrics->CurrClock[PPCLK_SOCCLK];
+               break;
+       case METRICS_CURR_UCLK:
+               *value = metrics->CurrClock[PPCLK_UCLK];
+               break;
+       case METRICS_CURR_VCLK:
+               *value = metrics->CurrClock[PPCLK_VCLK];
+               break;
+       case METRICS_CURR_DCLK:
+               *value = metrics->CurrClock[PPCLK_DCLK];
+               break;
+       case METRICS_CURR_DCEFCLK:
+               *value = metrics->CurrClock[PPCLK_DCEFCLK];
+               break;
+       case METRICS_AVERAGE_GFXCLK:
+               if (metrics->AverageGfxActivity > SMU_11_0_GFX_BUSY_THRESHOLD)
+                       *value = metrics->AverageGfxclkFrequencyPreDs;
+               else
+                       *value = metrics->AverageGfxclkFrequencyPostDs;
+               break;
+       case METRICS_AVERAGE_SOCCLK:
+               *value = metrics->AverageSocclkFrequency;
+               break;
+       case METRICS_AVERAGE_UCLK:
+               *value = metrics->AverageUclkFrequencyPostDs;
+               break;
+       case METRICS_AVERAGE_GFXACTIVITY:
+               *value = metrics->AverageGfxActivity;
+               break;
+       case METRICS_AVERAGE_MEMACTIVITY:
+               *value = metrics->AverageUclkActivity;
+               break;
+       case METRICS_AVERAGE_SOCKETPOWER:
+               *value = metrics->AverageSocketPower << 8;
+               break;
+       case METRICS_TEMPERATURE_EDGE:
+               *value = metrics->TemperatureEdge *
+                       SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+               break;
+       case METRICS_TEMPERATURE_HOTSPOT:
+               *value = metrics->TemperatureHotspot *
+                       SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+               break;
+       case METRICS_TEMPERATURE_MEM:
+               *value = metrics->TemperatureMem *
+                       SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+               break;
+       case METRICS_TEMPERATURE_VRGFX:
+               *value = metrics->TemperatureVrGfx *
+                       SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+               break;
+       case METRICS_TEMPERATURE_VRSOC:
+               *value = metrics->TemperatureVrSoc *
+                       SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+               break;
+       case METRICS_THROTTLER_STATUS:
+               *value = metrics->ThrottlerStatus;
+               break;
+       case METRICS_CURR_FANSPEED:
+               *value = metrics->CurrFanSpeed;
+               break;
+       default:
+               *value = UINT_MAX;
+               break;
+       }
+
+       mutex_unlock(&smu->metrics_lock);
+
+       return ret;
+}
+
+static int navi12_get_legacy_smu_metrics_data(struct smu_context *smu,
+                                             MetricsMember_t member,
+                                             uint32_t *value)
+{
+       struct smu_table_context *smu_table= &smu->smu_table;
+       SmuMetrics_NV12_legacy_t *metrics =
+               (SmuMetrics_NV12_legacy_t *)smu_table->metrics_table;
        int ret = 0;
 
        mutex_lock(&smu->metrics_lock);
@@ -600,6 +779,136 @@ static int navi10_get_smu_metrics_data(struct smu_context *smu,
        return ret;
 }
 
+static int navi12_get_smu_metrics_data(struct smu_context *smu,
+                                      MetricsMember_t member,
+                                      uint32_t *value)
+{
+       struct smu_table_context *smu_table= &smu->smu_table;
+       SmuMetrics_NV12_t *metrics =
+               (SmuMetrics_NV12_t *)smu_table->metrics_table;
+       int ret = 0;
+
+       mutex_lock(&smu->metrics_lock);
+
+       ret = smu_cmn_get_metrics_table_locked(smu,
+                                              NULL,
+                                              false);
+       if (ret) {
+               mutex_unlock(&smu->metrics_lock);
+               return ret;
+       }
+
+       switch (member) {
+       case METRICS_CURR_GFXCLK:
+               *value = metrics->CurrClock[PPCLK_GFXCLK];
+               break;
+       case METRICS_CURR_SOCCLK:
+               *value = metrics->CurrClock[PPCLK_SOCCLK];
+               break;
+       case METRICS_CURR_UCLK:
+               *value = metrics->CurrClock[PPCLK_UCLK];
+               break;
+       case METRICS_CURR_VCLK:
+               *value = metrics->CurrClock[PPCLK_VCLK];
+               break;
+       case METRICS_CURR_DCLK:
+               *value = metrics->CurrClock[PPCLK_DCLK];
+               break;
+       case METRICS_CURR_DCEFCLK:
+               *value = metrics->CurrClock[PPCLK_DCEFCLK];
+               break;
+       case METRICS_AVERAGE_GFXCLK:
+               if (metrics->AverageGfxActivity > SMU_11_0_GFX_BUSY_THRESHOLD)
+                       *value = metrics->AverageGfxclkFrequencyPreDs;
+               else
+                       *value = metrics->AverageGfxclkFrequencyPostDs;
+               break;
+       case METRICS_AVERAGE_SOCCLK:
+               *value = metrics->AverageSocclkFrequency;
+               break;
+       case METRICS_AVERAGE_UCLK:
+               *value = metrics->AverageUclkFrequencyPostDs;
+               break;
+       case METRICS_AVERAGE_GFXACTIVITY:
+               *value = metrics->AverageGfxActivity;
+               break;
+       case METRICS_AVERAGE_MEMACTIVITY:
+               *value = metrics->AverageUclkActivity;
+               break;
+       case METRICS_AVERAGE_SOCKETPOWER:
+               *value = metrics->AverageSocketPower << 8;
+               break;
+       case METRICS_TEMPERATURE_EDGE:
+               *value = metrics->TemperatureEdge *
+                       SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+               break;
+       case METRICS_TEMPERATURE_HOTSPOT:
+               *value = metrics->TemperatureHotspot *
+                       SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+               break;
+       case METRICS_TEMPERATURE_MEM:
+               *value = metrics->TemperatureMem *
+                       SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+               break;
+       case METRICS_TEMPERATURE_VRGFX:
+               *value = metrics->TemperatureVrGfx *
+                       SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+               break;
+       case METRICS_TEMPERATURE_VRSOC:
+               *value = metrics->TemperatureVrSoc *
+                       SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+               break;
+       case METRICS_THROTTLER_STATUS:
+               *value = metrics->ThrottlerStatus;
+               break;
+       case METRICS_CURR_FANSPEED:
+               *value = metrics->CurrFanSpeed;
+               break;
+       default:
+               *value = UINT_MAX;
+               break;
+       }
+
+       mutex_unlock(&smu->metrics_lock);
+
+       return ret;
+}
+
+static int navi1x_get_smu_metrics_data(struct smu_context *smu,
+                                      MetricsMember_t member,
+                                      uint32_t *value)
+{
+       struct amdgpu_device *adev = smu->adev;
+       uint32_t smu_version;
+       int ret = 0;
+
+       ret = smu_cmn_get_smc_version(smu, NULL, &smu_version);
+       if (ret) {
+               dev_err(adev->dev, "Failed to get smu version!\n");
+               return ret;
+       }
+
+       switch (adev->asic_type) {
+       case CHIP_NAVI12:
+               if (smu_version > 0x00341C00)
+                       ret = navi12_get_smu_metrics_data(smu, member, value);
+               else
+                       ret = navi12_get_legacy_smu_metrics_data(smu, member, value);
+               break;
+       case CHIP_NAVI10:
+       case CHIP_NAVI14:
+       default:
+               if (((adev->asic_type == CHIP_NAVI14) && smu_version > 0x00351F00) ||
+                     ((adev->asic_type == CHIP_NAVI10) && smu_version > 0x002A3B00))
+                       ret = navi10_get_smu_metrics_data(smu, member, value);
+               else
+                       ret = navi10_get_legacy_smu_metrics_data(smu, member, value);
+               break;
+       }
+
+       return ret;
+}
+
 static int navi10_allocate_dpm_context(struct smu_context *smu)
 {
        struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
@@ -880,7 +1189,7 @@ static int navi10_get_current_clk_freq_by_table(struct smu_context *smu,
                return -EINVAL;
        }
 
-       return navi10_get_smu_metrics_data(smu,
+       return navi1x_get_smu_metrics_data(smu,
                                           member_type,
                                           value);
 }
@@ -1328,7 +1637,7 @@ static int navi10_get_fan_speed_percent(struct smu_context *smu,
 
        switch (smu_v11_0_get_fan_control_mode(smu)) {
        case AMD_FAN_CTRL_AUTO:
-               ret = navi10_get_smu_metrics_data(smu,
+               ret = navi1x_get_smu_metrics_data(smu,
                                                  METRICS_CURR_FANSPEED,
                                                  &rpm);
                if (!ret && smu->fan_max_rpm)
@@ -1644,37 +1953,37 @@ static int navi10_read_sensor(struct smu_context *smu,
                *size = 4;
                break;
        case AMDGPU_PP_SENSOR_MEM_LOAD:
-               ret = navi10_get_smu_metrics_data(smu,
+               ret = navi1x_get_smu_metrics_data(smu,
                                                  METRICS_AVERAGE_MEMACTIVITY,
                                                  (uint32_t *)data);
                *size = 4;
                break;
        case AMDGPU_PP_SENSOR_GPU_LOAD:
-               ret = navi10_get_smu_metrics_data(smu,
+               ret = navi1x_get_smu_metrics_data(smu,
                                                  METRICS_AVERAGE_GFXACTIVITY,
                                                  (uint32_t *)data);
                *size = 4;
                break;
        case AMDGPU_PP_SENSOR_GPU_POWER:
-               ret = navi10_get_smu_metrics_data(smu,
+               ret = navi1x_get_smu_metrics_data(smu,
                                                  METRICS_AVERAGE_SOCKETPOWER,
                                                  (uint32_t *)data);
                *size = 4;
                break;
        case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
-               ret = navi10_get_smu_metrics_data(smu,
+               ret = navi1x_get_smu_metrics_data(smu,
                                                  METRICS_TEMPERATURE_HOTSPOT,
                                                  (uint32_t *)data);
                *size = 4;
                break;
        case AMDGPU_PP_SENSOR_EDGE_TEMP:
-               ret = navi10_get_smu_metrics_data(smu,
+               ret = navi1x_get_smu_metrics_data(smu,
                                                  METRICS_TEMPERATURE_EDGE,
                                                  (uint32_t *)data);
                *size = 4;
                break;
        case AMDGPU_PP_SENSOR_MEM_TEMP:
-               ret = navi10_get_smu_metrics_data(smu,
+               ret = navi1x_get_smu_metrics_data(smu,
                                                  METRICS_TEMPERATURE_MEM,
                                                  (uint32_t *)data);
                *size = 4;
@@ -1685,7 +1994,7 @@ static int navi10_read_sensor(struct smu_context *smu,
                *size = 4;
                break;
        case AMDGPU_PP_SENSOR_GFX_SCLK:
-               ret = navi10_get_smu_metrics_data(smu, METRICS_AVERAGE_GFXCLK, (uint32_t *)data);
+               ret = navi1x_get_smu_metrics_data(smu, METRICS_AVERAGE_GFXCLK, (uint32_t *)data);
                *(uint32_t *)data *= 100;
                *size = 4;
                break;
@@ -2287,14 +2596,75 @@ static int navi10_run_umc_cdr_workaround(struct smu_context *smu)
        return 0;
 }
 
+static ssize_t navi10_get_legacy_gpu_metrics(struct smu_context *smu,
+                                            void **table)
+{
+       struct smu_table_context *smu_table = &smu->smu_table;
+       struct gpu_metrics_v1_0 *gpu_metrics =
+               (struct gpu_metrics_v1_0 *)smu_table->gpu_metrics_table;
+       SmuMetrics_legacy_t metrics;
+       int ret = 0;
+
+       mutex_lock(&smu->metrics_lock);
+
+       ret = smu_cmn_get_metrics_table_locked(smu,
+                                              NULL,
+                                              true);
+       if (ret) {
+               mutex_unlock(&smu->metrics_lock);
+               return ret;
+       }
+
+       memcpy(&metrics, smu_table->metrics_table, sizeof(SmuMetrics_legacy_t));
+
+       mutex_unlock(&smu->metrics_lock);
+
+       smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 0);
+
+       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_socket_power = metrics.AverageSocketPower;
+
+       gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequency;
+       gpu_metrics->average_socclk_frequency = metrics.AverageSocclkFrequency;
+       gpu_metrics->average_uclk_frequency = metrics.AverageUclkFrequency;
+
+       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];
+       gpu_metrics->current_dclk0 = metrics.CurrClock[PPCLK_DCLK];
+
+       gpu_metrics->throttle_status = metrics.ThrottlerStatus;
+
+       gpu_metrics->current_fan_speed = metrics.CurrFanSpeed;
+
+       gpu_metrics->pcie_link_width =
+                       smu_v11_0_get_current_pcie_link_width(smu);
+       gpu_metrics->pcie_link_speed =
+                       smu_v11_0_get_current_pcie_link_speed(smu);
+
+       gpu_metrics->system_clock_counter = ktime_get_boottime_ns();
+
+       *table = (void *)gpu_metrics;
+
+       return sizeof(struct gpu_metrics_v1_0);
+}
+
 static ssize_t navi10_get_gpu_metrics(struct smu_context *smu,
                                      void **table)
 {
        struct smu_table_context *smu_table = &smu->smu_table;
        struct gpu_metrics_v1_0 *gpu_metrics =
                (struct gpu_metrics_v1_0 *)smu_table->gpu_metrics_table;
-       struct amdgpu_device *adev = smu->adev;
-       SmuMetrics_NV12_t nv12_metrics = { 0 };
        SmuMetrics_t metrics;
        int ret = 0;
 
@@ -2309,8 +2679,73 @@ static ssize_t navi10_get_gpu_metrics(struct smu_context *smu,
        }
 
        memcpy(&metrics, smu_table->metrics_table, sizeof(SmuMetrics_t));
-       if (adev->asic_type == CHIP_NAVI12)
-               memcpy(&nv12_metrics, smu_table->metrics_table, sizeof(SmuMetrics_NV12_t));
+
+       mutex_unlock(&smu->metrics_lock);
+
+       smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 0);
+
+       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_socket_power = metrics.AverageSocketPower;
+
+       if (metrics.AverageGfxActivity > SMU_11_0_GFX_BUSY_THRESHOLD)
+               gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequencyPreDs;
+       else
+               gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequencyPostDs;
+
+       gpu_metrics->average_socclk_frequency = metrics.AverageSocclkFrequency;
+       gpu_metrics->average_uclk_frequency = metrics.AverageUclkFrequencyPostDs;
+
+       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];
+       gpu_metrics->current_dclk0 = metrics.CurrClock[PPCLK_DCLK];
+
+       gpu_metrics->throttle_status = metrics.ThrottlerStatus;
+
+       gpu_metrics->current_fan_speed = metrics.CurrFanSpeed;
+
+       gpu_metrics->pcie_link_width =
+                       smu_v11_0_get_current_pcie_link_width(smu);
+       gpu_metrics->pcie_link_speed =
+                       smu_v11_0_get_current_pcie_link_speed(smu);
+
+       gpu_metrics->system_clock_counter = ktime_get_boottime_ns();
+
+       *table = (void *)gpu_metrics;
+
+       return sizeof(struct gpu_metrics_v1_0);
+}
+
+static ssize_t navi12_get_legacy_gpu_metrics(struct smu_context *smu,
+                                            void **table)
+{
+       struct smu_table_context *smu_table = &smu->smu_table;
+       struct gpu_metrics_v1_0 *gpu_metrics =
+               (struct gpu_metrics_v1_0 *)smu_table->gpu_metrics_table;
+       SmuMetrics_NV12_legacy_t metrics;
+       int ret = 0;
+
+       mutex_lock(&smu->metrics_lock);
+
+       ret = smu_cmn_get_metrics_table_locked(smu,
+                                              NULL,
+                                              true);
+       if (ret) {
+               mutex_unlock(&smu->metrics_lock);
+               return ret;
+       }
+
+       memcpy(&metrics, smu_table->metrics_table, sizeof(SmuMetrics_NV12_legacy_t));
 
        mutex_unlock(&smu->metrics_lock);
 
@@ -2332,13 +2767,83 @@ static ssize_t navi10_get_gpu_metrics(struct smu_context *smu,
        gpu_metrics->average_socclk_frequency = metrics.AverageSocclkFrequency;
        gpu_metrics->average_uclk_frequency = metrics.AverageUclkFrequency;
 
-       if (adev->asic_type == CHIP_NAVI12) {
-               gpu_metrics->energy_accumulator = nv12_metrics.EnergyAccumulator;
-               gpu_metrics->average_vclk0_frequency = nv12_metrics.AverageVclkFrequency;
-               gpu_metrics->average_dclk0_frequency = nv12_metrics.AverageDclkFrequency;
-               gpu_metrics->average_mm_activity = nv12_metrics.VcnActivityPercentage;
+       gpu_metrics->energy_accumulator = metrics.EnergyAccumulator;
+       gpu_metrics->average_vclk0_frequency = metrics.AverageVclkFrequency;
+       gpu_metrics->average_dclk0_frequency = metrics.AverageDclkFrequency;
+       gpu_metrics->average_mm_activity = metrics.VcnActivityPercentage;
+
+       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];
+       gpu_metrics->current_dclk0 = metrics.CurrClock[PPCLK_DCLK];
+
+       gpu_metrics->throttle_status = metrics.ThrottlerStatus;
+
+       gpu_metrics->current_fan_speed = metrics.CurrFanSpeed;
+
+       gpu_metrics->pcie_link_width =
+                       smu_v11_0_get_current_pcie_link_width(smu);
+       gpu_metrics->pcie_link_speed =
+                       smu_v11_0_get_current_pcie_link_speed(smu);
+
+       gpu_metrics->system_clock_counter = ktime_get_boottime_ns();
+
+       *table = (void *)gpu_metrics;
+
+       return sizeof(struct gpu_metrics_v1_0);
+}
+
+static ssize_t navi12_get_gpu_metrics(struct smu_context *smu,
+                                     void **table)
+{
+       struct smu_table_context *smu_table = &smu->smu_table;
+       struct gpu_metrics_v1_0 *gpu_metrics =
+               (struct gpu_metrics_v1_0 *)smu_table->gpu_metrics_table;
+       SmuMetrics_NV12_t metrics;
+       int ret = 0;
+
+       mutex_lock(&smu->metrics_lock);
+
+       ret = smu_cmn_get_metrics_table_locked(smu,
+                                              NULL,
+                                              true);
+       if (ret) {
+               mutex_unlock(&smu->metrics_lock);
+               return ret;
        }
 
+       memcpy(&metrics, smu_table->metrics_table, sizeof(SmuMetrics_NV12_t));
+
+       mutex_unlock(&smu->metrics_lock);
+
+       smu_cmn_init_soft_gpu_metrics(gpu_metrics, 1, 0);
+
+       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_socket_power = metrics.AverageSocketPower;
+
+       if (metrics.AverageGfxActivity > SMU_11_0_GFX_BUSY_THRESHOLD)
+               gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequencyPreDs;
+       else
+               gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequencyPostDs;
+
+       gpu_metrics->average_socclk_frequency = metrics.AverageSocclkFrequency;
+       gpu_metrics->average_uclk_frequency = metrics.AverageUclkFrequencyPostDs;
+
+       gpu_metrics->energy_accumulator = metrics.EnergyAccumulator;
+       gpu_metrics->average_vclk0_frequency = metrics.AverageVclkFrequency;
+       gpu_metrics->average_dclk0_frequency = metrics.AverageDclkFrequency;
+       gpu_metrics->average_mm_activity = metrics.VcnActivityPercentage;
+
        gpu_metrics->current_gfxclk = metrics.CurrClock[PPCLK_GFXCLK];
        gpu_metrics->current_socclk = metrics.CurrClock[PPCLK_SOCCLK];
        gpu_metrics->current_uclk = metrics.CurrClock[PPCLK_UCLK];
@@ -2361,6 +2866,40 @@ static ssize_t navi10_get_gpu_metrics(struct smu_context *smu,
        return sizeof(struct gpu_metrics_v1_0);
 }
 
+static ssize_t navi1x_get_gpu_metrics(struct smu_context *smu,
+                                     void **table)
+{
+       struct amdgpu_device *adev = smu->adev;
+       uint32_t smu_version;
+       int ret = 0;
+
+       ret = smu_cmn_get_smc_version(smu, NULL, &smu_version);
+       if (ret) {
+               dev_err(adev->dev, "Failed to get smu version!\n");
+               return ret;
+       }
+
+       switch (adev->asic_type) {
+       case CHIP_NAVI12:
+               if (smu_version > 0x00341C00)
+                       ret = navi12_get_gpu_metrics(smu, table);
+               else
+                       ret = navi12_get_legacy_gpu_metrics(smu, table);
+               break;
+       case CHIP_NAVI10:
+       case CHIP_NAVI14:
+       default:
+               if (((adev->asic_type == CHIP_NAVI14) && smu_version > 0x00351F00) ||
+                     ((adev->asic_type == CHIP_NAVI10) && smu_version > 0x002A3B00))
+                       ret = navi10_get_gpu_metrics(smu, table);
+               else
+                       ret =navi10_get_legacy_gpu_metrics(smu, table);
+               break;
+       }
+
+       return ret;
+}
+
 static int navi10_enable_mgpu_fan_boost(struct smu_context *smu)
 {
        struct amdgpu_device *adev = smu->adev;
@@ -2489,7 +3028,7 @@ static const struct pptable_funcs navi10_ppt_funcs = {
        .set_power_source = smu_v11_0_set_power_source,
        .get_pp_feature_mask = smu_cmn_get_pp_feature_mask,
        .set_pp_feature_mask = smu_cmn_set_pp_feature_mask,
-       .get_gpu_metrics = navi10_get_gpu_metrics,
+       .get_gpu_metrics = navi1x_get_gpu_metrics,
        .enable_mgpu_fan_boost = navi10_enable_mgpu_fan_boost,
        .gfx_ulv_control = smu_v11_0_gfx_ulv_control,
        .deep_sleep_control = smu_v11_0_deep_sleep_control,