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: Prashanth Prakash <pprakash@codeaurora.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index 80c123f..ed58883 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -54,6 +54,7 @@
 	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 @@
 /* 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 @@
 	.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 @@
 		 * 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 @@
 		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 @@
 		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 @@
 	/* 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 @@
 		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 @@
 	 */
 	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;
 	}
diff --git a/include/acpi/cppc_acpi.h b/include/acpi/cppc_acpi.h
index f50b533..0e83cc3 100644
--- a/include/acpi/cppc_acpi.h
+++ b/include/acpi/cppc_acpi.h
@@ -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. */