Commit 445722f9 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 3641b536 df3e0d1c
......@@ -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;
......
......@@ -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
......
......@@ -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
......
/*
* 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;
}
......@@ -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)
/*
......
......@@ -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
......@@ -127,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
......@@ -205,6 +164,119 @@ static uint __kprobes is_cmp_ctype_unc_inst(uint template, uint slot,
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.
......@@ -212,20 +284,17 @@ static uint __kprobes is_cmp_ctype_unc_inst(uint template, uint 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;
......
......@@ -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;
......
......@@ -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
......
......@@ -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);
......
......@@ -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()
{
......
......@@ -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,
......
......@@ -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;
......
......@@ -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 */
......
......@@ -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
......
......@@ -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 */
......
......@@ -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,
......
......@@ -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:
......
......@@ -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,
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment