From 282958be3a33b2f2b888e1ed3ac022bf8a199ec9 Mon Sep 17 00:00:00 2001 From: Liu Jinsong <jinsong.liu@intel.com> 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@intel.com> Signed-off-by: Jiang, Yunhong <yunhong.jiang@intel.com> --- 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 _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
From 282958be3a33b2f2b888e1ed3ac022bf8a199ec9 Mon Sep 17 00:00:00 2001 From: Liu Jinsong <jinsong.liu@intel.com> 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@intel.com> Signed-off-by: Jiang, Yunhong <yunhong.jiang@intel.com> --- 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
Konrad Rzeszutek Wilk
2012-Oct-03 13:31 UTC
Re: [PATCH 08/10] xen/acpi: add cpu hotadd support
On Thu, Dec 22, 2011 at 10:08:34AM +0000, Liu, Jinsong wrote:> >From 282958be3a33b2f2b888e1ed3ac022bf8a199ec9 Mon Sep 17 00:00:00 2001 > From: Liu Jinsong <jinsong.liu@intel.com> > 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.Is this needed anymore? Or is the existing code in the upstream kernel sufficient enough for this? Or do we need a hotplug CPU notifier in the xen-acpi-processor?> > Signed-off-by: Liu, Jinsong <jinsong.liu@intel.com> > Signed-off-by: Jiang, Yunhong <yunhong.jiang@intel.com> > --- > 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