Loading drivers/acpi/processor_perflib.c +228 −0 Original line number Diff line number Diff line Loading @@ -553,6 +553,234 @@ static void acpi_cpufreq_remove_file(struct acpi_processor *pr) } #endif /* CONFIG_X86_ACPI_CPUFREQ_PROC_INTF */ static int acpi_processor_get_psd(struct acpi_processor *pr) { int result = 0; acpi_status status = AE_OK; struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; struct acpi_buffer format = {sizeof("NNNNN"), "NNNNN"}; struct acpi_buffer state = {0, NULL}; union acpi_object *psd = NULL; struct acpi_psd_package *pdomain; ACPI_FUNCTION_TRACE("acpi_processor_get_psd"); status = acpi_evaluate_object(pr->handle, "_PSD", NULL, &buffer); if (ACPI_FAILURE(status)) { return_VALUE(-ENODEV); } psd = (union acpi_object *) buffer.pointer; if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n")); result = -EFAULT; goto end; } if (psd->package.count != 1) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n")); result = -EFAULT; goto end; } pdomain = &(pr->performance->domain_info); state.length = sizeof(struct acpi_psd_package); state.pointer = pdomain; status = acpi_extract_package(&(psd->package.elements[0]), &format, &state); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n")); result = -EFAULT; goto end; } if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:num_entries\n")); result = -EFAULT; goto end; } if (pdomain->revision != ACPI_PSD_REV0_REVISION) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:revision\n")); result = -EFAULT; goto end; } end: acpi_os_free(buffer.pointer); return_VALUE(result); } 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; ACPI_FUNCTION_TRACE("acpi_processor_preregister_performance"); down(&performance_sem); retval = 0; /* Call _PSD for all CPUs */ for_each_cpu(i) { pr = processors[i]; if (!pr) { /* Look only at processors in ACPI namespace */ continue; } if (pr->performance) { retval = -EBUSY; continue; } if (!performance || !performance[i]) { retval = -EINVAL; continue; } pr->performance = 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_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_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 || pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL) { pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL; } else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY) { pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ANY; } for_each_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_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: if (retval) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error while parsing _PSD domain information. Assuming no coordination\n")); } for_each_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 */ } up(&performance_sem); return_VALUE(retval); } EXPORT_SYMBOL(acpi_processor_preregister_performance); int acpi_processor_register_performance(struct acpi_processor_performance *performance, unsigned int cpu) Loading include/acpi/processor.h +26 −1 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ #include <linux/kernel.h> #include <linux/config.h> #include <linux/cpu.h> #include <asm/acpi.h> Loading @@ -18,6 +19,17 @@ #define ACPI_PDC_REVISION_ID 0x1 #define ACPI_PSD_REV0_REVISION 0 /* Support for _PSD as in ACPI 3.0 */ #define ACPI_PSD_REV0_ENTRIES 5 /* * Types of coordination defined in ACPI 3.0. Same macros can be used across * P, C and T states */ #define DOMAIN_COORD_TYPE_SW_ALL 0xfc #define DOMAIN_COORD_TYPE_SW_ANY 0xfd #define DOMAIN_COORD_TYPE_HW_ALL 0xfe /* Power Management */ struct acpi_processor_cx; Loading Loading @@ -66,6 +78,14 @@ struct acpi_processor_power { /* Performance Management */ struct acpi_psd_package { acpi_integer num_entries; acpi_integer revision; acpi_integer domain; acpi_integer coord_type; acpi_integer num_processors; } __attribute__ ((packed)); struct acpi_pct_register { u8 descriptor; u16 length; Loading @@ -92,7 +112,9 @@ struct acpi_processor_performance { struct acpi_pct_register status_register; unsigned int state_count; struct acpi_processor_px *states; struct acpi_psd_package domain_info; cpumask_t shared_cpu_map; unsigned int shared_type; }; /* Throttling Control */ Loading Loading @@ -161,6 +183,9 @@ struct acpi_processor_errata { } piix4; }; extern int acpi_processor_preregister_performance( struct acpi_processor_performance **performance); extern int acpi_processor_register_performance(struct acpi_processor_performance *performance, unsigned int cpu); extern void acpi_processor_unregister_performance(struct Loading include/linux/cpufreq.h +4 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,8 @@ struct cpufreq_real_policy { struct cpufreq_policy { cpumask_t cpus; /* affected CPUs */ unsigned int shared_type; /* ANY or ALL affected CPUs should set cpufreq */ unsigned int cpu; /* cpu nr of registered CPU */ struct cpufreq_cpuinfo cpuinfo;/* see above */ Loading @@ -99,6 +101,8 @@ struct cpufreq_policy { #define CPUFREQ_INCOMPATIBLE (1) #define CPUFREQ_NOTIFY (2) #define CPUFREQ_SHARED_TYPE_ALL (0) /* All dependent CPUs should set freq */ #define CPUFREQ_SHARED_TYPE_ANY (1) /* Freq can be set from any dependent CPU */ /******************** cpufreq transition notifiers *******************/ Loading Loading
drivers/acpi/processor_perflib.c +228 −0 Original line number Diff line number Diff line Loading @@ -553,6 +553,234 @@ static void acpi_cpufreq_remove_file(struct acpi_processor *pr) } #endif /* CONFIG_X86_ACPI_CPUFREQ_PROC_INTF */ static int acpi_processor_get_psd(struct acpi_processor *pr) { int result = 0; acpi_status status = AE_OK; struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; struct acpi_buffer format = {sizeof("NNNNN"), "NNNNN"}; struct acpi_buffer state = {0, NULL}; union acpi_object *psd = NULL; struct acpi_psd_package *pdomain; ACPI_FUNCTION_TRACE("acpi_processor_get_psd"); status = acpi_evaluate_object(pr->handle, "_PSD", NULL, &buffer); if (ACPI_FAILURE(status)) { return_VALUE(-ENODEV); } psd = (union acpi_object *) buffer.pointer; if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n")); result = -EFAULT; goto end; } if (psd->package.count != 1) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n")); result = -EFAULT; goto end; } pdomain = &(pr->performance->domain_info); state.length = sizeof(struct acpi_psd_package); state.pointer = pdomain; status = acpi_extract_package(&(psd->package.elements[0]), &format, &state); if (ACPI_FAILURE(status)) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n")); result = -EFAULT; goto end; } if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:num_entries\n")); result = -EFAULT; goto end; } if (pdomain->revision != ACPI_PSD_REV0_REVISION) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:revision\n")); result = -EFAULT; goto end; } end: acpi_os_free(buffer.pointer); return_VALUE(result); } 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; ACPI_FUNCTION_TRACE("acpi_processor_preregister_performance"); down(&performance_sem); retval = 0; /* Call _PSD for all CPUs */ for_each_cpu(i) { pr = processors[i]; if (!pr) { /* Look only at processors in ACPI namespace */ continue; } if (pr->performance) { retval = -EBUSY; continue; } if (!performance || !performance[i]) { retval = -EINVAL; continue; } pr->performance = 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_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_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 || pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL) { pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL; } else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY) { pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ANY; } for_each_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_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: if (retval) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error while parsing _PSD domain information. Assuming no coordination\n")); } for_each_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 */ } up(&performance_sem); return_VALUE(retval); } EXPORT_SYMBOL(acpi_processor_preregister_performance); int acpi_processor_register_performance(struct acpi_processor_performance *performance, unsigned int cpu) Loading
include/acpi/processor.h +26 −1 Original line number Diff line number Diff line Loading @@ -3,6 +3,7 @@ #include <linux/kernel.h> #include <linux/config.h> #include <linux/cpu.h> #include <asm/acpi.h> Loading @@ -18,6 +19,17 @@ #define ACPI_PDC_REVISION_ID 0x1 #define ACPI_PSD_REV0_REVISION 0 /* Support for _PSD as in ACPI 3.0 */ #define ACPI_PSD_REV0_ENTRIES 5 /* * Types of coordination defined in ACPI 3.0. Same macros can be used across * P, C and T states */ #define DOMAIN_COORD_TYPE_SW_ALL 0xfc #define DOMAIN_COORD_TYPE_SW_ANY 0xfd #define DOMAIN_COORD_TYPE_HW_ALL 0xfe /* Power Management */ struct acpi_processor_cx; Loading Loading @@ -66,6 +78,14 @@ struct acpi_processor_power { /* Performance Management */ struct acpi_psd_package { acpi_integer num_entries; acpi_integer revision; acpi_integer domain; acpi_integer coord_type; acpi_integer num_processors; } __attribute__ ((packed)); struct acpi_pct_register { u8 descriptor; u16 length; Loading @@ -92,7 +112,9 @@ struct acpi_processor_performance { struct acpi_pct_register status_register; unsigned int state_count; struct acpi_processor_px *states; struct acpi_psd_package domain_info; cpumask_t shared_cpu_map; unsigned int shared_type; }; /* Throttling Control */ Loading Loading @@ -161,6 +183,9 @@ struct acpi_processor_errata { } piix4; }; extern int acpi_processor_preregister_performance( struct acpi_processor_performance **performance); extern int acpi_processor_register_performance(struct acpi_processor_performance *performance, unsigned int cpu); extern void acpi_processor_unregister_performance(struct Loading
include/linux/cpufreq.h +4 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,8 @@ struct cpufreq_real_policy { struct cpufreq_policy { cpumask_t cpus; /* affected CPUs */ unsigned int shared_type; /* ANY or ALL affected CPUs should set cpufreq */ unsigned int cpu; /* cpu nr of registered CPU */ struct cpufreq_cpuinfo cpuinfo;/* see above */ Loading @@ -99,6 +101,8 @@ struct cpufreq_policy { #define CPUFREQ_INCOMPATIBLE (1) #define CPUFREQ_NOTIFY (2) #define CPUFREQ_SHARED_TYPE_ALL (0) /* All dependent CPUs should set freq */ #define CPUFREQ_SHARED_TYPE_ANY (1) /* Freq can be set from any dependent CPU */ /******************** cpufreq transition notifiers *******************/ Loading