aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiu Jinsong <jinsong.liu@intel.com>2013-01-25 02:43:34 -0500
committerKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>2013-02-19 22:02:29 -0500
commit39adc483d378f79711f291539f20e3797337892d (patch)
tree7f045e2f284864f5f16cb3b072d2cb25e6e16801
parent40a58637a4fa10a2faea71f0f30ff0b3d74c6e00 (diff)
xen/acpi: ACPI cpu hotplug
This patch implement real Xen ACPI cpu hotplug driver as module. When loaded, it replaces Xen stub driver. For booting existed cpus, the driver enumerates them. For hotadded cpus, which added at runtime and notify OS via device or container event, the driver is invoked to add them, parsing cpu information, hypercalling to Xen hypervisor to add them, and finally setting up new /sys interface for them. Signed-off-by: Liu Jinsong <jinsong.liu@intel.com> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
-rw-r--r--drivers/xen/Kconfig12
-rw-r--r--drivers/xen/Makefile1
-rw-r--r--drivers/xen/pcpu.c35
-rw-r--r--drivers/xen/xen-acpi-cpuhotplug.c471
-rw-r--r--include/xen/acpi.h3
-rw-r--r--include/xen/interface/platform.h8
6 files changed, 530 insertions, 0 deletions
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index dcffad1b47ca..5a32232cf7c1 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -202,6 +202,18 @@ config XEN_ACPI_HOTPLUG_MEMORY
202 to hot-add memory at runtime (the hot-added memory cannot be 202 to hot-add memory at runtime (the hot-added memory cannot be
203 removed until machine stop), select Y/M here, otherwise select N. 203 removed until machine stop), select Y/M here, otherwise select N.
204 204
205config XEN_ACPI_HOTPLUG_CPU
206 tristate "Xen ACPI cpu hotplug"
207 depends on XEN_DOM0 && XEN_STUB && ACPI
208 select ACPI_CONTAINER
209 default n
210 help
211 Xen ACPI cpu enumerating and hotplugging
212
213 For hotplugging, currently Xen only support ACPI cpu hotadd.
214 If you want to hotadd cpu at runtime (the hotadded cpu cannot
215 be removed until machine stop), select Y/M here.
216
205config XEN_ACPI_PROCESSOR 217config XEN_ACPI_PROCESSOR
206 tristate "Xen ACPI processor" 218 tristate "Xen ACPI processor"
207 depends on XEN && X86 && ACPI_PROCESSOR && CPU_FREQ 219 depends on XEN && X86 && ACPI_PROCESSOR && CPU_FREQ
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index 1605f594ff56..eabd0ee1c2bc 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback/
32obj-$(CONFIG_XEN_PRIVCMD) += xen-privcmd.o 32obj-$(CONFIG_XEN_PRIVCMD) += xen-privcmd.o
33obj-$(CONFIG_XEN_STUB) += xen-stub.o 33obj-$(CONFIG_XEN_STUB) += xen-stub.o
34obj-$(CONFIG_XEN_ACPI_HOTPLUG_MEMORY) += xen-acpi-memhotplug.o 34obj-$(CONFIG_XEN_ACPI_HOTPLUG_MEMORY) += xen-acpi-memhotplug.o
35obj-$(CONFIG_XEN_ACPI_HOTPLUG_CPU) += xen-acpi-cpuhotplug.o
35obj-$(CONFIG_XEN_ACPI_PROCESSOR) += xen-acpi-processor.o 36obj-$(CONFIG_XEN_ACPI_PROCESSOR) += xen-acpi-processor.o
36xen-evtchn-y := evtchn.o 37xen-evtchn-y := evtchn.o
37xen-gntdev-y := gntdev.o 38xen-gntdev-y := gntdev.o
diff --git a/drivers/xen/pcpu.c b/drivers/xen/pcpu.c
index 067fcfa1723e..0836a18675b1 100644
--- a/drivers/xen/pcpu.c
+++ b/drivers/xen/pcpu.c
@@ -333,6 +333,41 @@ static irqreturn_t xen_pcpu_interrupt(int irq, void *dev_id)
333 return IRQ_HANDLED; 333 return IRQ_HANDLED;
334} 334}
335 335
336/* Sync with Xen hypervisor after cpu hotadded */
337void xen_pcpu_hotplug_sync(void)
338{
339 schedule_work(&xen_pcpu_work);
340}
341EXPORT_SYMBOL_GPL(xen_pcpu_hotplug_sync);
342
343/*
344 * For hypervisor presented cpu, return logic cpu id;
345 * For hypervisor non-presented cpu, return -ENODEV.
346 */
347int xen_pcpu_id(uint32_t acpi_id)
348{
349 int cpu_id = 0, max_id = 0;
350 struct xen_platform_op op;
351
352 op.cmd = XENPF_get_cpuinfo;
353 while (cpu_id <= max_id) {
354 op.u.pcpu_info.xen_cpuid = cpu_id;
355 if (HYPERVISOR_dom0_op(&op)) {
356 cpu_id++;
357 continue;
358 }
359
360 if (acpi_id == op.u.pcpu_info.acpi_id)
361 return cpu_id;
362 if (op.u.pcpu_info.max_present > max_id)
363 max_id = op.u.pcpu_info.max_present;
364 cpu_id++;
365 }
366
367 return -ENODEV;
368}
369EXPORT_SYMBOL_GPL(xen_pcpu_id);
370
336static int __init xen_pcpu_init(void) 371static int __init xen_pcpu_init(void)
337{ 372{
338 int irq, ret; 373 int irq, ret;
diff --git a/drivers/xen/xen-acpi-cpuhotplug.c b/drivers/xen/xen-acpi-cpuhotplug.c
new file mode 100644
index 000000000000..9eefbb0f79a3
--- /dev/null
+++ b/drivers/xen/xen-acpi-cpuhotplug.c
@@ -0,0 +1,471 @@
1/*
2 * Copyright (C) 2012 Intel Corporation
3 * Author: Liu Jinsong <jinsong.liu@intel.com>
4 * Author: Jiang Yunhong <yunhong.jiang@intel.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or (at
9 * your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
14 * NON INFRINGEMENT. See the GNU General Public License for more
15 * details.
16 */
17
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/init.h>
21#include <linux/types.h>
22#include <linux/cpu.h>
23#include <linux/acpi.h>
24#include <linux/uaccess.h>
25#include <acpi/acpi_bus.h>
26#include <acpi/acpi_drivers.h>
27#include <acpi/processor.h>
28
29#include <xen/acpi.h>
30#include <xen/interface/platform.h>
31#include <asm/xen/hypercall.h>
32
33#define PREFIX "ACPI:xen_cpu_hotplug:"
34
35#define INSTALL_NOTIFY_HANDLER 0
36#define UNINSTALL_NOTIFY_HANDLER 1
37
38static acpi_status xen_acpi_cpu_hotadd(struct acpi_processor *pr);
39
40/* --------------------------------------------------------------------------
41 Driver Interface
42-------------------------------------------------------------------------- */
43
44static int xen_acpi_processor_enable(struct acpi_device *device)
45{
46 acpi_status status = 0;
47 unsigned long long value;
48 union acpi_object object = { 0 };
49 struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
50 struct acpi_processor *pr;
51
52 pr = acpi_driver_data(device);
53 if (!pr) {
54 pr_err(PREFIX "Cannot find driver data\n");
55 return -EINVAL;
56 }
57
58 if (!strcmp(acpi_device_hid(device), ACPI_PROCESSOR_OBJECT_HID)) {
59 /* Declared with "Processor" statement; match ProcessorID */
60 status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
61 if (ACPI_FAILURE(status)) {
62 pr_err(PREFIX "Evaluating processor object\n");
63 return -ENODEV;
64 }
65
66 pr->acpi_id = object.processor.proc_id;
67 } else {
68 /* Declared with "Device" statement; match _UID */
69 status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID,
70 NULL, &value);
71 if (ACPI_FAILURE(status)) {
72 pr_err(PREFIX "Evaluating processor _UID\n");
73 return -ENODEV;
74 }
75
76 pr->acpi_id = value;
77 }
78
79 pr->id = xen_pcpu_id(pr->acpi_id);
80
81 if ((int)pr->id < 0)
82 /* This cpu is not presented at hypervisor, try to hotadd it */
83 if (ACPI_FAILURE(xen_acpi_cpu_hotadd(pr))) {
84 pr_err(PREFIX "Hotadd CPU (acpi_id = %d) failed.\n",
85 pr->acpi_id);
86 return -ENODEV;
87 }
88
89 return 0;
90}
91
92static int __cpuinit xen_acpi_processor_add(struct acpi_device *device)
93{
94 int ret;
95 struct acpi_processor *pr;
96
97 if (!device)
98 return -EINVAL;
99
100 pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL);
101 if (!pr)
102 return -ENOMEM;
103
104 pr->handle = device->handle;
105 strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME);
106 strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
107 device->driver_data = pr;
108
109 ret = xen_acpi_processor_enable(device);
110 if (ret)
111 pr_err(PREFIX "Error when enabling Xen processor\n");
112
113 return ret;
114}
115
116static int xen_acpi_processor_remove(struct acpi_device *device, int type)
117{
118 struct acpi_processor *pr;
119
120 if (!device)
121 return -EINVAL;
122
123 pr = acpi_driver_data(device);
124 if (!pr)
125 return -EINVAL;
126
127 kfree(pr);
128 return 0;
129}
130
131/*--------------------------------------------------------------
132 Acpi processor hotplug support
133--------------------------------------------------------------*/
134
135static int is_processor_present(acpi_handle handle)
136{
137 acpi_status status;
138 unsigned long long sta = 0;
139
140
141 status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
142
143 if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_PRESENT))
144 return 1;
145
146 /*
147 * _STA is mandatory for a processor that supports hot plug
148 */
149 if (status == AE_NOT_FOUND)
150 pr_info(PREFIX "Processor does not support hot plug\n");
151 else
152 pr_info(PREFIX "Processor Device is not present");
153 return 0;
154}
155
156static int xen_apic_id(acpi_handle handle)
157{
158 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
159 union acpi_object *obj;
160 struct acpi_madt_local_apic *lapic;
161 int apic_id;
162
163 if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
164 return -EINVAL;
165
166 if (!buffer.length || !buffer.pointer)
167 return -EINVAL;
168
169 obj = buffer.pointer;
170 if (obj->type != ACPI_TYPE_BUFFER ||
171 obj->buffer.length < sizeof(*lapic)) {
172 kfree(buffer.pointer);
173 return -EINVAL;
174 }
175
176 lapic = (struct acpi_madt_local_apic *)obj->buffer.pointer;
177
178 if (lapic->header.type != ACPI_MADT_TYPE_LOCAL_APIC ||
179 !(lapic->lapic_flags & ACPI_MADT_ENABLED)) {
180 kfree(buffer.pointer);
181 return -EINVAL;
182 }
183
184 apic_id = (uint32_t)lapic->id;
185 kfree(buffer.pointer);
186 buffer.length = ACPI_ALLOCATE_BUFFER;
187 buffer.pointer = NULL;
188
189 return apic_id;
190}
191
192static int xen_hotadd_cpu(struct acpi_processor *pr)
193{
194 int cpu_id, apic_id, pxm;
195 struct xen_platform_op op;
196
197 apic_id = xen_apic_id(pr->handle);
198 if (apic_id < 0) {
199 pr_err(PREFIX "Failed to get apic_id for acpi_id %d\n",
200 pr->acpi_id);
201 return -ENODEV;
202 }
203
204 pxm = xen_acpi_get_pxm(pr->handle);
205 if (pxm < 0) {
206 pr_err(PREFIX "Failed to get _PXM for acpi_id %d\n",
207 pr->acpi_id);
208 return pxm;
209 }
210
211 op.cmd = XENPF_cpu_hotadd;
212 op.u.cpu_add.apic_id = apic_id;
213 op.u.cpu_add.acpi_id = pr->acpi_id;
214 op.u.cpu_add.pxm = pxm;
215
216 cpu_id = HYPERVISOR_dom0_op(&op);
217 if (cpu_id < 0)
218 pr_err(PREFIX "Failed to hotadd CPU for acpi_id %d\n",
219 pr->acpi_id);
220
221 return cpu_id;
222}
223
224static acpi_status xen_acpi_cpu_hotadd(struct acpi_processor *pr)
225{
226 if (!is_processor_present(pr->handle))
227 return AE_ERROR;
228
229 pr->id = xen_hotadd_cpu(pr);
230 if ((int)pr->id < 0)
231 return AE_ERROR;
232
233 /*
234 * Sync with Xen hypervisor, providing new /sys/.../xen_cpuX
235 * interface after cpu hotadded.
236 */
237 xen_pcpu_hotplug_sync();
238
239 return AE_OK;
240}
241
242static
243int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
244{
245 acpi_handle phandle;
246 struct acpi_device *pdev;
247
248 if (acpi_get_parent(handle, &phandle))
249 return -ENODEV;
250
251 if (acpi_bus_get_device(phandle, &pdev))
252 return -ENODEV;
253
254 if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR))
255 return -ENODEV;
256
257 return 0;
258}
259
260static int acpi_processor_device_remove(struct acpi_device *device)
261{
262 pr_debug(PREFIX "Xen does not support CPU hotremove\n");
263
264 return -ENOSYS;
265}
266
267static void acpi_processor_hotplug_notify(acpi_handle handle,
268 u32 event, void *data)
269{
270 struct acpi_processor *pr;
271 struct acpi_device *device = NULL;
272 u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
273 int result;
274
275 switch (event) {
276 case ACPI_NOTIFY_BUS_CHECK:
277 case ACPI_NOTIFY_DEVICE_CHECK:
278 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
279 "Processor driver received %s event\n",
280 (event == ACPI_NOTIFY_BUS_CHECK) ?
281 "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK"));
282
283 if (!is_processor_present(handle))
284 break;
285
286 if (!acpi_bus_get_device(handle, &device))
287 break;
288
289 result = acpi_processor_device_add(handle, &device);
290 if (result) {
291 pr_err(PREFIX "Unable to add the device\n");
292 break;
293 }
294
295 ost_code = ACPI_OST_SC_SUCCESS;
296 break;
297
298 case ACPI_NOTIFY_EJECT_REQUEST:
299 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
300 "received ACPI_NOTIFY_EJECT_REQUEST\n"));
301
302 if (acpi_bus_get_device(handle, &device)) {
303 pr_err(PREFIX "Device don't exist, dropping EJECT\n");
304 break;
305 }
306 pr = acpi_driver_data(device);
307 if (!pr) {
308 pr_err(PREFIX "Driver data is NULL, dropping EJECT\n");
309 break;
310 }
311
312 /*
313 * TBD: implement acpi_processor_device_remove if Xen support
314 * CPU hotremove in the future.
315 */
316 acpi_processor_device_remove(device);
317 break;
318
319 default:
320 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
321 "Unsupported event [0x%x]\n", event));
322
323 /* non-hotplug event; possibly handled by other handler */
324 return;
325 }
326
327 (void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
328 return;
329}
330
331static acpi_status is_processor_device(acpi_handle handle)
332{
333 struct acpi_device_info *info;
334 char *hid;
335 acpi_status status;
336
337 status = acpi_get_object_info(handle, &info);
338 if (ACPI_FAILURE(status))
339 return status;
340
341 if (info->type == ACPI_TYPE_PROCESSOR) {
342 kfree(info);
343 return AE_OK; /* found a processor object */
344 }
345
346 if (!(info->valid & ACPI_VALID_HID)) {
347 kfree(info);
348 return AE_ERROR;
349 }
350
351 hid = info->hardware_id.string;
352 if ((hid == NULL) || strcmp(hid, ACPI_PROCESSOR_DEVICE_HID)) {
353 kfree(info);
354 return AE_ERROR;
355 }
356
357 kfree(info);
358 return AE_OK; /* found a processor device object */
359}
360
361static acpi_status
362processor_walk_namespace_cb(acpi_handle handle,
363 u32 lvl, void *context, void **rv)
364{
365 acpi_status status;
366 int *action = context;
367
368 status = is_processor_device(handle);
369 if (ACPI_FAILURE(status))
370 return AE_OK; /* not a processor; continue to walk */
371
372 switch (*action) {
373 case INSTALL_NOTIFY_HANDLER:
374 acpi_install_notify_handler(handle,
375 ACPI_SYSTEM_NOTIFY,
376 acpi_processor_hotplug_notify,
377 NULL);
378 break;
379 case UNINSTALL_NOTIFY_HANDLER:
380 acpi_remove_notify_handler(handle,
381 ACPI_SYSTEM_NOTIFY,
382 acpi_processor_hotplug_notify);
383 break;
384 default:
385 break;
386 }
387
388 /* found a processor; skip walking underneath */
389 return AE_CTRL_DEPTH;
390}
391
392static
393void acpi_processor_install_hotplug_notify(void)
394{
395 int action = INSTALL_NOTIFY_HANDLER;
396 acpi_walk_namespace(ACPI_TYPE_ANY,
397 ACPI_ROOT_OBJECT,
398 ACPI_UINT32_MAX,
399 processor_walk_namespace_cb, NULL, &action, NULL);
400}
401
402static
403void acpi_processor_uninstall_hotplug_notify(void)
404{
405 int action = UNINSTALL_NOTIFY_HANDLER;
406 acpi_walk_namespace(ACPI_TYPE_ANY,
407 ACPI_ROOT_OBJECT,
408 ACPI_UINT32_MAX,
409 processor_walk_namespace_cb, NULL, &action, NULL);
410}
411
412static const struct acpi_device_id processor_device_ids[] = {
413 {ACPI_PROCESSOR_OBJECT_HID, 0},
414 {ACPI_PROCESSOR_DEVICE_HID, 0},
415 {"", 0},
416};
417MODULE_DEVICE_TABLE(acpi, processor_device_ids);
418
419static struct acpi_driver xen_acpi_processor_driver = {
420 .name = "processor",
421 .class = ACPI_PROCESSOR_CLASS,
422 .ids = processor_device_ids,
423 .ops = {
424 .add = xen_acpi_processor_add,
425 .remove = xen_acpi_processor_remove,
426 },
427};
428
429static int __init xen_acpi_processor_init(void)
430{
431 int result = 0;
432
433 if (!xen_initial_domain())
434 return -ENODEV;
435
436 /* unregister the stub which only used to reserve driver space */
437 xen_stub_processor_exit();
438
439 result = acpi_bus_register_driver(&xen_acpi_processor_driver);
440 if (result < 0) {
441 xen_stub_processor_init();
442 return result;
443 }
444
445 acpi_processor_install_hotplug_notify();
446 return 0;
447}
448
449static void __exit xen_acpi_processor_exit(void)
450{
451 if (!xen_initial_domain())
452 return;
453
454 acpi_processor_uninstall_hotplug_notify();
455
456 acpi_bus_unregister_driver(&xen_acpi_processor_driver);
457
458 /*
459 * stub reserve space again to prevent any chance of native
460 * driver loading.
461 */
462 xen_stub_processor_init();
463 return;
464}
465
466module_init(xen_acpi_processor_init);
467module_exit(xen_acpi_processor_exit);
468ACPI_MODULE_NAME("xen-acpi-cpuhotplug");
469MODULE_AUTHOR("Liu Jinsong <jinsong.liu@intel.com>");
470MODULE_DESCRIPTION("Xen Hotplug CPU Driver");
471MODULE_LICENSE("GPL");
diff --git a/include/xen/acpi.h b/include/xen/acpi.h
index dc69c91605b8..c962d5f5b38b 100644
--- a/include/xen/acpi.h
+++ b/include/xen/acpi.h
@@ -54,6 +54,9 @@ void xen_stub_memory_device_exit(void);
54int xen_stub_processor_init(void); 54int xen_stub_processor_init(void);
55void xen_stub_processor_exit(void); 55void xen_stub_processor_exit(void);
56 56
57void xen_pcpu_hotplug_sync(void);
58int xen_pcpu_id(uint32_t acpi_id);
59
57int xen_acpi_notify_hypervisor_state(u8 sleep_state, 60int xen_acpi_notify_hypervisor_state(u8 sleep_state,
58 u32 pm1a_cnt, u32 pm1b_cnd); 61 u32 pm1a_cnt, u32 pm1b_cnd);
59 62
diff --git a/include/xen/interface/platform.h b/include/xen/interface/platform.h
index 2c4fb4bb07df..c57d5f67f702 100644
--- a/include/xen/interface/platform.h
+++ b/include/xen/interface/platform.h
@@ -324,6 +324,13 @@ struct xenpf_cpu_ol {
324}; 324};
325DEFINE_GUEST_HANDLE_STRUCT(xenpf_cpu_ol); 325DEFINE_GUEST_HANDLE_STRUCT(xenpf_cpu_ol);
326 326
327#define XENPF_cpu_hotadd 58
328struct xenpf_cpu_hotadd {
329 uint32_t apic_id;
330 uint32_t acpi_id;
331 uint32_t pxm;
332};
333
327#define XENPF_mem_hotadd 59 334#define XENPF_mem_hotadd 59
328struct xenpf_mem_hotadd { 335struct xenpf_mem_hotadd {
329 uint64_t spfn; 336 uint64_t spfn;
@@ -361,6 +368,7 @@ struct xen_platform_op {
361 struct xenpf_set_processor_pminfo set_pminfo; 368 struct xenpf_set_processor_pminfo set_pminfo;
362 struct xenpf_pcpuinfo pcpu_info; 369 struct xenpf_pcpuinfo pcpu_info;
363 struct xenpf_cpu_ol cpu_ol; 370 struct xenpf_cpu_ol cpu_ol;
371 struct xenpf_cpu_hotadd cpu_add;
364 struct xenpf_mem_hotadd mem_add; 372 struct xenpf_mem_hotadd mem_add;
365 struct xenpf_core_parking core_parking; 373 struct xenpf_core_parking core_parking;
366 uint8_t pad[128]; 374 uint8_t pad[128];