int __stop_machine(int (*fn)(void *), void *data, const cpumask_t *cpus) { struct work_struct *sm_work; int i, ret; /* Set up initial state. */ mutex_lock(&lock); num_threads = num_online_cpus(); active_cpus = cpus; active.fn = fn; active.data = data; active.fnret = 0; idle.fn = chill; idle.data = NULL; set_state(STOPMACHINE_PREPARE); /* Schedule the stop_cpu work on all cpus: hold this CPU so one * doesn't hit this CPU until we're ready. */ get_cpu(); for_each_online_cpu(i) { sm_work = percpu_ptr(stop_machine_work, i); INIT_WORK(sm_work, stop_cpu); queue_work_on(i, stop_machine_wq, sm_work); } /* This will release the thread on our CPU. */ put_cpu(); flush_workqueue(stop_machine_wq); ret = active.fnret; mutex_unlock(&lock); return ret; }
int acpi_processor_preregister_performance( struct acpi_processor_performance *performance) { int count, count_target; int retval = 0; unsigned int i, j; cpumask_t covered_cpus; struct acpi_processor *pr; struct acpi_psd_package *pdomain; struct acpi_processor *match_pr; struct acpi_psd_package *match_pdomain; mutex_lock(&performance_mutex); retval = 0; /* Call _PSD for all CPUs */ for_each_possible_cpu(i) { pr = processors[i]; if (!pr) { /* Look only at processors in ACPI namespace */ continue; } if (pr->performance) { retval = -EBUSY; continue; } if (!performance || !percpu_ptr(performance, i)) { retval = -EINVAL; continue; } pr->performance = percpu_ptr(performance, i); cpu_set(i, pr->performance->shared_cpu_map); if (acpi_processor_get_psd(pr)) { retval = -EINVAL; continue; } } if (retval) goto err_ret; /* * Now that we have _PSD data from all CPUs, lets setup P-state * domain info. */ for_each_possible_cpu(i) { pr = processors[i]; if (!pr) continue; /* Basic validity check for domain info */ pdomain = &(pr->performance->domain_info); if ((pdomain->revision != ACPI_PSD_REV0_REVISION) || (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES)) { retval = -EINVAL; goto err_ret; } if (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL && pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY && pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL) { retval = -EINVAL; goto err_ret; } } cpus_clear(covered_cpus); for_each_possible_cpu(i) { pr = processors[i]; if (!pr) continue; if (cpu_isset(i, covered_cpus)) continue; pdomain = &(pr->performance->domain_info); cpu_set(i, pr->performance->shared_cpu_map); cpu_set(i, covered_cpus); if (pdomain->num_processors <= 1) continue; /* Validate the Domain info */ count_target = pdomain->num_processors; count = 1; if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL) pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL; else if (pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL) pr->performance->shared_type = CPUFREQ_SHARED_TYPE_HW; else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY) pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ANY; for_each_possible_cpu(j) { if (i == j) continue; match_pr = processors[j]; if (!match_pr) continue; match_pdomain = &(match_pr->performance->domain_info); if (match_pdomain->domain != pdomain->domain) continue; /* Here i and j are in the same domain */ if (match_pdomain->num_processors != count_target) { retval = -EINVAL; goto err_ret; } if (pdomain->coord_type != match_pdomain->coord_type) { retval = -EINVAL; goto err_ret; } cpu_set(j, covered_cpus); cpu_set(j, pr->performance->shared_cpu_map); count++; } for_each_possible_cpu(j) { if (i == j) continue; match_pr = processors[j]; if (!match_pr) continue; match_pdomain = &(match_pr->performance->domain_info); if (match_pdomain->domain != pdomain->domain) continue; match_pr->performance->shared_type = pr->performance->shared_type; match_pr->performance->shared_cpu_map = pr->performance->shared_cpu_map; } } err_ret: for_each_possible_cpu(i) { pr = processors[i]; if (!pr || !pr->performance) continue; /* Assume no coordination on any error parsing domain info */ if (retval) { cpus_clear(pr->performance->shared_cpu_map); cpu_set(i, pr->performance->shared_cpu_map); pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL; } pr->performance = NULL; /* Will be set for real in register */ } mutex_unlock(&performance_mutex); return retval; }