Commit d6810d7d authored by Sathishkumar S's avatar Sathishkumar S Committed by Alex Deucher

drm/amd/pm: support ss metrics read for smu11

support reading smartshift apu and dgpu power for smu11 based asic

v2: add new version of SmuMetrics and make calculation more readable (Lijo)
v3: avoid calculations that result in -ve values and skip related checks
v4: use the current power limit on dGPU and exclude smu 11_0_7 (Lijo)
v5: remove redundant code (Lijo)
Signed-off-by: default avatarSathishkumar S <sathishkumar.sundararaju@amd.com>
Acked-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Reviewed-by: default avatarLijo Lazar <lijo.lazar@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 87b5ab28
...@@ -1540,11 +1540,74 @@ typedef struct { ...@@ -1540,11 +1540,74 @@ typedef struct {
} SmuMetrics_V3_t; } SmuMetrics_V3_t;
typedef struct {
uint32_t CurrClock[PPCLK_COUNT];
uint16_t AverageGfxclkFrequencyPreDs;
uint16_t AverageGfxclkFrequencyPostDs;
uint16_t AverageFclkFrequencyPreDs;
uint16_t AverageFclkFrequencyPostDs;
uint16_t AverageUclkFrequencyPreDs;
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 AccCnt;
uint8_t ThrottlingPercentage[THROTTLER_COUNT];
uint8_t LinkDpmLevel;
uint8_t CurrFanPwm;
uint16_t CurrFanSpeed;
//BACO metrics, PMFW-1721
//metrics for D3hot entry/exit and driver ARM msgs
uint8_t D3HotEntryCountPerMode[D3HOT_SEQUENCE_COUNT];
uint8_t D3HotExitCountPerMode[D3HOT_SEQUENCE_COUNT];
uint8_t ArmMsgReceivedCountPerMode[D3HOT_SEQUENCE_COUNT];
//PMFW-4362
uint32_t EnergyAccumulator;
uint16_t AverageVclk0Frequency;
uint16_t AverageDclk0Frequency;
uint16_t AverageVclk1Frequency;
uint16_t AverageDclk1Frequency;
uint16_t VcnUsagePercentage0;
uint16_t VcnUsagePercentage1;
uint8_t PcieRate;
uint8_t PcieWidth;
uint16_t AverageGfxclkFrequencyTarget;
uint8_t ApuSTAPMSmartShiftLimit;
uint8_t AverageApuSocketPower;
uint8_t ApuSTAPMLimit;
uint8_t Padding8_2;
} SmuMetrics_V4_t;
typedef struct { typedef struct {
union { union {
SmuMetrics_t SmuMetrics; SmuMetrics_t SmuMetrics;
SmuMetrics_V2_t SmuMetrics_V2; SmuMetrics_V2_t SmuMetrics_V2;
SmuMetrics_V3_t SmuMetrics_V3; SmuMetrics_V3_t SmuMetrics_V3;
SmuMetrics_V4_t SmuMetrics_V4;
}; };
uint32_t Spare[1]; uint32_t Spare[1];
......
...@@ -585,6 +585,100 @@ static uint32_t sienna_cichlid_get_throttler_status_locked(struct smu_context *s ...@@ -585,6 +585,100 @@ static uint32_t sienna_cichlid_get_throttler_status_locked(struct smu_context *s
return throttler_status; return throttler_status;
} }
static int sienna_cichlid_get_power_limit(struct smu_context *smu,
uint32_t *current_power_limit,
uint32_t *default_power_limit,
uint32_t *max_power_limit)
{
struct smu_11_0_7_powerplay_table *powerplay_table =
(struct smu_11_0_7_powerplay_table *)smu->smu_table.power_play_table;
uint32_t power_limit, od_percent;
uint16_t *table_member;
GET_PPTABLE_MEMBER(SocketPowerLimitAc, &table_member);
if (smu_v11_0_get_current_power_limit(smu, &power_limit)) {
power_limit =
table_member[PPT_THROTTLER_PPT0];
}
if (current_power_limit)
*current_power_limit = power_limit;
if (default_power_limit)
*default_power_limit = power_limit;
if (max_power_limit) {
if (smu->od_enabled) {
od_percent =
le32_to_cpu(powerplay_table->overdrive_table.max[
SMU_11_0_7_ODSETTING_POWERPERCENTAGE]);
dev_dbg(smu->adev->dev, "ODSETTING_POWERPERCENTAGE: %d (default: %d)\n",
od_percent, power_limit);
power_limit *= (100 + od_percent);
power_limit /= 100;
}
*max_power_limit = power_limit;
}
return 0;
}
static void sienna_cichlid_get_smartshift_power_percentage(struct smu_context *smu,
uint32_t *apu_percent,
uint32_t *dgpu_percent)
{
struct smu_table_context *smu_table = &smu->smu_table;
SmuMetrics_V4_t *metrics_v4 =
&(((SmuMetricsExternal_t *)(smu_table->metrics_table))->SmuMetrics_V4);
uint16_t powerRatio = 0;
uint16_t apu_power_limit = 0;
uint16_t dgpu_power_limit = 0;
uint32_t apu_boost = 0;
uint32_t dgpu_boost = 0;
uint32_t cur_power_limit;
if (metrics_v4->ApuSTAPMSmartShiftLimit != 0) {
sienna_cichlid_get_power_limit(smu, &cur_power_limit, NULL, NULL);
apu_power_limit = metrics_v4->ApuSTAPMLimit;
dgpu_power_limit = cur_power_limit;
powerRatio = (((apu_power_limit +
dgpu_power_limit) * 100) /
metrics_v4->ApuSTAPMSmartShiftLimit);
if (powerRatio > 100) {
apu_power_limit = (apu_power_limit * 100) /
powerRatio;
dgpu_power_limit = (dgpu_power_limit * 100) /
powerRatio;
}
if (metrics_v4->AverageApuSocketPower > apu_power_limit &&
apu_power_limit != 0) {
apu_boost = ((metrics_v4->AverageApuSocketPower -
apu_power_limit) * 100) /
apu_power_limit;
if (apu_boost > 100)
apu_boost = 100;
}
if (metrics_v4->AverageSocketPower > dgpu_power_limit &&
dgpu_power_limit != 0) {
dgpu_boost = ((metrics_v4->AverageSocketPower -
dgpu_power_limit) * 100) /
dgpu_power_limit;
if (dgpu_boost > 100)
dgpu_boost = 100;
}
if (dgpu_boost >= apu_boost)
apu_boost = 0;
else
dgpu_boost = 0;
}
*apu_percent = apu_boost;
*dgpu_percent = dgpu_boost;
}
static int sienna_cichlid_get_smu_metrics_data(struct smu_context *smu, static int sienna_cichlid_get_smu_metrics_data(struct smu_context *smu,
MetricsMember_t member, MetricsMember_t member,
uint32_t *value) uint32_t *value)
...@@ -600,6 +694,8 @@ static int sienna_cichlid_get_smu_metrics_data(struct smu_context *smu, ...@@ -600,6 +694,8 @@ static int sienna_cichlid_get_smu_metrics_data(struct smu_context *smu,
bool use_metrics_v3 = false; bool use_metrics_v3 = false;
uint16_t average_gfx_activity; uint16_t average_gfx_activity;
int ret = 0; int ret = 0;
uint32_t apu_percent = 0;
uint32_t dgpu_percent = 0;
if ((smu->adev->ip_versions[MP1_HWIP][0] == IP_VERSION(11, 0, 7)) && if ((smu->adev->ip_versions[MP1_HWIP][0] == IP_VERSION(11, 0, 7)) &&
(smu->smc_fw_version >= 0x3A4900)) (smu->smc_fw_version >= 0x3A4900))
...@@ -738,6 +834,15 @@ static int sienna_cichlid_get_smu_metrics_data(struct smu_context *smu, ...@@ -738,6 +834,15 @@ static int sienna_cichlid_get_smu_metrics_data(struct smu_context *smu,
/* Only supported in 0x3A5300+, metrics_v3 requires 0x3A4900+ */ /* Only supported in 0x3A5300+, metrics_v3 requires 0x3A4900+ */
*value = use_metrics_v3 ? metrics_v3->PublicSerialNumLower32 : 0; *value = use_metrics_v3 ? metrics_v3->PublicSerialNumLower32 : 0;
break; break;
case METRICS_SS_APU_SHARE:
sienna_cichlid_get_smartshift_power_percentage(smu, &apu_percent, &dgpu_percent);
*value = apu_percent;
break;
case METRICS_SS_DGPU_SHARE:
sienna_cichlid_get_smartshift_power_percentage(smu, &apu_percent, &dgpu_percent);
*value = dgpu_percent;
break;
default: default:
*value = UINT_MAX; *value = UINT_MAX;
break; break;
...@@ -1728,6 +1833,7 @@ static int sienna_cichlid_read_sensor(struct smu_context *smu, ...@@ -1728,6 +1833,7 @@ static int sienna_cichlid_read_sensor(struct smu_context *smu,
{ {
int ret = 0; int ret = 0;
uint16_t *temp; uint16_t *temp;
struct amdgpu_device *adev = smu->adev;
if(!data || !size) if(!data || !size)
return -EINVAL; return -EINVAL;
...@@ -1788,6 +1894,24 @@ static int sienna_cichlid_read_sensor(struct smu_context *smu, ...@@ -1788,6 +1894,24 @@ static int sienna_cichlid_read_sensor(struct smu_context *smu,
ret = smu_v11_0_get_gfx_vdd(smu, (uint32_t *)data); ret = smu_v11_0_get_gfx_vdd(smu, (uint32_t *)data);
*size = 4; *size = 4;
break; break;
case AMDGPU_PP_SENSOR_SS_APU_SHARE:
if (adev->ip_versions[MP1_HWIP][0] != IP_VERSION(11, 0, 7)) {
ret = sienna_cichlid_get_smu_metrics_data(smu,
METRICS_SS_APU_SHARE, (uint32_t *)data);
*size = 4;
} else {
ret = -EOPNOTSUPP;
}
break;
case AMDGPU_PP_SENSOR_SS_DGPU_SHARE:
if (adev->ip_versions[MP1_HWIP][0] != IP_VERSION(11, 0, 7)) {
ret = sienna_cichlid_get_smu_metrics_data(smu,
METRICS_SS_DGPU_SHARE, (uint32_t *)data);
*size = 4;
} else {
ret = -EOPNOTSUPP;
}
break;
default: default:
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
break; break;
...@@ -1907,43 +2031,6 @@ static int sienna_cichlid_display_disable_memory_clock_switch(struct smu_context ...@@ -1907,43 +2031,6 @@ static int sienna_cichlid_display_disable_memory_clock_switch(struct smu_context
return ret; return ret;
} }
static int sienna_cichlid_get_power_limit(struct smu_context *smu,
uint32_t *current_power_limit,
uint32_t *default_power_limit,
uint32_t *max_power_limit)
{
struct smu_11_0_7_powerplay_table *powerplay_table =
(struct smu_11_0_7_powerplay_table *)smu->smu_table.power_play_table;
uint32_t power_limit, od_percent;
uint16_t *table_member;
GET_PPTABLE_MEMBER(SocketPowerLimitAc, &table_member);
if (smu_v11_0_get_current_power_limit(smu, &power_limit)) {
power_limit =
table_member[PPT_THROTTLER_PPT0];
}
if (current_power_limit)
*current_power_limit = power_limit;
if (default_power_limit)
*default_power_limit = power_limit;
if (max_power_limit) {
if (smu->od_enabled) {
od_percent = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_7_ODSETTING_POWERPERCENTAGE]);
dev_dbg(smu->adev->dev, "ODSETTING_POWERPERCENTAGE: %d (default: %d)\n", od_percent, power_limit);
power_limit *= (100 + od_percent);
power_limit /= 100;
}
*max_power_limit = power_limit;
}
return 0;
}
static int sienna_cichlid_update_pcie_parameters(struct smu_context *smu, static int sienna_cichlid_update_pcie_parameters(struct smu_context *smu,
uint32_t pcie_gen_cap, uint32_t pcie_gen_cap,
uint32_t pcie_width_cap) uint32_t pcie_width_cap)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment