From 7e2c70f8a104e777df799130b4a39c35f51ba19c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 11 Sep 2026 15:02:09 +0200 Subject: thermal: core: Introduce thermal_cooling_device_create() Currently, thermal cooling devices have no parents, but it would be generally useful to be able to create them under specific parents in the device hierarchy (for instance, it may help to identify the device representing the actual cooling hardware). To make that possible, add thermal_cooling_device_create() that will work like thermal_cooling_device_register() except that it will take an additional parent argument (which may be NULL). Redefine thermal_cooling_device_register() as a static inline wrapper around thermal_cooling_device_create(). Signed-off-by: Rafael J. Wysocki Reviewed-by: Armin Wolf Link: https://patch.msgid.link/8729484.T7Z3S40VBb@rafael.j.wysocki --- include/linux/thermal.h | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/linux/thermal.h b/include/linux/thermal.h index 083b4f533933..306ad17aed89 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -293,8 +293,9 @@ struct device *thermal_zone_device(struct thermal_zone_device *tzd); void thermal_zone_device_update(struct thermal_zone_device *, enum thermal_notify_event); -struct thermal_cooling_device *thermal_cooling_device_register(const char *, - void *, const struct thermal_cooling_device_ops *); +struct thermal_cooling_device *thermal_cooling_device_create( + struct device *parent, const char *type, void *devdata, + const struct thermal_cooling_device_ops *ops); struct thermal_cooling_device * devm_thermal_cooling_device_register(struct device *dev, const char *type, void *devdata, @@ -340,9 +341,9 @@ static inline void thermal_zone_device_update(struct thermal_zone_device *tz, enum thermal_notify_event event) { } -static inline struct thermal_cooling_device * -thermal_cooling_device_register(const char *type, void *devdata, - const struct thermal_cooling_device_ops *ops) +static inline struct thermal_cooling_device *thermal_cooling_device_create( + struct device *parent, const char *type, void *devdata, + const struct thermal_cooling_device_ops *ops) { return ERR_PTR(-ENODEV); } static inline struct thermal_cooling_device * @@ -391,4 +392,12 @@ static inline void thermal_pm_prepare(void) {} static inline void thermal_pm_complete(void) {} #endif /* CONFIG_THERMAL */ +static inline struct thermal_cooling_device *thermal_cooling_device_register( + const char *type, void *devdata, + const struct thermal_cooling_device_ops *ops) +{ + return thermal_cooling_device_create(NULL, type, devdata, ops); +} + + #endif /* __THERMAL_H__ */ -- cgit v1.2.3 From bb03cfceb1f11047a0155fa7871b729a345c8de2 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 11 Sep 2026 15:02:53 +0200 Subject: ACPI: processor: thermal: Use thermal_cooling_device_create() Instead of using thermal_cooling_device_register() for registering a cooling device in the ACPI processor driver, make it use thermal_cooling_device_create() and pass a pointer to the processor device representing the given CPU to that function as the cooling device's parent. That will cause the cooling device's sysfs directory to be created under the parent's sysfs directory (among other things). Since creating a class device under a parent causes a "device" symbolic link from the sysfs directory of the class device to the sysfs directory of the parent to appear automatically, remove the code creating the "device" symbolic link from the sysfs directory of the cooling device in question to the sysfs directory of the parent's companion ACPI device. That ACPI device is reachable through the "firmware_node" symbolic link in the parent's sysfs directory regardless. Moreover, since the cooling device is now located in sysfs under its parent and it can be easily identified as a cooling device, there is no need to create a "thermal_cooling" symbolic link from its parent's ACPI companion to it. Accordingly, also remove the code creating that symbolic link. While at it, check for error pointer values in addition to checking for NULL in acpi_processor_thermal_exit() to avoid dereferencing them mistakenly. Signed-off-by: Rafael J. Wysocki Reviewed-by: Armin Wolf [ rjw: Corrected typo in the changelog ] Link: https://patch.msgid.link/2362345.iZASKD2KPV@rafael.j.wysocki Signed-off-by: Rafael J. Wysocki --- drivers/acpi/processor_driver.c | 4 ++-- drivers/acpi/processor_thermal.c | 47 ++++++---------------------------------- include/acpi/processor.h | 3 +-- 3 files changed, 10 insertions(+), 44 deletions(-) (limited to 'include') diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index cdc2ae1632b2..90c14480393d 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -179,7 +179,7 @@ static int __acpi_processor_start(struct acpi_device *device) return 0; err_thermal_exit: - acpi_processor_thermal_exit(pr, device); + acpi_processor_thermal_exit(pr); err_power_exit: acpi_processor_power_exit(pr); return result; @@ -203,7 +203,7 @@ static int acpi_processor_stop(struct device *dev) acpi_cppc_processor_exit(pr); - acpi_processor_thermal_exit(pr, device); + acpi_processor_thermal_exit(pr); return 0; } diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index c7b1dc5687ec..6cd47551844a 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -311,52 +311,19 @@ const struct thermal_cooling_device_ops processor_cooling_ops = { int acpi_processor_thermal_init(struct acpi_processor *pr, struct acpi_device *device) { - int result = 0; - - pr->cdev = thermal_cooling_device_register("Processor", device, - &processor_cooling_ops); - if (IS_ERR(pr->cdev)) { - result = PTR_ERR(pr->cdev); - return result; - } - - dev_dbg(&device->dev, "registered as cooling_device%d\n", - pr->cdev->id); - - result = sysfs_create_link(&device->dev.kobj, - &pr->cdev->device.kobj, - "thermal_cooling"); - if (result) { - dev_err(&device->dev, - "Failed to create sysfs link 'thermal_cooling'\n"); - goto err_thermal_unregister; - } + pr->cdev = thermal_cooling_device_create(pr->dev, "Processor", device, + &processor_cooling_ops); + if (IS_ERR(pr->cdev)) + return PTR_ERR(pr->cdev); - result = sysfs_create_link(&pr->cdev->device.kobj, - &device->dev.kobj, - "device"); - if (result) { - dev_err(&pr->cdev->device, - "Failed to create sysfs link 'device'\n"); - goto err_remove_sysfs_thermal; - } + dev_dbg(pr->dev, "registered as cooling_device%d\n", pr->cdev->id); return 0; - -err_remove_sysfs_thermal: - sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); -err_thermal_unregister: - thermal_cooling_device_unregister(pr->cdev); - - return result; } -void acpi_processor_thermal_exit(struct acpi_processor *pr, - struct acpi_device *device) +void acpi_processor_thermal_exit(struct acpi_processor *pr) { - if (pr->cdev) { - sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); - sysfs_remove_link(&pr->cdev->device.kobj, "device"); + if (!IS_ERR_OR_NULL(pr->cdev)) { thermal_cooling_device_unregister(pr->cdev); pr->cdev = NULL; } diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 554be224ce76..656aaf74fb18 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -429,8 +429,7 @@ int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi); /* in processor_thermal.c */ int acpi_processor_thermal_init(struct acpi_processor *pr, struct acpi_device *device); -void acpi_processor_thermal_exit(struct acpi_processor *pr, - struct acpi_device *device); +void acpi_processor_thermal_exit(struct acpi_processor *pr); extern const struct thermal_cooling_device_ops processor_cooling_ops; #ifdef CONFIG_CPU_FREQ void acpi_thermal_cpufreq_init(struct cpufreq_policy *policy); -- cgit v1.2.3 From d1b25eb2d87738b5ad07070e0859017f6561760c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 11 Sep 2026 15:05:50 +0200 Subject: ACPI: processor: thermal: Use more suitable cooling device data Instead of passing an ACPI device object pointer as devdata to thermal_cooling_device_create(), make acpi_processor_thermal_init() pass a pointer to the struct acpi_processor representing the given CPU to it, which allows the callback functions in processor_cooling_ops to be simplified and the second argument of acpi_processor_thermal_init() and acpi_processor_thermal_exit() to be dropped. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Reviewed-by: Armin Wolf Link: https://patch.msgid.link/6192780.MhkbZ0Pkbq@rafael.j.wysocki --- drivers/acpi/processor_driver.c | 2 +- drivers/acpi/processor_thermal.c | 35 +++++------------------------------ include/acpi/processor.h | 3 +-- 3 files changed, 7 insertions(+), 33 deletions(-) (limited to 'include') diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 90c14480393d..bdd1529d79f0 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -164,7 +164,7 @@ static int __acpi_processor_start(struct acpi_device *device) acpi_pss_perf_init(pr); - result = acpi_processor_thermal_init(pr, device); + result = acpi_processor_thermal_init(pr); if (result) goto err_power_exit; diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index 6cd47551844a..11036f0d2b94 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -235,15 +235,7 @@ static int processor_get_max_state(struct thermal_cooling_device *cdev, unsigned long *state) { - struct acpi_device *device = cdev->devdata; - struct acpi_processor *pr; - - if (!device) - return -EINVAL; - - pr = acpi_driver_data(device); - if (!pr) - return -EINVAL; + struct acpi_processor *pr = cdev->devdata; *state = acpi_processor_max_state(pr); return 0; @@ -253,15 +245,7 @@ static int processor_get_cur_state(struct thermal_cooling_device *cdev, unsigned long *cur_state) { - struct acpi_device *device = cdev->devdata; - struct acpi_processor *pr; - - if (!device) - return -EINVAL; - - pr = acpi_driver_data(device); - if (!pr) - return -EINVAL; + struct acpi_processor *pr = cdev->devdata; *cur_state = cpufreq_get_cur_state(pr->id); if (pr->flags.throttling) @@ -273,18 +257,10 @@ static int processor_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) { - struct acpi_device *device = cdev->devdata; - struct acpi_processor *pr; + struct acpi_processor *pr = cdev->devdata; int result = 0; int max_pstate; - if (!device) - return -EINVAL; - - pr = acpi_driver_data(device); - if (!pr) - return -EINVAL; - max_pstate = cpufreq_get_max_state(pr->id); if (state > acpi_processor_max_state(pr)) @@ -308,10 +284,9 @@ const struct thermal_cooling_device_ops processor_cooling_ops = { .set_cur_state = processor_set_cur_state, }; -int acpi_processor_thermal_init(struct acpi_processor *pr, - struct acpi_device *device) +int acpi_processor_thermal_init(struct acpi_processor *pr) { - pr->cdev = thermal_cooling_device_create(pr->dev, "Processor", device, + pr->cdev = thermal_cooling_device_create(pr->dev, "Processor", pr, &processor_cooling_ops); if (IS_ERR(pr->cdev)) return PTR_ERR(pr->cdev); diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 656aaf74fb18..b5447af4d40b 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -427,8 +427,7 @@ int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi); #endif /* CONFIG_ACPI_PROCESSOR_IDLE */ /* in processor_thermal.c */ -int acpi_processor_thermal_init(struct acpi_processor *pr, - struct acpi_device *device); +int acpi_processor_thermal_init(struct acpi_processor *pr); void acpi_processor_thermal_exit(struct acpi_processor *pr); extern const struct thermal_cooling_device_ops processor_cooling_ops; #ifdef CONFIG_CPU_FREQ -- cgit v1.2.3 From b2ddc080570c9012359a786bf8ae5480c2911a6a Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 16 Sep 2026 21:42:54 +0200 Subject: ACPI: fan: Use __free() to simplify AML error handling Introduce acpi_object_free for freeing union acpi_object objects allocated by AML and use it for simplifying AML error handling in the ACPI fan driver. While at it, update the driver to use consistent error values across all function using the union acpi_object data type. Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko Reviewed-by: Armin Wolf [ rjw: Put the new free definition under CONFIG_ACPI ] Link: https://patch.msgid.link/6029013.DvuYhMxLoT@rafael.j.wysocki Signed-off-by: Rafael J. Wysocki --- drivers/acpi/fan_core.c | 80 +++++++++++++++++++------------------------------ include/linux/acpi.h | 2 ++ 2 files changed, 32 insertions(+), 50 deletions(-) (limited to 'include') diff --git a/drivers/acpi/fan_core.c b/drivers/acpi/fan_core.c index 5ad65975fbb4..3674f9613d40 100644 --- a/drivers/acpi/fan_core.c +++ b/drivers/acpi/fan_core.c @@ -71,37 +71,29 @@ static int fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long int acpi_fan_get_fst(acpi_handle handle, struct acpi_fan_fst *fst) { struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *obj; acpi_status status; - int ret = 0; status = acpi_evaluate_object(handle, "_FST", NULL, &buffer); if (ACPI_FAILURE(status)) - return -EIO; + return -ENXIO; - obj = buffer.pointer; + union acpi_object *obj __free(acpi_object_free) = buffer.pointer; if (!obj) return -ENODATA; - if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3) { - ret = -EPROTO; - goto err; - } + if (obj->type != ACPI_TYPE_PACKAGE || obj->package.count != 3) + return -EPROTO; if (obj->package.elements[0].type != ACPI_TYPE_INTEGER || obj->package.elements[1].type != ACPI_TYPE_INTEGER || - obj->package.elements[2].type != ACPI_TYPE_INTEGER) { - ret = -EPROTO; - goto err; - } + obj->package.elements[2].type != ACPI_TYPE_INTEGER) + return -EPROTO; fst->revision = obj->package.elements[0].integer.value; fst->control = obj->package.elements[1].integer.value; fst->speed = obj->package.elements[2].integer.value; -err: - kfree(obj); - return ret; + return 0; } static int fan_get_state_acpi4(struct acpi_fan *fan, unsigned long *state) @@ -237,25 +229,22 @@ static int acpi_fan_get_fif(struct acpi_device *device) struct acpi_buffer format = { sizeof("NNNN"), "NNNN" }; u64 fields[4]; struct acpi_buffer fif = { sizeof(fields), fields }; - union acpi_object *obj; acpi_status status; status = acpi_evaluate_object(device->handle, "_FIF", NULL, &buffer); if (ACPI_FAILURE(status)) - return status; + return -ENXIO; - obj = buffer.pointer; + union acpi_object *obj __free(acpi_object_free) = buffer.pointer; if (!obj || obj->type != ACPI_TYPE_PACKAGE) { dev_err(&device->dev, "Invalid _FIF data\n"); - status = -EINVAL; - goto err; + return -ENODATA; } status = acpi_extract_package(obj, &format, &fif); if (ACPI_FAILURE(status)) { dev_err(&device->dev, "Invalid _FIF element\n"); - status = -EINVAL; - goto err; + return -ENODATA; } fan->fif.revision = fields[0]; @@ -269,9 +258,8 @@ static int acpi_fan_get_fif(struct acpi_device *device) /* If step size > 9, change to 9 (by spec valid values 1-9) */ else if (fan->fif.step_size > 9) fan->fif.step_size = 9; -err: - kfree(obj); - return status; + + return 0; } static int acpi_fan_speed_cmp(const void *a, const void *b) @@ -285,27 +273,24 @@ static int acpi_fan_get_fps(struct device *dev, struct acpi_device *device) { struct acpi_fan *fan = acpi_driver_data(device); struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - union acpi_object *obj; acpi_status status; int i; status = acpi_evaluate_object(device->handle, "_FPS", NULL, &buffer); if (ACPI_FAILURE(status)) - return status; + return -ENXIO; - obj = buffer.pointer; + union acpi_object *obj __free(acpi_object_free) = buffer.pointer; if (!obj || obj->type != ACPI_TYPE_PACKAGE || obj->package.count < 2) { dev_err(&device->dev, "Invalid _FPS data\n"); - status = -EINVAL; - goto err; + return -ENODATA; } fan->fps_count = obj->package.count - 1; /* minus revision field */ fan->fps = devm_kcalloc(dev, fan->fps_count, sizeof(*fan->fps), GFP_KERNEL); - if (!fan->fps) { - status = -ENOMEM; - goto err; - } + if (!fan->fps) + return -ENOMEM; + for (i = 0; i < fan->fps_count; i++) { struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" }; struct acpi_buffer fps = { offsetof(struct acpi_fan_fps, name), @@ -314,7 +299,7 @@ static int acpi_fan_get_fps(struct device *dev, struct acpi_device *device) &format, &fps); if (ACPI_FAILURE(status)) { dev_err(&device->dev, "Invalid _FPS element\n"); - goto err; + return -ENODATA; } } @@ -322,9 +307,7 @@ static int acpi_fan_get_fps(struct device *dev, struct acpi_device *device) sort(fan->fps, fan->fps_count, sizeof(*fan->fps), acpi_fan_speed_cmp, NULL); -err: - kfree(obj); - return status; + return 0; } static int acpi_fan_dsm_init(struct device *dev) @@ -338,8 +321,6 @@ static int acpi_fan_dsm_init(struct device *dev) }; struct acpi_fan *fan = dev_get_drvdata(dev); acpi_handle fan_handle = fan->adev->handle; - union acpi_object *obj; - int ret = 0; if (!acpi_check_dsm(fan_handle, &acpi_fan_microsoft_guid, 0, BIT(ACPI_FAN_DSM_GET_TRIP_POINT_GRANULARITY) | @@ -348,20 +329,19 @@ static int acpi_fan_dsm_init(struct device *dev) dev_info(dev, "Using Microsoft fan extensions\n"); - obj = acpi_evaluate_dsm_typed(fan_handle, &acpi_fan_microsoft_guid, 0, - ACPI_FAN_DSM_GET_TRIP_POINT_GRANULARITY, &dummy, - ACPI_TYPE_INTEGER); + union acpi_object *obj __free(acpi_object_free) = + acpi_evaluate_dsm_typed(fan_handle, &acpi_fan_microsoft_guid, 0, + ACPI_FAN_DSM_GET_TRIP_POINT_GRANULARITY, + &dummy, ACPI_TYPE_INTEGER); if (!obj) - return -EIO; + return -ENXIO; if (obj->integer.value > U32_MAX) - ret = -EOVERFLOW; - else - fan->fan_trip_granularity = obj->integer.value; + return -EOVERFLOW; - kfree(obj); + fan->fan_trip_granularity = obj->integer.value; - return ret; + return 0; } static int acpi_fan_dsm_set_trip_points(struct device *dev, u64 upper, u64 lower) @@ -392,7 +372,7 @@ static int acpi_fan_dsm_set_trip_points(struct device *dev, u64 upper, u64 lower obj = acpi_evaluate_dsm(fan->adev->handle, &acpi_fan_microsoft_guid, 0, ACPI_FAN_DSM_SET_TRIP_POINTS, &in); - kfree(obj); + ACPI_FREE(obj); return 0; } diff --git a/include/linux/acpi.h b/include/linux/acpi.h index ddacac812094..99d7aa7afaa1 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -29,6 +29,8 @@ struct irq_domain_ops; #ifdef CONFIG_ACPI +DEFINE_FREE(acpi_object_free, union acpi_object *, if (_T) ACPI_FREE(_T)); + #include #include #include -- cgit v1.2.3 From 3bd2779b6cfdb67a05bc52b86a1d9cd2e31cdcc2 Mon Sep 17 00:00:00 2001 From: Bibo Mao Date: Tue, 22 Sep 2026 20:10:55 +0800 Subject: ACPICA: actbl2.h: Add bit constants of the Flags field in the IOVT IOMMU structure According to the IOVT specification, define macros for each bit of the Flags field in the IOVT IOMMU structure. Link: https://github.com/open-acpica/acpica/commit/352f750e4cc0 Signed-off-by: Bibo Mao Link: https://patch.msgid.link/20260922121058.972734-2-maobibo@loongson.cn Signed-off-by: Rafael J. Wysocki --- include/acpi/actbl2.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'include') diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index baef525367b5..76e4a5bc79b4 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -919,6 +919,13 @@ struct acpi_iovt_iommu { u32 device_entry_offset; }; +/* Masks for Flags field above */ +#define ACPI_IOVT_IOMMU_PCI_DEVICE (1<<0) +#define ACPI_IOVT_IOMMU_PXM_VALID (1<<1) +#define ACPI_IOVT_IOMMU_MAGAGE_BY_SEGMENT (1<<2) +#define ACPI_IOVT_IOMMU_HW_CAP_SUPPORT (1<<3) +#define ACPI_IOVT_IOMMU_MSI_INT_BYPASS (1<<4) + struct acpi_iovt_device_entry { u8 type; u8 length; -- cgit v1.2.3