mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 03:44:45 +01:00
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
This commit is contained in:
commit
2b0181a52f
4 changed files with 126 additions and 111 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
int acpi_processor_power_init(struct acpi_processor *pr)
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (!pr->flags.power)
|
||||
return;
|
||||
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
return;
|
||||
|
||||
per_cpu(acpi_cpuidle_device, pr->id) = dev;
|
||||
|
||||
acpi_processor_setup_cpuidle_dev(pr, dev);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* Register a cpuidle device for this CPU. The cpuidle driver using
|
||||
* this device is expected to be registered.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
per_cpu(acpi_cpuidle_device, pr->id) = 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++;
|
||||
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");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue