static void __ref acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data) { struct acpi_processor *pr; struct acpi_device *device = NULL; 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)) { result = acpi_processor_device_add(handle, &device); if (result) printk(KERN_ERR PREFIX "Unable to add the device\n"); break; } pr = acpi_driver_data(device); if (processor_cntl_external() && pr) processor_notify_external(pr, PROCESSOR_HOTPLUG, HOTPLUG_TYPE_ADD); 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)) { printk(KERN_ERR PREFIX "Device don't exist, dropping EJECT\n"); break; } pr = acpi_driver_data(device); if (!pr) { printk(KERN_ERR PREFIX "Driver data is NULL, dropping EJECT\n"); return; } if (processor_cntl_external()) processor_notify_external(pr, PROCESSOR_HOTPLUG, HOTPLUG_TYPE_REMOVE); break; default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported event [0x%x]\n", event)); break; } return; }
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; } if (processor_cntl_external() && acpi_driver_data(*device)) processor_notify_external(acpi_driver_data(*device), PROCESSOR_HOTPLUG, HOTPLUG_TYPE_ADD); return 0; }
static int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device) { acpi_handle phandle; struct acpi_device *pdev; struct acpi_processor *pr; 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; } acpi_bus_start(*device); pr = acpi_driver_data(*device); if (!pr) return -ENODEV; if (processor_cntl_external()) processor_notify_external(pr, PROCESSOR_HOTPLUG, HOTPLUG_TYPE_ADD); if ((pr->id >= 0) && (pr->id < NR_CPUS)) { kobject_uevent(&(*device)->kobj, KOBJ_ONLINE); } return 0; }
int acpi_processor_ppc_has_changed(struct acpi_processor *pr) { int ret; #ifdef CONFIG_PROCESSOR_EXTERNAL_CONTROL /* Xen hypervisor can handle cpufreq _PPC event */ if (ignore_ppc < 0 && processor_pmperf_external()) ignore_ppc = 0; #endif if (ignore_ppc) return 0; ret = acpi_processor_get_platform_limit(pr); if (ret < 0) return (ret); else #ifdef CONFIG_CPU_FREQ return cpufreq_update_policy(pr->id); #elif defined(CONFIG_PROCESSOR_EXTERNAL_CONTROL) return processor_notify_external(pr, PROCESSOR_PM_CHANGE, PM_TYPE_PERF); #endif }
/* * Existing ACPI module does parse performance states at some point, * when acpi-cpufreq driver is loaded which however is something * we'd like to disable to avoid confliction with external control * logic. So we have to collect raw performance information here * when ACPI processor object is found and started. */ static int processor_extcntl_get_performance(struct acpi_processor *pr) { int ret; struct acpi_processor_performance *perf; struct acpi_psd_package *pdomain; if (pr->performance) return -EBUSY; perf = kzalloc(sizeof(struct acpi_processor_performance), GFP_KERNEL); if (!perf) return -ENOMEM; pr->performance = perf; /* Get basic performance state information */ ret = acpi_processor_get_performance_info(pr); if (ret < 0) goto err_out; /* * Well, here we need retrieve performance dependency information * from _PSD object. The reason why existing interface is not used * is due to the reason that existing interface sticks to Linux cpu * id to construct some bitmap, however we want to split ACPI * processor objects from Linux cpu id logic. For example, even * when Linux is configured as UP, we still want to parse all ACPI * processor objects to external logic. In this case, it's preferred * to use ACPI ID instead. */ pdomain = &pr->performance->domain_info; pdomain->num_processors = 0; ret = acpi_processor_get_psd(pr); if (ret < 0) { /* * _PSD is optional - assume no coordination if absent (or * broken), matching native kernels' behavior. */ pdomain->num_entries = ACPI_PSD_REV0_ENTRIES; pdomain->revision = ACPI_PSD_REV0_REVISION; pdomain->domain = pr->acpi_id; pdomain->coord_type = DOMAIN_COORD_TYPE_SW_ALL; pdomain->num_processors = 1; } /* Some sanity check */ if ((pdomain->revision != ACPI_PSD_REV0_REVISION) || (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) || ((pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL) && (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY) && (pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL))) { ret = -EINVAL; goto err_out; } /* Last step is to notify BIOS that external logic exists */ processor_notify_smm(); processor_notify_external(pr, PROCESSOR_PM_INIT, PM_TYPE_PERF); return 0; err_out: pr->performance = NULL; kfree(perf); return ret; }
static void acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data) { struct acpi_processor *pr; struct acpi_device *device = NULL; int result; switch (event) { case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_DEVICE_CHECK: printk("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)) { result = acpi_processor_device_add(handle, &device); if (result) printk(KERN_ERR PREFIX "Unable to add the device\n"); break; } pr = acpi_driver_data(device); if (!pr) { printk(KERN_ERR PREFIX "Driver data is NULL\n"); break; } if (processor_cntl_external()) processor_notify_external(pr, PROCESSOR_HOTPLUG, HOTPLUG_TYPE_ADD); if (pr->id >= 0 && (pr->id < NR_CPUS)) { kobject_uevent(&device->kobj, KOBJ_OFFLINE); break; } result = acpi_processor_start(device); if ((!result) && ((pr->id >= 0) && (pr->id < NR_CPUS))) { kobject_uevent(&device->kobj, KOBJ_ONLINE); } else { printk(KERN_ERR PREFIX "Device [%s] failed to start\n", acpi_device_bid(device)); } 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)) { printk(KERN_ERR PREFIX "Device don't exist, dropping EJECT\n"); break; } pr = acpi_driver_data(device); if (!pr) { printk(KERN_ERR PREFIX "Driver data is NULL, dropping EJECT\n"); return; } if ((pr->id < NR_CPUS) && (cpu_present(pr->id))) kobject_uevent(&device->kobj, KOBJ_OFFLINE); if (processor_cntl_external()) processor_notify_external(pr, PROCESSOR_HOTPLUG, HOTPLUG_TYPE_REMOVE); break; default: ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported event [0x%x]\n", event)); break; } return; }