aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/cppc_acpi.c
diff options
context:
space:
mode:
authorPrakash, Prashanth <pprakash@codeaurora.org>2018-04-24 19:10:02 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2018-05-10 11:16:22 -0400
commit58e1c03536c959e0d45fde8261cb9c15da893fe6 (patch)
treeeee77e862fce70ff73394ed969b1303d8b3d21c1 /drivers/acpi/cppc_acpi.c
parentb382bf885269bffaa8444a9310db680f2f0f4151 (diff)
ACPI / CPPC: Fix invalid PCC channel status errors
Replace the faulty PCC status register polling code with a iopoll.h macro to fix incorrect reporting of PCC check errors ("PCC check channel failed"). There were potential codepaths where we could incorrectly return PCC channel status as busy even without checking the PCC status register once or not checking the status register before breaking out of the polling loop. For example, if the thread polling PCC status register was preempted and scheduled back after we have crossed the deadline then we can report that the channel is busy even without checking the status register. 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.c48
1 files changed, 19 insertions, 29 deletions
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 4446fa6c820e..d9ce4b162e2c 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -39,6 +39,7 @@
39 39
40#include <linux/cpufreq.h> 40#include <linux/cpufreq.h>
41#include <linux/delay.h> 41#include <linux/delay.h>
42#include <linux/iopoll.h>
42#include <linux/ktime.h> 43#include <linux/ktime.h>
43#include <linux/rwsem.h> 44#include <linux/rwsem.h>
44#include <linux/wait.h> 45#include <linux/wait.h>
@@ -49,7 +50,7 @@ struct cppc_pcc_data {
49 struct mbox_chan *pcc_channel; 50 struct mbox_chan *pcc_channel;
50 void __iomem *pcc_comm_addr; 51 void __iomem *pcc_comm_addr;
51 bool pcc_channel_acquired; 52 bool pcc_channel_acquired;
52 ktime_t deadline; 53 unsigned int deadline_us;
53 unsigned int pcc_mpar, pcc_mrtt, pcc_nominal; 54 unsigned int pcc_mpar, pcc_mrtt, pcc_nominal;
54 55
55 bool pending_pcc_write_cmd; /* Any pending/batched PCC write cmds? */ 56 bool pending_pcc_write_cmd; /* Any pending/batched PCC write cmds? */
@@ -198,42 +199,31 @@ static struct kobj_type cppc_ktype = {
198 199
199static int check_pcc_chan(int pcc_ss_id, bool chk_err_bit) 200static int check_pcc_chan(int pcc_ss_id, bool chk_err_bit)
200{ 201{
201 int ret = -EIO, status = 0; 202 int ret, status;
202 struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id]; 203 struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id];
203 struct acpi_pcct_shared_memory __iomem *generic_comm_base = 204 struct acpi_pcct_shared_memory __iomem *generic_comm_base =
204 pcc_ss_data->pcc_comm_addr; 205 pcc_ss_data->pcc_comm_addr;
205 ktime_t next_deadline = ktime_add(ktime_get(),
206 pcc_ss_data->deadline);
207 206
208 if (!pcc_ss_data->platform_owns_pcc) 207 if (!pcc_ss_data->platform_owns_pcc)
209 return 0; 208 return 0;
210 209
211 /* Retry in case the remote processor was too slow to catch up. */ 210 /*
212 while (!ktime_after(ktime_get(), next_deadline)) { 211 * Poll PCC status register every 3us(delay_us) for maximum of
213 /* 212 * deadline_us(timeout_us) until PCC command complete bit is set(cond)
214 * Per spec, prior to boot the PCC space wil be initialized by 213 */
215 * platform and should have set the command completion bit when 214 ret = readw_relaxed_poll_timeout(&generic_comm_base->status, status,
216 * PCC can be used by OSPM 215 status & PCC_CMD_COMPLETE_MASK, 3,
217 */ 216 pcc_ss_data->deadline_us);
218 status = readw_relaxed(&generic_comm_base->status);
219 if (status & PCC_CMD_COMPLETE_MASK) {
220 ret = 0;
221 if (chk_err_bit && (status & PCC_ERROR_MASK))
222 ret = -EIO;
223 break;
224 }
225 /*
226 * Reducing the bus traffic in case this loop takes longer than
227 * a few retries.
228 */
229 udelay(3);
230 }
231 217
232 if (likely(!ret)) 218 if (likely(!ret)) {
233 pcc_ss_data->platform_owns_pcc = false; 219 pcc_ss_data->platform_owns_pcc = false;
234 else 220 if (chk_err_bit && (status & PCC_ERROR_MASK))
235 pr_err("PCC check channel failed for ss: %d. Status=%x\n", 221 ret = -EIO;
236 pcc_ss_id, status); 222 }
223
224 if (unlikely(ret))
225 pr_err("PCC check channel failed for ss: %d. ret=%d\n",
226 pcc_ss_id, ret);
237 227
238 return ret; 228 return ret;
239} 229}
@@ -585,7 +575,7 @@ static int register_pcc_channel(int pcc_ss_idx)
585 * So add an arbitrary amount of wait on top of Nominal. 575 * So add an arbitrary amount of wait on top of Nominal.
586 */ 576 */
587 usecs_lat = NUM_RETRIES * cppc_ss->latency; 577 usecs_lat = NUM_RETRIES * cppc_ss->latency;
588 pcc_data[pcc_ss_idx]->deadline = ns_to_ktime(usecs_lat * NSEC_PER_USEC); 578 pcc_data[pcc_ss_idx]->deadline_us = usecs_lat;
589 pcc_data[pcc_ss_idx]->pcc_mrtt = cppc_ss->min_turnaround_time; 579 pcc_data[pcc_ss_idx]->pcc_mrtt = cppc_ss->min_turnaround_time;
590 pcc_data[pcc_ss_idx]->pcc_mpar = cppc_ss->max_access_rate; 580 pcc_data[pcc_ss_idx]->pcc_mpar = cppc_ss->max_access_rate;
591 pcc_data[pcc_ss_idx]->pcc_nominal = cppc_ss->latency; 581 pcc_data[pcc_ss_idx]->pcc_nominal = cppc_ss->latency;