diff options
Diffstat (limited to 'target/linux/generic/patches-2.6.39/330-mips-add-crash-and-kdump-support.patch')
-rw-r--r-- | target/linux/generic/patches-2.6.39/330-mips-add-crash-and-kdump-support.patch | 616 |
1 files changed, 0 insertions, 616 deletions
diff --git a/target/linux/generic/patches-2.6.39/330-mips-add-crash-and-kdump-support.patch b/target/linux/generic/patches-2.6.39/330-mips-add-crash-and-kdump-support.patch deleted file mode 100644 index 2e3766f180..0000000000 --- a/target/linux/generic/patches-2.6.39/330-mips-add-crash-and-kdump-support.patch +++ /dev/null @@ -1,616 +0,0 @@ -From eee16330c9de9adf7880cce9f1d32e13f89706bb Mon Sep 17 00:00:00 2001 -From: Wu Zhangjin <wuzhangjin@gmail.com> -Date: Tue, 11 Jan 2011 13:16:47 +0000 -Subject: MIPS: Add crash and kdump support - -From: http://patchwork.linux-mips.org/patch/1025/ - -Hello folks, - -Please find here MIPS crash and kdump patches. -This is patch set of 3 patches: -1. generic MIPS changes (kernel); -2. MIPS Cavium Octeon board kexec/kdump code (kernel); -3. Kexec user space MIPS changes. - -Patches were tested on the latest linux-mips@ git kernel and the latest -kexec-tools git on Cavium Octeon 50xx board. - -I also made the same code working on RMI XLR/XLS boards for both -mips32 and mips64 kernels. - -Best regards, -Maxim Uvarov. - ------- -[ Zhangjin: Several trivial building failure has been fixed. - -Note: the 2nd patch can not be cleanly applied, but may be a good -reference for the other board development: - - + MIPS Cavium Octeon board kexec,kdump support - http://patchwork.linux-mips.org/patch/1026/ - -And the 3rd patch has already been merged into the mainline kexec-tools: - - + some kexec MIPS improvements - http://patchwork.linux-mips.org/patch/1027/ - -kexec-tools is available here: - - + http://horms.net/projects/kexec/ - git://git.kernel.org/pub/scm/utils/kernel/kexec/kexec-tools.git -] -Signed-off-by: Wu Zhangjin <wuzhangjin@gmail.com> ---- -(limited to 'arch/mips/kernel') - ---- a/arch/mips/kernel/Makefile -+++ b/arch/mips/kernel/Makefile -@@ -92,7 +92,8 @@ obj-$(CONFIG_I8253) += i8253.o - - obj-$(CONFIG_GPIO_TXX9) += gpio_txx9.o - --obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o -+obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o -+obj-$(CONFIG_CRASH_DUMP) += crash_dump.o - obj-$(CONFIG_EARLY_PRINTK) += early_printk.o - obj-$(CONFIG_SPINLOCK_TEST) += spinlock_test.o - obj-$(CONFIG_MIPS_MACHINE) += mips_machine.o ---- /dev/null -+++ b/arch/mips/kernel/crash.c -@@ -0,0 +1,75 @@ -+#include <linux/kernel.h> -+#include <linux/smp.h> -+#include <linux/reboot.h> -+#include <linux/kexec.h> -+#include <linux/bootmem.h> -+#include <linux/crash_dump.h> -+#include <linux/delay.h> -+#include <linux/init.h> -+#include <linux/irq.h> -+#include <linux/types.h> -+#include <linux/sched.h> -+ -+#ifdef CONFIG_CRASH_DUMP -+unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX; -+#endif -+ -+/* This keeps a track of which one is crashing cpu. */ -+int crashing_cpu = -1; -+static cpumask_t cpus_in_crash = CPU_MASK_NONE; -+ -+#ifdef CONFIG_SMP -+void crash_shutdown_secondary(void *ignore) -+{ -+ struct pt_regs *regs; -+ int cpu = smp_processor_id(); -+ -+ regs = task_pt_regs(current); -+ -+ if (!cpu_online(cpu)) -+ return; -+ -+ local_irq_disable(); -+ if (!cpu_isset(cpu, cpus_in_crash)) -+ crash_save_cpu(regs, cpu); -+ cpu_set(cpu, cpus_in_crash); -+ -+ while (!atomic_read(&kexec_ready_to_reboot)) -+ cpu_relax(); -+ relocated_kexec_smp_wait(NULL); -+ /* NOTREACHED */ -+} -+ -+static void crash_kexec_prepare_cpus(void) -+{ -+ unsigned int msecs; -+ -+ unsigned int ncpus = num_online_cpus() - 1;/* Excluding the panic cpu */ -+ -+ dump_send_ipi(crash_shutdown_secondary); -+ smp_wmb(); -+ -+ /* -+ * The crash CPU sends an IPI and wait for other CPUs to -+ * respond. Delay of at least 10 seconds. -+ */ -+ printk(KERN_EMERG "Sending IPI to other cpus...\n"); -+ msecs = 10000; -+ while ((cpus_weight(cpus_in_crash) < ncpus) && (--msecs > 0)) { -+ cpu_relax(); -+ mdelay(1); -+ } -+} -+ -+#else -+static void crash_kexec_prepare_cpus(void) {} -+#endif -+ -+void default_machine_crash_shutdown(struct pt_regs *regs) -+{ -+ local_irq_disable(); -+ crashing_cpu = smp_processor_id(); -+ crash_save_cpu(regs, crashing_cpu); -+ crash_kexec_prepare_cpus(); -+ cpu_set(crashing_cpu, cpus_in_crash); -+} ---- /dev/null -+++ b/arch/mips/kernel/crash_dump.c -@@ -0,0 +1,86 @@ -+#include <linux/highmem.h> -+#include <linux/bootmem.h> -+#include <linux/crash_dump.h> -+#include <asm/uaccess.h> -+ -+#ifdef CONFIG_PROC_VMCORE -+static int __init parse_elfcorehdr(char *p) -+{ -+ if (p) -+ elfcorehdr_addr = memparse(p, &p); -+ return 1; -+} -+__setup("elfcorehdr=", parse_elfcorehdr); -+#endif -+ -+static int __init parse_savemaxmem(char *p) -+{ -+ if (p) -+ saved_max_pfn = (memparse(p, &p) >> PAGE_SHIFT) - 1; -+ -+ return 1; -+} -+__setup("savemaxmem=", parse_savemaxmem); -+ -+ -+static void *kdump_buf_page; -+ -+/** -+ * copy_oldmem_page - copy one page from "oldmem" -+ * @pfn: page frame number to be copied -+ * @buf: target memory address for the copy; this can be in kernel address -+ * space or user address space (see @userbuf) -+ * @csize: number of bytes to copy -+ * @offset: offset in bytes into the page (based on pfn) to begin the copy -+ * @userbuf: if set, @buf is in user address space, use copy_to_user(), -+ * otherwise @buf is in kernel address space, use memcpy(). -+ * -+ * Copy a page from "oldmem". For this page, there is no pte mapped -+ * in the current kernel. -+ * -+ * Calling copy_to_user() in atomic context is not desirable. Hence first -+ * copying the data to a pre-allocated kernel page and then copying to user -+ * space in non-atomic context. -+ */ -+ssize_t copy_oldmem_page(unsigned long pfn, char *buf, -+ size_t csize, unsigned long offset, int userbuf) -+{ -+ void *vaddr; -+ -+ if (!csize) -+ return 0; -+ -+ vaddr = kmap_atomic_pfn(pfn, KM_PTE0); -+ -+ if (!userbuf) { -+ memcpy(buf, (vaddr + offset), csize); -+ kunmap_atomic(vaddr, KM_PTE0); -+ } else { -+ if (!kdump_buf_page) { -+ printk(KERN_WARNING "Kdump: Kdump buffer page not" -+ " allocated\n"); -+ return -EFAULT; -+ } -+ copy_page(kdump_buf_page, vaddr); -+ kunmap_atomic(vaddr, KM_PTE0); -+ if (copy_to_user(buf, (kdump_buf_page + offset), csize)) -+ return -EFAULT; -+ } -+ -+ return csize; -+} -+ -+static int __init kdump_buf_page_init(void) -+{ -+ int ret = 0; -+ -+ kdump_buf_page = kmalloc(PAGE_SIZE, GFP_KERNEL); -+ if (!kdump_buf_page) { -+ printk(KERN_WARNING "Kdump: Failed to allocate kdump buffer" -+ " page\n"); -+ ret = -ENOMEM; -+ } -+ -+ return ret; -+} -+arch_initcall(kdump_buf_page_init); ---- a/arch/mips/kernel/machine_kexec.c -+++ b/arch/mips/kernel/machine_kexec.c -@@ -19,9 +19,19 @@ extern const size_t relocate_new_kernel_ - extern unsigned long kexec_start_address; - extern unsigned long kexec_indirection_page; - -+int (*_machine_kexec_prepare)(struct kimage *) = NULL; -+void (*_machine_kexec_shutdown)(void) = NULL; -+void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL; -+#ifdef CONFIG_SMP -+void (*relocated_kexec_smp_wait) (void *); -+atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0); -+#endif -+ - int - machine_kexec_prepare(struct kimage *kimage) - { -+ if (_machine_kexec_prepare) -+ return _machine_kexec_prepare(kimage); - return 0; - } - -@@ -33,11 +43,17 @@ machine_kexec_cleanup(struct kimage *kim - void - machine_shutdown(void) - { -+ if (_machine_kexec_shutdown) -+ _machine_kexec_shutdown(); - } - - void - machine_crash_shutdown(struct pt_regs *regs) - { -+ if (_machine_crash_shutdown) -+ _machine_crash_shutdown(regs); -+ else -+ default_machine_crash_shutdown(regs); - } - - typedef void (*noretfun_t)(void) __attribute__((noreturn)); -@@ -52,7 +68,9 @@ machine_kexec(struct kimage *image) - reboot_code_buffer = - (unsigned long)page_address(image->control_code_page); - -- kexec_start_address = (unsigned long) phys_to_virt(image->start); -+ kexec_start_address = -+ (unsigned long) phys_to_virt(image->start); -+ - kexec_indirection_page = - (unsigned long) phys_to_virt(image->head & PAGE_MASK); - -@@ -63,7 +81,7 @@ machine_kexec(struct kimage *image) - * The generic kexec code builds a page list with physical - * addresses. they are directly accessible through KSEG0 (or - * CKSEG0 or XPHYS if on 64bit system), hence the -- * pys_to_virt() call. -+ * phys_to_virt() call. - */ - for (ptr = &image->head; (entry = *ptr) && !(entry &IND_DONE); - ptr = (entry & IND_INDIRECTION) ? -@@ -81,5 +99,13 @@ machine_kexec(struct kimage *image) - printk("Will call new kernel at %08lx\n", image->start); - printk("Bye ...\n"); - __flush_cache_all(); -+#ifdef CONFIG_SMP -+ /* All secondary cpus now may jump to kexec_wait cycle */ -+ relocated_kexec_smp_wait = reboot_code_buffer + -+ (void *)(kexec_smp_wait - relocate_new_kernel); -+ smp_wmb(); -+ atomic_set(&kexec_ready_to_reboot, 1); -+#endif - ((noretfun_t) reboot_code_buffer)(); - } -+ ---- a/arch/mips/kernel/relocate_kernel.S -+++ b/arch/mips/kernel/relocate_kernel.S -@@ -15,6 +15,11 @@ - #include <asm/addrspace.h> - - LEAF(relocate_new_kernel) -+ PTR_L a0, arg0 -+ PTR_L a1, arg1 -+ PTR_L a2, arg2 -+ PTR_L a3, arg3 -+ - PTR_L s0, kexec_indirection_page - PTR_L s1, kexec_start_address - -@@ -26,7 +31,6 @@ process_entry: - and s3, s2, 0x1 - beq s3, zero, 1f - and s4, s2, ~0x1 /* store destination addr in s4 */ -- move a0, s4 - b process_entry - - 1: -@@ -60,23 +64,100 @@ copy_word: - b process_entry - - done: -+#ifdef CONFIG_SMP -+ /* kexec_flag reset is signal to other CPUs what kernel -+ was moved to it's location. Note - we need relocated address -+ of kexec_flag. */ -+ -+ bal 1f -+ 1: move t1,ra; -+ PTR_LA t2,1b -+ PTR_LA t0,kexec_flag -+ PTR_SUB t0,t0,t2; -+ PTR_ADD t0,t1,t0; -+ LONG_S zero,(t0) -+#endif -+ -+ sync - /* jump to kexec_start_address */ - j s1 - END(relocate_new_kernel) - --kexec_start_address: -- EXPORT(kexec_start_address) -+#ifdef CONFIG_SMP -+/* -+ * Other CPUs should wait until code is relocated and -+ * then start at entry (?) point. -+ */ -+LEAF(kexec_smp_wait) -+ PTR_L a0, s_arg0 -+ PTR_L a1, s_arg1 -+ PTR_L a2, s_arg2 -+ PTR_L a3, s_arg3 -+ PTR_L s1, kexec_start_address -+ -+ /* Non-relocated address works for args and kexec_start_address ( old -+ * kernel is not overwritten). But we need relocated address of -+ * kexec_flag. -+ */ -+ -+ bal 1f -+1: move t1,ra; -+ PTR_LA t2,1b -+ PTR_LA t0,kexec_flag -+ PTR_SUB t0,t0,t2; -+ PTR_ADD t0,t1,t0; -+ -+1: LONG_L s0, (t0) -+ bne s0, zero,1b -+ -+ sync -+ j s1 -+ END(kexec_smp_wait) -+#endif -+ -+#ifdef __mips64 -+ /* all PTR's must be aligned to 8 byte in 64-bit mode */ -+ .align 3 -+#endif -+ -+/* All parameters to new kernel are passed in registers a0-a3. -+ * kexec_args[0..3] are uses to prepare register values. -+ */ -+ -+EXPORT(kexec_args) -+arg0: PTR 0x0 -+arg1: PTR 0x0 -+arg2: PTR 0x0 -+arg3: PTR 0x0 -+ .size kexec_args,PTRSIZE*4 -+ -+#ifdef CONFIG_SMP -+/* -+ * Secondary CPUs may have different kernel parameters in -+ * their registers a0-a3. secondary_kexec_args[0..3] are used -+ * to prepare register values. -+ */ -+EXPORT(secondary_kexec_args) -+s_arg0: PTR 0x0 -+s_arg1: PTR 0x0 -+s_arg2: PTR 0x0 -+s_arg3: PTR 0x0 -+ .size secondary_kexec_args,PTRSIZE*4 -+kexec_flag: -+ LONG 0x1 -+ -+#endif -+ -+EXPORT(kexec_start_address) - PTR 0x0 - .size kexec_start_address, PTRSIZE - --kexec_indirection_page: -- EXPORT(kexec_indirection_page) -+EXPORT(kexec_indirection_page) - PTR 0 - .size kexec_indirection_page, PTRSIZE - - relocate_new_kernel_end: - --relocate_new_kernel_size: -- EXPORT(relocate_new_kernel_size) -+EXPORT(relocate_new_kernel_size) - PTR relocate_new_kernel_end - relocate_new_kernel - .size relocate_new_kernel_size, PTRSIZE ---- a/arch/mips/kernel/setup.c -+++ b/arch/mips/kernel/setup.c -@@ -21,6 +21,7 @@ - #include <linux/console.h> - #include <linux/pfn.h> - #include <linux/debugfs.h> -+#include <linux/kexec.h> - - #include <asm/addrspace.h> - #include <asm/bootinfo.h> -@@ -488,12 +489,62 @@ static void __init arch_mem_init(char ** - } - - bootmem_init(); -+#ifdef CONFIG_KEXEC -+ if (crashk_res.start != crashk_res.end) -+ reserve_bootmem(crashk_res.start, -+ crashk_res.end - crashk_res.start + 1, -+ BOOTMEM_DEFAULT); -+#endif - device_tree_init(); - sparse_init(); - plat_swiotlb_setup(); - paging_init(); - } - -+#ifdef CONFIG_KEXEC -+static inline unsigned long long get_total_mem(void) -+{ -+ unsigned long long total; -+ total = max_pfn - min_low_pfn; -+ return total << PAGE_SHIFT; -+} -+ -+static void __init mips_parse_crashkernel(void) -+{ -+ unsigned long long total_mem; -+ unsigned long long crash_size, crash_base; -+ int ret; -+ -+ total_mem = get_total_mem(); -+ ret = parse_crashkernel(boot_command_line, total_mem, -+ &crash_size, &crash_base); -+ if (ret != 0 || crash_size <= 0) -+ return; -+ -+ crashk_res.start = crash_base; -+ crashk_res.end = crash_base + crash_size - 1; -+} -+static void __init request_crashkernel(struct resource *res) -+{ -+ int ret; -+ -+ ret = request_resource(res, &crashk_res); -+ if (!ret) -+ printk(KERN_INFO "Reserving %ldMB of memory at %ldMB " -+ "for crashkernel\n", -+ (unsigned long)((crashk_res.end - -+ crashk_res.start + 1) >> 20), -+ (unsigned long)(crashk_res.start >> 20)); -+} -+#else -+static void __init mips_parse_crashkernel(void) -+{ -+} -+static void __init request_crashkernel(struct resource *res) -+{ -+} -+#endif -+ - static void __init resource_init(void) - { - int i; -@@ -509,6 +560,8 @@ static void __init resource_init(void) - /* - * Request address space for all standard RAM. - */ -+ mips_parse_crashkernel(); -+ - for (i = 0; i < boot_mem_map.nr_map; i++) { - struct resource *res; - unsigned long start, end; -@@ -544,6 +597,7 @@ static void __init resource_init(void) - */ - request_resource(res, &code_resource); - request_resource(res, &data_resource); -+ request_crashkernel(res); - } - } - ---- a/arch/mips/kernel/smp.c -+++ b/arch/mips/kernel/smp.c -@@ -433,3 +433,21 @@ void flush_tlb_one(unsigned long vaddr) - - EXPORT_SYMBOL(flush_tlb_page); - EXPORT_SYMBOL(flush_tlb_one); -+ -+#if defined(CONFIG_KEXEC) -+void (*dump_ipi_function_ptr)(void *) = NULL; -+void dump_send_ipi(void (*dump_ipi_callback)(void *)) -+{ -+ int i; -+ int cpu = smp_processor_id(); -+ -+ dump_ipi_function_ptr = dump_ipi_callback; -+ smp_mb(); -+ for_each_online_cpu(i) -+ if (i != cpu) -+ core_send_ipi(i, SMP_DUMP); -+ -+} -+EXPORT_SYMBOL(dump_send_ipi); -+#endif -+ ---- a/arch/mips/include/asm/kexec.h -+++ b/arch/mips/include/asm/kexec.h -@@ -9,22 +9,45 @@ - #ifndef _MIPS_KEXEC - # define _MIPS_KEXEC - -+#include <asm/stacktrace.h> -+ -+extern unsigned long long elfcorehdr_addr; -+ - /* Maximum physical address we can use pages from */ - #define KEXEC_SOURCE_MEMORY_LIMIT (0x20000000) - /* Maximum address we can reach in physical address mode */ - #define KEXEC_DESTINATION_MEMORY_LIMIT (0x20000000) - /* Maximum address we can use for the control code buffer */ - #define KEXEC_CONTROL_MEMORY_LIMIT (0x20000000) -- --#define KEXEC_CONTROL_PAGE_SIZE 4096 -+/* Reserve 3*4096 bytes for board-specific info */ -+#define KEXEC_CONTROL_PAGE_SIZE (4096 + 3*4096) - - /* The native architecture */ - #define KEXEC_ARCH KEXEC_ARCH_MIPS -+#define MAX_NOTE_BYTES 1024 - - static inline void crash_setup_regs(struct pt_regs *newregs, -- struct pt_regs *oldregs) -+ struct pt_regs *oldregs) - { -- /* Dummy implementation for now */ -+ if (oldregs) -+ memcpy(newregs, oldregs, sizeof(*newregs)); -+ else -+ prepare_frametrace(newregs); - } - -+#ifdef CONFIG_KEXEC -+struct kimage; -+extern unsigned long kexec_args[4]; -+extern int (*_machine_kexec_prepare)(struct kimage *); -+extern void (*_machine_kexec_shutdown)(void); -+extern void (*_machine_crash_shutdown)(struct pt_regs *regs); -+extern void default_machine_crash_shutdown(struct pt_regs *regs); -+#ifdef CONFIG_SMP -+extern const unsigned char kexec_smp_wait[]; -+extern unsigned long secondary_kexec_args[4]; -+extern void (*relocated_kexec_smp_wait) (void *); -+extern atomic_t kexec_ready_to_reboot; -+#endif -+#endif -+ - #endif /* !_MIPS_KEXEC */ ---- a/arch/mips/include/asm/smp.h -+++ b/arch/mips/include/asm/smp.h -@@ -40,6 +40,8 @@ extern int __cpu_logical_map[NR_CPUS]; - #define SMP_CALL_FUNCTION 0x2 - /* Octeon - Tell another core to flush its icache */ - #define SMP_ICACHE_FLUSH 0x4 -+/* Used by kexec crashdump to save all cpu's state */ -+#define SMP_DUMP 0x8 - - extern volatile cpumask_t cpu_callin_map; - -@@ -91,4 +93,9 @@ static inline void arch_send_call_functi - mp_ops->send_ipi_mask(mask, SMP_CALL_FUNCTION); - } - -+extern void core_send_ipi(int cpu, unsigned int action); -+#if defined(CONFIG_KEXEC) -+extern void (*dump_ipi_function_ptr)(void *); -+void dump_send_ipi(void (*dump_ipi_callback)(void *)); -+#endif - #endif /* __ASM_SMP_H */ |