From 78ddbfaa72d68acc98cd5ba12eca071d452702c4 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 6 Sep 2026 17:56:56 +0200 Subject: ACPI: utils: Adjust message printing macros for ACPI objects The majority of acpi_handle_() macros use neither pr_fmt() nor dev_fmt() and acpi_handle_debug() uses pr_fmt() like dev_fmt(), but only if dynamic debug is compiled in. For more consistency, redefine all of the macros in question to use dev_fmt() because they are more similar to the analogous dev_*() family of macros than to the pr_*() ones and make all of them use it in the same way. While at it, rephrase the comment documenting those macros for more clarity. Fixes: 45fef5b88d1f ("ACPI: add dynamic_debug support") Signed-off-by: Rafael J. Wysocki Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/2300525.irdbgypaU6@rafael.j.wysocki Signed-off-by: Rafael J. Wysocki --- include/linux/acpi.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/include/linux/acpi.h b/include/linux/acpi.h index ddacac812094..f7e3efd328f7 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -1305,34 +1305,34 @@ void __acpi_handle_debug(struct _ddebug *descriptor, acpi_handle handle, const c #endif /* - * acpi_handle_: Print message with ACPI prefix and object path + * acpi_handle_ - Print a message with ACPI prefix and object path * - * These interfaces acquire the global namespace mutex to obtain an object - * path. In interrupt context, it shows the object path as . + * In thread context, the global namespace mutex is acquired to obtain the + * object path. In interrupt context, the object path is shown as . */ #define acpi_handle_emerg(handle, fmt, ...) \ - acpi_handle_printk(KERN_EMERG, handle, fmt, ##__VA_ARGS__) + acpi_handle_printk(KERN_EMERG, handle, dev_fmt(fmt), ##__VA_ARGS__) #define acpi_handle_alert(handle, fmt, ...) \ - acpi_handle_printk(KERN_ALERT, handle, fmt, ##__VA_ARGS__) + acpi_handle_printk(KERN_ALERT, handle, dev_fmt(fmt), ##__VA_ARGS__) #define acpi_handle_crit(handle, fmt, ...) \ - acpi_handle_printk(KERN_CRIT, handle, fmt, ##__VA_ARGS__) + acpi_handle_printk(KERN_CRIT, handle, dev_fmt(fmt), ##__VA_ARGS__) #define acpi_handle_err(handle, fmt, ...) \ - acpi_handle_printk(KERN_ERR, handle, fmt, ##__VA_ARGS__) + acpi_handle_printk(KERN_ERR, handle, dev_fmt(fmt), ##__VA_ARGS__) #define acpi_handle_warn(handle, fmt, ...) \ - acpi_handle_printk(KERN_WARNING, handle, fmt, ##__VA_ARGS__) + acpi_handle_printk(KERN_WARNING, handle, dev_fmt(fmt), ##__VA_ARGS__) #define acpi_handle_notice(handle, fmt, ...) \ - acpi_handle_printk(KERN_NOTICE, handle, fmt, ##__VA_ARGS__) + acpi_handle_printk(KERN_NOTICE, handle, dev_fmt(fmt), ##__VA_ARGS__) #define acpi_handle_info(handle, fmt, ...) \ - acpi_handle_printk(KERN_INFO, handle, fmt, ##__VA_ARGS__) + acpi_handle_printk(KERN_INFO, handle, dev_fmt(fmt), ##__VA_ARGS__) #if defined(DEBUG) #define acpi_handle_debug(handle, fmt, ...) \ - acpi_handle_printk(KERN_DEBUG, handle, fmt, ##__VA_ARGS__) + acpi_handle_printk(KERN_DEBUG, handle, dev_fmt(fmt), ##__VA_ARGS__) #else #if defined(CONFIG_DYNAMIC_DEBUG) #define acpi_handle_debug(handle, fmt, ...) \ _dynamic_func_call(fmt, __acpi_handle_debug, \ - handle, pr_fmt(fmt), ##__VA_ARGS__) + handle, dev_fmt(fmt), ##__VA_ARGS__) #else #define acpi_handle_debug(handle, fmt, ...) \ ({ \ -- cgit v1.2.3 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 --- drivers/thermal/thermal_core.c | 28 ++++++++++++++++------------ drivers/thermal/thermal_core.h | 3 ++- drivers/thermal/thermal_of.c | 2 +- include/linux/thermal.h | 19 ++++++++++++++----- 4 files changed, 33 insertions(+), 19 deletions(-) (limited to 'include/linux') diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 82e2f0d8a26d..ac928c199829 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -1005,7 +1005,8 @@ out_kfree_cdev: return ERR_PTR(ret); } -int thermal_cooling_device_add(struct thermal_cooling_device *cdev, void *devdata) +int thermal_cooling_device_add(struct thermal_cooling_device *cdev, + struct device *parent, void *devdata) { unsigned long current_state; int ret; @@ -1013,6 +1014,7 @@ int thermal_cooling_device_add(struct thermal_cooling_device *cdev, void *devdat mutex_init(&cdev->lock); INIT_LIST_HEAD(&cdev->thermal_instances); cdev->updated = false; + cdev->device.parent = parent; cdev->device.class = &thermal_class; cdev->device.release = thermal_cdev_release; device_initialize(&cdev->device); @@ -1062,21 +1064,23 @@ out_put_device: } /** - * thermal_cooling_device_register() - register a new thermal cooling device + * thermal_cooling_device_create() - register a new thermal cooling device + * @parent: parent device (optional). * @type: the thermal cooling device type. * @devdata: device private data. * @ops: standard thermal cooling devices callbacks. * - * This interface function adds a new thermal cooling device (fan/processor/...) - * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself - * to all the thermal zone devices registered at the same time. + * Allocate and register a new thermal cooling device under the given parent (if + * not NULL) and with the given type, device data, and operations. During the + * registration, it will be matched against all of the registered thermal zones + * and it will be bound to the matching ones. * - * Return: a pointer to the created struct thermal_cooling_device or an - * ERR_PTR. Caller must check return value with IS_ERR*() helpers. + * Return: A pointer to the created struct thermal_cooling_device or an ERR_PTR. + * Callers must use IS_ERR*() helpers to check the return value. */ -struct thermal_cooling_device * -thermal_cooling_device_register(const char *type, void *devdata, - const struct thermal_cooling_device_ops *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 *cdev; int ret; @@ -1085,13 +1089,13 @@ thermal_cooling_device_register(const char *type, void *devdata, if (IS_ERR(cdev)) return cdev; - ret = thermal_cooling_device_add(cdev, devdata); + ret = thermal_cooling_device_add(cdev, parent, devdata); if (ret) return ERR_PTR(ret); return cdev; } -EXPORT_SYMBOL_GPL(thermal_cooling_device_register); +EXPORT_SYMBOL_GPL(thermal_cooling_device_create); static void thermal_cooling_device_release(void *data) { diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h index e98b0aa5aacc..7ef7c6cab437 100644 --- a/drivers/thermal/thermal_core.h +++ b/drivers/thermal/thermal_core.h @@ -270,7 +270,8 @@ void thermal_governor_update_tz(struct thermal_zone_device *tz, struct thermal_cooling_device * thermal_cooling_device_alloc(const char *type, const struct thermal_cooling_device_ops *ops); -int thermal_cooling_device_add(struct thermal_cooling_device *cdev, void *devdata); +int thermal_cooling_device_add(struct thermal_cooling_device *cdev, + struct device *parent, void *devdata); /* Helpers */ #define for_each_trip_desc(__tz, __td) \ diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c index 0217a49b08ae..14dfac9359b8 100644 --- a/drivers/thermal/thermal_of.c +++ b/drivers/thermal/thermal_of.c @@ -561,7 +561,7 @@ thermal_of_cooling_device_register(struct device_node *np, u32 cdev_id, cdev->np = np; cdev->cdev_id = cdev_id; - ret = thermal_cooling_device_add(cdev, devdata); + ret = thermal_cooling_device_add(cdev, NULL, devdata); if (ret) return ERR_PTR(ret); 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 b5aa69375d2fb46ca9c3cd43ecd843ffbce38be7 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 4 Sep 2026 14:12:06 -0700 Subject: PM: runtime: kerneldoc fixes When included into a Documentation/.../*.rst file, `make htmldocs` complains: ./include/linux/pm_runtime.h:359: WARNING: Bullet list ends without a blank line; unexpected unindent. [docutils] [... more ...] We should fix up the list format here to look nicer in HTML form, and avoid warnings. Adjust to a few other kerneldoc-isms (formatting, "Return:") while we're at it too. The result now passes 'make htmldocs' without warning, once these files are included in Documentation/.../*.rst. Signed-off-by: Brian Norris Link: https://patch.msgid.link/20260904141215.1.Ib31d6be7e93f6c02321d03c78ea410e02d7380fc@changeid Signed-off-by: Rafael J. Wysocki --- drivers/base/power/runtime.c | 24 ++-- include/linux/pm_runtime.h | 291 +++++++++++++++++++++++++------------------ 2 files changed, 183 insertions(+), 132 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 4d84d97f09c4..29e5ce69d04c 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -162,7 +162,7 @@ static void pm_runtime_cancel_pending(struct device *dev) dev->power.request = RPM_REQ_NONE; } -/* +/** * pm_runtime_autosuspend_expiration - Get a device's autosuspend-delay expiration time. * @dev: Device to handle. * @@ -200,7 +200,7 @@ static int dev_memalloc_noio(struct device *dev, void *data) return dev->power.memalloc_noio; } -/* +/** * pm_runtime_set_memalloc_noio - Set a device's memalloc_noio flag. * @dev: Device to handle. * @enable: True for setting the flag and False for clearing the flag. @@ -1044,6 +1044,11 @@ static enum hrtimer_restart pm_suspend_timer_fn(struct hrtimer *timer) * pm_schedule_suspend - Set up a timer to submit a suspend request in future. * @dev: Device to suspend. * @delay: Time to wait before submitting a suspend request, in milliseconds. + * + * Return: + * * %1: Success; @dev is already %RPM_SUSPENDED. + * * %0: Success. + * * Error code on failure. */ int pm_schedule_suspend(struct device *dev, unsigned int delay) { @@ -1106,7 +1111,7 @@ static int rpm_drop_usage_count(struct device *dev) * warning, increment it, and return an error). Then carry out an idle * notification, either synchronous or asynchronous. * - * This routine may be called in atomic context if the RPM_ASYNC flag is set, + * This routine may be called in atomic context if the %RPM_ASYNC flag is set, * or if pm_runtime_irq_safe() has been called. */ int __pm_runtime_idle(struct device *dev, int rpmflags) @@ -1144,7 +1149,7 @@ EXPORT_SYMBOL_GPL(__pm_runtime_idle); * warning, increment it, and return an error). Then carry out a suspend, * either synchronous or asynchronous. * - * This routine may be called in atomic context if the RPM_ASYNC flag is set, + * This routine may be called in atomic context if the %RPM_ASYNC flag is set, * or if pm_runtime_irq_safe() has been called. */ int __pm_runtime_suspend(struct device *dev, int rpmflags) @@ -1180,7 +1185,7 @@ EXPORT_SYMBOL_GPL(__pm_runtime_suspend); * If the RPM_GET_PUT flag is set, increment the device's usage count. Then * carry out a resume, either synchronous or asynchronous. * - * This routine may be called in atomic context if the RPM_ASYNC flag is set, + * This routine may be called in atomic context if the %RPM_ASYNC flag is set, * or if pm_runtime_irq_safe() has been called. */ int __pm_runtime_resume(struct device *dev, int rpmflags) @@ -1255,9 +1260,12 @@ static int pm_runtime_get_conditional(struct device *dev, bool ign_usage_count) * @dev: Target device. * * Increment the runtime PM usage counter of @dev if its runtime PM status is - * %RPM_ACTIVE, in which case it returns 1. If the device is in a different - * state, 0 is returned. -EINVAL is returned if runtime PM is disabled for the - * device, in which case also the usage_count will remain unmodified. + * already %RPM_ACTIVE + * + * Return: + * * %-EINVAL: Runtime PM is disabled for @dev. The usage counter is not incremented. + * * %1: Success; usage counter is incremented. + * * %0: @dev was not active. */ int pm_runtime_get_if_active(struct device *dev) { diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index 64921b10ac74..ab6a19a85880 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -137,13 +137,14 @@ static inline void pm_runtime_put_noidle(struct device *dev) * pm_runtime_suspended - Check whether or not a device is runtime-suspended. * @dev: Target device. * - * Return %true if runtime PM is enabled for @dev and its runtime PM status is - * %RPM_SUSPENDED, or %false otherwise. - * * Note that the return value of this function can only be trusted if it is * called under the runtime PM lock of @dev or under conditions in which * runtime PM cannot be either disabled or enabled for @dev and its runtime PM * status cannot change. + * + * Return: + * * %true: @dev has runtime PM enabled and its status is %RPM_SUSPENDED. + * * %false: Otherwise. */ static inline bool pm_runtime_suspended(struct device *dev) { @@ -155,13 +156,14 @@ static inline bool pm_runtime_suspended(struct device *dev) * pm_runtime_active - Check whether or not a device is runtime-active. * @dev: Target device. * - * Return %true if runtime PM is disabled for @dev or its runtime PM status is - * %RPM_ACTIVE, or %false otherwise. - * * Note that the return value of this function can only be trusted if it is * called under the runtime PM lock of @dev or under conditions in which * runtime PM cannot be either disabled or enabled for @dev and its runtime PM * status cannot change. + * + * Return: + * * %true: Runtime PM is disabled for @dev or its status is %RPM_ACTIVE. + * * %false: Otherwise. */ static inline bool pm_runtime_active(struct device *dev) { @@ -173,12 +175,13 @@ static inline bool pm_runtime_active(struct device *dev) * pm_runtime_status_suspended - Check if runtime PM status is "suspended". * @dev: Target device. * - * Return %true if the runtime PM status of @dev is %RPM_SUSPENDED, or %false - * otherwise, regardless of whether or not runtime PM has been enabled for @dev. - * * Note that the return value of this function can only be trusted if it is * called under the runtime PM lock of @dev or under conditions in which the * runtime PM status of @dev cannot change. + * + * Return: + * * %true: Runtime PM status of @dev is %RPM_SUSPENDED. + * * %false: Otherwise. */ static inline bool pm_runtime_status_suspended(struct device *dev) { @@ -189,11 +192,13 @@ static inline bool pm_runtime_status_suspended(struct device *dev) * pm_runtime_enabled - Check if runtime PM is enabled. * @dev: Target device. * - * Return %true if runtime PM is enabled for @dev or %false otherwise. - * * Note that the return value of this function can only be trusted if it is * called under the runtime PM lock of @dev or under conditions in which * runtime PM cannot be either disabled or enabled for @dev. + * + * Return: + * * %true: Runtime PM is enabled for @dev. + * * %false: Otherwise. */ static inline bool pm_runtime_enabled(struct device *dev) { @@ -205,6 +210,10 @@ static inline bool pm_runtime_enabled(struct device *dev) * @dev: Target device. * * Do not call this function outside system suspend/resume code paths. + * + * Return: + * * %true: Runtime PM enabling is blocked for @dev. + * * %false: Otherwise. */ static inline bool pm_runtime_blocked(struct device *dev) { @@ -215,8 +224,9 @@ static inline bool pm_runtime_blocked(struct device *dev) * pm_runtime_has_no_callbacks - Check if runtime PM callbacks may be present. * @dev: Target device. * - * Return %true if @dev is a special device without runtime PM callbacks or - * %false otherwise. + * Return: + * * %true: @dev is marked as having no runtime PM callbacks. + * * %false: Otherwise. */ static inline bool pm_runtime_has_no_callbacks(struct device *dev) { @@ -239,9 +249,11 @@ static inline void pm_runtime_mark_last_busy(struct device *dev) * pm_runtime_is_irq_safe - Check if runtime PM can work in interrupt context. * @dev: Target device. * - * Return %true if @dev has been marked as an "IRQ-safe" device (with respect - * to runtime PM), in which case its runtime PM callabcks can be expected to - * work correctly when invoked from interrupt handlers. + * Return: + * * %true: @dev has been marked as an "IRQ-safe" device, in which case its + * runtime PM callbacks can be expected to work correctly from interrupt + * handlers. + * * %false: Otherwise. */ static inline bool pm_runtime_is_irq_safe(struct device *dev) { @@ -348,17 +360,17 @@ static inline int pm_runtime_force_resume(struct device *dev) { return -ENXIO; } * autosuspend has been enabled for it). * * Return: - * * 0: Success. - * * -EINVAL: Runtime PM error. - * * -EACCES: Runtime PM disabled. - * * -EAGAIN: Runtime PM usage counter non-zero, Runtime PM status change - * ongoing or device not in %RPM_ACTIVE state. - * * -EBUSY: Runtime PM child_count non-zero. - * * -EPERM: Device PM QoS resume latency 0. - * * -EINPROGRESS: Suspend already in progress. - * * -ENOSYS: CONFIG_PM not enabled. - * Other values and conditions for the above values are possible as returned by - * Runtime PM idle and suspend callbacks. + * * %0: Success. + * * %-EINVAL: Runtime PM error. + * * %-EACCES: Runtime PM disabled. + * * %-EAGAIN: Runtime PM usage counter non-zero, Runtime PM status change + * ongoing or device not in %RPM_ACTIVE state. + * * %-EBUSY: Runtime PM child_count non-zero. + * * %-EPERM: Device PM QoS resume latency 0. + * * %-EINPROGRESS: Suspend already in progress. + * * %-ENOSYS: %CONFIG_PM not enabled. + * * Other values and conditions for the above values are possible as returned + * by Runtime PM idle and suspend callbacks. */ static inline int pm_runtime_idle(struct device *dev) { @@ -370,17 +382,17 @@ static inline int pm_runtime_idle(struct device *dev) * @dev: Target device. * * Return: - * * 1: Success; device was already suspended. - * * 0: Success. - * * -EINVAL: Runtime PM error. - * * -EACCES: Runtime PM disabled. - * * -EAGAIN: Runtime PM usage counter non-zero or Runtime PM status change - * ongoing. - * * -EBUSY: Runtime PM child_count non-zero. - * * -EPERM: Device PM QoS resume latency 0. - * * -ENOSYS: CONFIG_PM not enabled. - * Other values and conditions for the above values are possible as returned by - * Runtime PM suspend callbacks. + * * %1: Success; device was already suspended. + * * %0: Success. + * * %-EINVAL: Runtime PM error. + * * %-EACCES: Runtime PM disabled. + * * %-EAGAIN: Runtime PM usage counter non-zero or Runtime PM status change + * ongoing. + * * %-EBUSY: Runtime PM child_count non-zero. + * * %-EPERM: Device PM QoS resume latency 0. + * * %-ENOSYS: %CONFIG_PM not enabled. + * * Other values and conditions for the above values are possible as returned + * by Runtime PM suspend callbacks. */ static inline int pm_runtime_suspend(struct device *dev) { @@ -397,17 +409,17 @@ static inline int pm_runtime_suspend(struct device *dev) * engaging its "idle check" callback. * * Return: - * * 1: Success; device was already suspended. - * * 0: Success. - * * -EINVAL: Runtime PM error. - * * -EACCES: Runtime PM disabled. - * * -EAGAIN: Runtime PM usage counter non-zero or Runtime PM status change - * ongoing. - * * -EBUSY: Runtime PM child_count non-zero. - * * -EPERM: Device PM QoS resume latency 0. - * * -ENOSYS: CONFIG_PM not enabled. - * Other values and conditions for the above values are possible as returned by - * Runtime PM suspend callbacks. + * * %1: Success; device was already suspended. + * * %0: Success. + * * %-EINVAL: Runtime PM error. + * * %-EACCES: Runtime PM disabled. + * * %-EAGAIN: Runtime PM usage counter non-zero or Runtime PM status change + * ongoing. + * * %-EBUSY: Runtime PM child_count non-zero. + * * %-EPERM: Device PM QoS resume latency 0. + * * %-ENOSYS: %CONFIG_PM not enabled. + * * Other values and conditions for the above values are possible as returned + * by Runtime PM suspend callbacks. */ static inline int pm_runtime_autosuspend(struct device *dev) { @@ -418,6 +430,11 @@ static inline int pm_runtime_autosuspend(struct device *dev) /** * pm_runtime_resume - Resume a device synchronously. * @dev: Target device. + * + * Return: + * * %1: Success; @dev is already %RPM_ACTIVE. + * * %0: Success. + * * Error code on failure. */ static inline int pm_runtime_resume(struct device *dev) { @@ -432,15 +449,15 @@ static inline int pm_runtime_resume(struct device *dev) * asynchronously. * * Return: - * * 0: Success. - * * -EINVAL: Runtime PM error. - * * -EACCES: Runtime PM disabled. - * * -EAGAIN: Runtime PM usage counter non-zero, Runtime PM status change - * ongoing or device not in %RPM_ACTIVE state. - * * -EBUSY: Runtime PM child_count non-zero. - * * -EPERM: Device PM QoS resume latency 0. - * * -EINPROGRESS: Suspend already in progress. - * * -ENOSYS: CONFIG_PM not enabled. + * * %0: Success. + * * %-EINVAL: Runtime PM error. + * * %-EACCES: Runtime PM disabled. + * * %-EAGAIN: Runtime PM usage counter non-zero, Runtime PM status change + * ongoing or device not in %RPM_ACTIVE state. + * * %-EBUSY: Runtime PM child_count non-zero. + * * %-EPERM: Device PM QoS resume latency 0. + * * %-EINPROGRESS: Suspend already in progress. + * * %-ENOSYS: %CONFIG_PM not enabled. */ static inline int pm_request_idle(struct device *dev) { @@ -450,6 +467,11 @@ static inline int pm_request_idle(struct device *dev) /** * pm_request_resume - Queue up runtime-resume of a device. * @dev: Target device. + * + * Return: + * * %1: Success; @dev is already %RPM_ACTIVE. + * * %0: Success. + * * Error code on failure. */ static inline int pm_request_resume(struct device *dev) { @@ -465,16 +487,16 @@ static inline int pm_request_resume(struct device *dev) * equivalent pm_runtime_autosuspend() for @dev asynchronously. * * Return: - * * 1: Success; device was already suspended. - * * 0: Success. - * * -EINVAL: Runtime PM error. - * * -EACCES: Runtime PM disabled. - * * -EAGAIN: Runtime PM usage counter non-zero or Runtime PM status change - * ongoing. - * * -EBUSY: Runtime PM child_count non-zero. - * * -EPERM: Device PM QoS resume latency 0. - * * -EINPROGRESS: Suspend already in progress. - * * -ENOSYS: CONFIG_PM not enabled. + * * %1: Success; device was already suspended. + * * %0: Success. + * * %-EINVAL: Runtime PM error. + * * %-EACCES: Runtime PM disabled. + * * %-EAGAIN: Runtime PM usage counter non-zero or Runtime PM status change + * ongoing. + * * %-EBUSY: Runtime PM child_count non-zero. + * * %-EPERM: Device PM QoS resume latency 0. + * * %-EINPROGRESS: Suspend already in progress. + * * %-ENOSYS: %CONFIG_PM not enabled. */ static inline int pm_request_autosuspend(struct device *dev) { @@ -488,6 +510,11 @@ static inline int pm_request_autosuspend(struct device *dev) * * Bump up the runtime PM usage counter of @dev and queue up a work item to * carry out runtime-resume of it. + * + * Return: + * * %1: Success; @dev is already %RPM_ACTIVE. + * * %0: Success; runtime-resume was queued. + * * Error code on failure. */ static inline int pm_runtime_get(struct device *dev) { @@ -507,6 +534,11 @@ static inline int pm_runtime_get(struct device *dev) * Consider using pm_runtime_resume_and_get() instead of it, especially * if its return value is checked by the caller, as this is likely to result * in cleaner code. + * + * Return: + * * %1: Success; @dev is already %RPM_ACTIVE. + * * %0: Success. + * * Error code on failure. */ static inline int pm_runtime_get_sync(struct device *dev) { @@ -531,8 +563,11 @@ static inline int pm_runtime_get_active(struct device *dev, int rpmflags) * @dev: Target device. * * Resume @dev synchronously and if that is successful, increment its runtime - * PM usage counter. Return 0 if the runtime PM usage counter of @dev has been - * incremented or a negative error code otherwise. + * PM usage counter. + * + * Return: + * * %0: Success; @dev is active and its usage counter has been incremented. + * * Negative error code on failure; usage counter is unchanged. */ static inline int pm_runtime_resume_and_get(struct device *dev) { @@ -559,16 +594,16 @@ static inline void pm_runtime_put(struct device *dev) * equal to 0, queue up a work item for @dev like in pm_request_autosuspend(). * * Return: - * * 1: Success. Usage counter dropped to zero, but device was already suspended. - * * 0: Success. - * * -EINVAL: Runtime PM error. - * * -EACCES: Runtime PM disabled. - * * -EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status - * change ongoing. - * * -EBUSY: Runtime PM child_count non-zero. - * * -EPERM: Device PM QoS resume latency 0. - * * -EINPROGRESS: Suspend already in progress. - * * -ENOSYS: CONFIG_PM not enabled. + * * %1: Success. Usage counter dropped to zero, but device was already suspended. + * * %0: Success. + * * %-EINVAL: Runtime PM error. + * * %-EACCES: Runtime PM disabled. + * * %-EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status + * change ongoing. + * * %-EBUSY: Runtime PM child_count non-zero. + * * %-EPERM: Device PM QoS resume latency 0. + * * %-EINPROGRESS: Suspend already in progress. + * * %-ENOSYS: %CONFIG_PM not enabled. */ static inline int __pm_runtime_put_autosuspend(struct device *dev) { @@ -585,16 +620,16 @@ static inline int __pm_runtime_put_autosuspend(struct device *dev) * in pm_request_autosuspend(). * * Return: - * * 1: Success. Usage counter dropped to zero, but device was already suspended. - * * 0: Success. - * * -EINVAL: Runtime PM error. - * * -EACCES: Runtime PM disabled. - * * -EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status - * change ongoing. - * * -EBUSY: Runtime PM child_count non-zero. - * * -EPERM: Device PM QoS resume latency 0. - * * -EINPROGRESS: Suspend already in progress. - * * -ENOSYS: CONFIG_PM not enabled. + * * %1: Success. Usage counter dropped to zero, but device was already suspended. + * * %0: Success. + * * %-EINVAL: Runtime PM error. + * * %-EACCES: Runtime PM disabled. + * * %-EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status + * change ongoing. + * * %-EBUSY: Runtime PM child_count non-zero. + * * %-EPERM: Device PM QoS resume latency 0. + * * %-EINPROGRESS: Suspend already in progress. + * * %-ENOSYS: %CONFIG_PM not enabled. */ static inline int pm_runtime_put_autosuspend(struct device *dev) { @@ -662,17 +697,17 @@ DEFINE_GUARD_COND(pm_runtime_active_auto, _try_enabled, * if it returns an error code. * * Return: - * * 1: Success. Usage counter dropped to zero, but device was already suspended. - * * 0: Success. - * * -EINVAL: Runtime PM error. - * * -EACCES: Runtime PM disabled. - * * -EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status - * change ongoing. - * * -EBUSY: Runtime PM child_count non-zero. - * * -EPERM: Device PM QoS resume latency 0. - * * -ENOSYS: CONFIG_PM not enabled. - * Other values and conditions for the above values are possible as returned by - * Runtime PM suspend callbacks. + * * %1: Success. Usage counter dropped to zero, but device was already suspended. + * * %0: Success. + * * %-EINVAL: Runtime PM error. + * * %-EACCES: Runtime PM disabled. + * * %-EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status + * change ongoing. + * * %-EBUSY: Runtime PM child_count non-zero. + * * %-EPERM: Device PM QoS resume latency 0. + * * %-ENOSYS: %CONFIG_PM not enabled. + * * Other values and conditions for the above values are possible as returned + * by Runtime PM suspend callbacks. */ static inline int pm_runtime_put_sync(struct device *dev) { @@ -690,17 +725,17 @@ static inline int pm_runtime_put_sync(struct device *dev) * if it returns an error code. * * Return: - * * 1: Success. Usage counter dropped to zero, but device was already suspended. - * * 0: Success. - * * -EINVAL: Runtime PM error. - * * -EACCES: Runtime PM disabled. - * * -EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status - * change ongoing. - * * -EBUSY: Runtime PM child_count non-zero. - * * -EPERM: Device PM QoS resume latency 0. - * * -ENOSYS: CONFIG_PM not enabled. - * Other values and conditions for the above values are possible as returned by - * Runtime PM suspend callbacks. + * * %1: Success. Usage counter dropped to zero, but device was already suspended. + * * %0: Success. + * * %-EINVAL: Runtime PM error. + * * %-EACCES: Runtime PM disabled. + * * %-EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status + * change ongoing. + * * %-EBUSY: Runtime PM child_count non-zero. + * * %-EPERM: Device PM QoS resume latency 0. + * * %-ENOSYS: %CONFIG_PM not enabled. + * * Other values and conditions for the above values are possible as returned + * by Runtime PM suspend callbacks. */ static inline int pm_runtime_put_sync_suspend(struct device *dev) { @@ -721,18 +756,18 @@ static inline int pm_runtime_put_sync_suspend(struct device *dev) * if it returns an error code. * * Return: - * * 1: Success. Usage counter dropped to zero, but device was already suspended. - * * 0: Success. - * * -EINVAL: Runtime PM error. - * * -EACCES: Runtime PM disabled. - * * -EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status - * change ongoing. - * * -EBUSY: Runtime PM child_count non-zero. - * * -EPERM: Device PM QoS resume latency 0. - * * -EINPROGRESS: Suspend already in progress. - * * -ENOSYS: CONFIG_PM not enabled. - * Other values and conditions for the above values are possible as returned by - * Runtime PM suspend callbacks. + * * %1: Success. Usage counter dropped to zero, but device was already suspended. + * * %0: Success. + * * %-EINVAL: Runtime PM error. + * * %-EACCES: Runtime PM disabled. + * * %-EAGAIN: Runtime PM usage counter became non-zero or Runtime PM status + * change ongoing. + * * %-EBUSY: Runtime PM child_count non-zero. + * * %-EPERM: Device PM QoS resume latency 0. + * * %-EINPROGRESS: Suspend already in progress. + * * %-ENOSYS: %CONFIG_PM not enabled. + * * Other values and conditions for the above values are possible as returned + * by Runtime PM suspend callbacks. */ static inline int pm_runtime_put_sync_autosuspend(struct device *dev) { @@ -748,6 +783,10 @@ static inline int pm_runtime_put_sync_autosuspend(struct device *dev) * of it will be taken into account. * * It is not valid to call this function for devices with runtime PM enabled. + * + * Return: + * * %0: Success. + * * Error code on failure. */ static inline int pm_runtime_set_active(struct device *dev) { @@ -762,6 +801,10 @@ static inline int pm_runtime_set_active(struct device *dev) * dependencies of it will be taken into account. * * It is not valid to call this function for devices with runtime PM enabled. + * + * Return: + * * %0: Success. + * * Error code on failure. */ static inline int pm_runtime_set_suspended(struct device *dev) { -- cgit v1.2.3 From 4711357dd298594beac51de081d9ba4326a189e3 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 4 Sep 2026 14:12:07 -0700 Subject: PM: runtime: Improve set_{status,active,suspended} docs The set_active()/set_suspended() docs don't mention that they also clear the 'runtime_error' field. This is a very important note, since that's one key purpose for using them. Fix a typo in __pm_runtime_set_status() while we're at it. Signed-off-by: Brian Norris Link: https://patch.msgid.link/20260904141215.2.If02a538531ea004987c9a28a8d030ee9f71221cd@changeid Signed-off-by: Rafael J. Wysocki --- drivers/base/power/runtime.c | 4 ++-- include/linux/pm_runtime.h | 23 +++++++++++++++-------- 2 files changed, 17 insertions(+), 10 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 29e5ce69d04c..3c874b056af5 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -1296,7 +1296,7 @@ int pm_runtime_get_if_in_use(struct device *dev) EXPORT_SYMBOL_GPL(pm_runtime_get_if_in_use); /** - * __pm_runtime_set_status - Set runtime PM status of a device. + * __pm_runtime_set_status - Set runtime PM status of a device and clear errors. * @dev: Device to handle. * @status: New runtime PM status of the device. * @@ -1315,7 +1315,7 @@ EXPORT_SYMBOL_GPL(pm_runtime_get_if_in_use); * If @dev has any suppliers (as reflected by device links to them), and @status * is RPM_ACTIVE, they will be activated upfront and if the activation of one * of them fails, the status of @dev will be changed to RPM_SUSPENDED (instead - * of the @status value) and the suppliers will be deacticated on exit. The + * of the @status value) and the suppliers will be deactivated on exit. The * error returned by the failing supplier activation will be returned in that * case. */ diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index ab6a19a85880..1ffd9d5c3010 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -776,13 +776,18 @@ static inline int pm_runtime_put_sync_autosuspend(struct device *dev) } /** - * pm_runtime_set_active - Set runtime PM status to "active". + * pm_runtime_set_active - Set runtime PM status to "active" and clear errors. * @dev: Target device. * - * Set the runtime PM status of @dev to %RPM_ACTIVE and ensure that dependencies - * of it will be taken into account. + * Set the runtime PM status of @dev to %RPM_ACTIVE and ensure that its + * dependencies will be taken into account. Also clear the device's error + * status (@dev->power.runtime_error). * - * It is not valid to call this function for devices with runtime PM enabled. + * It is only valid to call this function if runtime PM is disabled or if + * @dev->power.runtime_error is set. + * + * This will fail if suppliers cannot be resumed, or if the parent is not in + * the correct state. * * Return: * * %0: Success. @@ -794,13 +799,15 @@ static inline int pm_runtime_set_active(struct device *dev) } /** - * pm_runtime_set_suspended - Set runtime PM status to "suspended". + * pm_runtime_set_suspended - Set runtime PM status to "suspended" and clear errors. * @dev: Target device. * - * Set the runtime PM status of @dev to %RPM_SUSPENDED and ensure that - * dependencies of it will be taken into account. + * Set the runtime PM status of @dev to %RPM_SUSPENDED and ensure that its + * dependencies will be taken into account. Also clear the device's error + * status (@dev->power.runtime_error). * - * It is not valid to call this function for devices with runtime PM enabled. + * It is only valid to call this function if runtime PM is disabled or if + * @dev->power.runtime_error is set. * * Return: * * %0: Success. -- cgit v1.2.3 From 3baf1652fde8e54754df0b8bc9a6014c1752383d Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 4 Sep 2026 14:12:08 -0700 Subject: PM: runtime: kerneldoc wording improvements In preparation for removing duplicate documentation from Documentation/power/runtime_pm.rst, borrow some of the useful wording from runtime_pm.rst, and update other language for clarity, ease of reading, and completeness. Other guiding principles in this change: * Try to highlight "core", as in, "functions that are not for driver use but are exported because the real entrypoints are inline functions" * Rework pm_runtime_barrier() docs significantly. More below. * Include some clarifying cross-references and recommendations for pm_runtime_put_sync{,_suspend,_autosuspend}() * Attempt to deemphasize some of the implementation details (e.g., "asynchronous" instead of "queue") * Try for more clear user-facing language. For example, "set up autosuspend" isn't quite clear whether we're configuring autosuspend, or if we're initiating an attempt to autosuspend (i.e., setting a timer). pm_runtime_barrier(): currently, we speak a lot about implementation details and sequences of events, but obscure the key point that it treats "pending resume" and "pending suspend" very differently -- I try to improve that. Signed-off-by: Brian Norris Link: https://patch.msgid.link/20260904141215.3.I3bdec7dcda46e1bee6d4f91530518fbe9c9096fd@changeid Signed-off-by: Rafael J. Wysocki --- drivers/base/power/runtime.c | 65 ++++++++++++++++-------------- include/linux/pm_runtime.h | 95 ++++++++++++++++++++++++-------------------- 2 files changed, 87 insertions(+), 73 deletions(-) (limited to 'include/linux') diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 3c874b056af5..bb008dfe85a1 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -1102,14 +1102,13 @@ static int rpm_drop_usage_count(struct device *dev) } /** - * __pm_runtime_idle - Entry point for runtime idle operations. + * __pm_runtime_idle - Core entry point for runtime idle operations. * @dev: Device to send idle notification for. * @rpmflags: Flag bits. * - * If the RPM_GET_PUT flag is set, decrement the device's usage count and - * return immediately if it is larger than zero (if it becomes negative, log a - * warning, increment it, and return an error). Then carry out an idle - * notification, either synchronous or asynchronous. + * Carry out an idle check for @dev, either synchronous or asynchronous. + * If %RPM_GET_PUT is set in @rpmflags, decrement the device's usage count + * first, proceeding with idle notification only if the counter drops to zero. * * This routine may be called in atomic context if the %RPM_ASYNC flag is set, * or if pm_runtime_irq_safe() has been called. @@ -1140,14 +1139,13 @@ int __pm_runtime_idle(struct device *dev, int rpmflags) EXPORT_SYMBOL_GPL(__pm_runtime_idle); /** - * __pm_runtime_suspend - Entry point for runtime put/suspend operations. + * __pm_runtime_suspend - Core entry point for runtime put/suspend operations. * @dev: Device to suspend. * @rpmflags: Flag bits. * - * If the RPM_GET_PUT flag is set, decrement the device's usage count and - * return immediately if it is larger than zero (if it becomes negative, log a - * warning, increment it, and return an error). Then carry out a suspend, - * either synchronous or asynchronous. + * Carry out a suspend operation for @dev, either synchronous or asynchronous. + * If %RPM_GET_PUT is set in @rpmflags, decrement the device's usage count + * first, proceeding with suspend only if the counter drops to zero. * * This routine may be called in atomic context if the %RPM_ASYNC flag is set, * or if pm_runtime_irq_safe() has been called. @@ -1178,12 +1176,13 @@ int __pm_runtime_suspend(struct device *dev, int rpmflags) EXPORT_SYMBOL_GPL(__pm_runtime_suspend); /** - * __pm_runtime_resume - Entry point for runtime resume operations. + * __pm_runtime_resume - Core entry point for runtime resume operations. * @dev: Device to resume. * @rpmflags: Flag bits. * - * If the RPM_GET_PUT flag is set, increment the device's usage count. Then - * carry out a resume, either synchronous or asynchronous. + * Carry out a runtime resume operation for @dev, either synchronous or + * asynchronous. If %RPM_GET_PUT is set in @rpmflags, increment the device's + * usage count first, then bring the device to %RPM_ACTIVE state. * * This routine may be called in atomic context if the %RPM_ASYNC flag is set, * or if pm_runtime_irq_safe() has been called. @@ -1277,17 +1276,15 @@ EXPORT_SYMBOL_GPL(pm_runtime_get_if_active); * pm_runtime_get_if_in_use - Conditionally bump up runtime PM usage counter. * @dev: Target device. * - * Increment the runtime PM usage counter of @dev if its runtime PM status is - * %RPM_ACTIVE and its runtime PM usage counter is greater than 0 or it is not - * ignoring children and its active child count is nonzero. 1 is returned in - * this case. - * - * If @dev is in a different state or it is not in use (that is, its usage - * counter is 0, or it is ignoring children, or its active child count is 0), - * 0 is returned. + * Increment the runtime PM usage counter of @dev if it is "in use." A device + * is considered in use if its runtime PM status is %RPM_ACTIVE and its runtime + * PM usage counter is greater than 0, or if it is not ignoring children and + * its active child count is nonzero. * - * -EINVAL is returned if runtime PM is disabled for the device, in which case - * also the usage counter of @dev is not updated. + * Return: + * * %-EINVAL: Runtime PM is disabled for @dev. The usage counter is not incremented. + * * %1: Success; usage counter is incremented. + * * %0: @dev was not in use; usage counter is not incremented. */ int pm_runtime_get_if_in_use(struct device *dev) { @@ -1471,11 +1468,13 @@ static void __pm_runtime_barrier(struct device *dev) * pm_runtime_barrier - Flush pending requests and wait for completions. * @dev: Device to handle. * - * Prevent the device from being suspended by incrementing its usage counter and - * if there's a pending resume request for the device, wake the device up. - * Next, make sure that all pending requests for the device have been flushed - * from pm_wq and wait for all runtime PM operations involving the device in - * progress to complete. + * If the device has a pending resume request, resume it synchronously. For all + * other request types, cancel any queued request, and wait for running + * operations to complete. + * + * Note that this is intentionally asymmetric, as it guarantees any queued + * asynchronous resume request will complete, but it may cancel asynchronous + * suspend requests. */ void pm_runtime_barrier(struct device *dev) { @@ -1559,8 +1558,16 @@ void __pm_runtime_disable(struct device *dev, bool check_resume) EXPORT_SYMBOL_GPL(__pm_runtime_disable); /** - * pm_runtime_enable - Enable runtime PM of a device. + * pm_runtime_enable - Enable runtime PM for a device. * @dev: Device to handle. + * + * Enable runtime PM transitions for @dev by decrementing its disable counter. + * Once the counter reaches zero, the PM core is permitted to execute runtime + * PM callbacks for @dev as power conditions change. + * + * Callers should ensure that the device's runtime PM status accurately reflects + * its physical hardware state (via pm_runtime_set_active() or + * pm_runtime_set_suspended()) before enabling runtime PM. */ void pm_runtime_enable(struct device *dev) { diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index 1ffd9d5c3010..322e3b17f987 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -352,11 +352,11 @@ static inline int pm_runtime_force_resume(struct device *dev) { return -ENXIO; } #endif /* CONFIG_PM_SLEEP */ /** - * pm_runtime_idle - Conditionally set up autosuspend of a device or suspend it. + * pm_runtime_idle - Conditionally initiate autosuspend of a device or suspend it. * @dev: Target device. * * Invoke the "idle check" callback of @dev and, depending on its return value, - * set up autosuspend of @dev or suspend it (depending on whether or not + * initiate autosuspend of @dev or suspend it (depending on whether or not * autosuspend has been enabled for it). * * Return: @@ -400,13 +400,13 @@ static inline int pm_runtime_suspend(struct device *dev) } /** - * pm_runtime_autosuspend - Update the last access time and set up autosuspend + * pm_runtime_autosuspend - Update the last access time and initiate autosuspend * of a device. * @dev: Target device. * - * First update the last access time, then set up autosuspend of @dev or suspend - * it (depending on whether or not autosuspend is enabled for it) without - * engaging its "idle check" callback. + * First update the last access time, then initiate autosuspend of @dev or + * suspend it (depending on whether or not autosuspend is enabled for it) + * without engaging its "idle check" callback. * * Return: * * %1: Success; device was already suspended. @@ -442,11 +442,11 @@ static inline int pm_runtime_resume(struct device *dev) } /** - * pm_request_idle - Queue up "idle check" execution for a device. + * pm_request_idle - Request an asynchronous idle check for a device. * @dev: Target device. * - * Queue up a work item to run an equivalent of pm_runtime_idle() for @dev - * asynchronously. + * Asynchronously request the PM core to evaluate whether @dev can be idled + * or suspended, invoking its ->runtime_idle() callback if provided. * * Return: * * %0: Success. @@ -465,9 +465,12 @@ static inline int pm_request_idle(struct device *dev) } /** - * pm_request_resume - Queue up runtime-resume of a device. + * pm_request_resume - Request an asynchronous runtime resume for a device. * @dev: Target device. * + * Asynchronously request the PM core to resume @dev to %RPM_ACTIVE state + * without modifying its usage counter. + * * Return: * * %1: Success; @dev is already %RPM_ACTIVE. * * %0: Success. @@ -479,12 +482,11 @@ static inline int pm_request_resume(struct device *dev) } /** - * pm_request_autosuspend - Update the last access time and queue up autosuspend - * of a device. + * pm_request_autosuspend - Update access time and request delayed suspension. * @dev: Target device. * - * Update the last access time of a device and queue up a work item to run an - * equivalent pm_runtime_autosuspend() for @dev asynchronously. + * Update the last access time of @dev and asynchronously request the PM core + * to suspend it after the autosuspend delay has elapsed. * * Return: * * %1: Success; device was already suspended. @@ -505,11 +507,11 @@ static inline int pm_request_autosuspend(struct device *dev) } /** - * pm_runtime_get - Bump up usage counter and queue up resume of a device. + * pm_runtime_get - Increment usage counter and request asynchronous resume. * @dev: Target device. * - * Bump up the runtime PM usage counter of @dev and queue up a work item to - * carry out runtime-resume of it. + * Increment the runtime PM usage counter of @dev and, if the device is + * currently suspended, asynchronously request the PM core to resume it. * * Return: * * %1: Success; @dev is already %RPM_ACTIVE. @@ -528,12 +530,10 @@ static inline int pm_runtime_get(struct device *dev) * Bump up the runtime PM usage counter of @dev and carry out runtime-resume of * it synchronously. * - * The possible return values of this function are the same as for - * pm_runtime_resume() and the runtime PM usage counter of @dev remains - * incremented in all cases, even if it returns an error code. - * Consider using pm_runtime_resume_and_get() instead of it, especially - * if its return value is checked by the caller, as this is likely to result - * in cleaner code. + * Note that the runtime PM usage counter of @dev remains incremented in all + * cases, even if it returns an error code. Consider using + * pm_runtime_resume_and_get() instead, especially if the return value is + * checked by the caller, as this is likely to result in cleaner code. * * Return: * * %1: Success; @dev is already %RPM_ACTIVE. @@ -575,11 +575,12 @@ static inline int pm_runtime_resume_and_get(struct device *dev) } /** - * pm_runtime_put - Drop device usage counter and queue up "idle check" if 0. + * pm_runtime_put - Drop device usage counter and request asynchronous idle check. * @dev: Target device. * - * Decrement the runtime PM usage counter of @dev and if it turns out to be - * equal to 0, queue up a work item for @dev like in pm_request_idle(). + * Decrement the runtime PM usage counter of @dev. If the counter reaches zero + * and the device has no active child dependencies, asynchronously request the + * PM core to idle or suspend the device. */ static inline void pm_runtime_put(struct device *dev) { @@ -611,13 +612,13 @@ static inline int __pm_runtime_put_autosuspend(struct device *dev) } /** - * pm_runtime_put_autosuspend - Update the last access time of a device, drop - * its usage counter and queue autosuspend if the usage counter becomes 0. + * pm_runtime_put_autosuspend - Update the last access time, drop usage counter + * and request autosuspend. * @dev: Target device. * - * Update the last access time of @dev, decrement runtime PM usage counter of - * @dev and if it turns out to be equal to 0, queue up a work item for @dev like - * in pm_request_autosuspend(). + * Update the last access time of @dev and decrement its runtime PM usage + * counter. If the counter drops to zero, asynchronously request the PM core to + * suspend the device once its autosuspend delay has elapsed. * * Return: * * %1: Success. Usage counter dropped to zero, but device was already suspended. @@ -688,10 +689,12 @@ DEFINE_GUARD_COND(pm_runtime_active_auto, _try_enabled, * pm_runtime_put_sync - Drop device usage counter and run "idle check" if 0. * @dev: Target device. * - * Decrement the runtime PM usage counter of @dev and if it turns out to be - * equal to 0, invoke the "idle check" callback of @dev and, depending on its - * return value, set up autosuspend of @dev or suspend it (depending on whether - * or not autosuspend has been enabled for it). + * Decrement the runtime PM usage counter of @dev. If the counter drops to zero, + * synchronously evaluate and trigger idle/suspend handling. + * + * Note that this does not update the last access time, but it does respect + * existing autosuspend timers. If @dev uses autosuspend, consider using + * pm_runtime_put_sync_autosuspend() or pm_runtime_put_sync_suspend() instead. * * The runtime PM usage counter of @dev remains decremented in all cases, even * if it returns an error code. @@ -718,8 +721,12 @@ static inline int pm_runtime_put_sync(struct device *dev) * pm_runtime_put_sync_suspend - Drop device usage counter and suspend if 0. * @dev: Target device. * - * Decrement the runtime PM usage counter of @dev and if it turns out to be - * equal to 0, carry out runtime-suspend of @dev synchronously. + * Decrement the runtime PM usage counter of @dev. If the counter drops to zero, + * suspend the device synchronously. + * + * This API differs from pm_runtime_put_sync() and + * pm_runtime_put_sync_autosuspend() in that it ignores any outstanding + * autosuspend delays. * * The runtime PM usage counter of @dev remains decremented in all cases, even * if it returns an error code. @@ -747,10 +754,11 @@ static inline int pm_runtime_put_sync_suspend(struct device *dev) * drop device usage counter and autosuspend if 0. * @dev: Target device. * - * Update the last access time of @dev, decrement the runtime PM usage counter - * of @dev and if it turns out to be equal to 0, set up autosuspend of @dev or - * suspend it synchronously (depending on whether or not autosuspend has been - * enabled for it). + * Update the last access time of @dev and decrement its runtime PM usage + * counter. If the counter drops to zero, synchronously suspend the device (or + * schedule autosuspend if the delay has not elapsed). + * + * Prefer this API over pm_runtime_put_sync() for devices that use autosuspend. * * The runtime PM usage counter of @dev remains decremented in all cases, even * if it returns an error code. @@ -827,9 +835,8 @@ static inline int pm_runtime_set_suspended(struct device *dev) * * If the counter is zero when this function runs and there is a pending runtime * resume request for @dev, it will be resumed. If the counter is still zero at - * that point, all of the pending runtime PM requests for @dev will be canceled - * and all runtime PM operations in progress involving it will be waited for to - * complete. + * that point, this function cancels all pending runtime PM requests for @dev + * and waits for its runtime PM operations to complete (if any). * * For each invocation of this function for @dev, there must be a matching * pm_runtime_enable() call, so that runtime PM is eventually enabled for it -- cgit v1.2.3 From 6881d8de92c70783fdc934024edeaa48cf6d8baa Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 4 Sep 2026 14:12:10 -0700 Subject: PM: core: Document struct dev_pm_info with kerneldoc Documentation/power/runtime_pm.rst includes several descriptions of dev_pm_info fields, but many of them are wrong these days, as the types or behaviors have changed. This is a prime reason for keeping docs closer to the code where possible. Adapt and rewrite some of these descriptions, and add them to include/linux/pm.h directly. Then pull these docs into the generated HTML. Tested with `make htmldocs`. Signed-off-by: Brian Norris Link: https://patch.msgid.link/20260904141215.5.Ib0272869f8b1178426106d911441c449ac299048@changeid Signed-off-by: Rafael J. Wysocki --- Documentation/power/runtime_pm.rst | 101 ++----------------------------------- include/linux/pm.h | 93 ++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 96 deletions(-) (limited to 'include/linux') diff --git a/Documentation/power/runtime_pm.rst b/Documentation/power/runtime_pm.rst index 380dad7590a9..39fdeeda7a1e 100644 --- a/Documentation/power/runtime_pm.rst +++ b/Documentation/power/runtime_pm.rst @@ -203,103 +203,12 @@ rules: 3. Runtime PM Device Fields =========================== -The following device runtime PM fields are present in 'struct dev_pm_info', as -defined in include/linux/pm.h: +Device PM fields are found in 'struct dev_pm_info', as defined in +include/linux/pm.h. Many of those fields track runtime PM configuration and +state. - `struct timer_list suspend_timer;` - - timer used for scheduling (delayed) suspend and autosuspend requests - - `unsigned long timer_expires;` - - timer expiration time, in jiffies (if this is different from zero, the - timer is running and will expire at that time, otherwise the timer is not - running) - - `struct work_struct work;` - - work structure used for queuing up requests (i.e. work items in pm_wq) - - `wait_queue_head_t wait_queue;` - - wait queue used if any of the helper functions needs to wait for another - one to complete - - `spinlock_t lock;` - - lock used for synchronization - - `atomic_t usage_count;` - - the usage counter of the device - - `atomic_t child_count;` - - the count of 'active' children of the device - - `unsigned int ignore_children;` - - if set, the value of child_count is ignored (but still updated) - - `unsigned int disable_depth;` - - used for disabling the helper functions (they work normally if this is - equal to zero); the initial value of it is 1 (i.e. runtime PM is - initially disabled for all devices) - - `int runtime_error;` - - if set, there was a fatal error (one of the callbacks returned error code - as described in Section 2), so the helper functions will not work until - this flag is cleared; this is the error code returned by the failing - callback - - `unsigned int idle_notification;` - - if set, ->runtime_idle() is being executed - - `unsigned int request_pending;` - - if set, there's a pending request (i.e. a work item queued up into pm_wq) - - `enum rpm_request request;` - - type of request that's pending (valid if request_pending is set) - - `unsigned int deferred_resume;` - - set if ->runtime_resume() is about to be run while ->runtime_suspend() is - being executed for that device and it is not practical to wait for the - suspend to complete; means "start a resume as soon as you've suspended" - - `enum rpm_status runtime_status;` - - the runtime PM status of the device; this field's initial value is - RPM_SUSPENDED, which means that each device is initially regarded by the - PM core as 'suspended', regardless of its real hardware status - - `enum rpm_status last_status;` - - the last runtime PM status of the device captured before disabling runtime - PM for it (invalid initially and when disable_depth is 0) - - `unsigned int runtime_auto;` - - if set, indicates that the user space has allowed the device driver to - power manage the device at run time via the /sys/devices/.../power/control - `interface;` it may only be modified with the help of the - pm_runtime_allow() and pm_runtime_forbid() helper functions - - `unsigned int no_callbacks;` - - indicates that the device does not use the runtime PM callbacks (see - Section 8); it may be modified only by the pm_runtime_no_callbacks() - helper function - - `unsigned int irq_safe;` - - indicates that the ->runtime_suspend() and ->runtime_resume() callbacks - will be invoked with the spinlock held and interrupts disabled - - `unsigned int use_autosuspend;` - - indicates that the device's driver supports delayed autosuspend (see - Section 9); it may be modified only by the - pm_runtime{_dont}_use_autosuspend() helper functions - - `unsigned int timer_autosuspends;` - - indicates that the PM core should attempt to carry out an autosuspend - when the timer expires rather than a normal suspend - - `int autosuspend_delay;` - - the delay time (in milliseconds) to be used for autosuspend - - `unsigned long last_busy;` - - the time (in jiffies) when the pm_runtime_mark_last_busy() helper - function was last called for this device; used in calculating inactivity - periods for autosuspend - -All of the above fields are members of the 'power' member of 'struct device'. +.. kernel-doc:: include/linux/pm.h + :identifiers: dev_pm_info 4. Runtime PM Device Helper Functions ===================================== diff --git a/include/linux/pm.h b/include/linux/pm.h index afcaaa37a812..ef3f1310e749 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -663,6 +663,99 @@ struct pm_subsys_data { #define DPM_FLAG_SMART_SUSPEND BIT(2) #define DPM_FLAG_MAY_SKIP_RESUME BIT(3) +/** + * struct dev_pm_info - Device power management information. + * + * @power_state: Legacy power state (mostly unused in modern kernels). + * @can_wakeup: Device is capable of generating wakeup signals. + * @async_suspend: Device can be suspended and resumed asynchronously. + * @in_dpm_list: Device is on the dpm_list. + * @is_prepared: Device's ->prepare() callback has run successfully. + * @is_suspended: Device is suspended during a system sleep transition. + * @is_noirq_suspended: Device's noirq suspend callback has run successfully. + * @is_late_suspended: Device's late suspend callback has run successfully. + * @no_pm: Device does not participate in power management transitions. + * @early_init: Device was initialized before standard PM initialization. + * @direct_complete: Device can skip suspend/resume callbacks and remain + * runtime-suspended during system sleep. + * @driver_flags: Driver flags (e.g. %DPM_FLAG_SMART_SUSPEND) set at probe time. + * @lock: Spinlock used for synchronizing PM state transitions and runtime PM + * operations. + * @entry: List head for device power management lists. + * @completion: Completion for synchronization during asynchronous system + * suspend/resume. + * @wakeup: Wakeup source object associated with the device. + * @work_in_progress: Asynchronous PM operation in progress. + * @wakeup_path: Device is in the wakeup path or can wake the system up. + * @syscore: Device participates in syscore power management operations. + * @no_pm_callbacks: Device has no PM callbacks; handled by parent or subsystem. + * @smart_suspend: Driver requested smart-suspend behavior. + * @must_resume: Device must be resumed during system resume. + * @may_skip_resume: Set by subsystems to indicate driver resume callbacks may + * be skipped. + * @out_band_wakeup: Out-of-band wakeup is supported. + * @strict_midlayer: Middle layer code does not want callbacks invoked via + * pm_runtime_force_suspend() / pm_runtime_force_resume(). + * @should_wakeup: Wakeup flag when system sleep is not enabled. + * @suspend_timer: High-resolution timer used for scheduling delayed runtime + * suspend and autosuspend requests. + * @timer_expires: Timer expiration time in nanoseconds monotonic time + * (runtime PM). + * @work: Work structure used for queuing up requests into pm_wq (runtime PM). + * @wait_queue: Wait queue used if any helper functions need to wait for another + * state change to complete (runtime PM). + * @wakeirq: Dedicated wakeup interrupt for the device. + * @usage_count: Device runtime PM usage counter. + * @child_count: Count of active children of the device (runtime PM). + * @disable_depth: Disable counter for runtime PM (runtime PM is enabled when + * this is 0; initial value is 1). + * @idle_notification: Set if ->runtime_idle() is being executed. + * @request_pending: Set if a work item is queued into pm_wq (runtime PM). + * @deferred_resume: Set if ->runtime_resume() should run as soon as + * ->runtime_suspend() completes. + * @needs_force_resume: Indicates the device was forced into suspend by + * pm_runtime_force_suspend() and must be resumed by + * pm_runtime_force_resume(). + * @runtime_auto: User space has allowed the driver to power manage the device + * at runtime via sysfs control attribute; also can be set by + * pm_runtime_allow() or pm_runtime_forbid(). + * @ignore_children: If set, the value of child_count is ignored for runtime + * suspend and idle decisions. + * @no_callbacks: Indicates the device does not use runtime PM callbacks. + * @irq_safe: Indicates runtime PM callbacks will be invoked with the spinlock + * held and interrupts disabled. + * @use_autosuspend: Indicates the device driver supports delayed runtime + * autosuspend. + * @timer_autosuspends: Indicates the runtime PM core should attempt an + * autosuspend rather than a normal suspend when the timer expires. + * @memalloc_noio: Indicates memory allocation during runtime PM transitions + * must avoid I/O (GFP_NOIO). + * @links_count: Number of device links that require runtime PM coordination. + * @request: Type of pending runtime PM request (valid if request_pending is + * set). + * @runtime_status: Runtime PM status of the device. + * @last_status: Last status captured before disabling runtime PM, or + * %RPM_BLOCKED / %RPM_INVALID. + * @runtime_error: Fatal error code returned by a failing callback, blocking + * helpers until cleared. + * @autosuspend_delay: Delay time in milliseconds to be used for runtime + * autosuspend. + * @last_busy: Timestamp in nanoseconds when pm_runtime_mark_last_busy() was + * last called. Used in calculating inactivity periods for autosuspend. + * @active_time: Accumulated time in nanoseconds spent in %RPM_ACTIVE state. + * @suspended_time: Accumulated time in nanoseconds spent in %RPM_SUSPENDED + * state. + * @accounting_timestamp: Timestamp in nanoseconds of the last runtime PM state + * accounting update. + * @subsys_data: Subsystem-specific power management data. + * @set_latency_tolerance: Callback for setting latency tolerance. + * @qos: Per-device PM Quality of Service (QoS) constraints. + * @detach_power_off: Indicates device should be detached from PM domain on + * power off. + * + * Device power management information stored in the "power" member of struct + * device. + */ struct dev_pm_info { pm_message_t power_state; bool can_wakeup:1; -- cgit v1.2.3 From e7280ab196ba4bcef6d3f6ee860bf0d2c8e96e51 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 21 Sep 2026 21:45:59 +0200 Subject: ACPI: bus: Use acpi/acpi_bus.h without CONFIG_ACPI Corrently acpi/acpi_bus.h is included in linux/acpi.h only if CONFIG_ACPI is set, but it contains declarations that are useful otherwise too. For consistency, modify linux/acpi.h to always include acpi/acpi_bus.h and update the latter to avoid exposing too much when CONFIG_ACPI is not set. Since acpi_has_method() is called from some code build when CONFIG_ACPI is unset, add a stub for it to the !CONFIG_ACPI block in acpi/acpi_bus.h. Signed-off-by: Rafael J. Wysocki Reviewed-by: Sudeep Holla Link: https://patch.msgid.link/3717753.iIbC2pHGDl@rafael.j.wysocki --- include/acpi/acpi_bus.h | 12 ++++++++---- include/linux/acpi.h | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index a10a591c18b2..32837f507f40 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -9,6 +9,8 @@ #ifndef __ACPI_BUS_H__ #define __ACPI_BUS_H__ +#ifdef CONFIG_ACPI + #include #include #include @@ -58,7 +60,6 @@ bool acpi_dock_match(acpi_handle handle); bool acpi_check_dsm(acpi_handle handle, const guid_t *guid, u64 rev, u64 funcs); union acpi_object *acpi_evaluate_dsm(acpi_handle handle, const guid_t *guid, u64 rev, u64 func, union acpi_object *argv4); -#ifdef CONFIG_ACPI bool acpi_get_physical_device_location(acpi_handle handle, struct acpi_pld_info **pld); @@ -77,7 +78,6 @@ acpi_evaluate_dsm_typed(acpi_handle handle, const guid_t *guid, u64 rev, return obj; } -#endif #define ACPI_INIT_DSM_ARGV4(cnt, eles) \ { \ @@ -90,8 +90,6 @@ bool acpi_dev_found(const char *hid); bool acpi_dev_present(const char *hid, const char *uid, s64 hrv); bool acpi_reduced_hardware(void); -#ifdef CONFIG_ACPI - struct proc_dir_entry; #define ACPI_BUS_FILE_ROOT "acpi" @@ -942,8 +940,14 @@ int acpi_wait_for_acpi_ipmi(void); int acpi_scan_add_dep(acpi_handle handle, struct acpi_handle_list *dep_devices); u32 arch_acpi_add_auto_dep(acpi_handle handle); + #else /* CONFIG_ACPI */ +static inline bool acpi_has_method(acpi_handle handle, char *name) +{ + return false; +} + static inline struct device *acpi_bus_get_primary_device(struct acpi_device *adev) { return NULL; diff --git a/include/linux/acpi.h b/include/linux/acpi.h index ddacac812094..ba5234bd93a2 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -25,6 +25,7 @@ struct irq_domain_ops; #define _LINUX #endif #include +#include #include #ifdef CONFIG_ACPI @@ -35,7 +36,6 @@ struct irq_domain_ops; #include #include -#include #include #include #include -- cgit v1.2.3 From 7a4c8ddba1dcf7c63b329d81de1d494188e5d2b0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 21 Sep 2026 21:49:49 +0200 Subject: platform/x86: apple-gmux: Switch to use acpi_bus_get_primary_device() Replace acpi_get_first_physical_node() that is slated for removal with acpi_bus_get_primary_device() that takes a reference to the device it is about to return. This addresses a potential use-after-free that may occur if the device returned by acpi_get_first_physical_node() is removed right after dropping its ACPI companion's physical_node_lock in that function. Signed-off-by: Rafael J. Wysocki Reviewed-by: Hans de Goede Link: https://patch.msgid.link/2287208.Mh6RI2rZIc@rafael.j.wysocki --- include/linux/apple-gmux.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/apple-gmux.h b/include/linux/apple-gmux.h index 206d97ffda79..d7939c3a08fd 100644 --- a/include/linux/apple-gmux.h +++ b/include/linux/apple-gmux.h @@ -109,7 +109,7 @@ static inline bool apple_gmux_detect(struct pnp_dev *pnp_dev, enum apple_gmux_ty if (!adev) return false; - dev = get_device(acpi_get_first_physical_node(adev)); + dev = acpi_bus_get_primary_device(adev); acpi_dev_put(adev); if (!dev) return false; -- cgit v1.2.3 From b9026ef6189ef44b32b4163431c8666be3cbd881 Mon Sep 17 00:00:00 2001 From: Lalit Shankar Chowdhury Date: Mon, 21 Sep 2026 08:14:11 +0000 Subject: ACPI: WMI: use IS_ENABLED() to simplify built-in or module check Replace the remaining built-in/module check for CONFIG_ACPI_WMI with IS_ENABLED() macro. Signed-off-by: Lalit Shankar Chowdhury Reviewed-by: Armin Wolf [ rjw: Subject tweaks ] Link: https://patch.msgid.link/20260921081411.4819-1-lalitshankarch@gmail.com Signed-off-by: Rafael J. Wysocki --- include/linux/acpi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/acpi.h b/include/linux/acpi.h index ddacac812094..b590f520dc57 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -434,7 +434,7 @@ extern acpi_handle ec_get_handle(void); extern bool acpi_is_pnp_device(struct acpi_device *); -#if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE) +#if IS_ENABLED(CONFIG_ACPI_WMI) typedef void (*wmi_notify_handler) (union acpi_object *data, void *context); -- 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/linux') 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 57c59c0bda8b19d8cbb877f61dbc8372e5f97749 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 25 Sep 2026 11:23:35 +0200 Subject: driver core/ACPI: Introduce companion_bus_register() The ACPI bus type does not allow drivers to be matched to devices, so the sysfs attributes related to drivers created for it are useless and their existence is confusing. Moreover, it is better to prevent drivers from being registered and looked up for a bus like that. To allow skipping the creation of those sysfs attributes and preventing driver registration and lookup for the ACPI bus type, introduce a "companion" bus type concept and add a special registration function for registering "companion" bus types, companion_bus_register(). The "drivers" directory under the ACPI bus type is still needed because there are versions of systemd that depend on it [1]. Link: https://lore.kernel.org/linux-acpi/SN6PR02MB41575266A4580339E186E5D9D4812@SN6PR02MB4157.namprd02.prod.outlook.com/ [1] Signed-off-by: Rafael J. Wysocki Acked-by: Greg Kroah-Hartman Reviewed-by: Danilo Krummrich Tested-by: Michael Kelley Reviewed-by: Michael Kelley [ rjw: Add comment regarding drivers_kset creation in bus_register_internal() ] Link: https://patch.msgid.link/12985239.O9o76ZdvQC@rafael.j.wysocki Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 8 +----- drivers/base/base.h | 2 ++ drivers/base/bus.c | 67 +++++++++++++++++++++++++++++++++++++--------- include/linux/device/bus.h | 1 + 4 files changed, 58 insertions(+), 20 deletions(-) (limited to 'include/linux') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 808c6746be14..48f0b4809f94 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -1120,11 +1120,6 @@ EXPORT_SYMBOL_GPL(acpi_driver_match_device); ACPI Bus operations -------------------------------------------------------------------------- */ -static int acpi_bus_match(struct device *dev, const struct device_driver *drv) -{ - return 0; -} - static int acpi_device_uevent(const struct device *dev, struct kobj_uevent_env *env) { return __acpi_device_uevent_modalias(to_acpi_device(dev), env); @@ -1132,7 +1127,6 @@ static int acpi_device_uevent(const struct device *dev, struct kobj_uevent_env * const struct bus_type acpi_bus_type = { .name = "acpi", - .match = acpi_bus_match, .uevent = acpi_device_uevent, }; @@ -1451,7 +1445,7 @@ static int __init acpi_bus_init(void) */ acpi_root_dir = proc_mkdir(ACPI_BUS_FILE_ROOT, NULL); - result = bus_register(&acpi_bus_type); + result = companion_bus_register(&acpi_bus_type); if (!result) return 0; diff --git a/drivers/base/base.h b/drivers/base/base.h index a5b7abc10ff0..21c7d244f8aa 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -27,6 +27,7 @@ * @drivers_autoprobe: gate whether new devices are automatically attached to * registered drivers, or new drivers automatically attach * to existing devices. + * @no_drivers: gate whether drivers can be registered. * @bus: pointer back to the struct bus_type that this structure is associated * with. * @dev_root: Default device to use as the parent. @@ -51,6 +52,7 @@ struct subsys_private { struct klist klist_drivers; struct blocking_notifier_head bus_notifier; unsigned int drivers_autoprobe:1; + unsigned int no_drivers:1; const struct bus_type *bus; struct device *dev_root; diff --git a/drivers/base/bus.c b/drivers/base/bus.c index d17bd91490ee..d89333806a4e 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -738,6 +738,11 @@ int bus_add_driver(struct device_driver *drv) if (!sp) return -EINVAL; + if (sp->no_drivers) { + error = -ENXIO; + goto out_put_bus; + } + /* * Reference in sp is now incremented and will be dropped when * the driver is removed from the bus @@ -930,15 +935,7 @@ static ssize_t bus_uevent_store(const struct bus_type *bus, static struct bus_attribute bus_attr_uevent = __ATTR(uevent, 0200, NULL, bus_uevent_store); -/** - * bus_register - register a driver-core subsystem - * @bus: bus to register - * - * Once we have that, we register the bus with the kobject - * infrastructure, then register the children subsystems it has: - * the devices and drivers that belong to the subsystem. - */ -int bus_register(const struct bus_type *bus) +static int bus_register_internal(const struct bus_type *bus, bool use_drivers) { int retval; struct subsys_private *priv; @@ -960,7 +957,8 @@ int bus_register(const struct bus_type *bus) bus_kobj->kset = bus_kset; bus_kobj->ktype = &bus_ktype; - priv->drivers_autoprobe = 1; + priv->drivers_autoprobe = use_drivers; + priv->no_drivers = !use_drivers; retval = kset_register(&priv->subsys); if (retval) @@ -976,6 +974,10 @@ int bus_register(const struct bus_type *bus) goto bus_devices_fail; } + /* + * Create the drivers kset even if use_drivers is unset to prevent some + * older versions of systemd from failing. + */ priv->drivers_kset = kset_create_and_add("drivers", NULL, bus_kobj); if (!priv->drivers_kset) { retval = -ENOMEM; @@ -989,9 +991,11 @@ int bus_register(const struct bus_type *bus) klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); klist_init(&priv->klist_drivers, NULL, NULL); - retval = add_probe_files(bus); - if (retval) - goto bus_probe_files_fail; + if (use_drivers) { + retval = add_probe_files(bus); + if (retval) + goto bus_probe_files_fail; + } retval = sysfs_create_groups(bus_kobj, bus->bus_groups); if (retval) @@ -1016,8 +1020,40 @@ out: kfree(priv); return retval; } + +/** + * bus_register - register a driver-core subsystem + * @bus: bus to register + * + * Once we have that, we register the bus with the kobject + * infrastructure, then register the children subsystems it has: + * the devices and drivers that belong to the subsystem. + */ +int bus_register(const struct bus_type *bus) +{ + return bus_register_internal(bus, true); +} EXPORT_SYMBOL_GPL(bus_register); +/** + * companion_bus_register - register a companion bus type + * @bus: companion bus to register + * + * A companion bus is a bus without drivers. Devices that belong to it can be + * bound to other devices as their "companions" and represent interfaces that + * can be used by the drivers of those other devices. They may also be used for + * the enumeration of those other devices. + * + * The ACPI bus is a specific example of a companion bus. + * + * Registering a companion bus is like registering a regular bus except that it + * skips the creation of sysfs interfaces related to drivers for @bus. + */ +int companion_bus_register(const struct bus_type *bus) +{ + return bus_register_internal(bus, false); +} + /** * bus_unregister - remove a bus from the system * @bus: bus. @@ -1415,6 +1451,11 @@ struct device_driver *driver_find(const char *name, const struct bus_type *bus) if (!sp) return NULL; + if (sp->no_drivers) { + subsys_put(sp); + return NULL; + } + k = kset_find_obj(sp->drivers_kset, name); subsys_put(sp); if (!k) diff --git a/include/linux/device/bus.h b/include/linux/device/bus.h index a38f7229b8f4..89e156b9acb5 100644 --- a/include/linux/device/bus.h +++ b/include/linux/device/bus.h @@ -113,6 +113,7 @@ struct bus_type { bool need_parent_lock; }; +int __must_check companion_bus_register(const struct bus_type *bus); int __must_check bus_register(const struct bus_type *bus); void bus_unregister(const struct bus_type *bus); -- cgit v1.2.3 From 1a58c47fae2a3982b38ec6348c739a7c60833189 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 11 Sep 2026 09:47:05 -0700 Subject: PCI/AER: Map a raw AER Capability image field by field struct aer_capability_regs is not the hardware layout: the embedded struct pcie_tlp_log spans 60 bytes where the Header Log it stands in for is 16, so a flat copy misplaces everything behind it. extlog_print_pcie(), ghes_handle_aer() and cxl_rch_get_aer_info() work around that by stopping at the Header Log, dropping everything past offset 44. Flit mode is never decoded either: the Flit bit and Logged TLP Size sit at offset 0x18, unread, so the Flit DWORDs at 0x38 are lost and the log prints as non-Flit. Add aer_cap_regs_unpack() to map the registers individually, taking the TLP Log layout from the Flit bit as pcie_read_tlp_log() does. Clamp the logged length: Logged TLP Size is 5 bits wide, so an untrusted value reaches 31 where dw[] holds 14 and pcie_print_tlp_log() walks header_len unbounded. Take the image little-endian, as both sources are: CPER by definition, PCIe registers on the wire. Read it with get_unaligned_le32(), since a CPER section sits wherever firmware put it, and take the two source IDs out of the Error Source Identification register by bit position rather than byte offset. cxl_rch_get_aer_info() uses readl(), so it hands back __le32. Convert all three callers. cxl_rch_get_aer_info() now reads the whole MMIO block, so size its ioremap by the hardware registers (96 bytes) rather than by sizeof(struct aer_capability_regs) (100). Shrinking the mapping is safe: the read it replaces stopped at 44 bytes. Reported-by: sashiko-bot@kernel.org Closes: https://sashiko.dev/#/patchset/20260904172337.1409775-1-dave.jiang@intel.com?part=5 Link: https://lore.kernel.org/linux-cxl/CAJZ5v0hDv11cPuztPZsaDd7uwD_49KznJy=tzuRO+dZc=CnAEQ@mail.gmail.com/ Assisted-by: LLM Signed-off-by: Dave Jiang Reviewed-by: Jonathan Cameron Link: https://patch.msgid.link/20260911164705.841407-1-dave.jiang@intel.com Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_extlog.c | 14 +------- drivers/acpi/apei/ghes.c | 15 +------- drivers/cxl/core/ras_rch.c | 27 +++++--------- drivers/pci/pcie/tlp.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/aer.h | 9 +++++ 5 files changed, 107 insertions(+), 46 deletions(-) (limited to 'include/linux') diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c index 9e61354a807b..bf5f7b1a9aea 100644 --- a/drivers/acpi/acpi_extlog.c +++ b/drivers/acpi/acpi_extlog.c @@ -156,19 +156,7 @@ static void extlog_print_pcie(struct cper_sec_pcie *pcie_err, aer_severity = cper_severity_to_aer(severity); - /* - * struct pcie_tlp_log is larger than the hardware layout, so aer_info - * only maps onto the struct up to the four Header Log DWORDs. Copy that - * much, then place the TLP Prefix Log from where the hardware keeps it. - * Everything else stays zero: nothing reads root_command, root_status or - * the error source IDs, and header_len and flit are software-only. - */ - memcpy(&aer_regs, pcie_err->aer_info, - offsetof(struct aer_capability_regs, header_log) + - PCIE_STD_NUM_TLP_HEADERLOG * sizeof(u32)); - memcpy(aer_regs.header_log.prefix, - pcie_err->aer_info + PCI_ERR_PREFIX_LOG, - sizeof(aer_regs.header_log.prefix)); + aer_cap_regs_unpack(&aer_regs, pcie_err->aer_info, sizeof(pcie_err->aer_info)); domain = pcie_err->device_id.segment; bus = pcie_err->device_id.bus; diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 08c985e729d6..ade1cc8c9f8d 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -668,20 +668,7 @@ static void ghes_handle_aer(struct acpi_hest_generic_data *gdata) if (!aer_info) return; - /* - * Map aer_info onto the struct as extlog_print_pcie() does: - * copy up to the four Header Log DWORDs, then place the TLP - * Prefix Log from where the hardware keeps it. The rest stays - * zero, so firmware cannot drive the pcie_print_tlp_log() loop - * over dw[] out of bounds. - */ - memset(aer_info, 0, sizeof(struct aer_capability_regs)); - memcpy(aer_info, pcie_err->aer_info, - offsetof(struct aer_capability_regs, header_log) + - PCIE_STD_NUM_TLP_HEADERLOG * sizeof(u32)); - memcpy(aer_info->header_log.prefix, - pcie_err->aer_info + PCI_ERR_PREFIX_LOG, - sizeof(aer_info->header_log.prefix)); + aer_cap_regs_unpack(aer_info, pcie_err->aer_info, sizeof(pcie_err->aer_info)); aer_recover_queue(pcie_err->device_id.segment, pcie_err->device_id.bus, diff --git a/drivers/cxl/core/ras_rch.c b/drivers/cxl/core/ras_rch.c index e0e01aa5eba6..50abbdc80722 100644 --- a/drivers/cxl/core/ras_rch.c +++ b/drivers/cxl/core/ras_rch.c @@ -19,7 +19,7 @@ void cxl_dport_map_rch_aer(struct cxl_dport *dport) aer_phys = aer_cap + dport->rcrb.base; dport->regs.dport_aer = devm_cxl_iomap_block(host, aer_phys, - sizeof(struct aer_capability_regs)); + PCIE_AER_CAP_HW_SIZE); } } @@ -58,31 +58,20 @@ void cxl_disable_rch_root_ints(struct cxl_dport *dport) static bool cxl_rch_get_aer_info(void __iomem *aer_base, struct aer_capability_regs *aer_regs) { - /* - * Bound the copy to the physically-defined AER registers (header - * through the 16-byte Header Log). struct aer_capability_regs is a - * software layout whose embedded struct pcie_tlp_log is larger than - * the on-wire AER capability; copying sizeof(*aer_regs) would - * over-read the RCRB-mapped MMIO block. - */ - int read_cnt = (PCI_ERR_HEADER_LOG + 16) / sizeof(u32); - u32 *aer_regs_buf = (u32 *)aer_regs; - int n; + /* A flat copy cannot fill the struct; aer_cap_regs_unpack() places it. */ + __le32 raw[PCIE_AER_CAP_HW_SIZE / sizeof(__le32)]; if (!aer_base) return false; /* - * Zero the destination so the software-only tail fields - * (e.g. header_log.header_len) are deterministic rather than - * left as uninitialized stack, which could drive a bogus loop - * length in pcie_print_tlp_log(). + * Use readl() to guarantee 32-bit accesses; it returns host order, so + * put the registers back little-endian for aer_cap_regs_unpack(). */ - memset(aer_regs, 0, sizeof(*aer_regs)); + for (int n = 0; n < ARRAY_SIZE(raw); n++) + raw[n] = cpu_to_le32(readl(aer_base + n * sizeof(u32))); - /* Use readl() to guarantee 32-bit accesses */ - for (n = 0; n < read_cnt; n++) - aer_regs_buf[n] = readl(aer_base + n * sizeof(u32)); + aer_cap_regs_unpack(aer_regs, raw, sizeof(raw)); writel(aer_regs->uncor_status, aer_base + PCI_ERR_UNCOR_STATUS); writel(aer_regs->cor_status, aer_base + PCI_ERR_COR_STATUS); diff --git a/drivers/pci/pcie/tlp.c b/drivers/pci/pcie/tlp.c index 71f8fc9ea2ed..7f94a09ac7c7 100644 --- a/drivers/pci/pcie/tlp.c +++ b/drivers/pci/pcie/tlp.c @@ -8,8 +8,11 @@ #include #include #include +#include +#include #include #include +#include #include "../pci.h" @@ -92,6 +95,91 @@ int pcie_read_tlp_log(struct pci_dev *dev, int where, int where2, return 0; } +/* The Prefix Log registers hold dw[4..13] in Flit mode. */ +static_assert((PCI_ERR_PREFIX_LOG + + (PCIE_STD_MAX_TLP_HEADERLOG - PCIE_STD_NUM_TLP_HEADERLOG) * + sizeof(u32)) == PCIE_AER_CAP_HW_SIZE); + +/** + * aer_cap_regs_unpack - Convert a raw AER Capability image to the kernel layout + * @regs: Destination, fully initialised + * @raw: AER Capability register block in hardware order, little-endian + * @raw_len: Bytes readable at @raw + * + * struct aer_capability_regs is not the hardware layout: struct pcie_tlp_log + * spans 60 bytes where the Header Log it stands in for is 16, so a flat copy + * misplaces everything behind it. Map the registers one by one instead, + * taking the TLP Log layout from the Flit bit as pcie_read_tlp_log() does. + * + * @raw is not necessarily aligned. Registers past @raw_len are left zero, so + * a short image cannot be read past. + */ +void aer_cap_regs_unpack(struct aer_capability_regs *regs, const void *raw, + size_t raw_len) +{ + unsigned int i, tlp_len; + bool flit; + + memset(regs, 0, sizeof(*regs)); + + if (raw_len < PCI_ERR_HEADER_LOG) + return; + + /* The Extended Capability Header, at offset 0, has no define */ + regs->header = get_unaligned_le32(raw); + regs->uncor_status = get_unaligned_le32(raw + PCI_ERR_UNCOR_STATUS); + regs->uncor_mask = get_unaligned_le32(raw + PCI_ERR_UNCOR_MASK); + regs->uncor_severity = get_unaligned_le32(raw + PCI_ERR_UNCOR_SEVER); + regs->cor_status = get_unaligned_le32(raw + PCI_ERR_COR_STATUS); + regs->cor_mask = get_unaligned_le32(raw + PCI_ERR_COR_MASK); + regs->cap_control = get_unaligned_le32(raw + PCI_ERR_CAP); + + flit = FIELD_GET(PCI_ERR_CAP_TLP_LOG_FLIT, regs->cap_control); + if (flit) { + tlp_len = FIELD_GET(PCI_ERR_CAP_TLP_LOG_SIZE, regs->cap_control); + } else { + /* + * dw[4..7] alias the Prefix Log. Take all four whatever + * eetlp_prefix_max says; pcie_print_tlp_log() stops at the + * first zero one. + */ + tlp_len = PCIE_STD_NUM_TLP_HEADERLOG + PCIE_STD_MAX_TLP_PREFIXLOG; + } + + tlp_len = min(tlp_len, ARRAY_SIZE(regs->header_log.dw)); + + for (i = 0; i < tlp_len; i++) { + unsigned int off; + + if (i < PCIE_STD_NUM_TLP_HEADERLOG) + off = PCI_ERR_HEADER_LOG + i * sizeof(u32); + else + off = PCI_ERR_PREFIX_LOG + + (i - PCIE_STD_NUM_TLP_HEADERLOG) * sizeof(u32); + + if (off + sizeof(u32) > raw_len) + break; + regs->header_log.dw[i] = get_unaligned_le32(raw + off); + } + + /* @i may be short of tlp_len; non-Flit needs the TLP parsed, so cap at 4 */ + regs->header_log.header_len = flit ? i : min(i, PCIE_STD_NUM_TLP_HEADERLOG); + regs->header_log.flit = flit; + + if (raw_len >= PCI_ERR_ROOT_COMMAND + sizeof(u32)) + regs->root_command = get_unaligned_le32(raw + PCI_ERR_ROOT_COMMAND); + if (raw_len >= PCI_ERR_ROOT_STATUS + sizeof(u32)) + regs->root_status = get_unaligned_le32(raw + PCI_ERR_ROOT_STATUS); + if (raw_len >= PCI_ERR_ROOT_ERR_SRC + sizeof(u32)) { + u32 src = get_unaligned_le32(raw + PCI_ERR_ROOT_ERR_SRC); + + /* One register: ERR_COR in 15:0, ERR_FATAL/NONFATAL in 31:16 */ + regs->cor_err_source = src; + regs->uncor_err_source = src >> 16; + } +} +EXPORT_SYMBOL_GPL(aer_cap_regs_unpack); + #define EE_PREFIX_STR " E-E Prefixes:" /** diff --git a/include/linux/aer.h b/include/linux/aer.h index df0f5c382286..043ee76b6f53 100644 --- a/include/linux/aer.h +++ b/include/linux/aer.h @@ -24,6 +24,13 @@ #define PCIE_STD_MAX_TLP_PREFIXLOG 4 #define PCIE_STD_MAX_TLP_HEADERLOG (PCIE_STD_NUM_TLP_HEADERLOG + 10) +/* + * Size of the AER Capability register block in hardware, long enough for the + * longest Flit mode TLP Log. struct aer_capability_regs below is larger and + * laid out differently; use aer_cap_regs_unpack() to convert. + */ +#define PCIE_AER_CAP_HW_SIZE 96 + struct pci_dev; struct pcie_tlp_log { @@ -68,6 +75,8 @@ static inline void pci_aer_unmask_internal_errors(struct pci_dev *dev) { } void pci_print_aer(struct pci_dev *dev, int aer_severity, struct aer_capability_regs *aer); +void aer_cap_regs_unpack(struct aer_capability_regs *regs, const void *raw, + size_t raw_len); int cper_severity_to_aer(int cper_severity); void aer_recover_queue(int domain, unsigned int bus, unsigned int devfn, int severity, struct aer_capability_regs *aer_regs); -- cgit v1.2.3 From 538076b45429652424801cb127581ed3dc56a0b7 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 30 Sep 2026 20:45:01 +0200 Subject: ACPI: bus: Drop acpi_get_first_physical_node() Fold acpi_get_first_physical_node() into acpi_primary_dev_companion() that is its only remaining caller and drop its signature from the header file. No intentional functional impact. Signed-off-by: Rafael J. Wysocki Reviewed-by: Sudeep Holla Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/4537440.ejJDZkT8p0@rafael.j.wysocki --- drivers/acpi/bus.c | 20 +++++--------------- include/linux/acpi.h | 7 ------- 2 files changed, 5 insertions(+), 22 deletions(-) (limited to 'include/linux') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 808c6746be14..cc6989d88645 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -809,24 +809,14 @@ struct device *acpi_bus_get_primary_device(struct acpi_device *adev) } EXPORT_SYMBOL_GPL(acpi_bus_get_primary_device); -/** - * acpi_get_first_physical_node - Find first physical node of an ACPI device - * @adev: ACPI device in question - * - * Return: First physical node of ACPI device @adev - */ -struct device *acpi_get_first_physical_node(struct acpi_device *adev) -{ - guard(mutex)(&adev->physical_node_lock); - - return primary_physical_device(adev); -} -EXPORT_SYMBOL_GPL(acpi_get_first_physical_node); - static struct acpi_device *acpi_primary_dev_companion(struct acpi_device *adev, const struct device *dev) { - const struct device *phys_dev = acpi_get_first_physical_node(adev); + const struct device *phys_dev; + + guard(mutex)(&adev->physical_node_lock); + + phys_dev = primary_physical_device(adev); return phys_dev && phys_dev == dev ? adev : NULL; } diff --git a/include/linux/acpi.h b/include/linux/acpi.h index ba5234bd93a2..6f69819f9c9a 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -105,8 +105,6 @@ static inline const char *acpi_dev_name(struct acpi_device *adev) return dev_name(&adev->dev); } -struct device *acpi_get_first_physical_node(struct acpi_device *adev); - enum acpi_irq_model_id { ACPI_IRQ_MODEL_PIC = 0, ACPI_IRQ_MODEL_IOAPIC, @@ -938,11 +936,6 @@ static inline const char *acpi_dev_name(struct acpi_device *adev) return NULL; } -static inline struct device *acpi_get_first_physical_node(struct acpi_device *adev) -{ - return NULL; -} - static inline void acpi_early_init(void) { } static inline void acpi_subsystem_init(void) { } -- cgit v1.2.3