From ae360a78f41164e7f9c4cf846696b5b6d8dae5c8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner <[tglx@linutronix.de]> Date: Sat, 31 Jul 2010 21:06:06 +0530 Subject: [PATCH] arm: Disable outer (L2) cache in kexec kexec does not disable the outer cache before disabling the inner caches in cpu_proc_fin(). So L2 is enabled across the kexec jump. When the new kernel enables chaches again, it randomly crashes. Disabling L2 before calling cpu_proc_fin() cures the problem. Disabling L2 requires the following new functions: flush_all(), inv_all() and disable(). Add them to outer_cache_fns and call them from the kexec code. Signed-off-by: Thomas Gleixner Acked-by: Catalin Marinas Acked-by: Linus Walleij --- arch/arm/include/asm/outercache.h | 24 ++++++++++++++++++++++++ arch/arm/kernel/machine_kexec.c | 3 +++ 2 files changed, 27 insertions(+) diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h index 25f76bae57ab..fc1900925275 100644 --- a/arch/arm/include/asm/outercache.h +++ b/arch/arm/include/asm/outercache.h @@ -25,6 +25,9 @@ struct outer_cache_fns { void (*inv_range)(unsigned long, unsigned long); void (*clean_range)(unsigned long, unsigned long); void (*flush_range)(unsigned long, unsigned long); + void (*flush_all)(void); + void (*inv_all)(void); + void (*disable)(void); #ifdef CONFIG_OUTER_CACHE_SYNC void (*sync)(void); #endif @@ -50,6 +53,24 @@ static inline void outer_flush_range(unsigned long start, unsigned long end) outer_cache.flush_range(start, end); } +static inline void outer_flush_all(void) +{ + if (outer_cache.flush_all) + outer_cache.flush_all(); +} + +static inline void outer_inv_all(void) +{ + if (outer_cache.inv_all) + outer_cache.inv_all(); +} + +static inline void outer_disable(void) +{ + if (outer_cache.disable) + outer_cache.disable(); +} + #else static inline void outer_inv_range(unsigned long start, unsigned long end) @@ -58,6 +79,9 @@ static inline void outer_clean_range(unsigned long start, unsigned long end) { } static inline void outer_flush_range(unsigned long start, unsigned long end) { } +static inline void outer_flush_all(void) { } +static inline void outer_inv_all(void) { } +static inline void outer_disable(void) { } #endif diff --git a/arch/arm/kernel/machine_kexec.c b/arch/arm/kernel/machine_kexec.c index 1fc74cbd1a19..3a8fd5140d7a 100644 --- a/arch/arm/kernel/machine_kexec.c +++ b/arch/arm/kernel/machine_kexec.c @@ -78,7 +78,10 @@ void machine_kexec(struct kimage *image) local_fiq_disable(); setup_mm_for_reboot(0); /* mode is not used, so just pass 0*/ flush_cache_all(); + outer_flush_all(); + outer_disable(); cpu_proc_fin(); + outer_inv_all(); flush_cache_all(); cpu_reset(reboot_code_buffer_phys); } -- 2.39.2