mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 01:53:29 +02:00
This was done entirely with mindless brute force, using
git grep -l '\<k[vmz]*alloc_objs*(.*, GFP_KERNEL)' |
xargs sed -i 's/\(alloc_objs*(.*\), GFP_KERNEL)/\1)/'
to convert the new alloc_obj() users that had a simple GFP_KERNEL
argument to just drop that argument.
Note that due to the extreme simplicity of the scripting, any slightly
more complex cases spread over multiple lines would not be triggered:
they definitely exist, but this covers the vast bulk of the cases, and
the resulting diff is also then easier to check automatically.
For the same reason the 'flex' versions will be done as a separate
conversion.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
245 lines
5.6 KiB
C
245 lines
5.6 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright 2024 Linaro Limited
|
|
*
|
|
* Author: Daniel Lezcano <daniel.lezcano@linaro.org>
|
|
*
|
|
* Thermal thresholds
|
|
*/
|
|
#include <linux/list.h>
|
|
#include <linux/list_sort.h>
|
|
#include <linux/slab.h>
|
|
|
|
#include "thermal_core.h"
|
|
#include "thermal_thresholds.h"
|
|
|
|
int thermal_thresholds_init(struct thermal_zone_device *tz)
|
|
{
|
|
INIT_LIST_HEAD(&tz->user_thresholds);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void __thermal_thresholds_flush(struct thermal_zone_device *tz)
|
|
{
|
|
struct list_head *thresholds = &tz->user_thresholds;
|
|
struct user_threshold *entry, *tmp;
|
|
|
|
list_for_each_entry_safe(entry, tmp, thresholds, list_node) {
|
|
list_del(&entry->list_node);
|
|
kfree(entry);
|
|
}
|
|
}
|
|
|
|
void thermal_thresholds_flush(struct thermal_zone_device *tz)
|
|
{
|
|
lockdep_assert_held(&tz->lock);
|
|
|
|
__thermal_thresholds_flush(tz);
|
|
|
|
thermal_notify_threshold_flush(tz);
|
|
|
|
__thermal_zone_device_update(tz, THERMAL_TZ_FLUSH_THRESHOLDS);
|
|
}
|
|
|
|
void thermal_thresholds_exit(struct thermal_zone_device *tz)
|
|
{
|
|
__thermal_thresholds_flush(tz);
|
|
}
|
|
|
|
static int __thermal_thresholds_cmp(void *data,
|
|
const struct list_head *l1,
|
|
const struct list_head *l2)
|
|
{
|
|
struct user_threshold *t1 = container_of(l1, struct user_threshold, list_node);
|
|
struct user_threshold *t2 = container_of(l2, struct user_threshold, list_node);
|
|
|
|
return t1->temperature - t2->temperature;
|
|
}
|
|
|
|
static struct user_threshold *__thermal_thresholds_find(const struct list_head *thresholds,
|
|
int temperature)
|
|
{
|
|
struct user_threshold *t;
|
|
|
|
list_for_each_entry(t, thresholds, list_node)
|
|
if (t->temperature == temperature)
|
|
return t;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static bool thermal_thresholds_handle_raising(struct list_head *thresholds, int temperature,
|
|
int last_temperature)
|
|
{
|
|
struct user_threshold *t;
|
|
|
|
list_for_each_entry(t, thresholds, list_node) {
|
|
|
|
if (!(t->direction & THERMAL_THRESHOLD_WAY_UP))
|
|
continue;
|
|
|
|
if (temperature >= t->temperature &&
|
|
last_temperature < t->temperature)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool thermal_thresholds_handle_dropping(struct list_head *thresholds, int temperature,
|
|
int last_temperature)
|
|
{
|
|
struct user_threshold *t;
|
|
|
|
list_for_each_entry_reverse(t, thresholds, list_node) {
|
|
|
|
if (!(t->direction & THERMAL_THRESHOLD_WAY_DOWN))
|
|
continue;
|
|
|
|
if (temperature <= t->temperature &&
|
|
last_temperature > t->temperature)
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static void thermal_threshold_find_boundaries(struct list_head *thresholds, int temperature,
|
|
int *low, int *high)
|
|
{
|
|
struct user_threshold *t;
|
|
|
|
list_for_each_entry(t, thresholds, list_node) {
|
|
if (temperature < t->temperature &&
|
|
(t->direction & THERMAL_THRESHOLD_WAY_UP) &&
|
|
*high > t->temperature)
|
|
*high = t->temperature;
|
|
}
|
|
|
|
list_for_each_entry_reverse(t, thresholds, list_node) {
|
|
if (temperature > t->temperature &&
|
|
(t->direction & THERMAL_THRESHOLD_WAY_DOWN) &&
|
|
*low < t->temperature)
|
|
*low = t->temperature;
|
|
}
|
|
}
|
|
|
|
void thermal_thresholds_handle(struct thermal_zone_device *tz, int *low, int *high)
|
|
{
|
|
struct list_head *thresholds = &tz->user_thresholds;
|
|
|
|
int temperature = tz->temperature;
|
|
int last_temperature = tz->last_temperature;
|
|
|
|
lockdep_assert_held(&tz->lock);
|
|
|
|
thermal_threshold_find_boundaries(thresholds, temperature, low, high);
|
|
|
|
/*
|
|
* We need a second update in order to detect a threshold being crossed
|
|
*/
|
|
if (last_temperature == THERMAL_TEMP_INVALID)
|
|
return;
|
|
|
|
/*
|
|
* The temperature is stable, so obviously we can not have
|
|
* crossed a threshold.
|
|
*/
|
|
if (last_temperature == temperature)
|
|
return;
|
|
|
|
/*
|
|
* Since last update the temperature:
|
|
* - increased : thresholds are crossed the way up
|
|
* - decreased : thresholds are crossed the way down
|
|
*/
|
|
if (temperature > last_temperature) {
|
|
if (thermal_thresholds_handle_raising(thresholds,
|
|
temperature, last_temperature))
|
|
thermal_notify_threshold_up(tz);
|
|
} else {
|
|
if (thermal_thresholds_handle_dropping(thresholds,
|
|
temperature, last_temperature))
|
|
thermal_notify_threshold_down(tz);
|
|
}
|
|
}
|
|
|
|
int thermal_thresholds_add(struct thermal_zone_device *tz,
|
|
int temperature, int direction)
|
|
{
|
|
struct list_head *thresholds = &tz->user_thresholds;
|
|
struct user_threshold *t;
|
|
|
|
lockdep_assert_held(&tz->lock);
|
|
|
|
t = __thermal_thresholds_find(thresholds, temperature);
|
|
if (t) {
|
|
if (t->direction == direction)
|
|
return -EEXIST;
|
|
|
|
t->direction |= direction;
|
|
} else {
|
|
|
|
t = kmalloc_obj(*t);
|
|
if (!t)
|
|
return -ENOMEM;
|
|
|
|
INIT_LIST_HEAD(&t->list_node);
|
|
t->temperature = temperature;
|
|
t->direction = direction;
|
|
list_add(&t->list_node, thresholds);
|
|
list_sort(NULL, thresholds, __thermal_thresholds_cmp);
|
|
}
|
|
|
|
thermal_notify_threshold_add(tz, temperature, direction);
|
|
|
|
__thermal_zone_device_update(tz, THERMAL_TZ_ADD_THRESHOLD);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int thermal_thresholds_delete(struct thermal_zone_device *tz,
|
|
int temperature, int direction)
|
|
{
|
|
struct list_head *thresholds = &tz->user_thresholds;
|
|
struct user_threshold *t;
|
|
|
|
lockdep_assert_held(&tz->lock);
|
|
|
|
t = __thermal_thresholds_find(thresholds, temperature);
|
|
if (!t)
|
|
return -ENOENT;
|
|
|
|
if (t->direction == direction) {
|
|
list_del(&t->list_node);
|
|
kfree(t);
|
|
} else {
|
|
t->direction &= ~direction;
|
|
}
|
|
|
|
thermal_notify_threshold_delete(tz, temperature, direction);
|
|
|
|
__thermal_zone_device_update(tz, THERMAL_TZ_DEL_THRESHOLD);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int thermal_thresholds_for_each(struct thermal_zone_device *tz,
|
|
int (*cb)(struct user_threshold *, void *arg), void *arg)
|
|
{
|
|
struct list_head *thresholds = &tz->user_thresholds;
|
|
struct user_threshold *entry;
|
|
int ret;
|
|
|
|
guard(thermal_zone)(tz);
|
|
|
|
list_for_each_entry(entry, thresholds, list_node) {
|
|
ret = cb(entry, arg);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|