static int acpi_cpu_soft_notify(struct notifier_block *nfb, unsigned long action, void *hcpu) { unsigned int cpu = (unsigned long)hcpu; struct acpi_processor *pr = per_cpu(processors, cpu); if (action == CPU_ONLINE && pr) { acpi_processor_ppc_has_changed(pr); acpi_processor_cst_has_changed(pr); acpi_processor_tstate_has_changed(pr); } return NOTIFY_OK; }
static void acpi_processor_notify(acpi_handle handle, u32 event, void *data) { struct acpi_device *device = data; struct acpi_processor *pr; int saved; if (device->handle != handle) return; pr = acpi_driver_data(device); if (!pr) return; switch (event) { case ACPI_PROCESSOR_NOTIFY_PERFORMANCE: saved = pr->performance_platform_limit; acpi_processor_ppc_has_changed(pr, 1); 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: 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); break; default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported event [0x%x]\n", event)); break; } return; }
static int acpi_cpu_soft_notify(struct notifier_block *nfb, unsigned long action, void *hcpu) { unsigned int cpu = (unsigned long)hcpu; struct acpi_processor *pr = per_cpu(processors, cpu); if (action == CPU_ONLINE && pr) { acpi_processor_ppc_has_changed(pr, 0); acpi_processor_cst_has_changed(pr); acpi_processor_reevaluate_tstate(pr, action); acpi_processor_tstate_has_changed(pr); } if (action == CPU_DEAD && pr) { /* invalidate the flag.throttling after one CPU is offline */ acpi_processor_reevaluate_tstate(pr, action); } return NOTIFY_OK; }
static int acpi_cpu_soft_notify(struct notifier_block *nfb, unsigned long action, void *hcpu) { unsigned int cpu = (unsigned long)hcpu; struct acpi_processor *pr = per_cpu(processors, cpu); if (action == CPU_ONLINE && pr) { /* CPU got physically hotplugged and onlined the first time: * Initialize missing things */ if (pr->flags.need_hotplug_init) { struct cpuidle_driver *idle_driver = cpuidle_get_driver(); printk(KERN_INFO "Will online and init hotplugged " "CPU: %d\n", pr->id); WARN(acpi_processor_start(pr), "Failed to start CPU:" " %d\n", pr->id); pr->flags.need_hotplug_init = 0; if (idle_driver && !strcmp(idle_driver->name, "intel_idle")) { intel_idle_cpu_init(pr->id); } /* Normal CPU soft online event */ } else { acpi_processor_ppc_has_changed(pr, 0); acpi_processor_cst_has_changed(pr); acpi_processor_reevaluate_tstate(pr, action); acpi_processor_tstate_has_changed(pr); } } if (action == CPU_DEAD && pr) { /* invalidate the flag.throttling after one CPU is offline */ acpi_processor_reevaluate_tstate(pr, action); } return NOTIFY_OK; }
static int acpi_processor_start(struct acpi_device *device) { int result = 0; acpi_status status = AE_OK; struct acpi_processor *pr; processor_extcntl_init(); pr = acpi_driver_data(device); result = acpi_processor_get_info(pr); if (result || ((pr->id == -1) && !processor_cntl_external())) { /* Processor is physically not present */ return 0; } BUG_ON(!processor_cntl_external() && ((pr->id >= NR_CPUS) || (pr->id < 0))); /* * Buggy BIOS check * ACPI id of processors can be reported wrongly by the BIOS. * Don't trust it blindly */ #ifdef CONFIG_XEN BUG_ON(pr->acpi_id >= NR_ACPI_CPUS); if (processor_device_array[pr->acpi_id] != NULL && processor_device_array[pr->acpi_id] != (void *)device) { #else if (processor_device_array[pr->id] != NULL && processor_device_array[pr->id] != (void *)device) { #endif /* CONFIG_XEN */ printk(KERN_WARNING "BIOS reported wrong ACPI id" "for the processor\n"); return -ENODEV; } #ifdef CONFIG_XEN processor_device_array[pr->acpi_id] = (void *)device; if (pr->id != -1) processors[pr->id] = pr; #else processor_device_array[pr->id] = (void *)device; processors[pr->id] = pr; #endif /* CONFIG_XEN */ result = acpi_processor_add_fs(device); if (result) goto end; status = acpi_install_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY, acpi_processor_notify, pr); /* _PDC call should be done before doing anything else (if reqd.). */ arch_acpi_processor_init_pdc(pr); acpi_processor_set_pdc(pr); #if defined(CONFIG_CPU_FREQ) || defined(CONFIG_PROCESSOR_EXTERNAL_CONTROL) acpi_processor_ppc_has_changed(pr); #endif /* * pr->id may equal to -1 while processor_cntl_external 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); } acpi_processor_power_init(pr, device); result = processor_extcntl_prepare(pr); if (result) goto end; 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 acpi_processor_notify(acpi_handle handle, u32 event, void *data) { struct acpi_processor *pr = (struct acpi_processor *)data; struct acpi_device *device = NULL; if (!pr) return; if (acpi_bus_get_device(pr->handle, &device)) return; switch (event) { case ACPI_PROCESSOR_NOTIFY_PERFORMANCE: acpi_processor_ppc_has_changed(pr); acpi_bus_generate_event(device, event, pr->performance_platform_limit); break; case ACPI_PROCESSOR_NOTIFY_POWER: acpi_processor_cst_has_changed(pr); acpi_bus_generate_event(device, event, 0); break; case ACPI_PROCESSOR_NOTIFY_THROTTLING: acpi_processor_tstate_has_changed(pr); acpi_bus_generate_event(device, event, 0); break; default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported event [0x%x]\n", event)); break; } return; } static int acpi_processor_add(struct acpi_device *device) { struct acpi_processor *pr = NULL; if (!device) return -EINVAL; pr = kmalloc(sizeof(struct acpi_processor), GFP_KERNEL); if (!pr) return -ENOMEM; memset(pr, 0, sizeof(struct acpi_processor)); pr->handle = device->handle; strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS); acpi_driver_data(device) = pr; return 0; } static int acpi_processor_remove(struct acpi_device *device, int type) { acpi_status status = AE_OK; struct acpi_processor *pr = NULL; if (!device || !acpi_driver_data(device)) return -EINVAL; pr = (struct acpi_processor *)acpi_driver_data(device); if (!processor_cntl_external() && pr->id >= NR_CPUS) { kfree(pr); return 0; } if (type == ACPI_BUS_REMOVAL_EJECT) { if (acpi_processor_handle_eject(pr)) return -EINVAL; } acpi_processor_power_exit(pr, device); status = acpi_remove_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY, acpi_processor_notify); acpi_processor_remove_fs(device); #ifdef CONFIG_XEN if (pr->id != -1) processors[pr->id] = NULL; #else processors[pr->id] = NULL; #endif /* CONFIG_XEN */ kfree(pr); return 0; }