From 7eb1136c27a839a18a4224b970b5a61587e29bd7 Mon Sep 17 00:00:00 2001 From: Tim Wawrzynczak Date: Fri, 29 May 2020 14:10:53 -0600 Subject: dptf: Add support for Passive Policies This patch adds support for emitting the Thermal Relationship Table, as well as _PSV Methods, which together form the basis for DPTF Passive Policies. BUG=b:143539650 TEST=compiles Change-Id: I82e1c9022999b0a2a733aa6cd9c98a850e6f5408 Signed-off-by: Tim Wawrzynczak Reviewed-on: https://review.coreboot.org/c/coreboot/+/41886 Tested-by: build bot (Jenkins) Reviewed-by: Duncan Laurie --- src/acpi/acpigen_dptf.c | 98 +++++++++++++++++++++++++++++++++++++++++ src/drivers/intel/dptf/chip.h | 1 + src/drivers/intel/dptf/dptf.c | 9 ++++ src/include/acpi/acpigen_dptf.h | 23 ++++++++++ 4 files changed, 131 insertions(+) diff --git a/src/acpi/acpigen_dptf.c b/src/acpi/acpigen_dptf.c index 74e91910bb..abd99c1394 100644 --- a/src/acpi/acpigen_dptf.c +++ b/src/acpi/acpigen_dptf.c @@ -9,6 +9,7 @@ /* Defaults */ enum { ART_REVISION = 0, + DEFAULT_PRIORITY = 100, DEFAULT_WEIGHT = 100, DPTF_MAX_ART_THRESHOLDS = 10, }; @@ -19,6 +20,12 @@ static int to_acpi_temp(int deg_c) return deg_c * 10 + 2732; } +/* Converts ms to 1/10th second for ACPI */ +static int to_acpi_time(int ms) +{ + return ms / 100; +} + /* Writes out a 0-argument non-Serialized Method that returns an Integer */ static void write_simple_return_method(const char *name, int value) { @@ -27,6 +34,13 @@ static void write_simple_return_method(const char *name, int value) acpigen_pop_len(); /* Method */ } +/* Writes out 'count' ZEROs in a row */ +static void write_zeros(int count) +{ + for (; count; --count) + acpigen_write_integer(0); +} + /* Return the assigned namestring of any participant */ static const char *namestring_of(enum dptf_participant participant) { @@ -164,3 +178,87 @@ void dptf_write_active_policies(const struct dptf_active_policy *policies, int m write_active_relationship_table(policies, max_count); write_active_cooling_methods(policies, max_count); } + +/* + * This writes out the Thermal Relationship Table, which describes the thermal relationships + * between participants in a thermal zone. This information is used to passively cool (i.e., + * throttle) the Source (source of heat), in order to indirectly cool the Target (temperature + * sensor). + */ +static void write_thermal_relationship_table(const struct dptf_passive_policy *policies, + int max_count) +{ + char *pkg_count; + int i; + + /* Nothing to do */ + if (!max_count || policies[0].source == DPTF_NONE) + return; + + acpigen_write_scope(TOPLEVEL_DPTF_SCOPE); + + /* + * A _TRT Revision (TRTR) of 1 means that the 'Priority' field is an arbitrary priority + * value to be used for this specific relationship. The priority value determines the + * order in which various sources are used in a passive thermal action for a given + * target. + */ + acpigen_write_name_integer("TRTR", 1); + + /* Thermal Relationship Table */ + acpigen_write_method("_TRT", 0); + + /* Return this package */ + acpigen_emit_byte(RETURN_OP); + pkg_count = acpigen_write_package(0); + + for (i = 0; i < max_count; ++i) { + /* Stop writing the table once an entry is empty */ + if (policies[i].source == DPTF_NONE) + break; + + /* Keep track of outer package item count */ + (*pkg_count)++; + + acpigen_write_package(8); + + /* Source, Target, Priority, Sampling Period */ + acpigen_emit_namestring(namestring_of(policies[i].source)); + acpigen_emit_namestring(namestring_of(policies[i].target)); + acpigen_write_integer(DEFAULT_IF_0(policies[i].priority, DEFAULT_PRIORITY)); + acpigen_write_integer(to_acpi_time(policies[i].period)); + + /* Reserved */ + write_zeros(4); + + acpigen_pop_len(); /* Package */ + } + + acpigen_pop_len(); /* Package */ + acpigen_pop_len(); /* Method */ + acpigen_pop_len(); /* Scope */ +} + +/* + * When a temperature sensor measures above its the temperature returned in its _PSV Method, + * DPTF will begin throttling Sources in order to indirectly cool the sensor. + */ +static void write_all_PSV(const struct dptf_passive_policy *policies, int max_count) +{ + int i; + + for (i = 0; i < max_count; ++i) { + if (policies[i].source == DPTF_NONE) + break; + + dptf_write_scope(policies[i].target); + write_simple_return_method("_PSV", to_acpi_temp(policies[i].temp)); + acpigen_pop_len(); /* Scope */ + } +} + +void dptf_write_passive_policies(const struct dptf_passive_policy *policies, int max_count) +{ + write_thermal_relationship_table(policies, max_count); + write_all_PSV(policies, max_count); +} diff --git a/src/drivers/intel/dptf/chip.h b/src/drivers/intel/dptf/chip.h index 730d23ed6b..0cd2ad2063 100644 --- a/src/drivers/intel/dptf/chip.h +++ b/src/drivers/intel/dptf/chip.h @@ -8,6 +8,7 @@ struct drivers_intel_dptf_config { struct { struct dptf_active_policy active[DPTF_MAX_ACTIVE_POLICIES]; + struct dptf_passive_policy passive[DPTF_MAX_PASSIVE_POLICIES]; } policies; }; diff --git a/src/drivers/intel/dptf/dptf.c b/src/drivers/intel/dptf/dptf.c index 20f8d9b4ae..74f481294d 100644 --- a/src/drivers/intel/dptf/dptf.c +++ b/src/drivers/intel/dptf/dptf.c @@ -35,6 +35,12 @@ static bool is_participant_used(const struct drivers_intel_dptf_config *config, if (config->policies.active[i].target == participant) return true; + /* Passive? */ + for (i = 0; i < DPTF_MAX_PASSIVE_POLICIES; ++i) + if (config->policies.passive[i].source == participant || + config->policies.passive[i].target == participant) + return true; + /* Check fan as well (its use is implicit in the Active policy) */ if (participant == DPTF_FAN && config->policies.active[0].target != DPTF_NONE) return true; @@ -55,6 +61,9 @@ static void dptf_fill_ssdt(const struct device *dev) dptf_write_active_policies(config->policies.active, DPTF_MAX_ACTIVE_POLICIES); + dptf_write_passive_policies(config->policies.passive, + DPTF_MAX_PASSIVE_POLICIES); + printk(BIOS_INFO, "\\_SB.DPTF: %s at %s\n", dev->chip_ops->name, dev_path(dev)); } diff --git a/src/include/acpi/acpigen_dptf.h b/src/include/acpi/acpigen_dptf.h index a082b62fd9..214578a4c1 100644 --- a/src/include/acpi/acpigen_dptf.h +++ b/src/include/acpi/acpigen_dptf.h @@ -27,6 +27,7 @@ enum { /* A device can only define _AC0 .. _AC9 i.e. between 0 and 10 Active Cooling Methods */ DPTF_MAX_ACX = 10, DPTF_MAX_ACTIVE_POLICIES = (DPTF_PARTICIPANT_COUNT-1), + DPTF_MAX_PASSIVE_POLICIES = (DPTF_PARTICIPANT_COUNT-1), }; /* Active Policy */ @@ -44,6 +45,20 @@ struct dptf_active_policy { } thresholds[DPTF_MAX_ACX]; }; +/* Passive Policy */ +struct dptf_passive_policy { + /* The device that can be throttled */ + enum dptf_participant source; + /* The device that controls the throttling */ + enum dptf_participant target; + /* How often to check the temperature for required throttling (ms) */ + uint16_t period; + /* The trip point for turning on throttling (degrees C) */ + uint8_t temp; + /* Relative priority between Policies */ + uint8_t priority; +}; + /* * This function provides tables of temperature and corresponding fan or percent. When the * temperature thresholds are met (_AC0 - _AC9), the fan is driven to corresponding percentage @@ -51,6 +66,14 @@ struct dptf_active_policy { */ void dptf_write_active_policies(const struct dptf_active_policy *policies, int max_count); +/* + * This function uses the definition of the passive policies to write out _PSV Methods on all + * participants that define it. It also writes out the Thermal Relationship Table + * (\_SB.DPTF._TRT), which describes various passive (i.e., throttling) policies that can be + * applies when temperature sensors reach the _PSV threshold. + */ +void dptf_write_passive_policies(const struct dptf_passive_policy *policies, int max_count); + /* Helper method to open the scope for a given participant. */ void dptf_write_scope(enum dptf_participant participant); -- cgit v1.2.3