linux-arch.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Alex Chiang <achiang@hp.com>
To: linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org
Cc: linux-acpi@vger.kernel.org, Alex Chiang <achiang@hp.com>,
	Andi Kleen <ak@linux.intel.com>
Subject: [PATCH 14/14] ACPI: Provide /sys/devices/system/cpu/cpuN/deconfigure
Date: Mon, 14 Jul 2008 20:34:56 -0600	[thread overview]
Message-ID: <20080715023455.2528.16193.stgit@blender.achiang> (raw)
In-Reply-To: <20080715023344.2528.1836.stgit@blender.achiang>

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 <achiang@hp.com>
Cc: Andi Kleen <ak@linux.intel.com>
---

 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 <achiang@hp.com>
+ *
+ * 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 <acpi/acpi.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/processor.h>
+
+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

  parent reply	other threads:[~2008-07-15  2:34 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-07-15  2:33 [PATCH 00/14] Introduce cpu_enabled_map and friends Alex Chiang
2008-07-15  2:33 ` Alex Chiang
2008-07-15  2:33 ` [PATCH 01/14] " Alex Chiang
2008-07-15  3:15   ` Matthew Wilcox
2008-07-15 10:03     ` Andi Kleen
2008-07-15 10:03       ` Andi Kleen
2008-07-15 10:21       ` Russell King
2008-07-15 17:57         ` Alex Chiang
2008-07-15 17:57           ` Alex Chiang
2008-07-15 18:16           ` Matthew Wilcox
2008-07-15 18:16             ` Matthew Wilcox
2008-07-15 18:48             ` Russell King
2008-07-15 19:15               ` Alex Chiang
2008-07-18 21:44                 ` Russell King
2008-07-18 23:08                   ` Alex Chiang
2008-07-18 23:08                     ` Alex Chiang
2008-07-16  1:11               ` Alex Chiang
2008-07-16  1:11                 ` Alex Chiang
2008-07-15  2:33 ` [PATCH 02/14] [M32R] Populate cpu_enabled_map Alex Chiang
2008-07-15  2:33   ` Alex Chiang
2008-07-15  2:33 ` [PATCH 03/14] [ALPHA] " Alex Chiang
2008-07-15  2:33   ` Alex Chiang
2008-07-15  2:34 ` [PATCH 04/14] [ARM] " Alex Chiang
2008-07-15  2:34   ` Alex Chiang
2008-07-15  2:34 ` [PATCH 05/14] [MIPS] " Alex Chiang
2008-07-15  2:34 ` [PATCH 06/14] [PARISC] " Alex Chiang
2008-07-15  2:34 ` [PATCH 07/14] [POWERPC] " Alex Chiang
2008-07-15  5:51   ` Benjamin Herrenschmidt
2008-07-16  1:04     ` Alex Chiang
2008-07-15  2:34 ` [PATCH 08/14] [S390] " Alex Chiang
2008-07-15  2:34   ` Alex Chiang
2008-07-15  2:34 ` [PATCH 09/14] [SH] " Alex Chiang
2008-07-15  2:34   ` Alex Chiang
2008-07-15  2:34 ` [PATCH 12/14] [IA64] Populate and use cpu_enabled_map Alex Chiang
2008-07-15  2:34 ` [PATCH 13/14] [IA64] Avoid overflowing ia64_cpu_to_sapicid in acpi_map_lsapic() Alex Chiang
2008-07-15  2:34   ` Alex Chiang
2008-07-15  2:34 ` Alex Chiang [this message]
2008-07-15  2:56 ` [PATCH 11/14] x86: Populate cpu_enabled_map Alex Chiang
2008-07-18 20:00   ` H. Peter Anvin
2008-07-18 20:00     ` H. Peter Anvin
2008-07-18 23:06     ` Alex Chiang
2008-07-15 20:10 ` [PATCH 00/14] Introduce cpu_enabled_map and friends Luck, Tony
2008-07-15 20:10   ` Luck, Tony
2008-07-15 23:54   ` Alex Chiang
2008-07-15 23:54     ` Alex Chiang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080715023455.2528.16193.stgit@blender.achiang \
    --to=achiang@hp.com \
    --cc=ak@linux.intel.com \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).