On Thu, Feb 8, 2018 at 6:18 AM, Rex Zhu <Rex.Zhu at amd.com> wrote: > v2: refine work queue name. > > Change-Id: I2521d83cbea9b3418bed63de86cf93deafaab3fb > Signed-off-by: Rex Zhu <Rex.Zhu at amd.com> Please provide a patch description. With that fixed: Reviewed-by: Alex Deucher <alexander.deucher at amd.com> > --- > drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c | 35 ++++ > drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c | 200 ++++++++++++++++++++++- > drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.h | 26 +++ > drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | 2 + > 4 files changed, 262 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c > index 33eabc1..b7f4a31 100644 > --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c > +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c > @@ -236,6 +236,20 @@ int hwmgr_early_init(struct pp_instance *handle) > return 0; > } > > +static void wattman_sample_handler(struct work_struct *work) > +{ > + struct pp_hwmgr *hwmgr = > + container_of(work, struct pp_hwmgr, wattman_update_work.work); > + > + if (hwmgr->autowattman_enabled) { > + if (hwmgr->hwmgr_func->update_auto_wattman != NULL) > + hwmgr->hwmgr_func->update_auto_wattman(hwmgr); > + > + if (hwmgr->hwmgr_func->start_auto_wattman != NULL) > + hwmgr->hwmgr_func->start_auto_wattman(hwmgr, true); > + } > +} > + > int hwmgr_hw_init(struct pp_instance *handle) > { > struct pp_hwmgr *hwmgr; > @@ -246,6 +260,8 @@ int hwmgr_hw_init(struct pp_instance *handle) > > hwmgr = handle->hwmgr; > > + INIT_DELAYED_WORK(&hwmgr->wattman_update_work, wattman_sample_handler); > + > if (hwmgr->pptable_func == NULL || > hwmgr->pptable_func->pptable_init == NULL || > hwmgr->hwmgr_func->backend_init == NULL) > @@ -279,6 +295,11 @@ int hwmgr_hw_init(struct pp_instance *handle) > if (ret) > goto err2; > > + if (hwmgr->autowattman_enabled) { > + if (hwmgr->hwmgr_func->start_auto_wattman != NULL) > + hwmgr->hwmgr_func->start_auto_wattman(hwmgr, true); > + } > + > return 0; > err2: > if (hwmgr->hwmgr_func->backend_fini) > @@ -300,6 +321,10 @@ int hwmgr_hw_fini(struct pp_instance *handle) > > hwmgr = handle->hwmgr; > > + if (hwmgr->autowattman_enabled) { > + if (hwmgr->hwmgr_func->start_auto_wattman != NULL) > + hwmgr->hwmgr_func->start_auto_wattman(hwmgr, false); > + } > phm_stop_thermal_controller(hwmgr); > psm_set_boot_states(hwmgr); > psm_adjust_power_state_dynamic(hwmgr, false, NULL); > @@ -322,6 +347,11 @@ int hwmgr_hw_suspend(struct pp_instance *handle) > return -EINVAL; > > hwmgr = handle->hwmgr; > + > + if (hwmgr->autowattman_enabled) { > + if (hwmgr->hwmgr_func->start_auto_wattman != NULL) > + hwmgr->hwmgr_func->start_auto_wattman(hwmgr, false); > + } > phm_disable_smc_firmware_ctf(hwmgr); > ret = psm_set_boot_states(hwmgr); > if (ret) > @@ -360,6 +390,11 @@ int hwmgr_hw_resume(struct pp_instance *handle) > > ret = psm_adjust_power_state_dynamic(hwmgr, false, NULL); > > + if (hwmgr->autowattman_enabled) { > + if (hwmgr->hwmgr_func->start_auto_wattman != NULL) > + hwmgr->hwmgr_func->start_auto_wattman(hwmgr, true); > + } > + > return ret; > } > > diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c > index 08e9e44..b89b530 100644 > --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c > +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c > @@ -80,6 +80,7 @@ > > #define PCIE_BUS_CLK 10000 > #define TCLK (PCIE_BUS_CLK / 10) > +#define WATTMAM_SAMPLE_PERIOD msecs_to_jiffies(1000) > > static const struct profile_mode_setting smu7_profiling[5] = > {{1, 0, 100, 30, 1, 0, 100, 10}, > @@ -2540,9 +2541,10 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) > data->pcie_gen_cap = AMDGPU_DEFAULT_PCIE_GEN_MASK; > else > data->pcie_gen_cap = (uint32_t)sys_info.value; > + > if (data->pcie_gen_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) > data->pcie_spc_cap = 20; > - sys_info.size = sizeof(struct cgs_system_info); > + > sys_info.info_id = CGS_SYSTEM_INFO_PCIE_MLW; > result = cgs_query_system_info(hwmgr->device, &sys_info); > if (result) > @@ -2550,6 +2552,11 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr) > else > data->pcie_lane_cap = (uint32_t)sys_info.value; > > + sys_info.info_id = CGS_SYSTEM_INFO_VRAM_WIDTH; > + result = cgs_query_system_info(hwmgr->device, &sys_info); > + if (!result) > + data->memory_bit_width = (uint32_t)sys_info.value; > + > hwmgr->platform_descriptor.vbiosInterruptId = 0x20000400; /* IRQ_SOURCE1_SW_INT */ > /* The true clock step depends on the frequency, typically 4.5 or 9 MHz. Here we use 5. */ > hwmgr->platform_descriptor.clockStep.engineClock = 500; > @@ -5070,6 +5077,195 @@ static int smu7_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, uint > return 0; > } > > +static void smu7_start_auto_wattman(struct pp_hwmgr *hwmgr, bool en) > +{ > + if (en) { > + smum_send_msg_to_smc(hwmgr, PPSMC_MSG_PmStatusLogStart); > + schedule_delayed_work(&hwmgr->wattman_update_work, WATTMAM_SAMPLE_PERIOD); > + } else { > + cancel_delayed_work_sync(&hwmgr->wattman_update_work); > + } > +} > + > +static void smu7_auto_wattman_get_data(struct pp_hwmgr *hwmgr) > +{ > + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); > + > + data->wattman_data.average_sclk_busy = cgs_read_ind_register( > + hwmgr->device, > + CGS_IND_REG__SMC, > + ixSMU_PM_STATUS_91); > + data->wattman_data.average_sclk_busy >>= 8; > + > + data->wattman_data.average_mclk_busy = cgs_read_ind_register( > + hwmgr->device, > + CGS_IND_REG__SMC, > + ixSMU_PM_STATUS_92); > + > + data->wattman_data.average_mclk_busy >>= 8; > + > + data->wattman_data.effective_sclk = cgs_read_ind_register( > + hwmgr->device, > + CGS_IND_REG__SMC, > + ixSMU_PM_STATUS_77); > + > + data->wattman_data.effective_mclk = cgs_read_ind_register( > + hwmgr->device, > + CGS_IND_REG__SMC, > + ixSMU_PM_STATUS_111); > + > + pr_debug("effective sclk: %x average sclk busy: %x\n", > + data->wattman_data.effective_sclk, > + data->wattman_data.average_sclk_busy); > + pr_debug("effective mclk: %x average mclk busy: %x\n", > + data->wattman_data.effective_mclk, > + data->wattman_data.average_mclk_busy); > + > + return; > +} > + > +static int smu7_auto_wattman_update_clk_setting(struct pp_hwmgr *hwmgr, > + struct smu7_auto_wattman_adjust_settings *setting, > + uint32_t clk_busy, uint32_t threshold) > +{ > + uint32_t adjust_factor = 0; > + uint32_t divide_factor = 0; > + > + if (setting == NULL) > + return -EINVAL; > + > + if (clk_busy < threshold) { > + divide_factor = threshold / AutoWattmanAlgorithmMaxAdjustFactor; > + adjust_factor = AutoWattmanAlgorithmMaxAdjustFactor - (clk_busy / divide_factor); > + setting->uphyst_adjust = adjust_factor; > + setting->uphyst_polarity = 1; > + setting->downhyst_adjust = 6 * adjust_factor; > + setting->downhyst_polarity = 0; > + setting->activity_adjust = 2 * adjust_factor; > + setting->activity_polarity = 1; > + } else { > + divide_factor = (100 - threshold) / AutoWattmanAlgorithmMaxAdjustFactor; > + adjust_factor = (clk_busy - threshold + divide_factor - 1) / divide_factor; > + setting->uphyst_adjust = adjust_factor; > + setting->uphyst_polarity = 0; > + setting->downhyst_adjust = 6 * adjust_factor; > + setting->downhyst_polarity = 1; > + setting->activity_adjust = 2 * adjust_factor; > + setting->activity_polarity = 0; > + } > + > + return 0; > +} > + > +static void smu7_auto_wattman_algorithm(struct pp_hwmgr *hwmgr) > +{ > + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); > + uint32_t threshold = 0x32; > + > + smu7_auto_wattman_update_clk_setting(hwmgr, &data->sclk_settings, > + data->wattman_data.average_sclk_busy, threshold); > + > + if (data->memory_bit_width == 64) > + threshold = 0xA; > + else if (hwmgr->chip_id == CHIP_POLARIS12) > + threshold = 0xF; > + else > + threshold = 0x14; > + > + smu7_auto_wattman_update_clk_setting(hwmgr, &data->mclk_settings, > + data->wattman_data.average_mclk_busy, threshold); > +} > + > +static int smu7_auto_wattman_get_adjust_setting(uint32_t low_limit, uint32_t high_limit, > + uint32_t polarity, uint32_t adjust_value, > + uint32_t original_setting) > +{ > + if (!polarity) { > + if (original_setting < low_limit + adjust_value) > + original_setting = low_limit; > + else > + original_setting -= adjust_value; > + } else { > + if ((high_limit < adjust_value) || (high_limit - adjust_value < original_setting)) > + original_setting = high_limit; > + else > + original_setting += adjust_value; > + } > + > + return original_setting; > +} > + > +static int smu7_update_auto_wattman(struct pp_hwmgr *hwmgr) > +{ > + struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); > + struct profile_mode_setting tmp; > + uint32_t high_limit, low_limit; > + > + high_limit = AutoWattmanSCLKHighLimits; > + low_limit = AutoWattmanSCLKLowLimits; > + > + smu7_auto_wattman_get_data(hwmgr); > + smu7_auto_wattman_algorithm(hwmgr); > + > + tmp.sclk_up_hyst = smu7_auto_wattman_get_adjust_setting(low_limit & 0xff, > + high_limit & 0xff, > + data->sclk_settings.uphyst_polarity, > + data->sclk_settings.uphyst_adjust, > + data->current_profile_setting.sclk_up_hyst); > + > + tmp.sclk_down_hyst = smu7_auto_wattman_get_adjust_setting((low_limit >> 8) & 0xff, > + (high_limit >> 8) & 0xff, > + data->sclk_settings.downhyst_polarity, > + data->sclk_settings.downhyst_adjust, > + data->current_profile_setting.sclk_down_hyst); > + > + tmp.sclk_activity = smu7_auto_wattman_get_adjust_setting((low_limit >> 16) & 0xffff, > + (high_limit >> 16) & 0xffff, > + data->sclk_settings.activity_polarity, > + data->sclk_settings.activity_adjust, > + data->current_profile_setting.sclk_activity); > + > + if ((tmp.sclk_up_hyst == data->current_profile_setting.sclk_up_hyst) && > + (tmp.sclk_down_hyst == data->current_profile_setting.sclk_down_hyst) && > + (tmp.sclk_activity == data->current_profile_setting.sclk_activity)) > + tmp.bupdate_sclk = false; > + else > + tmp.bupdate_sclk = true; > + > + high_limit = AutoWattmanMCLKHighLimits; > + low_limit = AutoWattmanMCLKLowLimits; > + > + tmp.mclk_up_hyst = smu7_auto_wattman_get_adjust_setting(low_limit && 0xff, > + high_limit && 0xff, > + data->mclk_settings.uphyst_polarity, > + data->mclk_settings.uphyst_adjust, > + data->current_profile_setting.mclk_up_hyst); > + > + tmp.mclk_down_hyst = smu7_auto_wattman_get_adjust_setting((low_limit >> 8) && 0xff, > + (high_limit >> 8) && 0xff, > + data->mclk_settings.downhyst_polarity, > + data->mclk_settings.downhyst_adjust, > + data->current_profile_setting.mclk_down_hyst); > + > + tmp.mclk_activity = smu7_auto_wattman_get_adjust_setting((low_limit >> 16) && 0xffff, > + (high_limit >> 16) && 0xffff, > + data->mclk_settings.activity_polarity, > + data->mclk_settings.activity_adjust, > + data->current_profile_setting.mclk_activity); > + > + if ((tmp.mclk_up_hyst == data->current_profile_setting.mclk_up_hyst) && > + (tmp.mclk_down_hyst == data->current_profile_setting.mclk_down_hyst) && > + (tmp.mclk_activity == data->current_profile_setting.mclk_activity)) > + tmp.bupdate_mclk = false; > + else > + tmp.bupdate_mclk = true; > + > + if (!smum_update_dpm_settings(hwmgr, &tmp) && ((tmp.bupdate_mclk) || tmp.bupdate_mclk)) > + memcpy(&data->current_profile_setting, &tmp, sizeof(struct profile_mode_setting)); > + > + return 0; > +} > + > static const struct pp_hwmgr_func smu7_hwmgr_funcs = { > .backend_init = &smu7_hwmgr_backend_init, > .backend_fini = &smu7_hwmgr_backend_fini, > @@ -5127,6 +5323,8 @@ static int smu7_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, uint > .set_power_limit = smu7_set_power_limit, > .get_power_profile_mode = smu7_get_power_profile_mode, > .set_power_profile_mode = smu7_set_power_profile_mode, > + .update_auto_wattman = smu7_update_auto_wattman, > + .start_auto_wattman = smu7_start_auto_wattman, > }; > > uint8_t smu7_get_sleep_divider_id_from_clock(uint32_t clock, > diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.h > index 3bcfc61..9f61507 100644 > --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.h > +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.h > @@ -186,6 +186,21 @@ struct smu7_odn_dpm_table { > uint32_t odn_mclk_min_limit; > }; > > +#define AutoWattmanSCLKHighLimits 0x002D3C0A > +#define AutoWattmanSCLKLowLimits 0x00190000 > +#define AutoWattmanMCLKHighLimits 0x002D3C0A > +#define AutoWattmanMCLKLowLimits 0x000A1000 > +#define AutoWattmanAlgorithmMaxAdjustFactor 5 > + > +struct smu7_auto_wattman_adjust_settings { > + uint32_t uphyst_adjust; > + uint32_t uphyst_polarity; > + uint32_t downhyst_adjust; > + uint32_t downhyst_polarity; > + uint32_t activity_adjust; > + uint32_t activity_polarity; > +}; > + > struct profile_mode_setting { > uint8_t bupdate_sclk; > uint8_t sclk_up_hyst; > @@ -197,6 +212,13 @@ struct profile_mode_setting { > uint16_t mclk_activity; > }; > > +struct smu7_auto_wattman_data { > + uint32_t effective_sclk; > + uint32_t effective_mclk; > + uint32_t average_sclk_busy; > + uint32_t average_mclk_busy; > +}; > + > struct smu7_hwmgr { > struct smu7_dpm_table dpm_table; > struct smu7_dpm_table golden_dpm_table; > @@ -327,6 +349,10 @@ struct smu7_hwmgr { > uint32_t vr_config; > struct profile_mode_setting custom_profile_setting; > struct profile_mode_setting current_profile_setting; > + struct smu7_auto_wattman_data wattman_data; > + uint32_t memory_bit_width; > + struct smu7_auto_wattman_adjust_settings sclk_settings; > + struct smu7_auto_wattman_adjust_settings mclk_settings; > }; > > /* To convert to Q8.8 format for firmware */ > diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h > index d809d96..b68ab71 100644 > --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h > +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h > @@ -767,6 +767,8 @@ struct pp_hwmgr { > bool od_enabled; > uint32_t power_limit; > uint32_t default_power_limit; > + bool autowattman_enabled; > + struct delayed_work wattman_update_work; > }; > > struct cgs_irq_src_funcs { > -- > 1.9.1 > > _______________________________________________ > amd-gfx mailing list > amd-gfx at lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/amd-gfx