1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 *  (C) 2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
4 */
5
6
7#include <unistd.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <errno.h>
11#include <string.h>
12#include <getopt.h>
13#include <sys/utsname.h>
14
15#include "helpers/helpers.h"
16#include "helpers/sysfs.h"
17#include "helpers/bitmask.h"
18
19static struct option set_opts[] = {
20	{"perf-bias", required_argument, NULL, 'b'},
21	{"epp", required_argument, NULL, 'e'},
22	{"amd-pstate-mode", required_argument, NULL, 'm'},
23	{"turbo-boost", required_argument, NULL, 't'},
24	{ },
25};
26
27static void print_wrong_arg_exit(void)
28{
29	printf(_("invalid or unknown argument\n"));
30	exit(EXIT_FAILURE);
31}
32
33int cmd_set(int argc, char **argv)
34{
35	extern char *optarg;
36	extern int optind, opterr, optopt;
37	unsigned int cpu;
38	struct utsname uts;
39
40	union {
41		struct {
42			int perf_bias:1;
43			int epp:1;
44			int mode:1;
45			int turbo_boost:1;
46		};
47		int params;
48	} params;
49	int perf_bias = 0, turbo_boost = 1;
50	int ret = 0;
51	char epp[30], mode[20];
52
53	ret = uname(&uts);
54	if (!ret && (!strcmp(uts.machine, "ppc64le") ||
55		     !strcmp(uts.machine, "ppc64"))) {
56		fprintf(stderr, _("Subcommand not supported on POWER.\n"));
57		return ret;
58	}
59
60	setlocale(LC_ALL, "");
61	textdomain(PACKAGE);
62
63	params.params = 0;
64	/* parameter parsing */
65	while ((ret = getopt_long(argc, argv, "b:e:m:",
66						set_opts, NULL)) != -1) {
67		switch (ret) {
68		case 'b':
69			if (params.perf_bias)
70				print_wrong_arg_exit();
71			perf_bias = atoi(optarg);
72			if (perf_bias < 0 || perf_bias > 15) {
73				printf(_("--perf-bias param out "
74					 "of range [0-%d]\n"), 15);
75				print_wrong_arg_exit();
76			}
77			params.perf_bias = 1;
78			break;
79		case 'e':
80			if (params.epp)
81				print_wrong_arg_exit();
82			if (sscanf(optarg, "%29s", epp) != 1) {
83				print_wrong_arg_exit();
84				return -EINVAL;
85			}
86			params.epp = 1;
87			break;
88		case 'm':
89			if (cpupower_cpu_info.vendor != X86_VENDOR_AMD)
90				print_wrong_arg_exit();
91			if (params.mode)
92				print_wrong_arg_exit();
93			if (sscanf(optarg, "%19s", mode) != 1) {
94				print_wrong_arg_exit();
95				return -EINVAL;
96			}
97			params.mode = 1;
98			break;
99		case 't':
100			if (params.turbo_boost)
101				print_wrong_arg_exit();
102			turbo_boost = atoi(optarg);
103			if (turbo_boost < 0 || turbo_boost > 1) {
104				printf("--turbo-boost param out of range [0-1]\n");
105				print_wrong_arg_exit();
106			}
107			params.turbo_boost = 1;
108			break;
109
110
111		default:
112			print_wrong_arg_exit();
113		}
114	}
115
116	if (!params.params)
117		print_wrong_arg_exit();
118
119	if (params.mode) {
120		ret = cpupower_set_amd_pstate_mode(mode);
121		if (ret)
122			fprintf(stderr, "Error setting mode\n");
123	}
124
125	if (params.turbo_boost) {
126		ret = cpupower_set_turbo_boost(turbo_boost);
127		if (ret)
128			fprintf(stderr, "Error setting turbo-boost\n");
129	}
130
131	/* Default is: set all CPUs */
132	if (bitmask_isallclear(cpus_chosen))
133		bitmask_setall(cpus_chosen);
134
135	/* loop over CPUs */
136	for (cpu = bitmask_first(cpus_chosen);
137	     cpu <= bitmask_last(cpus_chosen); cpu++) {
138
139		if (!bitmask_isbitset(cpus_chosen, cpu))
140			continue;
141
142		if (sysfs_is_cpu_online(cpu) != 1){
143			fprintf(stderr, _("Cannot set values on CPU %d:"), cpu);
144			fprintf(stderr, _(" *is offline\n"));
145			continue;
146		}
147
148		if (params.perf_bias) {
149			ret = cpupower_intel_set_perf_bias(cpu, perf_bias);
150			if (ret) {
151				fprintf(stderr, _("Error setting perf-bias "
152						  "value on CPU %d\n"), cpu);
153				break;
154			}
155		}
156
157		if (params.epp) {
158			ret = cpupower_set_epp(cpu, epp);
159			if (ret) {
160				fprintf(stderr,
161					"Error setting epp value on CPU %d\n", cpu);
162				break;
163			}
164		}
165
166	}
167	return ret;
168}
169