aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/processor_perflib.c228
-rw-r--r--include/acpi/processor.h27
-rw-r--r--include/linux/cpufreq.h4
3 files changed, 258 insertions, 1 deletions
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index abbdb37a7f5f..ffc5280334c8 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -553,6 +553,234 @@ static void acpi_cpufreq_remove_file(struct acpi_processor *pr)
553} 553}
554#endif /* CONFIG_X86_ACPI_CPUFREQ_PROC_INTF */ 554#endif /* CONFIG_X86_ACPI_CPUFREQ_PROC_INTF */
555 555
556static int acpi_processor_get_psd(struct acpi_processor *pr)
557{
558 int result = 0;
559 acpi_status status = AE_OK;
560 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
561 struct acpi_buffer format = {sizeof("NNNNN"), "NNNNN"};
562 struct acpi_buffer state = {0, NULL};
563 union acpi_object *psd = NULL;
564 struct acpi_psd_package *pdomain;
565
566 ACPI_FUNCTION_TRACE("acpi_processor_get_psd");
567
568 status = acpi_evaluate_object(pr->handle, "_PSD", NULL, &buffer);
569 if (ACPI_FAILURE(status)) {
570 return_VALUE(-ENODEV);
571 }
572
573 psd = (union acpi_object *) buffer.pointer;
574 if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) {
575 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n"));
576 result = -EFAULT;
577 goto end;
578 }
579
580 if (psd->package.count != 1) {
581 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n"));
582 result = -EFAULT;
583 goto end;
584 }
585
586 pdomain = &(pr->performance->domain_info);
587
588 state.length = sizeof(struct acpi_psd_package);
589 state.pointer = pdomain;
590
591 status = acpi_extract_package(&(psd->package.elements[0]),
592 &format, &state);
593 if (ACPI_FAILURE(status)) {
594 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n"));
595 result = -EFAULT;
596 goto end;
597 }
598
599 if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) {
600 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:num_entries\n"));
601 result = -EFAULT;
602 goto end;
603 }
604
605 if (pdomain->revision != ACPI_PSD_REV0_REVISION) {
606 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:revision\n"));
607 result = -EFAULT;
608 goto end;
609 }
610
611end:
612 acpi_os_free(buffer.pointer);
613 return_VALUE(result);
614}
615
616int acpi_processor_preregister_performance(
617 struct acpi_processor_performance **performance)
618{
619 int count, count_target;
620 int retval = 0;
621 unsigned int i, j;
622 cpumask_t covered_cpus;
623 struct acpi_processor *pr;
624 struct acpi_psd_package *pdomain;
625 struct acpi_processor *match_pr;
626 struct acpi_psd_package *match_pdomain;
627
628 ACPI_FUNCTION_TRACE("acpi_processor_preregister_performance");
629
630 down(&performance_sem);
631
632 retval = 0;
633
634 /* Call _PSD for all CPUs */
635 for_each_cpu(i) {
636 pr = processors[i];
637 if (!pr) {
638 /* Look only at processors in ACPI namespace */
639 continue;
640 }
641
642 if (pr->performance) {
643 retval = -EBUSY;
644 continue;
645 }
646
647 if (!performance || !performance[i]) {
648 retval = -EINVAL;
649 continue;
650 }
651
652 pr->performance = performance[i];
653 cpu_set(i, pr->performance->shared_cpu_map);
654 if (acpi_processor_get_psd(pr)) {
655 retval = -EINVAL;
656 continue;
657 }
658 }
659 if (retval)
660 goto err_ret;
661
662 /*
663 * Now that we have _PSD data from all CPUs, lets setup P-state
664 * domain info.
665 */
666 for_each_cpu(i) {
667 pr = processors[i];
668 if (!pr)
669 continue;
670
671 /* Basic validity check for domain info */
672 pdomain = &(pr->performance->domain_info);
673 if ((pdomain->revision != ACPI_PSD_REV0_REVISION) ||
674 (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES)) {
675 retval = -EINVAL;
676 goto err_ret;
677 }
678 if (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL &&
679 pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY &&
680 pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL) {
681 retval = -EINVAL;
682 goto err_ret;
683 }
684 }
685
686 cpus_clear(covered_cpus);
687 for_each_cpu(i) {
688 pr = processors[i];
689 if (!pr)
690 continue;
691
692 if (cpu_isset(i, covered_cpus))
693 continue;
694
695 pdomain = &(pr->performance->domain_info);
696 cpu_set(i, pr->performance->shared_cpu_map);
697 cpu_set(i, covered_cpus);
698 if (pdomain->num_processors <= 1)
699 continue;
700
701 /* Validate the Domain info */
702 count_target = pdomain->num_processors;
703 count = 1;
704 if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL ||
705 pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL) {
706 pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL;
707 } else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY) {
708 pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ANY;
709 }
710
711 for_each_cpu(j) {
712 if (i == j)
713 continue;
714
715 match_pr = processors[j];
716 if (!match_pr)
717 continue;
718
719 match_pdomain = &(match_pr->performance->domain_info);
720 if (match_pdomain->domain != pdomain->domain)
721 continue;
722
723 /* Here i and j are in the same domain */
724
725 if (match_pdomain->num_processors != count_target) {
726 retval = -EINVAL;
727 goto err_ret;
728 }
729
730 if (pdomain->coord_type != match_pdomain->coord_type) {
731 retval = -EINVAL;
732 goto err_ret;
733 }
734
735 cpu_set(j, covered_cpus);
736 cpu_set(j, pr->performance->shared_cpu_map);
737 count++;
738 }
739
740 for_each_cpu(j) {
741 if (i == j)
742 continue;
743
744 match_pr = processors[j];
745 if (!match_pr)
746 continue;
747
748 match_pdomain = &(match_pr->performance->domain_info);
749 if (match_pdomain->domain != pdomain->domain)
750 continue;
751
752 match_pr->performance->shared_type =
753 pr->performance->shared_type;
754 match_pr->performance->shared_cpu_map =
755 pr->performance->shared_cpu_map;
756 }
757 }
758
759err_ret:
760 if (retval) {
761 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error while parsing _PSD domain information. Assuming no coordination\n"));
762 }
763
764 for_each_cpu(i) {
765 pr = processors[i];
766 if (!pr || !pr->performance)
767 continue;
768
769 /* Assume no coordination on any error parsing domain info */
770 if (retval) {
771 cpus_clear(pr->performance->shared_cpu_map);
772 cpu_set(i, pr->performance->shared_cpu_map);
773 pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL;
774 }
775 pr->performance = NULL; /* Will be set for real in register */
776 }
777
778 up(&performance_sem);
779 return_VALUE(retval);
780}
781EXPORT_SYMBOL(acpi_processor_preregister_performance);
782
783
556int 784int
557acpi_processor_register_performance(struct acpi_processor_performance 785acpi_processor_register_performance(struct acpi_processor_performance
558 *performance, unsigned int cpu) 786 *performance, unsigned int cpu)
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index badf0277b1be..0c46d1b3dda2 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -3,6 +3,7 @@
3 3
4#include <linux/kernel.h> 4#include <linux/kernel.h>
5#include <linux/config.h> 5#include <linux/config.h>
6#include <linux/cpu.h>
6 7
7#include <asm/acpi.h> 8#include <asm/acpi.h>
8 9
@@ -18,6 +19,17 @@
18 19
19#define ACPI_PDC_REVISION_ID 0x1 20#define ACPI_PDC_REVISION_ID 0x1
20 21
22#define ACPI_PSD_REV0_REVISION 0 /* Support for _PSD as in ACPI 3.0 */
23#define ACPI_PSD_REV0_ENTRIES 5
24
25/*
26 * Types of coordination defined in ACPI 3.0. Same macros can be used across
27 * P, C and T states
28 */
29#define DOMAIN_COORD_TYPE_SW_ALL 0xfc
30#define DOMAIN_COORD_TYPE_SW_ANY 0xfd
31#define DOMAIN_COORD_TYPE_HW_ALL 0xfe
32
21/* Power Management */ 33/* Power Management */
22 34
23struct acpi_processor_cx; 35struct acpi_processor_cx;
@@ -66,6 +78,14 @@ struct acpi_processor_power {
66 78
67/* Performance Management */ 79/* Performance Management */
68 80
81struct acpi_psd_package {
82 acpi_integer num_entries;
83 acpi_integer revision;
84 acpi_integer domain;
85 acpi_integer coord_type;
86 acpi_integer num_processors;
87} __attribute__ ((packed));
88
69struct acpi_pct_register { 89struct acpi_pct_register {
70 u8 descriptor; 90 u8 descriptor;
71 u16 length; 91 u16 length;
@@ -92,7 +112,9 @@ struct acpi_processor_performance {
92 struct acpi_pct_register status_register; 112 struct acpi_pct_register status_register;
93 unsigned int state_count; 113 unsigned int state_count;
94 struct acpi_processor_px *states; 114 struct acpi_processor_px *states;
95 115 struct acpi_psd_package domain_info;
116 cpumask_t shared_cpu_map;
117 unsigned int shared_type;
96}; 118};
97 119
98/* Throttling Control */ 120/* Throttling Control */
@@ -161,6 +183,9 @@ struct acpi_processor_errata {
161 } piix4; 183 } piix4;
162}; 184};
163 185
186extern int acpi_processor_preregister_performance(
187 struct acpi_processor_performance **performance);
188
164extern int acpi_processor_register_performance(struct acpi_processor_performance 189extern int acpi_processor_register_performance(struct acpi_processor_performance
165 *performance, unsigned int cpu); 190 *performance, unsigned int cpu);
166extern void acpi_processor_unregister_performance(struct 191extern void acpi_processor_unregister_performance(struct
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 17866d7e2b71..f7d988366941 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -73,6 +73,8 @@ struct cpufreq_real_policy {
73 73
74struct cpufreq_policy { 74struct cpufreq_policy {
75 cpumask_t cpus; /* affected CPUs */ 75 cpumask_t cpus; /* affected CPUs */
76 unsigned int shared_type; /* ANY or ALL affected CPUs
77 should set cpufreq */
76 unsigned int cpu; /* cpu nr of registered CPU */ 78 unsigned int cpu; /* cpu nr of registered CPU */
77 struct cpufreq_cpuinfo cpuinfo;/* see above */ 79 struct cpufreq_cpuinfo cpuinfo;/* see above */
78 80
@@ -99,6 +101,8 @@ struct cpufreq_policy {
99#define CPUFREQ_INCOMPATIBLE (1) 101#define CPUFREQ_INCOMPATIBLE (1)
100#define CPUFREQ_NOTIFY (2) 102#define CPUFREQ_NOTIFY (2)
101 103
104#define CPUFREQ_SHARED_TYPE_ALL (0) /* All dependent CPUs should set freq */
105#define CPUFREQ_SHARED_TYPE_ANY (1) /* Freq can be set from any dependent CPU */
102 106
103/******************** cpufreq transition notifiers *******************/ 107/******************** cpufreq transition notifiers *******************/
104 108