diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-07-18 13:53:16 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-07-18 13:53:16 -0400 |
commit | 9b610fda0df5d0f0b0c64242e37441ad1b384aac (patch) | |
tree | 0ea14b15f2e6546f37fe18d8ac3dc83077ec0e55 /arch/powerpc/kernel | |
parent | b8f8c3cf0a4ac0632ec3f0e15e9dc0c29de917af (diff) | |
parent | 5b664cb235e97afbf34db9c4d77f08ebd725335e (diff) |
Merge branch 'linus' into timers/nohz
Diffstat (limited to 'arch/powerpc/kernel')
68 files changed, 2085 insertions, 994 deletions
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 2346d271fbfd..bf0b1fd0ec34 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile | |||
@@ -12,6 +12,18 @@ CFLAGS_prom_init.o += -fPIC | |||
12 | CFLAGS_btext.o += -fPIC | 12 | CFLAGS_btext.o += -fPIC |
13 | endif | 13 | endif |
14 | 14 | ||
15 | ifdef CONFIG_FTRACE | ||
16 | # Do not trace early boot code | ||
17 | CFLAGS_REMOVE_cputable.o = -pg | ||
18 | CFLAGS_REMOVE_prom_init.o = -pg | ||
19 | |||
20 | ifdef CONFIG_DYNAMIC_FTRACE | ||
21 | # dynamic ftrace setup. | ||
22 | CFLAGS_REMOVE_ftrace.o = -pg | ||
23 | endif | ||
24 | |||
25 | endif | ||
26 | |||
15 | obj-y := cputable.o ptrace.o syscalls.o \ | 27 | obj-y := cputable.o ptrace.o syscalls.o \ |
16 | irq.o align.o signal_32.o pmc.o vdso.o \ | 28 | irq.o align.o signal_32.o pmc.o vdso.o \ |
17 | init_task.o process.o systbl.o idle.o \ | 29 | init_task.o process.o systbl.o idle.o \ |
@@ -38,12 +50,13 @@ obj-$(CONFIG_IBMVIO) += vio.o | |||
38 | obj-$(CONFIG_IBMEBUS) += ibmebus.o | 50 | obj-$(CONFIG_IBMEBUS) += ibmebus.o |
39 | obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o | 51 | obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o |
40 | obj-$(CONFIG_CRASH_DUMP) += crash_dump.o | 52 | obj-$(CONFIG_CRASH_DUMP) += crash_dump.o |
53 | obj-$(CONFIG_E500) += idle_e500.o | ||
41 | obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o | 54 | obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o |
42 | obj-$(CONFIG_TAU) += tau_6xx.o | 55 | obj-$(CONFIG_TAU) += tau_6xx.o |
43 | obj-$(CONFIG_HIBERNATION) += swsusp.o suspend.o \ | 56 | obj-$(CONFIG_HIBERNATION) += swsusp.o suspend.o \ |
44 | swsusp_$(CONFIG_WORD_SIZE).o | 57 | swsusp_$(CONFIG_WORD_SIZE).o |
45 | obj64-$(CONFIG_HIBERNATION) += swsusp_asm64.o | 58 | obj64-$(CONFIG_HIBERNATION) += swsusp_asm64.o |
46 | obj-$(CONFIG_MODULES) += module_$(CONFIG_WORD_SIZE).o | 59 | obj-$(CONFIG_MODULES) += module.o module_$(CONFIG_WORD_SIZE).o |
47 | obj-$(CONFIG_44x) += cpu_setup_44x.o | 60 | obj-$(CONFIG_44x) += cpu_setup_44x.o |
48 | 61 | ||
49 | ifeq ($(CONFIG_PPC_MERGE),y) | 62 | ifeq ($(CONFIG_PPC_MERGE),y) |
@@ -78,6 +91,8 @@ obj-$(CONFIG_KEXEC) += machine_kexec.o crash.o \ | |||
78 | obj-$(CONFIG_AUDIT) += audit.o | 91 | obj-$(CONFIG_AUDIT) += audit.o |
79 | obj64-$(CONFIG_AUDIT) += compat_audit.o | 92 | obj64-$(CONFIG_AUDIT) += compat_audit.o |
80 | 93 | ||
94 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o | ||
95 | |||
81 | obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o | 96 | obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o |
82 | 97 | ||
83 | ifneq ($(CONFIG_PPC_INDIRECT_IO),y) | 98 | ifneq ($(CONFIG_PPC_INDIRECT_IO),y) |
diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c index e06f75daeba3..367129789cc0 100644 --- a/arch/powerpc/kernel/align.c +++ b/arch/powerpc/kernel/align.c | |||
@@ -48,6 +48,7 @@ struct aligninfo { | |||
48 | #define HARD 0x80 /* string, stwcx. */ | 48 | #define HARD 0x80 /* string, stwcx. */ |
49 | #define E4 0x40 /* SPE endianness is word */ | 49 | #define E4 0x40 /* SPE endianness is word */ |
50 | #define E8 0x80 /* SPE endianness is double word */ | 50 | #define E8 0x80 /* SPE endianness is double word */ |
51 | #define SPLT 0x80 /* VSX SPLAT load */ | ||
51 | 52 | ||
52 | /* DSISR bits reported for a DCBZ instruction: */ | 53 | /* DSISR bits reported for a DCBZ instruction: */ |
53 | #define DCBZ 0x5f /* 8xx/82xx dcbz faults when cache not enabled */ | 54 | #define DCBZ 0x5f /* 8xx/82xx dcbz faults when cache not enabled */ |
@@ -363,10 +364,10 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr, | |||
363 | * Only POWER6 has these instructions, and it does true little-endian, | 364 | * Only POWER6 has these instructions, and it does true little-endian, |
364 | * so we don't need the address swizzling. | 365 | * so we don't need the address swizzling. |
365 | */ | 366 | */ |
366 | static int emulate_fp_pair(struct pt_regs *regs, unsigned char __user *addr, | 367 | static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg, |
367 | unsigned int reg, unsigned int flags) | 368 | unsigned int flags) |
368 | { | 369 | { |
369 | char *ptr = (char *) ¤t->thread.fpr[reg]; | 370 | char *ptr = (char *) ¤t->thread.TS_FPR(reg); |
370 | int i, ret; | 371 | int i, ret; |
371 | 372 | ||
372 | if (!(flags & F)) | 373 | if (!(flags & F)) |
@@ -637,6 +638,36 @@ static int emulate_spe(struct pt_regs *regs, unsigned int reg, | |||
637 | } | 638 | } |
638 | #endif /* CONFIG_SPE */ | 639 | #endif /* CONFIG_SPE */ |
639 | 640 | ||
641 | #ifdef CONFIG_VSX | ||
642 | /* | ||
643 | * Emulate VSX instructions... | ||
644 | */ | ||
645 | static int emulate_vsx(unsigned char __user *addr, unsigned int reg, | ||
646 | unsigned int areg, struct pt_regs *regs, | ||
647 | unsigned int flags, unsigned int length) | ||
648 | { | ||
649 | char *ptr = (char *) ¤t->thread.TS_FPR(reg); | ||
650 | int ret; | ||
651 | |||
652 | flush_vsx_to_thread(current); | ||
653 | |||
654 | if (flags & ST) | ||
655 | ret = __copy_to_user(addr, ptr, length); | ||
656 | else { | ||
657 | if (flags & SPLT){ | ||
658 | ret = __copy_from_user(ptr, addr, length); | ||
659 | ptr += length; | ||
660 | } | ||
661 | ret |= __copy_from_user(ptr, addr, length); | ||
662 | } | ||
663 | if (flags & U) | ||
664 | regs->gpr[areg] = regs->dar; | ||
665 | if (ret) | ||
666 | return -EFAULT; | ||
667 | return 1; | ||
668 | } | ||
669 | #endif | ||
670 | |||
640 | /* | 671 | /* |
641 | * Called on alignment exception. Attempts to fixup | 672 | * Called on alignment exception. Attempts to fixup |
642 | * | 673 | * |
@@ -647,7 +678,7 @@ static int emulate_spe(struct pt_regs *regs, unsigned int reg, | |||
647 | 678 | ||
648 | int fix_alignment(struct pt_regs *regs) | 679 | int fix_alignment(struct pt_regs *regs) |
649 | { | 680 | { |
650 | unsigned int instr, nb, flags; | 681 | unsigned int instr, nb, flags, instruction = 0; |
651 | unsigned int reg, areg; | 682 | unsigned int reg, areg; |
652 | unsigned int dsisr; | 683 | unsigned int dsisr; |
653 | unsigned char __user *addr; | 684 | unsigned char __user *addr; |
@@ -689,6 +720,7 @@ int fix_alignment(struct pt_regs *regs) | |||
689 | if (cpu_has_feature(CPU_FTR_REAL_LE) && (regs->msr & MSR_LE)) | 720 | if (cpu_has_feature(CPU_FTR_REAL_LE) && (regs->msr & MSR_LE)) |
690 | instr = cpu_to_le32(instr); | 721 | instr = cpu_to_le32(instr); |
691 | dsisr = make_dsisr(instr); | 722 | dsisr = make_dsisr(instr); |
723 | instruction = instr; | ||
692 | } | 724 | } |
693 | 725 | ||
694 | /* extract the operation and registers from the dsisr */ | 726 | /* extract the operation and registers from the dsisr */ |
@@ -728,6 +760,30 @@ int fix_alignment(struct pt_regs *regs) | |||
728 | /* DAR has the operand effective address */ | 760 | /* DAR has the operand effective address */ |
729 | addr = (unsigned char __user *)regs->dar; | 761 | addr = (unsigned char __user *)regs->dar; |
730 | 762 | ||
763 | #ifdef CONFIG_VSX | ||
764 | if ((instruction & 0xfc00003e) == 0x7c000018) { | ||
765 | /* Additional register addressing bit (64 VSX vs 32 FPR/GPR */ | ||
766 | reg |= (instruction & 0x1) << 5; | ||
767 | /* Simple inline decoder instead of a table */ | ||
768 | if (instruction & 0x200) | ||
769 | nb = 16; | ||
770 | else if (instruction & 0x080) | ||
771 | nb = 8; | ||
772 | else | ||
773 | nb = 4; | ||
774 | flags = 0; | ||
775 | if (instruction & 0x100) | ||
776 | flags |= ST; | ||
777 | if (instruction & 0x040) | ||
778 | flags |= U; | ||
779 | /* splat load needs a special decoder */ | ||
780 | if ((instruction & 0x400) == 0){ | ||
781 | flags |= SPLT; | ||
782 | nb = 8; | ||
783 | } | ||
784 | return emulate_vsx(addr, reg, areg, regs, flags, nb); | ||
785 | } | ||
786 | #endif | ||
731 | /* A size of 0 indicates an instruction we don't support, with | 787 | /* A size of 0 indicates an instruction we don't support, with |
732 | * the exception of DCBZ which is handled as a special case here | 788 | * the exception of DCBZ which is handled as a special case here |
733 | */ | 789 | */ |
@@ -759,7 +815,7 @@ int fix_alignment(struct pt_regs *regs) | |||
759 | 815 | ||
760 | /* Special case for 16-byte FP loads and stores */ | 816 | /* Special case for 16-byte FP loads and stores */ |
761 | if (nb == 16) | 817 | if (nb == 16) |
762 | return emulate_fp_pair(regs, addr, reg, flags); | 818 | return emulate_fp_pair(addr, reg, flags); |
763 | 819 | ||
764 | /* If we are loading, get the data from user space, else | 820 | /* If we are loading, get the data from user space, else |
765 | * get it from register values | 821 | * get it from register values |
@@ -784,7 +840,7 @@ int fix_alignment(struct pt_regs *regs) | |||
784 | return -EFAULT; | 840 | return -EFAULT; |
785 | } | 841 | } |
786 | } else if (flags & F) { | 842 | } else if (flags & F) { |
787 | data.dd = current->thread.fpr[reg]; | 843 | data.dd = current->thread.TS_FPR(reg); |
788 | if (flags & S) { | 844 | if (flags & S) { |
789 | /* Single-precision FP store requires conversion... */ | 845 | /* Single-precision FP store requires conversion... */ |
790 | #ifdef CONFIG_PPC_FPU | 846 | #ifdef CONFIG_PPC_FPU |
@@ -862,7 +918,7 @@ int fix_alignment(struct pt_regs *regs) | |||
862 | if (unlikely(ret)) | 918 | if (unlikely(ret)) |
863 | return -EFAULT; | 919 | return -EFAULT; |
864 | } else if (flags & F) | 920 | } else if (flags & F) |
865 | current->thread.fpr[reg] = data.dd; | 921 | current->thread.TS_FPR(reg) = data.dd; |
866 | else | 922 | else |
867 | regs->gpr[reg] = data.ll; | 923 | regs->gpr[reg] = data.ll; |
868 | 924 | ||
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index ec9228d687b0..92768d3006f7 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c | |||
@@ -52,6 +52,10 @@ | |||
52 | #include <asm/iseries/alpaca.h> | 52 | #include <asm/iseries/alpaca.h> |
53 | #endif | 53 | #endif |
54 | 54 | ||
55 | #if defined(CONFIG_BOOKE) || defined(CONFIG_40x) | ||
56 | #include "head_booke.h" | ||
57 | #endif | ||
58 | |||
55 | int main(void) | 59 | int main(void) |
56 | { | 60 | { |
57 | DEFINE(THREAD, offsetof(struct task_struct, thread)); | 61 | DEFINE(THREAD, offsetof(struct task_struct, thread)); |
@@ -74,6 +78,10 @@ int main(void) | |||
74 | DEFINE(THREAD_VSCR, offsetof(struct thread_struct, vscr)); | 78 | DEFINE(THREAD_VSCR, offsetof(struct thread_struct, vscr)); |
75 | DEFINE(THREAD_USED_VR, offsetof(struct thread_struct, used_vr)); | 79 | DEFINE(THREAD_USED_VR, offsetof(struct thread_struct, used_vr)); |
76 | #endif /* CONFIG_ALTIVEC */ | 80 | #endif /* CONFIG_ALTIVEC */ |
81 | #ifdef CONFIG_VSX | ||
82 | DEFINE(THREAD_VSR0, offsetof(struct thread_struct, fpr)); | ||
83 | DEFINE(THREAD_USED_VSR, offsetof(struct thread_struct, used_vsr)); | ||
84 | #endif /* CONFIG_VSX */ | ||
77 | #ifdef CONFIG_PPC64 | 85 | #ifdef CONFIG_PPC64 |
78 | DEFINE(KSP_VSID, offsetof(struct thread_struct, ksp_vsid)); | 86 | DEFINE(KSP_VSID, offsetof(struct thread_struct, ksp_vsid)); |
79 | #else /* CONFIG_PPC64 */ | 87 | #else /* CONFIG_PPC64 */ |
@@ -242,6 +250,25 @@ int main(void) | |||
242 | DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8); | 250 | DEFINE(_SRR1, STACK_FRAME_OVERHEAD+sizeof(struct pt_regs)+8); |
243 | #endif /* CONFIG_PPC64 */ | 251 | #endif /* CONFIG_PPC64 */ |
244 | 252 | ||
253 | #if defined(CONFIG_BOOKE) || defined(CONFIG_40x) | ||
254 | DEFINE(EXC_LVL_SIZE, STACK_EXC_LVL_FRAME_SIZE); | ||
255 | DEFINE(MAS0, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, mas0)); | ||
256 | /* we overload MMUCR for 44x on MAS0 since they are mutually exclusive */ | ||
257 | DEFINE(MMUCR, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, mas0)); | ||
258 | DEFINE(MAS1, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, mas1)); | ||
259 | DEFINE(MAS2, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, mas2)); | ||
260 | DEFINE(MAS3, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, mas3)); | ||
261 | DEFINE(MAS6, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, mas6)); | ||
262 | DEFINE(MAS7, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, mas7)); | ||
263 | DEFINE(_SRR0, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, srr0)); | ||
264 | DEFINE(_SRR1, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, srr1)); | ||
265 | DEFINE(_CSRR0, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, csrr0)); | ||
266 | DEFINE(_CSRR1, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, csrr1)); | ||
267 | DEFINE(_DSRR0, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, dsrr0)); | ||
268 | DEFINE(_DSRR1, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, dsrr1)); | ||
269 | DEFINE(SAVED_KSP_LIMIT, STACK_INT_FRAME_SIZE+offsetof(struct exception_regs, saved_ksp_limit)); | ||
270 | #endif | ||
271 | |||
245 | DEFINE(CLONE_VM, CLONE_VM); | 272 | DEFINE(CLONE_VM, CLONE_VM); |
246 | DEFINE(CLONE_UNTRACED, CLONE_UNTRACED); | 273 | DEFINE(CLONE_UNTRACED, CLONE_UNTRACED); |
247 | 274 | ||
diff --git a/arch/powerpc/kernel/cpu_setup_44x.S b/arch/powerpc/kernel/cpu_setup_44x.S index e3623e3e3451..5465e8de0e61 100644 --- a/arch/powerpc/kernel/cpu_setup_44x.S +++ b/arch/powerpc/kernel/cpu_setup_44x.S | |||
@@ -33,6 +33,7 @@ _GLOBAL(__setup_cpu_440grx) | |||
33 | mtlr r4 | 33 | mtlr r4 |
34 | blr | 34 | blr |
35 | _GLOBAL(__setup_cpu_460ex) | 35 | _GLOBAL(__setup_cpu_460ex) |
36 | _GLOBAL(__setup_cpu_460gt) | ||
36 | b __init_fpu_44x | 37 | b __init_fpu_44x |
37 | _GLOBAL(__setup_cpu_440gx) | 38 | _GLOBAL(__setup_cpu_440gx) |
38 | _GLOBAL(__setup_cpu_440spe) | 39 | _GLOBAL(__setup_cpu_440spe) |
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index e44d5530f0a6..f7f3c215d06f 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c | |||
@@ -37,6 +37,7 @@ extern void __setup_cpu_440gx(unsigned long offset, struct cpu_spec* spec); | |||
37 | extern void __setup_cpu_440grx(unsigned long offset, struct cpu_spec* spec); | 37 | extern void __setup_cpu_440grx(unsigned long offset, struct cpu_spec* spec); |
38 | extern void __setup_cpu_440spe(unsigned long offset, struct cpu_spec* spec); | 38 | extern void __setup_cpu_440spe(unsigned long offset, struct cpu_spec* spec); |
39 | extern void __setup_cpu_460ex(unsigned long offset, struct cpu_spec* spec); | 39 | extern void __setup_cpu_460ex(unsigned long offset, struct cpu_spec* spec); |
40 | extern void __setup_cpu_460gt(unsigned long offset, struct cpu_spec* spec); | ||
40 | extern void __setup_cpu_603(unsigned long offset, struct cpu_spec* spec); | 41 | extern void __setup_cpu_603(unsigned long offset, struct cpu_spec* spec); |
41 | extern void __setup_cpu_604(unsigned long offset, struct cpu_spec* spec); | 42 | extern void __setup_cpu_604(unsigned long offset, struct cpu_spec* spec); |
42 | extern void __setup_cpu_750(unsigned long offset, struct cpu_spec* spec); | 43 | extern void __setup_cpu_750(unsigned long offset, struct cpu_spec* spec); |
@@ -52,6 +53,8 @@ extern void __setup_cpu_ppc970MP(unsigned long offset, struct cpu_spec* spec); | |||
52 | extern void __setup_cpu_pa6t(unsigned long offset, struct cpu_spec* spec); | 53 | extern void __setup_cpu_pa6t(unsigned long offset, struct cpu_spec* spec); |
53 | extern void __restore_cpu_pa6t(void); | 54 | extern void __restore_cpu_pa6t(void); |
54 | extern void __restore_cpu_ppc970(void); | 55 | extern void __restore_cpu_ppc970(void); |
56 | extern void __setup_cpu_power7(unsigned long offset, struct cpu_spec* spec); | ||
57 | extern void __restore_cpu_power7(void); | ||
55 | #endif /* CONFIG_PPC64 */ | 58 | #endif /* CONFIG_PPC64 */ |
56 | 59 | ||
57 | /* This table only contains "desktop" CPUs, it need to be filled with embedded | 60 | /* This table only contains "desktop" CPUs, it need to be filled with embedded |
@@ -67,7 +70,12 @@ extern void __restore_cpu_ppc970(void); | |||
67 | PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP) | 70 | PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP) |
68 | #define COMMON_USER_POWER6 (COMMON_USER_PPC64 | PPC_FEATURE_ARCH_2_05 |\ | 71 | #define COMMON_USER_POWER6 (COMMON_USER_PPC64 | PPC_FEATURE_ARCH_2_05 |\ |
69 | PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | \ | 72 | PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | \ |
70 | PPC_FEATURE_TRUE_LE) | 73 | PPC_FEATURE_TRUE_LE | \ |
74 | PPC_FEATURE_PSERIES_PERFMON_COMPAT) | ||
75 | #define COMMON_USER_POWER7 (COMMON_USER_PPC64 | PPC_FEATURE_ARCH_2_06 |\ | ||
76 | PPC_FEATURE_SMT | PPC_FEATURE_ICACHE_SNOOP | \ | ||
77 | PPC_FEATURE_TRUE_LE | \ | ||
78 | PPC_FEATURE_PSERIES_PERFMON_COMPAT) | ||
71 | #define COMMON_USER_PA6T (COMMON_USER_PPC64 | PPC_FEATURE_PA6T |\ | 79 | #define COMMON_USER_PA6T (COMMON_USER_PPC64 | PPC_FEATURE_PA6T |\ |
72 | PPC_FEATURE_TRUE_LE | \ | 80 | PPC_FEATURE_TRUE_LE | \ |
73 | PPC_FEATURE_HAS_ALTIVEC_COMP) | 81 | PPC_FEATURE_HAS_ALTIVEC_COMP) |
@@ -380,6 +388,37 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
380 | .machine_check = machine_check_generic, | 388 | .machine_check = machine_check_generic, |
381 | .platform = "power6", | 389 | .platform = "power6", |
382 | }, | 390 | }, |
391 | { /* 2.06-compliant processor, i.e. Power7 "architected" mode */ | ||
392 | .pvr_mask = 0xffffffff, | ||
393 | .pvr_value = 0x0f000003, | ||
394 | .cpu_name = "POWER7 (architected)", | ||
395 | .cpu_features = CPU_FTRS_POWER7, | ||
396 | .cpu_user_features = COMMON_USER_POWER7, | ||
397 | .icache_bsize = 128, | ||
398 | .dcache_bsize = 128, | ||
399 | .machine_check = machine_check_generic, | ||
400 | .platform = "power7", | ||
401 | }, | ||
402 | { /* Power7 */ | ||
403 | .pvr_mask = 0xffff0000, | ||
404 | .pvr_value = 0x003f0000, | ||
405 | .cpu_name = "POWER7 (raw)", | ||
406 | .cpu_features = CPU_FTRS_POWER7, | ||
407 | .cpu_user_features = COMMON_USER_POWER7, | ||
408 | .icache_bsize = 128, | ||
409 | .dcache_bsize = 128, | ||
410 | .num_pmcs = 6, | ||
411 | .pmc_type = PPC_PMC_IBM, | ||
412 | .cpu_setup = __setup_cpu_power7, | ||
413 | .cpu_restore = __restore_cpu_power7, | ||
414 | .oprofile_cpu_type = "ppc64/power7", | ||
415 | .oprofile_type = PPC_OPROFILE_POWER4, | ||
416 | .oprofile_mmcra_sihv = POWER6_MMCRA_SIHV, | ||
417 | .oprofile_mmcra_sipr = POWER6_MMCRA_SIPR, | ||
418 | .oprofile_mmcra_clear = POWER6_MMCRA_THRM | | ||
419 | POWER6_MMCRA_OTHER, | ||
420 | .platform = "power7", | ||
421 | }, | ||
383 | { /* Cell Broadband Engine */ | 422 | { /* Cell Broadband Engine */ |
384 | .pvr_mask = 0xffff0000, | 423 | .pvr_mask = 0xffff0000, |
385 | .pvr_value = 0x00700000, | 424 | .pvr_value = 0x00700000, |
@@ -1410,6 +1449,16 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
1410 | .machine_check = machine_check_440A, | 1449 | .machine_check = machine_check_440A, |
1411 | .platform = "ppc440", | 1450 | .platform = "ppc440", |
1412 | }, | 1451 | }, |
1452 | { /* 440 in Xilinx Virtex-5 FXT */ | ||
1453 | .pvr_mask = 0xfffffff0, | ||
1454 | .pvr_value = 0x7ff21910, | ||
1455 | .cpu_name = "440 in Virtex-5 FXT", | ||
1456 | .cpu_features = CPU_FTRS_44X, | ||
1457 | .cpu_user_features = COMMON_USER_BOOKE, | ||
1458 | .icache_bsize = 32, | ||
1459 | .dcache_bsize = 32, | ||
1460 | .platform = "ppc440", | ||
1461 | }, | ||
1413 | { /* 460EX */ | 1462 | { /* 460EX */ |
1414 | .pvr_mask = 0xffff0002, | 1463 | .pvr_mask = 0xffff0002, |
1415 | .pvr_value = 0x13020002, | 1464 | .pvr_value = 0x13020002, |
@@ -1427,9 +1476,10 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
1427 | .pvr_value = 0x13020000, | 1476 | .pvr_value = 0x13020000, |
1428 | .cpu_name = "460GT", | 1477 | .cpu_name = "460GT", |
1429 | .cpu_features = CPU_FTRS_44X, | 1478 | .cpu_features = CPU_FTRS_44X, |
1430 | .cpu_user_features = COMMON_USER_BOOKE, | 1479 | .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU, |
1431 | .icache_bsize = 32, | 1480 | .icache_bsize = 32, |
1432 | .dcache_bsize = 32, | 1481 | .dcache_bsize = 32, |
1482 | .cpu_setup = __setup_cpu_460gt, | ||
1433 | .machine_check = machine_check_440A, | 1483 | .machine_check = machine_check_440A, |
1434 | .platform = "ppc440", | 1484 | .platform = "ppc440", |
1435 | }, | 1485 | }, |
@@ -1491,7 +1541,6 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
1491 | .pvr_mask = 0xffff0000, | 1541 | .pvr_mask = 0xffff0000, |
1492 | .pvr_value = 0x80200000, | 1542 | .pvr_value = 0x80200000, |
1493 | .cpu_name = "e500", | 1543 | .cpu_name = "e500", |
1494 | /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */ | ||
1495 | .cpu_features = CPU_FTRS_E500, | 1544 | .cpu_features = CPU_FTRS_E500, |
1496 | .cpu_user_features = COMMON_USER_BOOKE | | 1545 | .cpu_user_features = COMMON_USER_BOOKE | |
1497 | PPC_FEATURE_HAS_SPE_COMP | | 1546 | PPC_FEATURE_HAS_SPE_COMP | |
@@ -1508,7 +1557,6 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
1508 | .pvr_mask = 0xffff0000, | 1557 | .pvr_mask = 0xffff0000, |
1509 | .pvr_value = 0x80210000, | 1558 | .pvr_value = 0x80210000, |
1510 | .cpu_name = "e500v2", | 1559 | .cpu_name = "e500v2", |
1511 | /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */ | ||
1512 | .cpu_features = CPU_FTRS_E500_2, | 1560 | .cpu_features = CPU_FTRS_E500_2, |
1513 | .cpu_user_features = COMMON_USER_BOOKE | | 1561 | .cpu_user_features = COMMON_USER_BOOKE | |
1514 | PPC_FEATURE_HAS_SPE_COMP | | 1562 | PPC_FEATURE_HAS_SPE_COMP | |
@@ -1522,6 +1570,20 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
1522 | .machine_check = machine_check_e500, | 1570 | .machine_check = machine_check_e500, |
1523 | .platform = "ppc8548", | 1571 | .platform = "ppc8548", |
1524 | }, | 1572 | }, |
1573 | { /* e500mc */ | ||
1574 | .pvr_mask = 0xffff0000, | ||
1575 | .pvr_value = 0x80230000, | ||
1576 | .cpu_name = "e500mc", | ||
1577 | .cpu_features = CPU_FTRS_E500MC, | ||
1578 | .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU, | ||
1579 | .icache_bsize = 64, | ||
1580 | .dcache_bsize = 64, | ||
1581 | .num_pmcs = 4, | ||
1582 | .oprofile_cpu_type = "ppc/e500", /* xxx - galak, e500mc? */ | ||
1583 | .oprofile_type = PPC_OPROFILE_FSL_EMB, | ||
1584 | .machine_check = machine_check_e500, | ||
1585 | .platform = "ppce500mc", | ||
1586 | }, | ||
1525 | { /* default match */ | 1587 | { /* default match */ |
1526 | .pvr_mask = 0x00000000, | 1588 | .pvr_mask = 0x00000000, |
1527 | .pvr_value = 0x00000000, | 1589 | .pvr_value = 0x00000000, |
@@ -1587,38 +1649,3 @@ struct cpu_spec * __init identify_cpu(unsigned long offset, unsigned int pvr) | |||
1587 | BUG(); | 1649 | BUG(); |
1588 | return NULL; | 1650 | return NULL; |
1589 | } | 1651 | } |
1590 | |||
1591 | void do_feature_fixups(unsigned long value, void *fixup_start, void *fixup_end) | ||
1592 | { | ||
1593 | struct fixup_entry { | ||
1594 | unsigned long mask; | ||
1595 | unsigned long value; | ||
1596 | long start_off; | ||
1597 | long end_off; | ||
1598 | } *fcur, *fend; | ||
1599 | |||
1600 | fcur = fixup_start; | ||
1601 | fend = fixup_end; | ||
1602 | |||
1603 | for (; fcur < fend; fcur++) { | ||
1604 | unsigned int *pstart, *pend, *p; | ||
1605 | |||
1606 | if ((value & fcur->mask) == fcur->value) | ||
1607 | continue; | ||
1608 | |||
1609 | /* These PTRRELOCs will disappear once the new scheme for | ||
1610 | * modules and vdso is implemented | ||
1611 | */ | ||
1612 | pstart = ((unsigned int *)fcur) + (fcur->start_off / 4); | ||
1613 | pend = ((unsigned int *)fcur) + (fcur->end_off / 4); | ||
1614 | |||
1615 | for (p = pstart; p < pend; p++) { | ||
1616 | *p = 0x60000000u; | ||
1617 | asm volatile ("dcbst 0, %0" : : "r" (p)); | ||
1618 | } | ||
1619 | asm volatile ("sync" : : : "memory"); | ||
1620 | for (p = pstart; p < pend; p++) | ||
1621 | asm volatile ("icbi 0,%0" : : "r" (p)); | ||
1622 | asm volatile ("sync; isync" : : : "memory"); | ||
1623 | } | ||
1624 | } | ||
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index eae401de3f76..0a8439aafdd1 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c | |||
@@ -48,7 +48,7 @@ int crashing_cpu = -1; | |||
48 | static cpumask_t cpus_in_crash = CPU_MASK_NONE; | 48 | static cpumask_t cpus_in_crash = CPU_MASK_NONE; |
49 | cpumask_t cpus_in_sr = CPU_MASK_NONE; | 49 | cpumask_t cpus_in_sr = CPU_MASK_NONE; |
50 | 50 | ||
51 | #define CRASH_HANDLER_MAX 1 | 51 | #define CRASH_HANDLER_MAX 2 |
52 | /* NULL terminated list of shutdown handles */ | 52 | /* NULL terminated list of shutdown handles */ |
53 | static crash_shutdown_t crash_shutdown_handles[CRASH_HANDLER_MAX+1]; | 53 | static crash_shutdown_t crash_shutdown_handles[CRASH_HANDLER_MAX+1]; |
54 | static DEFINE_SPINLOCK(crash_handlers_lock); | 54 | static DEFINE_SPINLOCK(crash_handlers_lock); |
diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c index 9ee3c5278db0..e0debcca0bfa 100644 --- a/arch/powerpc/kernel/crash_dump.c +++ b/arch/powerpc/kernel/crash_dump.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/crash_dump.h> | 14 | #include <linux/crash_dump.h> |
15 | #include <linux/bootmem.h> | 15 | #include <linux/bootmem.h> |
16 | #include <linux/lmb.h> | 16 | #include <linux/lmb.h> |
17 | #include <asm/code-patching.h> | ||
17 | #include <asm/kdump.h> | 18 | #include <asm/kdump.h> |
18 | #include <asm/prom.h> | 19 | #include <asm/prom.h> |
19 | #include <asm/firmware.h> | 20 | #include <asm/firmware.h> |
@@ -33,6 +34,8 @@ void __init reserve_kdump_trampoline(void) | |||
33 | 34 | ||
34 | static void __init create_trampoline(unsigned long addr) | 35 | static void __init create_trampoline(unsigned long addr) |
35 | { | 36 | { |
37 | unsigned int *p = (unsigned int *)addr; | ||
38 | |||
36 | /* The maximum range of a single instruction branch, is the current | 39 | /* The maximum range of a single instruction branch, is the current |
37 | * instruction's address + (32 MB - 4) bytes. For the trampoline we | 40 | * instruction's address + (32 MB - 4) bytes. For the trampoline we |
38 | * need to branch to current address + 32 MB. So we insert a nop at | 41 | * need to branch to current address + 32 MB. So we insert a nop at |
@@ -41,8 +44,8 @@ static void __init create_trampoline(unsigned long addr) | |||
41 | * branch to "addr" we jump to ("addr" + 32 MB). Although it requires | 44 | * branch to "addr" we jump to ("addr" + 32 MB). Although it requires |
42 | * two instructions it doesn't require any registers. | 45 | * two instructions it doesn't require any registers. |
43 | */ | 46 | */ |
44 | create_instruction(addr, 0x60000000); /* nop */ | 47 | patch_instruction(p, PPC_NOP_INSTR); |
45 | create_branch(addr + 4, addr + PHYSICAL_START, 0); | 48 | patch_branch(++p, addr + PHYSICAL_START, 0); |
46 | } | 49 | } |
47 | 50 | ||
48 | void __init setup_kdump_trampoline(void) | 51 | void __init setup_kdump_trampoline(void) |
diff --git a/arch/powerpc/kernel/dma_64.c b/arch/powerpc/kernel/dma_64.c index 3a317cb0636a..ae5708e3a312 100644 --- a/arch/powerpc/kernel/dma_64.c +++ b/arch/powerpc/kernel/dma_64.c | |||
@@ -15,15 +15,6 @@ | |||
15 | * Generic iommu implementation | 15 | * Generic iommu implementation |
16 | */ | 16 | */ |
17 | 17 | ||
18 | static inline unsigned long device_to_mask(struct device *dev) | ||
19 | { | ||
20 | if (dev->dma_mask && *dev->dma_mask) | ||
21 | return *dev->dma_mask; | ||
22 | /* Assume devices without mask can take 32 bit addresses */ | ||
23 | return 0xfffffffful; | ||
24 | } | ||
25 | |||
26 | |||
27 | /* Allocates a contiguous real buffer and creates mappings over it. | 18 | /* Allocates a contiguous real buffer and creates mappings over it. |
28 | * Returns the virtual address of the buffer and sets dma_handle | 19 | * Returns the virtual address of the buffer and sets dma_handle |
29 | * to the dma address (mapping) of the first page. | 20 | * to the dma address (mapping) of the first page. |
@@ -50,32 +41,38 @@ static void dma_iommu_free_coherent(struct device *dev, size_t size, | |||
50 | */ | 41 | */ |
51 | static dma_addr_t dma_iommu_map_single(struct device *dev, void *vaddr, | 42 | static dma_addr_t dma_iommu_map_single(struct device *dev, void *vaddr, |
52 | size_t size, | 43 | size_t size, |
53 | enum dma_data_direction direction) | 44 | enum dma_data_direction direction, |
45 | struct dma_attrs *attrs) | ||
54 | { | 46 | { |
55 | return iommu_map_single(dev, dev->archdata.dma_data, vaddr, size, | 47 | return iommu_map_single(dev, dev->archdata.dma_data, vaddr, size, |
56 | device_to_mask(dev), direction); | 48 | device_to_mask(dev), direction, attrs); |
57 | } | 49 | } |
58 | 50 | ||
59 | 51 | ||
60 | static void dma_iommu_unmap_single(struct device *dev, dma_addr_t dma_handle, | 52 | static void dma_iommu_unmap_single(struct device *dev, dma_addr_t dma_handle, |
61 | size_t size, | 53 | size_t size, |
62 | enum dma_data_direction direction) | 54 | enum dma_data_direction direction, |
55 | struct dma_attrs *attrs) | ||
63 | { | 56 | { |
64 | iommu_unmap_single(dev->archdata.dma_data, dma_handle, size, direction); | 57 | iommu_unmap_single(dev->archdata.dma_data, dma_handle, size, direction, |
58 | attrs); | ||
65 | } | 59 | } |
66 | 60 | ||
67 | 61 | ||
68 | static int dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist, | 62 | static int dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist, |
69 | int nelems, enum dma_data_direction direction) | 63 | int nelems, enum dma_data_direction direction, |
64 | struct dma_attrs *attrs) | ||
70 | { | 65 | { |
71 | return iommu_map_sg(dev, sglist, nelems, | 66 | return iommu_map_sg(dev, dev->archdata.dma_data, sglist, nelems, |
72 | device_to_mask(dev), direction); | 67 | device_to_mask(dev), direction, attrs); |
73 | } | 68 | } |
74 | 69 | ||
75 | static void dma_iommu_unmap_sg(struct device *dev, struct scatterlist *sglist, | 70 | static void dma_iommu_unmap_sg(struct device *dev, struct scatterlist *sglist, |
76 | int nelems, enum dma_data_direction direction) | 71 | int nelems, enum dma_data_direction direction, |
72 | struct dma_attrs *attrs) | ||
77 | { | 73 | { |
78 | iommu_unmap_sg(dev->archdata.dma_data, sglist, nelems, direction); | 74 | iommu_unmap_sg(dev->archdata.dma_data, sglist, nelems, direction, |
75 | attrs); | ||
79 | } | 76 | } |
80 | 77 | ||
81 | /* We support DMA to/from any memory page via the iommu */ | 78 | /* We support DMA to/from any memory page via the iommu */ |
@@ -148,19 +145,22 @@ static void dma_direct_free_coherent(struct device *dev, size_t size, | |||
148 | 145 | ||
149 | static dma_addr_t dma_direct_map_single(struct device *dev, void *ptr, | 146 | static dma_addr_t dma_direct_map_single(struct device *dev, void *ptr, |
150 | size_t size, | 147 | size_t size, |
151 | enum dma_data_direction direction) | 148 | enum dma_data_direction direction, |
149 | struct dma_attrs *attrs) | ||
152 | { | 150 | { |
153 | return virt_to_abs(ptr) + get_dma_direct_offset(dev); | 151 | return virt_to_abs(ptr) + get_dma_direct_offset(dev); |
154 | } | 152 | } |
155 | 153 | ||
156 | static void dma_direct_unmap_single(struct device *dev, dma_addr_t dma_addr, | 154 | static void dma_direct_unmap_single(struct device *dev, dma_addr_t dma_addr, |
157 | size_t size, | 155 | size_t size, |
158 | enum dma_data_direction direction) | 156 | enum dma_data_direction direction, |
157 | struct dma_attrs *attrs) | ||
159 | { | 158 | { |
160 | } | 159 | } |
161 | 160 | ||
162 | static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, | 161 | static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, |
163 | int nents, enum dma_data_direction direction) | 162 | int nents, enum dma_data_direction direction, |
163 | struct dma_attrs *attrs) | ||
164 | { | 164 | { |
165 | struct scatterlist *sg; | 165 | struct scatterlist *sg; |
166 | int i; | 166 | int i; |
@@ -174,7 +174,8 @@ static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, | |||
174 | } | 174 | } |
175 | 175 | ||
176 | static void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sg, | 176 | static void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sg, |
177 | int nents, enum dma_data_direction direction) | 177 | int nents, enum dma_data_direction direction, |
178 | struct dma_attrs *attrs) | ||
178 | { | 179 | { |
179 | } | 180 | } |
180 | 181 | ||
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 0c8614d9875c..da52269aec1e 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <asm/ppc_asm.h> | 30 | #include <asm/ppc_asm.h> |
31 | #include <asm/asm-offsets.h> | 31 | #include <asm/asm-offsets.h> |
32 | #include <asm/unistd.h> | 32 | #include <asm/unistd.h> |
33 | #include <asm/ftrace.h> | ||
33 | 34 | ||
34 | #undef SHOW_SYSCALLS | 35 | #undef SHOW_SYSCALLS |
35 | #undef SHOW_SYSCALLS_TASK | 36 | #undef SHOW_SYSCALLS_TASK |
@@ -44,29 +45,54 @@ | |||
44 | #endif | 45 | #endif |
45 | 46 | ||
46 | #ifdef CONFIG_BOOKE | 47 | #ifdef CONFIG_BOOKE |
47 | #include "head_booke.h" | ||
48 | #define TRANSFER_TO_HANDLER_EXC_LEVEL(exc_level) \ | ||
49 | mtspr exc_level##_SPRG,r8; \ | ||
50 | BOOKE_LOAD_EXC_LEVEL_STACK(exc_level); \ | ||
51 | lwz r0,GPR10-INT_FRAME_SIZE(r8); \ | ||
52 | stw r0,GPR10(r11); \ | ||
53 | lwz r0,GPR11-INT_FRAME_SIZE(r8); \ | ||
54 | stw r0,GPR11(r11); \ | ||
55 | mfspr r8,exc_level##_SPRG | ||
56 | |||
57 | .globl mcheck_transfer_to_handler | 48 | .globl mcheck_transfer_to_handler |
58 | mcheck_transfer_to_handler: | 49 | mcheck_transfer_to_handler: |
59 | TRANSFER_TO_HANDLER_EXC_LEVEL(MCHECK) | 50 | mfspr r0,SPRN_DSRR0 |
60 | b transfer_to_handler_full | 51 | stw r0,_DSRR0(r11) |
52 | mfspr r0,SPRN_DSRR1 | ||
53 | stw r0,_DSRR1(r11) | ||
54 | /* fall through */ | ||
61 | 55 | ||
62 | .globl debug_transfer_to_handler | 56 | .globl debug_transfer_to_handler |
63 | debug_transfer_to_handler: | 57 | debug_transfer_to_handler: |
64 | TRANSFER_TO_HANDLER_EXC_LEVEL(DEBUG) | 58 | mfspr r0,SPRN_CSRR0 |
65 | b transfer_to_handler_full | 59 | stw r0,_CSRR0(r11) |
60 | mfspr r0,SPRN_CSRR1 | ||
61 | stw r0,_CSRR1(r11) | ||
62 | /* fall through */ | ||
66 | 63 | ||
67 | .globl crit_transfer_to_handler | 64 | .globl crit_transfer_to_handler |
68 | crit_transfer_to_handler: | 65 | crit_transfer_to_handler: |
69 | TRANSFER_TO_HANDLER_EXC_LEVEL(CRIT) | 66 | #ifdef CONFIG_FSL_BOOKE |
67 | mfspr r0,SPRN_MAS0 | ||
68 | stw r0,MAS0(r11) | ||
69 | mfspr r0,SPRN_MAS1 | ||
70 | stw r0,MAS1(r11) | ||
71 | mfspr r0,SPRN_MAS2 | ||
72 | stw r0,MAS2(r11) | ||
73 | mfspr r0,SPRN_MAS3 | ||
74 | stw r0,MAS3(r11) | ||
75 | mfspr r0,SPRN_MAS6 | ||
76 | stw r0,MAS6(r11) | ||
77 | #ifdef CONFIG_PHYS_64BIT | ||
78 | mfspr r0,SPRN_MAS7 | ||
79 | stw r0,MAS7(r11) | ||
80 | #endif /* CONFIG_PHYS_64BIT */ | ||
81 | #endif /* CONFIG_FSL_BOOKE */ | ||
82 | #ifdef CONFIG_44x | ||
83 | mfspr r0,SPRN_MMUCR | ||
84 | stw r0,MMUCR(r11) | ||
85 | #endif | ||
86 | mfspr r0,SPRN_SRR0 | ||
87 | stw r0,_SRR0(r11) | ||
88 | mfspr r0,SPRN_SRR1 | ||
89 | stw r0,_SRR1(r11) | ||
90 | |||
91 | mfspr r8,SPRN_SPRG3 | ||
92 | lwz r0,KSP_LIMIT(r8) | ||
93 | stw r0,SAVED_KSP_LIMIT(r11) | ||
94 | rlwimi r0,r1,0,0,(31-THREAD_SHIFT) | ||
95 | stw r0,KSP_LIMIT(r8) | ||
70 | /* fall through */ | 96 | /* fall through */ |
71 | #endif | 97 | #endif |
72 | 98 | ||
@@ -77,6 +103,16 @@ crit_transfer_to_handler: | |||
77 | stw r0,GPR10(r11) | 103 | stw r0,GPR10(r11) |
78 | lwz r0,crit_r11@l(0) | 104 | lwz r0,crit_r11@l(0) |
79 | stw r0,GPR11(r11) | 105 | stw r0,GPR11(r11) |
106 | mfspr r0,SPRN_SRR0 | ||
107 | stw r0,crit_srr0@l(0) | ||
108 | mfspr r0,SPRN_SRR1 | ||
109 | stw r0,crit_srr1@l(0) | ||
110 | |||
111 | mfspr r8,SPRN_SPRG3 | ||
112 | lwz r0,KSP_LIMIT(r8) | ||
113 | stw r0,saved_ksp_limit@l(0) | ||
114 | rlwimi r0,r1,0,0,(31-THREAD_SHIFT) | ||
115 | stw r0,KSP_LIMIT(r8) | ||
80 | /* fall through */ | 116 | /* fall through */ |
81 | #endif | 117 | #endif |
82 | 118 | ||
@@ -141,13 +177,14 @@ transfer_to_handler: | |||
141 | cmplw r1,r9 /* if r1 <= ksp_limit */ | 177 | cmplw r1,r9 /* if r1 <= ksp_limit */ |
142 | ble- stack_ovf /* then the kernel stack overflowed */ | 178 | ble- stack_ovf /* then the kernel stack overflowed */ |
143 | 5: | 179 | 5: |
144 | #ifdef CONFIG_6xx | 180 | #if defined(CONFIG_6xx) || defined(CONFIG_E500) |
145 | rlwinm r9,r1,0,0,31-THREAD_SHIFT | 181 | rlwinm r9,r1,0,0,31-THREAD_SHIFT |
146 | tophys(r9,r9) /* check local flags */ | 182 | tophys(r9,r9) /* check local flags */ |
147 | lwz r12,TI_LOCAL_FLAGS(r9) | 183 | lwz r12,TI_LOCAL_FLAGS(r9) |
148 | mtcrf 0x01,r12 | 184 | mtcrf 0x01,r12 |
149 | bt- 31-TLF_NAPPING,4f | 185 | bt- 31-TLF_NAPPING,4f |
150 | #endif /* CONFIG_6xx */ | 186 | bt- 31-TLF_SLEEPING,7f |
187 | #endif /* CONFIG_6xx || CONFIG_E500 */ | ||
151 | .globl transfer_to_handler_cont | 188 | .globl transfer_to_handler_cont |
152 | transfer_to_handler_cont: | 189 | transfer_to_handler_cont: |
153 | 3: | 190 | 3: |
@@ -160,10 +197,17 @@ transfer_to_handler_cont: | |||
160 | SYNC | 197 | SYNC |
161 | RFI /* jump to handler, enable MMU */ | 198 | RFI /* jump to handler, enable MMU */ |
162 | 199 | ||
163 | #ifdef CONFIG_6xx | 200 | #if defined (CONFIG_6xx) || defined(CONFIG_E500) |
164 | 4: rlwinm r12,r12,0,~_TLF_NAPPING | 201 | 4: rlwinm r12,r12,0,~_TLF_NAPPING |
165 | stw r12,TI_LOCAL_FLAGS(r9) | 202 | stw r12,TI_LOCAL_FLAGS(r9) |
166 | b power_save_6xx_restore | 203 | b power_save_ppc32_restore |
204 | |||
205 | 7: rlwinm r12,r12,0,~_TLF_SLEEPING | ||
206 | stw r12,TI_LOCAL_FLAGS(r9) | ||
207 | lwz r9,_MSR(r11) /* if sleeping, clear MSR.EE */ | ||
208 | rlwinm r9,r9,0,~MSR_EE | ||
209 | lwz r12,_LINK(r11) /* and return to address in LR */ | ||
210 | b fast_exception_return | ||
167 | #endif | 211 | #endif |
168 | 212 | ||
169 | /* | 213 | /* |
@@ -668,7 +712,7 @@ user_exc_return: /* r10 contains MSR_KERNEL here */ | |||
668 | /* Check current_thread_info()->flags */ | 712 | /* Check current_thread_info()->flags */ |
669 | rlwinm r9,r1,0,0,(31-THREAD_SHIFT) | 713 | rlwinm r9,r1,0,0,(31-THREAD_SHIFT) |
670 | lwz r9,TI_FLAGS(r9) | 714 | lwz r9,TI_FLAGS(r9) |
671 | andi. r0,r9,(_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK|_TIF_NEED_RESCHED) | 715 | andi. r0,r9,_TIF_USER_WORK_MASK |
672 | bne do_work | 716 | bne do_work |
673 | 717 | ||
674 | restore_user: | 718 | restore_user: |
@@ -859,17 +903,90 @@ exc_exit_restart_end: | |||
859 | exc_lvl_rfi; \ | 903 | exc_lvl_rfi; \ |
860 | b .; /* prevent prefetch past exc_lvl_rfi */ | 904 | b .; /* prevent prefetch past exc_lvl_rfi */ |
861 | 905 | ||
906 | #define RESTORE_xSRR(exc_lvl_srr0, exc_lvl_srr1) \ | ||
907 | lwz r9,_##exc_lvl_srr0(r1); \ | ||
908 | lwz r10,_##exc_lvl_srr1(r1); \ | ||
909 | mtspr SPRN_##exc_lvl_srr0,r9; \ | ||
910 | mtspr SPRN_##exc_lvl_srr1,r10; | ||
911 | |||
912 | #if defined(CONFIG_FSL_BOOKE) | ||
913 | #ifdef CONFIG_PHYS_64BIT | ||
914 | #define RESTORE_MAS7 \ | ||
915 | lwz r11,MAS7(r1); \ | ||
916 | mtspr SPRN_MAS7,r11; | ||
917 | #else | ||
918 | #define RESTORE_MAS7 | ||
919 | #endif /* CONFIG_PHYS_64BIT */ | ||
920 | #define RESTORE_MMU_REGS \ | ||
921 | lwz r9,MAS0(r1); \ | ||
922 | lwz r10,MAS1(r1); \ | ||
923 | lwz r11,MAS2(r1); \ | ||
924 | mtspr SPRN_MAS0,r9; \ | ||
925 | lwz r9,MAS3(r1); \ | ||
926 | mtspr SPRN_MAS1,r10; \ | ||
927 | lwz r10,MAS6(r1); \ | ||
928 | mtspr SPRN_MAS2,r11; \ | ||
929 | mtspr SPRN_MAS3,r9; \ | ||
930 | mtspr SPRN_MAS6,r10; \ | ||
931 | RESTORE_MAS7; | ||
932 | #elif defined(CONFIG_44x) | ||
933 | #define RESTORE_MMU_REGS \ | ||
934 | lwz r9,MMUCR(r1); \ | ||
935 | mtspr SPRN_MMUCR,r9; | ||
936 | #else | ||
937 | #define RESTORE_MMU_REGS | ||
938 | #endif | ||
939 | |||
940 | #ifdef CONFIG_40x | ||
862 | .globl ret_from_crit_exc | 941 | .globl ret_from_crit_exc |
863 | ret_from_crit_exc: | 942 | ret_from_crit_exc: |
943 | mfspr r9,SPRN_SPRG3 | ||
944 | lis r10,saved_ksp_limit@ha; | ||
945 | lwz r10,saved_ksp_limit@l(r10); | ||
946 | tovirt(r9,r9); | ||
947 | stw r10,KSP_LIMIT(r9) | ||
948 | lis r9,crit_srr0@ha; | ||
949 | lwz r9,crit_srr0@l(r9); | ||
950 | lis r10,crit_srr1@ha; | ||
951 | lwz r10,crit_srr1@l(r10); | ||
952 | mtspr SPRN_SRR0,r9; | ||
953 | mtspr SPRN_SRR1,r10; | ||
864 | RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, RFCI) | 954 | RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, RFCI) |
955 | #endif /* CONFIG_40x */ | ||
865 | 956 | ||
866 | #ifdef CONFIG_BOOKE | 957 | #ifdef CONFIG_BOOKE |
958 | .globl ret_from_crit_exc | ||
959 | ret_from_crit_exc: | ||
960 | mfspr r9,SPRN_SPRG3 | ||
961 | lwz r10,SAVED_KSP_LIMIT(r1) | ||
962 | stw r10,KSP_LIMIT(r9) | ||
963 | RESTORE_xSRR(SRR0,SRR1); | ||
964 | RESTORE_MMU_REGS; | ||
965 | RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, RFCI) | ||
966 | |||
867 | .globl ret_from_debug_exc | 967 | .globl ret_from_debug_exc |
868 | ret_from_debug_exc: | 968 | ret_from_debug_exc: |
969 | mfspr r9,SPRN_SPRG3 | ||
970 | lwz r10,SAVED_KSP_LIMIT(r1) | ||
971 | stw r10,KSP_LIMIT(r9) | ||
972 | lwz r9,THREAD_INFO-THREAD(r9) | ||
973 | rlwinm r10,r1,0,0,(31-THREAD_SHIFT) | ||
974 | lwz r10,TI_PREEMPT(r10) | ||
975 | stw r10,TI_PREEMPT(r9) | ||
976 | RESTORE_xSRR(SRR0,SRR1); | ||
977 | RESTORE_xSRR(CSRR0,CSRR1); | ||
978 | RESTORE_MMU_REGS; | ||
869 | RET_FROM_EXC_LEVEL(SPRN_DSRR0, SPRN_DSRR1, RFDI) | 979 | RET_FROM_EXC_LEVEL(SPRN_DSRR0, SPRN_DSRR1, RFDI) |
870 | 980 | ||
871 | .globl ret_from_mcheck_exc | 981 | .globl ret_from_mcheck_exc |
872 | ret_from_mcheck_exc: | 982 | ret_from_mcheck_exc: |
983 | mfspr r9,SPRN_SPRG3 | ||
984 | lwz r10,SAVED_KSP_LIMIT(r1) | ||
985 | stw r10,KSP_LIMIT(r9) | ||
986 | RESTORE_xSRR(SRR0,SRR1); | ||
987 | RESTORE_xSRR(CSRR0,CSRR1); | ||
988 | RESTORE_xSRR(DSRR0,DSRR1); | ||
989 | RESTORE_MMU_REGS; | ||
873 | RET_FROM_EXC_LEVEL(SPRN_MCSRR0, SPRN_MCSRR1, RFMCI) | 990 | RET_FROM_EXC_LEVEL(SPRN_MCSRR0, SPRN_MCSRR1, RFMCI) |
874 | #endif /* CONFIG_BOOKE */ | 991 | #endif /* CONFIG_BOOKE */ |
875 | 992 | ||
@@ -925,7 +1042,7 @@ recheck: | |||
925 | lwz r9,TI_FLAGS(r9) | 1042 | lwz r9,TI_FLAGS(r9) |
926 | andi. r0,r9,_TIF_NEED_RESCHED | 1043 | andi. r0,r9,_TIF_NEED_RESCHED |
927 | bne- do_resched | 1044 | bne- do_resched |
928 | andi. r0,r9,_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK | 1045 | andi. r0,r9,_TIF_USER_WORK_MASK |
929 | beq restore_user | 1046 | beq restore_user |
930 | do_user_signal: /* r10 contains MSR_KERNEL here */ | 1047 | do_user_signal: /* r10 contains MSR_KERNEL here */ |
931 | ori r10,r10,MSR_EE | 1048 | ori r10,r10,MSR_EE |
@@ -1035,3 +1152,129 @@ machine_check_in_rtas: | |||
1035 | /* XXX load up BATs and panic */ | 1152 | /* XXX load up BATs and panic */ |
1036 | 1153 | ||
1037 | #endif /* CONFIG_PPC_RTAS */ | 1154 | #endif /* CONFIG_PPC_RTAS */ |
1155 | |||
1156 | #ifdef CONFIG_FTRACE | ||
1157 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
1158 | _GLOBAL(mcount) | ||
1159 | _GLOBAL(_mcount) | ||
1160 | stwu r1,-48(r1) | ||
1161 | stw r3, 12(r1) | ||
1162 | stw r4, 16(r1) | ||
1163 | stw r5, 20(r1) | ||
1164 | stw r6, 24(r1) | ||
1165 | mflr r3 | ||
1166 | stw r7, 28(r1) | ||
1167 | mfcr r5 | ||
1168 | stw r8, 32(r1) | ||
1169 | stw r9, 36(r1) | ||
1170 | stw r10,40(r1) | ||
1171 | stw r3, 44(r1) | ||
1172 | stw r5, 8(r1) | ||
1173 | subi r3, r3, MCOUNT_INSN_SIZE | ||
1174 | .globl mcount_call | ||
1175 | mcount_call: | ||
1176 | bl ftrace_stub | ||
1177 | nop | ||
1178 | lwz r6, 8(r1) | ||
1179 | lwz r0, 44(r1) | ||
1180 | lwz r3, 12(r1) | ||
1181 | mtctr r0 | ||
1182 | lwz r4, 16(r1) | ||
1183 | mtcr r6 | ||
1184 | lwz r5, 20(r1) | ||
1185 | lwz r6, 24(r1) | ||
1186 | lwz r0, 52(r1) | ||
1187 | lwz r7, 28(r1) | ||
1188 | lwz r8, 32(r1) | ||
1189 | mtlr r0 | ||
1190 | lwz r9, 36(r1) | ||
1191 | lwz r10,40(r1) | ||
1192 | addi r1, r1, 48 | ||
1193 | bctr | ||
1194 | |||
1195 | _GLOBAL(ftrace_caller) | ||
1196 | /* Based off of objdump optput from glibc */ | ||
1197 | stwu r1,-48(r1) | ||
1198 | stw r3, 12(r1) | ||
1199 | stw r4, 16(r1) | ||
1200 | stw r5, 20(r1) | ||
1201 | stw r6, 24(r1) | ||
1202 | mflr r3 | ||
1203 | lwz r4, 52(r1) | ||
1204 | mfcr r5 | ||
1205 | stw r7, 28(r1) | ||
1206 | stw r8, 32(r1) | ||
1207 | stw r9, 36(r1) | ||
1208 | stw r10,40(r1) | ||
1209 | stw r3, 44(r1) | ||
1210 | stw r5, 8(r1) | ||
1211 | subi r3, r3, MCOUNT_INSN_SIZE | ||
1212 | .globl ftrace_call | ||
1213 | ftrace_call: | ||
1214 | bl ftrace_stub | ||
1215 | nop | ||
1216 | lwz r6, 8(r1) | ||
1217 | lwz r0, 44(r1) | ||
1218 | lwz r3, 12(r1) | ||
1219 | mtctr r0 | ||
1220 | lwz r4, 16(r1) | ||
1221 | mtcr r6 | ||
1222 | lwz r5, 20(r1) | ||
1223 | lwz r6, 24(r1) | ||
1224 | lwz r0, 52(r1) | ||
1225 | lwz r7, 28(r1) | ||
1226 | lwz r8, 32(r1) | ||
1227 | mtlr r0 | ||
1228 | lwz r9, 36(r1) | ||
1229 | lwz r10,40(r1) | ||
1230 | addi r1, r1, 48 | ||
1231 | bctr | ||
1232 | #else | ||
1233 | _GLOBAL(mcount) | ||
1234 | _GLOBAL(_mcount) | ||
1235 | stwu r1,-48(r1) | ||
1236 | stw r3, 12(r1) | ||
1237 | stw r4, 16(r1) | ||
1238 | stw r5, 20(r1) | ||
1239 | stw r6, 24(r1) | ||
1240 | mflr r3 | ||
1241 | lwz r4, 52(r1) | ||
1242 | mfcr r5 | ||
1243 | stw r7, 28(r1) | ||
1244 | stw r8, 32(r1) | ||
1245 | stw r9, 36(r1) | ||
1246 | stw r10,40(r1) | ||
1247 | stw r3, 44(r1) | ||
1248 | stw r5, 8(r1) | ||
1249 | |||
1250 | subi r3, r3, MCOUNT_INSN_SIZE | ||
1251 | LOAD_REG_ADDR(r5, ftrace_trace_function) | ||
1252 | lwz r5,0(r5) | ||
1253 | |||
1254 | mtctr r5 | ||
1255 | bctrl | ||
1256 | |||
1257 | nop | ||
1258 | |||
1259 | lwz r6, 8(r1) | ||
1260 | lwz r0, 44(r1) | ||
1261 | lwz r3, 12(r1) | ||
1262 | mtctr r0 | ||
1263 | lwz r4, 16(r1) | ||
1264 | mtcr r6 | ||
1265 | lwz r5, 20(r1) | ||
1266 | lwz r6, 24(r1) | ||
1267 | lwz r0, 52(r1) | ||
1268 | lwz r7, 28(r1) | ||
1269 | lwz r8, 32(r1) | ||
1270 | mtlr r0 | ||
1271 | lwz r9, 36(r1) | ||
1272 | lwz r10,40(r1) | ||
1273 | addi r1, r1, 48 | ||
1274 | bctr | ||
1275 | #endif | ||
1276 | |||
1277 | _GLOBAL(ftrace_stub) | ||
1278 | blr | ||
1279 | |||
1280 | #endif /* CONFIG_MCOUNT */ | ||
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index c0db5b769e55..d7369243ae44 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <asm/bug.h> | 31 | #include <asm/bug.h> |
32 | #include <asm/ptrace.h> | 32 | #include <asm/ptrace.h> |
33 | #include <asm/irqflags.h> | 33 | #include <asm/irqflags.h> |
34 | #include <asm/ftrace.h> | ||
34 | 35 | ||
35 | /* | 36 | /* |
36 | * System calls. | 37 | * System calls. |
@@ -353,6 +354,11 @@ _GLOBAL(_switch) | |||
353 | mflr r20 /* Return to switch caller */ | 354 | mflr r20 /* Return to switch caller */ |
354 | mfmsr r22 | 355 | mfmsr r22 |
355 | li r0, MSR_FP | 356 | li r0, MSR_FP |
357 | #ifdef CONFIG_VSX | ||
358 | BEGIN_FTR_SECTION | ||
359 | oris r0,r0,MSR_VSX@h /* Disable VSX */ | ||
360 | END_FTR_SECTION_IFSET(CPU_FTR_VSX) | ||
361 | #endif /* CONFIG_VSX */ | ||
356 | #ifdef CONFIG_ALTIVEC | 362 | #ifdef CONFIG_ALTIVEC |
357 | BEGIN_FTR_SECTION | 363 | BEGIN_FTR_SECTION |
358 | oris r0,r0,MSR_VEC@h /* Disable altivec */ | 364 | oris r0,r0,MSR_VEC@h /* Disable altivec */ |
@@ -383,16 +389,16 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) | |||
383 | 389 | ||
384 | ld r8,KSP(r4) /* new stack pointer */ | 390 | ld r8,KSP(r4) /* new stack pointer */ |
385 | BEGIN_FTR_SECTION | 391 | BEGIN_FTR_SECTION |
386 | b 2f | 392 | BEGIN_FTR_SECTION_NESTED(95) |
387 | END_FTR_SECTION_IFCLR(CPU_FTR_SLB) | ||
388 | BEGIN_FTR_SECTION | ||
389 | clrrdi r6,r8,28 /* get its ESID */ | 393 | clrrdi r6,r8,28 /* get its ESID */ |
390 | clrrdi r9,r1,28 /* get current sp ESID */ | 394 | clrrdi r9,r1,28 /* get current sp ESID */ |
391 | END_FTR_SECTION_IFCLR(CPU_FTR_1T_SEGMENT) | 395 | FTR_SECTION_ELSE_NESTED(95) |
392 | BEGIN_FTR_SECTION | ||
393 | clrrdi r6,r8,40 /* get its 1T ESID */ | 396 | clrrdi r6,r8,40 /* get its 1T ESID */ |
394 | clrrdi r9,r1,40 /* get current sp 1T ESID */ | 397 | clrrdi r9,r1,40 /* get current sp 1T ESID */ |
395 | END_FTR_SECTION_IFSET(CPU_FTR_1T_SEGMENT) | 398 | ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_1T_SEGMENT, 95) |
399 | FTR_SECTION_ELSE | ||
400 | b 2f | ||
401 | ALT_FTR_SECTION_END_IFSET(CPU_FTR_SLB) | ||
396 | clrldi. r0,r6,2 /* is new ESID c00000000? */ | 402 | clrldi. r0,r6,2 /* is new ESID c00000000? */ |
397 | cmpd cr1,r6,r9 /* or is new ESID the same as current ESID? */ | 403 | cmpd cr1,r6,r9 /* or is new ESID the same as current ESID? */ |
398 | cror eq,4*cr1+eq,eq | 404 | cror eq,4*cr1+eq,eq |
@@ -870,3 +876,67 @@ _GLOBAL(enter_prom) | |||
870 | ld r0,16(r1) | 876 | ld r0,16(r1) |
871 | mtlr r0 | 877 | mtlr r0 |
872 | blr | 878 | blr |
879 | |||
880 | #ifdef CONFIG_FTRACE | ||
881 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
882 | _GLOBAL(mcount) | ||
883 | _GLOBAL(_mcount) | ||
884 | /* Taken from output of objdump from lib64/glibc */ | ||
885 | mflr r3 | ||
886 | stdu r1, -112(r1) | ||
887 | std r3, 128(r1) | ||
888 | subi r3, r3, MCOUNT_INSN_SIZE | ||
889 | .globl mcount_call | ||
890 | mcount_call: | ||
891 | bl ftrace_stub | ||
892 | nop | ||
893 | ld r0, 128(r1) | ||
894 | mtlr r0 | ||
895 | addi r1, r1, 112 | ||
896 | blr | ||
897 | |||
898 | _GLOBAL(ftrace_caller) | ||
899 | /* Taken from output of objdump from lib64/glibc */ | ||
900 | mflr r3 | ||
901 | ld r11, 0(r1) | ||
902 | stdu r1, -112(r1) | ||
903 | std r3, 128(r1) | ||
904 | ld r4, 16(r11) | ||
905 | subi r3, r3, MCOUNT_INSN_SIZE | ||
906 | .globl ftrace_call | ||
907 | ftrace_call: | ||
908 | bl ftrace_stub | ||
909 | nop | ||
910 | ld r0, 128(r1) | ||
911 | mtlr r0 | ||
912 | addi r1, r1, 112 | ||
913 | _GLOBAL(ftrace_stub) | ||
914 | blr | ||
915 | #else | ||
916 | _GLOBAL(mcount) | ||
917 | blr | ||
918 | |||
919 | _GLOBAL(_mcount) | ||
920 | /* Taken from output of objdump from lib64/glibc */ | ||
921 | mflr r3 | ||
922 | ld r11, 0(r1) | ||
923 | stdu r1, -112(r1) | ||
924 | std r3, 128(r1) | ||
925 | ld r4, 16(r11) | ||
926 | |||
927 | subi r3, r3, MCOUNT_INSN_SIZE | ||
928 | LOAD_REG_ADDR(r5,ftrace_trace_function) | ||
929 | ld r5,0(r5) | ||
930 | ld r5,0(r5) | ||
931 | mtctr r5 | ||
932 | bctrl | ||
933 | |||
934 | nop | ||
935 | ld r0, 128(r1) | ||
936 | mtlr r0 | ||
937 | addi r1, r1, 112 | ||
938 | _GLOBAL(ftrace_stub) | ||
939 | blr | ||
940 | |||
941 | #endif | ||
942 | #endif | ||
diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S index 821e152e093c..a088c064ae40 100644 --- a/arch/powerpc/kernel/fpu.S +++ b/arch/powerpc/kernel/fpu.S | |||
@@ -24,6 +24,29 @@ | |||
24 | #include <asm/ppc_asm.h> | 24 | #include <asm/ppc_asm.h> |
25 | #include <asm/asm-offsets.h> | 25 | #include <asm/asm-offsets.h> |
26 | 26 | ||
27 | #ifdef CONFIG_VSX | ||
28 | #define REST_32FPVSRS(n,c,base) \ | ||
29 | BEGIN_FTR_SECTION \ | ||
30 | b 2f; \ | ||
31 | END_FTR_SECTION_IFSET(CPU_FTR_VSX); \ | ||
32 | REST_32FPRS(n,base); \ | ||
33 | b 3f; \ | ||
34 | 2: REST_32VSRS(n,c,base); \ | ||
35 | 3: | ||
36 | |||
37 | #define SAVE_32FPVSRS(n,c,base) \ | ||
38 | BEGIN_FTR_SECTION \ | ||
39 | b 2f; \ | ||
40 | END_FTR_SECTION_IFSET(CPU_FTR_VSX); \ | ||
41 | SAVE_32FPRS(n,base); \ | ||
42 | b 3f; \ | ||
43 | 2: SAVE_32VSRS(n,c,base); \ | ||
44 | 3: | ||
45 | #else | ||
46 | #define REST_32FPVSRS(n,b,base) REST_32FPRS(n, base) | ||
47 | #define SAVE_32FPVSRS(n,b,base) SAVE_32FPRS(n, base) | ||
48 | #endif | ||
49 | |||
27 | /* | 50 | /* |
28 | * This task wants to use the FPU now. | 51 | * This task wants to use the FPU now. |
29 | * On UP, disable FP for the task which had the FPU previously, | 52 | * On UP, disable FP for the task which had the FPU previously, |
@@ -34,6 +57,11 @@ | |||
34 | _GLOBAL(load_up_fpu) | 57 | _GLOBAL(load_up_fpu) |
35 | mfmsr r5 | 58 | mfmsr r5 |
36 | ori r5,r5,MSR_FP | 59 | ori r5,r5,MSR_FP |
60 | #ifdef CONFIG_VSX | ||
61 | BEGIN_FTR_SECTION | ||
62 | oris r5,r5,MSR_VSX@h | ||
63 | END_FTR_SECTION_IFSET(CPU_FTR_VSX) | ||
64 | #endif | ||
37 | SYNC | 65 | SYNC |
38 | MTMSRD(r5) /* enable use of fpu now */ | 66 | MTMSRD(r5) /* enable use of fpu now */ |
39 | isync | 67 | isync |
@@ -50,7 +78,7 @@ _GLOBAL(load_up_fpu) | |||
50 | beq 1f | 78 | beq 1f |
51 | toreal(r4) | 79 | toreal(r4) |
52 | addi r4,r4,THREAD /* want last_task_used_math->thread */ | 80 | addi r4,r4,THREAD /* want last_task_used_math->thread */ |
53 | SAVE_32FPRS(0, r4) | 81 | SAVE_32FPVSRS(0, r5, r4) |
54 | mffs fr0 | 82 | mffs fr0 |
55 | stfd fr0,THREAD_FPSCR(r4) | 83 | stfd fr0,THREAD_FPSCR(r4) |
56 | PPC_LL r5,PT_REGS(r4) | 84 | PPC_LL r5,PT_REGS(r4) |
@@ -77,7 +105,7 @@ _GLOBAL(load_up_fpu) | |||
77 | #endif | 105 | #endif |
78 | lfd fr0,THREAD_FPSCR(r5) | 106 | lfd fr0,THREAD_FPSCR(r5) |
79 | MTFSF_L(fr0) | 107 | MTFSF_L(fr0) |
80 | REST_32FPRS(0, r5) | 108 | REST_32FPVSRS(0, r4, r5) |
81 | #ifndef CONFIG_SMP | 109 | #ifndef CONFIG_SMP |
82 | subi r4,r5,THREAD | 110 | subi r4,r5,THREAD |
83 | fromreal(r4) | 111 | fromreal(r4) |
@@ -85,7 +113,7 @@ _GLOBAL(load_up_fpu) | |||
85 | #endif /* CONFIG_SMP */ | 113 | #endif /* CONFIG_SMP */ |
86 | /* restore registers and return */ | 114 | /* restore registers and return */ |
87 | /* we haven't used ctr or xer or lr */ | 115 | /* we haven't used ctr or xer or lr */ |
88 | b fast_exception_return | 116 | blr |
89 | 117 | ||
90 | /* | 118 | /* |
91 | * giveup_fpu(tsk) | 119 | * giveup_fpu(tsk) |
@@ -96,6 +124,11 @@ _GLOBAL(load_up_fpu) | |||
96 | _GLOBAL(giveup_fpu) | 124 | _GLOBAL(giveup_fpu) |
97 | mfmsr r5 | 125 | mfmsr r5 |
98 | ori r5,r5,MSR_FP | 126 | ori r5,r5,MSR_FP |
127 | #ifdef CONFIG_VSX | ||
128 | BEGIN_FTR_SECTION | ||
129 | oris r5,r5,MSR_VSX@h | ||
130 | END_FTR_SECTION_IFSET(CPU_FTR_VSX) | ||
131 | #endif | ||
99 | SYNC_601 | 132 | SYNC_601 |
100 | ISYNC_601 | 133 | ISYNC_601 |
101 | MTMSRD(r5) /* enable use of fpu now */ | 134 | MTMSRD(r5) /* enable use of fpu now */ |
@@ -106,7 +139,7 @@ _GLOBAL(giveup_fpu) | |||
106 | addi r3,r3,THREAD /* want THREAD of task */ | 139 | addi r3,r3,THREAD /* want THREAD of task */ |
107 | PPC_LL r5,PT_REGS(r3) | 140 | PPC_LL r5,PT_REGS(r3) |
108 | PPC_LCMPI 0,r5,0 | 141 | PPC_LCMPI 0,r5,0 |
109 | SAVE_32FPRS(0, r3) | 142 | SAVE_32FPVSRS(0, r4 ,r3) |
110 | mffs fr0 | 143 | mffs fr0 |
111 | stfd fr0,THREAD_FPSCR(r3) | 144 | stfd fr0,THREAD_FPSCR(r3) |
112 | beq 1f | 145 | beq 1f |
diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c new file mode 100644 index 000000000000..3855ceb937b0 --- /dev/null +++ b/arch/powerpc/kernel/ftrace.c | |||
@@ -0,0 +1,154 @@ | |||
1 | /* | ||
2 | * Code for replacing ftrace calls with jumps. | ||
3 | * | ||
4 | * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com> | ||
5 | * | ||
6 | * Thanks goes out to P.A. Semi, Inc for supplying me with a PPC64 box. | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include <linux/spinlock.h> | ||
11 | #include <linux/hardirq.h> | ||
12 | #include <linux/ftrace.h> | ||
13 | #include <linux/percpu.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/list.h> | ||
16 | |||
17 | #include <asm/cacheflush.h> | ||
18 | #include <asm/ftrace.h> | ||
19 | |||
20 | |||
21 | static unsigned int ftrace_nop = 0x60000000; | ||
22 | |||
23 | #ifdef CONFIG_PPC32 | ||
24 | # define GET_ADDR(addr) addr | ||
25 | #else | ||
26 | /* PowerPC64's functions are data that points to the functions */ | ||
27 | # define GET_ADDR(addr) *(unsigned long *)addr | ||
28 | #endif | ||
29 | |||
30 | |||
31 | static unsigned int notrace ftrace_calc_offset(long ip, long addr) | ||
32 | { | ||
33 | return (int)(addr - ip); | ||
34 | } | ||
35 | |||
36 | notrace unsigned char *ftrace_nop_replace(void) | ||
37 | { | ||
38 | return (char *)&ftrace_nop; | ||
39 | } | ||
40 | |||
41 | notrace unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) | ||
42 | { | ||
43 | static unsigned int op; | ||
44 | |||
45 | /* | ||
46 | * It would be nice to just use create_function_call, but that will | ||
47 | * update the code itself. Here we need to just return the | ||
48 | * instruction that is going to be modified, without modifying the | ||
49 | * code. | ||
50 | */ | ||
51 | addr = GET_ADDR(addr); | ||
52 | |||
53 | /* Set to "bl addr" */ | ||
54 | op = 0x48000001 | (ftrace_calc_offset(ip, addr) & 0x03fffffc); | ||
55 | |||
56 | /* | ||
57 | * No locking needed, this must be called via kstop_machine | ||
58 | * which in essence is like running on a uniprocessor machine. | ||
59 | */ | ||
60 | return (unsigned char *)&op; | ||
61 | } | ||
62 | |||
63 | #ifdef CONFIG_PPC64 | ||
64 | # define _ASM_ALIGN " .align 3 " | ||
65 | # define _ASM_PTR " .llong " | ||
66 | #else | ||
67 | # define _ASM_ALIGN " .align 2 " | ||
68 | # define _ASM_PTR " .long " | ||
69 | #endif | ||
70 | |||
71 | notrace int | ||
72 | ftrace_modify_code(unsigned long ip, unsigned char *old_code, | ||
73 | unsigned char *new_code) | ||
74 | { | ||
75 | unsigned replaced; | ||
76 | unsigned old = *(unsigned *)old_code; | ||
77 | unsigned new = *(unsigned *)new_code; | ||
78 | int faulted = 0; | ||
79 | |||
80 | /* | ||
81 | * Note: Due to modules and __init, code can | ||
82 | * disappear and change, we need to protect against faulting | ||
83 | * as well as code changing. | ||
84 | * | ||
85 | * No real locking needed, this code is run through | ||
86 | * kstop_machine. | ||
87 | */ | ||
88 | asm volatile ( | ||
89 | "1: lwz %1, 0(%2)\n" | ||
90 | " cmpw %1, %5\n" | ||
91 | " bne 2f\n" | ||
92 | " stwu %3, 0(%2)\n" | ||
93 | "2:\n" | ||
94 | ".section .fixup, \"ax\"\n" | ||
95 | "3: li %0, 1\n" | ||
96 | " b 2b\n" | ||
97 | ".previous\n" | ||
98 | ".section __ex_table,\"a\"\n" | ||
99 | _ASM_ALIGN "\n" | ||
100 | _ASM_PTR "1b, 3b\n" | ||
101 | ".previous" | ||
102 | : "=r"(faulted), "=r"(replaced) | ||
103 | : "r"(ip), "r"(new), | ||
104 | "0"(faulted), "r"(old) | ||
105 | : "memory"); | ||
106 | |||
107 | if (replaced != old && replaced != new) | ||
108 | faulted = 2; | ||
109 | |||
110 | if (!faulted) | ||
111 | flush_icache_range(ip, ip + 8); | ||
112 | |||
113 | return faulted; | ||
114 | } | ||
115 | |||
116 | notrace int ftrace_update_ftrace_func(ftrace_func_t func) | ||
117 | { | ||
118 | unsigned long ip = (unsigned long)(&ftrace_call); | ||
119 | unsigned char old[MCOUNT_INSN_SIZE], *new; | ||
120 | int ret; | ||
121 | |||
122 | memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE); | ||
123 | new = ftrace_call_replace(ip, (unsigned long)func); | ||
124 | ret = ftrace_modify_code(ip, old, new); | ||
125 | |||
126 | return ret; | ||
127 | } | ||
128 | |||
129 | notrace int ftrace_mcount_set(unsigned long *data) | ||
130 | { | ||
131 | unsigned long ip = (long)(&mcount_call); | ||
132 | unsigned long *addr = data; | ||
133 | unsigned char old[MCOUNT_INSN_SIZE], *new; | ||
134 | |||
135 | /* | ||
136 | * Replace the mcount stub with a pointer to the | ||
137 | * ip recorder function. | ||
138 | */ | ||
139 | memcpy(old, &mcount_call, MCOUNT_INSN_SIZE); | ||
140 | new = ftrace_call_replace(ip, *addr); | ||
141 | *addr = ftrace_modify_code(ip, old, new); | ||
142 | |||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | int __init ftrace_dyn_arch_init(void *data) | ||
147 | { | ||
148 | /* This is running in kstop_machine */ | ||
149 | |||
150 | ftrace_mcount_set(data); | ||
151 | |||
152 | return 0; | ||
153 | } | ||
154 | |||
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index 785af9b56591..99ee2f0f0f2b 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S | |||
@@ -421,8 +421,10 @@ BEGIN_FTR_SECTION | |||
421 | b ProgramCheck | 421 | b ProgramCheck |
422 | END_FTR_SECTION_IFSET(CPU_FTR_FPU_UNAVAILABLE) | 422 | END_FTR_SECTION_IFSET(CPU_FTR_FPU_UNAVAILABLE) |
423 | EXCEPTION_PROLOG | 423 | EXCEPTION_PROLOG |
424 | bne load_up_fpu /* if from user, just load it up */ | 424 | beq 1f |
425 | addi r3,r1,STACK_FRAME_OVERHEAD | 425 | bl load_up_fpu /* if from user, just load it up */ |
426 | b fast_exception_return | ||
427 | 1: addi r3,r1,STACK_FRAME_OVERHEAD | ||
426 | EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception) | 428 | EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception) |
427 | 429 | ||
428 | /* Decrementer */ | 430 | /* Decrementer */ |
diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S index 8552e67e3a8b..56d8e5d90c5b 100644 --- a/arch/powerpc/kernel/head_40x.S +++ b/arch/powerpc/kernel/head_40x.S | |||
@@ -93,6 +93,12 @@ _ENTRY(crit_r10) | |||
93 | .space 4 | 93 | .space 4 |
94 | _ENTRY(crit_r11) | 94 | _ENTRY(crit_r11) |
95 | .space 4 | 95 | .space 4 |
96 | _ENTRY(crit_srr0) | ||
97 | .space 4 | ||
98 | _ENTRY(crit_srr1) | ||
99 | .space 4 | ||
100 | _ENTRY(saved_ksp_limit) | ||
101 | .space 4 | ||
96 | 102 | ||
97 | /* | 103 | /* |
98 | * Exception vector entry code. This code runs with address translation | 104 | * Exception vector entry code. This code runs with address translation |
@@ -148,14 +154,14 @@ _ENTRY(crit_r11) | |||
148 | mfcr r10; /* save CR in r10 for now */\ | 154 | mfcr r10; /* save CR in r10 for now */\ |
149 | mfspr r11,SPRN_SRR3; /* check whether user or kernel */\ | 155 | mfspr r11,SPRN_SRR3; /* check whether user or kernel */\ |
150 | andi. r11,r11,MSR_PR; \ | 156 | andi. r11,r11,MSR_PR; \ |
151 | lis r11,critical_stack_top@h; \ | 157 | lis r11,critirq_ctx@ha; \ |
152 | ori r11,r11,critical_stack_top@l; \ | 158 | tophys(r11,r11); \ |
159 | lwz r11,critirq_ctx@l(r11); \ | ||
153 | beq 1f; \ | 160 | beq 1f; \ |
154 | /* COMING FROM USER MODE */ \ | 161 | /* COMING FROM USER MODE */ \ |
155 | mfspr r11,SPRN_SPRG3; /* if from user, start at top of */\ | 162 | mfspr r11,SPRN_SPRG3; /* if from user, start at top of */\ |
156 | lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ | 163 | lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ |
157 | addi r11,r11,THREAD_SIZE; \ | 164 | 1: addi r11,r11,THREAD_SIZE-INT_FRAME_SIZE; /* Alloc an excpt frm */\ |
158 | 1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ | ||
159 | tophys(r11,r11); \ | 165 | tophys(r11,r11); \ |
160 | stw r10,_CCR(r11); /* save various registers */\ | 166 | stw r10,_CCR(r11); /* save various registers */\ |
161 | stw r12,GPR12(r11); \ | 167 | stw r12,GPR12(r11); \ |
@@ -996,16 +1002,6 @@ empty_zero_page: | |||
996 | swapper_pg_dir: | 1002 | swapper_pg_dir: |
997 | .space PGD_TABLE_SIZE | 1003 | .space PGD_TABLE_SIZE |
998 | 1004 | ||
999 | |||
1000 | /* Stack for handling critical exceptions from kernel mode */ | ||
1001 | .section .bss | ||
1002 | .align 12 | ||
1003 | exception_stack_bottom: | ||
1004 | .space 4096 | ||
1005 | critical_stack_top: | ||
1006 | .globl exception_stack_top | ||
1007 | exception_stack_top: | ||
1008 | |||
1009 | /* Room for two PTE pointers, usually the kernel and current user pointers | 1005 | /* Room for two PTE pointers, usually the kernel and current user pointers |
1010 | * to their respective root page table. | 1006 | * to their respective root page table. |
1011 | */ | 1007 | */ |
diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S index c2b9dc4fce5d..f3a1ea9d7fe4 100644 --- a/arch/powerpc/kernel/head_44x.S +++ b/arch/powerpc/kernel/head_44x.S | |||
@@ -293,114 +293,9 @@ interrupt_base: | |||
293 | MCHECK_EXCEPTION(0x0210, MachineCheckA, machine_check_exception) | 293 | MCHECK_EXCEPTION(0x0210, MachineCheckA, machine_check_exception) |
294 | 294 | ||
295 | /* Data Storage Interrupt */ | 295 | /* Data Storage Interrupt */ |
296 | START_EXCEPTION(DataStorage) | 296 | DATA_STORAGE_EXCEPTION |
297 | mtspr SPRN_SPRG0, r10 /* Save some working registers */ | ||
298 | mtspr SPRN_SPRG1, r11 | ||
299 | mtspr SPRN_SPRG4W, r12 | ||
300 | mtspr SPRN_SPRG5W, r13 | ||
301 | mfcr r11 | ||
302 | mtspr SPRN_SPRG7W, r11 | ||
303 | |||
304 | /* | ||
305 | * Check if it was a store fault, if not then bail | ||
306 | * because a user tried to access a kernel or | ||
307 | * read-protected page. Otherwise, get the | ||
308 | * offending address and handle it. | ||
309 | */ | ||
310 | mfspr r10, SPRN_ESR | ||
311 | andis. r10, r10, ESR_ST@h | ||
312 | beq 2f | ||
313 | |||
314 | mfspr r10, SPRN_DEAR /* Get faulting address */ | ||
315 | |||
316 | /* If we are faulting a kernel address, we have to use the | ||
317 | * kernel page tables. | ||
318 | */ | ||
319 | lis r11, PAGE_OFFSET@h | ||
320 | cmplw r10, r11 | ||
321 | blt+ 3f | ||
322 | lis r11, swapper_pg_dir@h | ||
323 | ori r11, r11, swapper_pg_dir@l | ||
324 | |||
325 | mfspr r12,SPRN_MMUCR | ||
326 | rlwinm r12,r12,0,0,23 /* Clear TID */ | ||
327 | |||
328 | b 4f | ||
329 | |||
330 | /* Get the PGD for the current thread */ | ||
331 | 3: | ||
332 | mfspr r11,SPRN_SPRG3 | ||
333 | lwz r11,PGDIR(r11) | ||
334 | |||
335 | /* Load PID into MMUCR TID */ | ||
336 | mfspr r12,SPRN_MMUCR /* Get MMUCR */ | ||
337 | mfspr r13,SPRN_PID /* Get PID */ | ||
338 | rlwimi r12,r13,0,24,31 /* Set TID */ | ||
339 | |||
340 | 4: | ||
341 | mtspr SPRN_MMUCR,r12 | ||
342 | |||
343 | rlwinm r12, r10, 13, 19, 29 /* Compute pgdir/pmd offset */ | ||
344 | lwzx r11, r12, r11 /* Get pgd/pmd entry */ | ||
345 | rlwinm. r12, r11, 0, 0, 20 /* Extract pt base address */ | ||
346 | beq 2f /* Bail if no table */ | ||
347 | |||
348 | rlwimi r12, r10, 23, 20, 28 /* Compute pte address */ | ||
349 | lwz r11, 4(r12) /* Get pte entry */ | ||
350 | |||
351 | andi. r13, r11, _PAGE_RW /* Is it writeable? */ | ||
352 | beq 2f /* Bail if not */ | ||
353 | |||
354 | /* Update 'changed'. | ||
355 | */ | ||
356 | ori r11, r11, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE | ||
357 | stw r11, 4(r12) /* Update Linux page table */ | ||
358 | |||
359 | li r13, PPC44x_TLB_SR@l /* Set SR */ | ||
360 | rlwimi r13, r11, 29, 29, 29 /* SX = _PAGE_HWEXEC */ | ||
361 | rlwimi r13, r11, 0, 30, 30 /* SW = _PAGE_RW */ | ||
362 | rlwimi r13, r11, 29, 28, 28 /* UR = _PAGE_USER */ | ||
363 | rlwimi r12, r11, 31, 26, 26 /* (_PAGE_USER>>1)->r12 */ | ||
364 | rlwimi r12, r11, 29, 30, 30 /* (_PAGE_USER>>3)->r12 */ | ||
365 | and r12, r12, r11 /* HWEXEC/RW & USER */ | ||
366 | rlwimi r13, r12, 0, 26, 26 /* UX = HWEXEC & USER */ | ||
367 | rlwimi r13, r12, 3, 27, 27 /* UW = RW & USER */ | ||
368 | |||
369 | rlwimi r11,r13,0,26,31 /* Insert static perms */ | ||
370 | |||
371 | rlwinm r11,r11,0,20,15 /* Clear U0-U3 */ | ||
372 | |||
373 | /* find the TLB index that caused the fault. It has to be here. */ | ||
374 | tlbsx r10, 0, r10 | ||
375 | |||
376 | tlbwe r11, r10, PPC44x_TLB_ATTRIB /* Write ATTRIB */ | ||
377 | |||
378 | /* Done...restore registers and get out of here. | ||
379 | */ | ||
380 | mfspr r11, SPRN_SPRG7R | ||
381 | mtcr r11 | ||
382 | mfspr r13, SPRN_SPRG5R | ||
383 | mfspr r12, SPRN_SPRG4R | ||
384 | |||
385 | mfspr r11, SPRN_SPRG1 | ||
386 | mfspr r10, SPRN_SPRG0 | ||
387 | rfi /* Force context change */ | ||
388 | |||
389 | 2: | ||
390 | /* | ||
391 | * The bailout. Restore registers to pre-exception conditions | ||
392 | * and call the heavyweights to help us out. | ||
393 | */ | ||
394 | mfspr r11, SPRN_SPRG7R | ||
395 | mtcr r11 | ||
396 | mfspr r13, SPRN_SPRG5R | ||
397 | mfspr r12, SPRN_SPRG4R | ||
398 | |||
399 | mfspr r11, SPRN_SPRG1 | ||
400 | mfspr r10, SPRN_SPRG0 | ||
401 | b data_access | ||
402 | 297 | ||
403 | /* Instruction Storage Interrupt */ | 298 | /* Instruction Storage Interrupt */ |
404 | INSTRUCTION_STORAGE_EXCEPTION | 299 | INSTRUCTION_STORAGE_EXCEPTION |
405 | 300 | ||
406 | /* External Input Interrupt */ | 301 | /* External Input Interrupt */ |
@@ -418,7 +313,6 @@ interrupt_base: | |||
418 | #else | 313 | #else |
419 | EXCEPTION(0x2010, FloatingPointUnavailable, unknown_exception, EXC_XFER_EE) | 314 | EXCEPTION(0x2010, FloatingPointUnavailable, unknown_exception, EXC_XFER_EE) |
420 | #endif | 315 | #endif |
421 | |||
422 | /* System Call Interrupt */ | 316 | /* System Call Interrupt */ |
423 | START_EXCEPTION(SystemCall) | 317 | START_EXCEPTION(SystemCall) |
424 | NORMAL_EXCEPTION_PROLOG | 318 | NORMAL_EXCEPTION_PROLOG |
@@ -479,18 +373,57 @@ interrupt_base: | |||
479 | 4: | 373 | 4: |
480 | mtspr SPRN_MMUCR,r12 | 374 | mtspr SPRN_MMUCR,r12 |
481 | 375 | ||
376 | /* Mask of required permission bits. Note that while we | ||
377 | * do copy ESR:ST to _PAGE_RW position as trying to write | ||
378 | * to an RO page is pretty common, we don't do it with | ||
379 | * _PAGE_DIRTY. We could do it, but it's a fairly rare | ||
380 | * event so I'd rather take the overhead when it happens | ||
381 | * rather than adding an instruction here. We should measure | ||
382 | * whether the whole thing is worth it in the first place | ||
383 | * as we could avoid loading SPRN_ESR completely in the first | ||
384 | * place... | ||
385 | * | ||
386 | * TODO: Is it worth doing that mfspr & rlwimi in the first | ||
387 | * place or can we save a couple of instructions here ? | ||
388 | */ | ||
389 | mfspr r12,SPRN_ESR | ||
390 | li r13,_PAGE_PRESENT|_PAGE_ACCESSED | ||
391 | rlwimi r13,r12,10,30,30 | ||
392 | |||
393 | /* Load the PTE */ | ||
482 | rlwinm r12, r10, 13, 19, 29 /* Compute pgdir/pmd offset */ | 394 | rlwinm r12, r10, 13, 19, 29 /* Compute pgdir/pmd offset */ |
483 | lwzx r11, r12, r11 /* Get pgd/pmd entry */ | 395 | lwzx r11, r12, r11 /* Get pgd/pmd entry */ |
484 | rlwinm. r12, r11, 0, 0, 20 /* Extract pt base address */ | 396 | rlwinm. r12, r11, 0, 0, 20 /* Extract pt base address */ |
485 | beq 2f /* Bail if no table */ | 397 | beq 2f /* Bail if no table */ |
486 | 398 | ||
487 | rlwimi r12, r10, 23, 20, 28 /* Compute pte address */ | 399 | rlwimi r12, r10, 23, 20, 28 /* Compute pte address */ |
488 | lwz r11, 4(r12) /* Get pte entry */ | 400 | lwz r11, 0(r12) /* Get high word of pte entry */ |
489 | andi. r13, r11, _PAGE_PRESENT /* Is the page present? */ | 401 | lwz r12, 4(r12) /* Get low word of pte entry */ |
490 | beq 2f /* Bail if not present */ | 402 | |
403 | lis r10,tlb_44x_index@ha | ||
404 | |||
405 | andc. r13,r13,r12 /* Check permission */ | ||
406 | |||
407 | /* Load the next available TLB index */ | ||
408 | lwz r13,tlb_44x_index@l(r10) | ||
491 | 409 | ||
492 | ori r11, r11, _PAGE_ACCESSED | 410 | bne 2f /* Bail if permission mismach */ |
493 | stw r11, 4(r12) | 411 | |
412 | /* Increment, rollover, and store TLB index */ | ||
413 | addi r13,r13,1 | ||
414 | |||
415 | /* Compare with watermark (instruction gets patched) */ | ||
416 | .globl tlb_44x_patch_hwater_D | ||
417 | tlb_44x_patch_hwater_D: | ||
418 | cmpwi 0,r13,1 /* reserve entries */ | ||
419 | ble 5f | ||
420 | li r13,0 | ||
421 | 5: | ||
422 | /* Store the next available TLB index */ | ||
423 | stw r13,tlb_44x_index@l(r10) | ||
424 | |||
425 | /* Re-load the faulting address */ | ||
426 | mfspr r10,SPRN_DEAR | ||
494 | 427 | ||
495 | /* Jump to common tlb load */ | 428 | /* Jump to common tlb load */ |
496 | b finish_tlb_load | 429 | b finish_tlb_load |
@@ -505,7 +438,7 @@ interrupt_base: | |||
505 | mfspr r12, SPRN_SPRG4R | 438 | mfspr r12, SPRN_SPRG4R |
506 | mfspr r11, SPRN_SPRG1 | 439 | mfspr r11, SPRN_SPRG1 |
507 | mfspr r10, SPRN_SPRG0 | 440 | mfspr r10, SPRN_SPRG0 |
508 | b data_access | 441 | b DataStorage |
509 | 442 | ||
510 | /* Instruction TLB Error Interrupt */ | 443 | /* Instruction TLB Error Interrupt */ |
511 | /* | 444 | /* |
@@ -549,18 +482,42 @@ interrupt_base: | |||
549 | 4: | 482 | 4: |
550 | mtspr SPRN_MMUCR,r12 | 483 | mtspr SPRN_MMUCR,r12 |
551 | 484 | ||
485 | /* Make up the required permissions */ | ||
486 | li r13,_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_HWEXEC | ||
487 | |||
552 | rlwinm r12, r10, 13, 19, 29 /* Compute pgdir/pmd offset */ | 488 | rlwinm r12, r10, 13, 19, 29 /* Compute pgdir/pmd offset */ |
553 | lwzx r11, r12, r11 /* Get pgd/pmd entry */ | 489 | lwzx r11, r12, r11 /* Get pgd/pmd entry */ |
554 | rlwinm. r12, r11, 0, 0, 20 /* Extract pt base address */ | 490 | rlwinm. r12, r11, 0, 0, 20 /* Extract pt base address */ |
555 | beq 2f /* Bail if no table */ | 491 | beq 2f /* Bail if no table */ |
556 | 492 | ||
557 | rlwimi r12, r10, 23, 20, 28 /* Compute pte address */ | 493 | rlwimi r12, r10, 23, 20, 28 /* Compute pte address */ |
558 | lwz r11, 4(r12) /* Get pte entry */ | 494 | lwz r11, 0(r12) /* Get high word of pte entry */ |
559 | andi. r13, r11, _PAGE_PRESENT /* Is the page present? */ | 495 | lwz r12, 4(r12) /* Get low word of pte entry */ |
560 | beq 2f /* Bail if not present */ | 496 | |
497 | lis r10,tlb_44x_index@ha | ||
561 | 498 | ||
562 | ori r11, r11, _PAGE_ACCESSED | 499 | andc. r13,r13,r12 /* Check permission */ |
563 | stw r11, 4(r12) | 500 | |
501 | /* Load the next available TLB index */ | ||
502 | lwz r13,tlb_44x_index@l(r10) | ||
503 | |||
504 | bne 2f /* Bail if permission mismach */ | ||
505 | |||
506 | /* Increment, rollover, and store TLB index */ | ||
507 | addi r13,r13,1 | ||
508 | |||
509 | /* Compare with watermark (instruction gets patched) */ | ||
510 | .globl tlb_44x_patch_hwater_I | ||
511 | tlb_44x_patch_hwater_I: | ||
512 | cmpwi 0,r13,1 /* reserve entries */ | ||
513 | ble 5f | ||
514 | li r13,0 | ||
515 | 5: | ||
516 | /* Store the next available TLB index */ | ||
517 | stw r13,tlb_44x_index@l(r10) | ||
518 | |||
519 | /* Re-load the faulting address */ | ||
520 | mfspr r10,SPRN_SRR0 | ||
564 | 521 | ||
565 | /* Jump to common TLB load point */ | 522 | /* Jump to common TLB load point */ |
566 | b finish_tlb_load | 523 | b finish_tlb_load |
@@ -582,86 +539,40 @@ interrupt_base: | |||
582 | 539 | ||
583 | /* | 540 | /* |
584 | * Local functions | 541 | * Local functions |
585 | */ | 542 | */ |
586 | /* | ||
587 | * Data TLB exceptions will bail out to this point | ||
588 | * if they can't resolve the lightweight TLB fault. | ||
589 | */ | ||
590 | data_access: | ||
591 | NORMAL_EXCEPTION_PROLOG | ||
592 | mfspr r5,SPRN_ESR /* Grab the ESR, save it, pass arg3 */ | ||
593 | stw r5,_ESR(r11) | ||
594 | mfspr r4,SPRN_DEAR /* Grab the DEAR, save it, pass arg2 */ | ||
595 | EXC_XFER_EE_LITE(0x0300, handle_page_fault) | ||
596 | 543 | ||
597 | /* | 544 | /* |
598 | 545 | ||
599 | * Both the instruction and data TLB miss get to this | 546 | * Both the instruction and data TLB miss get to this |
600 | * point to load the TLB. | 547 | * point to load the TLB. |
601 | * r10 - EA of fault | 548 | * r10 - EA of fault |
602 | * r11 - available to use | 549 | * r11 - PTE high word value |
603 | * r12 - Pointer to the 64-bit PTE | 550 | * r12 - PTE low word value |
604 | * r13 - available to use | 551 | * r13 - TLB index |
605 | * MMUCR - loaded with proper value when we get here | 552 | * MMUCR - loaded with proper value when we get here |
606 | * Upon exit, we reload everything and RFI. | 553 | * Upon exit, we reload everything and RFI. |
607 | */ | 554 | */ |
608 | finish_tlb_load: | 555 | finish_tlb_load: |
609 | /* | 556 | /* Combine RPN & ERPN an write WS 0 */ |
610 | * We set execute, because we don't have the granularity to | 557 | rlwimi r11,r12,0,0,19 |
611 | * properly set this at the page level (Linux problem). | 558 | tlbwe r11,r13,PPC44x_TLB_XLAT |
612 | * If shared is set, we cause a zero PID->TID load. | ||
613 | * Many of these bits are software only. Bits we don't set | ||
614 | * here we (properly should) assume have the appropriate value. | ||
615 | */ | ||
616 | |||
617 | /* Load the next available TLB index */ | ||
618 | lis r13, tlb_44x_index@ha | ||
619 | lwz r13, tlb_44x_index@l(r13) | ||
620 | /* Load the TLB high watermark */ | ||
621 | lis r11, tlb_44x_hwater@ha | ||
622 | lwz r11, tlb_44x_hwater@l(r11) | ||
623 | |||
624 | /* Increment, rollover, and store TLB index */ | ||
625 | addi r13, r13, 1 | ||
626 | cmpw 0, r13, r11 /* reserve entries */ | ||
627 | ble 7f | ||
628 | li r13, 0 | ||
629 | 7: | ||
630 | /* Store the next available TLB index */ | ||
631 | lis r11, tlb_44x_index@ha | ||
632 | stw r13, tlb_44x_index@l(r11) | ||
633 | |||
634 | lwz r11, 0(r12) /* Get MS word of PTE */ | ||
635 | lwz r12, 4(r12) /* Get LS word of PTE */ | ||
636 | rlwimi r11, r12, 0, 0 , 19 /* Insert RPN */ | ||
637 | tlbwe r11, r13, PPC44x_TLB_XLAT /* Write XLAT */ | ||
638 | 559 | ||
639 | /* | 560 | /* |
640 | * Create PAGEID. This is the faulting address, | 561 | * Create WS1. This is the faulting address (EPN), |
641 | * page size, and valid flag. | 562 | * page size, and valid flag. |
642 | */ | 563 | */ |
643 | li r11, PPC44x_TLB_VALID | PPC44x_TLB_4K | 564 | li r11,PPC44x_TLB_VALID | PPC44x_TLB_4K |
644 | rlwimi r10, r11, 0, 20, 31 /* Insert valid and page size */ | 565 | rlwimi r10,r11,0,20,31 /* Insert valid and page size*/ |
645 | tlbwe r10, r13, PPC44x_TLB_PAGEID /* Write PAGEID */ | 566 | tlbwe r10,r13,PPC44x_TLB_PAGEID /* Write PAGEID */ |
646 | 567 | ||
647 | li r10, PPC44x_TLB_SR@l /* Set SR */ | 568 | /* And WS 2 */ |
648 | rlwimi r10, r12, 0, 30, 30 /* Set SW = _PAGE_RW */ | 569 | li r10,0xf85 /* Mask to apply from PTE */ |
649 | rlwimi r10, r12, 29, 29, 29 /* SX = _PAGE_HWEXEC */ | 570 | rlwimi r10,r12,29,30,30 /* DIRTY -> SW position */ |
650 | rlwimi r10, r12, 29, 28, 28 /* UR = _PAGE_USER */ | 571 | and r11,r12,r10 /* Mask PTE bits to keep */ |
651 | rlwimi r11, r12, 31, 26, 26 /* (_PAGE_USER>>1)->r12 */ | 572 | andi. r10,r12,_PAGE_USER /* User page ? */ |
652 | and r11, r12, r11 /* HWEXEC & USER */ | 573 | beq 1f /* nope, leave U bits empty */ |
653 | rlwimi r10, r11, 0, 26, 26 /* UX = HWEXEC & USER */ | 574 | rlwimi r11,r11,3,26,28 /* yes, copy S bits to U */ |
654 | 575 | 1: tlbwe r11,r13,PPC44x_TLB_ATTRIB /* Write ATTRIB */ | |
655 | rlwimi r12, r10, 0, 26, 31 /* Insert static perms */ | ||
656 | |||
657 | /* | ||
658 | * Clear U0-U3 and WL1 IL1I IL1D IL2I IL2D bits which are added | ||
659 | * on newer 440 cores like the 440x6 used on AMCC 460EX/460GT (see | ||
660 | * include/asm-powerpc/pgtable-ppc32.h for details). | ||
661 | */ | ||
662 | rlwinm r12, r12, 0, 20, 10 | ||
663 | |||
664 | tlbwe r12, r13, PPC44x_TLB_ATTRIB /* Write ATTRIB */ | ||
665 | 576 | ||
666 | /* Done...restore registers and get out of here. | 577 | /* Done...restore registers and get out of here. |
667 | */ | 578 | */ |
@@ -737,15 +648,6 @@ empty_zero_page: | |||
737 | swapper_pg_dir: | 648 | swapper_pg_dir: |
738 | .space PGD_TABLE_SIZE | 649 | .space PGD_TABLE_SIZE |
739 | 650 | ||
740 | /* Reserved 4k for the critical exception stack & 4k for the machine | ||
741 | * check stack per CPU for kernel mode exceptions */ | ||
742 | .section .bss | ||
743 | .align 12 | ||
744 | exception_stack_bottom: | ||
745 | .space BOOKE_EXCEPTION_STACK_SIZE | ||
746 | .globl exception_stack_top | ||
747 | exception_stack_top: | ||
748 | |||
749 | /* | 651 | /* |
750 | * Room for two PTE pointers, usually the kernel and current user pointers | 652 | * Room for two PTE pointers, usually the kernel and current user pointers |
751 | * to their respective root page table. | 653 | * to their respective root page table. |
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 25e84c0e1166..cc8fb474d520 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S | |||
@@ -275,7 +275,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) | |||
275 | . = 0xf00 | 275 | . = 0xf00 |
276 | b performance_monitor_pSeries | 276 | b performance_monitor_pSeries |
277 | 277 | ||
278 | STD_EXCEPTION_PSERIES(0xf20, altivec_unavailable) | 278 | . = 0xf20 |
279 | b altivec_unavailable_pSeries | ||
280 | |||
281 | . = 0xf40 | ||
282 | b vsx_unavailable_pSeries | ||
279 | 283 | ||
280 | #ifdef CONFIG_CBE_RAS | 284 | #ifdef CONFIG_CBE_RAS |
281 | HSTD_EXCEPTION_PSERIES(0x1200, cbe_system_error) | 285 | HSTD_EXCEPTION_PSERIES(0x1200, cbe_system_error) |
@@ -295,6 +299,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) | |||
295 | 299 | ||
296 | /* moved from 0xf00 */ | 300 | /* moved from 0xf00 */ |
297 | STD_EXCEPTION_PSERIES(., performance_monitor) | 301 | STD_EXCEPTION_PSERIES(., performance_monitor) |
302 | STD_EXCEPTION_PSERIES(., altivec_unavailable) | ||
303 | STD_EXCEPTION_PSERIES(., vsx_unavailable) | ||
298 | 304 | ||
299 | /* | 305 | /* |
300 | * An interrupt came in while soft-disabled; clear EE in SRR1, | 306 | * An interrupt came in while soft-disabled; clear EE in SRR1, |
@@ -739,7 +745,8 @@ fp_unavailable_common: | |||
739 | ENABLE_INTS | 745 | ENABLE_INTS |
740 | bl .kernel_fp_unavailable_exception | 746 | bl .kernel_fp_unavailable_exception |
741 | BUG_OPCODE | 747 | BUG_OPCODE |
742 | 1: b .load_up_fpu | 748 | 1: bl .load_up_fpu |
749 | b fast_exception_return | ||
743 | 750 | ||
744 | .align 7 | 751 | .align 7 |
745 | .globl altivec_unavailable_common | 752 | .globl altivec_unavailable_common |
@@ -747,7 +754,10 @@ altivec_unavailable_common: | |||
747 | EXCEPTION_PROLOG_COMMON(0xf20, PACA_EXGEN) | 754 | EXCEPTION_PROLOG_COMMON(0xf20, PACA_EXGEN) |
748 | #ifdef CONFIG_ALTIVEC | 755 | #ifdef CONFIG_ALTIVEC |
749 | BEGIN_FTR_SECTION | 756 | BEGIN_FTR_SECTION |
750 | bne .load_up_altivec /* if from user, just load it up */ | 757 | beq 1f |
758 | bl .load_up_altivec | ||
759 | b fast_exception_return | ||
760 | 1: | ||
751 | END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) | 761 | END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) |
752 | #endif | 762 | #endif |
753 | bl .save_nvgprs | 763 | bl .save_nvgprs |
@@ -827,9 +837,70 @@ _STATIC(load_up_altivec) | |||
827 | std r4,0(r3) | 837 | std r4,0(r3) |
828 | #endif /* CONFIG_SMP */ | 838 | #endif /* CONFIG_SMP */ |
829 | /* restore registers and return */ | 839 | /* restore registers and return */ |
830 | b fast_exception_return | 840 | blr |
831 | #endif /* CONFIG_ALTIVEC */ | 841 | #endif /* CONFIG_ALTIVEC */ |
832 | 842 | ||
843 | .align 7 | ||
844 | .globl vsx_unavailable_common | ||
845 | vsx_unavailable_common: | ||
846 | EXCEPTION_PROLOG_COMMON(0xf40, PACA_EXGEN) | ||
847 | #ifdef CONFIG_VSX | ||
848 | BEGIN_FTR_SECTION | ||
849 | bne .load_up_vsx | ||
850 | 1: | ||
851 | END_FTR_SECTION_IFSET(CPU_FTR_VSX) | ||
852 | #endif | ||
853 | bl .save_nvgprs | ||
854 | addi r3,r1,STACK_FRAME_OVERHEAD | ||
855 | ENABLE_INTS | ||
856 | bl .vsx_unavailable_exception | ||
857 | b .ret_from_except | ||
858 | |||
859 | #ifdef CONFIG_VSX | ||
860 | /* | ||
861 | * load_up_vsx(unused, unused, tsk) | ||
862 | * Disable VSX for the task which had it previously, | ||
863 | * and save its vector registers in its thread_struct. | ||
864 | * Reuse the fp and vsx saves, but first check to see if they have | ||
865 | * been saved already. | ||
866 | * On entry: r13 == 'current' && last_task_used_vsx != 'current' | ||
867 | */ | ||
868 | _STATIC(load_up_vsx) | ||
869 | /* Load FP and VSX registers if they haven't been done yet */ | ||
870 | andi. r5,r12,MSR_FP | ||
871 | beql+ load_up_fpu /* skip if already loaded */ | ||
872 | andis. r5,r12,MSR_VEC@h | ||
873 | beql+ load_up_altivec /* skip if already loaded */ | ||
874 | |||
875 | #ifndef CONFIG_SMP | ||
876 | ld r3,last_task_used_vsx@got(r2) | ||
877 | ld r4,0(r3) | ||
878 | cmpdi 0,r4,0 | ||
879 | beq 1f | ||
880 | /* Disable VSX for last_task_used_vsx */ | ||
881 | addi r4,r4,THREAD | ||
882 | ld r5,PT_REGS(r4) | ||
883 | ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) | ||
884 | lis r6,MSR_VSX@h | ||
885 | andc r6,r4,r6 | ||
886 | std r6,_MSR-STACK_FRAME_OVERHEAD(r5) | ||
887 | 1: | ||
888 | #endif /* CONFIG_SMP */ | ||
889 | ld r4,PACACURRENT(r13) | ||
890 | addi r4,r4,THREAD /* Get THREAD */ | ||
891 | li r6,1 | ||
892 | stw r6,THREAD_USED_VSR(r4) /* ... also set thread used vsr */ | ||
893 | /* enable use of VSX after return */ | ||
894 | oris r12,r12,MSR_VSX@h | ||
895 | std r12,_MSR(r1) | ||
896 | #ifndef CONFIG_SMP | ||
897 | /* Update last_task_used_math to 'current' */ | ||
898 | ld r4,PACACURRENT(r13) | ||
899 | std r4,0(r3) | ||
900 | #endif /* CONFIG_SMP */ | ||
901 | b fast_exception_return | ||
902 | #endif /* CONFIG_VSX */ | ||
903 | |||
833 | /* | 904 | /* |
834 | * Hash table stuff | 905 | * Hash table stuff |
835 | */ | 906 | */ |
@@ -1127,7 +1198,6 @@ _GLOBAL(generic_secondary_smp_init) | |||
1127 | 3: HMT_LOW | 1198 | 3: HMT_LOW |
1128 | lbz r23,PACAPROCSTART(r13) /* Test if this processor should */ | 1199 | lbz r23,PACAPROCSTART(r13) /* Test if this processor should */ |
1129 | /* start. */ | 1200 | /* start. */ |
1130 | sync | ||
1131 | 1201 | ||
1132 | #ifndef CONFIG_SMP | 1202 | #ifndef CONFIG_SMP |
1133 | b 3b /* Never go on non-SMP */ | 1203 | b 3b /* Never go on non-SMP */ |
@@ -1135,6 +1205,8 @@ _GLOBAL(generic_secondary_smp_init) | |||
1135 | cmpwi 0,r23,0 | 1205 | cmpwi 0,r23,0 |
1136 | beq 3b /* Loop until told to go */ | 1206 | beq 3b /* Loop until told to go */ |
1137 | 1207 | ||
1208 | sync /* order paca.run and cur_cpu_spec */ | ||
1209 | |||
1138 | /* See if we need to call a cpu state restore handler */ | 1210 | /* See if we need to call a cpu state restore handler */ |
1139 | LOAD_REG_IMMEDIATE(r23, cur_cpu_spec) | 1211 | LOAD_REG_IMMEDIATE(r23, cur_cpu_spec) |
1140 | ld r23,0(r23) | 1212 | ld r23,0(r23) |
diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h index aefafc6330c9..fce2df988504 100644 --- a/arch/powerpc/kernel/head_booke.h +++ b/arch/powerpc/kernel/head_booke.h | |||
@@ -43,9 +43,7 @@ | |||
43 | SAVE_2GPRS(7, r11) | 43 | SAVE_2GPRS(7, r11) |
44 | 44 | ||
45 | /* To handle the additional exception priority levels on 40x and Book-E | 45 | /* To handle the additional exception priority levels on 40x and Book-E |
46 | * processors we allocate a 4k stack per additional priority level. The various | 46 | * processors we allocate a stack per additional priority level. |
47 | * head_xxx.S files allocate space (exception_stack_top) for each priority's | ||
48 | * stack times the number of CPUs | ||
49 | * | 47 | * |
50 | * On 40x critical is the only additional level | 48 | * On 40x critical is the only additional level |
51 | * On 44x/e500 we have critical and machine check | 49 | * On 44x/e500 we have critical and machine check |
@@ -61,36 +59,37 @@ | |||
61 | * going to critical or their own debug level we aren't currently | 59 | * going to critical or their own debug level we aren't currently |
62 | * providing configurations that micro-optimize space usage. | 60 | * providing configurations that micro-optimize space usage. |
63 | */ | 61 | */ |
64 | #ifdef CONFIG_44x | ||
65 | #define NUM_EXCEPTION_LVLS 2 | ||
66 | #else | ||
67 | #define NUM_EXCEPTION_LVLS 3 | ||
68 | #endif | ||
69 | #define BOOKE_EXCEPTION_STACK_SIZE (4096 * NUM_EXCEPTION_LVLS) | ||
70 | 62 | ||
71 | /* CRIT_SPRG only used in critical exception handling */ | 63 | /* CRIT_SPRG only used in critical exception handling */ |
72 | #define CRIT_SPRG SPRN_SPRG2 | 64 | #define CRIT_SPRG SPRN_SPRG2 |
73 | /* MCHECK_SPRG only used in machine check exception handling */ | 65 | /* MCHECK_SPRG only used in machine check exception handling */ |
74 | #define MCHECK_SPRG SPRN_SPRG6W | 66 | #define MCHECK_SPRG SPRN_SPRG6W |
75 | 67 | ||
76 | #define MCHECK_STACK_TOP (exception_stack_top - 4096) | 68 | #define MCHECK_STACK_BASE mcheckirq_ctx |
77 | #define CRIT_STACK_TOP (exception_stack_top) | 69 | #define CRIT_STACK_BASE critirq_ctx |
78 | 70 | ||
79 | /* only on e200 for now */ | 71 | /* only on e500mc/e200 */ |
80 | #define DEBUG_STACK_TOP (exception_stack_top - 8192) | 72 | #define DEBUG_STACK_BASE dbgirq_ctx |
73 | #ifdef CONFIG_PPC_E500MC | ||
74 | #define DEBUG_SPRG SPRN_SPRG9 | ||
75 | #else | ||
81 | #define DEBUG_SPRG SPRN_SPRG6W | 76 | #define DEBUG_SPRG SPRN_SPRG6W |
77 | #endif | ||
78 | |||
79 | #define EXC_LVL_FRAME_OVERHEAD (THREAD_SIZE - INT_FRAME_SIZE - EXC_LVL_SIZE) | ||
82 | 80 | ||
83 | #ifdef CONFIG_SMP | 81 | #ifdef CONFIG_SMP |
84 | #define BOOKE_LOAD_EXC_LEVEL_STACK(level) \ | 82 | #define BOOKE_LOAD_EXC_LEVEL_STACK(level) \ |
85 | mfspr r8,SPRN_PIR; \ | 83 | mfspr r8,SPRN_PIR; \ |
86 | mulli r8,r8,BOOKE_EXCEPTION_STACK_SIZE; \ | 84 | slwi r8,r8,2; \ |
87 | neg r8,r8; \ | 85 | addis r8,r8,level##_STACK_BASE@ha; \ |
88 | addis r8,r8,level##_STACK_TOP@ha; \ | 86 | lwz r8,level##_STACK_BASE@l(r8); \ |
89 | addi r8,r8,level##_STACK_TOP@l | 87 | addi r8,r8,EXC_LVL_FRAME_OVERHEAD; |
90 | #else | 88 | #else |
91 | #define BOOKE_LOAD_EXC_LEVEL_STACK(level) \ | 89 | #define BOOKE_LOAD_EXC_LEVEL_STACK(level) \ |
92 | lis r8,level##_STACK_TOP@h; \ | 90 | lis r8,level##_STACK_BASE@ha; \ |
93 | ori r8,r8,level##_STACK_TOP@l | 91 | lwz r8,level##_STACK_BASE@l(r8); \ |
92 | addi r8,r8,EXC_LVL_FRAME_OVERHEAD; | ||
94 | #endif | 93 | #endif |
95 | 94 | ||
96 | /* | 95 | /* |
@@ -104,22 +103,36 @@ | |||
104 | #define EXC_LEVEL_EXCEPTION_PROLOG(exc_level, exc_level_srr0, exc_level_srr1) \ | 103 | #define EXC_LEVEL_EXCEPTION_PROLOG(exc_level, exc_level_srr0, exc_level_srr1) \ |
105 | mtspr exc_level##_SPRG,r8; \ | 104 | mtspr exc_level##_SPRG,r8; \ |
106 | BOOKE_LOAD_EXC_LEVEL_STACK(exc_level);/* r8 points to the exc_level stack*/ \ | 105 | BOOKE_LOAD_EXC_LEVEL_STACK(exc_level);/* r8 points to the exc_level stack*/ \ |
107 | stw r10,GPR10-INT_FRAME_SIZE(r8); \ | 106 | stw r9,GPR9(r8); /* save various registers */\ |
108 | stw r11,GPR11-INT_FRAME_SIZE(r8); \ | 107 | mfcr r9; /* save CR in r9 for now */\ |
109 | mfcr r10; /* save CR in r10 for now */\ | 108 | stw r10,GPR10(r8); \ |
110 | mfspr r11,exc_level_srr1; /* check whether user or kernel */\ | 109 | stw r11,GPR11(r8); \ |
111 | andi. r11,r11,MSR_PR; \ | 110 | stw r9,_CCR(r8); /* save CR on stack */\ |
112 | mr r11,r8; \ | 111 | mfspr r10,exc_level_srr1; /* check whether user or kernel */\ |
113 | mfspr r8,exc_level##_SPRG; \ | 112 | andi. r10,r10,MSR_PR; \ |
114 | beq 1f; \ | ||
115 | /* COMING FROM USER MODE */ \ | ||
116 | mfspr r11,SPRN_SPRG3; /* if from user, start at top of */\ | 113 | mfspr r11,SPRN_SPRG3; /* if from user, start at top of */\ |
117 | lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ | 114 | lwz r11,THREAD_INFO-THREAD(r11); /* this thread's kernel stack */\ |
118 | addi r11,r11,THREAD_SIZE; \ | 115 | addi r11,r11,EXC_LVL_FRAME_OVERHEAD; /* allocate stack frame */\ |
119 | 1: subi r11,r11,INT_FRAME_SIZE; /* Allocate an exception frame */\ | 116 | beq 1f; \ |
120 | stw r10,_CCR(r11); /* save various registers */\ | 117 | /* COMING FROM USER MODE */ \ |
121 | stw r12,GPR12(r11); \ | 118 | stw r9,_CCR(r11); /* save CR */\ |
119 | lwz r10,GPR10(r8); /* copy regs from exception stack */\ | ||
120 | lwz r9,GPR9(r8); \ | ||
121 | stw r10,GPR10(r11); \ | ||
122 | lwz r10,GPR11(r8); \ | ||
122 | stw r9,GPR9(r11); \ | 123 | stw r9,GPR9(r11); \ |
124 | stw r10,GPR11(r11); \ | ||
125 | b 2f; \ | ||
126 | /* COMING FROM PRIV MODE */ \ | ||
127 | 1: lwz r9,TI_FLAGS-EXC_LVL_FRAME_OVERHEAD(r11); \ | ||
128 | lwz r10,TI_PREEMPT-EXC_LVL_FRAME_OVERHEAD(r11); \ | ||
129 | stw r9,TI_FLAGS-EXC_LVL_FRAME_OVERHEAD(r8); \ | ||
130 | stw r10,TI_PREEMPT-EXC_LVL_FRAME_OVERHEAD(r8); \ | ||
131 | lwz r9,TI_TASK-EXC_LVL_FRAME_OVERHEAD(r11); \ | ||
132 | stw r9,TI_TASK-EXC_LVL_FRAME_OVERHEAD(r8); \ | ||
133 | mr r11,r8; \ | ||
134 | 2: mfspr r8,exc_level##_SPRG; \ | ||
135 | stw r12,GPR12(r11); /* save various registers */\ | ||
123 | mflr r10; \ | 136 | mflr r10; \ |
124 | stw r10,_LINK(r11); \ | 137 | stw r10,_LINK(r11); \ |
125 | mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ | 138 | mfspr r12,SPRN_DEAR; /* save DEAR and ESR in the frame */\ |
@@ -231,7 +244,7 @@ label: | |||
231 | * the code where the exception occurred (since exception entry \ | 244 | * the code where the exception occurred (since exception entry \ |
232 | * doesn't turn off DE automatically). We simulate the effect \ | 245 | * doesn't turn off DE automatically). We simulate the effect \ |
233 | * of turning off DE on entry to an exception handler by turning \ | 246 | * of turning off DE on entry to an exception handler by turning \ |
234 | * off DE in the CSRR1 value and clearing the debug status. \ | 247 | * off DE in the DSRR1 value and clearing the debug status. \ |
235 | */ \ | 248 | */ \ |
236 | mfspr r10,SPRN_DBSR; /* check single-step/branch taken */ \ | 249 | mfspr r10,SPRN_DBSR; /* check single-step/branch taken */ \ |
237 | andis. r10,r10,DBSR_IC@h; \ | 250 | andis. r10,r10,DBSR_IC@h; \ |
@@ -262,17 +275,17 @@ label: | |||
262 | lwz r12,GPR12(r11); \ | 275 | lwz r12,GPR12(r11); \ |
263 | mtspr DEBUG_SPRG,r8; \ | 276 | mtspr DEBUG_SPRG,r8; \ |
264 | BOOKE_LOAD_EXC_LEVEL_STACK(DEBUG); /* r8 points to the debug stack */ \ | 277 | BOOKE_LOAD_EXC_LEVEL_STACK(DEBUG); /* r8 points to the debug stack */ \ |
265 | lwz r10,GPR10-INT_FRAME_SIZE(r8); \ | 278 | lwz r10,GPR10(r8); \ |
266 | lwz r11,GPR11-INT_FRAME_SIZE(r8); \ | 279 | lwz r11,GPR11(r8); \ |
267 | mfspr r8,DEBUG_SPRG; \ | 280 | mfspr r8,DEBUG_SPRG; \ |
268 | \ | 281 | \ |
269 | RFDI; \ | 282 | RFDI; \ |
270 | b .; \ | 283 | b .; \ |
271 | \ | 284 | \ |
272 | /* continue normal handling for a critical exception... */ \ | 285 | /* continue normal handling for a debug exception... */ \ |
273 | 2: mfspr r4,SPRN_DBSR; \ | 286 | 2: mfspr r4,SPRN_DBSR; \ |
274 | addi r3,r1,STACK_FRAME_OVERHEAD; \ | 287 | addi r3,r1,STACK_FRAME_OVERHEAD; \ |
275 | EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, debug_transfer_to_handler, ret_from_debug_exc) | 288 | EXC_XFER_TEMPLATE(DebugException, 0x2008, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, debug_transfer_to_handler, ret_from_debug_exc) |
276 | 289 | ||
277 | #define DEBUG_CRIT_EXCEPTION \ | 290 | #define DEBUG_CRIT_EXCEPTION \ |
278 | START_EXCEPTION(DebugCrit); \ | 291 | START_EXCEPTION(DebugCrit); \ |
@@ -315,8 +328,8 @@ label: | |||
315 | lwz r12,GPR12(r11); \ | 328 | lwz r12,GPR12(r11); \ |
316 | mtspr CRIT_SPRG,r8; \ | 329 | mtspr CRIT_SPRG,r8; \ |
317 | BOOKE_LOAD_EXC_LEVEL_STACK(CRIT); /* r8 points to the debug stack */ \ | 330 | BOOKE_LOAD_EXC_LEVEL_STACK(CRIT); /* r8 points to the debug stack */ \ |
318 | lwz r10,GPR10-INT_FRAME_SIZE(r8); \ | 331 | lwz r10,GPR10(r8); \ |
319 | lwz r11,GPR11-INT_FRAME_SIZE(r8); \ | 332 | lwz r11,GPR11(r8); \ |
320 | mfspr r8,CRIT_SPRG; \ | 333 | mfspr r8,CRIT_SPRG; \ |
321 | \ | 334 | \ |
322 | rfci; \ | 335 | rfci; \ |
@@ -327,6 +340,14 @@ label: | |||
327 | addi r3,r1,STACK_FRAME_OVERHEAD; \ | 340 | addi r3,r1,STACK_FRAME_OVERHEAD; \ |
328 | EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, crit_transfer_to_handler, ret_from_crit_exc) | 341 | EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, crit_transfer_to_handler, ret_from_crit_exc) |
329 | 342 | ||
343 | #define DATA_STORAGE_EXCEPTION \ | ||
344 | START_EXCEPTION(DataStorage) \ | ||
345 | NORMAL_EXCEPTION_PROLOG; \ | ||
346 | mfspr r5,SPRN_ESR; /* Grab the ESR and save it */ \ | ||
347 | stw r5,_ESR(r11); \ | ||
348 | mfspr r4,SPRN_DEAR; /* Grab the DEAR */ \ | ||
349 | EXC_XFER_EE_LITE(0x0300, handle_page_fault) | ||
350 | |||
330 | #define INSTRUCTION_STORAGE_EXCEPTION \ | 351 | #define INSTRUCTION_STORAGE_EXCEPTION \ |
331 | START_EXCEPTION(InstructionStorage) \ | 352 | START_EXCEPTION(InstructionStorage) \ |
332 | NORMAL_EXCEPTION_PROLOG; \ | 353 | NORMAL_EXCEPTION_PROLOG; \ |
@@ -363,8 +384,31 @@ label: | |||
363 | #define FP_UNAVAILABLE_EXCEPTION \ | 384 | #define FP_UNAVAILABLE_EXCEPTION \ |
364 | START_EXCEPTION(FloatingPointUnavailable) \ | 385 | START_EXCEPTION(FloatingPointUnavailable) \ |
365 | NORMAL_EXCEPTION_PROLOG; \ | 386 | NORMAL_EXCEPTION_PROLOG; \ |
366 | bne load_up_fpu; /* if from user, just load it up */ \ | 387 | beq 1f; \ |
367 | addi r3,r1,STACK_FRAME_OVERHEAD; \ | 388 | bl load_up_fpu; /* if from user, just load it up */ \ |
389 | b fast_exception_return; \ | ||
390 | 1: addi r3,r1,STACK_FRAME_OVERHEAD; \ | ||
368 | EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception) | 391 | EXC_XFER_EE_LITE(0x800, kernel_fp_unavailable_exception) |
369 | 392 | ||
393 | #ifndef __ASSEMBLY__ | ||
394 | struct exception_regs { | ||
395 | unsigned long mas0; | ||
396 | unsigned long mas1; | ||
397 | unsigned long mas2; | ||
398 | unsigned long mas3; | ||
399 | unsigned long mas6; | ||
400 | unsigned long mas7; | ||
401 | unsigned long srr0; | ||
402 | unsigned long srr1; | ||
403 | unsigned long csrr0; | ||
404 | unsigned long csrr1; | ||
405 | unsigned long dsrr0; | ||
406 | unsigned long dsrr1; | ||
407 | unsigned long saved_ksp_limit; | ||
408 | }; | ||
409 | |||
410 | /* ensure this structure is always sized to a multiple of the stack alignment */ | ||
411 | #define STACK_EXC_LVL_FRAME_SIZE _ALIGN_UP(sizeof (struct exception_regs), 16) | ||
412 | |||
413 | #endif /* __ASSEMBLY__ */ | ||
370 | #endif /* __HEAD_BOOKE_H__ */ | 414 | #endif /* __HEAD_BOOKE_H__ */ |
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index e581524d85bc..c4268500e856 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <asm/thread_info.h> | 39 | #include <asm/thread_info.h> |
40 | #include <asm/ppc_asm.h> | 40 | #include <asm/ppc_asm.h> |
41 | #include <asm/asm-offsets.h> | 41 | #include <asm/asm-offsets.h> |
42 | #include <asm/cache.h> | ||
42 | #include "head_booke.h" | 43 | #include "head_booke.h" |
43 | 44 | ||
44 | /* As with the other PowerPC ports, it is expected that when code | 45 | /* As with the other PowerPC ports, it is expected that when code |
@@ -304,7 +305,7 @@ skpinv: addi r6,r6,1 /* Increment */ | |||
304 | SET_IVOR(13, DataTLBError); | 305 | SET_IVOR(13, DataTLBError); |
305 | SET_IVOR(14, InstructionTLBError); | 306 | SET_IVOR(14, InstructionTLBError); |
306 | SET_IVOR(15, DebugDebug); | 307 | SET_IVOR(15, DebugDebug); |
307 | #if defined(CONFIG_E500) | 308 | #if defined(CONFIG_E500) && !defined(CONFIG_PPC_E500MC) |
308 | SET_IVOR(15, DebugCrit); | 309 | SET_IVOR(15, DebugCrit); |
309 | #endif | 310 | #endif |
310 | SET_IVOR(32, SPEUnavailable); | 311 | SET_IVOR(32, SPEUnavailable); |
@@ -313,6 +314,9 @@ skpinv: addi r6,r6,1 /* Increment */ | |||
313 | #ifndef CONFIG_E200 | 314 | #ifndef CONFIG_E200 |
314 | SET_IVOR(35, PerformanceMonitor); | 315 | SET_IVOR(35, PerformanceMonitor); |
315 | #endif | 316 | #endif |
317 | #ifdef CONFIG_PPC_E500MC | ||
318 | SET_IVOR(36, Doorbell); | ||
319 | #endif | ||
316 | 320 | ||
317 | /* Establish the interrupt vector base */ | 321 | /* Establish the interrupt vector base */ |
318 | lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */ | 322 | lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */ |
@@ -750,10 +754,13 @@ interrupt_base: | |||
750 | /* Performance Monitor */ | 754 | /* Performance Monitor */ |
751 | EXCEPTION(0x2060, PerformanceMonitor, performance_monitor_exception, EXC_XFER_STD) | 755 | EXCEPTION(0x2060, PerformanceMonitor, performance_monitor_exception, EXC_XFER_STD) |
752 | 756 | ||
757 | #ifdef CONFIG_PPC_E500MC | ||
758 | EXCEPTION(0x2070, Doorbell, unknown_exception, EXC_XFER_EE) | ||
759 | #endif | ||
753 | 760 | ||
754 | /* Debug Interrupt */ | 761 | /* Debug Interrupt */ |
755 | DEBUG_DEBUG_EXCEPTION | 762 | DEBUG_DEBUG_EXCEPTION |
756 | #if defined(CONFIG_E500) | 763 | #if defined(CONFIG_E500) && !defined(CONFIG_PPC_E500MC) |
757 | DEBUG_CRIT_EXCEPTION | 764 | DEBUG_CRIT_EXCEPTION |
758 | #endif | 765 | #endif |
759 | 766 | ||
@@ -1065,6 +1072,52 @@ _GLOBAL(set_context) | |||
1065 | isync /* Force context change */ | 1072 | isync /* Force context change */ |
1066 | blr | 1073 | blr |
1067 | 1074 | ||
1075 | _GLOBAL(flush_dcache_L1) | ||
1076 | mfspr r3,SPRN_L1CFG0 | ||
1077 | |||
1078 | rlwinm r5,r3,9,3 /* Extract cache block size */ | ||
1079 | twlgti r5,1 /* Only 32 and 64 byte cache blocks | ||
1080 | * are currently defined. | ||
1081 | */ | ||
1082 | li r4,32 | ||
1083 | subfic r6,r5,2 /* r6 = log2(1KiB / cache block size) - | ||
1084 | * log2(number of ways) | ||
1085 | */ | ||
1086 | slw r5,r4,r5 /* r5 = cache block size */ | ||
1087 | |||
1088 | rlwinm r7,r3,0,0xff /* Extract number of KiB in the cache */ | ||
1089 | mulli r7,r7,13 /* An 8-way cache will require 13 | ||
1090 | * loads per set. | ||
1091 | */ | ||
1092 | slw r7,r7,r6 | ||
1093 | |||
1094 | /* save off HID0 and set DCFA */ | ||
1095 | mfspr r8,SPRN_HID0 | ||
1096 | ori r9,r8,HID0_DCFA@l | ||
1097 | mtspr SPRN_HID0,r9 | ||
1098 | isync | ||
1099 | |||
1100 | lis r4,KERNELBASE@h | ||
1101 | mtctr r7 | ||
1102 | |||
1103 | 1: lwz r3,0(r4) /* Load... */ | ||
1104 | add r4,r4,r5 | ||
1105 | bdnz 1b | ||
1106 | |||
1107 | msync | ||
1108 | lis r4,KERNELBASE@h | ||
1109 | mtctr r7 | ||
1110 | |||
1111 | 1: dcbf 0,r4 /* ...and flush. */ | ||
1112 | add r4,r4,r5 | ||
1113 | bdnz 1b | ||
1114 | |||
1115 | /* restore HID0 */ | ||
1116 | mtspr SPRN_HID0,r8 | ||
1117 | isync | ||
1118 | |||
1119 | blr | ||
1120 | |||
1068 | /* | 1121 | /* |
1069 | * We put a few things here that have to be page-aligned. This stuff | 1122 | * We put a few things here that have to be page-aligned. This stuff |
1070 | * goes at the beginning of the data segment, which is page-aligned. | 1123 | * goes at the beginning of the data segment, which is page-aligned. |
@@ -1080,15 +1133,6 @@ empty_zero_page: | |||
1080 | swapper_pg_dir: | 1133 | swapper_pg_dir: |
1081 | .space PGD_TABLE_SIZE | 1134 | .space PGD_TABLE_SIZE |
1082 | 1135 | ||
1083 | /* Reserved 4k for the critical exception stack & 4k for the machine | ||
1084 | * check stack per CPU for kernel mode exceptions */ | ||
1085 | .section .bss | ||
1086 | .align 12 | ||
1087 | exception_stack_bottom: | ||
1088 | .space BOOKE_EXCEPTION_STACK_SIZE * NR_CPUS | ||
1089 | .globl exception_stack_top | ||
1090 | exception_stack_top: | ||
1091 | |||
1092 | /* | 1136 | /* |
1093 | * Room for two PTE pointers, usually the kernel and current user pointers | 1137 | * Room for two PTE pointers, usually the kernel and current user pointers |
1094 | * to their respective root page table. | 1138 | * to their respective root page table. |
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c index 9971159c8040..9d42eb57aea3 100644 --- a/arch/powerpc/kernel/ibmebus.c +++ b/arch/powerpc/kernel/ibmebus.c | |||
@@ -53,7 +53,7 @@ static struct device ibmebus_bus_device = { /* fake "parent" device */ | |||
53 | struct bus_type ibmebus_bus_type; | 53 | struct bus_type ibmebus_bus_type; |
54 | 54 | ||
55 | /* These devices will automatically be added to the bus during init */ | 55 | /* These devices will automatically be added to the bus during init */ |
56 | static struct of_device_id __initdata builtin_matches[] = { | 56 | static struct of_device_id __initdata ibmebus_matches[] = { |
57 | { .compatible = "IBM,lhca" }, | 57 | { .compatible = "IBM,lhca" }, |
58 | { .compatible = "IBM,lhea" }, | 58 | { .compatible = "IBM,lhea" }, |
59 | {}, | 59 | {}, |
@@ -82,7 +82,8 @@ static void ibmebus_free_coherent(struct device *dev, | |||
82 | static dma_addr_t ibmebus_map_single(struct device *dev, | 82 | static dma_addr_t ibmebus_map_single(struct device *dev, |
83 | void *ptr, | 83 | void *ptr, |
84 | size_t size, | 84 | size_t size, |
85 | enum dma_data_direction direction) | 85 | enum dma_data_direction direction, |
86 | struct dma_attrs *attrs) | ||
86 | { | 87 | { |
87 | return (dma_addr_t)(ptr); | 88 | return (dma_addr_t)(ptr); |
88 | } | 89 | } |
@@ -90,14 +91,16 @@ static dma_addr_t ibmebus_map_single(struct device *dev, | |||
90 | static void ibmebus_unmap_single(struct device *dev, | 91 | static void ibmebus_unmap_single(struct device *dev, |
91 | dma_addr_t dma_addr, | 92 | dma_addr_t dma_addr, |
92 | size_t size, | 93 | size_t size, |
93 | enum dma_data_direction direction) | 94 | enum dma_data_direction direction, |
95 | struct dma_attrs *attrs) | ||
94 | { | 96 | { |
95 | return; | 97 | return; |
96 | } | 98 | } |
97 | 99 | ||
98 | static int ibmebus_map_sg(struct device *dev, | 100 | static int ibmebus_map_sg(struct device *dev, |
99 | struct scatterlist *sgl, | 101 | struct scatterlist *sgl, |
100 | int nents, enum dma_data_direction direction) | 102 | int nents, enum dma_data_direction direction, |
103 | struct dma_attrs *attrs) | ||
101 | { | 104 | { |
102 | struct scatterlist *sg; | 105 | struct scatterlist *sg; |
103 | int i; | 106 | int i; |
@@ -112,7 +115,8 @@ static int ibmebus_map_sg(struct device *dev, | |||
112 | 115 | ||
113 | static void ibmebus_unmap_sg(struct device *dev, | 116 | static void ibmebus_unmap_sg(struct device *dev, |
114 | struct scatterlist *sg, | 117 | struct scatterlist *sg, |
115 | int nents, enum dma_data_direction direction) | 118 | int nents, enum dma_data_direction direction, |
119 | struct dma_attrs *attrs) | ||
116 | { | 120 | { |
117 | return; | 121 | return; |
118 | } | 122 | } |
@@ -350,7 +354,7 @@ static int __init ibmebus_bus_init(void) | |||
350 | return err; | 354 | return err; |
351 | } | 355 | } |
352 | 356 | ||
353 | err = ibmebus_create_devices(builtin_matches); | 357 | err = ibmebus_create_devices(ibmebus_matches); |
354 | if (err) { | 358 | if (err) { |
355 | device_unregister(&ibmebus_bus_device); | 359 | device_unregister(&ibmebus_bus_device); |
356 | bus_unregister(&ibmebus_bus_type); | 360 | bus_unregister(&ibmebus_bus_type); |
diff --git a/arch/powerpc/kernel/idle_6xx.S b/arch/powerpc/kernel/idle_6xx.S index 01bcd52bbf8e..019b02d8844f 100644 --- a/arch/powerpc/kernel/idle_6xx.S +++ b/arch/powerpc/kernel/idle_6xx.S | |||
@@ -153,7 +153,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) | |||
153 | * address of current. R11 points to the exception frame (physical | 153 | * address of current. R11 points to the exception frame (physical |
154 | * address). We have to preserve r10. | 154 | * address). We have to preserve r10. |
155 | */ | 155 | */ |
156 | _GLOBAL(power_save_6xx_restore) | 156 | _GLOBAL(power_save_ppc32_restore) |
157 | lwz r9,_LINK(r11) /* interrupted in ppc6xx_idle: */ | 157 | lwz r9,_LINK(r11) /* interrupted in ppc6xx_idle: */ |
158 | stw r9,_NIP(r11) /* make it do a blr */ | 158 | stw r9,_NIP(r11) /* make it do a blr */ |
159 | 159 | ||
diff --git a/arch/powerpc/kernel/idle_e500.S b/arch/powerpc/kernel/idle_e500.S new file mode 100644 index 000000000000..06304034b393 --- /dev/null +++ b/arch/powerpc/kernel/idle_e500.S | |||
@@ -0,0 +1,93 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2008 Freescale Semiconductor, Inc. All rights reserved. | ||
3 | * Dave Liu <daveliu@freescale.com> | ||
4 | * copy from idle_6xx.S and modify for e500 based processor, | ||
5 | * implement the power_save function in idle. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/threads.h> | ||
14 | #include <asm/reg.h> | ||
15 | #include <asm/page.h> | ||
16 | #include <asm/cputable.h> | ||
17 | #include <asm/thread_info.h> | ||
18 | #include <asm/ppc_asm.h> | ||
19 | #include <asm/asm-offsets.h> | ||
20 | |||
21 | .text | ||
22 | |||
23 | _GLOBAL(e500_idle) | ||
24 | rlwinm r3,r1,0,0,31-THREAD_SHIFT /* current thread_info */ | ||
25 | lwz r4,TI_LOCAL_FLAGS(r3) /* set napping bit */ | ||
26 | ori r4,r4,_TLF_NAPPING /* so when we take an exception */ | ||
27 | stw r4,TI_LOCAL_FLAGS(r3) /* it will return to our caller */ | ||
28 | |||
29 | /* Check if we can nap or doze, put HID0 mask in r3 */ | ||
30 | lis r3,0 | ||
31 | BEGIN_FTR_SECTION | ||
32 | lis r3,HID0_DOZE@h | ||
33 | END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE) | ||
34 | |||
35 | BEGIN_FTR_SECTION | ||
36 | /* Now check if user enabled NAP mode */ | ||
37 | lis r4,powersave_nap@ha | ||
38 | lwz r4,powersave_nap@l(r4) | ||
39 | cmpwi 0,r4,0 | ||
40 | beq 1f | ||
41 | stwu r1,-16(r1) | ||
42 | mflr r0 | ||
43 | stw r0,20(r1) | ||
44 | bl flush_dcache_L1 | ||
45 | lwz r0,20(r1) | ||
46 | addi r1,r1,16 | ||
47 | mtlr r0 | ||
48 | lis r3,HID0_NAP@h | ||
49 | END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP) | ||
50 | BEGIN_FTR_SECTION | ||
51 | msync | ||
52 | li r7,L2CSR0_L2FL@l | ||
53 | mtspr SPRN_L2CSR0,r7 | ||
54 | 2: | ||
55 | mfspr r7,SPRN_L2CSR0 | ||
56 | andi. r4,r7,L2CSR0_L2FL@l | ||
57 | bne 2b | ||
58 | END_FTR_SECTION_IFSET(CPU_FTR_L2CSR|CPU_FTR_CAN_NAP) | ||
59 | 1: | ||
60 | /* Go to NAP or DOZE now */ | ||
61 | mfspr r4,SPRN_HID0 | ||
62 | rlwinm r4,r4,0,~(HID0_DOZE|HID0_NAP|HID0_SLEEP) | ||
63 | or r4,r4,r3 | ||
64 | isync | ||
65 | mtspr SPRN_HID0,r4 | ||
66 | isync | ||
67 | |||
68 | mfmsr r7 | ||
69 | oris r7,r7,MSR_WE@h | ||
70 | ori r7,r7,MSR_EE | ||
71 | msync | ||
72 | mtmsr r7 | ||
73 | isync | ||
74 | 2: b 2b | ||
75 | |||
76 | /* | ||
77 | * Return from NAP/DOZE mode, restore some CPU specific registers, | ||
78 | * r2 containing physical address of current. | ||
79 | * r11 points to the exception frame (physical address). | ||
80 | * We have to preserve r10. | ||
81 | */ | ||
82 | _GLOBAL(power_save_ppc32_restore) | ||
83 | lwz r9,_LINK(r11) /* interrupted in e500_idle */ | ||
84 | stw r9,_NIP(r11) /* make it do a blr */ | ||
85 | |||
86 | #ifdef CONFIG_SMP | ||
87 | mfspr r12,SPRN_SPRG3 | ||
88 | lwz r11,TI_CPU(r12) /* get cpu number * 4 */ | ||
89 | slwi r11,r11,2 | ||
90 | #else | ||
91 | li r11,0 | ||
92 | #endif | ||
93 | b transfer_to_handler_cont | ||
diff --git a/arch/powerpc/kernel/io.c b/arch/powerpc/kernel/io.c index e31aca9208eb..1882bf419fa6 100644 --- a/arch/powerpc/kernel/io.c +++ b/arch/powerpc/kernel/io.c | |||
@@ -120,7 +120,8 @@ EXPORT_SYMBOL(_outsl_ns); | |||
120 | 120 | ||
121 | #define IO_CHECK_ALIGN(v,a) ((((unsigned long)(v)) & ((a) - 1)) == 0) | 121 | #define IO_CHECK_ALIGN(v,a) ((((unsigned long)(v)) & ((a) - 1)) == 0) |
122 | 122 | ||
123 | void _memset_io(volatile void __iomem *addr, int c, unsigned long n) | 123 | notrace void |
124 | _memset_io(volatile void __iomem *addr, int c, unsigned long n) | ||
124 | { | 125 | { |
125 | void *p = (void __force *)addr; | 126 | void *p = (void __force *)addr; |
126 | u32 lc = c; | 127 | u32 lc = c; |
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index 0c663669bc32..8c68ee9e5d1c 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c | |||
@@ -267,11 +267,11 @@ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, | |||
267 | spin_unlock_irqrestore(&(tbl->it_lock), flags); | 267 | spin_unlock_irqrestore(&(tbl->it_lock), flags); |
268 | } | 268 | } |
269 | 269 | ||
270 | int iommu_map_sg(struct device *dev, struct scatterlist *sglist, | 270 | int iommu_map_sg(struct device *dev, struct iommu_table *tbl, |
271 | int nelems, unsigned long mask, | 271 | struct scatterlist *sglist, int nelems, |
272 | enum dma_data_direction direction) | 272 | unsigned long mask, enum dma_data_direction direction, |
273 | struct dma_attrs *attrs) | ||
273 | { | 274 | { |
274 | struct iommu_table *tbl = dev->archdata.dma_data; | ||
275 | dma_addr_t dma_next = 0, dma_addr; | 275 | dma_addr_t dma_next = 0, dma_addr; |
276 | unsigned long flags; | 276 | unsigned long flags; |
277 | struct scatterlist *s, *outs, *segstart; | 277 | struct scatterlist *s, *outs, *segstart; |
@@ -412,7 +412,8 @@ int iommu_map_sg(struct device *dev, struct scatterlist *sglist, | |||
412 | 412 | ||
413 | 413 | ||
414 | void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, | 414 | void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, |
415 | int nelems, enum dma_data_direction direction) | 415 | int nelems, enum dma_data_direction direction, |
416 | struct dma_attrs *attrs) | ||
416 | { | 417 | { |
417 | struct scatterlist *sg; | 418 | struct scatterlist *sg; |
418 | unsigned long flags; | 419 | unsigned long flags; |
@@ -554,7 +555,7 @@ void iommu_free_table(struct iommu_table *tbl, const char *node_name) | |||
554 | */ | 555 | */ |
555 | dma_addr_t iommu_map_single(struct device *dev, struct iommu_table *tbl, | 556 | dma_addr_t iommu_map_single(struct device *dev, struct iommu_table *tbl, |
556 | void *vaddr, size_t size, unsigned long mask, | 557 | void *vaddr, size_t size, unsigned long mask, |
557 | enum dma_data_direction direction) | 558 | enum dma_data_direction direction, struct dma_attrs *attrs) |
558 | { | 559 | { |
559 | dma_addr_t dma_handle = DMA_ERROR_CODE; | 560 | dma_addr_t dma_handle = DMA_ERROR_CODE; |
560 | unsigned long uaddr; | 561 | unsigned long uaddr; |
@@ -587,7 +588,8 @@ dma_addr_t iommu_map_single(struct device *dev, struct iommu_table *tbl, | |||
587 | } | 588 | } |
588 | 589 | ||
589 | void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle, | 590 | void iommu_unmap_single(struct iommu_table *tbl, dma_addr_t dma_handle, |
590 | size_t size, enum dma_data_direction direction) | 591 | size_t size, enum dma_data_direction direction, |
592 | struct dma_attrs *attrs) | ||
591 | { | 593 | { |
592 | unsigned int npages; | 594 | unsigned int npages; |
593 | 595 | ||
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 2f73f705d564..6ac8612da3c3 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c | |||
@@ -98,7 +98,7 @@ EXPORT_SYMBOL(irq_desc); | |||
98 | 98 | ||
99 | int distribute_irqs = 1; | 99 | int distribute_irqs = 1; |
100 | 100 | ||
101 | static inline unsigned long get_hard_enabled(void) | 101 | static inline notrace unsigned long get_hard_enabled(void) |
102 | { | 102 | { |
103 | unsigned long enabled; | 103 | unsigned long enabled; |
104 | 104 | ||
@@ -108,13 +108,13 @@ static inline unsigned long get_hard_enabled(void) | |||
108 | return enabled; | 108 | return enabled; |
109 | } | 109 | } |
110 | 110 | ||
111 | static inline void set_soft_enabled(unsigned long enable) | 111 | static inline notrace void set_soft_enabled(unsigned long enable) |
112 | { | 112 | { |
113 | __asm__ __volatile__("stb %0,%1(13)" | 113 | __asm__ __volatile__("stb %0,%1(13)" |
114 | : : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled))); | 114 | : : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled))); |
115 | } | 115 | } |
116 | 116 | ||
117 | void raw_local_irq_restore(unsigned long en) | 117 | notrace void raw_local_irq_restore(unsigned long en) |
118 | { | 118 | { |
119 | /* | 119 | /* |
120 | * get_paca()->soft_enabled = en; | 120 | * get_paca()->soft_enabled = en; |
@@ -356,9 +356,42 @@ void __init init_IRQ(void) | |||
356 | { | 356 | { |
357 | if (ppc_md.init_IRQ) | 357 | if (ppc_md.init_IRQ) |
358 | ppc_md.init_IRQ(); | 358 | ppc_md.init_IRQ(); |
359 | |||
360 | exc_lvl_ctx_init(); | ||
361 | |||
359 | irq_ctx_init(); | 362 | irq_ctx_init(); |
360 | } | 363 | } |
361 | 364 | ||
365 | #if defined(CONFIG_BOOKE) || defined(CONFIG_40x) | ||
366 | struct thread_info *critirq_ctx[NR_CPUS] __read_mostly; | ||
367 | struct thread_info *dbgirq_ctx[NR_CPUS] __read_mostly; | ||
368 | struct thread_info *mcheckirq_ctx[NR_CPUS] __read_mostly; | ||
369 | |||
370 | void exc_lvl_ctx_init(void) | ||
371 | { | ||
372 | struct thread_info *tp; | ||
373 | int i; | ||
374 | |||
375 | for_each_possible_cpu(i) { | ||
376 | memset((void *)critirq_ctx[i], 0, THREAD_SIZE); | ||
377 | tp = critirq_ctx[i]; | ||
378 | tp->cpu = i; | ||
379 | tp->preempt_count = 0; | ||
380 | |||
381 | #ifdef CONFIG_BOOKE | ||
382 | memset((void *)dbgirq_ctx[i], 0, THREAD_SIZE); | ||
383 | tp = dbgirq_ctx[i]; | ||
384 | tp->cpu = i; | ||
385 | tp->preempt_count = 0; | ||
386 | |||
387 | memset((void *)mcheckirq_ctx[i], 0, THREAD_SIZE); | ||
388 | tp = mcheckirq_ctx[i]; | ||
389 | tp->cpu = i; | ||
390 | tp->preempt_count = HARDIRQ_OFFSET; | ||
391 | #endif | ||
392 | } | ||
393 | } | ||
394 | #endif | ||
362 | 395 | ||
363 | #ifdef CONFIG_IRQSTACKS | 396 | #ifdef CONFIG_IRQSTACKS |
364 | struct thread_info *softirq_ctx[NR_CPUS] __read_mostly; | 397 | struct thread_info *softirq_ctx[NR_CPUS] __read_mostly; |
@@ -465,7 +498,7 @@ struct irq_host *irq_alloc_host(struct device_node *of_node, | |||
465 | host->revmap_type = revmap_type; | 498 | host->revmap_type = revmap_type; |
466 | host->inval_irq = inval_irq; | 499 | host->inval_irq = inval_irq; |
467 | host->ops = ops; | 500 | host->ops = ops; |
468 | host->of_node = of_node; | 501 | host->of_node = of_node_get(of_node); |
469 | 502 | ||
470 | if (host->ops->match == NULL) | 503 | if (host->ops->match == NULL) |
471 | host->ops->match = default_irq_host_match; | 504 | host->ops->match = default_irq_host_match; |
@@ -1073,7 +1106,7 @@ static const struct file_operations virq_debug_fops = { | |||
1073 | static int __init irq_debugfs_init(void) | 1106 | static int __init irq_debugfs_init(void) |
1074 | { | 1107 | { |
1075 | if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root, | 1108 | if (debugfs_create_file("virq_mapping", S_IRUGO, powerpc_debugfs_root, |
1076 | NULL, &virq_debug_fops)) | 1109 | NULL, &virq_debug_fops) == NULL) |
1077 | return -ENOMEM; | 1110 | return -ENOMEM; |
1078 | 1111 | ||
1079 | return 0; | 1112 | return 0; |
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index c176c513566b..4ba2af125450 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c | |||
@@ -34,6 +34,13 @@ | |||
34 | #include <asm/cacheflush.h> | 34 | #include <asm/cacheflush.h> |
35 | #include <asm/sstep.h> | 35 | #include <asm/sstep.h> |
36 | #include <asm/uaccess.h> | 36 | #include <asm/uaccess.h> |
37 | #include <asm/system.h> | ||
38 | |||
39 | #ifdef CONFIG_BOOKE | ||
40 | #define MSR_SINGLESTEP (MSR_DE) | ||
41 | #else | ||
42 | #define MSR_SINGLESTEP (MSR_SE) | ||
43 | #endif | ||
37 | 44 | ||
38 | DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; | 45 | DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; |
39 | DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); | 46 | DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); |
@@ -53,7 +60,8 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
53 | ret = -EINVAL; | 60 | ret = -EINVAL; |
54 | } | 61 | } |
55 | 62 | ||
56 | /* insn must be on a special executable page on ppc64 */ | 63 | /* insn must be on a special executable page on ppc64. This is |
64 | * not explicitly required on ppc32 (right now), but it doesn't hurt */ | ||
57 | if (!ret) { | 65 | if (!ret) { |
58 | p->ainsn.insn = get_insn_slot(); | 66 | p->ainsn.insn = get_insn_slot(); |
59 | if (!p->ainsn.insn) | 67 | if (!p->ainsn.insn) |
@@ -95,7 +103,16 @@ void __kprobes arch_remove_kprobe(struct kprobe *p) | |||
95 | 103 | ||
96 | static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) | 104 | static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) |
97 | { | 105 | { |
98 | regs->msr |= MSR_SE; | 106 | /* We turn off async exceptions to ensure that the single step will |
107 | * be for the instruction we have the kprobe on, if we dont its | ||
108 | * possible we'd get the single step reported for an exception handler | ||
109 | * like Decrementer or External Interrupt */ | ||
110 | regs->msr &= ~MSR_EE; | ||
111 | regs->msr |= MSR_SINGLESTEP; | ||
112 | #ifdef CONFIG_BOOKE | ||
113 | regs->msr &= ~MSR_CE; | ||
114 | mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) | DBCR0_IC | DBCR0_IDM); | ||
115 | #endif | ||
99 | 116 | ||
100 | /* | 117 | /* |
101 | * On powerpc we should single step on the original | 118 | * On powerpc we should single step on the original |
@@ -158,7 +175,8 @@ static int __kprobes kprobe_handler(struct pt_regs *regs) | |||
158 | kprobe_opcode_t insn = *p->ainsn.insn; | 175 | kprobe_opcode_t insn = *p->ainsn.insn; |
159 | if (kcb->kprobe_status == KPROBE_HIT_SS && | 176 | if (kcb->kprobe_status == KPROBE_HIT_SS && |
160 | is_trap(insn)) { | 177 | is_trap(insn)) { |
161 | regs->msr &= ~MSR_SE; | 178 | /* Turn off 'trace' bits */ |
179 | regs->msr &= ~MSR_SINGLESTEP; | ||
162 | regs->msr |= kcb->kprobe_saved_msr; | 180 | regs->msr |= kcb->kprobe_saved_msr; |
163 | goto no_kprobe; | 181 | goto no_kprobe; |
164 | } | 182 | } |
@@ -376,6 +394,10 @@ static int __kprobes post_kprobe_handler(struct pt_regs *regs) | |||
376 | if (!cur) | 394 | if (!cur) |
377 | return 0; | 395 | return 0; |
378 | 396 | ||
397 | /* make sure we got here for instruction we have a kprobe on */ | ||
398 | if (((unsigned long)cur->ainsn.insn + 4) != regs->nip) | ||
399 | return 0; | ||
400 | |||
379 | if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) { | 401 | if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) { |
380 | kcb->kprobe_status = KPROBE_HIT_SSDONE; | 402 | kcb->kprobe_status = KPROBE_HIT_SSDONE; |
381 | cur->post_handler(cur, regs, 0); | 403 | cur->post_handler(cur, regs, 0); |
@@ -395,10 +417,10 @@ out: | |||
395 | 417 | ||
396 | /* | 418 | /* |
397 | * if somebody else is singlestepping across a probe point, msr | 419 | * if somebody else is singlestepping across a probe point, msr |
398 | * will have SE set, in which case, continue the remaining processing | 420 | * will have DE/SE set, in which case, continue the remaining processing |
399 | * of do_debug, as if this is not a probe hit. | 421 | * of do_debug, as if this is not a probe hit. |
400 | */ | 422 | */ |
401 | if (regs->msr & MSR_SE) | 423 | if (regs->msr & MSR_SINGLESTEP) |
402 | return 0; | 424 | return 0; |
403 | 425 | ||
404 | return 1; | 426 | return 1; |
@@ -421,7 +443,7 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) | |||
421 | * normal page fault. | 443 | * normal page fault. |
422 | */ | 444 | */ |
423 | regs->nip = (unsigned long)cur->addr; | 445 | regs->nip = (unsigned long)cur->addr; |
424 | regs->msr &= ~MSR_SE; | 446 | regs->msr &= ~MSR_SINGLESTEP; /* Turn off 'trace' bits */ |
425 | regs->msr |= kcb->kprobe_saved_msr; | 447 | regs->msr |= kcb->kprobe_saved_msr; |
426 | if (kcb->kprobe_status == KPROBE_REENTER) | 448 | if (kcb->kprobe_status == KPROBE_REENTER) |
427 | restore_previous_kprobe(kcb); | 449 | restore_previous_kprobe(kcb); |
@@ -498,7 +520,7 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self, | |||
498 | #ifdef CONFIG_PPC64 | 520 | #ifdef CONFIG_PPC64 |
499 | unsigned long arch_deref_entry_point(void *entry) | 521 | unsigned long arch_deref_entry_point(void *entry) |
500 | { | 522 | { |
501 | return (unsigned long)(((func_descr_t *)entry)->entry); | 523 | return ((func_descr_t *)entry)->entry; |
502 | } | 524 | } |
503 | #endif | 525 | #endif |
504 | 526 | ||
diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c index 61dd17449ddc..4d96e1db55ee 100644 --- a/arch/powerpc/kernel/legacy_serial.c +++ b/arch/powerpc/kernel/legacy_serial.c | |||
@@ -33,13 +33,14 @@ static struct legacy_serial_info { | |||
33 | phys_addr_t taddr; | 33 | phys_addr_t taddr; |
34 | } legacy_serial_infos[MAX_LEGACY_SERIAL_PORTS]; | 34 | } legacy_serial_infos[MAX_LEGACY_SERIAL_PORTS]; |
35 | 35 | ||
36 | static struct __initdata of_device_id parents[] = { | 36 | static struct __initdata of_device_id legacy_serial_parents[] = { |
37 | {.type = "soc",}, | 37 | {.type = "soc",}, |
38 | {.type = "tsi-bridge",}, | 38 | {.type = "tsi-bridge",}, |
39 | {.type = "opb", }, | 39 | {.type = "opb", }, |
40 | {.compatible = "ibm,opb",}, | 40 | {.compatible = "ibm,opb",}, |
41 | {.compatible = "simple-bus",}, | 41 | {.compatible = "simple-bus",}, |
42 | {.compatible = "wrs,epld-localbus",}, | 42 | {.compatible = "wrs,epld-localbus",}, |
43 | {}, | ||
43 | }; | 44 | }; |
44 | 45 | ||
45 | static unsigned int legacy_serial_count; | 46 | static unsigned int legacy_serial_count; |
@@ -136,6 +137,11 @@ static int __init add_legacy_soc_port(struct device_node *np, | |||
136 | if (of_get_property(np, "clock-frequency", NULL) == NULL) | 137 | if (of_get_property(np, "clock-frequency", NULL) == NULL) |
137 | return -1; | 138 | return -1; |
138 | 139 | ||
140 | /* if reg-shift or offset, don't try to use it */ | ||
141 | if ((of_get_property(np, "reg-shift", NULL) != NULL) || | ||
142 | (of_get_property(np, "reg-offset", NULL) != NULL)) | ||
143 | return -1; | ||
144 | |||
139 | /* if rtas uses this device, don't try to use it as well */ | 145 | /* if rtas uses this device, don't try to use it as well */ |
140 | if (of_get_property(np, "used-by-rtas", NULL) != NULL) | 146 | if (of_get_property(np, "used-by-rtas", NULL) != NULL) |
141 | return -1; | 147 | return -1; |
@@ -322,7 +328,7 @@ void __init find_legacy_serial_ports(void) | |||
322 | struct device_node *parent = of_get_parent(np); | 328 | struct device_node *parent = of_get_parent(np); |
323 | if (!parent) | 329 | if (!parent) |
324 | continue; | 330 | continue; |
325 | if (of_match_node(parents, parent) != NULL) { | 331 | if (of_match_node(legacy_serial_parents, parent) != NULL) { |
326 | index = add_legacy_soc_port(np, np); | 332 | index = add_legacy_soc_port(np, np); |
327 | if (index >= 0 && np == stdout) | 333 | if (index >= 0 && np == stdout) |
328 | legacy_serial_console = index; | 334 | legacy_serial_console = index; |
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c index 1e656b43ad7f..827a5726a035 100644 --- a/arch/powerpc/kernel/lparcfg.c +++ b/arch/powerpc/kernel/lparcfg.c | |||
@@ -573,7 +573,7 @@ static int lparcfg_open(struct inode *inode, struct file *file) | |||
573 | return single_open(file, lparcfg_data, NULL); | 573 | return single_open(file, lparcfg_data, NULL); |
574 | } | 574 | } |
575 | 575 | ||
576 | const struct file_operations lparcfg_fops = { | 576 | static const struct file_operations lparcfg_fops = { |
577 | .owner = THIS_MODULE, | 577 | .owner = THIS_MODULE, |
578 | .read = seq_read, | 578 | .read = seq_read, |
579 | .write = lparcfg_write, | 579 | .write = lparcfg_write, |
@@ -581,7 +581,7 @@ const struct file_operations lparcfg_fops = { | |||
581 | .release = single_release, | 581 | .release = single_release, |
582 | }; | 582 | }; |
583 | 583 | ||
584 | int __init lparcfg_init(void) | 584 | static int __init lparcfg_init(void) |
585 | { | 585 | { |
586 | struct proc_dir_entry *ent; | 586 | struct proc_dir_entry *ent; |
587 | mode_t mode = S_IRUSR | S_IRGRP | S_IROTH; | 587 | mode_t mode = S_IRUSR | S_IRGRP | S_IROTH; |
@@ -601,7 +601,7 @@ int __init lparcfg_init(void) | |||
601 | return 0; | 601 | return 0; |
602 | } | 602 | } |
603 | 603 | ||
604 | void __exit lparcfg_cleanup(void) | 604 | static void __exit lparcfg_cleanup(void) |
605 | { | 605 | { |
606 | if (proc_ppc64_lparcfg) | 606 | if (proc_ppc64_lparcfg) |
607 | remove_proc_entry("lparcfg", proc_ppc64_lparcfg->parent); | 607 | remove_proc_entry("lparcfg", proc_ppc64_lparcfg->parent); |
diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c index 704375bda73a..a168514d8609 100644 --- a/arch/powerpc/kernel/machine_kexec_64.c +++ b/arch/powerpc/kernel/machine_kexec_64.c | |||
@@ -158,7 +158,7 @@ void kexec_copy_flush(struct kimage *image) | |||
158 | * on calling the interrupts, but we would like to call it off irq level | 158 | * on calling the interrupts, but we would like to call it off irq level |
159 | * so that the interrupt controller is clean. | 159 | * so that the interrupt controller is clean. |
160 | */ | 160 | */ |
161 | void kexec_smp_down(void *arg) | 161 | static void kexec_smp_down(void *arg) |
162 | { | 162 | { |
163 | if (ppc_md.kexec_cpu_down) | 163 | if (ppc_md.kexec_cpu_down) |
164 | ppc_md.kexec_cpu_down(0, 1); | 164 | ppc_md.kexec_cpu_down(0, 1); |
@@ -172,7 +172,7 @@ static void kexec_prepare_cpus(void) | |||
172 | { | 172 | { |
173 | int my_cpu, i, notified=-1; | 173 | int my_cpu, i, notified=-1; |
174 | 174 | ||
175 | smp_call_function(kexec_smp_down, NULL, 0, /* wait */0); | 175 | smp_call_function(kexec_smp_down, NULL, /* wait */0); |
176 | my_cpu = get_cpu(); | 176 | my_cpu = get_cpu(); |
177 | 177 | ||
178 | /* check the others cpus are now down (via paca hw cpu id == -1) */ | 178 | /* check the others cpus are now down (via paca hw cpu id == -1) */ |
@@ -249,7 +249,7 @@ static void kexec_prepare_cpus(void) | |||
249 | * We could use a smaller stack if we don't care about anything using | 249 | * We could use a smaller stack if we don't care about anything using |
250 | * current, but that audit has not been performed. | 250 | * current, but that audit has not been performed. |
251 | */ | 251 | */ |
252 | union thread_union kexec_stack | 252 | static union thread_union kexec_stack |
253 | __attribute__((__section__(".data.init_task"))) = { }; | 253 | __attribute__((__section__(".data.init_task"))) = { }; |
254 | 254 | ||
255 | /* Our assembly helper, in kexec_stub.S */ | 255 | /* Our assembly helper, in kexec_stub.S */ |
diff --git a/arch/powerpc/kernel/misc.S b/arch/powerpc/kernel/misc.S index 7b9160220698..85cb6f340846 100644 --- a/arch/powerpc/kernel/misc.S +++ b/arch/powerpc/kernel/misc.S | |||
@@ -116,3 +116,8 @@ _GLOBAL(longjmp) | |||
116 | mtlr r0 | 116 | mtlr r0 |
117 | mr r3,r4 | 117 | mr r3,r4 |
118 | blr | 118 | blr |
119 | |||
120 | _GLOBAL(__setup_cpu_power7) | ||
121 | _GLOBAL(__restore_cpu_power7) | ||
122 | /* place holder */ | ||
123 | blr | ||
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 89aaaa6f3561..6321ae36f729 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S | |||
@@ -489,7 +489,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_UNIFIED_ID_CACHE) | |||
489 | * | 489 | * |
490 | * flush_icache_range(unsigned long start, unsigned long stop) | 490 | * flush_icache_range(unsigned long start, unsigned long stop) |
491 | */ | 491 | */ |
492 | _GLOBAL(__flush_icache_range) | 492 | _KPROBE(__flush_icache_range) |
493 | BEGIN_FTR_SECTION | 493 | BEGIN_FTR_SECTION |
494 | blr /* for 601, do nothing */ | 494 | blr /* for 601, do nothing */ |
495 | END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) | 495 | END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE) |
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index 942951e76586..4dd70cf7bb4e 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S | |||
@@ -506,6 +506,39 @@ _GLOBAL(giveup_altivec) | |||
506 | 506 | ||
507 | #endif /* CONFIG_ALTIVEC */ | 507 | #endif /* CONFIG_ALTIVEC */ |
508 | 508 | ||
509 | #ifdef CONFIG_VSX | ||
510 | /* | ||
511 | * __giveup_vsx(tsk) | ||
512 | * Disable VSX for the task given as the argument. | ||
513 | * Does NOT save vsx registers. | ||
514 | * Enables the VSX for use in the kernel on return. | ||
515 | */ | ||
516 | _GLOBAL(__giveup_vsx) | ||
517 | mfmsr r5 | ||
518 | oris r5,r5,MSR_VSX@h | ||
519 | mtmsrd r5 /* enable use of VSX now */ | ||
520 | isync | ||
521 | |||
522 | cmpdi 0,r3,0 | ||
523 | beqlr- /* if no previous owner, done */ | ||
524 | addi r3,r3,THREAD /* want THREAD of task */ | ||
525 | ld r5,PT_REGS(r3) | ||
526 | cmpdi 0,r5,0 | ||
527 | beq 1f | ||
528 | ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) | ||
529 | lis r3,MSR_VSX@h | ||
530 | andc r4,r4,r3 /* disable VSX for previous task */ | ||
531 | std r4,_MSR-STACK_FRAME_OVERHEAD(r5) | ||
532 | 1: | ||
533 | #ifndef CONFIG_SMP | ||
534 | li r5,0 | ||
535 | ld r4,last_task_used_vsx@got(r2) | ||
536 | std r5,0(r4) | ||
537 | #endif /* CONFIG_SMP */ | ||
538 | blr | ||
539 | |||
540 | #endif /* CONFIG_VSX */ | ||
541 | |||
509 | /* kexec_wait(phys_cpu) | 542 | /* kexec_wait(phys_cpu) |
510 | * | 543 | * |
511 | * wait for the flag to change, indicating this kernel is going away but | 544 | * wait for the flag to change, indicating this kernel is going away but |
diff --git a/arch/powerpc/kernel/module.c b/arch/powerpc/kernel/module.c new file mode 100644 index 000000000000..af07003573c4 --- /dev/null +++ b/arch/powerpc/kernel/module.c | |||
@@ -0,0 +1,116 @@ | |||
1 | /* Kernel module help for powerpc. | ||
2 | Copyright (C) 2001, 2003 Rusty Russell IBM Corporation. | ||
3 | Copyright (C) 2008 Freescale Semiconductor, Inc. | ||
4 | |||
5 | This program is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published by | ||
7 | the Free Software Foundation; either version 2 of the License, or | ||
8 | (at your option) any later version. | ||
9 | |||
10 | This program is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | GNU General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with this program; if not, write to the Free Software | ||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/elf.h> | ||
21 | #include <linux/moduleloader.h> | ||
22 | #include <linux/err.h> | ||
23 | #include <linux/vmalloc.h> | ||
24 | #include <linux/bug.h> | ||
25 | #include <asm/module.h> | ||
26 | #include <asm/uaccess.h> | ||
27 | #include <asm/firmware.h> | ||
28 | #include <linux/sort.h> | ||
29 | |||
30 | #include "setup.h" | ||
31 | |||
32 | LIST_HEAD(module_bug_list); | ||
33 | |||
34 | void *module_alloc(unsigned long size) | ||
35 | { | ||
36 | if (size == 0) | ||
37 | return NULL; | ||
38 | |||
39 | return vmalloc_exec(size); | ||
40 | } | ||
41 | |||
42 | /* Free memory returned from module_alloc */ | ||
43 | void module_free(struct module *mod, void *module_region) | ||
44 | { | ||
45 | vfree(module_region); | ||
46 | /* FIXME: If module_region == mod->init_region, trim exception | ||
47 | table entries. */ | ||
48 | } | ||
49 | |||
50 | static const Elf_Shdr *find_section(const Elf_Ehdr *hdr, | ||
51 | const Elf_Shdr *sechdrs, | ||
52 | const char *name) | ||
53 | { | ||
54 | char *secstrings; | ||
55 | unsigned int i; | ||
56 | |||
57 | secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | ||
58 | for (i = 1; i < hdr->e_shnum; i++) | ||
59 | if (strcmp(secstrings+sechdrs[i].sh_name, name) == 0) | ||
60 | return &sechdrs[i]; | ||
61 | return NULL; | ||
62 | } | ||
63 | |||
64 | int module_finalize(const Elf_Ehdr *hdr, | ||
65 | const Elf_Shdr *sechdrs, struct module *me) | ||
66 | { | ||
67 | const Elf_Shdr *sect; | ||
68 | int err; | ||
69 | |||
70 | err = module_bug_finalize(hdr, sechdrs, me); | ||
71 | if (err) | ||
72 | return err; | ||
73 | |||
74 | /* Apply feature fixups */ | ||
75 | sect = find_section(hdr, sechdrs, "__ftr_fixup"); | ||
76 | if (sect != NULL) | ||
77 | do_feature_fixups(cur_cpu_spec->cpu_features, | ||
78 | (void *)sect->sh_addr, | ||
79 | (void *)sect->sh_addr + sect->sh_size); | ||
80 | |||
81 | #ifdef CONFIG_PPC64 | ||
82 | sect = find_section(hdr, sechdrs, "__fw_ftr_fixup"); | ||
83 | if (sect != NULL) | ||
84 | do_feature_fixups(powerpc_firmware_features, | ||
85 | (void *)sect->sh_addr, | ||
86 | (void *)sect->sh_addr + sect->sh_size); | ||
87 | #endif | ||
88 | |||
89 | sect = find_section(hdr, sechdrs, "__lwsync_fixup"); | ||
90 | if (sect != NULL) | ||
91 | do_lwsync_fixups(cur_cpu_spec->cpu_features, | ||
92 | (void *)sect->sh_addr, | ||
93 | (void *)sect->sh_addr + sect->sh_size); | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | void module_arch_cleanup(struct module *mod) | ||
99 | { | ||
100 | module_bug_cleanup(mod); | ||
101 | } | ||
102 | |||
103 | struct bug_entry *module_find_bug(unsigned long bugaddr) | ||
104 | { | ||
105 | struct mod_arch_specific *mod; | ||
106 | unsigned int i; | ||
107 | struct bug_entry *bug; | ||
108 | |||
109 | list_for_each_entry(mod, &module_bug_list, bug_list) { | ||
110 | bug = mod->bug_table; | ||
111 | for (i = 0; i < mod->num_bugs; ++i, ++bug) | ||
112 | if (bugaddr == bug->bug_addr) | ||
113 | return bug; | ||
114 | } | ||
115 | return NULL; | ||
116 | } | ||
diff --git a/arch/powerpc/kernel/module_32.c b/arch/powerpc/kernel/module_32.c index eab313858315..2df91a03462a 100644 --- a/arch/powerpc/kernel/module_32.c +++ b/arch/powerpc/kernel/module_32.c | |||
@@ -34,23 +34,6 @@ | |||
34 | #define DEBUGP(fmt , ...) | 34 | #define DEBUGP(fmt , ...) |
35 | #endif | 35 | #endif |
36 | 36 | ||
37 | LIST_HEAD(module_bug_list); | ||
38 | |||
39 | void *module_alloc(unsigned long size) | ||
40 | { | ||
41 | if (size == 0) | ||
42 | return NULL; | ||
43 | return vmalloc(size); | ||
44 | } | ||
45 | |||
46 | /* Free memory returned from module_alloc */ | ||
47 | void module_free(struct module *mod, void *module_region) | ||
48 | { | ||
49 | vfree(module_region); | ||
50 | /* FIXME: If module_region == mod->init_region, trim exception | ||
51 | table entries. */ | ||
52 | } | ||
53 | |||
54 | /* Count how many different relocations (different symbol, different | 37 | /* Count how many different relocations (different symbol, different |
55 | addend) */ | 38 | addend) */ |
56 | static unsigned int count_relocs(const Elf32_Rela *rela, unsigned int num) | 39 | static unsigned int count_relocs(const Elf32_Rela *rela, unsigned int num) |
@@ -325,58 +308,3 @@ int apply_relocate_add(Elf32_Shdr *sechdrs, | |||
325 | } | 308 | } |
326 | return 0; | 309 | return 0; |
327 | } | 310 | } |
328 | |||
329 | static const Elf_Shdr *find_section(const Elf_Ehdr *hdr, | ||
330 | const Elf_Shdr *sechdrs, | ||
331 | const char *name) | ||
332 | { | ||
333 | char *secstrings; | ||
334 | unsigned int i; | ||
335 | |||
336 | secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | ||
337 | for (i = 1; i < hdr->e_shnum; i++) | ||
338 | if (strcmp(secstrings+sechdrs[i].sh_name, name) == 0) | ||
339 | return &sechdrs[i]; | ||
340 | return NULL; | ||
341 | } | ||
342 | |||
343 | int module_finalize(const Elf_Ehdr *hdr, | ||
344 | const Elf_Shdr *sechdrs, | ||
345 | struct module *me) | ||
346 | { | ||
347 | const Elf_Shdr *sect; | ||
348 | int err; | ||
349 | |||
350 | err = module_bug_finalize(hdr, sechdrs, me); | ||
351 | if (err) /* never true, currently */ | ||
352 | return err; | ||
353 | |||
354 | /* Apply feature fixups */ | ||
355 | sect = find_section(hdr, sechdrs, "__ftr_fixup"); | ||
356 | if (sect != NULL) | ||
357 | do_feature_fixups(cur_cpu_spec->cpu_features, | ||
358 | (void *)sect->sh_addr, | ||
359 | (void *)sect->sh_addr + sect->sh_size); | ||
360 | |||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | void module_arch_cleanup(struct module *mod) | ||
365 | { | ||
366 | module_bug_cleanup(mod); | ||
367 | } | ||
368 | |||
369 | struct bug_entry *module_find_bug(unsigned long bugaddr) | ||
370 | { | ||
371 | struct mod_arch_specific *mod; | ||
372 | unsigned int i; | ||
373 | struct bug_entry *bug; | ||
374 | |||
375 | list_for_each_entry(mod, &module_bug_list, bug_list) { | ||
376 | bug = mod->bug_table; | ||
377 | for (i = 0; i < mod->num_bugs; ++i, ++bug) | ||
378 | if (bugaddr == bug->bug_addr) | ||
379 | return bug; | ||
380 | } | ||
381 | return NULL; | ||
382 | } | ||
diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index 3a82b02b784b..ee6a2982d567 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <asm/module.h> | 24 | #include <asm/module.h> |
25 | #include <asm/uaccess.h> | 25 | #include <asm/uaccess.h> |
26 | #include <asm/firmware.h> | 26 | #include <asm/firmware.h> |
27 | #include <asm/code-patching.h> | ||
27 | #include <linux/sort.h> | 28 | #include <linux/sort.h> |
28 | 29 | ||
29 | #include "setup.h" | 30 | #include "setup.h" |
@@ -101,22 +102,6 @@ static unsigned int count_relocs(const Elf64_Rela *rela, unsigned int num) | |||
101 | return _count_relocs; | 102 | return _count_relocs; |
102 | } | 103 | } |
103 | 104 | ||
104 | void *module_alloc(unsigned long size) | ||
105 | { | ||
106 | if (size == 0) | ||
107 | return NULL; | ||
108 | |||
109 | return vmalloc_exec(size); | ||
110 | } | ||
111 | |||
112 | /* Free memory returned from module_alloc */ | ||
113 | void module_free(struct module *mod, void *module_region) | ||
114 | { | ||
115 | vfree(module_region); | ||
116 | /* FIXME: If module_region == mod->init_region, trim exception | ||
117 | table entries. */ | ||
118 | } | ||
119 | |||
120 | static int relacmp(const void *_x, const void *_y) | 105 | static int relacmp(const void *_x, const void *_y) |
121 | { | 106 | { |
122 | const Elf64_Rela *x, *y; | 107 | const Elf64_Rela *x, *y; |
@@ -346,7 +331,7 @@ static unsigned long stub_for_addr(Elf64_Shdr *sechdrs, | |||
346 | restore r2. */ | 331 | restore r2. */ |
347 | static int restore_r2(u32 *instruction, struct module *me) | 332 | static int restore_r2(u32 *instruction, struct module *me) |
348 | { | 333 | { |
349 | if (*instruction != 0x60000000) { | 334 | if (*instruction != PPC_NOP_INSTR) { |
350 | printk("%s: Expect noop after relocate, got %08x\n", | 335 | printk("%s: Expect noop after relocate, got %08x\n", |
351 | me->name, *instruction); | 336 | me->name, *instruction); |
352 | return 0; | 337 | return 0; |
@@ -466,65 +451,3 @@ int apply_relocate_add(Elf64_Shdr *sechdrs, | |||
466 | 451 | ||
467 | return 0; | 452 | return 0; |
468 | } | 453 | } |
469 | |||
470 | LIST_HEAD(module_bug_list); | ||
471 | |||
472 | static const Elf_Shdr *find_section(const Elf_Ehdr *hdr, | ||
473 | const Elf_Shdr *sechdrs, | ||
474 | const char *name) | ||
475 | { | ||
476 | char *secstrings; | ||
477 | unsigned int i; | ||
478 | |||
479 | secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | ||
480 | for (i = 1; i < hdr->e_shnum; i++) | ||
481 | if (strcmp(secstrings+sechdrs[i].sh_name, name) == 0) | ||
482 | return &sechdrs[i]; | ||
483 | return NULL; | ||
484 | } | ||
485 | |||
486 | int module_finalize(const Elf_Ehdr *hdr, | ||
487 | const Elf_Shdr *sechdrs, struct module *me) | ||
488 | { | ||
489 | const Elf_Shdr *sect; | ||
490 | int err; | ||
491 | |||
492 | err = module_bug_finalize(hdr, sechdrs, me); | ||
493 | if (err) | ||
494 | return err; | ||
495 | |||
496 | /* Apply feature fixups */ | ||
497 | sect = find_section(hdr, sechdrs, "__ftr_fixup"); | ||
498 | if (sect != NULL) | ||
499 | do_feature_fixups(cur_cpu_spec->cpu_features, | ||
500 | (void *)sect->sh_addr, | ||
501 | (void *)sect->sh_addr + sect->sh_size); | ||
502 | |||
503 | sect = find_section(hdr, sechdrs, "__fw_ftr_fixup"); | ||
504 | if (sect != NULL) | ||
505 | do_feature_fixups(powerpc_firmware_features, | ||
506 | (void *)sect->sh_addr, | ||
507 | (void *)sect->sh_addr + sect->sh_size); | ||
508 | |||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | void module_arch_cleanup(struct module *mod) | ||
513 | { | ||
514 | module_bug_cleanup(mod); | ||
515 | } | ||
516 | |||
517 | struct bug_entry *module_find_bug(unsigned long bugaddr) | ||
518 | { | ||
519 | struct mod_arch_specific *mod; | ||
520 | unsigned int i; | ||
521 | struct bug_entry *bug; | ||
522 | |||
523 | list_for_each_entry(mod, &module_bug_list, bug_list) { | ||
524 | bug = mod->bug_table; | ||
525 | for (i = 0; i < mod->num_bugs; ++i, ++bug) | ||
526 | if (bugaddr == bug->bug_addr) | ||
527 | return bug; | ||
528 | } | ||
529 | return NULL; | ||
530 | } | ||
diff --git a/arch/powerpc/kernel/msi.c b/arch/powerpc/kernel/msi.c index c62d1012c013..3bb7d3dd28be 100644 --- a/arch/powerpc/kernel/msi.c +++ b/arch/powerpc/kernel/msi.c | |||
@@ -34,5 +34,5 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | |||
34 | 34 | ||
35 | void arch_teardown_msi_irqs(struct pci_dev *dev) | 35 | void arch_teardown_msi_irqs(struct pci_dev *dev) |
36 | { | 36 | { |
37 | return ppc_md.teardown_msi_irqs(dev); | 37 | ppc_md.teardown_msi_irqs(dev); |
38 | } | 38 | } |
diff --git a/arch/powerpc/kernel/of_device.c b/arch/powerpc/kernel/of_device.c index 5748ddb47d9f..e9be908f199b 100644 --- a/arch/powerpc/kernel/of_device.c +++ b/arch/powerpc/kernel/of_device.c | |||
@@ -89,54 +89,6 @@ struct of_device *of_device_alloc(struct device_node *np, | |||
89 | } | 89 | } |
90 | EXPORT_SYMBOL(of_device_alloc); | 90 | EXPORT_SYMBOL(of_device_alloc); |
91 | 91 | ||
92 | ssize_t of_device_get_modalias(struct of_device *ofdev, | ||
93 | char *str, ssize_t len) | ||
94 | { | ||
95 | const char *compat; | ||
96 | int cplen, i; | ||
97 | ssize_t tsize, csize, repend; | ||
98 | |||
99 | /* Name & Type */ | ||
100 | csize = snprintf(str, len, "of:N%sT%s", | ||
101 | ofdev->node->name, ofdev->node->type); | ||
102 | |||
103 | /* Get compatible property if any */ | ||
104 | compat = of_get_property(ofdev->node, "compatible", &cplen); | ||
105 | if (!compat) | ||
106 | return csize; | ||
107 | |||
108 | /* Find true end (we tolerate multiple \0 at the end */ | ||
109 | for (i=(cplen-1); i>=0 && !compat[i]; i--) | ||
110 | cplen--; | ||
111 | if (!cplen) | ||
112 | return csize; | ||
113 | cplen++; | ||
114 | |||
115 | /* Check space (need cplen+1 chars including final \0) */ | ||
116 | tsize = csize + cplen; | ||
117 | repend = tsize; | ||
118 | |||
119 | if (csize>=len) /* @ the limit, all is already filled */ | ||
120 | return tsize; | ||
121 | |||
122 | if (tsize>=len) { /* limit compat list */ | ||
123 | cplen = len-csize-1; | ||
124 | repend = len; | ||
125 | } | ||
126 | |||
127 | /* Copy and do char replacement */ | ||
128 | memcpy(&str[csize+1], compat, cplen); | ||
129 | for (i=csize; i<repend; i++) { | ||
130 | char c = str[i]; | ||
131 | if (c=='\0') | ||
132 | str[i] = 'C'; | ||
133 | else if (c==' ') | ||
134 | str[i] = '_'; | ||
135 | } | ||
136 | |||
137 | return tsize; | ||
138 | } | ||
139 | |||
140 | int of_device_uevent(struct device *dev, struct kobj_uevent_env *env) | 92 | int of_device_uevent(struct device *dev, struct kobj_uevent_env *env) |
141 | { | 93 | { |
142 | struct of_device *ofdev; | 94 | struct of_device *ofdev; |
diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c index e79ad8afda07..3f37a6e62771 100644 --- a/arch/powerpc/kernel/of_platform.c +++ b/arch/powerpc/kernel/of_platform.c | |||
@@ -76,6 +76,8 @@ struct of_device* of_platform_device_create(struct device_node *np, | |||
76 | return NULL; | 76 | return NULL; |
77 | 77 | ||
78 | dev->dma_mask = 0xffffffffUL; | 78 | dev->dma_mask = 0xffffffffUL; |
79 | dev->dev.coherent_dma_mask = DMA_32BIT_MASK; | ||
80 | |||
79 | dev->dev.bus = &of_platform_bus_type; | 81 | dev->dev.bus = &of_platform_bus_type; |
80 | 82 | ||
81 | /* We do not fill the DMA ops for platform devices by default. | 83 | /* We do not fill the DMA ops for platform devices by default. |
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 52750745edfd..30eedfc5a566 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c | |||
@@ -189,7 +189,7 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, | |||
189 | 189 | ||
190 | dev->cfg_size = pci_cfg_space_size(dev); | 190 | dev->cfg_size = pci_cfg_space_size(dev); |
191 | 191 | ||
192 | sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus), | 192 | dev_set_name(&dev->dev, "%04x:%02x:%02x.%d", pci_domain_nr(bus), |
193 | dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); | 193 | dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); |
194 | dev->class = get_int_prop(node, "class-code", 0); | 194 | dev->class = get_int_prop(node, "class-code", 0); |
195 | dev->revision = get_int_prop(node, "revision-id", 0); | 195 | dev->revision = get_int_prop(node, "revision-id", 0); |
diff --git a/arch/powerpc/kernel/ppc32.h b/arch/powerpc/kernel/ppc32.h index 90e562771791..dc16aefe1dd0 100644 --- a/arch/powerpc/kernel/ppc32.h +++ b/arch/powerpc/kernel/ppc32.h | |||
@@ -120,6 +120,7 @@ struct mcontext32 { | |||
120 | elf_fpregset_t mc_fregs; | 120 | elf_fpregset_t mc_fregs; |
121 | unsigned int mc_pad[2]; | 121 | unsigned int mc_pad[2]; |
122 | elf_vrregset_t32 mc_vregs __attribute__((__aligned__(16))); | 122 | elf_vrregset_t32 mc_vregs __attribute__((__aligned__(16))); |
123 | elf_vsrreghalf_t32 mc_vsregs __attribute__((__aligned__(16))); | ||
123 | }; | 124 | }; |
124 | 125 | ||
125 | struct ucontext32 { | 126 | struct ucontext32 { |
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index cf6b5a7d8b3f..e1ea4fe5cfbd 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c | |||
@@ -8,7 +8,6 @@ | |||
8 | #include <linux/screen_info.h> | 8 | #include <linux/screen_info.h> |
9 | #include <linux/vt_kern.h> | 9 | #include <linux/vt_kern.h> |
10 | #include <linux/nvram.h> | 10 | #include <linux/nvram.h> |
11 | #include <linux/console.h> | ||
12 | #include <linux/irq.h> | 11 | #include <linux/irq.h> |
13 | #include <linux/pci.h> | 12 | #include <linux/pci.h> |
14 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
@@ -43,6 +42,7 @@ | |||
43 | #include <asm/div64.h> | 42 | #include <asm/div64.h> |
44 | #include <asm/signal.h> | 43 | #include <asm/signal.h> |
45 | #include <asm/dcr.h> | 44 | #include <asm/dcr.h> |
45 | #include <asm/ftrace.h> | ||
46 | 46 | ||
47 | #ifdef CONFIG_PPC32 | 47 | #ifdef CONFIG_PPC32 |
48 | extern void transfer_to_handler(void); | 48 | extern void transfer_to_handler(void); |
@@ -68,6 +68,10 @@ EXPORT_SYMBOL(single_step_exception); | |||
68 | EXPORT_SYMBOL(sys_sigreturn); | 68 | EXPORT_SYMBOL(sys_sigreturn); |
69 | #endif | 69 | #endif |
70 | 70 | ||
71 | #ifdef CONFIG_FTRACE | ||
72 | EXPORT_SYMBOL(_mcount); | ||
73 | #endif | ||
74 | |||
71 | EXPORT_SYMBOL(strcpy); | 75 | EXPORT_SYMBOL(strcpy); |
72 | EXPORT_SYMBOL(strncpy); | 76 | EXPORT_SYMBOL(strncpy); |
73 | EXPORT_SYMBOL(strcat); | 77 | EXPORT_SYMBOL(strcat); |
@@ -103,6 +107,9 @@ EXPORT_SYMBOL(giveup_fpu); | |||
103 | #ifdef CONFIG_ALTIVEC | 107 | #ifdef CONFIG_ALTIVEC |
104 | EXPORT_SYMBOL(giveup_altivec); | 108 | EXPORT_SYMBOL(giveup_altivec); |
105 | #endif /* CONFIG_ALTIVEC */ | 109 | #endif /* CONFIG_ALTIVEC */ |
110 | #ifdef CONFIG_VSX | ||
111 | EXPORT_SYMBOL(giveup_vsx); | ||
112 | #endif /* CONFIG_VSX */ | ||
106 | #ifdef CONFIG_SPE | 113 | #ifdef CONFIG_SPE |
107 | EXPORT_SYMBOL(giveup_spe); | 114 | EXPORT_SYMBOL(giveup_spe); |
108 | #endif /* CONFIG_SPE */ | 115 | #endif /* CONFIG_SPE */ |
@@ -160,7 +167,6 @@ EXPORT_SYMBOL(screen_info); | |||
160 | EXPORT_SYMBOL(timer_interrupt); | 167 | EXPORT_SYMBOL(timer_interrupt); |
161 | EXPORT_SYMBOL(irq_desc); | 168 | EXPORT_SYMBOL(irq_desc); |
162 | EXPORT_SYMBOL(tb_ticks_per_jiffy); | 169 | EXPORT_SYMBOL(tb_ticks_per_jiffy); |
163 | EXPORT_SYMBOL(console_drivers); | ||
164 | EXPORT_SYMBOL(cacheable_memcpy); | 170 | EXPORT_SYMBOL(cacheable_memcpy); |
165 | #endif | 171 | #endif |
166 | 172 | ||
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 7de41c3948ec..219f3634115e 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c | |||
@@ -53,6 +53,7 @@ extern unsigned long _get_SP(void); | |||
53 | #ifndef CONFIG_SMP | 53 | #ifndef CONFIG_SMP |
54 | struct task_struct *last_task_used_math = NULL; | 54 | struct task_struct *last_task_used_math = NULL; |
55 | struct task_struct *last_task_used_altivec = NULL; | 55 | struct task_struct *last_task_used_altivec = NULL; |
56 | struct task_struct *last_task_used_vsx = NULL; | ||
56 | struct task_struct *last_task_used_spe = NULL; | 57 | struct task_struct *last_task_used_spe = NULL; |
57 | #endif | 58 | #endif |
58 | 59 | ||
@@ -104,17 +105,6 @@ void enable_kernel_fp(void) | |||
104 | } | 105 | } |
105 | EXPORT_SYMBOL(enable_kernel_fp); | 106 | EXPORT_SYMBOL(enable_kernel_fp); |
106 | 107 | ||
107 | int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs) | ||
108 | { | ||
109 | if (!tsk->thread.regs) | ||
110 | return 0; | ||
111 | flush_fp_to_thread(current); | ||
112 | |||
113 | memcpy(fpregs, &tsk->thread.fpr[0], sizeof(*fpregs)); | ||
114 | |||
115 | return 1; | ||
116 | } | ||
117 | |||
118 | #ifdef CONFIG_ALTIVEC | 108 | #ifdef CONFIG_ALTIVEC |
119 | void enable_kernel_altivec(void) | 109 | void enable_kernel_altivec(void) |
120 | { | 110 | { |
@@ -148,36 +138,48 @@ void flush_altivec_to_thread(struct task_struct *tsk) | |||
148 | preempt_enable(); | 138 | preempt_enable(); |
149 | } | 139 | } |
150 | } | 140 | } |
141 | #endif /* CONFIG_ALTIVEC */ | ||
151 | 142 | ||
152 | int dump_task_altivec(struct task_struct *tsk, elf_vrregset_t *vrregs) | 143 | #ifdef CONFIG_VSX |
144 | #if 0 | ||
145 | /* not currently used, but some crazy RAID module might want to later */ | ||
146 | void enable_kernel_vsx(void) | ||
153 | { | 147 | { |
154 | /* ELF_NVRREG includes the VSCR and VRSAVE which we need to save | 148 | WARN_ON(preemptible()); |
155 | * separately, see below */ | ||
156 | const int nregs = ELF_NVRREG - 2; | ||
157 | elf_vrreg_t *reg; | ||
158 | u32 *dest; | ||
159 | |||
160 | if (tsk == current) | ||
161 | flush_altivec_to_thread(tsk); | ||
162 | |||
163 | reg = (elf_vrreg_t *)vrregs; | ||
164 | |||
165 | /* copy the 32 vr registers */ | ||
166 | memcpy(reg, &tsk->thread.vr[0], nregs * sizeof(*reg)); | ||
167 | reg += nregs; | ||
168 | 149 | ||
169 | /* copy the vscr */ | 150 | #ifdef CONFIG_SMP |
170 | memcpy(reg, &tsk->thread.vscr, sizeof(*reg)); | 151 | if (current->thread.regs && (current->thread.regs->msr & MSR_VSX)) |
171 | reg++; | 152 | giveup_vsx(current); |
153 | else | ||
154 | giveup_vsx(NULL); /* just enable vsx for kernel - force */ | ||
155 | #else | ||
156 | giveup_vsx(last_task_used_vsx); | ||
157 | #endif /* CONFIG_SMP */ | ||
158 | } | ||
159 | EXPORT_SYMBOL(enable_kernel_vsx); | ||
160 | #endif | ||
172 | 161 | ||
173 | /* vrsave is stored in the high 32bit slot of the final 128bits */ | 162 | void giveup_vsx(struct task_struct *tsk) |
174 | memset(reg, 0, sizeof(*reg)); | 163 | { |
175 | dest = (u32 *)reg; | 164 | giveup_fpu(tsk); |
176 | *dest = tsk->thread.vrsave; | 165 | giveup_altivec(tsk); |
166 | __giveup_vsx(tsk); | ||
167 | } | ||
177 | 168 | ||
178 | return 1; | 169 | void flush_vsx_to_thread(struct task_struct *tsk) |
170 | { | ||
171 | if (tsk->thread.regs) { | ||
172 | preempt_disable(); | ||
173 | if (tsk->thread.regs->msr & MSR_VSX) { | ||
174 | #ifdef CONFIG_SMP | ||
175 | BUG_ON(tsk != current); | ||
176 | #endif | ||
177 | giveup_vsx(tsk); | ||
178 | } | ||
179 | preempt_enable(); | ||
180 | } | ||
179 | } | 181 | } |
180 | #endif /* CONFIG_ALTIVEC */ | 182 | #endif /* CONFIG_VSX */ |
181 | 183 | ||
182 | #ifdef CONFIG_SPE | 184 | #ifdef CONFIG_SPE |
183 | 185 | ||
@@ -209,14 +211,6 @@ void flush_spe_to_thread(struct task_struct *tsk) | |||
209 | preempt_enable(); | 211 | preempt_enable(); |
210 | } | 212 | } |
211 | } | 213 | } |
212 | |||
213 | int dump_spe(struct pt_regs *regs, elf_vrregset_t *evrregs) | ||
214 | { | ||
215 | flush_spe_to_thread(current); | ||
216 | /* We copy u32 evr[32] + u64 acc + u32 spefscr -> 35 */ | ||
217 | memcpy(evrregs, ¤t->thread.evr[0], sizeof(u32) * 35); | ||
218 | return 1; | ||
219 | } | ||
220 | #endif /* CONFIG_SPE */ | 214 | #endif /* CONFIG_SPE */ |
221 | 215 | ||
222 | #ifndef CONFIG_SMP | 216 | #ifndef CONFIG_SMP |
@@ -233,6 +227,10 @@ void discard_lazy_cpu_state(void) | |||
233 | if (last_task_used_altivec == current) | 227 | if (last_task_used_altivec == current) |
234 | last_task_used_altivec = NULL; | 228 | last_task_used_altivec = NULL; |
235 | #endif /* CONFIG_ALTIVEC */ | 229 | #endif /* CONFIG_ALTIVEC */ |
230 | #ifdef CONFIG_VSX | ||
231 | if (last_task_used_vsx == current) | ||
232 | last_task_used_vsx = NULL; | ||
233 | #endif /* CONFIG_VSX */ | ||
236 | #ifdef CONFIG_SPE | 234 | #ifdef CONFIG_SPE |
237 | if (last_task_used_spe == current) | 235 | if (last_task_used_spe == current) |
238 | last_task_used_spe = NULL; | 236 | last_task_used_spe = NULL; |
@@ -297,6 +295,11 @@ struct task_struct *__switch_to(struct task_struct *prev, | |||
297 | if (prev->thread.regs && (prev->thread.regs->msr & MSR_VEC)) | 295 | if (prev->thread.regs && (prev->thread.regs->msr & MSR_VEC)) |
298 | giveup_altivec(prev); | 296 | giveup_altivec(prev); |
299 | #endif /* CONFIG_ALTIVEC */ | 297 | #endif /* CONFIG_ALTIVEC */ |
298 | #ifdef CONFIG_VSX | ||
299 | if (prev->thread.regs && (prev->thread.regs->msr & MSR_VSX)) | ||
300 | /* VMX and FPU registers are already save here */ | ||
301 | __giveup_vsx(prev); | ||
302 | #endif /* CONFIG_VSX */ | ||
300 | #ifdef CONFIG_SPE | 303 | #ifdef CONFIG_SPE |
301 | /* | 304 | /* |
302 | * If the previous thread used spe in the last quantum | 305 | * If the previous thread used spe in the last quantum |
@@ -317,6 +320,10 @@ struct task_struct *__switch_to(struct task_struct *prev, | |||
317 | if (new->thread.regs && last_task_used_altivec == new) | 320 | if (new->thread.regs && last_task_used_altivec == new) |
318 | new->thread.regs->msr |= MSR_VEC; | 321 | new->thread.regs->msr |= MSR_VEC; |
319 | #endif /* CONFIG_ALTIVEC */ | 322 | #endif /* CONFIG_ALTIVEC */ |
323 | #ifdef CONFIG_VSX | ||
324 | if (new->thread.regs && last_task_used_vsx == new) | ||
325 | new->thread.regs->msr |= MSR_VSX; | ||
326 | #endif /* CONFIG_VSX */ | ||
320 | #ifdef CONFIG_SPE | 327 | #ifdef CONFIG_SPE |
321 | /* Avoid the trap. On smp this this never happens since | 328 | /* Avoid the trap. On smp this this never happens since |
322 | * we don't set last_task_used_spe | 329 | * we don't set last_task_used_spe |
@@ -417,6 +424,8 @@ static struct regbit { | |||
417 | {MSR_EE, "EE"}, | 424 | {MSR_EE, "EE"}, |
418 | {MSR_PR, "PR"}, | 425 | {MSR_PR, "PR"}, |
419 | {MSR_FP, "FP"}, | 426 | {MSR_FP, "FP"}, |
427 | {MSR_VEC, "VEC"}, | ||
428 | {MSR_VSX, "VSX"}, | ||
420 | {MSR_ME, "ME"}, | 429 | {MSR_ME, "ME"}, |
421 | {MSR_IR, "IR"}, | 430 | {MSR_IR, "IR"}, |
422 | {MSR_DR, "DR"}, | 431 | {MSR_DR, "DR"}, |
@@ -484,10 +493,8 @@ void show_regs(struct pt_regs * regs) | |||
484 | * Lookup NIP late so we have the best change of getting the | 493 | * Lookup NIP late so we have the best change of getting the |
485 | * above info out without failing | 494 | * above info out without failing |
486 | */ | 495 | */ |
487 | printk("NIP ["REG"] ", regs->nip); | 496 | printk("NIP ["REG"] %pS\n", regs->nip, (void *)regs->nip); |
488 | print_symbol("%s\n", regs->nip); | 497 | printk("LR ["REG"] %pS\n", regs->link, (void *)regs->link); |
489 | printk("LR ["REG"] ", regs->link); | ||
490 | print_symbol("%s\n", regs->link); | ||
491 | #endif | 498 | #endif |
492 | show_stack(current, (unsigned long *) regs->gpr[1]); | 499 | show_stack(current, (unsigned long *) regs->gpr[1]); |
493 | if (!user_mode(regs)) | 500 | if (!user_mode(regs)) |
@@ -534,6 +541,7 @@ void prepare_to_copy(struct task_struct *tsk) | |||
534 | { | 541 | { |
535 | flush_fp_to_thread(current); | 542 | flush_fp_to_thread(current); |
536 | flush_altivec_to_thread(current); | 543 | flush_altivec_to_thread(current); |
544 | flush_vsx_to_thread(current); | ||
537 | flush_spe_to_thread(current); | 545 | flush_spe_to_thread(current); |
538 | } | 546 | } |
539 | 547 | ||
@@ -689,6 +697,9 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp) | |||
689 | #endif | 697 | #endif |
690 | 698 | ||
691 | discard_lazy_cpu_state(); | 699 | discard_lazy_cpu_state(); |
700 | #ifdef CONFIG_VSX | ||
701 | current->thread.used_vsr = 0; | ||
702 | #endif | ||
692 | memset(current->thread.fpr, 0, sizeof(current->thread.fpr)); | 703 | memset(current->thread.fpr, 0, sizeof(current->thread.fpr)); |
693 | current->thread.fpscr.val = 0; | 704 | current->thread.fpscr.val = 0; |
694 | #ifdef CONFIG_ALTIVEC | 705 | #ifdef CONFIG_ALTIVEC |
@@ -971,8 +982,7 @@ void show_stack(struct task_struct *tsk, unsigned long *stack) | |||
971 | newsp = stack[0]; | 982 | newsp = stack[0]; |
972 | ip = stack[STACK_FRAME_LR_SAVE]; | 983 | ip = stack[STACK_FRAME_LR_SAVE]; |
973 | if (!firstframe || ip != lr) { | 984 | if (!firstframe || ip != lr) { |
974 | printk("["REG"] ["REG"] ", sp, ip); | 985 | printk("["REG"] ["REG"] %pS", sp, ip, (void *)ip); |
975 | print_symbol("%s", ip); | ||
976 | if (firstframe) | 986 | if (firstframe) |
977 | printk(" (unreliable)"); | 987 | printk(" (unreliable)"); |
978 | printk("\n"); | 988 | printk("\n"); |
@@ -987,10 +997,9 @@ void show_stack(struct task_struct *tsk, unsigned long *stack) | |||
987 | && stack[STACK_FRAME_MARKER] == STACK_FRAME_REGS_MARKER) { | 997 | && stack[STACK_FRAME_MARKER] == STACK_FRAME_REGS_MARKER) { |
988 | struct pt_regs *regs = (struct pt_regs *) | 998 | struct pt_regs *regs = (struct pt_regs *) |
989 | (sp + STACK_FRAME_OVERHEAD); | 999 | (sp + STACK_FRAME_OVERHEAD); |
990 | printk("--- Exception: %lx", regs->trap); | ||
991 | print_symbol(" at %s\n", regs->nip); | ||
992 | lr = regs->link; | 1000 | lr = regs->link; |
993 | print_symbol(" LR = %s\n", lr); | 1001 | printk("--- Exception: %lx at %pS\n LR = %pS\n", |
1002 | regs->trap, (void *)regs->nip, (void *)lr); | ||
994 | firstframe = 1; | 1003 | firstframe = 1; |
995 | } | 1004 | } |
996 | 1005 | ||
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 2aefe2a4129a..87d83c56b31e 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
@@ -609,6 +609,10 @@ static struct feature_property { | |||
609 | {"altivec", 0, CPU_FTR_ALTIVEC, PPC_FEATURE_HAS_ALTIVEC}, | 609 | {"altivec", 0, CPU_FTR_ALTIVEC, PPC_FEATURE_HAS_ALTIVEC}, |
610 | {"ibm,vmx", 1, CPU_FTR_ALTIVEC, PPC_FEATURE_HAS_ALTIVEC}, | 610 | {"ibm,vmx", 1, CPU_FTR_ALTIVEC, PPC_FEATURE_HAS_ALTIVEC}, |
611 | #endif /* CONFIG_ALTIVEC */ | 611 | #endif /* CONFIG_ALTIVEC */ |
612 | #ifdef CONFIG_VSX | ||
613 | /* Yes, this _really_ is ibm,vmx == 2 to enable VSX */ | ||
614 | {"ibm,vmx", 2, CPU_FTR_VSX, PPC_FEATURE_HAS_VSX}, | ||
615 | #endif /* CONFIG_VSX */ | ||
612 | #ifdef CONFIG_PPC64 | 616 | #ifdef CONFIG_PPC64 |
613 | {"ibm,dfp", 1, 0, PPC_FEATURE_HAS_DFP}, | 617 | {"ibm,dfp", 1, 0, PPC_FEATURE_HAS_DFP}, |
614 | {"ibm,purr", 1, CPU_FTR_PURR, 0}, | 618 | {"ibm,purr", 1, CPU_FTR_PURR, 0}, |
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 6d6df1e60325..1ea8c8d3ce89 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c | |||
@@ -620,6 +620,7 @@ static void __init early_cmdline_parse(void) | |||
620 | #define OV1_PPC_2_03 0x10 /* set if we support PowerPC 2.03 */ | 620 | #define OV1_PPC_2_03 0x10 /* set if we support PowerPC 2.03 */ |
621 | #define OV1_PPC_2_04 0x08 /* set if we support PowerPC 2.04 */ | 621 | #define OV1_PPC_2_04 0x08 /* set if we support PowerPC 2.04 */ |
622 | #define OV1_PPC_2_05 0x04 /* set if we support PowerPC 2.05 */ | 622 | #define OV1_PPC_2_05 0x04 /* set if we support PowerPC 2.05 */ |
623 | #define OV1_PPC_2_06 0x02 /* set if we support PowerPC 2.06 */ | ||
623 | 624 | ||
624 | /* Option vector 2: Open Firmware options supported */ | 625 | /* Option vector 2: Open Firmware options supported */ |
625 | #define OV2_REAL_MODE 0x20 /* set if we want OF in real mode */ | 626 | #define OV2_REAL_MODE 0x20 /* set if we want OF in real mode */ |
@@ -650,6 +651,8 @@ static void __init early_cmdline_parse(void) | |||
650 | static unsigned char ibm_architecture_vec[] = { | 651 | static unsigned char ibm_architecture_vec[] = { |
651 | W(0xfffe0000), W(0x003a0000), /* POWER5/POWER5+ */ | 652 | W(0xfffe0000), W(0x003a0000), /* POWER5/POWER5+ */ |
652 | W(0xffff0000), W(0x003e0000), /* POWER6 */ | 653 | W(0xffff0000), W(0x003e0000), /* POWER6 */ |
654 | W(0xffff0000), W(0x003f0000), /* POWER7 */ | ||
655 | W(0xffffffff), W(0x0f000003), /* all 2.06-compliant */ | ||
653 | W(0xffffffff), W(0x0f000002), /* all 2.05-compliant */ | 656 | W(0xffffffff), W(0x0f000002), /* all 2.05-compliant */ |
654 | W(0xfffffffe), W(0x0f000001), /* all 2.04-compliant and earlier */ | 657 | W(0xfffffffe), W(0x0f000001), /* all 2.04-compliant and earlier */ |
655 | 5 - 1, /* 5 option vectors */ | 658 | 5 - 1, /* 5 option vectors */ |
@@ -658,7 +661,7 @@ static unsigned char ibm_architecture_vec[] = { | |||
658 | 3 - 2, /* length */ | 661 | 3 - 2, /* length */ |
659 | 0, /* don't ignore, don't halt */ | 662 | 0, /* don't ignore, don't halt */ |
660 | OV1_PPC_2_00 | OV1_PPC_2_01 | OV1_PPC_2_02 | OV1_PPC_2_03 | | 663 | OV1_PPC_2_00 | OV1_PPC_2_01 | OV1_PPC_2_02 | OV1_PPC_2_03 | |
661 | OV1_PPC_2_04 | OV1_PPC_2_05, | 664 | OV1_PPC_2_04 | OV1_PPC_2_05 | OV1_PPC_2_06, |
662 | 665 | ||
663 | /* option vector 2: Open Firmware options supported */ | 666 | /* option vector 2: Open Firmware options supported */ |
664 | 34 - 2, /* length */ | 667 | 34 - 2, /* length */ |
diff --git a/arch/powerpc/kernel/prom_init_check.sh b/arch/powerpc/kernel/prom_init_check.sh index 31729a9387df..2c7e8e87f770 100644 --- a/arch/powerpc/kernel/prom_init_check.sh +++ b/arch/powerpc/kernel/prom_init_check.sh | |||
@@ -48,6 +48,20 @@ do | |||
48 | fi | 48 | fi |
49 | done | 49 | done |
50 | 50 | ||
51 | # ignore register save/restore funcitons | ||
52 | if [ "${UNDEF:0:9}" = "_restgpr_" ]; then | ||
53 | OK=1 | ||
54 | fi | ||
55 | if [ "${UNDEF:0:11}" = "_rest32gpr_" ]; then | ||
56 | OK=1 | ||
57 | fi | ||
58 | if [ "${UNDEF:0:9}" = "_savegpr_" ]; then | ||
59 | OK=1 | ||
60 | fi | ||
61 | if [ "${UNDEF:0:11}" = "_save32gpr_" ]; then | ||
62 | OK=1 | ||
63 | fi | ||
64 | |||
51 | if [ $OK -eq 0 ]; then | 65 | if [ $OK -eq 0 ]; then |
52 | ERROR=1 | 66 | ERROR=1 |
53 | echo "Error: External symbol '$UNDEF' referenced" \ | 67 | echo "Error: External symbol '$UNDEF' referenced" \ |
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 2a9fe97e4521..8feb93e7890c 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c | |||
@@ -215,29 +215,56 @@ static int fpr_get(struct task_struct *target, const struct user_regset *regset, | |||
215 | unsigned int pos, unsigned int count, | 215 | unsigned int pos, unsigned int count, |
216 | void *kbuf, void __user *ubuf) | 216 | void *kbuf, void __user *ubuf) |
217 | { | 217 | { |
218 | #ifdef CONFIG_VSX | ||
219 | double buf[33]; | ||
220 | int i; | ||
221 | #endif | ||
218 | flush_fp_to_thread(target); | 222 | flush_fp_to_thread(target); |
219 | 223 | ||
224 | #ifdef CONFIG_VSX | ||
225 | /* copy to local buffer then write that out */ | ||
226 | for (i = 0; i < 32 ; i++) | ||
227 | buf[i] = target->thread.TS_FPR(i); | ||
228 | memcpy(&buf[32], &target->thread.fpscr, sizeof(double)); | ||
229 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, buf, 0, -1); | ||
230 | |||
231 | #else | ||
220 | BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) != | 232 | BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) != |
221 | offsetof(struct thread_struct, fpr[32])); | 233 | offsetof(struct thread_struct, TS_FPR(32))); |
222 | 234 | ||
223 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, | 235 | return user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
224 | &target->thread.fpr, 0, -1); | 236 | &target->thread.fpr, 0, -1); |
237 | #endif | ||
225 | } | 238 | } |
226 | 239 | ||
227 | static int fpr_set(struct task_struct *target, const struct user_regset *regset, | 240 | static int fpr_set(struct task_struct *target, const struct user_regset *regset, |
228 | unsigned int pos, unsigned int count, | 241 | unsigned int pos, unsigned int count, |
229 | const void *kbuf, const void __user *ubuf) | 242 | const void *kbuf, const void __user *ubuf) |
230 | { | 243 | { |
244 | #ifdef CONFIG_VSX | ||
245 | double buf[33]; | ||
246 | int i; | ||
247 | #endif | ||
231 | flush_fp_to_thread(target); | 248 | flush_fp_to_thread(target); |
232 | 249 | ||
250 | #ifdef CONFIG_VSX | ||
251 | /* copy to local buffer then write that out */ | ||
252 | i = user_regset_copyin(&pos, &count, &kbuf, &ubuf, buf, 0, -1); | ||
253 | if (i) | ||
254 | return i; | ||
255 | for (i = 0; i < 32 ; i++) | ||
256 | target->thread.TS_FPR(i) = buf[i]; | ||
257 | memcpy(&target->thread.fpscr, &buf[32], sizeof(double)); | ||
258 | return 0; | ||
259 | #else | ||
233 | BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) != | 260 | BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) != |
234 | offsetof(struct thread_struct, fpr[32])); | 261 | offsetof(struct thread_struct, TS_FPR(32))); |
235 | 262 | ||
236 | return user_regset_copyin(&pos, &count, &kbuf, &ubuf, | 263 | return user_regset_copyin(&pos, &count, &kbuf, &ubuf, |
237 | &target->thread.fpr, 0, -1); | 264 | &target->thread.fpr, 0, -1); |
265 | #endif | ||
238 | } | 266 | } |
239 | 267 | ||
240 | |||
241 | #ifdef CONFIG_ALTIVEC | 268 | #ifdef CONFIG_ALTIVEC |
242 | /* | 269 | /* |
243 | * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go. | 270 | * Get/set all the altivec registers vr0..vr31, vscr, vrsave, in one go. |
@@ -323,6 +350,56 @@ static int vr_set(struct task_struct *target, const struct user_regset *regset, | |||
323 | } | 350 | } |
324 | #endif /* CONFIG_ALTIVEC */ | 351 | #endif /* CONFIG_ALTIVEC */ |
325 | 352 | ||
353 | #ifdef CONFIG_VSX | ||
354 | /* | ||
355 | * Currently to set and and get all the vsx state, you need to call | ||
356 | * the fp and VMX calls aswell. This only get/sets the lower 32 | ||
357 | * 128bit VSX registers. | ||
358 | */ | ||
359 | |||
360 | static int vsr_active(struct task_struct *target, | ||
361 | const struct user_regset *regset) | ||
362 | { | ||
363 | flush_vsx_to_thread(target); | ||
364 | return target->thread.used_vsr ? regset->n : 0; | ||
365 | } | ||
366 | |||
367 | static int vsr_get(struct task_struct *target, const struct user_regset *regset, | ||
368 | unsigned int pos, unsigned int count, | ||
369 | void *kbuf, void __user *ubuf) | ||
370 | { | ||
371 | double buf[32]; | ||
372 | int ret, i; | ||
373 | |||
374 | flush_vsx_to_thread(target); | ||
375 | |||
376 | for (i = 0; i < 32 ; i++) | ||
377 | buf[i] = current->thread.fpr[i][TS_VSRLOWOFFSET]; | ||
378 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | ||
379 | buf, 0, 32 * sizeof(double)); | ||
380 | |||
381 | return ret; | ||
382 | } | ||
383 | |||
384 | static int vsr_set(struct task_struct *target, const struct user_regset *regset, | ||
385 | unsigned int pos, unsigned int count, | ||
386 | const void *kbuf, const void __user *ubuf) | ||
387 | { | ||
388 | double buf[32]; | ||
389 | int ret,i; | ||
390 | |||
391 | flush_vsx_to_thread(target); | ||
392 | |||
393 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | ||
394 | buf, 0, 32 * sizeof(double)); | ||
395 | for (i = 0; i < 32 ; i++) | ||
396 | current->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i]; | ||
397 | |||
398 | |||
399 | return ret; | ||
400 | } | ||
401 | #endif /* CONFIG_VSX */ | ||
402 | |||
326 | #ifdef CONFIG_SPE | 403 | #ifdef CONFIG_SPE |
327 | 404 | ||
328 | /* | 405 | /* |
@@ -399,6 +476,9 @@ enum powerpc_regset { | |||
399 | #ifdef CONFIG_ALTIVEC | 476 | #ifdef CONFIG_ALTIVEC |
400 | REGSET_VMX, | 477 | REGSET_VMX, |
401 | #endif | 478 | #endif |
479 | #ifdef CONFIG_VSX | ||
480 | REGSET_VSX, | ||
481 | #endif | ||
402 | #ifdef CONFIG_SPE | 482 | #ifdef CONFIG_SPE |
403 | REGSET_SPE, | 483 | REGSET_SPE, |
404 | #endif | 484 | #endif |
@@ -422,6 +502,13 @@ static const struct user_regset native_regsets[] = { | |||
422 | .active = vr_active, .get = vr_get, .set = vr_set | 502 | .active = vr_active, .get = vr_get, .set = vr_set |
423 | }, | 503 | }, |
424 | #endif | 504 | #endif |
505 | #ifdef CONFIG_VSX | ||
506 | [REGSET_VSX] = { | ||
507 | .core_note_type = NT_PPC_VSX, .n = 32, | ||
508 | .size = sizeof(double), .align = sizeof(double), | ||
509 | .active = vsr_active, .get = vsr_get, .set = vsr_set | ||
510 | }, | ||
511 | #endif | ||
425 | #ifdef CONFIG_SPE | 512 | #ifdef CONFIG_SPE |
426 | [REGSET_SPE] = { | 513 | [REGSET_SPE] = { |
427 | .n = 35, | 514 | .n = 35, |
@@ -728,7 +815,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
728 | tmp = ptrace_get_reg(child, (int) index); | 815 | tmp = ptrace_get_reg(child, (int) index); |
729 | } else { | 816 | } else { |
730 | flush_fp_to_thread(child); | 817 | flush_fp_to_thread(child); |
731 | tmp = ((unsigned long *)child->thread.fpr)[index - PT_FPR0]; | 818 | tmp = ((unsigned long *)child->thread.fpr) |
819 | [TS_FPRWIDTH * (index - PT_FPR0)]; | ||
732 | } | 820 | } |
733 | ret = put_user(tmp,(unsigned long __user *) data); | 821 | ret = put_user(tmp,(unsigned long __user *) data); |
734 | break; | 822 | break; |
@@ -755,7 +843,8 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
755 | ret = ptrace_put_reg(child, index, data); | 843 | ret = ptrace_put_reg(child, index, data); |
756 | } else { | 844 | } else { |
757 | flush_fp_to_thread(child); | 845 | flush_fp_to_thread(child); |
758 | ((unsigned long *)child->thread.fpr)[index - PT_FPR0] = data; | 846 | ((unsigned long *)child->thread.fpr) |
847 | [TS_FPRWIDTH * (index - PT_FPR0)] = data; | ||
759 | ret = 0; | 848 | ret = 0; |
760 | } | 849 | } |
761 | break; | 850 | break; |
@@ -820,6 +909,21 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
820 | sizeof(u32)), | 909 | sizeof(u32)), |
821 | (const void __user *) data); | 910 | (const void __user *) data); |
822 | #endif | 911 | #endif |
912 | #ifdef CONFIG_VSX | ||
913 | case PTRACE_GETVSRREGS: | ||
914 | return copy_regset_to_user(child, &user_ppc_native_view, | ||
915 | REGSET_VSX, | ||
916 | 0, (32 * sizeof(vector128) + | ||
917 | sizeof(u32)), | ||
918 | (void __user *) data); | ||
919 | |||
920 | case PTRACE_SETVSRREGS: | ||
921 | return copy_regset_from_user(child, &user_ppc_native_view, | ||
922 | REGSET_VSX, | ||
923 | 0, (32 * sizeof(vector128) + | ||
924 | sizeof(u32)), | ||
925 | (const void __user *) data); | ||
926 | #endif | ||
823 | #ifdef CONFIG_SPE | 927 | #ifdef CONFIG_SPE |
824 | case PTRACE_GETEVRREGS: | 928 | case PTRACE_GETEVRREGS: |
825 | /* Get the child spe register state. */ | 929 | /* Get the child spe register state. */ |
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c index 4c1de6af4c09..67bf1a1e7e14 100644 --- a/arch/powerpc/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c | |||
@@ -64,6 +64,11 @@ static long compat_ptrace_old(struct task_struct *child, long request, | |||
64 | return -EPERM; | 64 | return -EPERM; |
65 | } | 65 | } |
66 | 66 | ||
67 | /* Macros to workout the correct index for the FPR in the thread struct */ | ||
68 | #define FPRNUMBER(i) (((i) - PT_FPR0) >> 1) | ||
69 | #define FPRHALF(i) (((i) - PT_FPR0) & 1) | ||
70 | #define FPRINDEX(i) TS_FPRWIDTH * FPRNUMBER(i) + FPRHALF(i) | ||
71 | |||
67 | long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | 72 | long compat_arch_ptrace(struct task_struct *child, compat_long_t request, |
68 | compat_ulong_t caddr, compat_ulong_t cdata) | 73 | compat_ulong_t caddr, compat_ulong_t cdata) |
69 | { | 74 | { |
@@ -122,7 +127,8 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
122 | * to be an array of unsigned int (32 bits) - the | 127 | * to be an array of unsigned int (32 bits) - the |
123 | * index passed in is based on this assumption. | 128 | * index passed in is based on this assumption. |
124 | */ | 129 | */ |
125 | tmp = ((unsigned int *)child->thread.fpr)[index - PT_FPR0]; | 130 | tmp = ((unsigned int *)child->thread.fpr) |
131 | [FPRINDEX(index)]; | ||
126 | } | 132 | } |
127 | ret = put_user((unsigned int)tmp, (u32 __user *)data); | 133 | ret = put_user((unsigned int)tmp, (u32 __user *)data); |
128 | break; | 134 | break; |
@@ -162,7 +168,8 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
162 | CHECK_FULL_REGS(child->thread.regs); | 168 | CHECK_FULL_REGS(child->thread.regs); |
163 | if (numReg >= PT_FPR0) { | 169 | if (numReg >= PT_FPR0) { |
164 | flush_fp_to_thread(child); | 170 | flush_fp_to_thread(child); |
165 | tmp = ((unsigned long int *)child->thread.fpr)[numReg - PT_FPR0]; | 171 | tmp = ((unsigned long int *)child->thread.fpr) |
172 | [FPRINDEX(numReg)]; | ||
166 | } else { /* register within PT_REGS struct */ | 173 | } else { /* register within PT_REGS struct */ |
167 | tmp = ptrace_get_reg(child, numReg); | 174 | tmp = ptrace_get_reg(child, numReg); |
168 | } | 175 | } |
@@ -217,7 +224,8 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
217 | * to be an array of unsigned int (32 bits) - the | 224 | * to be an array of unsigned int (32 bits) - the |
218 | * index passed in is based on this assumption. | 225 | * index passed in is based on this assumption. |
219 | */ | 226 | */ |
220 | ((unsigned int *)child->thread.fpr)[index - PT_FPR0] = data; | 227 | ((unsigned int *)child->thread.fpr) |
228 | [FPRINDEX(index)] = data; | ||
221 | ret = 0; | 229 | ret = 0; |
222 | } | 230 | } |
223 | break; | 231 | break; |
diff --git a/arch/powerpc/kernel/rtas-proc.c b/arch/powerpc/kernel/rtas-proc.c index f9c6abc84a94..1be9fe38bcb5 100644 --- a/arch/powerpc/kernel/rtas-proc.c +++ b/arch/powerpc/kernel/rtas-proc.c | |||
@@ -160,7 +160,7 @@ static int sensors_open(struct inode *inode, struct file *file) | |||
160 | return single_open(file, ppc_rtas_sensors_show, NULL); | 160 | return single_open(file, ppc_rtas_sensors_show, NULL); |
161 | } | 161 | } |
162 | 162 | ||
163 | const struct file_operations ppc_rtas_sensors_operations = { | 163 | static const struct file_operations ppc_rtas_sensors_operations = { |
164 | .open = sensors_open, | 164 | .open = sensors_open, |
165 | .read = seq_read, | 165 | .read = seq_read, |
166 | .llseek = seq_lseek, | 166 | .llseek = seq_lseek, |
@@ -172,7 +172,7 @@ static int poweron_open(struct inode *inode, struct file *file) | |||
172 | return single_open(file, ppc_rtas_poweron_show, NULL); | 172 | return single_open(file, ppc_rtas_poweron_show, NULL); |
173 | } | 173 | } |
174 | 174 | ||
175 | const struct file_operations ppc_rtas_poweron_operations = { | 175 | static const struct file_operations ppc_rtas_poweron_operations = { |
176 | .open = poweron_open, | 176 | .open = poweron_open, |
177 | .read = seq_read, | 177 | .read = seq_read, |
178 | .llseek = seq_lseek, | 178 | .llseek = seq_lseek, |
@@ -185,7 +185,7 @@ static int progress_open(struct inode *inode, struct file *file) | |||
185 | return single_open(file, ppc_rtas_progress_show, NULL); | 185 | return single_open(file, ppc_rtas_progress_show, NULL); |
186 | } | 186 | } |
187 | 187 | ||
188 | const struct file_operations ppc_rtas_progress_operations = { | 188 | static const struct file_operations ppc_rtas_progress_operations = { |
189 | .open = progress_open, | 189 | .open = progress_open, |
190 | .read = seq_read, | 190 | .read = seq_read, |
191 | .llseek = seq_lseek, | 191 | .llseek = seq_lseek, |
@@ -198,7 +198,7 @@ static int clock_open(struct inode *inode, struct file *file) | |||
198 | return single_open(file, ppc_rtas_clock_show, NULL); | 198 | return single_open(file, ppc_rtas_clock_show, NULL); |
199 | } | 199 | } |
200 | 200 | ||
201 | const struct file_operations ppc_rtas_clock_operations = { | 201 | static const struct file_operations ppc_rtas_clock_operations = { |
202 | .open = clock_open, | 202 | .open = clock_open, |
203 | .read = seq_read, | 203 | .read = seq_read, |
204 | .llseek = seq_lseek, | 204 | .llseek = seq_lseek, |
@@ -211,7 +211,7 @@ static int tone_freq_open(struct inode *inode, struct file *file) | |||
211 | return single_open(file, ppc_rtas_tone_freq_show, NULL); | 211 | return single_open(file, ppc_rtas_tone_freq_show, NULL); |
212 | } | 212 | } |
213 | 213 | ||
214 | const struct file_operations ppc_rtas_tone_freq_operations = { | 214 | static const struct file_operations ppc_rtas_tone_freq_operations = { |
215 | .open = tone_freq_open, | 215 | .open = tone_freq_open, |
216 | .read = seq_read, | 216 | .read = seq_read, |
217 | .llseek = seq_lseek, | 217 | .llseek = seq_lseek, |
@@ -224,7 +224,7 @@ static int tone_volume_open(struct inode *inode, struct file *file) | |||
224 | return single_open(file, ppc_rtas_tone_volume_show, NULL); | 224 | return single_open(file, ppc_rtas_tone_volume_show, NULL); |
225 | } | 225 | } |
226 | 226 | ||
227 | const struct file_operations ppc_rtas_tone_volume_operations = { | 227 | static const struct file_operations ppc_rtas_tone_volume_operations = { |
228 | .open = tone_volume_open, | 228 | .open = tone_volume_open, |
229 | .read = seq_read, | 229 | .read = seq_read, |
230 | .llseek = seq_lseek, | 230 | .llseek = seq_lseek, |
@@ -237,7 +237,7 @@ static int rmo_buf_open(struct inode *inode, struct file *file) | |||
237 | return single_open(file, ppc_rtas_rmo_buf_show, NULL); | 237 | return single_open(file, ppc_rtas_rmo_buf_show, NULL); |
238 | } | 238 | } |
239 | 239 | ||
240 | const struct file_operations ppc_rtas_rmo_buf_ops = { | 240 | static const struct file_operations ppc_rtas_rmo_buf_ops = { |
241 | .open = rmo_buf_open, | 241 | .open = rmo_buf_open, |
242 | .read = seq_read, | 242 | .read = seq_read, |
243 | .llseek = seq_lseek, | 243 | .llseek = seq_lseek, |
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 34843c318419..c680f1bbd387 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c | |||
@@ -340,8 +340,8 @@ int rtas_get_error_log_max(void) | |||
340 | EXPORT_SYMBOL(rtas_get_error_log_max); | 340 | EXPORT_SYMBOL(rtas_get_error_log_max); |
341 | 341 | ||
342 | 342 | ||
343 | char rtas_err_buf[RTAS_ERROR_LOG_MAX]; | 343 | static char rtas_err_buf[RTAS_ERROR_LOG_MAX]; |
344 | int rtas_last_error_token; | 344 | static int rtas_last_error_token; |
345 | 345 | ||
346 | /** Return a copy of the detailed error text associated with the | 346 | /** Return a copy of the detailed error text associated with the |
347 | * most recent failed call to rtas. Because the error text | 347 | * most recent failed call to rtas. Because the error text |
@@ -484,7 +484,7 @@ unsigned int rtas_busy_delay(int status) | |||
484 | } | 484 | } |
485 | EXPORT_SYMBOL(rtas_busy_delay); | 485 | EXPORT_SYMBOL(rtas_busy_delay); |
486 | 486 | ||
487 | int rtas_error_rc(int rtas_rc) | 487 | static int rtas_error_rc(int rtas_rc) |
488 | { | 488 | { |
489 | int rc; | 489 | int rc; |
490 | 490 | ||
@@ -747,7 +747,7 @@ static int rtas_ibm_suspend_me(struct rtas_args *args) | |||
747 | /* Call function on all CPUs. One of us will make the | 747 | /* Call function on all CPUs. One of us will make the |
748 | * rtas call | 748 | * rtas call |
749 | */ | 749 | */ |
750 | if (on_each_cpu(rtas_percpu_suspend_me, &data, 1, 0)) | 750 | if (on_each_cpu(rtas_percpu_suspend_me, &data, 0)) |
751 | data.error = -EINVAL; | 751 | data.error = -EINVAL; |
752 | 752 | ||
753 | wait_for_completion(&done); | 753 | wait_for_completion(&done); |
diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c index 0a5e22b22729..09ded5c424a9 100644 --- a/arch/powerpc/kernel/rtas_flash.c +++ b/arch/powerpc/kernel/rtas_flash.c | |||
@@ -731,7 +731,7 @@ static const struct file_operations validate_flash_operations = { | |||
731 | .release = validate_flash_release, | 731 | .release = validate_flash_release, |
732 | }; | 732 | }; |
733 | 733 | ||
734 | int __init rtas_flash_init(void) | 734 | static int __init rtas_flash_init(void) |
735 | { | 735 | { |
736 | int rc; | 736 | int rc; |
737 | 737 | ||
@@ -817,7 +817,7 @@ cleanup: | |||
817 | return rc; | 817 | return rc; |
818 | } | 818 | } |
819 | 819 | ||
820 | void __exit rtas_flash_cleanup(void) | 820 | static void __exit rtas_flash_cleanup(void) |
821 | { | 821 | { |
822 | rtas_flash_term_hook = NULL; | 822 | rtas_flash_term_hook = NULL; |
823 | 823 | ||
diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c index 3ab88a9dc70d..589a2797eac2 100644 --- a/arch/powerpc/kernel/rtas_pci.c +++ b/arch/powerpc/kernel/rtas_pci.c | |||
@@ -155,12 +155,12 @@ static int rtas_pci_write_config(struct pci_bus *bus, | |||
155 | return PCIBIOS_DEVICE_NOT_FOUND; | 155 | return PCIBIOS_DEVICE_NOT_FOUND; |
156 | } | 156 | } |
157 | 157 | ||
158 | struct pci_ops rtas_pci_ops = { | 158 | static struct pci_ops rtas_pci_ops = { |
159 | .read = rtas_pci_read_config, | 159 | .read = rtas_pci_read_config, |
160 | .write = rtas_pci_write_config, | 160 | .write = rtas_pci_write_config, |
161 | }; | 161 | }; |
162 | 162 | ||
163 | int is_python(struct device_node *dev) | 163 | static int is_python(struct device_node *dev) |
164 | { | 164 | { |
165 | const char *model = of_get_property(dev, "model", NULL); | 165 | const char *model = of_get_property(dev, "model", NULL); |
166 | 166 | ||
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index db540eab09f4..61a3f4132087 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c | |||
@@ -500,6 +500,7 @@ void __init smp_setup_cpu_sibling_map(void) | |||
500 | } | 500 | } |
501 | #endif /* CONFIG_SMP */ | 501 | #endif /* CONFIG_SMP */ |
502 | 502 | ||
503 | #ifdef CONFIG_PCSPKR_PLATFORM | ||
503 | static __init int add_pcspkr(void) | 504 | static __init int add_pcspkr(void) |
504 | { | 505 | { |
505 | struct device_node *np; | 506 | struct device_node *np; |
@@ -522,6 +523,7 @@ static __init int add_pcspkr(void) | |||
522 | return ret; | 523 | return ret; |
523 | } | 524 | } |
524 | device_initcall(add_pcspkr); | 525 | device_initcall(add_pcspkr); |
526 | #endif /* CONFIG_PCSPKR_PLATFORM */ | ||
525 | 527 | ||
526 | void probe_machine(void) | 528 | void probe_machine(void) |
527 | { | 529 | { |
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 5112a4aa801d..4efebe88e64a 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c | |||
@@ -81,7 +81,7 @@ int ucache_bsize; | |||
81 | * from the address that it was linked at, so we must use RELOC/PTRRELOC | 81 | * from the address that it was linked at, so we must use RELOC/PTRRELOC |
82 | * to access static data (including strings). -- paulus | 82 | * to access static data (including strings). -- paulus |
83 | */ | 83 | */ |
84 | unsigned long __init early_init(unsigned long dt_ptr) | 84 | notrace unsigned long __init early_init(unsigned long dt_ptr) |
85 | { | 85 | { |
86 | unsigned long offset = reloc_offset(); | 86 | unsigned long offset = reloc_offset(); |
87 | struct cpu_spec *spec; | 87 | struct cpu_spec *spec; |
@@ -101,6 +101,10 @@ unsigned long __init early_init(unsigned long dt_ptr) | |||
101 | PTRRELOC(&__start___ftr_fixup), | 101 | PTRRELOC(&__start___ftr_fixup), |
102 | PTRRELOC(&__stop___ftr_fixup)); | 102 | PTRRELOC(&__stop___ftr_fixup)); |
103 | 103 | ||
104 | do_lwsync_fixups(spec->cpu_features, | ||
105 | PTRRELOC(&__start___lwsync_fixup), | ||
106 | PTRRELOC(&__stop___lwsync_fixup)); | ||
107 | |||
104 | return KERNELBASE + offset; | 108 | return KERNELBASE + offset; |
105 | } | 109 | } |
106 | 110 | ||
@@ -111,7 +115,7 @@ unsigned long __init early_init(unsigned long dt_ptr) | |||
111 | * This is called very early on the boot process, after a minimal | 115 | * This is called very early on the boot process, after a minimal |
112 | * MMU environment has been set up but before MMU_init is called. | 116 | * MMU environment has been set up but before MMU_init is called. |
113 | */ | 117 | */ |
114 | void __init machine_init(unsigned long dt_ptr, unsigned long phys) | 118 | notrace void __init machine_init(unsigned long dt_ptr, unsigned long phys) |
115 | { | 119 | { |
116 | /* Enable early debugging if any specified (see udbg.h) */ | 120 | /* Enable early debugging if any specified (see udbg.h) */ |
117 | udbg_early_init(); | 121 | udbg_early_init(); |
@@ -127,13 +131,18 @@ void __init machine_init(unsigned long dt_ptr, unsigned long phys) | |||
127 | ppc_md.power_save = ppc6xx_idle; | 131 | ppc_md.power_save = ppc6xx_idle; |
128 | #endif | 132 | #endif |
129 | 133 | ||
134 | #ifdef CONFIG_E500 | ||
135 | if (cpu_has_feature(CPU_FTR_CAN_DOZE) || | ||
136 | cpu_has_feature(CPU_FTR_CAN_NAP)) | ||
137 | ppc_md.power_save = e500_idle; | ||
138 | #endif | ||
130 | if (ppc_md.progress) | 139 | if (ppc_md.progress) |
131 | ppc_md.progress("id mach(): done", 0x200); | 140 | ppc_md.progress("id mach(): done", 0x200); |
132 | } | 141 | } |
133 | 142 | ||
134 | #ifdef CONFIG_BOOKE_WDT | 143 | #ifdef CONFIG_BOOKE_WDT |
135 | /* Checks wdt=x and wdt_period=xx command-line option */ | 144 | /* Checks wdt=x and wdt_period=xx command-line option */ |
136 | int __init early_parse_wdt(char *p) | 145 | notrace int __init early_parse_wdt(char *p) |
137 | { | 146 | { |
138 | if (p && strncmp(p, "0", 1) != 0) | 147 | if (p && strncmp(p, "0", 1) != 0) |
139 | booke_wdt_enabled = 1; | 148 | booke_wdt_enabled = 1; |
@@ -248,6 +257,28 @@ static void __init irqstack_early_init(void) | |||
248 | #define irqstack_early_init() | 257 | #define irqstack_early_init() |
249 | #endif | 258 | #endif |
250 | 259 | ||
260 | #if defined(CONFIG_BOOKE) || defined(CONFIG_40x) | ||
261 | static void __init exc_lvl_early_init(void) | ||
262 | { | ||
263 | unsigned int i; | ||
264 | |||
265 | /* interrupt stacks must be in lowmem, we get that for free on ppc32 | ||
266 | * as the lmb is limited to lowmem by LMB_REAL_LIMIT */ | ||
267 | for_each_possible_cpu(i) { | ||
268 | critirq_ctx[i] = (struct thread_info *) | ||
269 | __va(lmb_alloc(THREAD_SIZE, THREAD_SIZE)); | ||
270 | #ifdef CONFIG_BOOKE | ||
271 | dbgirq_ctx[i] = (struct thread_info *) | ||
272 | __va(lmb_alloc(THREAD_SIZE, THREAD_SIZE)); | ||
273 | mcheckirq_ctx[i] = (struct thread_info *) | ||
274 | __va(lmb_alloc(THREAD_SIZE, THREAD_SIZE)); | ||
275 | #endif | ||
276 | } | ||
277 | } | ||
278 | #else | ||
279 | #define exc_lvl_early_init() | ||
280 | #endif | ||
281 | |||
251 | /* Warning, IO base is not yet inited */ | 282 | /* Warning, IO base is not yet inited */ |
252 | void __init setup_arch(char **cmdline_p) | 283 | void __init setup_arch(char **cmdline_p) |
253 | { | 284 | { |
@@ -305,6 +336,8 @@ void __init setup_arch(char **cmdline_p) | |||
305 | init_mm.end_data = (unsigned long) _edata; | 336 | init_mm.end_data = (unsigned long) _edata; |
306 | init_mm.brk = klimit; | 337 | init_mm.brk = klimit; |
307 | 338 | ||
339 | exc_lvl_early_init(); | ||
340 | |||
308 | irqstack_early_init(); | 341 | irqstack_early_init(); |
309 | 342 | ||
310 | /* set up the bootmem stuff with available memory */ | 343 | /* set up the bootmem stuff with available memory */ |
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 098fd96a394a..04d8de9f0fc6 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c | |||
@@ -363,6 +363,8 @@ void __init setup_system(void) | |||
363 | &__start___ftr_fixup, &__stop___ftr_fixup); | 363 | &__start___ftr_fixup, &__stop___ftr_fixup); |
364 | do_feature_fixups(powerpc_firmware_features, | 364 | do_feature_fixups(powerpc_firmware_features, |
365 | &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup); | 365 | &__start___fw_ftr_fixup, &__stop___fw_ftr_fixup); |
366 | do_lwsync_fixups(cur_cpu_spec->cpu_features, | ||
367 | &__start___lwsync_fixup, &__stop___lwsync_fixup); | ||
366 | 368 | ||
367 | /* | 369 | /* |
368 | * Unflatten the device-tree passed by prom_init or kexec | 370 | * Unflatten the device-tree passed by prom_init or kexec |
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index a65a44fbe523..ad55488939c3 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c | |||
@@ -120,7 +120,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) | |||
120 | int ret; | 120 | int ret; |
121 | int is32 = is_32bit_task(); | 121 | int is32 = is_32bit_task(); |
122 | 122 | ||
123 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 123 | if (current_thread_info()->local_flags & _TLF_RESTORE_SIGMASK) |
124 | oldset = ¤t->saved_sigmask; | 124 | oldset = ¤t->saved_sigmask; |
125 | else if (!oldset) | 125 | else if (!oldset) |
126 | oldset = ¤t->blocked; | 126 | oldset = ¤t->blocked; |
@@ -131,9 +131,10 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) | |||
131 | check_syscall_restart(regs, &ka, signr > 0); | 131 | check_syscall_restart(regs, &ka, signr > 0); |
132 | 132 | ||
133 | if (signr <= 0) { | 133 | if (signr <= 0) { |
134 | struct thread_info *ti = current_thread_info(); | ||
134 | /* No signal to deliver -- put the saved sigmask back */ | 135 | /* No signal to deliver -- put the saved sigmask back */ |
135 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | 136 | if (ti->local_flags & _TLF_RESTORE_SIGMASK) { |
136 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 137 | ti->local_flags &= ~_TLF_RESTORE_SIGMASK; |
137 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | 138 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); |
138 | } | 139 | } |
139 | return 0; /* no signals delivered */ | 140 | return 0; /* no signals delivered */ |
@@ -169,10 +170,9 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs) | |||
169 | 170 | ||
170 | /* | 171 | /* |
171 | * A signal was successfully delivered; the saved sigmask is in | 172 | * A signal was successfully delivered; the saved sigmask is in |
172 | * its frame, and we can clear the TIF_RESTORE_SIGMASK flag. | 173 | * its frame, and we can clear the TLF_RESTORE_SIGMASK flag. |
173 | */ | 174 | */ |
174 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 175 | current_thread_info()->local_flags &= ~_TLF_RESTORE_SIGMASK; |
175 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
176 | } | 176 | } |
177 | 177 | ||
178 | return ret; | 178 | return ret; |
diff --git a/arch/powerpc/kernel/signal.h b/arch/powerpc/kernel/signal.h index 77efb3d5465a..28f4b9f5fe5e 100644 --- a/arch/powerpc/kernel/signal.h +++ b/arch/powerpc/kernel/signal.h | |||
@@ -24,6 +24,16 @@ extern int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, | |||
24 | siginfo_t *info, sigset_t *oldset, | 24 | siginfo_t *info, sigset_t *oldset, |
25 | struct pt_regs *regs); | 25 | struct pt_regs *regs); |
26 | 26 | ||
27 | extern unsigned long copy_fpr_to_user(void __user *to, | ||
28 | struct task_struct *task); | ||
29 | extern unsigned long copy_fpr_from_user(struct task_struct *task, | ||
30 | void __user *from); | ||
31 | #ifdef CONFIG_VSX | ||
32 | extern unsigned long copy_vsx_to_user(void __user *to, | ||
33 | struct task_struct *task); | ||
34 | extern unsigned long copy_vsx_from_user(struct task_struct *task, | ||
35 | void __user *from); | ||
36 | #endif | ||
27 | 37 | ||
28 | #ifdef CONFIG_PPC64 | 38 | #ifdef CONFIG_PPC64 |
29 | 39 | ||
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index ad6943468ee9..3e80aa32b8b0 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c | |||
@@ -68,6 +68,13 @@ | |||
68 | #define ucontext ucontext32 | 68 | #define ucontext ucontext32 |
69 | 69 | ||
70 | /* | 70 | /* |
71 | * Userspace code may pass a ucontext which doesn't include VSX added | ||
72 | * at the end. We need to check for this case. | ||
73 | */ | ||
74 | #define UCONTEXTSIZEWITHOUTVSX \ | ||
75 | (sizeof(struct ucontext) - sizeof(elf_vsrreghalf_t32)) | ||
76 | |||
77 | /* | ||
71 | * Returning 0 means we return to userspace via | 78 | * Returning 0 means we return to userspace via |
72 | * ret_from_except and thus restore all user | 79 | * ret_from_except and thus restore all user |
73 | * registers from *regs. This is what we need | 80 | * registers from *regs. This is what we need |
@@ -243,7 +250,7 @@ long sys_sigsuspend(old_sigset_t mask) | |||
243 | 250 | ||
244 | current->state = TASK_INTERRUPTIBLE; | 251 | current->state = TASK_INTERRUPTIBLE; |
245 | schedule(); | 252 | schedule(); |
246 | set_thread_flag(TIF_RESTORE_SIGMASK); | 253 | set_restore_sigmask(); |
247 | return -ERESTARTNOHAND; | 254 | return -ERESTARTNOHAND; |
248 | } | 255 | } |
249 | 256 | ||
@@ -328,6 +335,75 @@ struct rt_sigframe { | |||
328 | int abigap[56]; | 335 | int abigap[56]; |
329 | }; | 336 | }; |
330 | 337 | ||
338 | #ifdef CONFIG_VSX | ||
339 | unsigned long copy_fpr_to_user(void __user *to, | ||
340 | struct task_struct *task) | ||
341 | { | ||
342 | double buf[ELF_NFPREG]; | ||
343 | int i; | ||
344 | |||
345 | /* save FPR copy to local buffer then write to the thread_struct */ | ||
346 | for (i = 0; i < (ELF_NFPREG - 1) ; i++) | ||
347 | buf[i] = task->thread.TS_FPR(i); | ||
348 | memcpy(&buf[i], &task->thread.fpscr, sizeof(double)); | ||
349 | return __copy_to_user(to, buf, ELF_NFPREG * sizeof(double)); | ||
350 | } | ||
351 | |||
352 | unsigned long copy_fpr_from_user(struct task_struct *task, | ||
353 | void __user *from) | ||
354 | { | ||
355 | double buf[ELF_NFPREG]; | ||
356 | int i; | ||
357 | |||
358 | if (__copy_from_user(buf, from, ELF_NFPREG * sizeof(double))) | ||
359 | return 1; | ||
360 | for (i = 0; i < (ELF_NFPREG - 1) ; i++) | ||
361 | task->thread.TS_FPR(i) = buf[i]; | ||
362 | memcpy(&task->thread.fpscr, &buf[i], sizeof(double)); | ||
363 | |||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | unsigned long copy_vsx_to_user(void __user *to, | ||
368 | struct task_struct *task) | ||
369 | { | ||
370 | double buf[ELF_NVSRHALFREG]; | ||
371 | int i; | ||
372 | |||
373 | /* save FPR copy to local buffer then write to the thread_struct */ | ||
374 | for (i = 0; i < ELF_NVSRHALFREG; i++) | ||
375 | buf[i] = task->thread.fpr[i][TS_VSRLOWOFFSET]; | ||
376 | return __copy_to_user(to, buf, ELF_NVSRHALFREG * sizeof(double)); | ||
377 | } | ||
378 | |||
379 | unsigned long copy_vsx_from_user(struct task_struct *task, | ||
380 | void __user *from) | ||
381 | { | ||
382 | double buf[ELF_NVSRHALFREG]; | ||
383 | int i; | ||
384 | |||
385 | if (__copy_from_user(buf, from, ELF_NVSRHALFREG * sizeof(double))) | ||
386 | return 1; | ||
387 | for (i = 0; i < ELF_NVSRHALFREG ; i++) | ||
388 | task->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i]; | ||
389 | return 0; | ||
390 | } | ||
391 | #else | ||
392 | inline unsigned long copy_fpr_to_user(void __user *to, | ||
393 | struct task_struct *task) | ||
394 | { | ||
395 | return __copy_to_user(to, task->thread.fpr, | ||
396 | ELF_NFPREG * sizeof(double)); | ||
397 | } | ||
398 | |||
399 | inline unsigned long copy_fpr_from_user(struct task_struct *task, | ||
400 | void __user *from) | ||
401 | { | ||
402 | return __copy_from_user(task->thread.fpr, from, | ||
403 | ELF_NFPREG * sizeof(double)); | ||
404 | } | ||
405 | #endif | ||
406 | |||
331 | /* | 407 | /* |
332 | * Save the current user registers on the user stack. | 408 | * Save the current user registers on the user stack. |
333 | * We only save the altivec/spe registers if the process has used | 409 | * We only save the altivec/spe registers if the process has used |
@@ -336,13 +412,13 @@ struct rt_sigframe { | |||
336 | static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, | 412 | static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, |
337 | int sigret) | 413 | int sigret) |
338 | { | 414 | { |
415 | unsigned long msr = regs->msr; | ||
416 | |||
339 | /* Make sure floating point registers are stored in regs */ | 417 | /* Make sure floating point registers are stored in regs */ |
340 | flush_fp_to_thread(current); | 418 | flush_fp_to_thread(current); |
341 | 419 | ||
342 | /* save general and floating-point registers */ | 420 | /* save general registers */ |
343 | if (save_general_regs(regs, frame) || | 421 | if (save_general_regs(regs, frame)) |
344 | __copy_to_user(&frame->mc_fregs, current->thread.fpr, | ||
345 | ELF_NFPREG * sizeof(double))) | ||
346 | return 1; | 422 | return 1; |
347 | 423 | ||
348 | #ifdef CONFIG_ALTIVEC | 424 | #ifdef CONFIG_ALTIVEC |
@@ -354,8 +430,7 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, | |||
354 | return 1; | 430 | return 1; |
355 | /* set MSR_VEC in the saved MSR value to indicate that | 431 | /* set MSR_VEC in the saved MSR value to indicate that |
356 | frame->mc_vregs contains valid data */ | 432 | frame->mc_vregs contains valid data */ |
357 | if (__put_user(regs->msr | MSR_VEC, &frame->mc_gregs[PT_MSR])) | 433 | msr |= MSR_VEC; |
358 | return 1; | ||
359 | } | 434 | } |
360 | /* else assert((regs->msr & MSR_VEC) == 0) */ | 435 | /* else assert((regs->msr & MSR_VEC) == 0) */ |
361 | 436 | ||
@@ -367,7 +442,22 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, | |||
367 | if (__put_user(current->thread.vrsave, (u32 __user *)&frame->mc_vregs[32])) | 442 | if (__put_user(current->thread.vrsave, (u32 __user *)&frame->mc_vregs[32])) |
368 | return 1; | 443 | return 1; |
369 | #endif /* CONFIG_ALTIVEC */ | 444 | #endif /* CONFIG_ALTIVEC */ |
370 | 445 | if (copy_fpr_to_user(&frame->mc_fregs, current)) | |
446 | return 1; | ||
447 | #ifdef CONFIG_VSX | ||
448 | /* | ||
449 | * Copy VSR 0-31 upper half from thread_struct to local | ||
450 | * buffer, then write that to userspace. Also set MSR_VSX in | ||
451 | * the saved MSR value to indicate that frame->mc_vregs | ||
452 | * contains valid data | ||
453 | */ | ||
454 | if (current->thread.used_vsr) { | ||
455 | __giveup_vsx(current); | ||
456 | if (copy_vsx_to_user(&frame->mc_vsregs, current)) | ||
457 | return 1; | ||
458 | msr |= MSR_VSX; | ||
459 | } | ||
460 | #endif /* CONFIG_VSX */ | ||
371 | #ifdef CONFIG_SPE | 461 | #ifdef CONFIG_SPE |
372 | /* save spe registers */ | 462 | /* save spe registers */ |
373 | if (current->thread.used_spe) { | 463 | if (current->thread.used_spe) { |
@@ -377,8 +467,7 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, | |||
377 | return 1; | 467 | return 1; |
378 | /* set MSR_SPE in the saved MSR value to indicate that | 468 | /* set MSR_SPE in the saved MSR value to indicate that |
379 | frame->mc_vregs contains valid data */ | 469 | frame->mc_vregs contains valid data */ |
380 | if (__put_user(regs->msr | MSR_SPE, &frame->mc_gregs[PT_MSR])) | 470 | msr |= MSR_SPE; |
381 | return 1; | ||
382 | } | 471 | } |
383 | /* else assert((regs->msr & MSR_SPE) == 0) */ | 472 | /* else assert((regs->msr & MSR_SPE) == 0) */ |
384 | 473 | ||
@@ -387,6 +476,8 @@ static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, | |||
387 | return 1; | 476 | return 1; |
388 | #endif /* CONFIG_SPE */ | 477 | #endif /* CONFIG_SPE */ |
389 | 478 | ||
479 | if (__put_user(msr, &frame->mc_gregs[PT_MSR])) | ||
480 | return 1; | ||
390 | if (sigret) { | 481 | if (sigret) { |
391 | /* Set up the sigreturn trampoline: li r0,sigret; sc */ | 482 | /* Set up the sigreturn trampoline: li r0,sigret; sc */ |
392 | if (__put_user(0x38000000UL + sigret, &frame->tramp[0]) | 483 | if (__put_user(0x38000000UL + sigret, &frame->tramp[0]) |
@@ -409,6 +500,9 @@ static long restore_user_regs(struct pt_regs *regs, | |||
409 | long err; | 500 | long err; |
410 | unsigned int save_r2 = 0; | 501 | unsigned int save_r2 = 0; |
411 | unsigned long msr; | 502 | unsigned long msr; |
503 | #ifdef CONFIG_VSX | ||
504 | int i; | ||
505 | #endif | ||
412 | 506 | ||
413 | /* | 507 | /* |
414 | * restore general registers but not including MSR or SOFTE. Also | 508 | * restore general registers but not including MSR or SOFTE. Also |
@@ -436,16 +530,11 @@ static long restore_user_regs(struct pt_regs *regs, | |||
436 | */ | 530 | */ |
437 | discard_lazy_cpu_state(); | 531 | discard_lazy_cpu_state(); |
438 | 532 | ||
439 | /* force the process to reload the FP registers from | ||
440 | current->thread when it next does FP instructions */ | ||
441 | regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1); | ||
442 | if (__copy_from_user(current->thread.fpr, &sr->mc_fregs, | ||
443 | sizeof(sr->mc_fregs))) | ||
444 | return 1; | ||
445 | |||
446 | #ifdef CONFIG_ALTIVEC | 533 | #ifdef CONFIG_ALTIVEC |
447 | /* force the process to reload the altivec registers from | 534 | /* |
448 | current->thread when it next does altivec instructions */ | 535 | * Force the process to reload the altivec registers from |
536 | * current->thread when it next does altivec instructions | ||
537 | */ | ||
449 | regs->msr &= ~MSR_VEC; | 538 | regs->msr &= ~MSR_VEC; |
450 | if (msr & MSR_VEC) { | 539 | if (msr & MSR_VEC) { |
451 | /* restore altivec registers from the stack */ | 540 | /* restore altivec registers from the stack */ |
@@ -459,6 +548,31 @@ static long restore_user_regs(struct pt_regs *regs, | |||
459 | if (__get_user(current->thread.vrsave, (u32 __user *)&sr->mc_vregs[32])) | 548 | if (__get_user(current->thread.vrsave, (u32 __user *)&sr->mc_vregs[32])) |
460 | return 1; | 549 | return 1; |
461 | #endif /* CONFIG_ALTIVEC */ | 550 | #endif /* CONFIG_ALTIVEC */ |
551 | if (copy_fpr_from_user(current, &sr->mc_fregs)) | ||
552 | return 1; | ||
553 | |||
554 | #ifdef CONFIG_VSX | ||
555 | /* | ||
556 | * Force the process to reload the VSX registers from | ||
557 | * current->thread when it next does VSX instruction. | ||
558 | */ | ||
559 | regs->msr &= ~MSR_VSX; | ||
560 | if (msr & MSR_VSX) { | ||
561 | /* | ||
562 | * Restore altivec registers from the stack to a local | ||
563 | * buffer, then write this out to the thread_struct | ||
564 | */ | ||
565 | if (copy_vsx_from_user(current, &sr->mc_vsregs)) | ||
566 | return 1; | ||
567 | } else if (current->thread.used_vsr) | ||
568 | for (i = 0; i < 32 ; i++) | ||
569 | current->thread.fpr[i][TS_VSRLOWOFFSET] = 0; | ||
570 | #endif /* CONFIG_VSX */ | ||
571 | /* | ||
572 | * force the process to reload the FP registers from | ||
573 | * current->thread when it next does FP instructions | ||
574 | */ | ||
575 | regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1); | ||
462 | 576 | ||
463 | #ifdef CONFIG_SPE | 577 | #ifdef CONFIG_SPE |
464 | /* force the process to reload the spe registers from | 578 | /* force the process to reload the spe registers from |
@@ -823,12 +937,42 @@ long sys_swapcontext(struct ucontext __user *old_ctx, | |||
823 | { | 937 | { |
824 | unsigned char tmp; | 938 | unsigned char tmp; |
825 | 939 | ||
940 | #ifdef CONFIG_PPC64 | ||
941 | unsigned long new_msr = 0; | ||
942 | |||
943 | if (new_ctx && | ||
944 | __get_user(new_msr, &new_ctx->uc_mcontext.mc_gregs[PT_MSR])) | ||
945 | return -EFAULT; | ||
946 | /* | ||
947 | * Check that the context is not smaller than the original | ||
948 | * size (with VMX but without VSX) | ||
949 | */ | ||
950 | if (ctx_size < UCONTEXTSIZEWITHOUTVSX) | ||
951 | return -EINVAL; | ||
952 | /* | ||
953 | * If the new context state sets the MSR VSX bits but | ||
954 | * it doesn't provide VSX state. | ||
955 | */ | ||
956 | if ((ctx_size < sizeof(struct ucontext)) && | ||
957 | (new_msr & MSR_VSX)) | ||
958 | return -EINVAL; | ||
959 | #ifdef CONFIG_VSX | ||
960 | /* | ||
961 | * If userspace doesn't provide enough room for VSX data, | ||
962 | * but current thread has used VSX, we don't have anywhere | ||
963 | * to store the full context back into. | ||
964 | */ | ||
965 | if ((ctx_size < sizeof(struct ucontext)) && | ||
966 | (current->thread.used_vsr && old_ctx)) | ||
967 | return -EINVAL; | ||
968 | #endif | ||
969 | #else | ||
826 | /* Context size is for future use. Right now, we only make sure | 970 | /* Context size is for future use. Right now, we only make sure |
827 | * we are passed something we understand | 971 | * we are passed something we understand |
828 | */ | 972 | */ |
829 | if (ctx_size < sizeof(struct ucontext)) | 973 | if (ctx_size < sizeof(struct ucontext)) |
830 | return -EINVAL; | 974 | return -EINVAL; |
831 | 975 | #endif | |
832 | if (old_ctx != NULL) { | 976 | if (old_ctx != NULL) { |
833 | struct mcontext __user *mctx; | 977 | struct mcontext __user *mctx; |
834 | 978 | ||
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index faeb8f207ea4..65ad925c3a8f 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c | |||
@@ -87,6 +87,7 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, | |||
87 | #ifdef CONFIG_ALTIVEC | 87 | #ifdef CONFIG_ALTIVEC |
88 | elf_vrreg_t __user *v_regs = (elf_vrreg_t __user *)(((unsigned long)sc->vmx_reserve + 15) & ~0xful); | 88 | elf_vrreg_t __user *v_regs = (elf_vrreg_t __user *)(((unsigned long)sc->vmx_reserve + 15) & ~0xful); |
89 | #endif | 89 | #endif |
90 | unsigned long msr = regs->msr; | ||
90 | long err = 0; | 91 | long err = 0; |
91 | 92 | ||
92 | flush_fp_to_thread(current); | 93 | flush_fp_to_thread(current); |
@@ -102,7 +103,7 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, | |||
102 | /* set MSR_VEC in the MSR value in the frame to indicate that sc->v_reg) | 103 | /* set MSR_VEC in the MSR value in the frame to indicate that sc->v_reg) |
103 | * contains valid data. | 104 | * contains valid data. |
104 | */ | 105 | */ |
105 | regs->msr |= MSR_VEC; | 106 | msr |= MSR_VEC; |
106 | } | 107 | } |
107 | /* We always copy to/from vrsave, it's 0 if we don't have or don't | 108 | /* We always copy to/from vrsave, it's 0 if we don't have or don't |
108 | * use altivec. | 109 | * use altivec. |
@@ -111,10 +112,29 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, | |||
111 | #else /* CONFIG_ALTIVEC */ | 112 | #else /* CONFIG_ALTIVEC */ |
112 | err |= __put_user(0, &sc->v_regs); | 113 | err |= __put_user(0, &sc->v_regs); |
113 | #endif /* CONFIG_ALTIVEC */ | 114 | #endif /* CONFIG_ALTIVEC */ |
115 | flush_fp_to_thread(current); | ||
116 | /* copy fpr regs and fpscr */ | ||
117 | err |= copy_fpr_to_user(&sc->fp_regs, current); | ||
118 | #ifdef CONFIG_VSX | ||
119 | /* | ||
120 | * Copy VSX low doubleword to local buffer for formatting, | ||
121 | * then out to userspace. Update v_regs to point after the | ||
122 | * VMX data. | ||
123 | */ | ||
124 | if (current->thread.used_vsr) { | ||
125 | __giveup_vsx(current); | ||
126 | v_regs += ELF_NVRREG; | ||
127 | err |= copy_vsx_to_user(v_regs, current); | ||
128 | /* set MSR_VSX in the MSR value in the frame to | ||
129 | * indicate that sc->vs_reg) contains valid data. | ||
130 | */ | ||
131 | msr |= MSR_VSX; | ||
132 | } | ||
133 | #endif /* CONFIG_VSX */ | ||
114 | err |= __put_user(&sc->gp_regs, &sc->regs); | 134 | err |= __put_user(&sc->gp_regs, &sc->regs); |
115 | WARN_ON(!FULL_REGS(regs)); | 135 | WARN_ON(!FULL_REGS(regs)); |
116 | err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE); | 136 | err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE); |
117 | err |= __copy_to_user(&sc->fp_regs, ¤t->thread.fpr, FP_REGS_SIZE); | 137 | err |= __put_user(msr, &sc->gp_regs[PT_MSR]); |
118 | err |= __put_user(signr, &sc->signal); | 138 | err |= __put_user(signr, &sc->signal); |
119 | err |= __put_user(handler, &sc->handler); | 139 | err |= __put_user(handler, &sc->handler); |
120 | if (set != NULL) | 140 | if (set != NULL) |
@@ -135,29 +155,32 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig, | |||
135 | #endif | 155 | #endif |
136 | unsigned long err = 0; | 156 | unsigned long err = 0; |
137 | unsigned long save_r13 = 0; | 157 | unsigned long save_r13 = 0; |
138 | elf_greg_t *gregs = (elf_greg_t *)regs; | ||
139 | unsigned long msr; | 158 | unsigned long msr; |
159 | #ifdef CONFIG_VSX | ||
140 | int i; | 160 | int i; |
161 | #endif | ||
141 | 162 | ||
142 | /* If this is not a signal return, we preserve the TLS in r13 */ | 163 | /* If this is not a signal return, we preserve the TLS in r13 */ |
143 | if (!sig) | 164 | if (!sig) |
144 | save_r13 = regs->gpr[13]; | 165 | save_r13 = regs->gpr[13]; |
145 | 166 | ||
146 | /* copy everything before MSR */ | 167 | /* copy the GPRs */ |
147 | err |= __copy_from_user(regs, &sc->gp_regs, | 168 | err |= __copy_from_user(regs->gpr, sc->gp_regs, sizeof(regs->gpr)); |
148 | PT_MSR*sizeof(unsigned long)); | 169 | err |= __get_user(regs->nip, &sc->gp_regs[PT_NIP]); |
149 | |||
150 | /* get MSR separately, transfer the LE bit if doing signal return */ | 170 | /* get MSR separately, transfer the LE bit if doing signal return */ |
151 | err |= __get_user(msr, &sc->gp_regs[PT_MSR]); | 171 | err |= __get_user(msr, &sc->gp_regs[PT_MSR]); |
152 | if (sig) | 172 | if (sig) |
153 | regs->msr = (regs->msr & ~MSR_LE) | (msr & MSR_LE); | 173 | regs->msr = (regs->msr & ~MSR_LE) | (msr & MSR_LE); |
154 | 174 | err |= __get_user(regs->orig_gpr3, &sc->gp_regs[PT_ORIG_R3]); | |
175 | err |= __get_user(regs->ctr, &sc->gp_regs[PT_CTR]); | ||
176 | err |= __get_user(regs->link, &sc->gp_regs[PT_LNK]); | ||
177 | err |= __get_user(regs->xer, &sc->gp_regs[PT_XER]); | ||
178 | err |= __get_user(regs->ccr, &sc->gp_regs[PT_CCR]); | ||
155 | /* skip SOFTE */ | 179 | /* skip SOFTE */ |
156 | for (i = PT_MSR+1; i <= PT_RESULT; i++) { | 180 | err |= __get_user(regs->trap, &sc->gp_regs[PT_TRAP]); |
157 | if (i == PT_SOFTE) | 181 | err |= __get_user(regs->dar, &sc->gp_regs[PT_DAR]); |
158 | continue; | 182 | err |= __get_user(regs->dsisr, &sc->gp_regs[PT_DSISR]); |
159 | err |= __get_user(gregs[i], &sc->gp_regs[i]); | 183 | err |= __get_user(regs->result, &sc->gp_regs[PT_RESULT]); |
160 | } | ||
161 | 184 | ||
162 | if (!sig) | 185 | if (!sig) |
163 | regs->gpr[13] = save_r13; | 186 | regs->gpr[13] = save_r13; |
@@ -178,9 +201,7 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig, | |||
178 | * This has to be done before copying stuff into current->thread.fpr/vr | 201 | * This has to be done before copying stuff into current->thread.fpr/vr |
179 | * for the reasons explained in the previous comment. | 202 | * for the reasons explained in the previous comment. |
180 | */ | 203 | */ |
181 | regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1 | MSR_VEC); | 204 | regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1 | MSR_VEC | MSR_VSX); |
182 | |||
183 | err |= __copy_from_user(¤t->thread.fpr, &sc->fp_regs, FP_REGS_SIZE); | ||
184 | 205 | ||
185 | #ifdef CONFIG_ALTIVEC | 206 | #ifdef CONFIG_ALTIVEC |
186 | err |= __get_user(v_regs, &sc->v_regs); | 207 | err |= __get_user(v_regs, &sc->v_regs); |
@@ -200,7 +221,23 @@ static long restore_sigcontext(struct pt_regs *regs, sigset_t *set, int sig, | |||
200 | else | 221 | else |
201 | current->thread.vrsave = 0; | 222 | current->thread.vrsave = 0; |
202 | #endif /* CONFIG_ALTIVEC */ | 223 | #endif /* CONFIG_ALTIVEC */ |
224 | /* restore floating point */ | ||
225 | err |= copy_fpr_from_user(current, &sc->fp_regs); | ||
226 | #ifdef CONFIG_VSX | ||
227 | /* | ||
228 | * Get additional VSX data. Update v_regs to point after the | ||
229 | * VMX data. Copy VSX low doubleword from userspace to local | ||
230 | * buffer for formatting, then into the taskstruct. | ||
231 | */ | ||
232 | v_regs += ELF_NVRREG; | ||
233 | if ((msr & MSR_VSX) != 0) | ||
234 | err |= copy_vsx_from_user(current, v_regs); | ||
235 | else | ||
236 | for (i = 0; i < 32 ; i++) | ||
237 | current->thread.fpr[i][TS_VSRLOWOFFSET] = 0; | ||
203 | 238 | ||
239 | #else | ||
240 | #endif | ||
204 | return err; | 241 | return err; |
205 | } | 242 | } |
206 | 243 | ||
@@ -231,6 +268,13 @@ static long setup_trampoline(unsigned int syscall, unsigned int __user *tramp) | |||
231 | } | 268 | } |
232 | 269 | ||
233 | /* | 270 | /* |
271 | * Userspace code may pass a ucontext which doesn't include VSX added | ||
272 | * at the end. We need to check for this case. | ||
273 | */ | ||
274 | #define UCONTEXTSIZEWITHOUTVSX \ | ||
275 | (sizeof(struct ucontext) - 32*sizeof(long)) | ||
276 | |||
277 | /* | ||
234 | * Handle {get,set,swap}_context operations | 278 | * Handle {get,set,swap}_context operations |
235 | */ | 279 | */ |
236 | int sys_swapcontext(struct ucontext __user *old_ctx, | 280 | int sys_swapcontext(struct ucontext __user *old_ctx, |
@@ -239,13 +283,34 @@ int sys_swapcontext(struct ucontext __user *old_ctx, | |||
239 | { | 283 | { |
240 | unsigned char tmp; | 284 | unsigned char tmp; |
241 | sigset_t set; | 285 | sigset_t set; |
286 | unsigned long new_msr = 0; | ||
242 | 287 | ||
243 | /* Context size is for future use. Right now, we only make sure | 288 | if (new_ctx && |
244 | * we are passed something we understand | 289 | __get_user(new_msr, &new_ctx->uc_mcontext.gp_regs[PT_MSR])) |
290 | return -EFAULT; | ||
291 | /* | ||
292 | * Check that the context is not smaller than the original | ||
293 | * size (with VMX but without VSX) | ||
245 | */ | 294 | */ |
246 | if (ctx_size < sizeof(struct ucontext)) | 295 | if (ctx_size < UCONTEXTSIZEWITHOUTVSX) |
247 | return -EINVAL; | 296 | return -EINVAL; |
248 | 297 | /* | |
298 | * If the new context state sets the MSR VSX bits but | ||
299 | * it doesn't provide VSX state. | ||
300 | */ | ||
301 | if ((ctx_size < sizeof(struct ucontext)) && | ||
302 | (new_msr & MSR_VSX)) | ||
303 | return -EINVAL; | ||
304 | #ifdef CONFIG_VSX | ||
305 | /* | ||
306 | * If userspace doesn't provide enough room for VSX data, | ||
307 | * but current thread has used VSX, we don't have anywhere | ||
308 | * to store the full context back into. | ||
309 | */ | ||
310 | if ((ctx_size < sizeof(struct ucontext)) && | ||
311 | (current->thread.used_vsr && old_ctx)) | ||
312 | return -EINVAL; | ||
313 | #endif | ||
249 | if (old_ctx != NULL) { | 314 | if (old_ctx != NULL) { |
250 | if (!access_ok(VERIFY_WRITE, old_ctx, sizeof(*old_ctx)) | 315 | if (!access_ok(VERIFY_WRITE, old_ctx, sizeof(*old_ctx)) |
251 | || setup_sigcontext(&old_ctx->uc_mcontext, regs, 0, NULL, 0) | 316 | || setup_sigcontext(&old_ctx->uc_mcontext, regs, 0, NULL, 0) |
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 1457aa0a08f1..f5ae9fa222ea 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c | |||
@@ -72,12 +72,8 @@ struct smp_ops_t *smp_ops; | |||
72 | 72 | ||
73 | static volatile unsigned int cpu_callin_map[NR_CPUS]; | 73 | static volatile unsigned int cpu_callin_map[NR_CPUS]; |
74 | 74 | ||
75 | void smp_call_function_interrupt(void); | ||
76 | |||
77 | int smt_enabled_at_boot = 1; | 75 | int smt_enabled_at_boot = 1; |
78 | 76 | ||
79 | static int ipi_fail_ok; | ||
80 | |||
81 | static void (*crash_ipi_function_ptr)(struct pt_regs *) = NULL; | 77 | static void (*crash_ipi_function_ptr)(struct pt_regs *) = NULL; |
82 | 78 | ||
83 | #ifdef CONFIG_PPC64 | 79 | #ifdef CONFIG_PPC64 |
@@ -99,12 +95,15 @@ void smp_message_recv(int msg) | |||
99 | { | 95 | { |
100 | switch(msg) { | 96 | switch(msg) { |
101 | case PPC_MSG_CALL_FUNCTION: | 97 | case PPC_MSG_CALL_FUNCTION: |
102 | smp_call_function_interrupt(); | 98 | generic_smp_call_function_interrupt(); |
103 | break; | 99 | break; |
104 | case PPC_MSG_RESCHEDULE: | 100 | case PPC_MSG_RESCHEDULE: |
105 | /* XXX Do we have to do this? */ | 101 | /* XXX Do we have to do this? */ |
106 | set_need_resched(); | 102 | set_need_resched(); |
107 | break; | 103 | break; |
104 | case PPC_MSG_CALL_FUNC_SINGLE: | ||
105 | generic_smp_call_function_single_interrupt(); | ||
106 | break; | ||
108 | case PPC_MSG_DEBUGGER_BREAK: | 107 | case PPC_MSG_DEBUGGER_BREAK: |
109 | if (crash_ipi_function_ptr) { | 108 | if (crash_ipi_function_ptr) { |
110 | crash_ipi_function_ptr(get_irq_regs()); | 109 | crash_ipi_function_ptr(get_irq_regs()); |
@@ -128,6 +127,19 @@ void smp_send_reschedule(int cpu) | |||
128 | smp_ops->message_pass(cpu, PPC_MSG_RESCHEDULE); | 127 | smp_ops->message_pass(cpu, PPC_MSG_RESCHEDULE); |
129 | } | 128 | } |
130 | 129 | ||
130 | void arch_send_call_function_single_ipi(int cpu) | ||
131 | { | ||
132 | smp_ops->message_pass(cpu, PPC_MSG_CALL_FUNC_SINGLE); | ||
133 | } | ||
134 | |||
135 | void arch_send_call_function_ipi(cpumask_t mask) | ||
136 | { | ||
137 | unsigned int cpu; | ||
138 | |||
139 | for_each_cpu_mask(cpu, mask) | ||
140 | smp_ops->message_pass(cpu, PPC_MSG_CALL_FUNCTION); | ||
141 | } | ||
142 | |||
131 | #ifdef CONFIG_DEBUGGER | 143 | #ifdef CONFIG_DEBUGGER |
132 | void smp_send_debugger_break(int cpu) | 144 | void smp_send_debugger_break(int cpu) |
133 | { | 145 | { |
@@ -154,223 +166,13 @@ static void stop_this_cpu(void *dummy) | |||
154 | ; | 166 | ; |
155 | } | 167 | } |
156 | 168 | ||
157 | /* | ||
158 | * Structure and data for smp_call_function(). This is designed to minimise | ||
159 | * static memory requirements. It also looks cleaner. | ||
160 | * Stolen from the i386 version. | ||
161 | */ | ||
162 | static __cacheline_aligned_in_smp DEFINE_SPINLOCK(call_lock); | ||
163 | |||
164 | static struct call_data_struct { | ||
165 | void (*func) (void *info); | ||
166 | void *info; | ||
167 | atomic_t started; | ||
168 | atomic_t finished; | ||
169 | int wait; | ||
170 | } *call_data; | ||
171 | |||
172 | /* delay of at least 8 seconds */ | ||
173 | #define SMP_CALL_TIMEOUT 8 | ||
174 | |||
175 | /* | ||
176 | * These functions send a 'generic call function' IPI to other online | ||
177 | * CPUS in the system. | ||
178 | * | ||
179 | * [SUMMARY] Run a function on other CPUs. | ||
180 | * <func> The function to run. This must be fast and non-blocking. | ||
181 | * <info> An arbitrary pointer to pass to the function. | ||
182 | * <nonatomic> currently unused. | ||
183 | * <wait> If true, wait (atomically) until function has completed on other CPUs. | ||
184 | * [RETURNS] 0 on success, else a negative status code. Does not return until | ||
185 | * remote CPUs are nearly ready to execute <<func>> or are or have executed. | ||
186 | * <map> is a cpu map of the cpus to send IPI to. | ||
187 | * | ||
188 | * You must not call this function with disabled interrupts or from a | ||
189 | * hardware interrupt handler or from a bottom half handler. | ||
190 | */ | ||
191 | static int __smp_call_function_map(void (*func) (void *info), void *info, | ||
192 | int nonatomic, int wait, cpumask_t map) | ||
193 | { | ||
194 | struct call_data_struct data; | ||
195 | int ret = -1, num_cpus; | ||
196 | int cpu; | ||
197 | u64 timeout; | ||
198 | |||
199 | if (unlikely(smp_ops == NULL)) | ||
200 | return ret; | ||
201 | |||
202 | data.func = func; | ||
203 | data.info = info; | ||
204 | atomic_set(&data.started, 0); | ||
205 | data.wait = wait; | ||
206 | if (wait) | ||
207 | atomic_set(&data.finished, 0); | ||
208 | |||
209 | /* remove 'self' from the map */ | ||
210 | if (cpu_isset(smp_processor_id(), map)) | ||
211 | cpu_clear(smp_processor_id(), map); | ||
212 | |||
213 | /* sanity check the map, remove any non-online processors. */ | ||
214 | cpus_and(map, map, cpu_online_map); | ||
215 | |||
216 | num_cpus = cpus_weight(map); | ||
217 | if (!num_cpus) | ||
218 | goto done; | ||
219 | |||
220 | call_data = &data; | ||
221 | smp_wmb(); | ||
222 | /* Send a message to all CPUs in the map */ | ||
223 | for_each_cpu_mask(cpu, map) | ||
224 | smp_ops->message_pass(cpu, PPC_MSG_CALL_FUNCTION); | ||
225 | |||
226 | timeout = get_tb() + (u64) SMP_CALL_TIMEOUT * tb_ticks_per_sec; | ||
227 | |||
228 | /* Wait for indication that they have received the message */ | ||
229 | while (atomic_read(&data.started) != num_cpus) { | ||
230 | HMT_low(); | ||
231 | if (get_tb() >= timeout) { | ||
232 | printk("smp_call_function on cpu %d: other cpus not " | ||
233 | "responding (%d)\n", smp_processor_id(), | ||
234 | atomic_read(&data.started)); | ||
235 | if (!ipi_fail_ok) | ||
236 | debugger(NULL); | ||
237 | goto out; | ||
238 | } | ||
239 | } | ||
240 | |||
241 | /* optionally wait for the CPUs to complete */ | ||
242 | if (wait) { | ||
243 | while (atomic_read(&data.finished) != num_cpus) { | ||
244 | HMT_low(); | ||
245 | if (get_tb() >= timeout) { | ||
246 | printk("smp_call_function on cpu %d: other " | ||
247 | "cpus not finishing (%d/%d)\n", | ||
248 | smp_processor_id(), | ||
249 | atomic_read(&data.finished), | ||
250 | atomic_read(&data.started)); | ||
251 | debugger(NULL); | ||
252 | goto out; | ||
253 | } | ||
254 | } | ||
255 | } | ||
256 | |||
257 | done: | ||
258 | ret = 0; | ||
259 | |||
260 | out: | ||
261 | call_data = NULL; | ||
262 | HMT_medium(); | ||
263 | return ret; | ||
264 | } | ||
265 | |||
266 | static int __smp_call_function(void (*func)(void *info), void *info, | ||
267 | int nonatomic, int wait) | ||
268 | { | ||
269 | int ret; | ||
270 | spin_lock(&call_lock); | ||
271 | ret =__smp_call_function_map(func, info, nonatomic, wait, | ||
272 | cpu_online_map); | ||
273 | spin_unlock(&call_lock); | ||
274 | return ret; | ||
275 | } | ||
276 | |||
277 | int smp_call_function(void (*func) (void *info), void *info, int nonatomic, | ||
278 | int wait) | ||
279 | { | ||
280 | /* Can deadlock when called with interrupts disabled */ | ||
281 | WARN_ON(irqs_disabled()); | ||
282 | |||
283 | return __smp_call_function(func, info, nonatomic, wait); | ||
284 | } | ||
285 | EXPORT_SYMBOL(smp_call_function); | ||
286 | |||
287 | int smp_call_function_single(int cpu, void (*func) (void *info), void *info, | ||
288 | int nonatomic, int wait) | ||
289 | { | ||
290 | cpumask_t map = CPU_MASK_NONE; | ||
291 | int ret = 0; | ||
292 | |||
293 | /* Can deadlock when called with interrupts disabled */ | ||
294 | WARN_ON(irqs_disabled()); | ||
295 | |||
296 | if (!cpu_online(cpu)) | ||
297 | return -EINVAL; | ||
298 | |||
299 | cpu_set(cpu, map); | ||
300 | if (cpu != get_cpu()) { | ||
301 | spin_lock(&call_lock); | ||
302 | ret = __smp_call_function_map(func, info, nonatomic, wait, map); | ||
303 | spin_unlock(&call_lock); | ||
304 | } else { | ||
305 | local_irq_disable(); | ||
306 | func(info); | ||
307 | local_irq_enable(); | ||
308 | } | ||
309 | put_cpu(); | ||
310 | return ret; | ||
311 | } | ||
312 | EXPORT_SYMBOL(smp_call_function_single); | ||
313 | |||
314 | void smp_send_stop(void) | 169 | void smp_send_stop(void) |
315 | { | 170 | { |
316 | int nolock; | 171 | smp_call_function(stop_this_cpu, NULL, 0); |
317 | |||
318 | /* It's OK to fail sending the IPI, since the alternative is to | ||
319 | * be stuck forever waiting on the other CPU to take the interrupt. | ||
320 | * | ||
321 | * It's better to at least continue and go through reboot, since this | ||
322 | * function is usually called at panic or reboot time in the first | ||
323 | * place. | ||
324 | */ | ||
325 | ipi_fail_ok = 1; | ||
326 | |||
327 | /* Don't deadlock in case we got called through panic */ | ||
328 | nolock = !spin_trylock(&call_lock); | ||
329 | __smp_call_function_map(stop_this_cpu, NULL, 1, 0, cpu_online_map); | ||
330 | if (!nolock) | ||
331 | spin_unlock(&call_lock); | ||
332 | } | ||
333 | |||
334 | void smp_call_function_interrupt(void) | ||
335 | { | ||
336 | void (*func) (void *info); | ||
337 | void *info; | ||
338 | int wait; | ||
339 | |||
340 | /* call_data will be NULL if the sender timed out while | ||
341 | * waiting on us to receive the call. | ||
342 | */ | ||
343 | if (!call_data) | ||
344 | return; | ||
345 | |||
346 | func = call_data->func; | ||
347 | info = call_data->info; | ||
348 | wait = call_data->wait; | ||
349 | |||
350 | if (!wait) | ||
351 | smp_mb__before_atomic_inc(); | ||
352 | |||
353 | /* | ||
354 | * Notify initiating CPU that I've grabbed the data and am | ||
355 | * about to execute the function | ||
356 | */ | ||
357 | atomic_inc(&call_data->started); | ||
358 | /* | ||
359 | * At this point the info structure may be out of scope unless wait==1 | ||
360 | */ | ||
361 | (*func)(info); | ||
362 | if (wait) { | ||
363 | smp_mb__before_atomic_inc(); | ||
364 | atomic_inc(&call_data->finished); | ||
365 | } | ||
366 | } | 172 | } |
367 | 173 | ||
368 | extern struct gettimeofday_struct do_gtod; | ||
369 | |||
370 | struct thread_info *current_set[NR_CPUS]; | 174 | struct thread_info *current_set[NR_CPUS]; |
371 | 175 | ||
372 | DECLARE_PER_CPU(unsigned int, pvr); | ||
373 | |||
374 | static void __devinit smp_store_cpu_info(int id) | 176 | static void __devinit smp_store_cpu_info(int id) |
375 | { | 177 | { |
376 | per_cpu(pvr, id) = mfspr(SPRN_PVR); | 178 | per_cpu(pvr, id) = mfspr(SPRN_PVR); |
@@ -596,9 +398,9 @@ int __devinit start_secondary(void *unused) | |||
596 | 398 | ||
597 | secondary_cpu_time_init(); | 399 | secondary_cpu_time_init(); |
598 | 400 | ||
599 | spin_lock(&call_lock); | 401 | ipi_call_lock(); |
600 | cpu_set(cpu, cpu_online_map); | 402 | cpu_set(cpu, cpu_online_map); |
601 | spin_unlock(&call_lock); | 403 | ipi_call_unlock(); |
602 | 404 | ||
603 | local_irq_enable(); | 405 | local_irq_enable(); |
604 | 406 | ||
diff --git a/arch/powerpc/kernel/softemu8xx.c b/arch/powerpc/kernel/softemu8xx.c index 67d6f6890edc..c906c4bf6835 100644 --- a/arch/powerpc/kernel/softemu8xx.c +++ b/arch/powerpc/kernel/softemu8xx.c | |||
@@ -124,7 +124,7 @@ int Soft_emulate_8xx(struct pt_regs *regs) | |||
124 | disp = instword & 0xffff; | 124 | disp = instword & 0xffff; |
125 | 125 | ||
126 | ea = (u32 *)(regs->gpr[idxreg] + disp); | 126 | ea = (u32 *)(regs->gpr[idxreg] + disp); |
127 | ip = (u32 *)¤t->thread.fpr[flreg]; | 127 | ip = (u32 *)¤t->thread.TS_FPR(flreg); |
128 | 128 | ||
129 | switch ( inst ) | 129 | switch ( inst ) |
130 | { | 130 | { |
@@ -168,7 +168,7 @@ int Soft_emulate_8xx(struct pt_regs *regs) | |||
168 | break; | 168 | break; |
169 | case FMR: | 169 | case FMR: |
170 | /* assume this is a fp move -- Cort */ | 170 | /* assume this is a fp move -- Cort */ |
171 | memcpy(ip, ¤t->thread.fpr[(instword>>11)&0x1f], | 171 | memcpy(ip, ¤t->thread.TS_FPR((instword>>11)&0x1f), |
172 | sizeof(double)); | 172 | sizeof(double)); |
173 | break; | 173 | break; |
174 | default: | 174 | default: |
diff --git a/arch/powerpc/kernel/stacktrace.c b/arch/powerpc/kernel/stacktrace.c index 962944038430..071bee3ec749 100644 --- a/arch/powerpc/kernel/stacktrace.c +++ b/arch/powerpc/kernel/stacktrace.c | |||
@@ -10,33 +10,35 @@ | |||
10 | * 2 of the License, or (at your option) any later version. | 10 | * 2 of the License, or (at your option) any later version. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/module.h> | ||
13 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
14 | #include <linux/stacktrace.h> | 15 | #include <linux/stacktrace.h> |
16 | #include <linux/module.h> | ||
15 | #include <asm/ptrace.h> | 17 | #include <asm/ptrace.h> |
18 | #include <asm/processor.h> | ||
16 | 19 | ||
17 | /* | 20 | /* |
18 | * Save stack-backtrace addresses into a stack_trace buffer. | 21 | * Save stack-backtrace addresses into a stack_trace buffer. |
19 | */ | 22 | */ |
20 | void save_stack_trace(struct stack_trace *trace) | 23 | static void save_context_stack(struct stack_trace *trace, unsigned long sp, |
24 | struct task_struct *tsk, int savesched) | ||
21 | { | 25 | { |
22 | unsigned long sp; | ||
23 | |||
24 | asm("mr %0,1" : "=r" (sp)); | ||
25 | |||
26 | for (;;) { | 26 | for (;;) { |
27 | unsigned long *stack = (unsigned long *) sp; | 27 | unsigned long *stack = (unsigned long *) sp; |
28 | unsigned long newsp, ip; | 28 | unsigned long newsp, ip; |
29 | 29 | ||
30 | if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD)) | 30 | if (!validate_sp(sp, tsk, STACK_FRAME_OVERHEAD)) |
31 | return; | 31 | return; |
32 | 32 | ||
33 | newsp = stack[0]; | 33 | newsp = stack[0]; |
34 | ip = stack[STACK_FRAME_LR_SAVE]; | 34 | ip = stack[STACK_FRAME_LR_SAVE]; |
35 | 35 | ||
36 | if (!trace->skip) | 36 | if (savesched || !in_sched_functions(ip)) { |
37 | trace->entries[trace->nr_entries++] = ip; | 37 | if (!trace->skip) |
38 | else | 38 | trace->entries[trace->nr_entries++] = ip; |
39 | trace->skip--; | 39 | else |
40 | trace->skip--; | ||
41 | } | ||
40 | 42 | ||
41 | if (trace->nr_entries >= trace->max_entries) | 43 | if (trace->nr_entries >= trace->max_entries) |
42 | return; | 44 | return; |
@@ -44,3 +46,19 @@ void save_stack_trace(struct stack_trace *trace) | |||
44 | sp = newsp; | 46 | sp = newsp; |
45 | } | 47 | } |
46 | } | 48 | } |
49 | |||
50 | void save_stack_trace(struct stack_trace *trace) | ||
51 | { | ||
52 | unsigned long sp; | ||
53 | |||
54 | asm("mr %0,1" : "=r" (sp)); | ||
55 | |||
56 | save_context_stack(trace, sp, current, 1); | ||
57 | } | ||
58 | EXPORT_SYMBOL_GPL(save_stack_trace); | ||
59 | |||
60 | void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) | ||
61 | { | ||
62 | save_context_stack(trace, tsk->thread.regs->gpr[1], tsk, 0); | ||
63 | } | ||
64 | EXPORT_SYMBOL_GPL(save_stack_trace_tsk); | ||
diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c index 4fe69ca24481..c04832c4a02e 100644 --- a/arch/powerpc/kernel/syscalls.c +++ b/arch/powerpc/kernel/syscalls.c | |||
@@ -143,6 +143,9 @@ static inline unsigned long do_mmap2(unsigned long addr, size_t len, | |||
143 | struct file * file = NULL; | 143 | struct file * file = NULL; |
144 | unsigned long ret = -EINVAL; | 144 | unsigned long ret = -EINVAL; |
145 | 145 | ||
146 | if (!arch_validate_prot(prot)) | ||
147 | goto out; | ||
148 | |||
146 | if (shift) { | 149 | if (shift) { |
147 | if (off & ((1 << shift) - 1)) | 150 | if (off & ((1 << shift) - 1)) |
148 | goto out; | 151 | goto out; |
diff --git a/arch/powerpc/kernel/tau_6xx.c b/arch/powerpc/kernel/tau_6xx.c index 368a4934f7ee..c3a56d65c5a9 100644 --- a/arch/powerpc/kernel/tau_6xx.c +++ b/arch/powerpc/kernel/tau_6xx.c | |||
@@ -192,7 +192,7 @@ static void tau_timeout_smp(unsigned long unused) | |||
192 | 192 | ||
193 | /* schedule ourselves to be run again */ | 193 | /* schedule ourselves to be run again */ |
194 | mod_timer(&tau_timer, jiffies + shrink_timer) ; | 194 | mod_timer(&tau_timer, jiffies + shrink_timer) ; |
195 | on_each_cpu(tau_timeout, NULL, 1, 0); | 195 | on_each_cpu(tau_timeout, NULL, 0); |
196 | } | 196 | } |
197 | 197 | ||
198 | /* | 198 | /* |
@@ -234,7 +234,7 @@ int __init TAU_init(void) | |||
234 | tau_timer.expires = jiffies + shrink_timer; | 234 | tau_timer.expires = jiffies + shrink_timer; |
235 | add_timer(&tau_timer); | 235 | add_timer(&tau_timer); |
236 | 236 | ||
237 | on_each_cpu(TAU_init_smp, NULL, 1, 0); | 237 | on_each_cpu(TAU_init_smp, NULL, 0); |
238 | 238 | ||
239 | printk("Thermal assist unit "); | 239 | printk("Thermal assist unit "); |
240 | #ifdef CONFIG_TAU_INT | 240 | #ifdef CONFIG_TAU_INT |
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 73401e83739a..e2ee66b5831d 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c | |||
@@ -129,7 +129,7 @@ static unsigned long __initdata iSeries_recal_titan; | |||
129 | static signed long __initdata iSeries_recal_tb; | 129 | static signed long __initdata iSeries_recal_tb; |
130 | 130 | ||
131 | /* Forward declaration is only needed for iSereis compiles */ | 131 | /* Forward declaration is only needed for iSereis compiles */ |
132 | void __init clocksource_init(void); | 132 | static void __init clocksource_init(void); |
133 | #endif | 133 | #endif |
134 | 134 | ||
135 | #define XSEC_PER_SEC (1024*1024) | 135 | #define XSEC_PER_SEC (1024*1024) |
@@ -150,8 +150,8 @@ u64 tb_to_xs; | |||
150 | unsigned tb_to_us; | 150 | unsigned tb_to_us; |
151 | 151 | ||
152 | #define TICKLEN_SCALE NTP_SCALE_SHIFT | 152 | #define TICKLEN_SCALE NTP_SCALE_SHIFT |
153 | u64 last_tick_len; /* units are ns / 2^TICKLEN_SCALE */ | 153 | static u64 last_tick_len; /* units are ns / 2^TICKLEN_SCALE */ |
154 | u64 ticklen_to_xs; /* 0.64 fraction */ | 154 | static u64 ticklen_to_xs; /* 0.64 fraction */ |
155 | 155 | ||
156 | /* If last_tick_len corresponds to about 1/HZ seconds, then | 156 | /* If last_tick_len corresponds to about 1/HZ seconds, then |
157 | last_tick_len << TICKLEN_SHIFT will be about 2^63. */ | 157 | last_tick_len << TICKLEN_SHIFT will be about 2^63. */ |
@@ -164,7 +164,7 @@ static u64 tb_to_ns_scale __read_mostly; | |||
164 | static unsigned tb_to_ns_shift __read_mostly; | 164 | static unsigned tb_to_ns_shift __read_mostly; |
165 | static unsigned long boot_tb __read_mostly; | 165 | static unsigned long boot_tb __read_mostly; |
166 | 166 | ||
167 | struct gettimeofday_struct do_gtod; | 167 | static struct gettimeofday_struct do_gtod; |
168 | 168 | ||
169 | extern struct timezone sys_tz; | 169 | extern struct timezone sys_tz; |
170 | static long timezone_offset; | 170 | static long timezone_offset; |
@@ -322,7 +322,7 @@ void snapshot_timebases(void) | |||
322 | { | 322 | { |
323 | if (!cpu_has_feature(CPU_FTR_PURR)) | 323 | if (!cpu_has_feature(CPU_FTR_PURR)) |
324 | return; | 324 | return; |
325 | on_each_cpu(snapshot_tb_and_purr, NULL, 0, 1); | 325 | on_each_cpu(snapshot_tb_and_purr, NULL, 1); |
326 | } | 326 | } |
327 | 327 | ||
328 | /* | 328 | /* |
@@ -742,10 +742,6 @@ void __init generic_calibrate_decr(void) | |||
742 | } | 742 | } |
743 | 743 | ||
744 | #if defined(CONFIG_BOOKE) || defined(CONFIG_40x) | 744 | #if defined(CONFIG_BOOKE) || defined(CONFIG_40x) |
745 | /* Set the time base to zero */ | ||
746 | mtspr(SPRN_TBWL, 0); | ||
747 | mtspr(SPRN_TBWU, 0); | ||
748 | |||
749 | /* Clear any pending timer interrupts */ | 745 | /* Clear any pending timer interrupts */ |
750 | mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS); | 746 | mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_DIS | TSR_FIS); |
751 | 747 | ||
@@ -832,7 +828,7 @@ void update_vsyscall_tz(void) | |||
832 | ++vdso_data->tb_update_count; | 828 | ++vdso_data->tb_update_count; |
833 | } | 829 | } |
834 | 830 | ||
835 | void __init clocksource_init(void) | 831 | static void __init clocksource_init(void) |
836 | { | 832 | { |
837 | struct clocksource *clock; | 833 | struct clocksource *clock; |
838 | 834 | ||
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 4b5b7ff4f78b..878fbddb6ae1 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
@@ -967,6 +967,20 @@ void altivec_unavailable_exception(struct pt_regs *regs) | |||
967 | die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT); | 967 | die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT); |
968 | } | 968 | } |
969 | 969 | ||
970 | void vsx_unavailable_exception(struct pt_regs *regs) | ||
971 | { | ||
972 | if (user_mode(regs)) { | ||
973 | /* A user program has executed an vsx instruction, | ||
974 | but this kernel doesn't support vsx. */ | ||
975 | _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); | ||
976 | return; | ||
977 | } | ||
978 | |||
979 | printk(KERN_EMERG "Unrecoverable VSX Unavailable Exception " | ||
980 | "%lx at %lx\n", regs->trap, regs->nip); | ||
981 | die("Unrecoverable VSX Unavailable Exception", regs, SIGABRT); | ||
982 | } | ||
983 | |||
970 | void performance_monitor_exception(struct pt_regs *regs) | 984 | void performance_monitor_exception(struct pt_regs *regs) |
971 | { | 985 | { |
972 | perf_irq(regs); | 986 | perf_irq(regs); |
@@ -1030,21 +1044,29 @@ void SoftwareEmulation(struct pt_regs *regs) | |||
1030 | 1044 | ||
1031 | #if defined(CONFIG_40x) || defined(CONFIG_BOOKE) | 1045 | #if defined(CONFIG_40x) || defined(CONFIG_BOOKE) |
1032 | 1046 | ||
1033 | void DebugException(struct pt_regs *regs, unsigned long debug_status) | 1047 | void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status) |
1034 | { | 1048 | { |
1035 | if (debug_status & DBSR_IC) { /* instruction completion */ | 1049 | if (debug_status & DBSR_IC) { /* instruction completion */ |
1036 | regs->msr &= ~MSR_DE; | 1050 | regs->msr &= ~MSR_DE; |
1051 | |||
1052 | /* Disable instruction completion */ | ||
1053 | mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~DBCR0_IC); | ||
1054 | /* Clear the instruction completion event */ | ||
1055 | mtspr(SPRN_DBSR, DBSR_IC); | ||
1056 | |||
1057 | if (notify_die(DIE_SSTEP, "single_step", regs, 5, | ||
1058 | 5, SIGTRAP) == NOTIFY_STOP) { | ||
1059 | return; | ||
1060 | } | ||
1061 | |||
1062 | if (debugger_sstep(regs)) | ||
1063 | return; | ||
1064 | |||
1037 | if (user_mode(regs)) { | 1065 | if (user_mode(regs)) { |
1038 | current->thread.dbcr0 &= ~DBCR0_IC; | 1066 | current->thread.dbcr0 &= ~DBCR0_IC; |
1039 | } else { | ||
1040 | /* Disable instruction completion */ | ||
1041 | mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~DBCR0_IC); | ||
1042 | /* Clear the instruction completion event */ | ||
1043 | mtspr(SPRN_DBSR, DBSR_IC); | ||
1044 | if (debugger_sstep(regs)) | ||
1045 | return; | ||
1046 | } | 1067 | } |
1047 | _exception(SIGTRAP, regs, TRAP_TRACE, 0); | 1068 | |
1069 | _exception(SIGTRAP, regs, TRAP_TRACE, regs->nip); | ||
1048 | } | 1070 | } |
1049 | } | 1071 | } |
1050 | #endif /* CONFIG_4xx || CONFIG_BOOKE */ | 1072 | #endif /* CONFIG_4xx || CONFIG_BOOKE */ |
@@ -1091,6 +1113,21 @@ void altivec_assist_exception(struct pt_regs *regs) | |||
1091 | } | 1113 | } |
1092 | #endif /* CONFIG_ALTIVEC */ | 1114 | #endif /* CONFIG_ALTIVEC */ |
1093 | 1115 | ||
1116 | #ifdef CONFIG_VSX | ||
1117 | void vsx_assist_exception(struct pt_regs *regs) | ||
1118 | { | ||
1119 | if (!user_mode(regs)) { | ||
1120 | printk(KERN_EMERG "VSX assist exception in kernel mode" | ||
1121 | " at %lx\n", regs->nip); | ||
1122 | die("Kernel VSX assist exception", regs, SIGILL); | ||
1123 | } | ||
1124 | |||
1125 | flush_vsx_to_thread(current); | ||
1126 | printk(KERN_INFO "VSX assist not supported at %lx\n", regs->nip); | ||
1127 | _exception(SIGILL, regs, ILL_ILLOPC, regs->nip); | ||
1128 | } | ||
1129 | #endif /* CONFIG_VSX */ | ||
1130 | |||
1094 | #ifdef CONFIG_FSL_BOOKE | 1131 | #ifdef CONFIG_FSL_BOOKE |
1095 | void CacheLockingException(struct pt_regs *regs, unsigned long address, | 1132 | void CacheLockingException(struct pt_regs *regs, unsigned long address, |
1096 | unsigned long error_code) | 1133 | unsigned long error_code) |
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c index c21a626af676..f177c60ea766 100644 --- a/arch/powerpc/kernel/vdso.c +++ b/arch/powerpc/kernel/vdso.c | |||
@@ -142,7 +142,7 @@ static void dump_one_vdso_page(struct page *pg, struct page *upg) | |||
142 | printk("kpg: %p (c:%d,f:%08lx)", __va(page_to_pfn(pg) << PAGE_SHIFT), | 142 | printk("kpg: %p (c:%d,f:%08lx)", __va(page_to_pfn(pg) << PAGE_SHIFT), |
143 | page_count(pg), | 143 | page_count(pg), |
144 | pg->flags); | 144 | pg->flags); |
145 | if (upg/* && pg != upg*/) { | 145 | if (upg && !IS_ERR(upg) /* && pg != upg*/) { |
146 | printk(" upg: %p (c:%d,f:%08lx)", __va(page_to_pfn(upg) | 146 | printk(" upg: %p (c:%d,f:%08lx)", __va(page_to_pfn(upg) |
147 | << PAGE_SHIFT), | 147 | << PAGE_SHIFT), |
148 | page_count(upg), | 148 | page_count(upg), |
@@ -571,6 +571,11 @@ static __init int vdso_fixup_features(struct lib32_elfinfo *v32, | |||
571 | if (start64) | 571 | if (start64) |
572 | do_feature_fixups(powerpc_firmware_features, | 572 | do_feature_fixups(powerpc_firmware_features, |
573 | start64, start64 + size64); | 573 | start64, start64 + size64); |
574 | |||
575 | start64 = find_section64(v64->hdr, "__lwsync_fixup", &size64); | ||
576 | if (start64) | ||
577 | do_lwsync_fixups(cur_cpu_spec->cpu_features, | ||
578 | start64, start64 + size64); | ||
574 | #endif /* CONFIG_PPC64 */ | 579 | #endif /* CONFIG_PPC64 */ |
575 | 580 | ||
576 | start32 = find_section32(v32->hdr, "__ftr_fixup", &size32); | 581 | start32 = find_section32(v32->hdr, "__ftr_fixup", &size32); |
@@ -585,6 +590,11 @@ static __init int vdso_fixup_features(struct lib32_elfinfo *v32, | |||
585 | start32, start32 + size32); | 590 | start32, start32 + size32); |
586 | #endif /* CONFIG_PPC64 */ | 591 | #endif /* CONFIG_PPC64 */ |
587 | 592 | ||
593 | start32 = find_section32(v32->hdr, "__lwsync_fixup", &size32); | ||
594 | if (start32) | ||
595 | do_lwsync_fixups(cur_cpu_spec->cpu_features, | ||
596 | start32, start32 + size32); | ||
597 | |||
588 | return 0; | 598 | return 0; |
589 | } | 599 | } |
590 | 600 | ||
diff --git a/arch/powerpc/kernel/vdso32/vdso32.lds.S b/arch/powerpc/kernel/vdso32/vdso32.lds.S index 9352ab5200e5..be3b6a41dc09 100644 --- a/arch/powerpc/kernel/vdso32/vdso32.lds.S +++ b/arch/powerpc/kernel/vdso32/vdso32.lds.S | |||
@@ -24,7 +24,7 @@ SECTIONS | |||
24 | 24 | ||
25 | . = ALIGN(16); | 25 | . = ALIGN(16); |
26 | .text : { | 26 | .text : { |
27 | *(.text .stub .text.* .gnu.linkonce.t.*) | 27 | *(.text .stub .text.* .gnu.linkonce.t.* __ftr_alt_*) |
28 | } | 28 | } |
29 | PROVIDE(__etext = .); | 29 | PROVIDE(__etext = .); |
30 | PROVIDE(_etext = .); | 30 | PROVIDE(_etext = .); |
@@ -33,6 +33,9 @@ SECTIONS | |||
33 | . = ALIGN(8); | 33 | . = ALIGN(8); |
34 | __ftr_fixup : { *(__ftr_fixup) } | 34 | __ftr_fixup : { *(__ftr_fixup) } |
35 | 35 | ||
36 | . = ALIGN(8); | ||
37 | __lwsync_fixup : { *(__lwsync_fixup) } | ||
38 | |||
36 | #ifdef CONFIG_PPC64 | 39 | #ifdef CONFIG_PPC64 |
37 | . = ALIGN(8); | 40 | . = ALIGN(8); |
38 | __fw_ftr_fixup : { *(__fw_ftr_fixup) } | 41 | __fw_ftr_fixup : { *(__fw_ftr_fixup) } |
diff --git a/arch/powerpc/kernel/vdso64/vdso64.lds.S b/arch/powerpc/kernel/vdso64/vdso64.lds.S index 932b3fdb34b9..d0b2526dd38d 100644 --- a/arch/powerpc/kernel/vdso64/vdso64.lds.S +++ b/arch/powerpc/kernel/vdso64/vdso64.lds.S | |||
@@ -24,7 +24,7 @@ SECTIONS | |||
24 | 24 | ||
25 | . = ALIGN(16); | 25 | . = ALIGN(16); |
26 | .text : { | 26 | .text : { |
27 | *(.text .stub .text.* .gnu.linkonce.t.*) | 27 | *(.text .stub .text.* .gnu.linkonce.t.* __ftr_alt_*) |
28 | *(.sfpr .glink) | 28 | *(.sfpr .glink) |
29 | } :text | 29 | } :text |
30 | PROVIDE(__etext = .); | 30 | PROVIDE(__etext = .); |
@@ -35,6 +35,9 @@ SECTIONS | |||
35 | __ftr_fixup : { *(__ftr_fixup) } | 35 | __ftr_fixup : { *(__ftr_fixup) } |
36 | 36 | ||
37 | . = ALIGN(8); | 37 | . = ALIGN(8); |
38 | __lwsync_fixup : { *(__lwsync_fixup) } | ||
39 | |||
40 | . = ALIGN(8); | ||
38 | __fw_ftr_fixup : { *(__fw_ftr_fixup) } | 41 | __fw_ftr_fixup : { *(__fw_ftr_fixup) } |
39 | 42 | ||
40 | /* | 43 | /* |
@@ -43,15 +46,15 @@ SECTIONS | |||
43 | .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } | 46 | .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } |
44 | .rodata1 : { *(.rodata1) } | 47 | .rodata1 : { *(.rodata1) } |
45 | 48 | ||
49 | .dynamic : { *(.dynamic) } :text :dynamic | ||
50 | |||
46 | .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr | 51 | .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr |
47 | .eh_frame : { KEEP (*(.eh_frame)) } :text | 52 | .eh_frame : { KEEP (*(.eh_frame)) } :text |
48 | .gcc_except_table : { *(.gcc_except_table) } | 53 | .gcc_except_table : { *(.gcc_except_table) } |
54 | .rela.dyn ALIGN(8) : { *(.rela.dyn) } | ||
49 | 55 | ||
50 | .opd ALIGN(8) : { KEEP (*(.opd)) } | 56 | .opd ALIGN(8) : { KEEP (*(.opd)) } |
51 | .got ALIGN(8) : { *(.got .toc) } | 57 | .got ALIGN(8) : { *(.got .toc) } |
52 | .rela.dyn ALIGN(8) : { *(.rela.dyn) } | ||
53 | |||
54 | .dynamic : { *(.dynamic) } :text :dynamic | ||
55 | 58 | ||
56 | _end = .; | 59 | _end = .; |
57 | PROVIDE(end = .); | 60 | PROVIDE(end = .); |
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 0c3000bf8d75..87a72c66ce27 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S | |||
@@ -35,7 +35,7 @@ SECTIONS | |||
35 | ALIGN_FUNCTION(); | 35 | ALIGN_FUNCTION(); |
36 | *(.text.head) | 36 | *(.text.head) |
37 | _text = .; | 37 | _text = .; |
38 | *(.text .fixup .text.init.refok .exit.text.refok) | 38 | *(.text .fixup .text.init.refok .exit.text.refok __ftr_alt_*) |
39 | SCHED_TEXT | 39 | SCHED_TEXT |
40 | LOCK_TEXT | 40 | LOCK_TEXT |
41 | KPROBES_TEXT | 41 | KPROBES_TEXT |
@@ -64,8 +64,6 @@ SECTIONS | |||
64 | 64 | ||
65 | NOTES | 65 | NOTES |
66 | 66 | ||
67 | BUG_TABLE | ||
68 | |||
69 | /* | 67 | /* |
70 | * Init sections discarded at runtime | 68 | * Init sections discarded at runtime |
71 | */ | 69 | */ |
@@ -127,6 +125,12 @@ SECTIONS | |||
127 | *(__ftr_fixup) | 125 | *(__ftr_fixup) |
128 | __stop___ftr_fixup = .; | 126 | __stop___ftr_fixup = .; |
129 | } | 127 | } |
128 | . = ALIGN(8); | ||
129 | __lwsync_fixup : AT(ADDR(__lwsync_fixup) - LOAD_OFFSET) { | ||
130 | __start___lwsync_fixup = .; | ||
131 | *(__lwsync_fixup) | ||
132 | __stop___lwsync_fixup = .; | ||
133 | } | ||
130 | #ifdef CONFIG_PPC64 | 134 | #ifdef CONFIG_PPC64 |
131 | . = ALIGN(8); | 135 | . = ALIGN(8); |
132 | __fw_ftr_fixup : AT(ADDR(__fw_ftr_fixup) - LOAD_OFFSET) { | 136 | __fw_ftr_fixup : AT(ADDR(__fw_ftr_fixup) - LOAD_OFFSET) { |