[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