[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [linux-2.6.18-xen] xen: Basic framework of getting and notifying Px info



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1210769510 -3600
# Node ID 12bcbf80b8e4d2282429d5bab71749fb58b6643a
# Parent  e25f25110882876e12e584b5a6a7ef85a1a28cca
xen: Basic framework of getting and notifying Px info

Setup basic framework for ACPI Px parse, get basic Px info,
transfer Px info to hypervisor through platform op hypercall.
Add external control for ACPI parse, add notify mechanism for
dynamic Px event (like ppc).

Signed-off-by: Tian Kevin <kevin.tian@xxxxxxxxx>
Signed-off-by: Liu Jinsong <jinsong.liu@xxxxxxxxx>
---
 arch/i386/kernel/acpi/processor_extcntl_xen.c |   95 +++++++++++++++++++++
 drivers/acpi/processor_extcntl.c              |  113 +++++++++++++++++++++++++-
 drivers/acpi/processor_perflib.c              |    8 +
 include/acpi/processor.h                      |    2 
 include/xen/interface/platform.h              |   51 +++++++++++
 5 files changed, 266 insertions(+), 3 deletions(-)

diff -r e25f25110882 -r 12bcbf80b8e4 
arch/i386/kernel/acpi/processor_extcntl_xen.c
--- a/arch/i386/kernel/acpi/processor_extcntl_xen.c     Wed May 14 09:32:31 
2008 +0100
+++ b/arch/i386/kernel/acpi/processor_extcntl_xen.c     Wed May 14 13:51:50 
2008 +0100
@@ -28,6 +28,7 @@
 #include <linux/pm.h>
 #include <linux/cpu.h>
 
+#include <linux/cpufreq.h>
 #include <acpi/processor.h>
 #include <asm/hypercall.h>
 
@@ -110,9 +111,101 @@ static int xen_cx_notifier(struct acpi_p
        return ret;
 }
 
+static void 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 void 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 void 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_px_notifier(struct acpi_processor *pr, int action)
 {
-       return -EINVAL;
+       int ret;
+       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;
+
+       /* leave dynamic ppc handle in the future */
+       if (action == PROCESSOR_PM_CHANGE)
+               return 0;
+
+       perf = &op.u.set_pminfo.perf;
+       px = pr->performance;
+
+       perf->flags = XEN_PX_PPC | 
+                     XEN_PX_PCT | 
+                     XEN_PX_PSS | 
+                     XEN_PX_PSD;
+
+       /* ppc */
+       perf->ppc = pr->performance_platform_limit;
+
+       /* pct */
+       convert_pct_reg(&perf->control_register, &px->control_register);
+       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;
+       convert_pss_states(states, px->states, px->state_count);
+       set_xen_guest_handle(perf->states, states);
+
+       /* psd */
+       pdomain = &px->domain_info;
+       convert_psd_pack(&perf->domain_info, pdomain);
+       if (perf->domain_info.num_processors) {
+               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
+               perf->shared_type = CPUFREQ_SHARED_TYPE_NONE;
+
+       ret = HYPERVISOR_platform_op(&op);
+       kfree(states);
+       return ret;
 }
 
 static int xen_tx_notifier(struct acpi_processor *pr, int action)
diff -r e25f25110882 -r 12bcbf80b8e4 drivers/acpi/processor_extcntl.c
--- a/drivers/acpi/processor_extcntl.c  Wed May 14 09:32:31 2008 +0100
+++ b/drivers/acpi/processor_extcntl.c  Wed May 14 13:51:50 2008 +0100
@@ -31,11 +31,49 @@
 #include <acpi/processor.h>
 
 static int processor_extcntl_parse_csd(struct acpi_processor *pr);
+static int processor_extcntl_get_performance(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.
  */
 struct processor_extcntl_ops *processor_extcntl_ops;
+
+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_fadt.smi_cmd) || (!acpi_fadt.pstate_cnt)) {
+               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_fadt.pstate_cnt, acpi_fadt.smi_cmd));
+
+       /* FADT v1 doesn't support pstate_cnt, many BIOS vendors use
+        * it anyway, so we need to support it... */
+       if (acpi_fadt_is_v1) {
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                       "Using v1.0 FADT reserved value for pstate_cnt\n"));
+       }
+
+       status = acpi_os_write_port(acpi_fadt.smi_cmd,
+                                   (u32) acpi_fadt.pstate_cnt, 8);
+       if (ACPI_FAILURE(status)) 
+               return status;
+
+       is_done = 1;
+
+       return 0;
+}
 
 int processor_notify_external(struct acpi_processor *pr, int event, int type)
 {
@@ -109,7 +147,12 @@ int processor_extcntl_init(struct acpi_p
 int processor_extcntl_init(struct acpi_processor *pr)
 {
        /* parse cstate dependency information */
-       processor_extcntl_parse_csd(pr);
+       if (processor_pm_external())
+               processor_extcntl_parse_csd(pr);
+
+       /* Initialize performance states */
+       if (processor_pmperf_external())
+               processor_extcntl_get_performance(pr);
 
        return 0;
 }
@@ -135,3 +178,71 @@ static int processor_extcntl_parse_csd(s
 
        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 external control
+ * logic. So we have to collect raw performance information here 
+ * when ACPI processor object is found and started.
+ */
+#ifdef CONFIG_CPU_FREQ
+static int processor_extcntl_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 external logic. In this case, it's preferred
+        * to use ACPI ID instead.
+        */
+       pr->performance->domain_info.num_processors = 0;
+       ret = acpi_processor_get_psd(pr);
+       if (ret < 0)
+               goto err_out;
+
+       /* Some sanity check */
+       pdomain = &pr->performance->domain_info;
+       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 external logic exists */
+       processor_notify_smm();
+
+       processor_notify_external(pr, PROCESSOR_PM_INIT, PM_TYPE_PERF);
+
+       return 0;
+err_out:
+       pr->performance = NULL;
+       kfree(perf);
+       return ret;
+}
+#else
+static int processor_extcntl_get_performance(struct acpi_processor *pr) { 
return 0; }
+#endif
diff -r e25f25110882 -r 12bcbf80b8e4 drivers/acpi/processor_perflib.c
--- a/drivers/acpi/processor_perflib.c  Wed May 14 09:32:31 2008 +0100
+++ b/drivers/acpi/processor_perflib.c  Wed May 14 13:51:50 2008 +0100
@@ -304,7 +304,11 @@ static int acpi_processor_get_performanc
        return result;
 }
 
+#ifndef CONFIG_PROCESSOR_EXTERNAL_CONTROL
 static int acpi_processor_get_performance_info(struct acpi_processor *pr)
+#else
+int acpi_processor_get_performance_info(struct acpi_processor *pr)
+#endif
 {
        int result = 0;
        acpi_status status = AE_OK;
@@ -543,7 +547,11 @@ static void acpi_cpufreq_remove_file(str
 }
 #endif                         /* CONFIG_X86_ACPI_CPUFREQ_PROC_INTF */
 
+#ifndef CONFIG_PROCESSOR_EXTERNAL_CONTROL
 static int acpi_processor_get_psd(struct acpi_processor        *pr)
+#else
+int acpi_processor_get_psd(struct acpi_processor *pr)
+#endif
 {
        int result = 0;
        acpi_status status = AE_OK;
diff -r e25f25110882 -r 12bcbf80b8e4 include/acpi/processor.h
--- a/include/acpi/processor.h  Wed May 14 09:32:31 2008 +0100
+++ b/include/acpi/processor.h  Wed May 14 13:51:50 2008 +0100
@@ -353,6 +353,8 @@ extern int processor_register_extcntl(st
 extern int processor_register_extcntl(struct processor_extcntl_ops *ops);
 extern int processor_unregister_extcntl(struct processor_extcntl_ops *ops);
 extern int processor_extcntl_init(struct acpi_processor *pr);
+extern int acpi_processor_get_performance_info(struct acpi_processor *pr);
+extern int acpi_processor_get_psd(struct acpi_processor *pr);
 #else
 static inline int processor_cntl_external(void) {return 0;}
 static inline int processor_pm_external(void) {return 0;}
diff -r e25f25110882 -r 12bcbf80b8e4 include/xen/interface/platform.h
--- a/include/xen/interface/platform.h  Wed May 14 09:32:31 2008 +0100
+++ b/include/xen/interface/platform.h  Wed May 14 13:51:50 2008 +0100
@@ -211,6 +211,12 @@ DEFINE_XEN_GUEST_HANDLE(xenpf_getidletim
 #define XEN_PM_PX   1
 #define XEN_PM_TX   2
 
+/* Px sub info type */
+#define XEN_PX_PCT   1
+#define XEN_PX_PSS   2
+#define XEN_PX_PPC   4
+#define XEN_PX_PSD   8
+
 struct xen_power_register {
     uint32_t     space_id;
     uint32_t     bit_width;
@@ -252,12 +258,55 @@ struct xen_processor_power {
     XEN_GUEST_HANDLE(xen_processor_cx_t) states; /* supported c states */
 };
 
+struct xen_pct_register {
+    uint8_t  descriptor;
+    uint16_t length;
+    uint8_t  space_id;
+    uint8_t  bit_width;
+    uint8_t  bit_offset;
+    uint8_t  reserved;
+    uint64_t address;
+};
+
+struct xen_processor_px {
+    uint64_t core_frequency; /* megahertz */
+    uint64_t power;      /* milliWatts */
+    uint64_t transition_latency; /* microseconds */
+    uint64_t bus_master_latency; /* microseconds */
+    uint64_t control;        /* control value */
+    uint64_t status;     /* success indicator */
+};
+typedef struct xen_processor_px xen_processor_px_t;
+DEFINE_XEN_GUEST_HANDLE(xen_processor_px_t);
+
+struct xen_psd_package {
+    uint64_t num_entries;
+    uint64_t revision;
+    uint64_t domain;
+    uint64_t coord_type;
+    uint64_t num_processors;
+};
+
+struct xen_processor_performance {
+    uint32_t flags;     /* flag for Px sub info type */
+    uint32_t ppc;       /* Platform limitation on freq usage */
+    struct xen_pct_register control_register;
+    struct xen_pct_register status_register;
+    uint32_t state_count;     /* total available performance states */
+    XEN_GUEST_HANDLE(xen_processor_px_t) states;
+    struct xen_psd_package domain_info;
+    uint32_t shared_type;     /* coordination type of this processor */
+};
+typedef struct xen_processor_performance xen_processor_performance_t;
+DEFINE_XEN_GUEST_HANDLE(xen_processor_performance_t);
+
 struct xenpf_set_processor_pminfo {
     /* IN variables */
     uint32_t id;    /* ACPI CPU ID */
-    uint32_t type;  /* {XEN_PM_CX, ...} */
+    uint32_t type;  /* {XEN_PM_CX, XEN_PM_PX} */
     union {
         struct xen_processor_power          power;/* Cx: _CST/_CSD */
+        struct xen_processor_performance    perf; /* Px: _PPC/_PCT/_PSS/_PSD */
     };
 };
 typedef struct xenpf_set_processor_pminfo xenpf_set_processor_pminfo_t;

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.