[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH][1/2] pvops-dom0: Xen acpi processor logic cleanup
Base on git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen.git branch: xen/dom0/acpi-parser ==== Xen acpi processor logic cleanup From: Yu Ke <ke.yu@xxxxxxxxx> current xen acpi processor logic scattered in several places and mixed with other acpi_processor_driver logic. this patch try to split these logic out and consolidate them into a new xen acpi_processor_driver. this will make xen acpi processor logic more clean Signed-off-by: Yu Ke <ke.yu@xxxxxxxxx> --- arch/x86/kernel/acpi/processor.c | 16 +- drivers/acpi/processor_core.c | 344 ++++++++++++++++++++++++++++++++++++-- drivers/acpi/processor_idle.c | 94 ++++++++++ drivers/acpi/processor_perflib.c | 21 ++ include/acpi/processor.h | 9 + 5 files changed, 456 insertions(+), 28 deletions(-) diff --git a/arch/x86/kernel/acpi/processor.c b/arch/x86/kernel/acpi/processor.c index 721272b..05ef6a6 100644 --- a/arch/x86/kernel/acpi/processor.c +++ b/arch/x86/kernel/acpi/processor.c @@ -79,9 +79,6 @@ void arch_acpi_processor_init_pdc(struct acpi_processor *pr) { struct cpuinfo_x86 *c = &cpu_data(pr->id); - if (xen_pv_domain()) - c = &cpu_data(0); - pr->pdc = NULL; if (c->x86_vendor == X86_VENDOR_INTEL) init_intel_pdc(pr, c); @@ -91,6 +88,19 @@ void arch_acpi_processor_init_pdc(struct acpi_processor *pr) EXPORT_SYMBOL(arch_acpi_processor_init_pdc); +/* Initialize _PDC data based on the CPU vendor */ +void xen_arch_acpi_processor_init_pdc(struct acpi_processor *pr) +{ + struct cpuinfo_x86 *c = &cpu_data(0); + + pr->pdc = NULL; + if (c->x86_vendor == X86_VENDOR_INTEL) + init_intel_pdc(pr, c); + + return; +} +EXPORT_SYMBOL(xen_arch_acpi_processor_init_pdc); + void arch_acpi_processor_cleanup_pdc(struct acpi_processor *pr) { if (pr->pdc) { diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 98010d5..6a35118 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -87,6 +87,8 @@ static void acpi_processor_notify(struct acpi_device *device, u32 event); static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu); static int acpi_processor_handle_eject(struct acpi_processor *pr); +static int xen_acpi_processor_start(struct acpi_device *device); +static void xen_acpi_processor_notify(struct acpi_device *device, u32 event); static const struct acpi_device_id processor_device_ids[] = { {ACPI_PROCESSOR_OBJECT_HID, 0}, @@ -109,6 +111,20 @@ static struct acpi_driver acpi_processor_driver = { }, }; +static struct acpi_driver xen_acpi_processor_driver = { + .name = "processor", + .class = ACPI_PROCESSOR_CLASS, + .ids = processor_device_ids, + .ops = { + .add = acpi_processor_add, + .remove = acpi_processor_remove, + .start = xen_acpi_processor_start, + .suspend = acpi_processor_suspend, + .resume = acpi_processor_resume, + .notify = xen_acpi_processor_notify, + }, +}; + #define INSTALL_NOTIFY_HANDLER 1 #define UNINSTALL_NOTIFY_HANDLER 2 @@ -411,6 +427,10 @@ static int acpi_processor_remove_fs(struct acpi_device *device) #ifndef CONFIG_SMP static int get_cpu_id(acpi_handle handle, int type, u32 acpi_id) { return -1; } +static int is_processor_apic_enabled(struct acpi_processor *pr, int type) +{ + return 0; +} #else static struct acpi_table_madt *madt; @@ -561,6 +581,26 @@ static int get_cpu_id(acpi_handle handle, int type, u32 acpi_id) } return -1; } + +/* + * check the MADT entry to see if its apic is enabled or not. + * + * in Xen domain 0 case, one acpi processor may be physically present + * but not enumerated due to #vCPU != #pCPU + * this function can be used to check this case. + */ +static int is_processor_apic_enabled(struct acpi_processor *pr, int type) +{ + + int apic_id; + + apic_id = map_mat_entry(pr->handle, type, pr->acpi_id); + if (apic_id == -1) + apic_id = map_madt_entry(type, pr->acpi_id); + + return (apic_id != -1); +} + #endif /* -------------------------------------------------------------------------- @@ -639,9 +679,6 @@ static int acpi_processor_get_info(struct acpi_device *device) pr->id = cpu_index; - if (xen_pv_domain()) - pr->id = pr->acpi_id; - /* * Extra Processor objects may be enumerated on MP systems with * less than the max # of CPUs. They should be ignored _iff @@ -716,17 +753,15 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device) return 0; } - if (!xen_pv_domain()) - BUG_ON((pr->id >= nr_cpu_ids) || (pr->id < 0)); + 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 (!xen_pv_domain() && - per_cpu(processor_device_array, pr->id) != NULL && - per_cpu(processor_device_array, pr->id) != device) { + 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"); return -ENODEV; @@ -758,10 +793,6 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device) acpi_processor_power_init(pr, device); - result = processor_cntl_xen_prepare(pr); - if (result) - goto end; - pr->cdev = thermal_cooling_device_register("Processor", device, &processor_cooling_ops); if (IS_ERR(pr->cdev)) { @@ -1165,6 +1196,284 @@ void acpi_processor_uninstall_hotplug_notify(void) } /* + * xen specific ACPI processor driver + */ + +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 = get_cpu_id(pr->handle, device_declaration, pr->acpi_id); + + /* 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, or Xen vCPU < pCPU. + * They should be ignored _iff they are physically not present. + * + */ + if (pr->id == -1) { + if (ACPI_FAILURE(acpi_processor_hotadd_init(pr->handle, &pr->id)) + && !is_processor_apic_enabled(pr, device_declaration)) + 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; +} + +#define MAX_ACPI_ID 255 + +static struct acpi_device *processor_device_array[MAX_ACPI_ID + 1]; + +static int __cpuinit xen_acpi_processor_start(struct acpi_device *device) +{ + int result = 0; + struct acpi_processor *pr; + + pr = acpi_driver_data(device); + + result = xen_acpi_processor_get_info(device); + if (result) { + /* Processor is physically not present */ + return 0; + } + + if (pr->acpi_id > MAX_ACPI_ID) + return 0; + /* + * Buggy BIOS check + * ACPI id of processors can be reported wrongly by the BIOS. + * Don't trust it blindly + */ + if (processor_device_array[pr->acpi_id] != NULL && + processor_device_array[pr->acpi_id] != device) { + printk(KERN_WARNING "BIOS reported wrong ACPI id " + "for the processor\n"); + return -ENODEV; + } + + processor_device_array[pr->acpi_id] = device; + + if (pr->id != -1) { + per_cpu(processors, pr->id) = pr; + + result = acpi_processor_add_fs(device); + if (result) + goto end; + } + + /* _PDC call should be done before doing anything else (if reqd.). */ + xen_arch_acpi_processor_init_pdc(pr); + acpi_processor_set_pdc(pr); + arch_acpi_processor_cleanup_pdc(pr); + +#ifdef CONFIG_CPU_FREQ + xen_acpi_processor_ppc_has_changed(pr); +#endif + + /* + * pr->id may equal to -1 while Xen enabled. + * throttle and thermal module don't support this case. + * Tx only works when dom0 vcpu == pcpu num by far, as we give + * control to dom0. + */ + if (pr->id != -1) { + acpi_processor_get_throttling_info(pr); + acpi_processor_get_limit_info(pr); + } + + xen_acpi_processor_power_init(pr, device); + + result = processor_cntl_xen_prepare(pr); + if (result) + goto end; + + if (pr->id != -1) { + pr->cdev = thermal_cooling_device_register("Processor", device, + &processor_cooling_ops); + if (IS_ERR(pr->cdev)) { + result = PTR_ERR(pr->cdev); + goto end; + } + + dev_info(&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"); + result = sysfs_create_link(&pr->cdev->device.kobj, + &device->dev.kobj, + "device"); + if (result) + printk(KERN_ERR PREFIX "Create sysfs link\n"); + + if (pr->flags.throttling) { + printk(KERN_INFO PREFIX "%s [%s] (supports", + acpi_device_name(device), acpi_device_bid(device)); + printk(" %d throttling states", pr->throttling.state_count); + printk(")\n"); + } + } + +end: + + return result; +} + +static void xen_acpi_processor_notify(struct acpi_device *device, u32 event) +{ + struct acpi_processor *pr = acpi_driver_data(device); + int saved; + + if (!pr) + return; + + switch (event) { + case ACPI_PROCESSOR_NOTIFY_PERFORMANCE: + saved = pr->performance_platform_limit; + xen_acpi_processor_ppc_has_changed(pr); + if (saved == pr->performance_platform_limit) + break; + acpi_bus_generate_proc_event(device, event, + pr->performance_platform_limit); + acpi_bus_generate_netlink_event(device->pnp.device_class, + dev_name(&device->dev), event, + pr->performance_platform_limit); + break; + case ACPI_PROCESSOR_NOTIFY_POWER: + xen_acpi_processor_cst_has_changed(pr); + acpi_bus_generate_proc_event(device, event, 0); + acpi_bus_generate_netlink_event(device->pnp.device_class, + dev_name(&device->dev), event, 0); + break; + case ACPI_PROCESSOR_NOTIFY_THROTTLING: + acpi_processor_tstate_has_changed(pr); + acpi_bus_generate_proc_event(device, event, 0); + acpi_bus_generate_netlink_event(device->pnp.device_class, + dev_name(&device->dev), event, 0); + default: + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Unsupported event [0x%x]\n", event)); + break; + } + + return; +} + +/* * We keep the driver loaded even when ACPI is not running. * This is needed for the powernow-k8 driver, that works even without * ACPI, but needs symbols from this driver @@ -1198,7 +1507,11 @@ static int __init acpi_processor_init(void) if (result < 0) goto out_proc; - result = acpi_bus_register_driver(&acpi_processor_driver); + if (xen_initial_domain()) + result = acpi_bus_register_driver(&xen_acpi_processor_driver); + else + result = acpi_bus_register_driver(&acpi_processor_driver); + if (result < 0) goto out_cpuidle; @@ -1232,7 +1545,10 @@ static void __exit acpi_processor_exit(void) acpi_processor_uninstall_hotplug_notify(); - acpi_bus_unregister_driver(&acpi_processor_driver); + if (xen_initial_domain()) + acpi_bus_unregister_driver(&xen_acpi_processor_driver); + else + acpi_bus_unregister_driver(&acpi_processor_driver); cpuidle_unregister_driver(&acpi_idle_driver); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 25680c6..1b382e2 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -1148,13 +1148,6 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) if (!pr->flags.power_setup_done) return -ENODEV; - if (xen_initial_domain()) { - acpi_processor_get_power_info(pr); - processor_cntl_xen_notify(pr, - PROCESSOR_PM_CHANGE, PM_TYPE_IDLE); - return ret; - } - cpuidle_pause_and_lock(); cpuidle_disable_device(&pr->power.dev); acpi_processor_get_power_info(pr); @@ -1167,6 +1160,44 @@ int acpi_processor_cst_has_changed(struct acpi_processor *pr) return ret; } +static int xen_acpi_processor_get_power_info(struct acpi_processor *pr) +{ + int ret; + int invalid_pr_id = 0; + + /* + * acpi_processor_get_power_info need valid pr->id + * so set pr->id=0 temporarily + */ + if (pr->id == -1) { + invalid_pr_id = 1; + pr->id = 0; + } + + ret = acpi_processor_get_power_info(pr); + + if (invalid_pr_id) + pr->id = -1; + + return ret; +} + +int xen_acpi_processor_cst_has_changed(struct acpi_processor *pr) +{ + if (!pr) + return -EINVAL; + + if (!pr->flags.power_setup_done) + return -ENODEV; + + xen_acpi_processor_get_power_info(pr); + + processor_cntl_xen_notify(pr, + PROCESSOR_PM_CHANGE, PM_TYPE_IDLE); + + return 0; +} + int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, struct acpi_device *device) { @@ -1245,6 +1276,55 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr, return 0; } +int __cpuinit xen_acpi_processor_power_init(struct acpi_processor *pr, + struct acpi_device *device) +{ + acpi_status status = 0; + struct proc_dir_entry *entry = NULL; + unsigned int i; + + if (!pr) + return -EINVAL; + + if (acpi_gbl_FADT.cst_control) { + status = acpi_os_write_port(acpi_gbl_FADT.smi_command, + acpi_gbl_FADT.cst_control, 8); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, + "Notifying BIOS of _CST ability failed")); + } + } + + xen_acpi_processor_get_power_info(pr); + + pr->flags.power_setup_done = 1; + + if (pr->flags.power) { + processor_cntl_xen_notify(pr, + PROCESSOR_PM_INIT, PM_TYPE_IDLE); + + printk(KERN_INFO PREFIX "CPU%d (power states:", pr->id); + for (i = 1; i <= pr->power.count; i++) + if (pr->power.states[i].valid) + printk(" C%d[C%d]", i, + pr->power.states[i].type); + printk(")\n"); + } + + if (pr->id != -1) { + /* 'power' [R] + */ + entry = proc_create_data(ACPI_PROCESSOR_FILE_POWER, + S_IRUGO, acpi_device_dir(device), + &acpi_processor_power_fops, + acpi_driver_data(device)); + if (!entry) + return -EIO; + } + + return 0; +} + int acpi_processor_power_exit(struct acpi_processor *pr, struct acpi_device *device) { diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 8375075..f17e740 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -155,20 +155,33 @@ int acpi_processor_ppc_has_changed(struct acpi_processor *pr) { int ret; - if (ignore_ppc && !processor_cntl_xen_pmperf()) + if (ignore_ppc) return 0; ret = acpi_processor_get_platform_limit(pr); if (ret < 0) return (ret); - else if (processor_cntl_xen_pmperf()) - return processor_cntl_xen_notify(pr, - PROCESSOR_PM_CHANGE, PM_TYPE_PERF); else return cpufreq_update_policy(pr->id); } +int xen_acpi_processor_ppc_has_changed(struct acpi_processor *pr) +{ + int ret; + + if (!processor_cntl_xen_pmperf()) + return 0; + + ret = acpi_processor_get_platform_limit(pr); + + if (ret < 0) + return ret; + else + return processor_cntl_xen_notify(pr, + PROCESSOR_PM_CHANGE, PM_TYPE_PERF); +} + void acpi_processor_ppc_init(void) { if (!cpufreq_register_notifier diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 221d30d..c806ecf 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -259,6 +259,7 @@ extern struct acpi_processor_errata errata; void arch_acpi_processor_init_pdc(struct acpi_processor *pr); void arch_acpi_processor_cleanup_pdc(struct acpi_processor *pr); +void xen_arch_acpi_processor_init_pdc(struct acpi_processor *pr); #ifdef ARCH_HAS_POWER_INIT void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags, @@ -297,6 +298,7 @@ void acpi_processor_ppc_exit(void); int acpi_processor_ppc_has_changed(struct acpi_processor *pr); int acpi_processor_get_performance_info(struct acpi_processor *pr); int acpi_processor_get_psd(struct acpi_processor *pr); +int xen_acpi_processor_ppc_has_changed(struct acpi_processor *pr); #else static inline void acpi_processor_ppc_init(void) { @@ -318,6 +320,10 @@ static inline int acpi_processor_ppc_has_changed(struct acpi_processor *pr) } return 0; } +static inline int xen_acpi_processor_ppc_has_changed(struct acpi_processor *pr) +{ + return acpi_processor_ppc_has_changed(pr); +} #endif /* CONFIG_CPU_FREQ */ /* in processor_throttling.c */ @@ -330,7 +336,10 @@ extern void acpi_processor_throttling_init(void); /* in processor_idle.c */ int acpi_processor_power_init(struct acpi_processor *pr, struct acpi_device *device); +int xen_acpi_processor_power_init(struct acpi_processor *pr, + struct acpi_device *device); int acpi_processor_cst_has_changed(struct acpi_processor *pr); +int xen_acpi_processor_cst_has_changed(struct acpi_processor *pr); int acpi_processor_power_exit(struct acpi_processor *pr, struct acpi_device *device); int acpi_processor_suspend(struct acpi_device * device, pm_message_t state); Attachment:
xen-acpi-processor.patch _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |