diff options
author | Prakash, Prashanth <pprakash@codeaurora.org> | 2016-08-16 16:39:41 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-08-30 19:02:33 -0400 |
commit | be8b88d7d9877114172b32817d8eb3e85d3d8f99 (patch) | |
tree | 46cfd3c473ffcf900680952a437d137355eef6a2 | |
parent | 80b8286aeec056d21bffed2d1ece3904516e9c91 (diff) |
ACPI / CPPC: set a non-zero value for transition_latency
Compute the expected transition latency for frequency transitions
using the values from the PCCT tables when the desired perf
register is in PCC.
Signed-off-by: Prashanth Prakash <pprakash@codeaurora.org>
Reviewed-by: Alexey Klimov <alexey.klimov@arm.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r-- | drivers/acpi/cppc_acpi.c | 46 | ||||
-rw-r--r-- | drivers/cpufreq/cppc_cpufreq.c | 1 | ||||
-rw-r--r-- | include/acpi/cppc_acpi.h | 1 |
3 files changed, 46 insertions, 2 deletions
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index 5623fca54ca1..6c54a8f16706 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c | |||
@@ -85,7 +85,7 @@ static void __iomem *pcc_comm_addr; | |||
85 | static int pcc_subspace_idx = -1; | 85 | static int pcc_subspace_idx = -1; |
86 | static bool pcc_channel_acquired; | 86 | static bool pcc_channel_acquired; |
87 | static ktime_t deadline; | 87 | static ktime_t deadline; |
88 | static unsigned int pcc_mpar, pcc_mrtt; | 88 | static unsigned int pcc_mpar, pcc_mrtt, pcc_nominal; |
89 | 89 | ||
90 | /* pcc mapped address + header size + offset within PCC subspace */ | 90 | /* pcc mapped address + header size + offset within PCC subspace */ |
91 | #define GET_PCC_VADDR(offs) (pcc_comm_addr + 0x8 + (offs)) | 91 | #define GET_PCC_VADDR(offs) (pcc_comm_addr + 0x8 + (offs)) |
@@ -473,7 +473,6 @@ static int register_pcc_channel(int pcc_subspace_idx) | |||
473 | return -ENODEV; | 473 | return -ENODEV; |
474 | } | 474 | } |
475 | 475 | ||
476 | |||
477 | /* | 476 | /* |
478 | * cppc_ss->latency is just a Nominal value. In reality | 477 | * cppc_ss->latency is just a Nominal value. In reality |
479 | * the remote processor could be much slower to reply. | 478 | * the remote processor could be much slower to reply. |
@@ -483,6 +482,7 @@ static int register_pcc_channel(int pcc_subspace_idx) | |||
483 | deadline = ns_to_ktime(usecs_lat * NSEC_PER_USEC); | 482 | deadline = ns_to_ktime(usecs_lat * NSEC_PER_USEC); |
484 | pcc_mrtt = cppc_ss->min_turnaround_time; | 483 | pcc_mrtt = cppc_ss->min_turnaround_time; |
485 | pcc_mpar = cppc_ss->max_access_rate; | 484 | pcc_mpar = cppc_ss->max_access_rate; |
485 | pcc_nominal = cppc_ss->latency; | ||
486 | 486 | ||
487 | pcc_comm_addr = acpi_os_ioremap(cppc_ss->base_address, cppc_ss->length); | 487 | pcc_comm_addr = acpi_os_ioremap(cppc_ss->base_address, cppc_ss->length); |
488 | if (!pcc_comm_addr) { | 488 | if (!pcc_comm_addr) { |
@@ -1048,3 +1048,45 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) | |||
1048 | return ret; | 1048 | return ret; |
1049 | } | 1049 | } |
1050 | EXPORT_SYMBOL_GPL(cppc_set_perf); | 1050 | EXPORT_SYMBOL_GPL(cppc_set_perf); |
1051 | |||
1052 | /** | ||
1053 | * cppc_get_transition_latency - returns frequency transition latency in ns | ||
1054 | * | ||
1055 | * ACPI CPPC does not explicitly specifiy how a platform can specify the | ||
1056 | * transition latency for perfromance change requests. The closest we have | ||
1057 | * is the timing information from the PCCT tables which provides the info | ||
1058 | * on the number and frequency of PCC commands the platform can handle. | ||
1059 | */ | ||
1060 | unsigned int cppc_get_transition_latency(int cpu_num) | ||
1061 | { | ||
1062 | /* | ||
1063 | * Expected transition latency is based on the PCCT timing values | ||
1064 | * Below are definition from ACPI spec: | ||
1065 | * pcc_nominal- Expected latency to process a command, in microseconds | ||
1066 | * pcc_mpar - The maximum number of periodic requests that the subspace | ||
1067 | * channel can support, reported in commands per minute. 0 | ||
1068 | * indicates no limitation. | ||
1069 | * pcc_mrtt - The minimum amount of time that OSPM must wait after the | ||
1070 | * completion of a command before issuing the next command, | ||
1071 | * in microseconds. | ||
1072 | */ | ||
1073 | unsigned int latency_ns = 0; | ||
1074 | struct cpc_desc *cpc_desc; | ||
1075 | struct cpc_register_resource *desired_reg; | ||
1076 | |||
1077 | cpc_desc = per_cpu(cpc_desc_ptr, cpu_num); | ||
1078 | if (!cpc_desc) | ||
1079 | return CPUFREQ_ETERNAL; | ||
1080 | |||
1081 | desired_reg = &cpc_desc->cpc_regs[DESIRED_PERF]; | ||
1082 | if (!CPC_IN_PCC(desired_reg)) | ||
1083 | return CPUFREQ_ETERNAL; | ||
1084 | |||
1085 | if (pcc_mpar) | ||
1086 | latency_ns = 60 * (1000 * 1000 * 1000 / pcc_mpar); | ||
1087 | |||
1088 | latency_ns = max(latency_ns, (pcc_nominal + pcc_mrtt) * 1000); | ||
1089 | |||
1090 | return latency_ns; | ||
1091 | } | ||
1092 | EXPORT_SYMBOL_GPL(cppc_get_transition_latency); | ||
diff --git a/drivers/cpufreq/cppc_cpufreq.c b/drivers/cpufreq/cppc_cpufreq.c index 8882b8e2ecd0..e6a33596dea3 100644 --- a/drivers/cpufreq/cppc_cpufreq.c +++ b/drivers/cpufreq/cppc_cpufreq.c | |||
@@ -98,6 +98,7 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy) | |||
98 | policy->max = cpu->perf_caps.highest_perf; | 98 | policy->max = cpu->perf_caps.highest_perf; |
99 | policy->cpuinfo.min_freq = policy->min; | 99 | policy->cpuinfo.min_freq = policy->min; |
100 | policy->cpuinfo.max_freq = policy->max; | 100 | policy->cpuinfo.max_freq = policy->max; |
101 | policy->cpuinfo.transition_latency = cppc_get_transition_latency(cpu_num); | ||
101 | policy->shared_type = cpu->shared_type; | 102 | policy->shared_type = cpu->shared_type; |
102 | 103 | ||
103 | if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) | 104 | if (policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) |
diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h index d2101bcea013..42cbeb93ea32 100644 --- a/include/acpi/cppc_acpi.h +++ b/include/acpi/cppc_acpi.h | |||
@@ -131,5 +131,6 @@ extern int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs); | |||
131 | extern int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls); | 131 | extern int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls); |
132 | extern int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps); | 132 | extern int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps); |
133 | extern int acpi_get_psd_map(struct cpudata **); | 133 | extern int acpi_get_psd_map(struct cpudata **); |
134 | extern unsigned int cppc_get_transition_latency(int cpu); | ||
134 | 135 | ||
135 | #endif /* _CPPC_ACPI_H*/ | 136 | #endif /* _CPPC_ACPI_H*/ |