# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1209635587 -3600
# Node ID e97855b90cc280e75c583cc6ac78d924f8cf16b8
# Parent 3c564f80f2ef2b458f9a81598c0928acb72cc891
Notify xen about Cx acpi info, such as table returned by _CST/_CSD methods.
Add notifiers for P/T & hotplug as placeholders.
Add option "xen_processor_pmbits" for enable/disable control.
Signed-off-by: Tian Kevin <kevin.tian@xxxxxxxxx>
Signed-off-by: Wei Gang <gang.wei@xxxxxxxxx>
---
arch/i386/kernel/acpi/Makefile | 1
arch/i386/kernel/acpi/processor_extcntl_xen.c | 142 ++++++++++++++++++++++++++
arch/x86_64/kernel/acpi/Makefile | 2
drivers/acpi/Kconfig | 1
drivers/acpi/processor_extcntl.c | 26 ++++
drivers/acpi/processor_idle.c | 22 +++-
include/acpi/processor.h | 17 +++
include/xen/interface/platform.h | 73 +++++++++++++
8 files changed, 279 insertions(+), 5 deletions(-)
diff -r 3c564f80f2ef -r e97855b90cc2 arch/i386/kernel/acpi/Makefile
--- a/arch/i386/kernel/acpi/Makefile Thu May 01 10:52:31 2008 +0100
+++ b/arch/i386/kernel/acpi/Makefile Thu May 01 10:53:07 2008 +0100
@@ -1,6 +1,7 @@ obj-$(CONFIG_ACPI) += boot.o
obj-$(CONFIG_ACPI) += boot.o
obj-$(CONFIG_X86_IO_APIC) += earlyquirk.o
obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o
+obj-$(CONFIG_XEN) += processor_extcntl_xen.o
ifneq ($(CONFIG_ACPI_PROCESSOR),)
obj-y += cstate.o processor.o
diff -r 3c564f80f2ef -r e97855b90cc2
arch/i386/kernel/acpi/processor_extcntl_xen.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/arch/i386/kernel/acpi/processor_extcntl_xen.c Thu May 01 10:53:07
2008 +0100
@@ -0,0 +1,142 @@
+/*
+ * processor_extcntl_xen.c - interface to notify Xen
+ *
+ * Copyright (C) 2008, Intel corporation
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/acpi.h>
+#include <linux/pm.h>
+#include <linux/cpu.h>
+
+#include <acpi/processor.h>
+#include <asm/hypercall.h>
+
+static int xen_processor_pmbits;
+static int __init set_xen_processor_pmbits(char *str)
+{
+ get_option(&str, &xen_processor_pmbits);
+
+ return 1;
+}
+__setup("xen_processor_pmbits=", set_xen_processor_pmbits);
+EXPORT_SYMBOL(xen_processor_pmbits);
+
+static int xen_cx_notifier(struct acpi_processor *pr, int action)
+{
+ int ret, count = 0, i;
+ xen_platform_op_t op = {
+ .cmd = XENPF_set_processor_pminfo,
+ .interface_version = XENPF_INTERFACE_VERSION,
+ .u.set_pminfo.id = pr->acpi_id,
+ .u.set_pminfo.type = XEN_PM_CX,
+ };
+ struct xen_processor_cx *data, *buf;
+ struct acpi_processor_cx *cx;
+
+ if (action == PROCESSOR_PM_CHANGE)
+ return -EINVAL;
+
+ /* Convert to Xen defined structure and hypercall */
+ buf = kzalloc(pr->power.count * sizeof(struct xen_processor_cx),
+ GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ data = buf;
+ for (i = 1; i <= pr->power.count; i++) {
+ cx = &pr->power.states[i];
+ /* Skip invalid cstate entry */
+ if (!cx->valid)
+ continue;
+
+ data->type = cx->type;
+ data->latency = cx->latency;
+ data->power = cx->power;
+ data->reg.space_id = cx->reg.space_id;
+ data->reg.bit_width = cx->reg.bit_width;
+ data->reg.bit_offset = cx->reg.bit_offset;
+ data->reg.access_size = cx->reg.reserved;
+ data->reg.address = cx->reg.address;
+
+ /* Get dependency relationships */
+ if (cx->csd_count) {
+ printk("Wow! _CSD is found. Not support for now!\n");
+ kfree(buf);
+ return -EINVAL;
+ } else {
+ data->dpcnt = 0;
+ set_xen_guest_handle(data->dp, NULL);
+ }
+
+ data++;
+ count++;
+ }
+
+ if (!count) {
+ printk("No available Cx info for cpu %d\n", pr->acpi_id);
+ kfree(buf);
+ return -EINVAL;
+ }
+
+ op.u.set_pminfo.power.count = count;
+ op.u.set_pminfo.power.flags.bm_control = pr->flags.bm_control;
+ op.u.set_pminfo.power.flags.bm_check = pr->flags.bm_check;
+ op.u.set_pminfo.power.flags.has_cst = pr->flags.has_cst;
+ op.u.set_pminfo.power.flags.power_setup_done =
pr->flags.power_setup_done;
+
+ set_xen_guest_handle(op.u.set_pminfo.power.states, buf);
+ ret = HYPERVISOR_platform_op(&op);
+ kfree(buf);
+ return ret;
+}
+
+static int xen_px_notifier(struct acpi_processor *pr, int action)
+{
+ return -EINVAL;
+}
+
+static int xen_tx_notifier(struct acpi_processor *pr, int action)
+{
+ return -EINVAL;
+}
+static int xen_hotplug_notifier(struct acpi_processor *pr, int event)
+{
+ return -EINVAL;
+}
+
+static struct processor_extcntl_ops xen_extcntl_ops = {
+ .hotplug = xen_hotplug_notifier,
+};
+
+static int __cpuinit xen_init_processor_extcntl(void)
+{
+ if (xen_processor_pmbits & XEN_PROCESSOR_PM_CX)
+ xen_extcntl_ops.pm_ops[PM_TYPE_IDLE] = xen_cx_notifier;
+ if (xen_processor_pmbits & XEN_PROCESSOR_PM_PX)
+ xen_extcntl_ops.pm_ops[PM_TYPE_PERF] = xen_px_notifier;
+ if (xen_processor_pmbits & XEN_PROCESSOR_PM_TX)
+ xen_extcntl_ops.pm_ops[PM_TYPE_THR] = xen_tx_notifier;
+
+ return processor_register_extcntl(&xen_extcntl_ops);
+}
+core_initcall(xen_init_processor_extcntl);
diff -r 3c564f80f2ef -r e97855b90cc2 arch/x86_64/kernel/acpi/Makefile
--- a/arch/x86_64/kernel/acpi/Makefile Thu May 01 10:52:31 2008 +0100
+++ b/arch/x86_64/kernel/acpi/Makefile Thu May 01 10:53:07 2008 +0100
@@ -8,4 +8,6 @@ processor-$(CONFIG_XEN) := ../../../i386
processor-$(CONFIG_XEN) := ../../../i386/kernel/acpi/processor.o
endif
+obj-$(CONFIG_XEN) += processor_extcnt_xen.o
+processor_extcnt_xen-$(CONFIG_XEN) :=
../../../i386/kernel/acpi/processor_extcntl_xen.o
disabled-obj-$(CONFIG_XEN) := wakeup.o
diff -r 3c564f80f2ef -r e97855b90cc2 drivers/acpi/Kconfig
--- a/drivers/acpi/Kconfig Thu May 01 10:52:31 2008 +0100
+++ b/drivers/acpi/Kconfig Thu May 01 10:53:07 2008 +0100
@@ -371,6 +371,7 @@ config PROCESSOR_EXTERNAL_CONTROL
config PROCESSOR_EXTERNAL_CONTROL
bool
depends on X86 && XEN
+ select ACPI_PROCESSOR
default y
endif # ACPI
diff -r 3c564f80f2ef -r e97855b90cc2 drivers/acpi/processor_extcntl.c
--- a/drivers/acpi/processor_extcntl.c Thu May 01 10:52:31 2008 +0100
+++ b/drivers/acpi/processor_extcntl.c Thu May 01 10:53:07 2008 +0100
@@ -30,6 +30,7 @@
#include <acpi/processor.h>
+static int processor_extcntl_parse_csd(struct acpi_processor *pr);
/*
* External processor control logic may register with its own set of
* ops to get ACPI related notification. One example is like VMM.
@@ -107,5 +108,30 @@ int processor_unregister_extcntl(struct
*/
int processor_extcntl_init(struct acpi_processor *pr)
{
+ /* parse cstate dependency information */
+ processor_extcntl_parse_csd(pr);
+
return 0;
}
+
+/*
+ * Currently no _CSD is implemented which is why existing ACPI code
+ * doesn't parse _CSD at all. But to keep interface complete with
+ * external control logic, we put a placeholder here for future
+ * compatibility.
+ */
+static int processor_extcntl_parse_csd(struct acpi_processor *pr)
+{
+ int i;
+
+ for (i = 0; i < pr->power.count; i++) {
+ if (!pr->power.states[i].valid)
+ continue;
+
+ /* No dependency by default */
+ pr->power.states[i].domain_info = NULL;
+ pr->power.states[i].csd_count = 0;
+ }
+
+ return 0;
+}
diff -r 3c564f80f2ef -r e97855b90cc2 drivers/acpi/processor_idle.c
--- a/drivers/acpi/processor_idle.c Thu May 01 10:52:31 2008 +0100
+++ b/drivers/acpi/processor_idle.c Thu May 01 10:53:07 2008 +0100
@@ -714,8 +714,12 @@ static int acpi_processor_get_power_info
(reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE))
continue;
- cx.address = (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) ?
- 0 : reg->address;
+ if (!processor_pm_external())
+ cx.address = (reg->space_id ==
+ ACPI_ADR_SPACE_FIXED_HARDWARE) ?
+ 0 : reg->address;
+ else
+ cx.address = reg->address;
/* There should be an easy way to extract an integer... */
obj = (union acpi_object *)&(element->package.elements[1]);
@@ -724,9 +728,11 @@ static int acpi_processor_get_power_info
cx.type = obj->integer.value;
- if ((cx.type != ACPI_STATE_C1) &&
- (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO))
- continue;
+ /* Following check doesn't apply to external control case */
+ if (!processor_pm_external())
+ if ((cx.type != ACPI_STATE_C1) &&
+ (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO))
+ continue;
if ((cx.type < ACPI_STATE_C2) || (cx.type > ACPI_STATE_C3))
continue;
@@ -742,6 +748,12 @@ static int acpi_processor_get_power_info
continue;
cx.power = obj->integer.value;
+
+#ifdef CONFIG_PROCESSOR_EXTERNAL_CONTROL
+ /* cache control methods to notify external logic */
+ if (processor_pm_external())
+ memcpy(&cx.reg, reg, sizeof(*reg));
+#endif
current_count++;
memcpy(&(pr->power.states[current_count]), &cx, sizeof(cx));
diff -r 3c564f80f2ef -r e97855b90cc2 include/acpi/processor.h
--- a/include/acpi/processor.h Thu May 01 10:52:31 2008 +0100
+++ b/include/acpi/processor.h Thu May 01 10:53:07 2008 +0100
@@ -32,6 +32,17 @@
/* Power Management */
struct acpi_processor_cx;
+
+#ifdef CONFIG_PROCESSOR_EXTERNAL_CONTROL
+struct acpi_csd_package {
+ acpi_integer num_entries;
+ acpi_integer revision;
+ acpi_integer domain;
+ acpi_integer coord_type;
+ acpi_integer num_processors;
+ acpi_integer index;
+} __attribute__ ((packed));
+#endif
struct acpi_power_register {
u8 descriptor;
@@ -63,6 +74,12 @@ struct acpi_processor_cx {
u32 power;
u32 usage;
u64 time;
+#ifdef CONFIG_PROCESSOR_EXTERNAL_CONTROL
+ /* Require raw information for external control logic */
+ struct acpi_power_register reg;
+ u32 csd_count;
+ struct acpi_csd_package *domain_info;
+#endif
struct acpi_processor_cx_policy promotion;
struct acpi_processor_cx_policy demotion;
};
diff -r 3c564f80f2ef -r e97855b90cc2 include/xen/interface/platform.h
--- a/include/xen/interface/platform.h Thu May 01 10:52:31 2008 +0100
+++ b/include/xen/interface/platform.h Thu May 01 10:53:07 2008 +0100
@@ -199,6 +199,78 @@ typedef struct xenpf_getidletime xenpf_g
typedef struct xenpf_getidletime xenpf_getidletime_t;
DEFINE_XEN_GUEST_HANDLE(xenpf_getidletime_t);
+#define XENPF_set_processor_pminfo 54
+
+/* ability bits */
+#define XEN_PROCESSOR_PM_CX 1
+#define XEN_PROCESSOR_PM_PX 2
+#define XEN_PROCESSOR_PM_TX 4
+
+/* cmd type */
+#define XEN_PM_CX 0
+#define XEN_PM_PX 1
+#define XEN_PM_TX 2
+
+struct xen_power_register {
+ uint32_t space_id;
+ uint32_t bit_width;
+ uint32_t bit_offset;
+ uint32_t access_size;
+ uint64_t address;
+};
+
+struct xen_processor_csd {
+ uint32_t domain; /* domain number of one dependent group */
+ uint32_t coord_type; /* coordination type */
+ uint32_t num; /* number of processors in same domain */
+};
+typedef struct xen_processor_csd xen_processor_csd_t;
+DEFINE_XEN_GUEST_HANDLE(xen_processor_csd_t);
+
+struct xen_processor_cx {
+ struct xen_power_register reg; /* GAS for Cx trigger register */
+ uint8_t type; /* cstate value, c0: 0, c1: 1, ... */
+ uint32_t latency; /* worst latency (ms) to enter/exit this cstate */
+ uint32_t power; /* average power consumption(mW) */
+ uint32_t dpcnt; /* number of dependency entries */
+ XEN_GUEST_HANDLE(xen_processor_csd_t) dp; /* NULL if no dependency */
+};
+typedef struct xen_processor_cx xen_processor_cx_t;
+DEFINE_XEN_GUEST_HANDLE(xen_processor_cx_t);
+
+struct xen_processor_flags {
+ uint8_t bm_control:1;
+ uint8_t bm_check:1;
+ uint8_t has_cst:1;
+ uint8_t power_setup_done:1;
+ uint8_t bm_rld_set:1;
+};
+
+struct xen_processor_power {
+ uint32_t count; /* number of C state entries in array below */
+ struct xen_processor_flags flags; /* global flags of this processor */
+ XEN_GUEST_HANDLE(xen_processor_cx_t) states; /* supported c states */
+};
+
+struct xen_processor_performance {
+};
+
+struct xen_processor_throttling {
+};
+
+struct xenpf_set_processor_pminfo {
+ /* IN variables */
+ uint32_t id; /* ACPI CPU ID */
+ uint32_t type; /* {XEN_PM_CX, XEN_PM_PX, XEN_PM_TX} */
+ union {
+ struct xen_processor_power power;/* Cx: _CST/_CSD */
+ struct xen_processor_performance perf; /* Px: _PPC/_PCT/_PSS/_PSD */
+ struct xen_processor_throttling throt;/* Tx: _TPC/_PTC/_TSS/_TSD */
+ };
+};
+typedef struct xenpf_set_processor_pminfo xenpf_set_processor_pminfo_t;
+DEFINE_XEN_GUEST_HANDLE(xenpf_set_processor_pminfo_t);
+
struct xen_platform_op {
uint32_t cmd;
uint32_t interface_version; /* XENPF_INTERFACE_VERSION */
@@ -213,6 +285,7 @@ struct xen_platform_op {
struct xenpf_enter_acpi_sleep enter_acpi_sleep;
struct xenpf_change_freq change_freq;
struct xenpf_getidletime getidletime;
+ struct xenpf_set_processor_pminfo set_pminfo;
uint8_t pad[128];
} u;
};
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|