diff options
| author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2026-02-05 15:09:30 +0100 |
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2026-02-05 15:09:30 +0100 |
| commit | 2b0181a52fcbeba25c6b2d701236231b19499861 (patch) | |
| tree | fc87b0fa0505fdfebbd7f1966711f8fa8ca8691f | |
| parent | 1a91d4e27d67d87673a0f2c1f90a98ae67b89885 (diff) | |
| parent | cac173bea57d62c599f8717fde77b7824c6021ed (diff) | |
Merge branch 'acpi-processor'
Merge ACPI processor driver changes for 6.20-rc1/7.0-rc1:
- Rework the ACPI idle driver initialization to register it directly
from the common initialization code instead of doing that from a
CPU hotplug "online" callback and clean it up (Huisong Li, Rafael
Wysocki)
- Fix a possible NULL pointer dereference in
acpi_processor_errata_piix4() (Tuo Li)
* acpi-processor:
ACPI: processor: idle: Rework the handling of acpi_processor_ffh_lpi_probe()
ACPI: processor: idle: Convert acpi_processor_setup_cpuidle_dev() to void
ACPI: processor: idle: Convert acpi_processor_setup_cpuidle_states() to void
ACPI: processor: idle: Add debug log for states with invalid entry methods
ACPI: processor: Fix NULL-pointer dereference in acpi_processor_errata_piix4()
ACPI: processor: Do not expose global variable acpi_idle_driver
ACPI: processor: idle: Rearrange declarations in header file
ACPI: processor: idle: Redefine two functions as void
ACPI: processor: Update cpuidle driver check in __acpi_processor_start()
ACPI: processor: Remove unused empty stubs of some functions
ACPI: processor: idle: Optimize ACPI idle driver registration
| -rw-r--r-- | drivers/acpi/acpi_processor.c | 28 | ||||
| -rw-r--r-- | drivers/acpi/processor_driver.c | 13 | ||||
| -rw-r--r-- | drivers/acpi/processor_idle.c | 158 | ||||
| -rw-r--r-- | include/acpi/processor.h | 34 |
4 files changed, 124 insertions, 109 deletions
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 7ec1dc04fd11..85096ce7b658 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -50,6 +50,7 @@ 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) @@ -107,12 +108,12 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev) * each IDE controller's DMA status to make sure we catch all * DMA activity. */ - dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, + ide_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB, PCI_ANY_ID, PCI_ANY_ID, NULL); - if (dev) { - errata.piix4.bmisx = pci_resource_start(dev, 4); - pci_dev_put(dev); + if (ide_dev) { + errata.piix4.bmisx = pci_resource_start(ide_dev, 4); + pci_dev_put(ide_dev); } /* @@ -124,24 +125,25 @@ 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. */ - dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, + isa_dev = pci_get_subsys(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, PCI_ANY_ID, PCI_ANY_ID, NULL); - if (dev) { - pci_read_config_byte(dev, 0x76, &value1); - pci_read_config_byte(dev, 0x77, &value2); + if (isa_dev) { + pci_read_config_byte(isa_dev, 0x76, &value1); + pci_read_config_byte(isa_dev, 0x77, &value2); if ((value1 & 0x80) || (value2 & 0x80)) errata.piix4.fdma = 1; - pci_dev_put(dev); + pci_dev_put(isa_dev); } break; } - if (errata.piix4.bmisx) - dev_dbg(&dev->dev, "Bus master activity detection (BM-IDE) erratum enabled\n"); - if (errata.piix4.fdma) - dev_dbg(&dev->dev, "Type-F DMA livelock erratum (C3 disabled)\n"); + if (ide_dev) + dev_dbg(&ide_dev->dev, "Bus master activity detection (BM-IDE) erratum enabled\n"); + + if (isa_dev) + dev_dbg(&isa_dev->dev, "Type-F DMA livelock erratum (C3 disabled)\n"); return 0; } diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 65e779be64ff..882709796b4f 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -166,8 +166,7 @@ static int __acpi_processor_start(struct acpi_device *device) if (result && !IS_ENABLED(CONFIG_ACPI_CPU_FREQ_PSS)) dev_dbg(&device->dev, "CPPC data invalid or not present\n"); - if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver) - acpi_processor_power_init(pr); + acpi_processor_power_init(pr); acpi_pss_perf_init(pr); @@ -259,9 +258,11 @@ static int __init acpi_processor_driver_init(void) acpi_processor_ignore_ppc_init(); } + acpi_processor_register_idle_driver(); + result = driver_register(&acpi_processor_driver); if (result < 0) - return result; + goto unregister_idle_drv; result = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "acpi/cpu-drv:online", @@ -283,8 +284,13 @@ static int __init acpi_processor_driver_init(void) acpi_idle_rescan_dead_smt_siblings(); return 0; + err: driver_unregister(&acpi_processor_driver); + +unregister_idle_drv: + acpi_processor_unregister_idle_driver(); + return result; } @@ -302,6 +308,7 @@ static void __exit acpi_processor_driver_exit(void) cpuhp_remove_state_nocalls(hp_online); cpuhp_remove_state_nocalls(CPUHP_ACPI_CPUDRV_DEAD); driver_unregister(&acpi_processor_driver); + acpi_processor_unregister_idle_driver(); } module_init(acpi_processor_driver_init); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 89f2f08b2554..81f372c64074 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -51,7 +51,7 @@ module_param(latency_factor, uint, 0644); static DEFINE_PER_CPU(struct cpuidle_device *, acpi_cpuidle_device); -struct cpuidle_driver acpi_idle_driver = { +static struct cpuidle_driver acpi_idle_driver = { .name = "acpi_idle", .owner = THIS_MODULE, }; @@ -946,6 +946,8 @@ static int acpi_processor_evaluate_lpi(acpi_handle handle, lpi_state->entry_method = ACPI_CSTATE_INTEGER; lpi_state->address = obj->integer.value; } else { + pr_debug("Entry method of state-%d is invalid, disable it.\n", + state_idx); continue; } @@ -1178,7 +1180,7 @@ static int acpi_idle_lpi_enter(struct cpuidle_device *dev, return -EINVAL; } -static int acpi_processor_setup_lpi_states(struct acpi_processor *pr) +static void acpi_processor_setup_lpi_states(struct acpi_processor *pr) { int i; struct acpi_lpi_state *lpi; @@ -1186,7 +1188,7 @@ static int acpi_processor_setup_lpi_states(struct acpi_processor *pr) struct cpuidle_driver *drv = &acpi_idle_driver; if (!pr->flags.has_lpi) - return -EOPNOTSUPP; + return; for (i = 0; i < pr->power.count && i < CPUIDLE_STATE_MAX; i++) { lpi = &pr->power.lpi_states[i]; @@ -1204,8 +1206,6 @@ static int acpi_processor_setup_lpi_states(struct acpi_processor *pr) } drv->state_count = i; - - return 0; } /** @@ -1214,13 +1214,13 @@ static int acpi_processor_setup_lpi_states(struct acpi_processor *pr) * * @pr: the ACPI processor */ -static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) +static void acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) { int i; struct cpuidle_driver *drv = &acpi_idle_driver; if (!pr->flags.power_setup_done || !pr->flags.power) - return -EINVAL; + return; drv->safe_state_index = -1; for (i = ACPI_IDLE_STATE_START; i < CPUIDLE_STATE_MAX; i++) { @@ -1228,32 +1228,30 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr) drv->states[i].desc[0] = '\0'; } - if (pr->flags.has_lpi) - return acpi_processor_setup_lpi_states(pr); + if (pr->flags.has_lpi) { + acpi_processor_setup_lpi_states(pr); + return; + } acpi_processor_setup_cstates(pr); - return 0; } /** - * acpi_processor_setup_cpuidle_dev - prepares and configures CPUIDLE + * acpi_processor_setup_cpuidle_dev - configures CPUIDLE * device i.e. per-cpu data * * @pr: the ACPI processor * @dev : the cpuidle device */ -static int acpi_processor_setup_cpuidle_dev(struct acpi_processor *pr, - struct cpuidle_device *dev) +static void acpi_processor_setup_cpuidle_dev(struct acpi_processor *pr, + struct cpuidle_device *dev) { if (!pr->flags.power_setup_done || !pr->flags.power || !dev) - return -EINVAL; + return; dev->cpu = pr->id; - if (pr->flags.has_lpi) - return acpi_processor_ffh_lpi_probe(pr->id); - - acpi_processor_setup_cpuidle_cx(pr, dev); - return 0; + if (!pr->flags.has_lpi) + acpi_processor_setup_cpuidle_cx(pr, dev); } static int acpi_processor_get_power_info(struct acpi_processor *pr) @@ -1262,7 +1260,13 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr) ret = acpi_processor_get_lpi_info(pr); if (ret) - ret = acpi_processor_get_cstate_info(pr); + return acpi_processor_get_cstate_info(pr); + + if (pr->flags.has_lpi) { + ret = acpi_processor_ffh_lpi_probe(pr->id); + if (ret) + pr_err("CPU%u: Invalid FFH LPI data\n", pr->id); + } return ret; } @@ -1347,79 +1351,103 @@ int acpi_processor_power_state_has_changed(struct acpi_processor *pr) return 0; } -static int acpi_processor_registered; +void acpi_processor_register_idle_driver(void) +{ + struct acpi_processor *pr; + int ret = -ENODEV; + int cpu; + + /* + * ACPI idle driver is used by all possible CPUs. + * Use the processor power info of one in them to set up idle states. + * Note that the existing idle handler will be used on platforms that + * only support C1. + */ + for_each_possible_cpu(cpu) { + pr = per_cpu(processors, cpu); + if (!pr) + continue; + + acpi_processor_cstate_first_run_checks(); + ret = acpi_processor_get_power_info(pr); + if (!ret) { + pr->flags.power_setup_done = 1; + acpi_processor_setup_cpuidle_states(pr); + break; + } + } + + if (ret) { + pr_debug("No ACPI power information from any CPUs.\n"); + return; + } -int acpi_processor_power_init(struct acpi_processor *pr) + ret = cpuidle_register_driver(&acpi_idle_driver); + if (ret) { + pr_debug("register %s failed.\n", acpi_idle_driver.name); + return; + } + pr_debug("%s registered with cpuidle.\n", acpi_idle_driver.name); +} + +void acpi_processor_unregister_idle_driver(void) +{ + cpuidle_unregister_driver(&acpi_idle_driver); +} + +void acpi_processor_power_init(struct acpi_processor *pr) { - int retval; struct cpuidle_device *dev; + /* + * The code below only works if the current cpuidle driver is the ACPI + * idle driver. + */ + if (cpuidle_get_driver() != &acpi_idle_driver) + return; + if (disabled_by_idle_boot_param()) - return 0; + return; acpi_processor_cstate_first_run_checks(); if (!acpi_processor_get_power_info(pr)) pr->flags.power_setup_done = 1; - /* - * Install the idle handler if processor power management is supported. - * Note that we use previously set idle handler will be used on - * platforms that only support C1. - */ - if (pr->flags.power) { - /* Register acpi_idle_driver if not already registered */ - if (!acpi_processor_registered) { - acpi_processor_setup_cpuidle_states(pr); - retval = cpuidle_register_driver(&acpi_idle_driver); - if (retval) - return retval; - pr_debug("%s registered with cpuidle\n", - acpi_idle_driver.name); - } + if (!pr->flags.power) + return; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return; - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - per_cpu(acpi_cpuidle_device, pr->id) = dev; + per_cpu(acpi_cpuidle_device, pr->id) = dev; - acpi_processor_setup_cpuidle_dev(pr, dev); + acpi_processor_setup_cpuidle_dev(pr, dev); - /* Register per-cpu cpuidle_device. Cpuidle driver - * must already be registered before registering device - */ - retval = cpuidle_register_device(dev); - if (retval) { - if (acpi_processor_registered == 0) - cpuidle_unregister_driver(&acpi_idle_driver); - - per_cpu(acpi_cpuidle_device, pr->id) = NULL; - kfree(dev); - return retval; - } - acpi_processor_registered++; + /* + * Register a cpuidle device for this CPU. The cpuidle driver using + * this device is expected to be registered. + */ + if (cpuidle_register_device(dev)) { + per_cpu(acpi_cpuidle_device, pr->id) = NULL; + kfree(dev); } - return 0; } -int acpi_processor_power_exit(struct acpi_processor *pr) +void acpi_processor_power_exit(struct acpi_processor *pr) { struct cpuidle_device *dev = per_cpu(acpi_cpuidle_device, pr->id); if (disabled_by_idle_boot_param()) - return 0; + return; if (pr->flags.power) { cpuidle_unregister_device(dev); - acpi_processor_registered--; - if (acpi_processor_registered == 0) - cpuidle_unregister_driver(&acpi_idle_driver); - kfree(dev); } pr->flags.power_setup_done = 0; - return 0; } MODULE_IMPORT_NS("ACPI_PROCESSOR_IDLE"); diff --git a/include/acpi/processor.h b/include/acpi/processor.h index d0eccbd920e5..7146a8e9e9c2 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -417,32 +417,15 @@ static inline void acpi_processor_throttling_init(void) {} #endif /* CONFIG_ACPI_CPU_FREQ_PSS */ /* in processor_idle.c */ -extern struct cpuidle_driver acpi_idle_driver; #ifdef CONFIG_ACPI_PROCESSOR_IDLE -int acpi_processor_power_init(struct acpi_processor *pr); -int acpi_processor_power_exit(struct acpi_processor *pr); +void acpi_processor_power_init(struct acpi_processor *pr); +void acpi_processor_power_exit(struct acpi_processor *pr); int acpi_processor_power_state_has_changed(struct acpi_processor *pr); int acpi_processor_hotplug(struct acpi_processor *pr); -#else -static inline int acpi_processor_power_init(struct acpi_processor *pr) -{ - return -ENODEV; -} - -static inline int acpi_processor_power_exit(struct acpi_processor *pr) -{ - return -ENODEV; -} - -static inline int acpi_processor_power_state_has_changed(struct acpi_processor *pr) -{ - return -ENODEV; -} - -static inline int acpi_processor_hotplug(struct acpi_processor *pr) -{ - return -ENODEV; -} +void acpi_processor_register_idle_driver(void); +void acpi_processor_unregister_idle_driver(void); +int acpi_processor_ffh_lpi_probe(unsigned int cpu); +int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi); #endif /* CONFIG_ACPI_PROCESSOR_IDLE */ /* in processor_thermal.c */ @@ -465,11 +448,6 @@ static inline void acpi_thermal_cpufreq_exit(struct cpufreq_policy *policy) } #endif /* CONFIG_CPU_FREQ */ -#ifdef CONFIG_ACPI_PROCESSOR_IDLE -extern int acpi_processor_ffh_lpi_probe(unsigned int cpu); -extern int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi); -#endif - void acpi_processor_init_invariance_cppc(void); #endif |
