Skip to content

Commit 3ca7bc8

Browse files
wkarnyrafaeljw
authored andcommitted
cpufreq: amd-pstate: Add guided mode control support via sysfs
amd_pstate driver's `status` sysfs entry helps to control the driver's mode dynamically by user. After the addition of guided mode the combinations of mode transitions have been increased (16 combinations). Therefore optimise the amd_pstate_update_status function by implementing a state transition table. There are 4 states amd_pstate supports, namely: 'disable', 'passive', 'active', and 'guided'. The transition from any state to any other state is possible after this change. Sysfs interface: To disable amd_pstate driver: # echo disable > /sys/devices/system/cpu/amd_pstate/status To enable passive mode: # echo passive > /sys/devices/system/cpu/amd_pstate/status To change mode to active: # echo active > /sys/devices/system/cpu/amd_pstate/status To change mode to guided: # echo guided > /sys/devices/system/cpu/amd_pstate/status Acked-by: Huang Rui <ray.huang@amd.com> Reviewed-by: Mario Limonciello <mario.limonciello@amd.com> Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name> Signed-off-by: Wyes Karny <wyes.karny@amd.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent 2dd6d0e commit 3ca7bc8

1 file changed

Lines changed: 101 additions & 42 deletions

File tree

drivers/cpufreq/amd-pstate.c

Lines changed: 101 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ static unsigned int epp_values[] = {
106106
[EPP_INDEX_POWERSAVE] = AMD_CPPC_EPP_POWERSAVE,
107107
};
108108

109+
typedef int (*cppc_mode_transition_fn)(int);
110+
109111
static inline int get_mode_idx_from_str(const char *str, size_t size)
110112
{
111113
int i;
@@ -838,6 +840,98 @@ static ssize_t show_energy_performance_preference(
838840
return sysfs_emit(buf, "%s\n", energy_perf_strings[preference]);
839841
}
840842

843+
static void amd_pstate_driver_cleanup(void)
844+
{
845+
amd_pstate_enable(false);
846+
cppc_state = AMD_PSTATE_DISABLE;
847+
current_pstate_driver = NULL;
848+
}
849+
850+
static int amd_pstate_register_driver(int mode)
851+
{
852+
int ret;
853+
854+
if (mode == AMD_PSTATE_PASSIVE || mode == AMD_PSTATE_GUIDED)
855+
current_pstate_driver = &amd_pstate_driver;
856+
else if (mode == AMD_PSTATE_ACTIVE)
857+
current_pstate_driver = &amd_pstate_epp_driver;
858+
else
859+
return -EINVAL;
860+
861+
cppc_state = mode;
862+
ret = cpufreq_register_driver(current_pstate_driver);
863+
if (ret) {
864+
amd_pstate_driver_cleanup();
865+
return ret;
866+
}
867+
return 0;
868+
}
869+
870+
static int amd_pstate_unregister_driver(int dummy)
871+
{
872+
cpufreq_unregister_driver(current_pstate_driver);
873+
amd_pstate_driver_cleanup();
874+
return 0;
875+
}
876+
877+
static int amd_pstate_change_mode_without_dvr_change(int mode)
878+
{
879+
int cpu = 0;
880+
881+
cppc_state = mode;
882+
883+
if (boot_cpu_has(X86_FEATURE_CPPC) || cppc_state == AMD_PSTATE_ACTIVE)
884+
return 0;
885+
886+
for_each_present_cpu(cpu) {
887+
cppc_set_auto_sel(cpu, (cppc_state == AMD_PSTATE_PASSIVE) ? 0 : 1);
888+
}
889+
890+
return 0;
891+
}
892+
893+
static int amd_pstate_change_driver_mode(int mode)
894+
{
895+
int ret;
896+
897+
ret = amd_pstate_unregister_driver(0);
898+
if (ret)
899+
return ret;
900+
901+
ret = amd_pstate_register_driver(mode);
902+
if (ret)
903+
return ret;
904+
905+
return 0;
906+
}
907+
908+
cppc_mode_transition_fn mode_state_machine[AMD_PSTATE_MAX][AMD_PSTATE_MAX] = {
909+
[AMD_PSTATE_DISABLE] = {
910+
[AMD_PSTATE_DISABLE] = NULL,
911+
[AMD_PSTATE_PASSIVE] = amd_pstate_register_driver,
912+
[AMD_PSTATE_ACTIVE] = amd_pstate_register_driver,
913+
[AMD_PSTATE_GUIDED] = amd_pstate_register_driver,
914+
},
915+
[AMD_PSTATE_PASSIVE] = {
916+
[AMD_PSTATE_DISABLE] = amd_pstate_unregister_driver,
917+
[AMD_PSTATE_PASSIVE] = NULL,
918+
[AMD_PSTATE_ACTIVE] = amd_pstate_change_driver_mode,
919+
[AMD_PSTATE_GUIDED] = amd_pstate_change_mode_without_dvr_change,
920+
},
921+
[AMD_PSTATE_ACTIVE] = {
922+
[AMD_PSTATE_DISABLE] = amd_pstate_unregister_driver,
923+
[AMD_PSTATE_PASSIVE] = amd_pstate_change_driver_mode,
924+
[AMD_PSTATE_ACTIVE] = NULL,
925+
[AMD_PSTATE_GUIDED] = amd_pstate_change_driver_mode,
926+
},
927+
[AMD_PSTATE_GUIDED] = {
928+
[AMD_PSTATE_DISABLE] = amd_pstate_unregister_driver,
929+
[AMD_PSTATE_PASSIVE] = amd_pstate_change_mode_without_dvr_change,
930+
[AMD_PSTATE_ACTIVE] = amd_pstate_change_driver_mode,
931+
[AMD_PSTATE_GUIDED] = NULL,
932+
},
933+
};
934+
841935
static ssize_t amd_pstate_show_status(char *buf)
842936
{
843937
if (!current_pstate_driver)
@@ -846,57 +940,22 @@ static ssize_t amd_pstate_show_status(char *buf)
846940
return sysfs_emit(buf, "%s\n", amd_pstate_mode_string[cppc_state]);
847941
}
848942

849-
static void amd_pstate_driver_cleanup(void)
850-
{
851-
current_pstate_driver = NULL;
852-
}
853-
854943
static int amd_pstate_update_status(const char *buf, size_t size)
855944
{
856-
int ret = 0;
857945
int mode_idx;
858946

859-
if (size > 7 || size < 6)
947+
if (size > strlen("passive") || size < strlen("active"))
860948
return -EINVAL;
861-
mode_idx = get_mode_idx_from_str(buf, size);
862949

863-
switch(mode_idx) {
864-
case AMD_PSTATE_DISABLE:
865-
if (!current_pstate_driver)
866-
return -EINVAL;
867-
if (cppc_state == AMD_PSTATE_ACTIVE)
868-
return -EBUSY;
869-
cpufreq_unregister_driver(current_pstate_driver);
870-
amd_pstate_driver_cleanup();
871-
break;
872-
case AMD_PSTATE_PASSIVE:
873-
if (current_pstate_driver) {
874-
if (current_pstate_driver == &amd_pstate_driver)
875-
return 0;
876-
cpufreq_unregister_driver(current_pstate_driver);
877-
cppc_state = AMD_PSTATE_PASSIVE;
878-
current_pstate_driver = &amd_pstate_driver;
879-
}
950+
mode_idx = get_mode_idx_from_str(buf, size);
880951

881-
ret = cpufreq_register_driver(current_pstate_driver);
882-
break;
883-
case AMD_PSTATE_ACTIVE:
884-
if (current_pstate_driver) {
885-
if (current_pstate_driver == &amd_pstate_epp_driver)
886-
return 0;
887-
cpufreq_unregister_driver(current_pstate_driver);
888-
current_pstate_driver = &amd_pstate_epp_driver;
889-
cppc_state = AMD_PSTATE_ACTIVE;
890-
}
952+
if (mode_idx < 0 || mode_idx >= AMD_PSTATE_MAX)
953+
return -EINVAL;
891954

892-
ret = cpufreq_register_driver(current_pstate_driver);
893-
break;
894-
default:
895-
ret = -EINVAL;
896-
break;
897-
}
955+
if (mode_state_machine[cppc_state][mode_idx])
956+
return mode_state_machine[cppc_state][mode_idx](mode_idx);
898957

899-
return ret;
958+
return 0;
900959
}
901960

902961
static ssize_t show_status(struct kobject *kobj,

0 commit comments

Comments
 (0)