2007-02-06 21:29:00 +01:00
/*
* machine_kexec . c - handle transition of Linux booting another kernel
*/
# include <linux/mm.h>
# include <linux/kexec.h>
# include <linux/delay.h>
# include <linux/reboot.h>
2008-09-06 12:10:45 +01:00
# include <linux/io.h>
2012-02-03 14:48:01 +01:00
# include <linux/irq.h>
2012-09-21 18:56:11 +01:00
# include <linux/memblock.h>
2007-02-06 21:29:00 +01:00
# include <asm/pgtable.h>
2012-09-21 18:56:02 +01:00
# include <linux/of_fdt.h>
2007-02-06 21:29:00 +01:00
# include <asm/pgalloc.h>
# include <asm/mmu_context.h>
# include <asm/cacheflush.h>
2013-11-25 14:54:47 +01:00
# include <asm/fncpy.h>
2007-02-06 21:29:00 +01:00
# include <asm/mach-types.h>
2013-08-02 20:52:49 +01:00
# include <asm/smp_plat.h>
2012-03-28 18:30:01 +01:00
# include <asm/system_misc.h>
2007-02-06 21:29:00 +01:00
2013-11-25 14:54:47 +01:00
extern void relocate_new_kernel ( void ) ;
2009-02-09 21:35:39 +01:00
extern const unsigned int relocate_new_kernel_size ;
2007-02-06 21:29:00 +01:00
extern unsigned long kexec_start_address ;
extern unsigned long kexec_indirection_page ;
extern unsigned long kexec_mach_type ;
2008-01-02 00:56:46 +01:00
extern unsigned long kexec_boot_atags ;
2007-02-06 21:29:00 +01:00
2010-12-03 10:53:38 +01:00
static atomic_t waiting_for_crash_ipi ;
2014-05-12 10:31:56 +01:00
static unsigned long dt_mem ;
2007-02-06 21:29:00 +01:00
/*
* Provide a dummy crash_notes definition while crash dump arrives to arm .
* This prevents breakage of crash_notes attribute in kernel / ksysfs . c .
*/
int machine_kexec_prepare ( struct kimage * image )
{
2012-09-21 18:56:02 +01:00
struct kexec_segment * current_segment ;
__be32 header ;
int i , err ;
2013-08-02 20:52:49 +01:00
/*
* Validate that if the current HW supports SMP , then the SW supports
* and implements CPU hotplug for the current HW . If not , we won ' t be
* able to kexec reliably , so fail the prepare operation .
*/
2015-04-01 13:36:57 +01:00
if ( num_possible_cpus ( ) > 1 & & platform_can_secondary_boot ( ) & &
! platform_can_cpu_hotplug ( ) )
2013-08-02 20:52:49 +01:00
return - EINVAL ;
2012-09-21 18:56:02 +01:00
/*
* No segment at default ATAGs address . try to locate
* a dtb using magic .
*/
for ( i = 0 ; i < image - > nr_segments ; i + + ) {
current_segment = & image - > segment [ i ] ;
2012-10-16 19:35:14 +01:00
if ( ! memblock_is_region_memory ( current_segment - > mem ,
current_segment - > memsz ) )
return - EINVAL ;
2012-09-21 18:56:11 +01:00
2012-09-21 18:56:02 +01:00
err = get_user ( header , ( __be32 * ) current_segment - > buf ) ;
if ( err )
return err ;
if ( be32_to_cpu ( header ) = = OF_DT_HEADER )
2014-05-12 10:31:56 +01:00
dt_mem = current_segment - > mem ;
2012-09-21 18:56:02 +01:00
}
2007-02-06 21:29:00 +01:00
return 0 ;
}
void machine_kexec_cleanup ( struct kimage * image )
{
}
2010-12-03 10:53:38 +01:00
void machine_crash_nonpanic_core ( void * unused )
{
struct pt_regs regs ;
crash_setup_regs ( & regs , NULL ) ;
printk ( KERN_DEBUG " CPU %u will stop doing anything useful since another CPU has crashed \n " ,
smp_processor_id ( ) ) ;
crash_save_cpu ( & regs , smp_processor_id ( ) ) ;
flush_cache_all ( ) ;
2013-08-14 13:28:28 +01:00
set_cpu_online ( smp_processor_id ( ) , false ) ;
2010-12-03 10:53:38 +01:00
atomic_dec ( & waiting_for_crash_ipi ) ;
while ( 1 )
cpu_relax ( ) ;
}
2012-02-03 14:48:01 +01:00
static void machine_kexec_mask_interrupts ( void )
{
unsigned int i ;
struct irq_desc * desc ;
for_each_irq_desc ( i , desc ) {
struct irq_chip * chip ;
chip = irq_desc_get_chip ( desc ) ;
if ( ! chip )
continue ;
if ( chip - > irq_eoi & & irqd_irq_inprogress ( & desc - > irq_data ) )
chip - > irq_eoi ( & desc - > irq_data ) ;
if ( chip - > irq_mask )
chip - > irq_mask ( & desc - > irq_data ) ;
if ( chip - > irq_disable & & ! irqd_irq_disabled ( & desc - > irq_data ) )
chip - > irq_disable ( & desc - > irq_data ) ;
}
}
2007-02-06 21:29:00 +01:00
void machine_crash_shutdown ( struct pt_regs * regs )
{
2010-12-03 10:53:38 +01:00
unsigned long msecs ;
2010-05-10 09:23:37 +01:00
local_irq_disable ( ) ;
2010-12-03 10:53:38 +01:00
atomic_set ( & waiting_for_crash_ipi , num_online_cpus ( ) - 1 ) ;
smp_call_function ( machine_crash_nonpanic_core , NULL , false ) ;
msecs = 1000 ; /* Wait at most a second for the other cpus to stop */
while ( ( atomic_read ( & waiting_for_crash_ipi ) > 0 ) & & msecs ) {
mdelay ( 1 ) ;
msecs - - ;
}
if ( atomic_read ( & waiting_for_crash_ipi ) > 0 )
2014-10-28 11:26:42 +00:00
pr_warn ( " Non-crashing CPUs did not react to IPI \n " ) ;
2010-12-03 10:53:38 +01:00
2010-05-10 09:23:37 +01:00
crash_save_cpu ( regs , smp_processor_id ( ) ) ;
2012-02-03 14:48:01 +01:00
machine_kexec_mask_interrupts ( ) ;
2010-05-10 09:23:37 +01:00
2014-10-28 11:26:42 +00:00
pr_info ( " Loading crashdump kernel... \n " ) ;
2007-02-06 21:29:00 +01:00
}
2011-02-02 17:16:09 -05:00
/*
* Function pointer to optional machine - specific reinitialization
*/
void ( * kexec_reinit ) ( void ) ;
2007-02-06 21:29:00 +01:00
void machine_kexec ( struct kimage * image )
{
2016-01-11 17:03:54 +00:00
unsigned long page_list , reboot_entry_phys ;
void ( * reboot_entry ) ( void ) ;
2007-02-06 21:29:00 +01:00
void * reboot_code_buffer ;
2013-08-02 20:52:49 +01:00
/*
* This can only happen if machine_shutdown ( ) failed to disable some
* CPU , and that can only happen if the checks in
* machine_kexec_prepare ( ) were not correct . If this fails , we can ' t
* reliably kexec anyway , so BUG_ON is appropriate .
*/
BUG_ON ( num_online_cpus ( ) > 1 ) ;
2011-11-07 19:04:36 +00:00
page_list = image - > head & PAGE_MASK ;
2007-02-06 21:29:00 +01:00
reboot_code_buffer = page_address ( image - > control_code_page ) ;
2011-11-07 19:04:36 +00:00
/* Prepare parameters for reboot_code_buffer*/
2014-04-03 13:29:50 -07:00
set_kernel_text_rw ( ) ;
2011-11-07 19:04:36 +00:00
kexec_start_address = image - > start ;
kexec_indirection_page = page_list ;
kexec_mach_type = machine_arch_type ;
2014-05-12 10:31:56 +01:00
kexec_boot_atags = dt_mem ? : image - > start - KEXEC_ARM_ZIMAGE_OFFSET
+ KEXEC_ARM_ATAGS_OFFSET ;
2011-11-07 19:04:36 +00:00
/* copy our kernel relocation code to the control code page */
2013-11-25 14:54:47 +01:00
reboot_entry = fncpy ( reboot_code_buffer ,
2016-01-11 17:03:54 +00:00
& relocate_new_kernel ,
2013-11-25 14:54:47 +01:00
relocate_new_kernel_size ) ;
2016-01-11 17:03:54 +00:00
/* get the identity mapping physical address for the reboot code */
reboot_entry_phys = virt_to_idmap ( reboot_entry ) ;
2011-11-07 19:04:36 +00:00
2014-10-28 11:26:42 +00:00
pr_info ( " Bye! \n " ) ;
2007-02-06 21:29:00 +01:00
2011-02-02 17:16:09 -05:00
if ( kexec_reinit )
kexec_reinit ( ) ;
2011-06-06 12:35:46 +01:00
2013-11-25 14:54:47 +01:00
soft_restart ( reboot_entry_phys ) ;
2007-02-06 21:29:00 +01:00
}
2014-04-18 07:45:36 +01:00
void arch_crash_save_vmcoreinfo ( void )
{
# ifdef CONFIG_ARM_LPAE
VMCOREINFO_CONFIG ( ARM_LPAE ) ;
# endif
}