diff options
author | Ashwin Chaugule <ashwin.chaugule@linaro.org> | 2016-08-16 16:39:38 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-08-30 19:02:33 -0400 |
commit | 5bbb86aa4b8d84395e42cd05448820651d79f349 (patch) | |
tree | 31dd18e064b3f61fc969b617b3dba46804e92577 /drivers/acpi/cppc_acpi.c | |
parent | aca314efb177274b458f7e72c5ff375c80a5c2d0 (diff) |
ACPI / CPPC: restructure read/writes for efficient sys mapped reg ops
For cases where sys mapped CPC registers need to be accessed
frequently, it helps immensly to pre-map them rather than map
and unmap for each operation. e.g. case where feedback counters
are sys mem map registers.
Restructure cpc_read/write and the cpc_regs structure to allow
pre-mapping the system addresses and unmap them when the CPU exits.
Signed-off-by: Ashwin Chaugule <ashwin.chaugule@linaro.org>
Signed-off-by: Prashanth Prakash <pprakash@codeaurora.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/cppc_acpi.c')
-rw-r--r-- | drivers/acpi/cppc_acpi.c | 108 |
1 files changed, 71 insertions, 37 deletions
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 2e981732805b..fea58e209b5b 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c | |||
@@ -62,7 +62,6 @@ static DEFINE_PER_CPU(struct cpc_desc *, cpc_desc_ptr); | |||
62 | /* This layer handles all the PCC specifics for CPPC. */ | 62 | /* This layer handles all the PCC specifics for CPPC. */ |
63 | static struct mbox_chan *pcc_channel; | 63 | static struct mbox_chan *pcc_channel; |
64 | static void __iomem *pcc_comm_addr; | 64 | static void __iomem *pcc_comm_addr; |
65 | static u64 comm_base_addr; | ||
66 | static int pcc_subspace_idx = -1; | 65 | static int pcc_subspace_idx = -1; |
67 | static bool pcc_channel_acquired; | 66 | static bool pcc_channel_acquired; |
68 | static ktime_t deadline; | 67 | static ktime_t deadline; |
@@ -394,7 +393,6 @@ EXPORT_SYMBOL_GPL(acpi_get_psd_map); | |||
394 | static int register_pcc_channel(int pcc_subspace_idx) | 393 | static int register_pcc_channel(int pcc_subspace_idx) |
395 | { | 394 | { |
396 | struct acpi_pcct_hw_reduced *cppc_ss; | 395 | struct acpi_pcct_hw_reduced *cppc_ss; |
397 | unsigned int len; | ||
398 | u64 usecs_lat; | 396 | u64 usecs_lat; |
399 | 397 | ||
400 | if (pcc_subspace_idx >= 0) { | 398 | if (pcc_subspace_idx >= 0) { |
@@ -419,12 +417,6 @@ static int register_pcc_channel(int pcc_subspace_idx) | |||
419 | return -ENODEV; | 417 | return -ENODEV; |
420 | } | 418 | } |
421 | 419 | ||
422 | /* | ||
423 | * This is the shared communication region | ||
424 | * for the OS and Platform to communicate over. | ||
425 | */ | ||
426 | comm_base_addr = cppc_ss->base_address; | ||
427 | len = cppc_ss->length; | ||
428 | 420 | ||
429 | /* | 421 | /* |
430 | * cppc_ss->latency is just a Nominal value. In reality | 422 | * cppc_ss->latency is just a Nominal value. In reality |
@@ -436,7 +428,7 @@ static int register_pcc_channel(int pcc_subspace_idx) | |||
436 | pcc_mrtt = cppc_ss->min_turnaround_time; | 428 | pcc_mrtt = cppc_ss->min_turnaround_time; |
437 | pcc_mpar = cppc_ss->max_access_rate; | 429 | pcc_mpar = cppc_ss->max_access_rate; |
438 | 430 | ||
439 | pcc_comm_addr = acpi_os_ioremap(comm_base_addr, len); | 431 | pcc_comm_addr = acpi_os_ioremap(cppc_ss->base_address, cppc_ss->length); |
440 | if (!pcc_comm_addr) { | 432 | if (!pcc_comm_addr) { |
441 | pr_err("Failed to ioremap PCC comm region mem\n"); | 433 | pr_err("Failed to ioremap PCC comm region mem\n"); |
442 | return -ENOMEM; | 434 | return -ENOMEM; |
@@ -545,6 +537,8 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) | |||
545 | goto out_free; | 537 | goto out_free; |
546 | } | 538 | } |
547 | 539 | ||
540 | cpc_ptr->num_entries = num_ent; | ||
541 | |||
548 | /* Second entry should be revision. */ | 542 | /* Second entry should be revision. */ |
549 | cpc_obj = &out_obj->package.elements[1]; | 543 | cpc_obj = &out_obj->package.elements[1]; |
550 | if (cpc_obj->type == ACPI_TYPE_INTEGER) { | 544 | if (cpc_obj->type == ACPI_TYPE_INTEGER) { |
@@ -585,7 +579,16 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) | |||
585 | pr_debug("Mismatched PCC ids.\n"); | 579 | pr_debug("Mismatched PCC ids.\n"); |
586 | goto out_free; | 580 | goto out_free; |
587 | } | 581 | } |
588 | } else if (gas_t->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) { | 582 | } else if (gas_t->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { |
583 | if (gas_t->address) { | ||
584 | void __iomem *addr; | ||
585 | |||
586 | addr = ioremap(gas_t->address, gas_t->bit_width/8); | ||
587 | if (!addr) | ||
588 | goto out_free; | ||
589 | cpc_ptr->cpc_regs[i-2].sys_mem_vaddr = addr; | ||
590 | } | ||
591 | } else { | ||
589 | /* Support only PCC and SYS MEM type regs */ | 592 | /* Support only PCC and SYS MEM type regs */ |
590 | pr_debug("Unsupported register type: %d\n", gas_t->space_id); | 593 | pr_debug("Unsupported register type: %d\n", gas_t->space_id); |
591 | goto out_free; | 594 | goto out_free; |
@@ -623,6 +626,13 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) | |||
623 | return 0; | 626 | return 0; |
624 | 627 | ||
625 | out_free: | 628 | out_free: |
629 | /* Free all the mapped sys mem areas for this CPU */ | ||
630 | for (i = 2; i < cpc_ptr->num_entries; i++) { | ||
631 | void __iomem *addr = cpc_ptr->cpc_regs[i-2].sys_mem_vaddr; | ||
632 | |||
633 | if (addr) | ||
634 | iounmap(addr); | ||
635 | } | ||
626 | kfree(cpc_ptr); | 636 | kfree(cpc_ptr); |
627 | 637 | ||
628 | out_buf_free: | 638 | out_buf_free: |
@@ -640,7 +650,17 @@ EXPORT_SYMBOL_GPL(acpi_cppc_processor_probe); | |||
640 | void acpi_cppc_processor_exit(struct acpi_processor *pr) | 650 | void acpi_cppc_processor_exit(struct acpi_processor *pr) |
641 | { | 651 | { |
642 | struct cpc_desc *cpc_ptr; | 652 | struct cpc_desc *cpc_ptr; |
653 | unsigned int i; | ||
654 | void __iomem *addr; | ||
643 | cpc_ptr = per_cpu(cpc_desc_ptr, pr->id); | 655 | cpc_ptr = per_cpu(cpc_desc_ptr, pr->id); |
656 | |||
657 | /* Free all the mapped sys mem areas for this CPU */ | ||
658 | for (i = 2; i < cpc_ptr->num_entries; i++) { | ||
659 | addr = cpc_ptr->cpc_regs[i-2].sys_mem_vaddr; | ||
660 | if (addr) | ||
661 | iounmap(addr); | ||
662 | } | ||
663 | |||
644 | kfree(cpc_ptr); | 664 | kfree(cpc_ptr); |
645 | } | 665 | } |
646 | EXPORT_SYMBOL_GPL(acpi_cppc_processor_exit); | 666 | EXPORT_SYMBOL_GPL(acpi_cppc_processor_exit); |
@@ -651,15 +671,27 @@ EXPORT_SYMBOL_GPL(acpi_cppc_processor_exit); | |||
651 | * we can directly write to it. | 671 | * we can directly write to it. |
652 | */ | 672 | */ |
653 | 673 | ||
654 | static int cpc_read(struct cpc_reg *reg, u64 *val) | 674 | static int cpc_read(struct cpc_register_resource *reg_res, u64 *val) |
655 | { | 675 | { |
656 | int ret_val = 0; | 676 | int ret_val = 0; |
677 | void __iomem *vaddr = 0; | ||
678 | struct cpc_reg *reg = ®_res->cpc_entry.reg; | ||
679 | |||
680 | if (reg_res->type == ACPI_TYPE_INTEGER) { | ||
681 | *val = reg_res->cpc_entry.int_value; | ||
682 | return ret_val; | ||
683 | } | ||
657 | 684 | ||
658 | *val = 0; | 685 | *val = 0; |
659 | if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) { | 686 | if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) |
660 | void __iomem *vaddr = GET_PCC_VADDR(reg->address); | 687 | vaddr = GET_PCC_VADDR(reg->address); |
688 | else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) | ||
689 | vaddr = reg_res->sys_mem_vaddr; | ||
690 | else | ||
691 | return acpi_os_read_memory((acpi_physical_address)reg->address, | ||
692 | val, reg->bit_width); | ||
661 | 693 | ||
662 | switch (reg->bit_width) { | 694 | switch (reg->bit_width) { |
663 | case 8: | 695 | case 8: |
664 | *val = readb_relaxed(vaddr); | 696 | *val = readb_relaxed(vaddr); |
665 | break; | 697 | break; |
@@ -674,23 +706,28 @@ static int cpc_read(struct cpc_reg *reg, u64 *val) | |||
674 | break; | 706 | break; |
675 | default: | 707 | default: |
676 | pr_debug("Error: Cannot read %u bit width from PCC\n", | 708 | pr_debug("Error: Cannot read %u bit width from PCC\n", |
677 | reg->bit_width); | 709 | reg->bit_width); |
678 | ret_val = -EFAULT; | 710 | ret_val = -EFAULT; |
679 | } | 711 | } |
680 | } else | 712 | |
681 | ret_val = acpi_os_read_memory((acpi_physical_address)reg->address, | ||
682 | val, reg->bit_width); | ||
683 | return ret_val; | 713 | return ret_val; |
684 | } | 714 | } |
685 | 715 | ||
686 | static int cpc_write(struct cpc_reg *reg, u64 val) | 716 | static int cpc_write(struct cpc_register_resource *reg_res, u64 val) |
687 | { | 717 | { |
688 | int ret_val = 0; | 718 | int ret_val = 0; |
719 | void __iomem *vaddr = 0; | ||
720 | struct cpc_reg *reg = ®_res->cpc_entry.reg; | ||
689 | 721 | ||
690 | if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) { | 722 | if (reg->space_id == ACPI_ADR_SPACE_PLATFORM_COMM) |
691 | void __iomem *vaddr = GET_PCC_VADDR(reg->address); | 723 | vaddr = GET_PCC_VADDR(reg->address); |
724 | else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) | ||
725 | vaddr = reg_res->sys_mem_vaddr; | ||
726 | else | ||
727 | return acpi_os_write_memory((acpi_physical_address)reg->address, | ||
728 | val, reg->bit_width); | ||
692 | 729 | ||
693 | switch (reg->bit_width) { | 730 | switch (reg->bit_width) { |
694 | case 8: | 731 | case 8: |
695 | writeb_relaxed(val, vaddr); | 732 | writeb_relaxed(val, vaddr); |
696 | break; | 733 | break; |
@@ -705,13 +742,11 @@ static int cpc_write(struct cpc_reg *reg, u64 val) | |||
705 | break; | 742 | break; |
706 | default: | 743 | default: |
707 | pr_debug("Error: Cannot write %u bit width to PCC\n", | 744 | pr_debug("Error: Cannot write %u bit width to PCC\n", |
708 | reg->bit_width); | 745 | reg->bit_width); |
709 | ret_val = -EFAULT; | 746 | ret_val = -EFAULT; |
710 | break; | 747 | break; |
711 | } | 748 | } |
712 | } else | 749 | |
713 | ret_val = acpi_os_write_memory((acpi_physical_address)reg->address, | ||
714 | val, reg->bit_width); | ||
715 | return ret_val; | 750 | return ret_val; |
716 | } | 751 | } |
717 | 752 | ||
@@ -754,16 +789,16 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps) | |||
754 | } | 789 | } |
755 | } | 790 | } |
756 | 791 | ||
757 | cpc_read(&highest_reg->cpc_entry.reg, &high); | 792 | cpc_read(highest_reg, &high); |
758 | perf_caps->highest_perf = high; | 793 | perf_caps->highest_perf = high; |
759 | 794 | ||
760 | cpc_read(&lowest_reg->cpc_entry.reg, &low); | 795 | cpc_read(lowest_reg, &low); |
761 | perf_caps->lowest_perf = low; | 796 | perf_caps->lowest_perf = low; |
762 | 797 | ||
763 | cpc_read(&ref_perf->cpc_entry.reg, &ref); | 798 | cpc_read(ref_perf, &ref); |
764 | perf_caps->reference_perf = ref; | 799 | perf_caps->reference_perf = ref; |
765 | 800 | ||
766 | cpc_read(&nom_perf->cpc_entry.reg, &nom); | 801 | cpc_read(nom_perf, &nom); |
767 | perf_caps->nominal_perf = nom; | 802 | perf_caps->nominal_perf = nom; |
768 | 803 | ||
769 | if (!ref) | 804 | if (!ref) |
@@ -804,7 +839,7 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs) | |||
804 | 839 | ||
805 | /* Are any of the regs PCC ?*/ | 840 | /* Are any of the regs PCC ?*/ |
806 | if ((delivered_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) || | 841 | if ((delivered_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) || |
807 | (reference_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM)) { | 842 | (reference_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM)) { |
808 | /* Ring doorbell once to update PCC subspace */ | 843 | /* Ring doorbell once to update PCC subspace */ |
809 | if (send_pcc_cmd(CMD_READ) < 0) { | 844 | if (send_pcc_cmd(CMD_READ) < 0) { |
810 | ret = -EIO; | 845 | ret = -EIO; |
@@ -812,8 +847,8 @@ int cppc_get_perf_ctrs(int cpunum, struct cppc_perf_fb_ctrs *perf_fb_ctrs) | |||
812 | } | 847 | } |
813 | } | 848 | } |
814 | 849 | ||
815 | cpc_read(&delivered_reg->cpc_entry.reg, &delivered); | 850 | cpc_read(delivered_reg, &delivered); |
816 | cpc_read(&reference_reg->cpc_entry.reg, &reference); | 851 | cpc_read(reference_reg, &reference); |
817 | 852 | ||
818 | if (!delivered || !reference) { | 853 | if (!delivered || !reference) { |
819 | ret = -EFAULT; | 854 | ret = -EFAULT; |
@@ -868,7 +903,7 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) | |||
868 | * Skip writing MIN/MAX until Linux knows how to come up with | 903 | * Skip writing MIN/MAX until Linux knows how to come up with |
869 | * useful values. | 904 | * useful values. |
870 | */ | 905 | */ |
871 | cpc_write(&desired_reg->cpc_entry.reg, perf_ctrls->desired_perf); | 906 | cpc_write(desired_reg, perf_ctrls->desired_perf); |
872 | 907 | ||
873 | /* Is this a PCC reg ?*/ | 908 | /* Is this a PCC reg ?*/ |
874 | if (desired_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) { | 909 | if (desired_reg->cpc_entry.reg.space_id == ACPI_ADR_SPACE_PLATFORM_COMM) { |
@@ -878,7 +913,6 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) | |||
878 | } | 913 | } |
879 | busy_channel: | 914 | busy_channel: |
880 | spin_unlock(&pcc_lock); | 915 | spin_unlock(&pcc_lock); |
881 | |||
882 | return ret; | 916 | return ret; |
883 | } | 917 | } |
884 | EXPORT_SYMBOL_GPL(cppc_set_perf); | 918 | EXPORT_SYMBOL_GPL(cppc_set_perf); |