summaryrefslogtreecommitdiffstats
path: root/drivers/acpi/thermal_lib.c
diff options
context:
space:
mode:
authorKumar Kartikeya Dwivedi <memxor@gmail.com>2026-09-04 10:43:19 +0200
committerAlexei Starovoitov <ast@kernel.org>2026-09-04 07:58:36 -0700
commit6668ed271eaefaa63e686bdfbedaeb7b8e492722 (patch)
tree58e8288fead484f6755ad0815fc74c3742663761 /drivers/acpi/thermal_lib.c
downloadlinux-stable-6668ed271eaefaa63e686bdfbedaeb7b8e492722.tar.gz
linux-stable-6668ed271eaefaa63e686bdfbedaeb7b8e492722.zip
selftests/bpf: Reject graph kptr use after RCU unlockgrafted
Add a sleepable verifier test that loads a graph-node local kptr in an explicit RCU read-side critical section, then passes its node to bpf_rbtree_remove() after the section ends. Before the verifier fix, the stale NON_OWN_REF flag makes the node look like a live borrowed reference and the program is accepted. After the fix, the pointer is demoted without NON_OWN_REF and the graph kfunc argument is rejected. Also exercise a graph kptr loaded while a spin lock provides implicit RCU protection. The pointer must be invalidated when the lock is released, which guards the required ordering between non-owning-reference invalidation and RCU demotion. Update the existing fault-protected load test state description. The post-unlock pointer no longer carries NON_OWN_REF, but remains readable because the load is rewritten to use BPF_PROBE_MEM. Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Link: https://lore.kernel.org/r/20260904084325.52250-7-memxor@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'drivers/acpi/thermal_lib.c')
-rw-r--r--drivers/acpi/thermal_lib.c166
1 files changed, 166 insertions, 0 deletions
diff --git a/drivers/acpi/thermal_lib.c b/drivers/acpi/thermal_lib.c
new file mode 100644
index 000000000..f81591927
--- /dev/null
+++ b/drivers/acpi/thermal_lib.c
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2023 Linaro Limited
+ * Copyright 2023 Intel Corporation
+ *
+ * Library routines for retrieving trip point temperature values from the
+ * platform firmware via ACPI.
+ */
+#include <linux/acpi.h>
+#include <linux/units.h>
+#include <linux/thermal.h>
+#include "internal.h"
+
+/*
+ * Minimum temperature for full military grade is 218°K (-55°C) and
+ * max temperature is 448°K (175°C). We can consider those values as
+ * the boundaries for the [trips] temperature returned by the
+ * firmware. Any values out of these boundaries may be considered
+ * bogus and we can assume the firmware has no data to provide.
+ */
+#define TEMP_MIN_DECIK 2180ULL
+#define TEMP_MAX_DECIK 4480ULL
+
+static int acpi_trip_temp(struct acpi_device *adev, char *obj_name,
+ int *ret_temp)
+{
+ unsigned long long temp;
+ acpi_status status;
+
+ status = acpi_evaluate_integer(adev->handle, obj_name, NULL, &temp);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_debug(adev->handle, "%s evaluation failed\n", obj_name);
+ return -ENODATA;
+ }
+
+ if (temp >= TEMP_MIN_DECIK && temp <= TEMP_MAX_DECIK) {
+ *ret_temp = temp;
+ } else {
+ acpi_handle_debug(adev->handle, "%s result %llu out of range\n",
+ obj_name, temp);
+ *ret_temp = THERMAL_TEMP_INVALID;
+ }
+
+ return 0;
+}
+
+int acpi_active_trip_temp(struct acpi_device *adev, int id, int *ret_temp)
+{
+ char obj_name[] = {'_', 'A', 'C', '0' + id, '\0'};
+
+ if (id < 0 || id > 9)
+ return -EINVAL;
+
+ return acpi_trip_temp(adev, obj_name, ret_temp);
+}
+EXPORT_SYMBOL_NS_GPL(acpi_active_trip_temp, "ACPI_THERMAL");
+
+int acpi_passive_trip_temp(struct acpi_device *adev, int *ret_temp)
+{
+ return acpi_trip_temp(adev, "_PSV", ret_temp);
+}
+EXPORT_SYMBOL_NS_GPL(acpi_passive_trip_temp, "ACPI_THERMAL");
+
+int acpi_hot_trip_temp(struct acpi_device *adev, int *ret_temp)
+{
+ return acpi_trip_temp(adev, "_HOT", ret_temp);
+}
+EXPORT_SYMBOL_NS_GPL(acpi_hot_trip_temp, "ACPI_THERMAL");
+
+int acpi_critical_trip_temp(struct acpi_device *adev, int *ret_temp)
+{
+ return acpi_trip_temp(adev, "_CRT", ret_temp);
+}
+EXPORT_SYMBOL_NS_GPL(acpi_critical_trip_temp, "ACPI_THERMAL");
+
+static int thermal_temp(int error, int temp_decik, int *ret_temp)
+{
+ if (error)
+ return error;
+
+ if (temp_decik == THERMAL_TEMP_INVALID)
+ *ret_temp = THERMAL_TEMP_INVALID;
+ else
+ *ret_temp = deci_kelvin_to_millicelsius(temp_decik);
+
+ return 0;
+}
+
+/**
+ * thermal_acpi_active_trip_temp - Retrieve active trip point temperature
+ * @adev: Target thermal zone ACPI device object.
+ * @id: Active cooling level (0 - 9).
+ * @ret_temp: Address to store the retrieved temperature value on success.
+ *
+ * Evaluate the _ACx object for the thermal zone represented by @adev to obtain
+ * the temperature of the active cooling trip point corresponding to the active
+ * cooling level given by @id.
+ *
+ * Return 0 on success or a negative error value on failure.
+ */
+int thermal_acpi_active_trip_temp(struct acpi_device *adev, int id, int *ret_temp)
+{
+ int temp_decik = 0;
+ int ret = acpi_active_trip_temp(adev, id, &temp_decik);
+
+ return thermal_temp(ret, temp_decik, ret_temp);
+}
+EXPORT_SYMBOL_GPL(thermal_acpi_active_trip_temp);
+
+/**
+ * thermal_acpi_passive_trip_temp - Retrieve passive trip point temperature
+ * @adev: Target thermal zone ACPI device object.
+ * @ret_temp: Address to store the retrieved temperature value on success.
+ *
+ * Evaluate the _PSV object for the thermal zone represented by @adev to obtain
+ * the temperature of the passive cooling trip point.
+ *
+ * Return 0 on success or -ENODATA on failure.
+ */
+int thermal_acpi_passive_trip_temp(struct acpi_device *adev, int *ret_temp)
+{
+ int temp_decik = 0;
+ int ret = acpi_passive_trip_temp(adev, &temp_decik);
+
+ return thermal_temp(ret, temp_decik, ret_temp);
+}
+EXPORT_SYMBOL_GPL(thermal_acpi_passive_trip_temp);
+
+/**
+ * thermal_acpi_hot_trip_temp - Retrieve hot trip point temperature
+ * @adev: Target thermal zone ACPI device object.
+ * @ret_temp: Address to store the retrieved temperature value on success.
+ *
+ * Evaluate the _HOT object for the thermal zone represented by @adev to obtain
+ * the temperature of the trip point at which the system is expected to be put
+ * into the S4 sleep state.
+ *
+ * Return 0 on success or -ENODATA on failure.
+ */
+int thermal_acpi_hot_trip_temp(struct acpi_device *adev, int *ret_temp)
+{
+ int temp_decik = 0;
+ int ret = acpi_hot_trip_temp(adev, &temp_decik);
+
+ return thermal_temp(ret, temp_decik, ret_temp);
+}
+EXPORT_SYMBOL_GPL(thermal_acpi_hot_trip_temp);
+
+/**
+ * thermal_acpi_critical_trip_temp - Retrieve critical trip point temperature
+ * @adev: Target thermal zone ACPI device object.
+ * @ret_temp: Address to store the retrieved temperature value on success.
+ *
+ * Evaluate the _CRT object for the thermal zone represented by @adev to obtain
+ * the temperature of the critical cooling trip point.
+ *
+ * Return 0 on success or -ENODATA on failure.
+ */
+int thermal_acpi_critical_trip_temp(struct acpi_device *adev, int *ret_temp)
+{
+ int temp_decik = 0;
+ int ret = acpi_critical_trip_temp(adev, &temp_decik);
+
+ return thermal_temp(ret, temp_decik, ret_temp);
+}
+EXPORT_SYMBOL_GPL(thermal_acpi_critical_trip_temp);