ACPI / CPPC: check for error bit in PCC status field
authorPrakash, Prashanth <pprakash@codeaurora.org>
Tue, 16 Aug 2016 20:39:44 +0000 (14:39 -0600)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tue, 30 Aug 2016 23:02:34 +0000 (01:02 +0200)
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: Prashanth Prakash <pprakash@codeaurora.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/acpi/cppc_acpi.c
include/acpi/cppc_acpi.h

index 80c123fbfdcf251e00d6cc2b04ebfa1ba2e68a8d..ed58883d35ee06fcdc484d71bebfcfada9d08b03 100644 (file)
@@ -54,6 +54,7 @@ struct cppc_pcc_data {
        unsigned int pcc_mpar, pcc_mrtt, pcc_nominal;
 
        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 */
 
        /*
@@ -79,6 +80,7 @@ struct cppc_pcc_data {
 /* Structure to represent the single PCC channel */
 static struct cppc_pcc_data pcc_data = {
        .pcc_subspace_idx = -1,
+       .platform_owns_pcc = true,
 };
 
 /*
@@ -181,12 +183,15 @@ static struct kobj_type cppc_ktype = {
        .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;
        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. */
        while (!ktime_after(ktime_get(), next_deadline)) {
                /*
@@ -194,8 +199,11 @@ static int check_pcc_chan(void)
                 * platform and should have set the command completion bit when
                 * 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;
+                       if (chk_err_bit && (status & PCC_ERROR_MASK))
+                               ret = -EIO;
                        break;
                }
                /*
@@ -205,6 +213,11 @@ static int check_pcc_chan(void)
                udelay(3);
        }
 
+       if (likely(!ret))
+               pcc_data.platform_owns_pcc = false;
+       else
+               pr_err("PCC check channel failed. Status=%x\n", status);
+
        return ret;
 }
 
@@ -234,7 +247,7 @@ static int send_pcc_cmd(u16 cmd)
                if (pcc_data.pending_pcc_write_cmd)
                        send_pcc_cmd(CMD_WRITE);
 
-               ret = check_pcc_chan();
+               ret = check_pcc_chan(false);
                if (ret)
                        goto end;
        } else /* CMD_WRITE */
@@ -282,6 +295,8 @@ static int send_pcc_cmd(u16 cmd)
        /* Flip CMD COMPLETE bit */
        writew_relaxed(0, &generic_comm_base->status);
 
+       pcc_data.platform_owns_pcc = true;
+
        /* Ring doorbell */
        ret = mbox_send_message(pcc_data.pcc_channel, &cmd);
        if (ret < 0) {
@@ -290,23 +305,11 @@ static int send_pcc_cmd(u16 cmd)
                goto end;
        }
 
-       /*
-        * For READs we need to ensure the cmd completed to ensure
-        * 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)
-                       last_cmd_cmpl_time = ktime_get();
-       }
+       /* wait for completion and check for PCC errro bit */
+       ret = check_pcc_chan(true);
+
+       if (pcc_data.pcc_mrtt)
+               last_cmd_cmpl_time = ktime_get();
 
        mbox_client_txdone(pcc_data.pcc_channel, ret);
 
@@ -1059,25 +1062,18 @@ int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
         */
        if (CPC_IN_PCC(desired_reg)) {
                down_read(&pcc_data.pcc_lock);  /* BEGIN Phase-I */
-               /*
-                * If there are pending write commands i.e pending_pcc_write_cmd
-                * 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 (pcc_data.platform_owns_pcc) {
+                       ret = check_pcc_chan(false);
                        if (ret) {
                                up_read(&pcc_data.pcc_lock);
                                return ret;
                        }
-                       /*
-                        * Update the pending_write to make sure a PCC CMD_READ
-                        * will not arrive and steal the channel during the
-                        * transition to write lock
-                        */
-                       pcc_data.pending_pcc_write_cmd = TRUE;
                }
+               /*
+                * Update the pending_write to make sure a PCC CMD_READ will not
+                * arrive and steal the channel during the switch to write lock
+                */
+               pcc_data.pending_pcc_write_cmd = true;
                cpc_desc->write_cmd_id = pcc_data.pcc_write_cnt;
                cpc_desc->write_cmd_status = 0;
        }
index f50b5339b8880b99e36ddd34b97e08d4dee2427d..0e83cc3009bc5a1532de65b4e2a648f6cd269037 100644 (file)
@@ -24,7 +24,9 @@
 #define CPPC_NUM_ENT   21
 #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
 
 /* CPPC specific PCC commands. */