Skip to contentSkip to conversation

powerpc: Adjust CPU_FTR_SMT on all platforms

PATCH In review Benjamin Herrenschmidt 2 participants 8 messages Mar 28, 2014 – Apr 11, 2014

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/7 powerpc: Adjust CPU_FTR_SMT on all platforms

For historical reasons that code was under #ifdef CONFIG_PPC_PSERIES but it applies equally to all 64-bit platforms.

---
 arch/powerpc/kernel/prom.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/powerpc/kernel/prom.c +1 -1
index d711b7e..0fc55b5 100644
@@ -378,7 +378,7 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
 	check_cpu_pa_features(node);
 	check_cpu_slb_size(node);
 
-#ifdef CONFIG_PPC_PSERIES
+#ifdef CONFIG_PPC64
 	if (nthreads > 1)
 		cur_cpu_spec->cpu_features |= CPU_FTR_SMT;
 	else
Signature · 1 line
1.8.3.2
#1 lore raw

PATCH 2/7 powerpc: Make boot_cpuid common between 32 and 64-bit

Move the definition to setup-common.c and set the init value to -1 on both 32 and 64-bit (it was 0 on 64-bit).

Additionally add a check to prom.c to garantee that the init value has been udpated after the DT scan.

---
 arch/powerpc/kernel/prom.c         | 4 ++++
 arch/powerpc/kernel/setup-common.c | 3 +++
 arch/powerpc/kernel/setup_32.c     | 2 --
 arch/powerpc/kernel/setup_64.c     | 1 -
 4 files changed, 7 insertions(+), 3 deletions(-)
arch/powerpc/kernel/prom.c +4 -0
index 0fc55b5..f1002b1 100644
@@ -744,6 +744,10 @@ void __init early_init_devtree(void *params)
 	 * (altivec support, boot CPU ID, ...)
 	 */
 	of_scan_flat_dt(early_init_dt_scan_cpus, NULL);
+	if (boot_cpuid < 0) {
+		printk("Failed to indentify boot CPU !\n");
+		BUG();
+	}
 
 #if defined(CONFIG_SMP) && defined(CONFIG_PPC64)
 	/* We'll later wait for secondaries to check in; there are
arch/powerpc/kernel/setup-common.c +3 -0
index bc76cc6..79b7612 100644
@@ -76,6 +76,9 @@ EXPORT_SYMBOL(ppc_md);
 struct machdep_calls *machine_id;
 EXPORT_SYMBOL(machine_id);
 
+int boot_cpuid = -1;
+EXPORT_SYMBOL_GPL(boot_cpuid);
+
 unsigned long klimit = (unsigned long) _end;
 
 char cmd_line[COMMAND_LINE_SIZE];
arch/powerpc/kernel/setup_32.c +0 -2
index 04cc4fc..ea4fda6 100644
@@ -44,8 +44,6 @@
 
 extern void bootx_init(unsigned long r4, unsigned long phys);
 
-int boot_cpuid = -1;
-EXPORT_SYMBOL_GPL(boot_cpuid);
 int boot_cpuid_phys;
 EXPORT_SYMBOL_GPL(boot_cpuid_phys);
 
arch/powerpc/kernel/setup_64.c +0 -1
index 4933909..d8aabbd 100644
@@ -74,7 +74,6 @@
 #define DBG(fmt...)
 #endif
 
-int boot_cpuid = 0;
 int spinning_secondaries;
 u64 ppc64_pft_size;
 
Signature · 1 line
1.8.3.2
#2 lore raw

PATCH 3/7 powerpc/prom: early_init_dt_scan_cpus() updates cpu features only once

In reply to Benjamin Herrenschmidt

All our cpu feature updates were done for every CPU in the device-tree, thus overwriting the cputable bits over and over again. Instead do them only for the boot CPU.

---
 arch/powerpc/kernel/prom.c | 52 +++++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 26 deletions(-)
arch/powerpc/kernel/prom.c +26 -26
index f1002b1..7270ca1 100644
@@ -346,33 +346,34 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
 #endif
 	}
 
-	if (found >= 0) {
-		DBG("boot cpu: logical %d physical %d\n", found,
-			be32_to_cpu(intserv[found_thread]));
-		boot_cpuid = found;
-		set_hard_smp_processor_id(found,
-			be32_to_cpu(intserv[found_thread]));
+	/* Not the boot CPU */
+	if (found < 0)
+		return 0;
 
-		/*
-		 * PAPR defines "logical" PVR values for cpus that
-		 * meet various levels of the architecture:
-		 * 0x0f000001	Architecture version 2.04
-		 * 0x0f000002	Architecture version 2.05
-		 * If the cpu-version property in the cpu node contains
-		 * such a value, we call identify_cpu again with the
-		 * logical PVR value in order to use the cpu feature
-		 * bits appropriate for the architecture level.
-		 *
-		 * A POWER6 partition in "POWER6 architected" mode
-		 * uses the 0x0f000002 PVR value; in POWER5+ mode
-		 * it uses 0x0f000001.
-		 */
-		prop = of_get_flat_dt_prop(node, "cpu-version", NULL);
-		if (prop && (be32_to_cpup(prop) & 0xff000000) == 0x0f000000)
-			identify_cpu(0, be32_to_cpup(prop));
+	DBG("boot cpu: logical %d physical %d\n", found,
+	    be32_to_cpu(intserv[found_thread]));
+	boot_cpuid = found;
+	set_hard_smp_processor_id(found, be32_to_cpu(intserv[found_thread]));
 
-		identical_pvr_fixup(node);
-	}
+	/*
+	 * PAPR defines "logical" PVR values for cpus that
+	 * meet various levels of the architecture:
+	 * 0x0f000001	Architecture version 2.04
+	 * 0x0f000002	Architecture version 2.05
+	 * If the cpu-version property in the cpu node contains
+	 * such a value, we call identify_cpu again with the
+	 * logical PVR value in order to use the cpu feature
+	 * bits appropriate for the architecture level.
+	 *
+	 * A POWER6 partition in "POWER6 architected" mode
+	 * uses the 0x0f000002 PVR value; in POWER5+ mode
+	 * it uses 0x0f000001.
+	 */
+	prop = of_get_flat_dt_prop(node, "cpu-version", NULL);
+	if (prop && (be32_to_cpup(prop) & 0xff000000) == 0x0f000000)
+		identify_cpu(0, be32_to_cpup(prop));
+
+	identical_pvr_fixup(node);
 
 	check_cpu_feature_properties(node);
 	check_cpu_pa_features(node);
@@ -384,7 +385,6 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
 	else
 		cur_cpu_spec->cpu_features &= ~CPU_FTR_SMT;
 #endif
-
 	return 0;
 }
 
Signature · 1 line
1.8.3.2
#3 lore raw

PATCH 4/7 powerpc/ppc64: Gracefully handle early interrupts

In reply to Benjamin Herrenschmidt

If we take an interrupt such as a trap caused by a BUG_ON before the MMU has been setup, the interrupt handlers try to enable virutal mode and cause a recursive crash, making the original problem very hard to debug.

This fixes it by adjusting the "kernel_msr" value in the PACA so that it only has MSR_IR and MSR_DR (translation for instruction and data) set after the MMU has been initialized for the processor.

We may still not have a console yet but at least we don't get into a recursive fault (and early debug console or memory dump via JTAG of the kernel buffer *will* give us the proper error).

---
 arch/powerpc/kernel/paca.c     |  3 ++-
 arch/powerpc/kernel/setup_64.c | 15 +++++++++++++++
 2 files changed, 17 insertions(+), 1 deletion(-)
arch/powerpc/kernel/paca.c +2 -1
index bf0aada..ad302f8 100644
@@ -152,7 +152,8 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu)
 	new_paca->paca_index = cpu;
 	new_paca->kernel_toc = kernel_toc;
 	new_paca->kernelbase = (unsigned long) _stext;
-	new_paca->kernel_msr = MSR_KERNEL;
+	/* Only set MSR:IR/DR when MMU is initialized */
+	new_paca->kernel_msr = MSR_KERNEL & ~(MSR_IR | MSR_DR);
 	new_paca->hw_cpu_id = 0xffff;
 	new_paca->kexec_state = KEXEC_STATE_NONE;
 	new_paca->__current = &init_task;
arch/powerpc/kernel/setup_64.c +15 -0
index d8aabbd..1d33e81 100644
@@ -261,6 +261,14 @@ void __init early_setup(unsigned long dt_ptr)
 	/* Initialize the hash table or TLB handling */
 	early_init_mmu();
 
+	/*
+	 * At this point, we can let interrupts switch to virtual mode
+	 * (the MMU has been setup), so adjust the MSR in the PACA to
+	 * have IR and DR set.
+	 */
+	get_paca()->kernel_msr = MSR_KERNEL;
+
+	/* Reserve large chunks of memory for use by CMA for KVM */
 	kvm_cma_reserve();
 
 	/*
@@ -293,6 +301,13 @@ void early_setup_secondary(void)
 
 	/* Initialize the hash table or TLB handling */
 	early_init_mmu_secondary();
+
+	/*
+	 * At this point, we can let interrupts switch to virtual mode
+	 * (the MMU has been setup), so adjust the MSR in the PACA to
+	 * have IR and DR set.
+	 */
+	get_paca()->kernel_msr = MSR_KERNEL;
 }
 
 #endif /* CONFIG_SMP */
Signature · 1 line
1.8.3.2
#4 lore raw

PATCH 5/7 powerpc/ppc64: Do not turn AIL (reloc-on interrupts) too early

In reply to Benjamin Herrenschmidt

Turn them on at the same time as we allow MSR_IR/DR in the paca kernel MSR, ie, after the MMU has been setup enough to be able to handle relocated access to the linear mapping.

---
 arch/powerpc/kernel/cpu_setup_power.S |  2 --
 arch/powerpc/kernel/setup_64.c        | 18 +++++++++++++++---
 2 files changed, 15 insertions(+), 5 deletions(-)
arch/powerpc/kernel/cpu_setup_power.S +0 -2
index 37d1bb0..1557e7c 100644
@@ -56,7 +56,6 @@ _GLOBAL(__setup_cpu_power8)
 	li	r0,0
 	mtspr	SPRN_LPID,r0
 	mfspr	r3,SPRN_LPCR
-	oris	r3, r3, LPCR_AIL_3@h
 	bl	__init_LPCR
 	bl	__init_HFSCR
 	bl	__init_tlb_power8
@@ -75,7 +74,6 @@ _GLOBAL(__restore_cpu_power8)
 	li	r0,0
 	mtspr	SPRN_LPID,r0
 	mfspr   r3,SPRN_LPCR
-	oris	r3, r3, LPCR_AIL_3@h
 	bl	__init_LPCR
 	bl	__init_HFSCR
 	bl	__init_tlb_power8
arch/powerpc/kernel/setup_64.c +15 -3
index 1d33e81..3d7a50a 100644
@@ -195,6 +195,18 @@ static void fixup_boot_paca(void)
 	get_paca()->data_offset = 0;
 }
 
+static void cpu_ready_for_interrupts(void)
+{
+	/* Set IR and DR in PACA MSR */
+	get_paca()->kernel_msr = MSR_KERNEL;
+
+	/* Enable AIL if supported */
+	if (cpu_has_feature(CPU_FTR_ARCH_207S)) {
+		unsigned long lpcr = mfspr(SPRN_LPCR);
+		mtspr(SPRN_LPCR, lpcr | LPCR_AIL_3);
+	}
+}
+
 /*
  * Early initialization entry point. This is called by head.S
  * with MMU translation disabled. We rely on the "feature" of
@@ -264,9 +276,9 @@ void __init early_setup(unsigned long dt_ptr)
 	/*
 	 * At this point, we can let interrupts switch to virtual mode
 	 * (the MMU has been setup), so adjust the MSR in the PACA to
-	 * have IR and DR set.
+	 * have IR and DR set and enable AIL if it exists
 	 */
-	get_paca()->kernel_msr = MSR_KERNEL;
+	cpu_ready_for_interrupts();
 
 	/* Reserve large chunks of memory for use by CMA for KVM */
 	kvm_cma_reserve();
@@ -307,7 +319,7 @@ void early_setup_secondary(void)
 	 * (the MMU has been setup), so adjust the MSR in the PACA to
 	 * have IR and DR set.
 	 */
-	get_paca()->kernel_msr = MSR_KERNEL;
+	cpu_ready_for_interrupts();
 }
 
 #endif /* CONFIG_SMP */
Signature · 1 line
1.8.3.2
#5 lore raw

Re: [PATCH 5/7] powerpc/ppc64: Do not turn AIL (reloc-on interrupts) too early

Quoted 23 lines · Benjamin Herrenschmidt

Turn them on at the same time as we allow MSR_IR/DR in the paca kernel MSR, ie, after the MMU has been setup enough to be able to handle relocated access to the linear mapping.

---
 arch/powerpc/kernel/cpu_setup_power.S |  2 --
 arch/powerpc/kernel/setup_64.c        | 18 +++++++++++++++---
 2 files changed, 15 insertions(+), 5 deletions(-)
arch/powerpc/kernel/cpu_setup_power.S +0 -1
index 37d1bb0..1557e7c 100644
@@ -56,7 +56,6 @@ _GLOBAL(__setup_cpu_power8)
 	li	r0,0
 	mtspr	SPRN_LPID,r0
 	mfspr	r3,SPRN_LPCR
-	oris	r3, r3, LPCR_AIL_3@h
 	bl	__init_LPCR
 	bl	__init_HFSCR
 	bl	__init_tlb_power8

arch/powerpc/kernel/cpu_setup_power.S _GLOBAL(__restore_cpu_power8) · line 79

Quoted 7 lines
arch/powerpc/kernel/cpu_setup_power.S +0 -1
@@ -75,7 +74,6 @@ _GLOBAL(__restore_cpu_power8)
 	li	r0,0
 	mtspr	SPRN_LPID,r0
 	mfspr   r3,SPRN_LPCR
-	oris	r3, r3, LPCR_AIL_3@h
 	bl	__init_LPCR
 	bl	__init_HFSCR
 	bl	__init_tlb_power8

BTW with this we can put the "mfspr r3,SPRN_LPCR" in __init_LPCR
and clean this code up bit.

Mikey

Quoted 51 lines
arch/powerpc/kernel/setup_64.c +15 -3
index 1d33e81..3d7a50a 100644
@@ -195,6 +195,18 @@ static void fixup_boot_paca(void)
 	get_paca()->data_offset = 0;
 }
 
+static void cpu_ready_for_interrupts(void)
+{
+	/* Set IR and DR in PACA MSR */
+	get_paca()->kernel_msr = MSR_KERNEL;
+
+	/* Enable AIL if supported */
+	if (cpu_has_feature(CPU_FTR_ARCH_207S)) {
+		unsigned long lpcr = mfspr(SPRN_LPCR);
+		mtspr(SPRN_LPCR, lpcr | LPCR_AIL_3);
+	}
+}
+
 /*
  * Early initialization entry point. This is called by head.S
  * with MMU translation disabled. We rely on the "feature" of
@@ -264,9 +276,9 @@ void __init early_setup(unsigned long dt_ptr)
 	/*
 	 * At this point, we can let interrupts switch to virtual mode
 	 * (the MMU has been setup), so adjust the MSR in the PACA to
-	 * have IR and DR set.
+	 * have IR and DR set and enable AIL if it exists
 	 */
-	get_paca()->kernel_msr = MSR_KERNEL;
+	cpu_ready_for_interrupts();
 
 	/* Reserve large chunks of memory for use by CMA for KVM */
 	kvm_cma_reserve();
@@ -307,7 +319,7 @@ void early_setup_secondary(void)
 	 * (the MMU has been setup), so adjust the MSR in the PACA to
 	 * have IR and DR set.
 	 */
-	get_paca()->kernel_msr = MSR_KERNEL;
+	cpu_ready_for_interrupts();
 }
 
 #endif /* CONFIG_SMP */
Signature · 6 lines
1.8.3.2

_______________________________________________
Linuxppc-dev mailing list
[email protected]
https://lists.ozlabs.org/listinfo/linuxppc-dev
#6 lore raw

PATCH 6/7 powerpc/powernv: Add opal_notifier_unregister() and export to modules

In reply to Benjamin Herrenschmidt

opal_notifier_register() is missing a pending "unregister" variant and should be exposed to modules.

---
 arch/powerpc/include/asm/opal.h       |  2 ++
 arch/powerpc/platforms/powernv/opal.c | 14 ++++++++++++++
 2 files changed, 16 insertions(+)
arch/powerpc/include/asm/opal.h +2 -0
index ffafab0..1dd3f9b 100644
@@ -891,6 +891,8 @@ extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
 				   int depth, void *data);
 
 extern int opal_notifier_register(struct notifier_block *nb);
+extern int opal_notifier_unregister(struct notifier_block *nb);
+
 extern int opal_message_notifier_register(enum OpalMessageType msg_type,
 						struct notifier_block *nb);
 extern void opal_notifier_enable(void);
arch/powerpc/platforms/powernv/opal.c +14 -0
index e92f2f6..7835d5b 100644
@@ -180,6 +180,20 @@ int opal_notifier_register(struct notifier_block *nb)
 	atomic_notifier_chain_register(&opal_notifier_head, nb);
 	return 0;
 }
+EXPORT_SYMBOL_GPL(opal_notifier_register);
+
+int opal_notifier_unregister(struct notifier_block *nb)
+{
+	if (!nb) {
+		pr_warning("%s: Invalid argument (%p)\n",
+			   __func__, nb);
+		return -EINVAL;
+	}
+
+	atomic_notifier_chain_unregister(&opal_notifier_head, nb);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(opal_notifier_unregister);
 
 static void opal_do_notifier(uint64_t events)
 {
Signature · 1 line
1.8.3.2
#7 lore raw

PATCH 7/7 tty/hvc_opal: Kick the HVC thread on OPAL console events

In reply to Benjamin Herrenschmidt

The firmware can notify us when new input data is available, so let's make sure we wakeup the HVC thread in that case.

---
 drivers/tty/hvc/hvc_opal.c | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)
drivers/tty/hvc/hvc_opal.c +25 -1
index 6496872..e4f92c1 100644
@@ -61,6 +61,7 @@ static struct hvc_opal_priv *hvc_opal_privs[MAX_NR_HVC_CONSOLES];
 /* For early boot console */
 static struct hvc_opal_priv hvc_opal_boot_priv;
 static u32 hvc_opal_boot_termno;
+static bool hvc_opal_event_registered;
 
 static const struct hv_ops hvc_opal_raw_ops = {
 	.get_chars = opal_get_chars,
@@ -161,6 +162,18 @@ static const struct hv_ops hvc_opal_hvsi_ops = {
 	.tiocmset = hvc_opal_hvsi_tiocmset,
 };
 
+static int hvc_opal_console_event(struct notifier_block *nb,
+				  unsigned long events, void *change)
+{
+	if (events & OPAL_EVENT_CONSOLE_INPUT)
+		hvc_kick();
+	return 0;
+}
+
+static struct notifier_block hvc_opal_console_nb = {
+	.notifier_call	= hvc_opal_console_event,
+};
+
 static int hvc_opal_probe(struct platform_device *dev)
 {
 	const struct hv_ops *ops;
@@ -170,6 +183,7 @@ static int hvc_opal_probe(struct platform_device *dev)
 	unsigned int termno, boot = 0;
 	const __be32 *reg;
 
+
 	if (of_device_is_compatible(dev->dev.of_node, "ibm,opal-console-raw")) {
 		proto = HV_PROTOCOL_RAW;
 		ops = &hvc_opal_raw_ops;
@@ -213,12 +227,18 @@ static int hvc_opal_probe(struct platform_device *dev)
 		dev->dev.of_node->full_name,
 		boot ? " (boot console)" : "");
 
-	/* We don't do IRQ yet */
+	/* We don't do IRQ ... */
 	hp = hvc_alloc(termno, 0, ops, MAX_VIO_PUT_CHARS);
 	if (IS_ERR(hp))
 		return PTR_ERR(hp);
 	dev_set_drvdata(&dev->dev, hp);
 
+	/* ...  but we use OPAL event to kick the console */
+	if (!hvc_opal_event_registered) {
+		opal_notifier_register(&hvc_opal_console_nb);
+		hvc_opal_event_registered = true;
+	}
+
 	return 0;
 }
 
@@ -259,6 +279,10 @@ module_init(hvc_opal_init);
 
 static void __exit hvc_opal_exit(void)
 {
+	if (hvc_opal_event_registered)
+		opal_notifier_unregister(&hvc_opal_console_nb);
+	hvc_opal_event_registered = false;
+
 	platform_driver_unregister(&hvc_opal_driver);
 }
 module_exit(hvc_opal_exit);
Signature · 1 line
1.8.3.2