Skip to content

Commit 58e1c03

Browse files
Prakash, Prashanthrafaeljw
authored andcommitted
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 <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent b382bf8 commit 58e1c03

File tree

1 file changed

+19
-29
lines changed

1 file changed

+19
-29
lines changed

drivers/acpi/cppc_acpi.c

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
#include <linux/cpufreq.h>
4141
#include <linux/delay.h>
42+
#include <linux/iopoll.h>
4243
#include <linux/ktime.h>
4344
#include <linux/rwsem.h>
4445
#include <linux/wait.h>
@@ -49,7 +50,7 @@ struct cppc_pcc_data {
4950
struct mbox_chan *pcc_channel;
5051
void __iomem *pcc_comm_addr;
5152
bool pcc_channel_acquired;
52-
ktime_t deadline;
53+
unsigned int deadline_us;
5354
unsigned int pcc_mpar, pcc_mrtt, pcc_nominal;
5455

5556
bool pending_pcc_write_cmd; /* Any pending/batched PCC write cmds? */
@@ -198,42 +199,31 @@ static struct kobj_type cppc_ktype = {
198199

199200
static int check_pcc_chan(int pcc_ss_id, bool chk_err_bit)
200201
{
201-
int ret = -EIO, status = 0;
202+
int ret, status;
202203
struct cppc_pcc_data *pcc_ss_data = pcc_data[pcc_ss_id];
203204
struct acpi_pcct_shared_memory __iomem *generic_comm_base =
204205
pcc_ss_data->pcc_comm_addr;
205-
ktime_t next_deadline = ktime_add(ktime_get(),
206-
pcc_ss_data->deadline);
207206

208207
if (!pcc_ss_data->platform_owns_pcc)
209208
return 0;
210209

211-
/* Retry in case the remote processor was too slow to catch up. */
212-
while (!ktime_after(ktime_get(), next_deadline)) {
213-
/*
214-
* Per spec, prior to boot the PCC space wil be initialized by
215-
* platform and should have set the command completion bit when
216-
* PCC can be used by OSPM
217-
*/
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-
}
210+
/*
211+
* Poll PCC status register every 3us(delay_us) for maximum of
212+
* deadline_us(timeout_us) until PCC command complete bit is set(cond)
213+
*/
214+
ret = readw_relaxed_poll_timeout(&generic_comm_base->status, status,
215+
status & PCC_CMD_COMPLETE_MASK, 3,
216+
pcc_ss_data->deadline_us);
231217

232-
if (likely(!ret))
218+
if (likely(!ret)) {
233219
pcc_ss_data->platform_owns_pcc = false;
234-
else
235-
pr_err("PCC check channel failed for ss: %d. Status=%x\n",
236-
pcc_ss_id, status);
220+
if (chk_err_bit && (status & PCC_ERROR_MASK))
221+
ret = -EIO;
222+
}
223+
224+
if (unlikely(ret))
225+
pr_err("PCC check channel failed for ss: %d. ret=%d\n",
226+
pcc_ss_id, ret);
237227

238228
return ret;
239229
}
@@ -585,7 +575,7 @@ static int register_pcc_channel(int pcc_ss_idx)
585575
* So add an arbitrary amount of wait on top of Nominal.
586576
*/
587577
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;
589579
pcc_data[pcc_ss_idx]->pcc_mrtt = cppc_ss->min_turnaround_time;
590580
pcc_data[pcc_ss_idx]->pcc_mpar = cppc_ss->max_access_rate;
591581
pcc_data[pcc_ss_idx]->pcc_nominal = cppc_ss->latency;

0 commit comments

Comments
 (0)