diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2023-08-29 03:58:39 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2023-08-29 03:58:39 +0300 |
commit | 330235e87410349042468b52baff02af7cb7d331 (patch) | |
tree | ebe6975d5aa0f2caaa39abdaff82d7af9d9bf7d5 /drivers/acpi/thermal.c | |
parent | 2927d2261b539834d0bd483088c116106b440de6 (diff) | |
parent | b483d3b8a54a544ab8854ca6dbb8d99c423b3ba4 (diff) | |
download | linux-330235e87410349042468b52baff02af7cb7d331.tar.xz |
Merge tag 'acpi-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull ACPI updates from Rafael Wysocki:
"These include new ACPICA material, a rework of the ACPI thermal
driver, a switch-over of the ACPI processor driver to using _OSC
instead of (long deprecated) _PDC for CPU initialization, a rework of
firmware notifications handling in several drivers, fixes and cleanups
for suspend-to-idle handling on AMD systems, ACPI backlight driver
updates and more.
Specifics:
- Update the ACPICA code in the kernel to upstream revision 20230628
including the following changes:
- Suppress a GCC 12 dangling-pointer warning (Philip Prindeville)
- Reformat the ACPI_STATE_COMMON macro and its users (George Guo)
- Replace the ternary operator with ACPI_MIN() (Jiangshan Yi)
- Add support for _DSC as per ACPI 6.5 (Saket Dumbre)
- Remove a duplicate macro from zephyr header (Najumon B.A)
- Add data structures for GED and _EVT tracking (Jose Marinho)
- Fix misspelled CDAT DSMAS define (Dave Jiang)
- Simplify an error message in acpi_ds_result_push() (Christophe
Jaillet)
- Add a struct size macro related to SRAT (Dave Jiang)
- Add AML_NO_OPERAND_RESOLVE flag to Timer (Abhishek Mainkar)
- Add support for RISC-V external interrupt controllers in MADT
(Sunil V L)
- Add RHCT flags, CMO and MMU nodes (Sunil V L)
- Change ACPICA version to 20230628 (Bob Moore)
- Introduce new wrappers for ACPICA notify handler install/remove and
convert multiple drivers to using their own Notify() handlers
instead of the ACPI bus type .notify() slated for removal (Michal
Wilczynski)
- Add backlight=native DMI quirk for Apple iMac12,1 and iMac12,2
(Hans de Goede)
- Put ACPI video and its child devices explicitly into D0 on boot to
avoid platform firmware confusion (Kai-Heng Feng)
- Add backlight=native DMI quirk for Lenovo Ideapad Z470 (Jiri Slaby)
- Support obtaining physical CPU ID from MADT on LoongArch (Bibo Mao)
- Convert ACPI CPU initialization to using _OSC instead of _PDC that
has been depreceted since 2018 and dropped from the specification
in ACPI 6.5 (Michal Wilczynski, Rafael Wysocki)
- Drop non-functional nocrt parameter from ACPI thermal (Mario
Limonciello)
- Clean up the ACPI thermal driver, rework the handling of firmware
notifications in it and make it provide a table of generic trip
point structures to the core during initialization (Rafael Wysocki)
- Defer enumeration of devices with _DEP pointing to IVSC (Wentong
Wu)
- Install SystemCMOS address space handler for ACPI000E (TAD) to meet
platform firmware expectations on some platforms (Zhang Rui)
- Fix finding the generic error data in the ACPi extlog driver for
compatibility with old and new firmware interface versions
(Xiaochun Lee)
- Remove assorted unused declarations of functions (Yue Haibing)
- Move AMBA bus scan handling into arm64 specific directory (Sudeep
Holla)
- Fix and clean up suspend-to-idle interface for AMD systems (Mario
Limonciello, Andy Shevchenko)
- Fix string truncation warning in pnpacpi_add_device() (Sunil V L)"
* tag 'acpi-6.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (66 commits)
ACPI: x86: s2idle: Add a function to get LPS0 constraint for a device
ACPI: x86: s2idle: Add for_each_lpi_constraint() helper
ACPI: x86: s2idle: Add more debugging for AMD constraints parsing
ACPI: x86: s2idle: Fix a logic error parsing AMD constraints table
ACPI: x86: s2idle: Catch multiple ACPI_TYPE_PACKAGE objects
ACPI: x86: s2idle: Post-increment variables when getting constraints
ACPI: Adjust #ifdef for *_lps0_dev use
ACPI: TAD: Install SystemCMOS address space handler for ACPI000E
ACPI: Remove assorted unused declarations of functions
ACPI: extlog: Fix finding the generic error data for v3 structure
PNP: ACPI: Fix string truncation warning
ACPI: Remove unused extern declaration acpi_paddr_to_node()
ACPI: video: Add backlight=native DMI quirk for Apple iMac12,1 and iMac12,2
ACPI: video: Put ACPI video and its child devices into D0 on boot
ACPI: processor: LoongArch: Get physical ID from MADT
ACPI: scan: Defer enumeration of devices with a _DEP pointing to IVSC device
ACPI: thermal: Eliminate code duplication from acpi_thermal_notify()
ACPI: thermal: Drop unnecessary thermal zone callbacks
ACPI: thermal: Rework thermal_get_trend()
ACPI: thermal: Use trip point table to register thermal zones
...
Diffstat (limited to 'drivers/acpi/thermal.c')
-rw-r--r-- | drivers/acpi/thermal.c | 470 |
1 files changed, 219 insertions, 251 deletions
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index f9f6ebb08fdb..419590f41ed5 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -82,10 +82,6 @@ static int tzp; module_param(tzp, int, 0444); MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds."); -static int nocrt; -module_param(nocrt, int, 0); -MODULE_PARM_DESC(nocrt, "Set to take no action upon ACPI thermal zone critical trips points."); - static int off; module_param(off, int, 0); MODULE_PARM_DESC(off, "Set to disable ACPI thermal support."); @@ -96,35 +92,27 @@ MODULE_PARM_DESC(psv, "Disable or override all passive trip points."); static struct workqueue_struct *acpi_thermal_pm_queue; -struct acpi_thermal_critical { - unsigned long temperature; - bool valid; -}; - -struct acpi_thermal_hot { +struct acpi_thermal_trip { unsigned long temperature; bool valid; }; struct acpi_thermal_passive { + struct acpi_thermal_trip trip; struct acpi_handle_list devices; - unsigned long temperature; unsigned long tc1; unsigned long tc2; unsigned long tsp; - bool valid; }; struct acpi_thermal_active { + struct acpi_thermal_trip trip; struct acpi_handle_list devices; - unsigned long temperature; - bool valid; - bool enabled; }; struct acpi_thermal_trips { - struct acpi_thermal_critical critical; - struct acpi_thermal_hot hot; + struct acpi_thermal_trip critical; + struct acpi_thermal_trip hot; struct acpi_thermal_passive passive; struct acpi_thermal_active active[ACPI_THERMAL_MAX_ACTIVE]; }; @@ -137,6 +125,7 @@ struct acpi_thermal { unsigned long polling_frequency; volatile u8 zombie; struct acpi_thermal_trips trips; + struct thermal_trip *trip_table; struct acpi_handle_list devices; struct thermal_zone_device *thermal_zone; int kelvin_offset; /* in millidegrees */ @@ -190,7 +179,16 @@ static int acpi_thermal_get_polling_frequency(struct acpi_thermal *tz) return 0; } -static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) +static int acpi_thermal_temp(struct acpi_thermal *tz, int temp_deci_k) +{ + if (temp_deci_k == THERMAL_TEMP_INVALID) + return THERMAL_TEMP_INVALID; + + return deci_kelvin_to_millicelsius_with_offset(temp_deci_k, + tz->kelvin_offset); +} + +static void __acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) { acpi_status status; unsigned long long tmp; @@ -255,9 +253,9 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) } /* Passive (optional) */ - if (((flag & ACPI_TRIPS_PASSIVE) && tz->trips.passive.valid) || + if (((flag & ACPI_TRIPS_PASSIVE) && tz->trips.passive.trip.valid) || flag == ACPI_TRIPS_INIT) { - valid = tz->trips.passive.valid; + valid = tz->trips.passive.trip.valid; if (psv == -1) { status = AE_SUPPORT; } else if (psv > 0) { @@ -269,44 +267,44 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) } if (ACPI_FAILURE(status)) { - tz->trips.passive.valid = false; + tz->trips.passive.trip.valid = false; } else { - tz->trips.passive.temperature = tmp; - tz->trips.passive.valid = true; + tz->trips.passive.trip.temperature = tmp; + tz->trips.passive.trip.valid = true; if (flag == ACPI_TRIPS_INIT) { status = acpi_evaluate_integer(tz->device->handle, "_TC1", NULL, &tmp); if (ACPI_FAILURE(status)) - tz->trips.passive.valid = false; + tz->trips.passive.trip.valid = false; else tz->trips.passive.tc1 = tmp; status = acpi_evaluate_integer(tz->device->handle, "_TC2", NULL, &tmp); if (ACPI_FAILURE(status)) - tz->trips.passive.valid = false; + tz->trips.passive.trip.valid = false; else tz->trips.passive.tc2 = tmp; status = acpi_evaluate_integer(tz->device->handle, "_TSP", NULL, &tmp); if (ACPI_FAILURE(status)) - tz->trips.passive.valid = false; + tz->trips.passive.trip.valid = false; else tz->trips.passive.tsp = tmp; } } } - if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.valid) { + if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.trip.valid) { memset(&devices, 0, sizeof(struct acpi_handle_list)); status = acpi_evaluate_reference(tz->device->handle, "_PSL", NULL, &devices); if (ACPI_FAILURE(status)) { acpi_handle_info(tz->device->handle, "Invalid passive threshold\n"); - tz->trips.passive.valid = false; + tz->trips.passive.trip.valid = false; } else { - tz->trips.passive.valid = true; + tz->trips.passive.trip.valid = true; } if (memcmp(&tz->trips.passive.devices, &devices, @@ -317,24 +315,24 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) } } if ((flag & ACPI_TRIPS_PASSIVE) || (flag & ACPI_TRIPS_DEVICES)) { - if (valid != tz->trips.passive.valid) + if (valid != tz->trips.passive.trip.valid) ACPI_THERMAL_TRIPS_EXCEPTION(flag, tz, "state"); } /* Active (optional) */ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { char name[5] = { '_', 'A', 'C', ('0' + i), '\0' }; - valid = tz->trips.active[i].valid; + valid = tz->trips.active[i].trip.valid; if (act == -1) break; /* disable all active trip points */ if (flag == ACPI_TRIPS_INIT || ((flag & ACPI_TRIPS_ACTIVE) && - tz->trips.active[i].valid)) { + tz->trips.active[i].trip.valid)) { status = acpi_evaluate_integer(tz->device->handle, name, NULL, &tmp); if (ACPI_FAILURE(status)) { - tz->trips.active[i].valid = false; + tz->trips.active[i].trip.valid = false; if (i == 0) break; @@ -342,35 +340,36 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) break; if (i == 1) - tz->trips.active[0].temperature = celsius_to_deci_kelvin(act); + tz->trips.active[0].trip.temperature = + celsius_to_deci_kelvin(act); else /* * Don't allow override higher than * the next higher trip point */ - tz->trips.active[i-1].temperature = + tz->trips.active[i-1].trip.temperature = min_t(unsigned long, - tz->trips.active[i-2].temperature, + tz->trips.active[i-2].trip.temperature, celsius_to_deci_kelvin(act)); break; } else { - tz->trips.active[i].temperature = tmp; - tz->trips.active[i].valid = true; + tz->trips.active[i].trip.temperature = tmp; + tz->trips.active[i].trip.valid = true; } } name[2] = 'L'; - if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].valid) { + if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].trip.valid) { memset(&devices, 0, sizeof(struct acpi_handle_list)); status = acpi_evaluate_reference(tz->device->handle, name, NULL, &devices); if (ACPI_FAILURE(status)) { acpi_handle_info(tz->device->handle, "Invalid active%d threshold\n", i); - tz->trips.active[i].valid = false; + tz->trips.active[i].trip.valid = false; } else { - tz->trips.active[i].valid = true; + tz->trips.active[i].trip.valid = true; } if (memcmp(&tz->trips.active[i].devices, &devices, @@ -381,10 +380,10 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) } } if ((flag & ACPI_TRIPS_ACTIVE) || (flag & ACPI_TRIPS_DEVICES)) - if (valid != tz->trips.active[i].valid) + if (valid != tz->trips.active[i].trip.valid) ACPI_THERMAL_TRIPS_EXCEPTION(flag, tz, "state"); - if (!tz->trips.active[i].valid) + if (!tz->trips.active[i].trip.valid) break; } @@ -398,24 +397,73 @@ static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag) ACPI_THERMAL_TRIPS_EXCEPTION(flag, tz, "device"); } } +} + +static int acpi_thermal_adjust_trip(struct thermal_trip *trip, void *data) +{ + struct acpi_thermal_trip *acpi_trip = trip->priv; + struct acpi_thermal *tz = data; + + if (!acpi_trip) + return 0; + + if (acpi_trip->valid) + trip->temperature = acpi_thermal_temp(tz, acpi_trip->temperature); + else + trip->temperature = THERMAL_TEMP_INVALID; return 0; } +static void acpi_thermal_adjust_thermal_zone(struct thermal_zone_device *thermal, + unsigned long data) +{ + struct acpi_thermal *tz = thermal_zone_device_priv(thermal); + int flag = data == ACPI_THERMAL_NOTIFY_THRESHOLDS ? + ACPI_TRIPS_THRESHOLDS : ACPI_TRIPS_DEVICES; + + __acpi_thermal_trips_update(tz, flag); + + for_each_thermal_trip(tz->thermal_zone, acpi_thermal_adjust_trip, tz); +} + +static void acpi_queue_thermal_check(struct acpi_thermal *tz) +{ + if (!work_pending(&tz->thermal_check_work)) + queue_work(acpi_thermal_pm_queue, &tz->thermal_check_work); +} + +static void acpi_thermal_trips_update(struct acpi_thermal *tz, u32 event) +{ + struct acpi_device *adev = tz->device; + + /* + * Use thermal_zone_device_exec() to carry out the trip points + * update, so as to protect thermal_get_trend() from getting stale + * trip point temperatures and to prevent thermal_zone_device_update() + * invoked from acpi_thermal_check_fn() from producing inconsistent + * results. + */ + thermal_zone_device_exec(tz->thermal_zone, + acpi_thermal_adjust_thermal_zone, event); + acpi_queue_thermal_check(tz); + acpi_bus_generate_netlink_event(adev->pnp.device_class, + dev_name(&adev->dev), event, 0); +} + static int acpi_thermal_get_trip_points(struct acpi_thermal *tz) { - int i, ret = acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT); bool valid; + int i; - if (ret) - return ret; + __acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT); valid = tz->trips.critical.valid | tz->trips.hot.valid | - tz->trips.passive.valid; + tz->trips.passive.trip.valid; for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) - valid = valid || tz->trips.active[i].valid; + valid = valid || tz->trips.active[i].trip.valid; if (!valid) { pr_warn(FW_BUG "No valid trip found\n"); @@ -443,159 +491,55 @@ static int thermal_get_temp(struct thermal_zone_device *thermal, int *temp) return 0; } -static int thermal_get_trip_type(struct thermal_zone_device *thermal, - int trip, enum thermal_trip_type *type) +static int thermal_get_trend(struct thermal_zone_device *thermal, + int trip_index, enum thermal_trend *trend) { struct acpi_thermal *tz = thermal_zone_device_priv(thermal); - int i; + struct acpi_thermal_trip *acpi_trip; + int t, i; - if (!tz || trip < 0) + if (!tz || trip_index < 0) return -EINVAL; - if (tz->trips.critical.valid) { - if (!trip) { - *type = THERMAL_TRIP_CRITICAL; - return 0; - } - trip--; - } - - if (tz->trips.hot.valid) { - if (!trip) { - *type = THERMAL_TRIP_HOT; - return 0; - } - trip--; - } - - if (tz->trips.passive.valid) { - if (!trip) { - *type = THERMAL_TRIP_PASSIVE; - return 0; - } - trip--; - } - - for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips.active[i].valid; i++) { - if (!trip) { - *type = THERMAL_TRIP_ACTIVE; - return 0; - } - trip--; - } - - return -EINVAL; -} + if (tz->trips.critical.valid) + trip_index--; -static int thermal_get_trip_temp(struct thermal_zone_device *thermal, - int trip, int *temp) -{ - struct acpi_thermal *tz = thermal_zone_device_priv(thermal); - int i; + if (tz->trips.hot.valid) + trip_index--; - if (!tz || trip < 0) + if (trip_index < 0) return -EINVAL; - if (tz->trips.critical.valid) { - if (!trip) { - *temp = deci_kelvin_to_millicelsius_with_offset( - tz->trips.critical.temperature, - tz->kelvin_offset); - return 0; - } - trip--; - } - - if (tz->trips.hot.valid) { - if (!trip) { - *temp = deci_kelvin_to_millicelsius_with_offset( - tz->trips.hot.temperature, - tz->kelvin_offset); - return 0; - } - trip--; - } - - if (tz->trips.passive.valid) { - if (!trip) { - *temp = deci_kelvin_to_millicelsius_with_offset( - tz->trips.passive.temperature, - tz->kelvin_offset); - return 0; - } - trip--; - } - - for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && - tz->trips.active[i].valid; i++) { - if (!trip) { - *temp = deci_kelvin_to_millicelsius_with_offset( - tz->trips.active[i].temperature, - tz->kelvin_offset); - return 0; - } - trip--; - } - - return -EINVAL; -} - -static int thermal_get_crit_temp(struct thermal_zone_device *thermal, - int *temperature) -{ - struct acpi_thermal *tz = thermal_zone_device_priv(thermal); + acpi_trip = &tz->trips.passive.trip; + if (acpi_trip->valid && !trip_index--) { + t = tz->trips.passive.tc1 * (tz->temperature - + tz->last_temperature) + + tz->trips.passive.tc2 * (tz->temperature - + acpi_trip->temperature); + if (t > 0) + *trend = THERMAL_TREND_RAISING; + else if (t < 0) + *trend = THERMAL_TREND_DROPPING; + else + *trend = THERMAL_TREND_STABLE; - if (tz->trips.critical.valid) { - *temperature = deci_kelvin_to_millicelsius_with_offset( - tz->trips.critical.temperature, - tz->kelvin_offset); return 0; } - return -EINVAL; -} - -static int thermal_get_trend(struct thermal_zone_device *thermal, - int trip, enum thermal_trend *trend) -{ - struct acpi_thermal *tz = thermal_zone_device_priv(thermal); - enum thermal_trip_type type; - int i; - - if (thermal_get_trip_type(thermal, trip, &type)) - return -EINVAL; - - if (type == THERMAL_TRIP_ACTIVE) { - int trip_temp; - int temp = deci_kelvin_to_millicelsius_with_offset( - tz->temperature, tz->kelvin_offset); - if (thermal_get_trip_temp(thermal, trip, &trip_temp)) - return -EINVAL; + t = acpi_thermal_temp(tz, tz->temperature); - if (temp > trip_temp) { - *trend = THERMAL_TREND_RAISING; - return 0; - } else { - /* Fall back on default trend */ - return -EINVAL; + for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { + acpi_trip = &tz->trips.active[i].trip; + if (acpi_trip->valid && !trip_index--) { + if (t > acpi_thermal_temp(tz, acpi_trip->temperature)) { + *trend = THERMAL_TREND_RAISING; + return 0; + } + break; } } - /* - * tz->temperature has already been updated by generic thermal layer, - * before this callback being invoked - */ - i = tz->trips.passive.tc1 * (tz->temperature - tz->last_temperature) + - tz->trips.passive.tc2 * (tz->temperature - tz->trips.passive.temperature); - - if (i > 0) - *trend = THERMAL_TREND_RAISING; - else if (i < 0) - *trend = THERMAL_TREND_DROPPING; - else - *trend = THERMAL_TREND_STABLE; - - return 0; + return -EINVAL; } static void acpi_thermal_zone_device_hot(struct thermal_zone_device *thermal) @@ -637,7 +581,7 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, if (tz->trips.hot.valid) trip++; - if (tz->trips.passive.valid) { + if (tz->trips.passive.trip.valid) { trip++; for (i = 0; i < tz->trips.passive.devices.count; i++) { handle = tz->trips.passive.devices.handles[i]; @@ -662,7 +606,7 @@ static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal, } for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { - if (!tz->trips.active[i].valid) + if (!tz->trips.active[i].trip.valid) break; trip++; @@ -709,9 +653,6 @@ static struct thermal_zone_device_ops acpi_thermal_zone_ops = { .bind = acpi_thermal_bind_cooling_device, .unbind = acpi_thermal_unbind_cooling_device, .get_temp = thermal_get_temp, - .get_trip_type = thermal_get_trip_type, - .get_trip_temp = thermal_get_trip_temp, - .get_crit_temp = thermal_get_crit_temp, .get_trend = thermal_get_trend, .hot = acpi_thermal_zone_device_hot, .critical = acpi_thermal_zone_device_critical, @@ -745,63 +686,97 @@ static void acpi_thermal_zone_sysfs_remove(struct acpi_thermal *tz) static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz) { - int trips = 0; + struct acpi_thermal_trip *acpi_trip; + struct thermal_trip *trip; + int passive_delay = 0; + int trip_count = 0; int result; - acpi_status status; int i; if (tz->trips.critical.valid) - trips++; + trip_count++; if (tz->trips.hot.valid) - trips++; + trip_count++; + + if (tz->trips.passive.trip.valid) { + trip_count++; + passive_delay = tz->trips.passive.tsp * 100; + } - if (tz->trips.passive.valid) - trips++; + for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips.active[i].trip.valid; i++) + trip_count++; - for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && tz->trips.active[i].valid; - i++, trips++); + trip = kcalloc(trip_count, sizeof(*trip), GFP_KERNEL); + if (!trip) + return -ENOMEM; - if (tz->trips.passive.valid) - tz->thermal_zone = thermal_zone_device_register("acpitz", trips, 0, tz, - &acpi_thermal_zone_ops, NULL, - tz->trips.passive.tsp * 100, - tz->polling_frequency * 100); - else - tz->thermal_zone = - thermal_zone_device_register("acpitz", trips, 0, tz, - &acpi_thermal_zone_ops, NULL, - 0, tz->polling_frequency * 100); + tz->trip_table = trip; - if (IS_ERR(tz->thermal_zone)) - return -ENODEV; + if (tz->trips.critical.valid) { + trip->type = THERMAL_TRIP_CRITICAL; + trip->temperature = acpi_thermal_temp(tz, tz->trips.critical.temperature); + trip++; + } + + if (tz->trips.hot.valid) { + trip->type = THERMAL_TRIP_HOT; + trip->temperature = acpi_thermal_temp(tz, tz->trips.hot.temperature); + trip++; + } + + acpi_trip = &tz->trips.passive.trip; + if (acpi_trip->valid) { + trip->type = THERMAL_TRIP_PASSIVE; + trip->temperature = acpi_thermal_temp(tz, acpi_trip->temperature); + trip->priv = acpi_trip; + trip++; + } + + for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { + acpi_trip = &tz->trips.active[i].trip; + + if (!acpi_trip->valid) + break; + + trip->type = THERMAL_TRIP_ACTIVE; + trip->temperature = acpi_thermal_temp(tz, acpi_trip->temperature); + trip->priv = acpi_trip; + trip++; + } + + tz->thermal_zone = thermal_zone_device_register_with_trips("acpitz", + tz->trip_table, + trip_count, + 0, tz, + &acpi_thermal_zone_ops, + NULL, + passive_delay, + tz->polling_frequency * 100); + if (IS_ERR(tz->thermal_zone)) { + result = PTR_ERR(tz->thermal_zone); + goto free_trip_table; + } result = acpi_thermal_zone_sysfs_add(tz); if (result) goto unregister_tzd; - status = acpi_bus_attach_private_data(tz->device->handle, - tz->thermal_zone); - if (ACPI_FAILURE(status)) { - result = -ENODEV; - goto remove_links; - } - result = thermal_zone_device_enable(tz->thermal_zone); if (result) - goto acpi_bus_detach; + goto remove_links; dev_info(&tz->device->dev, "registered as thermal_zone%d\n", thermal_zone_device_id(tz->thermal_zone)); return 0; -acpi_bus_detach: - acpi_bus_detach_private_data(tz->device->handle); remove_links: acpi_thermal_zone_sysfs_remove(tz); unregister_tzd: thermal_zone_device_unregister(tz->thermal_zone); +free_trip_table: + kfree(tz->trip_table); return result; } @@ -810,8 +785,8 @@ static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz) { acpi_thermal_zone_sysfs_remove(tz); thermal_zone_device_unregister(tz->thermal_zone); + kfree(tz->trip_table); tz->thermal_zone = NULL; - acpi_bus_detach_private_data(tz->device->handle); } @@ -819,14 +794,9 @@ static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz) Driver Interface -------------------------------------------------------------------------- */ -static void acpi_queue_thermal_check(struct acpi_thermal *tz) -{ - if (!work_pending(&tz->thermal_check_work)) - queue_work(acpi_thermal_pm_queue, &tz->thermal_check_work); -} - -static void acpi_thermal_notify(struct acpi_device *device, u32 event) +static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data) { + struct acpi_device *device = data; struct acpi_thermal *tz = acpi_driver_data(device); if (!tz) @@ -837,16 +807,8 @@ static void acpi_thermal_notify(struct acpi_device *device, u32 event) acpi_queue_thermal_check(tz); break; case ACPI_THERMAL_NOTIFY_THRESHOLDS: - acpi_thermal_trips_update(tz, ACPI_TRIPS_THRESHOLDS); - acpi_queue_thermal_check(tz); - acpi_bus_generate_netlink_event(device->pnp.device_class, - dev_name(&device->dev), event, 0); - break; case ACPI_THERMAL_NOTIFY_DEVICES: - acpi_thermal_trips_update(tz, ACPI_TRIPS_DEVICES); - acpi_queue_thermal_check(tz); - acpi_bus_generate_netlink_event(device->pnp.device_class, - dev_name(&device->dev), event, 0); + acpi_thermal_trips_update(tz, event); break; default: acpi_handle_debug(device->handle, "Unsupported event [0x%x]\n", @@ -997,11 +959,20 @@ static int acpi_thermal_add(struct acpi_device *device) pr_info("%s [%s] (%ld C)\n", acpi_device_name(device), acpi_device_bid(device), deci_kelvin_to_celsius(tz->temperature)); - goto end; + result = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY, + acpi_thermal_notify); + if (result) + goto flush_wq; + + return 0; + +flush_wq: + flush_workqueue(acpi_thermal_pm_queue); + acpi_thermal_unregister_thermal_zone(tz); free_memory: kfree(tz); -end: + return result; } @@ -1012,10 +983,14 @@ static void acpi_thermal_remove(struct acpi_device *device) if (!device || !acpi_driver_data(device)) return; - flush_workqueue(acpi_thermal_pm_queue); tz = acpi_driver_data(device); + acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY, + acpi_thermal_notify); + + flush_workqueue(acpi_thermal_pm_queue); acpi_thermal_unregister_thermal_zone(tz); + kfree(tz); } @@ -1030,7 +1005,7 @@ static int acpi_thermal_suspend(struct device *dev) static int acpi_thermal_resume(struct device *dev) { struct acpi_thermal *tz; - int i, j, power_state, result; + int i, j, power_state; if (!dev) return -EINVAL; @@ -1040,18 +1015,12 @@ static int acpi_thermal_resume(struct device *dev) return -EINVAL; for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { - if (!tz->trips.active[i].valid) + if (!tz->trips.active[i].trip.valid) break; - tz->trips.active[i].enabled = true; for (j = 0; j < tz->trips.active[i].devices.count; j++) { - result = acpi_bus_update_power( - tz->trips.active[i].devices.handles[j], - &power_state); - if (result || (power_state != ACPI_STATE_D0)) { - tz->trips.active[i].enabled = false; - break; - } + acpi_bus_update_power(tz->trips.active[i].devices.handles[j], + &power_state); } } @@ -1078,7 +1047,6 @@ static struct acpi_driver acpi_thermal_driver = { .ops = { .add = acpi_thermal_add, .remove = acpi_thermal_remove, - .notify = acpi_thermal_notify, }, .drv.pm = &acpi_thermal_pm, }; @@ -1094,7 +1062,7 @@ static int thermal_act(const struct dmi_system_id *d) { static int thermal_nocrt(const struct dmi_system_id *d) { pr_notice("%s detected: disabling all critical thermal trip point actions.\n", d->ident); - nocrt = 1; + crt = -1; return 0; } static int thermal_tzp(const struct dmi_system_id *d) { |