aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSrinivas Pandruvada <srinivas.pandruvada@linux.intel.com>2016-09-01 16:37:10 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2016-09-08 17:02:14 -0400
commita6cbcdd5ab5f242d49f511127f0a601b71be2cc4 (patch)
tree6c7b1fad06bc5dfce0d10ffa9c6903959060df8e
parent5448f14698b916e5b04112b104433b90247e01c7 (diff)
ACPI / CPPC: Add support for functional fixed hardware address
The CPPC registers can also be accessed via functional fixed hardware addresse(FFH) in X86. Add support by modifying cpc_read and cpc_write to be able to read/write MSRs on x86 platform on per cpu basis. Also with this change, acpi_cppc_processor_probe doesn't bail out if address space id is not equal to PCC or memory address space and FFH is supported on the system. Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--arch/x86/kernel/acpi/Makefile1
-rw-r--r--arch/x86/kernel/acpi/cppc_msr.c58
-rw-r--r--drivers/acpi/cppc_acpi.c75
3 files changed, 121 insertions, 13 deletions
diff --git a/arch/x86/kernel/acpi/Makefile b/arch/x86/kernel/acpi/Makefile
index 3242e591fa82..26b78d86f25a 100644
--- a/arch/x86/kernel/acpi/Makefile
+++ b/arch/x86/kernel/acpi/Makefile
@@ -1,6 +1,7 @@
1obj-$(CONFIG_ACPI) += boot.o 1obj-$(CONFIG_ACPI) += boot.o
2obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_$(BITS).o 2obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup_$(BITS).o
3obj-$(CONFIG_ACPI_APEI) += apei.o 3obj-$(CONFIG_ACPI_APEI) += apei.o
4obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_msr.o
4 5
5ifneq ($(CONFIG_ACPI_PROCESSOR),) 6ifneq ($(CONFIG_ACPI_PROCESSOR),)
6obj-y += cstate.o 7obj-y += cstate.o
diff --git a/arch/x86/kernel/acpi/cppc_msr.c b/arch/x86/kernel/acpi/cppc_msr.c
new file mode 100644
index 000000000000..6fb478bf82fd
--- /dev/null
+++ b/arch/x86/kernel/acpi/cppc_msr.c
@@ -0,0 +1,58 @@
1/*
2 * cppc_msr.c: MSR Interface for CPPC
3 * Copyright (c) 2016, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 */
15
16#include <acpi/cppc_acpi.h>
17#include <asm/msr.h>
18
19/* Refer to drivers/acpi/cppc_acpi.c for the description of functions */
20
21bool cpc_ffh_supported(void)
22{
23 return true;
24}
25
26int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val)
27{
28 int err;
29
30 err = rdmsrl_safe_on_cpu(cpunum, reg->address, val);
31 if (!err) {
32 u64 mask = GENMASK_ULL(reg->bit_offset + reg->bit_width - 1,
33 reg->bit_offset);
34
35 *val &= mask;
36 *val >>= reg->bit_offset;
37 }
38 return err;
39}
40
41int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val)
42{
43 u64 rd_val;
44 int err;
45
46 err = rdmsrl_safe_on_cpu(cpunum, reg->address, &rd_val);
47 if (!err) {
48 u64 mask = GENMASK_ULL(reg->bit_offset + reg->bit_width - 1,
49 reg->bit_offset);
50
51 val <<= reg->bit_offset;
52 val &= mask;
53 rd_val &= ~mask;
54 rd_val |= val;
55 err = wrmsrl_safe_on_cpu(cpunum, reg->address, rd_val);
56 }
57 return err;
58}
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index ed58883d35ee..715fe8001d59 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -579,6 +579,19 @@ static int register_pcc_channel(int pcc_subspace_idx)
579 return 0; 579 return 0;
580} 580}
581 581
582/**
583 * cpc_ffh_supported() - check if FFH reading supported
584 *
585 * Check if the architecture has support for functional fixed hardware
586 * read/write capability.
587 *
588 * Return: true for supported, false for not supported
589 */
590bool __weak cpc_ffh_supported(void)
591{
592 return false;
593}
594
582/* 595/*
583 * An example CPC table looks like the following. 596 * An example CPC table looks like the following.
584 * 597 *
@@ -728,9 +741,11 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
728 cpc_ptr->cpc_regs[i-2].sys_mem_vaddr = addr; 741 cpc_ptr->cpc_regs[i-2].sys_mem_vaddr = addr;
729 } 742 }
730 } else { 743 } else {
731 /* Support only PCC and SYS MEM type regs */ 744 if (gas_t->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE || !cpc_ffh_supported()) {
732 pr_debug("Unsupported register type: %d\n", gas_t->space_id); 745 /* Support only PCC ,SYS MEM and FFH type regs */
733 goto out_free; 746 pr_debug("Unsupported register type: %d\n", gas_t->space_id);
747 goto out_free;
748 }
734 } 749 }
735 750
736 cpc_ptr->cpc_regs[i-2].type = ACPI_TYPE_BUFFER; 751 cpc_ptr->cpc_regs[i-2].type = ACPI_TYPE_BUFFER;
@@ -819,13 +834,43 @@ void acpi_cppc_processor_exit(struct acpi_processor *pr)
819} 834}
820EXPORT_SYMBOL_GPL(acpi_cppc_processor_exit); 835EXPORT_SYMBOL_GPL(acpi_cppc_processor_exit);
821 836
837/**
838 * cpc_read_ffh() - Read FFH register
839 * @cpunum: cpu number to read
840 * @reg: cppc register information
841 * @val: place holder for return value
842 *
843 * Read bit_width bits from a specified address and bit_offset
844 *
845 * Return: 0 for success and error code
846 */
847int __weak cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val)
848{
849 return -ENOTSUPP;
850}
851
852/**
853 * cpc_write_ffh() - Write FFH register
854 * @cpunum: cpu number to write
855 * @reg: cppc register information
856 * @val: value to write
857 *
858 * Write value of bit_width bits to a specified address and bit_offset
859 *
860 * Return: 0 for success and error code
861 */
862int __weak cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val)
863{
864 return -ENOTSUPP;
865}
866
822/* 867/*
823 * Since cpc_read and cpc_write are called while holding pcc_lock, it should be 868 * Since cpc_read and cpc_write are called while holding pcc_lock, it should be
824 * as fast as possible. We have already mapped the PCC subspace during init, so 869 * as fast as possible. We have already mapped the PCC subspace during init, so
825 * we can directly write to it. 870 * we can directly write to it.
826 */ 871 */
827 872
828static int cpc_read(struct cpc_register_resource *reg_res, u64 *val) 873static int cpc_read(int cpu, struct cpc_register_resource *reg_res, u64 *val)
829{ 874{
830 int ret_val = 0; 875 int ret_val = 0;
831 void __iomem *vaddr = 0; 876 void __iomem *vaddr = 0;
@@ -841,6 +886,8 @@ static int cpc_read(struct cpc_register_resource *reg_res, u64 *val)
841 vaddr = GET_PCC_VADDR(reg->address); 886 vaddr = GET_PCC_VADDR(reg->address);
842 else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) 887 else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
843 vaddr = reg_res->sys_mem_vaddr; 888 vaddr = reg_res->sys_mem_vaddr;
889 else if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE)
890 return cpc_read_ffh(cpu, reg, val);
844 else 891 else
845 return acpi_os_read_memory((acpi_physical_address)reg->address, 892 return acpi_os_read_memory((acpi_physical_address)reg->address,
846 val, reg->bit_width); 893 val, reg->bit_width);
@@ -867,7 +914,7 @@ static int cpc_read(struct cpc_register_resource *reg_res, u64 *val)
867 return ret_val; 914 return ret_val;
868} 915}
869 916
870static int cpc_write(struct cpc_register_resource *reg_res, u64 val) 917static int cpc_write(int cpu, struct cpc_register_resource *reg_res, u64 val)
871{ 918{
872 int ret_val = 0; 919 int ret_val = 0;
873 void __iomem *vaddr = 0; 920 void __iomem *vaddr = 0;
@@ -877,6 +924,8 @@ static int cpc_write(struct cpc_register_resource *reg_res, u64 val)
877 vaddr = GET_PCC_VADDR(reg->address); 924 vaddr = GET_PCC_VADDR(reg->address);
878 else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) 925 else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
879 vaddr = reg_res->sys_mem_vaddr; 926 vaddr = reg_res->sys_mem_vaddr;
927 else if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE)
928 return cpc_write_ffh(cpu, reg, val);
880 else 929 else
881 return acpi_os_write_memory((acpi_physical_address)reg->address, 930 return acpi_os_write_memory((acpi_physical_address)reg->address,
882 val, reg->bit_width); 931 val, reg->bit_width);
@@ -941,13 +990,13 @@ int cppc_get_perf_caps(int cpunum, struct cppc_perf_caps *perf_caps)
941 } 990 }
942 } 991 }
943 992
944 cpc_read(highest_reg, &high); 993 cpc_read(cpunum, highest_reg, &high);
945 perf_caps->highest_perf = high; 994 perf_caps->highest_perf = high;
946 995
947 c