root/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. psm_init_power_state_table
  2. psm_fini_power_state_table
  3. psm_get_ui_state
  4. psm_get_state_by_classification
  5. psm_set_states
  6. psm_set_boot_states
  7. psm_set_performance_states
  8. psm_set_user_performance_state
  9. power_state_management
  10. psm_adjust_power_state_dynamic

   1 /*
   2  * Copyright 2017 Advanced Micro Devices, Inc.
   3  *
   4  * Permission is hereby granted, free of charge, to any person obtaining a
   5  * copy of this software and associated documentation files (the "Software"),
   6  * to deal in the Software without restriction, including without limitation
   7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8  * and/or sell copies of the Software, and to permit persons to whom the
   9  * Software is furnished to do so, subject to the following conditions:
  10  *
  11  * The above copyright notice and this permission notice shall be included in
  12  * all copies or substantial portions of the Software.
  13  *
  14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20  * OTHER DEALINGS IN THE SOFTWARE.
  21  *
  22  */
  23 
  24 #include <linux/types.h>
  25 #include <linux/kernel.h>
  26 #include <linux/slab.h>
  27 #include "pp_psm.h"
  28 
  29 int psm_init_power_state_table(struct pp_hwmgr *hwmgr)
  30 {
  31         int result;
  32         unsigned int i;
  33         unsigned int table_entries;
  34         struct pp_power_state *state;
  35         int size;
  36 
  37         if (hwmgr->hwmgr_func->get_num_of_pp_table_entries == NULL)
  38                 return 0;
  39 
  40         if (hwmgr->hwmgr_func->get_power_state_size == NULL)
  41                 return 0;
  42 
  43         hwmgr->num_ps = table_entries = hwmgr->hwmgr_func->get_num_of_pp_table_entries(hwmgr);
  44 
  45         hwmgr->ps_size = size = hwmgr->hwmgr_func->get_power_state_size(hwmgr) +
  46                                           sizeof(struct pp_power_state);
  47 
  48         if (table_entries == 0 || size == 0) {
  49                 pr_warn("Please check whether power state management is supported on this asic\n");
  50                 return 0;
  51         }
  52 
  53         hwmgr->ps = kcalloc(table_entries, size, GFP_KERNEL);
  54         if (hwmgr->ps == NULL)
  55                 return -ENOMEM;
  56 
  57         hwmgr->request_ps = kzalloc(size, GFP_KERNEL);
  58         if (hwmgr->request_ps == NULL) {
  59                 kfree(hwmgr->ps);
  60                 hwmgr->ps = NULL;
  61                 return -ENOMEM;
  62         }
  63 
  64         hwmgr->current_ps = kzalloc(size, GFP_KERNEL);
  65         if (hwmgr->current_ps == NULL) {
  66                 kfree(hwmgr->request_ps);
  67                 kfree(hwmgr->ps);
  68                 hwmgr->request_ps = NULL;
  69                 hwmgr->ps = NULL;
  70                 return -ENOMEM;
  71         }
  72 
  73         state = hwmgr->ps;
  74 
  75         for (i = 0; i < table_entries; i++) {
  76                 result = hwmgr->hwmgr_func->get_pp_table_entry(hwmgr, i, state);
  77 
  78                 if (state->classification.flags & PP_StateClassificationFlag_Boot) {
  79                         hwmgr->boot_ps = state;
  80                         memcpy(hwmgr->current_ps, state, size);
  81                         memcpy(hwmgr->request_ps, state, size);
  82                 }
  83 
  84                 state->id = i + 1; /* assigned unique num for every power state id */
  85 
  86                 if (state->classification.flags & PP_StateClassificationFlag_Uvd)
  87                         hwmgr->uvd_ps = state;
  88                 state = (struct pp_power_state *)((unsigned long)state + size);
  89         }
  90 
  91         return 0;
  92 }
  93 
  94 int psm_fini_power_state_table(struct pp_hwmgr *hwmgr)
  95 {
  96         if (hwmgr == NULL)
  97                 return -EINVAL;
  98 
  99         if (!hwmgr->ps)
 100                 return 0;
 101 
 102         kfree(hwmgr->current_ps);
 103         kfree(hwmgr->request_ps);
 104         kfree(hwmgr->ps);
 105         hwmgr->request_ps = NULL;
 106         hwmgr->ps = NULL;
 107         hwmgr->current_ps = NULL;
 108         return 0;
 109 }
 110 
 111 static int psm_get_ui_state(struct pp_hwmgr *hwmgr,
 112                                 enum PP_StateUILabel ui_label,
 113                                 unsigned long *state_id)
 114 {
 115         struct pp_power_state *state;
 116         int table_entries;
 117         int i;
 118 
 119         table_entries = hwmgr->num_ps;
 120         state = hwmgr->ps;
 121 
 122         for (i = 0; i < table_entries; i++) {
 123                 if (state->classification.ui_label & ui_label) {
 124                         *state_id = state->id;
 125                         return 0;
 126                 }
 127                 state = (struct pp_power_state *)((unsigned long)state + hwmgr->ps_size);
 128         }
 129         return -EINVAL;
 130 }
 131 
 132 static int psm_get_state_by_classification(struct pp_hwmgr *hwmgr,
 133                                         enum PP_StateClassificationFlag flag,
 134                                         unsigned long *state_id)
 135 {
 136         struct pp_power_state *state;
 137         int table_entries;
 138         int i;
 139 
 140         table_entries = hwmgr->num_ps;
 141         state = hwmgr->ps;
 142 
 143         for (i = 0; i < table_entries; i++) {
 144                 if (state->classification.flags & flag) {
 145                         *state_id = state->id;
 146                         return 0;
 147                 }
 148                 state = (struct pp_power_state *)((unsigned long)state + hwmgr->ps_size);
 149         }
 150         return -EINVAL;
 151 }
 152 
 153 static int psm_set_states(struct pp_hwmgr *hwmgr, unsigned long state_id)
 154 {
 155         struct pp_power_state *state;
 156         int table_entries;
 157         int i;
 158 
 159         table_entries = hwmgr->num_ps;
 160 
 161         state = hwmgr->ps;
 162 
 163         for (i = 0; i < table_entries; i++) {
 164                 if (state->id == state_id) {
 165                         memcpy(hwmgr->request_ps, state, hwmgr->ps_size);
 166                         return 0;
 167                 }
 168                 state = (struct pp_power_state *)((unsigned long)state + hwmgr->ps_size);
 169         }
 170         return -EINVAL;
 171 }
 172 
 173 int psm_set_boot_states(struct pp_hwmgr *hwmgr)
 174 {
 175         unsigned long state_id;
 176         int ret = -EINVAL;
 177 
 178         if (!hwmgr->ps)
 179                 return 0;
 180 
 181         if (!psm_get_state_by_classification(hwmgr, PP_StateClassificationFlag_Boot,
 182                                         &state_id))
 183                 ret = psm_set_states(hwmgr, state_id);
 184 
 185         return ret;
 186 }
 187 
 188 int psm_set_performance_states(struct pp_hwmgr *hwmgr)
 189 {
 190         unsigned long state_id;
 191         int ret = -EINVAL;
 192 
 193         if (!hwmgr->ps)
 194                 return 0;
 195 
 196         if (!psm_get_ui_state(hwmgr, PP_StateUILabel_Performance,
 197                                         &state_id))
 198                 ret = psm_set_states(hwmgr, state_id);
 199 
 200         return ret;
 201 }
 202 
 203 int psm_set_user_performance_state(struct pp_hwmgr *hwmgr,
 204                                         enum PP_StateUILabel label_id,
 205                                         struct pp_power_state **state)
 206 {
 207         int table_entries;
 208         int i;
 209 
 210         if (!hwmgr->ps)
 211                 return 0;
 212 
 213         table_entries = hwmgr->num_ps;
 214         *state = hwmgr->ps;
 215 
 216 restart_search:
 217         for (i = 0; i < table_entries; i++) {
 218                 if ((*state)->classification.ui_label & label_id)
 219                         return 0;
 220                 *state = (struct pp_power_state *)((uintptr_t)*state + hwmgr->ps_size);
 221         }
 222 
 223         switch (label_id) {
 224         case PP_StateUILabel_Battery:
 225         case PP_StateUILabel_Balanced:
 226                 label_id = PP_StateUILabel_Performance;
 227                 goto restart_search;
 228         default:
 229                 break;
 230         }
 231         return -EINVAL;
 232 }
 233 
 234 static void power_state_management(struct pp_hwmgr *hwmgr,
 235                                                 struct pp_power_state *new_ps)
 236 {
 237         struct pp_power_state *pcurrent;
 238         struct pp_power_state *requested;
 239         bool equal;
 240 
 241         if (new_ps != NULL)
 242                 requested = new_ps;
 243         else
 244                 requested = hwmgr->request_ps;
 245 
 246         pcurrent = hwmgr->current_ps;
 247 
 248         phm_apply_state_adjust_rules(hwmgr, requested, pcurrent);
 249         if (pcurrent == NULL || (0 != phm_check_states_equal(hwmgr,
 250                         &pcurrent->hardware, &requested->hardware, &equal)))
 251                 equal = false;
 252 
 253         if (!equal || phm_check_smc_update_required_for_display_configuration(hwmgr)) {
 254                 phm_set_power_state(hwmgr, &pcurrent->hardware, &requested->hardware);
 255                 memcpy(hwmgr->current_ps, hwmgr->request_ps, hwmgr->ps_size);
 256         }
 257 }
 258 
 259 int psm_adjust_power_state_dynamic(struct pp_hwmgr *hwmgr, bool skip_display_settings,
 260                                                 struct pp_power_state *new_ps)
 261 {
 262         uint32_t index;
 263         long workload;
 264 
 265         if (!skip_display_settings)
 266                 phm_display_configuration_changed(hwmgr);
 267 
 268         if (hwmgr->ps)
 269                 power_state_management(hwmgr, new_ps);
 270         else
 271                 /*
 272                  * for vega12/vega20 which does not support power state manager
 273                  * DAL clock limits should also be honoured
 274                  */
 275                 phm_apply_clock_adjust_rules(hwmgr);
 276 
 277         if (!skip_display_settings)
 278                 phm_notify_smc_display_config_after_ps_adjustment(hwmgr);
 279 
 280         if (!phm_force_dpm_levels(hwmgr, hwmgr->request_dpm_level))
 281                 hwmgr->dpm_level = hwmgr->request_dpm_level;
 282 
 283         if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) {
 284                 index = fls(hwmgr->workload_mask);
 285                 index = index > 0 && index <= Workload_Policy_Max ? index - 1 : 0;
 286                 workload = hwmgr->workload_setting[index];
 287 
 288                 if (hwmgr->power_profile_mode != workload && hwmgr->hwmgr_func->set_power_profile_mode)
 289                         hwmgr->hwmgr_func->set_power_profile_mode(hwmgr, &workload, 0);
 290         }
 291 
 292         return 0;
 293 }
 294 

/* [<][>][^][v][top][bottom][index][help] */