On Tue, Jan 15, 2013 at 12:33:58PM +0000, Liu, Jinsong wrote: > >From c0166fed6d7ec8b902900157f02ad1eb189777d5 Mon Sep 17 00:00:00 2001 > From: Liu Jinsong <jinsong....@intel.com> > Date: Mon, 14 Jan 2013 15:21:24 +0800 > Subject: [PATCH 3/3] Xen processor driver > > This patch implement real Xen processor driver as module. > When loaded, it replaces Xen processor stub driver. > > For booting existed processor devices, Xen processor driver > enumerates them. For hotadded processor devices, which added > at runtime and notify OS via device or container event, Xen > processor driver is invoked to add them, parsing processors > information, hypercalling to Xen hypervisor to add processors, > and finally setting up new /sys interface for them. > > Signed-off-by: Liu Jinsong <jinsong....@intel.com> > --- > drivers/xen/Kconfig | 12 + > drivers/xen/Makefile | 1 + > drivers/xen/pcpu.c | 30 +++ > drivers/xen/xen-processor.c | 466 > ++++++++++++++++++++++++++++++++++++++ > include/xen/acpi.h | 2 + > include/xen/interface/platform.h | 8 + > 6 files changed, 519 insertions(+), 0 deletions(-) > create mode 100644 drivers/xen/xen-processor.c > > diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig > index 2dc7022..ca2535a 100644 > --- a/drivers/xen/Kconfig > +++ b/drivers/xen/Kconfig > @@ -202,6 +202,18 @@ config XEN_ACPI_HOTPLUG_MEMORY > to hot-add memory at runtime (the hot-added memory cannot be > removed until machine stop), select Y/M here, otherwise select N. > > +config XEN_PROCESSOR
I think the name should be XEN_ACPI_PROCESSOR but then the xen-acpi-processor gets in the way. Hm, perhaps this should be then called xen-acpi-cpu-hotplug.c ? Would that work? Or xen-acpi-cpu.c? So then it is called 'XEN_ACPI_CPU' ? > + tristate "Xen processor driver" > + depends on XEN_STUB && ACPI Is there anytime a scenario where the user might compile a kernel without DOM0 support, but with Xen_stub && ACPI? > + select ACPI_CONTAINER > + default n > + help > + Xen processor enumerating and hotplugging > + > + For hotplugging, currently Xen only support ACPI cpu hotadd. > + If you want to hotadd cpu at runtime (the hotadded cpu cannot > + be removed until machine stop), select Y/M here, otherwise N. > + > config XEN_ACPI_PROCESSOR > tristate "Xen ACPI processor" > depends on XEN && X86 && ACPI_PROCESSOR && CPU_FREQ > diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile > index 1605f59..82163e6 100644 > --- a/drivers/xen/Makefile > +++ b/drivers/xen/Makefile > @@ -32,6 +32,7 @@ obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback/ > obj-$(CONFIG_XEN_PRIVCMD) += xen-privcmd.o > obj-$(CONFIG_XEN_STUB) += xen-stub.o > obj-$(CONFIG_XEN_ACPI_HOTPLUG_MEMORY) += xen-acpi-memhotplug.o > +obj-$(CONFIG_XEN_PROCESSOR) += xen-processor.o > obj-$(CONFIG_XEN_ACPI_PROCESSOR) += xen-acpi-processor.o > xen-evtchn-y := evtchn.o > xen-gntdev-y := gntdev.o > diff --git a/drivers/xen/pcpu.c b/drivers/xen/pcpu.c > index 067fcfa..2fd5e78 100644 > --- a/drivers/xen/pcpu.c > +++ b/drivers/xen/pcpu.c > @@ -333,6 +333,36 @@ static irqreturn_t xen_pcpu_interrupt(int irq, void > *dev_id) > return IRQ_HANDLED; > } > Please explain why this is neccessary. Preferable via a comment in the code > +void xen_pcpu_hotplug_sync(void) > +{ > + schedule_work(&xen_pcpu_work); > +} > +EXPORT_SYMBOL_GPL(xen_pcpu_hotplug_sync); > + Please give it a nice comment explaining what it does. > +int xen_pcpu_id(uint32_t acpi_id) > +{ > + int cpu_id = 0, max_id = 0; > + struct xen_platform_op op; > + > + op.cmd = XENPF_get_cpuinfo; > + while (cpu_id <= max_id) { > + op.u.pcpu_info.xen_cpuid = cpu_id; > + if (HYPERVISOR_dom0_op(&op)) { > + cpu_id++; > + continue; > + } > + > + if (acpi_id == op.u.pcpu_info.acpi_id) > + return cpu_id; > + if (op.u.pcpu_info.max_present > max_id) > + max_id = op.u.pcpu_info.max_present; > + cpu_id++; > + } > + > + return -ENODEV; > +} > +EXPORT_SYMBOL_GPL(xen_pcpu_id); > + > static int __init xen_pcpu_init(void) > { > int irq, ret; > diff --git a/drivers/xen/xen-processor.c b/drivers/xen/xen-processor.c > new file mode 100644 > index 0000000..c5e39b6 > --- /dev/null > +++ b/drivers/xen/xen-processor.c > @@ -0,0 +1,466 @@ > +/* > + * Copyright (C) 2012 Intel Corporation > + * Author: Liu Jinsong <jinsong....@intel.com> > + * Author: Jiang Yunhong <yunhong.ji...@intel.com> > + * > + * 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, GOOD TITLE or > + * NON INFRINGEMENT. See the GNU General Public License for more > + * details. > + */ > + > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/init.h> > +#include <linux/types.h> > +#include <linux/cpu.h> > +#include <linux/acpi.h> > +#include <linux/uaccess.h> > +#include <acpi/acpi_bus.h> > +#include <acpi/acpi_drivers.h> > +#include <acpi/processor.h> > + > +#include <xen/acpi.h> > +#include <xen/interface/platform.h> > +#include <asm/xen/hypercall.h> > + > +#define PREFIX "ACPI:xen_cpu_hotplug:" So 'xen_cpu_hotplug' here but later on: ACPI_MODULE_NAME("xen-processor"); I think the "xen-acpi-cpu-hotplug" or "xen-acpi-cpu" would sound much better. > + > +#define INSTALL_NOTIFY_HANDLER 0 > +#define UNINSTALL_NOTIFY_HANDLER 1 > + > +static acpi_status xen_acpi_cpu_hotadd(struct acpi_processor *pr); > + > +/* -------------------------------------------------------------------------- > + Driver Interface > +-------------------------------------------------------------------------- */ > + > +static int xen_acpi_processor_enable(struct acpi_device *device) > +{ > + acpi_status status = 0; > + unsigned long long value; > + union acpi_object object = { 0 }; > + struct acpi_buffer buffer = { sizeof(union acpi_object), &object }; > + struct acpi_processor *pr; > + > + pr = acpi_driver_data(device); > + if (!pr) { > + pr_err(PREFIX "Cannot find driver data\n"); > + return -EINVAL; > + } > + > + if (!strcmp(acpi_device_hid(device), ACPI_PROCESSOR_OBJECT_HID)) { > + /* Declared with "Processor" statement; match ProcessorID */ > + status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer); > + if (ACPI_FAILURE(status)) { > + pr_err(PREFIX "Evaluating processor object\n"); > + return -ENODEV; > + } > + > + pr->acpi_id = object.processor.proc_id; > + } else { > + /* Declared with "Device" statement; match _UID */ > + status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID, > + NULL, &value); > + if (ACPI_FAILURE(status)) { > + pr_err(PREFIX "Evaluating processor _UID\n"); > + return -ENODEV; > + } > + > + pr->acpi_id = value; > + } > + > + pr->id = xen_pcpu_id(pr->acpi_id); > + > + if ((int)pr->id < 0) > + if (ACPI_FAILURE(xen_acpi_cpu_hotadd(pr))) { > + pr_err(PREFIX "Hotadd CPU (acpi_id = %d) fail.\n", failed > + pr->acpi_id); > + return -ENODEV; > + } > + > + return 0; > +} > + > +static int __cpuinit xen_acpi_processor_add(struct acpi_device *device) > +{ > + int ret; > + struct acpi_processor *pr; > + > + if (!device) > + return -EINVAL; > + > + pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL); > + if (!pr) > + return -ENOMEM; > + > + pr->handle = device->handle; > + strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME); > + strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS); > + device->driver_data = pr; > + > + ret = xen_acpi_processor_enable(device); > + if (ret) > + pr_err(PREFIX "Error when enable Xen processor\n"); Um. "Error when enabling Xen processor" > + > + return ret; > +} > + > +static int xen_acpi_processor_remove(struct acpi_device *device, int type) > +{ > + struct acpi_processor *pr; > + > + if (!device) > + return -EINVAL; > + > + pr = acpi_driver_data(device); > + if (!pr) > + return -EINVAL; > + > + kfree(pr); > + return 0; > +} > + > +/*-------------------------------------------------------------- > + Acpi processor hotplug support > +--------------------------------------------------------------*/ > + > +static int is_processor_present(acpi_handle handle) > +{ > + acpi_status status; > + unsigned long long sta = 0; > + > + > + status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); > + > + if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_PRESENT)) > + return 1; > + > + /* > + * _STA is mandatory for a processor that supports hot plug > + */ > + if (status == AE_NOT_FOUND) > + pr_info(PREFIX "Processor does not support hot plug\n"); > + else > + pr_info(PREFIX "Processor Device is not present"); > + return 0; > +} > + > +static int xen_apic_id(acpi_handle handle) > +{ > + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; > + union acpi_object *obj; > + struct acpi_madt_local_apic *lapic; > + int apic_id; > + > + if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer))) > + return -EINVAL; > + > + if (!buffer.length || !buffer.pointer) > + return -EINVAL; > + > + obj = buffer.pointer; > + if (obj->type != ACPI_TYPE_BUFFER || > + obj->buffer.length < sizeof(*lapic)) { > + kfree(buffer.pointer); > + return -EINVAL; > + } > + > + lapic = (struct acpi_madt_local_apic *)obj->buffer.pointer; > + > + if (lapic->header.type != ACPI_MADT_TYPE_LOCAL_APIC || > + !(lapic->lapic_flags & ACPI_MADT_ENABLED)) { > + kfree(buffer.pointer); > + return -EINVAL; > + } > + > + apic_id = (uint32_t)lapic->id; > + kfree(buffer.pointer); > + buffer.length = ACPI_ALLOCATE_BUFFER; > + buffer.pointer = NULL; > + > + return apic_id; > +} > + > +static int xen_hotadd_cpu(struct acpi_processor *pr) > +{ > + int cpu_id, apic_id, pxm; > + struct xen_platform_op op; > + > + apic_id = xen_apic_id(pr->handle); > + if (apic_id < 0) { > + pr_err(PREFIX "Fail to get apic_id for acpi_id %d\n", > + pr->acpi_id); Failed > + return -ENODEV; > + } > + > + pxm = xen_acpi_get_pxm(pr->handle); > + if (pxm < 0) { > + pr_err(PREFIX "Fail to get _PXM for acpi_id %d\n", > + pr->acpi_id); Failed > + return pxm; > + } > + > + op.cmd = XENPF_cpu_hotadd; > + op.u.cpu_add.apic_id = apic_id; > + op.u.cpu_add.acpi_id = pr->acpi_id; > + op.u.cpu_add.pxm = pxm; > + > + cpu_id = HYPERVISOR_dom0_op(&op); > + if (cpu_id < 0) > + pr_err(PREFIX "Fail to hotadd CPU for acpi_id %d\n", Failed .. > + pr->acpi_id); > + > + return cpu_id; > +} > + > +static acpi_status xen_acpi_cpu_hotadd(struct acpi_processor *pr) > +{ > + if (!is_processor_present(pr->handle)) > + return AE_ERROR; > + > + pr->id = xen_hotadd_cpu(pr); > + if ((int)pr->id < 0) > + return AE_ERROR; > + > + xen_pcpu_hotplug_sync(); > + > + return AE_OK; > +} > + > +static > +int acpi_processor_device_add(acpi_handle handle, struct acpi_device > **device) > +{ > + acpi_handle phandle; > + struct acpi_device *pdev; > + > + if (acpi_get_parent(handle, &phandle)) > + return -ENODEV; > + > + if (acpi_bus_get_device(phandle, &pdev)) > + return -ENODEV; > + > + if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR)) > + return -ENODEV; > + > + return 0; > +} > + > +static int acpi_processor_device_remove(struct acpi_device *device) > +{ > + pr_debug(PREFIX "Xen does not support CPU hotremove\n"); > + > + return -ENOSYS; > +} > + > +static void acpi_processor_hotplug_notify(acpi_handle handle, > + u32 event, void *data) > +{ > + struct acpi_processor *pr; > + struct acpi_device *device = NULL; > + u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */ > + int result; > + > + switch (event) { > + case ACPI_NOTIFY_BUS_CHECK: > + case ACPI_NOTIFY_DEVICE_CHECK: > + ACPI_DEBUG_PRINT((ACPI_DB_INFO, > + "Processor driver received %s event\n", > + (event == ACPI_NOTIFY_BUS_CHECK) ? > + "ACPI_NOTIFY_BUS_CHECK" : "ACPI_NOTIFY_DEVICE_CHECK")); > + > + if (!is_processor_present(handle)) > + break; > + > + if (!acpi_bus_get_device(handle, &device)) > + break; > + > + result = acpi_processor_device_add(handle, &device); > + if (result) { > + pr_err(PREFIX "Unable to add the device\n"); > + break; > + } > + > + ost_code = ACPI_OST_SC_SUCCESS; > + break; > + > + case ACPI_NOTIFY_EJECT_REQUEST: > + ACPI_DEBUG_PRINT((ACPI_DB_INFO, > + "received ACPI_NOTIFY_EJECT_REQUEST\n")); > + > + if (acpi_bus_get_device(handle, &device)) { > + pr_err(PREFIX "Device don't exist, dropping EJECT\n"); > + break; > + } > + pr = acpi_driver_data(device); > + if (!pr) { > + pr_err(PREFIX "Driver data is NULL, dropping EJECT\n"); > + break; > + } > + > + /* > + * TBD: implement acpi_processor_device_remove if Xen support > + * CPU hotremove in the future. > + */ > + acpi_processor_device_remove(device); > + break; > + > + default: > + ACPI_DEBUG_PRINT((ACPI_DB_INFO, > + "Unsupported event [0x%x]\n", event)); > + > + /* non-hotplug event; possibly handled by other handler */ > + return; > + } > + > + (void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL); > + return; > +} > + > +static acpi_status is_processor_device(acpi_handle handle) > +{ > + struct acpi_device_info *info; > + char *hid; > + acpi_status status; > + > + status = acpi_get_object_info(handle, &info); > + if (ACPI_FAILURE(status)) > + return status; > + > + if (info->type == ACPI_TYPE_PROCESSOR) { > + kfree(info); > + return AE_OK; /* found a processor object */ > + } > + > + if (!(info->valid & ACPI_VALID_HID)) { > + kfree(info); > + return AE_ERROR; > + } > + > + hid = info->hardware_id.string; > + if ((hid == NULL) || strcmp(hid, ACPI_PROCESSOR_DEVICE_HID)) { > + kfree(info); > + return AE_ERROR; > + } > + > + kfree(info); > + return AE_OK; /* found a processor device object */ > +} > + > +static acpi_status > +processor_walk_namespace_cb(acpi_handle handle, > + u32 lvl, void *context, void **rv) > +{ > + acpi_status status; > + int *action = context; > + > + status = is_processor_device(handle); > + if (ACPI_FAILURE(status)) > + return AE_OK; /* not a processor; continue to walk */ > + > + switch (*action) { > + case INSTALL_NOTIFY_HANDLER: > + acpi_install_notify_handler(handle, > + ACPI_SYSTEM_NOTIFY, > + acpi_processor_hotplug_notify, > + NULL); > + break; > + case UNINSTALL_NOTIFY_HANDLER: > + acpi_remove_notify_handler(handle, > + ACPI_SYSTEM_NOTIFY, > + acpi_processor_hotplug_notify); > + break; > + default: > + break; > + } > + > + /* found a processor; skip walking underneath */ > + return AE_CTRL_DEPTH; > +} > + > +static > +void acpi_processor_install_hotplug_notify(void) > +{ > + int action = INSTALL_NOTIFY_HANDLER; > + acpi_walk_namespace(ACPI_TYPE_ANY, > + ACPI_ROOT_OBJECT, > + ACPI_UINT32_MAX, > + processor_walk_namespace_cb, NULL, &action, NULL); > +} > + > +static > +void acpi_processor_uninstall_hotplug_notify(void) > +{ > + int action = UNINSTALL_NOTIFY_HANDLER; > + acpi_walk_namespace(ACPI_TYPE_ANY, > + ACPI_ROOT_OBJECT, > + ACPI_UINT32_MAX, > + processor_walk_namespace_cb, NULL, &action, NULL); > +} > + > +static const struct acpi_device_id processor_device_ids[] = { > + {ACPI_PROCESSOR_OBJECT_HID, 0}, > + {ACPI_PROCESSOR_DEVICE_HID, 0}, > + {"", 0}, > +}; > +MODULE_DEVICE_TABLE(acpi, processor_device_ids); > + > +static struct acpi_driver xen_acpi_processor_driver = { > + .name = "processor", > + .class = ACPI_PROCESSOR_CLASS, > + .ids = processor_device_ids, > + .ops = { > + .add = xen_acpi_processor_add, > + .remove = xen_acpi_processor_remove, > + }, > +}; > + > +static int __init xen_acpi_processor_init(void) > +{ > + int result = 0; > + > + if (!xen_initial_domain()) > + return -ENODEV; > + > + /* unregister the stub which only used to reserve driver space */ > + acpi_bus_unregister_driver(&xen_stub_processor_driver); So looking at my comments, perhaps you could make the xen_stub_processor_unint(void) return the 'struct acpi_driver *'? That way you can do: old = xen_stub_processor_deinit(void); > + > + result = acpi_bus_register_driver(&xen_acpi_processor_driver); > + if (result < 0) { > + acpi_bus_register_driver(&xen_stub_processor_driver); and here do: acpi_bus_register_driver(old); > + return result; > + } > + > + acpi_processor_install_hotplug_notify(); > + return 0; > +} > + > +static void __exit xen_acpi_processor_exit(void) > +{ > + if (!xen_initial_domain()) > + return; > + > + acpi_processor_uninstall_hotplug_notify(); > + > + acpi_bus_unregister_driver(&xen_acpi_processor_driver); > + > + /* > + * stub reserve space again to prevent any chance of native > + * driver loading. > + */ > + acpi_bus_register_driver(&xen_stub_processor_driver); > + return; > +} > + > +module_init(xen_acpi_processor_init); > +module_exit(xen_acpi_processor_exit); > +ACPI_MODULE_NAME("xen-processor"); > +MODULE_AUTHOR("Liu Jinsong <jinsong....@intel.com>"); > +MODULE_DESCRIPTION("Xen Processor Driver"); Xen ACPI Processor Driver > +MODULE_LICENSE("GPL"); > diff --git a/include/xen/acpi.h b/include/xen/acpi.h > index 5ac46d3..3de217e 100644 > --- a/include/xen/acpi.h > +++ b/include/xen/acpi.h > @@ -45,6 +45,8 @@ > #define ACPI_MEMORY_DEVICE_NAME "Hotplug Mem Device" > > extern struct acpi_driver xen_stub_memory_device_driver; > +extern void xen_pcpu_hotplug_sync(void); > +extern int xen_pcpu_id(uint32_t acpi_id); > > static inline int xen_acpi_get_pxm(acpi_handle h) > { > diff --git a/include/xen/interface/platform.h > b/include/xen/interface/platform.h > index 2c4fb4b..c57d5f6 100644 > --- a/include/xen/interface/platform.h > +++ b/include/xen/interface/platform.h > @@ -324,6 +324,13 @@ struct xenpf_cpu_ol { > }; > DEFINE_GUEST_HANDLE_STRUCT(xenpf_cpu_ol); > > +#define XENPF_cpu_hotadd 58 > +struct xenpf_cpu_hotadd { > + uint32_t apic_id; > + uint32_t acpi_id; > + uint32_t pxm; > +}; > + > #define XENPF_mem_hotadd 59 > struct xenpf_mem_hotadd { > uint64_t spfn; > @@ -361,6 +368,7 @@ struct xen_platform_op { > struct xenpf_set_processor_pminfo set_pminfo; > struct xenpf_pcpuinfo pcpu_info; > struct xenpf_cpu_ol cpu_ol; > + struct xenpf_cpu_hotadd cpu_add; > struct xenpf_mem_hotadd mem_add; > struct xenpf_core_parking core_parking; > uint8_t pad[128]; > -- > 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/