[Skiboot] [PATCH 1/2] core/direct-controls: fix p9_cont_thread for stopped/inactive threads

Nicholas Piggin npiggin at gmail.com
Thu May 3 18:38:08 AEST 2018


Firstly, p9_cont_thread should check that the thread actually was
quiesced before it tries to resume it. Anything could happen if we
try this from an arbitrary thread state.

Then when resuming a quiesced thread that is inactive or stopped (in
a stop idle state), we must not send a core_start direct control,
clear_maint must be used in these cases.

Signed-off-by: Nicholas Piggin <npiggin at gmail.com>
---
 core/direct-controls.c | 87 +++++++++++++++++++++++++++++++++---------
 1 file changed, 70 insertions(+), 17 deletions(-)

diff --git a/core/direct-controls.c b/core/direct-controls.c
index c7b9c9b7..4511a113 100644
--- a/core/direct-controls.c
+++ b/core/direct-controls.c
@@ -273,10 +273,14 @@ static int p8_sreset_thread(struct cpu_thread *cpu)
 #define P9_QUIESCE_POLL_INTERVAL	100
 #define P9_QUIESCE_TIMEOUT		100000
 
+#define P9_CORE_THREAD_STATE		0x10ab3
+#define P9_THREAD_INFO			0x10a9b
+
 #define P9_EC_DIRECT_CONTROLS		0x10a9c
 #define P9_THREAD_STOP(t)		PPC_BIT(7 + 8*(t))
 #define P9_THREAD_CONT(t)		PPC_BIT(6 + 8*(t))
 #define P9_THREAD_SRESET(t)		PPC_BIT(4 + 8*(t))
+#define P9_THREAD_CLEAR_MAINT(t)	PPC_BIT(3 + 8*(t))
 #define P9_THREAD_PWR(t)		PPC_BIT(32 + 8*(t))
 
 /* EC_PPM_SPECIAL_WKUP_HYP */
@@ -412,6 +416,72 @@ static int p9_thread_quiesced(struct cpu_thread *cpu)
 	return 0;
 }
 
+static int p9_cont_thread(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 thread_id = pir_to_thread_id(cpu->pir);
+	uint32_t cts_addr;
+	uint32_t ti_addr;
+	uint32_t dctl_addr;
+	uint64_t core_thread_state;
+	uint64_t thread_info;
+	bool active, stop;
+	int rc;
+
+	rc = p9_thread_quiesced(cpu);
+	if (rc < 0)
+		return rc;
+	if (!rc) {
+		prlog(PR_ERR, "Could not cont thread %u:%u:%u:"
+				" Thread is not quiesced.\n",
+				chip_id, core_id, thread_id);
+		return OPAL_BUSY;
+	}
+
+	cts_addr = XSCOM_ADDR_P9_EC(core_id, P9_CORE_THREAD_STATE);
+	ti_addr = XSCOM_ADDR_P9_EC(core_id, P9_THREAD_INFO);
+	dctl_addr = XSCOM_ADDR_P9_EC(core_id, P9_EC_DIRECT_CONTROLS);
+
+	if (xscom_read(chip_id, cts_addr, &core_thread_state)) {
+		prlog(PR_ERR, "Could not resume thread %u:%u:%u:"
+				" Unable to read CORE_THREAD_STATE.\n",
+				chip_id, core_id, thread_id);
+		return OPAL_HARDWARE;
+	}
+	if (core_thread_state & PPC_BIT(56 + thread_id))
+		stop = true;
+	else
+		stop = false;
+
+	if (xscom_read(chip_id, ti_addr, &thread_info)) {
+		prlog(PR_ERR, "Could not resume thread %u:%u:%u:"
+				" Unable to read THREAD_INFO.\n",
+				chip_id, core_id, thread_id);
+		return OPAL_HARDWARE;
+	}
+	if (thread_info & PPC_BIT(thread_id))
+		active = true;
+	else
+		active = false;
+
+	if (!active || stop) {
+		if (xscom_write(chip_id, dctl_addr, P9_THREAD_CLEAR_MAINT(thread_id))) {
+			prlog(PR_ERR, "Could not resume thread %u:%u:%u:"
+				      " Unable to write EC_DIRECT_CONTROLS.\n",
+				      chip_id, core_id, thread_id);
+		}
+	} else {
+		if (xscom_write(chip_id, dctl_addr, P9_THREAD_CONT(thread_id))) {
+			prlog(PR_ERR, "Could not resume thread %u:%u:%u:"
+				      " Unable to write EC_DIRECT_CONTROLS.\n",
+				      chip_id, core_id, thread_id);
+		}
+	}
+
+	return 0;
+}
+
 static int p9_stop_thread(struct cpu_thread *cpu)
 {
 	uint32_t chip_id = pir_to_chip_id(cpu->pir);
@@ -461,23 +531,6 @@ static int p9_stop_thread(struct cpu_thread *cpu)
 	return OPAL_HARDWARE;
 }
 
-static int p9_cont_thread(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 thread_id = pir_to_thread_id(cpu->pir);
-	uint32_t dctl_addr;
-
-	dctl_addr = XSCOM_ADDR_P9_EC(core_id, P9_EC_DIRECT_CONTROLS);
-	if (xscom_write(chip_id, dctl_addr, P9_THREAD_CONT(thread_id))) {
-		prlog(PR_ERR, "Could not resume thread %u:%u:%u:"
-				" Unable to write EC_DIRECT_CONTROLS.\n",
-				chip_id, core_id, thread_id);
-	}
-
-	return 0;
-}
-
 static int p9_sreset_thread(struct cpu_thread *cpu)
 {
 	uint32_t chip_id = pir_to_chip_id(cpu->pir);
-- 
2.17.0



More information about the Skiboot mailing list