diff options
Diffstat (limited to 'arch/sparc64')
32 files changed, 504 insertions, 716 deletions
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index 7c88263256a..36b4b7ab9cf 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig @@ -17,6 +17,7 @@ config SPARC64 select HAVE_LMB select HAVE_ARCH_KGDB select USE_GENERIC_SMP_HELPERS if SMP + select HAVE_ARCH_TRACEHOOK config GENERIC_TIME bool @@ -230,6 +231,7 @@ endmenu config NUMA bool "NUMA support" + depends on SMP config NODES_SHIFT int diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c index c55f0293eac..dd5c7bf8761 100644 --- a/arch/sparc64/kernel/auxio.c +++ b/arch/sparc64/kernel/auxio.c @@ -9,9 +9,9 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/ioport.h> +#include <linux/of_device.h> #include <asm/prom.h> -#include <asm/of_device.h> #include <asm/io.h> #include <asm/auxio.h> diff --git a/arch/sparc64/kernel/compat_audit.c b/arch/sparc64/kernel/compat_audit.c index c1979482aa9..c831b0a4e66 100644 --- a/arch/sparc64/kernel/compat_audit.c +++ b/arch/sparc64/kernel/compat_audit.c @@ -1,4 +1,4 @@ -#include <asm-sparc/unistd.h> +#include <asm/unistd_32.h> unsigned sparc32_dir_class[] = { #include <asm-generic/audit_dir_write.h> diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c index 4d58d7ce708..60d36d14255 100644 --- a/arch/sparc64/kernel/ebus.c +++ b/arch/sparc64/kernel/ebus.c @@ -14,13 +14,13 @@ #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/pci.h> +#include <linux/of_device.h> #include <asm/system.h> #include <asm/page.h> #include <asm/ebus.h> #include <asm/oplib.h> #include <asm/prom.h> -#include <asm/of_device.h> #include <asm/bpp.h> #include <asm/irq.h> #include <asm/io.h> diff --git a/arch/sparc64/kernel/entry.h b/arch/sparc64/kernel/entry.h index 32fbab62085..fc294a29289 100644 --- a/arch/sparc64/kernel/entry.h +++ b/arch/sparc64/kernel/entry.h @@ -22,8 +22,7 @@ extern void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long thread_info_flags); -extern asmlinkage void syscall_trace(struct pt_regs *regs, - int syscall_exit_p); +extern asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p); extern void bad_trap_tl1(struct pt_regs *regs, long lvl); diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index c481673d249..7495bc77468 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -7,6 +7,7 @@ #include <linux/module.h> #include <linux/sched.h> +#include <linux/linkage.h> #include <linux/ptrace.h> #include <linux/errno.h> #include <linux/kernel_stat.h> @@ -682,10 +683,32 @@ void ack_bad_irq(unsigned int virt_irq) ino, virt_irq); } +void *hardirq_stack[NR_CPUS]; +void *softirq_stack[NR_CPUS]; + +static __attribute__((always_inline)) void *set_hardirq_stack(void) +{ + void *orig_sp, *sp = hardirq_stack[smp_processor_id()]; + + __asm__ __volatile__("mov %%sp, %0" : "=r" (orig_sp)); + if (orig_sp < sp || + orig_sp > (sp + THREAD_SIZE)) { + sp += THREAD_SIZE - 192 - STACK_BIAS; + __asm__ __volatile__("mov %0, %%sp" : : "r" (sp)); + } + + return orig_sp; +} +static __attribute__((always_inline)) void restore_hardirq_stack(void *orig_sp) +{ + __asm__ __volatile__("mov %0, %%sp" : : "r" (orig_sp)); +} + void handler_irq(int irq, struct pt_regs *regs) { unsigned long pstate, bucket_pa; struct pt_regs *old_regs; + void *orig_sp; clear_softint(1 << irq); @@ -703,6 +726,8 @@ void handler_irq(int irq, struct pt_regs *regs) "i" (PSTATE_IE) : "memory"); + orig_sp = set_hardirq_stack(); + while (bucket_pa) { struct irq_desc *desc; unsigned long next_pa; @@ -719,10 +744,38 @@ void handler_irq(int irq, struct pt_regs *regs) bucket_pa = next_pa; } + restore_hardirq_stack(orig_sp); + irq_exit(); set_irq_regs(old_regs); } +void do_softirq(void) +{ + unsigned long flags; + + if (in_interrupt()) + return; + + local_irq_save(flags); + + if (local_softirq_pending()) { + void *orig_sp, *sp = softirq_stack[smp_processor_id()]; + + sp += THREAD_SIZE - 192 - STACK_BIAS; + + __asm__ __volatile__("mov %%sp, %0\n\t" + "mov %1, %%sp" + : "=&r" (orig_sp) + : "r" (sp)); + __do_softirq(); + __asm__ __volatile__("mov %0, %%sp" + : : "r" (orig_sp)); + } + + local_irq_restore(flags); +} + #ifdef CONFIG_HOTPLUG_CPU void fixup_irqs(void) { @@ -740,6 +793,8 @@ void fixup_irqs(void) } spin_unlock_irqrestore(&irq_desc[irq].lock, flags); } + + tick_ops->disable_irq(); } #endif @@ -812,7 +867,7 @@ static void kill_prom_timer(void) : "g1", "g2"); } -void init_irqwork_curcpu(void) +void notrace init_irqwork_curcpu(void) { int cpu = hard_smp_processor_id(); @@ -843,7 +898,7 @@ static void __cpuinit register_one_mondo(unsigned long paddr, unsigned long type } } -void __cpuinit sun4v_register_mondo_queues(int this_cpu) +void __cpuinit notrace sun4v_register_mondo_queues(int this_cpu) { struct trap_per_cpu *tb = &trap_block[this_cpu]; @@ -915,12 +970,18 @@ static void __init sun4v_init_mondo_queues(void) alloc_one_mondo(&tb->nonresum_mondo_pa, tb->nonresum_qmask); alloc_one_kbuf(&tb->nonresum_kernel_buf_pa, tb->nonresum_qmask); + } +} + +static void __init init_send_mondo_info(void) +{ + int cpu; + + for_each_possible_cpu(cpu) { + struct trap_per_cpu *tb = &trap_block[cpu]; init_cpu_send_mondo_info(tb); } - - /* Load up the boot cpu's entries. */ - sun4v_register_mondo_queues(hard_smp_processor_id()); } static struct irqaction timer_irq_action = { @@ -949,6 +1010,13 @@ void __init init_IRQ(void) if (tlb_type == hypervisor) sun4v_init_mondo_queues(); + init_send_mondo_info(); + + if (tlb_type == hypervisor) { + /* Load up the boot cpu's entries. */ + sun4v_register_mondo_queues(hard_smp_processor_id()); + } + /* We need to clear any IRQ's pending in the soft interrupt * registers, a spurious one could be left around from the * PROM timer which we just disabled. diff --git a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c index f43b5d75535..201a6e547e4 100644 --- a/arch/sparc64/kernel/kprobes.c +++ b/arch/sparc64/kernel/kprobes.c @@ -478,9 +478,9 @@ int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) return 0; } -/* Called with kretprobe_lock held. The value stored in the return - * address register is actually 2 instructions before where the - * callee will return to. Sequences usually look something like this +/* The value stored in the return address register is actually 2 + * instructions before where the callee will return to. + * Sequences usually look something like this * * call some_function <--- return register points here * nop <--- call delay slot @@ -512,8 +512,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline; INIT_HLIST_HEAD(&empty_rp); - spin_lock_irqsave(&kretprobe_lock, flags); - head = kretprobe_inst_table_head(current); + kretprobe_hash_lock(current, &head, &flags); /* * It is possible to have multiple instances associated with a given @@ -553,7 +552,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) regs->tnpc = orig_ret_address + 4; reset_current_kprobe(); - spin_unlock_irqrestore(&kretprobe_lock, flags); + kretprobe_hash_unlock(current, &flags); preempt_enable_no_resched(); hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) { diff --git a/arch/sparc64/kernel/kstack.h b/arch/sparc64/kernel/kstack.h new file mode 100644 index 00000000000..4248d969272 --- /dev/null +++ b/arch/sparc64/kernel/kstack.h @@ -0,0 +1,60 @@ +#ifndef _KSTACK_H +#define _KSTACK_H + +#include <linux/thread_info.h> +#include <linux/sched.h> +#include <asm/ptrace.h> +#include <asm/irq.h> + +/* SP must be STACK_BIAS adjusted already. */ +static inline bool kstack_valid(struct thread_info *tp, unsigned long sp) +{ + unsigned long base = (unsigned long) tp; + + if (sp >= (base + sizeof(struct thread_info)) && + sp <= (base + THREAD_SIZE - sizeof(struct sparc_stackf))) + return true; + + if (hardirq_stack[tp->cpu]) { + base = (unsigned long) hardirq_stack[tp->cpu]; + if (sp >= base && + sp <= (base + THREAD_SIZE - sizeof(struct sparc_stackf))) + return true; + base = (unsigned long) softirq_stack[tp->cpu]; + if (sp >= base && + sp <= (base + THREAD_SIZE - sizeof(struct sparc_stackf))) + return true; + } + return false; +} + +/* Does "regs" point to a valid pt_regs trap frame? */ +static inline bool kstack_is_trap_frame(struct thread_info *tp, struct pt_regs *regs) +{ + unsigned long base = (unsigned long) tp; + unsigned long addr = (unsigned long) regs; + + if (addr >= base && + addr <= (base + THREAD_SIZE - sizeof(*regs))) + goto check_magic; + + if (hardirq_stack[tp->cpu]) { + base = (unsigned long) hardirq_stack[tp->cpu]; + if (addr >= base && + addr <= (base + THREAD_SIZE - sizeof(*regs))) + goto check_magic; + base = (unsigned long) softirq_stack[tp->cpu]; + if (addr >= base && + addr <= (base + THREAD_SIZE - sizeof(*regs))) + goto check_magic; + } + return false; + +check_magic: + if ((regs->magic & ~0x1ff) == PT_REGS_MAGIC) + return true; + return false; + +} + +#endif /* _KSTACK_H */ diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 4fd48ab7dda..f845f150f56 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c @@ -56,9 +56,6 @@ struct of_device *of_find_device_by_node(struct device_node *dp) EXPORT_SYMBOL(of_find_device_by_node); #ifdef CONFIG_PCI -struct bus_type isa_bus_type; -EXPORT_SYMBOL(isa_bus_type); - struct bus_type ebus_bus_type; EXPORT_SYMBOL(ebus_bus_type); #endif @@ -99,7 +96,7 @@ struct of_bus { int *addrc, int *sizec); int (*map)(u32 *addr, const u32 *range, int na, int ns, int pna); - unsigned int (*get_flags)(const u32 *addr); + unsigned long (*get_flags)(const u32 *addr, unsigned long); }; /* @@ -159,8 +156,10 @@ static int of_bus_default_map(u32 *addr, const u32 *range, return 0; } -static unsigned int of_bus_default_get_flags(const u32 *addr) +static unsigned long of_bus_default_get_flags(const u32 *addr, unsigned long flags) { + if (flags) + return flags; return IORESOURCE_MEM; } @@ -252,17 +251,21 @@ static int of_bus_pci_map(u32 *addr, const u32 *range, return 0; } -static unsigned int of_bus_pci_get_flags(const u32 *addr) +static unsigned long of_bus_pci_get_flags(const u32 *addr, unsigned long flags) { - unsigned int flags = 0; u32 w = addr[0]; + /* For PCI, we override whatever child busses may have used. */ + flags = 0; switch((w >> 24) & 0x03) { case 0x01: flags |= IORESOURCE_IO; + break; + case 0x02: /* 32 bits */ case 0x03: /* 64 bits */ flags |= IORESOURCE_MEM; + break; } if (w & 0x40000000) flags |= IORESOURCE_PREFETCH; @@ -481,10 +484,10 @@ static void __init build_device_resources(struct of_device *op, int pna, pns; size = of_read_addr(reg + na, ns); - flags = bus->get_flags(reg); - memcpy(addr, reg, na * 4); + flags = bus->get_flags(addr, 0); + if (use_1to1_mapping(pp)) { result = of_read_addr(addr, na); goto build_res; @@ -509,6 +512,8 @@ static void __init build_device_resources(struct of_device *op, dna, dns, pna)) break; + flags = pbus->get_flags(addr, flags); + dna = pna; dns = pns; dbus = pbus; @@ -842,8 +847,6 @@ static int __init of_bus_driver_init(void) err = of_bus_type_init(&of_platform_bus_type, "of"); #ifdef CONFIG_PCI if (!err) - err = of_bus_type_init(&isa_bus_type, "isa"); - if (!err) err = of_bus_type_init(&ebus_bus_type, "ebus"); #endif #ifdef CONFIG_SBUS diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c index 19fa621d6a6..09a5ec200c6 100644 --- a/arch/sparc64/kernel/pci_common.c +++ b/arch/sparc64/kernel/pci_common.c @@ -8,9 +8,9 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/device.h> +#include <linux/of_device.h> #include <asm/prom.h> -#include <asm/of_device.h> #include <asm/oplib.h> #include "pci_impl.h" diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c index 994dbe0603d..f85b6bebb0b 100644 --- a/arch/sparc64/kernel/pci_psycho.c +++ b/arch/sparc64/kernel/pci_psycho.c @@ -11,12 +11,12 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/interrupt.h> +#include <linux/of_device.h> #include <asm/iommu.h> #include <asm/irq.h> #include <asm/starfire.h> #include <asm/prom.h> -#include <asm/of_device.h> #include <asm/oplib.h> #include "pci_impl.h" @@ -575,7 +575,7 @@ static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm, int is_pbm { unsigned long csr_reg, csr, csr_error_bits; irqreturn_t ret = IRQ_NONE; - u16 stat; + u16 stat, *addr; if (is_pbm_a) { csr_reg = pbm->controller_regs + PSYCHO_PCIA_CTRL; @@ -597,7 +597,9 @@ static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm, int is_pbm printk("%s: PCI SERR signal asserted.\n", pbm->name); ret = IRQ_HANDLED; } - pci_read_config_word(pbm->pci_bus->self, PCI_STATUS, &stat); + addr = psycho_pci_config_mkaddr(pbm, pbm->pci_first_busno, + 0, PCI_STATUS); + pci_config_read16(addr, &stat); if (stat & (PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT | PCI_STATUS_REC_TARGET_ABORT | @@ -605,7 +607,7 @@ static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm, int is_pbm PCI_STATUS_SIG_SYSTEM_ERROR)) { printk("%s: PCI bus error, PCI_STATUS[%04x]\n", pbm->name, stat); - pci_write_config_word(pbm->pci_bus->self, PCI_STATUS, 0xffff); + pci_config_write16(addr, 0xffff); ret = IRQ_HANDLED; } return ret; @@ -744,16 +746,16 @@ static void psycho_register_error_handlers(struct pci_pbm_info *pbm) * the second will just error out since we do not pass in * IRQF_SHARED. */ - err = request_irq(op->irqs[1], psycho_ue_intr, 0, + err = request_irq(op->irqs[1], psycho_ue_intr, IRQF_SHARED, "PSYCHO_UE", pbm); - err = request_irq(op->irqs[2], psycho_ce_intr, 0, + err = request_irq(op->irqs[2], psycho_ce_intr, IRQF_SHARED, "PSYCHO_CE", pbm); /* This one, however, ought not to fail. We can just warn * about it since the system can still operate properly even * if this fails. */ - err = request_irq(op->irqs[0], psycho_pcierr_intr, 0, + err = request_irq(op->irqs[0], psycho_pcierr_intr, IRQF_SHARED, "PSYCHO_PCIERR", pbm); if (err) printk(KERN_WARNING "%s: Could not register PCIERR, " diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c index 4c34195baf3..ade5184e75d 100644 --- a/arch/sparc64/kernel/pci_sabre.c +++ b/arch/sparc64/kernel/pci_sabre.c @@ -11,6 +11,7 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/interrupt.h> +#include <linux/of_device.h> #include <asm/apb.h> #include <asm/iommu.h> @@ -18,7 +19,6 @@ #include <asm/smp.h> #include <asm/oplib.h> #include <asm/prom.h> -#include <asm/of_device.h> #include "pci_impl.h" #include "iommu_common.h" diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c index 615edd9c8e2..9248c6737f0 100644 --- a/arch/sparc64/kernel/pci_schizo.c +++ b/arch/sparc64/kernel/pci_schizo.c @@ -9,13 +9,13 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/interrupt.h> +#include <linux/of_device.h> #include <asm/iommu.h> #include <asm/irq.h> #include <asm/upa.h> #include <asm/pstate.h> #include <asm/prom.h> -#include <asm/of_device.h> #include <asm/oplib.h> #include "pci_impl.h" diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c index eae8ca2a6ba..3bb987a6d03 100644 --- a/arch/sparc64/kernel/power.c +++ b/arch/sparc64/kernel/power.c @@ -13,11 +13,11 @@ #include <linux/pm.h> #include <linux/syscalls.h> #include <linux/reboot.h> +#include <linux/of_device.h> #include <asm/system.h> #include <asm/auxio.h> #include <asm/prom.h> -#include <asm/of_device.h> #include <asm/io.h> #include <asm/sstate.h> #include <asm/reboot.h> diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c index 8a9cd3e165b..15f4178592e 100644 --- a/arch/sparc64/kernel/process.c +++ b/arch/sparc64/kernel/process.c @@ -52,7 +52,7 @@ #include <asm/irq_regs.h> #include <asm/smp.h> -/* #define VERBOSE_SHOWREGS */ +#include "kstack.h" static void sparc64_yield(int cpu) { @@ -213,22 +213,8 @@ static void show_regwindow(struct pt_regs *regs) printk("I7: <%pS>\n", (void *) rwk->ins[7]); } -#ifdef CONFIG_SMP -static DEFINE_SPINLOCK(regdump_lock); -#endif - -void __show_regs(struct pt_regs * regs) +void show_regs(struct pt_regs *regs) { -#ifdef CONFIG_SMP - unsigned long flags; - - /* Protect against xcall ipis which might lead to livelock on the lock */ - __asm__ __volatile__("rdpr %%pstate, %0\n\t" - "wrpr %0, %1, %%pstate" - : "=r" (flags) - : "i" (PSTATE_IE)); - spin_lock(®dump_lock); -#endif printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %08x %s\n", regs->tstate, regs->tpc, regs->tnpc, regs->y, print_tainted()); printk("TPC: <%pS>\n", (void *) regs->tpc); @@ -246,61 +232,8 @@ void __show_regs(struct pt_regs * regs) regs->u_regs[15]); printk("RPC: <%pS>\n", (void *) regs->u_regs[15]); show_regwindow(regs); -#ifdef CONFIG_SMP - spin_unlock(®dump_lock); - __asm__ __volatile__("wrpr %0, 0, %%pstate" - : : "r" (flags)); -#endif -} - -#ifdef VERBOSE_SHOWREGS -static void idump_from_user (unsigned int *pc) -{ - int i; - int code; - - if((((unsigned long) pc) & 3)) - return; - - pc -= 3; - for(i = -3; i < 6; i++) { - get_user(code, pc); - printk("%c%08x%c",i?' ':'<',code,i?' ':'>'); - pc++; - } - printk("\n"); -} -#endif - -void show_regs(struct pt_regs *regs) -{ -#ifdef VERBOSE_SHOWREGS - extern long etrap, etraptl1; -#endif - __show_regs(regs); -#if 0 -#ifdef CONFIG_SMP - { - extern void smp_report_regs(void); - - smp_report_regs(); - } -#endif -#endif - -#ifdef VERBOSE_SHOWREGS - if (regs->tpc >= &etrap && regs->tpc < &etraptl1 && - regs->u_regs[14] >= (long)current - PAGE_SIZE && - regs->u_regs[14] < (long)current + 6 * PAGE_SIZE) { - printk ("*********parent**********\n"); - __show_regs((struct pt_regs *)(regs->u_regs[14] + PTREGS_OFF)); - idump_from_user(((struct pt_regs *)(regs->u_regs[14] + PTREGS_OFF))->tpc); - printk ("*********endpar**********\n"); - } -#endif } -#ifdef CONFIG_MAGIC_SYSRQ struct global_reg_snapshot global_reg_snapshot[NR_CPUS]; static DEFINE_SPINLOCK(global_reg_snapshot_lock); @@ -315,14 +248,22 @@ static void __global_reg_self(struct thread_info *tp, struct pt_regs *regs, global_reg_snapshot[this_cpu].o7 = regs->u_regs[UREG_I7]; if (regs->tstate & TSTATE_PRIV) { + struct thread_info *tp = current_thread_info(); struct reg_window *rw; rw = (struct reg_window *) (regs->u_regs[UREG_FP] + STACK_BIAS); - global_reg_snapshot[this_cpu].i7 = rw->ins[6]; - } else + if (kstack_valid(tp, (unsigned long) rw)) { + global_reg_snapshot[this_cpu].i7 = rw->ins[7]; + rw = (struct reg_window *) + (rw->ins[6] + STACK_BIAS); + if (kstack_valid(tp, (unsigned long) rw)) + global_reg_snapshot[this_cpu].rpc = rw->ins[7]; + } + } else { global_reg_snapshot[this_cpu].i7 = 0; - + global_reg_snapshot[this_cpu].rpc = 0; + } global_reg_snapshot[this_cpu].thread = tp; } @@ -341,7 +282,7 @@ static void __global_reg_poll(struct global_reg_snapshot *gp) } } -static void sysrq_handle_globreg(int key, struct tty_struct *tty) +void __trigger_all_cpu_backtrace(void) { struct thread_info *tp = current_thread_info(); struct pt_regs *regs = get_irq_regs(); @@ -375,13 +316,14 @@ static void sysrq_handle_globreg(int key, struct tty_struct *tty) ((tp && tp->task) ? tp->task->pid : -1)); if (gp->tstate & TSTATE_PRIV) { - printk(" TPC[%pS] O7[%pS] I7[%pS]\n", + printk(" TPC[%pS] O7[%pS] I7[%pS] RPC[%pS]\n", (void *) gp->tpc, (void *) gp->o7, - (void *) gp->i7); + (void *) gp->i7, + (void *) gp->rpc); } else { - printk(" TPC[%lx] O7[%lx] I7[%lx]\n", - gp->tpc, gp->o7, gp->i7); + printk(" TPC[%lx] O7[%lx] I7[%lx] RPC[%lx]\n", + gp->tpc, gp->o7, gp->i7, gp->rpc); } } @@ -390,6 +332,13 @@ static void sysrq_handle_globreg(int key, struct tty_struct *tty) spin_unlock_irqrestore(&global_reg_snapshot_lock, flags); } +#ifdef CONFIG_MAGIC_SYSRQ + +static void sysrq_handle_globreg(int key, struct tty_struct *tty) +{ + __trigger_all_cpu_backtrace(); +} + static struct sysrq_key_op sparc_globalreg_op = { .handler = sysrq_handle_globreg, .help_msg = "Globalregs", @@ -868,7 +817,7 @@ out: unsigned long get_wchan(struct task_struct *task) { unsigned long pc, fp, bias = 0; - unsigned long thread_info_base; + struct thread_info *tp; struct reg_window *rw; unsigned long ret = 0; int count = 0; @@ -877,14 +826,12 @@ unsigned long get_wchan(struct task_struct *task) task->state == TASK_RUNNING) goto out; - thread_info_base = (unsigned long) task_stack_page(task); + tp = task_thread_info(task); bias = STACK_BIAS; fp = task_thread_info(task)->ksp + bias; do { - /* Bogus frame pointer? */ - if (fp < (thread_info_base + sizeof(struct thread_info)) || - fp >= (thread_info_base + THREAD_SIZE)) + if (!kstack_valid(tp, fp)) break; rw = (struct reg_window *) fp; pc = rw->ins[7]; diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c index ed03a18d3b3..7151513f156 100644 --- a/arch/sparc64/kernel/prom.c +++ b/arch/sparc64/kernel/prom.c @@ -21,9 +21,9 @@ #include <linux/mm.h> #include <linux/module.h> #include <linux/lmb.h> +#include <linux/of_device.h> #include <asm/prom.h> -#include <asm/of_device.h> #include <asm/oplib.h> #include <asm/irq.h> #include <asm/asi.h> @@ -156,55 +156,11 @@ static unsigned long psycho_pcislot_imap_offset(unsigned long ino) return PSYCHO_IMAP_B_SLOT0 + (slot * 8); } -#define PSYCHO_IMAP_SCSI 0x1000UL -#define PSYCHO_IMAP_ETH 0x1008UL -#define PSYCHO_IMAP_BPP 0x1010UL -#define PSYCHO_IMAP_AU_REC 0x1018UL -#define PSYCHO_IMAP_AU_PLAY 0x1020UL -#define PSYCHO_IMAP_PFAIL 0x1028UL -#define PSYCHO_IMAP_KMS 0x1030UL -#define PSYCHO_IMAP_FLPY 0x1038UL -#define PSYCHO_IMAP_SHW 0x1040UL -#define PSYCHO_IMAP_KBD 0x1048UL -#define PSYCHO_IMAP_MS 0x1050UL -#define PSYCHO_IMAP_SER 0x1058UL -#define PSYCHO_IMAP_TIM0 0x1060UL -#define PSYCHO_IMAP_TIM1 0x1068UL -#define PSYCHO_IMAP_UE 0x1070UL -#define PSYCHO_IMAP_CE 0x1078UL -#define PSYCHO_IMAP_A_ERR 0x1080UL -#define PSYCHO_IMAP_B_ERR 0x1088UL -#define PSYCHO_IMAP_PMGMT 0x1090UL -#define PSYCHO_IMAP_GFX 0x1098UL -#define PSYCHO_IMAP_EUPA 0x10a0UL - -static unsigned long __psycho_onboard_imap_off[] = { -/*0x20*/ PSYCHO_IMAP_SCSI, -/*0x21*/ PSYCHO_IMAP_ETH, -/*0x22*/ PSYCHO_IMAP_BPP, -/*0x23*/ PSYCHO_IMAP_AU_REC, -/*0x24*/ PSYCHO_IMAP_AU_PLAY, -/*0x25*/ PSYCHO_IMAP_PFAIL, -/*0x26*/ PSYCHO_IMAP_KMS, -/*0x27*/ PSYCHO_IMAP_FLPY, -/*0x28*/ PSYCHO_IMAP_SHW, -/*0x29*/ PSYCHO_IMAP_KBD, -/*0x2a*/ PSYCHO_IMAP_MS, -/*0x2b*/ PSYCHO_IMAP_SER, -/*0x2c*/ PSYCHO_IMAP_TIM0, -/*0x2d*/ PSYCHO_IMAP_TIM1, -/*0x2e*/ PSYCHO_IMAP_UE, -/*0x2f*/ PSYCHO_IMAP_CE, -/*0x30*/ PSYCHO_IMAP_A_ERR, -/*0x31*/ PSYCHO_IMAP_B_ERR, -/*0x32*/ PSYCHO_IMAP_PMGMT, -/*0x33*/ PSYCHO_IMAP_GFX, -/*0x34*/ PSYCHO_IMAP_EUPA, -}; +#define PSYCHO_OBIO_IMAP_BASE 0x1000UL + #define PSYCHO_ONBOARD_IRQ_BASE 0x20 -#define PSYCHO_ONBOARD_IRQ_LAST 0x34 #define psycho_onboard_imap_offset(__ino) \ - __psycho_onboard_imap_off[(__ino) - PSYCHO_ONBOARD_IRQ_BASE] + (PSYCHO_OBIO_IMAP_BASE + (((__ino) & 0x1f) << 3)) #define PSYCHO_ICLR_A_SLOT0 0x1400UL #define PSYCHO_ICLR_SCSI 0x1800UL @@ -228,10 +184,6 @@ static unsigned int psycho_irq_build(struct device_node *dp, imap_off = psycho_pcislot_imap_offset(ino); } else { /* Onboard device */ - if (ino > PSYCHO_ONBOARD_IRQ_LAST) { - prom_printf("psycho_irq_build: Wacky INO [%x]\n", ino); - prom_halt(); - } imap_off = psycho_onboard_imap_offset(ino); } @@ -318,23 +270,6 @@ static void sabre_wsync_handler(unsigned int ino, void *_arg1, void *_arg2) #define SABRE_IMAP_A_SLOT0 0x0c00UL #define SABRE_IMAP_B_SLOT0 0x0c20UL -#define SABRE_IMAP_SCSI 0x1000UL -#define SABRE_IMAP_ETH 0x1008UL -#define SABRE_IMAP_BPP 0x1010UL -#define SABRE_IMAP_AU_REC 0x1018UL -#define SABRE_IMAP_AU_PLAY 0x1020UL -#define SABRE_IMAP_PFAIL 0x1028UL -#define SABRE_IMAP_KMS 0x1030UL -#define SABRE_IMAP_FLPY 0x1038UL -#define SABRE_IMAP_SHW 0x1040UL -#define SABRE_IMAP_KBD 0x1048UL -#define SABRE_IMAP_MS 0x1050UL -#define SABRE_IMAP_SER 0x1058UL -#define SABRE_IMAP_UE 0x1070UL -#define SABRE_IMAP_CE 0x1078UL -#define SABRE_IMAP_PCIERR 0x1080UL -#define SABRE_IMAP_GFX 0x1098UL -#define SABRE_IMAP_EUPA 0x10a0UL #define SABRE_ICLR_A_SLOT0 0x1400UL #define SABRE_ICLR_B_SLOT0 0x1480UL #define SABRE_ICLR_SCSI 0x1800UL @@ -364,33 +299,10 @@ static unsigned long sabre_pcislot_imap_offset(unsigned long ino) return SABRE_IMAP_B_SLOT0 + (slot * 8); } -static unsigned long __sabre_onboard_imap_off[] = { -/*0x20*/ SABRE_IMAP_SCSI, -/*0x21*/ SABRE_IMAP_ETH, -/*0x22*/ SABRE_IMAP_BPP, -/*0x23*/ SABRE_IMAP_AU_REC, -/*0x24*/ SABRE_IMAP_AU_PLAY, -/*0x25*/ SABRE_IMAP_PFAIL, -/*0x26*/ SABRE_IMAP_KMS, -/*0x27*/ SABRE_IMAP_FLPY, -/*0x28*/ SABRE_IMAP_SHW, -/*0x29*/ SABRE_IMAP_KBD, -/*0x2a*/ SABRE_IMAP_MS, -/*0x2b*/ SABRE_IMAP_SER, -/*0x2c*/ 0 /* reserved */, -/*0x2d*/ 0 /* reserved */, -/*0x2e*/ SABRE_IMAP_UE, -/*0x2f*/ SABRE_IMAP_CE, -/*0x30*/ SABRE_IMAP_PCIERR, -/*0x31*/ 0 /* reserved */, -/*0x32*/ 0 /* reserved */, -/*0x33*/ SABRE_IMAP_GFX, -/*0x34*/ SABRE_IMAP_EUPA, -}; -#define SABRE_ONBOARD_IRQ_BASE 0x20 -#define SABRE_ONBOARD_IRQ_LAST 0x30 +#define SABRE_OBIO_IMAP_BASE 0x1000UL +#define SABRE_ONBOARD_IRQ_BASE 0x20 #define sabre_onboard_imap_offset(__ino) \ - __sabre_onboard_imap_off[(__ino) - SABRE_ONBOARD_IRQ_BASE] + (SABRE_OBIO_IMAP_BASE + (((__ino) & 0x1f) << 3)) #define sabre_iclr_offset(ino) \ ((ino & 0x20) ? (SABRE_ICLR_SCSI + (((ino) & 0x1f) << 3)) : \ @@ -453,10 +365,6 @@ static unsigned int sabre_irq_build(struct device_node *dp, imap_off = sabre_pcislot_imap_offset(ino); } else { /* onboard device */ - if (ino > SABRE_ONBOARD_IRQ_LAST) { - prom_printf("sabre_irq_build: Wacky INO [%x]\n", ino); - prom_halt(); - } imap_off = sabre_onboard_imap_offset(ino); } diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c index f6c9fc92921..10306e476e3 100644 --- a/arch/sparc64/kernel/ptrace.c +++ b/arch/sparc64/kernel/ptrace.c @@ -23,6 +23,7 @@ #include <linux/audit.h> #include <linux/signal.h> #include <linux/regset.h> +#include <linux/tracehook.h> #include <linux/compat.h> #include <linux/elf.h> @@ -442,7 +443,7 @@ static const struct user_regset sparc64_regsets[] = { */ [REGSET_GENERAL] = { .core_note_type = NT_PRSTATUS, - .n = 36 * sizeof(u64), + .n = 36, .size = sizeof(u64), .align = sizeof(u64), .get = genregs64_get, .set = genregs64_set }, @@ -454,7 +455,7 @@ static const struct user_regset sparc64_regsets[] = { */ [REGSET_FP] = { .core_note_type = NT_PRFPREG, - .n = 35 * sizeof(u64), + .n = 35, .size = sizeof(u64), .align = sizeof(u64), .get = fpregs64_get, .set = fpregs64_set }, @@ -800,7 +801,7 @@ static const struct user_regset sparc32_regsets[] = { */ [REGSET_GENERAL] = { .core_note_type = NT_PRSTATUS, - .n = 38 * sizeof(u32), + .n = 38, .size = sizeof(u32), .align = sizeof(u32), .get = genregs32_get, .set = genregs32_set }, @@ -816,7 +817,7 @@ static const struct user_regset sparc32_regsets[] = { */ [REGSET_FP] = { .core_note_type = NT_PRFPREG, - .n = 99 * sizeof(u32), + .n = 99, .size = sizeof(u32), .align = sizeof(u32), .get = fpregs32_get, .set = fpregs32_set }, @@ -1049,8 +1050,10 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) return ret; } -asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p) +asmlinkage int syscall_trace(struct pt_regs *regs, int syscall_exit_p) { + int ret = 0; + /* do the secure computing check first */ secure_computing(regs->u_regs[UREG_G1]); @@ -1064,27 +1067,14 @@ asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p) audit_syscall_exit(result, regs->u_regs[UREG_I0]); } - if (!(current->ptrace & PT_PTRACED)) - goto out; - - if (!test_thread_flag(TIF_SYSCALL_TRACE)) - goto out; - - ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0)); - - /* - * this isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl - */ - if (current->exit_code) { - send_sig(current->exit_code, current, 1); - current->exit_code = 0; + if (test_thread_flag(TIF_SYSCALL_TRACE)) { + if (syscall_exit_p) + tracehook_report_syscall_exit(regs, 0); + else + ret = tracehook_report_syscall_entry(regs); } -out: - if (unlikely(current->audit_context) && !syscall_exit_p) + if (unlikely(current->audit_context) && !syscall_exit_p && !ret) audit_syscall_entry((test_thread_flag(TIF_32BIT) ? AUDIT_ARCH_SPARC : AUDIT_ARCH_SPARC64), @@ -1093,4 +1083,6 @@ out: regs->u_regs[UREG_I1], regs->u_regs[UREG_I2], regs->u_regs[UREG_I3]); + + return ret; } diff --git a/arch/sparc64/kernel/rtrap.S b/arch/sparc64/kernel/rtrap.S index c6fc695fe1f..97a993c1f7f 100644 --- a/arch/sparc64/kernel/rtrap.S +++ b/arch/sparc64/kernel/rtrap.S @@ -46,7 +46,7 @@ __handle_user_windows: wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate ldx [%g6 + TI_FLAGS], %l0 -1: andcc %l0, _TIF_SIGPENDING, %g0 +1: andcc %l0, _TIF_DO_NOTIFY_RESUME_MASK, %g0 be,pt %xcc, __handle_user_windows_continue nop mov %l5, %o1 @@ -86,7 +86,7 @@ __handle_perfctrs: wrpr %g0, RTRAP_PSTATE, %pstate wrpr %g0, RTRAP_PSTATE_IRQOFF, %pstate ldx [%g6 + TI_FLAGS], %l0 -1: andcc %l0, _TIF_SIGPENDING, %g0 +1: andcc %l0, _TIF_DO_NOTIFY_RESUME_MASK, %g0 be,pt %xcc, __handle_perfctrs_continue sethi %hi(TSTATE_PEF), %o0 @@ -195,7 +195,7 @@ __handle_preemption_continue: andcc %l1, %o0, %g0 andcc %l0, _TIF_NEED_RESCHED, %g0 bne,pn %xcc, __handle_preemption - andcc %l0, _TIF_SIGPENDING, %g0 + andcc %l0, _TIF_DO_NOTIFY_RESUME_MASK, %g0 bne,pn %xcc, __handle_signal __handle_signal_continue: ldub [%g6 + TI_WSAVED], %o2 diff --git a/arch/sparc64/kernel/signal.c b/arch/sparc64/kernel/signal.c index 9667e96fd51..ec82d76dc6f 100644 --- a/arch/sparc64/kernel/signal.c +++ b/arch/sparc64/kernel/signal.c @@ -2,7 +2,7 @@ * arch/sparc64/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Copyright (C) 1995, 2008 David S. Miller (davem@davemloft.net) * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -17,6 +17,7 @@ #include <linux/errno.h> #include <linux/wait.h> #include <linux/ptrace.h> +#include <linux/tracehook.h> #include <linux/unistd.h> #include <linux/mm.h> #include <linux/tty.h> @@ -89,7 +90,9 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs) err |= __get_user(regs->u_regs[UREG_G4], (&(*grp)[MC_G4])); err |= __get_user(regs->u_regs[UREG_G5], (&(*grp)[MC_G5])); err |= __get_user(regs->u_regs[UREG_G6], (&(*grp)[MC_G6])); - err |= __get_user(regs->u_regs[UREG_G7], (&(*grp)[MC_G7])); + + /* Skip %g7 as that's the thread register in userspace. */ + err |= __get_user(regs->u_regs[UREG_I0], (&(*grp)[MC_O0])); err |= __get_user(regs->u_regs[UREG_I1], (&(*grp)[MC_O1])); err |= __get_user(regs->u_regs[UREG_I2], (&(*grp)[MC_O2])); @@ -574,6 +577,8 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) * clear the TS_RESTORE_SIGMASK flag. */ current_thread_info()->status &= ~TS_RESTORE_SIGMASK; + + tracehook_signal_handler(signr, &info, &ka, regs, 0); return; } if (restart_syscall && @@ -605,4 +610,8 @@ void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long { if (thread_info_flags & _TIF_SIGPENDING) do_signal(regs, orig_i0); + if (thread_info_flags & _TIF_NOTIFY_RESUME) { + clear_thread_flag(TIF_NOTIFY_RESUME); + tracehook_notify_resume(regs); + } } diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c index 97cdd1bf4a1..ba5b09ad666 100644 --- a/arch/sparc64/kernel/signal32.c +++ b/arch/sparc64/kernel/signal32.c @@ -19,6 +19,7 @@ #include <linux/binfmts.h> #include <linux/compat.h> #include <linux/bitops.h> +#include <linux/tracehook.h> #include <asm/uaccess.h> #include <asm/ptrace.h> @@ -794,6 +795,8 @@ void do_signal32(sigset_t *oldset, struct pt_regs * regs, * clear the TS_RESTORE_SIGMASK flag. */ current_thread_info()->status &= ~TS_RESTORE_SIGMASK; + + tracehook_signal_handler(signr, &info, &ka, regs, 0); return; } if (restart_syscall && diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 7cf72b4bb10..2be166c544c 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -80,8 +80,6 @@ void smp_bogo(struct seq_file *m) i, cpu_data(i).clock_tick); } -static __cacheline_aligned_in_smp DEFINE_SPINLOCK(call_lock); - extern void setup_sparc64_timer(void); static volatile unsigned long callin_flag = 0; @@ -120,9 +118,9 @@ void __cpuinit smp_callin(void) while (!cpu_isset(cpuid, smp_commenced_mask)) rmb(); - spin_lock(&call_lock); + ipi_call_lock(); cpu_set(cpuid, cpu_online_map); - spin_unlock(&call_lock); + ipi_call_unlock(); /* idle thread is expected to have preempt disabled */ preempt_disable(); @@ -459,27 +457,35 @@ again: } } -static inline void spitfire_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask) +static void spitfire_xcall_deliver(struct trap_per_cpu *tb, int cnt) { + u64 *mondo, data0, data1, data2; + u16 *cpu_list; u64 pstate; int i; __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); - for_each_cpu_mask(i, mask) - spitfire_xcall_helper(data0, data1, data2, pstate, i); + cpu_list = __va(tb->cpu_list_pa); + mondo = __va(tb->cpu_mondo_block_pa); + data0 = mondo[0]; + data1 = mondo[1]; + data2 = mondo[2]; + for (i = 0; i < cnt; i++) + spitfire_xcall_helper(data0, data1, data2, pstate, cpu_list[i]); } /* Cheetah now allows to send the whole 64-bytes of data in the interrupt * packet, but we have no use for that. However we do take advantage of * the new pipelining feature (ie. dispatch to multiple cpus simultaneously). */ -static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask) +static void cheetah_xcall_deliver(struct trap_per_cpu *tb, int cnt) { - u64 pstate, ver, busy_mask; int nack_busy_id, is_jbus, need_more; + u64 *mondo, pstate, ver, busy_mask; + u16 *cpu_list; - if (cpus_empty(mask)) - return; + cpu_list = __va(tb->cpu_list_pa); + mondo = __va(tb->cpu_mondo_block_pa); /* Unfortunately, someone at Sun had the brilliant idea to make the * busy/nack fields hard-coded by ITID number for this Ultra-III @@ -502,7 +508,7 @@ retry: "stxa %2, [%5] %6\n\t" "membar #Sync\n\t" : /* no outputs */ - : "r" (data0), "r" (data1), "r" (data2), + : "r" (mondo[0]), "r" (mondo[1]), "r" (mondo[2]), "r" (0x40), "r" (0x50), "r" (0x60), "i" (ASI_INTR_W)); @@ -511,11 +517,16 @@ retry: { int i; - for_each_cpu_mask(i, mask) { - u64 target = (i << 14) | 0x70; + for (i = 0; i < cnt; i++) { + u64 target, nr; + + nr = cpu_list[i]; + if (nr == 0xffff) + continue; + target = (nr << 14) | 0x70; if (is_jbus) { - busy_mask |= (0x1UL << (i * 2)); + busy_mask |= (0x1UL << (nr * 2)); } else { target |= (nack_busy_id << 24); busy_mask |= (0x1UL << @@ -549,11 +560,13 @@ retry: __asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate)); if (unlikely(need_more)) { - int i, cnt = 0; - for_each_cpu_mask(i, mask) { - cpu_clear(i, mask); - cnt++; - if (cnt == 32) + int i, this_cnt = 0; + for (i = 0; i < cnt; i++) { + if (cpu_list[i] == 0xffff) + continue; + cpu_list[i] = 0xffff; + this_cnt++; + if (this_cnt == 32) break; } goto retry; @@ -584,16 +597,20 @@ retry: /* Clear out the mask bits for cpus which did not * NACK us. */ - for_each_cpu_mask(i, mask) { - u64 check_mask; + for (i = 0; i < cnt; i++) { + u64 check_mask, nr; + + nr = cpu_list[i]; + if (nr == 0xffff) + continue; if (is_jbus) - check_mask = (0x2UL << (2*i)); + check_mask = (0x2UL << (2*nr)); else check_mask = (0x2UL << this_busy_nack); if ((dispatch_stat & check_mask) == 0) - cpu_clear(i, mask); + cpu_list[i] = 0xffff; this_busy_nack += 2; if (this_busy_nack == 64) break; @@ -605,47 +622,17 @@ retry: } /* Multi-cpu list version. */ -static void hypervisor_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask) +static void hypervisor_xcall_deliver(struct trap_per_cpu *tb, int cnt) { - struct trap_per_cpu *tb; + int retries, this_cpu, prev_sent, i, saw_cpu_error; + unsigned long status; u16 *cpu_list; - u64 *mondo; - cpumask_t error_mask; - unsigned long flags, status; - int cnt, retries, this_cpu, prev_sent, i; - - if (cpus_empty(mask)) - return; - - /* We have to do this whole thing with interrupts fully disabled. - * Otherwise if we send an xcall from interrupt context it will - * corrupt both our mondo block and cpu list state. - * - * One consequence of this is that we cannot use timeout mechanisms - * that depend upon interrupts being delivered locally. So, for - * example, we cannot sample jiffies and expect it to advance. - * - * Fortunately, udelay() uses %stick/%tick so we can use that. - */ - local_irq_save(flags); this_cpu = smp_processor_id(); - tb = &trap_block[this_cpu]; - - mondo = __va(tb->cpu_mondo_block_pa); - mondo[0] = data0; - mondo[1] = data1; - mondo[2] = data2; - wmb(); cpu_list = __va(tb->cpu_list_pa); - /* Setup the initial cpu list. */ - cnt = 0; - for_each_cpu_mask(i, mask) - cpu_list[cnt++] = i; - - cpus_clear(error_mask); + saw_cpu_error = 0; retries = 0; prev_sent = 0; do { @@ -690,10 +677,9 @@ static void hypervisor_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t continue; err = sun4v_cpu_state(cpu); - if (err >= 0 && - err == HV_CPU_STATE_ERROR) { + if (err == HV_CPU_STATE_ERROR) { + saw_cpu_error = (cpu + 1); cpu_list[i] = 0xffff; - cpu_set(cpu, error_mask); } } } else if (unlikely(status != HV_EWOULDBLOCK)) @@ -717,32 +703,24 @@ static void hypervisor_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t } } while (1); - local_irq_restore(flags); - - if (unlikely(!cpus_empty(error_mask))) + if (unlikely(saw_cpu_error)) goto fatal_mondo_cpu_error; return; fatal_mondo_cpu_error: printk(KERN_CRIT "CPU[%d]: SUN4V mondo cpu error, some target cpus " - "were in error state\n", - this_cpu); - printk(KERN_CRIT "CPU[%d]: Error mask [ ", this_cpu); - for_each_cpu_mask(i, error_mask) - printk("%d ", i); - printk("]\n"); + "(including %d) were in error state\n", + this_cpu, saw_cpu_error - 1); return; fatal_mondo_timeout: - local_irq_restore(flags); printk(KERN_CRIT "CPU[%d]: SUN4V mondo timeout, no forward " " progress after %d retries.\n", this_cpu, retries); goto dump_cpu_list_and_out; fatal_mondo_error: - local_irq_restore(flags); printk(KERN_CRIT "CPU[%d]: Unexpected SUN4V mondo error %lu\n", this_cpu, status); printk(KERN_CRIT "CPU[%d]: Args were cnt(%d) cpulist_pa(%lx) " @@ -756,58 +734,93 @@ dump_cpu_list_and_out: printk("]\n"); } -/* Send cross call to all processors mentioned in MASK - * except self. +static void (*xcall_deliver_impl)(struct trap_per_cpu *, int); + +static void xcall_deliver(u64 data0, u64 data1, u64 data2, const cpumask_t *mask) +{ + struct trap_per_cpu *tb; + int this_cpu, i, cnt; + unsigned long flags; + u16 *cpu_list; + u64 *mondo; + + /* We have to do this whole thing with interrupts fully disabled. + * Otherwise if we send an xcall from interrupt context it will + * corrupt both our mondo block and cpu list state. + * + * One consequence of this is that we cannot use timeout mechanisms + * that depend upon interrupts being delivered locally. So, for + * example, we cannot sample jiffies and expect it to advance. + * + * Fortunately, udelay() uses %stick/%tick so we can use that. + */ + local_irq_save(flags); + + this_cpu = smp_processor_id(); + tb = &trap_block[this_cpu]; + + mondo = __va(tb->cpu_mondo_block_pa); + mondo[0] = data0; + mondo[1] = data1; + mondo[2] = data2; + wmb(); + + cpu_list = __va(tb->cpu_list_pa); + + /* Setup the initial cpu list. */ + cnt = 0; + for_each_cpu_mask_nr(i, *mask) { + if (i == this_cpu || !cpu_online(i)) + continue; + cpu_list[cnt++] = i; + } + + if (cnt) + xcall_deliver_impl(tb, cnt); + + local_irq_restore(flags); +} + +/* Send cross call to all processors mentioned in MASK_P + * except self. Really, there are only two cases currently, + * "&cpu_online_map" and "&mm->cpu_vm_mask". */ -static void smp_cross_call_masked(unsigned long *func, u32 ctx, u64 data1, u64 data2, cpumask_t mask) +static void smp_cross_call_masked(unsigned long *func, u32 ctx, u64 data1, u64 data2, const cpumask_t *mask) { u64 data0 = (((u64)ctx)<<32 | (((u64)func) & 0xffffffff)); - int this_cpu = get_cpu(); - cpus_and(mask, mask, cpu_online_map); - cpu_clear(this_cpu, mask); - - if (tlb_type == spitfire) - spitfire_xcall_deliver(data0, data1, data2, mask); - else if (tlb_type == cheetah || tlb_type == cheetah_plus) - cheetah_xcall_deliver(data0, data1, data2, mask); - else - hypervisor_xcall_deliver(data0, data1, data2, mask); - /* NOTE: Caller runs local copy on master. */ + xcall_deliver(data0, data1, data2, mask); +} - put_cpu(); +/* Send cross call to all processors except self. */ +static void smp_cross_call(unsigned long *func, u32 ctx, u64 data1, u64 data2) +{ + smp_cross_call_masked(func, ctx, data1, data2, &cpu_online_map); } extern unsigned long xcall_sync_tick; static void smp_start_sync_tick_client(int cpu) { - cpumask_t mask = cpumask_of_cpu(cpu); - - smp_cross_call_masked(&xcall_sync_tick, - 0, 0, 0, mask); + xcall_deliver((u64) &xcall_sync_tick, 0, 0, + &cpumask_of_cpu(cpu)); } extern unsigned long xcall_call_function; void arch_send_call_function_ipi(cpumask_t mask) { - smp_cross_call_masked(&xcall_call_function, 0, 0, 0, mask); + xcall_deliver((u64) &xcall_call_function, 0, 0, &mask); } extern unsigned long xcall_call_function_single; void arch_send_call_function_single_ipi(int cpu) { - cpumask_t mask = cpumask_of_cpu(cpu); - - smp_cross_call_masked(&xcall_call_function_single, 0, 0, 0, mask); + xcall_deliver((u64) &xcall_call_function_single, 0, 0, + &cpumask_of_cpu(cpu)); } -/* Send cross call to all processors except self. */ -#define smp_cross_call(func, ctx, data1, data2) \ - smp_cross_call_masked(func, ctx, data1, data2, cpu_online_map) - void smp_call_function_client(int irq, struct pt_regs *regs) { clear_softint(1 << irq); @@ -843,10 +856,7 @@ void smp_tsb_sync(struct mm_struct *mm) extern unsigned long xcall_flush_tlb_mm; extern unsigned long xcall_flush_tlb_pending; extern unsigned long xcall_flush_tlb_kernel_range; -extern unsigned long xcall_report_regs; -#ifdef CONFIG_MAGIC_SYSRQ extern unsigned long xcall_fetch_glob_regs; -#endif extern unsigned long xcall_receive_signal; extern unsigned long xcall_new_mmu_context_version; #ifdef CONFIG_KGDB @@ -878,7 +888,6 @@ static inline void __local_flush_dcache_page(struct page *page) void smp_flush_dcache_page_impl(struct page *page, int cpu) { - cpumask_t mask = cpumask_of_cpu(cpu); int this_cpu; if (tlb_type == hypervisor) @@ -894,29 +903,24 @@ void smp_flush_dcache_page_impl(struct page *page, int cpu) __local_flush_dcache_page(page); } else if (cpu_online(cpu)) { void *pg_addr = page_address(page); - u64 data0; + u64 data0 = 0; if (tlb_type == spitfire) { - data0 = - ((u64)&xcall_flush_dcache_page_spitfire); + data0 = ((u64)&xcall_flush_dcache_page_spitfire); if (page_mapping(page) != NULL) data0 |= ((u64)1 << 32); - spitfire_xcall_deliver(data0, - __pa(pg_addr), - (u64) pg_addr, - mask); } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { #ifdef DCACHE_ALIASING_POSSIBLE - data0 = - ((u64)&xcall_flush_dcache_page_cheetah); - cheetah_xcall_deliver(data0, - __pa(pg_addr), - 0, mask); + data0 = ((u64)&xcall_flush_dcache_page_cheetah); #endif } + if (data0) { + xcall_deliver(data0, __pa(pg_addr), + (u64) pg_addr, &cpumask_of_cpu(cpu)); #ifdef CONFIG_DEBUG_DCFLUSH - atomic_inc(&dcpage_flushes_xcall); + atomic_inc(&dcpage_flushes_xcall); #endif + } } put_cpu(); @@ -924,66 +928,41 @@ void smp_flush_dcache_page_impl(struct page *page, int cpu) void flush_dcache_page_all(struct mm_struct *mm, struct page *page) { - void *pg_addr = page_address(page); - cpumask_t mask = cpu_online_map; - u64 data0; + void *pg_addr; int this_cpu; + u64 data0; if (tlb_type == hypervisor) return; this_cpu = get_cpu(); - cpu_clear(this_cpu, mask); - #ifdef CONFIG_DEBUG_DCFLUSH atomic_inc(&dcpage_flushes); #endif - if (cpus_empty(mask)) - goto flush_self; + data0 = 0; + pg_addr = page_address(page); if (tlb_type == spitfire) { data0 = ((u64)&xcall_flush_dcache_page_spitfire); if (page_mapping(page) != NULL) data0 |= ((u64)1 << 32); - spitfire_xcall_deliver(data0, - __pa(pg_addr), - (u64) pg_addr, - mask); } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { #ifdef DCACHE_ALIASING_POSSIBLE data0 = ((u64)&xcall_flush_dcache_page_cheetah); - cheetah_xcall_deliver(data0, - __pa(pg_addr), - 0, mask); #endif } + if (data0) { + xcall_deliver(data0, __pa(pg_addr), + (u64) pg_addr, &cpu_online_map); #ifdef CONFIG_DEBUG_DCFLUSH - atomic_inc(&dcpage_flushes_xcall); + atomic_inc(&dcpage_flushes_xcall); #endif - flush_self: + } __local_flush_dcache_page(page); put_cpu(); } -static void __smp_receive_signal_mask(cpumask_t mask) -{ - smp_cross_call_masked(&xcall_receive_signal, 0, 0, 0, mask); -} - -void smp_receive_signal(int cpu) -{ - cpumask_t mask = cpumask_of_cpu(cpu); - - if (cpu_online(cpu)) - __smp_receive_signal_mask(mask); -} - -void smp_receive_signal_client(int irq, struct pt_regs *regs) -{ - clear_softint(1 << irq); -} - void smp_new_mmu_context_version_client(int irq, struct pt_regs *regs) { struct mm_struct *mm; @@ -1022,17 +1001,10 @@ void kgdb_roundup_cpus(unsigned long flags) } #endif -void smp_report_regs(void) -{ - smp_cross_call(&xcall_report_regs, 0, 0, 0); -} - -#ifdef CONFIG_MAGIC_SYSRQ void smp_fetch_global_regs(void) { smp_cross_call(&xcall_fetch_glob_regs, 0, 0, 0); } -#endif /* We know that the window frames of the user have been flushed * to the stack before we get here because all callers of us @@ -1089,7 +1061,7 @@ void smp_flush_tlb_mm(struct mm_struct *mm) smp_cross_call_masked(&xcall_flush_tlb_mm, ctx, 0, 0, - mm->cpu_vm_mask); + &mm->cpu_vm_mask); local_flush_and_out: __flush_tlb_mm(ctx, SECONDARY_CONTEXT); @@ -1107,7 +1079,7 @@ void smp_flush_tlb_pending(struct mm_struct *mm, unsigned long nr, unsigned long else smp_cross_call_masked(&xcall_flush_tlb_pending, ctx, nr, (unsigned long) vaddrs, - mm->cpu_vm_mask); + &mm->cpu_vm_mask); __flush_tlb_pending(ctx, nr, vaddrs); @@ -1208,6 +1180,16 @@ void __devinit smp_prepare_boot_cpu(void) { } +void __init smp_setup_processor_id(void) +{ + if (tlb_type == spitfire) + xcall_deliver_impl = spitfire_xcall_deliver; + else if (tlb_type == cheetah || tlb_type == cheetah_plus) + xcall_deliver_impl = cheetah_xcall_deliver; + else + xcall_deliver_impl = hypervisor_xcall_deliver; +} + void __devinit smp_fill_in_sib_core_maps(void) { unsigned int i; @@ -1321,10 +1303,6 @@ int __cpu_disable(void) c->core_id = 0; c->proc_id = -1; - spin_lock(&call_lock); - cpu_clear(cpu, cpu_online_map); - spin_unlock(&call_lock); - smp_wmb(); /* Make sure no interrupts point to this cpu. */ @@ -1334,6 +1312,10 @@ int __cpu_disable(void) mdelay(1); local_irq_disable(); + ipi_call_lock(); + cpu_clear(cpu, cpu_online_map); + ipi_call_unlock(); + return 0; } @@ -1376,7 +1358,13 @@ void __init smp_cpus_done(unsigned int max_cpus) void smp_send_reschedule(int cpu) { - smp_receive_signal(cpu); + xcall_deliver((u64) &xcall_receive_signal, 0, 0, + &cpumask_of_cpu(cpu)); +} + +void smp_receive_signal_client(int irq, struct pt_regs *regs) +{ + clear_softint(1 << irq); } /* This is a nop because we capture all other cpus diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 504e678ee12..0804f71df6c 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -68,7 +68,6 @@ extern void *__memscan_zero(void *, size_t); extern void *__memscan_generic(void *, int, size_t); extern int __memcmp(const void *, const void *, __kernel_size_t); extern __kernel_size_t strlen(const char *); -extern void show_regs(struct pt_regs *); extern void syscall_trace(struct pt_regs *, int); extern void sys_sigsuspend(void); extern int compat_sys_ioctl(unsigned int fd, unsigned int cmd, u32 arg); diff --git a/arch/sparc64/kernel/stacktrace.c b/arch/sparc64/kernel/stacktrace.c index b3e3737750d..4e21d4a57d3 100644 --- a/arch/sparc64/kernel/stacktrace.c +++ b/arch/sparc64/kernel/stacktrace.c @@ -5,10 +5,12 @@ #include <asm/ptrace.h> #include <asm/stacktrace.h> +#include "kstack.h" + void save_stack_trace(struct stack_trace *trace) { - unsigned long ksp, fp, thread_base; struct thread_info *tp = task_thread_info(current); + unsigned long ksp, fp; stack_trace_flush(); @@ -18,21 +20,18 @@ void save_stack_trace(struct stack_trace *trace) ); fp = ksp + STACK_BIAS; - thread_base = (unsigned long) tp; do { struct sparc_stackf *sf; struct pt_regs *regs; unsigned long pc; - /* Bogus frame pointer? */ - if (fp < (thread_base + sizeof(struct thread_info)) || - fp >= (thread_base + THREAD_SIZE)) + if (!kstack_valid(tp, fp)) break; sf = (struct sparc_stackf *) fp; regs = (struct pt_regs *) (sf + 1); - if ((regs->magic & ~0x1ff) == PT_REGS_MAGIC) { + if (kstack_is_trap_frame(tp, regs)) { if (!(regs->tstate & TSTATE_PRIV)) break; pc = regs->tpc; diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c index 97b77fb5c50..3d118531baf 100644 --- a/arch/sparc64/kernel/sys_sparc32.c +++ b/arch/sparc64/kernel/sys_sparc32.c @@ -58,182 +58,6 @@ #include <asm/mmu_context.h> #include <asm/compat_signal.h> -asmlinkage long sys32_chown16(const char __user * filename, u16 user, u16 group) -{ - return sys_chown(filename, low2highuid(user), low2highgid(group)); -} - -asmlinkage long sys32_lchown16(const char __user * filename, u16 user, u16 group) -{ - return sys_lchown(filename, low2highuid(user), low2highgid(group)); -} - -asmlinkage long sys32_fchown16(unsigned int fd, u16 user, u16 group) -{ - return sys_fchown(fd, low2highuid(user), low2highgid(group)); -} - -asmlinkage long sys32_setregid16(u16 rgid, u16 egid) -{ - return sys_setregid(low2highgid(rgid), low2highgid(egid)); -} - -asmlinkage long sys32_setgid16(u16 gid) -{ - return sys_setgid((gid_t)gid); -} - -asmlinkage long sys32_setreuid16(u16 ruid, u16 euid) -{ - return sys_setreuid(low2highuid(ruid), low2highuid(euid)); -} - -asmlinkage long sys32_setuid16(u16 uid) -{ - return sys_setuid((uid_t)uid); -} - -asmlinkage long sys32_setresuid16(u16 ruid, u16 euid, u16 suid) -{ - return sys_setresuid(low2highuid(ruid), low2highuid(euid), - low2highuid(suid)); -} - -asmlinkage long sys32_getresuid16(u16 __user *ruid, u16 __user *euid, u16 __user *suid) -{ - int retval; - - if (!(retval = put_user(high2lowuid(current->uid), ruid)) && - !(retval = put_user(high2lowuid(current->euid), euid))) - retval = put_user(high2lowuid(current->suid), suid); - - return retval; -} - -asmlinkage long sys32_setresgid16(u16 rgid, u16 egid, u16 sgid) -{ - return sys_setresgid(low2highgid(rgid), low2highgid(egid), - low2highgid(sgid)); -} - -asmlinkage long sys32_getresgid16(u16 __user *rgid, u16 __user *egid, u16 __user *sgid) -{ - int retval; - - if (!(retval = put_user(high2lowgid(current->gid), rgid)) && - !(retval = put_user(high2lowgid(current->egid), egid))) - retval = put_user(high2lowgid(current->sgid), sgid); - - return retval; -} - -asmlinkage long sys32_setfsuid16(u16 uid) -{ - return sys_setfsuid((uid_t)uid); -} - -asmlinkage long sys32_setfsgid16(u16 gid) -{ - return sys_setfsgid((gid_t)gid); -} - -static int groups16_to_user(u16 __user *grouplist, struct group_info *group_info) -{ - int i; - u16 group; - - for (i = 0; i < group_info->ngroups; i++) { - group = (u16)GROUP_AT(group_info, i); - if (put_user(group, grouplist+i)) - return -EFAULT; - } - - return 0; -} - -static int groups16_from_user(struct group_info *group_info, u16 __user *grouplist) -{ - int i; - u16 group; - - for (i = 0; i < group_info->ngroups; i++) { - if (get_user(group, grouplist+i)) - return -EFAULT; - GROUP_AT(group_info, i) = (gid_t)group; - } - - return 0; -} - -asmlinkage long sys32_getgroups16(int gidsetsize, u16 __user *grouplist) -{ - int i; - - if (gidsetsize < 0) - return -EINVAL; - - get_group_info(current->group_info); - i = current->group_info->ngroups; - if (gidsetsize) { - if (i > gidsetsize) { - i = -EINVAL; - goto out; - } - if (groups16_to_user(grouplist, current->group_info)) { - i = -EFAULT; - goto out; - } - } -out: - put_group_info(current->group_info); - return i; -} - -asmlinkage long sys32_setgroups16(int gidsetsize, u16 __user *grouplist) -{ - struct group_info *group_info; - int retval; - - if (!capable(CAP_SETGID)) - return -EPERM; - if ((unsigned)gidsetsize > NGROUPS_MAX) - return -EINVAL; - - group_info = groups_alloc(gidsetsize); - if (!group_info) - return -ENOMEM; - retval = groups16_from_user(group_info, grouplist); - if (retval) { - put_group_info(group_info); - return retval; - } - - retval = set_current_groups(group_info); - put_group_info(group_info); - - return retval; -} - -asmlinkage long sys32_getuid16(void) -{ - return high2lowuid(current->uid); -} - -asmlinkage long sys32_geteuid16(void) -{ - return high2lowuid(current->euid); -} - -asmlinkage long sys32_getgid16(void) -{ - return high2lowgid(current->gid); -} - -asmlinkage long sys32_getegid16(void) -{ - return high2lowgid(current->egid); -} - /* 32-bit timeval and related flotsam. */ static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i) diff --git a/arch/sparc64/kernel/syscalls.S b/arch/sparc64/kernel/syscalls.S index db19ed67acf..a2f24270ed8 100644 --- a/arch/sparc64/kernel/syscalls.S +++ b/arch/sparc64/kernel/syscalls.S @@ -162,6 +162,8 @@ linux_syscall_trace32: add %sp, PTREGS_OFF, %o0 call syscall_trace clr %o1 + brnz,pn %o0, 3f + mov -ENOSYS, %o0 srl %i0, 0, %o0 srl %i4, 0, %o4 srl %i1, 0, %o1 @@ -173,6 +175,8 @@ linux_syscall_trace: add %sp, PTREGS_OFF, %o0 call syscall_trace clr %o1 + brnz,pn %o0, 3f + mov -ENOSYS, %o0 mov %i0, %o0 mov %i1, %o1 mov %i2, %o2 diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index 8b5282d433c..0fdbf3ba956 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -20,21 +20,21 @@ sys_call_table32: /*0*/ .word sys_restart_syscall, sys32_exit, sys_fork, sys_read, sys_write /*5*/ .word sys32_open, sys_close, sys32_wait4, sys32_creat, sys_link -/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys32_chown16, sys32_mknod -/*15*/ .word sys_chmod, sys32_lchown16, sparc_brk, sys32_perfctr, sys32_lseek -/*20*/ .word sys_getpid, sys_capget, sys_capset, sys32_setuid16, sys32_getuid16 +/*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_chown16, sys32_mknod +/*15*/ .word sys_chmod, sys_lchown16, sparc_brk, sys32_perfctr, sys32_lseek +/*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid16, sys_getuid16 /*25*/ .word sys32_vmsplice, compat_sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause /*30*/ .word compat_sys_utime, sys_lchown, sys_fchown, sys32_access, sys32_nice .word sys_chown, sys_sync, sys32_kill, compat_sys_newstat, sys32_sendfile /*40*/ .word compat_sys_newlstat, sys_dup, sys_pipe, compat_sys_times, sys_getuid - .word sys32_umount, sys32_setgid16, sys32_getgid16, sys32_signal, sys32_geteuid16 -/*50*/ .word sys32_getegid16, sys_acct, sys_nis_syscall, sys_getgid, compat_sys_ioctl + .word sys32_umount, sys_setgid16, sys_getgid16, sys32_signal, sys_geteuid16 +/*50*/ .word sys_getegid16, sys_acct, sys_nis_syscall, sys_getgid, compat_sys_ioctl .word sys32_reboot, sys32_mmap2, sys_symlink, sys32_readlink, sys32_execve /*60*/ .word sys32_umask, sys_chroot, compat_sys_newfstat, compat_sys_fstat64, sys_getpagesize .word sys32_msync, sys_vfork, sys32_pread64, sys32_pwrite64, sys_geteuid /*70*/ .word sys_getegid, sys_mmap, sys_setreuid, sys_munmap, sys_mprotect - .word sys_madvise, sys_vhangup, sys32_truncate64, sys_mincore, sys32_getgroups16 -/*80*/ .word sys32_setgroups16, sys_getpgrp, sys32_setgroups, sys32_setitimer, sys32_ftruncate64 + .word sys_madvise, sys_vhangup, sys32_truncate64, sys_mincore, sys_getgroups16 +/*80*/ .word sys_setgroups16, sys_getpgrp, sys32_setgroups, sys32_setitimer, sys32_ftruncate64 .word sys32_swapon, sys32_getitimer, sys_setuid, sys32_sethostname, sys_setgid /*90*/ .word sys_dup2, sys_setfsuid, compat_sys_fcntl, sys32_select, sys_setfsgid .word sys_fsync, sys32_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall @@ -42,8 +42,8 @@ sys_call_table32: .word compat_sys_rt_sigtimedwait, sys32_rt_sigqueueinfo, compat_sys_rt_sigsuspend, sys_setresuid, sys_getresuid /*110*/ .word sys_setresgid, sys_getresgid, sys_setregid, sys_nis_syscall, sys_nis_syscall .word sys32_getgroups, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_getcwd -/*120*/ .word compat_sys_readv, compat_sys_writev, sys32_settimeofday, sys32_fchown16, sys_fchmod - .word sys_nis_syscall, sys32_setreuid16, sys32_setregid16, sys_rename, sys_truncate +/*120*/ .word compat_sys_readv, compat_sys_writev, sys32_settimeofday, sys_fchown16, sys_fchmod + .word sys_nis_syscall, sys_setreuid16, sys_setregid16, sys_rename, sys_truncate /*130*/ .word sys_ftruncate, sys_flock, compat_sys_lstat64, sys_nis_syscall, sys_nis_syscall .word sys_nis_syscall, sys32_mkdir, sys_rmdir, compat_sys_utimes, compat_sys_stat64 /*140*/ .word sys32_sendfile64, sys_nis_syscall, sys32_futex, sys_gettid, compat_sys_getrlimit @@ -63,7 +63,7 @@ sys_call_table32: /*210*/ .word sys32_fadvise64_64, sys32_tgkill, sys32_waitpid, sys_swapoff, compat_sys_sysinfo .word compat_sys_ipc, sys32_sigreturn, sys_clone, sys32_ioprio_get, compat_sys_adjtimex /*220*/ .word sys32_sigprocmask, sys_ni_syscall, sys32_delete_module, sys_ni_syscall, sys32_getpgid - .word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys32_setfsuid16, sys32_setfsgid16 + .word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid16, sys_setfsgid16 /*230*/ .word sys32_select, compat_sys_time, sys32_splice, compat_sys_stime, compat_sys_statfs64 .word compat_sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys32_mlockall /*240*/ .word sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys32_sched_setscheduler, sys32_sched_getscheduler @@ -81,7 +81,8 @@ sys_call_table32: /*300*/ .word compat_sys_set_robust_list, compat_sys_get_robust_list, compat_sys_migrate_pages, compat_sys_mbind, compat_sys_get_mempolicy .word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait /*310*/ .word compat_sys_utimensat, compat_sys_signalfd, sys_timerfd_create, sys_eventfd, compat_sys_fallocate - .word compat_sys_timerfd_settime, compat_sys_timerfd_gettime + .word compat_sys_timerfd_settime, compat_sys_timerfd_gettime, compat_sys_signalfd4, sys_eventfd2, sys_epoll_create1 +/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1 #endif /* CONFIG_COMPAT */ @@ -154,4 +155,5 @@ sys_call_table: /*300*/ .word sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy .word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait /*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate - .word sys_timerfd_settime, sys_timerfd_gettime + .word sys_timerfd_settime, sys_timerfd_gettime, sys_signalfd4, sys_eventfd2, sys_epoll_create1 +/*320*/ .word sys_dup3, sys_pipe2, sys_inotify_init1 diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index a0c6a97eec6..cc16fdcf98a 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -33,6 +33,7 @@ #include <linux/kernel_stat.h> #include <linux/clockchips.h> #include <linux/clocksource.h> +#include <linux/of_device.h> #include <asm/oplib.h> #include <asm/mostek.h> @@ -40,7 +41,6 @@ #include <asm/irq.h> #include <asm/io.h> #include <asm/prom.h> -#include <asm/of_device.h> #include <asm/starfire.h> #include <asm/smp.h> #include <asm/sections.h> diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c index bd30ecba563..c824df13f58 100644 --- a/arch/sparc64/kernel/traps.c +++ b/arch/sparc64/kernel/traps.c @@ -10,6 +10,7 @@ #include <linux/module.h> #include <linux/sched.h> +#include <linux/linkage.h> #include <linux/kernel.h> #include <linux/signal.h> #include <linux/smp.h> @@ -39,6 +40,7 @@ #include <asm/prom.h> #include "entry.h" +#include "kstack.h" /* When an irrecoverable trap occurs at tl > 0, the trap entry * code logs the trap state registers at every level in the trap @@ -1777,7 +1779,7 @@ static void sun4v_log_error(struct pt_regs *regs, struct sun4v_error_entry *ent, pfx, ent->err_raddr, ent->err_size, ent->err_cpu); - __show_regs(regs); + show_regs(regs); if ((cnt = atomic_read(ocnt)) != 0) { atomic_set(ocnt, 0); @@ -2115,14 +2117,12 @@ void show_stack(struct task_struct *tsk, unsigned long *_ksp) struct pt_regs *regs; unsigned long pc; - /* Bogus frame pointer? */ - if (fp < (thread_base + sizeof(struct thread_info)) || - fp >= (thread_base + THREAD_SIZE)) + if (!kstack_valid(tp, fp)) break; sf = (struct sparc_stackf *) fp; regs = (struct pt_regs *) (sf + 1); - if ((regs->magic & ~0x1ff) == PT_REGS_MAGIC) { + if (kstack_is_trap_frame(tp, regs)) { if (!(regs->tstate & TSTATE_PRIV)) break; pc = regs->tpc; @@ -2177,7 +2177,6 @@ static inline struct reg_window *kernel_stack_up(struct reg_window *rw) void die_if_kernel(char *str, struct pt_regs *regs) { static int die_counter; - extern void smp_report_regs(void); int count = 0; /* Amuse the user. */ @@ -2190,7 +2189,7 @@ void die_if_kernel(char *str, struct pt_regs *regs) printk("%s(%d): %s [#%d]\n", current->comm, task_pid_nr(current), str, ++die_counter); notify_die(DIE_OOPS, str, regs, 0, 255, SIGSEGV); __asm__ __volatile__("flushw"); - __show_regs(regs); + show_regs(regs); add_taint(TAINT_DIE); if (regs->tstate & TSTATE_PRIV) { struct reg_window *rw = (struct reg_window *) @@ -2215,11 +2214,6 @@ void die_if_kernel(char *str, struct pt_regs *regs) } user_instruction_dump ((unsigned int __user *) regs->tpc); } -#if 0 -#ifdef CONFIG_SMP - smp_report_regs(); -#endif -#endif if (regs->tstate & TSTATE_PRIV) do_exit(SIGKILL); do_exit(SIGSEGV); @@ -2460,7 +2454,7 @@ struct trap_per_cpu trap_block[NR_CPUS]; /* This can get invoked before sched_init() so play it super safe * and use hard_smp_processor_id(). */ -void init_cur_cpu_trap(struct thread_info *t) +void notrace init_cur_cpu_trap(struct thread_info *t) { int cpu = hard_smp_processor_id(); struct trap_per_cpu *p = &trap_block[cpu]; diff --git a/arch/sparc64/lib/mcount.S b/arch/sparc64/lib/mcount.S index 7735a7a6053..fad90ddb3a2 100644 --- a/arch/sparc64/lib/mcount.S +++ b/arch/sparc64/lib/mcount.S @@ -48,12 +48,45 @@ mcount: sub %g3, STACK_BIAS, %g3 cmp %sp, %g3 bg,pt %xcc, 1f - sethi %hi(panicstring), %g3 + nop + lduh [%g6 + TI_CPU], %g1 + sethi %hi(hardirq_stack), %g3 + or %g3, %lo(hardirq_stack), %g3 + sllx %g1, 3, %g1 + ldx [%g3 + %g1], %g7 + sub %g7, STACK_BIAS, %g7 + cmp %sp, %g7 + bleu,pt %xcc, 2f + sethi %hi(THREAD_SIZE), %g3 + add %g7, %g3, %g7 + cmp %sp, %g7 + blu,pn %xcc, 1f +2: sethi %hi(softirq_stack), %g3 + or %g3, %lo(softirq_stack), %g3 + ldx [%g3 + %g1], %g7 + cmp %sp, %g7 + bleu,pt %xcc, 2f + sethi %hi(THREAD_SIZE), %g3 + add %g7, %g3, %g7 + cmp %sp, %g7 + blu,pn %xcc, 1f + nop + /* If we are already on ovstack, don't hop onto it + * again, we are already trying to output the stack overflow + * message. + */ sethi %hi(ovstack), %g7 ! cant move to panic stack fast enough or %g7, %lo(ovstack), %g7 - add %g7, OVSTACKSIZE, %g7 + add %g7, OVSTACKSIZE, %g3 + sub %g3, STACK_BIAS + 192, %g3 sub %g7, STACK_BIAS, %g7 - mov %g7, %sp + cmp %sp, %g7 + blu,pn %xcc, 2f + cmp %sp, %g3 + bleu,pn %xcc, 1f + nop +2: mov %g3, %sp + sethi %hi(panicstring), %g3 call prom_printf or %g3, %lo(panicstring), %o0 call prom_halt diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index 71329747395..a41df7bef03 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -49,6 +49,7 @@ #include <asm/sstate.h> #include <asm/mdesc.h> #include <asm/cpudata.h> +#include <asm/irq.h> #define MAX_PHYS_ADDRESS (1UL << 42UL) #define KPTE_BITMAP_CHUNK_SZ (256UL * 1024UL * 1024UL) @@ -392,51 +393,6 @@ void __kprobes flush_icache_range(unsigned long start, unsigned long end) } } -void show_mem(void) -{ - unsigned long total = 0, reserved = 0; - unsigned long shared = 0, cached = 0; - pg_data_t *pgdat; - - printk(KERN_INFO "Mem-info:\n"); - show_free_areas(); - printk(KERN_INFO "Free swap: %6ldkB\n", - nr_swap_pages << (PAGE_SHIFT-10)); - for_each_online_pgdat(pgdat) { - unsigned long i, flags; - - pgdat_resize_lock(pgdat, &flags); - for (i = 0; i < pgdat->node_spanned_pages; i++) { - struct page *page = pgdat_page_nr(pgdat, i); - total++; - if (PageReserved(page)) - reserved++; - else if (PageSwapCache(page)) - cached++; - else if (page_count(page)) - shared += page_count(page) - 1; - } - pgdat_resize_unlock(pgdat, &flags); - } - - printk(KERN_INFO "%lu pages of RAM\n", total); - printk(KERN_INFO "%lu reserved pages\n", reserved); - printk(KERN_INFO "%lu pages shared\n", shared); - printk(KERN_INFO "%lu pages swap cached\n", cached); - - printk(KERN_INFO "%lu pages dirty\n", - global_page_state(NR_FILE_DIRTY)); - printk(KERN_INFO "%lu pages writeback\n", - global_page_state(NR_WRITEBACK)); - printk(KERN_INFO "%lu pages mapped\n", - global_page_state(NR_FILE_MAPPED)); - printk(KERN_INFO "%lu pages slab\n", - global_page_state(NR_SLAB_RECLAIMABLE) + - global_page_state(NR_SLAB_UNRECLAIMABLE)); - printk(KERN_INFO "%lu pages pagetables\n", - global_page_state(NR_PAGETABLE)); -} - void mmu_info(struct seq_file *m) { if (tlb_type == cheetah) @@ -840,6 +796,9 @@ static unsigned long nid_range(unsigned long start, unsigned long end, start += PAGE_SIZE; } + if (start > end) + start = end; + return start; } #else @@ -1767,8 +1726,7 @@ void __init paging_init(void) find_ramdisk(phys_base); - if (cmdline_memory_size) - lmb_enforce_memory_limit(phys_base + cmdline_memory_size); + lmb_enforce_memory_limit(cmdline_memory_size); lmb_analyze(); lmb_dump_all(); @@ -1816,6 +1774,16 @@ void __init paging_init(void) if (tlb_type == hypervisor) sun4v_mdesc_init(); + /* Once the OF device tree and MDESC have been setup, we know + * the list of possible cpus. Therefore we can allocate the + * IRQ stacks. + */ + for_each_possible_cpu(i) { + /* XXX Use node local allocations... XXX */ + softirq_stack[i] = __va(lmb_alloc(THREAD_SIZE, THREAD_SIZE)); + hardirq_stack[i] = __va(lmb_alloc(THREAD_SIZE, THREAD_SIZE)); + } + /* Setup bootmem... */ last_valid_pfn = end_pfn = bootmem_init(phys_base); @@ -1875,7 +1843,7 @@ static int pavail_rescan_ents __initdata; * memory list again, and make sure it provides at least as much * memory as 'pavail' does. */ -static void setup_valid_addr_bitmap_from_pavail(void) +static void __init setup_valid_addr_bitmap_from_pavail(void) { int i; @@ -1995,6 +1963,15 @@ void __init mem_init(void) void free_initmem(void) { unsigned long addr, initend; + int do_free = 1; + + /* If the physical memory maps were trimmed by kernel command + * line options, don't even try freeing this initmem stuff up. + * The kernel image could have been in the trimmed out region + * and if so the freeing below will free invalid page structs. + */ + if (cmdline_memory_size) + do_free = 0; /* * The init section is aligned to 8k in vmlinux.lds. Page align for >8k pagesizes. @@ -2009,13 +1986,16 @@ void free_initmem(void) ((unsigned long) __va(kern_base)) - ((unsigned long) KERNBASE)); memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE); - p = virt_to_page(page); - ClearPageReserved(p); - init_page_count(p); - __free_page(p); - num_physpages++; - totalram_pages++; + if (do_free) { + p = virt_to_page(page); + + ClearPageReserved(p); + init_page_count(p); + __free_page(p); + num_physpages++; + totalram_pages++; + } } } diff --git a/arch/sparc64/mm/tsb.c b/arch/sparc64/mm/tsb.c index 3547937b17a..587f8efb2e0 100644 --- a/arch/sparc64/mm/tsb.c +++ b/arch/sparc64/mm/tsb.c @@ -1,9 +1,10 @@ /* arch/sparc64/mm/tsb.c * - * Copyright (C) 2006 David S. Miller <davem@davemloft.net> + * Copyright (C) 2006, 2008 David S. Miller <davem@davemloft.net> */ #include <linux/kernel.h> +#include <linux/preempt.h> #include <asm/system.h> #include <asm/page.h> #include <asm/tlbflush.h> @@ -415,7 +416,9 @@ retry_tsb_alloc: tsb_context_switch(mm); /* Now force other processors to do the same. */ + preempt_disable(); smp_tsb_sync(mm); + preempt_enable(); /* Now it is safe to free the old tsb. */ kmem_cache_free(tsb_caches[old_cache_index], old_tsb); diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S index 4c8ca131ffa..86773e89dc1 100644 --- a/arch/sparc64/mm/ultra.S +++ b/arch/sparc64/mm/ultra.S @@ -480,42 +480,6 @@ xcall_sync_tick: b rtrap_xcall ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1 - /* NOTE: This is SPECIAL!! We do etrap/rtrap however - * we choose to deal with the "BH's run with - * %pil==15" problem (described in asm/pil.h) - * by just invoking rtrap directly past where - * BH's are checked for. - * - * We do it like this because we do not want %pil==15 - * lockups to prevent regs being reported. - */ - .globl xcall_report_regs -xcall_report_regs: - -661: rdpr %pstate, %g2 - wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate - .section .sun4v_2insn_patch, "ax" - .word 661b - nop - nop - .previous - - rdpr %pil, %g2 - wrpr %g0, 15, %pil - sethi %hi(109f), %g7 - b,pt %xcc, etrap_irq -109: or %g7, %lo(109b), %g7 -#ifdef CONFIG_TRACE_IRQFLAGS - call trace_hardirqs_off - nop -#endif - call __show_regs - add %sp, PTREGS_OFF, %o0 - /* Has to be a non-v9 branch due to the large distance. */ - b rtrap_xcall - ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1 - -#ifdef CONFIG_MAGIC_SYSRQ .globl xcall_fetch_glob_regs xcall_fetch_glob_regs: sethi %hi(global_reg_snapshot), %g1 @@ -531,6 +495,13 @@ xcall_fetch_glob_regs: stx %g7, [%g1 + GR_SNAP_TNPC] stx %o7, [%g1 + GR_SNAP_O7] stx %i7, [%g1 + GR_SNAP_I7] + /* Don't try this at home kids... */ + rdpr %cwp, %g2 + sub %g2, 1, %g7 + wrpr %g7, %cwp + mov %i7, %g7 + wrpr %g2, %cwp + stx %g7, [%g1 + GR_SNAP_RPC] sethi %hi(trap_block), %g7 or %g7, %lo(trap_block), %g7 sllx %g2, TRAP_BLOCK_SZ_SHIFT, %g2 @@ -539,7 +510,6 @@ xcall_fetch_glob_regs: membar #StoreStore stx %g3, [%g1 + GR_SNAP_THREAD] retry -#endif /* CONFIG_MAGIC_SYSRQ */ #ifdef DCACHE_ALIASING_POSSIBLE .align 32 |