summaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.osdl.org>2006-12-12 18:53:48 -0800
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-12 18:53:48 -0800
commit445722f97a0ecd3aed3f53d9f0dcaacaef8c6223 (patch)
treed8cbe88303972b282050e4e87a6ea30a3063145f /arch
parent3641b536ecc56f68fe182ac99f7ddc4827125118 (diff)
parentdf3e0d1c69c097f54588d720d39efdcdf31e3c24 (diff)
Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl/linux-2.6: [IA64] kprobe clears qp bits for special instructions [IA64] enable trap code on slot 1 [IA64] Take defensive stance on ia64_pal_get_brand_info() [IA64] fix possible XPC deadlock when disconnecting [IA64] - Reduce overhead of FP exception logging messages [IA64] fix arch/ia64/mm/contig.c:235: warning: unused variable `nid' [IA64] s/termios/ktermios/ in simserial.c [IA64] kexec/kdump: tidy up declaration of relocate_new_kernel_t [IA64] Kexec/Kdump: honour non-zero crashkernel offset. [IA64] CONFIG_KEXEC/CONFIG_CRASH_DUMP permutations [IA64] Do not call SN_SAL_SET_CPU_NUMBER twice on cpu 0
Diffstat (limited to 'arch')
-rw-r--r--arch/ia64/hp/sim/simserial.c2
-rw-r--r--arch/ia64/kernel/Makefile1
-rw-r--r--arch/ia64/kernel/crash.c22
-rw-r--r--arch/ia64/kernel/crash_dump.c48
-rw-r--r--arch/ia64/kernel/jprobes.S3
-rw-r--r--arch/ia64/kernel/kprobes.c226
-rw-r--r--arch/ia64/kernel/machine_kexec.c7
-rw-r--r--arch/ia64/kernel/mca.c2
-rw-r--r--arch/ia64/kernel/setup.c33
-rw-r--r--arch/ia64/kernel/smp.c4
-rw-r--r--arch/ia64/kernel/traps.c50
-rw-r--r--arch/ia64/mm/contig.c9
-rw-r--r--arch/ia64/mm/init.c9
-rw-r--r--arch/ia64/sn/kernel/setup.c12
-rw-r--r--arch/ia64/sn/kernel/xpc_channel.c15
-rw-r--r--arch/ia64/sn/kernel/xpc_main.c64
16 files changed, 358 insertions, 149 deletions
diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
index 1f16ebb9a80..324ea7565e2 100644
--- a/arch/ia64/hp/sim/simserial.c
+++ b/arch/ia64/hp/sim/simserial.c
@@ -488,7 +488,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
unsigned int cflag = tty->termios->c_cflag;
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index 8ae384eb535..098ee605bf5 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -29,6 +29,7 @@ obj-$(CONFIG_CPU_FREQ) += cpufreq/
obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o
obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o
+obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
obj-$(CONFIG_AUDIT) += audit.o
obj-$(CONFIG_PCI_MSI) += msi_ia64.o
diff --git a/arch/ia64/kernel/crash.c b/arch/ia64/kernel/crash.c
index 0aabedf95da..bc2f64d7224 100644
--- a/arch/ia64/kernel/crash.c
+++ b/arch/ia64/kernel/crash.c
@@ -19,29 +19,11 @@
#include <asm/kdebug.h>
#include <asm/mca.h>
-#include <asm/uaccess.h>
int kdump_status[NR_CPUS];
atomic_t kdump_cpu_freezed;
atomic_t kdump_in_progress;
int kdump_on_init = 1;
-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 = __va(pfn<<PAGE_SHIFT);
- if (userbuf) {
- if (copy_to_user(buf, (vaddr + offset), csize)) {
- return -EFAULT;
- }
- } else
- memcpy(buf, (vaddr + offset), csize);
- return csize;
-}
static inline Elf64_Word
*append_elf_note(Elf64_Word *buf, char *name, unsigned type, void *data,
@@ -225,14 +207,10 @@ static ctl_table sys_table[] = {
static int
machine_crash_setup(void)
{
- char *from = strstr(saved_command_line, "elfcorehdr=");
static struct notifier_block kdump_init_notifier_nb = {
.notifier_call = kdump_init_notifier,
};
int ret;
- if (from)
- elfcorehdr_addr = memparse(from+11, &from);
- saved_max_pfn = (unsigned long)-1;
if((ret = register_die_notifier(&kdump_init_notifier_nb)) != 0)
return ret;
#ifdef CONFIG_SYSCTL
diff --git a/arch/ia64/kernel/crash_dump.c b/arch/ia64/kernel/crash_dump.c
new file mode 100644
index 00000000000..83b8c91c140
--- /dev/null
+++ b/arch/ia64/kernel/crash_dump.c
@@ -0,0 +1,48 @@
+/*
+ * kernel/crash_dump.c - Memory preserving reboot related code.
+ *
+ * Created by: Simon Horman <horms@verge.net.au>
+ * Original code moved from kernel/crash.c
+ * Original code comment copied from the i386 version of this file
+ */
+
+#include <linux/errno.h>
+#include <linux/types.h>
+
+#include <linux/uaccess.h>
+
+/**
+ * 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. We stitch up a pte, similar to kmap_atomic.
+ *
+ * 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 = __va(pfn<<PAGE_SHIFT);
+ if (userbuf) {
+ if (copy_to_user(buf, (vaddr + offset), csize)) {
+ return -EFAULT;
+ }
+ } else
+ memcpy(buf, (vaddr + offset), csize);
+ return csize;
+}
+
diff --git a/arch/ia64/kernel/jprobes.S b/arch/ia64/kernel/jprobes.S
index 5cd6226f44f..621630256c4 100644
--- a/arch/ia64/kernel/jprobes.S
+++ b/arch/ia64/kernel/jprobes.S
@@ -45,13 +45,14 @@
* to the correct location.
*/
#include <asm/asmmacro.h>
+#include <asm-ia64/break.h>
/*
* void jprobe_break(void)
*/
.section .kprobes.text, "ax"
ENTRY(jprobe_break)
- break.m 0x80300
+ break.m __IA64_BREAK_JPROBE
END(jprobe_break)
/*
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index 76e778951e2..6cb56dd4056 100644
--- a/arch/ia64/kernel/kprobes.c
+++ b/arch/ia64/kernel/kprobes.c
@@ -88,6 +88,7 @@ static void __kprobes update_kprobe_inst_flag(uint template, uint slot,
{
p->ainsn.inst_flag = 0;
p->ainsn.target_br_reg = 0;
+ p->ainsn.slot = slot;
/* Check for Break instruction
* Bits 37:40 Major opcode to be zero
@@ -129,48 +130,6 @@ static void __kprobes update_kprobe_inst_flag(uint template, uint slot,
/*
* In this function we check to see if the instruction
- * on which we are inserting kprobe is supported.
- * Returns 0 if supported
- * Returns -EINVAL if unsupported
- */
-static int __kprobes unsupported_inst(uint template, uint slot,
- uint major_opcode,
- unsigned long kprobe_inst,
- unsigned long addr)
-{
- if (bundle_encoding[template][slot] == I) {
- switch (major_opcode) {
- case 0x0: //I_UNIT_MISC_OPCODE:
- /*
- * Check for Integer speculation instruction
- * - Bit 33-35 to be equal to 0x1
- */
- if (((kprobe_inst >> 33) & 0x7) == 1) {
- printk(KERN_WARNING
- "Kprobes on speculation inst at <0x%lx> not supported\n",
- addr);
- return -EINVAL;
- }
-
- /*
- * IP relative mov instruction
- * - Bit 27-35 to be equal to 0x30
- */
- if (((kprobe_inst >> 27) & 0x1FF) == 0x30) {
- printk(KERN_WARNING
- "Kprobes on \"mov r1=ip\" at <0x%lx> not supported\n",
- addr);
- return -EINVAL;
-
- }
- }
- }
- return 0;
-}
-
-
-/*
- * In this function we check to see if the instruction
* (qp) cmpx.crel.ctype p1,p2=r2,r3
* on which we are inserting kprobe is cmp instruction
* with ctype as unc.
@@ -206,26 +165,136 @@ out:
}
/*
+ * In this function we check to see if the instruction
+ * on which we are inserting kprobe is supported.
+ * Returns qp value if supported
+ * Returns -EINVAL if unsupported
+ */
+static int __kprobes unsupported_inst(uint template, uint slot,
+ uint major_opcode,
+ unsigned long kprobe_inst,
+ unsigned long addr)
+{
+ int qp;
+
+ qp = kprobe_inst & 0x3f;
+ if (is_cmp_ctype_unc_inst(template, slot, major_opcode, kprobe_inst)) {
+ if (slot == 1 && qp) {
+ printk(KERN_WARNING "Kprobes on cmp unc"
+ "instruction on slot 1 at <0x%lx>"
+ "is not supported\n", addr);
+ return -EINVAL;
+
+ }
+ qp = 0;
+ }
+ else if (bundle_encoding[template][slot] == I) {
+ if (major_opcode == 0) {
+ /*
+ * Check for Integer speculation instruction
+ * - Bit 33-35 to be equal to 0x1
+ */
+ if (((kprobe_inst >> 33) & 0x7) == 1) {
+ printk(KERN_WARNING
+ "Kprobes on speculation inst at <0x%lx> not supported\n",
+ addr);
+ return -EINVAL;
+ }
+ /*
+ * IP relative mov instruction
+ * - Bit 27-35 to be equal to 0x30
+ */
+ if (((kprobe_inst >> 27) & 0x1FF) == 0x30) {
+ printk(KERN_WARNING
+ "Kprobes on \"mov r1=ip\" at <0x%lx> not supported\n",
+ addr);
+ return -EINVAL;
+
+ }
+ }
+ else if ((major_opcode == 5) && !(kprobe_inst & (0xFUl << 33)) &&
+ (kprobe_inst & (0x1UL << 12))) {
+ /* test bit instructions, tbit,tnat,tf
+ * bit 33-36 to be equal to 0
+ * bit 12 to be equal to 1
+ */
+ if (slot == 1 && qp) {
+ printk(KERN_WARNING "Kprobes on test bit"
+ "instruction on slot at <0x%lx>"
+ "is not supported\n", addr);
+ return -EINVAL;
+ }
+ qp = 0;
+ }
+ }
+ else if (bundle_encoding[template][slot] == B) {
+ if (major_opcode == 7) {
+ /* IP-Relative Predict major code is 7 */
+ printk(KERN_WARNING "Kprobes on IP-Relative"
+ "Predict is not supported\n");
+ return -EINVAL;
+ }
+ else if (major_opcode == 2) {
+ /* Indirect Predict, major code is 2
+ * bit 27-32 to be equal to 10 or 11
+ */
+ int x6=(kprobe_inst >> 27) & 0x3F;
+ if ((x6 == 0x10) || (x6 == 0x11)) {
+ printk(KERN_WARNING "Kprobes on"
+ "Indirect Predict is not supported\n");
+ return -EINVAL;
+ }
+ }
+ }
+ /* kernel does not use float instruction, here for safety kprobe
+ * will judge whether it is fcmp/flass/float approximation instruction
+ */
+ else if (unlikely(bundle_encoding[template][slot] == F)) {
+ if ((major_opcode == 4 || major_opcode == 5) &&
+ (kprobe_inst & (0x1 << 12))) {
+ /* fcmp/fclass unc instruction */
+ if (slot == 1 && qp) {
+ printk(KERN_WARNING "Kprobes on fcmp/fclass "
+ "instruction on slot at <0x%lx> "
+ "is not supported\n", addr);
+ return -EINVAL;
+
+ }
+ qp = 0;
+ }
+ if ((major_opcode == 0 || major_opcode == 1) &&
+ (kprobe_inst & (0x1UL << 33))) {
+ /* float Approximation instruction */
+ if (slot == 1 && qp) {
+ printk(KERN_WARNING "Kprobes on float Approx "
+ "instr at <0x%lx> is not supported\n",
+ addr);
+ return -EINVAL;
+ }
+ qp = 0;
+ }
+ }
+ return qp;
+}
+
+/*
* In this function we override the bundle with
* the break instruction at the given slot.
*/
static void __kprobes prepare_break_inst(uint template, uint slot,
uint major_opcode,
unsigned long kprobe_inst,
- struct kprobe *p)
+ struct kprobe *p,
+ int qp)
{
unsigned long break_inst = BREAK_INST;
bundle_t *bundle = &p->opcode.bundle;
/*
* Copy the original kprobe_inst qualifying predicate(qp)
- * to the break instruction iff !is_cmp_ctype_unc_inst
- * because for cmp instruction with ctype equal to unc,
- * which is a special instruction always needs to be
- * executed regradless of qp
+ * to the break instruction
*/
- if (!is_cmp_ctype_unc_inst(template, slot, major_opcode, kprobe_inst))
- break_inst |= (0x3f & kprobe_inst);
+ break_inst |= qp;
switch (slot) {
case 0:
@@ -296,12 +365,6 @@ static int __kprobes valid_kprobe_addr(int template, int slot,
return -EINVAL;
}
- if (slot == 1 && bundle_encoding[template][1] != L) {
- printk(KERN_WARNING "Inserting kprobes on slot #1 "
- "is not supported\n");
- return -EINVAL;
- }
-
return 0;
}
@@ -427,6 +490,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
unsigned long kprobe_inst=0;
unsigned int slot = addr & 0xf, template, major_opcode = 0;
bundle_t *bundle;
+ int qp;
bundle = &((kprobe_opcode_t *)kprobe_addr)->bundle;
template = bundle->quad0.template;
@@ -441,9 +505,9 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
/* Get kprobe_inst and major_opcode from the bundle */
get_kprobe_inst(bundle, slot, &kprobe_inst, &major_opcode);
- if (unsupported_inst(template, slot, major_opcode, kprobe_inst, addr))
- return -EINVAL;
-
+ qp = unsupported_inst(template, slot, major_opcode, kprobe_inst, addr);
+ if (qp < 0)
+ return -EINVAL;
p->ainsn.insn = get_insn_slot();
if (!p->ainsn.insn)
@@ -451,30 +515,56 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
memcpy(&p->opcode, kprobe_addr, sizeof(kprobe_opcode_t));
memcpy(p->ainsn.insn, kprobe_addr, sizeof(kprobe_opcode_t));
- prepare_break_inst(template, slot, major_opcode, kprobe_inst, p);
+ prepare_break_inst(template, slot, major_opcode, kprobe_inst, p, qp);
return 0;
}
void __kprobes arch_arm_kprobe(struct kprobe *p)
{
- unsigned long addr = (unsigned long)p->addr;
- unsigned long arm_addr = addr & ~0xFULL;
+ unsigned long arm_addr;
+ bundle_t *src, *dest;
+
+ arm_addr = ((unsigned long)p->addr) & ~0xFUL;
+ dest = &((kprobe_opcode_t *)arm_addr)->bundle;
+ src = &p->opcode.bundle;
flush_icache_range((unsigned long)p->ainsn.insn,
(unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t));
- memcpy((char *)arm_addr, &p->opcode, sizeof(kprobe_opcode_t));
+ switch (p->ainsn.slot) {
+ case 0:
+ dest->quad0.slot0 = src->quad0.slot0;
+ break;
+ case 1:
+ dest->quad1.slot1_p1 = src->quad1.slot1_p1;
+ break;
+ case 2:
+ dest->quad1.slot2 = src->quad1.slot2;
+ break;
+ }
flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t));
}
void __kprobes arch_disarm_kprobe(struct kprobe *p)
{
- unsigned long addr = (unsigned long)p->addr;
- unsigned long arm_addr = addr & ~0xFULL;
+ unsigned long arm_addr;
+ bundle_t *src, *dest;
+ arm_addr = ((unsigned long)p->addr) & ~0xFUL;
+ dest = &((kprobe_opcode_t *)arm_addr)->bundle;
/* p->ainsn.insn contains the original unaltered kprobe_opcode_t */
- memcpy((char *) arm_addr, (char *) p->ainsn.insn,
- sizeof(kprobe_opcode_t));
+ src = &p->ainsn.insn->bundle;
+ switch (p->ainsn.slot) {
+ case 0:
+ dest->quad0.slot0 = src->quad0.slot0;
+ break;
+ case 1:
+ dest->quad1.slot1_p1 = src->quad1.slot1_p1;
+ break;
+ case 2:
+ dest->quad1.slot2 = src->quad1.slot2;
+ break;
+ }
flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t));
}
@@ -807,7 +897,9 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
switch(val) {
case DIE_BREAK:
/* err is break number from ia64_bad_break() */
- if (args->err == 0x80200 || args->err == 0x80300 || args->err == 0)
+ if ((args->err >> 12) == (__IA64_BREAK_KPROBE >> 12)
+ || args->err == __IA64_BREAK_JPROBE
+ || args->err == 0)
if (pre_kprobes_handler(args))
ret = NOTIFY_STOP;
break;
diff --git a/arch/ia64/kernel/machine_kexec.c b/arch/ia64/kernel/machine_kexec.c
index 468233fa2ce..e2ccc9f660c 100644
--- a/arch/ia64/kernel/machine_kexec.c
+++ b/arch/ia64/kernel/machine_kexec.c
@@ -19,8 +19,11 @@
#include <asm/delay.h>
#include <asm/meminit.h>
-typedef void (*relocate_new_kernel_t)(unsigned long, unsigned long,
- struct ia64_boot_param *, unsigned long);
+typedef NORET_TYPE void (*relocate_new_kernel_t)(
+ unsigned long indirection_page,
+ unsigned long start_address,
+ struct ia64_boot_param *boot_param,
+ unsigned long pal_addr) ATTRIB_NORET;
struct kimage *ia64_kimage;
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
index 87c1c4f4287..a76add3e76a 100644
--- a/arch/ia64/kernel/mca.c
+++ b/arch/ia64/kernel/mca.c
@@ -1239,7 +1239,7 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw,
} else {
/* Dump buffered message to console */
ia64_mlogbuf_finish(1);
-#ifdef CONFIG_CRASH_DUMP
+#ifdef CONFIG_KEXEC
atomic_set(&kdump_in_progress, 1);
monarch_cpu = -1;
#endif
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index 14e1200376a..ad567b8d432 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -256,7 +256,7 @@ reserve_memory (void)
#ifdef CONFIG_KEXEC
/* crashkernel=size@offset specifies the size to reserve for a crash
- * kernel.(offset is ingored for keep compatibility with other archs)
+ * kernel. If offset is 0, then it is determined automatically.
* 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.
@@ -266,10 +266,16 @@ reserve_memory (void)
unsigned long base, size;
if (from) {
size = memparse(from + 12, &from);
+ if (*from == '@')
+ base = memparse(from+1, &from);
+ else
+ base = 0;
if (size) {
- sort_regions(rsvd_region, n);
- base = kdump_find_rsvd_region(size,
- rsvd_region, n);
+ if (!base) {
+ sort_regions(rsvd_region, n);
+ base = kdump_find_rsvd_region(size,
+ rsvd_region, n);
+ }
if (base != ~0UL) {
rsvd_region[n].start =
(unsigned long)__va(base);
@@ -434,6 +440,21 @@ static __init int setup_nomca(char *s)
}
early_param("nomca", setup_nomca);
+#ifdef CONFIG_PROC_VMCORE
+/* elfcorehdr= specifies the location of elf core header
+ * stored by the crashed kernel.
+ */
+static int __init parse_elfcorehdr(char *arg)
+{
+ if (!arg)
+ return -EINVAL;
+
+ elfcorehdr_addr = memparse(arg, &arg);
+ return 0;
+}
+early_param("elfcorehdr", parse_elfcorehdr);
+#endif /* CONFIG_PROC_VMCORE */
+
void __init
setup_arch (char **cmdline_p)
{
@@ -653,6 +674,7 @@ get_model_name(__u8 family, __u8 model)
{
char brand[128];
+ memcpy(brand, "Unknown", 8);
if (ia64_pal_get_brand_info(brand)) {
if (family == 0x7)
memcpy(brand, "Merced", 7);
@@ -660,8 +682,7 @@ get_model_name(__u8 family, __u8 model)
case 0: memcpy(brand, "McKinley", 9); break;
case 1: memcpy(brand, "Madison", 8); break;
case 2: memcpy(brand, "Madison up to 9M cache", 23); break;
- } else
- memcpy(brand, "Unknown", 8);
+ }
}
if (brandname[0] == '\0')
return strcpy(brandname, brand);
diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c
index b1b9aa4364b..f4c7f7769cf 100644
--- a/arch/ia64/kernel/smp.c
+++ b/arch/ia64/kernel/smp.c
@@ -157,7 +157,7 @@ handle_IPI (int irq, void *dev_id)
case IPI_CPU_STOP:
stop_this_cpu();
break;
-#ifdef CONFIG_CRASH_DUMP
+#ifdef CONFIG_KEXEC
case IPI_KDUMP_CPU_STOP:
unw_init_running(kdump_cpu_freeze, NULL);
break;
@@ -219,7 +219,7 @@ send_IPI_self (int op)
send_IPI_single(smp_processor_id(), op);
}
-#ifdef CONFIG_CRASH_DUMP
+#ifdef CONFIG_KEXEC
void
kdump_smp_send_stop()
{
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
index fffa9e0826b..ab684747036 100644
--- a/arch/ia64/kernel/traps.c
+++ b/arch/ia64/kernel/traps.c
@@ -307,6 +307,15 @@ fp_emulate (int fp_fault, void *bundle, long *ipsr, long *fpsr, long *isr, long
return ret.status;
}
+struct fpu_swa_msg {
+ unsigned long count;
+ unsigned long time;
+};
+static DEFINE_PER_CPU(struct fpu_swa_msg, cpulast);
+DECLARE_PER_CPU(struct fpu_swa_msg, cpulast);
+static struct fpu_swa_msg last __cacheline_aligned;
+
+
/*
* Handle floating-point assist faults and traps.
*/
@@ -316,8 +325,6 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr)
long exception, bundle[2];
unsigned long fault_ip;
struct siginfo siginfo;
- static int fpu_swa_count = 0;
- static unsigned long last_time;
fault_ip = regs->cr_iip;
if (!fp_fault && (ia64_psr(regs)->ri == 0))
@@ -325,14 +332,37 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr)
if (copy_from_user(bundle, (void __user *) fault_ip, sizeof(bundle)))
return -1;
- if (jiffies - last_time > 5*HZ)
- fpu_swa_count = 0;
- if ((fpu_swa_count < 4) && !(current->thread.flags & IA64_THREAD_FPEMU_NOPRINT)) {
- last_time = jiffies;
- ++fpu_swa_count;
- printk(KERN_WARNING
- "%s(%d): floating-point assist fault at ip %016lx, isr %016lx\n",
- current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri, isr);
+ if (!(current->thread.flags & IA64_THREAD_FPEMU_NOPRINT)) {
+ unsigned long count, current_jiffies = jiffies;
+ struct fpu_swa_msg *cp = &__get_cpu_var(cpulast);
+
+ if (unlikely(current_jiffies > cp->time))
+ cp->count = 0;
+ if (unlikely(cp->count < 5)) {
+ cp->count++;
+ cp->time = current_jiffies + 5 * HZ;
+
+ /* minimize races by grabbing a copy of count BEFORE checking last.time. */
+ count = last.count;
+ barrier();
+
+ /*
+ * Lower 4 bits are used as a count. Upper bits are a sequence
+ * number that is updated when count is reset. The cmpxchg will
+ * fail is seqno has changed. This minimizes mutiple cpus
+ * reseting the count.
+ */
+ if (current_jiffies > last.time)
+ (void) cmpxchg_acq(&last.count, count, 16 + (count & ~15));
+
+ /* used fetchadd to atomically update the count */
+ if ((last.count & 15) < 5 && (ia64_fetchadd(1, &last.count, acq) & 15) < 5) {
+ last.time = current_jiffies + 5 * HZ;
+ printk(KERN_WARNING
+ "%s(%d): floating-point assist fault at ip %016lx, isr %016lx\n",
+ current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri, isr);
+ }
+ }
}
exception = fp_emulate(fp_fault, bundle, &regs->cr_ipsr, &regs->ar_fpsr, &isr, &regs->pr,
diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c
index 82deaa3a7c4..1e79551231b 100644
--- a/arch/ia64/mm/contig.c
+++ b/arch/ia64/mm/contig.c
@@ -174,6 +174,12 @@ find_memory (void)
reserve_bootmem(bootmap_start, bootmap_size);
find_initrd();
+
+#ifdef CONFIG_CRASH_DUMP
+ /* If we are doing a crash dump, we still need to know the real mem
+ * size before original memory map is * reset. */
+ saved_max_pfn = max_pfn;
+#endif
}
#ifdef CONFIG_SMP
@@ -226,7 +232,6 @@ void __init
paging_init (void)
{
unsigned long max_dma;
- unsigned long nid = 0;
unsigned long max_zone_pfns[MAX_NR_ZONES];
num_physpages = 0;
@@ -238,7 +243,7 @@ paging_init (void)
max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
#ifdef CONFIG_VIRTUAL_MEM_MAP
- efi_memmap_walk(register_active_ranges, &nid);
+ efi_memmap_walk(register_active_ranges, NULL);
efi_memmap_walk(find_largest_hole, (u64 *)&max_gap);
if (max_gap < LARGE_GAP) {
vmem_map = (struct page *) 0;
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index 56dc2024220..1a3d8a2feb9 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -595,14 +595,9 @@ find_largest_hole (u64 start, u64 end, void *arg)
}
int __init
-register_active_ranges(u64 start, u64 end, void *nid)
+register_active_ranges(u64 start, u64 end, void *arg)
{
- BUG_ON(nid == NULL);
- BUG_ON(*(unsigned long *)nid >= MAX_NUMNODES);
-
- add_active_range(*(unsigned long *)nid,
- __pa(start) >> PAGE_SHIFT,
- __pa(end) >> PAGE_SHIFT);
+ add_active_range(0, __pa(start) >> PAGE_SHIFT, __pa(end) >> PAGE_SHIFT);
return 0;
}
#endif /* CONFIG_VIRTUAL_MEM_MAP */
diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
index a934ad06942..8571e52c2ef 100644
--- a/arch/ia64/sn/kernel/setup.c
+++ b/arch/ia64/sn/kernel/setup.c
@@ -580,7 +580,7 @@ void __cpuinit sn_cpu_init(void)
int slice;
int cnode;
int i;
- static int wars_have_been_checked;
+ static int wars_have_been_checked, set_cpu0_number;
cpuid = smp_processor_id();
if (cpuid == 0 && IS_MEDUSA()) {
@@ -605,8 +605,16 @@ void __cpuinit sn_cpu_init(void)
/*
* Don't check status. The SAL call is not supported on all PROMs
* but a failure is harmless.
+ * Architechtuallly, cpu_init is always called twice on cpu 0. We
+ * should set cpu_number on cpu 0 once.
*/
- (void) ia64_sn_set_cpu_number(cpuid);
+ if (cpuid == 0) {
+ if (!set_cpu0_number) {
+ (void) ia64_sn_set_cpu_number(cpuid);
+ set_cpu0_number = 1;
+ }
+ } else
+ (void) ia64_sn_set_cpu_number(cpuid);
/*
* The boot cpu makes this call again after platform initialization is
diff --git a/arch/ia64/sn/kernel/xpc_channel.c b/arch/ia64/sn/kernel/xpc_channel.c
index 1f3540826e6..c08db9c2375 100644
--- a/arch/ia64/sn/kernel/xpc_channel.c
+++ b/arch/ia64/sn/kernel/xpc_channel.c
@@ -632,7 +632,7 @@ xpc_process_connect(struct xpc_channel *ch, unsigned long *irq_flags)
ch->number, ch->partid);
spin_unlock_irqrestore(&ch->lock, *irq_flags);
- xpc_create_kthreads(ch, 1);
+ xpc_create_kthreads(ch, 1, 0);
spin_lock_irqsave(&ch->lock, *irq_flags);
}
@@ -754,12 +754,12 @@ xpc_process_disconnect(struct xpc_channel *ch, unsigned long *irq_flags)
/* make sure all activity has settled down first */
- if (atomic_read(&ch->references) > 0 ||
- ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
- !(ch->flags & XPC_C_DISCONNECTINGCALLOUT_MADE))) {
+ if (atomic_read(&ch->kthreads_assigned) > 0 ||
+ atomic_read(&ch->references) > 0) {
return;
}
- DBUG_ON(atomic_read(&ch->kthreads_assigned) != 0);
+ DBUG_ON((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
+ !(ch->flags & XPC_C_DISCONNECTINGCALLOUT_MADE));
if (part->act_state == XPC_P_DEACTIVATING) {
/* can't proceed until the other side disengages from us */
@@ -1651,6 +1651,11 @@ xpc_disconnect_channel(const int line, struct xpc_channel *ch,
/* wake all idle kthreads so they can exit */
if (atomic_read(&ch->kthreads_idle) > 0) {
wake_up_all(&ch->idle_wq);
+
+ } else if ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
+ !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) {
+ /* start a kthread that will do the xpcDisconnecting callout */
+ xpc_create_kthreads(ch, 1, 1);
}
/* wake those waiting to allocate an entry from the local msg queue */
diff --git a/arch/ia64/sn/kernel/xpc_main.c b/arch/ia64/sn/kernel/xpc_main.c
index fa96dfc0e1a..7a387d23736 100644
--- a/arch/ia64/sn/kernel/xpc_main.c
+++ b/arch/ia64/sn/kernel/xpc_main.c
@@ -681,7 +681,7 @@ xpc_activate_kthreads(struct xpc_channel *ch, int needed)
dev_dbg(xpc_chan, "create %d new kthreads, partid=%d, channel=%d\n",
needed, ch->partid, ch->number);
- xpc_create_kthreads(ch, needed);
+ xpc_create_kthreads(ch, needed, 0);
}
@@ -775,26 +775,28 @@ xpc_daemonize_kthread(void *args)
xpc_kthread_waitmsgs(part, ch);
}
- if (atomic_dec_return(&ch->kthreads_assigned) == 0) {
- spin_lock_irqsave(&ch->lock, irq_flags);
- if ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
- !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) {
- ch->flags |= XPC_C_DISCONNECTINGCALLOUT;
- spin_unlock_irqrestore(&ch->lock, irq_flags);
+ /* let registerer know that connection is disconnecting */
- xpc_disconnect_callout(ch, xpcDisconnecting);
-
- spin_lock_irqsave(&ch->lock, irq_flags);
- ch->flags |= XPC_C_DISCONNECTINGCALLOUT_MADE;
- }
+ spin_lock_irqsave(&ch->lock, irq_flags);
+ if ((ch->flags & XPC_C_CONNECTEDCALLOUT_MADE) &&
+ !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) {
+ ch->flags |= XPC_C_DISCONNECTINGCALLOUT;
spin_unlock_irqrestore(&ch->lock, irq_flags);
+
+ xpc_disconnect_callout(ch, xpcDisconnecting);
+
+ spin_lock_irqsave(&ch->lock, irq_flags);
+ ch->flags |= XPC_C_DISCONNECTINGCALLOUT_MADE;
+ }
+ spin_unlock_irqrestore(&ch->lock, irq_flags);
+
+ if (atomic_dec_return(&ch->kthreads_assigned) == 0) {
if (atomic_dec_return(&part->nchannels_engaged) == 0) {
xpc_mark_partition_disengaged(part);
xpc_IPI_send_disengage(part);
}
}
-
xpc_msgqueue_deref(ch);
dev_dbg(xpc_chan, "kthread exiting, partid=%d, channel=%d\n",
@@ -818,7 +820,8 @@ xpc_daemonize_kthread(void *args)
* partition.
*/
void
-xpc_create_kthreads(struct xpc_channel *ch, int needed)
+xpc_create_kthreads(struct xpc_channel *ch, int needed,
+ int ignore_disconnecting)
{
unsigned long irq_flags;
pid_t pid;
@@ -833,16 +836,38 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed)
* kthread. That kthread is responsible for doing the
* counterpart to the following before it exits.
*/
+ if (ignore_disconnecting) {
+ if (!atomic_inc_not_zero(&ch->kthreads_assigned)) {
+ /* kthreads assigned had gone to zero */
+ BUG_ON(!(ch->flags &
+ XPC_C_DISCONNECTINGCALLOUT_MADE));
+ break;
+ }
+
+ } else if (ch->flags & XPC_C_DISCONNECTING) {
+ break;
+
+ } else if (atomic_inc_return(&ch->kthreads_assigned) == 1) {
+ if (atomic_inc_return(&part->nchannels_engaged) == 1)
+ xpc_mark_partition_engaged(part);
+ }
(void) xpc_part_ref(part);
xpc_msgqueue_ref(ch);
- if (atomic_inc_return(&ch->kthreads_assigned) == 1 &&
- atomic_inc_return(&part->nchannels_engaged) == 1) {
- xpc_mark_partition_engaged(part);
- }
pid = kernel_thread(xpc_daemonize_kthread, (void *) args, 0);
if (pid < 0) {
/* the fork failed */
+
+ /*
+ * NOTE: if (ignore_disconnecting &&
+ * !(ch->flags & XPC_C_DISCONNECTINGCALLOUT)) is true,
+ * then we'll deadlock if all other kthreads assigned
+ * to this channel are blocked in the channel's
+ * registerer, because the only thing that will unblock
+ * them is the xpcDisconnecting callout that this
+ * failed kernel_thread would have made.
+ */
+
if (atomic_dec_return(&ch->kthreads_assigned) == 0 &&
atomic_dec_return(&part->nchannels_engaged) == 0) {
xpc_mark_partition_disengaged(part);
@@ -857,9 +882,6 @@ xpc_create_kthreads(struct xpc_channel *ch, int needed)
* Flag this as an error only if we have an
* insufficient #of kthreads for the channel
* to function.
- *
- * No xpc_msgqueue_ref() is needed here since
- * the channel mgr is doing this.
*/
spin_lock_irqsave(&ch->lock, irq_flags);
XPC_DISCONNECT_CHANNEL(ch, xpcLackOfResources,