]>
Commit | Line | Data |
---|---|---|
35e5a9d9 GKH |
1 | From d474a4d365aaa5c7aabcf11a74ea43aa23f6f2e9 Mon Sep 17 00:00:00 2001 |
2 | From: Jacob Pan <jacob.jun.pan@linux.intel.com> | |
3 | Date: Fri, 13 Mar 2015 03:48:56 -0700 | |
4 | Subject: powercap / RAPL: handle domains with different energy units | |
5 | ||
6 | From: Jacob Pan <jacob.jun.pan@linux.intel.com> | |
7 | ||
8 | commit d474a4d365aaa5c7aabcf11a74ea43aa23f6f2e9 upstream. | |
9 | ||
10 | The current driver assumes all RAPL domains within a CPU package | |
11 | have the same energy unit. This is no longer true for HSW server | |
12 | CPUs since DRAM domain has is own fixed energy unit which can be | |
13 | different than the package energy unit enumerated by package | |
14 | power MSR. In fact, the default HSW EP package power unit is 61uJ | |
15 | whereas DRAM domain unit is 15.3uJ. The result is that DRAM power | |
16 | consumption is counted 4x more than real power reported by energy | |
17 | counters, similarly for max_energy_range_uj of DRAM domain. | |
18 | ||
19 | This patch adds domain specific energy unit per cpu type, it allows | |
20 | domain energy unit to override package energy unit if non zero. | |
21 | ||
22 | Please see this document for details. | |
23 | "Intel Xeon Processor E5-1600 and E5-2600 v3 Product Families, Volume 2 of 2. | |
24 | Datasheet, September 2014, Reference Number: 330784-001 " | |
25 | ||
26 | Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com> | |
27 | Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> | |
28 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
29 | ||
30 | --- | |
31 | drivers/powercap/intel_rapl.c | 54 ++++++++++++++++++++++++++++++------------ | |
32 | 1 file changed, 39 insertions(+), 15 deletions(-) | |
33 | ||
34 | --- a/drivers/powercap/intel_rapl.c | |
35 | +++ b/drivers/powercap/intel_rapl.c | |
36 | @@ -73,7 +73,7 @@ | |
37 | ||
38 | #define TIME_WINDOW_MAX_MSEC 40000 | |
39 | #define TIME_WINDOW_MIN_MSEC 250 | |
40 | - | |
41 | +#define ENERGY_UNIT_SCALE 1000 /* scale from driver unit to powercap unit */ | |
42 | enum unit_type { | |
43 | ARBITRARY_UNIT, /* no translation */ | |
44 | POWER_UNIT, | |
45 | @@ -158,6 +158,7 @@ struct rapl_domain { | |
46 | struct rapl_power_limit rpl[NR_POWER_LIMITS]; | |
47 | u64 attr_map; /* track capabilities */ | |
48 | unsigned int state; | |
49 | + unsigned int domain_energy_unit; | |
50 | int package_id; | |
51 | }; | |
52 | #define power_zone_to_rapl_domain(_zone) \ | |
53 | @@ -190,6 +191,7 @@ struct rapl_defaults { | |
54 | void (*set_floor_freq)(struct rapl_domain *rd, bool mode); | |
55 | u64 (*compute_time_window)(struct rapl_package *rp, u64 val, | |
56 | bool to_raw); | |
57 | + unsigned int dram_domain_energy_unit; | |
58 | }; | |
59 | static struct rapl_defaults *rapl_defaults; | |
60 | ||
61 | @@ -227,7 +229,8 @@ static int rapl_read_data_raw(struct rap | |
62 | static int rapl_write_data_raw(struct rapl_domain *rd, | |
63 | enum rapl_primitives prim, | |
64 | unsigned long long value); | |
65 | -static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value, | |
66 | +static u64 rapl_unit_xlate(struct rapl_domain *rd, int package, | |
67 | + enum unit_type type, u64 value, | |
68 | int to_raw); | |
69 | static void package_power_limit_irq_save(int package_id); | |
70 | ||
71 | @@ -305,7 +308,9 @@ static int get_energy_counter(struct pow | |
72 | ||
73 | static int get_max_energy_counter(struct powercap_zone *pcd_dev, u64 *energy) | |
74 | { | |
75 | - *energy = rapl_unit_xlate(0, ENERGY_UNIT, ENERGY_STATUS_MASK, 0); | |
76 | + struct rapl_domain *rd = power_zone_to_rapl_domain(pcd_dev); | |
77 | + | |
78 | + *energy = rapl_unit_xlate(rd, 0, ENERGY_UNIT, ENERGY_STATUS_MASK, 0); | |
79 | return 0; | |
80 | } | |
81 | ||
82 | @@ -639,6 +644,11 @@ static void rapl_init_domains(struct rap | |
83 | rd->msrs[4] = MSR_DRAM_POWER_INFO; | |
84 | rd->rpl[0].prim_id = PL1_ENABLE; | |
85 | rd->rpl[0].name = pl1_name; | |
86 | + rd->domain_energy_unit = | |
87 | + rapl_defaults->dram_domain_energy_unit; | |
88 | + if (rd->domain_energy_unit) | |
89 | + pr_info("DRAM domain energy unit %dpj\n", | |
90 | + rd->domain_energy_unit); | |
91 | break; | |
92 | } | |
93 | if (mask) { | |
94 | @@ -648,11 +658,13 @@ static void rapl_init_domains(struct rap | |
95 | } | |
96 | } | |
97 | ||
98 | -static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value, | |
99 | +static u64 rapl_unit_xlate(struct rapl_domain *rd, int package, | |
100 | + enum unit_type type, u64 value, | |
101 | int to_raw) | |
102 | { | |
103 | u64 units = 1; | |
104 | struct rapl_package *rp; | |
105 | + u64 scale = 1; | |
106 | ||
107 | rp = find_package_by_id(package); | |
108 | if (!rp) | |
109 | @@ -663,7 +675,12 @@ static u64 rapl_unit_xlate(int package, | |
110 | units = rp->power_unit; | |
111 | break; | |
112 | case ENERGY_UNIT: | |
113 | - units = rp->energy_unit; | |
114 | + scale = ENERGY_UNIT_SCALE; | |
115 | + /* per domain unit takes precedence */ | |
116 | + if (rd && rd->domain_energy_unit) | |
117 | + units = rd->domain_energy_unit; | |
118 | + else | |
119 | + units = rp->energy_unit; | |
120 | break; | |
121 | case TIME_UNIT: | |
122 | return rapl_defaults->compute_time_window(rp, value, to_raw); | |
123 | @@ -673,11 +690,11 @@ static u64 rapl_unit_xlate(int package, | |
124 | }; | |
125 | ||
126 | if (to_raw) | |
127 | - return div64_u64(value, units); | |
128 | + return div64_u64(value, units) * scale; | |
129 | ||
130 | value *= units; | |
131 | ||
132 | - return value; | |
133 | + return div64_u64(value, scale); | |
134 | } | |
135 | ||
136 | /* in the order of enum rapl_primitives */ | |
137 | @@ -773,7 +790,7 @@ static int rapl_read_data_raw(struct rap | |
138 | final = value & rp->mask; | |
139 | final = final >> rp->shift; | |
140 | if (xlate) | |
141 | - *data = rapl_unit_xlate(rd->package_id, rp->unit, final, 0); | |
142 | + *data = rapl_unit_xlate(rd, rd->package_id, rp->unit, final, 0); | |
143 | else | |
144 | *data = final; | |
145 | ||
146 | @@ -799,7 +816,7 @@ static int rapl_write_data_raw(struct ra | |
147 | "failed to read msr 0x%x on cpu %d\n", msr, cpu); | |
148 | return -EIO; | |
149 | } | |
150 | - value = rapl_unit_xlate(rd->package_id, rp->unit, value, 1); | |
151 | + value = rapl_unit_xlate(rd, rd->package_id, rp->unit, value, 1); | |
152 | msr_val &= ~rp->mask; | |
153 | msr_val |= value << rp->shift; | |
154 | if (wrmsrl_safe_on_cpu(cpu, msr, msr_val)) { | |
155 | @@ -818,7 +835,7 @@ static int rapl_write_data_raw(struct ra | |
156 | * calculate units differ on different CPUs. | |
157 | * We convert the units to below format based on CPUs. | |
158 | * i.e. | |
159 | - * energy unit: microJoules : Represented in microJoules by default | |
160 | + * energy unit: picoJoules : Represented in picoJoules by default | |
161 | * power unit : microWatts : Represented in milliWatts by default | |
162 | * time unit : microseconds: Represented in seconds by default | |
163 | */ | |
164 | @@ -834,7 +851,7 @@ static int rapl_check_unit_core(struct r | |
165 | } | |
166 | ||
167 | value = (msr_val & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET; | |
168 | - rp->energy_unit = 1000000 / (1 << value); | |
169 | + rp->energy_unit = ENERGY_UNIT_SCALE * 1000000 / (1 << value); | |
170 | ||
171 | value = (msr_val & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET; | |
172 | rp->power_unit = 1000000 / (1 << value); | |
173 | @@ -842,7 +859,7 @@ static int rapl_check_unit_core(struct r | |
174 | value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET; | |
175 | rp->time_unit = 1000000 / (1 << value); | |
176 | ||
177 | - pr_debug("Core CPU package %d energy=%duJ, time=%dus, power=%duW\n", | |
178 | + pr_debug("Core CPU package %d energy=%dpJ, time=%dus, power=%duW\n", | |
179 | rp->id, rp->energy_unit, rp->time_unit, rp->power_unit); | |
180 | ||
181 | return 0; | |
182 | @@ -859,7 +876,7 @@ static int rapl_check_unit_atom(struct r | |
183 | return -ENODEV; | |
184 | } | |
185 | value = (msr_val & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET; | |
186 | - rp->energy_unit = 1 << value; | |
187 | + rp->energy_unit = ENERGY_UNIT_SCALE * 1 << value; | |
188 | ||
189 | value = (msr_val & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET; | |
190 | rp->power_unit = (1 << value) * 1000; | |
191 | @@ -867,7 +884,7 @@ static int rapl_check_unit_atom(struct r | |
192 | value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET; | |
193 | rp->time_unit = 1000000 / (1 << value); | |
194 | ||
195 | - pr_debug("Atom package %d energy=%duJ, time=%dus, power=%duW\n", | |
196 | + pr_debug("Atom package %d energy=%dpJ, time=%dus, power=%duW\n", | |
197 | rp->id, rp->energy_unit, rp->time_unit, rp->power_unit); | |
198 | ||
199 | return 0; | |
200 | @@ -1017,6 +1034,13 @@ static const struct rapl_defaults rapl_d | |
201 | .compute_time_window = rapl_compute_time_window_core, | |
202 | }; | |
203 | ||
204 | +static const struct rapl_defaults rapl_defaults_hsw_server = { | |
205 | + .check_unit = rapl_check_unit_core, | |
206 | + .set_floor_freq = set_floor_freq_default, | |
207 | + .compute_time_window = rapl_compute_time_window_core, | |
208 | + .dram_domain_energy_unit = 15300, | |
209 | +}; | |
210 | + | |
211 | static const struct rapl_defaults rapl_defaults_atom = { | |
212 | .check_unit = rapl_check_unit_atom, | |
213 | .set_floor_freq = set_floor_freq_atom, | |
214 | @@ -1037,7 +1061,7 @@ static const struct x86_cpu_id rapl_ids[ | |
215 | RAPL_CPU(0x3a, rapl_defaults_core),/* Ivy Bridge */ | |
216 | RAPL_CPU(0x3c, rapl_defaults_core),/* Haswell */ | |
217 | RAPL_CPU(0x3d, rapl_defaults_core),/* Broadwell */ | |
218 | - RAPL_CPU(0x3f, rapl_defaults_core),/* Haswell */ | |
219 | + RAPL_CPU(0x3f, rapl_defaults_hsw_server),/* Haswell servers */ | |
220 | RAPL_CPU(0x45, rapl_defaults_core),/* Haswell ULT */ | |
221 | RAPL_CPU(0x4C, rapl_defaults_atom),/* Braswell */ | |
222 | RAPL_CPU(0x4A, rapl_defaults_atom),/* Tangier */ |