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 /drivers | |
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/acpi/processor_perflib.c | 228 |
1 files changed, 228 insertions, 0 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) |