[RFC] Old paca being written by firmware after kexec

Michael Ellerman michael at ellerman.id.au
Fri Oct 7 16:56:35 EST 2005


Hi again,

Here's a first cut at a patch. It needs some spit and polish, but I thought
I'd throw it out over the weekend in case anyone has any comments.

This seems to fix my bug, although on one reboot I got a cpu stuck - which
may or may not be related.

cheers

 arch/ppc64/kernel/machine_kexec.c  |   19 +++++++++++++++++++
 arch/ppc64/kernel/pSeries_lpar.c   |   10 +++-------
 include/asm-ppc64/plpar_wrappers.h |   24 ++++++++++++++++++++----
 include/asm-ppc64/smp.h            |    8 +-------
 4 files changed, 43 insertions(+), 18 deletions(-)

Index: kexec/arch/ppc64/kernel/pSeries_lpar.c
===================================================================
--- kexec.orig/arch/ppc64/kernel/pSeries_lpar.c
+++ kexec/arch/ppc64/kernel/pSeries_lpar.c
@@ -260,22 +260,18 @@ out:
 void vpa_init(int cpu)
 {
 	int hwcpu = get_hard_smp_processor_id(cpu);
-	unsigned long vpa = (unsigned long)&(paca[cpu].lppaca);
+	unsigned long vpa = __pa(&paca[cpu].lppaca);
 	long ret;
-	unsigned long flags;
-
-	/* Register the Virtual Processor Area (VPA) */
-	flags = 1UL << (63 - 18);
 
 	if (cpu_has_feature(CPU_FTR_ALTIVEC))
 		paca[cpu].lppaca.vmxregs_in_use = 1;
 
-	ret = register_vpa(flags, hwcpu, __pa(vpa));
+	ret = register_vpa(hwcpu, vpa);
 
 	if (ret)
 		printk(KERN_ERR "WARNING: vpa_init: VPA registration for "
 				"cpu %d (hw %d) of area %lx returns %ld\n",
-				cpu, hwcpu, __pa(vpa), ret);
+				cpu, hwcpu, vpa, ret);
 }
 
 long pSeries_lpar_hpte_insert(unsigned long hpte_group,
Index: kexec/include/asm-ppc64/plpar_wrappers.h
===================================================================
--- kexec.orig/include/asm-ppc64/plpar_wrappers.h
+++ kexec/include/asm-ppc64/plpar_wrappers.h
@@ -22,13 +22,29 @@ static inline long cede_processor(void)
 	return(0); 
 }
 
-static inline long register_vpa(unsigned long flags, unsigned long proc,
-				unsigned long vpa)
+static inline long unregister_vpa(unsigned long cpu, unsigned long vpa)
 {
-	return plpar_hcall_norets(H_REGISTER_VPA, flags, proc, vpa);
+	unsigned long flags;
+
+	/* The flags are in bits 16-18 (counting from most significant bit) */
+	flags = 5UL << (63 - 18);
+
+	printk("VPA unregister (%lx) cpu %d at %lx\n", flags, cpu, vpa);
+
+	return plpar_hcall_norets(H_REGISTER_VPA, flags, cpu, vpa);
 }
 
-void vpa_init(int cpu);
+static inline long register_vpa(unsigned long cpu, unsigned long vpa)
+{
+	unsigned long flags;
+
+	/* The flags are in bits 16-18 (counting from most significant bit) */
+	flags = 1UL << (63 - 18);
+
+	printk("VPA register (%lx) cpu %d at %lx\n", flags, cpu, vpa);
+
+	return plpar_hcall_norets(H_REGISTER_VPA, flags, cpu, vpa);
+}
 
 static inline long plpar_pte_remove(unsigned long flags,
 				    unsigned long ptex,
Index: kexec/include/asm-ppc64/smp.h
===================================================================
--- kexec.orig/include/asm-ppc64/smp.h
+++ kexec/include/asm-ppc64/smp.h
@@ -86,13 +86,7 @@ extern void smp_generic_take_timebase(vo
 
 extern struct smp_ops_t *smp_ops;
 
-#ifdef CONFIG_PPC_PSERIES
-void vpa_init(int cpu);
-#else
-static inline void vpa_init(int cpu)
-{
-}
-#endif /* CONFIG_PPC_PSERIES */
+extern void vpa_init(int cpu);
 
 #endif /* __ASSEMBLY__ */
 
Index: kexec/arch/ppc64/kernel/machine_kexec.c
===================================================================
--- kexec.orig/arch/ppc64/kernel/machine_kexec.c
+++ kexec/arch/ppc64/kernel/machine_kexec.c
@@ -24,6 +24,7 @@
 #include <asm/mmu.h>
 #include <asm/sections.h>	/* _end */
 #include <asm/prom.h>
+#include <asm/plpar_wrappers.h>
 
 #define HASH_GROUP_SIZE 0x80	/* size of each hash group, asm/mmu.h */
 
@@ -191,10 +192,26 @@ void kexec_smp_down(void *arg)
 	/* NOTREACHED */
 }
 
+static void vpa_shutdown(int cpu)
+{
+	unsigned long vpa = __pa(&paca[cpu].lppaca);
+	long ret;
+
+	ret = unregister_vpa(get_hard_smp_processor_id(cpu), vpa);
+
+	if (ret)
+		printk(KERN_ERR "WARNING: vpa_shutdown: VPA deregistration "
+				"failed with code %d\n", ret);
+}
+
 static void kexec_prepare_cpus(void)
 {
 	int my_cpu, i, notified=-1;
 
+	/* FIXME: I'd rather do this after the loop but we clobber hw_cpu_id */
+	for_each_cpu(i)
+		vpa_shutdown(i);
+
 	smp_call_function(kexec_smp_down, NULL, 0, /* wait */0);
 	my_cpu = get_cpu();
 
@@ -203,6 +220,8 @@ static void kexec_prepare_cpus(void)
 		if (i == my_cpu)
 			continue;
 
+		/* FIXME: Why do we abuse hw_cpu_id and not cpu_start? */
+
 		while (paca[i].hw_cpu_id != -1) {
 			barrier();
 			if (!cpu_possible(i)) {



More information about the Linuxppc64-dev mailing list