1 /*
2  *  (C) 2011 Thomas Renninger <trenn@suse.de>, Novell Inc.
3  *
4  *  Licensed under the terms of the GNU GPL License version 2.
5  */
6 
7 
8 #include <unistd.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <errno.h>
12 #include <string.h>
13 #include <getopt.h>
14 
15 #include <cpufreq.h>
16 #include "helpers/helpers.h"
17 #include "helpers/sysfs.h"
18 #include "helpers/bitmask.h"
19 
20 static struct option set_opts[] = {
21 	{ .name = "perf-bias",	.has_arg = optional_argument,	.flag = NULL,	.val = 'b'},
22 	{ .name = "sched-mc",	.has_arg = optional_argument,	.flag = NULL,	.val = 'm'},
23 	{ .name = "sched-smt",	.has_arg = optional_argument,	.flag = NULL,	.val = 's'},
24 	{ },
25 };
26 
27 static void print_wrong_arg_exit(void)
28 {
29 	printf(_("invalid or unknown argument\n"));
30 	exit(EXIT_FAILURE);
31 }
32 
33 int cmd_set(int argc, char **argv)
34 {
35 	extern char *optarg;
36 	extern int optind, opterr, optopt;
37 	unsigned int cpu;
38 
39 	union {
40 		struct {
41 			int sched_mc:1;
42 			int sched_smt:1;
43 			int perf_bias:1;
44 		};
45 		int params;
46 	} params;
47 	int sched_mc = 0, sched_smt = 0, perf_bias = 0;
48 	int ret = 0;
49 
50 	setlocale(LC_ALL, "");
51 	textdomain(PACKAGE);
52 
53 	params.params = 0;
54 	/* parameter parsing */
55 	while ((ret = getopt_long(argc, argv, "m:s:b:",
56 						set_opts, NULL)) != -1) {
57 		switch (ret) {
58 		case 'b':
59 			if (params.perf_bias)
60 				print_wrong_arg_exit();
61 			perf_bias = atoi(optarg);
62 			if (perf_bias < 0 || perf_bias > 15) {
63 				printf(_("--perf-bias param out "
64 					 "of range [0-%d]\n"), 15);
65 				print_wrong_arg_exit();
66 			}
67 			params.perf_bias = 1;
68 			break;
69 		case 'm':
70 			if (params.sched_mc)
71 				print_wrong_arg_exit();
72 			sched_mc = atoi(optarg);
73 			if (sched_mc < 0 || sched_mc > 2) {
74 				printf(_("--sched-mc param out "
75 					 "of range [0-%d]\n"), 2);
76 				print_wrong_arg_exit();
77 			}
78 			params.sched_mc = 1;
79 			break;
80 		case 's':
81 			if (params.sched_smt)
82 				print_wrong_arg_exit();
83 			sched_smt = atoi(optarg);
84 			if (sched_smt < 0 || sched_smt > 2) {
85 				printf(_("--sched-smt param out "
86 					 "of range [0-%d]\n"), 2);
87 				print_wrong_arg_exit();
88 			}
89 			params.sched_smt = 1;
90 			break;
91 		default:
92 			print_wrong_arg_exit();
93 		}
94 	};
95 
96 	if (!params.params)
97 		print_wrong_arg_exit();
98 
99 	if (params.sched_mc) {
100 		ret = sysfs_set_sched("mc", sched_mc);
101 		if (ret)
102 			fprintf(stderr, _("Error setting sched-mc %s\n"),
103 				(ret == -ENODEV) ? "not supported" : "");
104 	}
105 	if (params.sched_smt) {
106 		ret = sysfs_set_sched("smt", sched_smt);
107 		if (ret)
108 			fprintf(stderr, _("Error setting sched-smt %s\n"),
109 				(ret == -ENODEV) ? "not supported" : "");
110 	}
111 
112 	/* Default is: set all CPUs */
113 	if (bitmask_isallclear(cpus_chosen))
114 		bitmask_setall(cpus_chosen);
115 
116 	/* loop over CPUs */
117 	for (cpu = bitmask_first(cpus_chosen);
118 	     cpu <= bitmask_last(cpus_chosen); cpu++) {
119 
120 		if (!bitmask_isbitset(cpus_chosen, cpu) ||
121 		    cpufreq_cpu_exists(cpu))
122 			continue;
123 
124 		if (params.perf_bias) {
125 			ret = msr_intel_set_perf_bias(cpu, perf_bias);
126 			if (ret) {
127 				fprintf(stderr, _("Error setting perf-bias "
128 						  "value on CPU %d\n"), cpu);
129 				break;
130 			}
131 		}
132 	}
133 	return ret;
134 }
135