drm/amd/pm: Validate Tonga PPTable subtable bounds

v1:
Tonga PPTable parsing also relies on VBIOS offsets, revision fields
and entry counts for several subtables. Malformed data can cause
out-of-bounds reads, while voltage lookup tables can overrun their
fixed-size destination arrays.

Add common bounds helpers and validate fixed subtables, dynamic entry
arrays and revision-specific layouts before consuming voltage lookup,
dependency, PCIE, power-tune, hard-limit, thermal, fan, GPIO, PPM and
VCE state data.

v2:
correct to handle get_tonga_ppm_table() return value.

Signed-off-by: Yang Wang <kevinyang.wang@amd.com>
Reviewed-by: Asad Kamal <asad.kamal@amd.com>
Reviewed-by: Kenneth Feng <kenneth.feng@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Yang Wang 2026-06-23 16:37:07 +08:00 committed by Alex Deucher
parent 9914149f99
commit 53ef33c084

View File

@ -150,6 +150,368 @@ static const void *get_powerplay_table(struct pp_hwmgr *hwmgr)
return table_address;
}
static bool tonga_pp_table_has_space(struct pp_hwmgr *hwmgr, size_t offset,
size_t size)
{
size_t table_size = hwmgr->soft_pp_table_size;
return offset <= table_size && size <= table_size - offset;
}
static int get_tonga_subtable(struct pp_hwmgr *hwmgr,
const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
u16 table_offset, size_t table_size, const void **table)
{
PP_ASSERT_WITH_CODE((table_offset != 0),
"Invalid PowerPlay Table!", return -1);
PP_ASSERT_WITH_CODE((tonga_pp_table_has_space(hwmgr, table_offset,
table_size)),
"Invalid PowerPlay Table!", return -1);
*table = (const void *)(((unsigned long)powerplay_table) + table_offset);
return 0;
}
static int validate_tonga_table_entries(struct pp_hwmgr *hwmgr,
u16 table_offset, size_t entries_offset,
u8 num_entries, size_t entry_size)
{
size_t table_size;
PP_ASSERT_WITH_CODE((num_entries != 0),
"Invalid PowerPlay Table!", return -1);
table_size = entries_offset + num_entries * entry_size;
PP_ASSERT_WITH_CODE((tonga_pp_table_has_space(hwmgr, table_offset,
table_size)),
"Invalid PowerPlay Table!", return -1);
return 0;
}
static int get_tonga_voltage_lookup_table(struct pp_hwmgr *hwmgr,
const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
u16 table_offset, uint32_t max_levels,
const ATOM_Tonga_Voltage_Lookup_Table **lookup_table)
{
const ATOM_Tonga_Voltage_Lookup_Table *table;
size_t table_size;
int ret;
ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset,
sizeof(*table), (const void **)&table);
if (ret)
return ret;
PP_ASSERT_WITH_CODE((table->ucNumEntries != 0 &&
table->ucNumEntries <= max_levels),
"Invalid PowerPlay Table!", return -1);
table_size = offsetof(ATOM_Tonga_Voltage_Lookup_Table, entries) +
table->ucNumEntries * sizeof(ATOM_Tonga_Voltage_Lookup_Record);
PP_ASSERT_WITH_CODE((tonga_pp_table_has_space(hwmgr, table_offset,
table_size)),
"Invalid PowerPlay Table!", return -1);
*lookup_table = table;
return 0;
}
static int get_tonga_mclk_dependency_table(struct pp_hwmgr *hwmgr,
const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
const ATOM_Tonga_MCLK_Dependency_Table **mclk_dep_table)
{
const ATOM_Tonga_MCLK_Dependency_Table *table;
u16 table_offset;
int ret;
table_offset = le16_to_cpu(powerplay_table->usMclkDependencyTableOffset);
ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset,
sizeof(*table), (const void **)&table);
if (ret)
return ret;
ret = validate_tonga_table_entries(hwmgr, table_offset,
offsetof(ATOM_Tonga_MCLK_Dependency_Table,
entries),
table->ucNumEntries,
sizeof(ATOM_Tonga_MCLK_Dependency_Record));
if (ret)
return ret;
*mclk_dep_table = table;
return 0;
}
static int get_tonga_mm_dependency_table(struct pp_hwmgr *hwmgr,
const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
const ATOM_Tonga_MM_Dependency_Table **mm_dep_table)
{
const ATOM_Tonga_MM_Dependency_Table *table;
u16 table_offset;
int ret;
table_offset = le16_to_cpu(powerplay_table->usMMDependencyTableOffset);
ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset,
sizeof(*table), (const void **)&table);
if (ret)
return ret;
ret = validate_tonga_table_entries(hwmgr, table_offset,
offsetof(ATOM_Tonga_MM_Dependency_Table,
entries),
table->ucNumEntries,
sizeof(ATOM_Tonga_MM_Dependency_Record));
if (ret)
return ret;
*mm_dep_table = table;
return 0;
}
static int get_tonga_sclk_dependency_table(struct pp_hwmgr *hwmgr,
const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
const PPTable_Generic_SubTable_Header **sclk_dep_table)
{
const PPTable_Generic_SubTable_Header *header;
u16 table_offset;
size_t entries_offset;
size_t entry_size;
u8 num_entries;
int ret;
table_offset = le16_to_cpu(powerplay_table->usSclkDependencyTableOffset);
ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset,
sizeof(*header), (const void **)&header);
if (ret)
return ret;
if (header->ucRevId < 1) {
const ATOM_Tonga_SCLK_Dependency_Table *table =
(const ATOM_Tonga_SCLK_Dependency_Table *)header;
entries_offset = offsetof(ATOM_Tonga_SCLK_Dependency_Table, entries);
entry_size = sizeof(ATOM_Tonga_SCLK_Dependency_Record);
num_entries = table->ucNumEntries;
} else {
const ATOM_Polaris_SCLK_Dependency_Table *table =
(const ATOM_Polaris_SCLK_Dependency_Table *)header;
entries_offset = offsetof(ATOM_Polaris_SCLK_Dependency_Table, entries);
entry_size = sizeof(ATOM_Polaris_SCLK_Dependency_Record);
num_entries = table->ucNumEntries;
}
ret = validate_tonga_table_entries(hwmgr, table_offset, entries_offset,
num_entries, entry_size);
if (ret)
return ret;
*sclk_dep_table = header;
return 0;
}
static int get_tonga_pcie_table(struct pp_hwmgr *hwmgr,
const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
const PPTable_Generic_SubTable_Header **pcie_table)
{
const PPTable_Generic_SubTable_Header *header;
u16 table_offset;
size_t entries_offset;
size_t entry_size;
u8 num_entries;
int ret;
table_offset = le16_to_cpu(powerplay_table->usPCIETableOffset);
ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset,
sizeof(*header), (const void **)&header);
if (ret)
return ret;
if (header->ucRevId < 1) {
const ATOM_Tonga_PCIE_Table *table =
(const ATOM_Tonga_PCIE_Table *)header;
entries_offset = offsetof(ATOM_Tonga_PCIE_Table, entries);
entry_size = sizeof(ATOM_Tonga_PCIE_Record);
num_entries = table->ucNumEntries;
} else {
const ATOM_Polaris10_PCIE_Table *table =
(const ATOM_Polaris10_PCIE_Table *)header;
entries_offset = offsetof(ATOM_Polaris10_PCIE_Table, entries);
entry_size = sizeof(ATOM_Polaris10_PCIE_Record);
num_entries = table->ucNumEntries;
}
ret = validate_tonga_table_entries(hwmgr, table_offset, entries_offset,
num_entries, entry_size);
if (ret)
return ret;
*pcie_table = header;
return 0;
}
static int get_tonga_hard_limit_table(struct pp_hwmgr *hwmgr,
const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
const ATOM_Tonga_Hard_Limit_Table **hard_limit_table)
{
const ATOM_Tonga_Hard_Limit_Table *table;
u16 table_offset;
int ret;
table_offset = le16_to_cpu(powerplay_table->usHardLimitTableOffset);
ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset,
sizeof(*table), (const void **)&table);
if (ret)
return ret;
ret = validate_tonga_table_entries(hwmgr, table_offset,
offsetof(ATOM_Tonga_Hard_Limit_Table,
entries),
table->ucNumEntries,
sizeof(ATOM_Tonga_Hard_Limit_Record));
if (ret)
return ret;
*hard_limit_table = table;
return 0;
}
static int get_tonga_thermal_controller_table(struct pp_hwmgr *hwmgr,
const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
const ATOM_Tonga_Thermal_Controller **thermal_controller)
{
u16 table_offset;
table_offset = le16_to_cpu(powerplay_table->usThermalControllerOffset);
return get_tonga_subtable(hwmgr, powerplay_table, table_offset,
sizeof(**thermal_controller),
(const void **)thermal_controller);
}
static int get_tonga_fan_table(struct pp_hwmgr *hwmgr,
const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
const PPTable_Generic_SubTable_Header **fan_table)
{
const PPTable_Generic_SubTable_Header *header;
u16 table_offset;
size_t table_size;
int ret;
table_offset = le16_to_cpu(powerplay_table->usFanTableOffset);
ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset,
sizeof(*header), (const void **)&header);
if (ret)
return ret;
if (header->ucRevId < 8)
table_size = sizeof(ATOM_Tonga_Fan_Table);
else if (header->ucRevId == 8)
table_size = sizeof(ATOM_Fiji_Fan_Table);
else
table_size = sizeof(ATOM_Polaris_Fan_Table);
PP_ASSERT_WITH_CODE((tonga_pp_table_has_space(hwmgr, table_offset,
table_size)),
"Invalid PowerPlay Table!", return -1);
*fan_table = header;
return 0;
}
static int get_tonga_power_tune_table(struct pp_hwmgr *hwmgr,
const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
const PPTable_Generic_SubTable_Header **power_tune_table)
{
const PPTable_Generic_SubTable_Header *header;
u16 table_offset;
size_t table_size;
int ret;
table_offset = le16_to_cpu(powerplay_table->usPowerTuneTableOffset);
ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset,
sizeof(*header), (const void **)&header);
if (ret)
return ret;
if (header->ucRevId < 3)
table_size = sizeof(ATOM_Tonga_PowerTune_Table);
else if (header->ucRevId < 4)
table_size = sizeof(ATOM_Fiji_PowerTune_Table);
else
table_size = sizeof(ATOM_Polaris_PowerTune_Table);
PP_ASSERT_WITH_CODE((tonga_pp_table_has_space(hwmgr, table_offset,
table_size)),
"Invalid PowerPlay Table!", return -1);
*power_tune_table = header;
return 0;
}
static int get_tonga_ppm_table(struct pp_hwmgr *hwmgr,
const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
const ATOM_Tonga_PPM_Table **ppm_table)
{
u16 table_offset;
table_offset = le16_to_cpu(powerplay_table->usPPMTableOffset);
return get_tonga_subtable(hwmgr, powerplay_table, table_offset,
sizeof(**ppm_table), (const void **)ppm_table);
}
static int get_tonga_gpio_table(struct pp_hwmgr *hwmgr,
const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
const ATOM_Tonga_GPIO_Table **gpio_table)
{
u16 table_offset;
table_offset = le16_to_cpu(powerplay_table->usGPIOTableOffset);
return get_tonga_subtable(hwmgr, powerplay_table, table_offset,
sizeof(**gpio_table), (const void **)gpio_table);
}
static int get_tonga_vce_state_table(struct pp_hwmgr *hwmgr,
const ATOM_Tonga_POWERPLAYTABLE *powerplay_table,
const ATOM_Tonga_VCE_State_Table **vce_state_table)
{
const ATOM_Tonga_VCE_State_Table *table;
u16 table_offset;
int ret;
table_offset = le16_to_cpu(powerplay_table->usVCEStateTableOffset);
ret = get_tonga_subtable(hwmgr, powerplay_table, table_offset,
sizeof(*table), (const void **)&table);
if (ret)
return ret;
ret = validate_tonga_table_entries(hwmgr, table_offset,
offsetof(ATOM_Tonga_VCE_State_Table,
entries),
table->ucNumEntries,
sizeof(ATOM_Tonga_VCE_State_Record));
if (ret)
return ret;
*vce_state_table = table;
return 0;
}
static int get_vddc_lookup_table(
struct pp_hwmgr *hwmgr,
phm_ppt_v1_voltage_lookup_table **lookup_table,
@ -208,7 +570,7 @@ static int get_vddc_lookup_table(
*/
static int get_platform_power_management_table(
struct pp_hwmgr *hwmgr,
ATOM_Tonga_PPM_Table *atom_ppm_table)
const ATOM_Tonga_PPM_Table *atom_ppm_table)
{
struct phm_ppm_table *ptr = kzalloc_obj(*ptr);
struct phm_ppt_v1_information *pp_table_information =
@ -256,7 +618,7 @@ static int init_dpm_2_parameters(
{
int result = 0;
struct phm_ppt_v1_information *pp_table_information = (struct phm_ppt_v1_information *)(hwmgr->pptable);
ATOM_Tonga_PPM_Table *atom_ppm_table;
const ATOM_Tonga_PPM_Table *atom_ppm_table;
uint32_t disable_ppm = 0;
uint32_t disable_power_control = 0;
@ -285,30 +647,39 @@ static int init_dpm_2_parameters(
}
if (0 != powerplay_table->usVddcLookupTableOffset) {
const ATOM_Tonga_Voltage_Lookup_Table *pVddcCACTable =
(ATOM_Tonga_Voltage_Lookup_Table *)(((unsigned long)powerplay_table) +
le16_to_cpu(powerplay_table->usVddcLookupTableOffset));
const ATOM_Tonga_Voltage_Lookup_Table *pVddcCACTable;
result = get_vddc_lookup_table(hwmgr,
&pp_table_information->vddc_lookup_table, pVddcCACTable, 16);
result = get_tonga_voltage_lookup_table(hwmgr, powerplay_table,
le16_to_cpu(powerplay_table->usVddcLookupTableOffset),
16, &pVddcCACTable);
if (!result)
result = get_vddc_lookup_table(hwmgr,
&pp_table_information->vddc_lookup_table,
pVddcCACTable, 16);
}
if (0 != powerplay_table->usVddgfxLookupTableOffset) {
const ATOM_Tonga_Voltage_Lookup_Table *pVddgfxCACTable =
(ATOM_Tonga_Voltage_Lookup_Table *)(((unsigned long)powerplay_table) +
le16_to_cpu(powerplay_table->usVddgfxLookupTableOffset));
if (!result && 0 != powerplay_table->usVddgfxLookupTableOffset) {
const ATOM_Tonga_Voltage_Lookup_Table *pVddgfxCACTable;
result = get_vddc_lookup_table(hwmgr,
&pp_table_information->vddgfx_lookup_table, pVddgfxCACTable, 16);
result = get_tonga_voltage_lookup_table(hwmgr, powerplay_table,
le16_to_cpu(powerplay_table->usVddgfxLookupTableOffset),
16, &pVddgfxCACTable);
if (!result)
result = get_vddc_lookup_table(hwmgr,
&pp_table_information->vddgfx_lookup_table,
pVddgfxCACTable, 16);
}
disable_ppm = 0;
if (0 == disable_ppm) {
atom_ppm_table = (ATOM_Tonga_PPM_Table *)
(((unsigned long)powerplay_table) + le16_to_cpu(powerplay_table->usPPMTableOffset));
if (0 != powerplay_table->usPPMTableOffset) {
if (get_platform_power_management_table(hwmgr, atom_ppm_table) == 0) {
int ret;
ret = get_tonga_ppm_table(hwmgr, powerplay_table,
&atom_ppm_table);
if (!ret &&
get_platform_power_management_table(hwmgr,
atom_ppm_table) == 0) {
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_EnablePlatformPowerManagement);
}
@ -831,28 +1202,13 @@ static int init_clock_voltage_dependency(
int result = 0;
struct phm_ppt_v1_information *pp_table_information =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
const ATOM_Tonga_MM_Dependency_Table *mm_dependency_table =
(const ATOM_Tonga_MM_Dependency_Table *)(((unsigned long) powerplay_table) +
le16_to_cpu(powerplay_table->usMMDependencyTableOffset));
const PPTable_Generic_SubTable_Header *pPowerTuneTable =
(const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) +
le16_to_cpu(powerplay_table->usPowerTuneTableOffset));
const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table =
(const ATOM_Tonga_MCLK_Dependency_Table *)(((unsigned long) powerplay_table) +
le16_to_cpu(powerplay_table->usMclkDependencyTableOffset));
const PPTable_Generic_SubTable_Header *sclk_dep_table =
(const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) +
le16_to_cpu(powerplay_table->usSclkDependencyTableOffset));
const ATOM_Tonga_Hard_Limit_Table *pHardLimits =
(const ATOM_Tonga_Hard_Limit_Table *)(((unsigned long) powerplay_table) +
le16_to_cpu(powerplay_table->usHardLimitTableOffset));
const PPTable_Generic_SubTable_Header *pcie_table =
(const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) +
le16_to_cpu(powerplay_table->usPCIETableOffset));
const ATOM_Tonga_GPIO_Table *gpio_table =
(const ATOM_Tonga_GPIO_Table *)(((unsigned long) powerplay_table) +
le16_to_cpu(powerplay_table->usGPIOTableOffset));
const ATOM_Tonga_MM_Dependency_Table *mm_dependency_table;
const PPTable_Generic_SubTable_Header *pPowerTuneTable;
const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table;
const PPTable_Generic_SubTable_Header *sclk_dep_table;
const ATOM_Tonga_Hard_Limit_Table *pHardLimits;
const PPTable_Generic_SubTable_Header *pcie_table;
const ATOM_Tonga_GPIO_Table *gpio_table;
pp_table_information->vdd_dep_on_sclk = NULL;
pp_table_information->vdd_dep_on_mclk = NULL;
@ -860,29 +1216,58 @@ static int init_clock_voltage_dependency(
pp_table_information->pcie_table = NULL;
pp_table_information->gpio_table = NULL;
if (powerplay_table->usMMDependencyTableOffset != 0)
result = get_mm_clock_voltage_table(hwmgr,
&pp_table_information->mm_dep_table, mm_dependency_table);
if (powerplay_table->usMMDependencyTableOffset != 0) {
result = get_tonga_mm_dependency_table(hwmgr, powerplay_table,
&mm_dependency_table);
if (!result)
result = get_mm_clock_voltage_table(hwmgr,
&pp_table_information->mm_dep_table,
mm_dependency_table);
}
if (result == 0 && powerplay_table->usPowerTuneTableOffset != 0)
result = get_cac_tdp_table(hwmgr,
&pp_table_information->cac_dtp_table, pPowerTuneTable);
if (result == 0 && powerplay_table->usPowerTuneTableOffset != 0) {
result = get_tonga_power_tune_table(hwmgr, powerplay_table,
&pPowerTuneTable);
if (!result)
result = get_cac_tdp_table(hwmgr,
&pp_table_information->cac_dtp_table,
pPowerTuneTable);
}
if (result == 0 && powerplay_table->usSclkDependencyTableOffset != 0)
result = get_sclk_voltage_dependency_table(hwmgr,
&pp_table_information->vdd_dep_on_sclk, sclk_dep_table);
if (result == 0 && powerplay_table->usSclkDependencyTableOffset != 0) {
result = get_tonga_sclk_dependency_table(hwmgr, powerplay_table,
&sclk_dep_table);
if (!result)
result = get_sclk_voltage_dependency_table(hwmgr,
&pp_table_information->vdd_dep_on_sclk,
sclk_dep_table);
}
if (result == 0 && powerplay_table->usMclkDependencyTableOffset != 0)
result = get_mclk_voltage_dependency_table(hwmgr,
&pp_table_information->vdd_dep_on_mclk, mclk_dep_table);
if (result == 0 && powerplay_table->usMclkDependencyTableOffset != 0) {
result = get_tonga_mclk_dependency_table(hwmgr, powerplay_table,
&mclk_dep_table);
if (!result)
result = get_mclk_voltage_dependency_table(hwmgr,
&pp_table_information->vdd_dep_on_mclk,
mclk_dep_table);
}
if (result == 0 && powerplay_table->usPCIETableOffset != 0)
result = get_pcie_table(hwmgr,
&pp_table_information->pcie_table, pcie_table);
if (result == 0 && powerplay_table->usPCIETableOffset != 0) {
result = get_tonga_pcie_table(hwmgr, powerplay_table,
&pcie_table);
if (!result)
result = get_pcie_table(hwmgr,
&pp_table_information->pcie_table, pcie_table);
}
if (result == 0 && powerplay_table->usHardLimitTableOffset != 0)
result = get_hard_limits(hwmgr,
&pp_table_information->max_clock_voltage_on_dc, pHardLimits);
if (result == 0 && powerplay_table->usHardLimitTableOffset != 0) {
result = get_tonga_hard_limit_table(hwmgr, powerplay_table,
&pHardLimits);
if (!result)
result = get_hard_limits(hwmgr,
&pp_table_information->max_clock_voltage_on_dc,
pHardLimits);
}
hwmgr->dyn_state.max_clock_voltage_on_dc.sclk =
pp_table_information->max_clock_voltage_on_dc.sclk;
@ -903,9 +1288,13 @@ static int init_clock_voltage_dependency(
result = get_valid_clk(hwmgr, &pp_table_information->valid_sclk_values,
pp_table_information->vdd_dep_on_sclk);
if (!result && gpio_table)
result = get_gpio_table(hwmgr, &pp_table_information->gpio_table,
gpio_table);
if (!result && powerplay_table->usGPIOTableOffset) {
result = get_tonga_gpio_table(hwmgr, powerplay_table,
&gpio_table);
if (!result)
result = get_gpio_table(hwmgr,
&pp_table_information->gpio_table, gpio_table);
}
return result;
}
@ -950,14 +1339,17 @@ static int init_thermal_controller(
)
{
const PPTable_Generic_SubTable_Header *fan_table;
ATOM_Tonga_Thermal_Controller *thermal_controller;
const ATOM_Tonga_Thermal_Controller *thermal_controller;
int ret;
thermal_controller = (ATOM_Tonga_Thermal_Controller *)
(((unsigned long)powerplay_table) +
le16_to_cpu(powerplay_table->usThermalControllerOffset));
PP_ASSERT_WITH_CODE((0 != powerplay_table->usThermalControllerOffset),
"Thermal controller table not set!", return -1);
ret = get_tonga_thermal_controller_table(hwmgr, powerplay_table,
&thermal_controller);
if (ret)
return ret;
hwmgr->thermal_controller.ucType = thermal_controller->ucType;
hwmgr->thermal_controller.ucI2cLine = thermal_controller->ucI2cLine;
hwmgr->thermal_controller.ucI2cAddress = thermal_controller->ucI2cAddress;
@ -985,12 +1377,13 @@ static int init_thermal_controller(
return 0;
}
fan_table = (const PPTable_Generic_SubTable_Header *)
(((unsigned long)powerplay_table) +
le16_to_cpu(powerplay_table->usFanTableOffset));
PP_ASSERT_WITH_CODE((0 != powerplay_table->usFanTableOffset),
"Fan table not set!", return -1);
ret = get_tonga_fan_table(hwmgr, powerplay_table, &fan_table);
if (ret)
return ret;
PP_ASSERT_WITH_CODE((0 < fan_table->ucRevId),
"Unsupported fan table format!", return -1);
@ -1352,13 +1745,15 @@ static int ppt_get_num_of_vce_state_table_entries_v1_0(struct pp_hwmgr *hwmgr)
{
const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr);
const ATOM_Tonga_VCE_State_Table *vce_state_table;
int ret;
if (pp_table == NULL)
return 0;
vce_state_table = (void *)pp_table +
le16_to_cpu(pp_table->usVCEStateTableOffset);
ret = get_tonga_vce_state_table(hwmgr, pp_table, &vce_state_table);
if (ret)
return 0;
return vce_state_table->ucNumEntries;
}
@ -1367,18 +1762,39 @@ static int ppt_get_vce_state_table_entry_v1_0(struct pp_hwmgr *hwmgr, uint32_t i
struct amd_vce_state *vce_state, void **clock_info, uint32_t *flag)
{
const ATOM_Tonga_VCE_State_Record *vce_state_record;
ATOM_Tonga_SCLK_Dependency_Record *sclk_dep_record;
ATOM_Tonga_SCLK_Dependency_Record *sclk_dep_record = NULL;
ATOM_Polaris_SCLK_Dependency_Record *polaris_sclk_dep_record = NULL;
ATOM_Tonga_MCLK_Dependency_Record *mclk_dep_record;
ATOM_Tonga_MM_Dependency_Record *mm_dep_record;
const ATOM_Tonga_POWERPLAYTABLE *pptable = get_powerplay_table(hwmgr);
const ATOM_Tonga_VCE_State_Table *vce_state_table = (ATOM_Tonga_VCE_State_Table *)(((unsigned long)pptable)
+ le16_to_cpu(pptable->usVCEStateTableOffset));
const ATOM_Tonga_SCLK_Dependency_Table *sclk_dep_table = (ATOM_Tonga_SCLK_Dependency_Table *)(((unsigned long)pptable)
+ le16_to_cpu(pptable->usSclkDependencyTableOffset));
const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table = (ATOM_Tonga_MCLK_Dependency_Table *)(((unsigned long)pptable)
+ le16_to_cpu(pptable->usMclkDependencyTableOffset));
const ATOM_Tonga_MM_Dependency_Table *mm_dep_table = (ATOM_Tonga_MM_Dependency_Table *)(((unsigned long)pptable)
+ le16_to_cpu(pptable->usMMDependencyTableOffset));
const ATOM_Tonga_VCE_State_Table *vce_state_table;
const PPTable_Generic_SubTable_Header *sclk_dep_table_header;
const ATOM_Tonga_SCLK_Dependency_Table *sclk_dep_table;
const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table;
const ATOM_Tonga_MM_Dependency_Table *mm_dep_table;
int ret;
if (!pptable)
return -EINVAL;
ret = get_tonga_vce_state_table(hwmgr, pptable, &vce_state_table);
if (ret)
return ret;
ret = get_tonga_sclk_dependency_table(hwmgr, pptable,
&sclk_dep_table_header);
if (ret)
return ret;
sclk_dep_table = (const ATOM_Tonga_SCLK_Dependency_Table *)
sclk_dep_table_header;
ret = get_tonga_mclk_dependency_table(hwmgr, pptable, &mclk_dep_table);
if (ret)
return ret;
ret = get_tonga_mm_dependency_table(hwmgr, pptable, &mm_dep_table);
if (ret)
return ret;
PP_ASSERT_WITH_CODE((i < vce_state_table->ucNumEntries),
"Requested state entry ID is out of range!",
@ -1387,10 +1803,27 @@ static int ppt_get_vce_state_table_entry_v1_0(struct pp_hwmgr *hwmgr, uint32_t i
vce_state_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
ATOM_Tonga_VCE_State_Record,
entries, vce_state_table, i);
sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
ATOM_Tonga_SCLK_Dependency_Record,
entries, sclk_dep_table,
vce_state_record->ucSCLKIndex);
PP_ASSERT_WITH_CODE((vce_state_record->ucSCLKIndex <
sclk_dep_table->ucNumEntries),
"Invalid PowerPlay Table!", return -EINVAL);
PP_ASSERT_WITH_CODE((vce_state_record->ucVCEClockIndex <
mm_dep_table->ucNumEntries),
"Invalid PowerPlay Table!", return -EINVAL);
PP_ASSERT_WITH_CODE((mclk_dep_table->ucNumEntries != 0),
"Invalid PowerPlay Table!", return -EINVAL);
if (sclk_dep_table_header->ucRevId < 1)
sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
ATOM_Tonga_SCLK_Dependency_Record,
entries, sclk_dep_table,
vce_state_record->ucSCLKIndex);
else
polaris_sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
ATOM_Polaris_SCLK_Dependency_Record,
entries,
(ATOM_Polaris_SCLK_Dependency_Table *)
sclk_dep_table_header,
vce_state_record->ucSCLKIndex);
mm_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(
ATOM_Tonga_MM_Dependency_Record,
entries, mm_dep_table,
@ -1399,7 +1832,10 @@ static int ppt_get_vce_state_table_entry_v1_0(struct pp_hwmgr *hwmgr, uint32_t i
vce_state->evclk = le32_to_cpu(mm_dep_record->ulEClk);
vce_state->ecclk = le32_to_cpu(mm_dep_record->ulEClk);
vce_state->sclk = le32_to_cpu(sclk_dep_record->ulSclk);
if (sclk_dep_record)
vce_state->sclk = le32_to_cpu(sclk_dep_record->ulSclk);
else
vce_state->sclk = le32_to_cpu(polaris_sclk_dep_record->ulSclk);
if (vce_state_record->ucMCLKIndex >= mclk_dep_table->ucNumEntries)
mclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR(