diff -Nru thermald-2.4.9/debian/changelog thermald-2.4.9/debian/changelog --- thermald-2.4.9/debian/changelog 2022-03-23 17:31:22.000000000 +0800 +++ thermald-2.4.9/debian/changelog 2022-07-21 12:30:55.000000000 +0800 @@ -1,3 +1,9 @@ +thermald (2.4.9-2ubuntu1) unstable; urgency=medium + + * Support of new thermal table for Alder Lake (LP: #1983235) + + -- Koba Ko Thu, 21 Jul 2022 12:30:55 +0800 + thermald (2.4.9-1) unstable; urgency=medium * sync to thermald 2.4.9 (Closes: #1006819) diff -Nru thermald-2.4.9/debian/control thermald-2.4.9/debian/control --- thermald-2.4.9/debian/control 2022-02-24 02:14:12.000000000 +0800 +++ thermald-2.4.9/debian/control 2022-07-21 12:30:55.000000000 +0800 @@ -2,7 +2,7 @@ Rules-Requires-Root: no Section: admin Priority: optional -Maintainer: Colin Ian King +Maintainer: Koba Ko Standards-Version: 4.1.2 Build-Depends: debhelper (>= 13), debhelper-compat (=13), diff -Nru thermald-2.4.9/debian/patches/0001-Fixed-enumeration-of-cpu-thermal-sensors.patch thermald-2.4.9/debian/patches/0001-Fixed-enumeration-of-cpu-thermal-sensors.patch --- thermald-2.4.9/debian/patches/0001-Fixed-enumeration-of-cpu-thermal-sensors.patch 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/patches/0001-Fixed-enumeration-of-cpu-thermal-sensors.patch 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1,97 @@ +From df8ac025d22e51c237c8ebe2aa25bf672ec04edb Mon Sep 17 00:00:00 2001 +From: SSchloetzer +Date: Thu, 30 Jun 2022 16:46:48 +0200 +Subject: [PATCH] Fixed enumeration of cpu thermal sensors + +The current code can can just enumerate 4 hwmon sensors, which +is not enough for any modern systems with more than 4 logica +CPUs. + +Instead of using a mask traverse full directory and look for +each directory for coretemp and add. + +Ref: +https://github.com/intel/thermal_daemon/issues/356 +--- + src/thd_engine_default.cpp | 41 ++++++++++++++++++++++---------------- + 1 file changed, 24 insertions(+), 17 deletions(-) + +diff --git a/src/thd_engine_default.cpp b/src/thd_engine_default.cpp +index ce0e76b..153fab2 100644 +--- a/src/thd_engine_default.cpp ++++ b/src/thd_engine_default.cpp +@@ -22,6 +22,7 @@ + * + */ + ++#include + #include + #include + #include +@@ -94,7 +95,6 @@ int cthd_engine_default::read_thermal_sensors() { + int index; + DIR *dir; + struct dirent *entry; +- int sensor_mask = 0x0f; + cthd_sensor *sensor; + const std::string base_path[] = { "/sys/devices/platform/", + "/sys/class/hwmon/" }; +@@ -147,22 +147,30 @@ int cthd_engine_default::read_thermal_sensors() { + if (name != "coretemp") + continue; + +- int cnt = 0; +- unsigned int mask = 0x1; +- do { +- if (sensor_mask & mask) { +- std::stringstream temp_input_str; +- std::string path = base_path[i] + entry->d_name +- + "/"; +- csys_fs dts_sysfs(path.c_str()); +- temp_input_str << "temp" << cnt << "_input"; +- if (dts_sysfs.exists(temp_input_str.str())) { ++ std::string temp_dir_path = base_path[i] + entry->d_name ++ + "/"; ++ DIR *temp_dir = nullptr; ++ struct dirent *temp_dir_entry = nullptr; ++ int len_temp_dir_entry = 0; ++ int len_input = strlen("_input"); ++ ++ if ((temp_dir = opendir(temp_dir_path.c_str())) != NULL) { ++ while ((temp_dir_entry = readdir(temp_dir)) != NULL) { ++ len_temp_dir_entry = strlen(temp_dir_entry->d_name); ++ if ((len_temp_dir_entry >= len_input ++ && !strcmp( ++ temp_dir_entry->d_name ++ + len_temp_dir_entry ++ - len_input, "_input")) ++ && (!strncmp(temp_dir_entry->d_name, "temp", ++ strlen("temp")))) { ++ + cthd_sensor *sensor = new cthd_sensor(index, +- base_path[i] + entry->d_name + "/" +- + temp_input_str.str(), "hwmon", +- SENSOR_TYPE_RAW); ++ temp_dir_path + temp_dir_entry->d_name, ++ "hwmon", SENSOR_TYPE_RAW); + if (sensor->sensor_update() != THD_SUCCESS) { + delete sensor; ++ closedir(temp_dir); + closedir(dir); + return THD_ERROR; + } +@@ -170,9 +178,8 @@ int cthd_engine_default::read_thermal_sensors() { + ++index; + } + } +- mask = (mask << 1); +- cnt++; +- } while (mask != 0); ++ closedir(temp_dir); ++ } + } + } + closedir(dir); +-- +2.34.1 + diff -Nru thermald-2.4.9/debian/patches/0002-Parse-ITMT-Table.patch thermald-2.4.9/debian/patches/0002-Parse-ITMT-Table.patch --- thermald-2.4.9/debian/patches/0002-Parse-ITMT-Table.patch 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/patches/0002-Parse-ITMT-Table.patch 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1,144 @@ +From 0dd53a0b2f2e9507e54ced9982c1804323642248 Mon Sep 17 00:00:00 2001 +From: Srinivas Pandruvada +Date: Mon, 27 Jun 2022 15:15:16 -0700 +Subject: [PATCH 2/5] Parse ITMT Table + +Some of the newer device PSVT is replaced with ITMT table. Here +Adaptive Action table will point to ITMT table instead of PSVT. + +Parse ITMT, if present while parsing other adaptive tables. +--- + src/thd_engine_adaptive.cpp | 54 +++++++++++++++++++++++++++++++++++++ + src/thd_engine_adaptive.h | 16 +++++++++++ + 2 files changed, 70 insertions(+) + +diff --git a/src/thd_engine_adaptive.cpp b/src/thd_engine_adaptive.cpp +index 361a44f..2a8eabc 100644 +--- a/src/thd_engine_adaptive.cpp ++++ b/src/thd_engine_adaptive.cpp +@@ -622,6 +622,52 @@ struct psvt* cthd_engine_adaptive::find_def_psvt() { + return NULL; + } + ++int cthd_engine_adaptive::parse_itmt(char *name, char *buf, int len) { ++ int offset = 0; ++ int version = get_uint64(buf, &offset); ++ struct itmt itmt; ++ ++ thd_log_debug(" ITMT version %d %s\n", (int) version, name); ++ ++ if (name == NULL) ++ itmt.name = "Default"; ++ else ++ itmt.name = name; ++ ++ while (offset < len) { ++ struct itmt_entry itmt_entry; ++ ++ itmt_entry.target = get_string(buf, &offset); ++ itmt_entry.trip_point = get_uint64(buf, &offset); ++ itmt_entry.pl1_min = get_string(buf, &offset); ++ itmt_entry.pl1_max = get_string(buf, &offset); ++ itmt_entry.unused = get_string(buf, &offset); ++ offset += 12; ++ ++ itmt.itmt_entries.push_back(itmt_entry); ++ } ++ ++ itmts.push_back(itmt); ++ ++ return 0; ++} ++ ++void cthd_engine_adaptive::dump_itmt() { ++ thd_log_info("..itmt dump begin.. \n"); ++ for (unsigned int i = 0; i < itmts.size(); ++i) { ++ std::vector itmt = itmts[i].itmt_entries; ++ ++ thd_log_info("Name :%s\n", itmts[i].name.c_str()); ++ for (unsigned int j = 0; j < itmt.size(); ++j) { ++ thd_log_info("\t target:%s trip_temp:%d pl1_min:%s pl1.max:%s\n", ++ itmt[j].target.c_str(), ++ DECI_KELVIN_TO_CELSIUS(itmt[j].trip_point), ++ itmt[j].pl1_min.c_str(), itmt[j].pl1_max.c_str()); ++ } ++ } ++ thd_log_info("itmt dump end\n"); ++} ++ + // From Common/esif_sdk_iface_esif.h: + #define ESIF_SERVICE_CONFIG_COMPRESSED 0x40000000/* Payload is Compressed */ + // From Common/esif_sdk.h +@@ -757,6 +803,13 @@ int cthd_engine_adaptive::parse_gddv_key(char *buf, int size, int *end_offset) { + parse_apat(val, vallength); + } + ++ if (type && strcmp(type, "itmt") == 0) { ++ if (point == NULL) ++ parse_itmt(name, val, vallength); ++ else ++ parse_itmt(point, val, vallength); ++ } ++ + delete[] (key); + delete[] (val); + +@@ -1714,6 +1767,7 @@ int cthd_engine_adaptive::thd_engine_init(bool ignore_cpuid_check, bool adaptive + + dump_ppcc(); + dump_psvt(); ++ dump_itmt(); + dump_apat(); + dump_apct(); + +diff --git a/src/thd_engine_adaptive.h b/src/thd_engine_adaptive.h +index 4086fbe..2d38b95 100644 +--- a/src/thd_engine_adaptive.h ++++ b/src/thd_engine_adaptive.h +@@ -145,6 +145,19 @@ struct psvt { + std::vector psvs; + }; + ++struct itmt_entry { ++ std::string target; ++ int trip_point; ++ std::string pl1_min; ++ std::string pl1_max; ++ std::string unused; ++}; ++ ++struct itmt { ++ std::string name; ++ std::vector itmt_entries; ++}; ++ + class cthd_engine_adaptive: public cthd_engine_default { + protected: + std::vector ppccs; +@@ -152,6 +165,7 @@ protected: + std::vector custom_conditions; + std::vector targets; + std::vector psvts; ++ std::vector itmts; + std::string int3400_path; + UpClient *upower_client; + GDBusProxy *power_profiles_daemon; +@@ -179,6 +193,7 @@ protected: + int parse_apct(char *apct, int len); + int parse_ppcc(char *name, char *ppcc, int len); + int parse_psvt(char *name, char *psvt, int len); ++ int parse_itmt(char *name, char *itmt, int len); + int handle_compressed_gddv(char *buf, int size); + int parse_gddv_key(char *buf, int size, int *end_offset); + int parse_gddv(char *buf, int size, int *end_offset); +@@ -209,6 +224,7 @@ protected: + void dump_apct(); + void dump_ppcc(); + void dump_psvt(); ++ void dump_itmt(); + struct psvt *find_def_psvt(); + + public: +-- +2.34.1 + diff -Nru thermald-2.4.9/debian/patches/0003-Add-capability-for-min-max-per-trip.patch thermald-2.4.9/debian/patches/0003-Add-capability-for-min-max-per-trip.patch --- thermald-2.4.9/debian/patches/0003-Add-capability-for-min-max-per-trip.patch 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/patches/0003-Add-capability-for-min-max-per-trip.patch 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1,108 @@ +From d7360035dfa823820c89f914ae5735557dd7a023 Mon Sep 17 00:00:00 2001 +From: Srinivas Pandruvada +Date: Mon, 27 Jun 2022 15:22:32 -0700 +Subject: [PATCH 3/5] Add capability for min max per trip + +A trip currenly have +- A threshold temperature +- Sampling period +- Influence +- Target state + +Add also possible minimum and maximum state. This can be used +when target state is missing and minimum and maximum state +depends on cooling device minimum and maximum. With this +capability cooling device minimum and maximum state can be +limited per trip. +--- + src/thd_engine_adaptive.cpp | 2 +- + src/thd_trip_point.cpp | 11 ++++++++++- + src/thd_trip_point.h | 12 +++++++++++- + 3 files changed, 22 insertions(+), 3 deletions(-) + +diff --git a/src/thd_engine_adaptive.cpp b/src/thd_engine_adaptive.cpp +index 2a8eabc..53837e4 100644 +--- a/src/thd_engine_adaptive.cpp ++++ b/src/thd_engine_adaptive.cpp +@@ -1317,7 +1317,7 @@ int cthd_engine_adaptive::install_passive(struct psv *psv) { + psv->sample_period / 10, + target_state ? 1 : 0, + target_state, +- NULL); ++ NULL, 0, 0, 0); + zone->add_trip(trip_pt, 1); + zone->zone_cdev_set_binded(); + zone->set_zone_active(); +diff --git a/src/thd_trip_point.cpp b/src/thd_trip_point.cpp +index 0bb8bea..d1d33a3 100644 +--- a/src/thd_trip_point.cpp ++++ b/src/thd_trip_point.cpp +@@ -328,7 +328,8 @@ bool cthd_trip_point::thd_trip_point_check(int id, unsigned int read_temp, + + void cthd_trip_point::thd_trip_point_add_cdev(cthd_cdev &cdev, int influence, + int sampling_period, int target_state_valid, int target_state, +- pid_param_t *pid_param) { ++ pid_param_t *pid_param, int min_max_valid, int min_state, ++ int max_state) { + trip_pt_cdev_t thd_cdev; + thd_cdev.cdev = &cdev; + thd_cdev.influence = influence; +@@ -336,6 +337,14 @@ void cthd_trip_point::thd_trip_point_add_cdev(cthd_cdev &cdev, int influence, + thd_cdev.last_op_time = 0; + thd_cdev.target_state_valid = target_state_valid; + thd_cdev.target_state = target_state; ++ ++ thd_cdev.min_max_valid = min_max_valid; ++ ++ thd_log_info("min:%d max:%d\n", min_state, max_state); ++ if (min_max_valid) { ++ thd_cdev.min_state = min_state; ++ thd_cdev.max_state = max_state; ++ } + if (pid_param && pid_param->valid) { + thd_log_info("pid valid %f:%f:%f\n", pid_param->kp, pid_param->ki, + pid_param->kd); +diff --git a/src/thd_trip_point.h b/src/thd_trip_point.h +index e816251..cb46426 100644 +--- a/src/thd_trip_point.h ++++ b/src/thd_trip_point.h +@@ -62,6 +62,9 @@ typedef struct { + int target_state; + pid_param_t pid_param; + cthd_pid pid; ++ int min_max_valid; ++ int min_state; ++ int max_state; + } trip_pt_cdev_t; + + #define DEFAULT_SENSOR_ID 0xFFFF +@@ -112,7 +115,8 @@ public: + void thd_trip_point_add_cdev(cthd_cdev &cdev, int influence, + int sampling_period = 0, int target_state_valid = 0, + int target_state = +- TRIP_PT_INVALID_TARGET_STATE, pid_param_t *pid_param = NULL); ++ TRIP_PT_INVALID_TARGET_STATE, pid_param_t *pid_param = NULL, ++ int min_max_valid = 0, int min_state = 0, int max_state = 0); + + void delete_cdevs() { + cdevs.clear(); +@@ -254,10 +258,16 @@ public: + else + thd_log_info("\t target_state:not defined\n"); + ++ thd_log_info("min_max %d\n", cdevs[i].min_max_valid); ++ + if (cdevs[i].pid_param.valid) + thd_log_info("\t pid: kp=%g ki=%g kd=%g\n", + cdevs[i].pid_param.kp, cdevs[i].pid_param.ki, + cdevs[i].pid_param.kd); ++ if (cdevs[i].min_max_valid) { ++ thd_log_info("\t min_state:%d\n", cdevs[i].min_state); ++ thd_log_info("\t max_state:%d\n", cdevs[i].max_state); ++ } + } + } + }; +-- +2.34.1 + diff -Nru thermald-2.4.9/debian/patches/0004-Install-ITMT-target.patch thermald-2.4.9/debian/patches/0004-Install-ITMT-target.patch --- thermald-2.4.9/debian/patches/0004-Install-ITMT-target.patch 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/patches/0004-Install-ITMT-target.patch 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1,203 @@ +From abafe7611425a69cff9efe15d7fc67addd23dd5c Mon Sep 17 00:00:00 2001 +From: Srinivas Pandruvada +Date: Mon, 27 Jun 2022 15:37:55 -0700 +Subject: [PATCH 4/5] Install ITMT target + +Similar to PSVT install, implement ITMT install. When APAT calls +for ITMT instead of ITMT install ITMT target. The install portion +is much simpler. There can be only one trip in a ITMT entry so +no need to consolidate. + +An ITMT entry will have a trip, min and max value for RAPL PL1. +So create trip with this information and bind RAPL cooling device +to this. +--- + src/thd_engine_adaptive.cpp | 147 +++++++++++++++++++++++++++++++++++- + src/thd_engine_adaptive.h | 3 + + 2 files changed, 149 insertions(+), 1 deletion(-) + +diff --git a/src/thd_engine_adaptive.cpp b/src/thd_engine_adaptive.cpp +index 53837e4..3ecf61c 100644 +--- a/src/thd_engine_adaptive.cpp ++++ b/src/thd_engine_adaptive.cpp +@@ -1228,6 +1228,16 @@ struct psvt* cthd_engine_adaptive::find_psvt(std::string name) { + return NULL; + } + ++struct itmt* cthd_engine_adaptive::find_itmt(std::string name) { ++ for (int i = 0; i < (int) itmts.size(); i++) { ++ if (!strcasecmp(itmts[i].name.c_str(), name.c_str())) { ++ return &itmts[i]; ++ } ++ } ++ ++ return NULL; ++} ++ + int cthd_engine_adaptive::install_passive(struct psv *psv) { + std::string psv_zone; + +@@ -1426,9 +1436,144 @@ void cthd_engine_adaptive::psvt_consolidate() + } + } + ++#define DEFAULT_SAMPLE_TIME_SEC 5 ++ ++int cthd_engine_adaptive::install_itmt(struct itmt_entry *itmt_entry) { ++ std::string itmt_zone; ++ ++ size_t pos = itmt_entry->target.find_last_of("."); ++ if (pos == std::string::npos) ++ itmt_zone = itmt_entry->target; ++ else ++ itmt_zone = itmt_entry->target.substr(pos + 1); ++ ++ while (itmt_zone.back() == '_') { ++ itmt_zone.pop_back(); ++ } ++ ++ cthd_zone *zone = search_zone(itmt_zone); ++ if (!zone) { ++ if (!itmt_zone.compare(0, 4, "B0D4")) { ++ itmt_zone = "TCPU"; ++ zone = search_zone(itmt_zone); ++ } ++ ++ if (!zone) { ++ if (!itmt_zone.compare(0, 4, "TCPU")) { ++ itmt_zone = "B0D4"; ++ zone = search_zone(itmt_zone); ++ } ++ if (!zone) { ++ thd_log_warn("Unable to find a zone for %s\n", ++ itmt_zone.c_str()); ++ return THD_ERROR; ++ } ++ } ++ } ++ ++ cthd_cdev *cdev = search_cdev("rapl_controller_mmio"); ++ ++ if (!cdev) { ++ return THD_ERROR; ++ } ++ ++ cthd_sensor *sensor = search_sensor(itmt_zone); ++ if (!sensor) { ++ thd_log_warn("Unable to find a sensor for %s\n", itmt_zone.c_str()); ++ return THD_ERROR; ++ } ++ ++ int temp = (itmt_entry->trip_point - 2732) * 100; ++ int min_state = 0, max_state = 0; ++ ++ if (itmt_entry->pl1_max.length()) { ++ if (!strncasecmp(itmt_entry->pl1_max.c_str(), "MAX", 3)) { ++ max_state = TRIP_PT_INVALID_TARGET_STATE; ++ } else if (!strncasecmp(itmt_entry->pl1_max.c_str(), "MIN", 3)) { ++ max_state = 0; ++ } else { ++ std::istringstream buffer(itmt_entry->pl1_max); ++ buffer >> max_state; ++ max_state *= 1000; ++ } ++ } ++ ++ if (itmt_entry->pl1_min.length()) { ++ if (!strncasecmp(itmt_entry->pl1_min.c_str(), "MAX", 3)) { ++ min_state = TRIP_PT_INVALID_TARGET_STATE; ++ } else if (!strncasecmp(itmt_entry->pl1_min.c_str(), "MIN", 3)) { ++ min_state = 0; ++ } else { ++ std::istringstream buffer(itmt_entry->pl1_min); ++ buffer >> min_state; ++ min_state *= 1000; ++ } ++ } ++ ++ cthd_trip_point trip_pt(zone->get_trip_count(), PASSIVE, temp, 0, ++ zone->get_zone_index(), sensor->get_index(), SEQUENTIAL); ++ ++ trip_pt.thd_trip_point_add_cdev(*cdev, cthd_trip_point::default_influence, ++ DEFAULT_SAMPLE_TIME_SEC, 0, 0, ++ NULL, 1, max_state, min_state); ++ ++ zone->add_trip(trip_pt, 1); ++ zone->zone_cdev_set_binded(); ++ zone->set_zone_active(); ++ ++ return 0; ++} ++ ++int cthd_engine_adaptive::set_itmt_target(struct adaptive_target target) { ++ struct itmt *itmt; ++ ++ thd_log_info("set_int3400 ITMT target %s\n", target.argument.c_str()); ++ ++ itmt = find_itmt(target.argument); ++ if (!itmt) { ++ return THD_ERROR; ++ } ++ ++ for (unsigned int i = 0; i < zones.size(); ++i) { ++ cthd_zone *_zone = zones[i]; ++ ++ // This is only for debug to plot power, so keep ++ if (_zone->get_zone_type() == "rapl_pkg_power") ++ continue; ++ ++ _zone->zone_reset(1); ++ _zone->trip_delete_all(); ++ ++ if (_zone->zone_active_status()) ++ _zone->set_zone_inactive(); ++ } ++ ++ for (int i = 0; i < (int) itmt->itmt_entries.size(); i++) { ++ install_itmt(&itmt->itmt_entries[i]); ++ } ++ ++ thd_log_info("\n\n ZONE DUMP BEGIN\n"); ++ int new_zone_count = 0; ++ for (unsigned int i = 0; i < zones.size(); ++i) { ++ zones[i]->zone_dump(); ++ if (zones[i]->zone_active_status()) ++ ++new_zone_count; ++ } ++ thd_log_info("\n\n ZONE DUMP END\n"); ++ ++ return THD_SUCCESS; ++ ++} ++ + void cthd_engine_adaptive::set_int3400_target(struct adaptive_target target) { +- struct psvt *psvt; ++ ++ if (target.code == "ITMT") { ++ if (set_itmt_target(target) == THD_SUCCESS) ++ return; ++ } + if (target.code == "PSVT") { ++ struct psvt *psvt; ++ + thd_log_info("set_int3400 target %s\n", target.argument.c_str()); + + psvt = find_psvt(target.argument); +diff --git a/src/thd_engine_adaptive.h b/src/thd_engine_adaptive.h +index 2d38b95..2e1acd7 100644 +--- a/src/thd_engine_adaptive.h ++++ b/src/thd_engine_adaptive.h +@@ -198,7 +198,10 @@ protected: + int parse_gddv_key(char *buf, int size, int *end_offset); + int parse_gddv(char *buf, int size, int *end_offset); + struct psvt* find_psvt(std::string name); ++ struct itmt* find_itmt(std::string name); ++ int set_itmt_target(struct adaptive_target target); + int install_passive(struct psv *psv); ++ int install_itmt(struct itmt_entry *itmt_entry); + void psvt_consolidate(); + void set_trip(std::string device, std::string argument); + void set_int3400_target(struct adaptive_target target); +-- +2.34.1 + diff -Nru thermald-2.4.9/debian/patches/0005-Use-per-trip-min-max.patch thermald-2.4.9/debian/patches/0005-Use-per-trip-min-max.patch --- thermald-2.4.9/debian/patches/0005-Use-per-trip-min-max.patch 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/patches/0005-Use-per-trip-min-max.patch 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1,376 @@ +From 1bc1105ddadb24b26b971abd3cfd22a1b245b525 Mon Sep 17 00:00:00 2001 +From: Srinivas Pandruvada +Date: Mon, 27 Jun 2022 15:51:09 -0700 +Subject: [PATCH 5/5] Use per trip min max + +When throttling action takes place, use the trip specfic min +max if valid. But it will require some conflicts when two +trips in different zones calls for different min and max while +they are active. Use the most constrained one in this case. + +Refer to code comments for changes. +--- + src/thd_cdev.cpp | 155 ++++++++++++++++++++++++++++++++--------- + src/thd_cdev.h | 17 +++-- + src/thd_trip_point.cpp | 14 ++-- + 3 files changed, 140 insertions(+), 46 deletions(-) + +diff --git a/src/thd_cdev.cpp b/src/thd_cdev.cpp +index 5c0bbd2..824fb9e 100644 +--- a/src/thd_cdev.cpp ++++ b/src/thd_cdev.cpp +@@ -39,50 +39,78 @@ + #include "thd_cdev.h" + #include "thd_engine.h" + +-int cthd_cdev::thd_clamp_state_min(int _state) ++// Clamp to cdev min state or trip specific min if valid ++int cthd_cdev::thd_clamp_state_min(int _state, int temp_min_state) + { +- if ((min_state < max_state && _state < min_state) +- || (min_state > max_state && _state > min_state)) +- return min_state; ++ int _min_state = min_state; ++ ++ if (_min_state > max_state) { ++ if (temp_min_state && temp_min_state < _min_state) ++ _min_state = temp_min_state; ++ } else { ++ if (temp_min_state && temp_min_state > _min_state) ++ _min_state = temp_min_state; ++ } ++ ++ thd_log_debug("def_min_state:%d curr_min_state:%d\n", min_state, ++ _min_state); ++ ++ if ((_min_state < max_state && _state < _min_state) ++ || (_min_state > max_state && _state > _min_state)) ++ return _min_state; + else + return _state; + } + +-int cthd_cdev::thd_clamp_state_max(int _state) ++// Clamp to cdev max state or trip specific max if valid ++int cthd_cdev::thd_clamp_state_max(int _state, int temp_max_state) + { +- if ((min_state < max_state && _state > max_state) +- || (min_state > max_state && _state < max_state)) +- return max_state; ++ int _max_state = max_state; ++ ++ if (min_state > _max_state) { ++ if (temp_max_state && temp_max_state > _max_state) ++ _max_state = temp_max_state; ++ } else { ++ if (temp_max_state && temp_max_state < _max_state) ++ _max_state = temp_max_state; ++ } ++ ++ thd_log_debug("def_max_state:%d temp_max_state:%d curr_max_state:%d\n", ++ max_state, temp_max_state, _max_state); ++ ++ if ((min_state < _max_state && _state > _max_state) ++ || (min_state > _max_state && _state < _max_state)) ++ return _max_state; + else + return _state; + } + + int cthd_cdev::thd_cdev_exponential_controller(int set_point, int target_temp, +- int temperature, int state, int zone_id) { ++ int temperature, int state, int zone_id, int temp_min_state, int temp_max_state) { + + int control = state; +- int curr_state, max_state, _state; ++ int _curr_state, _max_state, _state; + +- max_state = get_max_state(); ++ _max_state = get_max_state(); + + if (state) { + // Get the latest state, which for some devices read the state from the hardware +- curr_state = get_curr_state(true); ++ _curr_state = get_curr_state(true); + // Clamp the current state to min_state, as we start from min to max for + // activation of a cooling device +- curr_state = thd_clamp_state_min(curr_state); ++ _curr_state = thd_clamp_state_min(_curr_state, temp_min_state); + thd_log_debug("thd_cdev_set_%d:curr state %d max state %d\n", index, +- curr_state, max_state); ++ _curr_state, _max_state); + + if (inc_val) +- _state = curr_state + inc_val; ++ _state = _curr_state + inc_val; + else +- _state = curr_state + inc_dec_val; ++ _state = _curr_state + inc_dec_val; + + if (trend_increase) { + // This means this is a repeat call for activation + if (curr_pow == 0) +- base_pow_state = curr_state; ++ base_pow_state = _curr_state; + ++curr_pow; + + if (inc_val) +@@ -90,25 +118,32 @@ int cthd_cdev::thd_cdev_exponential_controller(int set_point, int target_temp, + else + _state = base_pow_state + int_2_pow(curr_pow) * inc_dec_val; + ++ // Check for the overflow exhaust the valid range ++ if (((inc_val < 0) && (base_pow_state < _state)) ++ || ((inc_val > 0) && (base_pow_state > _state))) ++ _state = max_state; ++ + thd_log_info( +- "cdev index:%d consecutive call, increment exponentially state %d (min %d max %d)\n", +- index, _state, min_state, max_state); ++ "cdev index:%d consecutive call, increment exponentially state %d (min %d max %d) (%d:%d)\n", ++ index, _state, min_state, _max_state, base_pow_state, curr_pow); + +- // Make sure that the state is not beyond max_state +- _state = thd_clamp_state_max(_state); + } else { + curr_pow = 0; + } ++ ++ // Make sure that the state is not beyond max_state ++ _state = thd_clamp_state_max(_state, temp_max_state); ++ + trend_increase = true; + thd_log_debug("op->device:%s %d\n", type_str.c_str(), _state); + set_curr_state(_state, control); + } else { + // Get the latest state, which is not the latest from the hardware but last set state to the device +- curr_state = get_curr_state(); +- curr_state = thd_clamp_state_max(curr_state); ++ _curr_state = get_curr_state(); ++ _curr_state = thd_clamp_state_max(curr_state); + + thd_log_debug("thd_cdev_set_%d:curr state %d max state %d\n", index, +- curr_state, max_state); ++ curr_state, _max_state); + + curr_pow = 0; + trend_increase = false; +@@ -116,9 +151,9 @@ int cthd_cdev::thd_cdev_exponential_controller(int set_point, int target_temp, + if (auto_down_adjust == false) { + + if (dec_val) +- _state = curr_state - dec_val; ++ _state = _curr_state - dec_val; + else +- _state = curr_state - inc_dec_val; ++ _state = _curr_state - inc_dec_val; + + // Make sure that it is not beyond min_state + _state = thd_clamp_state_min(_state); +@@ -151,6 +186,16 @@ static bool sort_clamp_values_dec(zone_trip_limits_t limit_1, + return (limit_1.target_value > limit_2.target_value); + } + ++static bool sort_min_max_values_asc(zone_trip_limits_t limit_1, ++ zone_trip_limits_t limit_2) { ++ return (limit_1._min_state < limit_2._min_state); ++} ++ ++static bool sort_min_max_values_dec(zone_trip_limits_t limit_1, ++ zone_trip_limits_t limit_2) { ++ return (limit_1._max_state > limit_2._max_state); ++} ++ + /* + * How the state is set? + * If the state set is called before debounce interval, then simply return +@@ -183,8 +228,9 @@ static bool sort_clamp_values_dec(zone_trip_limits_t limit_1, + + int cthd_cdev::thd_cdev_set_state(int set_point, int target_temp, + int temperature, int hard_target, int state, int zone_id, int trip_id, +- int target_state_valid, int target_value, +- pid_param_t *pid_param, cthd_pid& pid, bool force) { ++ int target_state_valid, int target_value, pid_param_t *pid_param, ++ cthd_pid &pid, bool force, int min_max_valid, int _min_state, ++ int _max_state) { + + time_t tm; + int ret; +@@ -199,9 +245,9 @@ int cthd_cdev::thd_cdev_set_state(int set_point, int target_temp, + time(&tm); + + thd_log_debug( +- ">>thd_cdev_set_state temperature %d:%d index:%d state:%d :zone:%d trip_id:%d target_state_valid:%d target_value :%d force:%d\n", ++ ">>thd_cdev_set_state temperature %d:%d index:%d state:%d :zone:%d trip_id:%d target_state_valid:%d target_value :%d force:%d min_state:%d max_state:%d\n", + target_temp, temperature, index, state, zone_id, trip_id, +- target_state_valid, target_value, force); ++ target_state_valid, target_value, force, _min_state, _max_state); + + if (state) { + bool found = false; +@@ -226,9 +272,29 @@ int cthd_cdev::thd_cdev_set_state(int set_point, int target_temp, + limit.trip = trip_id; + limit.target_state_valid = target_state_valid; + limit.target_value = target_value; +- thd_log_info("Added zone %d trip %d clamp_valid %d clamp %d\n", ++ ++ // Cap the trip min max limits to actual cooling device trips ++ // Here min_state and max_state are for cooling device and ++ // _min_state and _max_state are defined for per trip ++ // in thermal table ++ if (min_max_valid) { ++ if (_min_state == TRIP_PT_INVALID_TARGET_STATE || !_min_state) ++ _min_state = min_state; ++ ++ if (_max_state == TRIP_PT_INVALID_TARGET_STATE || !_max_state) ++ _max_state = max_state; ++ } else { ++ _max_state = 0; ++ _min_state = 0; ++ } ++ ++ limit._max_state = _max_state; ++ limit._min_state = _min_state; ++ limit._min_max_valid = min_max_valid; ++ ++ thd_log_info("Added zone %d trip %d clamp_valid %d clamp %d _min:%d _max:%d\n", + limit.zone, limit.trip, limit.target_state_valid, +- limit.target_value); ++ limit.target_value, limit._min_state, limit._max_state); + zone_trip_limits.push_back(limit); + + if (target_state_valid) { +@@ -240,6 +306,21 @@ int cthd_cdev::thd_cdev_set_state(int set_point, int target_temp, + sort_clamp_values_dec); + } + } ++ ++ // Target state and min_max_valid or mutually exclusive ++ // in thermal tables. So no need to consolidate min/max with ++ // target ++ // The table will be ordered so that most restrictive is the ++ // first entry ++ if (min_max_valid) { ++ if (min_state < max_state) { ++ std::sort(zone_trip_limits.begin(), zone_trip_limits.end(), ++ sort_min_max_values_dec); ++ } else { ++ std::sort(zone_trip_limits.begin(), zone_trip_limits.end(), ++ sort_min_max_values_asc); ++ } ++ } + } + + zone_trip_limits_t limit; +@@ -247,6 +328,12 @@ int cthd_cdev::thd_cdev_set_state(int set_point, int target_temp, + limit = zone_trip_limits[zone_trip_limits.size() - 1]; + target_value = limit.target_value; + target_state_valid = limit.target_state_valid; ++ ++ target_value = limit.target_value; ++ min_max_valid = limit._min_max_valid; ++ _max_state = limit._max_state; ++ _min_state = limit._min_state; ++ + if (!first_entry && target_state_valid + && cmp_current_state( + map_target_state(target_state_valid, target_value)) +@@ -394,7 +481,7 @@ int cthd_cdev::thd_cdev_set_state(int set_point, int target_temp, + ret = THD_SUCCESS; + } else { + ret = thd_cdev_exponential_controller(set_point, target_temp, +- temperature, state, zone_id); ++ temperature, state, zone_id, _min_state, _max_state); + } + if (curr_state == get_max_state()) { + control_end(); +@@ -407,7 +494,7 @@ int cthd_cdev::thd_cdev_set_min_state(int zone_id, int trip_id) { + trend_increase = false; + cthd_pid unused; + thd_cdev_set_state(0, 0, 0, 0, 0, zone_id, trip_id, 1, min_state, NULL, +- unused, true); ++ unused, true, 0, 0, 0); + + return THD_SUCCESS; + } +diff --git a/src/thd_cdev.h b/src/thd_cdev.h +index f544d1a..ca3e542 100644 +--- a/src/thd_cdev.h ++++ b/src/thd_cdev.h +@@ -38,6 +38,9 @@ typedef struct { + int trip; + int target_state_valid; + int target_value; ++ int _min_state; ++ int _max_state; ++ int _min_max_valid; + } zone_trip_limits_t; + + #define ZONE_TRIP_LIMIT_COUNT 12 +@@ -79,9 +82,10 @@ private: + return _pow; + } + int thd_cdev_exponential_controller(int set_point, int target_temp, +- int temperature, int state, int arg); +- int thd_clamp_state_min(int _state); +- int thd_clamp_state_max(int _state); ++ int temperature, int state, int arg, int temp_min_state = 0, ++ int temp_max_state = 0); ++ int thd_clamp_state_min(int _state, int temp_min_state = 0); ++ int thd_clamp_state_max(int _state, int temp_max_state = 0); + public: + static const int default_debounce_interval = 2; // In seconds + cthd_cdev(unsigned int _index, std::string control_path) : +@@ -96,9 +100,10 @@ public: + virtual ~cthd_cdev() { + } + virtual int thd_cdev_set_state(int set_point, int target_temp, +- int temperature, int hard_target, int state, +- int zone_id, int trip_id, int target_state_valid, int target_value, +- pid_param_t *pid_param, cthd_pid& pid, bool force); ++ int temperature, int hard_target, int state, int zone_id, ++ int trip_id, int target_state_valid, int target_value, ++ pid_param_t *pid_param, cthd_pid &pid, bool force, ++ int min_max_valid, int _min_state, int _max_state); + + virtual int thd_cdev_set_min_state(int zone_id, int trip_id); + +diff --git a/src/thd_trip_point.cpp b/src/thd_trip_point.cpp +index d1d33a3..1dcb2cb 100644 +--- a/src/thd_trip_point.cpp ++++ b/src/thd_trip_point.cpp +@@ -281,11 +281,12 @@ bool cthd_trip_point::thd_trip_point_check(int id, unsigned int read_temp, + if (cdevs[i].target_state == TRIP_PT_INVALID_TARGET_STATE) + cdevs[i].target_state = cdev->get_min_state(); + +- ret = cdev->thd_cdev_set_state(temp, temp, read_temp, (type == MAX), 1, zone_id, +- index, cdevs[i].target_state_valid, ++ ret = cdev->thd_cdev_set_state(temp, temp, read_temp, (type == MAX), ++ 1, zone_id, index, cdevs[i].target_state_valid, + cdev->map_target_state(cdevs[i].target_state_valid, + cdevs[i].target_state), &cdevs[i].pid_param, +- cdevs[i].pid, false); ++ cdevs[i].pid, false, cdevs[i].min_max_valid, ++ cdevs[i].min_state, cdevs[i].max_state); + if (control_type == SEQUENTIAL && ret == THD_SUCCESS) { + // Only one cdev activation + break; +@@ -310,11 +311,12 @@ bool cthd_trip_point::thd_trip_point_check(int id, unsigned int read_temp, + if (cdevs[i].target_state == TRIP_PT_INVALID_TARGET_STATE) + cdevs[i].target_state = cdev->get_min_state(); + +- cdev->thd_cdev_set_state(temp, temp, read_temp, (type == MAX), 0, zone_id, index, +- cdevs[i].target_state_valid, ++ cdev->thd_cdev_set_state(temp, temp, read_temp, (type == MAX), 0, ++ zone_id, index, cdevs[i].target_state_valid, + cdev->map_target_state(cdevs[i].target_state_valid, + cdevs[i].target_state), &cdevs[i].pid_param, +- cdevs[i].pid, false); ++ cdevs[i].pid, false, cdevs[i].min_max_valid, ++ cdevs[i].min_state, cdevs[i].max_state); + + if (control_type == SEQUENTIAL) { + // Only one cdev activation +-- +2.34.1 + diff -Nru thermald-2.4.9/debian/patches/0006-Add-INT3400-base-path-for-Raptor-Lake.patch thermald-2.4.9/debian/patches/0006-Add-INT3400-base-path-for-Raptor-Lake.patch --- thermald-2.4.9/debian/patches/0006-Add-INT3400-base-path-for-Raptor-Lake.patch 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/patches/0006-Add-INT3400-base-path-for-Raptor-Lake.patch 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1,41 @@ +From 57c1fe95fef707051d7dd340544f290eae2184c1 Mon Sep 17 00:00:00 2001 +From: Srinivas Pandruvada +Date: Wed, 29 Jun 2022 17:22:18 -0700 +Subject: [PATCH 06/18] Add INT3400 base path for Raptor Lake + +Update the sysfs path for INT3400 sysfs to be able to run adaptive +mode. +--- + src/thd_engine_adaptive.cpp | 2 ++ + src/thd_int3400.cpp | 2 ++ + 2 files changed, 4 insertions(+) + +diff --git a/src/thd_engine_adaptive.cpp b/src/thd_engine_adaptive.cpp +index 3ecf61c..71fb550 100644 +--- a/src/thd_engine_adaptive.cpp ++++ b/src/thd_engine_adaptive.cpp +@@ -1866,6 +1866,8 @@ int cthd_engine_adaptive::thd_engine_init(bool ignore_cpuid_check, bool adaptive + int3400_base_path = "/sys/bus/platform/devices/INTC1040:00/"; + } else if (sysfs.exists("/sys/bus/platform/devices/INTC1041:00")) { + int3400_base_path = "/sys/bus/platform/devices/INTC1041:00/"; ++ } else if (sysfs.exists("/sys/bus/platform/devices/INTC10A0:00")) { ++ int3400_base_path = "/sys/bus/platform/devices/INTC10A0:00/"; + } else { + return THD_ERROR; + } +diff --git a/src/thd_int3400.cpp b/src/thd_int3400.cpp +index 3572997..da86760 100644 +--- a/src/thd_int3400.cpp ++++ b/src/thd_int3400.cpp +@@ -38,6 +38,8 @@ cthd_INT3400::cthd_INT3400(std::string _uuid) : uuid(_uuid), base_path("") { + base_path = "/sys/bus/acpi/devices/INTC1040:00/physical_node/uuids/"; + } else if (cdev_sysfs.exists("/sys/bus/acpi/devices/INTC1041:00/physical_node/uuids")) { + base_path = "/sys/bus/acpi/devices/INTC1041:00/physical_node/uuids/"; ++ } else if (cdev_sysfs.exists("/sys/bus/acpi/devices/INTC10A0:00/physical_node/uuids")) { ++ base_path = "/sys/bus/acpi/devices/INTC10A0:00/physical_node/uuids/"; + } + thd_log_info("INT3400 Base path is %s\n", base_path.c_str()); + } +-- +2.34.1 + diff -Nru thermald-2.4.9/debian/patches/0007-Move-interface-debug_mode_on-to-thd_engine.patch thermald-2.4.9/debian/patches/0007-Move-interface-debug_mode_on-to-thd_engine.patch --- thermald-2.4.9/debian/patches/0007-Move-interface-debug_mode_on-to-thd_engine.patch 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/patches/0007-Move-interface-debug_mode_on-to-thd_engine.patch 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1,83 @@ +From eaa77b41c1eddb6d0dc6ebbe8d3f903cf3029723 Mon Sep 17 00:00:00 2001 +From: Srinivas Pandruvada +Date: Tue, 5 Jul 2022 16:33:49 -0700 +Subject: [PATCH 07/18] Move interface debug_mode_on to thd_engine + +Move debug_mode_on() to thd_engine class instead of thd_engine_default +so it can be accessed via thd_engine pointer. +--- + src/thd_engine.cpp | 12 ++++++++++++ + src/thd_engine.h | 1 + + src/thd_engine_default.cpp | 11 ----------- + src/thd_engine_default.h | 1 - + 4 files changed, 13 insertions(+), 12 deletions(-) + +diff --git a/src/thd_engine.cpp b/src/thd_engine.cpp +index 994b18d..c312695 100644 +--- a/src/thd_engine.cpp ++++ b/src/thd_engine.cpp +@@ -1286,3 +1286,15 @@ void cthd_engine::parser_deinit() { + parser_init_done = false; + } + } ++ ++int cthd_engine::debug_mode_on(void) { ++ static const char *debug_mode = TDRUNDIR ++ "/debug_mode"; ++ struct stat s; ++ ++ if (stat(debug_mode, &s)) ++ return 0; ++ ++ return 1; ++} ++ +diff --git a/src/thd_engine.h b/src/thd_engine.h +index 697ff40..82ff1fe 100644 +--- a/src/thd_engine.h ++++ b/src/thd_engine.h +@@ -286,6 +286,7 @@ public: + + int parser_init(); + void parser_deinit(); ++ int debug_mode_on(void); + }; + + #endif /* THD_ENGINE_H_ */ +diff --git a/src/thd_engine_default.cpp b/src/thd_engine_default.cpp +index 153fab2..c1f9f90 100644 +--- a/src/thd_engine_default.cpp ++++ b/src/thd_engine_default.cpp +@@ -80,17 +80,6 @@ static cooling_dev_t cpu_def_cooling_devices[] = { + cthd_engine_default::~cthd_engine_default() { + } + +-int cthd_engine_default::debug_mode_on(void) { +- static const char *debug_mode = TDRUNDIR +- "/debug_mode"; +- struct stat s; +- +- if (stat(debug_mode, &s)) +- return 0; +- +- return 1; +-} +- + int cthd_engine_default::read_thermal_sensors() { + int index; + DIR *dir; +diff --git a/src/thd_engine_default.h b/src/thd_engine_default.h +index 0fbf847..1acf5b8 100644 +--- a/src/thd_engine_default.h ++++ b/src/thd_engine_default.h +@@ -74,7 +74,6 @@ public: + int read_cooling_devices(); + int read_thermal_sensors(); + void workarounds(); +- int debug_mode_on(void); + }; + + int thd_engine_create_default_engine(bool ignore_cpuid_check, +-- +2.34.1 + diff -Nru thermald-2.4.9/debian/patches/0008-Separate-Adaptive-engine-and-GDDV.patch thermald-2.4.9/debian/patches/0008-Separate-Adaptive-engine-and-GDDV.patch --- thermald-2.4.9/debian/patches/0008-Separate-Adaptive-engine-and-GDDV.patch 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/patches/0008-Separate-Adaptive-engine-and-GDDV.patch 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1,3661 @@ +From 82609c7e017a0461eb20d66935979e399f024e0e Mon Sep 17 00:00:00 2001 +From: Srinivas Pandruvada +Date: Thu, 30 Jun 2022 16:31:23 -0700 +Subject: [PATCH 08/18] Separate Adaptive engine and GDDV + +To better organize code, separate into two classes. One just +implement GDDV parsing and other actually doing adaptive processing. + +No functional changes are expected. +--- + Makefile.am | 3 +- + src/thd_engine_adaptive.cpp | 1546 +++-------------------------------- + src/thd_engine_adaptive.h | 197 +---- + src/thd_engine_default.h | 3 + + src/thd_gddv.cpp | 1413 ++++++++++++++++++++++++++++++++ + src/thd_gddv.h | 230 ++++++ + 6 files changed, 1760 insertions(+), 1632 deletions(-) + create mode 100644 src/thd_gddv.cpp + create mode 100644 src/thd_gddv.h + +diff --git a/Makefile.am b/Makefile.am +index a73dd7a..1bbc60f 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -83,7 +83,8 @@ thermald_SOURCES = \ + src/thd_sensor_kbl_g_mcp.cpp \ + src/thd_zone_kbl_amdgpu.cpp \ + src/thd_sensor_rapl_power.cpp \ +- src/thd_zone_rapl_power.cpp ++ src/thd_zone_rapl_power.cpp \ ++ src/thd_gddv.cpp + + man5_MANS = man/thermal-conf.xml.5 + man8_MANS = man/thermald.8 +diff --git a/src/thd_engine_adaptive.cpp b/src/thd_engine_adaptive.cpp +index 71fb550..8ab8be6 100644 +--- a/src/thd_engine_adaptive.cpp ++++ b/src/thd_engine_adaptive.cpp +@@ -30,1213 +30,6 @@ + #include + #include + #include "thd_engine_adaptive.h" +-#include "thd_zone_cpu.h" +-#include "thd_zone_generic.h" +-#include "thd_cdev_gen_sysfs.h" +-#include "thd_cdev_cpufreq.h" +-#include "thd_cdev_rapl.h" +-#include "thd_cdev_intel_pstate_driver.h" +-#include "thd_cdev_rapl_dram.h" +-#include "thd_sensor_virtual.h" +-#include "thd_cdev_backlight.h" +-#include "thd_int3400.h" +-#include "thd_sensor_kbl_amdgpu_thermal.h" +-#include "thd_sensor_kbl_amdgpu_power.h" +-#include "thd_cdev_kbl_amdgpu.h" +-#include "thd_zone_kbl_amdgpu.h" +-#include "thd_sensor_kbl_g_mcp.h" +-#include "thd_zone_kbl_g_mcp.h" +-#include "thd_cdev_kbl_amdgpu.h" +-#include "thd_zone_kbl_g_mcp.h" +- +-#ifdef GLIB_SUPPORT +-#include "thd_cdev_modem.h" +-#endif +- +-/* From esif_lilb_datavault.h */ +-#define ESIFDV_NAME_LEN 32 // Max DataVault Name (Cache Name) Length (not including NUL) +-#define ESIFDV_DESC_LEN 64 // Max DataVault Description Length (not including NUL) +- +-#define SHA256_HASH_BYTES 32 +- +-struct header { +- uint16_t signature; +- uint16_t headersize; +- uint32_t version; +- +- union { +- /* Added in V1 */ +- struct { +- uint32_t flags; +- } v1; +- +- /* Added in V2 */ +- struct { +- uint32_t flags; +- char segmentid[ESIFDV_NAME_LEN]; +- char comment[ESIFDV_DESC_LEN]; +- uint8_t payload_hash[SHA256_HASH_BYTES]; +- uint32_t payload_size; +- uint32_t payload_class; +- } v2; +- }; +-} __attribute__ ((packed)); +- +-class _gddv_exception: public std::exception { +- virtual const char* what() const throw () { +- return "GDDV parsing failed"; +- } +-} gddv_exception; +- +-void cthd_engine_adaptive::destroy_dynamic_sources() { +- g_clear_object(&upower_client); +- g_clear_object(&power_profiles_daemon); +- +- if (tablet_dev) { +- close(libevdev_get_fd(tablet_dev)); +- libevdev_free(tablet_dev); +- +- if (lid_dev == tablet_dev) +- lid_dev = NULL; +- tablet_dev = NULL; +- } +- +- if (lid_dev) { +- close(libevdev_get_fd(lid_dev)); +- libevdev_free(lid_dev); +- +- lid_dev = NULL; +- } +-} +- +-cthd_engine_adaptive::~cthd_engine_adaptive() { +- destroy_dynamic_sources(); +-} +- +-int cthd_engine_adaptive::get_type(char *object, int *offset) { +- return *(uint32_t*) (object + *offset); +-} +- +-uint64_t cthd_engine_adaptive::get_uint64(char *object, int *offset) { +- uint64_t value; +- int type = *(uint32_t*) (object + *offset); +- +- if (type != 4) { +- thd_log_warn("Found object of type %d, expecting 4\n", type); +- throw gddv_exception; +- } +- *offset += 4; +- +- value = *(uint64_t*) (object + *offset); +- *offset += 8; +- +- return value; +-} +- +-char* cthd_engine_adaptive::get_string(char *object, int *offset) { +- int type = *(uint32_t*) (object + *offset); +- uint64_t length; +- char *value; +- +- if (type != 8) { +- thd_log_warn("Found object of type %d, expecting 8\n", type); +- throw gddv_exception; +- } +- *offset += 4; +- +- length = *(uint64_t*) (object + *offset); +- *offset += 8; +- +- value = &object[*offset]; +- *offset += length; +- return value; +-} +- +-int cthd_engine_adaptive::merge_custom(struct custom_condition *custom, +- struct condition *condition) { +- condition->device = custom->participant; +- condition->condition = (enum adaptive_condition) custom->type; +- +- return 0; +-} +- +-int cthd_engine_adaptive::merge_appc() { +- for (int i = 0; i < (int) custom_conditions.size(); i++) { +- for (int j = 0; j < (int) conditions.size(); j++) { +- for (int k = 0; k < (int) conditions[j].size(); k++) { +- if (custom_conditions[i].condition +- == conditions[j][k].condition) { +- merge_custom(&custom_conditions[i], &conditions[j][k]); +- } +- } +- } +- } +- +- return 0; +-} +- +-int cthd_engine_adaptive::parse_appc(char *appc, int len) { +- int offset = 0; +- uint64_t version; +- +- if (appc[0] != 4) { +- thd_log_info("Found malformed APPC table, ignoring\n"); +- return 0; +- } +- +- version = get_uint64(appc, &offset); +- if (version != 1) { +- // Invalid APPC tables aren't fatal +- thd_log_info("Found unsupported or malformed APPC version %d\n", +- (int) version); +- return 0; +- } +- +- while (offset < len) { +- struct custom_condition condition; +- +- condition.condition = (enum adaptive_condition) get_uint64(appc, +- &offset); +- condition.name = get_string(appc, &offset); +- condition.participant = get_string(appc, &offset); +- condition.domain = get_uint64(appc, &offset); +- condition.type = get_uint64(appc, &offset); +- custom_conditions.push_back(condition); +- } +- +- return 0; +-} +- +-int cthd_engine_adaptive::parse_apat(char *apat, int len) { +- int offset = 0; +- uint64_t version = get_uint64(apat, &offset); +- +- if (version != 2) { +- thd_log_warn("Found unsupported APAT version %d\n", (int) version); +- throw gddv_exception; +- } +- +- while (offset < len) { +- struct adaptive_target target; +- +- if (offset >= len) +- return THD_ERROR; +- +- target.target_id = get_uint64(apat, &offset); +- target.name = get_string(apat, &offset); +- target.participant = get_string(apat, &offset); +- target.domain = get_uint64(apat, &offset); +- target.code = get_string(apat, &offset); +- target.argument = get_string(apat, &offset); +- targets.push_back(target); +- } +- return 0; +-} +- +-void cthd_engine_adaptive::dump_apat() +-{ +- thd_log_info("..apat dump begin.. \n"); +- for (unsigned int i = 0; i < targets.size(); ++i) { +- thd_log_info( +- "target_id:%" PRIu64 " name:%s participant:%s domain:%d code:%s argument:%s\n", +- targets[i].target_id, targets[i].name.c_str(), +- targets[i].participant.c_str(), (int)targets[i].domain, +- targets[i].code.c_str(), targets[i].argument.c_str()); +- } +- thd_log_info("apat dump end\n"); +-} +- +-int cthd_engine_adaptive::parse_apct(char *apct, int len) { +- int i; +- int offset = 0; +- uint64_t version = get_uint64(apct, &offset); +- +- if (version == 1) { +- while (offset < len) { +- std::vector condition_set; +- +- uint64_t target = get_uint64(apct, &offset); +- if (int(target) == -1) { +- thd_log_warn("Invalid APCT target\n"); +- throw gddv_exception; +- } +- +- for (i = 0; i < 10; i++) { +- struct condition condition; +- +- condition.condition = adaptive_condition(0); +- condition.device = ""; +- condition.comparison = adaptive_comparison(0); +- condition.argument = 0; +- condition.operation = adaptive_operation(0); +- condition.time_comparison = adaptive_comparison(0); +- condition.time = 0; +- condition.target = 0; +- condition.state = 0; +- condition.state_entry_time = 0; +- condition.target = target; +- condition.ignore_condition = 0; +- +- if (offset >= len) { +- thd_log_warn("Read off end of buffer in APCT parsing\n"); +- throw gddv_exception; +- } +- +- condition.condition = adaptive_condition( +- get_uint64(apct, &offset)); +- condition.comparison = adaptive_comparison( +- get_uint64(apct, &offset)); +- condition.argument = get_uint64(apct, &offset); +- if (i < 9) { +- condition.operation = adaptive_operation( +- get_uint64(apct, &offset)); +- if (condition.operation == FOR) { +- offset += 12; +- condition.time_comparison = adaptive_comparison( +- get_uint64(apct, &offset)); +- condition.time = get_uint64(apct, &offset); +- offset += 12; +- i++; +- } +- } +- condition_set.push_back(condition); +- } +- conditions.push_back(condition_set); +- } +- } else if (version == 2) { +- while (offset < len) { +- std::vector condition_set; +- +- uint64_t target = get_uint64(apct, &offset); +- if (int(target) == -1) { +- thd_log_warn("Invalid APCT target"); +- throw gddv_exception; +- } +- +- uint64_t count = get_uint64(apct, &offset); +- for (i = 0; i < int(count); i++) { +- struct condition condition; +- +- condition.condition = adaptive_condition(0); +- condition.device = ""; +- condition.comparison = adaptive_comparison(0); +- condition.argument = 0; +- condition.operation = adaptive_operation(0); +- condition.time_comparison = adaptive_comparison(0); +- condition.time = 0; +- condition.target = 0; +- condition.state = 0; +- condition.state_entry_time = 0; +- condition.target = target; +- +- if (offset >= len) { +- thd_log_warn("Read off end of buffer in parsing APCT\n"); +- throw gddv_exception; +- } +- +- condition.condition = adaptive_condition( +- get_uint64(apct, &offset)); +- condition.device = get_string(apct, &offset); +- offset += 12; +- condition.comparison = adaptive_comparison( +- get_uint64(apct, &offset)); +- condition.argument = get_uint64(apct, &offset); +- if (i < int(count - 1)) { +- condition.operation = adaptive_operation( +- get_uint64(apct, &offset)); +- if (condition.operation == FOR) { +- offset += 12; +- get_string(apct, &offset); +- offset += 12; +- condition.time_comparison = adaptive_comparison( +- get_uint64(apct, &offset)); +- condition.time = get_uint64(apct, &offset); +- offset += 12; +- i++; +- } +- } +- condition_set.push_back(condition); +- } +- conditions.push_back(condition_set); +- } +- } else { +- thd_log_warn("Unsupported APCT version %d\n", (int) version); +- throw gddv_exception; +- } +- return 0; +-} +- +-static const char *condition_names[] = { +- "Invalid", +- "Default", +- "Orientation", +- "Proximity", +- "Motion", +- "Dock", +- "Workload", +- "Cooling_mode", +- "Power_source", +- "Aggregate_power_percentage", +- "Lid_state", +- "Platform_type", +- "Platform_SKU", +- "Utilisation", +- "TDP", +- "Duty_cycle", +- "Power", +- "Temperature", +- "Display_orientation", +- "Oem0", +- "Oem1", +- "Oem2", +- "Oem3", +- "Oem4", +- "Oem5", +- "PMAX", +- "PSRC", +- "ARTG", +- "CTYP", +- "PROP", +- "Unk1", +- "Unk2", +- "Battery_state", +- "Battery_rate", +- "Battery_remaining", +- "Battery_voltage", +- "PBSS", +- "Battery_cycles", +- "Battery_last_full", +- "Power_personality", +- "Battery_design_capacity", +- "Screen_state", +- "AVOL", +- "ACUR", +- "AP01", +- "AP02", +- "AP10", +- "Time", +- "Temperature_without_hysteresis", +- "Mixed_reality", +- "User_presence", +- "RBHF", +- "VBNL", +- "CMPP", +- "Battery_percentage", +- "Battery_count", +- "Power_slider" +-}; +- +-static const char *comp_strs[] = { +- "INVALID", +- "ADAPTIVE_EQUAL", +- "ADAPTIVE_LESSER_OR_EQUAL", +- "ADAPTIVE_GREATER_OR_EQUAL" +-}; +- +-#define ARRAY_SIZE(array) \ +- (sizeof(array) / sizeof(array[0])) +- +-void cthd_engine_adaptive::dump_apct() { +- thd_log_info("..apct dump begin.. \n"); +- for (unsigned int i = 0; i < conditions.size(); ++i) { +- std::vector condition_set; +- +- thd_log_info("condition_set %d\n", i); +- condition_set = conditions[i]; +- for (unsigned int j = 0; j < condition_set.size(); ++j) { +- std::string cond_name, comp_str, op_str; +- +- if (condition_set[j].condition < ARRAY_SIZE(condition_names)) { +- cond_name = condition_names[condition_set[j].condition]; +- } else if (condition_set[j].condition >= 0x1000 && condition_set[j].condition < 0x10000) { +- std::stringstream msg; +- +- msg << "Oem" << (condition_set[j].condition - 0x1000 + 6); +- cond_name = msg.str(); +- } else { +- std::stringstream msg; +- +- msg << "UNKNOWN" << "( " << condition_set[j].condition << " )"; +- cond_name = msg.str(); +- } +- +- if (condition_set[j].comparison < ARRAY_SIZE(comp_strs)) { +- comp_str = comp_strs[condition_set[j].comparison]; +- } +- +- if (condition_set[j].operation == 1) { +- op_str = "AND"; +- } else if (condition_set[j].operation == 2) { +- op_str = "FOR"; +- } else { +- op_str = "INVALID"; +- } +- +- thd_log_info( +- "\ttarget:%d device:%s condition:%s comparison:%s argument:%d" +- " operation:%s time_comparison:%d time:%d" +- " stare:%d state_entry_time:%d \n", +- condition_set[j].target, condition_set[j].device.c_str(), +- cond_name.c_str(), comp_str.c_str(), +- condition_set[j].argument, op_str.c_str(), +- condition_set[j].time_comparison, condition_set[j].time, +- condition_set[j].state, condition_set[j].state_entry_time); +- } +- } +- thd_log_info("..apct dump end.. \n"); +-} +- +-ppcc_t* cthd_engine_adaptive::get_ppcc_param(std::string name) { +- for (int i = 0; i < (int) ppccs.size(); i++) { +- if (ppccs[i].name == name) +- return &ppccs[i]; +- } +- +- return NULL; +-} +- +-int cthd_engine_adaptive::parse_ppcc(char *name, char *buf, int len) { +- ppcc_t ppcc; +- +- ppcc.name = name; +- ppcc.power_limit_min = *(uint64_t*) (buf + 28); +- ppcc.power_limit_max = *(uint64_t*) (buf + 40); +- ppcc.time_wind_min = *(uint64_t*) (buf + 52); +- ppcc.time_wind_max = *(uint64_t*) (buf + 64); +- ppcc.step_size = *(uint64_t*) (buf + 76); +- ppcc.valid = 1; +- +- if (len < 156) +- return 0; +- +- thd_log_info("Processing ppcc limit 2, length %d\n", len); +- int start = 76 + 12; +- ppcc.power_limit_1_min = *(uint64_t*) (buf + start + 12); +- ppcc.power_limit_1_max = *(uint64_t*) (buf + start + 24); +- ppcc.time_wind_1_min = *(uint64_t*) (buf + start + 36); +- ppcc.time_wind_1_max = *(uint64_t*) (buf + start + 48); +- ppcc.step_1_size = *(uint64_t*) (buf + start + 60); +- +- if (ppcc.power_limit_1_max && ppcc.power_limit_1_min && ppcc.time_wind_1_min +- && ppcc.time_wind_1_max && ppcc.step_1_size) +- ppcc.limit_1_valid = 1; +- else +- ppcc.limit_1_valid = 0; +- +- ppccs.push_back(ppcc); +- +- return 0; +-} +- +-void cthd_engine_adaptive::dump_ppcc() +-{ +- thd_log_info("..ppcc dump begin.. \n"); +- for (unsigned int i = 0; i < ppccs.size(); ++i) { +- thd_log_info( +- "Name:%s Limit:0 power_limit_max:%d power_limit_min:%d step_size:%d time_win_max:%d time_win_min:%d\n", +- ppccs[i].name.c_str(), ppccs[i].power_limit_max, +- ppccs[i].power_limit_min, ppccs[i].step_size, +- ppccs[i].time_wind_max, ppccs[i].time_wind_min); +- thd_log_info( +- "Name:%s Limit:1 power_limit_max:%d power_limit_min:%d step_size:%d time_win_max:%d time_win_min:%d\n", +- ppccs[i].name.c_str(), ppccs[i].power_limit_1_max, +- ppccs[i].power_limit_1_min, ppccs[i].step_1_size, +- ppccs[i].time_wind_1_max, ppccs[i].time_wind_1_min); +- } +- thd_log_info("ppcc dump end\n"); +-} +- +-int cthd_engine_adaptive::parse_psvt(char *name, char *buf, int len) { +- int offset = 0; +- int version = get_uint64(buf, &offset); +- struct psvt psvt; +- +- if (version > 2) { +- thd_log_warn("Found unsupported PSVT version %d\n", (int) version); +- throw gddv_exception; +- } +- +- if (name == NULL) +- psvt.name = "Default"; +- else +- psvt.name = name; +- while (offset < len) { +- struct psv psv; +- +- psv.source = get_string(buf, &offset); +- psv.target = get_string(buf, &offset); +- psv.priority = get_uint64(buf, &offset); +- psv.sample_period = get_uint64(buf, &offset); +- psv.temp = get_uint64(buf, &offset); +- psv.domain = get_uint64(buf, &offset); +- psv.control_knob = get_uint64(buf, &offset); +- if (get_type(buf, &offset) == 8) { +- psv.limit = get_string(buf, &offset); +- } else { +- uint64_t tmp = get_uint64(buf, &offset); +- psv.limit = std::to_string(tmp); +- } +- psv.step_size = get_uint64(buf, &offset); +- psv.limit_coeff = get_uint64(buf, &offset); +- psv.unlimit_coeff = get_uint64(buf, &offset); +- offset += 12; +- psvt.psvs.push_back(psv); +- } +- +- psvts.push_back(psvt); +- +- return 0; +-} +- +-#define DECI_KELVIN_TO_CELSIUS(t) ({ \ +- int _t = (t); \ +- ((_t-2732 >= 0) ? (_t-2732+5)/10 : (_t-2732-5)/10); \ +-}) +- +-void cthd_engine_adaptive::dump_psvt() { +- thd_log_info("..psvt dump begin.. \n"); +- for (unsigned int i = 0; i < psvts.size(); ++i) { +- std::vector psvs = psvts[i].psvs; +- +- thd_log_info("Name :%s\n", psvts[i].name.c_str()); +- for (unsigned int j = 0; j < psvs.size(); ++j) { +- thd_log_info( +- "\t source:%s target:%s priority:%d sample_period:%d temp:%d domain:%d control_knob:%d psv.limit:%s\n", +- psvs[j].source.c_str(), psvs[j].target.c_str(), +- psvs[j].priority, psvs[j].sample_period, +- DECI_KELVIN_TO_CELSIUS(psvs[j].temp), psvs[j].domain, +- psvs[j].control_knob, psvs[j].limit.c_str()); +- +- } +- } +- thd_log_info("psvt dump end\n"); +-} +- +-struct psvt* cthd_engine_adaptive::find_def_psvt() { +- for (unsigned int i = 0; i < psvts.size(); ++i) { +- if (psvts[i].name == "IETM.D0") { +- return &psvts[i]; +- } +- } +- +- return NULL; +-} +- +-int cthd_engine_adaptive::parse_itmt(char *name, char *buf, int len) { +- int offset = 0; +- int version = get_uint64(buf, &offset); +- struct itmt itmt; +- +- thd_log_debug(" ITMT version %d %s\n", (int) version, name); +- +- if (name == NULL) +- itmt.name = "Default"; +- else +- itmt.name = name; +- +- while (offset < len) { +- struct itmt_entry itmt_entry; +- +- itmt_entry.target = get_string(buf, &offset); +- itmt_entry.trip_point = get_uint64(buf, &offset); +- itmt_entry.pl1_min = get_string(buf, &offset); +- itmt_entry.pl1_max = get_string(buf, &offset); +- itmt_entry.unused = get_string(buf, &offset); +- offset += 12; +- +- itmt.itmt_entries.push_back(itmt_entry); +- } +- +- itmts.push_back(itmt); +- +- return 0; +-} +- +-void cthd_engine_adaptive::dump_itmt() { +- thd_log_info("..itmt dump begin.. \n"); +- for (unsigned int i = 0; i < itmts.size(); ++i) { +- std::vector itmt = itmts[i].itmt_entries; +- +- thd_log_info("Name :%s\n", itmts[i].name.c_str()); +- for (unsigned int j = 0; j < itmt.size(); ++j) { +- thd_log_info("\t target:%s trip_temp:%d pl1_min:%s pl1.max:%s\n", +- itmt[j].target.c_str(), +- DECI_KELVIN_TO_CELSIUS(itmt[j].trip_point), +- itmt[j].pl1_min.c_str(), itmt[j].pl1_max.c_str()); +- } +- } +- thd_log_info("itmt dump end\n"); +-} +- +-// From Common/esif_sdk_iface_esif.h: +-#define ESIF_SERVICE_CONFIG_COMPRESSED 0x40000000/* Payload is Compressed */ +-// From Common/esif_sdk.h +-#define ESIFHDR_VERSION(major, minor, revision) ((uint32_t)((((major) & 0xFF) << 24) | (((minor) & 0xFF) << 16) | ((revision) & 0xFFFF))) +-#define ESIFHDR_GET_MAJOR(version) ((uint32_t)(((version) >> 24) & 0xFF)) +-#define ESIFHDR_GET_MINOR(version) ((uint32_t)(((version) >> 16) & 0xFF)) +-#define ESIFHDR_GET_REVISION(version) ((uint32_t)((version) & 0xFFFF)) +-//From ESIF/Products/ESIF_LIB/Sources/esif_lib_datavault.c +-#define ESIFDV_HEADER_SIGNATURE 0x1FE5 +-#define ESIFDV_ITEM_KEYS_REV0_SIGNATURE 0xA0D8 +- +-int cthd_engine_adaptive::handle_compressed_gddv(char *buf, int size) { +- struct header *header = (struct header*) buf; +- uint64_t payload_output_size; +- uint64_t output_size; +- lzma_ret ret; +- int res; +- unsigned char *decompressed; +- lzma_stream strm = LZMA_STREAM_INIT; +- +- payload_output_size = *(uint64_t*) (buf + header->headersize + 5); +- output_size = header->headersize + payload_output_size; +- decompressed = (unsigned char*) malloc(output_size); +- +- if (!decompressed) { +- thd_log_warn("Failed to allocate buffer for decompressed output\n"); +- throw gddv_exception; +- } +- ret = lzma_auto_decoder(&strm, 64 * 1024 * 1024, 0); +- if (ret) { +- thd_log_warn("Failed to initialize LZMA decoder: %d\n", ret); +- free(decompressed); +- throw gddv_exception; +- } +- strm.next_out = decompressed + header->headersize; +- strm.avail_out = output_size; +- strm.next_in = (const unsigned char*) (buf + header->headersize); +- strm.avail_in = size; +- ret = lzma_code(&strm, LZMA_FINISH); +- lzma_end(&strm); +- if (ret && ret != LZMA_STREAM_END) { +- thd_log_warn("Failed to decompress GDDV data: %d\n", ret); +- free(decompressed); +- throw gddv_exception; +- } +- +- /* Copy and update header. +- * This will contain one or more nested repositories usually. */ +- memcpy (decompressed, buf, header->headersize); +- header = (struct header*) decompressed; +- header->v2.flags &= ~ESIF_SERVICE_CONFIG_COMPRESSED; +- header->v2.payload_size = payload_output_size; +- +- res = parse_gddv((char*) decompressed, output_size, NULL); +- free(decompressed); +- +- return res; +-} +- +-int cthd_engine_adaptive::parse_gddv_key(char *buf, int size, int *end_offset) { +- int offset = 0; +- uint32_t keyflags; +- uint32_t keylength; +- uint32_t valtype; +- uint32_t vallength; +- char *key; +- char *val; +- char *str; +- char *name = NULL; +- char *type = NULL; +- char *point = NULL; +- char *ns = NULL; +- +- memcpy(&keyflags, buf + offset, sizeof(keyflags)); +- offset += sizeof(keyflags); +- memcpy(&keylength, buf + offset, sizeof(keylength)); +- offset += sizeof(keylength); +- key = new char[keylength]; +- memcpy(key, buf + offset, keylength); +- offset += keylength; +- memcpy(&valtype, buf + offset, sizeof(valtype)); +- offset += sizeof(valtype); +- memcpy(&vallength, buf + offset, sizeof(vallength)); +- offset += sizeof(vallength); +- val = new char[vallength]; +- memcpy(val, buf + offset, vallength); +- offset += vallength; +- +- if (end_offset) +- *end_offset = offset; +- +- str = strtok(key, "/"); +- if (!str) { +- thd_log_debug("Ignoring key %s\n", key); +- +- delete[] (key); +- delete[] (val); +- +- /* Ignore */ +- return THD_SUCCESS; +- } +- if (strcmp(str, "participants") == 0) { +- name = strtok(NULL, "/"); +- type = strtok(NULL, "/"); +- point = strtok(NULL, "/"); +- } else if (strcmp(str, "shared") == 0) { +- ns = strtok(NULL, "/"); +- type = strtok(NULL, "/"); +- if (strcmp(ns, "tables") == 0) { +- point = strtok(NULL, "/"); +- } +- } +- if (name && type && strcmp(type, "ppcc") == 0) { +- parse_ppcc(name, val, vallength); +- } +- +- if (type && strcmp(type, "psvt") == 0) { +- if (point == NULL) +- parse_psvt(name, val, vallength); +- else +- parse_psvt(point, val, vallength); +- } +- +- if (type && strcmp(type, "appc") == 0) { +- parse_appc(val, vallength); +- } +- +- if (type && strcmp(type, "apct") == 0) { +- parse_apct(val, vallength); +- } +- +- if (type && strcmp(type, "apat") == 0) { +- parse_apat(val, vallength); +- } +- +- if (type && strcmp(type, "itmt") == 0) { +- if (point == NULL) +- parse_itmt(name, val, vallength); +- else +- parse_itmt(point, val, vallength); +- } +- +- delete[] (key); +- delete[] (val); +- +- return THD_SUCCESS; +-} +- +-int cthd_engine_adaptive::parse_gddv(char *buf, int size, int *end_offset) { +- int offset = 0; +- struct header *header; +- +- if (size < (int) sizeof(struct header)) +- return THD_ERROR; +- +- header = (struct header*) buf; +- +- if (header->signature != ESIFDV_HEADER_SIGNATURE) { +- thd_log_warn("Unexpected GDDV signature 0x%x\n", header->signature); +- throw gddv_exception; +- } +- if (ESIFHDR_GET_MAJOR(header->version) != 1 +- && ESIFHDR_GET_MAJOR(header->version) != 2) +- return THD_ERROR; +- +- offset = header->headersize; +- +- thd_log_debug("header version[%d] size[%d] header_size[%d] flags[%08X]\n", +- ESIFHDR_GET_MAJOR(header->version), size, header->headersize, header->v1.flags); +- +- if (ESIFHDR_GET_MAJOR(header->version) == 2) { +- char name[ESIFDV_NAME_LEN + 1] = { 0 }; +- char comment[ESIFDV_DESC_LEN + 1] = { 0 }; +- +- if (header->v2.flags & ESIF_SERVICE_CONFIG_COMPRESSED) { +- thd_log_debug("Uncompress GDDV payload\n"); +- return handle_compressed_gddv(buf, size); +- } +- +- strncpy(name, header->v2.segmentid, sizeof(name) - 1); +- strncpy(comment, header->v2.comment, sizeof(comment) - 1); +- +- thd_log_debug("DV name: %s\n", name); +- thd_log_debug("DV comment: %s\n", comment); +- +- thd_log_debug("Got payload of size %d (data length: %d)\n", size, header->v2.payload_size); +- size = header->v2.payload_size; +- } +- +- while ((offset + header->headersize) < size) { +- int res; +- int end_offset = 0; +- +- if (ESIFHDR_GET_MAJOR(header->version) == 2) { +- unsigned short signature; +- +- signature = *(unsigned short *) (buf + offset); +- if (signature == ESIFDV_ITEM_KEYS_REV0_SIGNATURE) { +- offset += sizeof(unsigned short); +- res = parse_gddv_key(buf + offset, size - offset, &end_offset); +- if (res != THD_SUCCESS) +- return res; +- offset += end_offset; +- } else if (signature == ESIFDV_HEADER_SIGNATURE) { +- thd_log_info("Got subobject in buf %p at %d\n", buf, offset); +- res = parse_gddv(buf + offset, size - offset, &end_offset); +- if (res != THD_SUCCESS) +- return res; +- +- /* Parse recursively */ +- offset += end_offset; +- thd_log_info("Subobject ended at %d of %d\n", offset, size); +- } else { +- thd_log_info("No known signature found 0x%04X\n", *(unsigned short *) (buf + offset)); +- return THD_ERROR; +- } +- } else { +- res = parse_gddv_key(buf + offset, size - offset, &end_offset); +- if (res != THD_SUCCESS) +- return res; +- offset += end_offset; +- } +- } +- +- if (end_offset) +- *end_offset = offset; +- +- return 0; +-} +- +-int cthd_engine_adaptive::verify_condition(struct condition condition) { +- const char *cond_name; +- +- if (condition.condition >= Oem0 && condition.condition <= Oem5) +- return 0; +- if (condition.condition >= adaptive_condition(0x1000) +- && condition.condition < adaptive_condition(0x10000)) +- return 0; +- if (condition.condition == Default) +- return 0; +- if (condition.condition == Temperature +- || condition.condition == Temperature_without_hysteresis +- || condition.condition == (adaptive_condition) 0) { +- return 0; +- } +- if (condition.condition == Lid_state && lid_dev != NULL) +- return 0; +- if (condition.condition == Power_source && upower_client != NULL) +- return 0; +- if (condition.condition == Workload) +- return 0; +- if (condition.condition == Platform_type) +- return 0; +- if (condition.condition == Power_slider) +- return 0; +- +- if ( condition.condition >= ARRAY_SIZE(condition_names)) +- cond_name = "UKNKNOWN"; +- else +- cond_name = condition_names[condition.condition]; +- thd_log_error("Unsupported condition %" PRIu64 " (%s)\n", condition.condition, cond_name); +- +- return THD_ERROR; +-} +- +-int cthd_engine_adaptive::verify_conditions() { +- int result = 0; +- for (int i = 0; i < (int) conditions.size(); i++) { +- for (int j = 0; j < (int) conditions[i].size(); j++) { +- if (verify_condition(conditions[i][j])) +- result = THD_ERROR; +- } +- } +- +- if (result != 0) +- thd_log_error("Unsupported conditions are present\n"); +- +- return result; +-} +- +-int cthd_engine_adaptive::compare_condition(struct condition condition, +- int value) { +- +- if (debug_mode_on()) { +- if (condition.condition < ARRAY_SIZE(condition_names)) { +- std::string cond_name, comp_str, op_str; +- +- cond_name = condition_names[condition.condition]; +- if (condition.comparison < ARRAY_SIZE(comp_strs)) { +- comp_str = comp_strs[condition.comparison]; +- thd_log_debug( +- "compare condition [%s] comparison [%s] value [%d]\n", +- cond_name.c_str(), comp_str.c_str(), value); +- } else { +- thd_log_debug( +- "compare condition [%s] comparison [%" PRIu64 "] value [%d]\n", +- cond_name.c_str(), condition.comparison, value); +- } +- } else { +- thd_log_debug("compare condition %" PRIu64 " value %d\n", +- condition.comparison, value); +- } +- } +- +- switch (condition.comparison) { +- case ADAPTIVE_EQUAL: +- if (value == condition.argument) +- return THD_SUCCESS; +- else +- return THD_ERROR; +- break; +- case ADAPTIVE_LESSER_OR_EQUAL: +- if (value <= condition.argument) +- return THD_SUCCESS; +- else +- return THD_ERROR; +- break; +- case ADAPTIVE_GREATER_OR_EQUAL: +- if (value >= condition.argument) +- return THD_SUCCESS; +- else +- return THD_ERROR; +- break; +- default: +- return THD_ERROR; +- } +-} +- +-int cthd_engine_adaptive::compare_time(struct condition condition) { +- int elapsed = time(NULL) - condition.state_entry_time; +- +- switch (condition.time_comparison) { +- case ADAPTIVE_EQUAL: +- if (elapsed == condition.time) +- return THD_SUCCESS; +- else +- return THD_ERROR; +- break; +- case ADAPTIVE_LESSER_OR_EQUAL: +- if (elapsed <= condition.time) +- return THD_SUCCESS; +- else +- return THD_ERROR; +- break; +- case ADAPTIVE_GREATER_OR_EQUAL: +- if (elapsed >= condition.time) +- return THD_SUCCESS; +- else +- return THD_ERROR; +- break; +- default: +- return THD_ERROR; +- } +-} +- +-int cthd_engine_adaptive::evaluate_oem_condition(struct condition condition) { +- csys_fs sysfs(int3400_base_path.c_str()); +- int oem_condition = -1; +- +- if (condition.condition >= Oem0 && condition.condition <= Oem5) +- oem_condition = (int) condition.condition - Oem0; +- else if (condition.condition >= (adaptive_condition) 0x1000 +- && condition.condition < (adaptive_condition) 0x10000) +- oem_condition = (int) condition.condition - 0x1000 + 6; +- +- if (oem_condition != -1) { +- std::string filename = "odvp" + std::to_string(oem_condition); +- std::string data; +- if (sysfs.read(filename, data) < 0) { +- thd_log_error("Unable to read %s\n", filename.c_str()); +- return THD_ERROR; +- } +- int value = std::stoi(data, NULL); +- +- return compare_condition(condition, value); +- } +- +- return THD_ERROR; +-} +- +-int cthd_engine_adaptive::evaluate_temperature_condition( +- struct condition condition) { +- std::string sensor_name; +- +- if (condition.ignore_condition) +- return THD_ERROR; +- +- size_t pos = condition.device.find_last_of("."); +- if (pos == std::string::npos) +- sensor_name = condition.device; +- else +- sensor_name = condition.device.substr(pos + 1); +- +- cthd_sensor *sensor = search_sensor(sensor_name); +- if (!sensor) { +- thd_log_warn("Unable to find a sensor for %s\n", +- condition.device.c_str()); +- condition.ignore_condition = 1; +- return THD_ERROR; +- } +- +- int value = sensor->read_temperature(); +- +- // Conditions are specified in decikelvin, temperatures are in +- // millicelsius. +- value = value / 100 + 2732; +- return compare_condition(condition, value); +-} +- +-int cthd_engine_adaptive::evaluate_lid_condition(struct condition condition) { +- int value = 0; +- +- if (lid_dev) { +- struct input_event ev; +- +- while (libevdev_has_event_pending(lid_dev)) +- libevdev_next_event(lid_dev, LIBEVDEV_READ_FLAG_NORMAL, &ev); +- +- int lid_closed = libevdev_get_event_value(lid_dev, EV_SW, SW_LID); +- value = !lid_closed; +- } +- return compare_condition(condition, value); +-} +- +-int cthd_engine_adaptive::evaluate_workload_condition( +- struct condition condition) { +- // We don't have a good way to assert workload at the moment, so just +- // default to bursty +- +- return compare_condition(condition, 3); +-} +- +-int cthd_engine_adaptive::evaluate_platform_type_condition( +- struct condition condition) { +- int value = 1; +- +- if (tablet_dev) { +- struct input_event ev; +- +- while (libevdev_has_event_pending(tablet_dev)) +- libevdev_next_event(tablet_dev, LIBEVDEV_READ_FLAG_NORMAL, &ev); +- +- int tablet = libevdev_get_event_value(tablet_dev, EV_SW, +- SW_TABLET_MODE); +- if (tablet) +- value = 2; +- } +- return compare_condition(condition, value); +-} +- +-int cthd_engine_adaptive::evaluate_power_slider_condition( +- struct condition condition) { +- +- return compare_condition(condition, power_slider); +-} +- +-int cthd_engine_adaptive::evaluate_ac_condition(struct condition condition) { +- int value = 0; +- bool on_battery = up_client_get_on_battery(upower_client); +- +- if (on_battery) +- value = 1; +- +- return compare_condition(condition, value); +-} +- +-int cthd_engine_adaptive::evaluate_condition(struct condition condition) { +- int ret = THD_ERROR; +- +- if (condition.condition == Default) +- return THD_SUCCESS; +- +- thd_log_debug("evaluate condition.condition %" PRIu64 "\n", condition.condition); +- +- if ((condition.condition >= Oem0 && condition.condition <= Oem5) +- || (condition.condition >= (adaptive_condition) 0x1000 +- && condition.condition < (adaptive_condition) 0x10000)) +- ret = evaluate_oem_condition(condition); +- +- if (condition.condition == Temperature +- || condition.condition == Temperature_without_hysteresis +- || condition.condition == (adaptive_condition) 0) { +- ret = evaluate_temperature_condition(condition); +- } +- +- if (condition.condition == Lid_state) { +- ret = evaluate_lid_condition(condition); +- } +- +- if (condition.condition == Power_source) { +- ret = evaluate_ac_condition(condition); +- } +- +- if (condition.condition == Workload) { +- ret = evaluate_workload_condition(condition); +- } +- +- if (condition.condition == Platform_type) { +- ret = evaluate_platform_type_condition(condition); +- } +- +- if (condition.condition == Power_slider) { +- ret = evaluate_power_slider_condition(condition); +- } +- +- if (ret) { +- if (condition.time && condition.state_entry_time == 0) { +- condition.state_entry_time = time(NULL); +- } +- ret = compare_time(condition); +- } else { +- condition.state_entry_time = 0; +- } +- +- return ret; +-} +- +-int cthd_engine_adaptive::evaluate_condition_set( +- std::vector condition_set) { +- for (int i = 0; i < (int) condition_set.size(); i++) { +- thd_log_debug("evaluate condition.condition at index %d\n", i); +- if (evaluate_condition(condition_set[i]) != 0) +- return THD_ERROR; +- } +- return THD_SUCCESS; +-} +- +-int cthd_engine_adaptive::evaluate_conditions() { +- int target = -1; +- +- if (fallback_id >= 0) +- return -1; +- +- for (int i = 0; i < (int) conditions.size(); i++) { +- thd_log_debug("evaluate condition set %d\n", i); +- if (evaluate_condition_set(conditions[i]) == THD_SUCCESS) { +- if (policy_active && i == current_condition_set) +- break; +- +- current_condition_set = i; +- target = conditions[i][0].target; +- thd_log_info("Condition Set matched:%d target:%d\n", i, target); +- +- break; +- } +- } +- +- return target; +-} +- +-struct psvt* cthd_engine_adaptive::find_psvt(std::string name) { +- for (int i = 0; i < (int) psvts.size(); i++) { +- if (!strcasecmp(psvts[i].name.c_str(), name.c_str())) { +- return &psvts[i]; +- } +- } +- +- return NULL; +-} +- +-struct itmt* cthd_engine_adaptive::find_itmt(std::string name) { +- for (int i = 0; i < (int) itmts.size(); i++) { +- if (!strcasecmp(itmts[i].name.c_str(), name.c_str())) { +- return &itmts[i]; +- } +- } +- +- return NULL; +-} + + int cthd_engine_adaptive::install_passive(struct psv *psv) { + std::string psv_zone; +@@ -1254,17 +47,18 @@ int cthd_engine_adaptive::install_passive(struct psv *psv) { + cthd_zone *zone = search_zone(psv_zone); + if (!zone) { + if (!psv_zone.compare(0, 4, "B0D4")) { +- psv_zone= "TCPU"; ++ psv_zone = "TCPU"; + zone = search_zone(psv_zone); + } + + if (!zone) { + if (!psv_zone.compare(0, 4, "TCPU")) { +- psv_zone= "B0D4"; ++ psv_zone = "B0D4"; + zone = search_zone(psv_zone); + } + if (!zone) { +- thd_log_warn("Unable to find a zone for %s\n", psv_zone.c_str()); ++ thd_log_warn("Unable to find a zone for %s\n", ++ psv_zone.c_str()); + return THD_ERROR; + } + } +@@ -1285,13 +79,13 @@ int cthd_engine_adaptive::install_passive(struct psv *psv) { + + if (!cdev) { + if (!psv_cdev.compare(0, 4, "TCPU")) { +- psv_cdev= "B0D4"; ++ psv_cdev = "B0D4"; + cdev = search_cdev(psv_cdev); + } + + if (!cdev) { + thd_log_warn("Unable to find a cooling device for %s\n", +- psv_cdev.c_str()); ++ psv_cdev.c_str()); + return THD_ERROR; + } + } +@@ -1306,9 +100,9 @@ int cthd_engine_adaptive::install_passive(struct psv *psv) { + int target_state = 0; + + if (psv->limit.length()) { +- if (!strncasecmp(psv->limit.c_str(),"MAX", 3)) { ++ if (!strncasecmp(psv->limit.c_str(), "MAX", 3)) { + target_state = TRIP_PT_INVALID_TARGET_STATE; +- } else if (!strncasecmp(psv->limit.c_str(),"MIN", 3)) { ++ } else if (!strncasecmp(psv->limit.c_str(), "MIN", 3)) { + target_state = 0; + } else { + std::istringstream buffer(psv->limit); +@@ -1317,17 +111,11 @@ int cthd_engine_adaptive::install_passive(struct psv *psv) { + } + } + +- cthd_trip_point trip_pt(zone->get_trip_count(), +- PASSIVE, +- temp, 0, +- zone->get_zone_index(), sensor->get_index(), +- SEQUENTIAL); +- trip_pt.thd_trip_point_add_cdev(*cdev, +- cthd_trip_point::default_influence, +- psv->sample_period / 10, +- target_state ? 1 : 0, +- target_state, +- NULL, 0, 0, 0); ++ cthd_trip_point trip_pt(zone->get_trip_count(), PASSIVE, temp, 0, ++ zone->get_zone_index(), sensor->get_index(), SEQUENTIAL); ++ trip_pt.thd_trip_point_add_cdev(*cdev, cthd_trip_point::default_influence, ++ psv->sample_period / 10, target_state ? 1 : 0, target_state, ++ NULL, 0, 0, 0); + zone->add_trip(trip_pt, 1); + zone->zone_cdev_set_binded(); + zone->set_zone_active(); +@@ -1370,8 +158,7 @@ void cthd_engine_adaptive::set_trip(std::string target, std::string argument) { + thd_log_warn("Unable to find a passive trippoint for %s\n", target.c_str()); + } + +-void cthd_engine_adaptive::psvt_consolidate() +-{ ++void cthd_engine_adaptive::psvt_consolidate() { + /* Once all tables are installed, we need to consolidate since + * thermald has different implementation. + * If there is only entry of type MAX, then simply use thermald default at temperature + 1 +@@ -1529,7 +316,7 @@ int cthd_engine_adaptive::set_itmt_target(struct adaptive_target target) { + + thd_log_info("set_int3400 ITMT target %s\n", target.argument.c_str()); + +- itmt = find_itmt(target.argument); ++ itmt = gddv.find_itmt(target.argument); + if (!itmt) { + return THD_ERROR; + } +@@ -1576,7 +363,7 @@ void cthd_engine_adaptive::set_int3400_target(struct adaptive_target target) { + + thd_log_info("set_int3400 target %s\n", target.argument.c_str()); + +- psvt = find_psvt(target.argument); ++ psvt = gddv.find_psvt(target.argument); + if (!psvt) { + return; + } +@@ -1624,6 +411,41 @@ void cthd_engine_adaptive::set_int3400_target(struct adaptive_target target) { + } + } + ++void cthd_engine_adaptive::install_passive_default() { ++ if (passive_installed) ++ return; ++ ++ thd_log_info("IETM_D0 processed\n"); ++ ++ for (unsigned int i = 0; i < zones.size(); ++i) { ++ cthd_zone *_zone = zones[i]; ++ _zone->zone_reset(1); ++ _zone->trip_delete_all(); ++ ++ if (_zone->zone_active_status()) ++ _zone->set_zone_inactive(); ++ } ++ ++ struct psvt *psvt = gddv.find_def_psvt(); ++ if (!psvt) ++ return; ++ ++ std::vector psvs = psvt->psvs; ++ ++ thd_log_info("Name :%s\n", psvt->name.c_str()); ++ for (unsigned int j = 0; j < psvs.size(); ++j) { ++ install_passive(&psvs[j]); ++ } ++ ++ psvt_consolidate(); ++ thd_log_info("\n\n ZONE DUMP BEGIN\n"); ++ for (unsigned int i = 0; i < zones.size(); ++i) { ++ zones[i]->zone_dump(); ++ } ++ thd_log_info("\n\n ZONE DUMP END\n"); ++ passive_installed = 1; ++} ++ + void cthd_engine_adaptive::execute_target(struct adaptive_target target) { + cthd_cdev *cdev; + std::string name; +@@ -1661,10 +483,9 @@ void cthd_engine_adaptive::execute_target(struct adaptive_target target) { + + try { + argument = std::stoi(target.argument, NULL); +- } +- catch (...) { ++ } catch (...) { + thd_log_info("Invalid target target:%s %s\n", target.code.c_str(), +- target.argument.c_str()); ++ target.argument.c_str()); + return; + } + thd_log_info("target:%s %d\n", target.code.c_str(), argument); +@@ -1672,173 +493,42 @@ void cthd_engine_adaptive::execute_target(struct adaptive_target target) { + cdev->set_adaptive_target(target); + } + +-void cthd_engine_adaptive::exec_fallback_target(int target){ ++void cthd_engine_adaptive::exec_fallback_target(int target) { + thd_log_debug("exec_fallback_target %d\n", target); +- for (int i = 0; i < (int) targets.size(); i++) { +- if (targets[i].target_id != (uint64_t) target) ++ for (int i = 0; i < (int) gddv.targets.size(); i++) { ++ if (gddv.targets[i].target_id != (uint64_t) target) + continue; +- execute_target(targets[i]); ++ execute_target(gddv.targets[i]); + } + } + + void cthd_engine_adaptive::update_engine_state() { + +- if (passive_def_only || !passive_installed) { +- if (!passive_def_processed) { +- +- if (!passive_def_only && !passive_installed) { +- thd_log_warn( +- "Manufacturer didn't provide adequate support to run in\n"); +- thd_log_warn( +- "optimized configuration on Linux with open source\n"); +- thd_log_warn( +- "You may want to disable thermald on this system if you see issue\n"); +- } +- +- thd_log_info("IETM_D0 processed\n"); +- passive_def_processed = 1; +- +- for (unsigned int i = 0; i < zones.size(); ++i) { +- cthd_zone *_zone = zones[i]; +- _zone->zone_reset(1); +- _zone->trip_delete_all(); +- +- if (_zone->zone_active_status()) +- _zone->set_zone_inactive(); +- } +- +- struct psvt *psvt = find_def_psvt(); +- if (!psvt) +- return; ++ int target = -1; + +- std::vector psvs = psvt->psvs; ++ if (passive_def_only) ++ return; + +- thd_log_info("Name :%s\n", psvt->name.c_str()); +- for (unsigned int j = 0; j < psvs.size(); ++j) { +- install_passive(&psvs[j]); +- } +- psvt_consolidate(); +- thd_log_info("\n\n ZONE DUMP BEGIN\n"); +- for (unsigned int i = 0; i < zones.size(); ++i) { +- zones[i]->zone_dump(); +- } +- thd_log_info("\n\n ZONE DUMP END\n"); +- passive_installed = 1; +- } +- if (passive_def_only) +- return; +- } ++ if (fallback_id < 0) ++ target = gddv.evaluate_conditions(policy_active); + +- int target = evaluate_conditions(); + if (target == -1) { + if (fallback_id >= 0 && !policy_active) { +- exec_fallback_target(targets[fallback_id].target_id); ++ exec_fallback_target(gddv.targets[fallback_id].target_id); + policy_active = 1; + } + return; + } +- for (int i = 0; i < (int) targets.size(); i++) { +- if (targets[i].target_id != (uint64_t) target) ++ for (int i = 0; i < (int) gddv.targets.size(); i++) { ++ if (gddv.targets[i].target_id != (uint64_t) target) + continue; +- execute_target(targets[i]); ++ execute_target(gddv.targets[i]); + } + policy_active = 1; + } + +-int cthd_engine_adaptive::find_agressive_target() { +- int max_pl1_max = 0; +- int max_target_id = -1; +- +- for (int i = 0; i < (int) targets.size(); i++) { +- int argument; +- +- if (targets[i].code != "PL1MAX" && targets[i].code != "PL1PowerLimit") +- continue; +- +- try { +- argument = std::stoi(targets[i].argument, NULL); +- } +- catch (...) { +- thd_log_info("Invalid target target:%s %s\n", targets[i].code.c_str(), +- targets[i].argument.c_str()); +- continue; +- } +- thd_log_info("target:%s %d\n", targets[i].code.c_str(), argument); +- +- if (max_pl1_max < argument) { +- max_pl1_max = argument; +- max_target_id = i; +- } +- } +- +- return max_target_id; +-} +- +-static int is_event_device(const struct dirent *dir) { +- return strncmp("event", dir->d_name, 5) == 0; +-} +- +-void cthd_engine_adaptive::setup_input_devices() { +- struct dirent **namelist; +- int i, ndev, ret; +- +- ndev = scandir("/dev/input", &namelist, is_event_device, versionsort); +- for (i = 0; i < ndev; i++) { +- struct libevdev *dev = NULL; +- char fname[267]; +- int fd = -1; +- +- snprintf(fname, sizeof(fname), "/dev/input/%s", namelist[i]->d_name); +- fd = open(fname, O_RDONLY | O_NONBLOCK | O_CLOEXEC); +- if (fd < 0) +- continue; +- ret = libevdev_new_from_fd(fd, &dev); +- if (ret) { +- close(fd); +- continue; +- } +- +- if (!tablet_dev && libevdev_has_event_code(dev, EV_SW, SW_TABLET_MODE)) +- tablet_dev = dev; +- if (!lid_dev && libevdev_has_event_code(dev, EV_SW, SW_LID)) +- lid_dev = dev; +- +- if (lid_dev != dev && tablet_dev != dev) { +- libevdev_free(dev); +- close(fd); +- } +- } +-} +- +-void cthd_engine_adaptive::update_power_slider() +-{ +- g_autoptr(GVariant) active_profile_v = NULL; +- +- active_profile_v = g_dbus_proxy_get_cached_property (power_profiles_daemon, "ActiveProfile"); +- if (active_profile_v && g_variant_is_of_type (active_profile_v, G_VARIANT_TYPE_STRING)) { +- const char *active_profile = g_variant_get_string (active_profile_v, NULL); +- +- if (strcmp (active_profile, "power-saver") == 0) +- power_slider = 25; /* battery saver */ +- else if (strcmp (active_profile, "balanced") == 0) +- power_slider = 75; /* better performance */ +- else if (strcmp (active_profile, "performance") == 0) +- power_slider = 100; /* best performance */ +- else +- power_slider = 75; +- } else { +- power_slider = 75; +- } +- +- thd_log_info("Power slider is now set to %d\n", power_slider); +-} +- +-static void power_profiles_changed_cb(cthd_engine_adaptive *engine) +-{ +- engine->update_power_slider(); +-} +- +-int cthd_engine_adaptive::thd_engine_init(bool ignore_cpuid_check, bool adaptive) { ++int cthd_engine_adaptive::thd_engine_init(bool ignore_cpuid_check, ++ bool adaptive) { + csys_fs sysfs(""); + char *buf; + size_t size; +@@ -1877,9 +567,8 @@ int cthd_engine_adaptive::thd_engine_init(bool ignore_cpuid_check, bool adaptive + if (res != THD_SUCCESS) + return res; + +- +- if (sysfs.read(int3400_base_path + "firmware_node/path", +- int3400_path) < 0) { ++ if (sysfs.read(int3400_base_path + "firmware_node/path", int3400_path) ++ < 0) { + thd_log_debug("Unable to locate INT3400 firmware path\n"); + return THD_ERROR; + } +@@ -1896,39 +585,21 @@ int cthd_engine_adaptive::thd_engine_init(bool ignore_cpuid_check, bool adaptive + return THD_FATAL_ERROR; + } + +- if (sysfs.read(int3400_base_path + "data_vault", buf, size) +- < int(size)) { ++ if (sysfs.read(int3400_base_path + "data_vault", buf, size) < int(size)) { + thd_log_debug("Unable to read GDDV data vault\n"); + delete[] buf; + return THD_FATAL_ERROR; + } + +- try { +- if (parse_gddv(buf, size, NULL)) { +- thd_log_debug("Unable to parse GDDV"); +- delete[] buf; +- return THD_FATAL_ERROR; +- } +- +- merge_appc(); +- +- dump_ppcc(); +- dump_psvt(); +- dump_itmt(); +- dump_apat(); +- dump_apct(); +- +- delete [] buf; +- } catch (std::exception &e) { +- thd_log_warn("%s\n", e.what()); +- delete [] buf; +- return THD_FATAL_ERROR; ++ res = gddv.gddv_init(); ++ if (res != THD_SUCCESS) { ++ return res; + } + +- if (!conditions.size()) { ++ if (!gddv.conditions.size()) { + thd_log_info("No adaptive conditions present\n"); + +- struct psvt *psvt = find_def_psvt(); ++ struct psvt *psvt = gddv.find_def_psvt(); + + if (psvt) { + thd_log_info("IETM.D0 found\n"); +@@ -1941,63 +612,42 @@ int cthd_engine_adaptive::thd_engine_init(bool ignore_cpuid_check, bool adaptive + } + + int cthd_engine_adaptive::thd_engine_start() { +- g_autoptr(GDBusConnection) bus = NULL; +- +- if (passive_def_only) ++ if (passive_def_only) { ++ install_passive_default(); + return cthd_engine::thd_engine_start(); +- +- setup_input_devices(); +- +- upower_client = up_client_new(); +- if (!upower_client) { +- thd_log_info("Unable to connect to upower\n"); + } + +- if (verify_conditions()) { +- thd_log_info("Some conditions are not supported, so check if any condition set can be matched\n"); +- int target = evaluate_conditions(); ++ if (gddv.verify_conditions()) { ++ thd_log_info( ++ "Some conditions are not supported, so check if any condition set can be matched\n"); ++ int target = gddv.evaluate_conditions(policy_active); + if (target == -1) { + thd_log_info("Also unable to evaluate any conditions\n"); +- thd_log_info("Falling back to use configuration with the highest power\n"); +- +- destroy_dynamic_sources(); ++ thd_log_info( ++ "Falling back to use configuration with the highest power\n"); + +- int i = find_agressive_target(); ++ int i = gddv.find_agressive_target(); + thd_log_info("target:%d\n", i); + if (i >= 0) { + thd_log_info("fallback id:%d\n", i); + fallback_id = i; + } else { +- return THD_ERROR; ++ struct psvt *psvt = gddv.find_def_psvt(); ++ ++ if (psvt) { ++ thd_log_info("IETM.D0 found\n"); ++ install_passive_default(); ++ } else { ++ gddv.gddv_free(); ++ return THD_ERROR; ++ } + } + } + } + + set_control_mode(EXCLUSIVE); + +- bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); +- if (bus) { +- power_profiles_daemon = g_dbus_proxy_new_sync (bus, +- G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, +- NULL, +- "net.hadess.PowerProfiles", +- "/net/hadess/PowerProfiles", +- "net.hadess.PowerProfiles", +- NULL, +- NULL); +- +- if (power_profiles_daemon) { +- g_signal_connect_swapped (power_profiles_daemon, +- "g-properties-changed", +- (GCallback) power_profiles_changed_cb, +- this); +- power_profiles_changed_cb(this); +- } else { +- thd_log_info("Could not setup DBus watch for power-profiles-daemon"); +- } +- } +- +- evaluate_conditions(); ++ gddv.evaluate_conditions(policy_active); + thd_log_info("adaptive engine reached end\n"); + + return cthd_engine::thd_engine_start(); +@@ -2018,8 +668,10 @@ int thd_engine_create_adaptive_engine(bool ignore_cpuid_check, bool test_mode) { + thd_log_info("THD engine start failed\n"); + if (test_mode) { + thd_log_warn("This platform doesn't support adaptive mode\n"); +- thd_log_warn("It is possible that manufacturer doesn't support DPTF tables or\n"); +- thd_log_warn("didn't provide tables, which can be parsed in open source.\n"); ++ thd_log_warn( ++ "It is possible that manufacturer doesn't support DPTF tables or\n"); ++ thd_log_warn( ++ "didn't provide tables, which can be parsed in open source.\n"); + exit(0); + } + return THD_ERROR; +diff --git a/src/thd_engine_adaptive.h b/src/thd_engine_adaptive.h +index 2e1acd7..99c021c 100644 +--- a/src/thd_engine_adaptive.h ++++ b/src/thd_engine_adaptive.h +@@ -33,213 +33,42 @@ + #include "thd_cpu_default_binding.h" + #include "thd_adaptive_types.h" + +-enum adaptive_condition { +- Default = 0x01, +- Orientation, +- Proximity, +- Motion, +- Dock, +- Workload, +- Cooling_mode, +- Power_source, +- Aggregate_power_percentage, +- Lid_state, +- Platform_type, +- Platform_SKU, +- Utilisation, +- TDP, +- Duty_cycle, +- Power, +- Temperature, +- Display_orientation, +- Oem0, +- Oem1, +- Oem2, +- Oem3, +- Oem4, +- Oem5, +- PMAX, +- PSRC, +- ARTG, +- CTYP, +- PROP, +- Unk1, +- Unk2, +- Battery_state, +- Battery_rate, +- Battery_remaining, +- Battery_voltage, +- PBSS, +- Battery_cycles, +- Battery_last_full, +- Power_personality, +- Battery_design_capacity, +- Screen_state, +- AVOL, +- ACUR, +- AP01, +- AP02, +- AP10, +- Time, +- Temperature_without_hysteresis, +- Mixed_reality, +- User_presence, +- RBHF, +- VBNL, +- CMPP, +- Battery_percentage, +- Battery_count, +- Power_slider +-}; +- +-enum adaptive_comparison { +- ADAPTIVE_EQUAL = 0x01, +- ADAPTIVE_LESSER_OR_EQUAL, +- ADAPTIVE_GREATER_OR_EQUAL, +-}; +- +-enum adaptive_operation { +- AND = 0x01, +- FOR +-}; +- +-struct psv { +- std::string name; +- std::string source; +- std::string target; +- int priority; +- int sample_period; +- int temp; +- int domain; +- int control_knob; +- std::string limit; +- int step_size; +- int limit_coeff; +- int unlimit_coeff; +-}; +- +-struct condition { +- uint64_t condition; +- std::string device; +- uint64_t comparison; +- int argument; +- enum adaptive_operation operation; +- enum adaptive_comparison time_comparison; +- int time; +- int target; +- int state; +- int state_entry_time; +- int ignore_condition; +-}; +- +-struct custom_condition { +- enum adaptive_condition condition; +- std::string name; +- std::string participant; +- int domain; +- int type; +-}; +- +-struct psvt { +- std::string name; +- std::vector psvs; +-}; +- +-struct itmt_entry { +- std::string target; +- int trip_point; +- std::string pl1_min; +- std::string pl1_max; +- std::string unused; +-}; +- +-struct itmt { +- std::string name; +- std::vector itmt_entries; +-}; + + class cthd_engine_adaptive: public cthd_engine_default { + protected: +- std::vector ppccs; +- std::vector> conditions; +- std::vector custom_conditions; +- std::vector targets; +- std::vector psvts; +- std::vector itmts; +- std::string int3400_path; +- UpClient *upower_client; +- GDBusProxy *power_profiles_daemon; +- struct libevdev *tablet_dev; +- struct libevdev *lid_dev; +- int current_condition_set; ++ + int policy_active; + int fallback_id; ++ std::string int3400_path; + std::string int3400_base_path; + int passive_def_only; + int passive_def_processed; + int passive_installed; +- + int power_slider; + +- void destroy_dynamic_sources(); +- int get_type(char *object, int *offset); +- uint64_t get_uint64(char *object, int *offset); +- char* get_string(char *object, int *offset); +- int merge_custom(struct custom_condition *custom, +- struct condition *condition); +- int merge_appc(void); +- int parse_appc(char *appc, int len); +- int parse_apat(char *apat, int len); +- int parse_apct(char *apct, int len); +- int parse_ppcc(char *name, char *ppcc, int len); +- int parse_psvt(char *name, char *psvt, int len); +- int parse_itmt(char *name, char *itmt, int len); +- int handle_compressed_gddv(char *buf, int size); +- int parse_gddv_key(char *buf, int size, int *end_offset); +- int parse_gddv(char *buf, int size, int *end_offset); +- struct psvt* find_psvt(std::string name); +- struct itmt* find_itmt(std::string name); + int set_itmt_target(struct adaptive_target target); + int install_passive(struct psv *psv); + int install_itmt(struct itmt_entry *itmt_entry); + void psvt_consolidate(); + void set_trip(std::string device, std::string argument); + void set_int3400_target(struct adaptive_target target); +- int verify_condition(struct condition condition); +- int verify_conditions(); +- int compare_condition(struct condition condition, int value); +- int compare_time(struct condition condition); +- int evaluate_oem_condition(struct condition condition); +- int evaluate_temperature_condition(struct condition condition); +- int evaluate_ac_condition(struct condition condition); +- int evaluate_lid_condition(struct condition condition); +- int evaluate_workload_condition(struct condition condition); +- int evaluate_platform_type_condition(struct condition condition); +- int evaluate_power_slider_condition(struct condition condition); +- int evaluate_condition(struct condition condition); +- int evaluate_condition_set(std::vector condition_set); +- int evaluate_conditions(); +- void execute_target(struct adaptive_target target); +- void setup_input_devices(); +- int find_agressive_target(); + void exec_fallback_target(int target); +- void dump_apat(); +- void dump_apct(); +- void dump_ppcc(); +- void dump_psvt(); +- void dump_itmt(); +- struct psvt *find_def_psvt(); ++ void execute_target(struct adaptive_target target); ++ void install_passive_default(); + + public: + cthd_engine_adaptive() : +- cthd_engine_default("63BE270F-1C11-48FD-A6F7-3AF253FF3E2D"), upower_client( +- NULL), tablet_dev(NULL), current_condition_set(0xffff), policy_active( +- 0), fallback_id(-1), int3400_base_path(""), passive_def_only( +- 0), passive_def_processed(0), passive_installed(0), power_slider(75) { ++ cthd_engine_default("63BE270F-1C11-48FD-A6F7-3AF253FF3E2D"), policy_active( ++ 0), fallback_id(-1), int3400_path(""), int3400_base_path( ++ ""), passive_def_only(0), passive_def_processed(0), passive_installed( ++ 0), power_slider(75) { + } + +- ~cthd_engine_adaptive(); +- ppcc_t* get_ppcc_param(std::string name); ++ ~cthd_engine_adaptive() { ++ } ++ ppcc_t* get_ppcc_param(std::string name) { ++ return gddv.get_ppcc_param(name); ++ } + int thd_engine_init(bool ignore_cpuid_check, bool adaptive); + int thd_engine_start(); + void update_engine_state(); +diff --git a/src/thd_engine_default.h b/src/thd_engine_default.h +index 1acf5b8..7ce4a49 100644 +--- a/src/thd_engine_default.h ++++ b/src/thd_engine_default.h +@@ -27,6 +27,7 @@ + + #include "thd_engine.h" + #include "thd_cpu_default_binding.h" ++#include "thd_gddv.h" + + class cthd_engine_default: public cthd_engine { + private: +@@ -47,6 +48,8 @@ protected: + bool force_mmio_rapl; + public: + static const int power_clamp_reduction_percent = 5; ++ cthd_gddv gddv; ++ + #ifndef ANDROID + cthd_engine_default() : + cthd_engine("42A441D6-AE6A-462b-A84B-4A8CE79027D3"), +diff --git a/src/thd_gddv.cpp b/src/thd_gddv.cpp +new file mode 100644 +index 0000000..5563bfb +--- /dev/null ++++ b/src/thd_gddv.cpp +@@ -0,0 +1,1413 @@ ++/* ++ * cthd_gddv.cpp: Adaptive thermal engine ++ * ++ * Copyright (C) 2013 Intel Corporation. All rights reserved. ++ * Copyright 2020 Google LLC ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version ++ * 2 or later as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA. ++ * ++ * ++ * Author Name Matthew Garrett ++ * ++ */ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "thd_gddv.h" ++ ++/* From esif_lilb_datavault.h */ ++#define ESIFDV_NAME_LEN 32 // Max DataVault Name (Cache Name) Length (not including NULL) ++#define ESIFDV_DESC_LEN 64 // Max DataVault Description Length (not including NULL) ++ ++#define SHA256_HASH_BYTES 32 ++ ++struct header { ++ uint16_t signature; ++ uint16_t headersize; ++ uint32_t version; ++ ++ union { ++ /* Added in V1 */ ++ struct { ++ uint32_t flags; ++ } v1; ++ ++ /* Added in V2 */ ++ struct { ++ uint32_t flags; ++ char segmentid[ESIFDV_NAME_LEN]; ++ char comment[ESIFDV_DESC_LEN]; ++ uint8_t payload_hash[SHA256_HASH_BYTES]; ++ uint32_t payload_size; ++ uint32_t payload_class; ++ } v2; ++ }; ++} __attribute__ ((packed)); ++ ++class _gddv_exception: public std::exception { ++ virtual const char* what() const throw () { ++ return "GDDV parsing failed"; ++ } ++} gddv_exception; ++ ++void cthd_gddv::destroy_dynamic_sources() { ++ if (upower_client) ++ g_clear_object(&upower_client); ++ ++ if (power_profiles_daemon) ++ g_clear_object(&power_profiles_daemon); ++ ++ if (tablet_dev) { ++ close(libevdev_get_fd(tablet_dev)); ++ libevdev_free(tablet_dev); ++ ++ if (lid_dev == tablet_dev) ++ lid_dev = NULL; ++ tablet_dev = NULL; ++ } ++ ++ if (lid_dev) { ++ close(libevdev_get_fd(lid_dev)); ++ libevdev_free(lid_dev); ++ ++ lid_dev = NULL; ++ } ++} ++ ++cthd_gddv::~cthd_gddv() { ++} ++ ++int cthd_gddv::get_type(char *object, int *offset) { ++ return *(uint32_t*) (object + *offset); ++} ++ ++uint64_t cthd_gddv::get_uint64(char *object, int *offset) { ++ uint64_t value; ++ int type = *(uint32_t*) (object + *offset); ++ ++ if (type != 4) { ++ thd_log_warn("Found object of type %d, expecting 4\n", type); ++ throw gddv_exception; ++ } ++ *offset += 4; ++ ++ value = *(uint64_t*) (object + *offset); ++ *offset += 8; ++ ++ return value; ++} ++ ++char* cthd_gddv::get_string(char *object, int *offset) { ++ int type = *(uint32_t*) (object + *offset); ++ uint64_t length; ++ char *value; ++ ++ if (type != 8) { ++ thd_log_warn("Found object of type %d, expecting 8\n", type); ++ throw gddv_exception; ++ } ++ *offset += 4; ++ ++ length = *(uint64_t*) (object + *offset); ++ *offset += 8; ++ ++ value = &object[*offset]; ++ *offset += length; ++ return value; ++} ++ ++int cthd_gddv::merge_custom(struct custom_condition *custom, ++ struct condition *condition) { ++ condition->device = custom->participant; ++ condition->condition = (enum adaptive_condition) custom->type; ++ ++ return 0; ++} ++ ++int cthd_gddv::merge_appc() { ++ for (int i = 0; i < (int) custom_conditions.size(); i++) { ++ for (int j = 0; j < (int) conditions.size(); j++) { ++ for (int k = 0; k < (int) conditions[j].size(); k++) { ++ if (custom_conditions[i].condition ++ == conditions[j][k].condition) { ++ merge_custom(&custom_conditions[i], &conditions[j][k]); ++ } ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++int cthd_gddv::parse_appc(char *appc, int len) { ++ int offset = 0; ++ uint64_t version; ++ ++ if (appc[0] != 4) { ++ thd_log_info("Found malformed APPC table, ignoring\n"); ++ return 0; ++ } ++ ++ version = get_uint64(appc, &offset); ++ if (version != 1) { ++ // Invalid APPC tables aren't fatal ++ thd_log_info("Found unsupported or malformed APPC version %d\n", ++ (int) version); ++ return 0; ++ } ++ ++ while (offset < len) { ++ struct custom_condition condition; ++ ++ condition.condition = (enum adaptive_condition) get_uint64(appc, ++ &offset); ++ condition.name = get_string(appc, &offset); ++ condition.participant = get_string(appc, &offset); ++ condition.domain = get_uint64(appc, &offset); ++ condition.type = get_uint64(appc, &offset); ++ custom_conditions.push_back(condition); ++ } ++ ++ return 0; ++} ++ ++int cthd_gddv::parse_apat(char *apat, int len) { ++ int offset = 0; ++ uint64_t version = get_uint64(apat, &offset); ++ ++ if (version != 2) { ++ thd_log_warn("Found unsupported APAT version %d\n", (int) version); ++ throw gddv_exception; ++ } ++ ++ while (offset < len) { ++ struct adaptive_target target; ++ ++ if (offset >= len) ++ return THD_ERROR; ++ ++ target.target_id = get_uint64(apat, &offset); ++ target.name = get_string(apat, &offset); ++ target.participant = get_string(apat, &offset); ++ target.domain = get_uint64(apat, &offset); ++ target.code = get_string(apat, &offset); ++ target.argument = get_string(apat, &offset); ++ targets.push_back(target); ++ } ++ return 0; ++} ++ ++void cthd_gddv::dump_apat() ++{ ++ thd_log_info("..apat dump begin.. \n"); ++ for (unsigned int i = 0; i < targets.size(); ++i) { ++ thd_log_info( ++ "target_id:%" PRIu64 " name:%s participant:%s domain:%d code:%s argument:%s\n", ++ targets[i].target_id, targets[i].name.c_str(), ++ targets[i].participant.c_str(), (int)targets[i].domain, ++ targets[i].code.c_str(), targets[i].argument.c_str()); ++ } ++ thd_log_info("apat dump end\n"); ++} ++ ++int cthd_gddv::parse_apct(char *apct, int len) { ++ int i; ++ int offset = 0; ++ uint64_t version = get_uint64(apct, &offset); ++ ++ if (version == 1) { ++ while (offset < len) { ++ std::vector condition_set; ++ ++ uint64_t target = get_uint64(apct, &offset); ++ if (int(target) == -1) { ++ thd_log_warn("Invalid APCT target\n"); ++ throw gddv_exception; ++ } ++ ++ for (i = 0; i < 10; i++) { ++ struct condition condition; ++ ++ condition.condition = adaptive_condition(0); ++ condition.device = ""; ++ condition.comparison = adaptive_comparison(0); ++ condition.argument = 0; ++ condition.operation = adaptive_operation(0); ++ condition.time_comparison = adaptive_comparison(0); ++ condition.time = 0; ++ condition.target = 0; ++ condition.state = 0; ++ condition.state_entry_time = 0; ++ condition.target = target; ++ condition.ignore_condition = 0; ++ ++ if (offset >= len) { ++ thd_log_warn("Read off end of buffer in APCT parsing\n"); ++ throw gddv_exception; ++ } ++ ++ condition.condition = adaptive_condition( ++ get_uint64(apct, &offset)); ++ condition.comparison = adaptive_comparison( ++ get_uint64(apct, &offset)); ++ condition.argument = get_uint64(apct, &offset); ++ if (i < 9) { ++ condition.operation = adaptive_operation( ++ get_uint64(apct, &offset)); ++ if (condition.operation == FOR) { ++ offset += 12; ++ condition.time_comparison = adaptive_comparison( ++ get_uint64(apct, &offset)); ++ condition.time = get_uint64(apct, &offset); ++ offset += 12; ++ i++; ++ } ++ } ++ condition_set.push_back(condition); ++ } ++ conditions.push_back(condition_set); ++ } ++ } else if (version == 2) { ++ while (offset < len) { ++ std::vector condition_set; ++ ++ uint64_t target = get_uint64(apct, &offset); ++ if (int(target) == -1) { ++ thd_log_warn("Invalid APCT target"); ++ throw gddv_exception; ++ } ++ ++ uint64_t count = get_uint64(apct, &offset); ++ for (i = 0; i < int(count); i++) { ++ struct condition condition; ++ ++ condition.condition = adaptive_condition(0); ++ condition.device = ""; ++ condition.comparison = adaptive_comparison(0); ++ condition.argument = 0; ++ condition.operation = adaptive_operation(0); ++ condition.time_comparison = adaptive_comparison(0); ++ condition.time = 0; ++ condition.target = 0; ++ condition.state = 0; ++ condition.state_entry_time = 0; ++ condition.target = target; ++ ++ if (offset >= len) { ++ thd_log_warn("Read off end of buffer in parsing APCT\n"); ++ throw gddv_exception; ++ } ++ ++ condition.condition = adaptive_condition( ++ get_uint64(apct, &offset)); ++ condition.device = get_string(apct, &offset); ++ offset += 12; ++ condition.comparison = adaptive_comparison( ++ get_uint64(apct, &offset)); ++ condition.argument = get_uint64(apct, &offset); ++ if (i < int(count - 1)) { ++ condition.operation = adaptive_operation( ++ get_uint64(apct, &offset)); ++ if (condition.operation == FOR) { ++ offset += 12; ++ get_string(apct, &offset); ++ offset += 12; ++ condition.time_comparison = adaptive_comparison( ++ get_uint64(apct, &offset)); ++ condition.time = get_uint64(apct, &offset); ++ offset += 12; ++ i++; ++ } ++ } ++ condition_set.push_back(condition); ++ } ++ conditions.push_back(condition_set); ++ } ++ } else { ++ thd_log_warn("Unsupported APCT version %d\n", (int) version); ++ throw gddv_exception; ++ } ++ return 0; ++} ++ ++static const char *condition_names[] = { ++ "Invalid", ++ "Default", ++ "Orientation", ++ "Proximity", ++ "Motion", ++ "Dock", ++ "Workload", ++ "Cooling_mode", ++ "Power_source", ++ "Aggregate_power_percentage", ++ "Lid_state", ++ "Platform_type", ++ "Platform_SKU", ++ "Utilisation", ++ "TDP", ++ "Duty_cycle", ++ "Power", ++ "Temperature", ++ "Display_orientation", ++ "Oem0", ++ "Oem1", ++ "Oem2", ++ "Oem3", ++ "Oem4", ++ "Oem5", ++ "PMAX", ++ "PSRC", ++ "ARTG", ++ "CTYP", ++ "PROP", ++ "Unk1", ++ "Unk2", ++ "Battery_state", ++ "Battery_rate", ++ "Battery_remaining", ++ "Battery_voltage", ++ "PBSS", ++ "Battery_cycles", ++ "Battery_last_full", ++ "Power_personality", ++ "Battery_design_capacity", ++ "Screen_state", ++ "AVOL", ++ "ACUR", ++ "AP01", ++ "AP02", ++ "AP10", ++ "Time", ++ "Temperature_without_hysteresis", ++ "Mixed_reality", ++ "User_presence", ++ "RBHF", ++ "VBNL", ++ "CMPP", ++ "Battery_percentage", ++ "Battery_count", ++ "Power_slider" ++}; ++ ++static const char *comp_strs[] = { ++ "INVALID", ++ "ADAPTIVE_EQUAL", ++ "ADAPTIVE_LESSER_OR_EQUAL", ++ "ADAPTIVE_GREATER_OR_EQUAL" ++}; ++ ++#define ARRAY_SIZE(array) \ ++ (sizeof(array) / sizeof(array[0])) ++ ++void cthd_gddv::dump_apct() { ++ thd_log_info("..apct dump begin.. \n"); ++ for (unsigned int i = 0; i < conditions.size(); ++i) { ++ std::vector condition_set; ++ ++ thd_log_info("condition_set %d\n", i); ++ condition_set = conditions[i]; ++ for (unsigned int j = 0; j < condition_set.size(); ++j) { ++ std::string cond_name, comp_str, op_str; ++ ++ if (condition_set[j].condition < ARRAY_SIZE(condition_names)) { ++ cond_name = condition_names[condition_set[j].condition]; ++ } else if (condition_set[j].condition >= 0x1000 && condition_set[j].condition < 0x10000) { ++ std::stringstream msg; ++ ++ msg << "Oem" << (condition_set[j].condition - 0x1000 + 6); ++ cond_name = msg.str(); ++ } else { ++ std::stringstream msg; ++ ++ msg << "UNKNOWN" << "( " << condition_set[j].condition << " )"; ++ cond_name = msg.str(); ++ } ++ ++ if (condition_set[j].comparison < ARRAY_SIZE(comp_strs)) { ++ comp_str = comp_strs[condition_set[j].comparison]; ++ } ++ ++ if (condition_set[j].operation == 1) { ++ op_str = "AND"; ++ } else if (condition_set[j].operation == 2) { ++ op_str = "FOR"; ++ } else { ++ op_str = "INVALID"; ++ } ++ ++ thd_log_info( ++ "\ttarget:%d device:%s condition:%s comparison:%s argument:%d" ++ " operation:%s time_comparison:%d time:%d" ++ " stare:%d state_entry_time:%d \n", ++ condition_set[j].target, condition_set[j].device.c_str(), ++ cond_name.c_str(), comp_str.c_str(), ++ condition_set[j].argument, op_str.c_str(), ++ condition_set[j].time_comparison, condition_set[j].time, ++ condition_set[j].state, condition_set[j].state_entry_time); ++ } ++ } ++ thd_log_info("..apct dump end.. \n"); ++} ++ ++ppcc_t* cthd_gddv::get_ppcc_param(std::string name) { ++ for (int i = 0; i < (int) ppccs.size(); i++) { ++ if (ppccs[i].name == name) ++ return &ppccs[i]; ++ } ++ ++ return NULL; ++} ++ ++int cthd_gddv::parse_ppcc(char *name, char *buf, int len) { ++ ppcc_t ppcc; ++ ++ ppcc.name = name; ++ ppcc.power_limit_min = *(uint64_t*) (buf + 28); ++ ppcc.power_limit_max = *(uint64_t*) (buf + 40); ++ ppcc.time_wind_min = *(uint64_t*) (buf + 52); ++ ppcc.time_wind_max = *(uint64_t*) (buf + 64); ++ ppcc.step_size = *(uint64_t*) (buf + 76); ++ ppcc.valid = 1; ++ ++ if (len < 156) ++ return 0; ++ ++ thd_log_info("Processing ppcc limit 2, length %d\n", len); ++ int start = 76 + 12; ++ ppcc.power_limit_1_min = *(uint64_t*) (buf + start + 12); ++ ppcc.power_limit_1_max = *(uint64_t*) (buf + start + 24); ++ ppcc.time_wind_1_min = *(uint64_t*) (buf + start + 36); ++ ppcc.time_wind_1_max = *(uint64_t*) (buf + start + 48); ++ ppcc.step_1_size = *(uint64_t*) (buf + start + 60); ++ ++ if (ppcc.power_limit_1_max && ppcc.power_limit_1_min && ppcc.time_wind_1_min ++ && ppcc.time_wind_1_max && ppcc.step_1_size) ++ ppcc.limit_1_valid = 1; ++ else ++ ppcc.limit_1_valid = 0; ++ ++ ppccs.push_back(ppcc); ++ ++ return 0; ++} ++ ++void cthd_gddv::dump_ppcc() ++{ ++ thd_log_info("..ppcc dump begin.. \n"); ++ for (unsigned int i = 0; i < ppccs.size(); ++i) { ++ thd_log_info( ++ "Name:%s Limit:0 power_limit_max:%d power_limit_min:%d step_size:%d time_win_max:%d time_win_min:%d\n", ++ ppccs[i].name.c_str(), ppccs[i].power_limit_max, ++ ppccs[i].power_limit_min, ppccs[i].step_size, ++ ppccs[i].time_wind_max, ppccs[i].time_wind_min); ++ thd_log_info( ++ "Name:%s Limit:1 power_limit_max:%d power_limit_min:%d step_size:%d time_win_max:%d time_win_min:%d\n", ++ ppccs[i].name.c_str(), ppccs[i].power_limit_1_max, ++ ppccs[i].power_limit_1_min, ppccs[i].step_1_size, ++ ppccs[i].time_wind_1_max, ppccs[i].time_wind_1_min); ++ } ++ thd_log_info("ppcc dump end\n"); ++} ++ ++int cthd_gddv::parse_psvt(char *name, char *buf, int len) { ++ int offset = 0; ++ int version = get_uint64(buf, &offset); ++ struct psvt psvt; ++ ++ if (version > 2) { ++ thd_log_warn("Found unsupported PSVT version %d\n", (int) version); ++ throw gddv_exception; ++ } ++ ++ if (name == NULL) ++ psvt.name = "Default"; ++ else ++ psvt.name = name; ++ while (offset < len) { ++ struct psv psv; ++ ++ psv.source = get_string(buf, &offset); ++ psv.target = get_string(buf, &offset); ++ psv.priority = get_uint64(buf, &offset); ++ psv.sample_period = get_uint64(buf, &offset); ++ psv.temp = get_uint64(buf, &offset); ++ psv.domain = get_uint64(buf, &offset); ++ psv.control_knob = get_uint64(buf, &offset); ++ if (get_type(buf, &offset) == 8) { ++ psv.limit = get_string(buf, &offset); ++ } else { ++ uint64_t tmp = get_uint64(buf, &offset); ++ psv.limit = std::to_string(tmp); ++ } ++ psv.step_size = get_uint64(buf, &offset); ++ psv.limit_coeff = get_uint64(buf, &offset); ++ psv.unlimit_coeff = get_uint64(buf, &offset); ++ offset += 12; ++ psvt.psvs.push_back(psv); ++ } ++ ++ psvts.push_back(psvt); ++ ++ return 0; ++} ++ ++#define DECI_KELVIN_TO_CELSIUS(t) ({ \ ++ int _t = (t); \ ++ ((_t-2732 >= 0) ? (_t-2732+5)/10 : (_t-2732-5)/10); \ ++}) ++ ++void cthd_gddv::dump_psvt() { ++ thd_log_info("..psvt dump begin.. \n"); ++ for (unsigned int i = 0; i < psvts.size(); ++i) { ++ std::vector psvs = psvts[i].psvs; ++ ++ thd_log_info("Name :%s\n", psvts[i].name.c_str()); ++ for (unsigned int j = 0; j < psvs.size(); ++j) { ++ thd_log_info( ++ "\t source:%s target:%s priority:%d sample_period:%d temp:%d domain:%d control_knob:%d psv.limit:%s\n", ++ psvs[j].source.c_str(), psvs[j].target.c_str(), ++ psvs[j].priority, psvs[j].sample_period, ++ DECI_KELVIN_TO_CELSIUS(psvs[j].temp), psvs[j].domain, ++ psvs[j].control_knob, psvs[j].limit.c_str()); ++ ++ } ++ } ++ thd_log_info("psvt dump end\n"); ++} ++ ++struct psvt* cthd_gddv::find_def_psvt() { ++ for (unsigned int i = 0; i < psvts.size(); ++i) { ++ if (psvts[i].name == "IETM.D0") { ++ return &psvts[i]; ++ } ++ } ++ ++ return NULL; ++} ++ ++int cthd_gddv::parse_itmt(char *name, char *buf, int len) { ++ int offset = 0; ++ int version = get_uint64(buf, &offset); ++ struct itmt itmt; ++ ++ thd_log_debug(" ITMT version %d %s\n", (int) version, name); ++ ++ if (name == NULL) ++ itmt.name = "Default"; ++ else ++ itmt.name = name; ++ ++ while (offset < len) { ++ struct itmt_entry itmt_entry; ++ ++ itmt_entry.target = get_string(buf, &offset); ++ itmt_entry.trip_point = get_uint64(buf, &offset); ++ itmt_entry.pl1_min = get_string(buf, &offset); ++ itmt_entry.pl1_max = get_string(buf, &offset); ++ itmt_entry.unused = get_string(buf, &offset); ++ offset += 12; ++ ++ itmt.itmt_entries.push_back(itmt_entry); ++ } ++ ++ itmts.push_back(itmt); ++ ++ return 0; ++} ++ ++void cthd_gddv::dump_itmt() { ++ thd_log_info("..itmt dump begin.. \n"); ++ for (unsigned int i = 0; i < itmts.size(); ++i) { ++ std::vector itmt = itmts[i].itmt_entries; ++ ++ thd_log_info("Name :%s\n", itmts[i].name.c_str()); ++ for (unsigned int j = 0; j < itmt.size(); ++j) { ++ thd_log_info("\t target:%s trip_temp:%d pl1_min:%s pl1.max:%s\n", ++ itmt[j].target.c_str(), ++ DECI_KELVIN_TO_CELSIUS(itmt[j].trip_point), ++ itmt[j].pl1_min.c_str(), itmt[j].pl1_max.c_str()); ++ } ++ } ++ thd_log_info("itmt dump end\n"); ++} ++ ++// From Common/esif_sdk_iface_esif.h: ++#define ESIF_SERVICE_CONFIG_COMPRESSED 0x40000000/* Payload is Compressed */ ++// From Common/esif_sdk.h ++#define ESIFHDR_VERSION(major, minor, revision) ((uint32_t)((((major) & 0xFF) << 24) | (((minor) & 0xFF) << 16) | ((revision) & 0xFFFF))) ++#define ESIFHDR_GET_MAJOR(version) ((uint32_t)(((version) >> 24) & 0xFF)) ++#define ESIFHDR_GET_MINOR(version) ((uint32_t)(((version) >> 16) & 0xFF)) ++#define ESIFHDR_GET_REVISION(version) ((uint32_t)((version) & 0xFFFF)) ++//From ESIF/Products/ESIF_LIB/Sources/esif_lib_datavault.c ++#define ESIFDV_HEADER_SIGNATURE 0x1FE5 ++#define ESIFDV_ITEM_KEYS_REV0_SIGNATURE 0xA0D8 ++ ++int cthd_gddv::handle_compressed_gddv(char *buf, int size) { ++ struct header *header = (struct header*) buf; ++ uint64_t payload_output_size; ++ uint64_t output_size; ++ lzma_ret ret; ++ int res; ++ unsigned char *decompressed; ++ lzma_stream strm = LZMA_STREAM_INIT; ++ ++ payload_output_size = *(uint64_t*) (buf + header->headersize + 5); ++ output_size = header->headersize + payload_output_size; ++ decompressed = (unsigned char*) malloc(output_size); ++ ++ if (!decompressed) { ++ thd_log_warn("Failed to allocate buffer for decompressed output\n"); ++ throw gddv_exception; ++ } ++ ret = lzma_auto_decoder(&strm, 64 * 1024 * 1024, 0); ++ if (ret) { ++ thd_log_warn("Failed to initialize LZMA decoder: %d\n", ret); ++ free(decompressed); ++ throw gddv_exception; ++ } ++ strm.next_out = decompressed + header->headersize; ++ strm.avail_out = output_size; ++ strm.next_in = (const unsigned char*) (buf + header->headersize); ++ strm.avail_in = size; ++ ret = lzma_code(&strm, LZMA_FINISH); ++ lzma_end(&strm); ++ if (ret && ret != LZMA_STREAM_END) { ++ thd_log_warn("Failed to decompress GDDV data: %d\n", ret); ++ free(decompressed); ++ throw gddv_exception; ++ } ++ ++ /* Copy and update header. ++ * This will contain one or more nested repositories usually. */ ++ memcpy (decompressed, buf, header->headersize); ++ header = (struct header*) decompressed; ++ header->v2.flags &= ~ESIF_SERVICE_CONFIG_COMPRESSED; ++ header->v2.payload_size = payload_output_size; ++ ++ res = parse_gddv((char*) decompressed, output_size, NULL); ++ free(decompressed); ++ ++ return res; ++} ++ ++int cthd_gddv::parse_gddv_key(char *buf, int size, int *end_offset) { ++ int offset = 0; ++ uint32_t keyflags; ++ uint32_t keylength; ++ uint32_t valtype; ++ uint32_t vallength; ++ char *key; ++ char *val; ++ char *str; ++ char *name = NULL; ++ char *type = NULL; ++ char *point = NULL; ++ char *ns = NULL; ++ ++ memcpy(&keyflags, buf + offset, sizeof(keyflags)); ++ offset += sizeof(keyflags); ++ memcpy(&keylength, buf + offset, sizeof(keylength)); ++ offset += sizeof(keylength); ++ key = new char[keylength]; ++ memcpy(key, buf + offset, keylength); ++ offset += keylength; ++ memcpy(&valtype, buf + offset, sizeof(valtype)); ++ offset += sizeof(valtype); ++ memcpy(&vallength, buf + offset, sizeof(vallength)); ++ offset += sizeof(vallength); ++ val = new char[vallength]; ++ memcpy(val, buf + offset, vallength); ++ offset += vallength; ++ ++ if (end_offset) ++ *end_offset = offset; ++ ++ str = strtok(key, "/"); ++ if (!str) { ++ thd_log_debug("Ignoring key %s\n", key); ++ ++ delete[] (key); ++ delete[] (val); ++ ++ /* Ignore */ ++ return THD_SUCCESS; ++ } ++ if (strcmp(str, "participants") == 0) { ++ name = strtok(NULL, "/"); ++ type = strtok(NULL, "/"); ++ point = strtok(NULL, "/"); ++ } else if (strcmp(str, "shared") == 0) { ++ ns = strtok(NULL, "/"); ++ type = strtok(NULL, "/"); ++ if (strcmp(ns, "tables") == 0) { ++ point = strtok(NULL, "/"); ++ } ++ } ++ if (name && type && strcmp(type, "ppcc") == 0) { ++ parse_ppcc(name, val, vallength); ++ } ++ ++ if (type && strcmp(type, "psvt") == 0) { ++ if (point == NULL) ++ parse_psvt(name, val, vallength); ++ else ++ parse_psvt(point, val, vallength); ++ } ++ ++ if (type && strcmp(type, "appc") == 0) { ++ parse_appc(val, vallength); ++ } ++ ++ if (type && strcmp(type, "apct") == 0) { ++ parse_apct(val, vallength); ++ } ++ ++ if (type && strcmp(type, "apat") == 0) { ++ parse_apat(val, vallength); ++ } ++ ++ if (type && strcmp(type, "itmt") == 0) { ++ if (point == NULL) ++ parse_itmt(name, val, vallength); ++ else ++ parse_itmt(point, val, vallength); ++ } ++ ++ delete[] (key); ++ delete[] (val); ++ ++ return THD_SUCCESS; ++} ++ ++int cthd_gddv::parse_gddv(char *buf, int size, int *end_offset) { ++ int offset = 0; ++ struct header *header; ++ ++ if (size < (int) sizeof(struct header)) ++ return THD_ERROR; ++ ++ header = (struct header*) buf; ++ ++ if (header->signature != ESIFDV_HEADER_SIGNATURE) { ++ thd_log_warn("Unexpected GDDV signature 0x%x\n", header->signature); ++ throw gddv_exception; ++ } ++ if (ESIFHDR_GET_MAJOR(header->version) != 1 ++ && ESIFHDR_GET_MAJOR(header->version) != 2) ++ return THD_ERROR; ++ ++ offset = header->headersize; ++ ++ thd_log_debug("header version[%d] size[%d] header_size[%d] flags[%08X]\n", ++ ESIFHDR_GET_MAJOR(header->version), size, header->headersize, header->v1.flags); ++ ++ if (ESIFHDR_GET_MAJOR(header->version) == 2) { ++ char name[ESIFDV_NAME_LEN + 1] = { 0 }; ++ char comment[ESIFDV_DESC_LEN + 1] = { 0 }; ++ ++ if (header->v2.flags & ESIF_SERVICE_CONFIG_COMPRESSED) { ++ thd_log_debug("Uncompress GDDV payload\n"); ++ return handle_compressed_gddv(buf, size); ++ } ++ ++ strncpy(name, header->v2.segmentid, sizeof(name) - 1); ++ strncpy(comment, header->v2.comment, sizeof(comment) - 1); ++ ++ thd_log_debug("DV name: %s\n", name); ++ thd_log_debug("DV comment: %s\n", comment); ++ ++ thd_log_debug("Got payload of size %d (data length: %d)\n", size, header->v2.payload_size); ++ size = header->v2.payload_size; ++ } ++ ++ while ((offset + header->headersize) < size) { ++ int res; ++ int end_offset = 0; ++ ++ if (ESIFHDR_GET_MAJOR(header->version) == 2) { ++ unsigned short signature; ++ ++ signature = *(unsigned short *) (buf + offset); ++ if (signature == ESIFDV_ITEM_KEYS_REV0_SIGNATURE) { ++ offset += sizeof(unsigned short); ++ res = parse_gddv_key(buf + offset, size - offset, &end_offset); ++ if (res != THD_SUCCESS) ++ return res; ++ offset += end_offset; ++ } else if (signature == ESIFDV_HEADER_SIGNATURE) { ++ thd_log_info("Got subobject in buf %p at %d\n", buf, offset); ++ res = parse_gddv(buf + offset, size - offset, &end_offset); ++ if (res != THD_SUCCESS) ++ return res; ++ ++ /* Parse recursively */ ++ offset += end_offset; ++ thd_log_info("Subobject ended at %d of %d\n", offset, size); ++ } else { ++ thd_log_info("No known signature found 0x%04X\n", *(unsigned short *) (buf + offset)); ++ return THD_ERROR; ++ } ++ } else { ++ res = parse_gddv_key(buf + offset, size - offset, &end_offset); ++ if (res != THD_SUCCESS) ++ return res; ++ offset += end_offset; ++ } ++ } ++ ++ if (end_offset) ++ *end_offset = offset; ++ ++ return 0; ++} ++ ++int cthd_gddv::verify_condition(struct condition condition) { ++ const char *cond_name; ++ ++ if (condition.condition >= Oem0 && condition.condition <= Oem5) ++ return 0; ++ if (condition.condition >= adaptive_condition(0x1000) ++ && condition.condition < adaptive_condition(0x10000)) ++ return 0; ++ if (condition.condition == Default) ++ return 0; ++ if (condition.condition == Temperature ++ || condition.condition == Temperature_without_hysteresis ++ || condition.condition == (adaptive_condition) 0) { ++ return 0; ++ } ++ if (condition.condition == Lid_state && lid_dev != NULL) ++ return 0; ++ if (condition.condition == Power_source && upower_client != NULL) ++ return 0; ++ if (condition.condition == Workload) ++ return 0; ++ if (condition.condition == Platform_type) ++ return 0; ++ if (condition.condition == Power_slider) ++ return 0; ++ ++ if ( condition.condition >= ARRAY_SIZE(condition_names)) ++ cond_name = "UKNKNOWN"; ++ else ++ cond_name = condition_names[condition.condition]; ++ thd_log_error("Unsupported condition %" PRIu64 " (%s)\n", condition.condition, cond_name); ++ ++ return THD_ERROR; ++} ++ ++int cthd_gddv::verify_conditions() { ++ int result = 0; ++ for (int i = 0; i < (int) conditions.size(); i++) { ++ for (int j = 0; j < (int) conditions[i].size(); j++) { ++ if (verify_condition(conditions[i][j])) ++ result = THD_ERROR; ++ } ++ } ++ ++ if (result != 0) ++ thd_log_error("Unsupported conditions are present\n"); ++ ++ return result; ++} ++ ++int cthd_gddv::compare_condition(struct condition condition, ++ int value) { ++ ++ if (thd_engine && thd_engine->debug_mode_on()) { ++ if (condition.condition < ARRAY_SIZE(condition_names)) { ++ std::string cond_name, comp_str, op_str; ++ ++ cond_name = condition_names[condition.condition]; ++ if (condition.comparison < ARRAY_SIZE(comp_strs)) { ++ comp_str = comp_strs[condition.comparison]; ++ thd_log_debug( ++ "compare condition [%s] comparison [%s] value [%d]\n", ++ cond_name.c_str(), comp_str.c_str(), value); ++ } else { ++ thd_log_debug( ++ "compare condition [%s] comparison [%" PRIu64 "] value [%d]\n", ++ cond_name.c_str(), condition.comparison, value); ++ } ++ } else { ++ thd_log_debug("compare condition %" PRIu64 " value %d\n", ++ condition.comparison, value); ++ } ++ } ++ ++ switch (condition.comparison) { ++ case ADAPTIVE_EQUAL: ++ if (value == condition.argument) ++ return THD_SUCCESS; ++ else ++ return THD_ERROR; ++ break; ++ case ADAPTIVE_LESSER_OR_EQUAL: ++ if (value <= condition.argument) ++ return THD_SUCCESS; ++ else ++ return THD_ERROR; ++ break; ++ case ADAPTIVE_GREATER_OR_EQUAL: ++ if (value >= condition.argument) ++ return THD_SUCCESS; ++ else ++ return THD_ERROR; ++ break; ++ default: ++ return THD_ERROR; ++ } ++} ++ ++int cthd_gddv::compare_time(struct condition condition) { ++ int elapsed = time(NULL) - condition.state_entry_time; ++ ++ switch (condition.time_comparison) { ++ case ADAPTIVE_EQUAL: ++ if (elapsed == condition.time) ++ return THD_SUCCESS; ++ else ++ return THD_ERROR; ++ break; ++ case ADAPTIVE_LESSER_OR_EQUAL: ++ if (elapsed <= condition.time) ++ return THD_SUCCESS; ++ else ++ return THD_ERROR; ++ break; ++ case ADAPTIVE_GREATER_OR_EQUAL: ++ if (elapsed >= condition.time) ++ return THD_SUCCESS; ++ else ++ return THD_ERROR; ++ break; ++ default: ++ return THD_ERROR; ++ } ++} ++ ++int cthd_gddv::evaluate_oem_condition(struct condition condition) { ++ csys_fs sysfs(int3400_base_path.c_str()); ++ int oem_condition = -1; ++ ++ if (condition.condition >= Oem0 && condition.condition <= Oem5) ++ oem_condition = (int) condition.condition - Oem0; ++ else if (condition.condition >= (adaptive_condition) 0x1000 ++ && condition.condition < (adaptive_condition) 0x10000) ++ oem_condition = (int) condition.condition - 0x1000 + 6; ++ ++ if (oem_condition != -1) { ++ std::string filename = "odvp" + std::to_string(oem_condition); ++ std::string data; ++ if (sysfs.read(filename, data) < 0) { ++ thd_log_error("Unable to read %s\n", filename.c_str()); ++ return THD_ERROR; ++ } ++ int value = std::stoi(data, NULL); ++ ++ return compare_condition(condition, value); ++ } ++ ++ return THD_ERROR; ++} ++ ++int cthd_gddv::evaluate_temperature_condition( ++ struct condition condition) { ++ std::string sensor_name; ++ ++ if (condition.ignore_condition) ++ return THD_ERROR; ++ ++ size_t pos = condition.device.find_last_of("."); ++ if (pos == std::string::npos) ++ sensor_name = condition.device; ++ else ++ sensor_name = condition.device.substr(pos + 1); ++ ++ cthd_sensor *sensor = thd_engine->search_sensor(sensor_name); ++ if (!sensor) { ++ thd_log_warn("Unable to find a sensor for %s\n", ++ condition.device.c_str()); ++ condition.ignore_condition = 1; ++ return THD_ERROR; ++ } ++ ++ int value = sensor->read_temperature(); ++ ++ // Conditions are specified in decikelvin, temperatures are in ++ // millicelsius. ++ value = value / 100 + 2732; ++ return compare_condition(condition, value); ++} ++ ++int cthd_gddv::evaluate_lid_condition(struct condition condition) { ++ int value = 0; ++ ++ if (lid_dev) { ++ struct input_event ev; ++ ++ while (libevdev_has_event_pending(lid_dev)) ++ libevdev_next_event(lid_dev, LIBEVDEV_READ_FLAG_NORMAL, &ev); ++ ++ int lid_closed = libevdev_get_event_value(lid_dev, EV_SW, SW_LID); ++ value = !lid_closed; ++ } ++ return compare_condition(condition, value); ++} ++ ++int cthd_gddv::evaluate_workload_condition( ++ struct condition condition) { ++ // We don't have a good way to assert workload at the moment, so just ++ // default to bursty ++ ++ return compare_condition(condition, 3); ++} ++ ++int cthd_gddv::evaluate_platform_type_condition( ++ struct condition condition) { ++ int value = 1; ++ ++ if (tablet_dev) { ++ struct input_event ev; ++ ++ while (libevdev_has_event_pending(tablet_dev)) ++ libevdev_next_event(tablet_dev, LIBEVDEV_READ_FLAG_NORMAL, &ev); ++ ++ int tablet = libevdev_get_event_value(tablet_dev, EV_SW, ++ SW_TABLET_MODE); ++ if (tablet) ++ value = 2; ++ } ++ return compare_condition(condition, value); ++} ++ ++int cthd_gddv::evaluate_power_slider_condition( ++ struct condition condition) { ++ ++ return compare_condition(condition, power_slider); ++} ++ ++int cthd_gddv::evaluate_ac_condition(struct condition condition) { ++ int value = 0; ++ bool on_battery = up_client_get_on_battery(upower_client); ++ ++ if (on_battery) ++ value = 1; ++ ++ return compare_condition(condition, value); ++} ++ ++int cthd_gddv::evaluate_condition(struct condition condition) { ++ int ret = THD_ERROR; ++ ++ if (condition.condition == Default) ++ return THD_SUCCESS; ++ ++ thd_log_debug("evaluate condition.condition %" PRIu64 "\n", condition.condition); ++ ++ if ((condition.condition >= Oem0 && condition.condition <= Oem5) ++ || (condition.condition >= (adaptive_condition) 0x1000 ++ && condition.condition < (adaptive_condition) 0x10000)) ++ ret = evaluate_oem_condition(condition); ++ ++ if (condition.condition == Temperature ++ || condition.condition == Temperature_without_hysteresis ++ || condition.condition == (adaptive_condition) 0) { ++ ret = evaluate_temperature_condition(condition); ++ } ++ ++ if (condition.condition == Lid_state) { ++ ret = evaluate_lid_condition(condition); ++ } ++ ++ if (condition.condition == Power_source) { ++ ret = evaluate_ac_condition(condition); ++ } ++ ++ if (condition.condition == Workload) { ++ ret = evaluate_workload_condition(condition); ++ } ++ ++ if (condition.condition == Platform_type) { ++ ret = evaluate_platform_type_condition(condition); ++ } ++ ++ if (condition.condition == Power_slider) { ++ ret = evaluate_power_slider_condition(condition); ++ } ++ ++ if (ret) { ++ if (condition.time && condition.state_entry_time == 0) { ++ condition.state_entry_time = time(NULL); ++ } ++ ret = compare_time(condition); ++ } else { ++ condition.state_entry_time = 0; ++ } ++ ++ return ret; ++} ++ ++int cthd_gddv::evaluate_condition_set( ++ std::vector condition_set) { ++ for (int i = 0; i < (int) condition_set.size(); i++) { ++ thd_log_debug("evaluate condition.condition at index %d\n", i); ++ if (evaluate_condition(condition_set[i]) != 0) ++ return THD_ERROR; ++ } ++ return THD_SUCCESS; ++} ++ ++int cthd_gddv::evaluate_conditions(int policy_active) { ++ int target = -1; ++ ++ for (int i = 0; i < (int) conditions.size(); i++) { ++ thd_log_debug("evaluate condition set %d\n", i); ++ if (evaluate_condition_set(conditions[i]) == THD_SUCCESS) { ++ if (policy_active && i == current_condition_set) ++ break; ++ ++ current_condition_set = i; ++ target = conditions[i][0].target; ++ thd_log_info("Condition Set matched:%d target:%d\n", i, target); ++ ++ break; ++ } ++ } ++ ++ return target; ++} ++ ++struct psvt* cthd_gddv::find_psvt(std::string name) { ++ for (int i = 0; i < (int) psvts.size(); i++) { ++ if (!strcasecmp(psvts[i].name.c_str(), name.c_str())) { ++ return &psvts[i]; ++ } ++ } ++ ++ return NULL; ++} ++ ++struct itmt* cthd_gddv::find_itmt(std::string name) { ++ for (int i = 0; i < (int) itmts.size(); i++) { ++ if (!strcasecmp(itmts[i].name.c_str(), name.c_str())) { ++ return &itmts[i]; ++ } ++ } ++ ++ return NULL; ++} ++ ++int cthd_gddv::find_agressive_target() { ++ int max_pl1_max = 0; ++ int max_target_id = -1; ++ ++ for (int i = 0; i < (int) targets.size(); i++) { ++ int argument; ++ ++ if (targets[i].code != "PL1MAX" && targets[i].code != "PL1PowerLimit") ++ continue; ++ ++ try { ++ argument = std::stoi(targets[i].argument, NULL); ++ } catch (...) { ++ thd_log_info("Invalid target target:%s %s\n", ++ targets[i].code.c_str(), targets[i].argument.c_str()); ++ continue; ++ } ++ thd_log_info("target:%s %d\n", targets[i].code.c_str(), argument); ++ ++ if (max_pl1_max < argument) { ++ max_pl1_max = argument; ++ max_target_id = i; ++ } ++ } ++ ++ return max_target_id; ++} ++ ++void cthd_gddv::update_power_slider() ++{ ++ g_autoptr(GVariant) active_profile_v = NULL; ++ ++ active_profile_v = g_dbus_proxy_get_cached_property (power_profiles_daemon, "ActiveProfile"); ++ if (active_profile_v && g_variant_is_of_type (active_profile_v, G_VARIANT_TYPE_STRING)) { ++ const char *active_profile = g_variant_get_string (active_profile_v, NULL); ++ ++ if (strcmp (active_profile, "power-saver") == 0) ++ power_slider = 25; /* battery saver */ ++ else if (strcmp (active_profile, "balanced") == 0) ++ power_slider = 75; /* better performance */ ++ else if (strcmp (active_profile, "performance") == 0) ++ power_slider = 100; /* best performance */ ++ else ++ power_slider = 75; ++ } else { ++ power_slider = 75; ++ } ++ ++ thd_log_info("Power slider is now set to %d\n", power_slider); ++} ++ ++static void power_profiles_changed_cb(cthd_gddv *gddv) ++{ ++ gddv->update_power_slider(); ++} ++ ++static int is_event_device(const struct dirent *dir) { ++ return strncmp("event", dir->d_name, 5) == 0; ++} ++ ++void cthd_gddv::setup_input_devices() { ++ struct dirent **namelist; ++ int i, ndev, ret; ++ ++ ndev = scandir("/dev/input", &namelist, is_event_device, versionsort); ++ for (i = 0; i < ndev; i++) { ++ struct libevdev *dev = NULL; ++ char fname[267]; ++ int fd = -1; ++ ++ snprintf(fname, sizeof(fname), "/dev/input/%s", namelist[i]->d_name); ++ fd = open(fname, O_RDONLY | O_NONBLOCK | O_CLOEXEC); ++ if (fd < 0) ++ continue; ++ ret = libevdev_new_from_fd(fd, &dev); ++ if (ret) { ++ close(fd); ++ continue; ++ } ++ ++ if (!tablet_dev && libevdev_has_event_code(dev, EV_SW, SW_TABLET_MODE)) ++ tablet_dev = dev; ++ if (!lid_dev && libevdev_has_event_code(dev, EV_SW, SW_LID)) ++ lid_dev = dev; ++ ++ if (lid_dev != dev && tablet_dev != dev) { ++ libevdev_free(dev); ++ close(fd); ++ } ++ } ++} ++ ++int cthd_gddv::gddv_init(void) { ++ csys_fs sysfs(""); ++ char *buf; ++ size_t size; ++ ++ if (sysfs.exists("/sys/bus/platform/devices/INT3400:00")) { ++ int3400_base_path = "/sys/bus/platform/devices/INT3400:00/"; ++ } else if (sysfs.exists("/sys/bus/platform/devices/INTC1040:00")) { ++ int3400_base_path = "/sys/bus/platform/devices/INTC1040:00/"; ++ } else if (sysfs.exists("/sys/bus/platform/devices/INTC1041:00")) { ++ int3400_base_path = "/sys/bus/platform/devices/INTC1041:00/"; ++ } else if (sysfs.exists("/sys/bus/platform/devices/INTC10A0:00")) { ++ int3400_base_path = "/sys/bus/platform/devices/INTC10A0:00/"; ++ } else { ++ return THD_ERROR; ++ } ++ ++ if (sysfs.read(int3400_base_path + "firmware_node/path", ++ int3400_path) < 0) { ++ thd_log_debug("Unable to locate INT3400 firmware path\n"); ++ return THD_ERROR; ++ } ++ ++ size = sysfs.size(int3400_base_path + "data_vault"); ++ if (size == 0) { ++ thd_log_debug("Unable to open GDDV data vault\n"); ++ return THD_ERROR; ++ } ++ ++ buf = new char[size]; ++ if (!buf) { ++ thd_log_error("Unable to allocate memory for GDDV"); ++ return THD_FATAL_ERROR; ++ } ++ ++ if (sysfs.read(int3400_base_path + "data_vault", buf, size) ++ < int(size)) { ++ thd_log_debug("Unable to read GDDV data vault\n"); ++ delete[] buf; ++ return THD_FATAL_ERROR; ++ } ++ ++ try { ++ if (parse_gddv(buf, size, NULL)) { ++ thd_log_debug("Unable to parse GDDV"); ++ delete[] buf; ++ return THD_FATAL_ERROR; ++ } ++ ++ merge_appc(); ++ ++ dump_ppcc(); ++ dump_psvt(); ++ dump_itmt(); ++ dump_apat(); ++ dump_apct(); ++ ++ delete [] buf; ++ } catch (std::exception &e) { ++ thd_log_warn("%s\n", e.what()); ++ delete [] buf; ++ return THD_FATAL_ERROR; ++ } ++ ++ setup_input_devices(); ++ ++ upower_client = up_client_new(); ++ if (!upower_client) { ++ thd_log_info("Unable to connect to upower\n"); ++ /* But continue to work */ ++ } ++ ++ g_autoptr(GDBusConnection) bus = NULL; ++ ++ bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); ++ if (bus) { ++ power_profiles_daemon = g_dbus_proxy_new_sync (bus, ++ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, ++ NULL, ++ "net.hadess.PowerProfiles", ++ "/net/hadess/PowerProfiles", ++ "net.hadess.PowerProfiles", ++ NULL, ++ NULL); ++ ++ if (power_profiles_daemon) { ++ g_signal_connect_swapped (power_profiles_daemon, ++ "g-properties-changed", ++ (GCallback) power_profiles_changed_cb, ++ this); ++ power_profiles_changed_cb(this); ++ } else { ++ thd_log_info("Could not setup DBus watch for power-profiles-daemon"); ++ } ++ } ++ ++ return THD_SUCCESS; ++} ++ ++void cthd_gddv::gddv_free(void) ++{ ++ destroy_dynamic_sources(); ++} ++ +diff --git a/src/thd_gddv.h b/src/thd_gddv.h +new file mode 100644 +index 0000000..22a1018 +--- /dev/null ++++ b/src/thd_gddv.h +@@ -0,0 +1,230 @@ ++/* ++ * cthd_engine_adaptive.cpp: Adaptive thermal engine ++ * ++ * Copyright (C) 2013 Intel Corporation. All rights reserved. ++ * Copyright 2020 Google LLC ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version ++ * 2 or later as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA. ++ * ++ * ++ * Author Name Matthew Garrett ++ * ++ */ ++ ++#ifndef THD_GDDV_H_ ++#define THD_GDDV_H_ ++ ++#include ++#include ++ ++#include "thd_engine.h" ++ ++enum adaptive_condition { ++ Default = 0x01, ++ Orientation, ++ Proximity, ++ Motion, ++ Dock, ++ Workload, ++ Cooling_mode, ++ Power_source, ++ Aggregate_power_percentage, ++ Lid_state, ++ Platform_type, ++ Platform_SKU, ++ Utilisation, ++ TDP, ++ Duty_cycle, ++ Power, ++ Temperature, ++ Display_orientation, ++ Oem0, ++ Oem1, ++ Oem2, ++ Oem3, ++ Oem4, ++ Oem5, ++ PMAX, ++ PSRC, ++ ARTG, ++ CTYP, ++ PROP, ++ Unk1, ++ Unk2, ++ Battery_state, ++ Battery_rate, ++ Battery_remaining, ++ Battery_voltage, ++ PBSS, ++ Battery_cycles, ++ Battery_last_full, ++ Power_personality, ++ Battery_design_capacity, ++ Screen_state, ++ AVOL, ++ ACUR, ++ AP01, ++ AP02, ++ AP10, ++ Time, ++ Temperature_without_hysteresis, ++ Mixed_reality, ++ User_presence, ++ RBHF, ++ VBNL, ++ CMPP, ++ Battery_percentage, ++ Battery_count, ++ Power_slider ++}; ++ ++enum adaptive_comparison { ++ ADAPTIVE_EQUAL = 0x01, ADAPTIVE_LESSER_OR_EQUAL, ADAPTIVE_GREATER_OR_EQUAL, ++}; ++ ++enum adaptive_operation { ++ AND = 0x01, FOR ++}; ++ ++struct psv { ++ std::string name; ++ std::string source; ++ std::string target; ++ int priority; ++ int sample_period; ++ int temp; ++ int domain; ++ int control_knob; ++ std::string limit; ++ int step_size; ++ int limit_coeff; ++ int unlimit_coeff; ++}; ++ ++struct condition { ++ uint64_t condition; ++ std::string device; ++ uint64_t comparison; ++ int argument; ++ enum adaptive_operation operation; ++ enum adaptive_comparison time_comparison; ++ int time; ++ int target; ++ int state; ++ int state_entry_time; ++ int ignore_condition; ++}; ++ ++struct custom_condition { ++ enum adaptive_condition condition; ++ std::string name; ++ std::string participant; ++ int domain; ++ int type; ++}; ++ ++struct psvt { ++ std::string name; ++ std::vector psvs; ++}; ++ ++struct itmt_entry { ++ std::string target; ++ int trip_point; ++ std::string pl1_min; ++ std::string pl1_max; ++ std::string unused; ++}; ++ ++struct itmt { ++ std::string name; ++ std::vector itmt_entries; ++}; ++ ++class cthd_gddv { ++private: ++ std::vector ppccs; ++ std::vector custom_conditions; ++ std::vector psvts; ++ std::vector itmts; ++ std::string int3400_path; ++ UpClient *upower_client; ++ GDBusProxy *power_profiles_daemon; ++ struct libevdev *tablet_dev; ++ struct libevdev *lid_dev; ++ std::string int3400_base_path; ++ int power_slider; ++ int current_condition_set; ++ ++ void destroy_dynamic_sources(); ++ int get_type(char *object, int *offset); ++ uint64_t get_uint64(char *object, int *offset); ++ char* get_string(char *object, int *offset); ++ int merge_custom(struct custom_condition *custom, ++ struct condition *condition); ++ int merge_appc(void); ++ int parse_appc(char *appc, int len); ++ int parse_apat(char *apat, int len); ++ int parse_apct(char *apct, int len); ++ int parse_ppcc(char *name, char *ppcc, int len); ++ int parse_psvt(char *name, char *psvt, int len); ++ int parse_itmt(char *name, char *itmt, int len); ++ int handle_compressed_gddv(char *buf, int size); ++ int parse_gddv_key(char *buf, int size, int *end_offset); ++ int parse_gddv(char *buf, int size, int *end_offset); ++ int verify_condition(struct condition condition); ++ int compare_condition(struct condition condition, int value); ++ int compare_time(struct condition condition); ++ int evaluate_oem_condition(struct condition condition); ++ int evaluate_temperature_condition(struct condition condition); ++ int evaluate_ac_condition(struct condition condition); ++ int evaluate_lid_condition(struct condition condition); ++ int evaluate_workload_condition(struct condition condition); ++ int evaluate_platform_type_condition(struct condition condition); ++ int evaluate_power_slider_condition(struct condition condition); ++ int evaluate_condition(struct condition condition); ++ int evaluate_condition_set(std::vector condition_set); ++ void exec_fallback_target(int target); ++ void dump_apat(); ++ void dump_apct(); ++ void dump_ppcc(); ++ void dump_psvt(); ++ void dump_itmt(); ++ void setup_input_devices(); ++public: ++ cthd_gddv() : ++ upower_client( ++ NULL), tablet_dev(NULL), int3400_base_path(""), power_slider(75), current_condition_set( ++ 0xffff) { ++ } ++ ++ ~cthd_gddv(); ++ ++ std::vector> conditions; ++ std::vector targets; ++ ++ ppcc_t* get_ppcc_param(std::string name); ++ int gddv_init(void); ++ void gddv_free(void); ++ int verify_conditions(); ++ int evaluate_conditions(int policy_active); ++ void update_power_slider(); ++ int find_agressive_target(); ++ struct psvt* find_psvt(std::string name); ++ struct itmt* find_itmt(std::string name); ++ struct psvt* find_def_psvt(); ++}; ++ ++#endif /* THD_GDDV_H_ */ +-- +2.34.1 + diff -Nru thermald-2.4.9/debian/patches/0009-Parse-idsp-and-trips.patch thermald-2.4.9/debian/patches/0009-Parse-idsp-and-trips.patch --- thermald-2.4.9/debian/patches/0009-Parse-idsp-and-trips.patch 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/patches/0009-Parse-idsp-and-trips.patch 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1,228 @@ +From cbdd92b49574ceb2d05e500e042cc792cc21b313 Mon Sep 17 00:00:00 2001 +From: Srinivas Pandruvada +Date: Fri, 1 Jul 2022 14:04:23 -0700 +Subject: [PATCH 09/18] Parse idsp and trips + +Read idsp and trip from data vault as the existing sysfs read values +may not be present or wrong. +--- + src/thd_gddv.cpp | 122 +++++++++++++++++++++++++++++++++++++++++++++++ + src/thd_gddv.h | 20 ++++++++ + 2 files changed, 142 insertions(+) + +diff --git a/src/thd_gddv.cpp b/src/thd_gddv.cpp +index 5563bfb..0355488 100644 +--- a/src/thd_gddv.cpp ++++ b/src/thd_gddv.cpp +@@ -648,6 +648,114 @@ void cthd_gddv::dump_itmt() { + thd_log_info("itmt dump end\n"); + } + ++void cthd_gddv::parse_idsp(char *name, char *start, int length) { ++ int len, i = 0; ++ unsigned char *str = (unsigned char*) start; ++ ++ while (i < length) { ++ char idsp[64]; ++ std::string idsp_str; ++ ++ // The minimum length for a IDSP should be atleast 28 ++ // including headers and values ++ if ((length - i) < 28) ++ return; ++ ++ if (*str != 7) ++ break; ++ ++ str += 4; // Get to Length field ++ i += 4; ++ ++ len = *(int*) str; ++ str += 8; // Get to actual contents ++ i += 8; ++ ++ snprintf(idsp, sizeof(idsp), ++ "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", ++ str[3], str[2], str[1], str[0], str[5], str[4], str[7], str[6], ++ str[8], str[9], str[10], str[11], str[12], str[13], str[14], ++ str[15]); ++ ++ idsp_str = idsp; ++ std::transform(idsp_str.begin(), idsp_str.end(), idsp_str.begin(), ++ ::toupper); ++ idsps.push_back(idsp_str); ++ ++ str += len; ++ i += len; ++ } ++} ++ ++void cthd_gddv::dump_idsps() { ++ thd_log_info("..idsp dump begin.. \n"); ++ for (unsigned int i = 0; i < idsps.size(); ++i) { ++ thd_log_info("idsp :%s\n", idsps[i].c_str()); ++ } ++ thd_log_info("idsp dump end\n"); ++} ++ ++int cthd_gddv::search_idsp(std::string name) ++{ ++ for (unsigned int i = 0; i < idsps.size(); ++i) { ++ if (!idsps[i].compare(0, 36, name)) ++ return THD_SUCCESS; ++ } ++ ++ return THD_ERROR; ++} ++ ++void cthd_gddv::parse_trip_point(char *name, char *type, char *val, int len) ++{ ++ struct trippoint trip; ++ ++ trip.name = name; ++ trip.type_str = type; ++ if (!trip.type_str.compare(0, 2, "_c")) ++ trip.type = CRITICAL; ++ else if (!trip.type_str.compare(0, 2, "_p")) ++ trip.type = PASSIVE; ++ else if (!trip.type_str.compare(0, 2, "_h")) ++ trip.type = HOT; ++ else if (!trip.type_str.compare(0, 2, "_a")) ++ trip.type = ACTIVE; ++ else ++ trip.type = INVALID_TRIP_TYPE; ++ trip.temp = DECI_KELVIN_TO_CELSIUS(*(int *)val); ++ trippoints.push_back(trip); ++} ++ ++void cthd_gddv::dump_trips() { ++ thd_log_info("..trippoint dump begin.. \n"); ++ for (unsigned int i = 0; i < trippoints.size(); ++i) { ++ thd_log_info("name:%s type_str:%s type:%d temp:%d\n", ++ trippoints[i].name.c_str(), trippoints[i].type_str.c_str(), ++ trippoints[i].type, trippoints[i].temp); ++ } ++ thd_log_info("trippoint dump end\n"); ++} ++ ++int cthd_gddv::get_trip_temp(std::string name, trip_point_type_t type) { ++ std::string search_name = name + ".D0"; ++ for (unsigned int i = 0; i < trippoints.size(); ++i) { ++ if (!trippoints[i].name.compare(search_name) ++ && trippoints[i].type == type) ++ return trippoints[i].temp; ++ } ++ ++ return THD_ERROR; ++} ++ ++int cthd_gddv::parse_trt(char *trt, int len) ++{ ++ int offset = 0; ++ ++ while (offset < len) { ++ } ++ ++ return THD_SUCCESS; ++} ++ + // From Common/esif_sdk_iface_esif.h: + #define ESIF_SERVICE_CONFIG_COMPRESSED 0x40000000/* Payload is Compressed */ + // From Common/esif_sdk.h +@@ -790,6 +898,18 @@ int cthd_gddv::parse_gddv_key(char *buf, int size, int *end_offset) { + parse_itmt(point, val, vallength); + } + ++ if (name && type && strcmp(type, "idsp") == 0) { ++ parse_idsp(name, val, vallength); ++ } ++ ++ if (name && type && point && strcmp(type, "trippoint") == 0) { ++ parse_trip_point(name, point, val, vallength); ++ } ++ ++ if (type && strcmp(type, "trt") == 0) { ++ parse_trt(val, vallength); ++ } ++ + delete[] (key); + delete[] (val); + +@@ -1363,6 +1483,8 @@ int cthd_gddv::gddv_init(void) { + dump_itmt(); + dump_apat(); + dump_apct(); ++ dump_idsps(); ++ dump_trips(); + + delete [] buf; + } catch (std::exception &e) { +diff --git a/src/thd_gddv.h b/src/thd_gddv.h +index 22a1018..9a26a0c 100644 +--- a/src/thd_gddv.h ++++ b/src/thd_gddv.h +@@ -30,6 +30,7 @@ + #include + + #include "thd_engine.h" ++#include "thd_trt_art_reader.h" + + enum adaptive_condition { + Default = 0x01, +@@ -153,12 +154,22 @@ struct itmt { + std::vector itmt_entries; + }; + ++struct trippoint { ++ std::string name; ++ std::string type_str; ++ trip_point_type_t type; ++ int temp; ++}; ++ + class cthd_gddv { + private: + std::vector ppccs; + std::vector custom_conditions; ++ std::vector rel_list; + std::vector psvts; + std::vector itmts; ++ std::vector idsps; ++ std::vector trippoints; + std::string int3400_path; + UpClient *upower_client; + GDBusProxy *power_profiles_daemon; +@@ -181,6 +192,9 @@ private: + int parse_ppcc(char *name, char *ppcc, int len); + int parse_psvt(char *name, char *psvt, int len); + int parse_itmt(char *name, char *itmt, int len); ++ int parse_trt(char *trt, int len); ++ void parse_idsp(char *name, char *idsp, int len); ++ void parse_trip_point(char *name, char *type, char *val, int len); + int handle_compressed_gddv(char *buf, int size); + int parse_gddv_key(char *buf, int size, int *end_offset); + int parse_gddv(char *buf, int size, int *end_offset); +@@ -202,7 +216,11 @@ private: + void dump_ppcc(); + void dump_psvt(); + void dump_itmt(); ++ void dump_idsps(); ++ void dump_trips(); + void setup_input_devices(); ++ int get_trip_temp(std::string name, trip_point_type_t type); ++ + public: + cthd_gddv() : + upower_client( +@@ -225,6 +243,8 @@ public: + struct psvt* find_psvt(std::string name); + struct itmt* find_itmt(std::string name); + struct psvt* find_def_psvt(); ++ int search_idsp(std::string name); ++ + }; + + #endif /* THD_GDDV_H_ */ +-- +2.34.1 + diff -Nru thermald-2.4.9/debian/patches/0010-Add-_TRT-parsing.patch thermald-2.4.9/debian/patches/0010-Add-_TRT-parsing.patch --- thermald-2.4.9/debian/patches/0010-Add-_TRT-parsing.patch 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/patches/0010-Add-_TRT-parsing.patch 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1,84 @@ +From 5dc307496d4f589220844eb3dc594286b3cb90f8 Mon Sep 17 00:00:00 2001 +From: Srinivas Pandruvada +Date: Tue, 5 Jul 2022 07:44:37 -0700 +Subject: [PATCH 10/18] Add _TRT parsing + +Make a placeholder for parsing _TRT from data vault. The existing +sysfs read data may be invalid. +But this is not fully integrated to passive policy as there is no +such system available for test. +--- + src/thd_gddv.cpp | 23 +++++++++++++++++++++-- + src/thd_gddv.h | 11 +++++++++++ + 2 files changed, 32 insertions(+), 2 deletions(-) + +diff --git a/src/thd_gddv.cpp b/src/thd_gddv.cpp +index 0355488..f3a3cd9 100644 +--- a/src/thd_gddv.cpp ++++ b/src/thd_gddv.cpp +@@ -746,11 +746,30 @@ int cthd_gddv::get_trip_temp(std::string name, trip_point_type_t type) { + return THD_ERROR; + } + +-int cthd_gddv::parse_trt(char *trt, int len) ++int cthd_gddv::parse_trt(char *buf, int len) + { + int offset = 0; + ++ thd_log_debug("TRT len:%d\n", len); ++ ++ if (len > 0) { ++ thd_log_info( ++ "_TRT not implemented. Report this for implementation with the thermald log using --loglevel=debug\n"); ++ } ++ + while (offset < len) { ++ struct trt_entry entry; ++ ++ entry.source = get_string(buf, &offset); ++ entry.dest = get_string(buf, &offset); ++ entry.priority = get_uint64(buf, &offset); ++ entry.sample_rate = get_uint64(buf, &offset); ++ entry.resd0 = get_uint64(buf, &offset); ++ entry.resd1 = get_uint64(buf, &offset); ++ entry.resd2 = get_uint64(buf, &offset); ++ entry.resd3 = get_uint64(buf, &offset); ++ thd_log_info("trt source:%s dest:%s prio:%d sample_rate:%d\n", ++ entry.source.c_str(), entry.dest.c_str(), entry.priority, entry.sample_rate); + } + + return THD_SUCCESS; +@@ -906,7 +925,7 @@ int cthd_gddv::parse_gddv_key(char *buf, int size, int *end_offset) { + parse_trip_point(name, point, val, vallength); + } + +- if (type && strcmp(type, "trt") == 0) { ++ if (type && strcmp(type, "_trt") == 0) { + parse_trt(val, vallength); + } + +diff --git a/src/thd_gddv.h b/src/thd_gddv.h +index 9a26a0c..20cf2b3 100644 +--- a/src/thd_gddv.h ++++ b/src/thd_gddv.h +@@ -149,6 +149,17 @@ struct itmt_entry { + std::string unused; + }; + ++struct trt_entry { ++ std::string source; ++ std::string dest; ++ int priority; ++ int sample_rate; ++ int resd0; ++ int resd1; ++ int resd2; ++ int resd3; ++}; ++ + struct itmt { + std::string name; + std::vector itmt_entries; +-- +2.34.1 + diff -Nru thermald-2.4.9/debian/patches/0011-Use-PL1-max-min-from-PPCC-when-policies-match.patch thermald-2.4.9/debian/patches/0011-Use-PL1-max-min-from-PPCC-when-policies-match.patch --- thermald-2.4.9/debian/patches/0011-Use-PL1-max-min-from-PPCC-when-policies-match.patch 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/patches/0011-Use-PL1-max-min-from-PPCC-when-policies-match.patch 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1,86 @@ +From d385f20764e1e5477450405be71ec719adc973be Mon Sep 17 00:00:00 2001 +From: Srinivas Pandruvada +Date: Tue, 5 Jul 2022 16:41:46 -0700 +Subject: [PATCH 11/18] Use PL1 max/min from PPCC when policies match + +When Adaptive or Passive 2 policy are present in the idsp, use +RAPL PL1 max/min from PPCC table in data vault without checking +if that is lower than what system is booted with. +--- + src/thd_cdev_rapl.cpp | 12 ++++++++++++ + src/thd_engine.h | 3 +++ + src/thd_engine_adaptive.h | 6 ++++++ + src/thd_gddv.cpp | 3 +++ + 4 files changed, 24 insertions(+) + +diff --git a/src/thd_cdev_rapl.cpp b/src/thd_cdev_rapl.cpp +index 04d65b3..a57930d 100644 +--- a/src/thd_cdev_rapl.cpp ++++ b/src/thd_cdev_rapl.cpp +@@ -504,6 +504,18 @@ bool cthd_sysfs_cdev_rapl::read_ppcc_power_limits() { + + thd_log_info("ppcc limits max:%u min:%u min_win:%u step:%u\n", + pl0_max_pwr, pl0_min_pwr, pl0_min_window, pl0_step_pwr); ++ ++ int policy_matched; ++ ++ policy_matched = thd_engine->search_idsp("63BE270F-1C11-48FD-A6F7-3AF253FF3E2D"); ++ if (policy_matched != THD_SUCCESS) ++ policy_matched = thd_engine->search_idsp("9E04115A-AE87-4D1C-9500-0F3E340BFE75"); ++ ++ if (policy_matched == THD_SUCCESS) { ++ thd_log_info("IDSP policy matched, so trusting PPCC limits\n"); ++ return true; ++ } ++ + def_max_power = rapl_read_pl1_max(); + if (def_max_power > pl0_max_pwr) + thd_log_warn("ppcc limits is less than def PL1 max power :%d check thermal-conf.xml.auto\n", def_max_power); +diff --git a/src/thd_engine.h b/src/thd_engine.h +index 82ff1fe..4ad70f3 100644 +--- a/src/thd_engine.h ++++ b/src/thd_engine.h +@@ -234,6 +234,9 @@ public: + return config_file; + } + virtual ppcc_t *get_ppcc_param(std::string name); ++ virtual int search_idsp(std::string name) { ++ return THD_ERROR; ++ } + cthd_zone *search_zone(std::string name); + cthd_cdev *search_cdev(std::string name); + cthd_sensor *search_sensor(std::string name); +diff --git a/src/thd_engine_adaptive.h b/src/thd_engine_adaptive.h +index 99c021c..27b5e28 100644 +--- a/src/thd_engine_adaptive.h ++++ b/src/thd_engine_adaptive.h +@@ -69,6 +69,12 @@ public: + ppcc_t* get_ppcc_param(std::string name) { + return gddv.get_ppcc_param(name); + } ++ ++ int search_idsp(std::string name) ++ { ++ return gddv.search_idsp(name); ++ } ++ + int thd_engine_init(bool ignore_cpuid_check, bool adaptive); + int thd_engine_start(); + void update_engine_state(); +diff --git a/src/thd_gddv.cpp b/src/thd_gddv.cpp +index f3a3cd9..8bf7325 100644 +--- a/src/thd_gddv.cpp ++++ b/src/thd_gddv.cpp +@@ -467,6 +467,9 @@ void cthd_gddv::dump_apct() { + } + + ppcc_t* cthd_gddv::get_ppcc_param(std::string name) { ++ if (name != "TCPU.D0") ++ return NULL; ++ + for (int i = 0; i < (int) ppccs.size(); i++) { + if (ppccs[i].name == name) + return &ppccs[i]; +-- +2.34.1 + diff -Nru thermald-2.4.9/debian/patches/0012-Downgrade-warn-to-info-for-missing-sensor.patch thermald-2.4.9/debian/patches/0012-Downgrade-warn-to-info-for-missing-sensor.patch --- thermald-2.4.9/debian/patches/0012-Downgrade-warn-to-info-for-missing-sensor.patch 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/patches/0012-Downgrade-warn-to-info-for-missing-sensor.patch 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1,28 @@ +From 780b58455c7d3d27c306b11360b7c599ce2b11a4 Mon Sep 17 00:00:00 2001 +From: Srinivas Pandruvada +Date: Tue, 5 Jul 2022 16:43:55 -0700 +Subject: [PATCH 12/18] Downgrade warn to info for missing sensor + +When condition table refers to some sensor which is not present, +don't print warning on every check. Just use information level +instead of warning. +--- + src/thd_gddv.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/thd_gddv.cpp b/src/thd_gddv.cpp +index 8bf7325..b252b25 100644 +--- a/src/thd_gddv.cpp ++++ b/src/thd_gddv.cpp +@@ -1185,7 +1185,7 @@ int cthd_gddv::evaluate_temperature_condition( + + cthd_sensor *sensor = thd_engine->search_sensor(sensor_name); + if (!sensor) { +- thd_log_warn("Unable to find a sensor for %s\n", ++ thd_log_info("Unable to find a sensor for %s\n", + condition.device.c_str()); + condition.ignore_condition = 1; + return THD_ERROR; +-- +2.34.1 + diff -Nru thermald-2.4.9/debian/patches/0013-Parse-GDDV-before-thd_engine-init.patch thermald-2.4.9/debian/patches/0013-Parse-GDDV-before-thd_engine-init.patch --- thermald-2.4.9/debian/patches/0013-Parse-GDDV-before-thd_engine-init.patch 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/patches/0013-Parse-GDDV-before-thd_engine-init.patch 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1,44 @@ +From 611ae0cae6b0c5e7e28c9a0d064a8343cf8aff88 Mon Sep 17 00:00:00 2001 +From: Srinivas Pandruvada +Date: Tue, 5 Jul 2022 16:58:24 -0700 +Subject: [PATCH 13/18] Parse GDDV before thd_engine init + +Parse GDDV tables so that IDSP and PPCC information is available +for RAPL cdev. This is just parsing GDDV not evaluating any +conditions. Evaulating conditions will require all sensors +and zone intialized, so that is done during thd_engine_start(). +--- + src/thd_engine_adaptive.cpp | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/src/thd_engine_adaptive.cpp b/src/thd_engine_adaptive.cpp +index 8ab8be6..ddee66b 100644 +--- a/src/thd_engine_adaptive.cpp ++++ b/src/thd_engine_adaptive.cpp +@@ -562,11 +562,6 @@ int cthd_engine_adaptive::thd_engine_init(bool ignore_cpuid_check, + return THD_ERROR; + } + +- /* Read the sensors/zones */ +- res = cthd_engine::thd_engine_init(ignore_cpuid_check, adaptive); +- if (res != THD_SUCCESS) +- return res; +- + if (sysfs.read(int3400_base_path + "firmware_node/path", int3400_path) + < 0) { + thd_log_debug("Unable to locate INT3400 firmware path\n"); +@@ -608,6 +603,11 @@ int cthd_engine_adaptive::thd_engine_init(bool ignore_cpuid_check, + return THD_SUCCESS; + } + ++ /* Read the sensors/zones */ ++ res = cthd_engine::thd_engine_init(ignore_cpuid_check, adaptive); ++ if (res != THD_SUCCESS) ++ return res; ++ + return THD_SUCCESS; + } + +-- +2.34.1 + diff -Nru thermald-2.4.9/debian/patches/0014-Remove-dev-cpu-msr-access-for-TCC.patch thermald-2.4.9/debian/patches/0014-Remove-dev-cpu-msr-access-for-TCC.patch --- thermald-2.4.9/debian/patches/0014-Remove-dev-cpu-msr-access-for-TCC.patch 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/patches/0014-Remove-dev-cpu-msr-access-for-TCC.patch 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1,50 @@ +From 7e490fc79d784b3faf8314af98ec14981ba7fb75 Mon Sep 17 00:00:00 2001 +From: Srinivas Pandruvada +Date: Wed, 6 Jul 2022 12:25:44 -0700 +Subject: [PATCH 14/18] Remove /dev/cpu/*/msr access for TCC + +Since there is a sysfs interface now, remove this direct access. +--- + src/thd_engine_default.cpp | 26 +++----------------------- + 1 file changed, 3 insertions(+), 23 deletions(-) + +diff --git a/src/thd_engine_default.cpp b/src/thd_engine_default.cpp +index c1f9f90..35e3d07 100644 +--- a/src/thd_engine_default.cpp ++++ b/src/thd_engine_default.cpp +@@ -976,29 +976,9 @@ void cthd_engine_default::workaround_tcc_offset(void) + tcc_offset_checked = 1; + } + } else { +- csys_fs msr_sysfs; +- int ret; +- +- if(msr_sysfs.exists("/dev/cpu/0/msr")) { +- unsigned long long val = 0; +- +- ret = msr_sysfs.read("/dev/cpu/0/msr", 0x1a2, (char *)&val, sizeof(val)); +- if (ret > 0) { +- int tcc; +- +- tcc = (val >> 24) & 0xff; +- if (tcc > 10) { +- val &= ~(0xff << 24); +- val |= (0x05 << 24); +- msr_sysfs.write("/dev/cpu/0/msr", 0x1a2, val); +- tcc_offset_checked = 1; +- } else { +- if (!tcc_offset_checked) +- tcc_offset_low = 1; +- tcc_offset_checked = 1; +- } +- } +- } ++ thd_log_info("Kernel update is required to update TCC\n"); ++ tcc_offset_checked = 1; ++ tcc_offset_low = 1; + } + #endif + } +-- +2.34.1 + diff -Nru thermald-2.4.9/debian/patches/0015-Merge-ITM-and-PSVT-tables.patch thermald-2.4.9/debian/patches/0015-Merge-ITM-and-PSVT-tables.patch --- thermald-2.4.9/debian/patches/0015-Merge-ITM-and-PSVT-tables.patch 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/patches/0015-Merge-ITM-and-PSVT-tables.patch 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1,194 @@ +From 7f1d8b225f7dd257e34f2fc9c1b98c81023cdbc7 Mon Sep 17 00:00:00 2001 +From: Srinivas Pandruvada +Date: Thu, 7 Jul 2022 11:45:07 -0700 +Subject: [PATCH 15/18] Merge ITM and PSVT tables + +When both tables are specified for the same action, merge them. +--- + src/thd_engine_adaptive.cpp | 99 +++++++++++++++++++------------------ + src/thd_engine_adaptive.h | 3 +- + 2 files changed, 54 insertions(+), 48 deletions(-) + +diff --git a/src/thd_engine_adaptive.cpp b/src/thd_engine_adaptive.cpp +index ddee66b..a284bcc 100644 +--- a/src/thd_engine_adaptive.cpp ++++ b/src/thd_engine_adaptive.cpp +@@ -321,33 +321,26 @@ int cthd_engine_adaptive::set_itmt_target(struct adaptive_target target) { + return THD_ERROR; + } + +- for (unsigned int i = 0; i < zones.size(); ++i) { +- cthd_zone *_zone = zones[i]; ++ if (!int3400_installed) { ++ for (unsigned int i = 0; i < zones.size(); ++i) { ++ cthd_zone *_zone = zones[i]; + +- // This is only for debug to plot power, so keep +- if (_zone->get_zone_type() == "rapl_pkg_power") +- continue; ++ // This is only for debug to plot power, so keep ++ if (_zone->get_zone_type() == "rapl_pkg_power") ++ continue; + +- _zone->zone_reset(1); +- _zone->trip_delete_all(); ++ _zone->zone_reset(1); ++ _zone->trip_delete_all(); + +- if (_zone->zone_active_status()) +- _zone->set_zone_inactive(); ++ if (_zone->zone_active_status()) ++ _zone->set_zone_inactive(); ++ } + } + + for (int i = 0; i < (int) itmt->itmt_entries.size(); i++) { + install_itmt(&itmt->itmt_entries[i]); + } + +- thd_log_info("\n\n ZONE DUMP BEGIN\n"); +- int new_zone_count = 0; +- for (unsigned int i = 0; i < zones.size(); ++i) { +- zones[i]->zone_dump(); +- if (zones[i]->zone_active_status()) +- ++new_zone_count; +- } +- thd_log_info("\n\n ZONE DUMP END\n"); +- + return THD_SUCCESS; + + } +@@ -355,9 +348,12 @@ int cthd_engine_adaptive::set_itmt_target(struct adaptive_target target) { + void cthd_engine_adaptive::set_int3400_target(struct adaptive_target target) { + + if (target.code == "ITMT") { +- if (set_itmt_target(target) == THD_SUCCESS) +- return; ++ if (set_itmt_target(target) == THD_SUCCESS) { ++ int3400_installed = 1; ++ passive_installed = 1; ++ } + } ++ + if (target.code == "PSVT") { + struct psvt *psvt; + +@@ -368,44 +364,49 @@ void cthd_engine_adaptive::set_int3400_target(struct adaptive_target target) { + return; + } + +- for (unsigned int i = 0; i < zones.size(); ++i) { +- cthd_zone *_zone = zones[i]; ++ if (!int3400_installed) { ++ for (unsigned int i = 0; i < zones.size(); ++i) { ++ cthd_zone *_zone = zones[i]; + +- // This is only for debug to plot power, so keep +- if (_zone->get_zone_type() == "rapl_pkg_power") +- continue; ++ // This is only for debug to plot power, so keep ++ if (_zone->get_zone_type() == "rapl_pkg_power") ++ continue; + +- _zone->zone_reset(1); +- _zone->trip_delete_all(); ++ _zone->zone_reset(1); ++ _zone->trip_delete_all(); + +- if (_zone->zone_active_status()) +- _zone->set_zone_inactive(); ++ if (_zone->zone_active_status()) ++ _zone->set_zone_inactive(); ++ } + } + + for (int i = 0; i < (int) psvt->psvs.size(); i++) { + install_passive(&psvt->psvs[i]); + } ++ passive_installed = 1; ++ int3400_installed = 1; ++ } + +- psvt_consolidate(); ++ psvt_consolidate(); + +- thd_log_info("\n\n ZONE DUMP BEGIN\n"); +- int new_zone_count = 0; +- for (unsigned int i = 0; i < zones.size(); ++i) { +- zones[i]->zone_dump(); +- if (zones[i]->zone_active_status()) +- ++new_zone_count; +- } +- thd_log_info("\n\n ZONE DUMP END\n"); +- if (!new_zone_count) { +- thd_log_warn("Adaptive policy couldn't create any zones\n"); +- thd_log_warn("Possibly some sensors in the PSVT are missing\n"); +- thd_log_warn("Restart in non adaptive mode via systemd\n"); +- csys_fs sysfs("/tmp/ignore_adaptive"); +- sysfs.create(); +- exit(EXIT_FAILURE); +- } +- passive_installed = 1; ++ thd_log_info("\n\n ZONE DUMP BEGIN\n"); ++ int new_zone_count = 0; ++ for (unsigned int i = 0; i < zones.size(); ++i) { ++ zones[i]->zone_dump(); ++ if (zones[i]->zone_active_status()) ++ ++new_zone_count; ++ } ++ thd_log_info("\n\n ZONE DUMP END\n"); ++ ++ if (!new_zone_count) { ++ thd_log_warn("Adaptive policy couldn't create any zones\n"); ++ thd_log_warn("Possibly some sensors in the PSVT are missing\n"); ++ thd_log_warn("Restart in non adaptive mode via systemd\n"); ++ csys_fs sysfs("/tmp/ignore_adaptive"); ++ sysfs.create(); ++ exit(EXIT_FAILURE); + } ++ + if (target.code == "PSV") { + set_trip(target.participant, target.argument); + } +@@ -495,6 +496,7 @@ void cthd_engine_adaptive::execute_target(struct adaptive_target target) { + + void cthd_engine_adaptive::exec_fallback_target(int target) { + thd_log_debug("exec_fallback_target %d\n", target); ++ int3400_installed = 0; + for (int i = 0; i < (int) gddv.targets.size(); i++) { + if (gddv.targets[i].target_id != (uint64_t) target) + continue; +@@ -519,6 +521,9 @@ void cthd_engine_adaptive::update_engine_state() { + } + return; + } ++ ++ int3400_installed = 0; ++ + for (int i = 0; i < (int) gddv.targets.size(); i++) { + if (gddv.targets[i].target_id != (uint64_t) target) + continue; +diff --git a/src/thd_engine_adaptive.h b/src/thd_engine_adaptive.h +index 27b5e28..785d9d2 100644 +--- a/src/thd_engine_adaptive.h ++++ b/src/thd_engine_adaptive.h +@@ -45,6 +45,7 @@ protected: + int passive_def_processed; + int passive_installed; + int power_slider; ++ int int3400_installed; + + int set_itmt_target(struct adaptive_target target); + int install_passive(struct psv *psv); +@@ -61,7 +62,7 @@ public: + cthd_engine_default("63BE270F-1C11-48FD-A6F7-3AF253FF3E2D"), policy_active( + 0), fallback_id(-1), int3400_path(""), int3400_base_path( + ""), passive_def_only(0), passive_def_processed(0), passive_installed( +- 0), power_slider(75) { ++ 0), power_slider(75), int3400_installed(0) { + } + + ~cthd_engine_adaptive() { +-- +2.34.1 + diff -Nru thermald-2.4.9/debian/patches/0016-Add-missing-GPL2-header.patch thermald-2.4.9/debian/patches/0016-Add-missing-GPL2-header.patch --- thermald-2.4.9/debian/patches/0016-Add-missing-GPL2-header.patch 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/patches/0016-Add-missing-GPL2-header.patch 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1,114 @@ +From 193bb6f73c3450d18431f876b1a957bdfacb9fca Mon Sep 17 00:00:00 2001 +From: Srinivas Pandruvada +Date: Thu, 7 Jul 2022 14:37:03 -0700 +Subject: [PATCH 16/18] Add missing GPL2 header + +These files have no headers, so protex complains. +--- + src/thd_adaptive_types.h | 25 +++++++++++++++++++++++++ + src/thd_zone_dynamic.cpp | 23 ++++++++++++++++++++--- + src/thd_zone_dynamic.h | 23 ++++++++++++++++++++--- + 3 files changed, 65 insertions(+), 6 deletions(-) + +diff --git a/src/thd_adaptive_types.h b/src/thd_adaptive_types.h +index f246f26..ce68be2 100644 +--- a/src/thd_adaptive_types.h ++++ b/src/thd_adaptive_types.h +@@ -1,3 +1,28 @@ ++/* ++ * cthd_engine_adaptive.cpp: Adaptive thermal engine ++ * ++ * Copyright (C) 2013 Intel Corporation. All rights reserved. ++ * Copyright 2020 Google LLC ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version ++ * 2 or later as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA. ++ * ++ * ++ * Author Name Matthew Garrett ++ * ++ */ ++ + #ifndef THD_ADAPTIVE_TYPES_H_ + #define THD_ADAPTIVE_TYPES_H_ + +diff --git a/src/thd_zone_dynamic.cpp b/src/thd_zone_dynamic.cpp +index 4009b67..0178234 100644 +--- a/src/thd_zone_dynamic.cpp ++++ b/src/thd_zone_dynamic.cpp +@@ -1,8 +1,25 @@ + /* +- * thd_zone_dynamic.cpp ++ * thd_zone_generic.cpp: zone implementation for xml conf ++ * ++ * Copyright (C) 2013 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version ++ * 2 or later as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA. ++ * ++ * ++ * Author Name + * +- * Created on: Sep 19, 2014 +- * Author: spandruvada + */ + + #include "thd_zone_dynamic.h" +diff --git a/src/thd_zone_dynamic.h b/src/thd_zone_dynamic.h +index 9e00151..4926c23 100644 +--- a/src/thd_zone_dynamic.h ++++ b/src/thd_zone_dynamic.h +@@ -1,8 +1,25 @@ + /* +- * thd_zone_dynamic.h ++ * thd_zone_generic.cpp: zone implementation for xml conf ++ * ++ * Copyright (C) 2013 Intel Corporation. All rights reserved. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version ++ * 2 or later as published by the Free Software Foundation. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA ++ * 02110-1301, USA. ++ * ++ * ++ * Author Name + * +- * Created on: Sep 19, 2014 +- * Author: spandruvada + */ + + #ifndef THD_ZONE_DYNAMIC_H_ +-- +2.34.1 + diff -Nru thermald-2.4.9/debian/patches/0017-Update-version.patch thermald-2.4.9/debian/patches/0017-Update-version.patch --- thermald-2.4.9/debian/patches/0017-Update-version.patch 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/patches/0017-Update-version.patch 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1,731 @@ +From ae0487ab3e7745327689a4b9b91c127bbd398bff Mon Sep 17 00:00:00 2001 +From: Srinivas Pandruvada +Date: Thu, 7 Jul 2022 15:53:05 -0700 +Subject: [PATCH 17/18] Update version + +Update version and license info. +--- + tools/thermal_monitor/COPYING | 674 +++++++++++++++++++++++++++ + tools/thermal_monitor/README | 2 + + tools/thermal_monitor/mainwindow.cpp | 7 +- + 3 files changed, 681 insertions(+), 2 deletions(-) + create mode 100644 tools/thermal_monitor/COPYING + +diff --git a/tools/thermal_monitor/COPYING b/tools/thermal_monitor/COPYING +new file mode 100644 +index 0000000..f288702 +--- /dev/null ++++ b/tools/thermal_monitor/COPYING +@@ -0,0 +1,674 @@ ++ GNU GENERAL PUBLIC LICENSE ++ Version 3, 29 June 2007 ++ ++ Copyright (C) 2007 Free Software Foundation, Inc. ++ Everyone is permitted to copy and distribute verbatim copies ++ of this license document, but changing it is not allowed. ++ ++ Preamble ++ ++ The GNU General Public License is a free, copyleft license for ++software and other kinds of works. ++ ++ The licenses for most software and other practical works are designed ++to take away your freedom to share and change the works. By contrast, ++the GNU General Public License is intended to guarantee your freedom to ++share and change all versions of a program--to make sure it remains free ++software for all its users. We, the Free Software Foundation, use the ++GNU General Public License for most of our software; it applies also to ++any other work released this way by its authors. You can apply it to ++your programs, too. ++ ++ When we speak of free software, we are referring to freedom, not ++price. Our General Public Licenses are designed to make sure that you ++have the freedom to distribute copies of free software (and charge for ++them if you wish), that you receive source code or can get it if you ++want it, that you can change the software or use pieces of it in new ++free programs, and that you know you can do these things. ++ ++ To protect your rights, we need to prevent others from denying you ++these rights or asking you to surrender the rights. Therefore, you have ++certain responsibilities if you distribute copies of the software, or if ++you modify it: responsibilities to respect the freedom of others. ++ ++ For example, if you distribute copies of such a program, whether ++gratis or for a fee, you must pass on to the recipients the same ++freedoms that you received. You must make sure that they, too, receive ++or can get the source code. And you must show them these terms so they ++know their rights. ++ ++ Developers that use the GNU GPL protect your rights with two steps: ++(1) assert copyright on the software, and (2) offer you this License ++giving you legal permission to copy, distribute and/or modify it. ++ ++ For the developers' and authors' protection, the GPL clearly explains ++that there is no warranty for this free software. For both users' and ++authors' sake, the GPL requires that modified versions be marked as ++changed, so that their problems will not be attributed erroneously to ++authors of previous versions. ++ ++ Some devices are designed to deny users access to install or run ++modified versions of the software inside them, although the manufacturer ++can do so. This is fundamentally incompatible with the aim of ++protecting users' freedom to change the software. The systematic ++pattern of such abuse occurs in the area of products for individuals to ++use, which is precisely where it is most unacceptable. Therefore, we ++have designed this version of the GPL to prohibit the practice for those ++products. If such problems arise substantially in other domains, we ++stand ready to extend this provision to those domains in future versions ++of the GPL, as needed to protect the freedom of users. ++ ++ Finally, every program is threatened constantly by software patents. ++States should not allow patents to restrict development and use of ++software on general-purpose computers, but in those that do, we wish to ++avoid the special danger that patents applied to a free program could ++make it effectively proprietary. To prevent this, the GPL assures that ++patents cannot be used to render the program non-free. ++ ++ The precise terms and conditions for copying, distribution and ++modification follow. ++ ++ TERMS AND CONDITIONS ++ ++ 0. Definitions. ++ ++ "This License" refers to version 3 of the GNU General Public License. ++ ++ "Copyright" also means copyright-like laws that apply to other kinds of ++works, such as semiconductor masks. ++ ++ "The Program" refers to any copyrightable work licensed under this ++License. Each licensee is addressed as "you". "Licensees" and ++"recipients" may be individuals or organizations. ++ ++ To "modify" a work means to copy from or adapt all or part of the work ++in a fashion requiring copyright permission, other than the making of an ++exact copy. The resulting work is called a "modified version" of the ++earlier work or a work "based on" the earlier work. ++ ++ A "covered work" means either the unmodified Program or a work based ++on the Program. ++ ++ To "propagate" a work means to do anything with it that, without ++permission, would make you directly or secondarily liable for ++infringement under applicable copyright law, except executing it on a ++computer or modifying a private copy. Propagation includes copying, ++distribution (with or without modification), making available to the ++public, and in some countries other activities as well. ++ ++ To "convey" a work means any kind of propagation that enables other ++parties to make or receive copies. Mere interaction with a user through ++a computer network, with no transfer of a copy, is not conveying. ++ ++ An interactive user interface displays "Appropriate Legal Notices" ++to the extent that it includes a convenient and prominently visible ++feature that (1) displays an appropriate copyright notice, and (2) ++tells the user that there is no warranty for the work (except to the ++extent that warranties are provided), that licensees may convey the ++work under this License, and how to view a copy of this License. If ++the interface presents a list of user commands or options, such as a ++menu, a prominent item in the list meets this criterion. ++ ++ 1. Source Code. ++ ++ The "source code" for a work means the preferred form of the work ++for making modifications to it. "Object code" means any non-source ++form of a work. ++ ++ A "Standard Interface" means an interface that either is an official ++standard defined by a recognized standards body, or, in the case of ++interfaces specified for a particular programming language, one that ++is widely used among developers working in that language. ++ ++ The "System Libraries" of an executable work include anything, other ++than the work as a whole, that (a) is included in the normal form of ++packaging a Major Component, but which is not part of that Major ++Component, and (b) serves only to enable use of the work with that ++Major Component, or to implement a Standard Interface for which an ++implementation is available to the public in source code form. A ++"Major Component", in this context, means a major essential component ++(kernel, window system, and so on) of the specific operating system ++(if any) on which the executable work runs, or a compiler used to ++produce the work, or an object code interpreter used to run it. ++ ++ The "Corresponding Source" for a work in object code form means all ++the source code needed to generate, install, and (for an executable ++work) run the object code and to modify the work, including scripts to ++control those activities. However, it does not include the work's ++System Libraries, or general-purpose tools or generally available free ++programs which are used unmodified in performing those activities but ++which are not part of the work. For example, Corresponding Source ++includes interface definition files associated with source files for ++the work, and the source code for shared libraries and dynamically ++linked subprograms that the work is specifically designed to require, ++such as by intimate data communication or control flow between those ++subprograms and other parts of the work. ++ ++ The Corresponding Source need not include anything that users ++can regenerate automatically from other parts of the Corresponding ++Source. ++ ++ The Corresponding Source for a work in source code form is that ++same work. ++ ++ 2. Basic Permissions. ++ ++ All rights granted under this License are granted for the term of ++copyright on the Program, and are irrevocable provided the stated ++conditions are met. This License explicitly affirms your unlimited ++permission to run the unmodified Program. The output from running a ++covered work is covered by this License only if the output, given its ++content, constitutes a covered work. This License acknowledges your ++rights of fair use or other equivalent, as provided by copyright law. ++ ++ You may make, run and propagate covered works that you do not ++convey, without conditions so long as your license otherwise remains ++in force. You may convey covered works to others for the sole purpose ++of having them make modifications exclusively for you, or provide you ++with facilities for running those works, provided that you comply with ++the terms of this License in conveying all material for which you do ++not control copyright. Those thus making or running the covered works ++for you must do so exclusively on your behalf, under your direction ++and control, on terms that prohibit them from making any copies of ++your copyrighted material outside their relationship with you. ++ ++ Conveying under any other circumstances is permitted solely under ++the conditions stated below. Sublicensing is not allowed; section 10 ++makes it unnecessary. ++ ++ 3. Protecting Users' Legal Rights From Anti-Circumvention Law. ++ ++ No covered work shall be deemed part of an effective technological ++measure under any applicable law fulfilling obligations under article ++11 of the WIPO copyright treaty adopted on 20 December 1996, or ++similar laws prohibiting or restricting circumvention of such ++measures. ++ ++ When you convey a covered work, you waive any legal power to forbid ++circumvention of technological measures to the extent such circumvention ++is effected by exercising rights under this License with respect to ++the covered work, and you disclaim any intention to limit operation or ++modification of the work as a means of enforcing, against the work's ++users, your or third parties' legal rights to forbid circumvention of ++technological measures. ++ ++ 4. Conveying Verbatim Copies. ++ ++ You may convey verbatim copies of the Program's source code as you ++receive it, in any medium, provided that you conspicuously and ++appropriately publish on each copy an appropriate copyright notice; ++keep intact all notices stating that this License and any ++non-permissive terms added in accord with section 7 apply to the code; ++keep intact all notices of the absence of any warranty; and give all ++recipients a copy of this License along with the Program. ++ ++ You may charge any price or no price for each copy that you convey, ++and you may offer support or warranty protection for a fee. ++ ++ 5. Conveying Modified Source Versions. ++ ++ You may convey a work based on the Program, or the modifications to ++produce it from the Program, in the form of source code under the ++terms of section 4, provided that you also meet all of these conditions: ++ ++ a) The work must carry prominent notices stating that you modified ++ it, and giving a relevant date. ++ ++ b) The work must carry prominent notices stating that it is ++ released under this License and any conditions added under section ++ 7. This requirement modifies the requirement in section 4 to ++ "keep intact all notices". ++ ++ c) You must license the entire work, as a whole, under this ++ License to anyone who comes into possession of a copy. This ++ License will therefore apply, along with any applicable section 7 ++ additional terms, to the whole of the work, and all its parts, ++ regardless of how they are packaged. This License gives no ++ permission to license the work in any other way, but it does not ++ invalidate such permission if you have separately received it. ++ ++ d) If the work has interactive user interfaces, each must display ++ Appropriate Legal Notices; however, if the Program has interactive ++ interfaces that do not display Appropriate Legal Notices, your ++ work need not make them do so. ++ ++ A compilation of a covered work with other separate and independent ++works, which are not by their nature extensions of the covered work, ++and which are not combined with it such as to form a larger program, ++in or on a volume of a storage or distribution medium, is called an ++"aggregate" if the compilation and its resulting copyright are not ++used to limit the access or legal rights of the compilation's users ++beyond what the individual works permit. Inclusion of a covered work ++in an aggregate does not cause this License to apply to the other ++parts of the aggregate. ++ ++ 6. Conveying Non-Source Forms. ++ ++ You may convey a covered work in object code form under the terms ++of sections 4 and 5, provided that you also convey the ++machine-readable Corresponding Source under the terms of this License, ++in one of these ways: ++ ++ a) Convey the object code in, or embodied in, a physical product ++ (including a physical distribution medium), accompanied by the ++ Corresponding Source fixed on a durable physical medium ++ customarily used for software interchange. ++ ++ b) Convey the object code in, or embodied in, a physical product ++ (including a physical distribution medium), accompanied by a ++ written offer, valid for at least three years and valid for as ++ long as you offer spare parts or customer support for that product ++ model, to give anyone who possesses the object code either (1) a ++ copy of the Corresponding Source for all the software in the ++ product that is covered by this License, on a durable physical ++ medium customarily used for software interchange, for a price no ++ more than your reasonable cost of physically performing this ++ conveying of source, or (2) access to copy the ++ Corresponding Source from a network server at no charge. ++ ++ c) Convey individual copies of the object code with a copy of the ++ written offer to provide the Corresponding Source. This ++ alternative is allowed only occasionally and noncommercially, and ++ only if you received the object code with such an offer, in accord ++ with subsection 6b. ++ ++ d) Convey the object code by offering access from a designated ++ place (gratis or for a charge), and offer equivalent access to the ++ Corresponding Source in the same way through the same place at no ++ further charge. You need not require recipients to copy the ++ Corresponding Source along with the object code. If the place to ++ copy the object code is a network server, the Corresponding Source ++ may be on a different server (operated by you or a third party) ++ that supports equivalent copying facilities, provided you maintain ++ clear directions next to the object code saying where to find the ++ Corresponding Source. Regardless of what server hosts the ++ Corresponding Source, you remain obligated to ensure that it is ++ available for as long as needed to satisfy these requirements. ++ ++ e) Convey the object code using peer-to-peer transmission, provided ++ you inform other peers where the object code and Corresponding ++ Source of the work are being offered to the general public at no ++ charge under subsection 6d. ++ ++ A separable portion of the object code, whose source code is excluded ++from the Corresponding Source as a System Library, need not be ++included in conveying the object code work. ++ ++ A "User Product" is either (1) a "consumer product", which means any ++tangible personal property which is normally used for personal, family, ++or household purposes, or (2) anything designed or sold for incorporation ++into a dwelling. In determining whether a product is a consumer product, ++doubtful cases shall be resolved in favor of coverage. For a particular ++product received by a particular user, "normally used" refers to a ++typical or common use of that class of product, regardless of the status ++of the particular user or of the way in which the particular user ++actually uses, or expects or is expected to use, the product. A product ++is a consumer product regardless of whether the product has substantial ++commercial, industrial or non-consumer uses, unless such uses represent ++the only significant mode of use of the product. ++ ++ "Installation Information" for a User Product means any methods, ++procedures, authorization keys, or other information required to install ++and execute modified versions of a covered work in that User Product from ++a modified version of its Corresponding Source. The information must ++suffice to ensure that the continued functioning of the modified object ++code is in no case prevented or interfered with solely because ++modification has been made. ++ ++ If you convey an object code work under this section in, or with, or ++specifically for use in, a User Product, and the conveying occurs as ++part of a transaction in which the right of possession and use of the ++User Product is transferred to the recipient in perpetuity or for a ++fixed term (regardless of how the transaction is characterized), the ++Corresponding Source conveyed under this section must be accompanied ++by the Installation Information. But this requirement does not apply ++if neither you nor any third party retains the ability to install ++modified object code on the User Product (for example, the work has ++been installed in ROM). ++ ++ The requirement to provide Installation Information does not include a ++requirement to continue to provide support service, warranty, or updates ++for a work that has been modified or installed by the recipient, or for ++the User Product in which it has been modified or installed. Access to a ++network may be denied when the modification itself materially and ++adversely affects the operation of the network or violates the rules and ++protocols for communication across the network. ++ ++ Corresponding Source conveyed, and Installation Information provided, ++in accord with this section must be in a format that is publicly ++documented (and with an implementation available to the public in ++source code form), and must require no special password or key for ++unpacking, reading or copying. ++ ++ 7. Additional Terms. ++ ++ "Additional permissions" are terms that supplement the terms of this ++License by making exceptions from one or more of its conditions. ++Additional permissions that are applicable to the entire Program shall ++be treated as though they were included in this License, to the extent ++that they are valid under applicable law. If additional permissions ++apply only to part of the Program, that part may be used separately ++under those permissions, but the entire Program remains governed by ++this License without regard to the additional permissions. ++ ++ When you convey a copy of a covered work, you may at your option ++remove any additional permissions from that copy, or from any part of ++it. (Additional permissions may be written to require their own ++removal in certain cases when you modify the work.) You may place ++additional permissions on material, added by you to a covered work, ++for which you have or can give appropriate copyright permission. ++ ++ Notwithstanding any other provision of this License, for material you ++add to a covered work, you may (if authorized by the copyright holders of ++that material) supplement the terms of this License with terms: ++ ++ a) Disclaiming warranty or limiting liability differently from the ++ terms of sections 15 and 16 of this License; or ++ ++ b) Requiring preservation of specified reasonable legal notices or ++ author attributions in that material or in the Appropriate Legal ++ Notices displayed by works containing it; or ++ ++ c) Prohibiting misrepresentation of the origin of that material, or ++ requiring that modified versions of such material be marked in ++ reasonable ways as different from the original version; or ++ ++ d) Limiting the use for publicity purposes of names of licensors or ++ authors of the material; or ++ ++ e) Declining to grant rights under trademark law for use of some ++ trade names, trademarks, or service marks; or ++ ++ f) Requiring indemnification of licensors and authors of that ++ material by anyone who conveys the material (or modified versions of ++ it) with contractual assumptions of liability to the recipient, for ++ any liability that these contractual assumptions directly impose on ++ those licensors and authors. ++ ++ All other non-permissive additional terms are considered "further ++restrictions" within the meaning of section 10. If the Program as you ++received it, or any part of it, contains a notice stating that it is ++governed by this License along with a term that is a further ++restriction, you may remove that term. If a license document contains ++a further restriction but permits relicensing or conveying under this ++License, you may add to a covered work material governed by the terms ++of that license document, provided that the further restriction does ++not survive such relicensing or conveying. ++ ++ If you add terms to a covered work in accord with this section, you ++must place, in the relevant source files, a statement of the ++additional terms that apply to those files, or a notice indicating ++where to find the applicable terms. ++ ++ Additional terms, permissive or non-permissive, may be stated in the ++form of a separately written license, or stated as exceptions; ++the above requirements apply either way. ++ ++ 8. Termination. ++ ++ You may not propagate or modify a covered work except as expressly ++provided under this License. Any attempt otherwise to propagate or ++modify it is void, and will automatically terminate your rights under ++this License (including any patent licenses granted under the third ++paragraph of section 11). ++ ++ However, if you cease all violation of this License, then your ++license from a particular copyright holder is reinstated (a) ++provisionally, unless and until the copyright holder explicitly and ++finally terminates your license, and (b) permanently, if the copyright ++holder fails to notify you of the violation by some reasonable means ++prior to 60 days after the cessation. ++ ++ Moreover, your license from a particular copyright holder is ++reinstated permanently if the copyright holder notifies you of the ++violation by some reasonable means, this is the first time you have ++received notice of violation of this License (for any work) from that ++copyright holder, and you cure the violation prior to 30 days after ++your receipt of the notice. ++ ++ Termination of your rights under this section does not terminate the ++licenses of parties who have received copies or rights from you under ++this License. If your rights have been terminated and not permanently ++reinstated, you do not qualify to receive new licenses for the same ++material under section 10. ++ ++ 9. Acceptance Not Required for Having Copies. ++ ++ You are not required to accept this License in order to receive or ++run a copy of the Program. Ancillary propagation of a covered work ++occurring solely as a consequence of using peer-to-peer transmission ++to receive a copy likewise does not require acceptance. However, ++nothing other than this License grants you permission to propagate or ++modify any covered work. These actions infringe copyright if you do ++not accept this License. Therefore, by modifying or propagating a ++covered work, you indicate your acceptance of this License to do so. ++ ++ 10. Automatic Licensing of Downstream Recipients. ++ ++ Each time you convey a covered work, the recipient automatically ++receives a license from the original licensors, to run, modify and ++propagate that work, subject to this License. You are not responsible ++for enforcing compliance by third parties with this License. ++ ++ An "entity transaction" is a transaction transferring control of an ++organization, or substantially all assets of one, or subdividing an ++organization, or merging organizations. If propagation of a covered ++work results from an entity transaction, each party to that ++transaction who receives a copy of the work also receives whatever ++licenses to the work the party's predecessor in interest had or could ++give under the previous paragraph, plus a right to possession of the ++Corresponding Source of the work from the predecessor in interest, if ++the predecessor has it or can get it with reasonable efforts. ++ ++ You may not impose any further restrictions on the exercise of the ++rights granted or affirmed under this License. For example, you may ++not impose a license fee, royalty, or other charge for exercise of ++rights granted under this License, and you may not initiate litigation ++(including a cross-claim or counterclaim in a lawsuit) alleging that ++any patent claim is infringed by making, using, selling, offering for ++sale, or importing the Program or any portion of it. ++ ++ 11. Patents. ++ ++ A "contributor" is a copyright holder who authorizes use under this ++License of the Program or a work on which the Program is based. The ++work thus licensed is called the contributor's "contributor version". ++ ++ A contributor's "essential patent claims" are all patent claims ++owned or controlled by the contributor, whether already acquired or ++hereafter acquired, that would be infringed by some manner, permitted ++by this License, of making, using, or selling its contributor version, ++but do not include claims that would be infringed only as a ++consequence of further modification of the contributor version. For ++purposes of this definition, "control" includes the right to grant ++patent sublicenses in a manner consistent with the requirements of ++this License. ++ ++ Each contributor grants you a non-exclusive, worldwide, royalty-free ++patent license under the contributor's essential patent claims, to ++make, use, sell, offer for sale, import and otherwise run, modify and ++propagate the contents of its contributor version. ++ ++ In the following three paragraphs, a "patent license" is any express ++agreement or commitment, however denominated, not to enforce a patent ++(such as an express permission to practice a patent or covenant not to ++sue for patent infringement). To "grant" such a patent license to a ++party means to make such an agreement or commitment not to enforce a ++patent against the party. ++ ++ If you convey a covered work, knowingly relying on a patent license, ++and the Corresponding Source of the work is not available for anyone ++to copy, free of charge and under the terms of this License, through a ++publicly available network server or other readily accessible means, ++then you must either (1) cause the Corresponding Source to be so ++available, or (2) arrange to deprive yourself of the benefit of the ++patent license for this particular work, or (3) arrange, in a manner ++consistent with the requirements of this License, to extend the patent ++license to downstream recipients. "Knowingly relying" means you have ++actual knowledge that, but for the patent license, your conveying the ++covered work in a country, or your recipient's use of the covered work ++in a country, would infringe one or more identifiable patents in that ++country that you have reason to believe are valid. ++ ++ If, pursuant to or in connection with a single transaction or ++arrangement, you convey, or propagate by procuring conveyance of, a ++covered work, and grant a patent license to some of the parties ++receiving the covered work authorizing them to use, propagate, modify ++or convey a specific copy of the covered work, then the patent license ++you grant is automatically extended to all recipients of the covered ++work and works based on it. ++ ++ A patent license is "discriminatory" if it does not include within ++the scope of its coverage, prohibits the exercise of, or is ++conditioned on the non-exercise of one or more of the rights that are ++specifically granted under this License. You may not convey a covered ++work if you are a party to an arrangement with a third party that is ++in the business of distributing software, under which you make payment ++to the third party based on the extent of your activity of conveying ++the work, and under which the third party grants, to any of the ++parties who would receive the covered work from you, a discriminatory ++patent license (a) in connection with copies of the covered work ++conveyed by you (or copies made from those copies), or (b) primarily ++for and in connection with specific products or compilations that ++contain the covered work, unless you entered into that arrangement, ++or that patent license was granted, prior to 28 March 2007. ++ ++ Nothing in this License shall be construed as excluding or limiting ++any implied license or other defenses to infringement that may ++otherwise be available to you under applicable patent law. ++ ++ 12. No Surrender of Others' Freedom. ++ ++ If conditions are imposed on you (whether by court order, agreement or ++otherwise) that contradict the conditions of this License, they do not ++excuse you from the conditions of this License. If you cannot convey a ++covered work so as to satisfy simultaneously your obligations under this ++License and any other pertinent obligations, then as a consequence you may ++not convey it at all. For example, if you agree to terms that obligate you ++to collect a royalty for further conveying from those to whom you convey ++the Program, the only way you could satisfy both those terms and this ++License would be to refrain entirely from conveying the Program. ++ ++ 13. Use with the GNU Affero General Public License. ++ ++ Notwithstanding any other provision of this License, you have ++permission to link or combine any covered work with a work licensed ++under version 3 of the GNU Affero General Public License into a single ++combined work, and to convey the resulting work. The terms of this ++License will continue to apply to the part which is the covered work, ++but the special requirements of the GNU Affero General Public License, ++section 13, concerning interaction through a network will apply to the ++combination as such. ++ ++ 14. Revised Versions of this License. ++ ++ The Free Software Foundation may publish revised and/or new versions of ++the GNU General Public License from time to time. Such new versions will ++be similar in spirit to the present version, but may differ in detail to ++address new problems or concerns. ++ ++ Each version is given a distinguishing version number. If the ++Program specifies that a certain numbered version of the GNU General ++Public License "or any later version" applies to it, you have the ++option of following the terms and conditions either of that numbered ++version or of any later version published by the Free Software ++Foundation. If the Program does not specify a version number of the ++GNU General Public License, you may choose any version ever published ++by the Free Software Foundation. ++ ++ If the Program specifies that a proxy can decide which future ++versions of the GNU General Public License can be used, that proxy's ++public statement of acceptance of a version permanently authorizes you ++to choose that version for the Program. ++ ++ Later license versions may give you additional or different ++permissions. However, no additional obligations are imposed on any ++author or copyright holder as a result of your choosing to follow a ++later version. ++ ++ 15. Disclaimer of Warranty. ++ ++ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY ++APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT ++HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY ++OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, ++THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM ++IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ++ALL NECESSARY SERVICING, REPAIR OR CORRECTION. ++ ++ 16. Limitation of Liability. ++ ++ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING ++WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS ++THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY ++GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE ++USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF ++DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD ++PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), ++EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF ++SUCH DAMAGES. ++ ++ 17. Interpretation of Sections 15 and 16. ++ ++ If the disclaimer of warranty and limitation of liability provided ++above cannot be given local legal effect according to their terms, ++reviewing courts shall apply local law that most closely approximates ++an absolute waiver of all civil liability in connection with the ++Program, unless a warranty or assumption of liability accompanies a ++copy of the Program in return for a fee. ++ ++ END OF TERMS AND CONDITIONS ++ ++ How to Apply These Terms to Your New Programs ++ ++ If you develop a new program, and you want it to be of the greatest ++possible use to the public, the best way to achieve this is to make it ++free software which everyone can redistribute and change under these terms. ++ ++ To do so, attach the following notices to the program. It is safest ++to attach them to the start of each source file to most effectively ++state the exclusion of warranty; and each file should have at least ++the "copyright" line and a pointer to where the full notice is found. ++ ++ ++ Copyright (C) ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 3 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . ++ ++Also add information on how to contact you by electronic and paper mail. ++ ++ If the program does terminal interaction, make it output a short ++notice like this when it starts in an interactive mode: ++ ++ Copyright (C) ++ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. ++ This is free software, and you are welcome to redistribute it ++ under certain conditions; type `show c' for details. ++ ++The hypothetical commands `show w' and `show c' should show the appropriate ++parts of the General Public License. Of course, your program's commands ++might be different; for a GUI interface, you would use an "about box". ++ ++ You should also get your employer (if you work as a programmer) or school, ++if any, to sign a "copyright disclaimer" for the program, if necessary. ++For more information on this, and how to apply and follow the GNU GPL, see ++. ++ ++ The GNU General Public License does not permit incorporating your program ++into proprietary programs. If your program is a subroutine library, you ++may consider it more useful to permit linking proprietary applications with ++the library. If this is what you want to do, use the GNU Lesser General ++Public License instead of this License. But first, please read ++. +diff --git a/tools/thermal_monitor/README b/tools/thermal_monitor/README +index cb0c416..18ed932 100644 +--- a/tools/thermal_monitor/README ++++ b/tools/thermal_monitor/README +@@ -38,3 +38,5 @@ qmake ThermalMonitor.pro + + After the makefile has been created, use 'make' to build the project. The object files and executable will be in the same directory as the source code, a different location than when using Qt Creator. Use 'make clean' to clean up everything except the executable. + ++Dependency on qcustomplot ++To build you need to download qcustomplot-devel or libqcustomplot-dev depending on your distribution. +diff --git a/tools/thermal_monitor/mainwindow.cpp b/tools/thermal_monitor/mainwindow.cpp +index f29b135..f6be3a3 100644 +--- a/tools/thermal_monitor/mainwindow.cpp ++++ b/tools/thermal_monitor/mainwindow.cpp +@@ -27,7 +27,7 @@ + #define SAMPLE_STORE_SIZE 100 + #define DEFAULT_LOGFILE_NAME "log.txt" + #define CUSTOMPLOT_YAXIS_RANGE 120 +-#define VERSION_NUMBER "1.2" ++#define VERSION_NUMBER "1.3" + + MainWindow::MainWindow(ThermaldInterface *thermaldInterface) : QMainWindow(), + temp_samples(SAMPLE_STORE_SIZE), +@@ -488,7 +488,10 @@ void MainWindow::showAboutDialog() + QString str; + str = QString("

Thermal Monitor %1

" + "

GUI for Linux thermal daemon (thermald)

" +- "

Copyright (c) 2020, Intel Corporation

") ++ "

Copyright (c) 2022, Intel Corporation

" ++ "

This program comes with ABSOLUTELY NO WARRANTY

" ++ "

This work is licensed under GPL v3

" ++ "

Refer to https://www.gnu.org/licenses/gpl-3.0.txt

") + .arg(QString(VERSION_NUMBER)); + QMessageBox::about(this, "About Thermal Monitor", str); + } +-- +2.34.1 + diff -Nru thermald-2.4.9/debian/patches/0018-Update-help-text.patch thermald-2.4.9/debian/patches/0018-Update-help-text.patch --- thermald-2.4.9/debian/patches/0018-Update-help-text.patch 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/patches/0018-Update-help-text.patch 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1,31 @@ +From 70d1c182619367fa08631ef6f0e10e8306eac51d Mon Sep 17 00:00:00 2001 +From: Srinivas Pandruvada +Date: Thu, 7 Jul 2022 17:07:44 -0700 +Subject: [PATCH 18/18] Update help text + +--- + src/main.cpp | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/main.cpp b/src/main.cpp +index dba0de9..f915e18 100644 +--- a/src/main.cpp ++++ b/src/main.cpp +@@ -252,8 +252,12 @@ int main(int argc, char *argv[]) { + + g_option_context_set_summary(opt_ctx, + +- "Thermal daemon monitors temperature sensors and decides the best action " +- "based on the temperature readings and user preferences."); ++ "Thermal daemon monitors temperature sensors and decides the best action\n" ++ "based on the temperature readings and user preferences.\n\n" ++ "Copyright (c) 2022, Intel Corporation\n" ++ "This program comes with ABSOLUTELY NO WARRANTY.\n" ++ "This work is licensed under GPL v2.\n" ++ "Refer to https://github.com/intel/thermal_daemon/blob/master/COPYING."); + + success = g_option_context_parse(opt_ctx, &argc, &argv, NULL); + g_option_context_free(opt_ctx); +-- +2.34.1 + diff -Nru thermald-2.4.9/debian/patches/0019-main-Handle-signals-from-mainloop.patch thermald-2.4.9/debian/patches/0019-main-Handle-signals-from-mainloop.patch --- thermald-2.4.9/debian/patches/0019-main-Handle-signals-from-mainloop.patch 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/patches/0019-main-Handle-signals-from-mainloop.patch 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1,100 @@ +From 8caacb1d78a0322b0da392c331dfda4e4e4e3236 Mon Sep 17 00:00:00 2001 +From: Benjamin Berg +Date: Thu, 14 Jul 2022 11:24:14 +0200 +Subject: [PATCH] main: Handle signals from mainloop + +The signal handler ends up calling quite a lot of code, not all of this +code is signal safe. Fix the issue by instead using the GLib +infrastructure to execute the code from the mainloop instead. + +Note that there are probably more cleanups to be had here. But this is +sufficient to fix the signal safety. + +Fixes: #361 +--- + src/main.cpp | 12 +++++++----- + src/thd_dbus_interface.cpp | 6 +++--- + 2 files changed, 10 insertions(+), 8 deletions(-) + +diff --git a/src/main.cpp b/src/main.cpp +index f915e18..6e2f5e4 100644 +--- a/src/main.cpp ++++ b/src/main.cpp +@@ -37,8 +37,8 @@ + * if the thermal-conf.xml defines parameters. + */ + ++#include + #include +-#include + #include "thermald.h" + #include "thd_preference.h" + #include "thd_engine.h" +@@ -53,7 +53,7 @@ + + #define EXIT_UNSUPPORTED 2 + +-extern int thd_dbus_server_init(void (*exit_handler)(int)); ++extern int thd_dbus_server_init(gboolean (*exit_handler)(void)); + + // Lock file + static int lock_file_handle = -1; +@@ -159,7 +159,7 @@ bool check_thermald_running() { + } + + // SIGTERM & SIGINT handler +-void sig_int_handler(int signum) { ++gboolean sig_int_handler(void) { + if (thd_engine) + thd_engine->thd_engine_terminate(); + sleep(1); +@@ -168,6 +168,8 @@ void sig_int_handler(int signum) { + delete thd_engine; + clean_up_lockfile(); + exit(EXIT_SUCCESS); ++ ++ return FALSE; + } + + // main function +@@ -311,8 +313,8 @@ int main(int argc, char *argv[]) { + } + + if (!thd_daemonize) { +- signal(SIGINT, sig_int_handler); +- signal(SIGTERM, sig_int_handler); ++ g_unix_signal_add (SIGINT, G_SOURCE_FUNC (sig_int_handler), NULL); ++ g_unix_signal_add (SIGTERM, G_SOURCE_FUNC (sig_int_handler), NULL); + } + + // Initialize the GType/GObject system +diff --git a/src/thd_dbus_interface.cpp b/src/thd_dbus_interface.cpp +index f847554..0dcbf6f 100644 +--- a/src/thd_dbus_interface.cpp ++++ b/src/thd_dbus_interface.cpp +@@ -188,11 +188,11 @@ gboolean thd_dbus_interface_get_current_preference(PrefObject *obj, + return TRUE; + } + +-void (*thd_dbus_exit_callback)(int); ++gboolean (*thd_dbus_exit_callback)(void); + gboolean thd_dbus_interface_terminate(PrefObject *obj, GError **error) { + thd_engine->thd_engine_terminate(); + if (thd_dbus_exit_callback) +- thd_dbus_exit_callback(0); ++ thd_dbus_exit_callback(); + + return TRUE; + } +@@ -578,7 +578,7 @@ gboolean thd_dbus_interface_get_sensor_temperature(PrefObject *obj, int index, + } + + // Setup dbus server +-int thd_dbus_server_init(void (*exit_handler)(int)) { ++int thd_dbus_server_init(gboolean (*exit_handler)(void)) { + DBusGConnection *bus; + DBusGProxy *bus_proxy; + GError *error = NULL; +-- +2.34.1 + diff -Nru thermald-2.4.9/debian/patches/0020-Ensure-there-is-one-trips-element-per-zone.patch thermald-2.4.9/debian/patches/0020-Ensure-there-is-one-trips-element-per-zone.patch --- thermald-2.4.9/debian/patches/0020-Ensure-there-is-one-trips-element-per-zone.patch 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/patches/0020-Ensure-there-is-one-trips-element-per-zone.patch 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1,40 @@ +From 7486cdf7362a8711437b38c3789f17825a4f9615 Mon Sep 17 00:00:00 2001 +From: Ludovico Cavedon +Date: Tue, 12 Jul 2022 15:21:24 -0700 +Subject: [PATCH] Ensure there is one trips element per zone + +In some cases a trip element was not added for every zone, causing an +out-of-bound access to the trips vector (which is indexed by zone number). + +In this change we ensure that a (possinly empty) trips element is added for +each zone. +--- + tools/thermal_monitor/mainwindow.cpp | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/tools/thermal_monitor/mainwindow.cpp b/tools/thermal_monitor/mainwindow.cpp +index f6be3a3..d694970 100644 +--- a/tools/thermal_monitor/mainwindow.cpp ++++ b/tools/thermal_monitor/mainwindow.cpp +@@ -116,6 +116,9 @@ void MainWindow::setupPlotWidget() + currentTempsensorIndex = 0; + int active_zone = 0; + for (uint zone = 0; zone < m_thermaldInterface->getZoneCount(); zone++) { ++ // Trips is indexed by zone. We need to make sure there is a tips item ++ // (even if empty) for each zone. ++ trips.append(QVector()); + + zoneInformationType *zone_info = m_thermaldInterface->getZone(zone); + if (!zone_info) +@@ -180,7 +183,7 @@ void MainWindow::setupPlotWidget() + } + these_trips.append(line); + } +- trips.append(these_trips); ++ trips.last().swap(these_trips); + } + } + +-- +2.34.1 + diff -Nru thermald-2.4.9/debian/patches/series thermald-2.4.9/debian/patches/series --- thermald-2.4.9/debian/patches/series 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/patches/series 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1,20 @@ +0001-Fixed-enumeration-of-cpu-thermal-sensors.patch +0002-Parse-ITMT-Table.patch +0003-Add-capability-for-min-max-per-trip.patch +0004-Install-ITMT-target.patch +0005-Use-per-trip-min-max.patch +0006-Add-INT3400-base-path-for-Raptor-Lake.patch +0007-Move-interface-debug_mode_on-to-thd_engine.patch +0008-Separate-Adaptive-engine-and-GDDV.patch +0009-Parse-idsp-and-trips.patch +0010-Add-_TRT-parsing.patch +0011-Use-PL1-max-min-from-PPCC-when-policies-match.patch +0012-Downgrade-warn-to-info-for-missing-sensor.patch +0013-Parse-GDDV-before-thd_engine-init.patch +0014-Remove-dev-cpu-msr-access-for-TCC.patch +0015-Merge-ITM-and-PSVT-tables.patch +0016-Add-missing-GPL2-header.patch +0017-Update-version.patch +0018-Update-help-text.patch +0019-main-Handle-signals-from-mainloop.patch +0020-Ensure-there-is-one-trips-element-per-zone.patch diff -Nru thermald-2.4.9/debian/.pc/.quilt_patches thermald-2.4.9/debian/.pc/.quilt_patches --- thermald-2.4.9/debian/.pc/.quilt_patches 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/.pc/.quilt_patches 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1 @@ +patches diff -Nru thermald-2.4.9/debian/.pc/.quilt_series thermald-2.4.9/debian/.pc/.quilt_series --- thermald-2.4.9/debian/.pc/.quilt_series 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/.pc/.quilt_series 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1 @@ +series diff -Nru thermald-2.4.9/debian/.pc/.version thermald-2.4.9/debian/.pc/.version --- thermald-2.4.9/debian/.pc/.version 1970-01-01 08:00:00.000000000 +0800 +++ thermald-2.4.9/debian/.pc/.version 2022-07-21 12:30:55.000000000 +0800 @@ -0,0 +1 @@ +2