[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH 08/10] xen/acpi: add cpu hotadd support
>From 282958be3a33b2f2b888e1ed3ac022bf8a199ec9 Mon Sep 17 00:00:00 2001 From: Liu Jinsong <jinsong.liu@xxxxxxxxx> Date: Wed, 14 Dec 2011 11:38:11 +0800 Subject: [PATCH 08/10] xen/acpi: add cpu hotadd support This patch add cpu hotadd support. It keep similar cpu hotadd logic as native, w/ some changes according to xen requirement, hypercalling hypervisor related logic to hotadd cpu. Signed-off-by: Liu, Jinsong <jinsong.liu@xxxxxxxxx> Signed-off-by: Jiang, Yunhong <yunhong.jiang@xxxxxxxxx> --- drivers/acpi/processor_driver.c | 4 +- drivers/acpi/processor_xen.c | 242 ++++++++++++++++++++++++++++++++++++++- include/acpi/processor.h | 2 + include/xen/pcpu.h | 2 + 4 files changed, 246 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index 8a367d7..d473fd5 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -221,7 +221,7 @@ static int acpi_processor_errata_piix4(struct pci_dev *dev) return 0; } -static int acpi_processor_errata(struct acpi_processor *pr) +int acpi_processor_errata(struct acpi_processor *pr) { int result = 0; struct pci_dev *dev = NULL; @@ -378,7 +378,7 @@ static int acpi_processor_get_info(struct acpi_device *device) return 0; } -static DEFINE_PER_CPU(void *, processor_device_array); +DEFINE_PER_CPU(void *, processor_device_array); void acpi_processor_notify(struct acpi_device *device, u32 event) { diff --git a/drivers/acpi/processor_xen.c b/drivers/acpi/processor_xen.c index 38a1c05..3af1f73 100644 --- a/drivers/acpi/processor_xen.c +++ b/drivers/acpi/processor_xen.c @@ -24,6 +24,7 @@ #define PREFIX "ACPI: " #define ACPI_PROCESSOR_CLASS "processor" +#define ACPI_PROCESSOR_DEVICE_NAME "Processor" #define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80 #define ACPI_PROCESSOR_NOTIFY_POWER 0x81 #define ACPI_PROCESSOR_NOTIFY_THROTTLING 0x82 @@ -88,6 +89,8 @@ xen_acpi_processor_hotadd_init(struct acpi_processor *pr, int *p_cpu) PROCESSOR_HOTPLUG, HOTPLUG_TYPE_ADD)) return AE_ERROR; + *p_cpu = xen_pcpu_index(pr->acpi_id, 1); + return AE_OK; } @@ -149,13 +152,248 @@ err_out: } #endif /* CONFIG_CPU_FREQ */ +static int xen_acpi_processor_get_info(struct acpi_device *device) +{ + acpi_status status = 0; + union acpi_object object = { 0 }; + struct acpi_buffer buffer = { sizeof(union acpi_object), &object }; + struct acpi_processor *pr; + int cpu_index, device_declaration = 0; + static int cpu0_initialized; + + pr = acpi_driver_data(device); + if (!pr) + return -EINVAL; + + if (num_online_cpus() > 1) + errata.smp = TRUE; + + acpi_processor_errata(pr); + + /* + * Check to see if we have bus mastering arbitration control. This + * is required for proper C3 usage (to maintain cache coherency). + */ + if (acpi_gbl_FADT.pm2_control_block && acpi_gbl_FADT.pm2_control_length) { + pr->flags.bm_control = 1; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Bus mastering arbitration control present\n")); + } else + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "No bus mastering arbitration control\n")); + + 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)) { + printk(KERN_ERR PREFIX "Evaluating processor object\n"); + return -ENODEV; + } + + /* + * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP. + * >>> 'acpi_get_processor_id(acpi_id, &id)' in + * arch/xxx/acpi.c + */ + pr->acpi_id = object.processor.proc_id; + } else { + /* + * Declared with "Device" statement; match _UID. + * Note that we don't handle string _UIDs yet. + */ + unsigned long long value; + status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID, + NULL, &value); + if (ACPI_FAILURE(status)) { + printk(KERN_ERR PREFIX + "Evaluating processor _UID [%#x]\n", status); + return -ENODEV; + } + device_declaration = 1; + pr->acpi_id = value; + } + + cpu_index = xen_pcpu_index(pr->acpi_id, 1); + + /* Handle UP system running SMP kernel, with no LAPIC in MADT */ + if (!cpu0_initialized && (cpu_index == -1) && + (num_online_cpus() == 1)) { + cpu_index = 0; + } + + cpu0_initialized = 1; + + pr->id = cpu_index; + + /* + * Extra Processor objects may be enumerated on MP systems with + * less than the max # of CPUs. They should be ignored _iff + * they are physically not present. + */ + if (pr->id == -1) { + if (ACPI_FAILURE + (xen_acpi_processor_hotadd_init(pr, &pr->id))) { + return -ENODEV; + } + } + /* + * On some boxes several processors use the same processor bus id. + * But they are located in different scope. For example: + * \_SB.SCK0.CPU0 + * \_SB.SCK1.CPU0 + * Rename the processor device bus id. And the new bus id will be + * generated as the following format: + * CPU+CPU ID. + */ + sprintf(acpi_device_bid(device), "CPU%X", pr->id); + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d:%d]\n", pr->id, + pr->acpi_id)); + + if (!object.processor.pblk_address) + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No PBLK (NULL address)\n")); + else if (object.processor.pblk_length != 6) + printk(KERN_ERR PREFIX "Invalid PBLK length [%d]\n", + object.processor.pblk_length); + else { + pr->throttling.address = object.processor.pblk_address; + pr->throttling.duty_offset = acpi_gbl_FADT.duty_offset; + pr->throttling.duty_width = acpi_gbl_FADT.duty_width; + + pr->pblk = object.processor.pblk_address; + + /* + * We don't care about error returns - we just try to mark + * these reserved so that nobody else is confused into thinking + * that this region might be unused.. + * + * (In particular, allocating the IO range for Cardbus) + */ + request_region(pr->throttling.address, 6, "ACPI CPU throttle"); + } + + /* + * If ACPI describes a slot number for this CPU, we can use it + * ensure we get the right value in the "physical id" field + * of /proc/cpuinfo + */ + status = acpi_evaluate_object(pr->handle, "_SUN", NULL, &buffer); + if (ACPI_SUCCESS(status)) + arch_fix_phys_package_id(pr->id, object.integer.value); + + return 0; +} + +static int __cpuinit __xen_acpi_processor_add(struct acpi_device *device) +{ + struct acpi_processor *pr = NULL; + int result = 0; + struct sys_device *sysdev; + + pr = kzalloc(sizeof(struct acpi_processor), GFP_KERNEL); + if (!pr) + return -ENOMEM; + + if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) { + kfree(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; + + result = xen_acpi_processor_get_info(device); + if (result) { + /* Processor is physically not present */ + return 0; + } + +#ifdef CONFIG_SMP + if (pr->id >= setup_max_cpus && pr->id != 0) + return 0; +#endif + + BUG_ON((pr->id >= nr_cpu_ids) || (pr->id < 0)); + + /* + * Buggy BIOS check + * ACPI id of processors can be reported wrongly by the BIOS. + * Don't trust it blindly + */ + if (per_cpu(processor_device_array, pr->id) != NULL && + per_cpu(processor_device_array, pr->id) != device) { + printk(KERN_WARNING "BIOS reported wrong ACPI id " + "for the processor\n"); + result = -ENODEV; + goto err_free_cpumask; + } + per_cpu(processor_device_array, pr->id) = device; + + per_cpu(processors, pr->id) = pr; + + sysdev = get_cpu_sysdev(pr->id); + if (sysfs_create_link(&device->dev.kobj, &sysdev->kobj, "sysdev")) { + result = -EFAULT; + goto err_free_cpumask; + } + +#ifdef CONFIG_CPU_FREQ + acpi_processor_ppc_has_changed(pr, 0); +#endif + acpi_processor_get_throttling_info(pr); + acpi_processor_get_limit_info(pr); + + + if (cpuidle_get_driver() == &acpi_idle_driver) + acpi_processor_power_init(pr, device); + + pr->cdev = thermal_cooling_device_register("Processor", device, + &processor_cooling_ops); + if (IS_ERR(pr->cdev)) { + result = PTR_ERR(pr->cdev); + goto err_power_exit; + } + + dev_dbg(&device->dev, "registered as cooling_device%d\n", + pr->cdev->id); + + result = sysfs_create_link(&device->dev.kobj, + &pr->cdev->device.kobj, + "thermal_cooling"); + if (result) { + printk(KERN_ERR PREFIX "Create sysfs link\n"); + goto err_thermal_unregister; + } + result = sysfs_create_link(&pr->cdev->device.kobj, + &device->dev.kobj, + "device"); + if (result) { + printk(KERN_ERR PREFIX "Create sysfs link\n"); + goto err_remove_sysfs; + } + + return 0; + +err_remove_sysfs: + sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); +err_thermal_unregister: + thermal_cooling_device_unregister(pr->cdev); +err_power_exit: + acpi_processor_power_exit(pr, device); +err_free_cpumask: + free_cpumask_var(pr->throttling.shared_cpu_map); + + return result; +} + static int __cpuinit xen_acpi_processor_add(struct acpi_device *device) { struct acpi_processor *pr = NULL; int result = 0; - result = acpi_processor_add(device); - if (result < 0) + result = __xen_acpi_processor_add(device); + if (result) return result; pr = acpi_driver_data(device); diff --git a/include/acpi/processor.h b/include/acpi/processor.h index c48e2f9..3a1ee01 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -225,6 +225,8 @@ struct acpi_processor_errata { } piix4; }; +extern int acpi_processor_errata(struct acpi_processor *pr); + extern int acpi_processor_preregister_performance(struct acpi_processor_performance __percpu *performance); diff --git a/include/xen/pcpu.h b/include/xen/pcpu.h index 7e8f9d1..3e99db9 100644 --- a/include/xen/pcpu.h +++ b/include/xen/pcpu.h @@ -4,6 +4,8 @@ #include <xen/interface/platform.h> #include <linux/sysdev.h> +extern DEFINE_PER_CPU(void *, processor_device_array); + extern int xen_pcpu_hotplug(int type, uint32_t apic_id); #define XEN_PCPU_ONLINE 0x01 #define XEN_PCPU_OFFLINE 0x02 -- 1.6.5.6 Attachment:
0008-xen-acpi-add-cpu-hotadd-support.patch _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |