> commit beada884dd437b509c26b39f1a0b0c6b31e6f340
> tree ad7608f34ca8aa9e292e2a863484b3e13250107d
> parent b373e385743597f576b67c423807bbdfe3b862e7
> author Zou Nan hai <[EMAIL PROTECTED]> 1150320804 -0700
> committer Tony Luck <[EMAIL PROTECTED]> 1150320804 -0700
>
> [IA64] Miscellaneous updates for kexec/kdump
>
> Signed-off-by: Zou Nan hai <[EMAIL PROTECTED]>
Up-port from the test branch of Tony Luck's ia64 tree to 2.6.18-rc4
Cc: Zou Nan hai <[EMAIL PROTECTED]>
Signed-off-by: Simon Horman <[EMAIL PROTECTED]>
/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 <[EMAIL PROTECTED]>
- *
* Copyright (C) 2005 Hewlett-Packard Development Company, L.P.
+ * Copyright (C) 2005 Intel Corp Zou Nan hai <[EMAIL PROTECTED]>
*
*/
#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
+ /* [EMAIL PROTECTED] 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/
_______________________________________________
fastboot mailing list
[email protected]
https://lists.osdl.org/mailman/listinfo/fastboot