summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-devices-system-cpu18
-rw-r--r--Documentation/ABI/testing/sysfs-firmware-acpi6
-rw-r--r--Documentation/PCI/tph.rst4
-rw-r--r--Documentation/admin-guide/kernel-parameters.txt8
-rw-r--r--MAINTAINERS8
-rw-r--r--arch/arm64/include/asm/acpi.h17
-rw-r--r--arch/arm64/kernel/acpi.c30
-rw-r--r--arch/loongarch/include/asm/acpi.h5
-rw-r--r--arch/loongarch/kernel/acpi.c9
-rw-r--r--arch/riscv/include/asm/acpi.h4
-rw-r--r--arch/riscv/kernel/acpi.c16
-rw-r--r--arch/riscv/kernel/acpi_numa.c9
-rw-r--r--arch/x86/include/asm/cpu.h1
-rw-r--r--arch/x86/include/asm/smp.h1
-rw-r--r--arch/x86/kernel/acpi/boot.c20
-rw-r--r--arch/x86/kernel/rtc.c21
-rw-r--r--arch/x86/xen/enlighten_hvm.c5
-rw-r--r--drivers/acpi/Kconfig2
-rw-r--r--drivers/acpi/ac.c31
-rw-r--r--drivers/acpi/acpi_fpdt.c28
-rw-r--r--drivers/acpi/acpi_memhotplug.c4
-rw-r--r--drivers/acpi/acpi_pad.c28
-rw-r--r--drivers/acpi/acpi_pnp.c22
-rw-r--r--drivers/acpi/acpi_processor.c31
-rw-r--r--drivers/acpi/acpi_tad.c492
-rw-r--r--drivers/acpi/acpi_video.c100
-rw-r--r--drivers/acpi/acpica/utnonansi.c3
-rw-r--r--drivers/acpi/apei/Kconfig14
-rw-r--r--drivers/acpi/apei/Makefile1
-rw-r--r--drivers/acpi/apei/ghes-nvidia.c149
-rw-r--r--drivers/acpi/apei/ghes.c18
-rw-r--r--drivers/acpi/battery.c9
-rw-r--r--drivers/acpi/button.c11
-rw-r--r--drivers/acpi/cppc_acpi.c293
-rw-r--r--drivers/acpi/ec.c6
-rw-r--r--drivers/acpi/event.c7
-rw-r--r--drivers/acpi/osl.c19
-rw-r--r--drivers/acpi/pci_link.c4
-rw-r--r--drivers/acpi/pci_root.c9
-rw-r--r--drivers/acpi/power.c4
-rw-r--r--drivers/acpi/pptt.c81
-rw-r--r--drivers/acpi/processor_driver.c22
-rw-r--r--drivers/acpi/processor_idle.c82
-rw-r--r--drivers/acpi/riscv/rhct.c7
-rw-r--r--drivers/acpi/sbs.c4
-rw-r--r--drivers/acpi/sbshc.c6
-rw-r--r--drivers/acpi/thermal.c13
-rw-r--r--drivers/acpi/x86/cmos_rtc.c86
-rw-r--r--drivers/base/auxiliary.c10
-rw-r--r--drivers/cpufreq/cppc_cpufreq.c104
-rw-r--r--drivers/cpuidle/cpuidle.c22
-rw-r--r--drivers/gpu/drm/amd/include/amd_acpi.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon_acpi.c2
-rw-r--r--drivers/pci/controller/pcie-hisi-error.c12
-rw-r--r--drivers/pci/tph.c16
-rw-r--r--drivers/perf/arm_cspmu/arm_cspmu.c6
-rw-r--r--drivers/platform/x86/hp/hp-wmi.c2
-rw-r--r--drivers/platform/x86/lenovo/wmi-capdata.c1
-rw-r--r--drivers/rtc/rtc-cmos.c143
-rw-r--r--drivers/watchdog/ni903x_wdt.c27
-rw-r--r--drivers/xen/xen-acpi-pad.c23
-rw-r--r--include/acpi/acpi_bus.h14
-rw-r--r--include/acpi/cppc_acpi.h22
-rw-r--r--include/acpi/ghes.h11
-rw-r--r--include/acpi/processor.h2
-rw-r--r--include/linux/acpi.h21
-rw-r--r--include/linux/auxiliary_bus.h2
-rw-r--r--include/linux/cpuidle.h2
-rw-r--r--include/linux/pci-tph.h4
69 files changed, 1450 insertions, 766 deletions
diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu
index 3a05604c21bf..82d10d556cc8 100644
--- a/Documentation/ABI/testing/sysfs-devices-system-cpu
+++ b/Documentation/ABI/testing/sysfs-devices-system-cpu
@@ -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
diff --git a/Documentation/ABI/testing/sysfs-firmware-acpi b/Documentation/ABI/testing/sysfs-firmware-acpi
index 72e7c9161ce7..fa33dda331f2 100644
--- a/Documentation/ABI/testing/sysfs-firmware-acpi
+++ b/Documentation/ABI/testing/sysfs-firmware-acpi
@@ -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>
diff --git a/Documentation/PCI/tph.rst b/Documentation/PCI/tph.rst
index e8993be64fd6..b6cf22b9bd90 100644
--- a/Documentation/PCI/tph.rst
+++ b/Documentation/PCI/tph.rst
@@ -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
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 03a550630644..c17ad454dd81 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -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
diff --git a/MAINTAINERS b/MAINTAINERS
index 40689cbc0b3d..0ce430d6e2a5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -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
diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h
index c07a58b96329..8a54ca6ba602 100644
--- a/arch/arm64/include/asm/acpi.h
+++ b/arch/arm64/include/asm/acpi.h
@@ -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);
diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c
index a9d884fd1d00..5891f92c2035 100644
--- a/arch/arm64/kernel/acpi.c
+++ b/arch/arm64/kernel/acpi.c
@@ -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;
+}
diff --git a/arch/loongarch/include/asm/acpi.h b/arch/loongarch/include/asm/acpi.h
index 7376840fa9f7..eda9d4d0a493 100644
--- a/arch/loongarch/include/asm/acpi.h
+++ b/arch/loongarch/include/asm/acpi.h
@@ -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
diff --git a/arch/loongarch/kernel/acpi.c b/arch/loongarch/kernel/acpi.c
index 1367ca759468..058f0dbe8e8f 100644
--- a/arch/loongarch/kernel/acpi.c
+++ b/arch/loongarch/kernel/acpi.c
@@ -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);
diff --git a/arch/riscv/include/asm/acpi.h b/arch/riscv/include/asm/acpi.h
index 6e13695120bc..26ab37c171bc 100644
--- a/arch/riscv/include/asm/acpi.h
+++ b/arch/riscv/include/asm/acpi.h
@@ -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);
diff --git a/arch/riscv/kernel/acpi.c b/arch/riscv/kernel/acpi.c
index 71698ee11621..322ea92aa39f 100644
--- a/arch/riscv/kernel/acpi.c
+++ b/arch/riscv/kernel/acpi.c
@@ -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);
diff --git a/arch/riscv/kernel/acpi_numa.c b/arch/riscv/kernel/acpi_numa.c
index 130769e3a99c..6a2d4289f806 100644
--- a/arch/riscv/kernel/acpi_numa.c
+++ b/arch/riscv/kernel/acpi_numa.c
@@ -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;
}
diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h
index ad235dda1ded..57a0786dfd75 100644
--- a/arch/x86/include/asm/cpu.h
+++ b/arch/x86/include/asm/cpu.h
@@ -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
diff --git a/arch/x86/include/asm/smp.h b/arch/x86/include/asm/smp.h
index 84951572ab81..05d1d479b4cf 100644
--- a/arch/x86/include/asm/smp.h
+++ b/arch/x86/include/asm/smp.h
@@ -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
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index a3f2fb1fea1b..ceba24f65ae3 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -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);
diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c
index 51a849a79c98..314b062a15de 100644
--- a/arch/x86/kernel/rtc.c
+++ b/arch/x86/kernel/rtc.c
@@ -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;
-
- 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 (cmos_rtc_platform_device_present)
+ return 0;
+
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;
}
diff --git a/arch/x86/xen/enlighten_hvm.c b/arch/x86/xen/enlighten_hvm.c
index fe57ff85d004..2f9fa27e5a3c 100644
--- a/arch/x86/xen/enlighten_hvm.c
+++ b/arch/x86/xen/enlighten_hvm.c
@@ -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);
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 6f4b545f7377..f165d14cf61a 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -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
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index c5d77c3cb4bc..e9e970fd8f33 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -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);
diff --git a/drivers/acpi/acpi_fpdt.c b/drivers/acpi/acpi_fpdt.c
index 271092f2700a..e75dd28d31a9 100644
--- a/drivers/acpi/acpi_fpdt.c
+++ b/drivers/acpi/acpi_fpdt.c
@@ -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);
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index 02a472fa85fc..1d7dfe4ee9a6 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -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 */
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
index c9a0bcaba2e4..0a8e02bc8c8b 100644
--- a/drivers/acpi/acpi_pad.c
+++ b/drivers/acpi/acpi_pad.c
@@ -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[] = {
diff --git a/drivers/acpi/acpi_pnp.c b/drivers/acpi/acpi_pnp.c
index 85d9f78619a2..da886923b008 100644
--- a/drivers/acpi/acpi_pnp.c
+++ b/drivers/acpi/acpi_pnp.c
@@ -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);
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
index b1652cab631a..00775b91bd41 100644
--- a/drivers/acpi/acpi_processor.c
+++ b/drivers/acpi/acpi_processor.c
@@ -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);
diff --git a/drivers/acpi/acpi_tad.c b/drivers/acpi/acpi_tad.c
index 6d870d97ada6..b406d7a98996 100644
--- a/drivers/acpi/acpi_tad.c
+++ b/drivers/acpi/acpi_tad.c
@@ -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 @@ out_free:
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;
+ 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;
- ret = acpi_tad_evaluate_grt(dev, rt);
- if (ret)
- return ret;
+ 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,
diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c
index adbaf0226c90..05793ddef787 100644
--- a/drivers/acpi/acpi_video.c
+++ b/drivers/acpi/acpi_video.c
@@ -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);
diff --git a/drivers/acpi/acpica/utnonansi.c b/drivers/acpi/acpica/utnonansi.c
index ff0802ace19b..3a7952be6545 100644
--- a/drivers/acpi/acpica/utnonansi.c
+++ b/drivers/acpi/acpica/utnonansi.c
@@ -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
diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig
index 070c07d68dfb..428458c623f0 100644
--- a/drivers/acpi/apei/Kconfig
+++ b/drivers/acpi/apei/Kconfig
@@ -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
diff --git a/drivers/acpi/apei/Makefile b/drivers/acpi/apei/Makefile
index 1a0b85923cd4..66588d6be56f 100644
--- a/drivers/acpi/apei/Makefile
+++ b/drivers/acpi/apei/Makefile
@@ -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
diff --git a/drivers/acpi/apei/ghes-nvidia.c b/drivers/acpi/apei/ghes-nvidia.c
new file mode 100644
index 000000000000..597275d81de8
--- /dev/null
+++ b/drivers/acpi/apei/ghes-nvidia.c
@@ -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");
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 8acd2742bb27..3236a3ce79d6 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -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;
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 8fbad8bc4650..b4c25474f42f 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -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)
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 97b05246efab..dc064a388c23 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -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,
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index f0e513e9ed5d..053fc6765a59 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -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 */
@@ -854,6 +854,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
* LOWEST_FREQ and NOMINAL_FREQ regs as unsupported
@@ -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;
@@ -1739,6 +1789,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.
* @perf_ctrls: ptr to cppc_perf_ctrls. See cppc_acpi.h
@@ -1871,6 +2016,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().
*
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 6f0065257a77..45204538ed87 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -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. */
diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c
index 96a9aaaaf9f7..4d840d2e7b98 100644
--- a/drivers/acpi/event.c
+++ b/drivers/acpi/event.c
@@ -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)
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 62b9c83d4f20..c8fe6e54daea 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -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:
/*
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 45bdfd06bd21..e6ed13aee48d 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -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);
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 4a882e939525..a0ba64e45e8a 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -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);
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 4611159ee734..6b1680ec3694 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -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;
diff --git a/drivers/acpi/pptt.c b/drivers/acpi/pptt.c
index de5f8c018333..c01b8648242c 100644
--- a/drivers/acpi/pptt.c
+++ b/drivers/acpi/pptt.c
@@ -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);
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index 882709796b4f..cda8fd720000 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -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);
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index f6c72e3a2be1..ee5facccbe10 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -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();
- cpuidle_pause_and_lock();
- /* Disable all cpuidle devices */
- for_each_online_cpu(cpu) {
+ /* Unregister cpuidle device of all CPUs */
+ cpuidle_pause_and_lock();
+ for_each_possible_cpu(cpu) {
+ dev = per_cpu(acpi_cpuidle_device, cpu);
_pr = per_cpu(processors, cpu);
- if (!_pr || !_pr->flags.power_setup_done)
+ if (!_pr || !_pr->flags.power || !dev)
continue;
- dev = per_cpu(acpi_cpuidle_device, cpu);
- cpuidle_disable_device(dev);
+
+ cpuidle_unregister_device_no_lock(dev);
+ kfree(dev);
+ _pr->flags.power = 0;
}
+ cpuidle_resume_and_unlock();
- /* Populate Updated C-state information */
- acpi_processor_get_power_info(pr);
- acpi_processor_setup_cpuidle_states(pr);
+ /*
+ * Unregister ACPI idle driver, reinitialize ACPI idle states
+ * and register ACPI idle driver again.
+ */
+ acpi_processor_unregister_idle_driver();
+ acpi_processor_register_idle_driver();
- /* Enable all cpuidle devices */
- for_each_online_cpu(cpu) {
+ /*
+ * 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 || !_pr->flags.power_setup_done)
+ if (!_pr)
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);
- }
+ acpi_processor_power_init(_pr);
}
- cpuidle_resume_and_unlock();
+
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);
}
}
diff --git a/drivers/acpi/riscv/rhct.c b/drivers/acpi/riscv/rhct.c
index caa2c16e1697..8f3f38c64a88 100644
--- a/drivers/acpi/riscv/rhct.c
+++ b/drivers/acpi/riscv/rhct.c
@@ -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)
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index bbd3938f7b52..440f1d69aca8 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -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)
diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
index 36850831910b..f413270415b6 100644
--- a/drivers/acpi/sbshc.c
+++ b/drivers/acpi/sbshc.c
@@ -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;
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 64356b004a57..b8b487d89d25 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -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);
diff --git a/drivers/acpi/x86/cmos_rtc.c b/drivers/acpi/x86/cmos_rtc.c
index 51643ff6fe5f..ced334e19896 100644
--- a/drivers/acpi/x86/cmos_rtc.c
+++ b/drivers/acpi/x86/cmos_rtc.c
@@ -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);
+
+ if (function == ACPI_WRITE) {
+ for (i = 0; i < bytes; i++, address++, value++)
+ CMOS_WRITE(*value, address);
- spin_lock_irq(&rtc_lock);
+ return AE_OK;
+ }
- for (i = 0; i < DIV_ROUND_UP(bits, 8); ++i, ++address, ++value)
- if (function == ACPI_READ)
+ if (function == ACPI_READ) {
+ for (i = 0; i < bytes; i++, address++, value++)
*value = CMOS_READ(address);
- else
- CMOS_WRITE(*value, address);
- spin_unlock_irq(&rtc_lock);
+ return AE_OK;
+ }
- 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)
diff --git a/drivers/base/auxiliary.c b/drivers/base/auxiliary.c
index 16b8bdab30c8..e129bbcbefc7 100644
--- a/drivers/base/auxiliary.c
+++ b/drivers/base/auxiliary.c
@@ -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));
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c
index 011f35cb47b9..5dfb109cf1f4 100644
--- a/drivers/cpufreq/cppc_cpufreq.c
+++ b/drivers/cpufreq/cppc_cpufreq.c
@@ -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,
};
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index c7876e9e024f..1a55542efead 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -714,16 +714,12 @@ out_unregister:
EXPORT_SYMBOL_GPL(cpuidle_register_device);
-/**
- * cpuidle_unregister_device - unregisters a CPU's idle PM feature
- * @dev: the cpu
- */
-void cpuidle_unregister_device(struct cpuidle_device *dev)
+void cpuidle_unregister_device_no_lock(struct cpuidle_device *dev)
{
if (!dev || dev->registered == 0)
return;
- cpuidle_pause_and_lock();
+ lockdep_assert_held(&cpuidle_lock);
cpuidle_disable_device(dev);
@@ -732,10 +728,22 @@ void cpuidle_unregister_device(struct cpuidle_device *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
+ */
+void cpuidle_unregister_device(struct cpuidle_device *dev)
+{
+ if (!dev || dev->registered == 0)
+ return;
+ cpuidle_pause_and_lock();
+ cpuidle_unregister_device_no_lock(dev);
cpuidle_resume_and_unlock();
}
-
EXPORT_SYMBOL_GPL(cpuidle_unregister_device);
/**
diff --git a/drivers/gpu/drm/amd/include/amd_acpi.h b/drivers/gpu/drm/amd/include/amd_acpi.h
index 84933c07f720..4225640131f2 100644
--- a/drivers/gpu/drm/amd/include/amd_acpi.h
+++ b/drivers/gpu/drm/amd/include/amd_acpi.h
@@ -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 */
diff --git a/drivers/gpu/drm/radeon/radeon_acpi.c b/drivers/gpu/drm/radeon/radeon_acpi.c
index 08f8ba4fd148..9f511ff08822 100644
--- a/drivers/gpu/drm/radeon/radeon_acpi.c
+++ b/drivers/gpu/drm/radeon/radeon_acpi.c
@@ -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 */
diff --git a/drivers/pci/controller/pcie-hisi-error.c b/drivers/pci/controller/pcie-hisi-error.c
index aaf1ed2b6e59..36be86d827a8 100644
--- a/drivers/pci/controller/pcie-hisi-error.c
+++ b/drivers/pci/controller/pcie-hisi-error.c
@@ -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);
diff --git a/drivers/pci/tph.c b/drivers/pci/tph.c
index ca4f97be7538..b67c9ad14bda 100644
--- a/drivers/pci/tph.c
+++ b/drivers/pci/tph.c
@@ -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
diff --git a/drivers/perf/arm_cspmu/arm_cspmu.c b/drivers/perf/arm_cspmu/arm_cspmu.c
index 34430b68f602..ed72c3d1f796 100644
--- a/drivers/perf/arm_cspmu/arm_cspmu.c
+++ b/drivers/perf/arm_cspmu/arm_cspmu.c
@@ -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;
}
diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c
index 988a0acc9622..7df00447bba4 100644
--- a/drivers/platform/x86/hp/hp-wmi.c
+++ b/drivers/platform/x86/hp/hp-wmi.c
@@ -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 {
diff --git a/drivers/platform/x86/lenovo/wmi-capdata.c b/drivers/platform/x86/lenovo/wmi-capdata.c
index ee1fb02d8e31..b73d378f0e8b 100644
--- a/drivers/platform/x86/lenovo/wmi-capdata.c
+++ b/drivers/platform/x86/lenovo/wmi-capdata.c
@@ -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
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 0743c6acd6e2..acc064baefcd 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -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 @@ cleanup0:
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)
+ return 0;
- if (!cmos_rtc.dev) {
- retval = platform_driver_probe(&cmos_platform_driver,
- cmos_platform_probe);
- if (retval == 0)
- platform_driver_registered = true;
- }
+ retval = platform_driver_probe(&cmos_platform_driver, cmos_platform_probe);
+ if (retval)
+ return retval;
- if (retval == 0)
- return 0;
+ platform_driver_registered = true;
-#ifdef CONFIG_PNP
- if (pnp_driver_registered)
- pnp_unregister_driver(&cmos_pnp_driver);
-#endif
- return retval;
+ 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);
}
diff --git a/drivers/watchdog/ni903x_wdt.c b/drivers/watchdog/ni903x_wdt.c
index 045bb72d9a43..8b1b9baa914e 100644
--- a/drivers/watchdog/ni903x_wdt.c
+++ b/drivers/watchdog/ni903x_wdt.c
@@ -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>");
diff --git a/drivers/xen/xen-acpi-pad.c b/drivers/xen/xen-acpi-pad.c
index ede69a5278d3..75a39862c1df 100644
--- a/drivers/xen/xen-acpi-pad.c
+++ b/drivers/xen/xen-acpi-pad.c
@@ -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);
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index aad1a95e6863..b701b5f972cb 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -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)
{
diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
index 4d644f03098e..d8e405becdc3 100644
--- a/include/acpi/cppc_acpi.h
+++ b/include/acpi/cppc_acpi.h
@@ -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;
diff --git a/include/acpi/ghes.h b/include/acpi/ghes.h
index 7bea522c0657..8d7e5caef3f1 100644
--- a/include/acpi/ghes.h
+++ b/include/acpi/ghes.h
@@ -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);
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 7146a8e9e9c2..554be224ce76 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -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"
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 4d2f0bed7a06..bfacb9475aac 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -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
diff --git a/include/linux/auxiliary_bus.h b/include/linux/auxiliary_bus.h
index 4086afd0cc6b..bc09b55e3682 100644
--- a/include/linux/auxiliary_bus.h
+++ b/include/linux/auxiliary_bus.h
@@ -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
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 4073690504a7..a2485348def3 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -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; }
diff --git a/include/linux/pci-tph.h b/include/linux/pci-tph.h
index ba28140ce670..be68cd17f2f8 100644
--- a/include/linux/pci-tph.h
+++ b/include/linux/pci-tph.h
@@ -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)