[PATCH 14/14] ACPI: Provide /sys/devices/system/cpu/cpuN/deconfigure - Kernel
This is a discussion on [PATCH 14/14] ACPI: Provide /sys/devices/system/cpu/cpuN/deconfigure - Kernel ; Provide a new sysfs interface for CPU deconfiguration.
Since no vendors can agree on terminology for related but slightly
different features, provide a method for a platform to implement
its own version of what it thinks 'deconfiguring' a CPU might ...
-
[PATCH 14/14] ACPI: Provide /sys/devices/system/cpu/cpuN/deconfigure
Provide a new sysfs interface for CPU deconfiguration.
Since no vendors can agree on terminology for related but slightly
different features, provide a method for a platform to implement
its own version of what it thinks 'deconfiguring' a CPU might be.
Provide an HP-specific CPU deconfiguration implementation.
Signed-off-by: Alex Chiang
Cc: Andi Kleen
---
drivers/acpi/Kconfig | 18 ++
drivers/acpi/Makefile | 4
drivers/acpi/processor_core.c | 8 +
drivers/acpi/processor_deconfigure.c | 275 ++++++++++++++++++++++++++++++++++
include/acpi/processor.h | 6 +
5 files changed, 311 insertions(+), 0 deletions(-)
create mode 100644 drivers/acpi/processor_deconfigure.c
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index c52fca8..36ad177 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -188,6 +188,24 @@ config ACPI_HOTPLUG_CPU
select ACPI_CONTAINER
default y
+config ACPI_DECONFIGURE_CPU
+ bool "Processor deconfiguration"
+ depends on ACPI_PROCESSOR
+ default n
+ help
+ This processor driver submodule allows a user to mark a CPU
+ for firmware disabling/enabling. It will create the following
+ sysfs file:
+
+ /sys/devices/system/cpu/cpuN/deconfigure
+
+ Behavior of this interface is highly vendor-dependent and
+ requires firmware support.
+
+ This option is NOT required for CPU hotplug support.
+
+ If unsure, say N.
+
config ACPI_THERMAL
tristate "Thermal Zone"
depends on ACPI_PROCESSOR
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 40b0fca..92a5037 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -35,6 +35,10 @@ ifdef CONFIG_CPU_FREQ
processor-objs += processor_perflib.o
endif
+ifdef CONFIG_ACPI_DECONFIGURE_CPU
+processor-objs += processor_deconfigure.o
+endif
+
obj-y += sleep/
obj-y += bus.o glue.o
obj-y += scan.o
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 9dd0fa9..ef582ca 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -1099,6 +1099,10 @@ static int __init acpi_processor_init(void)
acpi_processor_throttling_init();
+#ifdef CONFIG_ACPI_DECONFIGURE_CPU
+ acpi_processor_deconfigure_init();
+#endif
+
return 0;
out_cpuidle:
@@ -1112,6 +1116,10 @@ out_proc:
static void __exit acpi_processor_exit(void)
{
+
+#ifdef CONFIG_ACPI_DECONFIGURE_CPU
+ acpi_processor_deconfigure_exit();
+#endif
acpi_processor_ppc_exit();
acpi_thermal_cpufreq_exit();
diff --git a/drivers/acpi/processor_deconfigure.c b/drivers/acpi/processor_deconfigure.c
new file mode 100644
index 0000000..e656f97
--- /dev/null
+++ b/drivers/acpi/processor_deconfigure.c
@@ -0,0 +1,275 @@
+/*
+ * processor_deconfigure.c - CPU deconfiguration submodule of the
+ * ACPI processor driver
+ *
+ * (c) Copyright 2008 Hewlett-Packard Development Company, L.P.
+ * Alex Chiang
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ */
+
+#include
+#include
+#include
+
+static int supports_cpu_deconfigure;
+
+/*
+ * These function pointers must be overwritten by platforms supporting
+ * cpu deconfigure.
+ */
+static ssize_t (*show_deconfigure)(struct sys_device *, char *);
+static ssize_t (*store_deconfigure)(struct sys_device *, const char *, size_t);
+
+/*
+ * Under HP semantics, CPU deconfiguration is defined as removing a
+ * processor core or socket from operation at boot time, typically
+ * due to managability concerns, such as excessive detected errors.
+ *
+ * The HP semantics of 'deconfigure' are defined as:
+ *
+ * Mark CPU for deconfiguration at next boot.
+ * # echo 1 > /sys/devices/system/cpu/cpuN/deconfigure
+ *
+ * Mark CPU as enabled at next boot.
+ * # echo 0 > /sys/devices/system/cpu/cpuN/deconfigure
+ *
+ * Display next boot's deconfigure status
+ * 0x0 - not marked for deconfiguration
+ * 0x1 - scheduled deconfig at next boot
+ * 0x3 - scheduled, OS-requested deconfig at next boot
+ * 0x4 - thread disabled by firmware
+ * # cat /sys/devices/system/cpu/cpuN/deconfigure
+ *
+ * After echo'ing 0 or 1 into deconfigure, cat'ing the file will
+ * return the next boot's status. However, the CPU will not actually
+ * be deconfigured until the next boot.
+ *
+ * Attempting to configure or deconfigure a disabled thread is disallowed.
+ */
+struct hp_deconfigure_cb_args {
+ int cpu;
+ char *method;
+};
+
+static acpi_status hp_deconfigure_cb(acpi_handle handle,
+ u32 lvl,
+ void *context,
+ void **rv)
+{
+ int cpu;
+ acpi_status status;
+ acpi_integer scfg;
+ struct hp_deconfigure_cb_args *args = context;
+ union acpi_object object = { 0 };
+ struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
+
+ status = acpi_evaluate_object(handle, NULL, NULL, &buffer);
+ if (ACPI_FAILURE(status))
+ return AE_OK;
+
+ cpu = object.processor.proc_id;
+ if (cpu != args->cpu)
+ return AE_OK;
+
+ /*
+ * Always check SCFG. If this is what the user actually wanted,
+ * great, just return the answer. If the user wanted something
+ * else, check to see if they were trying to poke a disabled
+ * hardware thread and disallow it if so.
+ */
+ status = acpi_evaluate_object(handle, "SCFG", NULL, &buffer);
+ scfg = object.integer.value;
+ if (!strcmp(args->method, "SCFG"))
+ **(int **)rv = ACPI_SUCCESS(status) ? scfg : -1;
+ /*
+ * Disallow E/DCFG on disabled threads
+ */
+ else if (scfg == 0x4)
+ **(int **)rv = -1;
+ else {
+ status = acpi_evaluate_object(handle, args->method,
+ NULL, &buffer);
+ **(int **)rv = ACPI_SUCCESS(status) ? status : -1;
+ }
+
+ return AE_CTRL_TERMINATE;
+}
+
+/*
+ * We can do this the easy way or the hard way. The easy way is,
+ * if the CPU is online, we have easy access to its ACPI handle
+ * via its per_cpu() data area, and we can call SCFG directly.
+ *
+ * The hard way is when the CPU is not online, and does not have
+ * a valid per_cpu() data area. In that case, we have to walk the
+ * ACPI namespace, looking for the CPU and calling SCFG that way.
+ */
+static ssize_t hp_show_deconfigure(struct sys_device *dev, char *buf)
+{
+ int logical_cpu;
+ unsigned long cfg;
+ struct cpu *cpu = container_of(dev, struct cpu, sysdev);
+
+ logical_cpu = cpu->sysdev.id;
+
+ if (cpu_isset(logical_cpu, cpu_online_map)) {
+ unsigned long tmp;
+ acpi_status status;
+ struct acpi_processor *pr;
+
+ pr = processors[logical_cpu];
+ status = acpi_evaluate_integer(pr->handle, "SCFG", NULL, &tmp);
+ cfg = ACPI_SUCCESS(status) ? tmp : -1;
+ } else {
+ int ret;
+ void *ret_ptr = &ret;
+ struct hp_deconfigure_cb_args args;
+
+ args.cpu = logical_cpu;
+ args.method = "SCFG";
+ acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
+ ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX,
+ hp_deconfigure_cb,
+ &args,
+ (void *)&ret_ptr);
+ cfg = ret;
+ }
+
+ return sprintf(buf, "%#lx\n", cfg);
+}
+
+/*
+ * We can do this the easy way or the hard way. The easy way is,
+ * if the CPU is online, we have easy access to its ACPI handle
+ * via its per_cpu() data area, and we can call E/D-CFG directly.
+ *
+ * The hard way is when the CPU is not online, and does not have
+ * a valid per_cpu() data area. In that case, we have to walk the
+ * ACPI namespace, looking for the CPU and calling E/D-CFG that way.
+ */
+static ssize_t hp_store_deconfigure(struct sys_device *dev, const char *buf,
+ size_t count)
+{
+ ssize_t ret;
+ char *method;
+ int logical_cpu;
+ struct cpu *cpu = container_of(dev, struct cpu, sysdev);
+
+ logical_cpu = cpu->sysdev.id;
+ switch (buf[0]) {
+ case '0':
+ method = "ECFG";
+ break;
+ case '1':
+ method = "DCFG";
+ break;
+ default:
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (cpu_isset(logical_cpu, cpu_online_map)) {
+ struct acpi_processor *pr;
+ pr = processors[logical_cpu];
+ ret = acpi_evaluate_object(pr->handle, method, NULL, NULL);
+ } else {
+ int r;
+ void *ret_ptr = &r;
+ struct hp_deconfigure_cb_args args;
+
+ args.cpu = logical_cpu;
+ args.method = method;
+ acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
+ ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX,
+ hp_deconfigure_cb,
+ &args,
+ (void *)&ret_ptr);
+ ret = r;
+ }
+
+ if (ret == 0)
+ if (!strcmp(method, "ECFG"))
+ cpu_set(logical_cpu, cpu_enabled_map);
+ else
+ cpu_clear(logical_cpu, cpu_enabled_map);
+
+out:
+ if (ret >= 0)
+ ret = count;
+ return ret;
+}
+
+static int hp_check_cpu_deconfigure(const struct dmi_system_id *d)
+{
+ acpi_handle hnd;
+ struct acpi_processor *pr;
+
+ /*
+ * Operating assumption is that either all or none of the CPUs
+ * will support deconfiguration.
+ */
+ pr = processors[0];
+ if (ACPI_SUCCESS(acpi_get_handle(pr->handle, "SCFG", &hnd))) {
+ supports_cpu_deconfigure = 1;
+ show_deconfigure = hp_show_deconfigure;
+ store_deconfigure = hp_store_deconfigure;
+ }
+
+ return 0;
+}
+
+static struct dmi_system_id cpu_deconfigure_dmi_table[] __initdata = {
+ {
+ .callback = hp_check_cpu_deconfigure,
+ .ident = "Hewlett-Packard",
+ .matches = {
+ DMI_MATCH(DMI_BIOS_VENDOR, "HP"),
+ },
+ },
+ {
+ .callback = hp_check_cpu_deconfigure,
+ .ident = "Hewlett-Packard",
+ .matches = {
+ DMI_MATCH(DMI_BIOS_VENDOR, "Hewlett-Packard"),
+ },
+ },
+ {}
+};
+
+static SYSDEV_ATTR(deconfigure, 0644, NULL, NULL);
+
+void __init acpi_processor_deconfigure_init(void)
+{
+ int i;
+ struct sys_device *sysdev;
+
+ dmi_check_system(cpu_deconfigure_dmi_table);
+
+ if (supports_cpu_deconfigure) {
+ attr_deconfigure.show = show_deconfigure;
+ attr_deconfigure.store = store_deconfigure;
+
+ for_each_present_cpu(i) {
+ sysdev = get_cpu_sysdev(i);
+ sysdev_create_file(sysdev, &attr_deconfigure);
+ }
+ }
+}
+
+void acpi_processor_deconfigure_exit(void)
+{
+ int i;
+ struct sys_device *sysdev;
+
+ if (supports_cpu_deconfigure) {
+ for_each_present_cpu(i) {
+ sysdev = get_cpu_sysdev(i);
+ sysdev_remove_file(sysdev, &attr_deconfigure);
+ }
+ }
+}
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 06ebb6e..071fd42 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -289,6 +289,12 @@ static inline void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx
}
#endif
+#ifdef CONFIG_ACPI_DECONFIGURE_CPU
+/* in processor_deconfigure.c */
+void __init acpi_processor_deconfigure_init(void);
+void acpi_processor_deconfigure_exit(void);
+#endif
+
/* in processor_perflib.c */
#ifdef CONFIG_CPU_FREQ
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
-
Re: [PATCH 14/14] ACPI: Provide /sys/devices/system/cpu/cpuN/deconfigure
Alex Chiang wrote:
> Provide a new sysfs interface for CPU deconfiguration.
>
> Since no vendors can agree on terminology for related but slightly
> different features, provide a method for a platform to implement
> its own version of what it thinks 'deconfiguring' a CPU might be.
>
> Provide an HP-specific CPU deconfiguration implementation.
Why are you ccing this to linux-arch? Dropped.
What is the standard status of these new SCFG and ECFG tables? Have they
been submitted for possible inclusion in ACPI? And is there a spec
available? I can't say I'm really thrilled with having HP specific
support in there.
It would be better at least if you could reserve the table names and
then drop the HP DMI check. This is needed anyways, otherwise the
standard at some point could add different ECFG/SCFG tables.
> + * After echo'ing 0 or 1 into deconfigure, cat'ing the file will
> + * return the next boot's status. However, the CPU will not actually
> + * be deconfigured until the next boot.
Now that seems like weird semantics for a public fixed API. What happens
when some other vendor adds hot deconfiguration?
My feeling is that this seems to be overly specific to your BIOS
and might better belong into some separate management tool. At least
until we can define a nice general API for this with clear semantics.
For what systems is this anyways?
-Andi
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
-
Re: [PATCH 14/14] ACPI: Provide /sys/devices/system/cpu/cpuN/deconfigure
* Andi Kleen :
> Alex Chiang wrote:
>> Provide a new sysfs interface for CPU deconfiguration.
>>
>> Since no vendors can agree on terminology for related but slightly
>> different features, provide a method for a platform to implement
>> its own version of what it thinks 'deconfiguring' a CPU might be.
>>
>> Provide an HP-specific CPU deconfiguration implementation.
>
> Why are you ccing this to linux-arch? Dropped.
Hm, sorry.
I thought it would have been weird to send patches 1-13 / 14 to
linux-arch, but not send 14 / 14. Perhaps I should set a Reply-to:
in the future?
> What is the standard status of these new SCFG and ECFG tables?
> Have they been submitted for possible inclusion in ACPI? And is
> there a spec available? I can't say I'm really thrilled with
> having HP specific support in there.
>
> It would be better at least if you could reserve the table
> names and then drop the HP DMI check. This is needed anyways,
> otherwise the standard at some point could add different
> ECFG/SCFG tables.
These are not new tables -- they are methods that live underneath
processor objects in the namespace.
Yes, they are specific to HP, but because they are methods, there
shouldn't be any collision with other vendors defining methods
with the same name (with the DMI check).
>> + * After echo'ing 0 or 1 into deconfigure, cat'ing the file will
>> + * return the next boot's status. However, the CPU will not actually
>> + * be deconfigured until the next boot.
>
> Now that seems like weird semantics for a public fixed API.
> What happens when some other vendor adds hot deconfiguration?
Yeah, I'm not totally happy with it either. But I'd like to
clarify -- are you concerned with the name of the interface
(deconfigure) or the "nothing happens until next boot" behavior?
Would it help if I renamed it to "enabled" and had something
like:
echo 0 > enabled
echo 1 > enabled
cat enabled
And then that would map to vendor-specific behavior?
Or is it really the "nothing happens until next boot" thing that
bothers you?
> My feeling is that this seems to be overly specific to your
> BIOS and might better belong into some separate management
> tool. At least until we can define a nice general API for this
> with clear semantics.
Well, life would be a lot easier if we had a generic way to poke
at ACPI methods, but dev_acpi has been rejected multiple times.

On a more serious note, my fear is that an interface like this is
not going to have agreement / clear semantics for a long time
because one vendor is going to want to call it 'deconfigured' and
another one might want to call it 'disabled' and a third might
want to call it 'puppy_dogs' and they'll all be kinda related but
not exactly the same.
That's why I was going down the road of creating at least one
generic interface, but with vendor-specific semantics.
Calling it 'enabled' might be a better idea.
> For what systems is this anyways?
We have HP ia64 systems shipping today that support this.
Thanks.
/ac
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/