lkml.org 
[lkml]   [2008]   [Jul]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 14/14] ACPI: Provide /sys/devices/system/cpu/cpuN/deconfigure
    Date
    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


    \
     
     \ /
      Last update: 2008-07-15 04:43    [W:0.038 / U:97.236 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site