[patch 1/2] arm: Disable outer (L2) cache in kexec

Catalin Marinas catalin.marinas at arm.com
Mon Jul 5 06:52:54 EDT 2010


On Mon, 2010-07-05 at 10:25 +0100, Thomas Gleixner wrote:
> 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 <tglx at linutronix.de>
> Index: linux-2.6/arch/arm/include/asm/outercache.h
> ===================================================================
> --- linux-2.6.orig/arch/arm/include/asm/outercache.h
> +++ linux-2.6/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);

Why don't we handle the flush_all/inv_all in the disable function and
avoid exporting them? Once exported, people may start using them in
drivers and they should use the DMA API for this. The inv_all is also
dangerous if called when the L2 is enabled.

> +static inline void outer_cache_disable(void)
> +{
> +       if (outer_cache.disable)
> +               outer_cache.disable();
> +}

Personal preference - "outer_disable()" as we don't call any of the
other functions outer_cache_*().

> --- linux-2.6.orig/arch/arm/kernel/machine_kexec.c
> +++ linux-2.6/arch/arm/kernel/machine_kexec.c
> @@ -74,7 +74,10 @@ void machine_kexec(struct kimage *image)
>                            (unsigned long) reboot_code_buffer + KEXEC_CONTROL_PAGE_SIZE);
>         printk(KERN_INFO "Bye!\n");
> 
> +       outer_flush_all();
> +       outer_cache_disable();
>         cpu_proc_fin();
> +       outer_inv_all();

As I said above, we could have just outer_disable() here which does
outer_flush_all, disabling and outer_inv_all. I don't think the
invalidation needs to be done after cup_proc_fin().

Thanks.

-- 
Catalin




More information about the linux-arm-kernel mailing list