diff options
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/processor_perflib.c | 224 |
1 files changed, 224 insertions, 0 deletions
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 44a7b168e0ec..f02c5ea9084f 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c | |||
@@ -554,6 +554,230 @@ static void acpi_cpufreq_remove_file(struct acpi_processor *pr) | |||
554 | } | 554 | } |
555 | #endif /* CONFIG_X86_ACPI_CPUFREQ_PROC_INTF */ | 555 | #endif /* CONFIG_X86_ACPI_CPUFREQ_PROC_INTF */ |
556 | 556 | ||
557 | static int acpi_processor_get_psd(struct acpi_processor *pr) | ||
558 | { | ||
559 | int result = 0; | ||
560 | acpi_status status = AE_OK; | ||
561 | struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; | ||
562 | struct acpi_buffer format = {sizeof("NNNNN"), "NNNNN"}; | ||
563 | struct acpi_buffer state = {0, NULL}; | ||
564 | union acpi_object *psd = NULL; | ||
565 | struct acpi_psd_package *pdomain; | ||
566 | |||
567 | status = acpi_evaluate_object(pr->handle, "_PSD", NULL, &buffer); | ||
568 | if (ACPI_FAILURE(status)) { | ||
569 | return -ENODEV; | ||
570 | } | ||
571 | |||
572 | psd = (union acpi_object *) buffer.pointer; | ||
573 | if (!psd || (psd->type != ACPI_TYPE_PACKAGE)) { | ||
574 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n")); | ||
575 | result = -EFAULT; | ||
576 | goto end; | ||
577 | } | ||
578 | |||
579 | if (psd->package.count != 1) { | ||
580 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n")); | ||
581 | result = -EFAULT; | ||
582 | goto end; | ||
583 | } | ||
584 | |||
585 | pdomain = &(pr->performance->domain_info); | ||
586 | |||
587 | state.length = sizeof(struct acpi_psd_package); | ||
588 | state.pointer = pdomain; | ||
589 | |||
590 | status = acpi_extract_package(&(psd->package.elements[0]), | ||
591 | &format, &state); | ||
592 | if (ACPI_FAILURE(status)) { | ||
593 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSD data\n")); | ||
594 | result = -EFAULT; | ||
595 | goto end; | ||
596 | } | ||
597 | |||
598 | if (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) { | ||
599 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:num_entries\n")); | ||
600 | result = -EFAULT; | ||
601 | goto end; | ||
602 | } | ||
603 | |||
604 | if (pdomain->revision != ACPI_PSD_REV0_REVISION) { | ||
605 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _PSD:revision\n")); | ||
606 | result = -EFAULT; | ||
607 | goto end; | ||
608 | } | ||
609 | |||
610 | end: | ||
611 | acpi_os_free(buffer.pointer); | ||
612 | return result; | ||
613 | } | ||
614 | |||
615 | int acpi_processor_preregister_performance( | ||
616 | struct acpi_processor_performance **performance) | ||
617 | { | ||
618 | int count, count_target; | ||
619 | int retval = 0; | ||
620 | unsigned int i, j; | ||
621 | cpumask_t covered_cpus; | ||
622 | struct acpi_processor *pr; | ||
623 | struct acpi_psd_package *pdomain; | ||
624 | struct acpi_processor *match_pr; | ||
625 | struct acpi_psd_package *match_pdomain; | ||
626 | |||
627 | down(&performance_sem); | ||
628 | |||
629 | retval = 0; | ||
630 | |||
631 | /* Call _PSD for all CPUs */ | ||
632 | for_each_possible_cpu(i) { | ||
633 | pr = processors[i]; | ||
634 | if (!pr) { | ||
635 | /* Look only at processors in ACPI namespace */ | ||
636 | continue; | ||
637 | } | ||
638 | |||
639 | if (pr->performance) { | ||
640 | retval = -EBUSY; | ||
641 | continue; | ||
642 | } | ||
643 | |||
644 | if (!performance || !performance[i]) { | ||
645 | retval = -EINVAL; | ||
646 | continue; | ||
647 | } | ||
648 | |||
649 | pr->performance = performance[i]; | ||
650 | cpu_set(i, pr->performance->shared_cpu_map); | ||
651 | if (acpi_processor_get_psd(pr)) { | ||
652 | retval = -EINVAL; | ||
653 | continue; | ||
654 | } | ||
655 | } | ||
656 | if (retval) | ||
657 | goto err_ret; | ||
658 | |||
659 | /* | ||
660 | * Now that we have _PSD data from all CPUs, lets setup P-state | ||
661 | * domain info. | ||
662 | */ | ||
663 | for_each_possible_cpu(i) { | ||
664 | pr = processors[i]; | ||
665 | if (!pr) | ||
666 | continue; | ||
667 | |||
668 | /* Basic validity check for domain info */ | ||
669 | pdomain = &(pr->performance->domain_info); | ||
670 | if ((pdomain->revision != ACPI_PSD_REV0_REVISION) || | ||
671 | (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES)) { | ||
672 | retval = -EINVAL; | ||
673 | goto err_ret; | ||
674 | } | ||
675 | if (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL && | ||
676 | pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY && | ||
677 | pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL) { | ||
678 | retval = -EINVAL; | ||
679 | goto err_ret; | ||
680 | } | ||
681 | } | ||
682 | |||
683 | cpus_clear(covered_cpus); | ||
684 | for_each_possible_cpu(i) { | ||
685 | pr = processors[i]; | ||
686 | if (!pr) | ||
687 | continue; | ||
688 | |||
689 | if (cpu_isset(i, covered_cpus)) | ||
690 | continue; | ||
691 | |||
692 | pdomain = &(pr->performance->domain_info); | ||
693 | cpu_set(i, pr->performance->shared_cpu_map); | ||
694 | cpu_set(i, covered_cpus); | ||
695 | if (pdomain->num_processors <= 1) | ||
696 | continue; | ||
697 | |||
698 | /* Validate the Domain info */ | ||
699 | count_target = pdomain->num_processors; | ||
700 | count = 1; | ||
701 | if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL || | ||
702 | pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL) { | ||
703 | pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL; | ||
704 | } else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY) { | ||
705 | pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ANY; | ||
706 | } | ||
707 | |||
708 | for_each_possible_cpu(j) { | ||
709 | if (i == j) | ||
710 | continue; | ||
711 | |||
712 | match_pr = processors[j]; | ||
713 | if (!match_pr) | ||
714 | continue; | ||
715 | |||
716 | match_pdomain = &(match_pr->performance->domain_info); | ||
717 | if (match_pdomain->domain != pdomain->domain) | ||
718 | continue; | ||
719 | |||
720 | /* Here i and j are in the same domain */ | ||
721 | |||
722 | if (match_pdomain->num_processors != count_target) { | ||
723 | retval = -EINVAL; | ||
724 | goto err_ret; | ||
725 | } | ||
726 | |||
727 | if (pdomain->coord_type != match_pdomain->coord_type) { | ||
728 | retval = -EINVAL; | ||
729 | goto err_ret; | ||
730 | } | ||
731 | |||
732 | cpu_set(j, covered_cpus); | ||
733 | cpu_set(j, pr->performance->shared_cpu_map); | ||
734 | count++; | ||
735 | } | ||
736 | |||
737 | for_each_possible_cpu(j) { | ||
738 | if (i == j) | ||
739 | continue; | ||
740 | |||
741 | match_pr = processors[j]; | ||
742 | if (!match_pr) | ||
743 | continue; | ||
744 | |||
745 | match_pdomain = &(match_pr->performance->domain_info); | ||
746 | if (match_pdomain->domain != pdomain->domain) | ||
747 | continue; | ||
748 | |||
749 | match_pr->performance->shared_type = | ||
750 | pr->performance->shared_type; | ||
751 | match_pr->performance->shared_cpu_map = | ||
752 | pr->performance->shared_cpu_map; | ||
753 | } | ||
754 | } | ||
755 | |||
756 | err_ret: | ||
757 | if (retval) { | ||
758 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error while parsing _PSD domain information. Assuming no coordination\n")); | ||
759 | } | ||
760 | |||
761 | for_each_possible_cpu(i) { | ||
762 | pr = processors[i]; | ||
763 | if (!pr || !pr->performance) | ||
764 | continue; | ||
765 | |||
766 | /* Assume no coordination on any error parsing domain info */ | ||
767 | if (retval) { | ||
768 | cpus_clear(pr->performance->shared_cpu_map); | ||
769 | cpu_set(i, pr->performance->shared_cpu_map); | ||
770 | pr->performance->shared_type = CPUFREQ_SHARED_TYPE_ALL; | ||
771 | } | ||
772 | pr->performance = NULL; /* Will be set for real in register */ | ||
773 | } | ||
774 | |||
775 | up(&performance_sem); | ||
776 | return retval; | ||
777 | } | ||
778 | EXPORT_SYMBOL(acpi_processor_preregister_performance); | ||
779 | |||
780 | |||
557 | int | 781 | int |
558 | acpi_processor_register_performance(struct acpi_processor_performance | 782 | acpi_processor_register_performance(struct acpi_processor_performance |
559 | *performance, unsigned int cpu) | 783 | *performance, unsigned int cpu) |