LCOV - code coverage report
Current view: top level - drivers/gpu/drm/amd/pm/powerplay/hwmgr - pp_psm.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 117 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 8 0.0 %

          Line data    Source code
       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           0 : 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           0 :         if (hwmgr->hwmgr_func->get_num_of_pp_table_entries == NULL)
      38             :                 return 0;
      39             : 
      40           0 :         if (hwmgr->hwmgr_func->get_power_state_size == NULL)
      41             :                 return 0;
      42             : 
      43           0 :         hwmgr->num_ps = table_entries = hwmgr->hwmgr_func->get_num_of_pp_table_entries(hwmgr);
      44             : 
      45           0 :         hwmgr->ps_size = size = hwmgr->hwmgr_func->get_power_state_size(hwmgr) +
      46             :                                           sizeof(struct pp_power_state);
      47             : 
      48           0 :         if (table_entries == 0 || size == 0) {
      49           0 :                 pr_warn("Please check whether power state management is supported on this asic\n");
      50           0 :                 return 0;
      51             :         }
      52             : 
      53           0 :         hwmgr->ps = kcalloc(table_entries, size, GFP_KERNEL);
      54           0 :         if (hwmgr->ps == NULL)
      55             :                 return -ENOMEM;
      56             : 
      57           0 :         hwmgr->request_ps = kzalloc(size, GFP_KERNEL);
      58           0 :         if (hwmgr->request_ps == NULL) {
      59           0 :                 kfree(hwmgr->ps);
      60           0 :                 hwmgr->ps = NULL;
      61           0 :                 return -ENOMEM;
      62             :         }
      63             : 
      64           0 :         hwmgr->current_ps = kzalloc(size, GFP_KERNEL);
      65           0 :         if (hwmgr->current_ps == NULL) {
      66           0 :                 kfree(hwmgr->request_ps);
      67           0 :                 kfree(hwmgr->ps);
      68           0 :                 hwmgr->request_ps = NULL;
      69           0 :                 hwmgr->ps = NULL;
      70           0 :                 return -ENOMEM;
      71             :         }
      72             : 
      73           0 :         state = hwmgr->ps;
      74             : 
      75           0 :         for (i = 0; i < table_entries; i++) {
      76           0 :                 result = hwmgr->hwmgr_func->get_pp_table_entry(hwmgr, i, state);
      77           0 :                 if (result) {
      78           0 :                         kfree(hwmgr->request_ps);
      79           0 :                         kfree(hwmgr->ps);
      80           0 :                         hwmgr->request_ps = NULL;
      81           0 :                         hwmgr->ps = NULL;
      82           0 :                         return -EINVAL;
      83             :                 }
      84             : 
      85           0 :                 if (state->classification.flags & PP_StateClassificationFlag_Boot) {
      86           0 :                         hwmgr->boot_ps = state;
      87           0 :                         memcpy(hwmgr->current_ps, state, size);
      88           0 :                         memcpy(hwmgr->request_ps, state, size);
      89             :                 }
      90             : 
      91           0 :                 state->id = i + 1; /* assigned unique num for every power state id */
      92             : 
      93           0 :                 if (state->classification.flags & PP_StateClassificationFlag_Uvd)
      94           0 :                         hwmgr->uvd_ps = state;
      95           0 :                 state = (struct pp_power_state *)((unsigned long)state + size);
      96             :         }
      97             : 
      98             :         return 0;
      99             : }
     100             : 
     101           0 : int psm_fini_power_state_table(struct pp_hwmgr *hwmgr)
     102             : {
     103           0 :         if (hwmgr == NULL)
     104             :                 return -EINVAL;
     105             : 
     106           0 :         if (!hwmgr->ps)
     107             :                 return 0;
     108             : 
     109           0 :         kfree(hwmgr->current_ps);
     110           0 :         kfree(hwmgr->request_ps);
     111           0 :         kfree(hwmgr->ps);
     112           0 :         hwmgr->request_ps = NULL;
     113           0 :         hwmgr->ps = NULL;
     114           0 :         hwmgr->current_ps = NULL;
     115           0 :         return 0;
     116             : }
     117             : 
     118             : static int psm_get_ui_state(struct pp_hwmgr *hwmgr,
     119             :                                 enum PP_StateUILabel ui_label,
     120             :                                 unsigned long *state_id)
     121             : {
     122             :         struct pp_power_state *state;
     123             :         int table_entries;
     124             :         int i;
     125             : 
     126           0 :         table_entries = hwmgr->num_ps;
     127           0 :         state = hwmgr->ps;
     128             : 
     129           0 :         for (i = 0; i < table_entries; i++) {
     130           0 :                 if (state->classification.ui_label & ui_label) {
     131           0 :                         *state_id = state->id;
     132             :                         return 0;
     133             :                 }
     134           0 :                 state = (struct pp_power_state *)((unsigned long)state + hwmgr->ps_size);
     135             :         }
     136             :         return -EINVAL;
     137             : }
     138             : 
     139             : static int psm_get_state_by_classification(struct pp_hwmgr *hwmgr,
     140             :                                         enum PP_StateClassificationFlag flag,
     141             :                                         unsigned long *state_id)
     142             : {
     143             :         struct pp_power_state *state;
     144             :         int table_entries;
     145             :         int i;
     146             : 
     147           0 :         table_entries = hwmgr->num_ps;
     148           0 :         state = hwmgr->ps;
     149             : 
     150           0 :         for (i = 0; i < table_entries; i++) {
     151           0 :                 if (state->classification.flags & flag) {
     152           0 :                         *state_id = state->id;
     153             :                         return 0;
     154             :                 }
     155           0 :                 state = (struct pp_power_state *)((unsigned long)state + hwmgr->ps_size);
     156             :         }
     157             :         return -EINVAL;
     158             : }
     159             : 
     160           0 : static int psm_set_states(struct pp_hwmgr *hwmgr, unsigned long state_id)
     161             : {
     162             :         struct pp_power_state *state;
     163             :         int table_entries;
     164             :         int i;
     165             : 
     166           0 :         table_entries = hwmgr->num_ps;
     167             : 
     168           0 :         state = hwmgr->ps;
     169             : 
     170           0 :         for (i = 0; i < table_entries; i++) {
     171           0 :                 if (state->id == state_id) {
     172           0 :                         memcpy(hwmgr->request_ps, state, hwmgr->ps_size);
     173           0 :                         return 0;
     174             :                 }
     175           0 :                 state = (struct pp_power_state *)((unsigned long)state + hwmgr->ps_size);
     176             :         }
     177             :         return -EINVAL;
     178             : }
     179             : 
     180           0 : int psm_set_boot_states(struct pp_hwmgr *hwmgr)
     181             : {
     182             :         unsigned long state_id;
     183           0 :         int ret = -EINVAL;
     184             : 
     185           0 :         if (!hwmgr->ps)
     186             :                 return 0;
     187             : 
     188           0 :         if (!psm_get_state_by_classification(hwmgr, PP_StateClassificationFlag_Boot,
     189             :                                         &state_id))
     190           0 :                 ret = psm_set_states(hwmgr, state_id);
     191             : 
     192             :         return ret;
     193             : }
     194             : 
     195           0 : int psm_set_performance_states(struct pp_hwmgr *hwmgr)
     196             : {
     197             :         unsigned long state_id;
     198           0 :         int ret = -EINVAL;
     199             : 
     200           0 :         if (!hwmgr->ps)
     201             :                 return 0;
     202             : 
     203           0 :         if (!psm_get_ui_state(hwmgr, PP_StateUILabel_Performance,
     204             :                                         &state_id))
     205           0 :                 ret = psm_set_states(hwmgr, state_id);
     206             : 
     207             :         return ret;
     208             : }
     209             : 
     210           0 : int psm_set_user_performance_state(struct pp_hwmgr *hwmgr,
     211             :                                         enum PP_StateUILabel label_id,
     212             :                                         struct pp_power_state **state)
     213             : {
     214             :         int table_entries;
     215             :         int i;
     216             : 
     217           0 :         if (!hwmgr->ps)
     218             :                 return 0;
     219             : 
     220           0 :         table_entries = hwmgr->num_ps;
     221           0 :         *state = hwmgr->ps;
     222             : 
     223             : restart_search:
     224           0 :         for (i = 0; i < table_entries; i++) {
     225           0 :                 if ((*state)->classification.ui_label & label_id)
     226             :                         return 0;
     227           0 :                 *state = (struct pp_power_state *)((uintptr_t)*state + hwmgr->ps_size);
     228             :         }
     229             : 
     230           0 :         switch (label_id) {
     231             :         case PP_StateUILabel_Battery:
     232             :         case PP_StateUILabel_Balanced:
     233             :                 label_id = PP_StateUILabel_Performance;
     234             :                 goto restart_search;
     235             :         default:
     236             :                 break;
     237             :         }
     238             :         return -EINVAL;
     239             : }
     240             : 
     241           0 : static void power_state_management(struct pp_hwmgr *hwmgr,
     242             :                                                 struct pp_power_state *new_ps)
     243             : {
     244             :         struct pp_power_state *pcurrent;
     245             :         struct pp_power_state *requested;
     246             :         bool equal;
     247             : 
     248           0 :         if (new_ps != NULL)
     249             :                 requested = new_ps;
     250             :         else
     251           0 :                 requested = hwmgr->request_ps;
     252             : 
     253           0 :         pcurrent = hwmgr->current_ps;
     254             : 
     255           0 :         phm_apply_state_adjust_rules(hwmgr, requested, pcurrent);
     256           0 :         if (pcurrent == NULL || (0 != phm_check_states_equal(hwmgr,
     257           0 :                         &pcurrent->hardware, &requested->hardware, &equal)))
     258           0 :                 equal = false;
     259             : 
     260           0 :         if (!equal || phm_check_smc_update_required_for_display_configuration(hwmgr)) {
     261           0 :                 phm_set_power_state(hwmgr, &pcurrent->hardware, &requested->hardware);
     262           0 :                 memcpy(hwmgr->current_ps, hwmgr->request_ps, hwmgr->ps_size);
     263             :         }
     264           0 : }
     265             : 
     266           0 : int psm_adjust_power_state_dynamic(struct pp_hwmgr *hwmgr, bool skip_display_settings,
     267             :                                                 struct pp_power_state *new_ps)
     268             : {
     269             :         uint32_t index;
     270             :         long workload;
     271             : 
     272           0 :         if (hwmgr->not_vf) {
     273           0 :                 if (!skip_display_settings)
     274           0 :                         phm_display_configuration_changed(hwmgr);
     275             : 
     276           0 :                 if (hwmgr->ps)
     277           0 :                         power_state_management(hwmgr, new_ps);
     278             :                 else
     279             :                         /*
     280             :                          * for vega12/vega20 which does not support power state manager
     281             :                          * DAL clock limits should also be honoured
     282             :                          */
     283           0 :                         phm_apply_clock_adjust_rules(hwmgr);
     284             : 
     285           0 :                 if (!skip_display_settings)
     286           0 :                         phm_notify_smc_display_config_after_ps_adjustment(hwmgr);
     287             :         }
     288             : 
     289           0 :         if (!phm_force_dpm_levels(hwmgr, hwmgr->request_dpm_level))
     290           0 :                 hwmgr->dpm_level = hwmgr->request_dpm_level;
     291             : 
     292           0 :         if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) {
     293           0 :                 index = fls(hwmgr->workload_mask);
     294           0 :                 index = index > 0 && index <= Workload_Policy_Max ? index - 1 : 0;
     295           0 :                 workload = hwmgr->workload_setting[index];
     296             : 
     297           0 :                 if (hwmgr->power_profile_mode != workload && hwmgr->hwmgr_func->set_power_profile_mode)
     298           0 :                         hwmgr->hwmgr_func->set_power_profile_mode(hwmgr, &workload, 0);
     299             :         }
     300             : 
     301           0 :         return 0;
     302             : }
     303             : 

Generated by: LCOV version 1.14