ACPI support updates for 7.1-rc1

- Update maintainers information regarding ACPICA (Rafael Wysocki)
 
  - Replace strncpy() with strscpy_pad() in acpi_ut_safe_strncpy() (Kees
    Cook)
 
  - Trigger an ordered system power off after encountering a fatal error
    operator in AML (Armin Wolf)
 
  - Enable ACPI FPDT parsing on LoongArch (Xi Ruoyao)
 
  - Remove the temporary stop-gap acpi_pptt_cache_v1_full structure from
    the ACPI PPTT parser (Ben Horgan)
 
  - Add support for exposing ACPI FPDT subtables FBPT and S3PT (Nate
    DeSimone)
 
  - Address multiple assorted issues and clean up the code in the ACPI
    processor idle driver (Huisong Li)
 
  - Replace strlcat() in the ACPI processor idle drive with a better
    alternative (Andy Shevchenko)
 
  - Rearrange and clean up acpi_processor_errata_piix4() (Rafael Wysocki)
 
  - Move reference performance to capabilities and fix an uninitialized
    variable in the ACPI CPPC library (Pengjie Zhang)
 
  - Add support for the Performance Limited Register to the ACPI CPPC
    library (Sumit Gupta)
 
  - Add cppc_get_perf() API to read performance controls, extend
    cppc_set_epp_perf() for FFH/SystemMemory, and make the ACPI CPPC
    library warn on missing mandatory DESIRED_PERF register (Sumit Gupta)
 
  - Modify the cpufreq CPPC driver to update MIN_PERF/MAX_PERF in target
    callbacks to allow it to control performance bounds via standard
    scaling_min_freq and scaling_max_freq sysfs attributes and add sysfs
    documentation for the Performance Limited Register to it (Sumit Gupta)
 
  - Add ACPI support to the platform device interface in the CMOS RTC
    driver, make the ACPI core device enumeration code create a platform
    device for the CMOS RTC, and drop CMOS RTC PNP device support (Rafael
    Wysocki)
 
  - Consolidate the x86-specific CMOS RTC handling with the ACPI TAD
    driver and clean up the CMOS RTC ACPI address space handler (Rafael
    Wysocki)
 
  - Enable ACPI alarm in the CMOS RTC driver if advertised in ACPI FADT
    and allow that driver to work without a dedicated IRQ if the ACPI
    alarm is used (Rafael Wysocki)
 
  - Clean up the ACPI TAD driver in various ways and add an RTC class
    device interface, including both the RTC setting/reading and alarm
    timer support, to it (Rafael Wysocki)
 
  - Clean up the ACPI AC and ACPI PAD (processor aggregator device)
    drivers (Rafael Wysocki)
 
  - Rework checking for duplicate video bus devices and consolidate
    pnp.bus_id workarounds handling in the ACPI video bus driver (Rafael
    Wysocki)
 
  - Update the ACPI core device drivers to stop setting acpi_device_name()
    unnecessarily (Rafael Wysocki)
 
  - Rearrange code using acpi_device_class() in the ACPI core device
    drivers and update them to stop setting acpi_device_class()
    unnecessarily (Rafael Wysocki)
 
  - Define ACPI_AC_CLASS in one place (Rafael Wysocki)
 
  - Convert the ni903x_wdt watchdog driver and the xen ACPI PAD driver to
    bind to platform devices instead of ACPI devices (Rafael Wysocki)
 
  - Add devm_ghes_register_vendor_record_notifier(), use it in the PCI
    hisi driver, and Add NVIDIA vendor CPER record handler (Kai-Heng
    Feng)
 
  - Consolidate the interface for obtaining a CPU UID from ACPI across
    architectures and use it to address incorrect PCI TPH Steering Tag
    on ARM64 resulting from the invalid assumption that the ACPI
    Processor UID would always be the same as the corresponding logical
    CPU ID in Linux (Chengwen Feng)
 -----BEGIN PGP SIGNATURE-----
 
 iQFGBAABCAAwFiEEcM8Aw/RY0dgsiRUR7l+9nS/U47UFAmnY/bcSHHJqd0Byand5
 c29ja2kubmV0AAoJEO5fvZ0v1OO1chAH/1cGRzh9lSgQ3ZdzIIA5rpRtwKC+CTNz
 iNDvQ97W73B2N+WYzMaloOh+ZVA1Vdqc+8921aH6HI+v7wtg/ZV3h/hU7TagHNY/
 bRFDYaeRXVj4aBXNfoVdn7G5UU9j/kIDcV25I2ubOBqZaO6T5p8p1BK0j0vEj+sG
 yR7XwpEhr2OUQwlIFGKskJwFaH57QJXPEY8wf+o+lMEx/7o/JQRJzKFwsYu01ZZV
 kQy9Ee08P/rsNJwU2ibmZu5P3JMnhategAT8VAMBvkfLScv2sKX+1Vz19NGXzm71
 ARaT7y8MSPNb7SAvWmNZ/rVYrYIL+D3a76Gd7MOGrbVWEn6oXIbCIhY=
 =6vEK
 -----END PGP SIGNATURE-----

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

Pull ACPI support updates from Rafael Wysocki:
 "These include an update of the CMOS RTC driver and the related ACPI
  and x86 code that, among other things, switches it over to using the
  platform device interface for device binding on x86 instead of the PNP
  device driver interface (which allows the code in question to be
  simplified quite a bit), a major update of the ACPI Time and Alarm
  Device (TAD) driver adding an RTC class device interface to it, and
  updates of core ACPI drivers that remove some unnecessary and not
  really useful code from them.

  Apart from that, two drivers are converted to using the platform
  driver interface for device binding instead of the ACPI driver one,
  which is slated for removal, support for the Performance Limited
  register is added to the ACPI CPPC library and there are some
  janitorial updates of it and the related cpufreq CPPC driver, the ACPI
  processor driver is fixed and cleaned up, and NVIDIA vendor CPER
  record handler is added to the APEI GHES code.

  Also, the interface for obtaining a CPU UID from ACPI is consolidated
  across architectures and used for fixing a problem with the PCI TPH
  Steering Tag on ARM64, there are two updates related to ACPICA, a
  minor ACPI OS Services Layer (OSL) update, and a few assorted updates
  related to ACPI tables parsing.

  Specifics:

   - Update maintainers information regarding ACPICA (Rafael Wysocki)

   - Replace strncpy() with strscpy_pad() in acpi_ut_safe_strncpy()
     (Kees Cook)

   - Trigger an ordered system power off after encountering a fatal
     error operator in AML (Armin Wolf)

   - Enable ACPI FPDT parsing on LoongArch (Xi Ruoyao)

   - Remove the temporary stop-gap acpi_pptt_cache_v1_full structure
     from the ACPI PPTT parser (Ben Horgan)

   - Add support for exposing ACPI FPDT subtables FBPT and S3PT (Nate
     DeSimone)

   - Address multiple assorted issues and clean up the code in the ACPI
     processor idle driver (Huisong Li)

   - Replace strlcat() in the ACPI processor idle drive with a better
     alternative (Andy Shevchenko)

   - Rearrange and clean up acpi_processor_errata_piix4() (Rafael
     Wysocki)

   - Move reference performance to capabilities and fix an uninitialized
     variable in the ACPI CPPC library (Pengjie Zhang)

   - Add support for the Performance Limited Register to the ACPI CPPC
     library (Sumit Gupta)

   - Add cppc_get_perf() API to read performance controls, extend
     cppc_set_epp_perf() for FFH/SystemMemory, and make the ACPI CPPC
     library warn on missing mandatory DESIRED_PERF register (Sumit
     Gupta)

   - Modify the cpufreq CPPC driver to update MIN_PERF/MAX_PERF in
     target callbacks to allow it to control performance bounds via
     standard scaling_min_freq and scaling_max_freq sysfs attributes and
     add sysfs documentation for the Performance Limited Register to it
     (Sumit Gupta)

   - Add ACPI support to the platform device interface in the CMOS RTC
     driver, make the ACPI core device enumeration code create a
     platform device for the CMOS RTC, and drop CMOS RTC PNP device
     support (Rafael Wysocki)

   - Consolidate the x86-specific CMOS RTC handling with the ACPI TAD
     driver and clean up the CMOS RTC ACPI address space handler (Rafael
     Wysocki)

   - Enable ACPI alarm in the CMOS RTC driver if advertised in ACPI FADT
     and allow that driver to work without a dedicated IRQ if the ACPI
     alarm is used (Rafael Wysocki)

   - Clean up the ACPI TAD driver in various ways and add an RTC class
     device interface, including both the RTC setting/reading and alarm
     timer support, to it (Rafael Wysocki)

   - Clean up the ACPI AC and ACPI PAD (processor aggregator device)
     drivers (Rafael Wysocki)

   - Rework checking for duplicate video bus devices and consolidate
     pnp.bus_id workarounds handling in the ACPI video bus driver
     (Rafael Wysocki)

   - Update the ACPI core device drivers to stop setting
     acpi_device_name() unnecessarily (Rafael Wysocki)

   - Rearrange code using acpi_device_class() in the ACPI core device
     drivers and update them to stop setting acpi_device_class()
     unnecessarily (Rafael Wysocki)

   - Define ACPI_AC_CLASS in one place (Rafael Wysocki)

   - Convert the ni903x_wdt watchdog driver and the xen ACPI PAD driver
     to bind to platform devices instead of ACPI devices (Rafael
     Wysocki)

   - Add devm_ghes_register_vendor_record_notifier(), use it in the PCI
     hisi driver, and Add NVIDIA vendor CPER record handler (Kai-Heng
     Feng)

   - Consolidate the interface for obtaining a CPU UID from ACPI across
     architectures and use it to address incorrect PCI TPH Steering Tag
     on ARM64 resulting from the invalid assumption that the ACPI
     Processor UID would always be the same as the corresponding logical
     CPU ID in Linux (Chengwen Feng)"

* tag 'acpi-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (73 commits)
  ACPICA: Update maintainers information
  watchdog: ni903x_wdt: Convert to a platform driver
  ACPI: PAD: xen: Convert to a platform driver
  ACPI: processor: idle: Reset cpuidle on C-state list changes
  cpuidle: Extract and export no-lock variants of cpuidle_unregister_device()
  PCI/TPH: Pass ACPI Processor UID to Cache Locality _DSM
  ACPI: PPTT: Use acpi_get_cpu_uid() and remove get_acpi_id_for_cpu()
  perf: arm_cspmu: Switch to acpi_get_cpu_uid() from get_acpi_id_for_cpu()
  ACPI: Centralize acpi_get_cpu_uid() declaration in include/linux/acpi.h
  x86/acpi: Add acpi_get_cpu_uid() for unified ACPI CPU UID retrieval
  RISC-V: ACPI: Add acpi_get_cpu_uid() for unified ACPI CPU UID retrieval
  LoongArch: Add acpi_get_cpu_uid() for unified ACPI CPU UID retrieval
  arm64: acpi: Add acpi_get_cpu_uid() for unified ACPI CPU UID retrieval
  ACPI: APEI: GHES: Add NVIDIA vendor CPER record handler
  PCI: hisi: Use devm_ghes_register_vendor_record_notifier()
  ACPI: APEI: GHES: Add devm_ghes_register_vendor_record_notifier()
  ACPI: tables: Enable FPDT on LoongArch
  ACPI: processor: idle: Fix NULL pointer dereference in hotplug path
  ACPI: processor: idle: Reset power_setup_done flag on initialization failure
  ACPI: TAD: Add alarm support to the RTC class device interface
  ...
This commit is contained in:
Linus Torvalds 2026-04-13 19:25:07 -07:00
commit 2e31b16101
69 changed files with 1458 additions and 774 deletions

View File

@ -327,6 +327,24 @@ Description: Energy performance preference
This file is only present if the cppc-cpufreq driver is in use.
What: /sys/devices/system/cpu/cpuX/cpufreq/perf_limited
Date: February 2026
Contact: linux-pm@vger.kernel.org
Description: Performance Limited
Read to check if platform throttling (thermal/power/current
limits) caused delivered performance to fall below the
requested level. A non-zero value indicates throttling occurred.
Write the bitmask of bits to clear:
- 0x1 = clear bit 0 (desired performance excursion)
- 0x2 = clear bit 1 (minimum performance excursion)
- 0x3 = clear both bits
The platform sets these bits; OSPM can only clear them.
This file is only present if the cppc-cpufreq driver is in use.
What: /sys/devices/system/cpu/cpu*/cache/index3/cache_disable_{0,1}
Date: August 2008

View File

@ -41,6 +41,12 @@ Description:
platform runtime firmware S3 resume, just prior to
handoff to the OS waking vector. In nanoseconds.
FBPT: The raw binary contents of the Firmware Basic Boot
Performance Table (FBPT) subtable.
S3PT: The raw binary contents of the S3 Performance Table
(S3PT) subtable.
What: /sys/firmware/acpi/bgrt/
Date: January 2012
Contact: Matthew Garrett <mjg@redhat.com>

View File

@ -79,10 +79,10 @@ To retrieve a Steering Tag for a target memory associated with a specific
CPU, use the following function::
int pcie_tph_get_cpu_st(struct pci_dev *pdev, enum tph_mem_type type,
unsigned int cpu_uid, u16 *tag);
unsigned int cpu, u16 *tag);
The `type` argument is used to specify the memory type, either volatile
or persistent, of the target memory. The `cpu_uid` argument specifies the
or persistent, of the target memory. The `cpu` argument specifies the
CPU where the memory is associated to.
After the ST value is retrieved, the device driver can use the following

View File

@ -190,6 +190,14 @@ Kernel parameters
unusable. The "log_buf_len" parameter may be useful
if you need to capture more output.
acpi.poweroff_on_fatal= [ACPI]
{0 | 1}
Causes the system to poweroff when the ACPI bytecode signals
a fatal error. The default value of this setting is 1.
Overriding this value should only be done for diagnosing
ACPI firmware problems, as the system might behave erratically
after having encountered a fatal ACPI error.
acpi_enforce_resources= [ACPI]
{ strict | lax | no }
Check for resource conflicts between native drivers

View File

@ -318,7 +318,7 @@ F: drivers/firmware/efi/cper*
ACPI COMPONENT ARCHITECTURE (ACPICA)
M: "Rafael J. Wysocki" <rafael@kernel.org>
M: Robert Moore <robert.moore@intel.com>
M: Saket Dumbre <saket.dumbre@intel.com>
L: linux-acpi@vger.kernel.org
L: acpica-devel@lists.linux.dev
S: Supported
@ -18923,6 +18923,12 @@ S: Maintained
F: drivers/video/fbdev/nvidia/
F: drivers/video/fbdev/riva/
NVIDIA GHES VENDOR CPER RECORD HANDLER
M: Kai-Heng Feng <kaihengf@nvidia.com>
L: linux-acpi@vger.kernel.org
S: Maintained
F: drivers/acpi/apei/nvidia-ghes.c
NVIDIA VRS RTC DRIVER
M: Shubhi Garg <shgarg@nvidia.com>
L: linux-tegra@vger.kernel.org

View File

@ -114,22 +114,7 @@ static inline bool acpi_has_cpu_in_madt(void)
}
struct acpi_madt_generic_interrupt *acpi_cpu_get_madt_gicc(int cpu);
static inline u32 get_acpi_id_for_cpu(unsigned int cpu)
{
return acpi_cpu_get_madt_gicc(cpu)->uid;
}
static inline int get_cpu_for_acpi_id(u32 uid)
{
int cpu;
for (cpu = 0; cpu < nr_cpu_ids; cpu++)
if (acpi_cpu_get_madt_gicc(cpu) &&
uid == get_acpi_id_for_cpu(cpu))
return cpu;
return -EINVAL;
}
int get_cpu_for_acpi_id(u32 uid);
static inline void arch_fix_phys_package_id(int num, u32 slot) { }
void __init acpi_init_cpus(void);

View File

@ -458,3 +458,33 @@ int acpi_unmap_cpu(int cpu)
}
EXPORT_SYMBOL(acpi_unmap_cpu);
#endif /* CONFIG_ACPI_HOTPLUG_CPU */
int acpi_get_cpu_uid(unsigned int cpu, u32 *uid)
{
struct acpi_madt_generic_interrupt *gicc;
if (cpu >= nr_cpu_ids)
return -EINVAL;
gicc = acpi_cpu_get_madt_gicc(cpu);
if (!gicc)
return -ENODEV;
*uid = gicc->uid;
return 0;
}
EXPORT_SYMBOL_GPL(acpi_get_cpu_uid);
int get_cpu_for_acpi_id(u32 uid)
{
u32 cpu_uid;
int ret;
for (int cpu = 0; cpu < nr_cpu_ids; cpu++) {
ret = acpi_get_cpu_uid(cpu, &cpu_uid);
if (ret == 0 && uid == cpu_uid)
return cpu;
}
return -EINVAL;
}

View File

@ -40,11 +40,6 @@ extern struct acpi_madt_core_pic acpi_core_pic[MAX_CORE_PIC];
extern int __init parse_acpi_topology(void);
static inline u32 get_acpi_id_for_cpu(unsigned int cpu)
{
return acpi_core_pic[cpu_logical_map(cpu)].processor_id;
}
#endif /* !CONFIG_ACPI */
#define ACPI_TABLE_UPGRADE_MAX_PHYS ARCH_LOW_ADDRESS_LIMIT

View File

@ -385,3 +385,12 @@ int acpi_unmap_cpu(int cpu)
EXPORT_SYMBOL(acpi_unmap_cpu);
#endif /* CONFIG_ACPI_HOTPLUG_CPU */
int acpi_get_cpu_uid(unsigned int cpu, u32 *uid)
{
if (cpu >= nr_cpu_ids)
return -EINVAL;
*uid = acpi_core_pic[cpu_logical_map(cpu)].processor_id;
return 0;
}
EXPORT_SYMBOL_GPL(acpi_get_cpu_uid);

View File

@ -61,10 +61,6 @@ static inline void arch_fix_phys_package_id(int num, u32 slot) { }
void acpi_init_rintc_map(void);
struct acpi_madt_rintc *acpi_cpu_get_madt_rintc(int cpu);
static inline u32 get_acpi_id_for_cpu(int cpu)
{
return acpi_cpu_get_madt_rintc(cpu)->uid;
}
int acpi_get_riscv_isa(struct acpi_table_header *table,
unsigned int cpu, const char **isa);

View File

@ -337,3 +337,19 @@ int raw_pci_write(unsigned int domain, unsigned int bus,
}
#endif /* CONFIG_PCI */
int acpi_get_cpu_uid(unsigned int cpu, u32 *uid)
{
struct acpi_madt_rintc *rintc;
if (cpu >= nr_cpu_ids)
return -EINVAL;
rintc = acpi_cpu_get_madt_rintc(cpu);
if (!rintc)
return -ENODEV;
*uid = rintc->uid;
return 0;
}
EXPORT_SYMBOL_GPL(acpi_get_cpu_uid);

View File

@ -37,11 +37,14 @@ static int __init acpi_numa_get_nid(unsigned int cpu)
static inline int get_cpu_for_acpi_id(u32 uid)
{
int cpu;
u32 cpu_uid;
int ret;
for (cpu = 0; cpu < nr_cpu_ids; cpu++)
if (uid == get_acpi_id_for_cpu(cpu))
for (int cpu = 0; cpu < nr_cpu_ids; cpu++) {
ret = acpi_get_cpu_uid(cpu, &cpu_uid);
if (ret == 0 && uid == cpu_uid)
return cpu;
}
return -EINVAL;
}

View File

@ -11,7 +11,6 @@
#ifndef CONFIG_SMP
#define cpu_physical_id(cpu) boot_cpu_physical_apicid
#define cpu_acpi_id(cpu) 0
#endif /* CONFIG_SMP */
#ifdef CONFIG_HOTPLUG_CPU

View File

@ -130,7 +130,6 @@ __visible void smp_call_function_interrupt(struct pt_regs *regs);
__visible void smp_call_function_single_interrupt(struct pt_regs *r);
#define cpu_physical_id(cpu) per_cpu(x86_cpu_to_apicid, cpu)
#define cpu_acpi_id(cpu) per_cpu(x86_cpu_to_acpiid, cpu)
/*
* This function is needed by all SMP systems. It must _always_ be valid

View File

@ -1848,3 +1848,23 @@ void __iomem * (*acpi_os_ioremap)(acpi_physical_address phys, acpi_size size) =
x86_acpi_os_ioremap;
EXPORT_SYMBOL_GPL(acpi_os_ioremap);
#endif
int acpi_get_cpu_uid(unsigned int cpu, u32 *uid)
{
u32 acpi_id;
if (cpu >= nr_cpu_ids)
return -EINVAL;
#ifdef CONFIG_SMP
acpi_id = per_cpu(x86_cpu_to_acpiid, cpu);
if (acpi_id == CPU_ACPIID_INVALID)
return -ENODEV;
#else
acpi_id = 0;
#endif
*uid = acpi_id;
return 0;
}
EXPORT_SYMBOL_GPL(acpi_get_cpu_uid);

View File

@ -2,10 +2,10 @@
/*
* RTC related functions
*/
#include <linux/acpi.h>
#include <linux/platform_device.h>
#include <linux/mc146818rtc.h>
#include <linux/export.h>
#include <linux/pnp.h>
#include <asm/vsyscall.h>
#include <asm/x86_init.h>
@ -133,25 +133,14 @@ static struct platform_device rtc_device = {
static __init int add_rtc_cmos(void)
{
#ifdef CONFIG_PNP
static const char * const ids[] __initconst =
{ "PNP0b00", "PNP0b01", "PNP0b02", };
struct pnp_dev *dev;
int i;
if (cmos_rtc_platform_device_present)
return 0;
pnp_for_each_dev(dev) {
for (i = 0; i < ARRAY_SIZE(ids); i++) {
if (compare_pnp_id(dev->id, ids[i]) != 0)
return 0;
}
}
#endif
if (!x86_platform.legacy.rtc)
return -ENODEV;
platform_device_register(&rtc_device);
dev_info(&rtc_device.dev,
"registered platform RTC device (no PNP device found)\n");
dev_info(&rtc_device.dev, "registered fallback platform RTC device\n");
return 0;
}

View File

@ -151,6 +151,7 @@ static void xen_hvm_crash_shutdown(struct pt_regs *regs)
static int xen_cpu_up_prepare_hvm(unsigned int cpu)
{
u32 cpu_uid;
int rc = 0;
/*
@ -161,8 +162,8 @@ static int xen_cpu_up_prepare_hvm(unsigned int cpu)
*/
xen_uninit_lock_cpu(cpu);
if (cpu_acpi_id(cpu) != CPU_ACPIID_INVALID)
per_cpu(xen_vcpu_id, cpu) = cpu_acpi_id(cpu);
if (acpi_get_cpu_uid(cpu, &cpu_uid) == 0)
per_cpu(xen_vcpu_id, cpu) = cpu_uid;
else
per_cpu(xen_vcpu_id, cpu) = cpu;
xen_vcpu_setup(cpu);

View File

@ -96,7 +96,7 @@ config ACPI_SPCR_TABLE
config ACPI_FPDT
bool "ACPI Firmware Performance Data Table (FPDT) support"
depends on X86_64 || ARM64
depends on X86_64 || ARM64 || LOONGARCH
help
Enable support for the Firmware Performance Data Table (FPDT).
This table provides information on the timing of the system

View File

@ -21,8 +21,6 @@
#include <linux/acpi.h>
#include <acpi/battery.h>
#define ACPI_AC_CLASS "ac_adapter"
#define ACPI_AC_DEVICE_NAME "AC Adapter"
#define ACPI_AC_FILE_STATE "state"
#define ACPI_AC_NOTIFY_STATUS 0x80
#define ACPI_AC_STATUS_OFFLINE 0x00
@ -33,22 +31,12 @@ MODULE_AUTHOR("Paul Diefenbaugh");
MODULE_DESCRIPTION("ACPI AC Adapter Driver");
MODULE_LICENSE("GPL");
static int acpi_ac_probe(struct platform_device *pdev);
static void acpi_ac_remove(struct platform_device *pdev);
static void acpi_ac_notify(acpi_handle handle, u32 event, void *data);
static const struct acpi_device_id ac_device_ids[] = {
{"ACPI0003", 0},
{"", 0},
};
MODULE_DEVICE_TABLE(acpi, ac_device_ids);
#ifdef CONFIG_PM_SLEEP
static int acpi_ac_resume(struct device *dev);
#endif
static SIMPLE_DEV_PM_OPS(acpi_ac_pm, NULL, acpi_ac_resume);
static int ac_sleep_before_get_state_ms;
static int ac_only;
@ -141,10 +129,11 @@ static void acpi_ac_notify(acpi_handle handle, u32 event, void *data)
msleep(ac_sleep_before_get_state_ms);
acpi_ac_get_state(ac);
acpi_bus_generate_netlink_event(adev->pnp.device_class,
dev_name(&adev->dev), event,
(u32) ac->state);
acpi_notifier_call_chain(adev, event, (u32) ac->state);
acpi_bus_generate_netlink_event(ACPI_AC_CLASS,
dev_name(&adev->dev), event,
ac->state);
acpi_notifier_call_chain(ACPI_AC_CLASS, acpi_device_bid(adev),
event, ac->state);
power_supply_changed(ac->charger);
}
}
@ -213,8 +202,6 @@ static int acpi_ac_probe(struct platform_device *pdev)
return -ENOMEM;
ac->device = adev;
strscpy(acpi_device_name(adev), ACPI_AC_DEVICE_NAME);
strscpy(acpi_device_class(adev), ACPI_AC_CLASS);
platform_set_drvdata(pdev, ac);
@ -236,8 +223,8 @@ static int acpi_ac_probe(struct platform_device *pdev)
goto err_release_ac;
}
pr_info("%s [%s] (%s-line)\n", acpi_device_name(adev),
acpi_device_bid(adev), str_on_off(ac->state));
pr_info("AC Adapter [%s] (%s-line)\n", acpi_device_bid(adev),
str_on_off(ac->state));
ac->battery_nb.notifier_call = acpi_ac_battery_notify;
register_acpi_notifier(&ac->battery_nb);
@ -272,10 +259,10 @@ static int acpi_ac_resume(struct device *dev)
return 0;
}
#else
#define acpi_ac_resume NULL
#endif
static SIMPLE_DEV_PM_OPS(acpi_ac_pm, NULL, acpi_ac_resume);
static void acpi_ac_remove(struct platform_device *pdev)
{
struct acpi_ac *ac = platform_get_drvdata(pdev);

View File

@ -141,6 +141,9 @@ static const struct attribute_group boot_attr_group = {
.name = "boot",
};
static BIN_ATTR(FBPT, 0400, sysfs_bin_attr_simple_read, NULL, 0);
static BIN_ATTR(S3PT, 0400, sysfs_bin_attr_simple_read, NULL, 0);
static struct kobject *fpdt_kobj;
#if defined CONFIG_X86 && defined CONFIG_PHYS_ADDR_T_64BIT
@ -254,9 +257,34 @@ static int fpdt_process_subtable(u64 address, u32 subtable_type)
break;
}
}
if (subtable_type == SUBTABLE_FBPT) {
bin_attr_FBPT.private = subtable_header;
bin_attr_FBPT.size = length;
result = sysfs_create_bin_file(fpdt_kobj, &bin_attr_FBPT);
if (result)
pr_warn("Failed to create FBPT sysfs attribute.\n");
} else if (subtable_type == SUBTABLE_S3PT) {
bin_attr_S3PT.private = subtable_header;
bin_attr_S3PT.size = length;
result = sysfs_create_bin_file(fpdt_kobj, &bin_attr_S3PT);
if (result)
pr_warn("Failed to create S3PT sysfs attribute.\n");
}
return 0;
err:
if (bin_attr_FBPT.private) {
sysfs_remove_bin_file(fpdt_kobj, &bin_attr_FBPT);
bin_attr_FBPT.private = NULL;
}
if (bin_attr_S3PT.private) {
sysfs_remove_bin_file(fpdt_kobj, &bin_attr_S3PT);
bin_attr_S3PT.private = NULL;
}
if (record_boot)
sysfs_remove_group(fpdt_kobj, &boot_attr_group);

View File

@ -18,9 +18,7 @@
#include "internal.h"
#define ACPI_MEMORY_DEVICE_CLASS "memory"
#define ACPI_MEMORY_DEVICE_HID "PNP0C80"
#define ACPI_MEMORY_DEVICE_NAME "Hotplug Mem Device"
static const struct acpi_device_id memory_device_ids[] = {
{ACPI_MEMORY_DEVICE_HID, 0},
@ -297,8 +295,6 @@ static int acpi_memory_device_add(struct acpi_device *device,
INIT_LIST_HEAD(&mem_device->res_list);
mem_device->device = device;
mem_device->mgid = -1;
sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME);
sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS);
device->driver_data = mem_device;
/* Get the range from the _CRS */

View File

@ -23,8 +23,6 @@
#include <asm/mwait.h>
#include <xen/xen.h>
#define ACPI_PROCESSOR_AGGREGATOR_CLASS "acpi_pad"
#define ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME "Processor Aggregator"
#define ACPI_PROCESSOR_AGGREGATOR_NOTIFY 0x80
#define ACPI_PROCESSOR_AGGREGATOR_STATUS_SUCCESS 0
@ -407,16 +405,15 @@ static void acpi_pad_handle_notify(acpi_handle handle)
mutex_unlock(&isolated_cpus_lock);
}
static void acpi_pad_notify(acpi_handle handle, u32 event,
void *data)
static void acpi_pad_notify(acpi_handle handle, u32 event, void *data)
{
struct acpi_device *adev = data;
switch (event) {
case ACPI_PROCESSOR_AGGREGATOR_NOTIFY:
acpi_pad_handle_notify(handle);
acpi_bus_generate_netlink_event(adev->pnp.device_class,
dev_name(&adev->dev), event, 0);
acpi_bus_generate_netlink_event("acpi_pad",
dev_name(&adev->dev), event, 0);
break;
default:
pr_warn("Unsupported event [0x%x]\n", event);
@ -427,30 +424,19 @@ static void acpi_pad_notify(acpi_handle handle, u32 event,
static int acpi_pad_probe(struct platform_device *pdev)
{
struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
acpi_status status;
strscpy(acpi_device_name(adev), ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME);
strscpy(acpi_device_class(adev), ACPI_PROCESSOR_AGGREGATOR_CLASS);
status = acpi_install_notify_handler(adev->handle,
ACPI_DEVICE_NOTIFY, acpi_pad_notify, adev);
if (ACPI_FAILURE(status))
return -ENODEV;
return 0;
return acpi_dev_install_notify_handler(adev, ACPI_DEVICE_NOTIFY,
acpi_pad_notify, adev);
}
static void acpi_pad_remove(struct platform_device *pdev)
{
struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
mutex_lock(&isolated_cpus_lock);
acpi_pad_idle_cpus(0);
mutex_unlock(&isolated_cpus_lock);
acpi_remove_notify_handler(adev->handle,
ACPI_DEVICE_NOTIFY, acpi_pad_notify);
acpi_dev_remove_notify_handler(ACPI_COMPANION(&pdev->dev),
ACPI_DEVICE_NOTIFY, acpi_pad_notify);
}
static const struct acpi_device_id pad_device_ids[] = {

View File

@ -125,10 +125,6 @@ static const struct acpi_device_id acpi_pnp_device_ids[] = {
{"PNP0401"}, /* ECP Printer Port */
/* apple-gmux */
{"APP000B"},
/* rtc_cmos */
{"PNP0b00"},
{"PNP0b01"},
{"PNP0b02"},
/* c6xdigio */
{"PNP0400"}, /* Standard LPT Printer Port */
{"PNP0401"}, /* ECP Printer Port */
@ -355,25 +351,9 @@ static struct acpi_scan_handler acpi_pnp_handler = {
.attach = acpi_pnp_attach,
};
/*
* For CMOS RTC devices, the PNP ACPI scan handler does not work, because
* there is a CMOS RTC ACPI scan handler installed already, so we need to
* check those devices and enumerate them to the PNP bus directly.
*/
static int is_cmos_rtc_device(struct acpi_device *adev)
{
static const struct acpi_device_id ids[] = {
{ "PNP0B00" },
{ "PNP0B01" },
{ "PNP0B02" },
{""},
};
return !acpi_match_device_ids(adev, ids);
}
bool acpi_is_pnp_device(struct acpi_device *adev)
{
return adev->handler == &acpi_pnp_handler || is_cmos_rtc_device(adev);
return adev->handler == &acpi_pnp_handler;
}
EXPORT_SYMBOL_GPL(acpi_is_pnp_device);

View File

@ -48,11 +48,6 @@ acpi_handle acpi_get_processor_handle(int cpu)
static int acpi_processor_errata_piix4(struct pci_dev *dev)
{
u8 value1 = 0;
u8 value2 = 0;
struct pci_dev *ide_dev = NULL, *isa_dev = NULL;
if (!dev)
return -EINVAL;
@ -108,16 +103,16 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev)
* each IDE controller's DMA status to make sure we catch all
* DMA activity.
*/
ide_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82371AB,
PCI_ANY_ID, PCI_ANY_ID, NULL);
if (ide_dev) {
errata.piix4.bmisx = pci_resource_start(ide_dev, 4);
if (dev) {
errata.piix4.bmisx = pci_resource_start(dev, 4);
if (errata.piix4.bmisx)
dev_dbg(&ide_dev->dev,
dev_dbg(&dev->dev,
"Bus master activity detection (BM-IDE) erratum enabled\n");
pci_dev_put(ide_dev);
pci_dev_put(dev);
}
/*
@ -129,18 +124,20 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev)
* disable C3 support if this is enabled, as some legacy
* devices won't operate well if fast DMA is disabled.
*/
isa_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82371AB_0,
PCI_ANY_ID, PCI_ANY_ID, NULL);
if (isa_dev) {
pci_read_config_byte(isa_dev, 0x76, &value1);
pci_read_config_byte(isa_dev, 0x77, &value2);
if (dev) {
u8 value1 = 0, value2 = 0;
pci_read_config_byte(dev, 0x76, &value1);
pci_read_config_byte(dev, 0x77, &value2);
if ((value1 & 0x80) || (value2 & 0x80)) {
errata.piix4.fdma = 1;
dev_dbg(&isa_dev->dev,
dev_dbg(&dev->dev,
"Type-F DMA livelock erratum (C3 disabled)\n");
}
pci_dev_put(isa_dev);
pci_dev_put(dev);
}
break;
@ -439,8 +436,6 @@ static int acpi_processor_add(struct acpi_device *device,
}
pr->handle = device->handle;
strscpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME);
strscpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
device->driver_data = pr;
result = acpi_processor_get_info(device);

View File

@ -2,12 +2,10 @@
/*
* ACPI Time and Alarm (TAD) Device Driver
*
* Copyright (C) 2018 Intel Corporation
* Copyright (C) 2018 - 2026 Intel Corporation
* Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
*
* This driver is based on Section 9.18 of the ACPI 6.2 specification revision.
*
* It only supports the system wakeup capabilities of the TAD.
* This driver is based on ACPI 6.6, Section 9.17.
*
* Provided are sysfs attributes, available under the TAD platform device,
* allowing user space to manage the AC and DC wakeup timers of the TAD:
@ -18,20 +16,27 @@
*
* The wakeup events handling and power management of the TAD is expected to
* be taken care of by the ACPI PM domain attached to its platform device.
*
* If the TAD supports the get/set real time features, as indicated by the
* capability mask returned by _GCP under the TAD object, additional sysfs
* attributes are created allowing the real time to be set and read and an RTC
* class device is registered under the TAD platform device.
*/
#include <linux/acpi.h>
#include <linux/kernel.h>
#include <linux/ktime.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/rtc.h>
#include <linux/suspend.h>
MODULE_DESCRIPTION("ACPI Time and Alarm (TAD) Device Driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Rafael J. Wysocki");
/* ACPI TAD capability flags (ACPI 6.2, Section 9.18.2) */
/* ACPI TAD capability flags (ACPI 6.6, Section 9.17.2) */
#define ACPI_TAD_AC_WAKE BIT(0)
#define ACPI_TAD_DC_WAKE BIT(1)
#define ACPI_TAD_RT BIT(2)
@ -49,6 +54,10 @@ MODULE_AUTHOR("Rafael J. Wysocki");
/* Special value for disabled timer or expired timer wake policy. */
#define ACPI_TAD_WAKE_DISABLED (~(u32)0)
/* ACPI TAD RTC */
#define ACPI_TAD_TZ_UNSPEC 2047
#define ACPI_TAD_TIME_ISDST 3
struct acpi_tad_driver_data {
u32 capabilities;
};
@ -67,6 +76,16 @@ struct acpi_tad_rt {
u8 padding[3]; /* must be 0 */
} __packed;
static bool acpi_tad_rt_is_invalid(struct acpi_tad_rt *rt)
{
return rt->year < 1900 || rt->year > 9999 ||
rt->month < 1 || rt->month > 12 ||
rt->hour > 23 || rt->minute > 59 || rt->second > 59 ||
rt->tz < -1440 ||
(rt->tz > 1440 && rt->tz != ACPI_TAD_TZ_UNSPEC) ||
rt->daylight > 3;
}
static int acpi_tad_set_real_time(struct device *dev, struct acpi_tad_rt *rt)
{
acpi_handle handle = ACPI_HANDLE(dev);
@ -80,12 +99,12 @@ static int acpi_tad_set_real_time(struct device *dev, struct acpi_tad_rt *rt)
unsigned long long retval;
acpi_status status;
if (rt->year < 1900 || rt->year > 9999 ||
rt->month < 1 || rt->month > 12 ||
rt->hour > 23 || rt->minute > 59 || rt->second > 59 ||
rt->tz < -1440 || (rt->tz > 1440 && rt->tz != 2047) ||
rt->daylight > 3)
return -ERANGE;
if (acpi_tad_rt_is_invalid(rt))
return -EINVAL;
rt->valid = 0;
rt->msec = 0;
memset(rt->padding, 0, 3);
args[0].buffer.pointer = (u8 *)rt;
args[0].buffer.length = sizeof(*rt);
@ -133,21 +152,78 @@ static int acpi_tad_evaluate_grt(struct device *dev, struct acpi_tad_rt *rt)
return ret;
}
static int acpi_tad_get_real_time(struct device *dev, struct acpi_tad_rt *rt)
static int __acpi_tad_get_real_time(struct device *dev, struct acpi_tad_rt *rt)
{
int ret;
PM_RUNTIME_ACQUIRE(dev, pm);
if (PM_RUNTIME_ACQUIRE_ERR(&pm))
return -ENXIO;
ret = acpi_tad_evaluate_grt(dev, rt);
if (ret)
return ret;
if (acpi_tad_rt_is_invalid(rt))
return -ENODATA;
return 0;
}
static int acpi_tad_get_real_time(struct device *dev, struct acpi_tad_rt *rt)
{
PM_RUNTIME_ACQUIRE(dev, pm);
if (PM_RUNTIME_ACQUIRE_ERR(&pm))
return -ENXIO;
return __acpi_tad_get_real_time(dev, rt);
}
static int __acpi_tad_wake_set(struct device *dev, char *method, u32 timer_id,
u32 value)
{
acpi_handle handle = ACPI_HANDLE(dev);
union acpi_object args[] = {
{ .type = ACPI_TYPE_INTEGER, },
{ .type = ACPI_TYPE_INTEGER, },
};
struct acpi_object_list arg_list = {
.pointer = args,
.count = ARRAY_SIZE(args),
};
unsigned long long retval;
acpi_status status;
args[0].integer.value = timer_id;
args[1].integer.value = value;
status = acpi_evaluate_integer(handle, method, &arg_list, &retval);
if (ACPI_FAILURE(status) || retval)
return -EIO;
return 0;
}
static int __acpi_tad_wake_read(struct device *dev, char *method, u32 timer_id,
unsigned long long *retval)
{
acpi_handle handle = ACPI_HANDLE(dev);
union acpi_object args[] = {
{ .type = ACPI_TYPE_INTEGER, },
};
struct acpi_object_list arg_list = {
.pointer = args,
.count = ARRAY_SIZE(args),
};
acpi_status status;
args[0].integer.value = timer_id;
status = acpi_evaluate_integer(handle, method, &arg_list, retval);
if (ACPI_FAILURE(status))
return -EIO;
return 0;
}
/* sysfs interface */
static char *acpi_tad_rt_next_field(char *s, int *val)
{
char *p;
@ -167,69 +243,65 @@ static ssize_t time_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct acpi_tad_rt rt;
char *str, *s;
int val, ret = -ENODATA;
int val, ret;
char *s;
str = kmemdup_nul(buf, count, GFP_KERNEL);
char *str __free(kfree) = kmemdup_nul(buf, count, GFP_KERNEL);
if (!str)
return -ENOMEM;
s = acpi_tad_rt_next_field(str, &val);
if (!s)
goto out_free;
return -ENODATA;
rt.year = val;
s = acpi_tad_rt_next_field(s, &val);
if (!s)
goto out_free;
return -ENODATA;
rt.month = val;
s = acpi_tad_rt_next_field(s, &val);
if (!s)
goto out_free;
return -ENODATA;
rt.day = val;
s = acpi_tad_rt_next_field(s, &val);
if (!s)
goto out_free;
return -ENODATA;
rt.hour = val;
s = acpi_tad_rt_next_field(s, &val);
if (!s)
goto out_free;
return -ENODATA;
rt.minute = val;
s = acpi_tad_rt_next_field(s, &val);
if (!s)
goto out_free;
return -ENODATA;
rt.second = val;
s = acpi_tad_rt_next_field(s, &val);
if (!s)
goto out_free;
return -ENODATA;
rt.tz = val;
if (kstrtoint(s, 10, &val))
goto out_free;
return -ENODATA;
rt.daylight = val;
rt.valid = 0;
rt.msec = 0;
memset(rt.padding, 0, 3);
ret = acpi_tad_set_real_time(dev, &rt);
if (ret)
return ret;
out_free:
kfree(str);
return ret ? ret : count;
return count;
}
static ssize_t time_show(struct device *dev, struct device_attribute *attr,
@ -249,41 +321,14 @@ static ssize_t time_show(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR_RW(time);
static struct attribute *acpi_tad_time_attrs[] = {
&dev_attr_time.attr,
NULL,
};
static const struct attribute_group acpi_tad_time_attr_group = {
.attrs = acpi_tad_time_attrs,
};
static int acpi_tad_wake_set(struct device *dev, char *method, u32 timer_id,
u32 value)
{
acpi_handle handle = ACPI_HANDLE(dev);
union acpi_object args[] = {
{ .type = ACPI_TYPE_INTEGER, },
{ .type = ACPI_TYPE_INTEGER, },
};
struct acpi_object_list arg_list = {
.pointer = args,
.count = ARRAY_SIZE(args),
};
unsigned long long retval;
acpi_status status;
args[0].integer.value = timer_id;
args[1].integer.value = value;
PM_RUNTIME_ACQUIRE(dev, pm);
if (PM_RUNTIME_ACQUIRE_ERR(&pm))
return -ENXIO;
status = acpi_evaluate_integer(handle, method, &arg_list, &retval);
if (ACPI_FAILURE(status) || retval)
return -EIO;
return 0;
return __acpi_tad_wake_set(dev, method, timer_id, value);
}
static int acpi_tad_wake_write(struct device *dev, const char *buf, char *method,
@ -309,26 +354,16 @@ static int acpi_tad_wake_write(struct device *dev, const char *buf, char *method
static ssize_t acpi_tad_wake_read(struct device *dev, char *buf, char *method,
u32 timer_id, const char *specval)
{
acpi_handle handle = ACPI_HANDLE(dev);
union acpi_object args[] = {
{ .type = ACPI_TYPE_INTEGER, },
};
struct acpi_object_list arg_list = {
.pointer = args,
.count = ARRAY_SIZE(args),
};
unsigned long long retval;
acpi_status status;
args[0].integer.value = timer_id;
int ret;
PM_RUNTIME_ACQUIRE(dev, pm);
if (PM_RUNTIME_ACQUIRE_ERR(&pm))
return -ENXIO;
status = acpi_evaluate_integer(handle, method, &arg_list, &retval);
if (ACPI_FAILURE(status))
return -EIO;
ret = __acpi_tad_wake_read(dev, method, timer_id, &retval);
if (ret)
return ret;
if ((u32)retval == ACPI_TAD_WAKE_DISABLED)
return sprintf(buf, "%s\n", specval);
@ -486,17 +521,6 @@ static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR_RW(ac_status);
static struct attribute *acpi_tad_attrs[] = {
&dev_attr_caps.attr,
&dev_attr_ac_alarm.attr,
&dev_attr_ac_policy.attr,
&dev_attr_ac_status.attr,
NULL,
};
static const struct attribute_group acpi_tad_attr_group = {
.attrs = acpi_tad_attrs,
};
static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
@ -545,16 +569,227 @@ static ssize_t dc_status_show(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR_RW(dc_status);
static struct attribute *acpi_tad_dc_attrs[] = {
static struct attribute *acpi_tad_attrs[] = {
&dev_attr_caps.attr,
&dev_attr_ac_alarm.attr,
&dev_attr_ac_policy.attr,
&dev_attr_ac_status.attr,
&dev_attr_dc_alarm.attr,
&dev_attr_dc_policy.attr,
&dev_attr_dc_status.attr,
&dev_attr_time.attr,
NULL,
};
static const struct attribute_group acpi_tad_dc_attr_group = {
.attrs = acpi_tad_dc_attrs,
static umode_t acpi_tad_attr_is_visible(struct kobject *kobj,
struct attribute *a, int n)
{
struct acpi_tad_driver_data *dd = dev_get_drvdata(kobj_to_dev(kobj));
if (a == &dev_attr_caps.attr)
return a->mode;
if ((dd->capabilities & ACPI_TAD_AC_WAKE) &&
(a == &dev_attr_ac_alarm.attr || a == &dev_attr_ac_policy.attr ||
a == &dev_attr_ac_status.attr))
return a->mode;
if ((dd->capabilities & ACPI_TAD_DC_WAKE) &&
(a == &dev_attr_dc_alarm.attr || a == &dev_attr_dc_policy.attr ||
a == &dev_attr_dc_status.attr))
return a->mode;
if ((dd->capabilities & ACPI_TAD_RT) && a == &dev_attr_time.attr)
return a->mode;
return 0;
}
static const struct attribute_group acpi_tad_attr_group = {
.attrs = acpi_tad_attrs,
.is_visible = acpi_tad_attr_is_visible,
};
static const struct attribute_group *acpi_tad_attr_groups[] = {
&acpi_tad_attr_group,
NULL,
};
#ifdef CONFIG_RTC_CLASS
/* RTC class device interface */
static void acpi_tad_rt_to_tm(struct acpi_tad_rt *rt, struct rtc_time *tm)
{
tm->tm_year = rt->year - 1900;
tm->tm_mon = rt->month - 1;
tm->tm_mday = rt->day;
tm->tm_hour = rt->hour;
tm->tm_min = rt->minute;
tm->tm_sec = rt->second;
tm->tm_isdst = rt->daylight == ACPI_TAD_TIME_ISDST;
}
static int acpi_tad_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct acpi_tad_rt rt;
rt.year = tm->tm_year + 1900;
rt.month = tm->tm_mon + 1;
rt.day = tm->tm_mday;
rt.hour = tm->tm_hour;
rt.minute = tm->tm_min;
rt.second = tm->tm_sec;
rt.tz = ACPI_TAD_TZ_UNSPEC;
rt.daylight = ACPI_TAD_TIME_ISDST * !!tm->tm_isdst;
return acpi_tad_set_real_time(dev, &rt);
}
static int acpi_tad_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct acpi_tad_rt rt;
int ret;
ret = acpi_tad_get_real_time(dev, &rt);
if (ret)
return ret;
acpi_tad_rt_to_tm(&rt, tm);
return 0;
}
static int acpi_tad_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct acpi_tad_driver_data *dd = dev_get_drvdata(dev);
s64 value = ACPI_TAD_WAKE_DISABLED;
struct rtc_time tm_now;
struct acpi_tad_rt rt;
int ret;
PM_RUNTIME_ACQUIRE(dev, pm);
if (PM_RUNTIME_ACQUIRE_ERR(&pm))
return -ENXIO;
if (t->enabled) {
/*
* The value to pass to _STV is expected to be the number of
* seconds between the time when the timer is programmed and the
* time when it expires represented as a 32-bit integer.
*/
ret = __acpi_tad_get_real_time(dev, &rt);
if (ret)
return ret;
acpi_tad_rt_to_tm(&rt, &tm_now);
value = ktime_divns(ktime_sub(rtc_tm_to_ktime(t->time),
rtc_tm_to_ktime(tm_now)), NSEC_PER_SEC);
if (value <= 0 || value > U32_MAX)
return -EINVAL;
}
ret = __acpi_tad_wake_set(dev, "_STV", ACPI_TAD_AC_TIMER, value);
if (ret && t->enabled)
return ret;
/*
* If a separate DC alarm timer is supported, set it to the same value
* as the AC alarm timer.
*/
if (dd->capabilities & ACPI_TAD_DC_WAKE) {
ret = __acpi_tad_wake_set(dev, "_STV", ACPI_TAD_DC_TIMER, value);
if (ret && t->enabled) {
__acpi_tad_wake_set(dev, "_STV", ACPI_TAD_AC_TIMER,
ACPI_TAD_WAKE_DISABLED);
return ret;
}
}
/* Assume success if the alarm is being disabled. */
return 0;
}
static int acpi_tad_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *t)
{
unsigned long long retval;
struct rtc_time tm_now;
struct acpi_tad_rt rt;
int ret;
PM_RUNTIME_ACQUIRE(dev, pm);
if (PM_RUNTIME_ACQUIRE_ERR(&pm))
return -ENXIO;
ret = __acpi_tad_get_real_time(dev, &rt);
if (ret)
return ret;
acpi_tad_rt_to_tm(&rt, &tm_now);
/*
* Assume that the alarm was set by acpi_tad_rtc_set_alarm(), so the AC
* and DC alarm timer settings are the same and it is sufficient to read
* the former.
*
* The value returned by _TIV should be the number of seconds till the
* expiration of the timer, represented as a 32-bit integer, or the
* special ACPI_TAD_WAKE_DISABLED value meaning that the timer has
* been disabled.
*/
ret = __acpi_tad_wake_read(dev, "_TIV", ACPI_TAD_AC_TIMER, &retval);
if (ret)
return ret;
if (retval > U32_MAX)
return -ENODATA;
t->pending = 0;
if (retval != ACPI_TAD_WAKE_DISABLED) {
t->enabled = 1;
t->time = rtc_ktime_to_tm(ktime_add_ns(rtc_tm_to_ktime(tm_now),
(u64)retval * NSEC_PER_SEC));
} else {
t->enabled = 0;
t->time = tm_now;
}
return 0;
}
static const struct rtc_class_ops acpi_tad_rtc_ops = {
.read_time = acpi_tad_rtc_read_time,
.set_time = acpi_tad_rtc_set_time,
.set_alarm = acpi_tad_rtc_set_alarm,
.read_alarm = acpi_tad_rtc_read_alarm,
};
static void acpi_tad_register_rtc(struct device *dev, unsigned long long caps)
{
struct rtc_device *rtc;
rtc = devm_rtc_allocate_device(dev);
if (IS_ERR(rtc))
return;
rtc->range_min = mktime64(1900, 1, 1, 0, 0, 0);
rtc->range_max = mktime64(9999, 12, 31, 23, 59, 59);
rtc->ops = &acpi_tad_rtc_ops;
if (!(caps & ACPI_TAD_AC_WAKE))
clear_bit(RTC_FEATURE_ALARM, rtc->features);
devm_rtc_register_device(rtc);
}
#else /* !CONFIG_RTC_CLASS */
static inline void acpi_tad_register_rtc(struct device *dev,
unsigned long long caps) {}
#endif /* !CONFIG_RTC_CLASS */
/* Platform driver interface */
static int acpi_tad_disable_timer(struct device *dev, u32 timer_id)
{
return acpi_tad_wake_set(dev, "_STV", timer_id, ACPI_TAD_WAKE_DISABLED);
@ -563,22 +798,15 @@ static int acpi_tad_disable_timer(struct device *dev, u32 timer_id)
static void acpi_tad_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
acpi_handle handle = ACPI_HANDLE(dev);
struct acpi_tad_driver_data *dd = dev_get_drvdata(dev);
device_init_wakeup(dev, false);
if (dd->capabilities & ACPI_TAD_RT)
sysfs_remove_group(&dev->kobj, &acpi_tad_time_attr_group);
if (dd->capabilities & ACPI_TAD_DC_WAKE)
sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group);
sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group);
scoped_guard(pm_runtime_noresume, dev) {
acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER);
acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER);
if (dd->capabilities & ACPI_TAD_AC_WAKE) {
acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER);
acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER);
}
if (dd->capabilities & ACPI_TAD_DC_WAKE) {
acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER);
acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER);
@ -587,7 +815,6 @@ static void acpi_tad_remove(struct platform_device *pdev)
pm_runtime_suspend(dev);
pm_runtime_disable(dev);
acpi_remove_cmos_rtc_space_handler(handle);
}
static int acpi_tad_probe(struct platform_device *pdev)
@ -597,13 +824,7 @@ static int acpi_tad_probe(struct platform_device *pdev)
struct acpi_tad_driver_data *dd;
acpi_status status;
unsigned long long caps;
int ret;
ret = acpi_install_cmos_rtc_space_handler(handle);
if (ret < 0) {
dev_info(dev, "Unable to install space handler\n");
return -ENODEV;
}
/*
* Initialization failure messages are mostly about firmware issues, so
* print them at the "info" level.
@ -611,27 +832,20 @@ static int acpi_tad_probe(struct platform_device *pdev)
status = acpi_evaluate_integer(handle, "_GCP", NULL, &caps);
if (ACPI_FAILURE(status)) {
dev_info(dev, "Unable to get capabilities\n");
ret = -ENODEV;
goto remove_handler;
}
if (!(caps & ACPI_TAD_AC_WAKE)) {
dev_info(dev, "Unsupported capabilities\n");
ret = -ENODEV;
goto remove_handler;
return -ENODEV;
}
if (!acpi_has_method(handle, "_PRW")) {
dev_info(dev, "Missing _PRW\n");
ret = -ENODEV;
goto remove_handler;
caps &= ~(ACPI_TAD_AC_WAKE | ACPI_TAD_DC_WAKE);
}
if (!(caps & ACPI_TAD_AC_WAKE))
caps &= ~ACPI_TAD_DC_WAKE;
dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL);
if (!dd) {
ret = -ENOMEM;
goto remove_handler;
}
if (!dd)
return -ENOMEM;
dd->capabilities = caps;
dev_set_drvdata(dev, dd);
@ -642,9 +856,12 @@ static int acpi_tad_probe(struct platform_device *pdev)
* runtime suspend. Everything else should be taken care of by the ACPI
* PM domain callbacks.
*/
device_init_wakeup(dev, true);
dev_pm_set_driver_flags(dev, DPM_FLAG_SMART_SUSPEND |
DPM_FLAG_MAY_SKIP_RESUME);
if (ACPI_TAD_AC_WAKE) {
device_init_wakeup(dev, true);
dev_pm_set_driver_flags(dev, DPM_FLAG_SMART_SUSPEND |
DPM_FLAG_MAY_SKIP_RESUME);
}
/*
* The platform bus type layer tells the ACPI PM domain powers up the
* device, so set the runtime PM status of it to "active".
@ -653,32 +870,10 @@ static int acpi_tad_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
pm_runtime_suspend(dev);
ret = sysfs_create_group(&dev->kobj, &acpi_tad_attr_group);
if (ret)
goto fail;
if (caps & ACPI_TAD_DC_WAKE) {
ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group);
if (ret)
goto fail;
}
if (caps & ACPI_TAD_RT) {
ret = sysfs_create_group(&dev->kobj, &acpi_tad_time_attr_group);
if (ret)
goto fail;
}
if (caps & ACPI_TAD_RT)
acpi_tad_register_rtc(dev, caps);
return 0;
fail:
acpi_tad_remove(pdev);
/* Don't fallthrough because cmos rtc space handler is removed in acpi_tad_remove() */
return ret;
remove_handler:
acpi_remove_cmos_rtc_space_handler(handle);
return ret;
}
static const struct acpi_device_id acpi_tad_ids[] = {
@ -690,6 +885,7 @@ static struct platform_driver acpi_tad_driver = {
.driver = {
.name = "acpi-tad",
.acpi_match_table = acpi_tad_ids,
.dev_groups = acpi_tad_attr_groups,
},
.probe = acpi_tad_probe,
.remove = acpi_tad_remove,

View File

@ -30,9 +30,6 @@
#include <linux/uaccess.h>
#include <linux/string_choices.h>
#define ACPI_VIDEO_BUS_NAME "Video Bus"
#define ACPI_VIDEO_DEVICE_NAME "Video Device"
#define MAX_NAME_LEN 20
MODULE_AUTHOR("Bruno Ducrot");
@ -1144,9 +1141,6 @@ static int acpi_video_bus_get_one_device(struct acpi_device *device, void *arg)
return -ENOMEM;
}
strscpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
strscpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
data->device_id = device_id;
data->video = video;
data->dev = device;
@ -1570,7 +1564,8 @@ static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
break;
}
if (acpi_notifier_call_chain(device, event, 0))
if (acpi_notifier_call_chain(ACPI_VIDEO_CLASS, acpi_device_bid(device),
event, 0))
/* Something vetoed the keypress. */
keycode = 0;
@ -1611,7 +1606,8 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
if (video_device->backlight)
backlight_force_update(video_device->backlight,
BACKLIGHT_UPDATE_HOTKEY);
acpi_notifier_call_chain(device, event, 0);
acpi_notifier_call_chain(ACPI_VIDEO_CLASS, acpi_device_bid(device),
event, 0);
return;
}
@ -1644,7 +1640,8 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
if (keycode)
may_report_brightness_keys = true;
acpi_notifier_call_chain(device, event, 0);
acpi_notifier_call_chain(ACPI_VIDEO_CLASS, acpi_device_bid(device),
event, 0);
if (keycode && (report_key_events & REPORT_BRIGHTNESS_KEY_EVENTS)) {
input_report_key(input, keycode, 1);
@ -1681,26 +1678,6 @@ static int acpi_video_resume(struct notifier_block *nb,
return NOTIFY_DONE;
}
static acpi_status
acpi_video_bus_match(acpi_handle handle, u32 level, void *context,
void **return_value)
{
struct acpi_device *device = context;
struct acpi_device *sibling;
if (handle == device->handle)
return AE_CTRL_TERMINATE;
sibling = acpi_fetch_acpi_dev(handle);
if (!sibling)
return AE_OK;
if (!strcmp(acpi_device_name(sibling), ACPI_VIDEO_BUS_NAME))
return AE_ALREADY_EXISTS;
return AE_OK;
}
static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
{
struct backlight_properties props;
@ -1902,7 +1879,7 @@ static int acpi_video_bus_add_notify_handler(struct acpi_video_bus *video,
snprintf(video->phys, sizeof(video->phys),
"%s/video/input0", acpi_device_hid(video->device));
input->name = acpi_device_name(video->device);
input->name = "Video Bus";
input->phys = video->phys;
input->id.bustype = BUS_HOST;
input->id.product = 0x06;
@ -1976,53 +1953,69 @@ static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
return 0;
}
static int instance;
static int duplicate_dev_check(struct device *sibling, void *data)
{
struct acpi_video_bus *video;
if (sibling == data || !dev_is_auxiliary(sibling))
return 0;
guard(mutex)(&video_list_lock);
list_for_each_entry(video, &video_bus_head, entry) {
if (video == dev_get_drvdata(sibling))
return -EEXIST;
}
return 0;
}
static bool acpi_video_bus_dev_is_duplicate(struct device *dev)
{
return device_for_each_child(dev->parent, dev, duplicate_dev_check);
}
static int acpi_video_bus_probe(struct auxiliary_device *aux_dev,
const struct auxiliary_device_id *id_unused)
{
struct acpi_device *device = ACPI_COMPANION(&aux_dev->dev);
static DEFINE_MUTEX(probe_lock);
struct acpi_video_bus *video;
static int instance;
bool auto_detect;
int error;
acpi_status status;
status = acpi_walk_namespace(ACPI_TYPE_DEVICE,
acpi_dev_parent(device)->handle, 1,
acpi_video_bus_match, NULL,
device, NULL);
if (status == AE_ALREADY_EXISTS) {
/* Probe one video bus device at a time in case there are duplicates. */
guard(mutex)(&probe_lock);
if (!allow_duplicates && acpi_video_bus_dev_is_duplicate(&aux_dev->dev)) {
pr_info(FW_BUG
"Duplicate ACPI video bus devices for the"
" same VGA controller, please try module "
"parameter \"video.allow_duplicates=1\""
"if the current driver doesn't work.\n");
if (!allow_duplicates)
return -ENODEV;
return -ENODEV;
}
video = kzalloc_obj(struct acpi_video_bus);
if (!video)
return -ENOMEM;
/* a hack to fix the duplicate name "VID" problem on T61 */
if (!strcmp(device->pnp.bus_id, "VID")) {
if (instance)
device->pnp.bus_id[3] = '0' + instance;
instance++;
}
/* a hack to fix the duplicate name "VGA" problem on Pa 3553 */
if (!strcmp(device->pnp.bus_id, "VGA")) {
/*
* A hack to fix the duplicate name "VID" problem on T61 and the
* duplicate name "VGA" problem on Pa 3553.
*/
if (!strcmp(device->pnp.bus_id, "VID") ||
!strcmp(device->pnp.bus_id, "VGA")) {
if (instance)
device->pnp.bus_id[3] = '0' + instance;
instance++;
}
auxiliary_set_drvdata(aux_dev, video);
video->device = device;
strscpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);
strscpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
device->driver_data = video;
acpi_video_bus_find_cap(video);
@ -2043,11 +2036,10 @@ static int acpi_video_bus_probe(struct auxiliary_device *aux_dev,
*/
acpi_device_fix_up_power_children(device);
pr_info("%s [%s] (multi-head: %s rom: %s post: %s)\n",
ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device),
str_yes_no(video->flags.multihead),
str_yes_no(video->flags.rom),
str_yes_no(video->flags.post));
pr_info("Video Device [%s] (multi-head: %s rom: %s post: %s)\n",
acpi_device_bid(device), str_yes_no(video->flags.multihead),
str_yes_no(video->flags.rom), str_yes_no(video->flags.post));
mutex_lock(&video_list_lock);
list_add_tail(&video->entry, &video_bus_head);
mutex_unlock(&video_list_lock);

View File

@ -168,8 +168,7 @@ void acpi_ut_safe_strncpy(char *dest, char *source, acpi_size dest_size)
{
/* Always terminate destination string */
strncpy(dest, source, dest_size);
dest[dest_size - 1] = 0;
strscpy_pad(dest, source, dest_size);
}
#endif

View File

@ -74,6 +74,20 @@ config ACPI_APEI_EINJ_CXL
If unsure say 'n'
config ACPI_APEI_GHES_NVIDIA
tristate "NVIDIA GHES vendor record handler"
depends on ACPI_APEI_GHES
help
Support for decoding NVIDIA-specific CPER sections delivered via
the APEI GHES vendor record notifier chain. Registers a handler
for the NVIDIA section GUID and logs error signatures, severity,
socket, and diagnostic register address-value pairs.
Enable on NVIDIA server platforms (e.g. DGX, HGX) that expose
ACPI device NVDA2012 in their firmware tables.
If unsure, say N.
config ACPI_APEI_ERST_DEBUG
tristate "APEI Error Record Serialization Table (ERST) Debug Support"
depends on ACPI_APEI

View File

@ -10,5 +10,6 @@ obj-$(CONFIG_ACPI_APEI_EINJ) += einj.o
einj-y := einj-core.o
einj-$(CONFIG_ACPI_APEI_EINJ_CXL) += einj-cxl.o
obj-$(CONFIG_ACPI_APEI_ERST_DEBUG) += erst-dbg.o
obj-$(CONFIG_ACPI_APEI_GHES_NVIDIA) += ghes-nvidia.o
apei-y := apei-base.o hest.o erst.o bert.o

View File

@ -0,0 +1,149 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* NVIDIA GHES vendor record handler
*
* Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
*/
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/uuid.h>
#include <acpi/ghes.h>
static const guid_t nvidia_sec_guid =
GUID_INIT(0x6d5244f2, 0x2712, 0x11ec,
0xbe, 0xa7, 0xcb, 0x3f, 0xdb, 0x95, 0xc7, 0x86);
struct cper_sec_nvidia {
char signature[16];
__le16 error_type;
__le16 error_instance;
u8 severity;
u8 socket;
u8 number_regs;
u8 reserved;
__le64 instance_base;
struct {
__le64 addr;
__le64 val;
} regs[] __counted_by(number_regs);
};
struct nvidia_ghes_private {
struct notifier_block nb;
struct device *dev;
};
static void nvidia_ghes_print_error(struct device *dev,
const struct cper_sec_nvidia *nvidia_err,
size_t error_data_length, bool fatal)
{
const char *level = fatal ? KERN_ERR : KERN_INFO;
size_t min_size;
dev_printk(level, dev, "signature: %.16s\n", nvidia_err->signature);
dev_printk(level, dev, "error_type: %u\n", le16_to_cpu(nvidia_err->error_type));
dev_printk(level, dev, "error_instance: %u\n", le16_to_cpu(nvidia_err->error_instance));
dev_printk(level, dev, "severity: %u\n", nvidia_err->severity);
dev_printk(level, dev, "socket: %u\n", nvidia_err->socket);
dev_printk(level, dev, "number_regs: %u\n", nvidia_err->number_regs);
dev_printk(level, dev, "instance_base: 0x%016llx\n",
le64_to_cpu(nvidia_err->instance_base));
if (nvidia_err->number_regs == 0)
return;
/*
* Validate that all registers fit within error_data_length.
* Each register pair is two little-endian u64s.
*/
min_size = struct_size(nvidia_err, regs, nvidia_err->number_regs);
if (error_data_length < min_size) {
dev_err(dev, "Invalid number_regs %u (section size %zu, need %zu)\n",
nvidia_err->number_regs, error_data_length, min_size);
return;
}
for (int i = 0; i < nvidia_err->number_regs; i++)
dev_printk(level, dev, "register[%d]: address=0x%016llx value=0x%016llx\n",
i, le64_to_cpu(nvidia_err->regs[i].addr),
le64_to_cpu(nvidia_err->regs[i].val));
}
static int nvidia_ghes_notify(struct notifier_block *nb,
unsigned long event, void *data)
{
struct acpi_hest_generic_data *gdata = data;
struct nvidia_ghes_private *priv;
const struct cper_sec_nvidia *nvidia_err;
guid_t sec_guid;
import_guid(&sec_guid, gdata->section_type);
if (!guid_equal(&sec_guid, &nvidia_sec_guid))
return NOTIFY_DONE;
priv = container_of(nb, struct nvidia_ghes_private, nb);
if (acpi_hest_get_error_length(gdata) < sizeof(*nvidia_err)) {
dev_err(priv->dev, "Section too small (%d < %zu)\n",
acpi_hest_get_error_length(gdata), sizeof(*nvidia_err));
return NOTIFY_OK;
}
nvidia_err = acpi_hest_get_payload(gdata);
if (event >= GHES_SEV_RECOVERABLE)
dev_err(priv->dev, "NVIDIA CPER section, error_data_length: %u\n",
acpi_hest_get_error_length(gdata));
else
dev_info(priv->dev, "NVIDIA CPER section, error_data_length: %u\n",
acpi_hest_get_error_length(gdata));
nvidia_ghes_print_error(priv->dev, nvidia_err, acpi_hest_get_error_length(gdata),
event >= GHES_SEV_RECOVERABLE);
return NOTIFY_OK;
}
static int nvidia_ghes_probe(struct platform_device *pdev)
{
struct nvidia_ghes_private *priv;
int ret;
priv = devm_kmalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
*priv = (struct nvidia_ghes_private) {
.nb.notifier_call = nvidia_ghes_notify,
.dev = &pdev->dev,
};
ret = devm_ghes_register_vendor_record_notifier(&pdev->dev, &priv->nb);
if (ret)
return dev_err_probe(&pdev->dev, ret,
"Failed to register NVIDIA GHES vendor record notifier\n");
return 0;
}
static const struct acpi_device_id nvidia_ghes_acpi_match[] = {
{ "NVDA2012" },
{ }
};
MODULE_DEVICE_TABLE(acpi, nvidia_ghes_acpi_match);
static struct platform_driver nvidia_ghes_driver = {
.driver = {
.name = "nvidia-ghes",
.acpi_match_table = nvidia_ghes_acpi_match,
},
.probe = nvidia_ghes_probe,
};
module_platform_driver(nvidia_ghes_driver);
MODULE_AUTHOR("Kai-Heng Feng <kaihengf@nvidia.com>");
MODULE_DESCRIPTION("NVIDIA GHES vendor CPER record handler");
MODULE_LICENSE("GPL");

View File

@ -689,6 +689,24 @@ void ghes_unregister_vendor_record_notifier(struct notifier_block *nb)
}
EXPORT_SYMBOL_GPL(ghes_unregister_vendor_record_notifier);
static void ghes_vendor_record_notifier_destroy(void *nb)
{
ghes_unregister_vendor_record_notifier(nb);
}
int devm_ghes_register_vendor_record_notifier(struct device *dev,
struct notifier_block *nb)
{
int ret;
ret = ghes_register_vendor_record_notifier(nb);
if (ret)
return ret;
return devm_add_action_or_reset(dev, ghes_vendor_record_notifier_destroy, nb);
}
EXPORT_SYMBOL_GPL(devm_ghes_register_vendor_record_notifier);
static void ghes_vendor_record_work_func(struct work_struct *work)
{
struct ghes_vendor_record_entry *entry;

View File

@ -33,8 +33,6 @@
#define ACPI_BATTERY_CAPACITY_VALID(capacity) \
((capacity) != 0 && (capacity) != ACPI_BATTERY_VALUE_UNKNOWN)
#define ACPI_BATTERY_DEVICE_NAME "Battery"
/* Battery power unit: 0 means mW, 1 means mA */
#define ACPI_BATTERY_POWER_UNIT_MA 1
@ -1080,10 +1078,11 @@ static void acpi_battery_notify(acpi_handle handle, u32 event, void *data)
if (event == ACPI_BATTERY_NOTIFY_INFO)
acpi_battery_refresh(battery);
acpi_battery_update(battery, false);
acpi_bus_generate_netlink_event(device->pnp.device_class,
acpi_bus_generate_netlink_event(ACPI_BATTERY_CLASS,
dev_name(&device->dev), event,
acpi_battery_present(battery));
acpi_notifier_call_chain(device, event, acpi_battery_present(battery));
acpi_notifier_call_chain(ACPI_BATTERY_CLASS, acpi_device_bid(device),
event, acpi_battery_present(battery));
/* acpi_battery_update could remove power_supply object */
if (old && battery->bat)
power_supply_changed(battery->bat);
@ -1229,8 +1228,6 @@ static int acpi_battery_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, battery);
battery->device = device;
strscpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
strscpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
result = devm_mutex_init(&pdev->dev, &battery->update_lock);
if (result)

View File

@ -468,7 +468,7 @@ static void acpi_button_notify(acpi_handle handle, u32 event, void *data)
input_report_key(input, keycode, 0);
input_sync(input);
acpi_bus_generate_netlink_event(device->pnp.device_class,
acpi_bus_generate_netlink_event(acpi_device_class(device),
dev_name(&device->dev),
event, ++button->pushed);
}
@ -558,27 +558,26 @@ static int acpi_button_probe(struct platform_device *pdev)
goto err_free_button;
}
name = acpi_device_name(device);
class = acpi_device_class(device);
if (!strcmp(hid, ACPI_BUTTON_HID_POWER) ||
!strcmp(hid, ACPI_BUTTON_HID_POWERF)) {
button->type = ACPI_BUTTON_TYPE_POWER;
handler = acpi_button_notify;
strscpy(name, ACPI_BUTTON_DEVICE_NAME_POWER, MAX_ACPI_DEVICE_NAME_LEN);
name = ACPI_BUTTON_DEVICE_NAME_POWER;
sprintf(class, "%s/%s",
ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
} else if (!strcmp(hid, ACPI_BUTTON_HID_SLEEP) ||
!strcmp(hid, ACPI_BUTTON_HID_SLEEPF)) {
button->type = ACPI_BUTTON_TYPE_SLEEP;
handler = acpi_button_notify;
strscpy(name, ACPI_BUTTON_DEVICE_NAME_SLEEP, MAX_ACPI_DEVICE_NAME_LEN);
name = ACPI_BUTTON_DEVICE_NAME_SLEEP;
sprintf(class, "%s/%s",
ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
} else if (!strcmp(hid, ACPI_BUTTON_HID_LID)) {
button->type = ACPI_BUTTON_TYPE_LID;
handler = acpi_lid_notify;
strscpy(name, ACPI_BUTTON_DEVICE_NAME_LID, MAX_ACPI_DEVICE_NAME_LEN);
name = ACPI_BUTTON_DEVICE_NAME_LID;
sprintf(class, "%s/%s",
ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID);
input->open = acpi_lid_input_open;
@ -698,6 +697,8 @@ static void acpi_button_remove(struct platform_device *pdev)
acpi_button_remove_fs(button);
input_unregister_device(button->input);
kfree(button);
memset(acpi_device_class(adev), 0, sizeof(acpi_device_class));
}
static int param_set_lid_init_state(const char *val,

View File

@ -177,12 +177,12 @@ __ATTR(_name, 0444, show_##_name, NULL)
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, highest_perf);
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_perf);
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_perf);
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, reference_perf);
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_nonlinear_perf);
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, guaranteed_perf);
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, lowest_freq);
show_cppc_data(cppc_get_perf_caps, cppc_perf_caps, nominal_freq);
show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, reference_perf);
show_cppc_data(cppc_get_perf_ctrs, cppc_perf_fb_ctrs, wraparound_time);
/* Check for valid access_width, otherwise, fallback to using bit_width */
@ -853,6 +853,16 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
}
per_cpu(cpu_pcc_subspace_idx, pr->id) = pcc_subspace_id;
/*
* In CPPC v1, DESIRED_PERF is mandatory. In CPPC v2, it is optional
* only when AUTO_SEL_ENABLE is supported.
*/
if (!CPC_SUPPORTED(&cpc_ptr->cpc_regs[DESIRED_PERF]) &&
(!osc_sb_cppc2_support_acked ||
!CPC_SUPPORTED(&cpc_ptr->cpc_regs[AUTO_SEL_ENABLE])))
pr_warn("Desired perf. register is mandatory if CPPC v2 is not supported "
"or autonomous selection is disabled\n");
/*
* Initialize the remaining cpc_regs as unsupported.
* Example: In case FW exposes CPPC v2, the below loop will initialize
@ -1342,9 +1352,10 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
{
struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum);
struct cpc_register_resource *highest_reg, *lowest_reg,
*lowest_non_linear_reg, *nominal_reg, *guaranteed_reg,
*low_freq_reg = NULL, *nom_freq_reg = NULL;
u64 high, low, guaranteed, nom, min_nonlinear, low_f = 0, nom_f = 0;
*lowest_non_linear_reg, *nominal_reg, *reference_reg,
*guaranteed_reg, *low_freq_reg = NULL, *nom_freq_reg = NULL;
u64 high, low, guaranteed, nom, ref, min_nonlinear,
low_f = 0, nom_f = 0;
int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum);
struct cppc_pcc_data *pcc_ss_data = NULL;
int ret = 0, regs_in_pcc = 0;
@ -1358,6 +1369,7 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
lowest_reg = &cpc_desc->cpc_regs[LOWEST_PERF];
lowest_non_linear_reg = &cpc_desc->cpc_regs[LOW_NON_LINEAR_PERF];
nominal_reg = &cpc_desc->cpc_regs[NOMINAL_PERF];
reference_reg = &cpc_desc->cpc_regs[REFERENCE_PERF];
low_freq_reg = &cpc_desc->cpc_regs[LOWEST_FREQ];
nom_freq_reg = &cpc_desc->cpc_regs[NOMINAL_FREQ];
guaranteed_reg = &cpc_desc->cpc_regs[GUARANTEED_PERF];
@ -1365,6 +1377,7 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
/* Are any of the regs PCC ?*/
if (CPC_IN_PCC(highest_reg) || CPC_IN_PCC(lowest_reg) ||
CPC_IN_PCC(lowest_non_linear_reg) || CPC_IN_PCC(nominal_reg) ||
(CPC_SUPPORTED(reference_reg) && CPC_IN_PCC(reference_reg)) ||
CPC_IN_PCC(low_freq_reg) || CPC_IN_PCC(nom_freq_reg) ||
CPC_IN_PCC(guaranteed_reg)) {
if (pcc_ss_id < 0) {
@ -1381,35 +1394,66 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
}
}
cpc_read(cpunum, highest_reg, &high);
ret = cpc_read(cpunum, highest_reg, &high);
if (ret)
goto out_err;
perf_caps->highest_perf = high;
cpc_read(cpunum, lowest_reg, &low);
ret = cpc_read(cpunum, lowest_reg, &low);
if (ret)
goto out_err;
perf_caps->lowest_perf = low;
cpc_read(cpunum, nominal_reg, &nom);
ret = cpc_read(cpunum, nominal_reg, &nom);
if (ret)
goto out_err;
perf_caps->nominal_perf = nom;
/*
* If reference perf register is not supported then we should
* use the nominal perf value
*/
if (CPC_SUPPORTED(reference_reg)) {
ret = cpc_read(cpunum, reference_reg, &ref);
if (ret)
goto out_err;
} else {
ref = nom;
}
perf_caps->reference_perf = ref;
if (guaranteed_reg->type != ACPI_TYPE_BUFFER ||
IS_NULL_REG(&guaranteed_reg->cpc_entry.reg)) {
perf_caps->guaranteed_perf = 0;
} else {
cpc_read(cpunum, guaranteed_reg, &guaranteed);
ret = cpc_read(cpunum, guaranteed_reg, &guaranteed);
if (ret)
goto out_err;
perf_caps->guaranteed_perf = guaranteed;
}
cpc_read(cpunum, lowest_non_linear_reg, &min_nonlinear);
ret = cpc_read(cpunum, lowest_non_linear_reg, &min_nonlinear);
if (ret)
goto out_err;
perf_caps->lowest_nonlinear_perf = min_nonlinear;
if (!high || !low || !nom || !min_nonlinear)
if (!high || !low || !nom || !ref || !min_nonlinear) {
ret = -EFAULT;
goto out_err;
}
/* Read optional lowest and nominal frequencies if present */
if (CPC_SUPPORTED(low_freq_reg))
cpc_read(cpunum, low_freq_reg, &low_f);
if (CPC_SUPPORTED(low_freq_reg)) {
ret = cpc_read(cpunum, low_freq_reg, &low_f);
if (ret)
goto out_err;
}
if (CPC_SUPPORTED(nom_freq_reg))
cpc_read(cpunum, nom_freq_reg, &nom_f);
if (CPC_SUPPORTED(nom_freq_reg)) {
ret = cpc_read(cpunum, nom_freq_reg, &nom_f);
if (ret)
goto out_err;
}
perf_caps->lowest_freq = low_f;
perf_caps->nominal_freq = nom_f;
@ -1431,20 +1475,10 @@ EXPORT_SYMBOL_GPL(cppc_get_perf_caps);
bool cppc_perf_ctrs_in_pcc_cpu(unsigned int cpu)
{
struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu);
struct cpc_register_resource *ref_perf_reg;
/*
* If reference perf register is not supported then we should use the
* nominal perf value
*/
ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF];
if (!CPC_SUPPORTED(ref_perf_reg))
ref_perf_reg = &cpc_desc->cpc_regs[NOMINAL_PERF];
return CPC_IN_PCC(&cpc_desc->cpc_regs[DELIVERED_CTR]) ||
CPC_IN_PCC(&cpc_desc->cpc_regs[REFERENCE_CTR]) ||
CPC_IN_PCC(&cpc_desc->cpc_regs[CTR_WRAP_TIME]) ||
CPC_IN_PCC(ref_perf_reg);
CPC_IN_PCC(&cpc_desc->cpc_regs[CTR_WRAP_TIME]);
}
EXPORT_SYMBOL_GPL(cppc_perf_ctrs_in_pcc_cpu);
@ -1481,10 +1515,10 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
{
struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum);
struct cpc_register_resource *delivered_reg, *reference_reg,
*ref_perf_reg, *ctr_wrap_reg;
*ctr_wrap_reg;
int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum);
struct cppc_pcc_data *pcc_ss_data = NULL;
u64 delivered, reference, ref_perf, ctr_wrap_time;
u64 delivered, reference, ctr_wrap_time;
int ret = 0, regs_in_pcc = 0;
if (!cpc_desc) {
@ -1494,19 +1528,11 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
delivered_reg = &cpc_desc->cpc_regs[DELIVERED_CTR];
reference_reg = &cpc_desc->cpc_regs[REFERENCE_CTR];
ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF];
ctr_wrap_reg = &cpc_desc->cpc_regs[CTR_WRAP_TIME];
/*
* If reference perf register is not supported then we should
* use the nominal perf value
*/
if (!CPC_SUPPORTED(ref_perf_reg))
ref_perf_reg = &cpc_desc->cpc_regs[NOMINAL_PERF];
/* Are any of the regs PCC ?*/
if (CPC_IN_PCC(delivered_reg) || CPC_IN_PCC(reference_reg) ||
CPC_IN_PCC(ctr_wrap_reg) || CPC_IN_PCC(ref_perf_reg)) {
CPC_IN_PCC(ctr_wrap_reg)) {
if (pcc_ss_id < 0) {
pr_debug("Invalid pcc_ss_id\n");
return -ENODEV;
@ -1521,9 +1547,13 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
}
}
cpc_read(cpunum, delivered_reg, &delivered);
cpc_read(cpunum, reference_reg, &reference);
cpc_read(cpunum, ref_perf_reg, &ref_perf);
ret = cpc_read(cpunum, delivered_reg, &delivered);
if (ret)
goto out_err;
ret = cpc_read(cpunum, reference_reg, &reference);
if (ret)
goto out_err;
/*
* Per spec, if ctr_wrap_time optional register is unsupported, then the
@ -1531,17 +1561,19 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
* platform
*/
ctr_wrap_time = (u64)(~((u64)0));
if (CPC_SUPPORTED(ctr_wrap_reg))
cpc_read(cpunum, ctr_wrap_reg, &ctr_wrap_time);
if (CPC_SUPPORTED(ctr_wrap_reg)) {
ret = cpc_read(cpunum, ctr_wrap_reg, &ctr_wrap_time);
if (ret)
goto out_err;
}
if (!delivered || !reference || !ref_perf) {
if (!delivered || !reference) {
ret = -EFAULT;
goto out_err;
}
perf_fb_ctrs->delivered = delivered;
perf_fb_ctrs->reference = reference;
perf_fb_ctrs->reference_perf = ref_perf;
perf_fb_ctrs->wraparound_time = ctr_wrap_time;
out_err:
if (regs_in_pcc)
@ -1561,6 +1593,8 @@ int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable)
struct cpc_register_resource *auto_sel_reg;
struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu);
struct cppc_pcc_data *pcc_ss_data = NULL;
bool autosel_ffh_sysmem;
bool epp_ffh_sysmem;
int ret;
if (!cpc_desc) {
@ -1571,6 +1605,11 @@ int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable)
auto_sel_reg = &cpc_desc->cpc_regs[AUTO_SEL_ENABLE];
epp_set_reg = &cpc_desc->cpc_regs[ENERGY_PERF];
epp_ffh_sysmem = CPC_SUPPORTED(epp_set_reg) &&
(CPC_IN_FFH(epp_set_reg) || CPC_IN_SYSTEM_MEMORY(epp_set_reg));
autosel_ffh_sysmem = CPC_SUPPORTED(auto_sel_reg) &&
(CPC_IN_FFH(auto_sel_reg) || CPC_IN_SYSTEM_MEMORY(auto_sel_reg));
if (CPC_IN_PCC(epp_set_reg) || CPC_IN_PCC(auto_sel_reg)) {
if (pcc_ss_id < 0) {
pr_debug("Invalid pcc_ss_id for CPU:%d\n", cpu);
@ -1596,11 +1635,22 @@ int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable)
ret = send_pcc_cmd(pcc_ss_id, CMD_WRITE);
up_write(&pcc_ss_data->pcc_lock);
} else if (osc_cpc_flexible_adr_space_confirmed &&
CPC_SUPPORTED(epp_set_reg) && CPC_IN_FFH(epp_set_reg)) {
ret = cpc_write(cpu, epp_set_reg, perf_ctrls->energy_perf);
(epp_ffh_sysmem || autosel_ffh_sysmem)) {
if (autosel_ffh_sysmem) {
ret = cpc_write(cpu, auto_sel_reg, enable);
if (ret)
return ret;
}
if (epp_ffh_sysmem) {
ret = cpc_write(cpu, epp_set_reg,
perf_ctrls->energy_perf);
if (ret)
return ret;
}
} else {
ret = -ENOTSUPP;
pr_debug("_CPC in PCC and _CPC in FFH are not supported\n");
pr_debug("_CPC in PCC/FFH/SystemMemory are not supported\n");
}
return ret;
@ -1738,6 +1788,101 @@ int cppc_set_enable(int cpu, bool enable)
}
EXPORT_SYMBOL_GPL(cppc_set_enable);
/**
* cppc_get_perf - Get a CPU's performance controls.
* @cpu: CPU for which to get performance controls.
* @perf_ctrls: ptr to cppc_perf_ctrls. See cppc_acpi.h
*
* 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,
*energy_perf_reg, *auto_sel_reg;
u64 desired_perf = 0, 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;
if (!cpc_desc) {
pr_debug("No CPC descriptor for CPU:%d\n", cpu);
return -ENODEV;
}
if (!perf_ctrls) {
pr_debug("Invalid perf_ctrls pointer\n");
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) ||
CPC_IN_PCC(auto_sel_reg)) {
if (pcc_ss_id < 0) {
pr_debug("Invalid pcc_ss_id for CPU:%d\n", cpu);
return -ENODEV;
}
pcc_ss_data = pcc_data[pcc_ss_id];
regs_in_pcc = 1;
down_write(&pcc_ss_data->pcc_lock);
/* Ring doorbell once to update PCC subspace */
if (send_pcc_cmd(pcc_ss_id, CMD_READ) < 0) {
ret = -EIO;
goto out_err;
}
}
/* Read optional elements if present */
if (CPC_SUPPORTED(max_perf_reg)) {
ret = cpc_read(cpu, max_perf_reg, &max);
if (ret)
goto out_err;
}
perf_ctrls->max_perf = max;
if (CPC_SUPPORTED(min_perf_reg)) {
ret = cpc_read(cpu, min_perf_reg, &min);
if (ret)
goto out_err;
}
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;
if (CPC_SUPPORTED(energy_perf_reg)) {
ret = cpc_read(cpu, energy_perf_reg, &energy_perf);
if (ret)
goto out_err;
}
perf_ctrls->energy_perf = energy_perf;
if (CPC_SUPPORTED(auto_sel_reg)) {
ret = cpc_read(cpu, auto_sel_reg, &auto_sel);
if (ret)
goto out_err;
}
perf_ctrls->auto_sel = (bool)auto_sel;
out_err:
if (regs_in_pcc)
up_write(&pcc_ss_data->pcc_lock);
return ret;
}
EXPORT_SYMBOL_GPL(cppc_get_perf);
/**
* cppc_set_perf - Set a CPU's performance controls.
* @cpu: CPU for which to set performance controls.
@ -1870,6 +2015,62 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
}
EXPORT_SYMBOL_GPL(cppc_set_perf);
/**
* cppc_get_perf_limited - Get the Performance Limited register value.
* @cpu: CPU from which to get Performance Limited register.
* @perf_limited: Pointer to store the Performance Limited value.
*
* The returned value contains sticky status bits indicating platform-imposed
* performance limitations.
*
* Return: 0 for success, -EIO on failure, -EOPNOTSUPP if not supported.
*/
int cppc_get_perf_limited(int cpu, u64 *perf_limited)
{
return cppc_get_reg_val(cpu, PERF_LIMITED, perf_limited);
}
EXPORT_SYMBOL_GPL(cppc_get_perf_limited);
/**
* cppc_set_perf_limited() - Clear bits in the Performance Limited register.
* @cpu: CPU on which to write register.
* @bits_to_clear: Bitmask of bits to clear in the perf_limited register.
*
* The Performance Limited register contains two sticky bits set by platform:
* - Bit 0 (Desired_Excursion): Set when delivered performance is constrained
* below desired performance. Not used when Autonomous Selection is enabled.
* - Bit 1 (Minimum_Excursion): Set when delivered performance is constrained
* below minimum performance.
*
* These bits are sticky and remain set until OSPM explicitly clears them.
* This function only allows clearing bits (the platform sets them).
*
* Return: 0 for success, -EINVAL for invalid bits, -EIO on register
* access failure, -EOPNOTSUPP if not supported.
*/
int cppc_set_perf_limited(int cpu, u64 bits_to_clear)
{
u64 current_val, new_val;
int ret;
/* Only bits 0 and 1 are valid */
if (bits_to_clear & ~CPPC_PERF_LIMITED_MASK)
return -EINVAL;
if (!bits_to_clear)
return 0;
ret = cppc_get_perf_limited(cpu, &current_val);
if (ret)
return ret;
/* Clear the specified bits */
new_val = current_val & ~bits_to_clear;
return cppc_set_reg_val(cpu, PERF_LIMITED, new_val);
}
EXPORT_SYMBOL_GPL(cppc_set_perf_limited);
/**
* cppc_get_transition_latency - returns frequency transition latency in ns
* @cpu_num: CPU number for per_cpu().

View File

@ -35,9 +35,6 @@
#include "internal.h"
#define ACPI_EC_CLASS "embedded_controller"
#define ACPI_EC_DEVICE_NAME "Embedded Controller"
/* EC status register */
#define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */
#define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */
@ -1683,9 +1680,6 @@ static int acpi_ec_probe(struct platform_device *pdev)
struct acpi_ec *ec;
int ret;
strscpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
strscpy(acpi_device_class(device), ACPI_EC_CLASS);
if (boot_ec && (boot_ec->handle == device->handle ||
!strcmp(acpi_device_hid(device), ACPI_ECDT_HID))) {
/* Fast path: this device corresponds to the boot EC. */

View File

@ -24,12 +24,13 @@
/* ACPI notifier chain */
static BLOCKING_NOTIFIER_HEAD(acpi_chain_head);
int acpi_notifier_call_chain(struct acpi_device *dev, u32 type, u32 data)
int acpi_notifier_call_chain(const char *device_class,
const char *bus_id, u32 type, u32 data)
{
struct acpi_bus_event event;
strscpy(event.device_class, dev->pnp.device_class);
strscpy(event.bus_id, dev->pnp.bus_id);
strscpy(event.device_class, device_class);
strscpy(event.bus_id, bus_id);
event.type = type;
event.data = data;
return (blocking_notifier_call_chain(&acpi_chain_head, 0, (void *)&event)

View File

@ -13,6 +13,8 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/panic.h>
#include <linux/reboot.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/highmem.h>
@ -70,6 +72,10 @@ static bool acpi_os_initialized;
unsigned int acpi_sci_irq = INVALID_ACPI_IRQ;
bool acpi_permanent_mmap = false;
static bool poweroff_on_fatal = true;
module_param(poweroff_on_fatal, bool, 0);
MODULE_PARM_DESC(poweroff_on_fatal, "Poweroff when encountering a fatal ACPI error");
/*
* This list of permanent mappings is for memory that may be accessed from
* interrupt context, where we can't do the ioremap().
@ -1381,9 +1387,20 @@ acpi_status acpi_os_notify_command_complete(void)
acpi_status acpi_os_signal(u32 function, void *info)
{
struct acpi_signal_fatal_info *fatal_info;
switch (function) {
case ACPI_SIGNAL_FATAL:
pr_err("Fatal opcode executed\n");
fatal_info = info;
pr_emerg("Fatal error while evaluating ACPI control method\n");
pr_emerg("Type 0x%X Code 0x%X Argument 0x%X\n",
fatal_info->type, fatal_info->code, fatal_info->argument);
if (poweroff_on_fatal)
orderly_poweroff(true);
else
add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
break;
case ACPI_SIGNAL_BREAKPOINT:
/*

View File

@ -29,8 +29,6 @@
#include "internal.h"
#define ACPI_PCI_LINK_CLASS "pci_irq_routing"
#define ACPI_PCI_LINK_DEVICE_NAME "PCI Interrupt Link"
#define ACPI_PCI_LINK_MAX_POSSIBLE 16
static int acpi_pci_link_add(struct acpi_device *device,
@ -725,8 +723,6 @@ static int acpi_pci_link_add(struct acpi_device *device,
return -ENOMEM;
link->device = device;
strscpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME);
strscpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS);
device->driver_data = link;
mutex_lock(&acpi_link_lock);

View File

@ -24,8 +24,6 @@
#include <linux/platform_data/x86/apple.h>
#include "internal.h"
#define ACPI_PCI_ROOT_CLASS "pci_bridge"
#define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge"
static int acpi_pci_root_add(struct acpi_device *device,
const struct acpi_device_id *not_used);
static void acpi_pci_root_remove(struct acpi_device *device);
@ -689,8 +687,6 @@ static int acpi_pci_root_add(struct acpi_device *device,
root->device = device;
root->segment = segment & 0xFFFF;
strscpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME);
strscpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
device->driver_data = root;
if (hotadd && dmar_device_add(handle)) {
@ -698,9 +694,8 @@ static int acpi_pci_root_add(struct acpi_device *device,
goto end;
}
pr_info("%s [%s] (domain %04x %pR)\n",
acpi_device_name(device), acpi_device_bid(device),
root->segment, &root->secondary);
pr_info("PCI Root Bridge [%s] (domain %04x %pR)\n",
acpi_device_bid(device), root->segment, &root->secondary);
root->mcfg_addr = acpi_pci_root_get_mcfg_addr(handle);

View File

@ -37,8 +37,6 @@
#include "sleep.h"
#include "internal.h"
#define ACPI_POWER_CLASS "power_resource"
#define ACPI_POWER_DEVICE_NAME "Power Resource"
#define ACPI_POWER_RESOURCE_STATE_OFF 0x00
#define ACPI_POWER_RESOURCE_STATE_ON 0x01
#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
@ -955,8 +953,6 @@ struct acpi_device *acpi_add_power_resource(acpi_handle handle)
mutex_init(&resource->resource_lock);
INIT_LIST_HEAD(&resource->list_node);
INIT_LIST_HEAD(&resource->dependents);
strscpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
strscpy(acpi_device_class(device), ACPI_POWER_CLASS);
device->power.state = ACPI_STATE_UNKNOWN;
device->flags.match_driver = true;

View File

@ -21,25 +21,6 @@
#include <linux/cacheinfo.h>
#include <acpi/processor.h>
/*
* The acpi_pptt_cache_v1 in actbl2.h, which is imported from acpica,
* only contains the cache_id field rather than all the fields of the
* Cache Type Structure. Use this alternative structure until it is
* resolved in acpica.
*/
struct acpi_pptt_cache_v1_full {
struct acpi_subtable_header header;
u16 reserved;
u32 flags;
u32 next_level_of_cache;
u32 size;
u32 number_of_sets;
u8 associativity;
u8 attributes;
u16 line_size;
u32 cache_id;
} __packed;
static struct acpi_subtable_header *fetch_pptt_subtable(struct acpi_table_header *table_hdr,
u32 pptt_ref)
{
@ -75,16 +56,16 @@ static struct acpi_pptt_cache *fetch_pptt_cache(struct acpi_table_header *table_
return (struct acpi_pptt_cache *)fetch_pptt_subtable(table_hdr, pptt_ref);
}
static struct acpi_pptt_cache_v1_full *upgrade_pptt_cache(struct acpi_pptt_cache *cache)
static struct acpi_pptt_cache_v1 *upgrade_pptt_cache(struct acpi_pptt_cache *cache)
{
if (cache->header.length < sizeof(struct acpi_pptt_cache_v1_full))
if (cache->header.length < sizeof(struct acpi_pptt_cache_v1))
return NULL;
/* No use for v1 if the only additional field is invalid */
if (!(cache->flags & ACPI_PPTT_CACHE_ID_VALID))
return NULL;
return (struct acpi_pptt_cache_v1_full *)cache;
return (struct acpi_pptt_cache_v1 *)cache;
}
static struct acpi_subtable_header *acpi_get_pptt_resource(struct acpi_table_header *table_hdr,
@ -397,7 +378,7 @@ static void update_cache_properties(struct cacheinfo *this_leaf,
struct acpi_pptt_cache *found_cache,
struct acpi_pptt_processor *cpu_node)
{
struct acpi_pptt_cache_v1_full *found_cache_v1;
struct acpi_pptt_cache_v1 *found_cache_v1;
this_leaf->fw_token = cpu_node;
if (found_cache->flags & ACPI_PPTT_SIZE_PROPERTY_VALID)
@ -459,11 +440,14 @@ static void cache_setup_acpi_cpu(struct acpi_table_header *table,
{
struct acpi_pptt_cache *found_cache;
struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu);
u32 acpi_cpu_id;
struct cacheinfo *this_leaf;
unsigned int index = 0;
struct acpi_pptt_processor *cpu_node = NULL;
if (acpi_get_cpu_uid(cpu, &acpi_cpu_id) != 0)
return;
while (index < get_cpu_cacheinfo(cpu)->num_leaves) {
this_leaf = this_cpu_ci->info_list + index;
found_cache = acpi_find_cache_node(table, acpi_cpu_id,
@ -546,7 +530,10 @@ static int topology_get_acpi_cpu_tag(struct acpi_table_header *table,
unsigned int cpu, int level, int flag)
{
struct acpi_pptt_processor *cpu_node;
u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu);
u32 acpi_cpu_id;
if (acpi_get_cpu_uid(cpu, &acpi_cpu_id) != 0)
return -ENOENT;
cpu_node = acpi_find_processor_node(table, acpi_cpu_id);
if (cpu_node) {
@ -614,18 +601,22 @@ static int find_acpi_cpu_topology_tag(unsigned int cpu, int level, int flag)
*
* Check the node representing a CPU for a given flag.
*
* Return: -ENOENT if the PPTT doesn't exist, the CPU cannot be found or
* the table revision isn't new enough.
* Return: -ENOENT if can't get CPU's ACPI Processor UID, the PPTT doesn't
* exist, the CPU cannot be found or the table revision isn't new
* enough.
* 1, any passed flag set
* 0, flag unset
*/
static int check_acpi_cpu_flag(unsigned int cpu, int rev, u32 flag)
{
struct acpi_table_header *table;
u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu);
u32 acpi_cpu_id;
struct acpi_pptt_processor *cpu_node = NULL;
int ret = -ENOENT;
if (acpi_get_cpu_uid(cpu, &acpi_cpu_id) != 0)
return -ENOENT;
table = acpi_get_pptt();
if (!table)
return -ENOENT;
@ -651,7 +642,8 @@ static int check_acpi_cpu_flag(unsigned int cpu, int rev, u32 flag)
* in the PPTT. Errors caused by lack of a PPTT table, or otherwise, return 0
* indicating we didn't find any cache levels.
*
* Return: -ENOENT if no PPTT table or no PPTT processor struct found.
* Return: -ENOENT if no PPTT table, can't get CPU's ACPI Process UID or no PPTT
* processor struct found.
* 0 on success.
*/
int acpi_get_cache_info(unsigned int cpu, unsigned int *levels,
@ -671,7 +663,9 @@ int acpi_get_cache_info(unsigned int cpu, unsigned int *levels,
pr_debug("Cache Setup: find cache levels for CPU=%d\n", cpu);
acpi_cpu_id = get_acpi_id_for_cpu(cpu);
if (acpi_get_cpu_uid(cpu, &acpi_cpu_id))
return -ENOENT;
cpu_node = acpi_find_processor_node(table, acpi_cpu_id);
if (!cpu_node)
return -ENOENT;
@ -780,8 +774,9 @@ int find_acpi_cpu_topology_package(unsigned int cpu)
* It may not exist in single CPU systems. In simple multi-CPU systems,
* it may be equal to the package topology level.
*
* Return: -ENOENT if the PPTT doesn't exist, the CPU cannot be found
* or there is no toplogy level above the CPU..
* Return: -ENOENT if the PPTT doesn't exist, can't get CPU's ACPI
* Processor UID, the CPU cannot be found or there is no toplogy level
* above the CPU.
* Otherwise returns a value which represents the package for this CPU.
*/
@ -797,7 +792,9 @@ int find_acpi_cpu_topology_cluster(unsigned int cpu)
if (!table)
return -ENOENT;
acpi_cpu_id = get_acpi_id_for_cpu(cpu);
if (acpi_get_cpu_uid(cpu, &acpi_cpu_id) != 0)
return -ENOENT;
cpu_node = acpi_find_processor_node(table, acpi_cpu_id);
if (!cpu_node || !cpu_node->parent)
return -ENOENT;
@ -872,7 +869,9 @@ static void acpi_pptt_get_child_cpus(struct acpi_table_header *table_hdr,
cpumask_clear(cpus);
for_each_possible_cpu(cpu) {
acpi_id = get_acpi_id_for_cpu(cpu);
if (acpi_get_cpu_uid(cpu, &acpi_id) != 0)
continue;
cpu_node = acpi_find_processor_node(table_hdr, acpi_id);
while (cpu_node) {
@ -966,10 +965,13 @@ int find_acpi_cache_level_from_id(u32 cache_id)
for_each_possible_cpu(cpu) {
bool empty;
int level = 1;
u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu);
u32 acpi_cpu_id;
struct acpi_pptt_cache *cache;
struct acpi_pptt_processor *cpu_node;
if (acpi_get_cpu_uid(cpu, &acpi_cpu_id) != 0)
continue;
cpu_node = acpi_find_processor_node(table, acpi_cpu_id);
if (!cpu_node)
continue;
@ -979,7 +981,7 @@ int find_acpi_cache_level_from_id(u32 cache_id)
empty = true;
for (int i = 0; i < ARRAY_SIZE(cache_type); i++) {
struct acpi_pptt_cache_v1_full *cache_v1;
struct acpi_pptt_cache_v1 *cache_v1;
cache = acpi_find_cache_node(table, acpi_cpu_id, cache_type[i],
level, &cpu_node);
@ -1030,10 +1032,13 @@ int acpi_pptt_get_cpumask_from_cache_id(u32 cache_id, cpumask_t *cpus)
for_each_possible_cpu(cpu) {
bool empty;
int level = 1;
u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu);
u32 acpi_cpu_id;
struct acpi_pptt_cache *cache;
struct acpi_pptt_processor *cpu_node;
if (acpi_get_cpu_uid(cpu, &acpi_cpu_id) != 0)
continue;
cpu_node = acpi_find_processor_node(table, acpi_cpu_id);
if (!cpu_node)
continue;
@ -1043,7 +1048,7 @@ int acpi_pptt_get_cpumask_from_cache_id(u32 cache_id, cpumask_t *cpus)
empty = true;
for (int i = 0; i < ARRAY_SIZE(cache_type); i++) {
struct acpi_pptt_cache_v1_full *cache_v1;
struct acpi_pptt_cache_v1 *cache_v1;
cache = acpi_find_cache_node(table, acpi_cpu_id, cache_type[i],
level, &cpu_node);

View File

@ -53,7 +53,7 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
{
struct acpi_device *device = data;
struct acpi_processor *pr;
int saved;
int saved, ev_data = 0;
if (device->handle != handle)
return;
@ -66,33 +66,27 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
case ACPI_PROCESSOR_NOTIFY_PERFORMANCE:
saved = pr->performance_platform_limit;
acpi_processor_ppc_has_changed(pr, 1);
if (saved == pr->performance_platform_limit)
break;
acpi_bus_generate_netlink_event(device->pnp.device_class,
dev_name(&device->dev), event,
pr->performance_platform_limit);
ev_data = pr->performance_platform_limit;
if (saved == ev_data)
return;
break;
case ACPI_PROCESSOR_NOTIFY_POWER:
acpi_processor_power_state_has_changed(pr);
acpi_bus_generate_netlink_event(device->pnp.device_class,
dev_name(&device->dev), event, 0);
break;
case ACPI_PROCESSOR_NOTIFY_THROTTLING:
acpi_processor_tstate_has_changed(pr);
acpi_bus_generate_netlink_event(device->pnp.device_class,
dev_name(&device->dev), event, 0);
break;
case ACPI_PROCESSOR_NOTIFY_HIGEST_PERF_CHANGED:
cpufreq_update_limits(pr->id);
acpi_bus_generate_netlink_event(device->pnp.device_class,
dev_name(&device->dev), event, 0);
break;
default:
acpi_handle_debug(handle, "Unsupported event [0x%x]\n", event);
break;
return;
}
return;
acpi_bus_generate_netlink_event("processor", dev_name(&device->dev),
event, ev_data);
}
static int __acpi_processor_start(struct acpi_device *device);

View File

@ -819,19 +819,13 @@ static void acpi_processor_setup_cstates(struct acpi_processor *pr)
drv->state_count = count;
}
static inline void acpi_processor_cstate_first_run_checks(void)
static inline void acpi_processor_update_max_cstate(void)
{
static int first_run;
if (first_run)
return;
dmi_check_system(processor_power_dmi_table);
max_cstate = acpi_processor_cstate_check(max_cstate);
if (max_cstate < ACPI_C_STATES_MAX)
pr_notice("processor limited to max C-state %d\n", max_cstate);
first_run++;
if (nocst)
return;
@ -840,7 +834,7 @@ static inline void acpi_processor_cstate_first_run_checks(void)
#else
static inline int disabled_by_idle_boot_param(void) { return 0; }
static inline void acpi_processor_cstate_first_run_checks(void) { }
static inline void acpi_processor_update_max_cstate(void) { }
static int acpi_processor_get_cstate_info(struct acpi_processor *pr)
{
return -ENODEV;
@ -1016,9 +1010,7 @@ static bool combine_lpi_states(struct acpi_lpi_state *local,
result->arch_flags = parent->arch_flags;
result->index = parent->index;
strscpy(result->desc, local->desc, ACPI_CX_DESC_LEN);
strlcat(result->desc, "+", ACPI_CX_DESC_LEN);
strlcat(result->desc, parent->desc, ACPI_CX_DESC_LEN);
scnprintf(result->desc, ACPI_CX_DESC_LEN, "%s+%s", local->desc, parent->desc);
return true;
}
@ -1068,6 +1060,8 @@ static unsigned int flatten_lpi_states(struct acpi_processor *pr,
stash_composite_state(curr_level, flpi);
flat_state_cnt++;
flpi++;
if (flat_state_cnt >= ACPI_PROCESSOR_MAX_POWER)
break;
}
}
}
@ -1273,16 +1267,15 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr)
int acpi_processor_hotplug(struct acpi_processor *pr)
{
struct cpuidle_device *dev = per_cpu(acpi_cpuidle_device, pr->id);
int ret = 0;
struct cpuidle_device *dev;
if (disabled_by_idle_boot_param())
return 0;
if (!pr->flags.power_setup_done)
if (!pr->flags.power_setup_done || !dev)
return -ENODEV;
dev = per_cpu(acpi_cpuidle_device, pr->id);
cpuidle_pause_and_lock();
cpuidle_disable_device(dev);
ret = acpi_processor_get_power_info(pr);
@ -1314,37 +1307,42 @@ int acpi_processor_power_state_has_changed(struct acpi_processor *pr)
*/
if (pr->id == 0 && cpuidle_get_driver() == &acpi_idle_driver) {
/* Protect against cpu-hotplug */
cpus_read_lock();
/* Unregister cpuidle device of all CPUs */
cpuidle_pause_and_lock();
/* Disable all cpuidle devices */
for_each_online_cpu(cpu) {
_pr = per_cpu(processors, cpu);
if (!_pr || !_pr->flags.power_setup_done)
continue;
for_each_possible_cpu(cpu) {
dev = per_cpu(acpi_cpuidle_device, cpu);
cpuidle_disable_device(dev);
}
/* Populate Updated C-state information */
acpi_processor_get_power_info(pr);
acpi_processor_setup_cpuidle_states(pr);
/* Enable all cpuidle devices */
for_each_online_cpu(cpu) {
_pr = per_cpu(processors, cpu);
if (!_pr || !_pr->flags.power_setup_done)
if (!_pr || !_pr->flags.power || !dev)
continue;
acpi_processor_get_power_info(_pr);
if (_pr->flags.power) {
dev = per_cpu(acpi_cpuidle_device, cpu);
acpi_processor_setup_cpuidle_dev(_pr, dev);
cpuidle_enable_device(dev);
}
cpuidle_unregister_device_no_lock(dev);
kfree(dev);
_pr->flags.power = 0;
}
cpuidle_resume_and_unlock();
/*
* Unregister ACPI idle driver, reinitialize ACPI idle states
* and register ACPI idle driver again.
*/
acpi_processor_unregister_idle_driver();
acpi_processor_register_idle_driver();
/*
* Reinitialize power information of all CPUs and re-register
* all cpuidle devices. Now idle states is ok to use, can enable
* cpuidle of each CPU safely one by one.
*/
for_each_possible_cpu(cpu) {
_pr = per_cpu(processors, cpu);
if (!_pr)
continue;
acpi_processor_power_init(_pr);
}
cpus_read_unlock();
}
@ -1357,6 +1355,8 @@ void acpi_processor_register_idle_driver(void)
int ret = -ENODEV;
int cpu;
acpi_processor_update_max_cstate();
/*
* ACPI idle driver is used by all possible CPUs.
* Use the processor power info of one in them to set up idle states.
@ -1368,7 +1368,6 @@ void acpi_processor_register_idle_driver(void)
if (!pr)
continue;
acpi_processor_cstate_first_run_checks();
ret = acpi_processor_get_power_info(pr);
if (!ret) {
pr->flags.power_setup_done = 1;
@ -1384,6 +1383,7 @@ void acpi_processor_register_idle_driver(void)
ret = cpuidle_register_driver(&acpi_idle_driver);
if (ret) {
pr->flags.power_setup_done = 0;
pr_debug("register %s failed.\n", acpi_idle_driver.name);
return;
}
@ -1392,7 +1392,16 @@ void acpi_processor_register_idle_driver(void)
void acpi_processor_unregister_idle_driver(void)
{
struct acpi_processor *pr;
int cpu;
cpuidle_unregister_driver(&acpi_idle_driver);
for_each_possible_cpu(cpu) {
pr = per_cpu(processors, cpu);
if (!pr)
continue;
pr->flags.power_setup_done = 0;
}
}
void acpi_processor_power_init(struct acpi_processor *pr)
@ -1409,8 +1418,6 @@ void acpi_processor_power_init(struct acpi_processor *pr)
if (disabled_by_idle_boot_param())
return;
acpi_processor_cstate_first_run_checks();
if (!acpi_processor_get_power_info(pr))
pr->flags.power_setup_done = 1;
@ -1431,6 +1438,7 @@ void acpi_processor_power_init(struct acpi_processor *pr)
*/
if (cpuidle_register_device(dev)) {
per_cpu(acpi_cpuidle_device, pr->id) = NULL;
pr->flags.power_setup_done = 0;
kfree(dev);
}
}

View File

@ -44,10 +44,15 @@ int acpi_get_riscv_isa(struct acpi_table_header *table, unsigned int cpu, const
struct acpi_rhct_isa_string *isa_node;
struct acpi_table_rhct *rhct;
u32 *hart_info_node_offset;
u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu);
u32 acpi_cpu_id;
int ret;
BUG_ON(acpi_disabled);
ret = acpi_get_cpu_uid(cpu, &acpi_cpu_id);
if (ret != 0)
return ret;
if (!table) {
rhct = acpi_get_rhct();
if (!rhct)

View File

@ -26,8 +26,6 @@
#include "sbshc.h"
#define ACPI_SBS_CLASS "sbs"
#define ACPI_AC_CLASS "ac_adapter"
#define ACPI_SBS_DEVICE_NAME "Smart Battery System"
#define ACPI_BATTERY_DIR_NAME "BAT%i"
#define ACPI_AC_DIR_NAME "AC0"
@ -648,8 +646,6 @@ static int acpi_sbs_probe(struct platform_device *pdev)
sbs->hc = dev_get_drvdata(pdev->dev.parent);
sbs->device = device;
strscpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME);
strscpy(acpi_device_class(device), ACPI_SBS_CLASS);
result = acpi_charger_add(sbs);
if (result && result != -ENODEV)

View File

@ -18,9 +18,6 @@
#include "sbshc.h"
#include "internal.h"
#define ACPI_SMB_HC_CLASS "smbus_host_ctl"
#define ACPI_SMB_HC_DEVICE_NAME "ACPI SMBus HC"
struct acpi_smb_hc {
struct acpi_ec *ec;
struct mutex lock;
@ -251,9 +248,6 @@ static int acpi_smbus_hc_probe(struct platform_device *pdev)
return -EIO;
}
strscpy(acpi_device_name(device), ACPI_SMB_HC_DEVICE_NAME);
strscpy(acpi_device_class(device), ACPI_SMB_HC_CLASS);
hc = kzalloc_obj(struct acpi_smb_hc);
if (!hc)
return -ENOMEM;

View File

@ -35,7 +35,6 @@
#include "internal.h"
#define ACPI_THERMAL_CLASS "thermal_zone"
#define ACPI_THERMAL_DEVICE_NAME "Thermal Zone"
#define ACPI_THERMAL_NOTIFY_TEMPERATURE 0x80
#define ACPI_THERMAL_NOTIFY_THRESHOLDS 0x81
#define ACPI_THERMAL_NOTIFY_DEVICES 0x82
@ -341,7 +340,7 @@ static void acpi_thermal_trips_update(struct acpi_thermal *tz, u32 event)
thermal_zone_for_each_trip(tz->thermal_zone,
acpi_thermal_adjust_trip, &atd);
acpi_queue_thermal_check(tz);
acpi_bus_generate_netlink_event(adev->pnp.device_class,
acpi_bus_generate_netlink_event(ACPI_THERMAL_CLASS,
dev_name(&adev->dev), event, 0);
}
@ -543,7 +542,7 @@ static void acpi_thermal_zone_device_hot(struct thermal_zone_device *thermal)
{
struct acpi_thermal *tz = thermal_zone_device_priv(thermal);
acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
acpi_bus_generate_netlink_event(ACPI_THERMAL_CLASS,
dev_name(&tz->device->dev),
ACPI_THERMAL_NOTIFY_HOT, 1);
}
@ -552,7 +551,7 @@ static void acpi_thermal_zone_device_critical(struct thermal_zone_device *therma
{
struct acpi_thermal *tz = thermal_zone_device_priv(thermal);
acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
acpi_bus_generate_netlink_event(ACPI_THERMAL_CLASS,
dev_name(&tz->device->dev),
ACPI_THERMAL_NOTIFY_CRITICAL, 1);
@ -800,8 +799,6 @@ static int acpi_thermal_probe(struct platform_device *pdev)
tz->device = device;
strscpy(tz->name, device->pnp.bus_id);
strscpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
strscpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
acpi_thermal_aml_dependency_fix(tz);
@ -879,8 +876,8 @@ static int acpi_thermal_probe(struct platform_device *pdev)
mutex_init(&tz->thermal_check_lock);
INIT_WORK(&tz->thermal_check_work, acpi_thermal_check_fn);
pr_info("%s [%s] (%ld C)\n", acpi_device_name(device),
acpi_device_bid(device), deci_kelvin_to_celsius(tz->temp_dk));
pr_info("Thermal Zone [%s] (%ld C)\n", acpi_device_bid(device),
deci_kelvin_to_celsius(tz->temp_dk));
result = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY,
acpi_thermal_notify, tz);

View File

@ -18,78 +18,86 @@
#include "../internal.h"
static const struct acpi_device_id acpi_cmos_rtc_ids[] = {
{ "PNP0B00" },
{ "PNP0B01" },
{ "PNP0B02" },
{}
{ "ACPI000E", 1 }, /* ACPI Time and Alarm Device (TAD) */
ACPI_CMOS_RTC_IDS
};
static acpi_status
acpi_cmos_rtc_space_handler(u32 function, acpi_physical_address address,
u32 bits, u64 *value64,
void *handler_context, void *region_context)
bool cmos_rtc_platform_device_present;
static acpi_status acpi_cmos_rtc_space_handler(u32 function,
acpi_physical_address address,
u32 bits, u64 *value64,
void *handler_context,
void *region_context)
{
int i;
unsigned int i, bytes = DIV_ROUND_UP(bits, 8);
u8 *value = (u8 *)value64;
if (address > 0xff || !value64)
return AE_BAD_PARAMETER;
if (function != ACPI_WRITE && function != ACPI_READ)
return AE_BAD_PARAMETER;
guard(spinlock_irq)(&rtc_lock);
spin_lock_irq(&rtc_lock);
for (i = 0; i < DIV_ROUND_UP(bits, 8); ++i, ++address, ++value)
if (function == ACPI_READ)
*value = CMOS_READ(address);
else
if (function == ACPI_WRITE) {
for (i = 0; i < bytes; i++, address++, value++)
CMOS_WRITE(*value, address);
spin_unlock_irq(&rtc_lock);
return AE_OK;
}
return AE_OK;
if (function == ACPI_READ) {
for (i = 0; i < bytes; i++, address++, value++)
*value = CMOS_READ(address);
return AE_OK;
}
return AE_BAD_PARAMETER;
}
int acpi_install_cmos_rtc_space_handler(acpi_handle handle)
static int acpi_install_cmos_rtc_space_handler(acpi_handle handle)
{
static bool cmos_rtc_space_handler_present __read_mostly;
acpi_status status;
if (cmos_rtc_space_handler_present)
return 0;
status = acpi_install_address_space_handler(handle,
ACPI_ADR_SPACE_CMOS,
&acpi_cmos_rtc_space_handler,
NULL, NULL);
ACPI_ADR_SPACE_CMOS,
acpi_cmos_rtc_space_handler,
NULL, NULL);
if (ACPI_FAILURE(status)) {
pr_err("Error installing CMOS-RTC region handler\n");
pr_err("Failed to install CMOS-RTC address space handler\n");
return -ENODEV;
}
cmos_rtc_space_handler_present = true;
return 1;
}
EXPORT_SYMBOL_GPL(acpi_install_cmos_rtc_space_handler);
void acpi_remove_cmos_rtc_space_handler(acpi_handle handle)
static int acpi_cmos_rtc_attach(struct acpi_device *adev,
const struct acpi_device_id *id)
{
if (ACPI_FAILURE(acpi_remove_address_space_handler(handle,
ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler)))
pr_err("Error removing CMOS-RTC region handler\n");
}
EXPORT_SYMBOL_GPL(acpi_remove_cmos_rtc_space_handler);
int ret;
static int acpi_cmos_rtc_attach_handler(struct acpi_device *adev, const struct acpi_device_id *id)
{
return acpi_install_cmos_rtc_space_handler(adev->handle);
}
ret = acpi_install_cmos_rtc_space_handler(adev->handle);
if (ret < 0)
return ret;
static void acpi_cmos_rtc_detach_handler(struct acpi_device *adev)
{
acpi_remove_cmos_rtc_space_handler(adev->handle);
if (IS_ERR_OR_NULL(acpi_create_platform_device(adev, NULL))) {
pr_err("Failed to create a platform device for %s\n", (char *)id->id);
return 0;
} else if (!id->driver_data) {
cmos_rtc_platform_device_present = true;
}
return 1;
}
static struct acpi_scan_handler cmos_rtc_handler = {
.ids = acpi_cmos_rtc_ids,
.attach = acpi_cmos_rtc_attach_handler,
.detach = acpi_cmos_rtc_detach_handler,
.attach = acpi_cmos_rtc_attach,
};
void __init acpi_cmos_rtc_init(void)

View File

@ -496,6 +496,16 @@ struct auxiliary_device *__devm_auxiliary_device_create(struct device *dev,
}
EXPORT_SYMBOL_GPL(__devm_auxiliary_device_create);
/**
* dev_is_auxiliary - check if the device is an auxiliary one
* @dev: device to check
*/
bool dev_is_auxiliary(struct device *dev)
{
return dev->bus == &auxiliary_bus_type;
}
EXPORT_SYMBOL_GPL(dev_is_auxiliary);
void __init auxiliary_bus_init(void)
{
WARN_ON(bus_register(&auxiliary_bus_type));

View File

@ -50,7 +50,8 @@ struct cppc_freq_invariance {
static DEFINE_PER_CPU(struct cppc_freq_invariance, cppc_freq_inv);
static struct kthread_worker *kworker_fie;
static int cppc_perf_from_fbctrs(struct cppc_perf_fb_ctrs *fb_ctrs_t0,
static int cppc_perf_from_fbctrs(u64 reference_perf,
struct cppc_perf_fb_ctrs *fb_ctrs_t0,
struct cppc_perf_fb_ctrs *fb_ctrs_t1);
/**
@ -70,7 +71,7 @@ static void __cppc_scale_freq_tick(struct cppc_freq_invariance *cppc_fi)
struct cppc_perf_fb_ctrs fb_ctrs = {0};
struct cppc_cpudata *cpu_data;
unsigned long local_freq_scale;
u64 perf;
u64 perf, ref_perf;
cpu_data = cppc_fi->cpu_data;
@ -79,7 +80,9 @@ static void __cppc_scale_freq_tick(struct cppc_freq_invariance *cppc_fi)
return;
}
perf = cppc_perf_from_fbctrs(&cppc_fi->prev_perf_fb_ctrs, &fb_ctrs);
ref_perf = cpu_data->perf_caps.reference_perf;
perf = cppc_perf_from_fbctrs(ref_perf,
&cppc_fi->prev_perf_fb_ctrs, &fb_ctrs);
if (!perf)
return;
@ -287,6 +290,21 @@ static inline void cppc_freq_invariance_exit(void)
}
#endif /* CONFIG_ACPI_CPPC_CPUFREQ_FIE */
static void cppc_cpufreq_update_perf_limits(struct cppc_cpudata *cpu_data,
struct cpufreq_policy *policy)
{
struct cppc_perf_caps *caps = &cpu_data->perf_caps;
u32 min_perf, max_perf;
min_perf = cppc_khz_to_perf(caps, policy->min);
max_perf = cppc_khz_to_perf(caps, policy->max);
cpu_data->perf_ctrls.min_perf =
clamp_t(u32, min_perf, caps->lowest_perf, caps->highest_perf);
cpu_data->perf_ctrls.max_perf =
clamp_t(u32, max_perf, caps->lowest_perf, caps->highest_perf);
}
static int cppc_cpufreq_set_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
@ -298,6 +316,8 @@ static int cppc_cpufreq_set_target(struct cpufreq_policy *policy,
cpu_data->perf_ctrls.desired_perf =
cppc_khz_to_perf(&cpu_data->perf_caps, target_freq);
cppc_cpufreq_update_perf_limits(cpu_data, policy);
freqs.old = policy->cur;
freqs.new = target_freq;
@ -322,8 +342,9 @@ static unsigned int cppc_cpufreq_fast_switch(struct cpufreq_policy *policy,
desired_perf = cppc_khz_to_perf(&cpu_data->perf_caps, target_freq);
cpu_data->perf_ctrls.desired_perf = desired_perf;
ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls);
cppc_cpufreq_update_perf_limits(cpu_data, policy);
ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls);
if (ret) {
pr_debug("Failed to set target on CPU:%d. ret:%d\n",
cpu, ret);
@ -594,6 +615,12 @@ static struct cppc_cpudata *cppc_cpufreq_get_cpu_data(unsigned int cpu)
goto free_mask;
}
ret = cppc_get_perf(cpu, &cpu_data->perf_ctrls);
if (ret) {
pr_debug("Err reading CPU%d perf ctrls: ret:%d\n", cpu, ret);
goto free_mask;
}
return cpu_data;
free_mask:
@ -723,13 +750,11 @@ static inline u64 get_delta(u64 t1, u64 t0)
return (u32)t1 - (u32)t0;
}
static int cppc_perf_from_fbctrs(struct cppc_perf_fb_ctrs *fb_ctrs_t0,
static int cppc_perf_from_fbctrs(u64 reference_perf,
struct cppc_perf_fb_ctrs *fb_ctrs_t0,
struct cppc_perf_fb_ctrs *fb_ctrs_t1)
{
u64 delta_reference, delta_delivered;
u64 reference_perf;
reference_perf = fb_ctrs_t0->reference_perf;
delta_reference = get_delta(fb_ctrs_t1->reference,
fb_ctrs_t0->reference);
@ -766,7 +791,7 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu)
struct cpufreq_policy *policy __free(put_cpufreq_policy) = cpufreq_cpu_get(cpu);
struct cppc_perf_fb_ctrs fb_ctrs_t0 = {0}, fb_ctrs_t1 = {0};
struct cppc_cpudata *cpu_data;
u64 delivered_perf;
u64 delivered_perf, reference_perf;
int ret;
if (!policy)
@ -783,7 +808,9 @@ static unsigned int cppc_cpufreq_get_rate(unsigned int cpu)
return 0;
}
delivered_perf = cppc_perf_from_fbctrs(&fb_ctrs_t0, &fb_ctrs_t1);
reference_perf = cpu_data->perf_caps.reference_perf;
delivered_perf = cppc_perf_from_fbctrs(reference_perf,
&fb_ctrs_t0, &fb_ctrs_t1);
if (!delivered_perf)
goto out_invalid_counters;
@ -849,6 +876,7 @@ static ssize_t show_auto_select(struct cpufreq_policy *policy, char *buf)
static ssize_t store_auto_select(struct cpufreq_policy *policy,
const char *buf, size_t count)
{
struct cppc_cpudata *cpu_data = policy->driver_data;
bool val;
int ret;
@ -860,6 +888,29 @@ static ssize_t store_auto_select(struct cpufreq_policy *policy,
if (ret)
return ret;
cpu_data->perf_ctrls.auto_sel = val;
if (val) {
u32 old_min_perf = cpu_data->perf_ctrls.min_perf;
u32 old_max_perf = cpu_data->perf_ctrls.max_perf;
/*
* When enabling autonomous selection, program MIN_PERF and
* MAX_PERF from current policy limits so that the platform
* uses the correct performance bounds immediately.
*/
cppc_cpufreq_update_perf_limits(cpu_data, policy);
ret = cppc_set_perf(policy->cpu, &cpu_data->perf_ctrls);
if (ret) {
cpu_data->perf_ctrls.min_perf = old_min_perf;
cpu_data->perf_ctrls.max_perf = old_max_perf;
cppc_set_auto_sel(policy->cpu, false);
cpu_data->perf_ctrls.auto_sel = false;
return ret;
}
}
return count;
}
@ -910,19 +961,48 @@ static ssize_t store_##_name(struct cpufreq_policy *policy, \
CPPC_CPUFREQ_ATTR_RW_U64(auto_act_window, cppc_get_auto_act_window,
cppc_set_auto_act_window)
CPPC_CPUFREQ_ATTR_RW_U64(energy_performance_preference_val,
cppc_get_epp_perf, cppc_set_epp)
static ssize_t
show_energy_performance_preference_val(struct cpufreq_policy *policy, char *buf)
{
return cppc_cpufreq_sysfs_show_u64(policy->cpu, cppc_get_epp_perf, buf);
}
static ssize_t
store_energy_performance_preference_val(struct cpufreq_policy *policy,
const char *buf, size_t count)
{
struct cppc_cpudata *cpu_data = policy->driver_data;
u64 val;
int ret;
ret = kstrtou64(buf, 0, &val);
if (ret)
return ret;
ret = cppc_set_epp(policy->cpu, val);
if (ret)
return ret;
cpu_data->perf_ctrls.energy_perf = val;
return count;
}
CPPC_CPUFREQ_ATTR_RW_U64(perf_limited, cppc_get_perf_limited,
cppc_set_perf_limited)
cpufreq_freq_attr_ro(freqdomain_cpus);
cpufreq_freq_attr_rw(auto_select);
cpufreq_freq_attr_rw(auto_act_window);
cpufreq_freq_attr_rw(energy_performance_preference_val);
cpufreq_freq_attr_rw(perf_limited);
static struct freq_attr *cppc_cpufreq_attr[] = {
&freqdomain_cpus,
&auto_select,
&auto_act_window,
&energy_performance_preference_val,
&perf_limited,
NULL,
};

View File

@ -714,6 +714,23 @@ int cpuidle_register_device(struct cpuidle_device *dev)
EXPORT_SYMBOL_GPL(cpuidle_register_device);
void cpuidle_unregister_device_no_lock(struct cpuidle_device *dev)
{
if (!dev || dev->registered == 0)
return;
lockdep_assert_held(&cpuidle_lock);
cpuidle_disable_device(dev);
cpuidle_remove_sysfs(dev);
__cpuidle_unregister_device(dev);
cpuidle_coupled_unregister_device(dev);
}
EXPORT_SYMBOL_GPL(cpuidle_unregister_device_no_lock);
/**
* cpuidle_unregister_device - unregisters a CPU's idle PM feature
* @dev: the cpu
@ -724,18 +741,9 @@ void cpuidle_unregister_device(struct cpuidle_device *dev)
return;
cpuidle_pause_and_lock();
cpuidle_disable_device(dev);
cpuidle_remove_sysfs(dev);
__cpuidle_unregister_device(dev);
cpuidle_coupled_unregister_device(dev);
cpuidle_unregister_device_no_lock(dev);
cpuidle_resume_and_unlock();
}
EXPORT_SYMBOL_GPL(cpuidle_unregister_device);
/**

View File

@ -26,8 +26,6 @@
#include <linux/types.h>
#define ACPI_AC_CLASS "ac_adapter"
struct atif_verify_interface {
u16 size; /* structure size in bytes (includes size field) */
u16 version; /* version */

View File

@ -44,8 +44,6 @@ bool radeon_atpx_dgpu_req_power_for_displays(void);
static inline bool radeon_atpx_dgpu_req_power_for_displays(void) { return false; }
#endif
#define ACPI_AC_CLASS "ac_adapter"
struct atif_verify_interface {
u16 size; /* structure size in bytes (includes size field) */
u16 version; /* version */

View File

@ -287,25 +287,16 @@ static int hisi_pcie_error_handler_probe(struct platform_device *pdev)
priv->nb.notifier_call = hisi_pcie_notify_error;
priv->dev = &pdev->dev;
ret = ghes_register_vendor_record_notifier(&priv->nb);
ret = devm_ghes_register_vendor_record_notifier(&pdev->dev, &priv->nb);
if (ret) {
dev_err(&pdev->dev,
"Failed to register hisi pcie controller error handler with apei\n");
return ret;
}
platform_set_drvdata(pdev, priv);
return 0;
}
static void hisi_pcie_error_handler_remove(struct platform_device *pdev)
{
struct hisi_pcie_error_private *priv = platform_get_drvdata(pdev);
ghes_unregister_vendor_record_notifier(&priv->nb);
}
static const struct acpi_device_id hisi_pcie_acpi_match[] = {
{ "HISI0361", 0 },
{ }
@ -317,7 +308,6 @@ static struct platform_driver hisi_pcie_error_handler_driver = {
.acpi_match_table = hisi_pcie_acpi_match,
},
.probe = hisi_pcie_error_handler_probe,
.remove = hisi_pcie_error_handler_remove,
};
module_platform_driver(hisi_pcie_error_handler_driver);

View File

@ -236,21 +236,27 @@ static int write_tag_to_st_table(struct pci_dev *pdev, int index, u16 tag)
* with a specific CPU
* @pdev: PCI device
* @mem_type: target memory type (volatile or persistent RAM)
* @cpu_uid: associated CPU id
* @cpu: associated CPU id
* @tag: Steering Tag to be returned
*
* Return the Steering Tag for a target memory that is associated with a
* specific CPU as indicated by cpu_uid.
* specific CPU as indicated by cpu.
*
* Return: 0 if success, otherwise negative value (-errno)
*/
int pcie_tph_get_cpu_st(struct pci_dev *pdev, enum tph_mem_type mem_type,
unsigned int cpu_uid, u16 *tag)
unsigned int cpu, u16 *tag)
{
#ifdef CONFIG_ACPI
struct pci_dev *rp;
acpi_handle rp_acpi_handle;
union st_info info;
u32 cpu_uid;
int ret;
ret = acpi_get_cpu_uid(cpu, &cpu_uid);
if (ret != 0)
return ret;
rp = pcie_find_root_port(pdev);
if (!rp || !rp->bus || !rp->bus->bridge)
@ -265,9 +271,9 @@ int pcie_tph_get_cpu_st(struct pci_dev *pdev, enum tph_mem_type mem_type,
*tag = tph_extract_tag(mem_type, pdev->tph_req_type, &info);
pci_dbg(pdev, "get steering tag: mem_type=%s, cpu_uid=%d, tag=%#04x\n",
pci_dbg(pdev, "get steering tag: mem_type=%s, cpu=%d, tag=%#04x\n",
(mem_type == TPH_MEM_TYPE_VM) ? "volatile" : "persistent",
cpu_uid, *tag);
cpu, *tag);
return 0;
#else

View File

@ -1107,15 +1107,17 @@ static int arm_cspmu_acpi_get_cpus(struct arm_cspmu *cspmu)
{
struct acpi_apmt_node *apmt_node;
int affinity_flag;
u32 cpu_uid;
int cpu;
int ret;
apmt_node = arm_cspmu_apmt_node(cspmu->dev);
affinity_flag = apmt_node->flags & ACPI_APMT_FLAGS_AFFINITY;
if (affinity_flag == ACPI_APMT_FLAGS_AFFINITY_PROC) {
for_each_possible_cpu(cpu) {
if (apmt_node->proc_affinity ==
get_acpi_id_for_cpu(cpu)) {
ret = acpi_get_cpu_uid(cpu, &cpu_uid);
if (ret == 0 && apmt_node->proc_affinity == cpu_uid) {
cpumask_set_cpu(cpu, &cspmu->associated_cpus);
break;
}

View File

@ -58,8 +58,6 @@ enum hp_ec_offsets {
#define HP_POWER_LIMIT_DEFAULT 0x00
#define HP_POWER_LIMIT_NO_CHANGE 0xFF
#define ACPI_AC_CLASS "ac_adapter"
#define zero_if_sup(tmp) (zero_insize_support?0:sizeof(tmp)) // use when zero insize is required
enum hp_thermal_profile_omen_v0 {

View File

@ -53,7 +53,6 @@
#define LENOVO_CAPABILITY_DATA_01_GUID "7A8F5407-CB67-4D6E-B547-39B3BE018154"
#define LENOVO_FAN_TEST_DATA_GUID "B642801B-3D21-45DE-90AE-6E86F164FB21"
#define ACPI_AC_CLASS "ac_adapter"
#define ACPI_AC_NOTIFY_STATUS 0x80
#define LWMI_FEATURE_ID_FAN_TEST 0x05

View File

@ -27,6 +27,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/acpi.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@ -215,6 +216,11 @@ static inline void cmos_write_bank2(unsigned char val, unsigned char addr)
/*----------------------------------------------------------------*/
static bool cmos_no_alarm(struct cmos_rtc *cmos)
{
return !is_valid_irq(cmos->irq) && !cmos_use_acpi_alarm();
}
static int cmos_read_time(struct device *dev, struct rtc_time *t)
{
int ret;
@ -286,7 +292,7 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
};
/* This not only a rtc_op, but also called directly */
if (!is_valid_irq(cmos->irq))
if (cmos_no_alarm(cmos))
return -ETIMEDOUT;
/* Basic alarms only support hour, minute, and seconds fields.
@ -519,7 +525,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
int ret;
/* This not only a rtc_op, but also called directly */
if (!is_valid_irq(cmos->irq))
if (cmos_no_alarm(cmos))
return -EIO;
ret = cmos_validate_alarm(dev, t);
@ -816,6 +822,9 @@ static void rtc_wake_off(struct device *dev)
#ifdef CONFIG_X86
static void use_acpi_alarm_quirks(void)
{
if (acpi_gbl_FADT.flags & ACPI_FADT_FIXED_RTC)
return;
switch (boot_cpu_data.x86_vendor) {
case X86_VENDOR_INTEL:
if (dmi_get_bios_year() < 2015)
@ -829,8 +838,6 @@ static void use_acpi_alarm_quirks(void)
default:
return;
}
if (!is_hpet_enabled())
return;
use_acpi_alarm = true;
}
@ -1094,7 +1101,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq);
goto cleanup1;
}
} else {
} else if (!cmos_use_acpi_alarm()) {
clear_bit(RTC_FEATURE_ALARM, cmos_rtc.rtc->features);
}
@ -1119,7 +1126,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
acpi_rtc_event_setup(dev);
dev_info(dev, "%s%s, %d bytes nvram%s\n",
!is_valid_irq(rtc_irq) ? "no alarms" :
cmos_no_alarm(&cmos_rtc) ? "no alarms" :
cmos_rtc.mon_alrm ? "alarms up to one year" :
cmos_rtc.day_alrm ? "alarms up to one month" :
"alarms up to one day",
@ -1145,7 +1152,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
static void cmos_do_shutdown(int rtc_irq)
{
spin_lock_irq(&rtc_lock);
if (is_valid_irq(rtc_irq))
if (!cmos_no_alarm(&cmos_rtc))
cmos_irq_disable(&cmos_rtc, RTC_IRQMASK);
spin_unlock_irq(&rtc_lock);
}
@ -1369,85 +1376,6 @@ static int __maybe_unused cmos_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(cmos_pm_ops, cmos_suspend, cmos_resume);
/*----------------------------------------------------------------*/
/* On non-x86 systems, a "CMOS" RTC lives most naturally on platform_bus.
* ACPI systems always list these as PNPACPI devices, and pre-ACPI PCs
* probably list them in similar PNPBIOS tables; so PNP is more common.
*
* We don't use legacy "poke at the hardware" probing. Ancient PCs that
* predate even PNPBIOS should set up platform_bus devices.
*/
#ifdef CONFIG_PNP
#include <linux/pnp.h>
static int cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
{
int irq;
if (pnp_port_start(pnp, 0) == 0x70 && !pnp_irq_valid(pnp, 0)) {
irq = 0;
#ifdef CONFIG_X86
/* Some machines contain a PNP entry for the RTC, but
* don't define the IRQ. It should always be safe to
* hardcode it on systems with a legacy PIC.
*/
if (nr_legacy_irqs())
irq = RTC_IRQ;
#endif
} else {
irq = pnp_irq(pnp, 0);
}
return cmos_do_probe(&pnp->dev, pnp_get_resource(pnp, IORESOURCE_IO, 0), irq);
}
static void cmos_pnp_remove(struct pnp_dev *pnp)
{
cmos_do_remove(&pnp->dev);
}
static void cmos_pnp_shutdown(struct pnp_dev *pnp)
{
struct device *dev = &pnp->dev;
struct cmos_rtc *cmos = dev_get_drvdata(dev);
if (system_state == SYSTEM_POWER_OFF) {
int retval = cmos_poweroff(dev);
if (cmos_aie_poweroff(dev) < 0 && !retval)
return;
}
cmos_do_shutdown(cmos->irq);
}
static const struct pnp_device_id rtc_ids[] = {
{ .id = "PNP0b00", },
{ .id = "PNP0b01", },
{ .id = "PNP0b02", },
{ },
};
MODULE_DEVICE_TABLE(pnp, rtc_ids);
static struct pnp_driver cmos_pnp_driver = {
.name = driver_name,
.id_table = rtc_ids,
.probe = cmos_pnp_probe,
.remove = cmos_pnp_remove,
.shutdown = cmos_pnp_shutdown,
/* flag ensures resume() gets called, and stops syslog spam */
.flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
.driver = {
.pm = &cmos_pm_ops,
},
};
#endif /* CONFIG_PNP */
#ifdef CONFIG_OF
static const struct of_device_id of_cmos_match[] = {
{
@ -1476,6 +1404,14 @@ static __init void cmos_of_init(struct platform_device *pdev)
#else
static inline void cmos_of_init(struct platform_device *pdev) {}
#endif
#ifdef CONFIG_ACPI
static const struct acpi_device_id acpi_cmos_rtc_ids[] = {
ACPI_CMOS_RTC_IDS
};
MODULE_DEVICE_TABLE(acpi, acpi_cmos_rtc_ids);
#endif
/*----------------------------------------------------------------*/
/* Platform setup should have set up an RTC device, when PNP is
@ -1530,48 +1466,31 @@ static struct platform_driver cmos_platform_driver = {
.name = driver_name,
.pm = &cmos_pm_ops,
.of_match_table = of_match_ptr(of_cmos_match),
.acpi_match_table = ACPI_PTR(acpi_cmos_rtc_ids),
}
};
#ifdef CONFIG_PNP
static bool pnp_driver_registered;
#endif
static bool platform_driver_registered;
static int __init cmos_init(void)
{
int retval = 0;
int retval;
#ifdef CONFIG_PNP
retval = pnp_register_driver(&cmos_pnp_driver);
if (retval == 0)
pnp_driver_registered = true;
#endif
if (!cmos_rtc.dev) {
retval = platform_driver_probe(&cmos_platform_driver,
cmos_platform_probe);
if (retval == 0)
platform_driver_registered = true;
}
if (retval == 0)
if (cmos_rtc.dev)
return 0;
#ifdef CONFIG_PNP
if (pnp_driver_registered)
pnp_unregister_driver(&cmos_pnp_driver);
#endif
return retval;
retval = platform_driver_probe(&cmos_platform_driver, cmos_platform_probe);
if (retval)
return retval;
platform_driver_registered = true;
return 0;
}
module_init(cmos_init);
static void __exit cmos_exit(void)
{
#ifdef CONFIG_PNP
if (pnp_driver_registered)
pnp_unregister_driver(&cmos_pnp_driver);
#endif
if (platform_driver_registered)
platform_driver_unregister(&cmos_platform_driver);
}

View File

@ -8,6 +8,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/watchdog.h>
#define NIWD_CONTROL 0x01
@ -177,9 +178,9 @@ static const struct watchdog_ops ni903x_wdd_ops = {
.get_timeleft = ni903x_wdd_get_timeleft,
};
static int ni903x_acpi_add(struct acpi_device *device)
static int ni903x_acpi_probe(struct platform_device *pdev)
{
struct device *dev = &device->dev;
struct device *dev = &pdev->dev;
struct watchdog_device *wdd;
struct ni903x_wdt *wdt;
acpi_status status;
@ -189,10 +190,10 @@ static int ni903x_acpi_add(struct acpi_device *device)
if (!wdt)
return -ENOMEM;
device->driver_data = wdt;
platform_set_drvdata(pdev, wdt);
wdt->dev = dev;
status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
status = acpi_walk_resources(ACPI_HANDLE(dev), METHOD_NAME__CRS,
ni903x_resources, wdt);
if (ACPI_FAILURE(status) || wdt->io_base == 0) {
dev_err(dev, "failed to get resources\n");
@ -224,9 +225,9 @@ static int ni903x_acpi_add(struct acpi_device *device)
return 0;
}
static void ni903x_acpi_remove(struct acpi_device *device)
static void ni903x_acpi_remove(struct platform_device *pdev)
{
struct ni903x_wdt *wdt = acpi_driver_data(device);
struct ni903x_wdt *wdt = platform_get_drvdata(pdev);
ni903x_wdd_stop(&wdt->wdd);
watchdog_unregister_device(&wdt->wdd);
@ -238,16 +239,16 @@ static const struct acpi_device_id ni903x_device_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, ni903x_device_ids);
static struct acpi_driver ni903x_acpi_driver = {
.name = NIWD_NAME,
.ids = ni903x_device_ids,
.ops = {
.add = ni903x_acpi_add,
.remove = ni903x_acpi_remove,
static struct platform_driver ni903x_acpi_driver = {
.probe = ni903x_acpi_probe,
.remove = ni903x_acpi_remove,
.driver = {
.name = NIWD_NAME,
.acpi_match_table = ni903x_device_ids,
},
};
module_acpi_driver(ni903x_acpi_driver);
module_platform_driver(ni903x_acpi_driver);
MODULE_DESCRIPTION("NI 903x Watchdog");
MODULE_AUTHOR("Jeff Westfahl <jeff.westfahl@ni.com>");

View File

@ -11,6 +11,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/acpi.h>
#include <linux/platform_device.h>
#include <xen/xen.h>
#include <xen/interface/version.h>
#include <xen/xen-ops.h>
@ -107,8 +108,9 @@ static void acpi_pad_notify(acpi_handle handle, u32 event,
}
}
static int acpi_pad_add(struct acpi_device *device)
static int acpi_pad_probe(struct platform_device *pdev)
{
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
acpi_status status;
strcpy(acpi_device_name(device), ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME);
@ -122,13 +124,13 @@ static int acpi_pad_add(struct acpi_device *device)
return 0;
}
static void acpi_pad_remove(struct acpi_device *device)
static void acpi_pad_remove(struct platform_device *pdev)
{
mutex_lock(&xen_cpu_lock);
xen_acpi_pad_idle_cpus(0);
mutex_unlock(&xen_cpu_lock);
acpi_remove_notify_handler(device->handle,
acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev),
ACPI_DEVICE_NOTIFY, acpi_pad_notify);
}
@ -137,13 +139,12 @@ static const struct acpi_device_id pad_device_ids[] = {
{"", 0},
};
static struct acpi_driver acpi_pad_driver = {
.name = "processor_aggregator",
.class = ACPI_PROCESSOR_AGGREGATOR_CLASS,
.ids = pad_device_ids,
.ops = {
.add = acpi_pad_add,
.remove = acpi_pad_remove,
static struct platform_driver acpi_pad_driver = {
.probe = acpi_pad_probe,
.remove = acpi_pad_remove,
.driver = {
.name = "acpi_processor_aggregator",
.acpi_match_table = pad_device_ids,
},
};
@ -157,6 +158,6 @@ static int __init xen_acpi_pad_init(void)
if (!xen_running_on_version_or_later(4, 2))
return -ENODEV;
return acpi_bus_register_driver(&acpi_pad_driver);
return platform_driver_register(&acpi_pad_driver);
}
subsys_initcall(xen_acpi_pad_init);

View File

@ -613,6 +613,8 @@ struct acpi_bus_event {
u32 data;
};
#define ACPI_AC_CLASS "ac_adapter"
extern struct kobject *acpi_kobj;
extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int);
void acpi_bus_private_data_handler(acpi_handle, void *);
@ -625,7 +627,8 @@ int acpi_dev_install_notify_handler(struct acpi_device *adev,
void acpi_dev_remove_notify_handler(struct acpi_device *adev,
u32 handler_type,
acpi_notify_handler handler);
extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32);
extern int acpi_notifier_call_chain(const char *device_class,
const char *bus_id, u32 type, u32 data);
extern int register_acpi_notifier(struct notifier_block *);
extern int unregister_acpi_notifier(struct notifier_block *);
@ -760,8 +763,6 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev);
#ifdef CONFIG_X86
bool acpi_device_override_status(struct acpi_device *adev, unsigned long long *status);
bool acpi_quirk_skip_acpi_ac_and_battery(void);
int acpi_install_cmos_rtc_space_handler(acpi_handle handle);
void acpi_remove_cmos_rtc_space_handler(acpi_handle handle);
int acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *skip);
#else
static inline bool acpi_device_override_status(struct acpi_device *adev,
@ -773,13 +774,6 @@ static inline bool acpi_quirk_skip_acpi_ac_and_battery(void)
{
return false;
}
static inline int acpi_install_cmos_rtc_space_handler(acpi_handle handle)
{
return 1;
}
static inline void acpi_remove_cmos_rtc_space_handler(acpi_handle handle)
{
}
static inline int
acpi_quirk_skip_serdev_enumeration(struct device *controller_parent, bool *skip)
{

View File

@ -42,6 +42,11 @@
#define CPPC_EPP_PERFORMANCE_PREF 0x00
#define CPPC_EPP_ENERGY_EFFICIENCY_PREF 0xFF
#define CPPC_PERF_LIMITED_DESIRED_EXCURSION BIT(0)
#define CPPC_PERF_LIMITED_MINIMUM_EXCURSION BIT(1)
#define CPPC_PERF_LIMITED_MASK (CPPC_PERF_LIMITED_DESIRED_EXCURSION | \
CPPC_PERF_LIMITED_MINIMUM_EXCURSION)
/* Each register has the folowing format. */
struct cpc_reg {
u8 descriptor;
@ -116,6 +121,7 @@ struct cppc_perf_caps {
u32 guaranteed_perf;
u32 highest_perf;
u32 nominal_perf;
u32 reference_perf;
u32 lowest_perf;
u32 lowest_nonlinear_perf;
u32 lowest_freq;
@ -133,7 +139,6 @@ struct cppc_perf_ctrls {
struct cppc_perf_fb_ctrs {
u64 reference;
u64 delivered;
u64 reference_perf;
u64 wraparound_time;
};
@ -151,6 +156,7 @@ extern int cppc_get_desired_perf(int cpunum, u64 *desired_perf);
extern int cppc_get_nominal_perf(int cpunum, u64 *nominal_perf);
extern int cppc_get_highest_perf(int cpunum, u64 *highest_perf);
extern int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs);
extern int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls);
extern int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls);
extern int cppc_set_enable(int cpu, bool enable);
extern int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps);
@ -173,6 +179,8 @@ extern int cppc_get_auto_act_window(int cpu, u64 *auto_act_window);
extern int cppc_set_auto_act_window(int cpu, u64 auto_act_window);
extern int cppc_get_auto_sel(int cpu, bool *enable);
extern int cppc_set_auto_sel(int cpu, bool enable);
extern int cppc_get_perf_limited(int cpu, u64 *perf_limited);
extern int cppc_set_perf_limited(int cpu, u64 bits_to_clear);
extern int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf);
extern int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator);
extern int amd_detect_prefcore(bool *detected);
@ -193,6 +201,10 @@ static inline int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_
{
return -EOPNOTSUPP;
}
static inline int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
{
return -EOPNOTSUPP;
}
static inline int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
{
return -EOPNOTSUPP;
@ -265,6 +277,14 @@ static inline int cppc_set_auto_sel(int cpu, bool enable)
{
return -EOPNOTSUPP;
}
static inline int cppc_get_perf_limited(int cpu, u64 *perf_limited)
{
return -EOPNOTSUPP;
}
static inline int cppc_set_perf_limited(int cpu, u64 bits_to_clear)
{
return -EOPNOTSUPP;
}
static inline int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf)
{
return -ENODEV;

View File

@ -71,6 +71,17 @@ int ghes_register_vendor_record_notifier(struct notifier_block *nb);
*/
void ghes_unregister_vendor_record_notifier(struct notifier_block *nb);
/**
* devm_ghes_register_vendor_record_notifier - device-managed vendor
* record notifier registration.
* @dev: device that owns the notifier lifetime
* @nb: pointer to the notifier_block structure of the vendor record handler
*
* Return: 0 on success, negative errno on failure.
*/
int devm_ghes_register_vendor_record_notifier(struct device *dev,
struct notifier_block *nb);
struct list_head *ghes_get_devices(void);
void ghes_estatus_pool_region_free(unsigned long addr, u32 size);

View File

@ -14,8 +14,6 @@
#include <asm/acpi.h>
#define ACPI_PROCESSOR_CLASS "processor"
#define ACPI_PROCESSOR_DEVICE_NAME "Processor"
#define ACPI_PROCESSOR_DEVICE_HID "ACPI0007"
#define ACPI_PROCESSOR_CONTAINER_HID "ACPI0010"

View File

@ -324,6 +324,17 @@ int acpi_unmap_cpu(int cpu);
acpi_handle acpi_get_processor_handle(int cpu);
/**
* acpi_get_cpu_uid() - Get ACPI Processor UID of from MADT table
* @cpu: Logical CPU number (0-based)
* @uid: Pointer to store ACPI Processor UID
*
* Return: 0 on success (ACPI Processor ID stored in *uid);
* -EINVAL if CPU number is invalid or out of range;
* -ENODEV if ACPI Processor UID for the CPU is not found.
*/
int acpi_get_cpu_uid(unsigned int cpu, u32 *uid);
#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC
int acpi_get_ioapic_id(acpi_handle handle, u32 gsi_base, u64 *phys_addr);
#endif
@ -791,6 +802,14 @@ const char *acpi_get_subsystem_id(acpi_handle handle);
int acpi_mrrm_max_mem_region(void);
#endif
#define ACPI_CMOS_RTC_IDS \
{ "PNP0B00", }, \
{ "PNP0B01", }, \
{ "PNP0B02", }, \
{ "", }
extern bool cmos_rtc_platform_device_present;
#else /* !CONFIG_ACPI */
#define acpi_disabled 1
@ -1116,6 +1135,8 @@ static inline int acpi_mrrm_max_mem_region(void)
return 1;
}
#define cmos_rtc_platform_device_present false
#endif /* !CONFIG_ACPI */
#ifdef CONFIG_ACPI_HMAT

View File

@ -271,6 +271,8 @@ struct auxiliary_device *__devm_auxiliary_device_create(struct device *dev,
__devm_auxiliary_device_create(dev, KBUILD_MODNAME, devname, \
platform_data, 0)
bool dev_is_auxiliary(struct device *dev);
/**
* module_auxiliary_driver() - Helper macro for registering an auxiliary driver
* @__auxiliary_driver: auxiliary driver struct

View File

@ -188,6 +188,7 @@ extern void cpuidle_driver_state_disabled(struct cpuidle_driver *drv, int idx,
extern void cpuidle_unregister_driver(struct cpuidle_driver *drv);
extern int cpuidle_register_device(struct cpuidle_device *dev);
extern void cpuidle_unregister_device(struct cpuidle_device *dev);
extern void cpuidle_unregister_device_no_lock(struct cpuidle_device *dev);
extern int cpuidle_register(struct cpuidle_driver *drv,
const struct cpumask *const coupled_cpus);
extern void cpuidle_unregister(struct cpuidle_driver *drv);
@ -226,6 +227,7 @@ static inline void cpuidle_unregister_driver(struct cpuidle_driver *drv) { }
static inline int cpuidle_register_device(struct cpuidle_device *dev)
{return -ENODEV; }
static inline void cpuidle_unregister_device(struct cpuidle_device *dev) { }
static inline void cpuidle_unregister_device_no_lock(struct cpuidle_device *dev) {}
static inline int cpuidle_register(struct cpuidle_driver *drv,
const struct cpumask *const coupled_cpus)
{return -ENODEV; }

View File

@ -25,7 +25,7 @@ int pcie_tph_set_st_entry(struct pci_dev *pdev,
unsigned int index, u16 tag);
int pcie_tph_get_cpu_st(struct pci_dev *dev,
enum tph_mem_type mem_type,
unsigned int cpu_uid, u16 *tag);
unsigned int cpu, u16 *tag);
void pcie_disable_tph(struct pci_dev *pdev);
int pcie_enable_tph(struct pci_dev *pdev, int mode);
u16 pcie_tph_get_st_table_size(struct pci_dev *pdev);
@ -36,7 +36,7 @@ static inline int pcie_tph_set_st_entry(struct pci_dev *pdev,
{ return -EINVAL; }
static inline int pcie_tph_get_cpu_st(struct pci_dev *dev,
enum tph_mem_type mem_type,
unsigned int cpu_uid, u16 *tag)
unsigned int cpu, u16 *tag)
{ return -EINVAL; }
static inline void pcie_disable_tph(struct pci_dev *pdev) { }
static inline int pcie_enable_tph(struct pci_dev *pdev, int mode)