diff options
50 files changed, 807 insertions, 683 deletions
diff --git a/Documentation/driver-api/acpi/acpi-drivers.rst b/Documentation/driver-api/acpi/acpi-drivers.rst deleted file mode 100644 index 376b6d8a678c..000000000000 --- a/Documentation/driver-api/acpi/acpi-drivers.rst +++ /dev/null @@ -1,80 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 -.. include:: <isonum.txt> - -========================================= -Why using ACPI drivers is not a good idea -========================================= - -:Copyright: |copy| 2026, Intel Corporation - -:Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com> - -Even though binding drivers directly to struct acpi_device objects, also -referred to as "ACPI device nodes", allows basic functionality to be provided -at least in some cases, there are problems with it, related to general -consistency, sysfs layout, power management operation ordering, and code -cleanliness. - -First of all, ACPI device nodes represent firmware entities rather than -hardware and in many cases they provide auxiliary information on devices -enumerated independently (like PCI devices or CPUs). It is therefore generally -questionable to assign resources to them because the entities represented by -them do not decode addresses in the memory or I/O address spaces and do not -generate interrupts or similar (all of that is done by hardware). - -Second, as a general rule, a struct acpi_device can only be a parent of another -struct acpi_device. If that is not the case, the location of the child device -in the device hierarchy is at least confusing and it may not be straightforward -to identify the piece of hardware providing functionality represented by it. -However, binding a driver directly to an ACPI device node may cause that to -happen if the given driver registers input devices or wakeup sources under it, -for example. - -Next, using system suspend and resume callbacks directly on ACPI device nodes -is also questionable because it may cause ordering problems to appear. Namely, -ACPI device nodes are registered before enumerating hardware corresponding to -them and they land on the PM list in front of the majority of other device -objects. Consequently, the execution ordering of their PM callbacks may be -different from what is generally expected. Also, in general, dependencies -returned by _DEP objects do not affect ACPI device nodes themselves, but the -"physical" devices associated with them, which potentially is one more source -of inconsistency related to treating ACPI device nodes as "real" device -representation. - -All of the above means that binding drivers to ACPI device nodes should -generally be avoided and so struct acpi_driver objects should not be used. - -Moreover, a device ID is necessary to bind a driver directly to an ACPI device -node, but device IDs are not generally associated with all of them. Some of -them contain alternative information allowing the corresponding pieces of -hardware to be identified, for example represented by an _ADR object return -value, and device IDs are not used in those cases. In consequence, confusingly -enough, binding an ACPI driver to an ACPI device node may even be impossible. - -When that happens, the piece of hardware corresponding to the given ACPI device -node is represented by another device object, like a struct pci_dev, and the -ACPI device node is the "ACPI companion" of that device, accessible through its -fwnode pointer used by the ACPI_COMPANION() macro. The ACPI companion holds -additional information on the device configuration and possibly some "recipes" -on device manipulation in the form of AML (ACPI Machine Language) bytecode -provided by the platform firmware. Thus the role of the ACPI device node is -similar to the role of a struct device_node on a system where Device Tree is -used for platform description. - -For consistency, this approach has been extended to the cases in which ACPI -device IDs are used. Namely, in those cases, an additional device object is -created to represent the piece of hardware corresponding to a given ACPI device -node. By default, it is a platform device, but it may also be a PNP device, a -CPU device, or another type of device, depending on what the given piece of -hardware actually is. There are even cases in which multiple devices are -"backed" or "accompanied" by one ACPI device node (e.g. ACPI device nodes -corresponding to GPUs that may provide firmware interfaces for backlight -brightness control in addition to GPU configuration information). - -This means that it really should never be necessary to bind a driver directly to -an ACPI device node because there is a "proper" device object representing the -corresponding piece of hardware that can be bound to by a "proper" driver using -the given ACPI device node as the device's ACPI companion. Thus, in principle, -there is no reason to use ACPI drivers and if they all were replaced with other -driver types (for example, platform drivers), some code could be dropped and -some complexity would go away. diff --git a/Documentation/driver-api/acpi/index.rst b/Documentation/driver-api/acpi/index.rst index 2b10d83f9994..ace0008e54c2 100644 --- a/Documentation/driver-api/acpi/index.rst +++ b/Documentation/driver-api/acpi/index.rst @@ -7,4 +7,3 @@ ACPI Support linuxized-acpica scan_handlers - acpi-drivers diff --git a/Documentation/firmware-guide/acpi/dsd/motorcomm-yt8xxx-phy.rst b/Documentation/firmware-guide/acpi/dsd/motorcomm-yt8xxx-phy.rst index d64a396fac81..78d9b712721c 100644 --- a/Documentation/firmware-guide/acpi/dsd/motorcomm-yt8xxx-phy.rst +++ b/Documentation/firmware-guide/acpi/dsd/motorcomm-yt8xxx-phy.rst @@ -64,9 +64,10 @@ defaults as [motorcomm-yt8xxx]_. Enables adjustments related to ``motorcomm,tx-clk-*-inverted`` usage; see [motorcomm-yt8xxx]_. -``motorcomm,tx-clk-10-inverted`` (boolean, optional) -``motorcomm,tx-clk-100-inverted`` (boolean, optional) +``motorcomm,tx-clk-10-inverted`` (boolean, optional), +``motorcomm,tx-clk-100-inverted`` (boolean, optional), ``motorcomm,tx-clk-1000-inverted`` (boolean, optional) + Per-speed TX clock inversion options; see [motorcomm-yt8xxx]_. ASL example (illustrative) diff --git a/arch/riscv/include/asm/acpi.h b/arch/riscv/include/asm/acpi.h index 26ab37c171bc..f598520ac903 100644 --- a/arch/riscv/include/asm/acpi.h +++ b/arch/riscv/include/asm/acpi.h @@ -67,6 +67,7 @@ int acpi_get_riscv_isa(struct acpi_table_header *table, void acpi_get_cbo_block_size(struct acpi_table_header *table, u32 *cbom_size, u32 *cboz_size, u32 *cbop_size); +acpi_handle acpi_get_riscv_gsi_handle(u32 gsi); #else static inline void acpi_init_rintc_map(void) { } static inline struct acpi_madt_rintc *acpi_cpu_get_madt_rintc(int cpu) diff --git a/drivers/acpi/acpi_fpdt.c b/drivers/acpi/acpi_fpdt.c index e75dd28d31a9..79191ed20f76 100644 --- a/drivers/acpi/acpi_fpdt.c +++ b/drivers/acpi/acpi_fpdt.c @@ -168,7 +168,7 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type) struct fpdt_subtable_header *subtable_header; struct fpdt_record_header *record_header; char *signature = (subtable_type == SUBTABLE_FBPT ? "FBPT" : "S3PT"); - u32 length, offset; + u32 length, offset, remaining; int result; if (!fpdt_address_valid(address)) { @@ -182,10 +182,17 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type) if (strncmp((char *)&subtable_header->signature, signature, 4)) { pr_info(FW_BUG "subtable signature and type mismatch!\n"); + acpi_os_unmap_memory(subtable_header, sizeof(*subtable_header)); return -EINVAL; } length = subtable_header->length; + if (length < sizeof(*subtable_header)) { + pr_err(FW_BUG "Invalid FPDT subtable length %u.\n", length); + acpi_os_unmap_memory(subtable_header, sizeof(*subtable_header)); + return -EINVAL; + } + acpi_os_unmap_memory(subtable_header, sizeof(*subtable_header)); subtable_header = acpi_os_map_memory(address, length); @@ -194,17 +201,29 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type) offset = sizeof(*subtable_header); while (offset < length) { - record_header = (void *)subtable_header + offset; - offset += record_header->length; + remaining = length - offset; + if (remaining < sizeof(*record_header)) { + pr_err(FW_BUG "Truncated FPDT record header.\n"); + result = -EINVAL; + goto err; + } - if (!record_header->length) { - pr_err(FW_BUG "Zero-length record found in FPTD.\n"); + record_header = (void *)subtable_header + offset; + if (record_header->length < sizeof(*record_header) || + record_header->length > remaining) { + pr_err(FW_BUG "Invalid FPDT record length %u.\n", + record_header->length); result = -EINVAL; goto err; } + offset += record_header->length; switch (record_header->type) { case RECORD_S3_RESUME: + if (record_header->length < sizeof(*record_resume)) { + result = -EINVAL; + goto err; + } if (subtable_type != SUBTABLE_S3PT) { pr_err(FW_BUG "Invalid record %d for subtable %s\n", record_header->type, signature); @@ -221,6 +240,10 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type) goto err; break; case RECORD_S3_SUSPEND: + if (record_header->length < sizeof(*record_suspend)) { + result = -EINVAL; + goto err; + } if (subtable_type != SUBTABLE_S3PT) { pr_err(FW_BUG "Invalid %d for subtable %s\n", record_header->type, signature); @@ -236,6 +259,10 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type) goto err; break; case RECORD_BOOT: + if (record_header->length < sizeof(*record_boot)) { + result = -EINVAL; + goto err; + } if (subtable_type != SUBTABLE_FBPT) { pr_err(FW_BUG "Invalid %d for subtable %s\n", record_header->type, signature); @@ -317,7 +344,21 @@ static int __init acpi_init_fpdt(void) } while (offset < header->length) { + if (header->length - offset < sizeof(*subtable)) { + pr_err(FW_BUG "Truncated FPDT subtable entry.\n"); + result = -EINVAL; + goto err_subtable; + } + subtable = (void *)header + offset; + if (subtable->length < sizeof(*subtable) || + subtable->length > header->length - offset) { + pr_err(FW_BUG "Invalid FPDT subtable entry length %u.\n", + subtable->length); + result = -EINVAL; + goto err_subtable; + } + switch (subtable->type) { case SUBTABLE_FBPT: case SUBTABLE_S3PT: @@ -330,7 +371,7 @@ static int __init acpi_init_fpdt(void) /* Other types are reserved in ACPI 6.4 spec. */ break; } - offset += sizeof(*subtable); + offset += subtable->length; } return 0; err_subtable: diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c index a09636a4168e..373c94de7590 100644 --- a/drivers/acpi/acpi_platform.c +++ b/drivers/acpi/acpi_platform.c @@ -12,6 +12,7 @@ #include <linux/bits.h> #include <linux/device.h> #include <linux/err.h> +#include <linux/ioport.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/dma-mapping.h> @@ -71,6 +72,36 @@ static struct notifier_block acpi_platform_notifier = { .notifier_call = acpi_platform_device_remove_notify, }; +static unsigned int acpi_platform_adjust_resources(struct acpi_device *adev, + struct resource *new_res, + struct resource *resources, + unsigned int count) +{ + unsigned int i; + + if (!(new_res->flags & (IORESOURCE_IO | IORESOURCE_MEM))) + return count; + + for (i = 0; i < count; ) { + struct resource *res = &resources[i]; + + if (resource_type(new_res) != resource_type(res) || + !resource_union(new_res, res, new_res)) { + i++; + continue; + } + + dev_info(&adev->dev, "%pR expanded due to overlap\n", new_res); + /* + * Eliminate the previously processed resource that overlapped + * with the new one because it is not necessary any more. + */ + memmove(res, res + 1, (--count - i) * sizeof(*res)); + } + + return count; +} + static void acpi_platform_fill_resource(struct acpi_device *adev, const struct resource *src, struct resource *dest) { @@ -151,10 +182,14 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev, return ERR_PTR(-ENOMEM); } count = 0; - list_for_each_entry(rentry, &resource_list, node) + list_for_each_entry(rentry, &resource_list, node) { + count = acpi_platform_adjust_resources(adev, + rentry->res, + resources, + count); acpi_platform_fill_resource(adev, rentry->res, &resources[count++]); - + } acpi_dev_free_resource_list(&resource_list); } } diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c index fc43df083738..45459a4cafae 100644 --- a/drivers/acpi/acpi_tad.c +++ b/drivers/acpi/acpi_tad.c @@ -27,6 +27,7 @@ #include <linux/kernel.h> #include <linux/ktime.h> #include <linux/module.h> +#include <linux/mutex.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/rtc.h> @@ -86,6 +87,8 @@ static bool acpi_tad_rt_is_invalid(struct acpi_tad_rt *rt) rt->daylight > 3; } +static DEFINE_MUTEX(acpi_tad_aml_lock); + static int acpi_tad_set_real_time(struct device *dev, struct acpi_tad_rt *rt) { acpi_handle handle = ACPI_HANDLE(dev); @@ -113,6 +116,8 @@ static int acpi_tad_set_real_time(struct device *dev, struct acpi_tad_rt *rt) if (PM_RUNTIME_ACQUIRE_ERR(&pm)) return -ENXIO; + guard(mutex)(&acpi_tad_aml_lock); + status = acpi_evaluate_integer(handle, "_SRT", &arg_list, &retval); if (ACPI_FAILURE(status) || retval) return -EIO; @@ -124,30 +129,27 @@ static int acpi_tad_evaluate_grt(struct device *dev, struct acpi_tad_rt *rt) { acpi_handle handle = ACPI_HANDLE(dev); struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER }; - union acpi_object *out_obj; - struct acpi_tad_rt *data; acpi_status status; int ret = -EIO; - status = acpi_evaluate_object(handle, "_GRT", NULL, &output); - if (ACPI_FAILURE(status)) - goto out_free; - - out_obj = output.pointer; - if (out_obj->type != ACPI_TYPE_BUFFER) - goto out_free; - - if (out_obj->buffer.length != sizeof(*rt)) - goto out_free; - - data = (struct acpi_tad_rt *)(out_obj->buffer.pointer); - if (!data->valid) - goto out_free; - - memcpy(rt, data, sizeof(*rt)); - ret = 0; + guard(mutex)(&acpi_tad_aml_lock); -out_free: + status = acpi_evaluate_object(handle, "_GRT", NULL, &output); + if (ACPI_SUCCESS(status)) { + union acpi_object *out_obj; + + out_obj = output.pointer; + if (out_obj->type == ACPI_TYPE_BUFFER && + out_obj->buffer.length == sizeof(*rt)) { + struct acpi_tad_rt *data; + + data = (struct acpi_tad_rt *)(out_obj->buffer.pointer); + if (data->valid) { + memcpy(rt, data, sizeof(*rt)); + ret = 0; + } + } + } ACPI_FREE(output.pointer); return ret; } @@ -193,6 +195,8 @@ static int __acpi_tad_wake_set(struct device *dev, char *method, u32 timer_id, args[0].integer.value = timer_id; args[1].integer.value = value; + guard(mutex)(&acpi_tad_aml_lock); + status = acpi_evaluate_integer(handle, method, &arg_list, &retval); if (ACPI_FAILURE(status) || retval) return -EIO; @@ -215,6 +219,8 @@ static int __acpi_tad_wake_read(struct device *dev, char *method, u32 timer_id, args[0].integer.value = timer_id; + guard(mutex)(&acpi_tad_aml_lock); + status = acpi_evaluate_integer(handle, method, &arg_list, retval); if (ACPI_FAILURE(status)) return -EIO; @@ -416,6 +422,8 @@ static int acpi_tad_clear_status(struct device *dev, u32 timer_id) if (PM_RUNTIME_ACQUIRE_ERR(&pm)) return -ENXIO; + guard(mutex)(&acpi_tad_aml_lock); + status = acpi_evaluate_integer(handle, "_CWS", &arg_list, &retval); if (ACPI_FAILURE(status) || retval) return -EIO; @@ -456,6 +464,8 @@ static ssize_t acpi_tad_status_read(struct device *dev, char *buf, u32 timer_id) if (PM_RUNTIME_ACQUIRE_ERR(&pm)) return -ENXIO; + guard(mutex)(&acpi_tad_aml_lock); + status = acpi_evaluate_integer(handle, "_GWS", &arg_list, &retval); if (ACPI_FAILURE(status)) return -EIO; diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index f93e877f87f6..4d6fd9f6e9ad 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -1048,7 +1048,7 @@ static int acpi_video_bus_check(struct acpi_video_bus *video) if (!video) return -EINVAL; - dev = acpi_get_pci_dev(video->device->handle); + dev = acpi_dev_get_pci_dev(video->device); if (!dev) return -ENODEV; pci_dev_put(dev); @@ -1702,7 +1702,6 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device) { struct backlight_properties props; struct pci_dev *pdev; - acpi_handle acpi_parent; struct device *parent = NULL; int result; static int count; @@ -1717,13 +1716,9 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device) return; count++; - if (ACPI_SUCCESS(acpi_get_parent(device->dev->handle, &acpi_parent))) { - pdev = acpi_get_pci_dev(acpi_parent); - if (pdev) { - parent = &pdev->dev; - pci_dev_put(pdev); - } - } + pdev = acpi_dev_get_pci_dev(acpi_dev_parent(device->dev)); + if (pdev) + parent = &pdev->dev; memset(&props, 0, sizeof(struct backlight_properties)); props.type = BACKLIGHT_FIRMWARE; @@ -1734,6 +1729,7 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device) device, &acpi_backlight_ops, &props); + put_device(parent); kfree(name); if (IS_ERR(device->backlight)) { device->backlight = NULL; diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index bf65e3461531..15ab797641cf 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -108,7 +108,7 @@ static inline u64 erst_get_timeout(void) if (erst_erange.attr & ERST_RANGE_SLOW) { timeout = ((erst_erange.timings & ERST_EXEC_TIMING_MAX_MASK) >> - ERST_EXEC_TIMING_MAX_SHIFT) * NSEC_PER_MSEC; + ERST_EXEC_TIMING_MAX_SHIFT) * NSEC_PER_USEC; if (timeout < FIRMWARE_TIMEOUT) timeout = FIRMWARE_TIMEOUT; } diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 3236a3ce79d6..bc1dfa3398b4 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -576,7 +576,7 @@ static bool ghes_handle_arm_hw_error(struct acpi_hest_generic_data *gdata, return false; p = (char *)(err + 1); - length -= sizeof(err); + length -= sizeof(*err); for (i = 0; i < err->err_info_num; i++) { struct cper_arm_err_info *err_info; @@ -1383,8 +1383,16 @@ static int ghes_in_nmi_queue_one_entry(struct ghes *ghes, ghes_clear_estatus(ghes, &tmp_header, buf_paddr, fixmap_idx); /* This error has been reported before, don't process it again. */ - if (ghes_estatus_cached(estatus)) + if (ghes_estatus_cached(estatus)) { + /* + * Return failure on duplicate SEA entries so that the + * subsequent SEA handler invocation sends a SIGBUS signal to + * the task to prevent it from re-entering the handler loop. + */ + if (is_hest_sync_notify(ghes)) + rc = -ECANCELED; goto no_work; + } llist_add(&estatus_node->llnode, &ghes_estatus_llist); @@ -1397,8 +1405,8 @@ no_work: return rc; } -static int ghes_in_nmi_spool_from_list(struct list_head *rcu_list, - enum fixed_addresses fixmap_idx) +static int __maybe_unused ghes_in_nmi_spool_from_list(struct list_head *rcu_list, + enum fixed_addresses fixmap_idx) { int ret = -ENOENT; struct ghes *ghes; diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index af7a9b2fd5bc..34412cd697d8 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -789,11 +789,9 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 id, return irq_find_matching_fwnode(handle, bus_token); } -struct fwnode_handle *iort_iwb_handle(u32 iwb_id) +acpi_handle iort_iwb_handle(u32 iwb_id) { - struct fwnode_handle *fwnode; struct acpi_iort_node *node; - struct acpi_device *device; struct acpi_iort_iwb *iwb; acpi_status status; acpi_handle handle; @@ -808,6 +806,19 @@ struct fwnode_handle *iort_iwb_handle(u32 iwb_id) if (ACPI_FAILURE(status)) return NULL; + return handle; +} + +struct fwnode_handle *iort_iwb_handle_fwnode(u32 iwb_id) +{ + struct fwnode_handle *fwnode; + struct acpi_device *device; + acpi_handle handle; + + handle = iort_iwb_handle(iwb_id); + if (!handle) + return NULL; + device = acpi_get_acpi_dev(handle); if (!device) return NULL; @@ -2090,6 +2101,11 @@ static void __init iort_init_platform_devices(void) } } +u32 arch_acpi_add_auto_dep(acpi_handle handle) +{ + return acpi_irq_add_auto_dep(handle); +} + void __init acpi_iort_init(void) { acpi_status status; diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index f5e0eb299610..0084f308b790 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -10,10 +10,12 @@ #define pr_fmt(fmt) "ACPI: battery: " fmt +#include <linux/ctype.h> #include <linux/delay.h> #include <linux/dmi.h> #include <linux/jiffies.h> #include <linux/kernel.h> +#include <linux/kfifo.h> #include <linux/list.h> #include <linux/module.h> #include <linux/mutex.h> @@ -21,6 +23,7 @@ #include <linux/slab.h> #include <linux/suspend.h> #include <linux/types.h> +#include <linux/workqueue.h> #include <linux/unaligned.h> @@ -43,6 +46,9 @@ #define MAX_STRING_LENGTH 64 +#define MAX_QUEUED_EVENTS 16 +#define NOTIF_MERGING_MS 10 + MODULE_AUTHOR("Paul Diefenbaugh"); MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>"); MODULE_DESCRIPTION("ACPI Battery Driver"); @@ -95,6 +101,8 @@ struct acpi_battery { struct power_supply_desc bat_desc; struct acpi_device *device; struct device *phys_dev; + struct kfifo acpi_notif_fifo; + struct delayed_work acpi_notif_dwork; struct notifier_block pm_nb; struct list_head list; unsigned long update_time; @@ -150,27 +158,28 @@ static int acpi_battery_technology(struct acpi_battery *battery) static int acpi_battery_get_state(struct acpi_battery *battery); -static int acpi_battery_is_charged(struct acpi_battery *battery) +static bool acpi_battery_is_full(struct acpi_battery *battery) { - /* charging, discharging, critical low or charge limited */ - if (battery->state != 0) - return 0; - /* battery not reporting charge */ if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN || battery->capacity_now == 0) - return 0; + return false; /* good batteries update full_charge as the batteries degrade */ if (battery->full_charge_capacity == battery->capacity_now) - return 1; + return true; /* fallback to using design values for broken batteries */ - if (battery->design_capacity <= battery->capacity_now) - return 1; + return battery->design_capacity <= battery->capacity_now; +} - /* we don't do any sort of metric based on percentages */ - return 0; +static int acpi_battery_is_charged(struct acpi_battery *battery) +{ + /* charging, discharging, critical low or charge limited */ + if (battery->state != 0) + return 0; + + return acpi_battery_is_full(battery); } static bool acpi_battery_is_degraded(struct acpi_battery *battery) @@ -211,13 +220,14 @@ static int acpi_battery_get_property(struct power_supply *psy, if (battery->state & ACPI_BATTERY_STATE_DISCHARGING) val->intval = acpi_battery_handle_discharging(battery); else if (battery->state & ACPI_BATTERY_STATE_CHARGING) - /* Validate the status by checking the current. */ - if (battery->rate_now != ACPI_BATTERY_VALUE_UNKNOWN && - battery->rate_now == 0) { - /* On charge but no current (0W/0mA). */ - val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; - } else { + /* Check the rate and capacity to validate the status. */ + if (!acpi_battery_is_full(battery) || + (battery->rate_now != ACPI_BATTERY_VALUE_UNKNOWN && + battery->rate_now > 0)) { val->intval = POWER_SUPPLY_STATUS_CHARGING; + } else { + /* Full and zero rate. */ + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; } else if (battery->state & ACPI_BATTERY_STATE_CHARGE_LIMITING) val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; @@ -483,6 +493,15 @@ static int acpi_battery_get_status(struct acpi_battery *battery) return 0; } +static void acpi_battery_clean_unprintable_chars(char *str, size_t length) +{ + for (unsigned int i = 0; i < length; i++) { + if (!isascii(str[i]) || !isprint(str[i])) { + str[i] = '\0'; + break; + } + } +} static int extract_battery_info(const int use_bix, struct acpi_battery *battery, @@ -524,6 +543,10 @@ static int extract_battery_info(const int use_bix, battery->capacity_now > battery->full_charge_capacity) battery->capacity_now = battery->full_charge_capacity; + if (!result) + acpi_battery_clean_unprintable_chars(battery->model_number, + ARRAY_SIZE(battery->model_number)); + return result; } @@ -668,9 +691,13 @@ static ssize_t acpi_battery_alarm_store(struct device *dev, { unsigned long x; struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); + int err; + + err = kstrtoul(buf, 10, &x); + if (err) + return err; - if (sscanf(buf, "%lu\n", &x) == 1) - battery->alarm = x/1000; + battery->alarm = x / 1000; if (acpi_battery_present(battery)) acpi_battery_set_alarm(battery); return count; @@ -1059,14 +1086,24 @@ static void acpi_battery_refresh(struct acpi_battery *battery) } /* Driver Interface */ -static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) +static void acpi_battery_notification_worker(struct work_struct *work) { - struct acpi_battery *battery = data; + struct acpi_battery *battery = container_of(work, struct acpi_battery, + acpi_notif_dwork.work); struct acpi_device *device = battery->device; + u32 events[MAX_QUEUED_EVENTS]; struct power_supply *old; + unsigned int count, i; guard(mutex)(&battery->update_lock); + count = kfifo_out(&battery->acpi_notif_fifo, events, sizeof(events)); + count /= sizeof(events[0]); + if (!count) + return; + + pr_debug("merged %u battery notifications within %dms\n", count, NOTIF_MERGING_MS); + old = battery->bat; /* * On Acer Aspire V5-573G notifications are sometimes triggered too @@ -1076,19 +1113,46 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) */ if (battery_notification_delay_ms > 0) msleep(battery_notification_delay_ms); - if (event == ACPI_BATTERY_NOTIFY_INFO) - acpi_battery_refresh(battery); + + for (i = 0; i < count; i++) { + if (events[i] == ACPI_BATTERY_NOTIFY_INFO) { + acpi_battery_refresh(battery); + break; + } + } + acpi_battery_update(battery, false); - acpi_bus_generate_netlink_event(ACPI_BATTERY_CLASS, - dev_name(&device->dev), event, - acpi_battery_present(battery)); - acpi_notifier_call_chain(ACPI_BATTERY_CLASS, acpi_device_bid(device), - event, acpi_battery_present(battery)); + + for (i = 0; i < count; i++) { + acpi_bus_generate_netlink_event(ACPI_BATTERY_CLASS, + dev_name(&device->dev), events[i], + acpi_battery_present(battery)); + acpi_notifier_call_chain(ACPI_BATTERY_CLASS, acpi_device_bid(device), + events[i], acpi_battery_present(battery)); + } + /* acpi_battery_update could remove power_supply object */ if (old && battery->bat) power_supply_changed(battery->bat); } +static void acpi_battery_notify(acpi_handle handle, u32 event, void *data) +{ + struct acpi_battery *battery = data; + + guard(mutex)(&battery->update_lock); + + if (kfifo_avail(&battery->acpi_notif_fifo) >= sizeof(event)) { + kfifo_in(&battery->acpi_notif_fifo, &event, sizeof(event)); + schedule_delayed_work(&battery->acpi_notif_dwork, + msecs_to_jiffies(NOTIF_MERGING_MS)); + + return; + } + + pr_err_ratelimited("too many battery notifications within %dms\n", NOTIF_MERGING_MS); +} + static int battery_notify(struct notifier_block *nb, unsigned long mode, void *_unused) { @@ -1231,6 +1295,29 @@ static int devm_acpi_battery_update_retry(struct device *dev, return ret; } +static void acpi_battery_notify_dwork_cleanup(void *data) +{ + struct acpi_battery *battery = data; + + cancel_delayed_work_sync(&battery->acpi_notif_dwork); + kfifo_free(&battery->acpi_notif_fifo); +} + +static int devm_acpi_battery_init_notify_dwork(struct device *dev, + struct acpi_battery *battery) +{ + int ret; + + INIT_DELAYED_WORK(&battery->acpi_notif_dwork, acpi_battery_notification_worker); + + ret = kfifo_alloc(&battery->acpi_notif_fifo, + MAX_QUEUED_EVENTS * sizeof(u32), GFP_KERNEL); + if (ret) + return ret; + + return devm_add_action_or_reset(dev, acpi_battery_notify_dwork_cleanup, battery); +} + static int acpi_battery_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1272,6 +1359,10 @@ static int acpi_battery_probe(struct platform_device *pdev) if (result) return result; + result = devm_acpi_battery_init_notify_dwork(dev, battery); + if (result) + return result; + result = devm_acpi_install_notify_handler(dev, ACPI_ALL_NOTIFY, acpi_battery_notify, battery); if (result) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index a30a904f6535..c1876f145ae4 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -335,7 +335,7 @@ static int acpi_osc_handshake(acpi_handle handle, const char *uuid_str, .length = bufsize * sizeof(u32), }; struct acpi_buffer output; - u32 *retbuf, test; + u32 *retbuf, test, errors; guid_t guid; int ret, i; @@ -395,10 +395,18 @@ static int acpi_osc_handshake(acpi_handle handle, const char *uuid_str, * Clear the feature bits in capbuf[] that have not been acknowledged. * After that, capbuf[] contains the resultant feature mask. */ - for (i = OSC_QUERY_DWORD + 1; i < bufsize; i++) + for (i = OSC_QUERY_DWORD + 1, test = 0; i < bufsize; i++) { + test |= capbuf[i] & ~retbuf[i]; capbuf[i] &= retbuf[i]; + } - if (retbuf[OSC_QUERY_DWORD] & OSC_ERROR_MASK) { + errors = retbuf[OSC_QUERY_DWORD] & OSC_ERROR_MASK; + /* + * Some platforms set OSC_CAPABILITIES_MASK_ERROR even though they + * acknowledge all of the requested features, so avoid complaining in + * those cases unless any other error bits are also set. + */ + if (errors && (test || errors != OSC_CAPABILITIES_MASK_ERROR)) { /* * Complain about the unexpected errors and print diagnostic * information related to them. @@ -620,41 +628,6 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) acpi_evaluate_ost(handle, type, ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL); } -static void acpi_notify_device(acpi_handle handle, u32 event, void *data) -{ - struct acpi_device *device = data; - struct acpi_driver *acpi_drv = to_acpi_driver(device->dev.driver); - - acpi_drv->ops.notify(device, event); -} - -static int acpi_device_install_notify_handler(struct acpi_device *device, - struct acpi_driver *acpi_drv) -{ - u32 type = acpi_drv->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS ? - ACPI_ALL_NOTIFY : ACPI_DEVICE_NOTIFY; - acpi_status status; - - status = acpi_install_notify_handler(device->handle, type, - acpi_notify_device, device); - if (ACPI_FAILURE(status)) - return -EINVAL; - - return 0; -} - -static void acpi_device_remove_notify_handler(struct acpi_device *device, - struct acpi_driver *acpi_drv) -{ - u32 type = acpi_drv->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS ? - ACPI_ALL_NOTIFY : ACPI_DEVICE_NOTIFY; - - acpi_remove_notify_handler(device->handle, type, - acpi_notify_device); - - acpi_os_wait_events_complete(); -} - int acpi_dev_install_notify_handler(struct acpi_device *adev, u32 handler_type, acpi_notify_handler handler, void *context) @@ -1122,56 +1095,12 @@ bool acpi_driver_match_device(struct device *dev, EXPORT_SYMBOL_GPL(acpi_driver_match_device); /* -------------------------------------------------------------------------- - ACPI Driver Management - -------------------------------------------------------------------------- */ - -/** - * __acpi_bus_register_driver - register a driver with the ACPI bus - * @driver: driver being registered - * @owner: owning module/driver - * - * Registers a driver with the ACPI bus. Searches the namespace for all - * devices that match the driver's criteria and binds. Returns zero for - * success or a negative error status for failure. - */ -int __acpi_bus_register_driver(struct acpi_driver *driver, struct module *owner) -{ - if (acpi_disabled) - return -ENODEV; - driver->drv.name = driver->name; - driver->drv.bus = &acpi_bus_type; - driver->drv.owner = owner; - - return driver_register(&driver->drv); -} - -EXPORT_SYMBOL(__acpi_bus_register_driver); - -/** - * acpi_bus_unregister_driver - unregisters a driver with the ACPI bus - * @driver: driver to unregister - * - * Unregisters a driver with the ACPI bus. Searches the namespace for all - * devices that match the driver's criteria and unbinds. - */ -void acpi_bus_unregister_driver(struct acpi_driver *driver) -{ - driver_unregister(&driver->drv); -} - -EXPORT_SYMBOL(acpi_bus_unregister_driver); - -/* -------------------------------------------------------------------------- ACPI Bus operations -------------------------------------------------------------------------- */ static int acpi_bus_match(struct device *dev, const struct device_driver *drv) { - struct acpi_device *acpi_dev = to_acpi_device(dev); - const struct acpi_driver *acpi_drv = to_acpi_driver(drv); - - return acpi_dev->flags.match_driver - && !acpi_match_device_ids(acpi_dev, acpi_drv->ids); + return 0; } static int acpi_device_uevent(const struct device *dev, struct kobj_uevent_env *env) @@ -1179,66 +1108,9 @@ static int acpi_device_uevent(const struct device *dev, struct kobj_uevent_env * return __acpi_device_uevent_modalias(to_acpi_device(dev), env); } -static int acpi_device_probe(struct device *dev) -{ - struct acpi_device *acpi_dev = to_acpi_device(dev); - struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver); - int ret; - - if (acpi_dev->handler && !acpi_is_pnp_device(acpi_dev)) - return -EINVAL; - - if (!acpi_drv->ops.add) - return -ENOSYS; - - ret = acpi_drv->ops.add(acpi_dev); - if (ret) { - acpi_dev->driver_data = NULL; - return ret; - } - - pr_debug("Driver [%s] successfully bound to device [%s]\n", - acpi_drv->name, acpi_dev->pnp.bus_id); - - if (acpi_drv->ops.notify) { - ret = acpi_device_install_notify_handler(acpi_dev, acpi_drv); - if (ret) { - if (acpi_drv->ops.remove) - acpi_drv->ops.remove(acpi_dev); - - acpi_dev->driver_data = NULL; - return ret; - } - } - - pr_debug("Found driver [%s] for device [%s]\n", acpi_drv->name, - acpi_dev->pnp.bus_id); - - get_device(dev); - return 0; -} - -static void acpi_device_remove(struct device *dev) -{ - struct acpi_device *acpi_dev = to_acpi_device(dev); - struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver); - - if (acpi_drv->ops.notify) - acpi_device_remove_notify_handler(acpi_dev, acpi_drv); - - if (acpi_drv->ops.remove) - acpi_drv->ops.remove(acpi_dev); - - acpi_dev->driver_data = NULL; - - put_device(dev); -} - const struct bus_type acpi_bus_type = { .name = "acpi", .match = acpi_bus_match, - .probe = acpi_device_probe, - .remove = acpi_device_remove, .uevent = acpi_device_uevent, }; diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 53d09ca98f06..2f7c09552566 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -200,6 +200,72 @@ show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, wraparound_time); ((((val) & GENMASK(((reg)->bit_width) - 1, 0)) << (reg)->bit_offset) | \ ((prev_val) & ~(GENMASK(((reg)->bit_width) - 1, 0) << (reg)->bit_offset))) \ +static u64 cpc_sysmem_access_size(const struct cpc_register_resource *reg) +{ + const struct cpc_reg *gas = ®->cpc_entry.reg; + unsigned int width; + + if (gas->access_width > 4) + return 0; + + width = GET_BIT_WIDTH(gas); + + if (width != 8 && width != 16 && width != 32 && width != 64) + return 0; + + return width / 8; +} + +static bool cpc_sysmem_access_units_overlap(const struct cpc_register_resource *a, + const struct cpc_register_resource *b) +{ + const struct cpc_reg *a_gas = &a->cpc_entry.reg; + const struct cpc_reg *b_gas = &b->cpc_entry.reg; + u64 a_size = cpc_sysmem_access_size(a); + u64 b_size = cpc_sysmem_access_size(b); + + /* Keep the conservative locking path for malformed access widths. */ + if (!a_size || !b_size) + return true; + + if (a_gas->address < b_gas->address) + return b_gas->address - a_gas->address < a_size; + + return a_gas->address - b_gas->address < b_size; +} + +static void cpc_mark_rmw_lock_users(struct cpc_desc *cpc_desc) +{ + int i, j; + + for (i = 0; i < cpc_desc->num_entries - 2; i++) { + struct cpc_register_resource *a = &cpc_desc->cpc_regs[i]; + struct cpc_reg *gas; + u64 access_size; + + if (!CPC_SUPPORTED(a) || !CPC_IN_SYSTEM_MEMORY(a)) + continue; + + gas = &a->cpc_entry.reg; + access_size = cpc_sysmem_access_size(a); + if (gas->bit_offset || !access_size || + gas->bit_width != access_size * 8) + a->cpc_entry.use_rmw_lock = true; + + for (j = i + 1; j < cpc_desc->num_entries - 2; j++) { + struct cpc_register_resource *b = &cpc_desc->cpc_regs[j]; + + if (!CPC_SUPPORTED(b) || !CPC_IN_SYSTEM_MEMORY(b)) + continue; + if (!cpc_sysmem_access_units_overlap(a, b)) + continue; + + a->cpc_entry.use_rmw_lock = true; + b->cpc_entry.use_rmw_lock = true; + } + } +} + static ssize_t show_feedback_ctrs(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -904,6 +970,7 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) /* Store CPU Logical ID */ cpc_ptr->cpu_id = pr->id; + cpc_mark_rmw_lock_users(cpc_ptr); raw_spin_lock_init(&cpc_ptr->rmw_lock); /* Parse PSD data for this CPU */ @@ -1123,6 +1190,7 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val) struct cpc_reg *reg = ®_res->cpc_entry.reg; struct cpc_desc *cpc_desc; unsigned long flags; + bool locked = false; size = GET_BIT_WIDTH(reg); @@ -1156,31 +1224,43 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val) val, size); if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { - cpc_desc = per_cpu(cpc_desc_ptr, cpu); - if (!cpc_desc) { - pr_debug("No CPC descriptor for CPU:%d\n", cpu); - return -ENODEV; + /* + * The _CPC layout is immutable after probe. The precomputed flag + * retains serialization for partial fields or overlapping access + * units; standalone full-width registers avoid the lock. + */ + locked = reg_res->cpc_entry.use_rmw_lock; + if (locked) { + cpc_desc = per_cpu(cpc_desc_ptr, cpu); + if (!cpc_desc) { + pr_debug("No CPC descriptor for CPU:%d\n", cpu); + return -ENODEV; + } + raw_spin_lock_irqsave(&cpc_desc->rmw_lock, flags); } - raw_spin_lock_irqsave(&cpc_desc->rmw_lock, flags); - switch (size) { - case 8: - prev_val = readb_relaxed(vaddr); - break; - case 16: - prev_val = readw_relaxed(vaddr); - break; - case 32: - prev_val = readl_relaxed(vaddr); - break; - case 64: - prev_val = readq_relaxed(vaddr); - break; - default: - raw_spin_unlock_irqrestore(&cpc_desc->rmw_lock, flags); - return -EFAULT; + if (reg->bit_offset || reg->bit_width != size) { + switch (size) { + case 8: + prev_val = readb_relaxed(vaddr); + break; + case 16: + prev_val = readw_relaxed(vaddr); + break; + case 32: + prev_val = readl_relaxed(vaddr); + break; + case 64: + prev_val = readq_relaxed(vaddr); + break; + default: + if (locked) + raw_spin_unlock_irqrestore(&cpc_desc->rmw_lock, + flags); + return -EFAULT; + } + val = MASK_VAL_WRITE(reg, prev_val, val); } - val = MASK_VAL_WRITE(reg, prev_val, val); } switch (size) { @@ -1208,7 +1288,7 @@ static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val) break; } - if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) + if (locked) raw_spin_unlock_irqrestore(&cpc_desc->rmw_lock, flags); return ret_val; @@ -1316,15 +1396,30 @@ static int cppc_set_reg_val(int cpu, enum cppc_regs reg_idx, u64 val) return cpc_write(cpu, reg, val); } +static bool cppc_desired_perf_readable(const struct cpc_desc *cpc_desc) +{ + return cpc_desc->version < CPPC_V4_REV; +} + /** * cppc_get_desired_perf - Get the desired performance register value. * @cpunum: CPU from which to get desired performance. * @desired_perf: Return address. * - * Return: 0 for success, -EIO otherwise. + * Return: 0 for success, -EOPNOTSUPP for _CPC revision 4 or later, and a + * negative errno otherwise. */ int cppc_get_desired_perf(int cpunum, u64 *desired_perf) { + struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum); + + if (!cpc_desc) + return -ENODEV; + + /* _CPC revision 4 no longer specifies Desired Performance as readable. */ + if (!cppc_desired_perf_readable(cpc_desc)) + return -EOPNOTSUPP; + return cppc_get_reg_val(cpunum, DESIRED_PERF, desired_perf); } EXPORT_SYMBOL_GPL(cppc_get_desired_perf); @@ -1819,15 +1914,16 @@ EXPORT_SYMBOL_GPL(cppc_set_enable); * @cpu: CPU for which to get performance controls. * @perf_ctrls: ptr to cppc_perf_ctrls. See cppc_acpi.h * + * Desired Performance is not read and is returned as 0. + * * Return: 0 for success with perf_ctrls, -ERRNO otherwise. */ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) { struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu); - struct cpc_register_resource *desired_perf_reg, - *min_perf_reg, *max_perf_reg, + struct cpc_register_resource *min_perf_reg, *max_perf_reg, *energy_perf_reg, *auto_sel_reg; - u64 desired_perf = 0, min = 0, max = 0, energy_perf = 0, auto_sel = 0; + u64 min = 0, max = 0, energy_perf = 0, auto_sel = 0; int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu); struct cppc_pcc_data *pcc_ss_data = NULL; int ret = 0, regs_in_pcc = 0; @@ -1842,15 +1938,14 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) return -EINVAL; } - desired_perf_reg = &cpc_desc->cpc_regs[DESIRED_PERF]; min_perf_reg = &cpc_desc->cpc_regs[MIN_PERF]; max_perf_reg = &cpc_desc->cpc_regs[MAX_PERF]; energy_perf_reg = &cpc_desc->cpc_regs[ENERGY_PERF]; auto_sel_reg = &cpc_desc->cpc_regs[AUTO_SEL_ENABLE]; /* Are any of the regs PCC ?*/ - if (CPC_IN_PCC(desired_perf_reg) || CPC_IN_PCC(min_perf_reg) || - CPC_IN_PCC(max_perf_reg) || CPC_IN_PCC(energy_perf_reg) || + if (CPC_IN_PCC(min_perf_reg) || CPC_IN_PCC(max_perf_reg) || + CPC_IN_PCC(energy_perf_reg) || CPC_IN_PCC(auto_sel_reg)) { if (pcc_ss_id < 0) { pr_debug("Invalid pcc_ss_id for CPU:%d\n", cpu); @@ -1881,12 +1976,7 @@ int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) } perf_ctrls->min_perf = min; - if (CPC_SUPPORTED(desired_perf_reg)) { - ret = cpc_read(cpu, desired_perf_reg, &desired_perf); - if (ret) - goto out_err; - } - perf_ctrls->desired_perf = desired_perf; + perf_ctrls->desired_perf = 0; if (CPC_SUPPORTED(energy_perf_reg)) { ret = cpc_read(cpu, energy_perf_reg, &energy_perf); @@ -1922,6 +2012,7 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) struct cpc_register_resource *desired_reg, *min_perf_reg, *max_perf_reg; int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu); struct cppc_pcc_data *pcc_ss_data = NULL; + bool regs_in_pcc; int ret = 0; if (!cpc_desc) { @@ -1932,6 +2023,8 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) desired_reg = &cpc_desc->cpc_regs[DESIRED_PERF]; min_perf_reg = &cpc_desc->cpc_regs[MIN_PERF]; max_perf_reg = &cpc_desc->cpc_regs[MAX_PERF]; + regs_in_pcc = CPC_IN_PCC(desired_reg) || CPC_IN_PCC(min_perf_reg) || + CPC_IN_PCC(max_perf_reg); /* * This is Phase-I where we want to write to CPC registers @@ -1940,7 +2033,7 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) * Since read_lock can be acquired by multiple CPUs simultaneously we * achieve that goal here */ - if (CPC_IN_PCC(desired_reg) || CPC_IN_PCC(min_perf_reg) || CPC_IN_PCC(max_perf_reg)) { + if (regs_in_pcc) { if (pcc_ss_id < 0) { pr_debug("Invalid pcc_ss_id\n"); return -ENODEV; @@ -1976,7 +2069,7 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) if (perf_ctrls->max_perf && CPC_SUPPORTED(max_perf_reg)) cpc_write(cpu, max_perf_reg, perf_ctrls->max_perf); - if (CPC_IN_PCC(desired_reg) || CPC_IN_PCC(min_perf_reg) || CPC_IN_PCC(max_perf_reg)) + if (regs_in_pcc) up_read(&pcc_ss_data->pcc_lock); /* END Phase-I */ /* * This is Phase-II where we transfer the ownership of PCC to Platform @@ -2024,7 +2117,7 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) * case during a CMD_READ and if there are pending writes it delivers * the write command before servicing the read command */ - if (CPC_IN_PCC(desired_reg) || CPC_IN_PCC(min_perf_reg) || CPC_IN_PCC(max_perf_reg)) { + if (regs_in_pcc) { if (down_write_trylock(&pcc_ss_data->pcc_lock)) {/* BEGIN Phase-II */ /* Update only if there are pending write commands */ if (pcc_ss_data->pending_pcc_write_cmd) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 64ad4cfa6208..a89f10256dbb 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -1510,6 +1510,24 @@ static bool install_gpio_irq_event_handler(struct acpi_ec *ec) IRQF_SHARED | IRQF_ONESHOT, "ACPI EC", ec) >= 0; } +static int ec_prepare_gpio_irq(struct acpi_ec *ec, struct acpi_device *device) +{ + int irq; + + if (!device || ec->gpe >= 0 || ec->irq >= 0) + return 0; + + /* ACPI reduced hardware platforms use a GpioInt from _CRS. */ + irq = acpi_dev_gpio_irq_get(device, 0); + if (irq == -EPROBE_DEFER) + return irq; + + if (irq >= 0) + ec->irq = irq; + + return 0; +} + /** * ec_install_handlers - Install service callbacks and register query methods. * @ec: Target EC. @@ -1524,7 +1542,6 @@ static bool install_gpio_irq_event_handler(struct acpi_ec *ec) * Return: * -ENODEV if the address space handler cannot be installed, which means * "unable to handle transactions", - * -EPROBE_DEFER if GPIO IRQ acquisition needs to be deferred, * or 0 (success) otherwise. */ static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device, @@ -1557,19 +1574,6 @@ static int ec_install_handlers(struct acpi_ec *ec, struct acpi_device *device, if (!device) return 0; - if (ec->gpe < 0) { - /* ACPI reduced hardware platforms use a GpioInt from _CRS. */ - int irq = acpi_dev_gpio_irq_get(device, 0); - /* - * Bail out right away for deferred probing or complete the - * initialization regardless of any other errors. - */ - if (irq == -EPROBE_DEFER) - return -EPROBE_DEFER; - else if (irq >= 0) - ec->irq = irq; - } - if (!test_bit(EC_FLAGS_QUERY_METHODS_INSTALLED, &ec->flags)) { /* Find and register all query methods */ acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1, @@ -1647,6 +1651,14 @@ static int acpi_ec_setup(struct acpi_ec *ec, struct acpi_device *device, bool ca { int ret; + /* + * GPIO IRQ lookup can defer. Do it before publishing the EC + * OpRegion to AML to avoid a spurious _REG(disconnect). + */ + ret = ec_prepare_gpio_irq(ec, device); + if (ret) + return ret; + /* First EC capable of handling transactions */ if (!first_ec) first_ec = ec; diff --git a/drivers/acpi/fan.h b/drivers/acpi/fan.h index 97ce3212edf3..e20d6ad9df80 100644 --- a/drivers/acpi/fan.h +++ b/drivers/acpi/fan.h @@ -10,20 +10,21 @@ #ifndef _ACPI_FAN_H_ #define _ACPI_FAN_H_ -#include <linux/kconfig.h> +#include <linux/device.h> #include <linux/limits.h> +#include <linux/types.h> -#define ACPI_FAN_DEVICE_IDS \ - {"INT3404", }, /* Fan */ \ - {"INTC1044", }, /* Fan for Tiger Lake generation */ \ - {"INTC1048", }, /* Fan for Alder Lake generation */ \ - {"INTC1063", }, /* Fan for Meteor Lake generation */ \ - {"INTC106A", }, /* Fan for Lunar Lake generation */ \ - {"INTC10A2", }, /* Fan for Raptor Lake generation */ \ - {"INTC10D6", }, /* Fan for Panther Lake generation */ \ - {"INTC10FE", }, /* Fan for Wildcat Lake generation */ \ - {"INTC10F5", }, /* Fan for Nova Lake generation */ \ - {"PNP0C0B", } /* Generic ACPI fan */ +#define ACPI_FAN_DEVICE_IDS \ + { .id = "INT3404" }, /* Fan */ \ + { .id = "INTC1044" }, /* Fan for Tiger Lake generation */ \ + { .id = "INTC1048" }, /* Fan for Alder Lake generation */ \ + { .id = "INTC1063" }, /* Fan for Meteor Lake generation */ \ + { .id = "INTC106A" }, /* Fan for Lunar Lake generation */ \ + { .id = "INTC10A2" }, /* Fan for Raptor Lake generation */ \ + { .id = "INTC10D6" }, /* Fan for Panther Lake generation */ \ + { .id = "INTC10FE" }, /* Fan for Wildcat Lake generation */ \ + { .id = "INTC10F5" }, /* Fan for Nova Lake generation */ \ + { .id = "PNP0C0B" } /* Generic ACPI fan */ #define ACPI_FPS_NAME_LEN 20 @@ -69,7 +70,7 @@ struct acpi_fan { /** * acpi_fan_speed_valid - Check if fan speed value is valid - * @speeed: Speed value returned by the ACPI firmware + * @speed: Speed value returned by the ACPI firmware * * Check if the fan speed value returned by the ACPI firmware is valid. This function is * necessary as ACPI firmware implementations can return 0xFFFFFFFF to signal that the diff --git a/drivers/acpi/fan_core.c b/drivers/acpi/fan_core.c index fb08b8549ed7..624d0736b581 100644 --- a/drivers/acpi/fan_core.c +++ b/drivers/acpi/fan_core.c @@ -489,26 +489,6 @@ static void acpi_fan_notify_handler(acpi_handle handle, u32 event, void *context } } -static void acpi_fan_notify_remove(void *data) -{ - struct acpi_fan *fan = data; - - acpi_remove_notify_handler(fan->handle, ACPI_DEVICE_NOTIFY, acpi_fan_notify_handler); -} - -static int devm_acpi_fan_notify_init(struct device *dev) -{ - struct acpi_fan *fan = dev_get_drvdata(dev); - acpi_status status; - - status = acpi_install_notify_handler(fan->handle, ACPI_DEVICE_NOTIFY, - acpi_fan_notify_handler, dev); - if (ACPI_FAILURE(status)) - return -EIO; - - return devm_add_action_or_reset(dev, acpi_fan_notify_remove, fan); -} - static int acpi_fan_probe(struct platform_device *pdev) { int result = 0; @@ -556,7 +536,10 @@ static int acpi_fan_probe(struct platform_device *pdev) if (result) return result; - result = devm_acpi_fan_notify_init(&pdev->dev); + result = devm_acpi_install_notify_handler(&pdev->dev, + ACPI_DEVICE_NOTIFY, + acpi_fan_notify_handler, + &pdev->dev); if (result) return result; diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c index d1595156c86a..e4293458bf61 100644 --- a/drivers/acpi/irq.c +++ b/drivers/acpi/irq.c @@ -13,6 +13,7 @@ enum acpi_irq_model_id acpi_irq_model; static acpi_gsi_domain_disp_fn acpi_get_gsi_domain_id; +static acpi_gsi_handle_disp_fn acpi_get_gsi_handle; static u32 (*acpi_gsi_to_irq_fallback)(u32 gsi); /** @@ -321,15 +322,19 @@ const struct cpumask *acpi_irq_get_affinity(acpi_handle handle, /** * acpi_set_irq_model - Setup the GSI irqdomain information - * @model: the value assigned to acpi_irq_model - * @fn: a dispatcher function that will return the domain fwnode - * for a given GSI + * @model: the value assigned to acpi_irq_model + * @fn: a dispatcher function that will return the domain fwnode + * for a given GSI + * @gsi_dep_fn: a function to retrieve the acpi_handle a GSI interrupt is + * dependent on + * */ void __init acpi_set_irq_model(enum acpi_irq_model_id model, - acpi_gsi_domain_disp_fn fn) + acpi_gsi_domain_disp_fn fn, acpi_gsi_handle_disp_fn gsi_dep_fn) { acpi_irq_model = model; acpi_get_gsi_domain_id = fn; + acpi_get_gsi_handle = gsi_dep_fn; } /* @@ -385,3 +390,162 @@ struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags, host_data); } EXPORT_SYMBOL_GPL(acpi_irq_create_hierarchy); + +struct acpi_irq_dep_ctx { + int rc; + unsigned int index; + acpi_handle handle; +}; + +static acpi_status acpi_irq_get_parent(struct acpi_resource *ares, void *context) +{ + struct acpi_irq_dep_ctx *ctx = context; + struct acpi_resource_irq *irq; + struct acpi_resource_extended_irq *eirq; + + switch (ares->type) { + case ACPI_RESOURCE_TYPE_IRQ: + irq = &ares->data.irq; + if (ctx->index >= irq->interrupt_count) { + ctx->index -= irq->interrupt_count; + return AE_OK; + } + ctx->handle = acpi_get_gsi_handle(irq->interrupts[ctx->index]); + ctx->rc = 0; + return AE_CTRL_TERMINATE; + case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: + eirq = &ares->data.extended_irq; + if (eirq->producer_consumer == ACPI_PRODUCER) + return AE_OK; + + if (ctx->index >= eirq->interrupt_count) { + ctx->index -= eirq->interrupt_count; + return AE_OK; + } + + /* Support GSIs only */ + if (eirq->resource_source.string_length) + return AE_OK; + + ctx->handle = acpi_get_gsi_handle(eirq->interrupts[ctx->index]); + ctx->rc = 0; + return AE_CTRL_TERMINATE; + } + + return AE_OK; +} + +static int acpi_irq_get_dep(acpi_handle handle, unsigned int index, acpi_handle *gsi_handle) +{ + struct acpi_irq_dep_ctx ctx = {-EINVAL, index, NULL}; + + if (!gsi_handle) + return -EINVAL; + + acpi_walk_resources(handle, METHOD_NAME__CRS, acpi_irq_get_parent, &ctx); + *gsi_handle = ctx.handle; + + return ctx.rc; +} + +static bool acpi_prt_entry_valid(void *prt_entry) +{ + struct acpi_pci_routing_table *entry = prt_entry; + + return entry && entry->length > 0; +} + +static void *acpi_prt_next_entry(void *prt_entry) +{ + struct acpi_pci_routing_table *entry = prt_entry; + + return prt_entry + entry->length; +} + +static u32 acpi_add_prt_dep(acpi_handle handle) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + struct acpi_pci_routing_table *entry; + struct acpi_handle_list dep_devices; + acpi_handle gsi_handle; + acpi_handle link_handle; + acpi_status status; + u32 count = 0; + + status = acpi_get_irq_routing_table(handle, &buffer); + if (ACPI_FAILURE(status)) { + acpi_handle_err(handle, "failed to get IRQ routing table\n"); + kfree(buffer.pointer); + return 0; + } + + entry = buffer.pointer; + for (; acpi_prt_entry_valid(entry); entry = acpi_prt_next_entry(entry)) { + if (entry->source[0]) { + status = acpi_get_handle(handle, entry->source, &link_handle); + if (ACPI_FAILURE(status)) + continue; + dep_devices.count = 1; + dep_devices.handles = kcalloc(1, sizeof(*dep_devices.handles), GFP_KERNEL); + if (!dep_devices.handles) { + acpi_handle_err(handle, "failed to allocate memory\n"); + continue; + } + + dep_devices.handles[0] = link_handle; + count += acpi_scan_add_dep(handle, &dep_devices); + } else { + gsi_handle = acpi_get_gsi_handle(entry->source_index); + if (!gsi_handle) + continue; + dep_devices.count = 1; + dep_devices.handles = kcalloc(1, sizeof(*dep_devices.handles), GFP_KERNEL); + if (!dep_devices.handles) { + acpi_handle_err(handle, "failed to allocate memory\n"); + continue; + } + + dep_devices.handles[0] = gsi_handle; + count += acpi_scan_add_dep(handle, &dep_devices); + } + } + + kfree(buffer.pointer); + return count; +} + +static u32 acpi_add_irq_dep(acpi_handle handle) +{ + struct acpi_handle_list dep_devices; + acpi_handle gsi_handle; + u32 count = 0; + int i; + + for (i = 0; !acpi_irq_get_dep(handle, i, &gsi_handle); i++) { + if (!gsi_handle) + continue; + + dep_devices.count = 1; + dep_devices.handles = kcalloc(1, sizeof(*dep_devices.handles), GFP_KERNEL); + if (!dep_devices.handles) { + acpi_handle_err(handle, "failed to allocate memory\n"); + continue; + } + + dep_devices.handles[0] = gsi_handle; + count += acpi_scan_add_dep(handle, &dep_devices); + } + + return count; +} + +u32 acpi_irq_add_auto_dep(acpi_handle handle) +{ + if (!acpi_get_gsi_handle) + return 0; + + if (acpi_has_method(handle, "_PRT")) + return acpi_add_prt_dep(handle); + + return acpi_add_irq_dep(handle); +} diff --git a/drivers/acpi/numa/srat.c b/drivers/acpi/numa/srat.c index 62d4a8df0b8c..5c407dc6401e 100644 --- a/drivers/acpi/numa/srat.c +++ b/drivers/acpi/numa/srat.c @@ -399,8 +399,6 @@ acpi_parse_memory_affinity(union acpi_subtable_headers *header, goto out_err_bad_srat; } - node_set(node, numa_nodes_parsed); - pr_info("SRAT: Node %u PXM %u [mem %#010Lx-%#010Lx]%s%s\n", node, pxm, (unsigned long long) start, (unsigned long long) end - 1, diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c index 6eaad7dd0241..12aee4102696 100644 --- a/drivers/acpi/nvs.c +++ b/drivers/acpi/nvs.c @@ -133,7 +133,7 @@ void suspend_nvs_free(void) list_for_each_entry(entry, &nvs_list, node) if (entry->data) { - free_page((unsigned long)entry->data); + kfree(entry->data); entry->data = NULL; if (entry->kaddr) { if (entry->unmap) { @@ -156,7 +156,7 @@ int suspend_nvs_alloc(void) struct nvs_page *entry; list_for_each_entry(entry, &nvs_list, node) { - entry->data = (void *)__get_free_page(GFP_KERNEL); + entry->data = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!entry->data) { suspend_nvs_free(); return -ENOMEM; diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 4c06c3ffd0cb..88c65f34e305 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -8,6 +8,7 @@ #define pr_fmt(fmt) "ACPI: " fmt +#include <linux/cleanup.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> @@ -292,41 +293,37 @@ struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle) EXPORT_SYMBOL_GPL(acpi_pci_find_root); /** - * acpi_get_pci_dev - convert ACPI CA handle to struct pci_dev - * @handle: the handle in question + * acpi_dev_get_pci_dev - Get a struct pci_dev for a given ACPI device + * @adev: Target ACPI device. * - * Given an ACPI CA handle, the desired PCI device is located in the - * list of PCI devices. + * Find the PCI device associated with @adev, if any, and bump up its reference + * counter. * - * If the device is found, its reference count is increased and this - * function returns a pointer to its data structure. The caller must - * decrement the reference count by calling pci_dev_put(). - * If no device is found, %NULL is returned. + * Callers are responsible for dropping the PCI device reference obtained by + * this function. + * + * Return: The struct pci_dev pointer of a reference-counted PCI device on + * success or NULL on failure. */ -struct pci_dev *acpi_get_pci_dev(acpi_handle handle) +struct pci_dev *acpi_dev_get_pci_dev(struct acpi_device *adev) { - struct acpi_device *adev = acpi_fetch_acpi_dev(handle); struct acpi_device_physical_node *pn; - struct pci_dev *pci_dev = NULL; if (!adev) return NULL; - mutex_lock(&adev->physical_node_lock); + guard(mutex)(&adev->physical_node_lock); list_for_each_entry(pn, &adev->physical_node_list, node) { if (dev_is_pci(pn->dev)) { get_device(pn->dev); - pci_dev = to_pci_dev(pn->dev); - break; + return to_pci_dev(pn->dev); } } - mutex_unlock(&adev->physical_node_lock); - - return pci_dev; + return NULL; } -EXPORT_SYMBOL_GPL(acpi_get_pci_dev); +EXPORT_SYMBOL_GPL(acpi_dev_get_pci_dev); /** * acpi_pci_osc_control_set - Request control of PCI root _OSC features. @@ -574,6 +571,13 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm) return; } + if (!is_pcie(root) && !is_cxl(root) && !acpi_has_method(handle, "_OSC")) { + dev_dbg(&device->dev, "Non-PCIe host bridge without _OSC, skipping\n"); + + *no_aspm = 1; + return; + } + support = calculate_support(); decode_osc_support(root, "OS supports", support); @@ -615,10 +619,6 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm) */ *no_aspm = 1; - /* _OSC is optional for PCI host bridges */ - if (status == AE_NOT_FOUND && !is_pcie(root)) - return; - if (control) { decode_osc_control(root, "OS requested", requested); decode_osc_control(root, "platform willing to grant", control); @@ -725,7 +725,6 @@ static int acpi_pci_root_add(struct acpi_device *device, dev_err(&device->dev, "Bus %04x:%02x not present in PCI namespace\n", root->segment, (unsigned int)root->secondary.start); - device->driver_data = NULL; result = -ENODEV; goto remove_dmar; } @@ -765,6 +764,7 @@ remove_dmar: if (hotadd) dmar_device_remove(handle); end: + device->driver_data = NULL; kfree(root); return result; } @@ -788,6 +788,7 @@ static void acpi_pci_root_remove(struct acpi_device *device) pci_unlock_rescan_remove(); + device->driver_data = NULL; kfree(root); } diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index d4131c184be8..23a4e207a01e 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -954,7 +954,6 @@ struct acpi_device *acpi_add_power_resource(acpi_handle handle) INIT_LIST_HEAD(&resource->list_node); INIT_LIST_HEAD(&resource->dependents); device->power.state = ACPI_STATE_UNKNOWN; - device->flags.match_driver = true; /* Evaluate the object to get the system level and resource order. */ status = acpi_evaluate_object(handle, NULL, NULL, &buffer); diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index a4498357bd16..3bf076c150fa 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -336,11 +336,26 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id) EXPORT_SYMBOL_GPL(acpi_get_cpuid); #ifdef CONFIG_ACPI_HOTPLUG_IOAPIC -static int get_ioapic_id(struct acpi_subtable_header *entry, u32 gsi_base, +static bool madt_entry_is_valid(struct acpi_subtable_header *entry, + unsigned long end) +{ + unsigned long start = (unsigned long)entry; + + if (start >= end || end - start < sizeof(*entry)) + return false; + + return entry->length >= sizeof(*entry) && entry->length <= end - start; +} + +static int get_ioapic_id(struct acpi_subtable_header *entry, + const unsigned long end, u32 gsi_base, u64 *phys_addr, int *ioapic_id) { struct acpi_madt_io_apic *ioapic = (struct acpi_madt_io_apic *)entry; + if (!madt_entry_is_valid(entry, end) || BAD_MADT_ENTRY(ioapic, end)) + return 0; + if (ioapic->global_irq_base != gsi_base) return 0; @@ -361,17 +376,19 @@ static int parse_madt_ioapic_entry(u32 gsi_base, u64 *phys_addr) return apic_id; entry = (unsigned long)madt; + if (madt->header.length < sizeof(*madt)) + return apic_id; madt_end = entry + madt->header.length; /* Parse all entries looking for a match. */ entry += sizeof(struct acpi_table_madt); - while (entry + sizeof(struct acpi_subtable_header) < madt_end) { + while (madt_entry_is_valid((struct acpi_subtable_header *)entry, + madt_end)) { hdr = (struct acpi_subtable_header *)entry; if (hdr->type == ACPI_MADT_TYPE_IO_APIC && - get_ioapic_id(hdr, gsi_base, phys_addr, &apic_id)) + get_ioapic_id(hdr, madt_end, gsi_base, phys_addr, &apic_id)) break; - else - entry += hdr->length; + entry += hdr->length; } return apic_id; @@ -398,7 +415,9 @@ static int parse_mat_ioapic_entry(acpi_handle handle, u32 gsi_base, header = (struct acpi_subtable_header *)obj->buffer.pointer; if (header->type == ACPI_MADT_TYPE_IO_APIC) - get_ioapic_id(header, gsi_base, phys_addr, &apic_id); + get_ioapic_id(header, + (unsigned long)header + obj->buffer.length, + gsi_base, phys_addr, &apic_id); exit: kfree(buffer.pointer); diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index cda8fd720000..cdc2ae1632b2 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -285,6 +285,12 @@ err: unregister_idle_drv: acpi_processor_unregister_idle_driver(); + if (acpi_processor_cpufreq_init) { + cpufreq_unregister_notifier(&acpi_processor_notifier_block, + CPUFREQ_POLICY_NOTIFIER); + acpi_processor_cpufreq_init = false; + } + return result; } diff --git a/drivers/acpi/riscv/irq.c b/drivers/acpi/riscv/irq.c index 9b88d0993e88..da2c42e0ebfd 100644 --- a/drivers/acpi/riscv/irq.c +++ b/drivers/acpi/riscv/irq.c @@ -23,12 +23,6 @@ struct riscv_ext_intc_list { struct list_head list; }; -struct acpi_irq_dep_ctx { - int rc; - unsigned int index; - acpi_handle handle; -}; - LIST_HEAD(ext_intc_list); static int irqchip_cmp_func(const void *in0, const void *in1) @@ -254,7 +248,7 @@ void __init riscv_acpi_init_gsi_mapping(void) acpi_get_devices("RSCV0006", riscv_acpi_create_gsi_map_smsi, NULL, NULL); } -static acpi_handle riscv_acpi_get_gsi_handle(u32 gsi) +acpi_handle acpi_get_riscv_gsi_handle(u32 gsi) { struct riscv_ext_intc_list *ext_intc_element; struct list_head *i; @@ -269,138 +263,7 @@ static acpi_handle riscv_acpi_get_gsi_handle(u32 gsi) return NULL; } -static acpi_status riscv_acpi_irq_get_parent(struct acpi_resource *ares, void *context) -{ - struct acpi_irq_dep_ctx *ctx = context; - struct acpi_resource_irq *irq; - struct acpi_resource_extended_irq *eirq; - - switch (ares->type) { - case ACPI_RESOURCE_TYPE_IRQ: - irq = &ares->data.irq; - if (ctx->index >= irq->interrupt_count) { - ctx->index -= irq->interrupt_count; - return AE_OK; - } - ctx->handle = riscv_acpi_get_gsi_handle(irq->interrupts[ctx->index]); - return AE_CTRL_TERMINATE; - case ACPI_RESOURCE_TYPE_EXTENDED_IRQ: - eirq = &ares->data.extended_irq; - if (eirq->producer_consumer == ACPI_PRODUCER) - return AE_OK; - - if (ctx->index >= eirq->interrupt_count) { - ctx->index -= eirq->interrupt_count; - return AE_OK; - } - - /* Support GSIs only */ - if (eirq->resource_source.string_length) - return AE_OK; - - ctx->handle = riscv_acpi_get_gsi_handle(eirq->interrupts[ctx->index]); - return AE_CTRL_TERMINATE; - } - - return AE_OK; -} - -static int riscv_acpi_irq_get_dep(acpi_handle handle, unsigned int index, acpi_handle *gsi_handle) -{ - struct acpi_irq_dep_ctx ctx = {-EINVAL, index, NULL}; - - if (!gsi_handle) - return 0; - - acpi_walk_resources(handle, METHOD_NAME__CRS, riscv_acpi_irq_get_parent, &ctx); - *gsi_handle = ctx.handle; - if (*gsi_handle) - return 1; - - return 0; -} - -static u32 riscv_acpi_add_prt_dep(acpi_handle handle) -{ - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - struct acpi_pci_routing_table *entry; - struct acpi_handle_list dep_devices; - acpi_handle gsi_handle; - acpi_handle link_handle; - acpi_status status; - u32 count = 0; - - status = acpi_get_irq_routing_table(handle, &buffer); - if (ACPI_FAILURE(status)) { - acpi_handle_err(handle, "failed to get IRQ routing table\n"); - kfree(buffer.pointer); - return 0; - } - - entry = buffer.pointer; - while (entry && (entry->length > 0)) { - if (entry->source[0]) { - acpi_get_handle(handle, entry->source, &link_handle); - dep_devices.count = 1; - dep_devices.handles = kzalloc_objs(*dep_devices.handles, - 1); - if (!dep_devices.handles) { - acpi_handle_err(handle, "failed to allocate memory\n"); - continue; - } - - dep_devices.handles[0] = link_handle; - count += acpi_scan_add_dep(handle, &dep_devices); - } else { - gsi_handle = riscv_acpi_get_gsi_handle(entry->source_index); - dep_devices.count = 1; - dep_devices.handles = kzalloc_objs(*dep_devices.handles, - 1); - if (!dep_devices.handles) { - acpi_handle_err(handle, "failed to allocate memory\n"); - continue; - } - - dep_devices.handles[0] = gsi_handle; - count += acpi_scan_add_dep(handle, &dep_devices); - } - - entry = (struct acpi_pci_routing_table *) - ((unsigned long)entry + entry->length); - } - - kfree(buffer.pointer); - return count; -} - -static u32 riscv_acpi_add_irq_dep(acpi_handle handle) -{ - struct acpi_handle_list dep_devices; - acpi_handle gsi_handle; - u32 count = 0; - int i; - - for (i = 0; - riscv_acpi_irq_get_dep(handle, i, &gsi_handle); - i++) { - dep_devices.count = 1; - dep_devices.handles = kzalloc_objs(*dep_devices.handles, 1); - if (!dep_devices.handles) { - acpi_handle_err(handle, "failed to allocate memory\n"); - continue; - } - - dep_devices.handles[0] = gsi_handle; - count += acpi_scan_add_dep(handle, &dep_devices); - } - - return count; -} - u32 arch_acpi_add_auto_dep(acpi_handle handle) { - if (acpi_has_method(handle, "_PRT")) - return riscv_acpi_add_prt_dep(handle); - - return riscv_acpi_add_irq_dep(handle); + return acpi_irq_add_auto_dep(handle); } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 9a7ac2eb9ce0..e9e374f2ad66 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -273,13 +273,9 @@ static int acpi_scan_check_and_detach(struct acpi_device *adev, void *p) } } - adev->flags.match_driver = false; - if (handler) { - if (handler->detach) - handler->detach(adev); - } else { - device_release_driver(&adev->dev); - } + if (handler && handler->detach) + handler->detach(adev); + /* * Most likely, the device is going away, so put it into D3cold before * that. @@ -854,6 +850,7 @@ static const char * const acpi_ignore_dep_ids[] = { /* List of HIDs for which we honor deps of matching ACPI devs, when checking _DEP lists. */ static const char * const acpi_honor_dep_ids[] = { + "ARMH0003", /* ARM GICv5 IWB */ "INT3472", /* Camera sensor PMIC / clk and regulator info */ "INTC1059", /* IVSC (TGL) driver must be loaded to allow i2c access to camera sensors */ "INTC1095", /* IVSC (ADL) driver must be loaded to allow i2c access to camera sensors */ @@ -1768,7 +1765,6 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device) * Some ACPI devs contain SerialBus resources even though they are not * attached to a serial bus at all. */ - {ACPI_VIDEO_HID, }, {"MSHW0028", }, /* * HIDs of device with an UartSerialBusV2 resource for which userspace @@ -1791,6 +1787,9 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device) fwnode_property_present(&device->fwnode, "baud"))) return true; + if (acpi_dev_is_video_device(device)) + return false; + if (!acpi_match_device_ids(device, ignore_serial_bus_ids)) return false; @@ -1815,13 +1814,13 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, device->dev.release = release; device->dev.bus = &acpi_bus_type; device->dev.groups = acpi_groups; + device_set_pm_not_required(&device->dev); fwnode_init(&device->fwnode, &acpi_device_fwnode_ops); acpi_set_device_status(device, ACPI_STA_DEFAULT); acpi_device_get_busid(device); acpi_set_pnp_ids(handle, &device->pnp, type); acpi_init_properties(device); acpi_bus_get_flags(device); - device->flags.match_driver = false; device->flags.initialized = true; device->flags.enumeration_by_parent = acpi_device_enumeration_by_parent(device); @@ -2375,16 +2374,11 @@ static int acpi_bus_attach(struct acpi_device *device, void *first_pass) if (ret < 0) return 0; - device->flags.match_driver = true; if (ret > 0 && !device->flags.enumeration_by_parent) { acpi_device_set_enumerated(device); goto ok; } - ret = device_attach(&device->dev); - if (ret < 0) - return 0; - if (device->pnp.type.platform_id || device->pnp.type.backlight || device->flags.enumeration_by_parent) acpi_default_enumeration(device); diff --git a/drivers/acpi/sysfs.c b/drivers/acpi/sysfs.c index 908cc5c7e643..dd4a99f09efe 100644 --- a/drivers/acpi/sysfs.c +++ b/drivers/acpi/sysfs.c @@ -316,6 +316,7 @@ struct acpi_table_attr { struct acpi_data_attr { struct bin_attribute attr; u64 addr; + char filename[ACPI_NAMESEG_SIZE+ACPI_INST_SIZE]; }; static ssize_t acpi_table_show(struct file *filp, struct kobject *kobj, @@ -447,13 +448,12 @@ static int acpi_bert_data_init(void *th, struct acpi_data_attr *data_attr) struct acpi_table_bert *bert = th; if (bert->header.length < sizeof(struct acpi_table_bert) || - bert->region_length < sizeof(struct acpi_hest_generic_status)) { + bert->region_length < sizeof(struct acpi_bert_region)) { kfree(data_attr); return -EINVAL; } data_attr->addr = bert->address; data_attr->attr.size = bert->region_length; - data_attr->attr.attr.name = "BERT"; return sysfs_create_bin_file(tables_data_kobj, &data_attr->attr); } @@ -469,7 +469,6 @@ static int acpi_ccel_data_init(void *th, struct acpi_data_attr *data_attr) } data_attr->addr = ccel->log_area_start_address; data_attr->attr.size = ccel->log_area_minimum_length; - data_attr->attr.attr.name = "CCEL"; return sysfs_create_bin_file(tables_data_kobj, &data_attr->attr); } @@ -484,7 +483,7 @@ static struct acpi_data_obj { #define NUM_ACPI_DATA_OBJS ARRAY_SIZE(acpi_data_objs) -static int acpi_table_data_init(struct acpi_table_header *th) +static int acpi_table_data_init(struct acpi_table_header *th, struct acpi_table_attr *table_attr) { struct acpi_data_attr *data_attr; int i; @@ -497,6 +496,8 @@ static int acpi_table_data_init(struct acpi_table_header *th) sysfs_attr_init(&data_attr->attr.attr); data_attr->attr.read = acpi_data_show; data_attr->attr.attr.mode = 0400; + strscpy(data_attr->filename, table_attr->filename); + data_attr->attr.attr.name = data_attr->filename; return acpi_data_objs[i].fn(th, data_attr); } } @@ -543,7 +544,7 @@ static int acpi_tables_sysfs_init(void) return ret; } list_add_tail(&table_attr->node, &acpi_table_attr_list); - acpi_table_data_init(table_header); + acpi_table_data_init(table_header, table_attr); } kobject_uevent(tables_kobj, KOBJ_ADD); diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 6ab27e4826d1..d499b72574ab 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -1048,6 +1048,23 @@ static int __init acpi_backlight(char *str) __setup("acpi_backlight=", acpi_backlight); /** + * acpi_dev_is_video_device - test if device matches against ACPI video device IDs + * @adev: ACPI device to test + * + * Return: true when matches, otherwise false. + */ +bool acpi_dev_is_video_device(struct acpi_device *adev) +{ + static const struct acpi_device_id video_device_ids[] = { + { .id = ACPI_VIDEO_HID }, + { } + }; + + return adev && !acpi_match_device_ids(adev, video_device_ids); +} +EXPORT_SYMBOL(acpi_dev_is_video_device); + +/** * acpi_match_platform_list - Check if the system matches with a given list * @plat: pointer to acpi_platform_list table terminated by a NULL entry * diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index 458efa4fe9d4..e3b69f876d24 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -67,13 +67,8 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv) long *cap = context; struct pci_dev *dev; - static const struct acpi_device_id video_ids[] = { - {ACPI_VIDEO_HID, 0}, - {"", 0}, - }; - - if (acpi_dev && !acpi_match_device_ids(acpi_dev, video_ids)) { - dev = acpi_get_pci_dev(handle); + if (acpi_dev_is_video_device(acpi_dev)) { + dev = acpi_dev_get_pci_dev(acpi_dev); if (!dev) return AE_OK; pci_dev_put(dev); @@ -137,8 +132,10 @@ static int video_detect_portege_r100(const struct dmi_system_id *d) struct pci_dev *dev; /* Search for Trident CyberBlade XP4m32 to confirm Portégé R100 */ dev = pci_get_device(PCI_VENDOR_ID_TRIDENT, 0x2100, NULL); - if (dev) + if (dev) { acpi_backlight_dmi = acpi_backlight_vendor; + pci_dev_put(dev); + } return 0; } @@ -924,6 +921,14 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "OMEN by HP Gaming Laptop 16-n0xxx"), }, }, + { + .callback = video_detect_force_native, + /* Acer Nitro AN515-46 */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Nitro AN515-46"), + }, + }, /* * x86 android tablets which directly control the backlight through diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index 6fe0e972952a..80893844353c 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c @@ -836,7 +836,7 @@ out_invalid_counters: * value first as some platforms may update the actual delivered perf * there; if failed, resort to the cached desired perf. */ - if (cppc_get_desired_perf(cpu, &delivered_perf)) + if (cppc_get_desired_perf(cpu, &delivered_perf) || !delivered_perf) delivered_perf = cpu_data->perf_ctrls.desired_perf; return cppc_perf_to_khz(&cpu_data->perf_caps, delivered_perf); diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index e5fddacae9a4..42a7e777346b 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -131,15 +131,6 @@ static int i2c_acpi_fill_info(struct acpi_resource *ares, void *data) return 1; } -static const struct acpi_device_id i2c_acpi_ignored_device_ids[] = { - /* - * ACPI video acpi_devices, which are handled by the acpi-video driver - * sometimes contain a SERIAL_TYPE_I2C ACPI resource, ignore these. - */ - { ACPI_VIDEO_HID, 0 }, - {} -}; - struct i2c_acpi_irq_context { int irq; bool wake_capable; @@ -158,7 +149,11 @@ static int i2c_acpi_do_lookup(struct acpi_device *adev, if (!acpi_dev_ready_for_enumeration(adev)) return -ENODEV; - if (acpi_match_device_ids(adev, i2c_acpi_ignored_device_ids) == 0) + /* + * ACPI video devices, which are handled by the acpi-video driver, + * sometimes contain a SERIAL_TYPE_I2C ACPI resource, ignore these. + */ + if (acpi_dev_is_video_device(adev)) return -ENODEV; memset(info, 0, sizeof(*info)); diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 99444a1b2ffa..2673954d4577 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -2588,7 +2588,7 @@ gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end) if (err) goto out_fwhandle_free; - acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v3_get_gsi_domain_id); + acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v3_get_gsi_domain_id, NULL); if (static_branch_likely(&supports_deactivate_key)) gic_acpi_setup_kvm_info(); diff --git a/drivers/irqchip/irq-gic-v5-iwb.c b/drivers/irqchip/irq-gic-v5-iwb.c index 9103feb70ce8..6b02b90d9cce 100644 --- a/drivers/irqchip/irq-gic-v5-iwb.c +++ b/drivers/irqchip/irq-gic-v5-iwb.c @@ -269,6 +269,8 @@ static int gicv5_iwb_device_probe(struct platform_device *pdev) if (IS_ERR(iwb_node)) return PTR_ERR(iwb_node); + acpi_device_clear_deps(&pdev->dev); + return 0; } diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c index e9d1795235a6..5dcf404ab4c8 100644 --- a/drivers/irqchip/irq-gic-v5.c +++ b/drivers/irqchip/irq-gic-v5.c @@ -1226,11 +1226,19 @@ static struct fwnode_handle *gsi_domain_handle; static struct fwnode_handle *gic_v5_get_gsi_domain_id(u32 gsi) { if (FIELD_GET(GICV5_GSI_IC_TYPE, gsi) == GICV5_GSI_IWB_TYPE) - return iort_iwb_handle(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi)); + return iort_iwb_handle_fwnode(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi)); return gsi_domain_handle; } +static acpi_handle gic_v5_get_gsi_handle(u32 gsi) +{ + if (FIELD_GET(GICV5_GSI_IC_TYPE, gsi) == GICV5_GSI_IWB_TYPE) + return iort_iwb_handle(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi)); + + return NULL; +} + static int __init gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end) { struct acpi_madt_gicv5_irs *irs = (struct acpi_madt_gicv5_irs *)header; @@ -1251,7 +1259,8 @@ static int __init gic_acpi_init(union acpi_subtable_headers *header, const unsig if (ret) goto out_irs; - acpi_set_irq_model(ACPI_IRQ_MODEL_GIC_V5, gic_v5_get_gsi_domain_id); + acpi_set_irq_model(ACPI_IRQ_MODEL_GIC_V5, gic_v5_get_gsi_domain_id, + gic_v5_get_gsi_handle); return 0; diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index ec70c84e9f91..f6bc29f515fb 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -1690,7 +1690,7 @@ static int __init gic_v2_acpi_init(union acpi_subtable_headers *header, return ret; } - acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v2_get_gsi_domain_id); + acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v2_get_gsi_domain_id, NULL); if (IS_ENABLED(CONFIG_ARM_GIC_V2M)) gicv2m_init(NULL, gic_data[0].domain); diff --git a/drivers/irqchip/irq-loongarch-cpu.c b/drivers/irqchip/irq-loongarch-cpu.c index 950bc087e388..84ce24889488 100644 --- a/drivers/irqchip/irq-loongarch-cpu.c +++ b/drivers/irqchip/irq-loongarch-cpu.c @@ -168,7 +168,7 @@ static int __init cpuintc_acpi_init(union acpi_subtable_headers *header, panic("Failed to add irqdomain for LoongArch CPU"); set_handle_irq(&handle_cpu_irq); - acpi_set_irq_model(ACPI_IRQ_MODEL_LPIC, lpic_get_gsi_domain_id); + acpi_set_irq_model(ACPI_IRQ_MODEL_LPIC, lpic_get_gsi_domain_id, NULL); acpi_set_gsi_to_irq_fallback(lpic_gsi_to_irq); ret = acpi_cascade_irqdomain_init(); diff --git a/drivers/irqchip/irq-riscv-intc.c b/drivers/irqchip/irq-riscv-intc.c index 84418dbd5a27..0595144116e2 100644 --- a/drivers/irqchip/irq-riscv-intc.c +++ b/drivers/irqchip/irq-riscv-intc.c @@ -384,7 +384,8 @@ static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header, if (rc) irq_domain_free_fwnode(fn); else - acpi_set_irq_model(ACPI_IRQ_MODEL_RINTC, riscv_acpi_get_gsi_domain_id); + acpi_set_irq_model(ACPI_IRQ_MODEL_RINTC, riscv_acpi_get_gsi_domain_id, + acpi_get_riscv_gsi_handle); return rc; } diff --git a/drivers/pci/vgaarb.c b/drivers/pci/vgaarb.c index c360eee11dd9..3de05aee7859 100644 --- a/drivers/pci/vgaarb.c +++ b/drivers/pci/vgaarb.c @@ -575,9 +575,7 @@ static bool vga_is_firmware_default(struct pci_dev *pdev) static bool vga_arb_integrated_gpu(struct device *dev) { #if defined(CONFIG_ACPI) - struct acpi_device *adev = ACPI_COMPANION(dev); - - return adev && !strcmp(acpi_device_hid(adev), ACPI_VIDEO_HID); + return acpi_dev_is_video_device(ACPI_COMPANION(dev)); #else return false; #endif diff --git a/drivers/platform/x86/lenovo/thinkpad_acpi.c b/drivers/platform/x86/lenovo/thinkpad_acpi.c index 445e1403308e..b528a1e67dd3 100644 --- a/drivers/platform/x86/lenovo/thinkpad_acpi.c +++ b/drivers/platform/x86/lenovo/thinkpad_acpi.c @@ -768,7 +768,7 @@ static acpi_status __init tpacpi_acpi_handle_locate_callback(acpi_handle handle, if (!strcmp(context, "video")) { struct acpi_device *dev = acpi_fetch_acpi_dev(handle); - if (!dev || strcmp(ACPI_VIDEO_HID, acpi_device_hid(dev))) + if (!acpi_dev_is_video_device(dev)) return AE_OK; } diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c index 87f5af454751..df5e3d3cbf6c 100644 --- a/drivers/pnp/card.c +++ b/drivers/pnp/card.c @@ -254,9 +254,16 @@ int pnp_add_card(struct pnp_card *card) /* we wait until now to add devices in order to ensure the drivers * will be able to use all of the related devices on the card * without waiting an unreasonable length of time */ - list_for_each(pos, &card->devices) { + list_for_each_safe(pos, temp, &card->devices) { struct pnp_dev *dev = card_to_pnp_dev(pos); - __pnp_add_device(dev); + error = __pnp_add_device(dev); + if (error) { + mutex_lock(&pnp_lock); + list_del(&dev->card_list); + dev->card = NULL; + mutex_unlock(&pnp_lock); + put_device(&dev->dev); + } } /* match with card drivers */ diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index fbf03ff007eb..d8ec0ad2ab4e 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -248,10 +248,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device) if (acpi_has_method(device->handle, "_DIS")) dev->capabilities |= PNP_DISABLE; - if (strlen(acpi_device_name(device))) - strscpy(dev->name, acpi_device_name(device), sizeof(dev->name)); - else - strscpy(dev->name, acpi_device_bid(device), sizeof(dev->name)); + strscpy(dev->name, acpi_device_bid(device), sizeof(dev->name)); if (dev->active) pnpacpi_parse_allocated_resource(dev); diff --git a/drivers/pnp/system.c b/drivers/pnp/system.c index 835113b2cb04..bd939b564379 100644 --- a/drivers/pnp/system.c +++ b/drivers/pnp/system.c @@ -17,10 +17,10 @@ static const struct pnp_device_id pnp_dev_table[] = { /* General ID for reserving resources */ - {"PNP0c02", 0}, + { .id = "PNP0c02" }, /* memory controller */ - {"PNP0c01", 0}, - {"", 0} + { .id = "PNP0c01" }, + { } }; static void reserve_range(struct pnp_dev *dev, struct resource *r, int port) diff --git a/drivers/xen/xen-acpi-pad.c b/drivers/xen/xen-acpi-pad.c index 5b98e0e93807..2fa9c7d3581f 100644 --- a/drivers/xen/xen-acpi-pad.c +++ b/drivers/xen/xen-acpi-pad.c @@ -17,8 +17,6 @@ #include <xen/xen-ops.h> #include <asm/xen/hypercall.h> -#define ACPI_PROCESSOR_AGGREGATOR_CLASS "acpi_pad" -#define ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME "Processor Aggregator" #define ACPI_PROCESSOR_AGGREGATOR_NOTIFY 0x80 static DEFINE_MUTEX(xen_cpu_lock); @@ -117,9 +115,6 @@ static int acpi_pad_probe(struct platform_device *pdev) if (!device) return -ENODEV; - strcpy(acpi_device_name(device), ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME); - strcpy(acpi_device_class(device), ACPI_PROCESSOR_AGGREGATOR_CLASS); - status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, acpi_pad_notify, device); if (ACPI_FAILURE(status)) diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 714d111d8053..32cac3a6f362 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -108,7 +108,6 @@ enum acpi_bus_device_type { ACPI_BUS_DEVICE_TYPE_COUNT }; -struct acpi_driver; struct acpi_device; /* @@ -159,32 +158,6 @@ struct acpi_hotplug_context { }; /* - * ACPI Driver - * ----------- - */ - -typedef int (*acpi_op_add) (struct acpi_device * device); -typedef void (*acpi_op_remove) (struct acpi_device *device); -typedef void (*acpi_op_notify) (struct acpi_device * device, u32 event); - -struct acpi_device_ops { - acpi_op_add add; - acpi_op_remove remove; - acpi_op_notify notify; -}; - -#define ACPI_DRIVER_ALL_NOTIFY_EVENTS 0x1 /* system AND device events */ - -struct acpi_driver { - char name[80]; - char class[80]; - const struct acpi_device_id *ids; /* Supported Hardware IDs */ - unsigned int flags; - struct acpi_device_ops ops; - struct device_driver drv; -}; - -/* * ACPI Device * ----------- */ @@ -211,7 +184,6 @@ struct acpi_device_flags { u32 removable:1; u32 ejectable:1; u32 power_manageable:1; - u32 match_driver:1; u32 initialized:1; u32 visited:1; u32 hotplug_notify:1; @@ -221,7 +193,7 @@ struct acpi_device_flags { u32 cca_seen:1; u32 enumeration_by_parent:1; u32 honor_deps:1; - u32 reserved:18; + u32 reserved:19; }; /* File System */ @@ -438,7 +410,7 @@ enum acpi_device_swnode_ep_props { * @lane_polarities: "lane-polarities" property values. * @link_frequencies: "link_frequencies" property values. * @port_nr: Port number. - * @crs_crs2_local: _CRS CSI2 record present (i.e. this is a transmitter one). + * @crs_csi2_local: _CRS CSI2 record present (i.e. this is a transmitter one). * @port_props: Port properties. * @ep_props: Endpoint properties. * @remote_ep: Reference to the remote endpoint. @@ -461,7 +433,7 @@ struct acpi_device_software_node_port { * struct acpi_device_software_nodes - Software nodes for an ACPI device * @dev_props: Device properties. * @nodes: Software nodes for root as well as ports and endpoints. - * @nodeprts: Array of software node pointers, for (un)registering them. + * @nodeptrs: Array of software node pointers, for (un)registering them. * @ports: Information related to each port and endpoint within a port. * @num_ports: The number of ports. */ @@ -570,7 +542,6 @@ static inline void *acpi_driver_data(struct acpi_device *d) } #define to_acpi_device(d) container_of(d, struct acpi_device, dev) -#define to_acpi_driver(d) container_of_const(d, struct acpi_driver, drv) static inline struct acpi_device *acpi_dev_parent(struct acpi_device *adev) { @@ -676,13 +647,6 @@ void acpi_scan_lock_release(void); void acpi_lock_hp_context(void); void acpi_unlock_hp_context(void); int acpi_scan_add_handler(struct acpi_scan_handler *handler); -/* - * use a macro to avoid include chaining to get THIS_MODULE - */ -#define acpi_bus_register_driver(drv) \ - __acpi_bus_register_driver(drv, THIS_MODULE) -int __acpi_bus_register_driver(struct acpi_driver *driver, struct module *owner); -void acpi_bus_unregister_driver(struct acpi_driver *driver); int acpi_bus_scan(acpi_handle handle); void acpi_bus_trim(struct acpi_device *start); acpi_status acpi_bus_get_ejd(acpi_handle handle, acpi_handle * ejd); @@ -696,18 +660,6 @@ static inline bool acpi_device_enumerated(struct acpi_device *adev) return adev && adev->flags.initialized && adev->flags.visited; } -/** - * module_acpi_driver(acpi_driver) - Helper macro for registering an ACPI driver - * @__acpi_driver: acpi_driver struct - * - * Helper macro for ACPI drivers which do not do anything special in module - * init/exit. This eliminates a lot of boilerplate. Each module may only - * use this macro once, and calling it replaces module_init() and module_exit() - */ -#define module_acpi_driver(__acpi_driver) \ - module_driver(__acpi_driver, acpi_bus_register_driver, \ - acpi_bus_unregister_driver) - /* * Bind physical devices with ACPI devices */ diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index 402b97d12138..bff2ca035fcf 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -59,14 +59,19 @@ int acpi_pci_link_free_irq(acpi_handle handle); struct pci_bus; #ifdef CONFIG_PCI -struct pci_dev *acpi_get_pci_dev(acpi_handle); +struct pci_dev *acpi_dev_get_pci_dev(struct acpi_device *adev); #else -static inline struct pci_dev *acpi_get_pci_dev(acpi_handle handle) +static inline struct pci_dev *acpi_dev_get_pci_dev(struct acpi_device *adev) { return NULL; } #endif +static inline struct pci_dev *acpi_get_pci_dev(acpi_handle handle) +{ + return acpi_dev_get_pci_dev(acpi_fetch_acpi_dev(handle)); +} + /* Arch-defined function to add a bus to the system */ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root); diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h index 8c191b9ac18f..19830146c644 100644 --- a/include/acpi/cppc_acpi.h +++ b/include/acpi/cppc_acpi.h @@ -69,7 +69,10 @@ struct cpc_register_resource { acpi_object_type type; u64 __iomem *sys_mem_vaddr; union { - struct cpc_reg reg; + struct { + struct cpc_reg reg; + bool use_rmw_lock; + }; u64 int_value; } cpc_entry; }; diff --git a/include/acpi/nhlt.h b/include/acpi/nhlt.h index 2108aa6d0207..370958d93706 100644 --- a/include/acpi/nhlt.h +++ b/include/acpi/nhlt.h @@ -10,7 +10,6 @@ #define __ACPI_NHLT_H__ #include <linux/acpi.h> -#include <linux/kconfig.h> #include <linux/overflow.h> #include <linux/types.h> diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 60ab50cb8930..99afad0eb49e 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -94,6 +94,12 @@ static inline void acpi_preset_companion(struct device *dev, ACPI_COMPANION_SET(dev, acpi_find_child_device(parent, addr, false)); } +static inline void acpi_device_clear_deps(struct device *dev) +{ + if (has_acpi_companion(dev)) + acpi_dev_clear_dependencies(ACPI_COMPANION(dev)); +} + static inline const char *acpi_dev_name(struct acpi_device *adev) { return dev_name(&adev->dev); @@ -360,9 +366,10 @@ int acpi_gsi_to_irq (u32 gsi, unsigned int *irq); int acpi_isa_irq_to_gsi (unsigned isa_irq, u32 *gsi); typedef struct fwnode_handle *(*acpi_gsi_domain_disp_fn)(u32); +typedef acpi_handle (*acpi_gsi_handle_disp_fn)(u32); void acpi_set_irq_model(enum acpi_irq_model_id model, - acpi_gsi_domain_disp_fn fn); + acpi_gsi_domain_disp_fn fn, acpi_gsi_handle_disp_fn gsi_dep_fn); acpi_gsi_domain_disp_fn acpi_get_gsi_dispatcher(void); void acpi_set_gsi_to_irq_fallback(u32 (*)(u32)); @@ -372,6 +379,8 @@ struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags, const struct irq_domain_ops *ops, void *host_data); +u32 acpi_irq_add_auto_dep(acpi_handle handle); + #ifdef CONFIG_X86_IO_APIC extern int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity); #else @@ -448,6 +457,7 @@ extern char *wmi_get_acpi_device_uid(const char *guid); #define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO 0x0800 extern char acpi_video_backlight_string[]; +extern bool acpi_dev_is_video_device(struct acpi_device *adev); extern long acpi_is_video_device(acpi_handle handle); extern void acpi_osi_setup(char *str); @@ -908,6 +918,8 @@ static inline void acpi_preset_companion(struct device *dev, { } +static inline void acpi_device_clear_deps(struct device *dev) {} + static inline const char *acpi_dev_name(struct acpi_device *adev) { return NULL; diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h index 17bb3374f4ca..931eaa7bbf6a 100644 --- a/include/linux/acpi_iort.h +++ b/include/linux/acpi_iort.h @@ -27,7 +27,8 @@ int iort_register_domain_token(int trans_id, phys_addr_t base, struct fwnode_handle *fw_node); void iort_deregister_domain_token(int trans_id); struct fwnode_handle *iort_find_domain_token(int trans_id); -struct fwnode_handle *iort_iwb_handle(u32 iwb_id); +acpi_handle iort_iwb_handle(u32 iwb_id); +struct fwnode_handle *iort_iwb_handle_fwnode(u32 iwb_id); #ifdef CONFIG_ACPI_IORT u32 iort_msi_map_id(struct device *dev, u32 id); diff --git a/include/linux/acpi_pmtmr.h b/include/linux/acpi_pmtmr.h index 0ded9220d379..cceed294d0b5 100644 --- a/include/linux/acpi_pmtmr.h +++ b/include/linux/acpi_pmtmr.h @@ -27,15 +27,17 @@ static inline u32 acpi_pm_read_early(void) } /** - * Register callback for suspend and resume event + * acpi_pmtmr_register_suspend_resume_callback - Register callback for + * suspend and resume event * - * @cb Callback triggered on suspend and resume - * @data Data passed with the callback + * @cb: Callback triggered on suspend and resume + * @data: Data passed with the callback */ void acpi_pmtmr_register_suspend_resume_callback(void (*cb)(void *data, bool suspend), void *data); /** - * Remove registered callback for suspend and resume event + * acpi_pmtmr_unregister_suspend_resume_callback - Remove registered callback + * for suspend and resume event */ void acpi_pmtmr_unregister_suspend_resume_callback(void); |
