[patch 2/5] Miscellaneous updates for kexec/kdump

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



> commit beada884dd437b509c26b39f1a0b0c6b31e6f340
> tree ad7608f34ca8aa9e292e2a863484b3e13250107d
> parent b373e385743597f576b67c423807bbdfe3b862e7
> author Zou Nan hai <nanhai.zou@xxxxxxxxx> 1150320804 -0700
> committer Tony Luck <tony.luck@xxxxxxxxx> 1150320804 -0700
> 
> [IA64] Miscellaneous updates for kexec/kdump
> 
> Signed-off-by: Zou Nan hai <nanhai.zou@xxxxxxxxx>

Up-port from the test branch of Tony Luck's ia64 tree to 2.6.18-rc4

Cc: Zou Nan hai <nanhai.zou@xxxxxxxxx>
Signed-off-by: Simon Horman <horms@xxxxxxxxxxxx>

 /arch/ia64/Kconfig                  |    8 +
 /arch/ia64/kernel/crash.c           |  113 ++++++++++++++++++++-
 /arch/ia64/kernel/efi.c             |   17 ++-
 /arch/ia64/kernel/machine_kexec.c   |   43 +------
 /arch/ia64/kernel/relocate_kernel.S |   38 ++-----
 /arch/ia64/kernel/setup.c           |   38 +++++++
 /include/asm-ia64/kexec.h           |    4 
 /include/asm-ia64/meminit.h         |    3 
 /include/linux/irq.h                |    1 
 /kernel/irq/manage.c                |   12 ++
 10 files changed, 211 insertions(+), 66 deletions(-)

Index: linux//arch/ia64/Kconfig
===================================================================
--- linux.orig//arch/ia64/Kconfig	2006-08-17 13:14:10.000000000 +0900
+++ linux//arch/ia64/Kconfig	2006-08-17 13:13:49.000000000 +0900
@@ -452,7 +452,11 @@
 	  support.  As of this writing the exact hardware interface is
 	  strongly in flux, so no good recommendation can be made.
 
-source "drivers/sn/Kconfig"
+config CRASH_DUMP
+	  bool "kernel crash dumps (EXPERIMENTAL)"
+	  depends on EXPERIMENTAL
+	  help
+	    Generate crash dump after being started by kexec.
 
 source "drivers/firmware/Kconfig"
 
Index: linux//arch/ia64/kernel/crash.c
===================================================================
--- linux.orig//arch/ia64/kernel/crash.c	2006-08-17 13:14:10.000000000 +0900
+++ linux//arch/ia64/kernel/crash.c	2006-08-17 13:13:49.000000000 +0900
@@ -4,8 +4,8 @@
  * Architecture specific (ia64) functions for kexec based crash dumps.
  *
  * Created by: Khalid Aziz <khalid.aziz@xxxxxx>
- *
  * Copyright (C) 2005 Hewlett-Packard Development Company, L.P.
+ * Copyright (C) 2005 Intel Corp	Zou Nan hai <nanhai.zou@xxxxxxxxx>
  *
  */
 #include <linux/init.h>
@@ -13,6 +13,7 @@
 #include <linux/kernel.h>
 #include <linux/smp.h>
 #include <linux/irq.h>
+#include <linux/pci.h>
 #include <linux/reboot.h>
 #include <linux/kexec.h>
 #include <linux/irq.h>
@@ -20,6 +21,111 @@
 #include <linux/elf.h>
 #include <linux/elfcore.h>
 #include <linux/device.h>
+#include <asm/uaccess.h>
+
+size_t copy_oldmem_page(unsigned long pfn, char *buf,
+                               size_t csize, unsigned long offset, int userbuf)
+{
+        void  *vaddr;
+
+        if (!csize)
+                return 0;
+        vaddr = page_address(pfn_to_page(pfn));
+
+        if (userbuf) {
+                if (copy_to_user(buf, (vaddr + offset), csize)) {
+                        return -EFAULT;
+                }
+        } else
+                memcpy(buf, (vaddr + offset), csize);
+        return csize;
+}
+
+static void device_shootdown(void)
+{
+       struct pci_dev *dev;
+       irq_desc_t *desc;
+       u16 pci_command;
+
+       list_for_each_entry(dev, &pci_devices, global_list) {
+               desc = irq_descp(dev->irq);
+               if (!desc->action)
+                       continue;
+               pci_read_config_word(dev, PCI_COMMAND, &pci_command);
+               if (pci_command & PCI_COMMAND_MASTER) {
+                       pci_command &= ~PCI_COMMAND_MASTER;
+                       pci_write_config_word(dev, PCI_COMMAND, pci_command);
+               }
+               disable_irq_nosync(dev->irq);
+               desc->handler->end(dev->irq);
+       }
+}
+
+static Elf64_Word
+*append_elf_note(Elf64_Word *buf, char *name, unsigned type, void *data,
+		size_t data_len)
+{
+	struct elf_note *note = (struct elf_note *)buf;
+	note->n_namesz = strlen(name) + 1;
+	note->n_descsz = data_len;
+	note->n_type   = type;
+	buf += (sizeof(*note) + 3)/4;
+	memcpy(buf, name, note->n_namesz);
+	buf += (note->n_namesz + 3)/4;
+	memcpy(buf, data, data_len);
+	buf += (data_len + 3)/4;
+	return buf;
+}
+
+static void
+final_note(void *buf)
+{
+	memset(buf, 0, sizeof(struct elf_note));
+}
+
+static void
+crash_save_this_cpu(void)
+{
+	void *buf;
+	struct elf_prstatus prstatus;
+	int cpu = smp_processor_id();
+	elf_greg_t *dst = (elf_greg_t *)&prstatus.pr_reg;
+
+	memset(&prstatus, 0, sizeof(prstatus));
+	prstatus.pr_pid = current->pid;
+
+    	dst[1] = ia64_getreg(_IA64_REG_GP);
+    	dst[12] = ia64_getreg(_IA64_REG_SP);
+    	dst[13] = ia64_getreg(_IA64_REG_TP);
+
+    	dst[42] = ia64_getreg(_IA64_REG_IP);
+    	dst[45] = ia64_getreg(_IA64_REG_AR_RSC);
+
+	ia64_setreg(_IA64_REG_AR_RSC, 0);
+	ia64_srlz_i();
+
+    	dst[46] = ia64_getreg(_IA64_REG_AR_BSP);
+    	dst[47] = ia64_getreg(_IA64_REG_AR_BSPSTORE);
+
+    	dst[48] = ia64_getreg(_IA64_REG_AR_RNAT);
+    	dst[49] = ia64_getreg(_IA64_REG_AR_CCV);
+    	dst[50] = ia64_getreg(_IA64_REG_AR_UNAT);
+
+    	dst[51] = ia64_getreg(_IA64_REG_AR_FPSR);
+    	dst[52] = ia64_getreg(_IA64_REG_AR_PFS);
+    	dst[53] = ia64_getreg(_IA64_REG_AR_LC);
+
+    	dst[54] = ia64_getreg(_IA64_REG_AR_LC);
+    	dst[55] = ia64_getreg(_IA64_REG_AR_CSD);
+    	dst[56] = ia64_getreg(_IA64_REG_AR_SSD);
+
+        buf = (u64 *) per_cpu_ptr(crash_notes, cpu);
+	if (!buf)
+		return;
+	buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus,
+		sizeof(prstatus));
+	final_note(buf);
+}
 
 void
 machine_crash_shutdown(struct pt_regs *pt)
@@ -32,8 +138,11 @@
 	 * In practice this means shooting down the other cpus in
 	 * an SMP system.
 	 */
-	if (in_interrupt())
+	if (in_interrupt()) {
 		ia64_eoi();
+	}
+	crash_save_this_cpu();
+	device_shootdown();
 #ifdef CONFIG_SMP
 	smp_send_stop();
 #endif
Index: linux//arch/ia64/kernel/efi.c
===================================================================
--- linux.orig//arch/ia64/kernel/efi.c	2006-08-17 13:14:10.000000000 +0900
+++ linux//arch/ia64/kernel/efi.c	2006-08-17 13:13:50.000000000 +0900
@@ -26,6 +26,7 @@
 #include <linux/types.h>
 #include <linux/time.h>
 #include <linux/efi.h>
+#include <linux/kexec.h>
 
 #include <asm/io.h>
 #include <asm/kregs.h>
@@ -41,7 +42,7 @@
 struct efi efi;
 EXPORT_SYMBOL(efi);
 static efi_runtime_services_t *runtime;
-static unsigned long mem_limit = ~0UL, max_addr = ~0UL;
+static unsigned long mem_limit = ~0UL, max_addr = ~0UL, min_addr = 0UL;
 
 #define efi_call_virt(f, args...)	(*(f))(args)
 
@@ -421,6 +422,8 @@
 			mem_limit = memparse(cp + 4, &cp);
 		} else if (memcmp(cp, "max_addr=", 9) == 0) {
 			max_addr = GRANULEROUNDDOWN(memparse(cp + 9, &cp));
+		} else if (memcmp(cp, "min_addr=", 9) == 0) {
+			min_addr = GRANULEROUNDDOWN(memparse(cp + 9, &cp));
 		} else {
 			while (*cp != ' ' && *cp)
 				++cp;
@@ -428,6 +431,8 @@
 				++cp;
 		}
 	}
+	if (min_addr != 0UL)
+		printk(KERN_INFO "Ignoring memory below %luMB\n", min_addr >> 20);
 	if (max_addr != ~0UL)
 		printk(KERN_INFO "Ignoring memory above %luMB\n", max_addr >> 20);
 
@@ -894,7 +899,8 @@
 		as = max(contig_low, md->phys_addr);
 		ae = min(contig_high, efi_md_end(md));
 
-		/* keep within max_addr= command line arg */
+		/* keep within max_addr= and min_addr= command line arg */
+		as = max(as, min_addr);
 		ae = min(ae, max_addr);
 		if (ae <= as)
 			continue;
@@ -1004,7 +1010,8 @@
 		} else
 			ae = efi_md_end(md);
 
-		/* keep within max_addr= command line arg */
+		/* keep within max_addr= and min_addr= command line arg */
+		as = max(as, min_addr);
 		ae = min(ae, max_addr);
 		if (ae <= as)
 			continue;
@@ -1116,6 +1123,10 @@
 			 */
 			insert_resource(res, code_resource);
 			insert_resource(res, data_resource);
+#ifdef CONFIG_KEXEC
+			if (crashk_res.end > crashk_res.start)
+				insert_resource(res, &crashk_res);
+#endif
 		}
 	}
 }
Index: linux//arch/ia64/kernel/machine_kexec.c
===================================================================
--- linux.orig//arch/ia64/kernel/machine_kexec.c	2006-08-17 13:14:10.000000000 +0900
+++ linux//arch/ia64/kernel/machine_kexec.c	2006-08-17 13:13:50.000000000 +0900
@@ -1,5 +1,5 @@
 /*
- * arch/ia64/kernel/machine_kexec.c
+ * arch/ia64/kernel/machine_kexec.c 
  *
  * Handle transition of Linux booting another kernel
  * Copyright (C) 2005 Hewlett-Packard Development Comapny, L.P.
@@ -25,9 +25,7 @@
 #include <asm/delay.h>
 #include <asm/meminit.h>
 
-extern unsigned long ia64_iobase;
-
-typedef void (*relocate_new_kernel_t)( unsigned long, unsigned long,
+typedef void (*relocate_new_kernel_t)(unsigned long, unsigned long,
 		struct ia64_boot_param *, unsigned long);
 
 /*
@@ -43,9 +41,9 @@
 	func = (unsigned long *)&relocate_new_kernel;
 	/* Pre-load control code buffer to minimize work in kexec path */
 	control_code_buffer = page_address(image->control_code_page);
-	memcpy((void *)control_code_buffer, (const void *)func[0],
+	memcpy((void *)control_code_buffer, (const void *)func[0], 
 			relocate_new_kernel_size);
-	flush_icache_range((unsigned long)control_code_buffer,
+	flush_icache_range((unsigned long)control_code_buffer, 
 			(unsigned long)control_code_buffer + relocate_new_kernel_size);
 
 	return 0;
@@ -61,7 +59,6 @@
 	struct pci_dev *dev = NULL;
 	irq_desc_t *idesc;
 	cpumask_t mask = CPU_MASK_NONE;
-
 	/* Disable all PCI devices */
 	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
 		if (!(dev->is_enabled))
@@ -91,7 +88,6 @@
 	smp_call_function(kexec_stop_this_cpu, (void *)image->start, 0, 0);
 #endif
 
-	ia64_set_itv(1<<16);
 
 #ifdef CONFIG_IA64_HP_ZX1
 	ioc_iova_disable();
@@ -100,41 +96,20 @@
 
 /*
  * Do not allocate memory (or fail in any way) in machine_kexec().
- * We are past the point of no return, committed to rebooting now.
+ * We are past the point of no return, committed to rebooting now. 
  */
+extern void *efi_get_pal_addr(void);
 void machine_kexec(struct kimage *image)
 {
-	unsigned long indirection_page;
 	relocate_new_kernel_t rnk;
-	unsigned long pta, impl_va_bits;
 	void *pal_addr = efi_get_pal_addr();
 	unsigned long code_addr = (unsigned long)page_address(image->control_code_page);
-
 	/* Interrupts aren't acceptable while we reboot */
+	ia64_set_itv(1<<16);
 	local_irq_disable();
-
-	/* Disable VHPT */
-	impl_va_bits = ffz(~(local_cpu_data->unimpl_va_mask | (7UL << 61)));
-	pta = POW2(61) - POW2(vmlpt_bits);
-	ia64_set_pta(pta | (0 << 8) | (vmlpt_bits << 2) | 0);
-
-	/* now execute the control code.
-	 * We will start by executing the control code linked into the
-	 * kernel as opposed to the code we copied in control code buffer		 * page. When this code switches to physical mode, we will start
-	 * executing the code in control code buffer page. Reason for
-	 * doing this is we start code execution in virtual address space.
-	 * If we were to try to execute the newly copied code in virtual
-	 * address space, we will need to make an ITLB entry to avoid ITLB
-	 * miss. By executing the code linked into kernel, we take advantage
-	 * of the ITLB entry already in place for kernel and avoid making
-	 * a new entry.
-	 */
-	indirection_page = image->head & PAGE_MASK;
-
 	rnk = (relocate_new_kernel_t)&code_addr;
-	(*rnk)(indirection_page, image->start, ia64_boot_param,
+	(*rnk)(image->head, image->start, ia64_boot_param,
 		     GRANULEROUNDDOWN((unsigned long) pal_addr));
 	BUG();
-	for (;;)
-		;
+	for (;;);
 }
Index: linux//arch/ia64/kernel/relocate_kernel.S
===================================================================
--- linux.orig//arch/ia64/kernel/relocate_kernel.S	2006-08-17 13:14:10.000000000 +0900
+++ linux//arch/ia64/kernel/relocate_kernel.S	2006-08-17 13:13:50.000000000 +0900
@@ -1,5 +1,5 @@
 /*
- * arch/ia64/kernel/relocate_kernel.S
+ * arch/ia64/kernel/relocate_kernel.S 
  *
  * Relocate kexec'able kernel and start it
  *
@@ -17,9 +17,7 @@
 #include <asm/pgtable.h>
 #include <asm/mca_asm.h>
 
-       /* Must be relocatable PIC code callable as a C function, that once
-        * it starts can not use the previous processes stack.
-        *
+       /* Must be relocatable PIC code callable as a C function
         */
 GLOBAL_ENTRY(relocate_new_kernel)
 	.prologue
@@ -36,22 +34,16 @@
         srlz.i
 }
 	;;
-
+	dep r2=0,r2,61,3		//to physical address
+	;;
 	//first switch to physical mode
 	add r3=1f-.reloc_entry, r2
-	movl r16 = IA64_PSR_AC|IA64_PSR_BN|IA64_PSR_IC|IA64_PSR_MFL
+	movl r16 = IA64_PSR_AC|IA64_PSR_BN|IA64_PSR_IC
 	mov ar.rsc=0	          	// put RSE in enforced lazy mode
 	;;
-	add r2=(memory_stack-.reloc_entry), r2
-	;;
-	add sp=(memory_stack_end - .reloc_entry),r2
+	add sp=(memory_stack_end - 16 - .reloc_entry),r2
 	add r8=(register_stack - .reloc_entry),r2
 	;;
-	tpa sp=sp
-	tpa r3=r3
-	;;
-	loadrs
-	;;
 	mov r18=ar.rnat
 	mov ar.bspstore=r8
 	;;
@@ -66,7 +58,7 @@
 1:
 	//physical mode code begin
 	mov b6=in1
-	tpa r28=in2			// tpa must before TLB purge
+	dep r28=0,in2,61,3	//to physical address
 
 	// purge all TC entries
 #define O(member)       IA64_CPUINFO_##member##_OFFSET
@@ -145,10 +137,10 @@
         srlz.i
 	;;
 
-	// copy kexec kernel segments
+	//copy segments
 	movl r16=PAGE_MASK
-	ld8  r30=[in0],8;;			// in0 is page_list
-	br.sptk.few .dest_page
+        mov  r30=in0                    // in0 is page_list
+        br.sptk.few .dest_page
 	;;
 .loop:
 	ld8  r30=[in0], 8;;
@@ -188,6 +180,8 @@
 	srlz.d
 	;;
 	br.call.sptk.many b0=b6;;
+
+.align  32
 memory_stack:
 	.fill           8192, 1, 0
 memory_stack_end:
@@ -310,7 +304,7 @@
 	cmp.eq	p6,p0=0,r8
 (p6)	br.cond.sptk.few	check_irr0
 	br.few	call_start
-
+	
 check_irr1:
 	mov	r8=cr.irr1
 	;;
@@ -319,7 +313,7 @@
 	cmp.eq	p6,p0=0,r8
 (p6)	br.cond.sptk.few	check_irr1
 	br.few	call_start
-
+	
 check_irr2:
 	mov	r8=cr.irr2
 	;;
@@ -328,7 +322,7 @@
 	cmp.eq	p6,p0=0,r8
 (p6)	br.cond.sptk.few	check_irr2
 	br.few	call_start
-
+	
 check_irr3:
 	mov	r8=cr.irr3
 	;;
@@ -337,7 +331,7 @@
 	cmp.eq	p6,p0=0,r8
 (p6)	br.cond.sptk.few	check_irr3
 	br.few	call_start
-
+	
 call_start:
 	mov	cr.eoi=r0
 	;;
Index: linux//arch/ia64/kernel/setup.c
===================================================================
--- linux.orig//arch/ia64/kernel/setup.c	2006-08-17 13:14:10.000000000 +0900
+++ linux//arch/ia64/kernel/setup.c	2006-08-17 13:13:50.000000000 +0900
@@ -43,6 +43,8 @@
 #include <linux/initrd.h>
 #include <linux/pm.h>
 #include <linux/cpufreq.h>
+#include <linux/kexec.h>
+#include <linux/crash_dump.h>
 
 #include <asm/ia32.h>
 #include <asm/machvec.h>
@@ -250,6 +252,32 @@
 	}
 #endif
 
+#ifdef CONFIG_KEXEC
+	/* crashkernel=size@addr specifies the location to reserve for
+	 * a crash kernel.  By reserving this memory we guarantee
+	 * that linux never set's it up as a DMA target.
+	 * Useful for holding code to do something appropriate
+	 * after a kernel panic.
+	 */
+	{
+		char *from = strstr(saved_command_line, "crashkernel=");
+		if (from) {
+			unsigned long size, base;
+			size = memparse(from + 12, &from);
+			if (*from == '@') {
+				base = memparse(from + 1, &from);
+				rsvd_region[n].start =
+					(unsigned long)__va(base);
+				rsvd_region[n].end =
+					(unsigned long)__va(base + size);
+				crashk_res.start = base;
+				crashk_res.end = base + size - 1;
+				n++;
+			}
+		}
+	}
+#endif
+
 	efi_memmap_init(&rsvd_region[n].start, &rsvd_region[n].end);
 	n++;
 
@@ -484,6 +512,16 @@
 	if (!nomca)
 		ia64_mca_init();
 
+#ifdef CONFIG_CRASH_DUMP
+	{
+		char *from = strstr(saved_command_line, "elfcorehdr=");
+
+		if (from)
+			elfcorehdr_addr = memparse(from+11, &from);
+		saved_max_pfn = (unsigned long) -1;
+	}
+#endif
+
 	platform_setup(cmdline_p);
 	paging_init();
 }
Index: linux//include/asm-ia64/kexec.h
===================================================================
--- linux.orig//include/asm-ia64/kexec.h	2006-08-17 13:14:10.000000000 +0900
+++ linux//include/asm-ia64/kexec.h	2006-08-17 13:13:50.000000000 +0900
@@ -21,14 +21,12 @@
 #define POW2(n)		(1ULL << (n))
 
 DECLARE_PER_CPU(u64, ia64_mca_pal_base);
-
 const extern unsigned int relocate_new_kernel_size;
 volatile extern long kexec_rendez;
-extern void relocate_new_kernel(unsigned long, unsigned long,
+extern void relocate_new_kernel(unsigned long, unsigned long, 
 		struct ia64_boot_param *, unsigned long);
 extern void kexec_fake_sal_rendez(void *start, unsigned long wake_up,
 		unsigned long pal_base);
-
 static inline void
 crash_setup_regs(struct pt_regs *newregs, struct pt_regs *oldregs)
 {
Index: linux//include/asm-ia64/meminit.h
===================================================================
--- linux.orig//include/asm-ia64/meminit.h	2006-08-17 13:14:10.000000000 +0900
+++ linux//include/asm-ia64/meminit.h	2006-08-17 13:13:50.000000000 +0900
@@ -15,11 +15,12 @@
  * 	- initrd (optional)
  * 	- command line string
  * 	- kernel code & data
+ * 	- crash dumping code reserved region
  * 	- Kernel memory map built from EFI memory map
  *
  * More could be added if necessary
  */
-#define IA64_MAX_RSVD_REGIONS 6
+#define IA64_MAX_RSVD_REGIONS 7
 
 struct rsvd_region {
 	unsigned long start;	/* virtual address of beginning of element */
Index: linux//include/linux/irq.h
===================================================================
--- linux.orig//include/linux/irq.h	2006-08-17 13:14:35.000000000 +0900
+++ linux//include/linux/irq.h	2006-08-17 13:13:50.000000000 +0900
@@ -182,6 +182,7 @@
 #include <asm/hw_irq.h>
 
 extern int setup_irq(unsigned int irq, struct irqaction *new);
+extern void terminate_irqs(void);
 
 #ifdef CONFIG_GENERIC_HARDIRQS
 
Index: linux//kernel/irq/manage.c
===================================================================
--- linux.orig//kernel/irq/manage.c	2006-08-17 13:14:10.000000000 +0900
+++ linux//kernel/irq/manage.c	2006-08-17 13:13:50.000000000 +0900
@@ -476,3 +476,22 @@
 }
 EXPORT_SYMBOL(request_irq);
 
+/*
+ * Terminate any outstanding interrupts
+ */
+void terminate_irqs(void)
+{
+	struct irqaction * action;
+	irq_desc_t *idesc;
+	int i;
+
+	for (i=0; i < NR_IRQS; i++) {
+		idesc = irq_descp(i);
+		action = idesc->action;
+		if (!action)
+			continue;
+		if (idesc->handler->end)
+			idesc->handler->end(i);
+	}
+}
+

--

-- 
Horms
  H: http://www.vergenet.net/~horms/
  W: http://www.valinux.co.jp/en/

-
To unsubscribe from this list: send the line "unsubscribe linux-ia64" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel]     [Sparc Linux]     [DCCP]     [Linux ARM]     [Yosemite News]     [Linux SCSI]     [Linux x86_64]     [Linux for Ham Radio]

  Powered by Linux