AMD General -----Original Message----- From: amd-gfx <[email protected]> On Behalf Of Yang Wang Sent: Tuesday, June 23, 2026 3:53 PM To: [email protected] Cc: Deucher, Alexander <[email protected]>; Zhang, Hawking <[email protected]>; Feng, Kenneth <[email protected]> Subject: [PATCH 3/3] drm/amd/pm: Validate remaining legacy PPLIB table bounds
The legacy PPLIB parser still had paths that consumed VBIOS offsets, entry counts and clock-info indices before proving the referenced data fit within soft_pp_table_size. Malformed tables can trigger out-of-bounds reads while parsing clock-voltage, CAC, fan, PPM and phase-shedding data. Add shared bounds checks for the remaining fixed and variable-length legacy subtables. Also validate UVD/VCE clock-info indices before indexing their clock-info arrays. Signed-off-by: Yang Wang <[email protected]> --- .../amd/pm/powerplay/hwmgr/processpptables.c | 427 ++++++++++++++---- 1 file changed, 338 insertions(+), 89 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c index b2e1123844ec..678c31abe4c4 100644 --- a/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c +++ b/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c @@ -55,6 +55,159 @@ static bool pp_table_has_space(struct pp_hwmgr *hwmgr, size_t offset, return offset <= table_size && size <= table_size - offset; } +static int get_pplib_subtable(struct pp_hwmgr *hwmgr, + const ATOM_PPLIB_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((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_pplib_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((pp_table_has_space(hwmgr, table_offset, + table_size)), + "Invalid PowerPlay Table!", return -1); + + return 0; +} + +static int validate_pplib_optional_table_entries(struct pp_hwmgr *hwmgr, + u16 table_offset, size_t entries_offset, + u8 num_entries, size_t entry_size) { + size_t table_size; + + table_size = entries_offset + num_entries * entry_size; + PP_ASSERT_WITH_CODE((pp_table_has_space(hwmgr, table_offset, + table_size)), + "Invalid PowerPlay Table!", return -1); + + return 0; +} + +static int get_pplib_clock_voltage_dependency_table(struct pp_hwmgr *hwmgr, + const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table, + u16 table_offset, + const ATOM_PPLIB_Clock_Voltage_Dependency_Table **table) { + const ATOM_PPLIB_Clock_Voltage_Dependency_Table *dep_table; + int ret; + + ret = get_pplib_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*dep_table), (const void **)&dep_table); + if (ret) + return ret; + + ret = validate_pplib_table_entries(hwmgr, table_offset, + offsetof(ATOM_PPLIB_Clock_Voltage_Dependency_Table, + entries), + dep_table->ucNumEntries, + sizeof(ATOM_PPLIB_Clock_Voltage_Dependency_Record)); + if (ret) + return ret; + + *table = dep_table; + + return 0; +} + +static int get_pplib_clock_voltage_limit_table(struct pp_hwmgr *hwmgr, + const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table, + u16 table_offset, + const ATOM_PPLIB_Clock_Voltage_Limit_Table **table) { + const ATOM_PPLIB_Clock_Voltage_Limit_Table *limit_table; + int ret; + + ret = get_pplib_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*limit_table), + (const void **)&limit_table); + if (ret) + return ret; + + ret = validate_pplib_table_entries(hwmgr, table_offset, + offsetof(ATOM_PPLIB_Clock_Voltage_Limit_Table, + entries), + limit_table->ucNumEntries, + sizeof(ATOM_PPLIB_Clock_Voltage_Limit_Record)); + if (ret) + return ret; + + *table = limit_table; + + return 0; +} + +static int get_pplib_cac_leakage_table(struct pp_hwmgr *hwmgr, + const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table, + u16 table_offset, + const ATOM_PPLIB_CAC_Leakage_Table **table) { + const ATOM_PPLIB_CAC_Leakage_Table *leakage_table; + int ret; + + ret = get_pplib_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*leakage_table), + (const void **)&leakage_table); + if (ret) + return ret; + + ret = validate_pplib_optional_table_entries(hwmgr, table_offset, + offsetof(ATOM_PPLIB_CAC_Leakage_Table, + entries), + leakage_table->ucNumEntries, + sizeof(ATOM_PPLIB_CAC_Leakage_Record)); + if (ret) + return ret; + + *table = leakage_table; + + return 0; +} + +static int get_pplib_phase_shedding_table(struct pp_hwmgr *hwmgr, + const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table, + u16 table_offset, + const ATOM_PPLIB_PhaseSheddingLimits_Table **table) { + const ATOM_PPLIB_PhaseSheddingLimits_Table *phase_table; + int ret; + + ret = get_pplib_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*phase_table), (const void **)&phase_table); + if (ret) + return ret; + + ret = validate_pplib_optional_table_entries(hwmgr, table_offset, + offsetof(ATOM_PPLIB_PhaseSheddingLimits_Table, + entries), + phase_table->ucNumEntries, + sizeof(ATOM_PPLIB_PhaseSheddingLimits_Record)); + if (ret) + return ret; + + *table = phase_table; + + return 0; +} + static const ATOM_PPLIB_EXTENDEDHEADER * get_extended_header(struct pp_hwmgr *hwmgr, const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table, @@ -1143,14 +1296,36 @@ static int init_thermal_controller( if (powerplay_table->usTableSize >= sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) { const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 = (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table; + u16 fan_table_offset; if (0 == le16_to_cpu(powerplay_table3->usFanTableOffset)) { hwmgr->thermal_controller.use_hw_fan_control = 1; return 0; } else { - const ATOM_PPLIB_FANTABLE *fan_table = - (const ATOM_PPLIB_FANTABLE *)(((unsigned long)powerplay_table) + - le16_to_cpu(powerplay_table3->usFanTableOffset)); + const ATOM_PPLIB_FANTABLE *fan_table; + size_t fan_table_size; + + fan_table_offset = le16_to_cpu(powerplay_table3->usFanTableOffset); + if (!pp_table_has_space(hwmgr, fan_table_offset, + sizeof(*fan_table))) + return -EINVAL; + + fan_table = (const ATOM_PPLIB_FANTABLE *) + (((unsigned long)powerplay_table) + fan_table_offset); + if (fan_table->ucFanTableFormat >= 7) + fan_table_size = sizeof(ATOM_PPLIB_FANTABLE5); + else if (fan_table->ucFanTableFormat >= 6) + fan_table_size = sizeof(ATOM_PPLIB_FANTABLE4); + else if (fan_table->ucFanTableFormat >= 3) + fan_table_size = sizeof(ATOM_PPLIB_FANTABLE3); + else if (fan_table->ucFanTableFormat >= 2) + fan_table_size = sizeof(ATOM_PPLIB_FANTABLE2); + else + fan_table_size = sizeof(ATOM_PPLIB_FANTABLE); + + if (!pp_table_has_space(hwmgr, fan_table_offset, + fan_table_size)) + return -EINVAL; if (1 <= fan_table->ucFanTableFormat) { hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst = @@ -1176,16 +1351,14 @@ static int init_thermal_controller( if (2 <= fan_table->ucFanTableFormat) { const ATOM_PPLIB_FANTABLE2 *fan_table2 = - (const ATOM_PPLIB_FANTABLE2 *)(((unsigned long)powerplay_table) + - le16_to_cpu(powerplay_table3->usFanTableOffset)); + (const ATOM_PPLIB_FANTABLE2 *)fan_table; hwmgr->thermal_controller.advanceFanControlParameters.usTMax = le16_to_cpu(fan_table2->usTMax); } if (3 <= fan_table->ucFanTableFormat) { const ATOM_PPLIB_FANTABLE3 *fan_table3 = - (const ATOM_PPLIB_FANTABLE3 *) (((unsigned long)powerplay_table) + - le16_to_cpu(powerplay_table3->usFanTableOffset)); + (const ATOM_PPLIB_FANTABLE3 *)fan_table; hwmgr->thermal_controller.advanceFanControlParameters.ucFanControlMode = fan_table3->ucFanControlMode; @@ -1206,8 +1379,7 @@ static int init_thermal_controller( if (6 <= fan_table->ucFanTableFormat) { const ATOM_PPLIB_FANTABLE4 *fan_table4 = - (const ATOM_PPLIB_FANTABLE4 *)(((unsigned long)powerplay_table) + - le16_to_cpu(powerplay_table3->usFanTableOffset)); + (const ATOM_PPLIB_FANTABLE4 *)fan_table; phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_FanSpeedInTableIsRPM); @@ -1218,8 +1390,7 @@ static int init_thermal_controller( if (7 <= fan_table->ucFanTableFormat) { const ATOM_PPLIB_FANTABLE5 *fan_table5 = - (const ATOM_PPLIB_FANTABLE5 *)(((unsigned long)powerplay_table) + - le16_to_cpu(powerplay_table3->usFanTableOffset)); + (const ATOM_PPLIB_FANTABLE5 *)fan_table; if (0x67A2 == adev->pdev->device || 0x67A9 == adev->pdev->device || @@ -1351,8 +1522,14 @@ static int get_uvd_clock_voltage_limit_table(struct pp_hwmgr *hwmgr, uvd_table->count = table->numEntries; for (i = 0; i < table->numEntries; i++) { - const UVDClockInfo *entry = - &array->entries[table->entries[i].ucUVDClockInfoIndex]; + const UVDClockInfo *entry; + + if (table->entries[i].ucUVDClockInfoIndex >= array->ucNumEntries) { + kfree(uvd_table); + return -EINVAL; + } + + entry = &array->entries[table->entries[i].ucUVDClockInfoIndex]; uvd_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage); uvd_table->entries[i].vclk = ((unsigned long)entry->ucVClkHigh << 16) | le16_to_cpu(entry->usVClkLow); @@ -1380,7 +1557,14 @@ static int get_vce_clock_voltage_limit_table(struct pp_hwmgr *hwmgr, vce_table->count = table->numEntries; for (i = 0; i < table->numEntries; i++) { - const VCEClockInfo *entry = &array->entries[table->entries[i].ucVCEClockInfoIndex]; + const VCEClockInfo *entry; + + if (table->entries[i].ucVCEClockInfoIndex >= array->ucNumEntries) { + kfree(vce_table); + return -EINVAL; + } + + entry = &array->entries[table->entries[i].ucVCEClockInfoIndex]; vce_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage); vce_table->entries[i].evclk = ((unsigned long)entry->ucEVClkHigh << 16) @@ -1474,12 +1658,20 @@ static int init_clock_voltage_dependency(struct pp_hwmgr *hwmgr, const VCEClockInfoArray *array = (const VCEClockInfoArray *) (((unsigned long) powerplay_table) + vce_clock_info_array_offset); - const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *table = - (const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *) - (((unsigned long) powerplay_table) + table_offset); - result = get_vce_clock_voltage_limit_table(hwmgr, - &hwmgr->dyn_state.vce_clock_voltage_dependency_table, - table, array); + const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *table; + + result = get_pplib_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*table), (const void **)&table); + if (!result) + result = validate_pplib_optional_table_entries(hwmgr, table_offset, + offsetof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table, + entries), + table->numEntries, + sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record)); + if (!result) + result = get_vce_clock_voltage_limit_table(hwmgr, + &hwmgr->dyn_state.vce_clock_voltage_dependency_table, + table, array); } uvd_clock_info_array_offset = get_uvd_clock_info_array_offset(hwmgr, powerplay_table); @@ -1489,40 +1681,78 @@ static int init_clock_voltage_dependency(struct pp_hwmgr *hwmgr, const UVDClockInfoArray *array = (const UVDClockInfoArray *) (((unsigned long) powerplay_table) + uvd_clock_info_array_offset); - const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *ptable = - (const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *) - (((unsigned long) powerplay_table) + table_offset); - result = get_uvd_clock_voltage_limit_table(hwmgr, - &hwmgr->dyn_state.uvd_clock_voltage_dependency_table, ptable, array); + const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *ptable; + + result = get_pplib_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*ptable), (const void **)&ptable); + if (!result) + result = validate_pplib_optional_table_entries(hwmgr, table_offset, + offsetof(ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table, + entries), + ptable->numEntries, + sizeof(ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record)); + if (!result) + result = get_uvd_clock_voltage_limit_table(hwmgr, + &hwmgr->dyn_state.uvd_clock_voltage_dependency_table, + ptable, array); } table_offset = get_samu_clock_voltage_limit_table_offset(hwmgr, powerplay_table); if (table_offset > 0) { - const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *ptable = - (const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *) - (((unsigned long) powerplay_table) + table_offset); - result = get_samu_clock_voltage_limit_table(hwmgr, - &hwmgr->dyn_state.samu_clock_voltage_dependency_table, ptable); + const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *ptable; + + result = get_pplib_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*ptable), (const void **)&ptable); + if (!result) + result = validate_pplib_optional_table_entries(hwmgr, table_offset, + offsetof(ATOM_PPLIB_SAMClk_Voltage_Limit_Table, + entries), + ptable->numEntries, + sizeof(ATOM_PPLIB_SAMClk_Voltage_Limit_Record)); + if (!result) + result = get_samu_clock_voltage_limit_table(hwmgr, + &hwmgr->dyn_state.samu_clock_voltage_dependency_table, + ptable); } table_offset = get_acp_clock_voltage_limit_table_offset(hwmgr, powerplay_table); if (table_offset > 0) { - const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *ptable = - (const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *) - (((unsigned long) powerplay_table) + table_offset); - result = get_acp_clock_voltage_limit_table(hwmgr, - &hwmgr->dyn_state.acp_clock_voltage_dependency_table, ptable); + const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *ptable; + + result = get_pplib_subtable(hwmgr, powerplay_table, table_offset, + sizeof(*ptable), (const void **)&ptable); + if (!result) + result = validate_pplib_optional_table_entries(hwmgr, table_offset, + offsetof(ATOM_PPLIB_ACPClk_Voltage_Limit_Table, + entries), + ptable->numEntries, + sizeof(ATOM_PPLIB_ACPClk_Voltage_Limit_Record)); + if (!result) + result = get_acp_clock_voltage_limit_table(hwmgr, + &hwmgr->dyn_state.acp_clock_voltage_dependency_table, + ptable); } table_offset = get_cacp_tdp_table_offset(hwmgr, powerplay_table); if (table_offset > 0) { - UCHAR rev_id = *(UCHAR *)(((unsigned long)powerplay_table) + table_offset); + const void *tune_table; + UCHAR rev_id; - if (rev_id > 0) { + if (!pp_table_has_space(hwmgr, table_offset, sizeof(rev_id))) + return -EINVAL; + + rev_id = *(UCHAR *)(((unsigned long)powerplay_table) + table_offset); + result = get_pplib_subtable(hwmgr, powerplay_table, table_offset, + (rev_id > 0) ? + sizeof(ATOM_PPLIB_POWERTUNE_Table_V1) : + sizeof(ATOM_PPLIB_POWERTUNE_Table), + (const void **)&tune_table); AK: A non zero result will cause SCLK/MCLK/VDDCI/MVDD table to skip. Is it Ok? Was it same in earlier code? + + if (!result && rev_id > 0) { const ATOM_PPLIB_POWERTUNE_Table_V1 *tune_table = (const ATOM_PPLIB_POWERTUNE_Table_V1 *) (((unsigned long) powerplay_table) + table_offset); @@ -1531,7 +1761,7 @@ static int init_clock_voltage_dependency(struct pp_hwmgr *hwmgr, le16_to_cpu(tune_table->usMaximumPowerDeliveryLimit)); hwmgr->dyn_state.cac_dtp_table->usDefaultTargetOperatingTemp = le16_to_cpu(tune_table->usTjMax); - } else { + } else if (!result) { const ATOM_PPLIB_POWERTUNE_Table *tune_table = (const ATOM_PPLIB_POWERTUNE_Table *) (((unsigned long) powerplay_table) + table_offset); @@ -1546,35 +1776,44 @@ static int init_clock_voltage_dependency(struct pp_hwmgr *hwmgr, const ATOM_PPLIB_POWERPLAYTABLE4 *powerplay_table4 = (const ATOM_PPLIB_POWERPLAYTABLE4 *)powerplay_table; if (0 != powerplay_table4->usVddcDependencyOnSCLKOffset) { - table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) - (((unsigned long) powerplay_table4) + - le16_to_cpu(powerplay_table4->usVddcDependencyOnSCLKOffset)); - result = get_clock_voltage_dependency_table(hwmgr, - &hwmgr->dyn_state.vddc_dependency_on_sclk, table); + result = get_pplib_clock_voltage_dependency_table(hwmgr, + powerplay_table, + le16_to_cpu(powerplay_table4->usVddcDependencyOnSCLKOffset), + (const ATOM_PPLIB_Clock_Voltage_Dependency_Table **)&table); + if (!result) + result = get_clock_voltage_dependency_table(hwmgr, + &hwmgr->dyn_state.vddc_dependency_on_sclk, table); } if (result == 0 && (0 != powerplay_table4->usVddciDependencyOnMCLKOffset)) { - table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) - (((unsigned long) powerplay_table4) + - le16_to_cpu(powerplay_table4->usVddciDependencyOnMCLKOffset)); - result = get_clock_voltage_dependency_table(hwmgr, - &hwmgr->dyn_state.vddci_dependency_on_mclk, table); + result = get_pplib_clock_voltage_dependency_table(hwmgr, + powerplay_table, + le16_to_cpu(powerplay_table4->usVddciDependencyOnMCLKOffset), + (const ATOM_PPLIB_Clock_Voltage_Dependency_Table **)&table); + if (!result) + result = get_clock_voltage_dependency_table(hwmgr, + &hwmgr->dyn_state.vddci_dependency_on_mclk, table); } if (result == 0 && (0 != powerplay_table4->usVddcDependencyOnMCLKOffset)) { - table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) - (((unsigned long) powerplay_table4) + - le16_to_cpu(powerplay_table4->usVddcDependencyOnMCLKOffset)); - result = get_clock_voltage_dependency_table(hwmgr, - &hwmgr->dyn_state.vddc_dependency_on_mclk, table); + result = get_pplib_clock_voltage_dependency_table(hwmgr, + powerplay_table, + le16_to_cpu(powerplay_table4->usVddcDependencyOnMCLKOffset), + (const ATOM_PPLIB_Clock_Voltage_Dependency_Table **)&table); + if (!result) + result = get_clock_voltage_dependency_table(hwmgr, + &hwmgr->dyn_state.vddc_dependency_on_mclk, table); } if (result == 0 && (0 != powerplay_table4->usMaxClockVoltageOnDCOffset)) { - limit_table = (ATOM_PPLIB_Clock_Voltage_Limit_Table *) - (((unsigned long) powerplay_table4) + - le16_to_cpu(powerplay_table4->usMaxClockVoltageOnDCOffset)); - result = get_clock_voltage_limit(hwmgr, - &hwmgr->dyn_state.max_clock_voltage_on_dc, limit_table); + result = get_pplib_clock_voltage_limit_table(hwmgr, + powerplay_table, + le16_to_cpu(powerplay_table4->usMaxClockVoltageOnDCOffset), + (const ATOM_PPLIB_Clock_Voltage_Limit_Table **)&limit_table); + if (!result) + result = get_clock_voltage_limit(hwmgr, + &hwmgr->dyn_state.max_clock_voltage_on_dc, + limit_table); } if (result == 0 && (NULL != hwmgr->dyn_state.vddc_dependency_on_mclk) && @@ -1589,11 +1828,14 @@ static int init_clock_voltage_dependency(struct pp_hwmgr *hwmgr, hwmgr->dyn_state.vddc_dependency_on_sclk); if (result == 0 && (0 != powerplay_table4->usMvddDependencyOnMCLKOffset)) { - table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) - (((unsigned long) powerplay_table4) + - le16_to_cpu(powerplay_table4->usMvddDependencyOnMCLKOffset)); - result = get_clock_voltage_dependency_table(hwmgr, - &hwmgr->dyn_state.mvdd_dependency_on_mclk, table); + result = get_pplib_clock_voltage_dependency_table(hwmgr, + powerplay_table, + le16_to_cpu(powerplay_table4->usMvddDependencyOnMCLKOffset), + (const ATOM_PPLIB_Clock_Voltage_Dependency_Table **)&table); + if (!result) + result = get_clock_voltage_dependency_table(hwmgr, + &hwmgr->dyn_state.mvdd_dependency_on_mclk, + table); } } @@ -1601,10 +1843,13 @@ static int init_clock_voltage_dependency(struct pp_hwmgr *hwmgr, powerplay_table); if (table_offset > 0) { - table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) - (((unsigned long) powerplay_table) + table_offset); - result = get_clock_voltage_dependency_table(hwmgr, - &hwmgr->dyn_state.vdd_gfx_dependency_on_sclk, table); + result = get_pplib_clock_voltage_dependency_table(hwmgr, + powerplay_table, table_offset, + (const ATOM_PPLIB_Clock_Voltage_Dependency_Table **)&table); + if (!result) + result = get_clock_voltage_dependency_table(hwmgr, + &hwmgr->dyn_state.vdd_gfx_dependency_on_sclk, + table); } return result; @@ -1676,12 +1921,6 @@ static int init_dpm2_parameters(struct pp_hwmgr *hwmgr, sizeof(ATOM_PPLIB_POWERPLAYTABLE5)) { const ATOM_PPLIB_POWERPLAYTABLE5 *ptable5 = (const ATOM_PPLIB_POWERPLAYTABLE5 *)powerplay_table; - const ATOM_PPLIB_POWERPLAYTABLE4 *ptable4 = - (const ATOM_PPLIB_POWERPLAYTABLE4 *) - (&ptable5->basicTable4); - const ATOM_PPLIB_POWERPLAYTABLE3 *ptable3 = - (const ATOM_PPLIB_POWERPLAYTABLE3 *) - (&ptable4->basicTable3); const ATOM_PPLIB_EXTENDEDHEADER *extended_header; uint16_t table_offset; ATOM_PPLIB_PPM_Table *atom_ppm_table; @@ -1711,28 +1950,34 @@ static int init_dpm2_parameters(struct pp_hwmgr *hwmgr, hwmgr->dyn_state.cac_leakage_table = NULL; if (0 != ptable5->usCACLeakageTableOffset) { - const ATOM_PPLIB_CAC_Leakage_Table *pCAC_leakage_table = - (ATOM_PPLIB_CAC_Leakage_Table *)(((unsigned long)ptable5) + - le16_to_cpu(ptable5->usCACLeakageTableOffset)); - result = get_cac_leakage_table(hwmgr, - &hwmgr->dyn_state.cac_leakage_table, pCAC_leakage_table); + const ATOM_PPLIB_CAC_Leakage_Table *pCAC_leakage_table; + + result = get_pplib_cac_leakage_table(hwmgr, powerplay_table, + le16_to_cpu(ptable5->usCACLeakageTableOffset), + &pCAC_leakage_table); + if (!result) + result = get_cac_leakage_table(hwmgr, + &hwmgr->dyn_state.cac_leakage_table, + pCAC_leakage_table); } hwmgr->platform_descriptor.LoadLineSlope = le16_to_cpu(ptable5->usLoadLineSlope); hwmgr->dyn_state.ppm_parameter_table = NULL; - if (0 != ptable3->usExtendendedHeaderOffset) { - extended_header = (const ATOM_PPLIB_EXTENDEDHEADER *) - (((unsigned long)powerplay_table) + - le16_to_cpu(ptable3->usExtendendedHeaderOffset)); + extended_header = get_extended_header(hwmgr, powerplay_table, + SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5); + if (extended_header) { if ((extended_header->usPPMTableOffset > 0) && le16_to_cpu(extended_header->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5) { table_offset = le16_to_cpu(extended_header->usPPMTableOffset); - atom_ppm_table = (ATOM_PPLIB_PPM_Table *) - (((unsigned long)powerplay_table) + table_offset); - if (0 == get_platform_power_management_table(hwmgr, atom_ppm_table)) + result = get_pplib_subtable(hwmgr, powerplay_table, + table_offset, sizeof(*atom_ppm_table), + (const void **)&atom_ppm_table); AK: Same as patch 2 may be causing regression, previous failure was silent and does not affected result Thanks & Regards Asad + if (!result && + !get_platform_power_management_table(hwmgr, + atom_ppm_table)) phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_EnablePlatformPowerManagement); } @@ -1750,13 +1995,17 @@ static int init_phase_shedding_table(struct pp_hwmgr *hwmgr, (const ATOM_PPLIB_POWERPLAYTABLE4 *)powerplay_table; if (0 != powerplay_table4->usVddcPhaseShedLimitsTableOffset) { - const ATOM_PPLIB_PhaseSheddingLimits_Table *ptable = - (ATOM_PPLIB_PhaseSheddingLimits_Table *) - (((unsigned long)powerplay_table4) + - le16_to_cpu(powerplay_table4->usVddcPhaseShedLimitsTableOffset)); + const ATOM_PPLIB_PhaseSheddingLimits_Table *ptable; struct phm_phase_shedding_limits_table *table; unsigned long i; + int result; + result = get_pplib_phase_shedding_table(hwmgr, + powerplay_table, + le16_to_cpu(powerplay_table4->usVddcPhaseShedLimitsTableOffset), + &ptable); + if (result) + return result; table = kzalloc(struct_size(table, entries, ptable->ucNumEntries), GFP_KERNEL); -- 2.47.3
