summaryrefslogtreecommitdiff
path: root/include/linux/intel_rapl.h
blob: 328004f605c34fb2c55c448a1e466ecec35f47c9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
/* SPDX-License-Identifier: GPL-2.0 */
/*
 *  Data types and headers for RAPL support
 *
 *  Copyright (C) 2019  Intel Corporation.
 *
 *  Author: Zhang Rui <rui.zhang@intel.com>
 */

#ifndef __INTEL_RAPL_H__
#define __INTEL_RAPL_H__

#include <linux/types.h>
#include <linux/powercap.h>
#include <linux/cpuhotplug.h>

enum rapl_if_type {
	RAPL_IF_MSR,	/* RAPL I/F using MSR registers */
	RAPL_IF_MMIO,	/* RAPL I/F using MMIO registers */
	RAPL_IF_TPMI,	/* RAPL I/F using TPMI registers */
};

enum rapl_domain_type {
	RAPL_DOMAIN_PACKAGE,	/* entire package/socket */
	RAPL_DOMAIN_PP0,	/* core power plane */
	RAPL_DOMAIN_PP1,	/* graphics uncore */
	RAPL_DOMAIN_DRAM,	/* DRAM control_type */
	RAPL_DOMAIN_PLATFORM,	/* PSys control_type */
	RAPL_DOMAIN_MAX,
};

enum rapl_domain_reg_id {
	RAPL_DOMAIN_REG_LIMIT,
	RAPL_DOMAIN_REG_STATUS,
	RAPL_DOMAIN_REG_PERF,
	RAPL_DOMAIN_REG_POLICY,
	RAPL_DOMAIN_REG_INFO,
	RAPL_DOMAIN_REG_PL4,
	RAPL_DOMAIN_REG_UNIT,
	RAPL_DOMAIN_REG_PL2,
	RAPL_DOMAIN_REG_MAX,
};

struct rapl_domain;

enum rapl_primitives {
	POWER_LIMIT1,
	POWER_LIMIT2,
	POWER_LIMIT4,
	ENERGY_COUNTER,
	FW_LOCK,
	FW_HIGH_LOCK,
	PL1_LOCK,
	PL2_LOCK,
	PL4_LOCK,

	PL1_ENABLE,		/* power limit 1, aka long term */
	PL1_CLAMP,		/* allow frequency to go below OS request */
	PL2_ENABLE,		/* power limit 2, aka short term, instantaneous */
	PL2_CLAMP,
	PL4_ENABLE,		/* power limit 4, aka max peak power */

	TIME_WINDOW1,		/* long term */
	TIME_WINDOW2,		/* short term */
	THERMAL_SPEC_POWER,
	MAX_POWER,

	MIN_POWER,
	MAX_TIME_WINDOW,
	THROTTLED_TIME,
	PRIORITY_LEVEL,

	PSYS_POWER_LIMIT1,
	PSYS_POWER_LIMIT2,
	PSYS_PL1_ENABLE,
	PSYS_PL2_ENABLE,
	PSYS_TIME_WINDOW1,
	PSYS_TIME_WINDOW2,
	/* below are not raw primitive data */
	NR_RAPL_PRIMITIVES,
};

struct rapl_domain_data {
	u64 primitives[NR_RAPL_PRIMITIVES];
	unsigned long timestamp;
};

#define NR_POWER_LIMITS	(POWER_LIMIT4 + 1)

struct rapl_power_limit {
	struct powercap_zone_constraint *constraint;
	struct rapl_domain *domain;
	const char *name;
	bool locked;
	u64 last_power_limit;
};

struct rapl_package;

#define RAPL_DOMAIN_NAME_LENGTH 16

union rapl_reg {
	void __iomem *mmio;
	u32 msr;
	u64 val;
};

struct rapl_domain {
	char name[RAPL_DOMAIN_NAME_LENGTH];
	enum rapl_domain_type id;
	union rapl_reg regs[RAPL_DOMAIN_REG_MAX];
	struct powercap_zone power_zone;
	struct rapl_domain_data rdd;
	struct rapl_power_limit rpl[NR_POWER_LIMITS];
	u64 attr_map;		/* track capabilities */
	unsigned int state;
	unsigned int power_unit;
	unsigned int energy_unit;
	unsigned int time_unit;
	struct rapl_package *rp;
};

struct reg_action {
	union rapl_reg reg;
	u64 mask;
	u64 value;
	int err;
};

struct rapl_defaults {
	u8 floor_freq_reg_addr;
	int (*check_unit)(struct rapl_domain *rd);
	void (*set_floor_freq)(struct rapl_domain *rd, bool mode);
	u64 (*compute_time_window)(struct rapl_domain *rd, u64 val, bool to_raw);
	unsigned int dram_domain_energy_unit;
	unsigned int psys_domain_energy_unit;
	bool spr_psys_bits;
	bool msr_pl4_support;
	bool msr_pmu_support;
};

#define PRIMITIVE_INFO_INIT(p, m, s, i, u, f) {	\
		.name = #p,			\
		.mask = m,			\
		.shift = s,			\
		.id = i,			\
		.unit = u,			\
		.flag = f			\
	}

enum unit_type {
	ARBITRARY_UNIT,		/* no translation */
	POWER_UNIT,
	ENERGY_UNIT,
	TIME_UNIT,
};

/* per domain data. used to describe individual knobs such that access function
 * can be consolidated into one instead of many inline functions.
 */
struct rapl_primitive_info {
	const char *name;
	u64 mask;
	int shift;
	enum rapl_domain_reg_id id;
	enum unit_type unit;
	u32 flag;
};

/**
 * struct rapl_if_priv: private data for different RAPL interfaces
 * @control_type:		Each RAPL interface must have its own powercap
 *				control type.
 * @platform_rapl_domain:	Optional. Some RAPL interface may have platform
 *				level RAPL control.
 * @pcap_rapl_online:		CPU hotplug state for each RAPL interface.
 * @reg_unit:			Register for getting energy/power/time unit.
 * @regs:			Register sets for different RAPL Domains.
 * @limits:			Number of power limits supported by each domain.
 * @read_raw:			Callback for reading RAPL interface specific
 *				registers.
 * @write_raw:			Callback for writing RAPL interface specific
 *				registers.
 * @defaults:			pointer to default settings
 * @rpi:			pointer to interface primitive info
 */
struct rapl_if_priv {
	enum rapl_if_type type;
	struct powercap_control_type *control_type;
	enum cpuhp_state pcap_rapl_online;
	union rapl_reg reg_unit;
	union rapl_reg regs[RAPL_DOMAIN_MAX][RAPL_DOMAIN_REG_MAX];
	int limits[RAPL_DOMAIN_MAX];
	int (*read_raw)(int id, struct reg_action *ra, bool pmu_ctx);
	int (*write_raw)(int id, struct reg_action *ra);
	const struct rapl_defaults *defaults;
	struct rapl_primitive_info *rpi;
};

#ifdef CONFIG_PERF_EVENTS
/**
 * struct rapl_package_pmu_data: Per package data for PMU support
 * @scale:		Scale of 2^-32 Joules for each energy counter increase.
 * @lock:		Lock to protect n_active and active_list.
 * @n_active:		Number of active events.
 * @active_list:	List of active events.
 * @timer_interval:	Maximum timer expiration time before counter overflow.
 * @hrtimer:		Periodically update the counter to prevent overflow.
 */
struct rapl_package_pmu_data {
	u64 scale[RAPL_DOMAIN_MAX];
	raw_spinlock_t lock;
	int n_active;
	struct list_head active_list;
	ktime_t timer_interval;
	struct hrtimer hrtimer;
};
#endif

/* maximum rapl package domain name: package-%d-die-%d */
#define PACKAGE_DOMAIN_NAME_LENGTH 30

struct rapl_package {
	unsigned int id;	/* logical die id, equals physical 1-die systems */
	unsigned int nr_domains;
	unsigned long domain_map;	/* bit map of active domains */
	struct rapl_domain *domains;	/* array of domains, sized at runtime */
	struct powercap_zone *power_zone;	/* keep track of parent zone */
	unsigned long power_limit_irq;	/* keep track of package power limit
					 * notify interrupt enable status.
					 */
	struct list_head plist;
	int lead_cpu;		/* one active cpu per package for access */
	/* Track active cpus */
	struct cpumask cpumask;
	char name[PACKAGE_DOMAIN_NAME_LENGTH];
	struct rapl_if_priv *priv;
#ifdef CONFIG_PERF_EVENTS
	bool has_pmu;
	struct rapl_package_pmu_data pmu_data;
#endif
};

struct rapl_package *rapl_find_package_domain_cpuslocked(int id, struct rapl_if_priv *priv,
						       bool id_is_cpu);
struct rapl_package *rapl_add_package_cpuslocked(int id, struct rapl_if_priv *priv,
						 bool id_is_cpu);
void rapl_remove_package_cpuslocked(struct rapl_package *rp);

struct rapl_package *rapl_find_package_domain(int id, struct rapl_if_priv *priv, bool id_is_cpu);
struct rapl_package *rapl_add_package(int id, struct rapl_if_priv *priv, bool id_is_cpu);
void rapl_remove_package(struct rapl_package *rp);
int rapl_default_check_unit(struct rapl_domain *rd);
void rapl_default_set_floor_freq(struct rapl_domain *rd, bool mode);
u64 rapl_default_compute_time_window(struct rapl_domain *rd, u64 value, bool to_raw);

#ifdef CONFIG_PERF_EVENTS
int rapl_package_add_pmu(struct rapl_package *rp);
int rapl_package_add_pmu_locked(struct rapl_package *rp);
void rapl_package_remove_pmu(struct rapl_package *rp);
void rapl_package_remove_pmu_locked(struct rapl_package *rp);
#else
static inline int rapl_package_add_pmu(struct rapl_package *rp) { return 0; }
static inline int rapl_package_add_pmu_locked(struct rapl_package *rp) { return 0; }
static inline void rapl_package_remove_pmu(struct rapl_package *rp) { }
static inline void rapl_package_remove_pmu_locked(struct rapl_package *rp) { }
#endif

#endif /* __INTEL_RAPL_H__ */