Commit 239708a3 authored by Ashwin Chaugule's avatar Ashwin Chaugule Committed by Rafael J. Wysocki

ACPI: Split out ACPI PSS from ACPI Processor driver

The ACPI processor driver is currently tied too closely
to the ACPI P-states (PSS) and other related constructs
for controlling CPU performance.

The newer ACPI specification (v5.1 onwards) introduces
alternative methods to PSS. These new mechanisms are
described within each ACPI Processor object and so they
need to be scanned whenever a new Processor object is detected.
This patch introduces a new Kconfig symbol to allow for
finer configurability among the two options for controlling
performance states. There is no change in functionality and
the option is auto-selected by the architectures which support it.

A future commit will introduce support for CPPC: A newer method of
controlling CPU performance. The OS is not expected to support
CPPC and PSS at the same time, so the Kconfig option lets us make
the two mutually exclusive at compile time.
Signed-off-by: default avatarAshwin Chaugule <ashwin.chaugule@linaro.org>
[ rjw: Changelog ]
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent d3c68f21
...@@ -189,17 +189,20 @@ config ACPI_DOCK ...@@ -189,17 +189,20 @@ config ACPI_DOCK
This driver supports ACPI-controlled docking stations and removable This driver supports ACPI-controlled docking stations and removable
drive bays such as the IBM Ultrabay and the Dell Module Bay. drive bays such as the IBM Ultrabay and the Dell Module Bay.
config ACPI_CPU_FREQ_PSS
bool
select THERMAL
config ACPI_PROCESSOR config ACPI_PROCESSOR
tristate "Processor" tristate "Processor"
select THERMAL
select CPU_IDLE
depends on X86 || IA64 depends on X86 || IA64
select CPU_IDLE
select ACPI_CPU_FREQ_PSS
default y default y
help help
This driver installs ACPI as the idle handler for Linux and uses This driver adds support for the ACPI Processor package. It is required
ACPI C2 and C3 processor states to save power on systems that by several flavors of cpufreq performance-state, thermal, throttling and
support it. It is required by several flavors of cpufreq idle drivers.
performance-state drivers.
To compile this driver as a module, choose M here: To compile this driver as a module, choose M here:
the module will be called processor. the module will be called processor.
......
...@@ -80,8 +80,9 @@ obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o ...@@ -80,8 +80,9 @@ obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
obj-$(CONFIG_ACPI_BGRT) += bgrt.o obj-$(CONFIG_ACPI_BGRT) += bgrt.o
# processor has its own "processor." module_param namespace # processor has its own "processor." module_param namespace
processor-y := processor_driver.o processor_throttling.o processor-y := processor_driver.o processor_idle.o
processor-y += processor_idle.o processor_thermal.o processor-$(CONFIG_ACPI_CPU_FREQ_PSS) += processor_throttling.o \
processor_thermal.o
processor-$(CONFIG_CPU_FREQ) += processor_perflib.o processor-$(CONFIG_CPU_FREQ) += processor_perflib.o
obj-$(CONFIG_ACPI_PROCESSOR_AGGREGATOR) += acpi_pad.o obj-$(CONFIG_ACPI_PROCESSOR_AGGREGATOR) += acpi_pad.o
......
...@@ -163,34 +163,24 @@ static struct notifier_block acpi_cpu_notifier = { ...@@ -163,34 +163,24 @@ static struct notifier_block acpi_cpu_notifier = {
.notifier_call = acpi_cpu_soft_notify, .notifier_call = acpi_cpu_soft_notify,
}; };
static int __acpi_processor_start(struct acpi_device *device) #ifdef CONFIG_ACPI_CPU_FREQ_PSS
static int acpi_pss_perf_init(struct acpi_processor *pr,
struct acpi_device *device)
{ {
struct acpi_processor *pr = acpi_driver_data(device);
acpi_status status;
int result = 0; int result = 0;
if (!pr)
return -ENODEV;
if (pr->flags.need_hotplug_init)
return 0;
#ifdef CONFIG_CPU_FREQ
acpi_processor_ppc_has_changed(pr, 0); acpi_processor_ppc_has_changed(pr, 0);
#endif
acpi_processor_get_throttling_info(pr); acpi_processor_get_throttling_info(pr);
if (pr->flags.throttling) if (pr->flags.throttling)
pr->flags.limit = 1; pr->flags.limit = 1;
if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver)
acpi_processor_power_init(pr);
pr->cdev = thermal_cooling_device_register("Processor", device, pr->cdev = thermal_cooling_device_register("Processor", device,
&processor_cooling_ops); &processor_cooling_ops);
if (IS_ERR(pr->cdev)) { if (IS_ERR(pr->cdev)) {
result = PTR_ERR(pr->cdev); result = PTR_ERR(pr->cdev);
goto err_power_exit; return result;
} }
dev_dbg(&device->dev, "registered as cooling_device%d\n", dev_dbg(&device->dev, "registered as cooling_device%d\n",
...@@ -204,6 +194,7 @@ static int __acpi_processor_start(struct acpi_device *device) ...@@ -204,6 +194,7 @@ static int __acpi_processor_start(struct acpi_device *device)
"Failed to create sysfs link 'thermal_cooling'\n"); "Failed to create sysfs link 'thermal_cooling'\n");
goto err_thermal_unregister; goto err_thermal_unregister;
} }
result = sysfs_create_link(&pr->cdev->device.kobj, result = sysfs_create_link(&pr->cdev->device.kobj,
&device->dev.kobj, &device->dev.kobj,
"device"); "device");
...@@ -213,17 +204,61 @@ static int __acpi_processor_start(struct acpi_device *device) ...@@ -213,17 +204,61 @@ static int __acpi_processor_start(struct acpi_device *device)
goto err_remove_sysfs_thermal; goto err_remove_sysfs_thermal;
} }
status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
acpi_processor_notify, device);
if (ACPI_SUCCESS(status))
return 0;
sysfs_remove_link(&pr->cdev->device.kobj, "device"); sysfs_remove_link(&pr->cdev->device.kobj, "device");
err_remove_sysfs_thermal: err_remove_sysfs_thermal:
sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
err_thermal_unregister: err_thermal_unregister:
thermal_cooling_device_unregister(pr->cdev); thermal_cooling_device_unregister(pr->cdev);
err_power_exit:
return result;
}
static void acpi_pss_perf_exit(struct acpi_processor *pr,
struct acpi_device *device)
{
if (pr->cdev) {
sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
sysfs_remove_link(&pr->cdev->device.kobj, "device");
thermal_cooling_device_unregister(pr->cdev);
pr->cdev = NULL;
}
}
#else
static inline int acpi_pss_perf_init(struct acpi_processor *pr,
struct acpi_device *device)
{
return 0;
}
static inline void acpi_pss_perf_exit(struct acpi_processor *pr,
struct acpi_device *device) {}
#endif /* CONFIG_ACPI_CPU_FREQ_PSS */
static int __acpi_processor_start(struct acpi_device *device)
{
struct acpi_processor *pr = acpi_driver_data(device);
acpi_status status;
int result = 0;
if (!pr)
return -ENODEV;
if (pr->flags.need_hotplug_init)
return 0;
if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver)
acpi_processor_power_init(pr);
result = acpi_pss_perf_init(pr, device);
if (result)
goto err_power_exit;
status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
acpi_processor_notify, device);
if (ACPI_SUCCESS(status))
return 0;
err_power_exit:
acpi_processor_power_exit(pr); acpi_processor_power_exit(pr);
return result; return result;
} }
...@@ -252,15 +287,10 @@ static int acpi_processor_stop(struct device *dev) ...@@ -252,15 +287,10 @@ static int acpi_processor_stop(struct device *dev)
pr = acpi_driver_data(device); pr = acpi_driver_data(device);
if (!pr) if (!pr)
return 0; return 0;
acpi_processor_power_exit(pr); acpi_processor_power_exit(pr);
if (pr->cdev) { acpi_pss_perf_exit(pr, device);
sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
sysfs_remove_link(&pr->cdev->device.kobj, "device");
thermal_cooling_device_unregister(pr->cdev);
pr->cdev = NULL;
}
return 0; return 0;
} }
......
...@@ -318,6 +318,7 @@ int acpi_get_cpuid(acpi_handle, int type, u32 acpi_id); ...@@ -318,6 +318,7 @@ int acpi_get_cpuid(acpi_handle, int type, u32 acpi_id);
void acpi_processor_set_pdc(acpi_handle handle); void acpi_processor_set_pdc(acpi_handle handle);
/* in processor_throttling.c */ /* in processor_throttling.c */
#ifdef CONFIG_ACPI_CPU_FREQ_PSS
int acpi_processor_tstate_has_changed(struct acpi_processor *pr); int acpi_processor_tstate_has_changed(struct acpi_processor *pr);
int acpi_processor_get_throttling_info(struct acpi_processor *pr); int acpi_processor_get_throttling_info(struct acpi_processor *pr);
extern int acpi_processor_set_throttling(struct acpi_processor *pr, extern int acpi_processor_set_throttling(struct acpi_processor *pr,
...@@ -330,6 +331,29 @@ extern void acpi_processor_reevaluate_tstate(struct acpi_processor *pr, ...@@ -330,6 +331,29 @@ extern void acpi_processor_reevaluate_tstate(struct acpi_processor *pr,
unsigned long action); unsigned long action);
extern const struct file_operations acpi_processor_throttling_fops; extern const struct file_operations acpi_processor_throttling_fops;
extern void acpi_processor_throttling_init(void); extern void acpi_processor_throttling_init(void);
#else
static inline int acpi_processor_tstate_has_changed(struct acpi_processor *pr)
{
return 0;
}
static inline int acpi_processor_get_throttling_info(struct acpi_processor *pr)
{
return -ENODEV;
}
static inline int acpi_processor_set_throttling(struct acpi_processor *pr,
int state, bool force)
{
return -ENODEV;
}
static inline void acpi_processor_reevaluate_tstate(struct acpi_processor *pr,
unsigned long action) {}
static inline void acpi_processor_throttling_init(void) {}
#endif /* CONFIG_ACPI_CPU_FREQ_PSS */
/* in processor_idle.c */ /* in processor_idle.c */
int acpi_processor_power_init(struct acpi_processor *pr); int acpi_processor_power_init(struct acpi_processor *pr);
int acpi_processor_power_exit(struct acpi_processor *pr); int acpi_processor_power_exit(struct acpi_processor *pr);
...@@ -348,7 +372,7 @@ static inline void acpi_processor_syscore_exit(void) {} ...@@ -348,7 +372,7 @@ static inline void acpi_processor_syscore_exit(void) {}
/* in processor_thermal.c */ /* in processor_thermal.c */
int acpi_processor_get_limit_info(struct acpi_processor *pr); int acpi_processor_get_limit_info(struct acpi_processor *pr);
extern const struct thermal_cooling_device_ops processor_cooling_ops; extern const struct thermal_cooling_device_ops processor_cooling_ops;
#ifdef CONFIG_CPU_FREQ #if defined(CONFIG_ACPI_CPU_FREQ_PSS) & defined(CONFIG_CPU_FREQ)
void acpi_thermal_cpufreq_init(void); void acpi_thermal_cpufreq_init(void);
void acpi_thermal_cpufreq_exit(void); void acpi_thermal_cpufreq_exit(void);
#else #else
...@@ -360,6 +384,6 @@ static inline void acpi_thermal_cpufreq_exit(void) ...@@ -360,6 +384,6 @@ static inline void acpi_thermal_cpufreq_exit(void)
{ {
return; return;
} }
#endif #endif /* CONFIG_ACPI_CPU_FREQ_PSS */
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment