Merge tag 'acpi-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull ACPI support updates from Rafael Wysocki:
 "The most significant change here is the elimination of struct
  acpi_driver that has no more users in the tree now along with some
  documentation related to it, and a follow-up update to set the "no PM"
  flag for all ACPI devices that are now only going to play the role of
  other devices' "companions" (in analogy with DT nodes).

  There is also a significant update of irqchip code related to ACPI
  done in order to enable GICv5 IWB ACPI probe ordering detection on
  ARM, which involves RISC-V interrupt controller management code
  refactoring to extract generic code from it into the common ACPI IRQ
  code.

  The rest is mostly fixes, including some fallout of the _OSC handling
  rework in 7.0, ACPI CPPC library fixes, a workaround for registering
  ACPI platform devices with overlapping I/O or memory resources, an
  ACPI EC driver fix related to probe deferral on platforms using
  HW-reduced ACPI, two ACPI battery driver fixes and a workaround for
  handling model numbers with unprintable characters in it, probe error
  cleanup and driver unload code path fixes, hardware error reporting
  fixes, documentation fixes, and assorted code cleanups all over.

  Specifics:

   - Eliminate struct acpi_driver whose users have all been converted to
     bind to platform devices or auxiliary devices and set the "no power
     management" flag for all struct acpi_device objects (Rafael
     Wysocki)

   - Avoid complaints regarding missing _OSC features on platforms where
     OSC_CAPABILITIES_MASK_ERROR is set in _OSC error bits even though
     all of the requested features are actually acknowledged (Rafael
     Wysocki)

   - Avoid printing confusing _OSC messages for non-PCIe host bridges
     without _OSC which is a valid configuration (Kazuma Kondo)

   - Use correct region struct for BERT region size check and properly
     map BERT and CCEL data to their ACPI tables (Thomas Renninger)

   - Add acpi_device_clear_deps(), refactor RISC-V interrupt controller
     management code to extract generic code from it into the common
     ACPI IRQ code, and enable GICv5 IWB ACPI probe ordering detection
     on ARM on top of that (Lorenzo Pieralisi)

   - Stop using acpi_device_name() in the PNP core, stop setting
     acpi_device_name/class() in the Xen variant of the ACPI PAD
     (Processor Aggregator Device) driver, and make the Loongarch laptop
     driver stop setting acpi_device_class() (Rafael Wysocki)

   - Fix issues related to the desired_perf register access in the ACPI
     CPPC library and update it to avoid unnecessary overhead (Christian
     Loehle)

   - Simplify acpi_get_pci_dev() with the help of a mutex guard,
     introduce acpi_dev_get_pci_dev() for code that has a struct ACPI
     device for which it wants to get the struct pci_dev pointer of the
     associated PCI device, and use it in the ACPI video bus driver
     (Rafael Wysocki)

   - Avoid registering platform devices with resource overlaps in the
     ACPI core device enumeration code (Rafael Wysocki)

   - Clean up the list of included header files in the NHLT table parser
     and validate the table and record lengths in the FPDT parser (Andy
     Shevchenko and Pengpeng Hou)

   - Unregister the cpufreq notifier on init failure in the ACPI
     processor driver (Can Peng)

   - Validate MADT IOAPIC entry bounds during IOAPIC hotplug lookup in
     the ACPI processor driver (Pengpeng Hou)

   - Avoid _REG disconnect on probe deferrals related to GPIO IRQ in the
     ACPI EC driver (Zhu Ling)

   - Update kerneldoc comments of two structures in the ACPI bus type
     code to use correct struct member names to avoid warnings (Randy
     Dunlap)

   - Use a correct function parameter name in kernel-doc in the ACPI fan
     driver (Randy Dunlap)

   - Update ACPI fan IDs to follow modern style and clean up header file
     inclusions in the ACPI fan driver (Andy Shevchenko)

   - Use devm_acpi_install_notify_handler() to replace a custom
     open-coded devres-based management of an ACPI notify handler in the
     ACPI fan driver (Rafael Wysocki)

   - Adjust charging status validation check in the ACPI battery driver
     to avoid incorrect status reporting (Rafael Wysocki)

   - Merge consecutive battery notifications in the ACPI battery driver
     to reduce the pressure on STA, _BST and _BIX/_BIF ACPI control
     methods and make that driver use kstrtoul() instead of
     sscanf("%lu\n") (Rong Zhang)

   - Sanitise model_number in the ACPI battery driver by dropping
     unprintable characters (Kate Hsuan)

   - Remove a node_set() call that is redundant from
     acpi_parse_memory_affinity() (Sang-Heon Jeon)

   - Prevent kernel-doc warnings by converting 2 function description
     comments to kernel-doc format (Randy Dunlap)

   - Fix docs build error in the ACPI admin-guide documentation (Randy
     Dunlap)

   - Replace __get_free_page() with kmalloc() in the code handling ACPI
     NVS memory during system suspend/resume (Mike Rapoport)

   - Fix card device cleanup on registration failure in the core PNP
     code (Yuho Choi)

   - Drop an unused assignment of pnp_device_id driver data (Uwe
     Kleine-König)

   - Clear driver_data on all paths that free acpi_pci_root in
     acpi_pci_root_add() (Chen Pei)

   - Add locking around evaluation of ACPI control methods in the ACPI
     TAD driver to avoid race conditions (Rafael Wysocki)

   - Handle repeated SEA error storms in APEI (Junhao He)

   - Fix ERST timeout unit conversion in APEI (Nirmoy Das)

   - Fix ARM section length accounting after header in the ACPI APEI
     GHES driver (TanZheng)

   - Mark ghes_in_nmi_spool_from_list() as maybe unused (Rui Qi)

   - Introduce helper function acpi_dev_is_video_device() and use it in
     the core ACPI device enumeration code, in the ACPI video bus
     driver, in the ACPI support code for I2C, in the PCI VGA driver,
     and in the x86 platform thinkpad_acpi driver (Andy Shevchenko)

   - Add a quirk to use the native backlight on Acer Nitro AN515-46 to
     the ACPI video bus driver (Marcos Paulo Medeiros)

   - Release PCI device reference after lookup in
     video_detect_portege_r100() in the ACPI video bus driver (Yuho
     Choi)"

* tag 'acpi-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (61 commits)
  ACPI: scan: Avoid registering platform devices with resource overlaps
  ACPI: APEI: Handle repeated SEA error storms
  ACPI: APEI: Fix ERST timeout unit conversion
  ACPI: APEI: GHES: fix ARM section length accounting after header
  ACPI: video: Release PCI device reference after lookup
  ACPI: PCI: Avoid misleading _OSC messages for non-PCIe host bridges without _OSC
  ACPI: TAD: Add locking around AML evaluations
  ACPI: video: force native backlight on Acer Nitro AN515-46
  ACPI: CPPC: Evaluate performance-control PCC use once
  ACPI: CPPC: Avoid locking standalone full-width registers
  ACPI: CPPC: Avoid unnecessary reads for full-width writes
  ACPI: CPPC: Stop reading desired_perf in cppc_get_perf()
  ACPI: CPPC: Skip desired_perf read in cppc_get_perf()
  ACPI: CPPC: Reject desired_perf reads on _CPC revision 4+
  ACPI: processor: Unregister cpufreq notifier on init failure
  ACPI: bus: Avoid confusing complaints regarding missing _OSC features
  ACPI: battery: Adjust charging status validation check
  ACPI: pmtmr: Convert to kernel-doc format
  ACPI: bus: Use correct struct member names
  ACPI: fan: Use correct function parameter name in kernel-doc
  ...
This commit is contained in:
Linus Torvalds
2026-08-18 08:29:30 -07:00
50 changed files with 810 additions and 686 deletions

View File

@@ -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.

View File

@@ -7,4 +7,3 @@ ACPI Support
linuxized-acpica
scan_handlers
acpi-drivers

View File

@@ -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)

View File

@@ -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)

View File

@@ -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;
if (!record_header->length) {
pr_err(FW_BUG "Zero-length record found in FPTD.\n");
remaining = length - offset;
if (remaining < sizeof(*record_header)) {
pr_err(FW_BUG "Truncated FPDT record header.\n");
result = -EINVAL;
goto err;
}
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:

View File

@@ -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);
}
}

View File

@@ -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;
guard(mutex)(&acpi_tad_aml_lock);
status = acpi_evaluate_object(handle, "_GRT", NULL, &output);
if (ACPI_FAILURE(status))
goto out_free;
if (ACPI_SUCCESS(status)) {
union acpi_object *out_obj;
out_obj = output.pointer;
if (out_obj->type != ACPI_TYPE_BUFFER)
goto out_free;
out_obj = output.pointer;
if (out_obj->type == ACPI_TYPE_BUFFER &&
out_obj->buffer.length == sizeof(*rt)) {
struct acpi_tad_rt *data;
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;
out_free:
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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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 @@ static int ghes_in_nmi_queue_one_entry(struct ghes *ghes,
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;

View File

@@ -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;

View File

@@ -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 bool acpi_battery_is_full(struct acpi_battery *battery)
{
/* battery not reporting charge */
if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN ||
battery->capacity_now == 0)
return false;
/* good batteries update full_charge as the batteries degrade */
if (battery->full_charge_capacity == battery->capacity_now)
return true;
/* fallback to using design values for broken batteries */
return battery->design_capacity <= battery->capacity_now;
}
static int acpi_battery_is_charged(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;
/* good batteries update full_charge as the batteries degrade */
if (battery->full_charge_capacity == battery->capacity_now)
return 1;
/* fallback to using design values for broken batteries */
if (battery->design_capacity <= battery->capacity_now)
return 1;
/* we don't do any sort of metric based on percentages */
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;
if (sscanf(buf, "%lu\n", &x) == 1)
battery->alarm = x/1000;
err = kstrtoul(buf, 10, &x);
if (err)
return err;
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)

View File

@@ -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)
@@ -1121,57 +1094,13 @@ 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,
};

View File

@@ -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)

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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,

View File

@@ -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;

View File

@@ -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 @@ static int acpi_pci_root_add(struct acpi_device *device,
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);
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -285,6 +285,12 @@ static int __init acpi_processor_driver_init(void)
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;
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -1047,6 +1047,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

View File

@@ -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

View File

@@ -836,7 +836,7 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu)
* 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);

View File

@@ -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));

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -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);

View File

@@ -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)

View File

@@ -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))

View File

@@ -108,7 +108,6 @@ enum acpi_bus_device_type {
ACPI_BUS_DEVICE_TYPE_COUNT
};
struct acpi_driver;
struct acpi_device;
/*
@@ -158,32 +157,6 @@ struct acpi_hotplug_context {
acpi_hp_fixup fixup;
};
/*
* 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
*/

View File

@@ -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);

View File

@@ -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;
};

View File

@@ -10,7 +10,6 @@
#define __ACPI_NHLT_H__
#include <linux/acpi.h>
#include <linux/kconfig.h>
#include <linux/overflow.h>
#include <linux/types.h>

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);