1*8c37df3dSThomas Renninger // SPDX-License-Identifier: GPL-2.0-only
2*8c37df3dSThomas Renninger /*
3*8c37df3dSThomas Renninger  *  (C) 2016 SUSE Software Solutions GmbH
4*8c37df3dSThomas Renninger  *           Thomas Renninger <trenn@suse.de>
5*8c37df3dSThomas Renninger  */
6*8c37df3dSThomas Renninger 
7*8c37df3dSThomas Renninger #if defined(__i386__) || defined(__x86_64__)
8*8c37df3dSThomas Renninger 
9*8c37df3dSThomas Renninger #include <stdio.h>
10*8c37df3dSThomas Renninger #include <stdlib.h>
11*8c37df3dSThomas Renninger #include <stdint.h>
12*8c37df3dSThomas Renninger #include <time.h>
13*8c37df3dSThomas Renninger #include <string.h>
14*8c37df3dSThomas Renninger 
15*8c37df3dSThomas Renninger #include <pci/pci.h>
16*8c37df3dSThomas Renninger 
17*8c37df3dSThomas Renninger #include "idle_monitor/cpupower-monitor.h"
18*8c37df3dSThomas Renninger #include "helpers/helpers.h"
19*8c37df3dSThomas Renninger #include "powercap.h"
20*8c37df3dSThomas Renninger 
21*8c37df3dSThomas Renninger #define MAX_RAPL_ZONES 10
22*8c37df3dSThomas Renninger 
23*8c37df3dSThomas Renninger int rapl_zone_count;
24*8c37df3dSThomas Renninger cstate_t rapl_zones[MAX_RAPL_ZONES];
25*8c37df3dSThomas Renninger struct powercap_zone *rapl_zones_pt[MAX_RAPL_ZONES] = { 0 };
26*8c37df3dSThomas Renninger 
27*8c37df3dSThomas Renninger unsigned long long rapl_zone_previous_count[MAX_RAPL_ZONES];
28*8c37df3dSThomas Renninger unsigned long long rapl_zone_current_count[MAX_RAPL_ZONES];
29*8c37df3dSThomas Renninger unsigned long long rapl_max_count;
30*8c37df3dSThomas Renninger 
rapl_get_count_uj(unsigned int id,unsigned long long * count,unsigned int cpu)31*8c37df3dSThomas Renninger static int rapl_get_count_uj(unsigned int id, unsigned long long *count,
32*8c37df3dSThomas Renninger 			     unsigned int cpu)
33*8c37df3dSThomas Renninger {
34*8c37df3dSThomas Renninger 	if (rapl_zones_pt[id] == NULL)
35*8c37df3dSThomas Renninger 		/* error */
36*8c37df3dSThomas Renninger 		return -1;
37*8c37df3dSThomas Renninger 
38*8c37df3dSThomas Renninger 	*count = rapl_zone_current_count[id] - rapl_zone_previous_count[id];
39*8c37df3dSThomas Renninger 
40*8c37df3dSThomas Renninger 	return 0;
41*8c37df3dSThomas Renninger }
42*8c37df3dSThomas Renninger 
powercap_count_zones(struct powercap_zone * zone)43*8c37df3dSThomas Renninger static int powercap_count_zones(struct powercap_zone *zone)
44*8c37df3dSThomas Renninger {
45*8c37df3dSThomas Renninger 	uint64_t val;
46*8c37df3dSThomas Renninger 	int uj;
47*8c37df3dSThomas Renninger 
48*8c37df3dSThomas Renninger 	if (rapl_zone_count >= MAX_RAPL_ZONES)
49*8c37df3dSThomas Renninger 		return -1;
50*8c37df3dSThomas Renninger 
51*8c37df3dSThomas Renninger 	if (!zone->has_energy_uj)
52*8c37df3dSThomas Renninger 		return 0;
53*8c37df3dSThomas Renninger 
54*8c37df3dSThomas Renninger 	printf("%s\n", zone->sys_name);
55*8c37df3dSThomas Renninger 	uj = powercap_get_energy_uj(zone, &val);
56*8c37df3dSThomas Renninger 	printf("%d\n", uj);
57*8c37df3dSThomas Renninger 
58*8c37df3dSThomas Renninger 	strncpy(rapl_zones[rapl_zone_count].name, zone->name, CSTATE_NAME_LEN - 1);
59*8c37df3dSThomas Renninger 	strcpy(rapl_zones[rapl_zone_count].desc, "");
60*8c37df3dSThomas Renninger 	rapl_zones[rapl_zone_count].id = rapl_zone_count;
61*8c37df3dSThomas Renninger 	rapl_zones[rapl_zone_count].range = RANGE_MACHINE;
62*8c37df3dSThomas Renninger 	rapl_zones[rapl_zone_count].get_count = rapl_get_count_uj;
63*8c37df3dSThomas Renninger 	rapl_zones_pt[rapl_zone_count] = zone;
64*8c37df3dSThomas Renninger 	rapl_zone_count++;
65*8c37df3dSThomas Renninger 
66*8c37df3dSThomas Renninger 	return 0;
67*8c37df3dSThomas Renninger }
68*8c37df3dSThomas Renninger 
rapl_start(void)69*8c37df3dSThomas Renninger static int rapl_start(void)
70*8c37df3dSThomas Renninger {
71*8c37df3dSThomas Renninger 	int i, ret;
72*8c37df3dSThomas Renninger 	uint64_t uj_val;
73*8c37df3dSThomas Renninger 
74*8c37df3dSThomas Renninger 	for (i = 0; i < rapl_zone_count; i++) {
75*8c37df3dSThomas Renninger 		ret = powercap_get_energy_uj(rapl_zones_pt[i], &uj_val);
76*8c37df3dSThomas Renninger 		if (ret)
77*8c37df3dSThomas Renninger 			return ret;
78*8c37df3dSThomas Renninger 		rapl_zone_previous_count[i] = uj_val;
79*8c37df3dSThomas Renninger 	}
80*8c37df3dSThomas Renninger 
81*8c37df3dSThomas Renninger 	return 0;
82*8c37df3dSThomas Renninger }
83*8c37df3dSThomas Renninger 
rapl_stop(void)84*8c37df3dSThomas Renninger static int rapl_stop(void)
85*8c37df3dSThomas Renninger {
86*8c37df3dSThomas Renninger 	int i;
87*8c37df3dSThomas Renninger 	uint64_t uj_val;
88*8c37df3dSThomas Renninger 
89*8c37df3dSThomas Renninger 	for (i = 0; i < rapl_zone_count; i++) {
90*8c37df3dSThomas Renninger 		int ret;
91*8c37df3dSThomas Renninger 
92*8c37df3dSThomas Renninger 		ret = powercap_get_energy_uj(rapl_zones_pt[i], &uj_val);
93*8c37df3dSThomas Renninger 		if (ret)
94*8c37df3dSThomas Renninger 			return ret;
95*8c37df3dSThomas Renninger 		rapl_zone_current_count[i] = uj_val;
96*8c37df3dSThomas Renninger 		if (rapl_max_count < uj_val)
97*8c37df3dSThomas Renninger 			rapl_max_count = uj_val - rapl_zone_previous_count[i];
98*8c37df3dSThomas Renninger 	}
99*8c37df3dSThomas Renninger 	return 0;
100*8c37df3dSThomas Renninger }
101*8c37df3dSThomas Renninger 
rapl_register(void)102*8c37df3dSThomas Renninger struct cpuidle_monitor *rapl_register(void)
103*8c37df3dSThomas Renninger {
104*8c37df3dSThomas Renninger 	struct powercap_zone *root_zone;
105*8c37df3dSThomas Renninger 	char line[MAX_LINE_LEN] = "";
106*8c37df3dSThomas Renninger 	int ret, val;
107*8c37df3dSThomas Renninger 
108*8c37df3dSThomas Renninger 	ret = powercap_get_driver(line, MAX_LINE_LEN);
109*8c37df3dSThomas Renninger 	if (ret < 0) {
110*8c37df3dSThomas Renninger 		dprint("No powercapping driver loaded\n");
111*8c37df3dSThomas Renninger 		return NULL;
112*8c37df3dSThomas Renninger 	}
113*8c37df3dSThomas Renninger 
114*8c37df3dSThomas Renninger 	dprint("Driver: %s\n", line);
115*8c37df3dSThomas Renninger 	ret = powercap_get_enabled(&val);
116*8c37df3dSThomas Renninger 	if (ret < 0)
117*8c37df3dSThomas Renninger 		return NULL;
118*8c37df3dSThomas Renninger 	if (!val) {
119*8c37df3dSThomas Renninger 		dprint("Powercapping is disabled\n");
120*8c37df3dSThomas Renninger 		return NULL;
121*8c37df3dSThomas Renninger 	}
122*8c37df3dSThomas Renninger 
123*8c37df3dSThomas Renninger 	dprint("Powercap domain hierarchy:\n\n");
124*8c37df3dSThomas Renninger 	root_zone = powercap_init_zones();
125*8c37df3dSThomas Renninger 
126*8c37df3dSThomas Renninger 	if (root_zone == NULL) {
127*8c37df3dSThomas Renninger 		dprint("No powercap info found\n");
128*8c37df3dSThomas Renninger 		return NULL;
129*8c37df3dSThomas Renninger 	}
130*8c37df3dSThomas Renninger 
131*8c37df3dSThomas Renninger 	powercap_walk_zones(root_zone, powercap_count_zones);
132*8c37df3dSThomas Renninger 	rapl_monitor.hw_states_num = rapl_zone_count;
133*8c37df3dSThomas Renninger 
134*8c37df3dSThomas Renninger 	return &rapl_monitor;
135*8c37df3dSThomas Renninger }
136*8c37df3dSThomas Renninger 
137*8c37df3dSThomas Renninger struct cpuidle_monitor rapl_monitor = {
138*8c37df3dSThomas Renninger 	.name			= "RAPL",
139*8c37df3dSThomas Renninger 	.hw_states		= rapl_zones,
140*8c37df3dSThomas Renninger 	.hw_states_num		= 0,
141*8c37df3dSThomas Renninger 	.start			= rapl_start,
142*8c37df3dSThomas Renninger 	.stop			= rapl_stop,
143*8c37df3dSThomas Renninger 	.do_register		= rapl_register,
144*8c37df3dSThomas Renninger 	.flags.needs_root	= 0,
145*8c37df3dSThomas Renninger 	.overflow_s		= 60 * 60 * 24 * 100, /* To be implemented */
146*8c37df3dSThomas Renninger };
147*8c37df3dSThomas Renninger 
148*8c37df3dSThomas Renninger #endif
149