coreboot
coreboot is an Open Source project aimed at replacing the proprietary BIOS found in most computers.
acpigen_dptf.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <acpi/acpigen.h>
4 #include <acpi/acpigen_dptf.h>
5 #include <stdbool.h>
6 #include <stdint.h>
7 
8 /* Defaults */
9 #define DEFAULT_RAW_UNIT "ma"
10 
11 /* DPTF-specific UUIDs */
12 #define DPTF_PASSIVE_POLICY_1_0_UUID "42A441D6-AE6A-462B-A84B-4A8CE79027D3"
13 #define DPTF_CRITICAL_POLICY_UUID "97C68AE7-15FA-499c-B8C9-5DA81D606E0A"
14 #define DPTF_ACTIVE_POLICY_UUID "3A95C389-E4B8-4629-A526-C52C88626BAE"
15 
16 enum {
19  DEFAULT_TRIP_POINT = 0xFFFFFFFFull,
26 };
27 
28 /* Convert degrees C to 1/10 degree Kelvin for ACPI */
29 static int to_acpi_temp(int deg_c)
30 {
31  return deg_c * 10 + 2732;
32 }
33 
34 /* Converts ms to 1/10th second for ACPI */
35 static int to_acpi_time(int ms)
36 {
37  return ms / 100;
38 }
39 
40 /* Writes out a 0-argument non-Serialized Method that returns an Integer */
41 static void write_simple_return_method(const char *name, int value)
42 {
45  acpigen_pop_len(); /* Method */
46 }
47 
48 /* Writes out 'count' ZEROs in a row */
49 static void write_zeros(int count)
50 {
51  for (; count; --count)
53 }
54 
55 /* Return the assigned namestring of any participant */
56 static const char *namestring_of(enum dptf_participant participant)
57 {
58  switch (participant) {
59  case DPTF_CPU:
60  return "TCPU";
61  case DPTF_CHARGER:
62  return "TCHG";
63  case DPTF_FAN:
64  return "TFN1";
65  case DPTF_TEMP_SENSOR_0:
66  return "TSR0";
67  case DPTF_TEMP_SENSOR_1:
68  return "TSR1";
69  case DPTF_TEMP_SENSOR_2:
70  return "TSR2";
71  case DPTF_TEMP_SENSOR_3:
72  return "TSR3";
73  case DPTF_TEMP_SENSOR_4:
74  return "TSR4";
75  case DPTF_TPCH:
76  return "TPCH";
77  case DPTF_POWER:
78  return "TPWR";
79  case DPTF_BATTERY:
80  return "TBAT";
81  default:
82  return "";
83  }
84 }
85 
86 /* Helper to get Scope for participants underneath \_SB.DPTF */
87 static const char *scope_of(enum dptf_participant participant)
88 {
89  static char scope[16];
90 
91  if (participant == DPTF_CPU)
92  snprintf(scope, sizeof(scope), TCPU_SCOPE ".%s", namestring_of(participant));
93  else
94  snprintf(scope, sizeof(scope), DPTF_DEVICE_PATH ".%s",
95  namestring_of(participant));
96 
97  return scope;
98 }
99 
100 /*
101  * Most of the DPTF participants are underneath the \_SB.DPTF scope, so we can just get away
102  * with using the simple namestring for references, but the TCPU has a different scope, so
103  * either an absolute or relative path must be used instead.
104  */
105 static const char *path_of(enum dptf_participant participant)
106 {
107  if (participant == DPTF_CPU)
108  return scope_of(participant);
109  else
110  return namestring_of(participant);
111 }
112 
113 /* Write out scope of a participant */
114 void dptf_write_scope(enum dptf_participant participant)
115 {
116  acpigen_write_scope(scope_of(participant));
117 }
118 
119 /*
120  * This table describes active cooling relationships between the system's fan and the
121  * temperature sensors that it can have an effect on. As ever-increasing temperature thresholds
122  * are crossed (_AC9.._AC0, low to high), the corresponding fan percentages listed in this table
123  * are used to increase the speed of the fan in order to speed up cooling.
124  */
125 static void write_active_relationship_table(const struct dptf_active_policy *policies,
126  int max_count)
127 {
128  char *pkg_count;
129  int i, j;
130 
131  /* Nothing to do */
132  if (!max_count || policies[0].target == DPTF_NONE)
133  return;
134 
136  acpigen_write_method("_ART", 0);
137 
138  /* Return this package */
140 
141  /* Keep track of items added to the package */
142  pkg_count = acpigen_write_package(1); /* The '1' here is for the revision */
144 
145  for (i = 0; i < max_count; ++i) {
146  /*
147  * These have to be filled out from AC0 down to AC9, filling in only as many
148  * as are used. As soon as one isn't filled in, we're done.
149  */
150  if (policies[i].target == DPTF_NONE)
151  break;
152 
153  (*pkg_count)++;
154 
155  /* Source, Target, Percent, Fan % for each of _AC0 ... _AC9 */
158  acpigen_emit_namestring(path_of(policies[i].target));
159  acpigen_write_integer(DEFAULT_IF_0(policies[i].weight, DEFAULT_WEIGHT));
160 
161  /* Write out fan %; corresponds with target's _ACx methods */
162  for (j = 0; j < DPTF_MAX_ART_THRESHOLDS; ++j)
163  acpigen_write_integer(policies[i].thresholds[j].fan_pct);
164 
165  acpigen_pop_len(); /* inner Package */
166  }
167 
168  acpigen_pop_len(); /* outer Package */
169  acpigen_pop_len(); /* Method _ART */
170  acpigen_pop_len(); /* Scope */
171 }
172 
173 /*
174  * _AC9 through _AC0 represent temperature thresholds, in increasing order, defined from _AC0
175  * down, that, when reached, DPTF will activate TFN1 in order to actively cool the temperature
176  * sensor(s). As increasing thresholds are reached, the fan is spun faster.
177  */
178 static void write_active_cooling_methods(const struct dptf_active_policy *policies,
179  int max_count)
180 {
181  char name[5];
182  int i, j;
183 
184  /* Nothing to do */
185  if (!max_count || policies[0].target == DPTF_NONE)
186  return;
187 
188  for (i = 0; i < max_count; ++i) {
189  if (policies[i].target == DPTF_NONE)
190  break;
191 
192  dptf_write_scope(policies[i].target);
193 
194  /* Write out as many of _AC0 through _AC9 that are applicable */
195  for (j = 0; j < DPTF_MAX_ACX; ++j) {
196  if (!policies[i].thresholds[j].temp)
197  break;
198 
199  snprintf(name, sizeof(name), "_AC%1X", j);
201  policies[i].thresholds[j].temp));
202  }
203 
204  acpigen_pop_len(); /* Scope */
205  }
206 }
207 
208 void dptf_write_active_policies(const struct dptf_active_policy *policies, int max_count)
209 {
210  write_active_relationship_table(policies, max_count);
211  write_active_cooling_methods(policies, max_count);
212 }
213 
214 /*
215  * This writes out the Thermal Relationship Table, which describes the thermal relationships
216  * between participants in a thermal zone. This information is used to passively cool (i.e.,
217  * throttle) the Source (source of heat), in order to indirectly cool the Target (temperature
218  * sensor).
219  */
220 static void write_thermal_relationship_table(const struct dptf_passive_policy *policies,
221  int max_count)
222 {
223  char *pkg_count;
224  int i;
225 
226  /* Nothing to do */
227  if (!max_count || policies[0].source == DPTF_NONE)
228  return;
229 
231 
232  /*
233  * A _TRT Revision (TRTR) of 1 means that the 'Priority' field is an arbitrary priority
234  * value to be used for this specific relationship. The priority value determines the
235  * order in which various sources are used in a passive thermal action for a given
236  * target.
237  */
238  acpigen_write_name_integer("TRTR", 1);
239 
240  /* Thermal Relationship Table */
241  acpigen_write_method("_TRT", 0);
242 
243  /* Return this package */
245  pkg_count = acpigen_write_package(0);
246 
247  for (i = 0; i < max_count; ++i) {
248  /* Stop writing the table once an entry is empty */
249  if (policies[i].source == DPTF_NONE)
250  break;
251 
252  /* Keep track of outer package item count */
253  (*pkg_count)++;
254 
256 
257  /* Source, Target, Priority, Sampling Period */
258  acpigen_emit_namestring(path_of(policies[i].source));
259  acpigen_emit_namestring(path_of(policies[i].target));
260  acpigen_write_integer(DEFAULT_IF_0(policies[i].priority, DEFAULT_PRIORITY));
261  acpigen_write_integer(to_acpi_time(policies[i].period));
262 
263  /* Reserved */
264  write_zeros(4);
265 
266  acpigen_pop_len(); /* Package */
267  }
268 
269  acpigen_pop_len(); /* Package */
270  acpigen_pop_len(); /* Method */
271  acpigen_pop_len(); /* Scope */
272 }
273 
274 /*
275  * When a temperature sensor measures above its the temperature returned in its _PSV Method,
276  * DPTF will begin throttling Sources in order to indirectly cool the sensor.
277  */
278 static void write_all_PSV(const struct dptf_passive_policy *policies, int max_count)
279 {
280  int i;
281 
282  for (i = 0; i < max_count; ++i) {
283  if (policies[i].source == DPTF_NONE)
284  break;
285 
286  dptf_write_scope(policies[i].target);
287  write_simple_return_method("_PSV", to_acpi_temp(policies[i].temp));
288  acpigen_pop_len(); /* Scope */
289  }
290 }
291 
292 void dptf_write_passive_policies(const struct dptf_passive_policy *policies, int max_count)
293 {
294  write_thermal_relationship_table(policies, max_count);
295  write_all_PSV(policies, max_count);
296 }
297 
298 void dptf_write_critical_policies(const struct dptf_critical_policy *policies, int max_count)
299 {
300  int i;
301 
302  for (i = 0; i < max_count; ++i) {
303  if (policies[i].source == DPTF_NONE)
304  break;
305 
306  dptf_write_scope(policies[i].source);
307 
308  /* Choose _CRT or _HOT */
310  "_CRT" : "_HOT", to_acpi_temp(policies[i].temp));
311 
312  acpigen_pop_len(); /* Scope */
313  }
314 }
315 
316 void dptf_write_charger_perf(const struct dptf_charger_perf *states, int max_count)
317 {
318  char *pkg_count;
319  int i;
320 
321  if (!max_count || !states[0].control)
322  return;
323 
325 
326  /* PPSS - Participant Performance Supported States */
327  acpigen_write_method("PPSS", 0);
329 
330  pkg_count = acpigen_write_package(0);
331  for (i = 0; i < max_count; ++i) {
332  if (!states[i].control)
333  break;
334 
335  (*pkg_count)++;
336 
337  /*
338  * 0, 0, 0, 0, # Reserved
339  * Control, Raw Performance, Raw Unit, 0 # Reserved
340  */
342  write_zeros(4);
343  acpigen_write_integer(states[i].control);
344  acpigen_write_integer(states[i].raw_perf);
347  acpigen_pop_len(); /* inner Package */
348  }
349 
350  acpigen_pop_len(); /* outer Package */
351  acpigen_pop_len(); /* Method PPSS */
352  acpigen_pop_len(); /* Scope */
353 }
354 
355 void dptf_write_fan_perf(const struct dptf_fan_perf *states, int max_count)
356 {
357  char *pkg_count;
358  int i;
359 
360  if (!max_count || !states[0].percent)
361  return;
362 
364 
365  /* _FPS - Fan Performance States */
366  acpigen_write_name("_FPS");
367  pkg_count = acpigen_write_package(1); /* 1 for Revision */
368  acpigen_write_integer(FPS_REVISION); /* revision */
369 
370  for (i = 0; i < max_count; ++i) {
371  /*
372  * Some _FPS tables do include a last entry where Percent is 0, but Power is
373  * called out, so this table is finished when both are zero.
374  */
375  if (!states[i].percent && !states[i].power)
376  break;
377 
378  (*pkg_count)++;
380  acpigen_write_integer(states[i].percent);
382  acpigen_write_integer(states[i].speed);
383  acpigen_write_integer(states[i].noise_level);
384  acpigen_write_integer(states[i].power);
385  acpigen_pop_len(); /* inner Package */
386  }
387 
388  acpigen_pop_len(); /* Package */
389  acpigen_pop_len(); /* Scope */
390 }
391 
393 {
394  char *pkg_count;
395 
396  /* Nothing to do */
397  if (!limits->pl1.min_power && !limits->pl2.min_power)
398  return;
399 
401  acpigen_write_method("PPCC", 0);
402 
403  pkg_count = acpigen_write_package(1); /* 1 for the Revision */
404  acpigen_write_integer(PPCC_REVISION); /* revision */
405 
406  if (limits->pl1.min_power) {
407  (*pkg_count)++;
410  acpigen_write_integer(limits->pl1.min_power);
411  acpigen_write_integer(limits->pl1.max_power);
412  acpigen_write_integer(limits->pl1.time_window_min);
413  acpigen_write_integer(limits->pl1.time_window_max);
414  acpigen_write_integer(limits->pl1.granularity);
415  acpigen_pop_len(); /* inner Package */
416  }
417 
418  if (limits->pl2.min_power) {
419  (*pkg_count)++;
422  acpigen_write_integer(limits->pl2.min_power);
423  acpigen_write_integer(limits->pl2.max_power);
424  acpigen_write_integer(limits->pl2.time_window_min);
425  acpigen_write_integer(limits->pl2.time_window_max);
426  acpigen_write_integer(limits->pl2.granularity);
427  acpigen_pop_len(); /* inner Package */
428  }
429 
430  acpigen_pop_len(); /* outer Package */
431  acpigen_pop_len(); /* Method */
432  acpigen_pop_len(); /* Scope */
433 }
434 
435 void dptf_write_STR(const char *str)
436 {
437  if (!str)
438  return;
439 
440  acpigen_write_name_string("_STR", str);
441 }
442 
443 void dptf_write_fan_options(bool fine_grained, int step_size, bool low_speed_notify)
444 {
445  acpigen_write_name("_FIF");
447 
448  acpigen_write_integer(0); /* Revision */
449  acpigen_write_integer(fine_grained);
450  acpigen_write_integer(step_size);
451  acpigen_write_integer(low_speed_notify);
452  acpigen_pop_len(); /* Package */
453 }
454 
456 {
457  if (!hysteresis)
458  return;
459 
460  acpigen_write_name_integer("GTSH", hysteresis);
461 }
462 
463 void dptf_write_enabled_policies(const struct dptf_active_policy *active_policies,
464  int active_count,
465  const struct dptf_passive_policy *passive_policies,
466  int passive_count,
467  const struct dptf_critical_policy *critical_policies,
468  int critical_count)
469 {
470  bool is_active_used;
471  bool is_passive_used;
472  bool is_critical_used;
473  int pkg_count;
474 
475  is_active_used = (active_count && active_policies[0].target != DPTF_NONE);
476  is_passive_used = (passive_count && passive_policies[0].target != DPTF_NONE);
477  is_critical_used = (critical_count && critical_policies[0].source != DPTF_NONE);
478  pkg_count = is_active_used + is_passive_used + is_critical_used;
479 
480  if (!pkg_count)
481  return;
482 
484  acpigen_write_name("IDSP");
485  acpigen_write_package(pkg_count);
486 
487  if (is_active_used)
489 
490  if (is_passive_used)
492 
493  if (is_critical_used)
495 
496  acpigen_pop_len(); /* Package */
497  acpigen_pop_len(); /* Scope */
498 }
void acpigen_emit_namestring(const char *namepath)
Definition: acpigen.c:275
void acpigen_write_return_integer(uint64_t arg)
Definition: acpigen.c:1583
void acpigen_write_integer(uint64_t data)
Definition: acpigen.c:136
void acpigen_write_uuid(const char *uuid)
Definition: acpigen.c:1277
void acpigen_pop_len(void)
Definition: acpigen.c:37
void acpigen_write_scope(const char *name)
Definition: acpigen.c:326
char * acpigen_write_package(int nr_el)
Definition: acpigen.c:86
void acpigen_write_name_integer(const char *name, uint64_t val)
Definition: acpigen.c:170
void acpigen_emit_byte(unsigned char b)
Definition: acpigen.c:61
void acpigen_write_string(const char *string)
Definition: acpigen.c:210
void acpigen_write_method(const char *name, int nargs)
Definition: acpigen.c:758
void acpigen_write_name(const char *name)
Definition: acpigen.c:320
void acpigen_write_name_string(const char *name, const char *string)
Definition: acpigen.c:176
void dptf_write_enabled_policies(const struct dptf_active_policy *active_policies, int active_count, const struct dptf_passive_policy *passive_policies, int passive_count, const struct dptf_critical_policy *critical_policies, int critical_count)
Definition: acpigen_dptf.c:463
static int to_acpi_temp(int deg_c)
Definition: acpigen_dptf.c:29
@ DEFAULT_WEIGHT
Definition: acpigen_dptf.c:20
@ FPS_REVISION
Definition: acpigen_dptf.c:22
@ RAPL_PL2_INDEX
Definition: acpigen_dptf.c:25
@ ART_REVISION
Definition: acpigen_dptf.c:17
@ PPCC_REVISION
Definition: acpigen_dptf.c:23
@ RAPL_PL1_INDEX
Definition: acpigen_dptf.c:24
@ DEFAULT_PRIORITY
Definition: acpigen_dptf.c:18
@ DEFAULT_TRIP_POINT
Definition: acpigen_dptf.c:19
@ DPTF_MAX_ART_THRESHOLDS
Definition: acpigen_dptf.c:21
#define DPTF_CRITICAL_POLICY_UUID
Definition: acpigen_dptf.c:13
static const char * namestring_of(enum dptf_participant participant)
Definition: acpigen_dptf.c:56
void dptf_write_active_policies(const struct dptf_active_policy *policies, int max_count)
Definition: acpigen_dptf.c:208
void dptf_write_STR(const char *str)
Definition: acpigen_dptf.c:435
static int to_acpi_time(int ms)
Definition: acpigen_dptf.c:35
static void write_thermal_relationship_table(const struct dptf_passive_policy *policies, int max_count)
Definition: acpigen_dptf.c:220
void dptf_write_fan_options(bool fine_grained, int step_size, bool low_speed_notify)
Definition: acpigen_dptf.c:443
#define DPTF_PASSIVE_POLICY_1_0_UUID
Definition: acpigen_dptf.c:12
static void write_simple_return_method(const char *name, int value)
Definition: acpigen_dptf.c:41
static void write_all_PSV(const struct dptf_passive_policy *policies, int max_count)
Definition: acpigen_dptf.c:278
void dptf_write_passive_policies(const struct dptf_passive_policy *policies, int max_count)
Definition: acpigen_dptf.c:292
static const char * scope_of(enum dptf_participant participant)
Definition: acpigen_dptf.c:87
void dptf_write_tsr_hysteresis(uint8_t hysteresis)
Definition: acpigen_dptf.c:455
static void write_zeros(int count)
Definition: acpigen_dptf.c:49
void dptf_write_fan_perf(const struct dptf_fan_perf *states, int max_count)
Definition: acpigen_dptf.c:355
void dptf_write_power_limits(const struct dptf_power_limits *limits)
Definition: acpigen_dptf.c:392
static const char * path_of(enum dptf_participant participant)
Definition: acpigen_dptf.c:105
#define DPTF_ACTIVE_POLICY_UUID
Definition: acpigen_dptf.c:14
void dptf_write_scope(enum dptf_participant participant)
Definition: acpigen_dptf.c:114
void dptf_write_charger_perf(const struct dptf_charger_perf *states, int max_count)
Definition: acpigen_dptf.c:316
static void write_active_relationship_table(const struct dptf_active_policy *policies, int max_count)
Definition: acpigen_dptf.c:125
#define DEFAULT_RAW_UNIT
Definition: acpigen_dptf.c:9
void dptf_write_critical_policies(const struct dptf_critical_policy *policies, int max_count)
Definition: acpigen_dptf.c:298
static void write_active_cooling_methods(const struct dptf_active_policy *policies, int max_count)
Definition: acpigen_dptf.c:178
@ DPTF_CRITICAL_SHUTDOWN
Definition: acpigen_dptf.h:85
@ DPTF_MAX_ACX
Definition: acpigen_dptf.h:37
dptf_participant
Definition: acpigen_dptf.h:18
@ DPTF_TEMP_SENSOR_0
Definition: acpigen_dptf.h:23
@ DPTF_TPCH
Definition: acpigen_dptf.h:28
@ DPTF_TEMP_SENSOR_4
Definition: acpigen_dptf.h:27
@ DPTF_TEMP_SENSOR_2
Definition: acpigen_dptf.h:25
@ DPTF_POWER
Definition: acpigen_dptf.h:29
@ DPTF_TEMP_SENSOR_3
Definition: acpigen_dptf.h:26
@ DPTF_CHARGER
Definition: acpigen_dptf.h:21
@ DPTF_NONE
Definition: acpigen_dptf.h:19
@ DPTF_FAN
Definition: acpigen_dptf.h:22
@ DPTF_BATTERY
Definition: acpigen_dptf.h:30
@ DPTF_CPU
Definition: acpigen_dptf.h:20
@ DPTF_TEMP_SENSOR_1
Definition: acpigen_dptf.h:24
#define TCPU_SCOPE
Definition: acpigen_dptf.h:15
#define DEFAULT_IF_0(thing, default_)
Definition: acpigen_dptf.h:11
#define DPTF_DEVICE_PATH
Definition: acpigen_dptf.h:14
pte_t value
Definition: mmu.c:91
const char * name
Definition: mmu.c:92
@ RETURN_OP
Definition: acpigen.h:146
unsigned int type
Definition: edid.c:57
const struct cpu_power_limits limits[]
Definition: ramstage.c:11
static const struct pnpconfig power[]
Definition: pnpconfig.c:14
unsigned char uint8_t
Definition: stdint.h:8
enum dptf_participant target
Definition: acpigen_dptf.h:56
enum dptf_participant source
Definition: acpigen_dptf.h:91
enum dptf_participant target
Definition: acpigen_dptf.h:73
#define count
int snprintf(char *buf, size_t size, const char *fmt,...)
Note: This file is only for POSIX compatibility, and is meant to be chain-included via string....
Definition: vsprintf.c:35