diff options
author | Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> | 2005-12-14 15:05:00 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2006-02-09 03:21:48 -0500 |
commit | 3b2d99429e3386b6e2ac949fc72486509c8bbe36 (patch) | |
tree | b2162152b2c7fa56b13f74a0b166b978dd3ee548 | |
parent | 0bdd340c092b0936f78a54bdbd3927463ed4fca3 (diff) |
P-state software coordination for ACPI core
http://bugzilla.kernel.org/show_bug.cgi?id=5737
Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r-- | drivers/acpi/processor_perflib.c | 228 | ||||
-rw-r--r-- | include/acpi/processor.h | 27 | ||||
-rw-r--r-- | include/linux/cpufreq.h | 4 |
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 | ||
556 | static 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 | |||
611 | end: | ||
612 | acpi_os_free(buffer.pointer); | ||
613 | return_VALUE(result); | ||
614 | } | ||
615 | |||
616 | int 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 | |||
759 | err_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 | } | ||
781 | EXPORT_SYMBOL(acpi_processor_preregister_performance); | ||
782 | |||
783 | |||
556 | int | 784 | int |
557 | acpi_processor_register_performance(struct acpi_processor_performance | 785 | acpi_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 | ||
23 | struct acpi_processor_cx; | 35 | struct acpi_processor_cx; |
@@ -66,6 +78,14 @@ struct acpi_processor_power { | |||
66 | 78 | ||
67 | /* Performance Management */ | 79 | /* Performance Management */ |
68 | 80 | ||
81 | struct 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 | |||
69 | struct acpi_pct_register { | 89 | struct 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 | ||
186 | extern int acpi_processor_preregister_performance( | ||
187 | struct acpi_processor_performance **performance); | ||
188 | |||
164 | extern int acpi_processor_register_performance(struct acpi_processor_performance | 189 | extern int acpi_processor_register_performance(struct acpi_processor_performance |
165 | *performance, unsigned int cpu); | 190 | *performance, unsigned int cpu); |
166 | extern void acpi_processor_unregister_performance(struct | 191 | extern 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 | ||
74 | struct cpufreq_policy { | 74 | struct 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 | ||