Commit d84e1733 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull ACPI updates from Rafael Wysocki:
 "This one is significantly larger than previous ACPI support pull
  requests because several significant updates have coincided in it.

  First, there is a routine ACPICA code update, to upstream version
  20251212, but this time it covers new ACPI 6.6 material that has not
  been covered yet. Among other things, it includes definitions of a few
  new ACPI tables and updates of some others, like the GICv5 MADT
  structures and ARM IORT IWB node definitions that are used for adding
  GICv5 ACPI probing on ARM (that technically is IRQ subsystem material,
  but it depends on the ACPICA changes, so it is included here). The
  latter alone adds a few hundred lines of new code.

  Second, there is an update of ACPI _OSC handling including a fix that
  prevents failures from occurring in some corner cases due to careless
  handling of _OSC error bits.

  On top of that, the "system resource" ACPI device objects with the
  PNP0C01 and PNP0C02 are now going to be handled by the ACPI core
  device enumeration code instead of handing them over to the legacy PNP
  system driver which causes device enumeration issues to occur. Some of
  those issues have been worked around in device drivers and elsewhere
  and those workarounds should not be necessary any more, so they are
  going away.

  Moreover, the time has come to convert all "core ACPI" device drivers
  that were still using struct acpi_driver objects for device binding
  into proper platform drivers that use struct platform_driver for this
  purpose. These updates are accompanied by some requisite core ACPI
  device enumeration code changes.

  Next, there are ACPI APEI updates, including changes to avoid excess
  overhead in the NMI handler and in SEA on the ARM side, changes to
  unify ACPI-based HW error tracing and logging, and changes to prevent
  APEI code from reaching out of its allocated memory.

  There are also some ACPI power management updates, mostly related to
  the ACPI cpuidle support in the processor driver, suspend-to-idle
  handling on systems with ACPI support and to ACPI PM of devices.

  In addition to the above, bugs are fixed and the code is cleaned up in
  assorted places all over.

  Specifics:

   - Update the ACPICA code in the kernel to upstream version 20251212
     which includes the following changes:
      * Add support for new ACPI table DTPR (Michal Camacho Romero)
      * Release objects with acpi_ut_delete_object_desc() (Zilin Guan)
      * Add UUIDs for Microsoft fan extensions and UUIDs associated with
        TPM 2.0 devices (Armin Wolf)
      * Fix NULL pointer dereference in acpi_ev_address_space_dispatch()
        (Alexey Simakov)
      * Add KEYP ACPI table definition (Dave Jiang)
      * Add support for the Microsoft display mux _OSI string (Armin
        Wolf)
      * Add definitions for the IOVT ACPI table (Xianglai Li)
      * Abort AML bytecode execution on AML_FATAL_OP (Armin Wolf)
      * Include all fields in subtable type1 for PPTT (Ben Horgan)
      * Add GICv5 MADT structures and Arm IORT IWB node definitions
        (Jose Marinho)
      * Update Parameter Block structure for RAS2 and add a new flag in
        Memory Affinity Structure for SRAT (Pawel Chmielewski)
      * Add _VDM (Voltage Domain) object (Pawel Chmielewski)

   - Add support for GICv5 ACPI probing on ARM which is based on the
     GICv5 MADT structures and ARM IORT IWB node definitions recently
     added to ACPICA (Lorenzo Pieralisi)

   - Rework ACPI PM notification setup for PCI root buses and modify the
     ACPI PM setup for devices to register wakeup source objects under
     physical (that is, PCI, platform, etc.) devices instead of doing
     that under their ACPI companions (Rafael Wysocki)

   - Adjust debug messages regarding postponed ACPI PM printed during
     system resume to be more accurate (Rafael Wysocki)

   - Remove dead code from lps0_device_attach() (Gergo Koteles)

   - Start to invoke Microsoft Function 9 (Turn On Display) of the Low-
     Power S0 Idle (LPS0) _DSM in the suspend-to-idle resume flow on
     systems with ACPI LPS0 support to address a functional issue on
     Lenovo Yoga Slim 7i Aura (15ILL9), where system fans and keyboard
     backlights fail to resume after suspend (Jakob Riemenschneider)

   - Add sysfs attribute cid for exposing _CID lists under ACPI device
     objects (Rafael Wysocki)

   - Replace sprintf() with sysfs_emit() in all of the core ACPI sysfs
     interface code (Sumeet Pawnikar)

   - Use acpi_get_local_u64_address() in the code implementing ACPI
     support for PCI to evaluate _ADR instead of evaluating that object
     directly (Andy Shevchenko)

   - Add JWIPC JVC9100 to irq1_level_low_skip_override[] to unbreak
     serial IRQs on that system (Ai Chao)

   - Fix handling of _OSC errors in acpi_run_osc() to avoid failures on
     systems where _OSC error bits are set even though the _OSC return
     buffer contains acknowledged feature bits (Rafael Wysocki)

   - Clean up and rearrange \_SB._OSC handling for general platform
     features and USB4 features to avoid code duplication and
     unnecessary memory management overhead (Rafael Wysocki)

   - Make the ACPI core device enumeration code handle PNP0C01 and
     PNP0C02 ("system resource") device objects directly instead of
     letting the legacy PNP system driver handle them to avoid device
     enumeration issues on systems where PNP0C02 is present in the _CID
     list under ACPI device objects with a _HID matching a proper device
     driver in Linux (Rafael Wysocki)

   - Drop workarounds for the known device enumeration issues related to
     _CID lists containing PNP0C02 (Rafael Wysocki)

   - Drop outdated comment regarding removed function in the ACPI-based
     device enumeration code (Julia Lawall)

   - Make PRP0001 device matching work as expected for ACPI device
     objects using it as a _HID for board development and similar
     purposes (Kartik Rajput)

   - Use async schedule function in acpi_scan_clear_dep_fn() to avoid
     races with user space initialization on some systems (Yicong Yang)

   - Add a piece of documentation explaining why binding drivers
     directly to ACPI device objects is not a good idea in general and
     why it is desirable to convert drivers doing so into proper
     platform drivers that use struct platform_driver for device binding
     (Rafael Wysocki)

   - Convert multiple "core ACPI" drivers, including the NFIT ACPI
     device driver, the generic ACPI button drivers, the generic ACPI
     thermal zone driver, the ACPI hardware event device (HED) driver,
     the ACPI EC driver, the ACPI SMBUS HC driver, the ACPI Smart
     Battery Subsystem (SBS) driver, and the ACPI backlight (video)
     driver to proper platform drivers that use struct platform_driver
     for device binding (Rafael Wysocki)

   - Use acpi_get_local_u64_address() in the ACPI backlight (video)
     driver to evaluate _ADR instead of evaluating that object directly
     (Andy Shevchenko)

   - Convert the generic ACPI battery driver to a proper platform driver
     using struct platform_driver for device binding (Rafael Wysocki)

   - Fix incorrect charging status when current is zero in the generic
     ACPI battery driver (Ata İlhan Köktürk)

   - Use LIST_HEAD() for initializing a stack-allocated list in the
     generic ACPI watchdog device driver (Can Peng)

   - Rework the ACPI idle driver initialization to register it directly
     from the common initialization code instead of doing that from a
     CPU hotplug "online" callback and clean it up (Huisong Li, Rafael
     Wysocki)

   - Fix a possible NULL pointer dereference in
     acpi_processor_errata_piix4() (Tuo Li)

   - Make read-only array non_mmio_desc[] static const (Colin Ian King)

   - Prevent the APEI GHES support code on ARM from accessing memory out
     of bounds or going past the ARM processor CPER record buffer (Mauro
     Carvalho Chehab)

   - Prevent cper_print_fw_err() from dumping the entire memory on
     systems with defective firmware (Mauro Carvalho Chehab)

   - Improve ghes_notify_nmi() status check to avoid unnecessary
     overhead in the NMI handler by carrying out all of the requisite
     preparations and the NMI registration time (Tony Luck)

   - Refactor the GHES driver by extracting common functionality into
     reusable helper functions to reduce code duplication and improve
     the ghes_notify_sea() status check in analogy with the previous
     ghes_notify_nmi() status check improvement (Shuai Xue)

   - Make ELOG and GHES log and trace consistently and support the CPER
     CXL protocol analogously (Fabio De Francesco)

   - Disable KASAN instrumentation in the APEI GHES driver when compile
     testing with clang < 18 (Nathan Chancellor)

   - Let ghes_edac be the preferred driver to load on __ZX__ and _BYO_
     systems by extending the platform detection list in the APEI GHES
     driver (Tony W Wang-oc)

   - Clean up cppc_perf_caps and cppc_perf_ctrls structs and rename EPP
     constants for clarity in the ACPI CPPC library (Sumit Gupta)"

* tag 'acpi-6.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (117 commits)
  ACPI: battery: fix incorrect charging status when current is zero
  ACPI: scan: Use async schedule function in acpi_scan_clear_dep_fn()
  ACPI: x86: s2idle: Invoke Microsoft _DSM Function 9 (Turn On Display)
  ACPI: APEI: GHES: Add ghes_edac support for __ZX__ and _BYO_ systems
  ACPI: APEI: GHES: Disable KASAN instrumentation when compile testing with clang < 18
  ACPI: sysfs: Replace sprintf() with sysfs_emit()
  ACPI: CPPC: Rename EPP constants for clarity
  ACPI: CPPC: Clean up cppc_perf_caps and cppc_perf_ctrls structs
  ACPI: processor: idle: Rework the handling of acpi_processor_ffh_lpi_probe()
  ACPI: processor: idle: Convert acpi_processor_setup_cpuidle_dev() to void
  ACPI: processor: idle: Convert acpi_processor_setup_cpuidle_states() to void
  irqchip/gic-v5: Add ACPI IWB probing
  irqchip/gic-v5: Add ACPI ITS probing
  irqchip/gic-v5: Add ACPI IRS probing
  irqchip/gic-v5: Split IRS probing into OF and generic portions
  PCI/MSI: Make the pci_msi_map_rid_ctlr_node() interface firmware agnostic
  irqdomain: Add parent field to struct irqchip_fwid
  ACPI: PCI: simplify code with acpi_get_local_u64_address()
  ACPI: video: simplify code with acpi_get_local_u64_address()
  ACPI: PM: Adjust messages regarding postponed ACPI PM
  ...
parents 4adc13ed dfa5dc3a
Loading
Loading
Loading
Loading
+80 −0
Original line number Diff line number Diff line
.. 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 represeted 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.
+1 −0
Original line number Diff line number Diff line
@@ -7,3 +7,4 @@ ACPI Support

   linuxized-acpica
   scan_handlers
   acpi-drivers
+2 −0
Original line number Diff line number Diff line
@@ -494,6 +494,8 @@ config ACPI_EXTLOG
	tristate "Extended Error Log support"
	depends on X86_MCE && X86_LOCAL_APIC && EDAC
	select UEFI_CPER
	select ACPI_APEI
	select ACPI_APEI_GHES
	help
	  Certain usages such as Predictive Failure Analysis (PFA) require
	  more information about the error than what can be described in
+64 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/ratelimit.h>
#include <linux/edac.h>
#include <linux/ras.h>
#include <cxl/event.h>
#include <acpi/ghes.h>
#include <asm/cpu.h>
#include <asm/mce.h>
@@ -132,6 +133,53 @@ static int print_extlog_rcd(const char *pfx,
	return 1;
}

static void extlog_print_pcie(struct cper_sec_pcie *pcie_err,
			      int severity)
{
#ifdef ACPI_APEI_PCIEAER
	struct aer_capability_regs *aer;
	struct pci_dev *pdev;
	unsigned int devfn;
	unsigned int bus;
	int aer_severity;
	int domain;

	if (!(pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID &&
	      pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO))
		return;

	aer_severity = cper_severity_to_aer(severity);
	aer = (struct aer_capability_regs *)pcie_err->aer_info;
	domain = pcie_err->device_id.segment;
	bus = pcie_err->device_id.bus;
	devfn = PCI_DEVFN(pcie_err->device_id.device,
			  pcie_err->device_id.function);
	pdev = pci_get_domain_bus_and_slot(domain, bus, devfn);
	if (!pdev)
		return;

	pci_print_aer(pdev, aer_severity, aer);
	pci_dev_put(pdev);
#endif
}

static void
extlog_cxl_cper_handle_prot_err(struct cxl_cper_sec_prot_err *prot_err,
				int severity)
{
#ifdef ACPI_APEI_PCIEAER
	struct cxl_cper_prot_err_work_data wd;

	if (cxl_cper_sec_prot_err_valid(prot_err))
		return;

	if (cxl_cper_setup_prot_err_work_data(&wd, prot_err, severity))
		return;

	cxl_cper_handle_prot_err(&wd);
#endif
}

static int extlog_print(struct notifier_block *nb, unsigned long val,
			void *data)
{
@@ -183,6 +231,22 @@ static int extlog_print(struct notifier_block *nb, unsigned long val,
			if (gdata->error_data_length >= sizeof(*mem))
				trace_extlog_mem_event(mem, err_seq, fru_id, fru_text,
						       (u8)gdata->error_severity);
		} else if (guid_equal(sec_type, &CPER_SEC_CXL_PROT_ERR)) {
			struct cxl_cper_sec_prot_err *prot_err =
				acpi_hest_get_payload(gdata);

			extlog_cxl_cper_handle_prot_err(prot_err,
							gdata->error_severity);
		} else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
			struct cper_sec_pcie *pcie_err = acpi_hest_get_payload(gdata);

			extlog_print_pcie(pcie_err, gdata->error_severity);
		} else {
			void *err = acpi_hest_get_payload(gdata);

			log_non_standard_event(sec_type, fru_id, fru_text,
					       gdata->error_severity, err,
					       gdata->error_data_length);
		}
	}

+22 −18
Original line number Diff line number Diff line
@@ -114,13 +114,11 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
	struct platform_device *pdev = NULL;
	struct platform_device_info pdevinfo;
	const struct acpi_device_id *match;
	struct resource_entry *rentry;
	struct list_head resource_list;
	struct resource *resources = NULL;
	int count;
	int count = 0;

	/* If the ACPI node already has a physical device attached, skip it. */
	if (adev->physical_node_count)
	if (adev->physical_node_count && !adev->pnp.type.backlight)
		return NULL;

	match = acpi_match_acpi_device(forbidden_id_list, adev);
@@ -137,11 +135,16 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
		}
	}

	INIT_LIST_HEAD(&resource_list);
	if (adev->device_type == ACPI_BUS_TYPE_DEVICE && !adev->pnp.type.backlight) {
		LIST_HEAD(resource_list);

		count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
		if (count < 0)
		return NULL;
			return ERR_PTR(-ENODATA);

		if (count > 0) {
			struct resource_entry *rentry;

			resources = kcalloc(count, sizeof(*resources), GFP_KERNEL);
			if (!resources) {
				acpi_dev_free_resource_list(&resource_list);
@@ -154,6 +157,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev,

			acpi_dev_free_resource_list(&resource_list);
		}
	}

	memset(&pdevinfo, 0, sizeof(pdevinfo));
	/*
Loading