162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  (C) 2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <unistd.h>
862306a36Sopenharmony_ci#include <stdio.h>
962306a36Sopenharmony_ci#include <stdlib.h>
1062306a36Sopenharmony_ci#include <errno.h>
1162306a36Sopenharmony_ci#include <string.h>
1262306a36Sopenharmony_ci#include <getopt.h>
1362306a36Sopenharmony_ci#include <sys/utsname.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include "helpers/helpers.h"
1662306a36Sopenharmony_ci#include "helpers/sysfs.h"
1762306a36Sopenharmony_ci#include "helpers/bitmask.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic struct option set_opts[] = {
2062306a36Sopenharmony_ci	{"perf-bias", required_argument, NULL, 'b'},
2162306a36Sopenharmony_ci	{"epp", required_argument, NULL, 'e'},
2262306a36Sopenharmony_ci	{"amd-pstate-mode", required_argument, NULL, 'm'},
2362306a36Sopenharmony_ci	{"turbo-boost", required_argument, NULL, 't'},
2462306a36Sopenharmony_ci	{ },
2562306a36Sopenharmony_ci};
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic void print_wrong_arg_exit(void)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	printf(_("invalid or unknown argument\n"));
3062306a36Sopenharmony_ci	exit(EXIT_FAILURE);
3162306a36Sopenharmony_ci}
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ciint cmd_set(int argc, char **argv)
3462306a36Sopenharmony_ci{
3562306a36Sopenharmony_ci	extern char *optarg;
3662306a36Sopenharmony_ci	extern int optind, opterr, optopt;
3762306a36Sopenharmony_ci	unsigned int cpu;
3862306a36Sopenharmony_ci	struct utsname uts;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	union {
4162306a36Sopenharmony_ci		struct {
4262306a36Sopenharmony_ci			int perf_bias:1;
4362306a36Sopenharmony_ci			int epp:1;
4462306a36Sopenharmony_ci			int mode:1;
4562306a36Sopenharmony_ci			int turbo_boost:1;
4662306a36Sopenharmony_ci		};
4762306a36Sopenharmony_ci		int params;
4862306a36Sopenharmony_ci	} params;
4962306a36Sopenharmony_ci	int perf_bias = 0, turbo_boost = 1;
5062306a36Sopenharmony_ci	int ret = 0;
5162306a36Sopenharmony_ci	char epp[30], mode[20];
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	ret = uname(&uts);
5462306a36Sopenharmony_ci	if (!ret && (!strcmp(uts.machine, "ppc64le") ||
5562306a36Sopenharmony_ci		     !strcmp(uts.machine, "ppc64"))) {
5662306a36Sopenharmony_ci		fprintf(stderr, _("Subcommand not supported on POWER.\n"));
5762306a36Sopenharmony_ci		return ret;
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	setlocale(LC_ALL, "");
6162306a36Sopenharmony_ci	textdomain(PACKAGE);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	params.params = 0;
6462306a36Sopenharmony_ci	/* parameter parsing */
6562306a36Sopenharmony_ci	while ((ret = getopt_long(argc, argv, "b:e:m:",
6662306a36Sopenharmony_ci						set_opts, NULL)) != -1) {
6762306a36Sopenharmony_ci		switch (ret) {
6862306a36Sopenharmony_ci		case 'b':
6962306a36Sopenharmony_ci			if (params.perf_bias)
7062306a36Sopenharmony_ci				print_wrong_arg_exit();
7162306a36Sopenharmony_ci			perf_bias = atoi(optarg);
7262306a36Sopenharmony_ci			if (perf_bias < 0 || perf_bias > 15) {
7362306a36Sopenharmony_ci				printf(_("--perf-bias param out "
7462306a36Sopenharmony_ci					 "of range [0-%d]\n"), 15);
7562306a36Sopenharmony_ci				print_wrong_arg_exit();
7662306a36Sopenharmony_ci			}
7762306a36Sopenharmony_ci			params.perf_bias = 1;
7862306a36Sopenharmony_ci			break;
7962306a36Sopenharmony_ci		case 'e':
8062306a36Sopenharmony_ci			if (params.epp)
8162306a36Sopenharmony_ci				print_wrong_arg_exit();
8262306a36Sopenharmony_ci			if (sscanf(optarg, "%29s", epp) != 1) {
8362306a36Sopenharmony_ci				print_wrong_arg_exit();
8462306a36Sopenharmony_ci				return -EINVAL;
8562306a36Sopenharmony_ci			}
8662306a36Sopenharmony_ci			params.epp = 1;
8762306a36Sopenharmony_ci			break;
8862306a36Sopenharmony_ci		case 'm':
8962306a36Sopenharmony_ci			if (cpupower_cpu_info.vendor != X86_VENDOR_AMD)
9062306a36Sopenharmony_ci				print_wrong_arg_exit();
9162306a36Sopenharmony_ci			if (params.mode)
9262306a36Sopenharmony_ci				print_wrong_arg_exit();
9362306a36Sopenharmony_ci			if (sscanf(optarg, "%19s", mode) != 1) {
9462306a36Sopenharmony_ci				print_wrong_arg_exit();
9562306a36Sopenharmony_ci				return -EINVAL;
9662306a36Sopenharmony_ci			}
9762306a36Sopenharmony_ci			params.mode = 1;
9862306a36Sopenharmony_ci			break;
9962306a36Sopenharmony_ci		case 't':
10062306a36Sopenharmony_ci			if (params.turbo_boost)
10162306a36Sopenharmony_ci				print_wrong_arg_exit();
10262306a36Sopenharmony_ci			turbo_boost = atoi(optarg);
10362306a36Sopenharmony_ci			if (turbo_boost < 0 || turbo_boost > 1) {
10462306a36Sopenharmony_ci				printf("--turbo-boost param out of range [0-1]\n");
10562306a36Sopenharmony_ci				print_wrong_arg_exit();
10662306a36Sopenharmony_ci			}
10762306a36Sopenharmony_ci			params.turbo_boost = 1;
10862306a36Sopenharmony_ci			break;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci		default:
11262306a36Sopenharmony_ci			print_wrong_arg_exit();
11362306a36Sopenharmony_ci		}
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	if (!params.params)
11762306a36Sopenharmony_ci		print_wrong_arg_exit();
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	if (params.mode) {
12062306a36Sopenharmony_ci		ret = cpupower_set_amd_pstate_mode(mode);
12162306a36Sopenharmony_ci		if (ret)
12262306a36Sopenharmony_ci			fprintf(stderr, "Error setting mode\n");
12362306a36Sopenharmony_ci	}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	if (params.turbo_boost) {
12662306a36Sopenharmony_ci		ret = cpupower_set_turbo_boost(turbo_boost);
12762306a36Sopenharmony_ci		if (ret)
12862306a36Sopenharmony_ci			fprintf(stderr, "Error setting turbo-boost\n");
12962306a36Sopenharmony_ci	}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	/* Default is: set all CPUs */
13262306a36Sopenharmony_ci	if (bitmask_isallclear(cpus_chosen))
13362306a36Sopenharmony_ci		bitmask_setall(cpus_chosen);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	/* loop over CPUs */
13662306a36Sopenharmony_ci	for (cpu = bitmask_first(cpus_chosen);
13762306a36Sopenharmony_ci	     cpu <= bitmask_last(cpus_chosen); cpu++) {
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci		if (!bitmask_isbitset(cpus_chosen, cpu))
14062306a36Sopenharmony_ci			continue;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci		if (sysfs_is_cpu_online(cpu) != 1){
14362306a36Sopenharmony_ci			fprintf(stderr, _("Cannot set values on CPU %d:"), cpu);
14462306a36Sopenharmony_ci			fprintf(stderr, _(" *is offline\n"));
14562306a36Sopenharmony_ci			continue;
14662306a36Sopenharmony_ci		}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci		if (params.perf_bias) {
14962306a36Sopenharmony_ci			ret = cpupower_intel_set_perf_bias(cpu, perf_bias);
15062306a36Sopenharmony_ci			if (ret) {
15162306a36Sopenharmony_ci				fprintf(stderr, _("Error setting perf-bias "
15262306a36Sopenharmony_ci						  "value on CPU %d\n"), cpu);
15362306a36Sopenharmony_ci				break;
15462306a36Sopenharmony_ci			}
15562306a36Sopenharmony_ci		}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci		if (params.epp) {
15862306a36Sopenharmony_ci			ret = cpupower_set_epp(cpu, epp);
15962306a36Sopenharmony_ci			if (ret) {
16062306a36Sopenharmony_ci				fprintf(stderr,
16162306a36Sopenharmony_ci					"Error setting epp value on CPU %d\n", cpu);
16262306a36Sopenharmony_ci				break;
16362306a36Sopenharmony_ci			}
16462306a36Sopenharmony_ci		}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	}
16762306a36Sopenharmony_ci	return ret;
16862306a36Sopenharmony_ci}
169