diff mbox series

[V4,2/4] core/direct-controls: wait for core special wkup bit cleared

Message ID 1511158236-19477-1-git-send-email-shilpa.bhat@linux.vnet.ibm.com
State Accepted
Headers show
Series Fixes for reading DTS sensors of cores in idle state | expand

Commit Message

Shilpasri G Bhat Nov. 20, 2017, 6:10 a.m. UTC
From: Robert Lippert <rlippert@google.com>

When clearing special wakeup bit on a core, wait until the
bit is actually cleared by the hardware in the status register
until returning success.

This may help avoid issues with back-to-back reads where the
special wakeup request is cleared but the firmware is still
processing the request and the next attempt to set the bit
reads an immediate success from the previous operation.

Change-Id: I86ec8cbbbddd1a5724f451244907693bc09e01ea
Signed-off-by: Robert Lippert <rlippert@google.com>
---
 core/direct-controls.c | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/core/direct-controls.c b/core/direct-controls.c
index fcb9350..0ed00c1 100644
--- a/core/direct-controls.c
+++ b/core/direct-controls.c
@@ -95,8 +95,12 @@  static int p9_core_clear_special_wakeup(struct cpu_thread *cpu)
 	uint32_t chip_id = pir_to_chip_id(cpu->pir);
 	uint32_t core_id = pir_to_core_id(cpu->pir);
 	uint32_t swake_addr;
+	uint32_t sshhyp_addr;
+	uint64_t val;
+	int i;
 
 	swake_addr = XSCOM_ADDR_P9_EC_SLAVE(core_id, EC_PPM_SPECIAL_WKUP_HYP);
+	sshhyp_addr = XSCOM_ADDR_P9_EC_SLAVE(core_id, P9_EC_PPM_SSHHYP);
 
 	/*
 	 * De-assert special wakeup after a small delay.
@@ -110,8 +114,25 @@  static int p9_core_clear_special_wakeup(struct cpu_thread *cpu)
 				chip_id, core_id);
 		return OPAL_HARDWARE;
 	}
+	time_wait_us(1);
 
-	return OPAL_SUCCESS;
+	for (i = 0; i < P9_SPWKUP_TIMEOUT/P9_SPWKUP_POLL_INTERVAL; i++) {
+		if (xscom_read(chip_id, sshhyp_addr, &val)) {
+			prlog(PR_ERR, "Could not clear special wakeup on %u:%u:"
+					" Unable to read PPM_SSHHYP.\n",
+					chip_id, core_id);
+			return OPAL_HARDWARE;
+		}
+		if (!(val & P9_SPECIAL_WKUP_DONE))
+			return 0;
+
+		time_wait_us(P9_SPWKUP_POLL_INTERVAL);
+	}
+
+	prlog(PR_ERR, "Could not clear special wakeup on %u:%u:"
+			" timeout waiting for clear of SPECIAL_WKUP_DONE.\n",
+			chip_id, core_id);
+	return OPAL_HARDWARE;
 }
 
 static int p9_thread_quiesced(struct cpu_thread *cpu)