diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2008-08-07 08:55:03 (GMT) |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2008-08-07 08:55:03 (GMT) |
commit | 4fb8af10d0fd09372d52966b76922b9e82bbc950 (patch) | |
tree | d240e4d40357583e3f3eb228dccf20122a5b31ed /arch/powerpc/kernel | |
parent | f44f82e8a20b98558486eb14497b2f71c78fa325 (diff) | |
parent | 64a99d2a8c3ed5c4e39f3ae1cc682aa8fd3977fc (diff) | |
download | linux-fsl-qoriq-4fb8af10d0fd09372d52966b76922b9e82bbc950.tar.xz |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sam/kbuild-fixes
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r-- | arch/powerpc/kernel/Makefile | 14 | ||||
-rw-r--r-- | arch/powerpc/kernel/cpu_setup_44x.S | 6 | ||||
-rw-r--r-- | arch/powerpc/kernel/entry_32.S | 17 | ||||
-rw-r--r-- | arch/powerpc/kernel/entry_64.S | 10 | ||||
-rw-r--r-- | arch/powerpc/kernel/irq.c | 25 | ||||
-rw-r--r-- | arch/powerpc/kernel/legacy_serial.c | 44 | ||||
-rw-r--r-- | arch/powerpc/kernel/lparcfg.c | 4 | ||||
-rw-r--r-- | arch/powerpc/kernel/process.c | 10 | ||||
-rw-r--r-- | arch/powerpc/kernel/prom_init.c | 39 | ||||
-rw-r--r-- | arch/powerpc/kernel/ptrace.c | 64 | ||||
-rw-r--r-- | arch/powerpc/kernel/ptrace32.c | 2 | ||||
-rw-r--r-- | arch/powerpc/kernel/setup-common.c | 24 | ||||
-rw-r--r-- | arch/powerpc/kernel/setup_64.c | 3 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal.c | 23 | ||||
-rw-r--r-- | arch/powerpc/kernel/smp.c | 119 | ||||
-rw-r--r-- | arch/powerpc/kernel/stacktrace.c | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/sysfs.c | 311 | ||||
-rw-r--r-- | arch/powerpc/kernel/vdso.c | 2 | ||||
-rw-r--r-- | arch/powerpc/kernel/vio.c | 6 |
19 files changed, 525 insertions, 199 deletions
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 1a40947..64f5948 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile @@ -59,8 +59,6 @@ obj64-$(CONFIG_HIBERNATION) += swsusp_asm64.o obj-$(CONFIG_MODULES) += module.o module_$(CONFIG_WORD_SIZE).o obj-$(CONFIG_44x) += cpu_setup_44x.o -ifeq ($(CONFIG_PPC_MERGE),y) - extra-$(CONFIG_PPC_STD_MMU) := head_32.o extra-$(CONFIG_PPC64) := head_64.o extra-$(CONFIG_40x) := head_40x.o @@ -100,12 +98,6 @@ ifneq ($(CONFIG_PPC_INDIRECT_IO),y) obj-y += iomap.o endif -else -# stuff used from here for ARCH=ppc -smpobj-$(CONFIG_SMP) += smp.o - -endif - obj-$(CONFIG_PPC64) += $(obj64-y) extra-$(CONFIG_PPC_FPU) += fpu.o @@ -121,9 +113,6 @@ PHONY += systbl_chk systbl_chk: $(src)/systbl_chk.sh $(obj)/systbl_chk.i $(call cmd,systbl_chk) - -ifeq ($(CONFIG_PPC_MERGE),y) - $(obj)/built-in.o: prom_init_check quiet_cmd_prom_init_check = CALL $< @@ -133,7 +122,4 @@ PHONY += prom_init_check prom_init_check: $(src)/prom_init_check.sh $(obj)/prom_init.o $(call cmd,prom_init_check) -endif - - clean-files := vmlinux.lds diff --git a/arch/powerpc/kernel/cpu_setup_44x.S b/arch/powerpc/kernel/cpu_setup_44x.S index 5465e8d..80cac98 100644 --- a/arch/powerpc/kernel/cpu_setup_44x.S +++ b/arch/powerpc/kernel/cpu_setup_44x.S @@ -39,12 +39,6 @@ _GLOBAL(__setup_cpu_440gx) _GLOBAL(__setup_cpu_440spe) b __fixup_440A_mcheck - /* Temporary fixup for arch/ppc until we kill the whole thing */ -#ifndef CONFIG_PPC_MERGE -_GLOBAL(__fixup_440A_mcheck) - blr -#endif - /* enable APU between CPU and FPU */ _GLOBAL(__init_fpu_44x) mfspr r3,SPRN_CCR0 diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 81c8324..1cbbf70 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -148,7 +148,7 @@ transfer_to_handler: /* Check to see if the dbcr0 register is set up to debug. Use the internal debug mode bit to do this. */ lwz r12,THREAD_DBCR0(r12) - andis. r12,r12,(DBCR0_IDM | DBSR_DAC1R | DBSR_DAC1W)@h + andis. r12,r12,DBCR0_IDM@h beq+ 3f /* From user and task is ptraced - load up global dbcr0 */ li r12,-1 /* clear all pending debug events */ @@ -292,7 +292,7 @@ syscall_exit_cont: /* If the process has its own DBCR0 value, load it up. The internal debug mode bit tells us that dbcr0 should be loaded. */ lwz r0,THREAD+THREAD_DBCR0(r2) - andis. r10,r0,(DBCR0_IDM | DBSR_DAC1R | DBSR_DAC1W)@h + andis. r10,r0,DBCR0_IDM@h bnel- load_dbcr0 #endif #ifdef CONFIG_44x @@ -343,7 +343,12 @@ syscall_dotrace: stw r0,_TRAP(r1) addi r3,r1,STACK_FRAME_OVERHEAD bl do_syscall_trace_enter - lwz r0,GPR0(r1) /* Restore original registers */ + /* + * Restore argument registers possibly just changed. + * We use the return value of do_syscall_trace_enter + * for call number to look up in the table (r0). + */ + mr r0,r3 lwz r3,GPR3(r1) lwz r4,GPR4(r1) lwz r5,GPR5(r1) @@ -720,7 +725,7 @@ restore_user: /* Check whether this process has its own DBCR0 value. The internal debug mode bit tells us that dbcr0 should be loaded. */ lwz r0,THREAD+THREAD_DBCR0(r2) - andis. r10,r0,(DBCR0_IDM | DBSR_DAC1R | DBSR_DAC1W)@h + andis. r10,r0,DBCR0_IDM@h bnel- load_dbcr0 #endif @@ -1055,8 +1060,8 @@ do_user_signal: /* r10 contains MSR_KERNEL here */ SAVE_NVGPRS(r1) rlwinm r3,r3,0,0,30 stw r3,_TRAP(r1) -2: li r3,0 - addi r4,r1,STACK_FRAME_OVERHEAD +2: addi r3,r1,STACK_FRAME_OVERHEAD + mr r4,r9 bl do_signal REST_NVGPRS(r1) b recheck diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index d736924..2d802e9 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -214,7 +214,12 @@ syscall_dotrace: bl .save_nvgprs addi r3,r1,STACK_FRAME_OVERHEAD bl .do_syscall_trace_enter - ld r0,GPR0(r1) /* Restore original registers */ + /* + * Restore argument registers possibly just changed. + * We use the return value of do_syscall_trace_enter + * for the call number to look up in the table (r0). + */ + mr r0,r3 ld r3,GPR3(r1) ld r4,GPR4(r1) ld r5,GPR5(r1) @@ -638,8 +643,7 @@ user_work: b .ret_from_except_lite 1: bl .save_nvgprs - li r3,0 - addi r4,r1,STACK_FRAME_OVERHEAD + addi r3,r1,STACK_FRAME_OVERHEAD bl .do_signal b .ret_from_except diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 6ac8612..d972dec 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -77,22 +77,12 @@ static int ppc_spurious_interrupts; EXPORT_SYMBOL(__irq_offset_value); atomic_t ppc_n_lost_interrupts; -#ifndef CONFIG_PPC_MERGE -#define NR_MASK_WORDS ((NR_IRQS + 31) / 32) -unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; -#endif - #ifdef CONFIG_TAU_INT extern int tau_initialized; extern int tau_interrupts(int); #endif #endif /* CONFIG_PPC32 */ -#if defined(CONFIG_SMP) && !defined(CONFIG_PPC_MERGE) -extern atomic_t ipi_recv; -extern atomic_t ipi_sent; -#endif - #ifdef CONFIG_PPC64 EXPORT_SYMBOL(irq_desc); @@ -216,21 +206,14 @@ int show_interrupts(struct seq_file *p, void *v) skip: spin_unlock_irqrestore(&desc->lock, flags); } else if (i == NR_IRQS) { -#ifdef CONFIG_PPC32 -#ifdef CONFIG_TAU_INT +#if defined(CONFIG_PPC32) && defined(CONFIG_TAU_INT) if (tau_initialized){ seq_puts(p, "TAU: "); for_each_online_cpu(j) seq_printf(p, "%10u ", tau_interrupts(j)); seq_puts(p, " PowerPC Thermal Assist (cpu temp)\n"); } -#endif -#if defined(CONFIG_SMP) && !defined(CONFIG_PPC_MERGE) - /* should this be per processor send/receive? */ - seq_printf(p, "IPI (recv/sent): %10u/%u\n", - atomic_read(&ipi_recv), atomic_read(&ipi_sent)); -#endif -#endif /* CONFIG_PPC32 */ +#endif /* CONFIG_PPC32 && CONFIG_TAU_INT*/ seq_printf(p, "BAD: %10u\n", ppc_spurious_interrupts); } return 0; @@ -454,8 +437,6 @@ void do_softirq(void) * IRQ controller and virtual interrupts */ -#ifdef CONFIG_PPC_MERGE - static LIST_HEAD(irq_hosts); static DEFINE_SPINLOCK(irq_big_lock); static DEFINE_PER_CPU(unsigned int, irq_radix_reader); @@ -1114,8 +1095,6 @@ static int __init irq_debugfs_init(void) __initcall(irq_debugfs_init); #endif /* CONFIG_VIRQ_DEBUG */ -#endif /* CONFIG_PPC_MERGE */ - #ifdef CONFIG_PPC64 static int __init setup_noirqdistrib(char *str) { diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c index 4d96e1d..9ddfaef 100644 --- a/arch/powerpc/kernel/legacy_serial.c +++ b/arch/powerpc/kernel/legacy_serial.c @@ -493,18 +493,18 @@ static int __init serial_dev_init(void) device_initcall(serial_dev_init); +#ifdef CONFIG_SERIAL_8250_CONSOLE /* * This is called very early, as part of console_init() (typically just after * time_init()). This function is respondible for trying to find a good * default console on serial ports. It tries to match the open firmware - * default output with one of the available serial console drivers, either - * one of the platform serial ports that have been probed earlier by - * find_legacy_serial_ports() or some more platform specific ones. + * default output with one of the available serial console drivers that have + * been probed earlier by find_legacy_serial_ports() */ static int __init check_legacy_serial_console(void) { struct device_node *prom_stdout = NULL; - int speed = 0, offset = 0; + int i, speed = 0, offset = 0; const char *name; const u32 *spd; @@ -548,31 +548,20 @@ static int __init check_legacy_serial_console(void) if (spd) speed = *spd; - if (0) - ; -#ifdef CONFIG_SERIAL_8250_CONSOLE - else if (strcmp(name, "serial") == 0) { - int i; - /* Look for it in probed array */ - for (i = 0; i < legacy_serial_count; i++) { - if (prom_stdout != legacy_serial_infos[i].np) - continue; - offset = i; - speed = legacy_serial_infos[i].speed; - break; - } - if (i >= legacy_serial_count) - goto not_found; + if (strcmp(name, "serial") != 0) + goto not_found; + + /* Look for it in probed array */ + for (i = 0; i < legacy_serial_count; i++) { + if (prom_stdout != legacy_serial_infos[i].np) + continue; + offset = i; + speed = legacy_serial_infos[i].speed; + break; } -#endif /* CONFIG_SERIAL_8250_CONSOLE */ -#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE - else if (strcmp(name, "ch-a") == 0) - offset = 0; - else if (strcmp(name, "ch-b") == 0) - offset = 1; -#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ - else + if (i >= legacy_serial_count) goto not_found; + of_node_put(prom_stdout); DBG("Found serial console at ttyS%d\n", offset); @@ -591,3 +580,4 @@ static int __init check_legacy_serial_console(void) } console_initcall(check_legacy_serial_console); +#endif /* CONFIG_SERIAL_8250_CONSOLE */ diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c index 9f856a0..1a09719 100644 --- a/arch/powerpc/kernel/lparcfg.c +++ b/arch/powerpc/kernel/lparcfg.c @@ -636,10 +636,6 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf, retval = -EIO; } else if (retval == H_PARAMETER) { retval = -EINVAL; - } else { - printk(KERN_WARNING "%s: received unknown hv return code %ld", - __func__, retval); - retval = -EIO; } return retval; diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index db2497c..957bded 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -254,7 +254,7 @@ void do_dabr(struct pt_regs *regs, unsigned long address, return; /* Clear the DAC and struct entries. One shot trigger */ -#if (defined(CONFIG_44x) || defined(CONFIG_BOOKE)) +#if defined(CONFIG_BOOKE) mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~(DBSR_DAC1R | DBSR_DAC1W | DBCR0_IDM)); #endif @@ -276,17 +276,15 @@ int set_dabr(unsigned long dabr) { __get_cpu_var(current_dabr) = dabr; -#ifdef CONFIG_PPC_MERGE /* XXX for now */ if (ppc_md.set_dabr) return ppc_md.set_dabr(dabr); -#endif /* XXX should we have a CPU_FTR_HAS_DABR ? */ #if defined(CONFIG_PPC64) || defined(CONFIG_6xx) mtspr(SPRN_DABR, dabr); #endif -#if defined(CONFIG_44x) || defined(CONFIG_BOOKE) +#if defined(CONFIG_BOOKE) mtspr(SPRN_DAC1, dabr); #endif @@ -373,7 +371,7 @@ struct task_struct *__switch_to(struct task_struct *prev, if (unlikely(__get_cpu_var(current_dabr) != new->thread.dabr)) set_dabr(new->thread.dabr); -#if defined(CONFIG_44x) || defined(CONFIG_BOOKE) +#if defined(CONFIG_BOOKE) /* If new thread DAC (HW breakpoint) is the same then leave it */ if (new->thread.dabr) set_dabr(new->thread.dabr); @@ -568,7 +566,7 @@ void flush_thread(void) current->thread.dabr = 0; set_dabr(0); -#if defined(CONFIG_44x) || defined(CONFIG_BOOKE) +#if defined(CONFIG_BOOKE) current->thread.dbcr0 &= ~(DBSR_DAC1R | DBSR_DAC1W); #endif } diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index c4ab219..b72849a 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -205,8 +205,6 @@ static int __initdata mem_reserve_cnt; static cell_t __initdata regbuf[1024]; -#define MAX_CPU_THREADS 2 - /* * Error results ... some OF calls will return "-1" on error, some * will return 0, some will return either. To simplify, here are @@ -1339,10 +1337,6 @@ static void __init prom_hold_cpus(void) unsigned int reg; phandle node; char type[64]; - int cpuid = 0; - unsigned int interrupt_server[MAX_CPU_THREADS]; - unsigned int cpu_threads, hw_cpu_num; - int propsize; struct prom_t *_prom = &RELOC(prom); unsigned long *spinloop = (void *) LOW_ADDR(__secondary_hold_spinloop); @@ -1386,7 +1380,6 @@ static void __init prom_hold_cpus(void) reg = -1; prom_getprop(node, "reg", ®, sizeof(reg)); - prom_debug("\ncpuid = 0x%x\n", cpuid); prom_debug("cpu hw idx = 0x%x\n", reg); /* Init the acknowledge var which will be reset by @@ -1395,28 +1388,9 @@ static void __init prom_hold_cpus(void) */ *acknowledge = (unsigned long)-1; - propsize = prom_getprop(node, "ibm,ppc-interrupt-server#s", - &interrupt_server, - sizeof(interrupt_server)); - if (propsize < 0) { - /* no property. old hardware has no SMT */ - cpu_threads = 1; - interrupt_server[0] = reg; /* fake it with phys id */ - } else { - /* We have a threaded processor */ - cpu_threads = propsize / sizeof(u32); - if (cpu_threads > MAX_CPU_THREADS) { - prom_printf("SMT: too many threads!\n" - "SMT: found %x, max is %x\n", - cpu_threads, MAX_CPU_THREADS); - cpu_threads = 1; /* ToDo: panic? */ - } - } - - hw_cpu_num = interrupt_server[0]; - if (hw_cpu_num != _prom->cpu) { + if (reg != _prom->cpu) { /* Primary Thread of non-boot cpu */ - prom_printf("%x : starting cpu hw idx %x... ", cpuid, reg); + prom_printf("starting cpu hw idx %x... ", reg); call_prom("start-cpu", 3, 0, node, secondary_hold, reg); @@ -1431,17 +1405,10 @@ static void __init prom_hold_cpus(void) } #ifdef CONFIG_SMP else - prom_printf("%x : boot cpu %x\n", cpuid, reg); + prom_printf("boot cpu hw idx %x\n", reg); #endif /* CONFIG_SMP */ - - /* Reserve cpu #s for secondary threads. They start later. */ - cpuid += cpu_threads; } - if (cpuid > NR_CPUS) - prom_printf("WARNING: maximum CPUs (" __stringify(NR_CPUS) - ") exceeded: ignoring extras\n"); - prom_debug("prom_hold_cpus: end...\n"); } diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index a5d0e78..3635be6 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -22,6 +22,7 @@ #include <linux/errno.h> #include <linux/ptrace.h> #include <linux/regset.h> +#include <linux/tracehook.h> #include <linux/elf.h> #include <linux/user.h> #include <linux/security.h> @@ -374,7 +375,7 @@ static int vsr_get(struct task_struct *target, const struct user_regset *regset, flush_vsx_to_thread(target); for (i = 0; i < 32 ; i++) - buf[i] = current->thread.fpr[i][TS_VSRLOWOFFSET]; + buf[i] = target->thread.fpr[i][TS_VSRLOWOFFSET]; ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, 32 * sizeof(double)); @@ -393,7 +394,7 @@ static int vsr_set(struct task_struct *target, const struct user_regset *regset, ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, 32 * sizeof(double)); for (i = 0; i < 32 ; i++) - current->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i]; + target->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i]; return ret; @@ -717,7 +718,7 @@ void user_disable_single_step(struct task_struct *task) struct pt_regs *regs = task->thread.regs; -#if defined(CONFIG_44x) || defined(CONFIG_BOOKE) +#if defined(CONFIG_BOOKE) /* If DAC then do not single step, skip */ if (task->thread.dabr) return; @@ -744,10 +745,11 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, if (addr > 0) return -EINVAL; + /* The bottom 3 bits in dabr are flags */ if ((data & ~0x7UL) >= TASK_SIZE) return -EIO; -#ifdef CONFIG_PPC64 +#ifndef CONFIG_BOOKE /* For processors using DABR (i.e. 970), the bottom 3 bits are flags. * It was assumed, on previous implementations, that 3 bits were @@ -769,7 +771,7 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, task->thread.dabr = data; #endif -#if defined(CONFIG_44x) || defined(CONFIG_BOOKE) +#if defined(CONFIG_BOOKE) /* As described above, it was assumed 3 bits were passed with the data * address, but we will assume only the mode bits will be passed @@ -973,15 +975,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) case PTRACE_GETVSRREGS: return copy_regset_to_user(child, &user_ppc_native_view, REGSET_VSX, - 0, (32 * sizeof(vector128) + - sizeof(u32)), + 0, 32 * sizeof(double), (void __user *) data); case PTRACE_SETVSRREGS: return copy_regset_from_user(child, &user_ppc_native_view, REGSET_VSX, - 0, (32 * sizeof(vector128) + - sizeof(u32)), + 0, 32 * sizeof(double), (const void __user *) data); #endif #ifdef CONFIG_SPE @@ -1013,31 +1013,24 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) return ret; } -static void do_syscall_trace(void) +/* + * We must return the syscall number to actually look up in the table. + * This can be -1L to skip running any syscall at all. + */ +long do_syscall_trace_enter(struct pt_regs *regs) { - /* the 0x80 provides a way for the tracing parent to distinguish - between a syscall stop and SIGTRAP delivery */ - 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; - } -} + long ret = 0; -void do_syscall_trace_enter(struct pt_regs *regs) -{ secure_computing(regs->gpr[0]); - if (test_thread_flag(TIF_SYSCALL_TRACE) - && (current->ptrace & PT_PTRACED)) - do_syscall_trace(); + if (test_thread_flag(TIF_SYSCALL_TRACE) && + tracehook_report_syscall_entry(regs)) + /* + * Tracing decided this syscall should not happen. + * We'll return a bogus call number to get an ENOSYS + * error, but leave the original number in regs->gpr[0]. + */ + ret = -1L; if (unlikely(current->audit_context)) { #ifdef CONFIG_PPC64 @@ -1055,16 +1048,19 @@ void do_syscall_trace_enter(struct pt_regs *regs) regs->gpr[5] & 0xffffffff, regs->gpr[6] & 0xffffffff); } + + return ret ?: regs->gpr[0]; } void do_syscall_trace_leave(struct pt_regs *regs) { + int step; + if (unlikely(current->audit_context)) audit_syscall_exit((regs->ccr&0x10000000)?AUDITSC_FAILURE:AUDITSC_SUCCESS, regs->result); - if ((test_thread_flag(TIF_SYSCALL_TRACE) - || test_thread_flag(TIF_SINGLESTEP)) - && (current->ptrace & PT_PTRACED)) - do_syscall_trace(); + step = test_thread_flag(TIF_SINGLESTEP); + if (step || test_thread_flag(TIF_SYSCALL_TRACE)) + tracehook_report_syscall_exit(regs, step); } diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c index 67bf1a1..197d49c 100644 --- a/arch/powerpc/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c @@ -294,6 +294,8 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, case PTRACE_SETFPREGS: case PTRACE_GETVRREGS: case PTRACE_SETVRREGS: + case PTRACE_GETVSRREGS: + case PTRACE_SETVSRREGS: case PTRACE_GETREGS64: case PTRACE_SETREGS64: case PPC_PTRACE_GETFPREGS: diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 61a3f413..9cc5a52 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c @@ -367,7 +367,6 @@ static void __init cpu_init_thread_core_maps(int tpc) * setup_cpu_maps - initialize the following cpu maps: * cpu_possible_map * cpu_present_map - * cpu_sibling_map * * Having the possible map set up early allows us to restrict allocations * of things like irqstacks to num_possible_cpus() rather than NR_CPUS. @@ -475,29 +474,6 @@ void __init smp_setup_cpu_maps(void) */ cpu_init_thread_core_maps(nthreads); } - -/* - * Being that cpu_sibling_map is now a per_cpu array, then it cannot - * be initialized until the per_cpu areas have been created. This - * function is now called from setup_per_cpu_areas(). - */ -void __init smp_setup_cpu_sibling_map(void) -{ -#ifdef CONFIG_PPC64 - int i, cpu, base; - - for_each_possible_cpu(cpu) { - DBG("Sibling map for CPU %d:", cpu); - base = cpu_first_thread_in_core(cpu); - for (i = 0; i < threads_per_core; i++) { - cpu_set(base + i, per_cpu(cpu_sibling_map, cpu)); - DBG(" %d", base + i); - } - DBG("\n"); - } - -#endif /* CONFIG_PPC64 */ -} #endif /* CONFIG_SMP */ #ifdef CONFIG_PCSPKR_PLATFORM diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 04d8de9..8b25f51 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c @@ -611,9 +611,6 @@ void __init setup_per_cpu_areas(void) paca[i].data_offset = ptr - __per_cpu_start; memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); } - - /* Now that per_cpu is setup, initialize cpu_sibling_map */ - smp_setup_cpu_sibling_map(); } #endif diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index 7aada78..a54405e 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c @@ -9,7 +9,7 @@ * this archive for more details. */ -#include <linux/ptrace.h> +#include <linux/tracehook.h> #include <linux/signal.h> #include <asm/uaccess.h> #include <asm/unistd.h> @@ -112,7 +112,7 @@ static void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka, } } -int do_signal(sigset_t *oldset, struct pt_regs *regs) +static int do_signal_pending(sigset_t *oldset, struct pt_regs *regs) { siginfo_t info; int signr; @@ -147,7 +147,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) */ if (current->thread.dabr) { set_dabr(current->thread.dabr); -#if defined(CONFIG_44x) || defined(CONFIG_BOOKE) +#if defined(CONFIG_BOOKE) mtspr(SPRN_DBCR0, current->thread.dbcr0); #endif } @@ -177,11 +177,28 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) * its frame, and we can clear the TLF_RESTORE_SIGMASK flag. */ current_thread_info()->local_flags &= ~_TLF_RESTORE_SIGMASK; + + /* + * Let tracing know that we've done the handler setup. + */ + tracehook_signal_handler(signr, &info, &ka, regs, + test_thread_flag(TIF_SINGLESTEP)); } return ret; } +void do_signal(struct pt_regs *regs, unsigned long thread_info_flags) +{ + if (thread_info_flags & _TIF_SIGPENDING) + do_signal_pending(NULL, regs); + + if (thread_info_flags & _TIF_NOTIFY_RESUME) { + clear_thread_flag(TIF_NOTIFY_RESUME); + tracehook_notify_resume(regs); + } +} + long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, unsigned long r5, unsigned long r6, unsigned long r7, unsigned long r8, struct pt_regs *regs) diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index f5ae9fa..5337ca7 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c @@ -41,6 +41,7 @@ #include <asm/smp.h> #include <asm/time.h> #include <asm/machdep.h> +#include <asm/cputhreads.h> #include <asm/cputable.h> #include <asm/system.h> #include <asm/mpic.h> @@ -62,10 +63,12 @@ struct thread_info *secondary_ti; cpumask_t cpu_possible_map = CPU_MASK_NONE; cpumask_t cpu_online_map = CPU_MASK_NONE; DEFINE_PER_CPU(cpumask_t, cpu_sibling_map) = CPU_MASK_NONE; +DEFINE_PER_CPU(cpumask_t, cpu_core_map) = CPU_MASK_NONE; EXPORT_SYMBOL(cpu_online_map); EXPORT_SYMBOL(cpu_possible_map); EXPORT_PER_CPU_SYMBOL(cpu_sibling_map); +EXPORT_PER_CPU_SYMBOL(cpu_core_map); /* SMP operations for this machine */ struct smp_ops_t *smp_ops; @@ -228,6 +231,8 @@ void __devinit smp_prepare_boot_cpu(void) BUG_ON(smp_processor_id() != boot_cpuid); cpu_set(boot_cpuid, cpu_online_map); + cpu_set(boot_cpuid, per_cpu(cpu_sibling_map, boot_cpuid)); + cpu_set(boot_cpuid, per_cpu(cpu_core_map, boot_cpuid)); #ifdef CONFIG_PPC64 paca[boot_cpuid].__current = current; #endif @@ -375,11 +380,60 @@ int __cpuinit __cpu_up(unsigned int cpu) return 0; } +/* Return the value of the reg property corresponding to the given + * logical cpu. + */ +int cpu_to_core_id(int cpu) +{ + struct device_node *np; + const int *reg; + int id = -1; + + np = of_get_cpu_node(cpu, NULL); + if (!np) + goto out; + + reg = of_get_property(np, "reg", NULL); + if (!reg) + goto out; + + id = *reg; +out: + of_node_put(np); + return id; +} + +/* Must be called when no change can occur to cpu_present_map, + * i.e. during cpu online or offline. + */ +static struct device_node *cpu_to_l2cache(int cpu) +{ + struct device_node *np; + const phandle *php; + phandle ph; + + if (!cpu_present(cpu)) + return NULL; + + np = of_get_cpu_node(cpu, NULL); + if (np == NULL) + return NULL; + + php = of_get_property(np, "l2-cache", NULL); + if (php == NULL) + return NULL; + ph = *php; + of_node_put(np); + + return of_find_node_by_phandle(ph); +} /* Activate a secondary processor. */ int __devinit start_secondary(void *unused) { unsigned int cpu = smp_processor_id(); + struct device_node *l2_cache; + int i, base; atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; @@ -400,6 +454,33 @@ int __devinit start_secondary(void *unused) ipi_call_lock(); cpu_set(cpu, cpu_online_map); + /* Update sibling maps */ + base = cpu_first_thread_in_core(cpu); + for (i = 0; i < threads_per_core; i++) { + if (cpu_is_offline(base + i)) + continue; + cpu_set(cpu, per_cpu(cpu_sibling_map, base + i)); + cpu_set(base + i, per_cpu(cpu_sibling_map, cpu)); + + /* cpu_core_map should be a superset of + * cpu_sibling_map even if we don't have cache + * information, so update the former here, too. + */ + cpu_set(cpu, per_cpu(cpu_core_map, base +i)); + cpu_set(base + i, per_cpu(cpu_core_map, cpu)); + } + l2_cache = cpu_to_l2cache(cpu); + for_each_online_cpu(i) { + struct device_node *np = cpu_to_l2cache(i); + if (!np) + continue; + if (np == l2_cache) { + cpu_set(cpu, per_cpu(cpu_core_map, i)); + cpu_set(i, per_cpu(cpu_core_map, cpu)); + } + of_node_put(np); + } + of_node_put(l2_cache); ipi_call_unlock(); local_irq_enable(); @@ -437,10 +518,42 @@ void __init smp_cpus_done(unsigned int max_cpus) #ifdef CONFIG_HOTPLUG_CPU int __cpu_disable(void) { - if (smp_ops->cpu_disable) - return smp_ops->cpu_disable(); + struct device_node *l2_cache; + int cpu = smp_processor_id(); + int base, i; + int err; - return -ENOSYS; + if (!smp_ops->cpu_disable) + return -ENOSYS; + + err = smp_ops->cpu_disable(); + if (err) + return err; + + /* Update sibling maps */ + base = cpu_first_thread_in_core(cpu); + for (i = 0; i < threads_per_core; i++) { + cpu_clear(cpu, per_cpu(cpu_sibling_map, base + i)); + cpu_clear(base + i, per_cpu(cpu_sibling_map, cpu)); + cpu_clear(cpu, per_cpu(cpu_core_map, base +i)); + cpu_clear(base + i, per_cpu(cpu_core_map, cpu)); + } + + l2_cache = cpu_to_l2cache(cpu); + for_each_present_cpu(i) { + struct device_node *np = cpu_to_l2cache(i); + if (!np) + continue; + if (np == l2_cache) { + cpu_clear(cpu, per_cpu(cpu_core_map, i)); + cpu_clear(i, per_cpu(cpu_core_map, cpu)); + } + of_node_put(np); + } + of_node_put(l2_cache); + + + return 0; } void __cpu_die(unsigned int cpu) diff --git a/arch/powerpc/kernel/stacktrace.c b/arch/powerpc/kernel/stacktrace.c index f258964..b0dbb1d 100644 --- a/arch/powerpc/kernel/stacktrace.c +++ b/arch/powerpc/kernel/stacktrace.c @@ -13,7 +13,6 @@ #include <linux/module.h> #include <linux/sched.h> #include <linux/stacktrace.h> -#include <linux/module.h> #include <asm/ptrace.h> #include <asm/processor.h> diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index 800e5e9..56d172d 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c @@ -22,6 +22,8 @@ static DEFINE_PER_CPU(struct cpu, cpu_devices); +static DEFINE_PER_CPU(struct kobject *, cache_toplevel); + /* SMT stuff */ #ifdef CONFIG_PPC_MULTIPLATFORM @@ -297,8 +299,289 @@ static struct sysdev_attribute pa6t_attrs[] = { #endif /* CONFIG_DEBUG_KERNEL */ }; +struct cache_desc { + struct kobject kobj; + struct cache_desc *next; + const char *type; /* Instruction, Data, or Unified */ + u32 size; /* total cache size in KB */ + u32 line_size; /* in bytes */ + u32 nr_sets; /* number of sets */ + u32 level; /* e.g. 1, 2, 3... */ + u32 associativity; /* e.g. 8-way... 0 is fully associative */ +}; + +DEFINE_PER_CPU(struct cache_desc *, cache_desc); + +static struct cache_desc *kobj_to_cache_desc(struct kobject *k) +{ + return container_of(k, struct cache_desc, kobj); +} + +static void cache_desc_release(struct kobject *k) +{ + struct cache_desc *desc = kobj_to_cache_desc(k); + + pr_debug("%s: releasing %s\n", __func__, kobject_name(k)); + + if (desc->next) + kobject_put(&desc->next->kobj); + + kfree(kobj_to_cache_desc(k)); +} + +static ssize_t cache_desc_show(struct kobject *k, struct attribute *attr, char *buf) +{ + struct kobj_attribute *kobj_attr; + + kobj_attr = container_of(attr, struct kobj_attribute, attr); + + return kobj_attr->show(k, kobj_attr, buf); +} + +static struct sysfs_ops cache_desc_sysfs_ops = { + .show = cache_desc_show, +}; + +static struct kobj_type cache_desc_type = { + .release = cache_desc_release, + .sysfs_ops = &cache_desc_sysfs_ops, +}; + +static ssize_t cache_size_show(struct kobject *k, struct kobj_attribute *attr, char *buf) +{ + struct cache_desc *cache = kobj_to_cache_desc(k); + + return sprintf(buf, "%uK\n", cache->size); +} + +static struct kobj_attribute cache_size_attr = + __ATTR(size, 0444, cache_size_show, NULL); + +static ssize_t cache_line_size_show(struct kobject *k, struct kobj_attribute *attr, char *buf) +{ + struct cache_desc *cache = kobj_to_cache_desc(k); + + return sprintf(buf, "%u\n", cache->line_size); +} + +static struct kobj_attribute cache_line_size_attr = + __ATTR(coherency_line_size, 0444, cache_line_size_show, NULL); + +static ssize_t cache_nr_sets_show(struct kobject *k, struct kobj_attribute *attr, char *buf) +{ + struct cache_desc *cache = kobj_to_cache_desc(k); + + return sprintf(buf, "%u\n", cache->nr_sets); +} + +static struct kobj_attribute cache_nr_sets_attr = + __ATTR(number_of_sets, 0444, cache_nr_sets_show, NULL); + +static ssize_t cache_type_show(struct kobject *k, struct kobj_attribute *attr, char *buf) +{ + struct cache_desc *cache = kobj_to_cache_desc(k); + + return sprintf(buf, "%s\n", cache->type); +} + +static struct kobj_attribute cache_type_attr = + __ATTR(type, 0444, cache_type_show, NULL); + +static ssize_t cache_level_show(struct kobject *k, struct kobj_attribute *attr, char *buf) +{ + struct cache_desc *cache = kobj_to_cache_desc(k); + + return sprintf(buf, "%u\n", cache->level); +} + +static struct kobj_attribute cache_level_attr = + __ATTR(level, 0444, cache_level_show, NULL); + +static ssize_t cache_assoc_show(struct kobject *k, struct kobj_attribute *attr, char *buf) +{ + struct cache_desc *cache = kobj_to_cache_desc(k); + + return sprintf(buf, "%u\n", cache->associativity); +} + +static struct kobj_attribute cache_assoc_attr = + __ATTR(ways_of_associativity, 0444, cache_assoc_show, NULL); + +struct cache_desc_info { + const char *type; + const char *size_prop; + const char *line_size_prop; + const char *nr_sets_prop; +}; + +/* PowerPC Processor binding says the [di]-cache-* must be equal on + * unified caches, so just use d-cache properties. */ +static struct cache_desc_info ucache_info = { + .type = "Unified", + .size_prop = "d-cache-size", + .line_size_prop = "d-cache-line-size", + .nr_sets_prop = "d-cache-sets", +}; -static void register_cpu_online(unsigned int cpu) +static struct cache_desc_info dcache_info = { + .type = "Data", + .size_prop = "d-cache-size", + .line_size_prop = "d-cache-line-size", + .nr_sets_prop = "d-cache-sets", +}; + +static struct cache_desc_info icache_info = { + .type = "Instruction", + .size_prop = "i-cache-size", + .line_size_prop = "i-cache-line-size", + .nr_sets_prop = "i-cache-sets", +}; + +static struct cache_desc * __cpuinit create_cache_desc(struct device_node *np, struct kobject *parent, int index, int level, struct cache_desc_info *info) +{ + const u32 *cache_line_size; + struct cache_desc *new; + const u32 *cache_size; + const u32 *nr_sets; + int rc; + + new = kzalloc(sizeof(*new), GFP_KERNEL); + if (!new) + return NULL; + + rc = kobject_init_and_add(&new->kobj, &cache_desc_type, parent, + "index%d", index); + if (rc) + goto err; + + /* type */ + new->type = info->type; + rc = sysfs_create_file(&new->kobj, &cache_type_attr.attr); + WARN_ON(rc); + + /* level */ + new->level = level; + rc = sysfs_create_file(&new->kobj, &cache_level_attr.attr); + WARN_ON(rc); + + /* size */ + cache_size = of_get_property(np, info->size_prop, NULL); + if (cache_size) { + new->size = *cache_size / 1024; + rc = sysfs_create_file(&new->kobj, + &cache_size_attr.attr); + WARN_ON(rc); + } + + /* coherency_line_size */ + cache_line_size = of_get_property(np, info->line_size_prop, NULL); + if (cache_line_size) { + new->line_size = *cache_line_size; + rc = sysfs_create_file(&new->kobj, + &cache_line_size_attr.attr); + WARN_ON(rc); + } + + /* number_of_sets */ + nr_sets = of_get_property(np, info->nr_sets_prop, NULL); + if (nr_sets) { + new->nr_sets = *nr_sets; + rc = sysfs_create_file(&new->kobj, + &cache_nr_sets_attr.attr); + WARN_ON(rc); + } + + /* ways_of_associativity */ + if (new->nr_sets == 1) { + /* fully associative */ + new->associativity = 0; + goto create_assoc; + } + + if (new->nr_sets && new->size && new->line_size) { + /* If we have values for all of these we can derive + * the associativity. */ + new->associativity = + ((new->size * 1024) / new->nr_sets) / new->line_size; +create_assoc: + rc = sysfs_create_file(&new->kobj, + &cache_assoc_attr.attr); + WARN_ON(rc); + } + + return new; +err: + kfree(new); + return NULL; +} + +static bool cache_is_unified(struct device_node *np) +{ + return of_get_property(np, "cache-unified", NULL); +} + +static struct cache_desc * __cpuinit create_cache_index_info(struct device_node *np, struct kobject *parent, int index, int level) +{ + const phandle *next_cache_phandle; + struct device_node *next_cache; + struct cache_desc *new, **end; + + pr_debug("%s(node = %s, index = %d)\n", __func__, np->full_name, index); + + if (cache_is_unified(np)) { + new = create_cache_desc(np, parent, index, level, + &ucache_info); + } else { + new = create_cache_desc(np, parent, index, level, + &dcache_info); + if (new) { + index++; + new->next = create_cache_desc(np, parent, index, level, + &icache_info); + } + } + if (!new) + return NULL; + + end = &new->next; + while (*end) + end = &(*end)->next; + + next_cache_phandle = of_get_property(np, "l2-cache", NULL); + if (!next_cache_phandle) + goto out; + + next_cache = of_find_node_by_phandle(*next_cache_phandle); + if (!next_cache) + goto out; + + *end = create_cache_index_info(next_cache, parent, ++index, ++level); + + of_node_put(next_cache); +out: + return new; +} + +static void __cpuinit create_cache_info(struct sys_device *sysdev) +{ + struct kobject *cache_toplevel; + struct device_node *np = NULL; + int cpu = sysdev->id; + + cache_toplevel = kobject_create_and_add("cache", &sysdev->kobj); + if (!cache_toplevel) + return; + per_cpu(cache_toplevel, cpu) = cache_toplevel; + np = of_get_cpu_node(cpu, NULL); + if (np != NULL) { + per_cpu(cache_desc, cpu) = + create_cache_index_info(np, cache_toplevel, 0, 1); + of_node_put(np); + } + return; +} + +static void __cpuinit register_cpu_online(unsigned int cpu) { struct cpu *c = &per_cpu(cpu_devices, cpu); struct sys_device *s = &c->sysdev; @@ -346,9 +629,33 @@ static void register_cpu_online(unsigned int cpu) if (cpu_has_feature(CPU_FTR_DSCR)) sysdev_create_file(s, &attr_dscr); + + create_cache_info(s); } #ifdef CONFIG_HOTPLUG_CPU +static void remove_cache_info(struct sys_device *sysdev) +{ + struct kobject *cache_toplevel; + struct cache_desc *cache_desc; + int cpu = sysdev->id; + + cache_desc = per_cpu(cache_desc, cpu); + if (cache_desc != NULL) { + sysfs_remove_file(&cache_desc->kobj, &cache_size_attr.attr); + sysfs_remove_file(&cache_desc->kobj, &cache_line_size_attr.attr); + sysfs_remove_file(&cache_desc->kobj, &cache_type_attr.attr); + sysfs_remove_file(&cache_desc->kobj, &cache_level_attr.attr); + sysfs_remove_file(&cache_desc->kobj, &cache_nr_sets_attr.attr); + sysfs_remove_file(&cache_desc->kobj, &cache_assoc_attr.attr); + + kobject_put(&cache_desc->kobj); + } + cache_toplevel = per_cpu(cache_toplevel, cpu); + if (cache_toplevel != NULL) + kobject_put(cache_toplevel); +} + static void unregister_cpu_online(unsigned int cpu) { struct cpu *c = &per_cpu(cpu_devices, cpu); @@ -399,6 +706,8 @@ static void unregister_cpu_online(unsigned int cpu) if (cpu_has_feature(CPU_FTR_DSCR)) sysdev_remove_file(s, &attr_dscr); + + remove_cache_info(s); } #endif /* CONFIG_HOTPLUG_CPU */ diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c index f177c60..65639a4 100644 --- a/arch/powerpc/kernel/vdso.c +++ b/arch/powerpc/kernel/vdso.c @@ -788,9 +788,7 @@ static int __init vdso_init(void) return 0; } -#ifdef CONFIG_PPC_MERGE arch_initcall(vdso_init); -#endif int in_gate_area_no_task(unsigned long addr) { diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index ade8aea..22a3c33 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c @@ -530,7 +530,7 @@ static dma_addr_t vio_dma_iommu_map_single(struct device *dev, void *vaddr, } ret = dma_iommu_ops.map_single(dev, vaddr, size, direction, attrs); - if (unlikely(dma_mapping_error(ret))) { + if (unlikely(dma_mapping_error(dev, ret))) { vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE)); atomic_inc(&viodev->cmo.allocs_failed); } @@ -1031,8 +1031,8 @@ void vio_cmo_set_dev_desired(struct vio_dev *viodev, size_t desired) {} static int vio_cmo_bus_probe(struct vio_dev *viodev) { return 0; } static void vio_cmo_bus_remove(struct vio_dev *viodev) {} static void vio_cmo_set_dma_ops(struct vio_dev *viodev) {} -static void vio_cmo_bus_init() {} -static void vio_cmo_sysfs_init() { } +static void vio_cmo_bus_init(void) {} +static void vio_cmo_sysfs_init(void) { } #endif /* CONFIG_PPC_SMLPAR */ EXPORT_SYMBOL(vio_cmo_entitlement_update); EXPORT_SYMBOL(vio_cmo_set_dev_desired); |