diff --git a/src/modules/cpufreq/e_mod_main.c b/src/modules/cpufreq/e_mod_main.c index 9f8b15ff0..cfb8a31bf 100644 --- a/src/modules/cpufreq/e_mod_main.c +++ b/src/modules/cpufreq/e_mod_main.c @@ -40,6 +40,7 @@ static void _button_cb_mouse_down(void *data, Evas *e, Evas_Object *obj, vo static void _menu_cb_post(void *data, E_Menu *m); static void _cpufreq_set_governor(const char *governor); static void _cpufreq_set_frequency(int frequency); +static void _cpufreq_set_pstate(int min, int max, int turbo); static Eina_Bool _cpufreq_cb_check(void *data); static Status *_cpufreq_status_new(void); static void _cpufreq_status_free(Status *s); @@ -62,6 +63,8 @@ static void _cpufreq_menu_auto_powersave(void *data, E_Menu *m, E_Menu_Item static void _cpufreq_menu_governor(void *data, E_Menu *m, E_Menu_Item *mi); static void _cpufreq_menu_powersave_governor(void *data, E_Menu *m, E_Menu_Item *mi); static void _cpufreq_menu_frequency(void *data, E_Menu *m, E_Menu_Item *mi); +static void _cpufreq_menu_pstate_min(void *data, E_Menu *m, E_Menu_Item *mi); +static void _cpufreq_menu_pstate_max(void *data, E_Menu *m, E_Menu_Item *mi); static void _cpufreq_poll_interval_update(void); static E_Config_DD *conf_edd = NULL; @@ -330,6 +333,47 @@ _button_cb_mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED_ } } + if (cpufreq_config->status->pstate) + { + int set; + + mo = e_menu_new(); + cpufreq_config->menu_pstate1 = mo; + + set = 0; +#define VALMIN(_n) \ + mi = e_menu_item_new(mo); \ + e_menu_item_label_set(mi, #_n); \ + e_menu_item_radio_set(mi, 1); \ + e_menu_item_radio_group_set(mi, 1); \ + if ((!set) && (cpufreq_config->status->pstate_min <= _n)) \ + { set = 1; e_menu_item_toggle_set(mi, 1); } \ + e_menu_item_callback_set(mi, _cpufreq_menu_pstate_min, (void *)_n) + VALMIN(0); + VALMIN(25); + VALMIN(50); + VALMIN(75); + VALMIN(100); + + mo = e_menu_new(); + cpufreq_config->menu_pstate2 = mo; + + set = 0; +#define VALMAX(_n) \ + mi = e_menu_item_new(mo); \ + e_menu_item_label_set(mi, #_n); \ + e_menu_item_radio_set(mi, 1); \ + e_menu_item_radio_group_set(mi, 1); \ + if ((!set) && (cpufreq_config->status->pstate_max <= _n)) \ + { set = 1; e_menu_item_toggle_set(mi, 1); } \ + e_menu_item_callback_set(mi, _cpufreq_menu_pstate_max, (void *)_n) + VALMAX(5); + VALMAX(25); + VALMAX(50); + VALMAX(75); + VALMAX(100); + } + mg = e_menu_new(); mi = e_menu_item_new(mg); e_menu_item_label_set(mi, _("Time Between Updates")); @@ -354,6 +398,18 @@ _button_cb_mouse_down(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED_ e_menu_item_label_set(mi, _("Powersaving behavior")); e_menu_item_submenu_set(mi, cpufreq_config->menu_powersave); } + if (cpufreq_config->menu_pstate1) + { + mi = e_menu_item_new(mg); + e_menu_item_label_set(mi, _("Power State Min")); + e_menu_item_submenu_set(mi, cpufreq_config->menu_pstate1); + } + if (cpufreq_config->menu_pstate2) + { + mi = e_menu_item_new(mg); + e_menu_item_label_set(mi, _("Power State Max")); + e_menu_item_submenu_set(mi, cpufreq_config->menu_pstate2); + } e_gadcon_canvas_zone_geometry_get(inst->gcc->gadcon, &cx, &cy, NULL, NULL); @@ -411,6 +467,10 @@ _menu_cb_post(void *data, E_Menu *m __UNUSED__) cpufreq_config->menu_frequency = NULL; if (cpufreq_config->menu_powersave) e_object_del(E_OBJECT(cpufreq_config->menu_powersave)); + if (cpufreq_config->menu_pstate1) + e_object_del(E_OBJECT(cpufreq_config->menu_pstate1)); + if (cpufreq_config->menu_pstate2) + e_object_del(E_OBJECT(cpufreq_config->menu_pstate2)); cpufreq_config->menu_powersave = NULL; } @@ -498,6 +558,35 @@ _cpufreq_set_frequency(int frequency) } } +static void +_cpufreq_set_pstate(int min, int max, int turbo) +{ + char buf[4096]; + int ret; + + snprintf(buf, sizeof(buf), + "%s %s %i %i %i", cpufreq_config->set_exe_path, "pstate", min, max, turbo); + fprintf(stderr, buf); + ret = system(buf); + if (ret != 0) + { + E_Dialog *dia; + E_Container *con; + + con = e_container_current_get(e_manager_current_get()); + if (!(dia = e_dialog_new(con, "E", "_e_mod_cpufreq_error_setfreq"))) + return; + e_dialog_title_set(dia, "Enlightenment Cpufreq Module"); + e_dialog_icon_set(dia, "enlightenment", 64); + e_dialog_text_set(dia, _("There was an error trying to set the
" + "cpu power state setting via the module's
" + "setfreq utility.")); + e_dialog_button_add(dia, _("OK"), NULL, NULL, NULL); + e_win_centered_set(dia->win, 1); + e_dialog_show(dia); + } +} + static Eina_Bool _cpufreq_cb_check(void *data __UNUSED__) { @@ -859,6 +948,38 @@ _cpufreq_status_check_current(Status *s) } } } + f = fopen("/sys/devices/system/cpu/intel_pstate/min_perf_pct", "r"); + if (f) + { + if (fgets(buf, sizeof(buf), f) != NULL) + { + s->pstate_min = atoi(buf); + s->pstate = 1; + } + fclose(f); + } + f = fopen("/sys/devices/system/cpu/intel_pstate/max_perf_pct", "r"); + if (f) + { + if (fgets(buf, sizeof(buf), f) != NULL) + { + s->pstate_max = atoi(buf); + s->pstate = 1; + } + fclose(f); + } + f = fopen("/sys/devices/system/cpu/intel_pstate/no_turbo", "r"); + if (f) + { + if (fgets(buf, sizeof(buf), f) != NULL) + { + s->pstate_turbo = atoi(buf); + if (s->pstate_turbo) s->pstate_turbo = 0; + else s->pstate_turbo = 1; + s->pstate = 1; + } + fclose(f); + } #endif return ret; } @@ -1108,6 +1229,30 @@ _cpufreq_menu_frequency(void *data, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUS if (frequency > 0) _cpufreq_set_frequency(frequency); } +static void +_cpufreq_menu_pstate_min(void *data, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__) +{ + int min = (long)data; + cpufreq_config->pstate_min = min + 1; + if (cpufreq_config->pstate_max < cpufreq_config->pstate_min) + cpufreq_config->pstate_max = cpufreq_config->pstate_min; + _cpufreq_set_pstate(cpufreq_config->pstate_min - 1, + cpufreq_config->pstate_max - 1, 1); + e_config_save_queue(); +} + +static void +_cpufreq_menu_pstate_max(void *data, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__) +{ + int max = (long)data; + cpufreq_config->pstate_max = max + 1; + if (cpufreq_config->pstate_min > cpufreq_config->pstate_max) + cpufreq_config->pstate_min = cpufreq_config->pstate_max; + _cpufreq_set_pstate(cpufreq_config->pstate_min - 1, + cpufreq_config->pstate_max - 1, 1); + e_config_save_queue(); +} + static void _cpufreq_poll_interval_update(void) { @@ -1143,6 +1288,8 @@ e_modapi_init(E_Module *m) E_CONFIG_VAL(D, T, auto_powersave, INT); E_CONFIG_VAL(D, T, powersave_governor, STR); E_CONFIG_VAL(D, T, governor, STR); + E_CONFIG_VAL(D, T, pstate_min, INT); + E_CONFIG_VAL(D, T, pstate_max, INT); cpufreq_config = e_config_domain_load("module.cpufreq", conf_edd); if ((cpufreq_config) && @@ -1158,6 +1305,13 @@ e_modapi_init(E_Module *m) cpufreq_config->auto_powersave = 1; cpufreq_config->powersave_governor = NULL; cpufreq_config->governor = NULL; + cpufreq_config->pstate_min = 1; + cpufreq_config->pstate_max = 101; + } + else + { + if (cpufreq_config->pstate_min == 0) cpufreq_config->pstate_min = 1; + if (cpufreq_config->pstate_max == 0) cpufreq_config->pstate_max = 101; } E_CONFIG_LIMIT(cpufreq_config->poll_interval, 1, 1024); @@ -1205,6 +1359,9 @@ e_modapi_init(E_Module *m) } } + _cpufreq_set_pstate(cpufreq_config->pstate_min - 1, + cpufreq_config->pstate_max - 1, 1); + cpufreq_config->module = m; e_gadcon_provider_register(&_gadcon_class); diff --git a/src/modules/cpufreq/e_mod_main.h b/src/modules/cpufreq/e_mod_main.h index 5cd5a6c13..f462c9bf3 100644 --- a/src/modules/cpufreq/e_mod_main.h +++ b/src/modules/cpufreq/e_mod_main.h @@ -17,9 +17,13 @@ struct _Status int cur_min_frequency; int cur_max_frequency; int can_set_frequency; + int pstate_min; + int pstate_max; char *cur_governor; const char *orig_governor; unsigned char active; + unsigned char pstate; + unsigned char pstate_turbo; }; struct _Config @@ -31,6 +35,8 @@ struct _Config int auto_powersave; const char *powersave_governor; const char *governor; + int pstate_min; + int pstate_max; /* just config state */ E_Module *module; Eina_List *instances; @@ -39,6 +45,8 @@ struct _Config E_Menu *menu_governor; E_Menu *menu_frequency; E_Menu *menu_powersave; + E_Menu *menu_pstate1; + E_Menu *menu_pstate2; Status *status; char *set_exe_path; Ecore_Poller *frequency_check_poller; diff --git a/src/modules/cpufreq/freqset.c b/src/modules/cpufreq/freqset.c index 3bda901a0..a5da6229c 100644 --- a/src/modules/cpufreq/freqset.c +++ b/src/modules/cpufreq/freqset.c @@ -16,14 +16,16 @@ static int sys_cpu_setall(const char *control, const char *value); static int sys_cpufreq_set(const char *control, const char *value); +static int sys_cpu_pstate(int min, int max, int turbo); int main(int argc, char *argv[]) { - if (argc != 3) + if (argc < 3) { fprintf(stderr, "Invalid command. Syntax:\n"); fprintf(stderr, "\tfreqset \n"); + fprintf(stderr, "\tfreqset \n"); return 1; } @@ -99,6 +101,28 @@ main(int argc, char *argv[]) sys_cpufreq_set("conservative/ignore_nice_load", "0"); return 0; } + else if (!strcmp(argv[1], "pstate")) + { + int min, max, turbo; + + if (argc < 5) + { + fprintf(stderr, "Invalid number of arguments.\n"); + return 1; + } + min = atoi(argv[2]); + max = atoi(argv[3]); + turbo = atoi(argv[4]); + if ((min < 0) || (min > 100) || + (max < 0) || (max > 100) || + (turbo < 0) || (turbo > 1)) + { + fprintf(stderr, "Invalid pstate values.\n"); + return 1; + } + sys_cpu_pstate(min, max, turbo); + return 0; + } else { fprintf(stderr, "Unknown command.\n"); @@ -156,3 +180,25 @@ sys_cpufreq_set(const char *control, const char *value) return 1; } +static int +sys_cpu_pstate(int min, int max, int turbo) +{ + FILE *f; + + f = fopen("/sys/devices/system/cpu/intel_pstate/min_perf_pct", "w"); + if (!f) return 0; + fprintf(f, "%i\n", min); + fclose(f); + + f = fopen("/sys/devices/system/cpu/intel_pstate/max_perf_pct", "w"); + if (!f) return 0; + fprintf(f, "%i\n", max); + fclose(f); + + f = fopen("/sys/devices/system/cpu/intel_pstate/no_turbo", "w"); + if (!f) return 0; + fprintf(f, "%i\n", turbo ? 0 : 1); + fclose(f); + + return 1; +}