aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLiu, Jinsong <jinsong.liu@intel.com>2012-11-08 00:41:13 -0500
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2012-11-26 15:07:19 -0500
commit92e3229dcdc80ff0b6304f14c578d76e7e10e226 (patch)
tree6c4a67d4b721b3eb6c2c2b07db2cd173313c9669 /drivers
parentb3e40b72bb24237b0aee9f6ba2e9f88dd4ff3c0a (diff)
xen/acpi: ACPI PAD driver
PAD is acpi Processor Aggregator Device which provides a control point that enables the platform to perform specific processor configuration and control that applies to all processors in the platform. This patch is to implement Xen acpi pad logic. When running under Xen virt platform, native pad driver would not work. Instead Xen pad driver, a self-contained and thin logic level, would take over acpi pad logic. When acpi pad notify OSPM, xen pad logic intercept and parse _PUR object to get the expected idle cpu number, and then hypercall to hypervisor. Xen hypervisor would then do the rest work, say, core parking, to idle specific number of cpus on its own policy. Signed-off-by: Jan Beulich <JBeulich@suse.com> Signed-off-by: Liu Jinsong <jinsong.liu@intel.com> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/xen/Makefile3
-rw-r--r--drivers/xen/xen-acpi-pad.c181
2 files changed, 183 insertions, 1 deletions
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index 0e8637035457..3c397170f39c 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -10,7 +10,8 @@ CFLAGS_features.o := $(nostackp)
10 10
11dom0-$(CONFIG_PCI) += pci.o 11dom0-$(CONFIG_PCI) += pci.o
12dom0-$(CONFIG_USB_SUPPORT) += dbgp.o 12dom0-$(CONFIG_USB_SUPPORT) += dbgp.o
13dom0-$(CONFIG_ACPI) += acpi.o 13dom0-$(CONFIG_ACPI) += acpi.o $(xen-pad-y)
14xen-pad-$(CONFIG_X86) += xen-acpi-pad.o
14dom0-$(CONFIG_X86) += pcpu.o 15dom0-$(CONFIG_X86) += pcpu.o
15obj-$(CONFIG_XEN_DOM0) += $(dom0-y) 16obj-$(CONFIG_XEN_DOM0) += $(dom0-y)
16obj-$(CONFIG_BLOCK) += biomerge.o 17obj-$(CONFIG_BLOCK) += biomerge.o
diff --git a/drivers/xen/xen-acpi-pad.c b/drivers/xen/xen-acpi-pad.c
new file mode 100644
index 000000000000..f23ecf380088
--- /dev/null
+++ b/drivers/xen/xen-acpi-pad.c
@@ -0,0 +1,181 @@
1/*
2 * xen-acpi-pad.c - Xen pad interface
3 *
4 * Copyright (c) 2012, Intel Corporation.
5 * Author: Liu, Jinsong <jinsong.liu@intel.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms and conditions of the GNU General Public License,
9 * version 2, as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 */
16
17#include <linux/kernel.h>
18#include <linux/types.h>
19#include <acpi/acpi_bus.h>
20#include <acpi/acpi_drivers.h>
21#include <asm/xen/hypercall.h>
22#include <xen/interface/version.h>
23
24#define ACPI_PROCESSOR_AGGREGATOR_CLASS "acpi_pad"
25#define ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME "Processor Aggregator"
26#define ACPI_PROCESSOR_AGGREGATOR_NOTIFY 0x80
27static DEFINE_MUTEX(xen_cpu_lock);
28
29static int xen_acpi_pad_idle_cpus(unsigned int idle_nums)
30{
31 struct xen_platform_op op;
32
33 op.cmd = XENPF_core_parking;
34 op.u.core_parking.type = XEN_CORE_PARKING_SET;
35 op.u.core_parking.idle_nums = idle_nums;
36
37 return HYPERVISOR_dom0_op(&op);
38}
39
40static int xen_acpi_pad_idle_cpus_num(void)
41{
42 struct xen_platform_op op;
43
44 op.cmd = XENPF_core_parking;
45 op.u.core_parking.type = XEN_CORE_PARKING_GET;
46
47 return HYPERVISOR_dom0_op(&op)
48 ?: op.u.core_parking.idle_nums;
49}
50
51/*
52 * Query firmware how many CPUs should be idle
53 * return -1 on failure
54 */
55static int acpi_pad_pur(acpi_handle handle)
56{
57 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
58 union acpi_object *package;
59 int num = -1;
60
61 if (ACPI_FAILURE(acpi_evaluate_object(handle, "_PUR", NULL, &buffer)))
62 return num;
63
64 if (!buffer.length || !buffer.pointer)
65 return num;
66
67 package = buffer.pointer;
68
69 if (package->type == ACPI_TYPE_PACKAGE &&
70 package->package.count == 2 &&
71 package->package.elements[0].integer.value == 1) /* rev 1 */
72 num = package->package.elements[1].integer.value;
73
74 kfree(buffer.pointer);
75 return num;
76}
77
78/* Notify firmware how many CPUs are idle */
79static void acpi_pad_ost(acpi_handle handle, int stat,
80 uint32_t idle_nums)
81{
82 union acpi_object params[3] = {
83 {.type = ACPI_TYPE_INTEGER,},
84 {.type = ACPI_TYPE_INTEGER,},
85 {.type = ACPI_TYPE_BUFFER,},
86 };
87 struct acpi_object_list arg_list = {3, params};
88
89 params[0].integer.value = ACPI_PROCESSOR_AGGREGATOR_NOTIFY;
90 params[1].integer.value = stat;
91 params[2].buffer.length = 4;
92 params[2].buffer.pointer = (void *)&idle_nums;
93 acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
94}
95
96static void acpi_pad_handle_notify(acpi_handle handle)
97{
98 int idle_nums;
99
100 mutex_lock(&xen_cpu_lock);
101 idle_nums = acpi_pad_pur(handle);
102 if (idle_nums < 0) {
103 mutex_unlock(&xen_cpu_lock);
104 return;
105 }
106
107 idle_nums = xen_acpi_pad_idle_cpus(idle_nums)
108 ?: xen_acpi_pad_idle_cpus_num();
109 if (idle_nums >= 0)
110 acpi_pad_ost(handle, 0, idle_nums);
111 mutex_unlock(&xen_cpu_lock);
112}
113
114static void acpi_pad_notify(acpi_handle handle, u32 event,
115 void *data)
116{
117 switch (event) {
118 case ACPI_PROCESSOR_AGGREGATOR_NOTIFY:
119 acpi_pad_handle_notify(handle);
120 break;
121 default:
122 pr_warn("Unsupported event [0x%x]\n", event);
123 break;
124 }
125}
126
127static int acpi_pad_add(struct acpi_device *device)
128{
129 acpi_status status;
130
131 strcpy(acpi_device_name(device), ACPI_PROCESSOR_AGGREGATOR_DEVICE_NAME);
132 strcpy(acpi_device_class(device), ACPI_PROCESSOR_AGGREGATOR_CLASS);
133
134 status = acpi_install_notify_handler(device->handle,
135 ACPI_DEVICE_NOTIFY, acpi_pad_notify, device);
136 if (ACPI_FAILURE(status))
137 return -ENODEV;
138
139 return 0;
140}
141
142static int acpi_pad_remove(struct acpi_device *device,
143 int type)
144{
145 mutex_lock(&xen_cpu_lock);
146 xen_acpi_pad_idle_cpus(0);
147 mutex_unlock(&xen_cpu_lock);
148
149 acpi_remove_notify_handler(device->handle,
150 ACPI_DEVICE_NOTIFY, acpi_pad_notify);
151 return 0;
152}
153
154static const struct acpi_device_id pad_device_ids[] = {
155 {"ACPI000C", 0},
156 {"", 0},
157};
158
159static struct acpi_driver acpi_pad_driver = {
160 .name = "processor_aggregator",
161 .class = ACPI_PROCESSOR_AGGREGATOR_CLASS,
162 .ids = pad_device_ids,
163 .ops = {
164 .add = acpi_pad_add,
165 .remove = acpi_pad_remove,
166 },
167};
168
169static int __init xen_acpi_pad_init(void)
170{
171 /* Only DOM0 is responsible for Xen acpi pad */
172 if (!xen_initial_domain())
173 return -ENODEV;
174
175 /* Only Xen4.2 or later support Xen acpi pad */
176 if (!xen_running_on_version_or_later(4, 2))
177 return -ENODEV;
178
179 return acpi_bus_register_driver(&acpi_pad_driver);
180}
181subsys_initcall(xen_acpi_pad_init);