^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * acpi_thermal.c - ACPI Thermal Zone Driver ($Revision: 41 $)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * This driver fully implements the ACPI thermal policy as described in the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * ACPI 2.0 Specification.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * TBD: 1. Implement passive cooling hysteresis.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * 2. Enhance passive cooling (CPU) states/limit interface to support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * concepts of 'multiple limiters', upper/lower limits, etc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/dmi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/jiffies.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/kmod.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/reboot.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <linux/thermal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include <linux/acpi.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <linux/workqueue.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/units.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define PREFIX "ACPI: "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define ACPI_THERMAL_CLASS "thermal_zone"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define ACPI_THERMAL_DEVICE_NAME "Thermal Zone"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define ACPI_THERMAL_NOTIFY_TEMPERATURE 0x80
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #define ACPI_THERMAL_NOTIFY_THRESHOLDS 0x81
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) #define ACPI_THERMAL_NOTIFY_DEVICES 0x82
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define ACPI_THERMAL_NOTIFY_CRITICAL 0xF0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define ACPI_THERMAL_NOTIFY_HOT 0xF1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define ACPI_THERMAL_MODE_ACTIVE 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) #define ACPI_THERMAL_MAX_ACTIVE 10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) #define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define _COMPONENT ACPI_THERMAL_COMPONENT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) ACPI_MODULE_NAME("thermal");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) MODULE_AUTHOR("Paul Diefenbaugh");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) MODULE_DESCRIPTION("ACPI Thermal Zone Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static int act;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) module_param(act, int, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) MODULE_PARM_DESC(act, "Disable or override all lowest active trip points.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static int crt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) module_param(crt, int, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) MODULE_PARM_DESC(crt, "Disable or lower all critical trip points.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) static int tzp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) module_param(tzp, int, 0444);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static int nocrt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) module_param(nocrt, int, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) MODULE_PARM_DESC(nocrt, "Set to take no action upon ACPI thermal zone critical trips points.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static int off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) module_param(off, int, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) MODULE_PARM_DESC(off, "Set to disable ACPI thermal support.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) static int psv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) module_param(psv, int, 0644);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) MODULE_PARM_DESC(psv, "Disable or override all passive trip points.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) static struct workqueue_struct *acpi_thermal_pm_queue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) static int acpi_thermal_add(struct acpi_device *device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) static int acpi_thermal_remove(struct acpi_device *device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static void acpi_thermal_notify(struct acpi_device *device, u32 event);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) static const struct acpi_device_id thermal_device_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) {ACPI_THERMAL_HID, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) {"", 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) MODULE_DEVICE_TABLE(acpi, thermal_device_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) #ifdef CONFIG_PM_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static int acpi_thermal_suspend(struct device *dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) static int acpi_thermal_resume(struct device *dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) #define acpi_thermal_suspend NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) #define acpi_thermal_resume NULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, acpi_thermal_suspend, acpi_thermal_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) static struct acpi_driver acpi_thermal_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) .name = "thermal",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) .class = ACPI_THERMAL_CLASS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) .ids = thermal_device_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) .ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) .add = acpi_thermal_add,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) .remove = acpi_thermal_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) .notify = acpi_thermal_notify,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) .drv.pm = &acpi_thermal_pm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct acpi_thermal_state {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) u8 critical:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) u8 hot:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) u8 passive:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) u8 active:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) u8 reserved:4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) int active_index;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) struct acpi_thermal_state_flags {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) u8 valid:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) u8 enabled:1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) u8 reserved:6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) struct acpi_thermal_critical {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) struct acpi_thermal_state_flags flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) unsigned long temperature;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) struct acpi_thermal_hot {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) struct acpi_thermal_state_flags flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) unsigned long temperature;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) struct acpi_thermal_passive {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) struct acpi_thermal_state_flags flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) unsigned long temperature;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) unsigned long tc1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) unsigned long tc2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) unsigned long tsp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) struct acpi_handle_list devices;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) struct acpi_thermal_active {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) struct acpi_thermal_state_flags flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) unsigned long temperature;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) struct acpi_handle_list devices;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) struct acpi_thermal_trips {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) struct acpi_thermal_critical critical;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) struct acpi_thermal_hot hot;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) struct acpi_thermal_passive passive;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) struct acpi_thermal_active active[ACPI_THERMAL_MAX_ACTIVE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) struct acpi_thermal_flags {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) u8 cooling_mode:1; /* _SCP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) u8 devices:1; /* _TZD */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) u8 reserved:6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) struct acpi_thermal {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) struct acpi_device * device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) acpi_bus_id name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) unsigned long temperature;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) unsigned long last_temperature;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) unsigned long polling_frequency;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) volatile u8 zombie;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) struct acpi_thermal_flags flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) struct acpi_thermal_state state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) struct acpi_thermal_trips trips;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) struct acpi_handle_list devices;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) struct thermal_zone_device *thermal_zone;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) int kelvin_offset; /* in millidegrees */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) struct work_struct thermal_check_work;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) struct mutex thermal_check_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) refcount_t thermal_check_count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) /* --------------------------------------------------------------------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) Thermal Zone Management
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) -------------------------------------------------------------------------- */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) static int acpi_thermal_get_temperature(struct acpi_thermal *tz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) acpi_status status = AE_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) unsigned long long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) if (!tz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) tz->last_temperature = tz->temperature;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) status = acpi_evaluate_integer(tz->device->handle, "_TMP", NULL, &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) if (ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) tz->temperature = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Temperature is %lu dK\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) tz->temperature));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) acpi_status status = AE_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) unsigned long long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) if (!tz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) status = acpi_evaluate_integer(tz->device->handle, "_TZP", NULL, &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) if (ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) tz->polling_frequency = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency is %lu dS\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) tz->polling_frequency));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (!tz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) if (ACPI_FAILURE(acpi_execute_simple_method(tz->device->handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) "_SCP", mode)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) #define ACPI_TRIPS_CRITICAL 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) #define ACPI_TRIPS_HOT 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) #define ACPI_TRIPS_PASSIVE 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) #define ACPI_TRIPS_ACTIVE 0x08
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) #define ACPI_TRIPS_DEVICES 0x10
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) #define ACPI_TRIPS_REFRESH_THRESHOLDS (ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) #define ACPI_TRIPS_REFRESH_DEVICES ACPI_TRIPS_DEVICES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) #define ACPI_TRIPS_INIT (ACPI_TRIPS_CRITICAL | ACPI_TRIPS_HOT | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE | \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) ACPI_TRIPS_DEVICES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) * This exception is thrown out in two cases:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) * 1.An invalid trip point becomes invalid or a valid trip point becomes invalid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) * when re-evaluating the AML code.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) * 2.TODO: Devices listed in _PSL, _ALx, _TZD may change.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) * We need to re-bind the cooling devices of a thermal zone when this occurs.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) #define ACPI_THERMAL_TRIPS_EXCEPTION(flags, str) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) do { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) if (flags != ACPI_TRIPS_INIT) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) ACPI_EXCEPTION((AE_INFO, AE_ERROR, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) "ACPI thermal trip point %s changed\n" \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) "Please send acpidump to linux-acpi@vger.kernel.org", str)); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) } while (0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) acpi_status status = AE_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) unsigned long long tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) struct acpi_handle_list devices;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) int valid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) /* Critical Shutdown */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) if (flag & ACPI_TRIPS_CRITICAL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) status = acpi_evaluate_integer(tz->device->handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) "_CRT", NULL, &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) tz->trips.critical.temperature = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) * Treat freezing temperatures as invalid as well; some
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) * BIOSes return really low values and cause reboots at startup.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) * Below zero (Celsius) values clearly aren't right for sure..
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) * ... so lets discard those as invalid.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) tz->trips.critical.flags.valid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) ACPI_DEBUG_PRINT((ACPI_DB_INFO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) "No critical threshold\n"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) } else if (tmp <= 2732) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) pr_warn(FW_BUG "Invalid critical threshold (%llu)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) tz->trips.critical.flags.valid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) tz->trips.critical.flags.valid = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) ACPI_DEBUG_PRINT((ACPI_DB_INFO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) "Found critical threshold [%lu]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) tz->trips.critical.temperature));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) if (tz->trips.critical.flags.valid == 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) if (crt == -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) tz->trips.critical.flags.valid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) } else if (crt > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) unsigned long crt_k = celsius_to_deci_kelvin(crt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) * Allow override critical threshold
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) if (crt_k > tz->trips.critical.temperature)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) pr_warn(PREFIX "Critical threshold %d C\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) crt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) tz->trips.critical.temperature = crt_k;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) /* Critical Sleep (optional) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) if (flag & ACPI_TRIPS_HOT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) status = acpi_evaluate_integer(tz->device->handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) "_HOT", NULL, &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) tz->trips.hot.flags.valid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) ACPI_DEBUG_PRINT((ACPI_DB_INFO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) "No hot threshold\n"));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) tz->trips.hot.temperature = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) tz->trips.hot.flags.valid = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) ACPI_DEBUG_PRINT((ACPI_DB_INFO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) "Found hot threshold [%lu]\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) tz->trips.hot.temperature));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) /* Passive (optional) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (((flag & ACPI_TRIPS_PASSIVE) && tz->trips.passive.flags.valid) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) (flag == ACPI_TRIPS_INIT)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) valid = tz->trips.passive.flags.valid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) if (psv == -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) status = AE_SUPPORT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) } else if (psv > 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) tmp = celsius_to_deci_kelvin(psv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) status = AE_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) status = acpi_evaluate_integer(tz->device->handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) "_PSV", NULL, &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) if (ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) tz->trips.passive.flags.valid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) tz->trips.passive.temperature = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) tz->trips.passive.flags.valid = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) if (flag == ACPI_TRIPS_INIT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) status = acpi_evaluate_integer(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) tz->device->handle, "_TC1",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) NULL, &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) if (ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) tz->trips.passive.flags.valid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) tz->trips.passive.tc1 = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) status = acpi_evaluate_integer(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) tz->device->handle, "_TC2",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) NULL, &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) if (ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) tz->trips.passive.flags.valid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) tz->trips.passive.tc2 = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) status = acpi_evaluate_integer(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) tz->device->handle, "_TSP",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) NULL, &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) if (ACPI_FAILURE(status))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) tz->trips.passive.flags.valid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) tz->trips.passive.tsp = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.flags.valid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) memset(&devices, 0, sizeof(struct acpi_handle_list));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) status = acpi_evaluate_reference(tz->device->handle, "_PSL",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) NULL, &devices);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) pr_warn(PREFIX "Invalid passive threshold\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) tz->trips.passive.flags.valid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) tz->trips.passive.flags.valid = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) if (memcmp(&tz->trips.passive.devices, &devices,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) sizeof(struct acpi_handle_list))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) memcpy(&tz->trips.passive.devices, &devices,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) sizeof(struct acpi_handle_list));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) if ((flag & ACPI_TRIPS_PASSIVE) || (flag & ACPI_TRIPS_DEVICES)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) if (valid != tz->trips.passive.flags.valid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) /* Active (optional) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) valid = tz->trips.active[i].flags.valid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) if (act == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) break; /* disable all active trip points */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) if ((flag == ACPI_TRIPS_INIT) || ((flag & ACPI_TRIPS_ACTIVE) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) tz->trips.active[i].flags.valid)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) status = acpi_evaluate_integer(tz->device->handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) name, NULL, &tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) tz->trips.active[i].flags.valid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) if (i == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) if (act <= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) if (i == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) tz->trips.active[0].temperature =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) celsius_to_deci_kelvin(act);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) * Don't allow override higher than
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) * the next higher trip point
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) tz->trips.active[i - 1].temperature =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) (tz->trips.active[i - 2].temperature <
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) celsius_to_deci_kelvin(act) ?
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) tz->trips.active[i - 2].temperature :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) celsius_to_deci_kelvin(act));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) tz->trips.active[i].temperature = tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) tz->trips.active[i].flags.valid = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) name[2] = 'L';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].flags.valid ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) memset(&devices, 0, sizeof(struct acpi_handle_list));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) status = acpi_evaluate_reference(tz->device->handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) name, NULL, &devices);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) pr_warn(PREFIX "Invalid active%d threshold\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) tz->trips.active[i].flags.valid = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) tz->trips.active[i].flags.valid = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) if (memcmp(&tz->trips.active[i].devices, &devices,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) sizeof(struct acpi_handle_list))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) memcpy(&tz->trips.active[i].devices, &devices,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) sizeof(struct acpi_handle_list));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) if ((flag & ACPI_TRIPS_ACTIVE) || (flag & ACPI_TRIPS_DEVICES))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) if (valid != tz->trips.active[i].flags.valid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) if (!tz->trips.active[i].flags.valid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) if (flag & ACPI_TRIPS_DEVICES) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) memset(&devices, 0, sizeof(devices));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) status = acpi_evaluate_reference(tz->device->handle, "_TZD",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) NULL, &devices);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) if (ACPI_SUCCESS(status)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) && memcmp(&tz->devices, &devices, sizeof(devices))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) tz->devices = devices;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) int i, valid, ret = acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) valid = tz->trips.critical.flags.valid |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) tz->trips.hot.flags.valid |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) tz->trips.passive.flags.valid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) valid |= tz->trips.active[i].flags.valid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) if (!valid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) pr_warn(FW_BUG "No valid trip found\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) /* sys I/F for generic thermal sysfs support */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) struct acpi_thermal *tz = thermal->devdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) if (!tz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) result = acpi_thermal_get_temperature(tz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) *temp = deci_kelvin_to_millicelsius_with_offset(tz->temperature,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) tz->kelvin_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) static int thermal_get_trip_type(struct thermal_zone_device *thermal,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) int trip, enum thermal_trip_type *type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) struct acpi_thermal *tz = thermal->devdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) if (!tz || trip < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) if (tz->trips.critical.flags.valid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) if (!trip) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) *type = THERMAL_TRIP_CRITICAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) trip--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) if (tz->trips.hot.flags.valid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) if (!trip) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) *type = THERMAL_TRIP_HOT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) trip--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) if (tz->trips.passive.flags.valid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) if (!trip) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) *type = THERMAL_TRIP_PASSIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) trip--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) tz->trips.active[i].flags.valid; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) if (!trip) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) *type = THERMAL_TRIP_ACTIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) trip--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) int trip, int *temp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) struct acpi_thermal *tz = thermal->devdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) if (!tz || trip < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) if (tz->trips.critical.flags.valid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) if (!trip) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) *temp = deci_kelvin_to_millicelsius_with_offset(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) tz->trips.critical.temperature,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) tz->kelvin_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) trip--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) if (tz->trips.hot.flags.valid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) if (!trip) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) *temp = deci_kelvin_to_millicelsius_with_offset(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) tz->trips.hot.temperature,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) tz->kelvin_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) trip--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) if (tz->trips.passive.flags.valid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) if (!trip) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) *temp = deci_kelvin_to_millicelsius_with_offset(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) tz->trips.passive.temperature,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) tz->kelvin_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) trip--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) tz->trips.active[i].flags.valid; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) if (!trip) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) *temp = deci_kelvin_to_millicelsius_with_offset(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) tz->trips.active[i].temperature,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) tz->kelvin_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) trip--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) int *temperature)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) struct acpi_thermal *tz = thermal->devdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) if (tz->trips.critical.flags.valid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) *temperature = deci_kelvin_to_millicelsius_with_offset(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) tz->trips.critical.temperature,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) tz->kelvin_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) static int thermal_get_trend(struct thermal_zone_device *thermal,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) int trip, enum thermal_trend *trend)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) struct acpi_thermal *tz = thermal->devdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) enum thermal_trip_type type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) if (thermal_get_trip_type(thermal, trip, &type))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) if (type == THERMAL_TRIP_ACTIVE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) int trip_temp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) int temp = deci_kelvin_to_millicelsius_with_offset(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) tz->temperature, tz->kelvin_offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) if (thermal_get_trip_temp(thermal, trip, &trip_temp))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) if (temp > trip_temp) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) *trend = THERMAL_TREND_RAISING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) /* Fall back on default trend */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) * tz->temperature has already been updated by generic thermal layer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) * before this callback being invoked
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) i = (tz->trips.passive.tc1 * (tz->temperature - tz->last_temperature))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) + (tz->trips.passive.tc2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) * (tz->temperature - tz->trips.passive.temperature));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) if (i > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) *trend = THERMAL_TREND_RAISING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) else if (i < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) *trend = THERMAL_TREND_DROPPING;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) *trend = THERMAL_TREND_STABLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) static int thermal_notify(struct thermal_zone_device *thermal, int trip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) enum thermal_trip_type trip_type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) u8 type = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) struct acpi_thermal *tz = thermal->devdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) if (trip_type == THERMAL_TRIP_CRITICAL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) type = ACPI_THERMAL_NOTIFY_CRITICAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) else if (trip_type == THERMAL_TRIP_HOT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) type = ACPI_THERMAL_NOTIFY_HOT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) dev_name(&tz->device->dev), type, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) if (trip_type == THERMAL_TRIP_CRITICAL && nocrt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) struct thermal_cooling_device *cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) bool bind)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) struct acpi_device *device = cdev->devdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) struct acpi_thermal *tz = thermal->devdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) struct acpi_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) acpi_handle handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) int j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) int trip = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) int result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) if (tz->trips.critical.flags.valid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) trip++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) if (tz->trips.hot.flags.valid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) trip++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) if (tz->trips.passive.flags.valid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) trip++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) for (i = 0; i < tz->trips.passive.devices.count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) handle = tz->trips.passive.devices.handles[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) status = acpi_bus_get_device(handle, &dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) if (ACPI_FAILURE(status) || dev != device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) if (bind)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) result =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) thermal_zone_bind_cooling_device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) (thermal, trip, cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) THERMAL_NO_LIMIT, THERMAL_NO_LIMIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) THERMAL_WEIGHT_DEFAULT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) result =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) thermal_zone_unbind_cooling_device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) (thermal, trip, cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) goto failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) if (!tz->trips.active[i].flags.valid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) trip++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) for (j = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) j < tz->trips.active[i].devices.count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) handle = tz->trips.active[i].devices.handles[j];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) status = acpi_bus_get_device(handle, &dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) if (ACPI_FAILURE(status) || dev != device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) if (bind)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) result = thermal_zone_bind_cooling_device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) (thermal, trip, cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) THERMAL_NO_LIMIT, THERMAL_NO_LIMIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) THERMAL_WEIGHT_DEFAULT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) result = thermal_zone_unbind_cooling_device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) (thermal, trip, cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) goto failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) for (i = 0; i < tz->devices.count; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) handle = tz->devices.handles[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) status = acpi_bus_get_device(handle, &dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) if (ACPI_SUCCESS(status) && (dev == device)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) if (bind)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) result = thermal_zone_bind_cooling_device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) (thermal, THERMAL_TRIPS_NONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) cdev, THERMAL_NO_LIMIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) THERMAL_NO_LIMIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) THERMAL_WEIGHT_DEFAULT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) result = thermal_zone_unbind_cooling_device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) (thermal, THERMAL_TRIPS_NONE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) goto failed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) failed:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) acpi_thermal_bind_cooling_device(struct thermal_zone_device *thermal,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) struct thermal_cooling_device *cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) return acpi_thermal_cooling_device_cb(thermal, cdev, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) struct thermal_cooling_device *cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) return acpi_thermal_cooling_device_cb(thermal, cdev, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) .bind = acpi_thermal_bind_cooling_device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) .unbind = acpi_thermal_unbind_cooling_device,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) .get_temp = thermal_get_temp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) .get_trip_type = thermal_get_trip_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) .get_trip_temp = thermal_get_trip_temp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) .get_crit_temp = thermal_get_crit_temp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) .get_trend = thermal_get_trend,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) .notify = thermal_notify,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) int trips = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) int result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819) if (tz->trips.critical.flags.valid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) trips++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) if (tz->trips.hot.flags.valid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) trips++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) if (tz->trips.passive.flags.valid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) trips++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) tz->trips.active[i].flags.valid; i++, trips++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) if (tz->trips.passive.flags.valid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) tz->thermal_zone =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) thermal_zone_device_register("acpitz", trips, 0, tz,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) &acpi_thermal_zone_ops, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) tz->trips.passive.tsp*100,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) tz->polling_frequency*100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) tz->thermal_zone =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) thermal_zone_device_register("acpitz", trips, 0, tz,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) &acpi_thermal_zone_ops, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) 0, tz->polling_frequency*100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) if (IS_ERR(tz->thermal_zone))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) result = sysfs_create_link(&tz->device->dev.kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) &tz->thermal_zone->device.kobj, "thermal_zone");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) goto unregister_tzd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) result = sysfs_create_link(&tz->thermal_zone->device.kobj,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) &tz->device->dev.kobj, "device");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) goto remove_tz_link;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) status = acpi_bus_attach_private_data(tz->device->handle,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) tz->thermal_zone);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) if (ACPI_FAILURE(status)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) result = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) goto remove_dev_link;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) result = thermal_zone_device_enable(tz->thermal_zone);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) goto acpi_bus_detach;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) dev_info(&tz->device->dev, "registered as thermal_zone%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) tz->thermal_zone->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) acpi_bus_detach:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) acpi_bus_detach_private_data(tz->device->handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) remove_dev_link:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) sysfs_remove_link(&tz->thermal_zone->device.kobj, "device");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) remove_tz_link:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) unregister_tzd:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) thermal_zone_device_unregister(tz->thermal_zone);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) sysfs_remove_link(&tz->thermal_zone->device.kobj, "device");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) thermal_zone_device_unregister(tz->thermal_zone);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) tz->thermal_zone = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) acpi_bus_detach_private_data(tz->device->handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) /* --------------------------------------------------------------------------
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) Driver Interface
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) -------------------------------------------------------------------------- */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) static void acpi_queue_thermal_check(struct acpi_thermal *tz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) if (!work_pending(&tz->thermal_check_work))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) queue_work(acpi_thermal_pm_queue, &tz->thermal_check_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) static void acpi_thermal_notify(struct acpi_device *device, u32 event)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) struct acpi_thermal *tz = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) if (!tz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) switch (event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) case ACPI_THERMAL_NOTIFY_TEMPERATURE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) acpi_queue_thermal_check(tz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) case ACPI_THERMAL_NOTIFY_THRESHOLDS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) acpi_queue_thermal_check(tz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) acpi_bus_generate_netlink_event(device->pnp.device_class,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) dev_name(&device->dev), event, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) case ACPI_THERMAL_NOTIFY_DEVICES:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) acpi_queue_thermal_check(tz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) acpi_bus_generate_netlink_event(device->pnp.device_class,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) dev_name(&device->dev), event, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) ACPI_DEBUG_PRINT((ACPI_DB_INFO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) "Unsupported event [0x%x]\n", event));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) * On some platforms, the AML code has dependency about
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) * the evaluating order of _TMP and _CRT/_HOT/_PSV/_ACx.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) * 1. On HP Pavilion G4-1016tx, _TMP must be invoked after
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) * /_CRT/_HOT/_PSV/_ACx, or else system will be power off.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) * 2. On HP Compaq 6715b/6715s, the return value of _PSV is 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) * if _TMP has never been evaluated.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) * As this dependency is totally transparent to OS, evaluate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) * all of them once, in the order of _CRT/_HOT/_PSV/_ACx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) * _TMP, before they are actually used.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) static void acpi_thermal_aml_dependency_fix(struct acpi_thermal *tz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) acpi_handle handle = tz->device->handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) unsigned long long value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) acpi_evaluate_integer(handle, "_CRT", NULL, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) acpi_evaluate_integer(handle, "_HOT", NULL, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) acpi_evaluate_integer(handle, "_PSV", NULL, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) acpi_status status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) status = acpi_evaluate_integer(handle, name, NULL, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) if (status == AE_NOT_FOUND)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) acpi_evaluate_integer(handle, "_TMP", NULL, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) static int acpi_thermal_get_info(struct acpi_thermal *tz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) int result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) if (!tz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) acpi_thermal_aml_dependency_fix(tz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) /* Get trip points [_CRT, _PSV, etc.] (required) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) result = acpi_thermal_get_trip_points(tz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) /* Get temperature [_TMP] (required) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) result = acpi_thermal_get_temperature(tz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) /* Set the cooling mode [_SCP] to active cooling (default) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) if (!result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) tz->flags.cooling_mode = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) /* Get default polling frequency [_TZP] (optional) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) if (tzp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) tz->polling_frequency = tzp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) acpi_thermal_get_polling_frequency(tz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) * The exact offset between Kelvin and degree Celsius is 273.15. However ACPI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) * handles temperature values with a single decimal place. As a consequence,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) * some implementations use an offset of 273.1 and others use an offset of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) * 273.2. Try to find out which one is being used, to present the most
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) * accurate and visually appealing number.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) * The heuristic below should work for all ACPI thermal zones which have a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) * critical trip point with a value being a multiple of 0.5 degree Celsius.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) static void acpi_thermal_guess_offset(struct acpi_thermal *tz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) if (tz->trips.critical.flags.valid &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) (tz->trips.critical.temperature % 5) == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) tz->kelvin_offset = 273100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) tz->kelvin_offset = 273200;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) static void acpi_thermal_check_fn(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) struct acpi_thermal *tz = container_of(work, struct acpi_thermal,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) thermal_check_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) * In general, it is not sufficient to check the pending bit, because
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) * subsequent instances of this function may be queued after one of them
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) * has started running (e.g. if _TMP sleeps). Avoid bailing out if just
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) * one of them is running, though, because it may have done the actual
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) * check some time ago, so allow at least one of them to block on the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) * mutex while another one is running the update.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) if (!refcount_dec_not_one(&tz->thermal_check_count))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) mutex_lock(&tz->thermal_check_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) thermal_zone_device_update(tz->thermal_zone, THERMAL_EVENT_UNSPECIFIED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) refcount_inc(&tz->thermal_check_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) mutex_unlock(&tz->thermal_check_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) static int acpi_thermal_add(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) int result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) struct acpi_thermal *tz = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) if (!device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) tz = kzalloc(sizeof(struct acpi_thermal), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) if (!tz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) tz->device = device;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) strcpy(tz->name, device->pnp.bus_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) device->driver_data = tz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) result = acpi_thermal_get_info(tz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) goto free_memory;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) acpi_thermal_guess_offset(tz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) result = acpi_thermal_register_thermal_zone(tz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) if (result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) goto free_memory;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) refcount_set(&tz->thermal_check_count, 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) mutex_init(&tz->thermal_check_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) INIT_WORK(&tz->thermal_check_work, acpi_thermal_check_fn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) pr_info(PREFIX "%s [%s] (%ld C)\n", acpi_device_name(device),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) acpi_device_bid(device), deci_kelvin_to_celsius(tz->temperature));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) goto end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) free_memory:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) kfree(tz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) end:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) static int acpi_thermal_remove(struct acpi_device *device)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) struct acpi_thermal *tz = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) if (!device || !acpi_driver_data(device))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) flush_workqueue(acpi_thermal_pm_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) tz = acpi_driver_data(device);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) acpi_thermal_unregister_thermal_zone(tz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) kfree(tz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) #ifdef CONFIG_PM_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) static int acpi_thermal_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) /* Make sure the previously queued thermal check work has been done */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) flush_workqueue(acpi_thermal_pm_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) static int acpi_thermal_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) struct acpi_thermal *tz;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) int i, j, power_state, result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) if (!dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) tz = acpi_driver_data(to_acpi_device(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) if (!tz)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) if (!(&tz->trips.active[i]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) if (!tz->trips.active[i].flags.valid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) tz->trips.active[i].flags.enabled = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) for (j = 0; j < tz->trips.active[i].devices.count; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) result = acpi_bus_update_power(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) tz->trips.active[i].devices.handles[j],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) &power_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) if (result || (power_state != ACPI_STATE_D0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) tz->trips.active[i].flags.enabled = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) tz->state.active |= tz->trips.active[i].flags.enabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) acpi_queue_thermal_check(tz);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) return AE_OK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) static int thermal_act(const struct dmi_system_id *d) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) if (act == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) pr_notice(PREFIX "%s detected: "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) "disabling all active thermal trip points\n", d->ident);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) act = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) static int thermal_nocrt(const struct dmi_system_id *d) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) pr_notice(PREFIX "%s detected: "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) "disabling all critical thermal trip point actions.\n", d->ident);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) nocrt = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) static int thermal_tzp(const struct dmi_system_id *d) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) if (tzp == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) pr_notice(PREFIX "%s detected: "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) "enabling thermal zone polling\n", d->ident);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) tzp = 300; /* 300 dS = 30 Seconds */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) static int thermal_psv(const struct dmi_system_id *d) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) if (psv == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) pr_notice(PREFIX "%s detected: "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) "disabling all passive thermal trip points\n", d->ident);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) psv = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) static const struct dmi_system_id thermal_dmi_table[] __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) * Award BIOS on this AOpen makes thermal control almost worthless.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) * http://bugzilla.kernel.org/show_bug.cgi?id=8842
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) .callback = thermal_act,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) .ident = "AOpen i915GMm-HFS",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) .callback = thermal_psv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) .ident = "AOpen i915GMm-HFS",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) .callback = thermal_tzp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) .ident = "AOpen i915GMm-HFS",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) DMI_MATCH(DMI_BOARD_VENDOR, "AOpen"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) DMI_MATCH(DMI_BOARD_NAME, "i915GMm-HFS"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) .callback = thermal_nocrt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) .ident = "Gigabyte GA-7ZX",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) .matches = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) DMI_MATCH(DMI_BOARD_VENDOR, "Gigabyte Technology Co., Ltd."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) DMI_MATCH(DMI_BOARD_NAME, "7ZX"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) {}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) static int __init acpi_thermal_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) int result = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) dmi_check_system(thermal_dmi_table);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) if (off) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) pr_notice(PREFIX "thermal control disabled\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) acpi_thermal_pm_queue = alloc_workqueue("acpi_thermal_pm",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) WQ_HIGHPRI | WQ_MEM_RECLAIM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) if (!acpi_thermal_pm_queue)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) result = acpi_bus_register_driver(&acpi_thermal_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) if (result < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) destroy_workqueue(acpi_thermal_pm_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) static void __exit acpi_thermal_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) acpi_bus_unregister_driver(&acpi_thermal_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) destroy_workqueue(acpi_thermal_pm_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) module_init(acpi_thermal_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) module_exit(acpi_thermal_exit);