[Skiboot] [PATCH v2 22/23] cpu: Rework HILE change

Michael Neuling mikey at neuling.org
Sun Jun 25 05:17:27 AEST 2017


From: Benjamin Herrenschmidt <benh at kernel.crashing.org>

Create a more generic helper for changing HID0 bits on all
processors.

Signed-off-by: Benjamin Herrenschmidt <benh at kernel.crashing.org>
Signed-off-by: Michael Neuling <mikey at neuling.org>
---
 core/cpu.c         | 71 +++++++++++++++++++++++++++++++++---------------------
 core/fast-reboot.c |  5 ++--
 include/cpu.h      |  3 ++-
 3 files changed, 48 insertions(+), 31 deletions(-)

diff --git a/core/cpu.c b/core/cpu.c
index a083ed7e0d..31f5c928bb 100644
--- a/core/cpu.c
+++ b/core/cpu.c
@@ -52,6 +52,7 @@ static bool hile_supported;
 static unsigned long hid0_hile;
 static unsigned long hid0_attn;
 static bool pm_enabled;
+static bool current_hile_mode;
 
 unsigned long cpu_secondary_start __force_data = 0;
 
@@ -1024,44 +1025,51 @@ static int64_t opal_return_cpu(void)
 }
 opal_call(OPAL_RETURN_CPU, opal_return_cpu, 0);
 
-static void cpu_change_hile(void *hilep)
-{
-	bool hile = *(bool *)hilep;
-	unsigned long hid0;
-
-	hid0 = mfspr(SPR_HID0);
-	if (hile)
-		hid0 |= hid0_hile;
-	else
-		hid0 &= ~hid0_hile;
-	prlog(PR_DEBUG, "CPU: [%08x] HID0 set to 0x%016lx\n",
-	      this_cpu()->pir, hid0);
-	set_hid0(hid0);
+struct hid0_change_req {
+	uint64_t clr_bits;
+	uint64_t set_bits;
+};
 
-	this_cpu()->current_hile = hile;
+static void cpu_change_hid0(void *__req)
+{
+	struct hid0_change_req *req = __req;
+	unsigned long hid0, new_hid0;
+
+	hid0 = new_hid0 = mfspr(SPR_HID0);
+	new_hid0 &= ~req->clr_bits;
+	new_hid0 |= req->set_bits;
+	prlog(PR_DEBUG, "CPU: [%08x] HID0 change 0x%016lx -> 0x%016lx\n",
+		this_cpu()->pir, hid0, new_hid0);
+	set_hid0(new_hid0);
 }
 
-static int64_t cpu_change_all_hile(bool hile)
+static int64_t cpu_change_all_hid0(struct hid0_change_req *req)
 {
 	struct cpu_thread *cpu;
 
-	prlog(PR_INFO, "CPU: Switching HILE on all CPUs to %d\n", hile);
-
 	for_each_available_cpu(cpu) {
-		if (cpu->current_hile == hile)
+		if (!cpu_is_thread0(cpu))
 			continue;
 		if (cpu == this_cpu()) {
-			cpu_change_hile(&hile);
+			cpu_change_hid0(req);
 			continue;
 		}
-		cpu_wait_job(cpu_queue_job(cpu, "cpu_change_hile",
-					   cpu_change_hile, &hile), true);
+		cpu_wait_job(cpu_queue_job(cpu, "cpu_change_hid0",
+			cpu_change_hid0, req), true);
 	}
 	return OPAL_SUCCESS;
 }
 
+void cpu_fast_reboot_complete(void)
+{
+	/* Fast reboot will have cleared HID0:HILE */
+	current_hile_mode = false;
+
+}
+
 static int64_t opal_reinit_cpus(uint64_t flags)
 {
+	struct hid0_change_req req = { 0, 0 };
 	struct cpu_thread *cpu;
 	int64_t rc = OPAL_SUCCESS;
 	int i;
@@ -1105,19 +1113,26 @@ static int64_t opal_reinit_cpus(uint64_t flags)
 	this_cpu()->in_reinit = true;
 	unlock(&reinit_lock);
 
-	/*
-	 * If the flags affect endianness and we are on P8 DD2 or later, then
-	 * use the HID bit. We use the PVR (we could use the EC level in
-	 * the chip but the PVR is more readily available).
-	 */
+	/* If HILE change via HID0 is supported ... */
 	if (hile_supported &&
-	    (flags & (OPAL_REINIT_CPUS_HILE_BE | OPAL_REINIT_CPUS_HILE_LE))) {
+	    (flags & (OPAL_REINIT_CPUS_HILE_BE |
+		      OPAL_REINIT_CPUS_HILE_LE))) {
 		bool hile = !!(flags & OPAL_REINIT_CPUS_HILE_LE);
 
 		flags &= ~(OPAL_REINIT_CPUS_HILE_BE | OPAL_REINIT_CPUS_HILE_LE);
-		rc = cpu_change_all_hile(hile);
+		if (hile != current_hile_mode) {
+			if (hile)
+				req.set_bits |= hid0_hile;
+			else
+				req.clr_bits |= hid0_hile;
+			current_hile_mode = hile;
+		}
 	}
 
+	/* Apply HID bits changes if any */
+	if (req.set_bits || req.clr_bits)
+		cpu_change_all_hid0(&req);
+
 	/* If we have a P7, error out for LE switch, do nothing for BE */
 	if (proc_gen < proc_gen_p8) {
 		if (flags & OPAL_REINIT_CPUS_HILE_LE)
diff --git a/core/fast-reboot.c b/core/fast-reboot.c
index 884441df7c..7bfc06dee0 100644
--- a/core/fast-reboot.c
+++ b/core/fast-reboot.c
@@ -370,8 +370,6 @@ static void cleanup_cpu_state(void)
 {
 	struct cpu_thread *cpu = this_cpu();
 
-	cpu->current_hile = false;
-
 	/* Per core cleanup */
 	if (cpu_is_thread0(cpu)) {
 		/* Shared SPRs whacked back to normal */
@@ -562,6 +560,9 @@ void __noreturn fast_reboot_entry(void)
 	/* Set our state to active */
 	this_cpu()->state = cpu_state_active;
 
+	/* Let the CPU layer do some last minute global cleanups */
+	cpu_fast_reboot_complete();
+
 	/* We can now do NAP mode */
 	cpu_set_pm_enable(true);
 
diff --git a/include/cpu.h b/include/cpu.h
index 0cb6389ac0..1d19c200cd 100644
--- a/include/cpu.h
+++ b/include/cpu.h
@@ -48,7 +48,6 @@ struct cpu_thread {
 	uint32_t			server_no;
 	uint32_t			chip_id;
 	bool				is_secondary;
-	bool				current_hile;
 	struct cpu_thread		*primary;
 	enum cpu_thread_state		state;
 	struct dt_node			*node;
@@ -271,4 +270,6 @@ extern unsigned long __attrconst cpu_stack_top(unsigned int pir);
 extern void cpu_idle_job(void);
 extern void cpu_idle_delay(unsigned long delay, unsigned long min_pm);
 
+extern void cpu_fast_reboot_complete(void);
+
 #endif /* __CPU_H */
-- 
2.11.0



More information about the Skiboot mailing list