summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/driver-api/acpi/acpi-drivers.rst80
-rw-r--r--Documentation/driver-api/acpi/index.rst1
-rw-r--r--Documentation/firmware-guide/acpi/dsd/motorcomm-yt8xxx-phy.rst5
-rw-r--r--arch/riscv/include/asm/acpi.h1
-rw-r--r--drivers/acpi/acpi_fpdt.c53
-rw-r--r--drivers/acpi/acpi_platform.c39
-rw-r--r--drivers/acpi/acpi_tad.c50
-rw-r--r--drivers/acpi/acpi_video.c14
-rw-r--r--drivers/acpi/apei/erst.c2
-rw-r--r--drivers/acpi/apei/ghes.c16
-rw-r--r--drivers/acpi/arm64/iort.c22
-rw-r--r--drivers/acpi/battery.c147
-rw-r--r--drivers/acpi/bus.c152
-rw-r--r--drivers/acpi/cppc_acpi.c171
-rw-r--r--drivers/acpi/ec.c40
-rw-r--r--drivers/acpi/fan.h27
-rw-r--r--drivers/acpi/fan_core.c25
-rw-r--r--drivers/acpi/irq.c172
-rw-r--r--drivers/acpi/numa/srat.c2
-rw-r--r--drivers/acpi/nvs.c4
-rw-r--r--drivers/acpi/pci_root.c47
-rw-r--r--drivers/acpi/power.c1
-rw-r--r--drivers/acpi/processor_core.c31
-rw-r--r--drivers/acpi/processor_driver.c6
-rw-r--r--drivers/acpi/riscv/irq.c141
-rw-r--r--drivers/acpi/scan.c22
-rw-r--r--drivers/acpi/sysfs.c11
-rw-r--r--drivers/acpi/utils.c17
-rw-r--r--drivers/acpi/video_detect.c21
-rw-r--r--drivers/cpufreq/cppc_cpufreq.c2
-rw-r--r--drivers/i2c/i2c-core-acpi.c15
-rw-r--r--drivers/irqchip/irq-gic-v3.c2
-rw-r--r--drivers/irqchip/irq-gic-v5-iwb.c2
-rw-r--r--drivers/irqchip/irq-gic-v5.c13
-rw-r--r--drivers/irqchip/irq-gic.c2
-rw-r--r--drivers/irqchip/irq-loongarch-cpu.c2
-rw-r--r--drivers/irqchip/irq-riscv-intc.c3
-rw-r--r--drivers/pci/vgaarb.c4
-rw-r--r--drivers/platform/x86/lenovo/thinkpad_acpi.c2
-rw-r--r--drivers/pnp/card.c11
-rw-r--r--drivers/pnp/pnpacpi/core.c5
-rw-r--r--drivers/pnp/system.c6
-rw-r--r--drivers/xen/xen-acpi-pad.c5
-rw-r--r--include/acpi/acpi_bus.h54
-rw-r--r--include/acpi/acpi_drivers.h9
-rw-r--r--include/acpi/cppc_acpi.h5
-rw-r--r--include/acpi/nhlt.h1
-rw-r--r--include/linux/acpi.h14
-rw-r--r--include/linux/acpi_iort.h3
-rw-r--r--include/linux/acpi_pmtmr.h10
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 = &reg->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 = &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);