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 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" -M: Robert Moore +M: Saket Dumbre 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 +L: linux-acpi@vger.kernel.org +S: Maintained +F: drivers/acpi/apei/nvidia-ghes.c + NVIDIA VRS RTC DRIVER M: Shubhi Garg 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 #include #include #include -#include #include #include @@ -133,25 +133,14 @@ static struct platform_device rtc_device = { static __init int add_rtc_cmos(void) { -#ifdef CONFIG_PNP - static const char * const ids[] __initconst = - { "PNP0b00", "PNP0b01", "PNP0b02", }; - struct pnp_dev *dev; - int i; + if (cmos_rtc_platform_device_present) + return 0; - pnp_for_each_dev(dev) { - for (i = 0; i < ARRAY_SIZE(ids); i++) { - if (compare_pnp_id(dev->id, ids[i]) != 0) - return 0; - } - } -#endif if (!x86_platform.legacy.rtc) return -ENODEV; platform_device_register(&rtc_device); - dev_info(&rtc_device.dev, - "registered platform RTC device (no PNP device found)\n"); + dev_info(&rtc_device.dev, "registered fallback platform RTC device\n"); return 0; } 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 #include -#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 #include -#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 * - * 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 #include +#include #include #include #include +#include #include MODULE_DESCRIPTION("ACPI Time and Alarm (TAD) Device Driver"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Rafael J. Wysocki"); -/* ACPI TAD capability flags (ACPI 6.2, Section 9.18.2) */ +/* ACPI TAD capability flags (ACPI 6.6, Section 9.17.2) */ #define ACPI_TAD_AC_WAKE BIT(0) #define ACPI_TAD_DC_WAKE BIT(1) #define ACPI_TAD_RT BIT(2) @@ -49,6 +54,10 @@ MODULE_AUTHOR("Rafael J. Wysocki"); /* Special value for disabled timer or expired timer wake policy. */ #define ACPI_TAD_WAKE_DISABLED (~(u32)0) +/* ACPI TAD RTC */ +#define ACPI_TAD_TZ_UNSPEC 2047 +#define ACPI_TAD_TIME_ISDST 3 + struct acpi_tad_driver_data { u32 capabilities; }; @@ -67,6 +76,16 @@ struct acpi_tad_rt { u8 padding[3]; /* must be 0 */ } __packed; +static bool acpi_tad_rt_is_invalid(struct acpi_tad_rt *rt) +{ + return rt->year < 1900 || rt->year > 9999 || + rt->month < 1 || rt->month > 12 || + rt->hour > 23 || rt->minute > 59 || rt->second > 59 || + rt->tz < -1440 || + (rt->tz > 1440 && rt->tz != ACPI_TAD_TZ_UNSPEC) || + rt->daylight > 3; +} + static int acpi_tad_set_real_time(struct device *dev, struct acpi_tad_rt *rt) { acpi_handle handle = ACPI_HANDLE(dev); @@ -80,12 +99,12 @@ static int acpi_tad_set_real_time(struct device *dev, struct acpi_tad_rt *rt) unsigned long long retval; acpi_status status; - if (rt->year < 1900 || rt->year > 9999 || - rt->month < 1 || rt->month > 12 || - rt->hour > 23 || rt->minute > 59 || rt->second > 59 || - rt->tz < -1440 || (rt->tz > 1440 && rt->tz != 2047) || - rt->daylight > 3) - return -ERANGE; + if (acpi_tad_rt_is_invalid(rt)) + return -EINVAL; + + rt->valid = 0; + rt->msec = 0; + memset(rt->padding, 0, 3); args[0].buffer.pointer = (u8 *)rt; args[0].buffer.length = sizeof(*rt); @@ -133,21 +152,78 @@ static int acpi_tad_evaluate_grt(struct device *dev, struct acpi_tad_rt *rt) return ret; } -static int acpi_tad_get_real_time(struct device *dev, struct acpi_tad_rt *rt) +static int __acpi_tad_get_real_time(struct device *dev, struct acpi_tad_rt *rt) { int ret; - PM_RUNTIME_ACQUIRE(dev, pm); - if (PM_RUNTIME_ACQUIRE_ERR(&pm)) - return -ENXIO; - ret = acpi_tad_evaluate_grt(dev, rt); if (ret) return ret; + if (acpi_tad_rt_is_invalid(rt)) + return -ENODATA; + return 0; } +static int acpi_tad_get_real_time(struct device *dev, struct acpi_tad_rt *rt) +{ + PM_RUNTIME_ACQUIRE(dev, pm); + if (PM_RUNTIME_ACQUIRE_ERR(&pm)) + return -ENXIO; + + return __acpi_tad_get_real_time(dev, rt); +} + +static int __acpi_tad_wake_set(struct device *dev, char *method, u32 timer_id, + u32 value) +{ + acpi_handle handle = ACPI_HANDLE(dev); + union acpi_object args[] = { + { .type = ACPI_TYPE_INTEGER, }, + { .type = ACPI_TYPE_INTEGER, }, + }; + struct acpi_object_list arg_list = { + .pointer = args, + .count = ARRAY_SIZE(args), + }; + unsigned long long retval; + acpi_status status; + + args[0].integer.value = timer_id; + args[1].integer.value = value; + + status = acpi_evaluate_integer(handle, method, &arg_list, &retval); + if (ACPI_FAILURE(status) || retval) + return -EIO; + + return 0; +} + +static int __acpi_tad_wake_read(struct device *dev, char *method, u32 timer_id, + unsigned long long *retval) +{ + acpi_handle handle = ACPI_HANDLE(dev); + union acpi_object args[] = { + { .type = ACPI_TYPE_INTEGER, }, + }; + struct acpi_object_list arg_list = { + .pointer = args, + .count = ARRAY_SIZE(args), + }; + acpi_status status; + + args[0].integer.value = timer_id; + + status = acpi_evaluate_integer(handle, method, &arg_list, retval); + if (ACPI_FAILURE(status)) + return -EIO; + + return 0; +} + +/* sysfs interface */ + static char *acpi_tad_rt_next_field(char *s, int *val) { char *p; @@ -167,69 +243,65 @@ static ssize_t time_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct acpi_tad_rt rt; - char *str, *s; - int val, ret = -ENODATA; + int val, ret; + char *s; - str = kmemdup_nul(buf, count, GFP_KERNEL); + char *str __free(kfree) = kmemdup_nul(buf, count, GFP_KERNEL); if (!str) return -ENOMEM; s = acpi_tad_rt_next_field(str, &val); if (!s) - goto out_free; + return -ENODATA; rt.year = val; s = acpi_tad_rt_next_field(s, &val); if (!s) - goto out_free; + return -ENODATA; rt.month = val; s = acpi_tad_rt_next_field(s, &val); if (!s) - goto out_free; + return -ENODATA; rt.day = val; s = acpi_tad_rt_next_field(s, &val); if (!s) - goto out_free; + return -ENODATA; rt.hour = val; s = acpi_tad_rt_next_field(s, &val); if (!s) - goto out_free; + return -ENODATA; rt.minute = val; s = acpi_tad_rt_next_field(s, &val); if (!s) - goto out_free; + return -ENODATA; rt.second = val; s = acpi_tad_rt_next_field(s, &val); if (!s) - goto out_free; + return -ENODATA; rt.tz = val; if (kstrtoint(s, 10, &val)) - goto out_free; + return -ENODATA; rt.daylight = val; - rt.valid = 0; - rt.msec = 0; - memset(rt.padding, 0, 3); - ret = acpi_tad_set_real_time(dev, &rt); + if (ret) + return ret; -out_free: - kfree(str); - return ret ? ret : count; + return count; } static ssize_t time_show(struct device *dev, struct device_attribute *attr, @@ -249,41 +321,14 @@ static ssize_t time_show(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RW(time); -static struct attribute *acpi_tad_time_attrs[] = { - &dev_attr_time.attr, - NULL, -}; -static const struct attribute_group acpi_tad_time_attr_group = { - .attrs = acpi_tad_time_attrs, -}; - static int acpi_tad_wake_set(struct device *dev, char *method, u32 timer_id, u32 value) { - acpi_handle handle = ACPI_HANDLE(dev); - union acpi_object args[] = { - { .type = ACPI_TYPE_INTEGER, }, - { .type = ACPI_TYPE_INTEGER, }, - }; - struct acpi_object_list arg_list = { - .pointer = args, - .count = ARRAY_SIZE(args), - }; - unsigned long long retval; - acpi_status status; - - args[0].integer.value = timer_id; - args[1].integer.value = value; - PM_RUNTIME_ACQUIRE(dev, pm); if (PM_RUNTIME_ACQUIRE_ERR(&pm)) return -ENXIO; - status = acpi_evaluate_integer(handle, method, &arg_list, &retval); - if (ACPI_FAILURE(status) || retval) - return -EIO; - - return 0; + return __acpi_tad_wake_set(dev, method, timer_id, value); } static int acpi_tad_wake_write(struct device *dev, const char *buf, char *method, @@ -309,26 +354,16 @@ static int acpi_tad_wake_write(struct device *dev, const char *buf, char *method static ssize_t acpi_tad_wake_read(struct device *dev, char *buf, char *method, u32 timer_id, const char *specval) { - acpi_handle handle = ACPI_HANDLE(dev); - union acpi_object args[] = { - { .type = ACPI_TYPE_INTEGER, }, - }; - struct acpi_object_list arg_list = { - .pointer = args, - .count = ARRAY_SIZE(args), - }; unsigned long long retval; - acpi_status status; - - args[0].integer.value = timer_id; + int ret; PM_RUNTIME_ACQUIRE(dev, pm); if (PM_RUNTIME_ACQUIRE_ERR(&pm)) return -ENXIO; - status = acpi_evaluate_integer(handle, method, &arg_list, &retval); - if (ACPI_FAILURE(status)) - return -EIO; + ret = __acpi_tad_wake_read(dev, method, timer_id, &retval); + if (ret) + return ret; if ((u32)retval == ACPI_TAD_WAKE_DISABLED) return sprintf(buf, "%s\n", specval); @@ -486,17 +521,6 @@ static ssize_t ac_status_show(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RW(ac_status); -static struct attribute *acpi_tad_attrs[] = { - &dev_attr_caps.attr, - &dev_attr_ac_alarm.attr, - &dev_attr_ac_policy.attr, - &dev_attr_ac_status.attr, - NULL, -}; -static const struct attribute_group acpi_tad_attr_group = { - .attrs = acpi_tad_attrs, -}; - static ssize_t dc_alarm_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -545,16 +569,227 @@ static ssize_t dc_status_show(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR_RW(dc_status); -static struct attribute *acpi_tad_dc_attrs[] = { +static struct attribute *acpi_tad_attrs[] = { + &dev_attr_caps.attr, + &dev_attr_ac_alarm.attr, + &dev_attr_ac_policy.attr, + &dev_attr_ac_status.attr, &dev_attr_dc_alarm.attr, &dev_attr_dc_policy.attr, &dev_attr_dc_status.attr, + &dev_attr_time.attr, NULL, }; -static const struct attribute_group acpi_tad_dc_attr_group = { - .attrs = acpi_tad_dc_attrs, + +static umode_t acpi_tad_attr_is_visible(struct kobject *kobj, + struct attribute *a, int n) +{ + struct acpi_tad_driver_data *dd = dev_get_drvdata(kobj_to_dev(kobj)); + + if (a == &dev_attr_caps.attr) + return a->mode; + + if ((dd->capabilities & ACPI_TAD_AC_WAKE) && + (a == &dev_attr_ac_alarm.attr || a == &dev_attr_ac_policy.attr || + a == &dev_attr_ac_status.attr)) + return a->mode; + + if ((dd->capabilities & ACPI_TAD_DC_WAKE) && + (a == &dev_attr_dc_alarm.attr || a == &dev_attr_dc_policy.attr || + a == &dev_attr_dc_status.attr)) + return a->mode; + + if ((dd->capabilities & ACPI_TAD_RT) && a == &dev_attr_time.attr) + return a->mode; + + return 0; +} + +static const struct attribute_group acpi_tad_attr_group = { + .attrs = acpi_tad_attrs, + .is_visible = acpi_tad_attr_is_visible, }; +static const struct attribute_group *acpi_tad_attr_groups[] = { + &acpi_tad_attr_group, + NULL, +}; + +#ifdef CONFIG_RTC_CLASS +/* RTC class device interface */ + +static void acpi_tad_rt_to_tm(struct acpi_tad_rt *rt, struct rtc_time *tm) +{ + tm->tm_year = rt->year - 1900; + tm->tm_mon = rt->month - 1; + tm->tm_mday = rt->day; + tm->tm_hour = rt->hour; + tm->tm_min = rt->minute; + tm->tm_sec = rt->second; + tm->tm_isdst = rt->daylight == ACPI_TAD_TIME_ISDST; +} + +static int acpi_tad_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct acpi_tad_rt rt; + + rt.year = tm->tm_year + 1900; + rt.month = tm->tm_mon + 1; + rt.day = tm->tm_mday; + rt.hour = tm->tm_hour; + rt.minute = tm->tm_min; + rt.second = tm->tm_sec; + rt.tz = ACPI_TAD_TZ_UNSPEC; + rt.daylight = ACPI_TAD_TIME_ISDST * !!tm->tm_isdst; + + return acpi_tad_set_real_time(dev, &rt); +} + +static int acpi_tad_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct acpi_tad_rt rt; + int ret; + + ret = acpi_tad_get_real_time(dev, &rt); + if (ret) + return ret; + + acpi_tad_rt_to_tm(&rt, tm); + + return 0; +} + +static int acpi_tad_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct acpi_tad_driver_data *dd = dev_get_drvdata(dev); + s64 value = ACPI_TAD_WAKE_DISABLED; + struct rtc_time tm_now; + struct acpi_tad_rt rt; + int ret; + + PM_RUNTIME_ACQUIRE(dev, pm); + if (PM_RUNTIME_ACQUIRE_ERR(&pm)) + return -ENXIO; + + if (t->enabled) { + /* + * The value to pass to _STV is expected to be the number of + * seconds between the time when the timer is programmed and the + * time when it expires represented as a 32-bit integer. + */ + ret = __acpi_tad_get_real_time(dev, &rt); + if (ret) + return ret; + + acpi_tad_rt_to_tm(&rt, &tm_now); + + value = ktime_divns(ktime_sub(rtc_tm_to_ktime(t->time), + rtc_tm_to_ktime(tm_now)), NSEC_PER_SEC); + if (value <= 0 || value > U32_MAX) + return -EINVAL; + } + + ret = __acpi_tad_wake_set(dev, "_STV", ACPI_TAD_AC_TIMER, value); + if (ret && t->enabled) + return ret; + + /* + * If a separate DC alarm timer is supported, set it to the same value + * as the AC alarm timer. + */ + if (dd->capabilities & ACPI_TAD_DC_WAKE) { + ret = __acpi_tad_wake_set(dev, "_STV", ACPI_TAD_DC_TIMER, value); + if (ret && t->enabled) { + __acpi_tad_wake_set(dev, "_STV", ACPI_TAD_AC_TIMER, + ACPI_TAD_WAKE_DISABLED); + return ret; + } + } + + /* Assume success if the alarm is being disabled. */ + return 0; +} + +static int acpi_tad_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + unsigned long long retval; + struct rtc_time tm_now; + struct acpi_tad_rt rt; + int ret; + + PM_RUNTIME_ACQUIRE(dev, pm); + if (PM_RUNTIME_ACQUIRE_ERR(&pm)) + return -ENXIO; + + ret = __acpi_tad_get_real_time(dev, &rt); + if (ret) + return ret; + + acpi_tad_rt_to_tm(&rt, &tm_now); + + /* + * Assume that the alarm was set by acpi_tad_rtc_set_alarm(), so the AC + * and DC alarm timer settings are the same and it is sufficient to read + * the former. + * + * The value returned by _TIV should be the number of seconds till the + * expiration of the timer, represented as a 32-bit integer, or the + * special ACPI_TAD_WAKE_DISABLED value meaning that the timer has + * been disabled. + */ + ret = __acpi_tad_wake_read(dev, "_TIV", ACPI_TAD_AC_TIMER, &retval); + if (ret) + return ret; + + if (retval > U32_MAX) + return -ENODATA; + + t->pending = 0; + + if (retval != ACPI_TAD_WAKE_DISABLED) { + t->enabled = 1; + t->time = rtc_ktime_to_tm(ktime_add_ns(rtc_tm_to_ktime(tm_now), + (u64)retval * NSEC_PER_SEC)); + } else { + t->enabled = 0; + t->time = tm_now; + } + + return 0; +} + +static const struct rtc_class_ops acpi_tad_rtc_ops = { + .read_time = acpi_tad_rtc_read_time, + .set_time = acpi_tad_rtc_set_time, + .set_alarm = acpi_tad_rtc_set_alarm, + .read_alarm = acpi_tad_rtc_read_alarm, +}; + +static void acpi_tad_register_rtc(struct device *dev, unsigned long long caps) +{ + struct rtc_device *rtc; + + rtc = devm_rtc_allocate_device(dev); + if (IS_ERR(rtc)) + return; + + rtc->range_min = mktime64(1900, 1, 1, 0, 0, 0); + rtc->range_max = mktime64(9999, 12, 31, 23, 59, 59); + + rtc->ops = &acpi_tad_rtc_ops; + + if (!(caps & ACPI_TAD_AC_WAKE)) + clear_bit(RTC_FEATURE_ALARM, rtc->features); + + devm_rtc_register_device(rtc); +} +#else /* !CONFIG_RTC_CLASS */ +static inline void acpi_tad_register_rtc(struct device *dev, + unsigned long long caps) {} +#endif /* !CONFIG_RTC_CLASS */ + +/* Platform driver interface */ + static int acpi_tad_disable_timer(struct device *dev, u32 timer_id) { return acpi_tad_wake_set(dev, "_STV", timer_id, ACPI_TAD_WAKE_DISABLED); @@ -563,22 +798,15 @@ static int acpi_tad_disable_timer(struct device *dev, u32 timer_id) static void acpi_tad_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; - acpi_handle handle = ACPI_HANDLE(dev); struct acpi_tad_driver_data *dd = dev_get_drvdata(dev); device_init_wakeup(dev, false); - if (dd->capabilities & ACPI_TAD_RT) - sysfs_remove_group(&dev->kobj, &acpi_tad_time_attr_group); - - if (dd->capabilities & ACPI_TAD_DC_WAKE) - sysfs_remove_group(&dev->kobj, &acpi_tad_dc_attr_group); - - sysfs_remove_group(&dev->kobj, &acpi_tad_attr_group); - scoped_guard(pm_runtime_noresume, dev) { - acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); - acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); + if (dd->capabilities & ACPI_TAD_AC_WAKE) { + acpi_tad_disable_timer(dev, ACPI_TAD_AC_TIMER); + acpi_tad_clear_status(dev, ACPI_TAD_AC_TIMER); + } if (dd->capabilities & ACPI_TAD_DC_WAKE) { acpi_tad_disable_timer(dev, ACPI_TAD_DC_TIMER); acpi_tad_clear_status(dev, ACPI_TAD_DC_TIMER); @@ -587,7 +815,6 @@ static void acpi_tad_remove(struct platform_device *pdev) pm_runtime_suspend(dev); pm_runtime_disable(dev); - acpi_remove_cmos_rtc_space_handler(handle); } static int acpi_tad_probe(struct platform_device *pdev) @@ -597,13 +824,7 @@ static int acpi_tad_probe(struct platform_device *pdev) struct acpi_tad_driver_data *dd; acpi_status status; unsigned long long caps; - int ret; - ret = acpi_install_cmos_rtc_space_handler(handle); - if (ret < 0) { - dev_info(dev, "Unable to install space handler\n"); - return -ENODEV; - } /* * Initialization failure messages are mostly about firmware issues, so * print them at the "info" level. @@ -611,27 +832,20 @@ static int acpi_tad_probe(struct platform_device *pdev) status = acpi_evaluate_integer(handle, "_GCP", NULL, &caps); if (ACPI_FAILURE(status)) { dev_info(dev, "Unable to get capabilities\n"); - ret = -ENODEV; - goto remove_handler; - } - - if (!(caps & ACPI_TAD_AC_WAKE)) { - dev_info(dev, "Unsupported capabilities\n"); - ret = -ENODEV; - goto remove_handler; + return -ENODEV; } if (!acpi_has_method(handle, "_PRW")) { dev_info(dev, "Missing _PRW\n"); - ret = -ENODEV; - goto remove_handler; + caps &= ~(ACPI_TAD_AC_WAKE | ACPI_TAD_DC_WAKE); } + if (!(caps & ACPI_TAD_AC_WAKE)) + caps &= ~ACPI_TAD_DC_WAKE; + dd = devm_kzalloc(dev, sizeof(*dd), GFP_KERNEL); - if (!dd) { - ret = -ENOMEM; - goto remove_handler; - } + if (!dd) + return -ENOMEM; dd->capabilities = caps; dev_set_drvdata(dev, dd); @@ -642,9 +856,12 @@ static int acpi_tad_probe(struct platform_device *pdev) * runtime suspend. Everything else should be taken care of by the ACPI * PM domain callbacks. */ - device_init_wakeup(dev, true); - dev_pm_set_driver_flags(dev, DPM_FLAG_SMART_SUSPEND | - DPM_FLAG_MAY_SKIP_RESUME); + if (ACPI_TAD_AC_WAKE) { + device_init_wakeup(dev, true); + dev_pm_set_driver_flags(dev, DPM_FLAG_SMART_SUSPEND | + DPM_FLAG_MAY_SKIP_RESUME); + } + /* * The platform bus type layer tells the ACPI PM domain powers up the * device, so set the runtime PM status of it to "active". @@ -653,32 +870,10 @@ static int acpi_tad_probe(struct platform_device *pdev) pm_runtime_enable(dev); pm_runtime_suspend(dev); - ret = sysfs_create_group(&dev->kobj, &acpi_tad_attr_group); - if (ret) - goto fail; - - if (caps & ACPI_TAD_DC_WAKE) { - ret = sysfs_create_group(&dev->kobj, &acpi_tad_dc_attr_group); - if (ret) - goto fail; - } - - if (caps & ACPI_TAD_RT) { - ret = sysfs_create_group(&dev->kobj, &acpi_tad_time_attr_group); - if (ret) - goto fail; - } + if (caps & ACPI_TAD_RT) + acpi_tad_register_rtc(dev, caps); return 0; - -fail: - acpi_tad_remove(pdev); - /* Don't fallthrough because cmos rtc space handler is removed in acpi_tad_remove() */ - return ret; - -remove_handler: - acpi_remove_cmos_rtc_space_handler(handle); - return ret; } static const struct acpi_device_id acpi_tad_ids[] = { @@ -690,6 +885,7 @@ static struct platform_driver acpi_tad_driver = { .driver = { .name = "acpi-tad", .acpi_match_table = acpi_tad_ids, + .dev_groups = acpi_tad_attr_groups, }, .probe = acpi_tad_probe, .remove = acpi_tad_remove, 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 #include -#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 +#include +#include +#include +#include +#include + +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 "); +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 */ @@ -853,6 +853,16 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) } per_cpu(cpu_pcc_subspace_idx, pr->id) = pcc_subspace_id; + /* + * In CPPC v1, DESIRED_PERF is mandatory. In CPPC v2, it is optional + * only when AUTO_SEL_ENABLE is supported. + */ + if (!CPC_SUPPORTED(&cpc_ptr->cpc_regs[DESIRED_PERF]) && + (!osc_sb_cppc2_support_acked || + !CPC_SUPPORTED(&cpc_ptr->cpc_regs[AUTO_SEL_ENABLE]))) + pr_warn("Desired perf. register is mandatory if CPPC v2 is not supported " + "or autonomous selection is disabled\n"); + /* * Initialize the remaining cpc_regs as unsupported. * Example: In case FW exposes CPPC v2, the below loop will initialize @@ -1342,9 +1352,10 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) { struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum); struct cpc_register_resource *highest_reg, *lowest_reg, - *lowest_non_linear_reg, *nominal_reg, *guaranteed_reg, - *low_freq_reg = NULL, *nom_freq_reg = NULL; - u64 high, low, guaranteed, nom, min_nonlinear, low_f = 0, nom_f = 0; + *lowest_non_linear_reg, *nominal_reg, *reference_reg, + *guaranteed_reg, *low_freq_reg = NULL, *nom_freq_reg = NULL; + u64 high, low, guaranteed, nom, ref, min_nonlinear, + low_f = 0, nom_f = 0; int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum); struct cppc_pcc_data *pcc_ss_data = NULL; int ret = 0, regs_in_pcc = 0; @@ -1358,6 +1369,7 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) lowest_reg = &cpc_desc->cpc_regs[LOWEST_PERF]; lowest_non_linear_reg = &cpc_desc->cpc_regs[LOW_NON_LINEAR_PERF]; nominal_reg = &cpc_desc->cpc_regs[NOMINAL_PERF]; + reference_reg = &cpc_desc->cpc_regs[REFERENCE_PERF]; low_freq_reg = &cpc_desc->cpc_regs[LOWEST_FREQ]; nom_freq_reg = &cpc_desc->cpc_regs[NOMINAL_FREQ]; guaranteed_reg = &cpc_desc->cpc_regs[GUARANTEED_PERF]; @@ -1365,6 +1377,7 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) /* Are any of the regs PCC ?*/ if (CPC_IN_PCC(highest_reg) || CPC_IN_PCC(lowest_reg) || CPC_IN_PCC(lowest_non_linear_reg) || CPC_IN_PCC(nominal_reg) || + (CPC_SUPPORTED(reference_reg) && CPC_IN_PCC(reference_reg)) || CPC_IN_PCC(low_freq_reg) || CPC_IN_PCC(nom_freq_reg) || CPC_IN_PCC(guaranteed_reg)) { if (pcc_ss_id < 0) { @@ -1381,35 +1394,66 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) } } - cpc_read(cpunum, highest_reg, &high); + ret = cpc_read(cpunum, highest_reg, &high); + if (ret) + goto out_err; perf_caps->highest_perf = high; - cpc_read(cpunum, lowest_reg, &low); + ret = cpc_read(cpunum, lowest_reg, &low); + if (ret) + goto out_err; perf_caps->lowest_perf = low; - cpc_read(cpunum, nominal_reg, &nom); + ret = cpc_read(cpunum, nominal_reg, &nom); + if (ret) + goto out_err; perf_caps->nominal_perf = nom; + /* + * If reference perf register is not supported then we should + * use the nominal perf value + */ + if (CPC_SUPPORTED(reference_reg)) { + ret = cpc_read(cpunum, reference_reg, &ref); + if (ret) + goto out_err; + } else { + ref = nom; + } + perf_caps->reference_perf = ref; + if (guaranteed_reg->type != ACPI_TYPE_BUFFER || IS_NULL_REG(&guaranteed_reg->cpc_entry.reg)) { perf_caps->guaranteed_perf = 0; } else { - cpc_read(cpunum, guaranteed_reg, &guaranteed); + ret = cpc_read(cpunum, guaranteed_reg, &guaranteed); + if (ret) + goto out_err; perf_caps->guaranteed_perf = guaranteed; } - cpc_read(cpunum, lowest_non_linear_reg, &min_nonlinear); + ret = cpc_read(cpunum, lowest_non_linear_reg, &min_nonlinear); + if (ret) + goto out_err; perf_caps->lowest_nonlinear_perf = min_nonlinear; - if (!high || !low || !nom || !min_nonlinear) + if (!high || !low || !nom || !ref || !min_nonlinear) { ret = -EFAULT; + goto out_err; + } /* Read optional lowest and nominal frequencies if present */ - if (CPC_SUPPORTED(low_freq_reg)) - cpc_read(cpunum, low_freq_reg, &low_f); + if (CPC_SUPPORTED(low_freq_reg)) { + ret = cpc_read(cpunum, low_freq_reg, &low_f); + if (ret) + goto out_err; + } - if (CPC_SUPPORTED(nom_freq_reg)) - cpc_read(cpunum, nom_freq_reg, &nom_f); + if (CPC_SUPPORTED(nom_freq_reg)) { + ret = cpc_read(cpunum, nom_freq_reg, &nom_f); + if (ret) + goto out_err; + } perf_caps->lowest_freq = low_f; perf_caps->nominal_freq = nom_f; @@ -1431,20 +1475,10 @@ EXPORT_SYMBOL_GPL(cppc_get_perf_caps); bool cppc_perf_ctrs_in_pcc_cpu(unsigned int cpu) { struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu); - struct cpc_register_resource *ref_perf_reg; - - /* - * If reference perf register is not supported then we should use the - * nominal perf value - */ - ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF]; - if (!CPC_SUPPORTED(ref_perf_reg)) - ref_perf_reg = &cpc_desc->cpc_regs[NOMINAL_PERF]; return CPC_IN_PCC(&cpc_desc->cpc_regs[DELIVERED_CTR]) || CPC_IN_PCC(&cpc_desc->cpc_regs[REFERENCE_CTR]) || - CPC_IN_PCC(&cpc_desc->cpc_regs[CTR_WRAP_TIME]) || - CPC_IN_PCC(ref_perf_reg); + CPC_IN_PCC(&cpc_desc->cpc_regs[CTR_WRAP_TIME]); } EXPORT_SYMBOL_GPL(cppc_perf_ctrs_in_pcc_cpu); @@ -1481,10 +1515,10 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs) { struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpunum); struct cpc_register_resource *delivered_reg, *reference_reg, - *ref_perf_reg, *ctr_wrap_reg; + *ctr_wrap_reg; int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpunum); struct cppc_pcc_data *pcc_ss_data = NULL; - u64 delivered, reference, ref_perf, ctr_wrap_time; + u64 delivered, reference, ctr_wrap_time; int ret = 0, regs_in_pcc = 0; if (!cpc_desc) { @@ -1494,19 +1528,11 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs) delivered_reg = &cpc_desc->cpc_regs[DELIVERED_CTR]; reference_reg = &cpc_desc->cpc_regs[REFERENCE_CTR]; - ref_perf_reg = &cpc_desc->cpc_regs[REFERENCE_PERF]; ctr_wrap_reg = &cpc_desc->cpc_regs[CTR_WRAP_TIME]; - /* - * If reference perf register is not supported then we should - * use the nominal perf value - */ - if (!CPC_SUPPORTED(ref_perf_reg)) - ref_perf_reg = &cpc_desc->cpc_regs[NOMINAL_PERF]; - /* Are any of the regs PCC ?*/ if (CPC_IN_PCC(delivered_reg) || CPC_IN_PCC(reference_reg) || - CPC_IN_PCC(ctr_wrap_reg) || CPC_IN_PCC(ref_perf_reg)) { + CPC_IN_PCC(ctr_wrap_reg)) { if (pcc_ss_id < 0) { pr_debug("Invalid pcc_ss_id\n"); return -ENODEV; @@ -1521,9 +1547,13 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs) } } - cpc_read(cpunum, delivered_reg, &delivered); - cpc_read(cpunum, reference_reg, &reference); - cpc_read(cpunum, ref_perf_reg, &ref_perf); + ret = cpc_read(cpunum, delivered_reg, &delivered); + if (ret) + goto out_err; + + ret = cpc_read(cpunum, reference_reg, &reference); + if (ret) + goto out_err; /* * Per spec, if ctr_wrap_time optional register is unsupported, then the @@ -1531,17 +1561,19 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs) * platform */ ctr_wrap_time = (u64)(~((u64)0)); - if (CPC_SUPPORTED(ctr_wrap_reg)) - cpc_read(cpunum, ctr_wrap_reg, &ctr_wrap_time); + if (CPC_SUPPORTED(ctr_wrap_reg)) { + ret = cpc_read(cpunum, ctr_wrap_reg, &ctr_wrap_time); + if (ret) + goto out_err; + } - if (!delivered || !reference || !ref_perf) { + if (!delivered || !reference) { ret = -EFAULT; goto out_err; } perf_fb_ctrs->delivered = delivered; perf_fb_ctrs->reference = reference; - perf_fb_ctrs->reference_perf = ref_perf; perf_fb_ctrs->wraparound_time = ctr_wrap_time; out_err: if (regs_in_pcc) @@ -1561,6 +1593,8 @@ int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable) struct cpc_register_resource *auto_sel_reg; struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu); struct cppc_pcc_data *pcc_ss_data = NULL; + bool autosel_ffh_sysmem; + bool epp_ffh_sysmem; int ret; if (!cpc_desc) { @@ -1571,6 +1605,11 @@ int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable) auto_sel_reg = &cpc_desc->cpc_regs[AUTO_SEL_ENABLE]; epp_set_reg = &cpc_desc->cpc_regs[ENERGY_PERF]; + epp_ffh_sysmem = CPC_SUPPORTED(epp_set_reg) && + (CPC_IN_FFH(epp_set_reg) || CPC_IN_SYSTEM_MEMORY(epp_set_reg)); + autosel_ffh_sysmem = CPC_SUPPORTED(auto_sel_reg) && + (CPC_IN_FFH(auto_sel_reg) || CPC_IN_SYSTEM_MEMORY(auto_sel_reg)); + if (CPC_IN_PCC(epp_set_reg) || CPC_IN_PCC(auto_sel_reg)) { if (pcc_ss_id < 0) { pr_debug("Invalid pcc_ss_id for CPU:%d\n", cpu); @@ -1596,11 +1635,22 @@ int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable) ret = send_pcc_cmd(pcc_ss_id, CMD_WRITE); up_write(&pcc_ss_data->pcc_lock); } else if (osc_cpc_flexible_adr_space_confirmed && - CPC_SUPPORTED(epp_set_reg) && CPC_IN_FFH(epp_set_reg)) { - ret = cpc_write(cpu, epp_set_reg, perf_ctrls->energy_perf); + (epp_ffh_sysmem || autosel_ffh_sysmem)) { + if (autosel_ffh_sysmem) { + ret = cpc_write(cpu, auto_sel_reg, enable); + if (ret) + return ret; + } + + if (epp_ffh_sysmem) { + ret = cpc_write(cpu, epp_set_reg, + perf_ctrls->energy_perf); + if (ret) + return ret; + } } else { ret = -ENOTSUPP; - pr_debug("_CPC in PCC and _CPC in FFH are not supported\n"); + pr_debug("_CPC in PCC/FFH/SystemMemory are not supported\n"); } return ret; @@ -1738,6 +1788,101 @@ int cppc_set_enable(int cpu, bool enable) } EXPORT_SYMBOL_GPL(cppc_set_enable); +/** + * cppc_get_perf - Get a CPU's performance controls. + * @cpu: CPU for which to get performance controls. + * @perf_ctrls: ptr to cppc_perf_ctrls. See cppc_acpi.h + * + * Return: 0 for success with perf_ctrls, -ERRNO otherwise. + */ +int cppc_get_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) +{ + struct cpc_desc *cpc_desc = per_cpu(cpc_desc_ptr, cpu); + struct cpc_register_resource *desired_perf_reg, + *min_perf_reg, *max_perf_reg, + *energy_perf_reg, *auto_sel_reg; + u64 desired_perf = 0, min = 0, max = 0, energy_perf = 0, auto_sel = 0; + int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, cpu); + struct cppc_pcc_data *pcc_ss_data = NULL; + int ret = 0, regs_in_pcc = 0; + + if (!cpc_desc) { + pr_debug("No CPC descriptor for CPU:%d\n", cpu); + return -ENODEV; + } + + if (!perf_ctrls) { + pr_debug("Invalid perf_ctrls pointer\n"); + return -EINVAL; + } + + desired_perf_reg = &cpc_desc->cpc_regs[DESIRED_PERF]; + min_perf_reg = &cpc_desc->cpc_regs[MIN_PERF]; + max_perf_reg = &cpc_desc->cpc_regs[MAX_PERF]; + energy_perf_reg = &cpc_desc->cpc_regs[ENERGY_PERF]; + auto_sel_reg = &cpc_desc->cpc_regs[AUTO_SEL_ENABLE]; + + /* Are any of the regs PCC ?*/ + if (CPC_IN_PCC(desired_perf_reg) || CPC_IN_PCC(min_perf_reg) || + CPC_IN_PCC(max_perf_reg) || CPC_IN_PCC(energy_perf_reg) || + CPC_IN_PCC(auto_sel_reg)) { + if (pcc_ss_id < 0) { + pr_debug("Invalid pcc_ss_id for CPU:%d\n", cpu); + return -ENODEV; + } + pcc_ss_data = pcc_data[pcc_ss_id]; + regs_in_pcc = 1; + down_write(&pcc_ss_data->pcc_lock); + /* Ring doorbell once to update PCC subspace */ + if (send_pcc_cmd(pcc_ss_id, CMD_READ) < 0) { + ret = -EIO; + goto out_err; + } + } + + /* Read optional elements if present */ + if (CPC_SUPPORTED(max_perf_reg)) { + ret = cpc_read(cpu, max_perf_reg, &max); + if (ret) + goto out_err; + } + perf_ctrls->max_perf = max; + + if (CPC_SUPPORTED(min_perf_reg)) { + ret = cpc_read(cpu, min_perf_reg, &min); + if (ret) + goto out_err; + } + perf_ctrls->min_perf = min; + + if (CPC_SUPPORTED(desired_perf_reg)) { + ret = cpc_read(cpu, desired_perf_reg, &desired_perf); + if (ret) + goto out_err; + } + perf_ctrls->desired_perf = desired_perf; + + if (CPC_SUPPORTED(energy_perf_reg)) { + ret = cpc_read(cpu, energy_perf_reg, &energy_perf); + if (ret) + goto out_err; + } + perf_ctrls->energy_perf = energy_perf; + + if (CPC_SUPPORTED(auto_sel_reg)) { + ret = cpc_read(cpu, auto_sel_reg, &auto_sel); + if (ret) + goto out_err; + } + perf_ctrls->auto_sel = (bool)auto_sel; + +out_err: + if (regs_in_pcc) + up_write(&pcc_ss_data->pcc_lock); + return ret; +} +EXPORT_SYMBOL_GPL(cppc_get_perf); + /** * cppc_set_perf - Set a CPU's performance controls. * @cpu: CPU for which to set performance controls. @@ -1870,6 +2015,62 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) } EXPORT_SYMBOL_GPL(cppc_set_perf); +/** + * cppc_get_perf_limited - Get the Performance Limited register value. + * @cpu: CPU from which to get Performance Limited register. + * @perf_limited: Pointer to store the Performance Limited value. + * + * The returned value contains sticky status bits indicating platform-imposed + * performance limitations. + * + * Return: 0 for success, -EIO on failure, -EOPNOTSUPP if not supported. + */ +int cppc_get_perf_limited(int cpu, u64 *perf_limited) +{ + return cppc_get_reg_val(cpu, PERF_LIMITED, perf_limited); +} +EXPORT_SYMBOL_GPL(cppc_get_perf_limited); + +/** + * cppc_set_perf_limited() - Clear bits in the Performance Limited register. + * @cpu: CPU on which to write register. + * @bits_to_clear: Bitmask of bits to clear in the perf_limited register. + * + * The Performance Limited register contains two sticky bits set by platform: + * - Bit 0 (Desired_Excursion): Set when delivered performance is constrained + * below desired performance. Not used when Autonomous Selection is enabled. + * - Bit 1 (Minimum_Excursion): Set when delivered performance is constrained + * below minimum performance. + * + * These bits are sticky and remain set until OSPM explicitly clears them. + * This function only allows clearing bits (the platform sets them). + * + * Return: 0 for success, -EINVAL for invalid bits, -EIO on register + * access failure, -EOPNOTSUPP if not supported. + */ +int cppc_set_perf_limited(int cpu, u64 bits_to_clear) +{ + u64 current_val, new_val; + int ret; + + /* Only bits 0 and 1 are valid */ + if (bits_to_clear & ~CPPC_PERF_LIMITED_MASK) + return -EINVAL; + + if (!bits_to_clear) + return 0; + + ret = cppc_get_perf_limited(cpu, ¤t_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 #include +#include +#include #include #include #include @@ -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 #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 #include -/* - * 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(); + + /* Unregister cpuidle device of all CPUs */ cpuidle_pause_and_lock(); - - /* Disable all cpuidle devices */ - for_each_online_cpu(cpu) { - _pr = per_cpu(processors, cpu); - if (!_pr || !_pr->flags.power_setup_done) - continue; + for_each_possible_cpu(cpu) { dev = per_cpu(acpi_cpuidle_device, cpu); - cpuidle_disable_device(dev); - } - - /* Populate Updated C-state information */ - acpi_processor_get_power_info(pr); - acpi_processor_setup_cpuidle_states(pr); - - /* Enable all cpuidle devices */ - for_each_online_cpu(cpu) { _pr = per_cpu(processors, cpu); - if (!_pr || !_pr->flags.power_setup_done) + if (!_pr || !_pr->flags.power || !dev) continue; - acpi_processor_get_power_info(_pr); - if (_pr->flags.power) { - dev = per_cpu(acpi_cpuidle_device, cpu); - acpi_processor_setup_cpuidle_dev(_pr, dev); - cpuidle_enable_device(dev); - } + + cpuidle_unregister_device_no_lock(dev); + kfree(dev); + _pr->flags.power = 0; } cpuidle_resume_and_unlock(); + + /* + * Unregister ACPI idle driver, reinitialize ACPI idle states + * and register ACPI idle driver again. + */ + acpi_processor_unregister_idle_driver(); + acpi_processor_register_idle_driver(); + + /* + * Reinitialize power information of all CPUs and re-register + * all cpuidle devices. Now idle states is ok to use, can enable + * cpuidle of each CPU safely one by one. + */ + for_each_possible_cpu(cpu) { + _pr = per_cpu(processors, cpu); + if (!_pr) + continue; + acpi_processor_power_init(_pr); + } + cpus_read_unlock(); } @@ -1357,6 +1355,8 @@ void acpi_processor_register_idle_driver(void) int ret = -ENODEV; int cpu; + acpi_processor_update_max_cstate(); + /* * ACPI idle driver is used by all possible CPUs. * Use the processor power info of one in them to set up idle states. @@ -1368,7 +1368,6 @@ void acpi_processor_register_idle_driver(void) if (!pr) continue; - acpi_processor_cstate_first_run_checks(); ret = acpi_processor_get_power_info(pr); if (!ret) { pr->flags.power_setup_done = 1; @@ -1384,6 +1383,7 @@ void acpi_processor_register_idle_driver(void) ret = cpuidle_register_driver(&acpi_idle_driver); if (ret) { + pr->flags.power_setup_done = 0; pr_debug("register %s failed.\n", acpi_idle_driver.name); return; } @@ -1392,7 +1392,16 @@ void acpi_processor_register_idle_driver(void) void acpi_processor_unregister_idle_driver(void) { + struct acpi_processor *pr; + int cpu; + cpuidle_unregister_driver(&acpi_idle_driver); + for_each_possible_cpu(cpu) { + pr = per_cpu(processors, cpu); + if (!pr) + continue; + pr->flags.power_setup_done = 0; + } } void acpi_processor_power_init(struct acpi_processor *pr) @@ -1409,8 +1418,6 @@ void acpi_processor_power_init(struct acpi_processor *pr) if (disabled_by_idle_boot_param()) return; - acpi_processor_cstate_first_run_checks(); - if (!acpi_processor_get_power_info(pr)) pr->flags.power_setup_done = 1; @@ -1431,6 +1438,7 @@ void acpi_processor_power_init(struct acpi_processor *pr) */ if (cpuidle_register_device(dev)) { per_cpu(acpi_cpuidle_device, pr->id) = NULL; + pr->flags.power_setup_done = 0; kfree(dev); } } 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); - spin_lock_irq(&rtc_lock); - - for (i = 0; i < DIV_ROUND_UP(bits, 8); ++i, ++address, ++value) - if (function == ACPI_READ) - *value = CMOS_READ(address); - else + if (function == ACPI_WRITE) { + for (i = 0; i < bytes; i++, address++, value++) CMOS_WRITE(*value, address); - spin_unlock_irq(&rtc_lock); + return AE_OK; + } - return AE_OK; + if (function == ACPI_READ) { + for (i = 0; i < bytes; i++, address++, value++) + *value = CMOS_READ(address); + + return AE_OK; + } + + return AE_BAD_PARAMETER; } -int acpi_install_cmos_rtc_space_handler(acpi_handle handle) +static int acpi_install_cmos_rtc_space_handler(acpi_handle handle) { + static bool cmos_rtc_space_handler_present __read_mostly; acpi_status status; + if (cmos_rtc_space_handler_present) + return 0; + status = acpi_install_address_space_handler(handle, - ACPI_ADR_SPACE_CMOS, - &acpi_cmos_rtc_space_handler, - NULL, NULL); + ACPI_ADR_SPACE_CMOS, + acpi_cmos_rtc_space_handler, + NULL, NULL); if (ACPI_FAILURE(status)) { - pr_err("Error installing CMOS-RTC region handler\n"); + pr_err("Failed to install CMOS-RTC address space handler\n"); return -ENODEV; } + cmos_rtc_space_handler_present = true; + return 1; } -EXPORT_SYMBOL_GPL(acpi_install_cmos_rtc_space_handler); -void acpi_remove_cmos_rtc_space_handler(acpi_handle handle) +static int acpi_cmos_rtc_attach(struct acpi_device *adev, + const struct acpi_device_id *id) { - if (ACPI_FAILURE(acpi_remove_address_space_handler(handle, - ACPI_ADR_SPACE_CMOS, &acpi_cmos_rtc_space_handler))) - pr_err("Error removing CMOS-RTC region handler\n"); -} -EXPORT_SYMBOL_GPL(acpi_remove_cmos_rtc_space_handler); + int ret; -static int acpi_cmos_rtc_attach_handler(struct acpi_device *adev, const struct acpi_device_id *id) -{ - return acpi_install_cmos_rtc_space_handler(adev->handle); -} + ret = acpi_install_cmos_rtc_space_handler(adev->handle); + if (ret < 0) + return ret; -static void acpi_cmos_rtc_detach_handler(struct acpi_device *adev) -{ - acpi_remove_cmos_rtc_space_handler(adev->handle); + if (IS_ERR_OR_NULL(acpi_create_platform_device(adev, NULL))) { + pr_err("Failed to create a platform device for %s\n", (char *)id->id); + return 0; + } else if (!id->driver_data) { + cmos_rtc_platform_device_present = true; + } + return 1; } static struct acpi_scan_handler cmos_rtc_handler = { .ids = acpi_cmos_rtc_ids, - .attach = acpi_cmos_rtc_attach_handler, - .detach = acpi_cmos_rtc_detach_handler, + .attach = acpi_cmos_rtc_attach, }; void __init acpi_cmos_rtc_init(void) 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,6 +714,23 @@ int cpuidle_register_device(struct cpuidle_device *dev) EXPORT_SYMBOL_GPL(cpuidle_register_device); +void cpuidle_unregister_device_no_lock(struct cpuidle_device *dev) +{ + if (!dev || dev->registered == 0) + return; + + lockdep_assert_held(&cpuidle_lock); + + cpuidle_disable_device(dev); + + cpuidle_remove_sysfs(dev); + + __cpuidle_unregister_device(dev); + + cpuidle_coupled_unregister_device(dev); +} +EXPORT_SYMBOL_GPL(cpuidle_unregister_device_no_lock); + /** * cpuidle_unregister_device - unregisters a CPU's idle PM feature * @dev: the cpu @@ -724,18 +741,9 @@ void cpuidle_unregister_device(struct cpuidle_device *dev) return; cpuidle_pause_and_lock(); - - cpuidle_disable_device(dev); - - cpuidle_remove_sysfs(dev); - - __cpuidle_unregister_device(dev); - - cpuidle_coupled_unregister_device(dev); - + cpuidle_unregister_device_no_lock(dev); cpuidle_resume_and_unlock(); } - EXPORT_SYMBOL_GPL(cpuidle_unregister_device); /** 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 -#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 #include #include #include @@ -215,6 +216,11 @@ static inline void cmos_write_bank2(unsigned char val, unsigned char addr) /*----------------------------------------------------------------*/ +static bool cmos_no_alarm(struct cmos_rtc *cmos) +{ + return !is_valid_irq(cmos->irq) && !cmos_use_acpi_alarm(); +} + static int cmos_read_time(struct device *dev, struct rtc_time *t) { int ret; @@ -286,7 +292,7 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t) }; /* This not only a rtc_op, but also called directly */ - if (!is_valid_irq(cmos->irq)) + if (cmos_no_alarm(cmos)) return -ETIMEDOUT; /* Basic alarms only support hour, minute, and seconds fields. @@ -519,7 +525,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) int ret; /* This not only a rtc_op, but also called directly */ - if (!is_valid_irq(cmos->irq)) + if (cmos_no_alarm(cmos)) return -EIO; ret = cmos_validate_alarm(dev, t); @@ -816,6 +822,9 @@ static void rtc_wake_off(struct device *dev) #ifdef CONFIG_X86 static void use_acpi_alarm_quirks(void) { + if (acpi_gbl_FADT.flags & ACPI_FADT_FIXED_RTC) + return; + switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_INTEL: if (dmi_get_bios_year() < 2015) @@ -829,8 +838,6 @@ static void use_acpi_alarm_quirks(void) default: return; } - if (!is_hpet_enabled()) - return; use_acpi_alarm = true; } @@ -1094,7 +1101,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq); goto cleanup1; } - } else { + } else if (!cmos_use_acpi_alarm()) { clear_bit(RTC_FEATURE_ALARM, cmos_rtc.rtc->features); } @@ -1119,7 +1126,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) acpi_rtc_event_setup(dev); dev_info(dev, "%s%s, %d bytes nvram%s\n", - !is_valid_irq(rtc_irq) ? "no alarms" : + cmos_no_alarm(&cmos_rtc) ? "no alarms" : cmos_rtc.mon_alrm ? "alarms up to one year" : cmos_rtc.day_alrm ? "alarms up to one month" : "alarms up to one day", @@ -1145,7 +1152,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) static void cmos_do_shutdown(int rtc_irq) { spin_lock_irq(&rtc_lock); - if (is_valid_irq(rtc_irq)) + if (!cmos_no_alarm(&cmos_rtc)) cmos_irq_disable(&cmos_rtc, RTC_IRQMASK); spin_unlock_irq(&rtc_lock); } @@ -1369,85 +1376,6 @@ static int __maybe_unused cmos_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(cmos_pm_ops, cmos_suspend, cmos_resume); -/*----------------------------------------------------------------*/ - -/* On non-x86 systems, a "CMOS" RTC lives most naturally on platform_bus. - * ACPI systems always list these as PNPACPI devices, and pre-ACPI PCs - * probably list them in similar PNPBIOS tables; so PNP is more common. - * - * We don't use legacy "poke at the hardware" probing. Ancient PCs that - * predate even PNPBIOS should set up platform_bus devices. - */ - -#ifdef CONFIG_PNP - -#include - -static int cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id) -{ - int irq; - - if (pnp_port_start(pnp, 0) == 0x70 && !pnp_irq_valid(pnp, 0)) { - irq = 0; -#ifdef CONFIG_X86 - /* Some machines contain a PNP entry for the RTC, but - * don't define the IRQ. It should always be safe to - * hardcode it on systems with a legacy PIC. - */ - if (nr_legacy_irqs()) - irq = RTC_IRQ; -#endif - } else { - irq = pnp_irq(pnp, 0); - } - - return cmos_do_probe(&pnp->dev, pnp_get_resource(pnp, IORESOURCE_IO, 0), irq); -} - -static void cmos_pnp_remove(struct pnp_dev *pnp) -{ - cmos_do_remove(&pnp->dev); -} - -static void cmos_pnp_shutdown(struct pnp_dev *pnp) -{ - struct device *dev = &pnp->dev; - struct cmos_rtc *cmos = dev_get_drvdata(dev); - - if (system_state == SYSTEM_POWER_OFF) { - int retval = cmos_poweroff(dev); - - if (cmos_aie_poweroff(dev) < 0 && !retval) - return; - } - - cmos_do_shutdown(cmos->irq); -} - -static const struct pnp_device_id rtc_ids[] = { - { .id = "PNP0b00", }, - { .id = "PNP0b01", }, - { .id = "PNP0b02", }, - { }, -}; -MODULE_DEVICE_TABLE(pnp, rtc_ids); - -static struct pnp_driver cmos_pnp_driver = { - .name = driver_name, - .id_table = rtc_ids, - .probe = cmos_pnp_probe, - .remove = cmos_pnp_remove, - .shutdown = cmos_pnp_shutdown, - - /* flag ensures resume() gets called, and stops syslog spam */ - .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, - .driver = { - .pm = &cmos_pm_ops, - }, -}; - -#endif /* CONFIG_PNP */ - #ifdef CONFIG_OF static const struct of_device_id of_cmos_match[] = { { @@ -1476,6 +1404,14 @@ static __init void cmos_of_init(struct platform_device *pdev) #else static inline void cmos_of_init(struct platform_device *pdev) {} #endif + +#ifdef CONFIG_ACPI +static const struct acpi_device_id acpi_cmos_rtc_ids[] = { + ACPI_CMOS_RTC_IDS +}; +MODULE_DEVICE_TABLE(acpi, acpi_cmos_rtc_ids); +#endif + /*----------------------------------------------------------------*/ /* Platform setup should have set up an RTC device, when PNP is @@ -1530,48 +1466,31 @@ static struct platform_driver cmos_platform_driver = { .name = driver_name, .pm = &cmos_pm_ops, .of_match_table = of_match_ptr(of_cmos_match), + .acpi_match_table = ACPI_PTR(acpi_cmos_rtc_ids), } }; -#ifdef CONFIG_PNP -static bool pnp_driver_registered; -#endif static bool platform_driver_registered; static int __init cmos_init(void) { - int retval = 0; + int retval; -#ifdef CONFIG_PNP - retval = pnp_register_driver(&cmos_pnp_driver); - if (retval == 0) - pnp_driver_registered = true; -#endif - - if (!cmos_rtc.dev) { - retval = platform_driver_probe(&cmos_platform_driver, - cmos_platform_probe); - if (retval == 0) - platform_driver_registered = true; - } - - if (retval == 0) + if (cmos_rtc.dev) return 0; -#ifdef CONFIG_PNP - if (pnp_driver_registered) - pnp_unregister_driver(&cmos_pnp_driver); -#endif - return retval; + retval = platform_driver_probe(&cmos_platform_driver, cmos_platform_probe); + if (retval) + return retval; + + platform_driver_registered = true; + + return 0; } module_init(cmos_init); static void __exit cmos_exit(void) { -#ifdef CONFIG_PNP - if (pnp_driver_registered) - pnp_unregister_driver(&cmos_pnp_driver); -#endif if (platform_driver_registered) platform_driver_unregister(&cmos_platform_driver); } 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 #include #include +#include #include #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 "); 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 #include #include +#include #include #include #include @@ -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 -#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)