Commit 139aee73 authored by Prakash, Prashanth's avatar Prakash, Prashanth Committed by Rafael J. Wysocki

ACPI / CPPC: check for error bit in PCC status field

PCC status field exposes an error bit(2) to indicate any errors during
the execution of last comamnd. This patch checks the error bit before
notifying success/failure to the cpufreq driver.
Signed-off-by: default avatarPrashanth Prakash <pprakash@codeaurora.org>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 8482ef8c
...@@ -54,6 +54,7 @@ struct cppc_pcc_data { ...@@ -54,6 +54,7 @@ struct cppc_pcc_data {
unsigned int pcc_mpar, pcc_mrtt, pcc_nominal; unsigned int pcc_mpar, pcc_mrtt, pcc_nominal;
bool pending_pcc_write_cmd; /* Any pending/batched PCC write cmds? */ bool pending_pcc_write_cmd; /* Any pending/batched PCC write cmds? */
bool platform_owns_pcc; /* Ownership of PCC subspace */
unsigned int pcc_write_cnt; /* Running count of PCC write commands */ unsigned int pcc_write_cnt; /* Running count of PCC write commands */
/* /*
...@@ -79,6 +80,7 @@ struct cppc_pcc_data { ...@@ -79,6 +80,7 @@ struct cppc_pcc_data {
/* Structure to represent the single PCC channel */ /* Structure to represent the single PCC channel */
static struct cppc_pcc_data pcc_data = { static struct cppc_pcc_data pcc_data = {
.pcc_subspace_idx = -1, .pcc_subspace_idx = -1,
.platform_owns_pcc = true,
}; };
/* /*
...@@ -181,12 +183,15 @@ static struct kobj_type cppc_ktype = { ...@@ -181,12 +183,15 @@ static struct kobj_type cppc_ktype = {
.default_attrs = cppc_attrs, .default_attrs = cppc_attrs,
}; };
static int check_pcc_chan(void) static int check_pcc_chan(bool chk_err_bit)
{ {
int ret = -EIO; int ret = -EIO, status = 0;
struct acpi_pcct_shared_memory __iomem *generic_comm_base = pcc_data.pcc_comm_addr; struct acpi_pcct_shared_memory __iomem *generic_comm_base = pcc_data.pcc_comm_addr;
ktime_t next_deadline = ktime_add(ktime_get(), pcc_data.deadline); ktime_t next_deadline = ktime_add(ktime_get(), pcc_data.deadline);
if (!pcc_data.platform_owns_pcc)
return 0;
/* Retry in case the remote processor was too slow to catch up. */ /* Retry in case the remote processor was too slow to catch up. */
while (!ktime_after(ktime_get(), next_deadline)) { while (!ktime_after(ktime_get(), next_deadline)) {
/* /*
...@@ -194,8 +199,11 @@ static int check_pcc_chan(void) ...@@ -194,8 +199,11 @@ static int check_pcc_chan(void)
* platform and should have set the command completion bit when * platform and should have set the command completion bit when
* PCC can be used by OSPM * PCC can be used by OSPM
*/ */
if (readw_relaxed(&generic_comm_base->status) & PCC_CMD_COMPLETE) { status = readw_relaxed(&generic_comm_base->status);
if (status & PCC_CMD_COMPLETE_MASK) {
ret = 0; ret = 0;
if (chk_err_bit && (status & PCC_ERROR_MASK))
ret = -EIO;
break; break;
} }
/* /*
...@@ -205,6 +213,11 @@ static int check_pcc_chan(void) ...@@ -205,6 +213,11 @@ static int check_pcc_chan(void)
udelay(3); udelay(3);
} }
if (likely(!ret))
pcc_data.platform_owns_pcc = false;
else
pr_err("PCC check channel failed. Status=%x\n", status);
return ret; return ret;
} }
...@@ -234,7 +247,7 @@ static int send_pcc_cmd(u16 cmd) ...@@ -234,7 +247,7 @@ static int send_pcc_cmd(u16 cmd)
if (pcc_data.pending_pcc_write_cmd) if (pcc_data.pending_pcc_write_cmd)
send_pcc_cmd(CMD_WRITE); send_pcc_cmd(CMD_WRITE);
ret = check_pcc_chan(); ret = check_pcc_chan(false);
if (ret) if (ret)
goto end; goto end;
} else /* CMD_WRITE */ } else /* CMD_WRITE */
...@@ -282,6 +295,8 @@ static int send_pcc_cmd(u16 cmd) ...@@ -282,6 +295,8 @@ static int send_pcc_cmd(u16 cmd)
/* Flip CMD COMPLETE bit */ /* Flip CMD COMPLETE bit */
writew_relaxed(0, &generic_comm_base->status); writew_relaxed(0, &generic_comm_base->status);
pcc_data.platform_owns_pcc = true;
/* Ring doorbell */ /* Ring doorbell */
ret = mbox_send_message(pcc_data.pcc_channel, &cmd); ret = mbox_send_message(pcc_data.pcc_channel, &cmd);
if (ret < 0) { if (ret < 0) {
...@@ -290,23 +305,11 @@ static int send_pcc_cmd(u16 cmd) ...@@ -290,23 +305,11 @@ static int send_pcc_cmd(u16 cmd)
goto end; goto end;
} }
/* /* wait for completion and check for PCC errro bit */
* For READs we need to ensure the cmd completed to ensure ret = check_pcc_chan(true);
* the ensuing read()s can proceed. For WRITEs we dont care
* because the actual write()s are done before coming here
* and the next READ or WRITE will check if the channel
* is busy/free at the entry of this call.
*
* If Minimum Request Turnaround Time is non-zero, we need
* to record the completion time of both READ and WRITE
* command for proper handling of MRTT, so we need to check
* for pcc_mrtt in addition to CMD_READ
*/
if (cmd == CMD_READ || pcc_data.pcc_mrtt) {
ret = check_pcc_chan();
if (pcc_data.pcc_mrtt) if (pcc_data.pcc_mrtt)
last_cmd_cmpl_time = ktime_get(); last_cmd_cmpl_time = ktime_get();
}
mbox_client_txdone(pcc_data.pcc_channel, ret); mbox_client_txdone(pcc_data.pcc_channel, ret);
...@@ -1059,25 +1062,18 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls) ...@@ -1059,25 +1062,18 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
*/ */
if (CPC_IN_PCC(desired_reg)) { if (CPC_IN_PCC(desired_reg)) {
down_read(&pcc_data.pcc_lock); /* BEGIN Phase-I */ down_read(&pcc_data.pcc_lock); /* BEGIN Phase-I */
/* if (pcc_data.platform_owns_pcc) {
* If there are pending write commands i.e pending_pcc_write_cmd ret = check_pcc_chan(false);
* is TRUE, then we know OSPM owns the channel as another CPU
* has already checked for command completion bit and updated
* the corresponding CPC registers
*/
if (!pcc_data.pending_pcc_write_cmd) {
ret = check_pcc_chan();
if (ret) { if (ret) {
up_read(&pcc_data.pcc_lock); up_read(&pcc_data.pcc_lock);
return ret; return ret;
} }
}
/* /*
* Update the pending_write to make sure a PCC CMD_READ * Update the pending_write to make sure a PCC CMD_READ will not
* will not arrive and steal the channel during the * arrive and steal the channel during the switch to write lock
* transition to write lock
*/ */
pcc_data.pending_pcc_write_cmd = TRUE; pcc_data.pending_pcc_write_cmd = true;
}
cpc_desc->write_cmd_id = pcc_data.pcc_write_cnt; cpc_desc->write_cmd_id = pcc_data.pcc_write_cnt;
cpc_desc->write_cmd_status = 0; cpc_desc->write_cmd_status = 0;
} }
......
...@@ -24,7 +24,9 @@ ...@@ -24,7 +24,9 @@
#define CPPC_NUM_ENT 21 #define CPPC_NUM_ENT 21
#define CPPC_REV 2 #define CPPC_REV 2
#define PCC_CMD_COMPLETE 1 #define PCC_CMD_COMPLETE_MASK (1 << 0)
#define PCC_ERROR_MASK (1 << 2)
#define MAX_CPC_REG_ENT 19 #define MAX_CPC_REG_ENT 19
/* CPPC specific PCC commands. */ /* CPPC specific PCC commands. */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment