diff mbox

[Xen-devel,pvops_dom0,2/4] Introduce the external control operation interface for domain0 ACPI parser

Message ID 4D05DB80B95B23498C72C700BD6C2E0B315D671A@pdsmsx502.ccr.corp.intel.com (mailing list archive)
State RFC, archived
Headers show

Commit Message

Yu, Ke July 29, 2009, 2:47 p.m. UTC
>I'd like the patch better if you
>
>s/extcntl/xen/ to make it clear why this code exists --
>or is there an expected "external control" other than Xen?
>
>-Len

This attached is the revised patch per your suggestion, which move all the external control logic to xen specific file, thus reduce the modification to acpi subsystem to only several places.

== PATCH ==

Leverage domain0 ACPI parser for xen

From: Yu Ke <ke.yu@intel.com>

This patch reuse dom0 ACPI parser to get C/P state for Xen

Comments

Len Brown July 30, 2009, 4:29 p.m. UTC | #1
Unclear that the power management partitioning between xen hypervisor
and dom0 is fully baked.

Uncear (to me) what xen is doing internally with these power management 
objects, and how that differs from what Linux would do.

While patches to the Linux kernel may be a good RFE, prototype, or base
for discussion, the unknowns above need to be addressed to before it
makes much sense to spent a large amount of time on the source.

some things did jump out of the patch, however...

I do not recommend believing _PSD.
Our experience is that 50% of the time it is crap.

Why does xen_processor_px exists when it is the same as acpi_processor_px?
ditto for acpi_processor_cx and xen_processor_cx

Lose the ifdefs.
Lose the tests for xen on the inline code when
they can be inside the called routines.

This doesn't look like an abstraction layer,
it looks more like a simple conduit.
The thing at the other end (xen) will need to know
just as much about these data structures as the
thing that sent them (linux)

the patch doesn't apply to the upstream kernel --
even the ACPI specific parts.

checkpatch.pl:
total: 168 errors, 42 warnings, 643 lines checked

Don't send me another patch that can't pass checkpatch.pl,
even if just an RFC.

thanks,
Len Brown, Intel Open Source Technology Center

--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jeremy Fitzhardinge July 30, 2009, 10:04 p.m. UTC | #2
On 07/30/09 09:29, Len Brown wrote:
> Unclear that the power management partitioning between xen hypervisor
> and dom0 is fully baked.
>
> Uncear (to me) what xen is doing internally with these power management 
> objects, and how that differs from what Linux would do.
>   

Yes.  The key thing is that Xen is the only entity which really knows
about physical CPUs and how they're being used, and so is the only thing
which can correctly apply the chosen policy.  If any particular guest
domain did it, it would only take into account that particular domain's
CPU use, and ignore everyone else (or have the extra complexity of
extracting system-wide usage from Xen then applying that to its own policy).

If I understand correctly, the code currently relies on Linux running
the _PSD method with its AML interpreter, and then feeding the results
to Xen as it doesn't have an AML interpreter.  And putting AML into Xen
would be an all-or-nothing proposition, because the entity which runs
AML maintains a lot of state which can't be separated between Xen and
Linux, and can't be shared.

    J
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Yu, Ke July 31, 2009, 8:05 a.m. UTC | #3
>-----Original Message-----
>From: Len Brown [mailto:lenb@kernel.org]
>Sent: Friday, July 31, 2009 12:29 AM
>To: Yu, Ke
>Cc: linux-acpi@vger.kernel.org; Jeremy Fitzhardinge; Tian, Kevin
>Subject: RE: [Xen-devel] [PATCH][pvops_dom0][2/4] Introduce the external
>control operation interface for domain0 ACPI parser
>
>Unclear that the power management partitioning between xen hypervisor
>and dom0 is fully baked.
>
>Uncear (to me) what xen is doing internally with these power management
>objects, and how that differs from what Linux would do.
>
>While patches to the Linux kernel may be a good RFE, prototype, or base
>for discussion, the unknowns above need to be addressed to before it
>makes much sense to spent a large amount of time on the source.

Oh yes, I would like to add the background. In xen architecture, only hypervisor can control the physical CPU, so all the physical CPU Cx/Px power management is done in hypervisor side. And the cpuidle/cpufreq driver in dom0 is disabled. the Xen PM algorithm is ported from linux side, so it is similar as linux. For cpuidle part, when idle vcpu is scheduled (similar as idle process in linux), it will invoke cpuidle routine. cpuidle routine firstly decide which C state to go by calling cpuidle governor (e.g. menu governor), then cpuidle routine will enter C state using the ACPI method (e.g. I/O port, mwait described in _CST).
For cpufreq part, cpufreq driver will register the governor (e.g. ondemand) and cpu driver (cpufreq-acpi driver). once the cpufreq start on certain CPU, the governor will change the frequency by calling the corresponding cpu driver. http://wiki.xensource.com/xenwiki/xenpm has one picture on the cpufreq architecture.

All the necessary ACPI information in the above process is parsed by dom0 and pass to hypervisor.

>
>some things did jump out of the patch, however...
>
>I do not recommend believing _PSD.
>Our experience is that 50% of the time it is crap.

That is true, we also meet crap _PSD in especially the new platform. We will add more check on the _PSD data.

>
>Why does xen_processor_px exists when it is the same as acpi_processor_px?
>ditto for acpi_processor_cx and xen_processor_cx

xen_processor_px is part of the hypercall interface, and mainly used in hypervisor. since hypervisor has no acpi_processor_px as kernel has, so we have to add the same data structure for information passing purpose. similar for xen_processor_cx.

>
>Lose the ifdefs

Can you elaborate which part lose the ifdef? for the drivers/xen/processor_extcntl.c, since it has "obj-$(CONFIG_ACPI_PROCESSOR_XEN) += processor_extcntl.o" in Makefile, it implies #ifdef CONFIG_ACPI_PROCESSOR_XEN. 

>Lose the tests for xen on the inline code when
>they can be inside the called routines.

Can you elaborate which part? 

>
>This doesn't look like an abstraction layer,
>it looks more like a simple conduit.
>The thing at the other end (xen) will need to know
>just as much about these data structures as the
>thing that sent them (linux)

The reason is that xen and linux use the similar power management algorithm, so the data structure xen need is also similar as Linux side. This actually make life easier, in that we don't need to invent an abstraction layer here to handle the difference, since there is actually no difference.

>
>the patch doesn't apply to the upstream kernel --
>even the ACPI specific parts.

That is strange. I can successfully apply the ACPI specific parts to the upstream (linus 2.6 tree, parent commit b592972). 
For the xen part, it is based on Jeremy's git tree (git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen.git) rebase/master branch, so it cannot be cleanly applied to upstream.

>
>checkpatch.pl:
>total: 168 errors, 42 warnings, 643 lines checked
>
>Don't send me another patch that can't pass checkpatch.pl,
>even if just an RFC.

Sorry for that. I have fix the code style issue and the attached updated version can pass the checkpatch.pl

BTW, thanks for your comments.

Best Regards
Ke
diff mbox

Patch

=== Overview ===

Requirement: Xen hypervisor need Cx/Px ACPI info to do the Cx/Px states
power management. This info is provided by BIOS ACPI table. Since
hypervisor has no ACPI parser, this info has to be parsed by domain0
kernel ACPI sub-system, and then passed to hypervisor by hypercall.

To make this happen, the key point is to add hook in the kernel ACPI
sub-system. Fortunately, kernel already has good abstraction, and
only several places need to add hook. To be more detail, there is an
acpi_processor_driver (in drivers/acpi/processor_core.c) , which all the
Cx/Px parsing event will go to. This driver will call its acpi processor
event handler, e.g. add/remove, start/stop, notify to handle these
events. These event handlers in turn will call some library functions (in
drivers/acpi/processor_perflib.c), e.g. acpi_processor_ppc_has_changed,
acpi_processor_ppc_has_changed, acpi_processor_cst_has_changed, to finish
the acpi info parsing.

So this patch add the xen hook in these places to notify xen for the parsed
Cx/Px state information.

Signed-off-by: Yu Ke <ke.yu@intel.com>
Signed-off-by: Tian Kevin <kevin.tian@intel.com>
---

 drivers/acpi/processor_core.c    |   17 ++
 drivers/acpi/processor_idle.c    |   25 ++
 drivers/acpi/processor_perflib.c |   10 +
 drivers/xen/Kconfig              |    7 +
 drivers/xen/Makefile             |    3
 drivers/xen/processor_extcntl.c  |  413 ++++++++++++++++++++++++++++++++++++++
 include/acpi/processor.h         |    6 +
 include/xen/acpi.h               |   55 +++++
 8 files changed, 528 insertions(+), 8 deletions(-)
 create mode 100644 drivers/xen/processor_extcntl.c


diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 84e0f3c..2707d65 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -58,6 +58,7 @@ 
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 #include <acpi/processor.h>
+#include <xen/acpi.h>

 #define ACPI_PROCESSOR_CLASS           "processor"
 #define ACPI_PROCESSOR_DEVICE_NAME     "Processor"
@@ -751,6 +752,10 @@  static int __cpuinit acpi_processor_start(struct acpi_device *device)

        acpi_processor_power_init(pr, device);

+       result = processor_cntl_xen_prepare(pr);
+       if (result)
+               goto end;
+
        pr->cdev = thermal_cooling_device_register("Processor", device,
                                                &processor_cooling_ops);
        if (IS_ERR(pr->cdev)) {
@@ -963,6 +968,10 @@  int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
        if (!pr)
                return -ENODEV;

+       if (processor_cntl_xen())
+               processor_cntl_xen_notify(pr,
+                       PROCESSOR_HOTPLUG, HOTPLUG_TYPE_ADD);
+
        if ((pr->id >= 0) && (pr->id < nr_cpu_ids)) {
                kobject_uevent(&(*device)->dev.kobj, KOBJ_ONLINE);
        }
@@ -1002,11 +1011,19 @@  static void __ref acpi_processor_hotplug_notify(acpi_handle handle,
                        break;
                }

+               if (processor_cntl_xen())
+                       processor_cntl_xen_notify(pr,
+                                       PROCESSOR_HOTPLUG, HOTPLUG_TYPE_ADD);
+
                if (pr->id >= 0 && (pr->id < nr_cpu_ids)) {
                        kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
                        break;
                }

+               if (processor_cntl_xen())
+                       processor_cntl_xen_notify(pr, PROCESSOR_HOTPLUG,
+                                                       HOTPLUG_TYPE_REMOVE);
+
                result = acpi_processor_start(device);
                if ((!result) && ((pr->id >= 0) && (pr->id < nr_cpu_ids))) {
                        kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 0efa59e..8994aff 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -58,6 +58,7 @@ 

 #include <acpi/acpi_bus.h>
 #include <acpi/processor.h>
+#include <xen/acpi.h>
 #include <asm/processor.h>

 #define ACPI_PROCESSOR_CLASS            "processor"
@@ -455,6 +456,12 @@  static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)

                cx.power = obj->integer.value;

+#ifdef CONFIG_ACPI_PROCESSOR_XEN
+               /* cache control methods to notify xen*/
+               if (processor_cntl_xen_pm())
+                       memcpy(&cx.reg, reg, sizeof(*reg));
+#endif
+
                current_count++;
                memcpy(&(pr->power.states[current_count]), &cx, sizeof(cx));

@@ -1141,6 +1148,13 @@  int acpi_processor_cst_has_changed(struct acpi_processor *pr)
        if (!pr->flags.power_setup_done)
                return -ENODEV;

+    if (processor_cntl_xen_pm()) {
+               acpi_processor_get_power_info(pr);
+               processor_cntl_xen_notify(pr,
+                       PROCESSOR_PM_CHANGE, PM_TYPE_IDLE);
+               return ret;
+       }
+
        cpuidle_pause_and_lock();
        cpuidle_disable_device(&pr->power.dev);
        acpi_processor_get_power_info(pr);
@@ -1204,9 +1218,14 @@  int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
         * platforms that only support C1.
         */
        if (pr->flags.power) {
-               acpi_processor_setup_cpuidle(pr);
-               if (cpuidle_register_device(&pr->power.dev))
-                       return -EIO;
+               if (processor_cntl_xen_pm())
+                       processor_cntl_xen_notify(pr,
+                                       PROCESSOR_PM_INIT, PM_TYPE_IDLE);
+               else {
+                       acpi_processor_setup_cpuidle(pr);
+                       if (cpuidle_register_device(&pr->power.dev))
+                               return -EIO;
+               }

                printk(KERN_INFO PREFIX "CPU%d (power states:", pr->id);
                for (i = 1; i <= pr->power.count; i++)
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index 60e543d..8375075 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -38,6 +38,7 @@ 
 #include <acpi/acpi_bus.h>
 #include <acpi/acpi_drivers.h>
 #include <acpi/processor.h>
+#include <xen/acpi.h>

 #define ACPI_PROCESSOR_CLASS           "processor"
 #define ACPI_PROCESSOR_FILE_PERFORMANCE        "performance"
@@ -154,13 +155,16 @@  int acpi_processor_ppc_has_changed(struct acpi_processor *pr)
 {
        int ret;

-       if (ignore_ppc)
+       if (ignore_ppc && !processor_cntl_xen_pmperf())
                return 0;

        ret = acpi_processor_get_platform_limit(pr);

        if (ret < 0)
                return (ret);
+       else if (processor_cntl_xen_pmperf())
+               return processor_cntl_xen_notify(pr,
+                               PROCESSOR_PM_CHANGE, PM_TYPE_PERF);
        else
                return cpufreq_update_policy(pr->id);
 }
@@ -330,7 +334,7 @@  static int acpi_processor_get_performance_states(struct acpi_processor *pr)
        return result;
 }

-static int acpi_processor_get_performance_info(struct acpi_processor *pr)
+int acpi_processor_get_performance_info(struct acpi_processor *pr)
 {
        int result = 0;
        acpi_status status = AE_OK;
@@ -432,7 +436,7 @@  int acpi_processor_notify_smm(struct module *calling_module)

 EXPORT_SYMBOL(acpi_processor_notify_smm);

-static int acpi_processor_get_psd(struct acpi_processor        *pr)
+int acpi_processor_get_psd(struct acpi_processor       *pr)
 {
        int result = 0;
        acpi_status status = AE_OK;
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index 3b1c421..d303c25 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -90,4 +90,9 @@  config XEN_XENBUS_FRONTEND

 config XEN_S3
        def_bool y
-       depends on XEN_DOM0 && ACPI
\ No newline at end of file
+       depends on XEN_DOM0 && ACPI
+
+config ACPI_PROCESSOR_XEN
+       bool
+       depends on XEN_DOM0 && ACPI_PROCESSOR && CPU_FREQ
+       default y
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index 386c775..42c9ace 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -9,4 +9,5 @@  obj-$(CONFIG_XEN_BLKDEV_BACKEND)        += blkback/
 obj-$(CONFIG_XEN_NETDEV_BACKEND)       += netback/
 obj-$(CONFIG_XENFS)                    += xenfs/
 obj-$(CONFIG_XEN_SYS_HYPERVISOR)       += sys-hypervisor.o
-obj-$(CONFIG_XEN_S3)                   += acpi.o
\ No newline at end of file
+obj-$(CONFIG_XEN_S3)                   += acpi.o
+obj-$(CONFIG_ACPI_PROCESSOR_XEN) += processor_extcntl.o
diff --git a/drivers/xen/processor_extcntl.c b/drivers/xen/processor_extcntl.c
new file mode 100644
index 0000000..7307cd8
--- /dev/null
+++ b/drivers/xen/processor_extcntl.c
@@ -0,0 +1,413 @@ 
+/*
+ * processor_extcntl.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 <linux/cpufreq.h>
+#include <acpi/processor.h>
+#include <xen/acpi.h>
+
+#include <asm/xen/hypercall.h>
+#include <asm/xen/hypervisor.h>
+
+static int processor_cntl_xen_get_performance(struct acpi_processor *pr);
+static int xen_hotplug_notifier(struct acpi_processor *pr, int event);
+
+static struct processor_cntl_xen_ops xen_ops = {
+       .hotplug                = xen_hotplug_notifier,
+};
+
+int processor_cntl_xen(void)
+{
+       return 1;
+}
+
+int processor_cntl_xen_pm(void)
+{
+       return (xen_ops.pm_ops[PM_TYPE_IDLE] != NULL);
+}
+
+int processor_cntl_xen_pmperf(void)
+{
+       return  (xen_ops.pm_ops[PM_TYPE_PERF] != NULL);
+}
+
+int processor_cntl_xen_pmthr(void)
+{
+       return (xen_ops.pm_ops[PM_TYPE_THR] != NULL);
+}
+
+static int processor_notify_smm(void)
+{
+       acpi_status status;
+       static int is_done = 0;
+
+       /* only need successfully notify BIOS once */
+       /* avoid double notification which may lead to unexpected result */
+       if (is_done)
+               return 0;
+
+       /* Can't write pstate_cnt to smi_cmd if either value is zero */
+       if ((!acpi_gbl_FADT.smi_command) || (!acpi_gbl_FADT.pstate_control)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO,"No SMI port or pstate_cnt\n"));
+               return 0;
+       }
+
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+               "Writing pstate_cnt [0x%x] to smi_cmd [0x%x]\n",
+               acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command));
+
+       status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
+                                   (u32) acpi_gbl_FADT.pstate_control, 8);
+       if (ACPI_FAILURE(status))
+               return status;
+
+       is_done = 1;
+
+       return 0;
+}
+
+int processor_cntl_xen_notify(struct acpi_processor *pr, int event, int type)
+{
+       int ret = -EINVAL;
+
+       switch (event) {
+       case PROCESSOR_PM_INIT:
+       case PROCESSOR_PM_CHANGE:
+               if ((type >= PM_TYPE_MAX) ||
+                       !xen_ops.pm_ops[type])
+                       break;
+
+               ret = xen_ops.pm_ops[type](pr, event);
+               break;
+       case PROCESSOR_HOTPLUG:
+               if (xen_ops.hotplug)
+                       ret = xen_ops.hotplug(pr, type);
+               break;
+       default:
+               printk(KERN_ERR "Unsupport processor events %d.\n", event);
+               break;
+       }
+
+       return ret;
+}
+
+/*
+ * This is called from ACPI processor init, and targeted to hold
+ * some tricky housekeeping jobs to satisfy xen.
+ * For example, we may put dependency parse stub here for idle
+ * and performance state. Those information may be not available
+ * if splitting from dom0 control logic like cpufreq driver.
+ */
+int processor_cntl_xen_prepare(struct acpi_processor *pr)
+{
+
+       /* Initialize performance states */
+       if (processor_cntl_xen_pmperf())
+               processor_cntl_xen_get_performance(pr);
+
+       return 0;
+}
+
+/*
+ * Existing ACPI module does parse performance states at some point,
+ * when acpi-cpufreq driver is loaded which however is something
+ * we'd like to disable to avoid confliction with xen PM
+ * logic. So we have to collect raw performance information here
+ * when ACPI processor object is found and started.
+ */
+static int processor_cntl_xen_get_performance(struct acpi_processor *pr)
+{
+       int ret;
+       struct acpi_processor_performance *perf;
+       struct acpi_psd_package *pdomain;
+
+       if (pr->performance)
+               return -EBUSY;
+
+       perf = kzalloc(sizeof(struct acpi_processor_performance), GFP_KERNEL);
+       if (!perf)
+               return -ENOMEM;
+
+       pr->performance = perf;
+       /* Get basic performance state information */
+       ret = acpi_processor_get_performance_info(pr);
+       if (ret < 0)
+               goto err_out;
+
+       /*
+        * Well, here we need retrieve performance dependency information
+        * from _PSD object. The reason why existing interface is not used
+        * is due to the reason that existing interface sticks to Linux cpu
+        * id to construct some bitmap, however we want to split ACPI
+        * processor objects from Linux cpu id logic. For example, even
+        * when Linux is configured as UP, we still want to parse all ACPI
+        * processor objects to xen. In this case, it's preferred
+        * to use ACPI ID instead.
+        */
+       pdomain = &pr->performance->domain_info;
+       pdomain->num_processors = 0;
+       ret = acpi_processor_get_psd(pr);
+       if (ret < 0) {
+               /*
+                * _PSD is optional - assume no coordination if absent (or
+                * broken), matching native kernels' behavior.
+                */
+               pdomain->num_entries = ACPI_PSD_REV0_ENTRIES;
+               pdomain->revision = ACPI_PSD_REV0_REVISION;
+               pdomain->domain = pr->acpi_id;
+               pdomain->coord_type = DOMAIN_COORD_TYPE_SW_ALL;
+               pdomain->num_processors = 1;
+       }
+
+       /* Some sanity check */
+       if ((pdomain->revision != ACPI_PSD_REV0_REVISION) ||
+           (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) ||
+           ((pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL) &&
+            (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY) &&
+            (pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL))) {
+               ret = -EINVAL;
+               goto err_out;
+       }
+
+       /* Last step is to notify BIOS that xen exists */
+       processor_notify_smm();
+
+       processor_cntl_xen_notify(pr, PROCESSOR_PM_INIT, PM_TYPE_PERF);
+
+       return 0;
+err_out:
+       pr->performance = NULL;
+       kfree(perf);
+       return ret;
+}
+
+static inline void xen_convert_pct_reg(struct xen_pct_register *xpct,
+       struct acpi_pct_register *apct)
+{
+       xpct->descriptor = apct->descriptor;
+       xpct->length     = apct->length;
+       xpct->space_id   = apct->space_id;
+       xpct->bit_width  = apct->bit_width;
+       xpct->bit_offset = apct->bit_offset;
+       xpct->reserved   = apct->reserved;
+       xpct->address    = apct->address;
+}
+
+static inline void xen_convert_pss_states(struct xen_processor_px *xpss,
+       struct acpi_processor_px *apss, int state_count)
+{
+       int i;
+       for(i=0; i<state_count; i++) {
+               xpss->core_frequency     = apss->core_frequency;
+               xpss->power              = apss->power;
+               xpss->transition_latency = apss->transition_latency;
+               xpss->bus_master_latency = apss->bus_master_latency;
+               xpss->control            = apss->control;
+               xpss->status             = apss->status;
+               xpss++;
+               apss++;
+       }
+}
+
+static inline void xen_convert_psd_pack(struct xen_psd_package *xpsd,
+       struct acpi_psd_package *apsd)
+{
+       xpsd->num_entries    = apsd->num_entries;
+       xpsd->revision       = apsd->revision;
+       xpsd->domain         = apsd->domain;
+       xpsd->coord_type     = apsd->coord_type;
+       xpsd->num_processors = apsd->num_processors;
+}
+
+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, _CSD is not supported yet */
+               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_dom0_op(&op);
+       kfree(buf);
+       return ret;
+}
+
+static int xen_px_notifier(struct acpi_processor *pr, int action)
+{
+       int ret = -EINVAL;
+       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_PX,
+       };
+       struct xen_processor_performance *perf;
+       struct xen_processor_px *states = NULL;
+       struct acpi_processor_performance *px;
+       struct acpi_psd_package *pdomain;
+
+       if (!pr)
+               return -EINVAL;
+
+       perf = &op.u.set_pminfo.perf;
+       px = pr->performance;
+
+       switch(action) {
+       case PROCESSOR_PM_CHANGE:
+               /* ppc dynamic handle */
+               perf->flags = XEN_PX_PPC;
+               perf->platform_limit = pr->performance_platform_limit;
+
+               ret = HYPERVISOR_dom0_op(&op);
+               break;
+
+       case PROCESSOR_PM_INIT:
+               /* px normal init */
+               perf->flags = XEN_PX_PPC |
+                             XEN_PX_PCT |
+                             XEN_PX_PSS |
+                             XEN_PX_PSD;
+
+               /* ppc */
+               perf->platform_limit = pr->performance_platform_limit;
+
+               /* pct */
+               xen_convert_pct_reg(&perf->control_register, &px->control_register);
+               xen_convert_pct_reg(&perf->status_register, &px->status_register);
+
+               /* pss */
+               perf->state_count = px->state_count;
+               states = kzalloc(px->state_count*sizeof(xen_processor_px_t),GFP_KERNEL);
+               if (!states)
+                       return -ENOMEM;
+               xen_convert_pss_states(states, px->states, px->state_count);
+               set_xen_guest_handle(perf->states, states);
+
+               /* psd */
+               pdomain = &px->domain_info;
+               xen_convert_psd_pack(&perf->domain_info, pdomain);
+               if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL)
+                       perf->shared_type = CPUFREQ_SHARED_TYPE_ALL;
+               else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY)
+                       perf->shared_type = CPUFREQ_SHARED_TYPE_ANY;
+               else if (pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL)
+                       perf->shared_type = CPUFREQ_SHARED_TYPE_HW;
+               else {
+                       ret = -ENODEV;
+                       kfree(states);
+                       break;
+               }
+
+               ret = HYPERVISOR_dom0_op(&op);
+               kfree(states);
+               break;
+
+       default:
+               break;
+       }
+
+       return ret;
+}
+
+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 int __init xen_acpi_processor_extcntl_init(void)
+{
+       unsigned int pmbits = (xen_start_info->flags & SIF_PM_MASK) >> 8;
+
+       if (!pmbits)
+               return 0;
+       if (pmbits & XEN_PROCESSOR_PM_CX)
+               xen_ops.pm_ops[PM_TYPE_IDLE] = xen_cx_notifier;
+       if (pmbits & XEN_PROCESSOR_PM_PX)
+               xen_ops.pm_ops[PM_TYPE_PERF] = xen_px_notifier;
+       if (pmbits & XEN_PROCESSOR_PM_TX)
+               xen_ops.pm_ops[PM_TYPE_THR] = xen_tx_notifier;
+
+       return 0;
+}
+
+subsys_initcall(xen_acpi_processor_extcntl_init);
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index baf1e0a..14c7e4c 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -77,6 +77,10 @@  struct acpi_processor_cx {
        struct acpi_processor_cx_policy promotion;
        struct acpi_processor_cx_policy demotion;
        char desc[ACPI_CX_DESC_LEN];
+#ifdef CONFIG_ACPI_PROCESSOR_XEN
+       /* Require raw information for xen*/
+       struct acpi_power_register reg;
+#endif /* CONFIG_ACPI_PROCESSOE_XEN */
 };

 struct acpi_processor_power {
@@ -295,6 +299,8 @@  static inline void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx
 void acpi_processor_ppc_init(void);
 void acpi_processor_ppc_exit(void);
 int acpi_processor_ppc_has_changed(struct acpi_processor *pr);
+int acpi_processor_get_performance_info(struct acpi_processor *pr);
+int acpi_processor_get_psd(struct acpi_processor *pr);
 #else
 static inline void acpi_processor_ppc_init(void)
 {
diff --git a/include/xen/acpi.h b/include/xen/acpi.h
index fea4cfb..636c3e6 100644
--- a/include/xen/acpi.h
+++ b/include/xen/acpi.h
@@ -20,4 +20,59 @@  static inline bool xen_pv_acpi(void)
 int acpi_notify_hypervisor_state(u8 sleep_state,
                                 u32 pm1a_cnt, u32 pm1b_cnd);

+/*
+ * Following are interfaces for xen acpi processor control
+ */
+
+/* Events notified to xen */
+#define PROCESSOR_PM_INIT      1
+#define PROCESSOR_PM_CHANGE    2
+#define PROCESSOR_HOTPLUG      3
+
+/* Objects for the PM events */
+#define PM_TYPE_IDLE           0
+#define PM_TYPE_PERF           1
+#define PM_TYPE_THR            2
+#define PM_TYPE_MAX            3
+
+/* Processor hotplug events */
+#define HOTPLUG_TYPE_ADD       0
+#define HOTPLUG_TYPE_REMOVE    1
+
+#ifdef CONFIG_ACPI_PROCESSOR_XEN
+#include <acpi/acpi_drivers.h>
+#include <acpi/processor.h>
+
+struct processor_cntl_xen_ops {
+       /* Transfer processor PM events to xen */
+int (*pm_ops[PM_TYPE_MAX])(struct acpi_processor *pr, int event);
+       /* Notify physical processor status to xen */
+       int (*hotplug)(struct acpi_processor *pr, int type);
+};
+
+extern int processor_cntl_xen(void);
+extern int processor_cntl_xen_pm(void);
+extern int processor_cntl_xen_pmperf(void);
+extern int processor_cntl_xen_pmthr(void);
+extern int processor_cntl_xen_prepare(struct acpi_processor *pr);
+extern int processor_cntl_xen_notify(struct acpi_processor *pr,
+                       int event, int type);
+
+#else
+
+static inline int processor_cntl_xen(void) {return 0;}
+static inline int processor_cntl_xen_pm(void) {return 0;}
+static inline int processor_cntl_xen_pmperf(void) {return 0;}
+static inline int processor_cntl_xen_pmthr(void) {return 0;}
+static inline int processor_cntl_xen_notify(struct acpi_processor *pr,
+                       int event, int type)
+{
+       return 0;
+}
+static inline int processor_cntl_xen_prepare(struct acpi_processor *pr)
+{
+       return 0;
+}
+#endif /* CONFIG_ACPI_PROCESSOR_XEN */
+
 #endif /* _XEN_ACPI_H */