From adf142e379bd20ad906a7e36f722eaabb3b44b0c Mon Sep 17 00:00:00 2001 From: Jay Lan Date: Mon, 11 Dec 2006 15:39:23 -0800 Subject: [IA64] Do not call SN_SAL_SET_CPU_NUMBER twice on cpu 0 This is an SN specific patch. Architectually, cpu_init is always called twice on cpu 0 and thus resulted in two SN_SAL_SET_CPU_NUMBER calls. This was harmless in production kernel; however, it can cause problem on booting up a crashdump kernel at Altix. Here is the patch that detects the second sn_cpu_init call and skips the second call to SN_SAL_SET_CPU_NUMBER. Signed-Off-By: Jay Lan Signed-off-by: Tony Luck --- arch/ia64/sn/kernel/setup.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c index a934ad069425..8571e52c2efd 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 -- cgit v1.2.3-59-g8ed1b From 45a98fc622ae700eed34eb2be00743910d50dbe1 Mon Sep 17 00:00:00 2001 From: Horms Date: Tue, 12 Dec 2006 17:49:03 +0900 Subject: [IA64] CONFIG_KEXEC/CONFIG_CRASH_DUMP permutations Actually, on reflection I think that there is a good case for keeping the options separate. I am thinking particularly of people who want a very small crashdump kernel and thus don't want to compile in kexec. The patch below should fix things up so that all valid combinations of KEXEC, CRASH_DUMP and VMCORE compile cleanly - VMCORE depends on CRASH_DUMP which is why I said valid combinations. In a nutshell it just untangles unrelated code and switches around a few defines. Please note that it creats a new file, arch/ia64/kernel/crash_dump.c This is in keeping with the i386 implementation. Signed-off-by: Simon Horman Signed-off-by: Tony Luck --- arch/ia64/kernel/Makefile | 1 + arch/ia64/kernel/crash.c | 22 -------------------- arch/ia64/kernel/crash_dump.c | 48 +++++++++++++++++++++++++++++++++++++++++++ arch/ia64/kernel/mca.c | 2 +- arch/ia64/kernel/setup.c | 15 ++++++++++++++ arch/ia64/kernel/smp.c | 4 ++-- arch/ia64/mm/contig.c | 6 ++++++ 7 files changed, 73 insertions(+), 25 deletions(-) create mode 100644 arch/ia64/kernel/crash_dump.c diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile index 8ae384eb5357..098ee605bf5e 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 0aabedf95dad..bc2f64d72244 100644 --- a/arch/ia64/kernel/crash.c +++ b/arch/ia64/kernel/crash.c @@ -19,29 +19,11 @@ #include #include -#include 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< Date: Tue, 12 Dec 2006 18:08:10 +0900 Subject: [IA64] Kexec/Kdump: honour non-zero crashkernel offset. There seems to be a value in both allowing the kernel to determine the base offset of the crashkernel automatically and allowing users's to sepcify it. The old behaviour on ia64, which is still the current behaviour on most architectures is for the user to always specify the address. Recently ia64 was changed so that it is always automatically determined. With this patch the kernel automatically determines the offset if the supplied value is 0, otherwise it uses the value provided. This should probably be backed by a documentation change. Signed-Off-By: Simon Horman Signed-off-by: Tony Luck --- arch/ia64/kernel/setup.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index 66377baea6a5..be398451d45c 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); -- cgit v1.2.3-59-g8ed1b From 53da5763bf129def6fe69ea5301d625ce9a86edf Mon Sep 17 00:00:00 2001 From: Horms Date: Tue, 12 Dec 2006 18:06:13 +0900 Subject: [IA64] kexec/kdump: tidy up declaration of relocate_new_kernel_t * Make NORET_TYPE and ATTRIB_NORET in line with the declaration for other architectures * Add parameter names Signed-Off-By: Simon Horman Signed-off-by: Tony Luck --- arch/ia64/kernel/machine_kexec.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/arch/ia64/kernel/machine_kexec.c b/arch/ia64/kernel/machine_kexec.c index 468233fa2cee..e2ccc9f660c5 100644 --- a/arch/ia64/kernel/machine_kexec.c +++ b/arch/ia64/kernel/machine_kexec.c @@ -19,8 +19,11 @@ #include #include -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; -- cgit v1.2.3-59-g8ed1b From f889a26a703b03c774849685583cec7746738f3c Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Tue, 12 Dec 2006 10:47:36 -0800 Subject: [IA64] s/termios/ktermios/ in simserial.c This got missed in 606d099cdd1080bbb50ea50dc52d98252f8f10a1 Signed-off-by: Tony Luck --- arch/ia64/hp/sim/simserial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c index 1f16ebb9a800..324ea7565e2c 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; -- cgit v1.2.3-59-g8ed1b From 8b9c106856d92c8266697328b148d115538b59ce Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Tue, 12 Dec 2006 11:18:55 -0800 Subject: [IA64] fix arch/ia64/mm/contig.c:235: warning: unused variable `nid' This warning only shows up with CONFIG_VIRTUAL_MEM_MAP=y and CONFIG_FLATMEM=y. There is only one caller left for register_active_ranges() from the contig.c code ... so it doesn't need to pick up the node number, the node number is always zero. Signed-off-by: Tony Luck --- arch/ia64/mm/contig.c | 3 +-- arch/ia64/mm/init.c | 9 ++------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c index fd103886bb0a..1e79551231b9 100644 --- a/arch/ia64/mm/contig.c +++ b/arch/ia64/mm/contig.c @@ -232,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; @@ -244,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 56dc2024220e..1a3d8a2feb94 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 */ -- cgit v1.2.3-59-g8ed1b From 1cf24bdbbbd2eb5439796dc399ab1649d150ed1d Mon Sep 17 00:00:00 2001 From: Jack Steiner Date: Wed, 22 Nov 2006 09:55:08 -0600 Subject: [IA64] - Reduce overhead of FP exception logging messages Improve the scalability of the fpswa code that rate-limits logging of messages. There are 2 distinctly different problems in this code. 1) If prctl is used to disable logging, last_time is never updated. The result is that fpu_swa_count is zeroed out on EVERY fp fault. This causes a very very hot cache line. The fix reduces the wallclock time of a 1024p FP exception test from 28734 sec to 19 sec!!! 2) On VERY large systems, excessive messages are logged because multiple cpus can each reset or increment fpu_swa_count at about the same time. The result is that hundreds of messages are logged each second. The fixes reduces the logging rate to ~1 per second. Signed-off-by: Jack Steiner Signed-off-by: Tony Luck --- arch/ia64/kernel/traps.c | 50 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c index fffa9e0826bc..ab684747036f 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, ®s->cr_ipsr, ®s->ar_fpsr, &isr, ®s->pr, -- cgit v1.2.3-59-g8ed1b From a460ef8d0a98ac9ef6b829ae292c9b6c13bc0120 Mon Sep 17 00:00:00 2001 From: Dean Nelson Date: Wed, 22 Nov 2006 08:25:00 -0600 Subject: [IA64] fix possible XPC deadlock when disconnecting This patch eliminates a potential deadlock that is possible when XPC disconnects a channel to a partition that has gone down. This deadlock will occur if at least one of the kthreads created by XPC for the purpose of making callouts to the channel's registerer is detained in the registerer and will not be returning back to XPC until some registerer request occurs on the now downed partition. The potential for a deadlock is removed by ensuring that there always is a kthread available to make the channel disconnecting callout to the registerer. Signed-off-by: Dean Nelson Signed-off-by: Tony Luck --- arch/ia64/sn/kernel/xpc_channel.c | 15 ++++++--- arch/ia64/sn/kernel/xpc_main.c | 64 ++++++++++++++++++++++++++------------- include/asm-ia64/sn/xpc.h | 2 +- 3 files changed, 54 insertions(+), 27 deletions(-) diff --git a/arch/ia64/sn/kernel/xpc_channel.c b/arch/ia64/sn/kernel/xpc_channel.c index 1f3540826e68..c08db9c2375d 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 fa96dfc0e1aa..7a387d237363 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, diff --git a/include/asm-ia64/sn/xpc.h b/include/asm-ia64/sn/xpc.h index 1d45e1518fb3..e52b8508083b 100644 --- a/include/asm-ia64/sn/xpc.h +++ b/include/asm-ia64/sn/xpc.h @@ -673,7 +673,7 @@ extern irqreturn_t xpc_notify_IRQ_handler(int, void *); extern void xpc_dropped_IPI_check(struct xpc_partition *); extern void xpc_activate_partition(struct xpc_partition *); extern void xpc_activate_kthreads(struct xpc_channel *, int); -extern void xpc_create_kthreads(struct xpc_channel *, int); +extern void xpc_create_kthreads(struct xpc_channel *, int, int); extern void xpc_disconnect_wait(int); -- cgit v1.2.3-59-g8ed1b From 75f6a1de41f90543792403bf0ffb3ead59d0d8cc Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Tue, 12 Dec 2006 11:56:36 -0800 Subject: [IA64] Take defensive stance on ia64_pal_get_brand_info() Stephane thought he saw a problem here (but was just confused by the return value from ia64_pal_get_brand_info()). But we should be more defensive here in case an prototype PAL for a future processor doesn't implement this PAL call. Signed-off-by: Tony Luck --- arch/ia64/kernel/setup.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index be398451d45c..ad567b8d432e 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c @@ -674,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); @@ -681,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); -- cgit v1.2.3-59-g8ed1b From 08ed38b68099f2a492196414b08a7f5dd8dc3537 Mon Sep 17 00:00:00 2001 From: Tony Luck Date: Tue, 14 Nov 2006 09:33:38 -0800 Subject: [IA64] enable trap code on slot 1 Because slot 1 of one instr bundle crosses border of two consecutive 8-bytes, kprobe on slot 1 is disabled. This patch enables kprobe on slot1, it only replaces higher 8-bytes of the instruction bundle and changes the exception code to ignore the low 12 bits of the break number (which is across the border in the lower 8-bytes of the bundle). For those instructions which must execute regardless qp bits, kprobe on slot 1 is still disabled. Signed-off-by: bibo,mao Signed-off-by: Tony Luck --- arch/ia64/kernel/jprobes.S | 3 ++- arch/ia64/kernel/kprobes.c | 51 +++++++++++++++++++++++++++++++++------------- include/asm-ia64/break.h | 4 ++-- include/asm-ia64/kprobes.h | 1 + 4 files changed, 42 insertions(+), 17 deletions(-) diff --git a/arch/ia64/kernel/jprobes.S b/arch/ia64/kernel/jprobes.S index 5cd6226f44f2..621630256c4a 100644 --- a/arch/ia64/kernel/jprobes.S +++ b/arch/ia64/kernel/jprobes.S @@ -45,13 +45,14 @@ * to the correct location. */ #include +#include /* * 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 76e778951e20..8406d24d516b 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 @@ -296,12 +297,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; } @@ -458,23 +453,49 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) 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 +828,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/include/asm-ia64/break.h b/include/asm-ia64/break.h index 8167828edc4b..f03402039896 100644 --- a/include/asm-ia64/break.h +++ b/include/asm-ia64/break.h @@ -12,8 +12,8 @@ * OS-specific debug break numbers: */ #define __IA64_BREAK_KDB 0x80100 -#define __IA64_BREAK_KPROBE 0x80200 -#define __IA64_BREAK_JPROBE 0x80300 +#define __IA64_BREAK_KPROBE 0x81000 /* .. 0x81fff */ +#define __IA64_BREAK_JPROBE 0x82000 /* * OS-specific break numbers: diff --git a/include/asm-ia64/kprobes.h b/include/asm-ia64/kprobes.h index 1b45b71c79b9..828ae00e47c1 100644 --- a/include/asm-ia64/kprobes.h +++ b/include/asm-ia64/kprobes.h @@ -115,6 +115,7 @@ struct arch_specific_insn { #define INST_FLAG_BREAK_INST 4 unsigned long inst_flag; unsigned short target_br_reg; + unsigned short slot; }; extern int kprobe_exceptions_notify(struct notifier_block *self, -- cgit v1.2.3-59-g8ed1b From df3e0d1c69c097f54588d720d39efdcdf31e3c24 Mon Sep 17 00:00:00 2001 From: "bibo,mao" Date: Tue, 12 Dec 2006 12:04:42 -0800 Subject: [IA64] kprobe clears qp bits for special instructions On IA64 there exists some special instructions which always need to be executed regradless of qp bits, such as com.crel.unc, tbit.trel.unc etc. This patch clears qp bits when inserting kprobe trap code and disables probepoint on slot 1 for these special instructions. Signed-off-by: bibo,mao Signed-off-by: Tony Luck --- arch/ia64/kernel/kprobes.c | 175 +++++++++++++++++++++++++++++++-------------- 1 file changed, 122 insertions(+), 53 deletions(-) diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c index 8406d24d516b..6cb56dd4056d 100644 --- a/arch/ia64/kernel/kprobes.c +++ b/arch/ia64/kernel/kprobes.c @@ -128,48 +128,6 @@ static void __kprobes update_kprobe_inst_flag(uint template, uint slot, return; } -/* - * 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 @@ -206,6 +164,119 @@ out: return ctype_unc; } +/* + * 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. @@ -213,20 +284,17 @@ out: 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: @@ -422,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; @@ -436,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) @@ -446,7 +515,7 @@ 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; } -- cgit v1.2.3-59-g8ed1b