diff options
Diffstat (limited to 'arch/powerpc/kernel')
41 files changed, 958 insertions, 493 deletions
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 8e5e2c74971e..9ba1bb731fcc 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile | |||
| @@ -18,12 +18,10 @@ CFLAGS_REMOVE_cputable.o = -pg -mno-sched-epilog | |||
| 18 | CFLAGS_REMOVE_prom_init.o = -pg -mno-sched-epilog | 18 | CFLAGS_REMOVE_prom_init.o = -pg -mno-sched-epilog |
| 19 | CFLAGS_REMOVE_btext.o = -pg -mno-sched-epilog | 19 | CFLAGS_REMOVE_btext.o = -pg -mno-sched-epilog |
| 20 | CFLAGS_REMOVE_prom.o = -pg -mno-sched-epilog | 20 | CFLAGS_REMOVE_prom.o = -pg -mno-sched-epilog |
| 21 | 21 | # do not trace tracer code | |
| 22 | ifdef CONFIG_DYNAMIC_FTRACE | ||
| 23 | # dynamic ftrace setup. | ||
| 24 | CFLAGS_REMOVE_ftrace.o = -pg -mno-sched-epilog | 22 | CFLAGS_REMOVE_ftrace.o = -pg -mno-sched-epilog |
| 25 | endif | 23 | # timers used by tracing |
| 26 | 24 | CFLAGS_REMOVE_time.o = -pg -mno-sched-epilog | |
| 27 | endif | 25 | endif |
| 28 | 26 | ||
| 29 | obj-y := cputable.o ptrace.o syscalls.o \ | 27 | obj-y := cputable.o ptrace.o syscalls.o \ |
| @@ -61,6 +59,7 @@ obj-$(CONFIG_HIBERNATION) += swsusp.o suspend.o \ | |||
| 61 | obj64-$(CONFIG_HIBERNATION) += swsusp_asm64.o | 59 | obj64-$(CONFIG_HIBERNATION) += swsusp_asm64.o |
| 62 | obj-$(CONFIG_MODULES) += module.o module_$(CONFIG_WORD_SIZE).o | 60 | obj-$(CONFIG_MODULES) += module.o module_$(CONFIG_WORD_SIZE).o |
| 63 | obj-$(CONFIG_44x) += cpu_setup_44x.o | 61 | obj-$(CONFIG_44x) += cpu_setup_44x.o |
| 62 | obj-$(CONFIG_FSL_BOOKE) += cpu_setup_fsl_booke.o dbell.o | ||
| 64 | 63 | ||
| 65 | extra-$(CONFIG_PPC_STD_MMU) := head_32.o | 64 | extra-$(CONFIG_PPC_STD_MMU) := head_32.o |
| 66 | extra-$(CONFIG_PPC64) := head_64.o | 65 | extra-$(CONFIG_PPC64) := head_64.o |
| @@ -76,7 +75,7 @@ obj-y += time.o prom.o traps.o setup-common.o \ | |||
| 76 | obj-$(CONFIG_PPC32) += entry_32.o setup_32.o | 75 | obj-$(CONFIG_PPC32) += entry_32.o setup_32.o |
| 77 | obj-$(CONFIG_PPC64) += dma-iommu.o iommu.o | 76 | obj-$(CONFIG_PPC64) += dma-iommu.o iommu.o |
| 78 | obj-$(CONFIG_KGDB) += kgdb.o | 77 | obj-$(CONFIG_KGDB) += kgdb.o |
| 79 | obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o | 78 | obj-$(CONFIG_PPC_OF_BOOT_TRAMPOLINE) += prom_init.o |
| 80 | obj-$(CONFIG_MODULES) += ppc_ksyms.o | 79 | obj-$(CONFIG_MODULES) += ppc_ksyms.o |
| 81 | obj-$(CONFIG_BOOTX_TEXT) += btext.o | 80 | obj-$(CONFIG_BOOTX_TEXT) += btext.o |
| 82 | obj-$(CONFIG_SMP) += smp.o | 81 | obj-$(CONFIG_SMP) += smp.o |
| @@ -94,6 +93,7 @@ obj-$(CONFIG_AUDIT) += audit.o | |||
| 94 | obj64-$(CONFIG_AUDIT) += compat_audit.o | 93 | obj64-$(CONFIG_AUDIT) += compat_audit.o |
| 95 | 94 | ||
| 96 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o | 95 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o |
| 96 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o | ||
| 97 | obj-$(CONFIG_PERF_COUNTERS) += perf_counter.o power4-pmu.o ppc970-pmu.o \ | 97 | obj-$(CONFIG_PERF_COUNTERS) += perf_counter.o power4-pmu.o ppc970-pmu.o \ |
| 98 | power5-pmu.o power5+-pmu.o power6-pmu.o | 98 | power5-pmu.o power5+-pmu.o power6-pmu.o |
| 99 | 99 | ||
diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c index 73cb6a3229ae..5ffcfaa77d6a 100644 --- a/arch/powerpc/kernel/align.c +++ b/arch/powerpc/kernel/align.c | |||
| @@ -187,7 +187,7 @@ static struct aligninfo aligninfo[128] = { | |||
| 187 | { 4, ST+F+S+U }, /* 11 1 1010: stfsux */ | 187 | { 4, ST+F+S+U }, /* 11 1 1010: stfsux */ |
| 188 | { 8, ST+F+U }, /* 11 1 1011: stfdux */ | 188 | { 8, ST+F+U }, /* 11 1 1011: stfdux */ |
| 189 | INVALID, /* 11 1 1100 */ | 189 | INVALID, /* 11 1 1100 */ |
| 190 | INVALID, /* 11 1 1101 */ | 190 | { 4, LD+F }, /* 11 1 1101: lfiwzx */ |
| 191 | INVALID, /* 11 1 1110 */ | 191 | INVALID, /* 11 1 1110 */ |
| 192 | INVALID, /* 11 1 1111 */ | 192 | INVALID, /* 11 1 1111 */ |
| 193 | }; | 193 | }; |
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 3734973f7394..e981d1ce1914 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c | |||
| @@ -49,7 +49,7 @@ | |||
| 49 | #include <asm/iseries/alpaca.h> | 49 | #include <asm/iseries/alpaca.h> |
| 50 | #endif | 50 | #endif |
| 51 | #ifdef CONFIG_KVM | 51 | #ifdef CONFIG_KVM |
| 52 | #include <asm/kvm_44x.h> | 52 | #include <linux/kvm_host.h> |
| 53 | #endif | 53 | #endif |
| 54 | 54 | ||
| 55 | #if defined(CONFIG_BOOKE) || defined(CONFIG_40x) | 55 | #if defined(CONFIG_BOOKE) || defined(CONFIG_40x) |
| @@ -285,9 +285,6 @@ int main(void) | |||
| 285 | #endif /* ! CONFIG_PPC64 */ | 285 | #endif /* ! CONFIG_PPC64 */ |
| 286 | 286 | ||
| 287 | /* About the CPU features table */ | 287 | /* About the CPU features table */ |
| 288 | DEFINE(CPU_SPEC_ENTRY_SIZE, sizeof(struct cpu_spec)); | ||
| 289 | DEFINE(CPU_SPEC_PVR_MASK, offsetof(struct cpu_spec, pvr_mask)); | ||
| 290 | DEFINE(CPU_SPEC_PVR_VALUE, offsetof(struct cpu_spec, pvr_value)); | ||
| 291 | DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features)); | 288 | DEFINE(CPU_SPEC_FEATURES, offsetof(struct cpu_spec, cpu_features)); |
| 292 | DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup)); | 289 | DEFINE(CPU_SPEC_SETUP, offsetof(struct cpu_spec, cpu_setup)); |
| 293 | DEFINE(CPU_SPEC_RESTORE, offsetof(struct cpu_spec, cpu_restore)); | 290 | DEFINE(CPU_SPEC_RESTORE, offsetof(struct cpu_spec, cpu_restore)); |
| @@ -362,8 +359,6 @@ int main(void) | |||
| 362 | DEFINE(PTE_SIZE, sizeof(pte_t)); | 359 | DEFINE(PTE_SIZE, sizeof(pte_t)); |
| 363 | 360 | ||
| 364 | #ifdef CONFIG_KVM | 361 | #ifdef CONFIG_KVM |
| 365 | DEFINE(TLBE_BYTES, sizeof(struct kvmppc_44x_tlbe)); | ||
| 366 | |||
| 367 | DEFINE(VCPU_HOST_STACK, offsetof(struct kvm_vcpu, arch.host_stack)); | 362 | DEFINE(VCPU_HOST_STACK, offsetof(struct kvm_vcpu, arch.host_stack)); |
| 368 | DEFINE(VCPU_HOST_PID, offsetof(struct kvm_vcpu, arch.host_pid)); | 363 | DEFINE(VCPU_HOST_PID, offsetof(struct kvm_vcpu, arch.host_pid)); |
| 369 | DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr)); | 364 | DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr)); |
diff --git a/arch/powerpc/kernel/cpu_setup_44x.S b/arch/powerpc/kernel/cpu_setup_44x.S index 10b4ab1008af..7d606f89a839 100644 --- a/arch/powerpc/kernel/cpu_setup_44x.S +++ b/arch/powerpc/kernel/cpu_setup_44x.S | |||
| @@ -34,6 +34,7 @@ _GLOBAL(__setup_cpu_440grx) | |||
| 34 | blr | 34 | blr |
| 35 | _GLOBAL(__setup_cpu_460ex) | 35 | _GLOBAL(__setup_cpu_460ex) |
| 36 | _GLOBAL(__setup_cpu_460gt) | 36 | _GLOBAL(__setup_cpu_460gt) |
| 37 | _GLOBAL(__setup_cpu_460sx) | ||
| 37 | mflr r4 | 38 | mflr r4 |
| 38 | bl __init_fpu_44x | 39 | bl __init_fpu_44x |
| 39 | bl __fixup_440A_mcheck | 40 | bl __fixup_440A_mcheck |
diff --git a/arch/powerpc/kernel/cpu_setup_6xx.S b/arch/powerpc/kernel/cpu_setup_6xx.S index 72d1d7395254..54f767e31a1a 100644 --- a/arch/powerpc/kernel/cpu_setup_6xx.S +++ b/arch/powerpc/kernel/cpu_setup_6xx.S | |||
| @@ -15,9 +15,14 @@ | |||
| 15 | #include <asm/ppc_asm.h> | 15 | #include <asm/ppc_asm.h> |
| 16 | #include <asm/asm-offsets.h> | 16 | #include <asm/asm-offsets.h> |
| 17 | #include <asm/cache.h> | 17 | #include <asm/cache.h> |
| 18 | #include <asm/mmu.h> | ||
| 18 | 19 | ||
| 19 | _GLOBAL(__setup_cpu_603) | 20 | _GLOBAL(__setup_cpu_603) |
| 20 | mflr r4 | 21 | mflr r4 |
| 22 | BEGIN_MMU_FTR_SECTION | ||
| 23 | li r10,0 | ||
| 24 | mtspr SPRN_SPRG4,r10 /* init SW LRU tracking */ | ||
| 25 | END_MMU_FTR_SECTION_IFSET(MMU_FTR_NEED_DTLB_SW_LRU) | ||
| 21 | BEGIN_FTR_SECTION | 26 | BEGIN_FTR_SECTION |
| 22 | bl __init_fpu_registers | 27 | bl __init_fpu_registers |
| 23 | END_FTR_SECTION_IFCLR(CPU_FTR_FPU_UNAVAILABLE) | 28 | END_FTR_SECTION_IFCLR(CPU_FTR_FPU_UNAVAILABLE) |
diff --git a/arch/powerpc/kernel/cpu_setup_fsl_booke.S b/arch/powerpc/kernel/cpu_setup_fsl_booke.S new file mode 100644 index 000000000000..eb4b9adcedb4 --- /dev/null +++ b/arch/powerpc/kernel/cpu_setup_fsl_booke.S | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | /* | ||
| 2 | * This file contains low level CPU setup functions. | ||
| 3 | * Kumar Gala <galak@kernel.crashing.org> | ||
| 4 | * Copyright 2009 Freescale Semiconductor, Inc. | ||
| 5 | * | ||
| 6 | * Based on cpu_setup_6xx code by | ||
| 7 | * Benjamin Herrenschmidt <benh@kernel.crashing.org> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or | ||
| 10 | * modify it under the terms of the GNU General Public License | ||
| 11 | * as published by the Free Software Foundation; either version | ||
| 12 | * 2 of the License, or (at your option) any later version. | ||
| 13 | * | ||
| 14 | */ | ||
| 15 | |||
| 16 | #include <asm/processor.h> | ||
| 17 | #include <asm/cputable.h> | ||
| 18 | #include <asm/ppc_asm.h> | ||
| 19 | |||
| 20 | _GLOBAL(__setup_cpu_e200) | ||
| 21 | /* enable dedicated debug exception handling resources (Debug APU) */ | ||
| 22 | mfspr r3,SPRN_HID0 | ||
| 23 | ori r3,r3,HID0_DAPUEN@l | ||
| 24 | mtspr SPRN_HID0,r3 | ||
| 25 | b __setup_e200_ivors | ||
| 26 | _GLOBAL(__setup_cpu_e500v1) | ||
| 27 | _GLOBAL(__setup_cpu_e500v2) | ||
| 28 | b __setup_e500_ivors | ||
| 29 | _GLOBAL(__setup_cpu_e500mc) | ||
| 30 | b __setup_e500mc_ivors | ||
| 31 | |||
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 923f87aff20a..cd1b687544f3 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c | |||
| @@ -35,6 +35,10 @@ const char *powerpc_base_platform; | |||
| 35 | * and ppc64 | 35 | * and ppc64 |
| 36 | */ | 36 | */ |
| 37 | #ifdef CONFIG_PPC32 | 37 | #ifdef CONFIG_PPC32 |
| 38 | extern void __setup_cpu_e200(unsigned long offset, struct cpu_spec* spec); | ||
| 39 | extern void __setup_cpu_e500v1(unsigned long offset, struct cpu_spec* spec); | ||
| 40 | extern void __setup_cpu_e500v2(unsigned long offset, struct cpu_spec* spec); | ||
| 41 | extern void __setup_cpu_e500mc(unsigned long offset, struct cpu_spec* spec); | ||
| 38 | extern void __setup_cpu_440ep(unsigned long offset, struct cpu_spec* spec); | 42 | extern void __setup_cpu_440ep(unsigned long offset, struct cpu_spec* spec); |
| 39 | extern void __setup_cpu_440epx(unsigned long offset, struct cpu_spec* spec); | 43 | extern void __setup_cpu_440epx(unsigned long offset, struct cpu_spec* spec); |
| 40 | extern void __setup_cpu_440gx(unsigned long offset, struct cpu_spec* spec); | 44 | extern void __setup_cpu_440gx(unsigned long offset, struct cpu_spec* spec); |
| @@ -43,6 +47,7 @@ extern void __setup_cpu_440spe(unsigned long offset, struct cpu_spec* spec); | |||
| 43 | extern void __setup_cpu_440x5(unsigned long offset, struct cpu_spec* spec); | 47 | extern void __setup_cpu_440x5(unsigned long offset, struct cpu_spec* spec); |
| 44 | extern void __setup_cpu_460ex(unsigned long offset, struct cpu_spec* spec); | 48 | extern void __setup_cpu_460ex(unsigned long offset, struct cpu_spec* spec); |
| 45 | extern void __setup_cpu_460gt(unsigned long offset, struct cpu_spec* spec); | 49 | extern void __setup_cpu_460gt(unsigned long offset, struct cpu_spec* spec); |
| 50 | extern void __setup_cpu_460sx(unsigned long offset, struct cpu_spec *spec); | ||
| 46 | extern void __setup_cpu_603(unsigned long offset, struct cpu_spec* spec); | 51 | extern void __setup_cpu_603(unsigned long offset, struct cpu_spec* spec); |
| 47 | extern void __setup_cpu_604(unsigned long offset, struct cpu_spec* spec); | 52 | extern void __setup_cpu_604(unsigned long offset, struct cpu_spec* spec); |
| 48 | extern void __setup_cpu_750(unsigned long offset, struct cpu_spec* spec); | 53 | extern void __setup_cpu_750(unsigned long offset, struct cpu_spec* spec); |
| @@ -726,6 +731,8 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
| 726 | .cpu_setup = __setup_cpu_750, | 731 | .cpu_setup = __setup_cpu_750, |
| 727 | .machine_check = machine_check_generic, | 732 | .machine_check = machine_check_generic, |
| 728 | .platform = "ppc750", | 733 | .platform = "ppc750", |
| 734 | .oprofile_cpu_type = "ppc/750", | ||
| 735 | .oprofile_type = PPC_OPROFILE_G4, | ||
| 729 | }, | 736 | }, |
| 730 | { /* 750FX rev 2.0 must disable HID0[DPM] */ | 737 | { /* 750FX rev 2.0 must disable HID0[DPM] */ |
| 731 | .pvr_mask = 0xffffffff, | 738 | .pvr_mask = 0xffffffff, |
| @@ -741,6 +748,8 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
| 741 | .cpu_setup = __setup_cpu_750, | 748 | .cpu_setup = __setup_cpu_750, |
| 742 | .machine_check = machine_check_generic, | 749 | .machine_check = machine_check_generic, |
| 743 | .platform = "ppc750", | 750 | .platform = "ppc750", |
| 751 | .oprofile_cpu_type = "ppc/750", | ||
| 752 | .oprofile_type = PPC_OPROFILE_G4, | ||
| 744 | }, | 753 | }, |
| 745 | { /* 750FX (All revs except 2.0) */ | 754 | { /* 750FX (All revs except 2.0) */ |
| 746 | .pvr_mask = 0xffff0000, | 755 | .pvr_mask = 0xffff0000, |
| @@ -756,6 +765,8 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
| 756 | .cpu_setup = __setup_cpu_750fx, | 765 | .cpu_setup = __setup_cpu_750fx, |
| 757 | .machine_check = machine_check_generic, | 766 | .machine_check = machine_check_generic, |
| 758 | .platform = "ppc750", | 767 | .platform = "ppc750", |
| 768 | .oprofile_cpu_type = "ppc/750", | ||
| 769 | .oprofile_type = PPC_OPROFILE_G4, | ||
| 759 | }, | 770 | }, |
| 760 | { /* 750GX */ | 771 | { /* 750GX */ |
| 761 | .pvr_mask = 0xffff0000, | 772 | .pvr_mask = 0xffff0000, |
| @@ -771,6 +782,8 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
| 771 | .cpu_setup = __setup_cpu_750fx, | 782 | .cpu_setup = __setup_cpu_750fx, |
| 772 | .machine_check = machine_check_generic, | 783 | .machine_check = machine_check_generic, |
| 773 | .platform = "ppc750", | 784 | .platform = "ppc750", |
| 785 | .oprofile_cpu_type = "ppc/750", | ||
| 786 | .oprofile_type = PPC_OPROFILE_G4, | ||
| 774 | }, | 787 | }, |
| 775 | { /* 740/750 (L2CR bit need fixup for 740) */ | 788 | { /* 740/750 (L2CR bit need fixup for 740) */ |
| 776 | .pvr_mask = 0xffff0000, | 789 | .pvr_mask = 0xffff0000, |
| @@ -1077,7 +1090,8 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
| 1077 | .cpu_name = "e300c2", | 1090 | .cpu_name = "e300c2", |
| 1078 | .cpu_features = CPU_FTRS_E300C2, | 1091 | .cpu_features = CPU_FTRS_E300C2, |
| 1079 | .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, | 1092 | .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU, |
| 1080 | .mmu_features = MMU_FTR_USE_HIGH_BATS, | 1093 | .mmu_features = MMU_FTR_USE_HIGH_BATS | |
| 1094 | MMU_FTR_NEED_DTLB_SW_LRU, | ||
| 1081 | .icache_bsize = 32, | 1095 | .icache_bsize = 32, |
| 1082 | .dcache_bsize = 32, | 1096 | .dcache_bsize = 32, |
| 1083 | .cpu_setup = __setup_cpu_603, | 1097 | .cpu_setup = __setup_cpu_603, |
| @@ -1090,7 +1104,8 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
| 1090 | .cpu_name = "e300c3", | 1104 | .cpu_name = "e300c3", |
| 1091 | .cpu_features = CPU_FTRS_E300, | 1105 | .cpu_features = CPU_FTRS_E300, |
| 1092 | .cpu_user_features = COMMON_USER, | 1106 | .cpu_user_features = COMMON_USER, |
| 1093 | .mmu_features = MMU_FTR_USE_HIGH_BATS, | 1107 | .mmu_features = MMU_FTR_USE_HIGH_BATS | |
| 1108 | MMU_FTR_NEED_DTLB_SW_LRU, | ||
| 1094 | .icache_bsize = 32, | 1109 | .icache_bsize = 32, |
| 1095 | .dcache_bsize = 32, | 1110 | .dcache_bsize = 32, |
| 1096 | .cpu_setup = __setup_cpu_603, | 1111 | .cpu_setup = __setup_cpu_603, |
| @@ -1105,7 +1120,8 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
| 1105 | .cpu_name = "e300c4", | 1120 | .cpu_name = "e300c4", |
| 1106 | .cpu_features = CPU_FTRS_E300, | 1121 | .cpu_features = CPU_FTRS_E300, |
| 1107 | .cpu_user_features = COMMON_USER, | 1122 | .cpu_user_features = COMMON_USER, |
| 1108 | .mmu_features = MMU_FTR_USE_HIGH_BATS, | 1123 | .mmu_features = MMU_FTR_USE_HIGH_BATS | |
| 1124 | MMU_FTR_NEED_DTLB_SW_LRU, | ||
| 1109 | .icache_bsize = 32, | 1125 | .icache_bsize = 32, |
| 1110 | .dcache_bsize = 32, | 1126 | .dcache_bsize = 32, |
| 1111 | .cpu_setup = __setup_cpu_603, | 1127 | .cpu_setup = __setup_cpu_603, |
| @@ -1634,6 +1650,19 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
| 1634 | .machine_check = machine_check_440A, | 1650 | .machine_check = machine_check_440A, |
| 1635 | .platform = "ppc440", | 1651 | .platform = "ppc440", |
| 1636 | }, | 1652 | }, |
| 1653 | { /* 460SX */ | ||
| 1654 | .pvr_mask = 0xffffff00, | ||
| 1655 | .pvr_value = 0x13541800, | ||
| 1656 | .cpu_name = "460SX", | ||
| 1657 | .cpu_features = CPU_FTRS_44X, | ||
| 1658 | .cpu_user_features = COMMON_USER_BOOKE, | ||
| 1659 | .mmu_features = MMU_FTR_TYPE_44x, | ||
| 1660 | .icache_bsize = 32, | ||
| 1661 | .dcache_bsize = 32, | ||
| 1662 | .cpu_setup = __setup_cpu_460sx, | ||
| 1663 | .machine_check = machine_check_440A, | ||
| 1664 | .platform = "ppc440", | ||
| 1665 | }, | ||
| 1637 | { /* default match */ | 1666 | { /* default match */ |
| 1638 | .pvr_mask = 0x00000000, | 1667 | .pvr_mask = 0x00000000, |
| 1639 | .pvr_value = 0x00000000, | 1668 | .pvr_value = 0x00000000, |
| @@ -1687,6 +1716,7 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
| 1687 | PPC_FEATURE_UNIFIED_CACHE, | 1716 | PPC_FEATURE_UNIFIED_CACHE, |
| 1688 | .mmu_features = MMU_FTR_TYPE_FSL_E, | 1717 | .mmu_features = MMU_FTR_TYPE_FSL_E, |
| 1689 | .dcache_bsize = 32, | 1718 | .dcache_bsize = 32, |
| 1719 | .cpu_setup = __setup_cpu_e200, | ||
| 1690 | .machine_check = machine_check_e200, | 1720 | .machine_check = machine_check_e200, |
| 1691 | .platform = "ppc5554", | 1721 | .platform = "ppc5554", |
| 1692 | } | 1722 | } |
| @@ -1706,6 +1736,7 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
| 1706 | .num_pmcs = 4, | 1736 | .num_pmcs = 4, |
| 1707 | .oprofile_cpu_type = "ppc/e500", | 1737 | .oprofile_cpu_type = "ppc/e500", |
| 1708 | .oprofile_type = PPC_OPROFILE_FSL_EMB, | 1738 | .oprofile_type = PPC_OPROFILE_FSL_EMB, |
| 1739 | .cpu_setup = __setup_cpu_e500v1, | ||
| 1709 | .machine_check = machine_check_e500, | 1740 | .machine_check = machine_check_e500, |
| 1710 | .platform = "ppc8540", | 1741 | .platform = "ppc8540", |
| 1711 | }, | 1742 | }, |
| @@ -1724,6 +1755,7 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
| 1724 | .num_pmcs = 4, | 1755 | .num_pmcs = 4, |
| 1725 | .oprofile_cpu_type = "ppc/e500", | 1756 | .oprofile_cpu_type = "ppc/e500", |
| 1726 | .oprofile_type = PPC_OPROFILE_FSL_EMB, | 1757 | .oprofile_type = PPC_OPROFILE_FSL_EMB, |
| 1758 | .cpu_setup = __setup_cpu_e500v2, | ||
| 1727 | .machine_check = machine_check_e500, | 1759 | .machine_check = machine_check_e500, |
| 1728 | .platform = "ppc8548", | 1760 | .platform = "ppc8548", |
| 1729 | }, | 1761 | }, |
| @@ -1733,12 +1765,14 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
| 1733 | .cpu_name = "e500mc", | 1765 | .cpu_name = "e500mc", |
| 1734 | .cpu_features = CPU_FTRS_E500MC, | 1766 | .cpu_features = CPU_FTRS_E500MC, |
| 1735 | .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU, | 1767 | .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU, |
| 1736 | .mmu_features = MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS, | 1768 | .mmu_features = MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS | |
| 1769 | MMU_FTR_USE_TLBILX, | ||
| 1737 | .icache_bsize = 64, | 1770 | .icache_bsize = 64, |
| 1738 | .dcache_bsize = 64, | 1771 | .dcache_bsize = 64, |
| 1739 | .num_pmcs = 4, | 1772 | .num_pmcs = 4, |
| 1740 | .oprofile_cpu_type = "ppc/e500", /* xxx - galak, e500mc? */ | 1773 | .oprofile_cpu_type = "ppc/e500", /* xxx - galak, e500mc? */ |
| 1741 | .oprofile_type = PPC_OPROFILE_FSL_EMB, | 1774 | .oprofile_type = PPC_OPROFILE_FSL_EMB, |
| 1775 | .cpu_setup = __setup_cpu_e500mc, | ||
| 1742 | .machine_check = machine_check_e500, | 1776 | .machine_check = machine_check_e500, |
| 1743 | .platform = "ppce500mc", | 1777 | .platform = "ppce500mc", |
| 1744 | }, | 1778 | }, |
| @@ -1762,74 +1796,84 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
| 1762 | 1796 | ||
| 1763 | static struct cpu_spec the_cpu_spec; | 1797 | static struct cpu_spec the_cpu_spec; |
| 1764 | 1798 | ||
| 1765 | struct cpu_spec * __init identify_cpu(unsigned long offset, unsigned int pvr) | 1799 | static void __init setup_cpu_spec(unsigned long offset, struct cpu_spec *s) |
| 1766 | { | 1800 | { |
| 1767 | struct cpu_spec *s = cpu_specs; | ||
| 1768 | struct cpu_spec *t = &the_cpu_spec; | 1801 | struct cpu_spec *t = &the_cpu_spec; |
| 1769 | int i; | 1802 | struct cpu_spec old; |
| 1770 | 1803 | ||
| 1771 | s = PTRRELOC(s); | ||
| 1772 | t = PTRRELOC(t); | 1804 | t = PTRRELOC(t); |
| 1805 | old = *t; | ||
| 1773 | 1806 | ||
| 1774 | for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++) | 1807 | /* Copy everything, then do fixups */ |
| 1775 | if ((pvr & s->pvr_mask) == s->pvr_value) { | 1808 | *t = *s; |
| 1776 | /* | 1809 | |
| 1777 | * If we are overriding a previous value derived | 1810 | /* |
| 1778 | * from the real PVR with a new value obtained | 1811 | * If we are overriding a previous value derived from the real |
| 1779 | * using a logical PVR value, don't modify the | 1812 | * PVR with a new value obtained using a logical PVR value, |
| 1780 | * performance monitor fields. | 1813 | * don't modify the performance monitor fields. |
| 1781 | */ | 1814 | */ |
| 1782 | if (t->num_pmcs && !s->num_pmcs) { | 1815 | if (old.num_pmcs && !s->num_pmcs) { |
| 1783 | t->cpu_name = s->cpu_name; | 1816 | t->num_pmcs = old.num_pmcs; |
| 1784 | t->cpu_features = s->cpu_features; | 1817 | t->pmc_type = old.pmc_type; |
| 1785 | t->cpu_user_features = s->cpu_user_features; | 1818 | t->oprofile_type = old.oprofile_type; |
| 1786 | t->icache_bsize = s->icache_bsize; | 1819 | t->oprofile_mmcra_sihv = old.oprofile_mmcra_sihv; |
| 1787 | t->dcache_bsize = s->dcache_bsize; | 1820 | t->oprofile_mmcra_sipr = old.oprofile_mmcra_sipr; |
| 1788 | t->cpu_setup = s->cpu_setup; | 1821 | t->oprofile_mmcra_clear = old.oprofile_mmcra_clear; |
| 1789 | t->cpu_restore = s->cpu_restore; | 1822 | |
| 1790 | t->platform = s->platform; | 1823 | /* |
| 1791 | /* | 1824 | * If we have passed through this logic once before and |
| 1792 | * If we have passed through this logic once | 1825 | * have pulled the default case because the real PVR was |
| 1793 | * before and have pulled the default case | 1826 | * not found inside cpu_specs[], then we are possibly |
| 1794 | * because the real PVR was not found inside | 1827 | * running in compatibility mode. In that case, let the |
| 1795 | * cpu_specs[], then we are possibly running in | 1828 | * oprofiler know which set of compatibility counters to |
| 1796 | * compatibility mode. In that case, let the | 1829 | * pull from by making sure the oprofile_cpu_type string |
| 1797 | * oprofiler know which set of compatibility | 1830 | * is set to that of compatibility mode. If the |
| 1798 | * counters to pull from by making sure the | 1831 | * oprofile_cpu_type already has a value, then we are |
| 1799 | * oprofile_cpu_type string is set to that of | 1832 | * possibly overriding a real PVR with a logical one, |
| 1800 | * compatibility mode. If the oprofile_cpu_type | 1833 | * and, in that case, keep the current value for |
| 1801 | * already has a value, then we are possibly | 1834 | * oprofile_cpu_type. |
| 1802 | * overriding a real PVR with a logical one, and, | 1835 | */ |
| 1803 | * in that case, keep the current value for | 1836 | if (old.oprofile_cpu_type == NULL) |
| 1804 | * oprofile_cpu_type. | 1837 | t->oprofile_cpu_type = s->oprofile_cpu_type; |
| 1805 | */ | 1838 | } |
| 1806 | if (t->oprofile_cpu_type == NULL) | ||
| 1807 | t->oprofile_cpu_type = s->oprofile_cpu_type; | ||
| 1808 | } else | ||
| 1809 | *t = *s; | ||
| 1810 | *PTRRELOC(&cur_cpu_spec) = &the_cpu_spec; | ||
| 1811 | 1839 | ||
| 1812 | /* | 1840 | *PTRRELOC(&cur_cpu_spec) = &the_cpu_spec; |
| 1813 | * Set the base platform string once; assumes | 1841 | |
| 1814 | * we're called with real pvr first. | 1842 | /* |
| 1815 | */ | 1843 | * Set the base platform string once; assumes |
| 1816 | if (*PTRRELOC(&powerpc_base_platform) == NULL) | 1844 | * we're called with real pvr first. |
| 1817 | *PTRRELOC(&powerpc_base_platform) = t->platform; | 1845 | */ |
| 1846 | if (*PTRRELOC(&powerpc_base_platform) == NULL) | ||
| 1847 | *PTRRELOC(&powerpc_base_platform) = t->platform; | ||
| 1818 | 1848 | ||
| 1819 | #if defined(CONFIG_PPC64) || defined(CONFIG_BOOKE) | 1849 | #if defined(CONFIG_PPC64) || defined(CONFIG_BOOKE) |
| 1820 | /* ppc64 and booke expect identify_cpu to also call | 1850 | /* ppc64 and booke expect identify_cpu to also call setup_cpu for |
| 1821 | * setup_cpu for that processor. I will consolidate | 1851 | * that processor. I will consolidate that at a later time, for now, |
| 1822 | * that at a later time, for now, just use #ifdef. | 1852 | * just use #ifdef. We also don't need to PTRRELOC the function |
| 1823 | * we also don't need to PTRRELOC the function pointer | 1853 | * pointer on ppc64 and booke as we are running at 0 in real mode |
| 1824 | * on ppc64 and booke as we are running at 0 in real | 1854 | * on ppc64 and reloc_offset is always 0 on booke. |
| 1825 | * mode on ppc64 and reloc_offset is always 0 on booke. | 1855 | */ |
| 1826 | */ | 1856 | if (s->cpu_setup) { |
| 1827 | if (s->cpu_setup) { | 1857 | s->cpu_setup(offset, s); |
| 1828 | s->cpu_setup(offset, s); | 1858 | } |
| 1829 | } | ||
| 1830 | #endif /* CONFIG_PPC64 || CONFIG_BOOKE */ | 1859 | #endif /* CONFIG_PPC64 || CONFIG_BOOKE */ |
| 1860 | } | ||
| 1861 | |||
| 1862 | struct cpu_spec * __init identify_cpu(unsigned long offset, unsigned int pvr) | ||
| 1863 | { | ||
| 1864 | struct cpu_spec *s = cpu_specs; | ||
| 1865 | int i; | ||
| 1866 | |||
| 1867 | s = PTRRELOC(s); | ||
| 1868 | |||
| 1869 | for (i = 0; i < ARRAY_SIZE(cpu_specs); i++,s++) { | ||
| 1870 | if ((pvr & s->pvr_mask) == s->pvr_value) { | ||
| 1871 | setup_cpu_spec(offset, s); | ||
| 1831 | return s; | 1872 | return s; |
| 1832 | } | 1873 | } |
| 1874 | } | ||
| 1875 | |||
| 1833 | BUG(); | 1876 | BUG(); |
| 1877 | |||
| 1834 | return NULL; | 1878 | return NULL; |
| 1835 | } | 1879 | } |
diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c index 19671aca6591..5fb667a60894 100644 --- a/arch/powerpc/kernel/crash_dump.c +++ b/arch/powerpc/kernel/crash_dump.c | |||
| @@ -48,7 +48,7 @@ static void __init create_trampoline(unsigned long addr) | |||
| 48 | * branch to "addr" we jump to ("addr" + 32 MB). Although it requires | 48 | * branch to "addr" we jump to ("addr" + 32 MB). Although it requires |
| 49 | * two instructions it doesn't require any registers. | 49 | * two instructions it doesn't require any registers. |
| 50 | */ | 50 | */ |
| 51 | patch_instruction(p, PPC_NOP_INSTR); | 51 | patch_instruction(p, PPC_INST_NOP); |
| 52 | patch_branch(++p, addr + PHYSICAL_START, 0); | 52 | patch_branch(++p, addr + PHYSICAL_START, 0); |
| 53 | } | 53 | } |
| 54 | 54 | ||
diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c new file mode 100644 index 000000000000..1493734cd871 --- /dev/null +++ b/arch/powerpc/kernel/dbell.c | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | /* | ||
| 2 | * Author: Kumar Gala <galak@kernel.crashing.org> | ||
| 3 | * | ||
| 4 | * Copyright 2009 Freescale Semiconductor Inc. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms of the GNU General Public License as published by the | ||
| 8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
| 9 | * option) any later version. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/stddef.h> | ||
| 13 | #include <linux/kernel.h> | ||
| 14 | #include <linux/smp.h> | ||
| 15 | #include <linux/threads.h> | ||
| 16 | |||
| 17 | #include <asm/dbell.h> | ||
| 18 | |||
| 19 | #ifdef CONFIG_SMP | ||
| 20 | unsigned long dbell_smp_message[NR_CPUS]; | ||
| 21 | |||
| 22 | void smp_dbell_message_pass(int target, int msg) | ||
| 23 | { | ||
| 24 | int i; | ||
| 25 | |||
| 26 | if(target < NR_CPUS) { | ||
| 27 | set_bit(msg, &dbell_smp_message[target]); | ||
| 28 | ppc_msgsnd(PPC_DBELL, 0, target); | ||
| 29 | } | ||
| 30 | else if(target == MSG_ALL_BUT_SELF) { | ||
| 31 | for_each_online_cpu(i) { | ||
| 32 | if (i == smp_processor_id()) | ||
| 33 | continue; | ||
| 34 | set_bit(msg, &dbell_smp_message[i]); | ||
| 35 | ppc_msgsnd(PPC_DBELL, 0, i); | ||
| 36 | } | ||
| 37 | } | ||
| 38 | else { /* target == MSG_ALL */ | ||
| 39 | for_each_online_cpu(i) | ||
| 40 | set_bit(msg, &dbell_smp_message[i]); | ||
| 41 | ppc_msgsnd(PPC_DBELL, PPC_DBELL_MSG_BRDCAST, 0); | ||
| 42 | } | ||
| 43 | } | ||
| 44 | #endif | ||
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 6f7eb7e00c79..4dd38f129153 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S | |||
| @@ -63,7 +63,7 @@ debug_transfer_to_handler: | |||
| 63 | 63 | ||
| 64 | .globl crit_transfer_to_handler | 64 | .globl crit_transfer_to_handler |
| 65 | crit_transfer_to_handler: | 65 | crit_transfer_to_handler: |
| 66 | #ifdef CONFIG_FSL_BOOKE | 66 | #ifdef CONFIG_PPC_BOOK3E_MMU |
| 67 | mfspr r0,SPRN_MAS0 | 67 | mfspr r0,SPRN_MAS0 |
| 68 | stw r0,MAS0(r11) | 68 | stw r0,MAS0(r11) |
| 69 | mfspr r0,SPRN_MAS1 | 69 | mfspr r0,SPRN_MAS1 |
| @@ -78,7 +78,7 @@ crit_transfer_to_handler: | |||
| 78 | mfspr r0,SPRN_MAS7 | 78 | mfspr r0,SPRN_MAS7 |
| 79 | stw r0,MAS7(r11) | 79 | stw r0,MAS7(r11) |
| 80 | #endif /* CONFIG_PHYS_64BIT */ | 80 | #endif /* CONFIG_PHYS_64BIT */ |
| 81 | #endif /* CONFIG_FSL_BOOKE */ | 81 | #endif /* CONFIG_PPC_BOOK3E_MMU */ |
| 82 | #ifdef CONFIG_44x | 82 | #ifdef CONFIG_44x |
| 83 | mfspr r0,SPRN_MMUCR | 83 | mfspr r0,SPRN_MMUCR |
| 84 | stw r0,MMUCR(r11) | 84 | stw r0,MMUCR(r11) |
| @@ -914,7 +914,7 @@ exc_exit_restart_end: | |||
| 914 | mtspr SPRN_##exc_lvl_srr0,r9; \ | 914 | mtspr SPRN_##exc_lvl_srr0,r9; \ |
| 915 | mtspr SPRN_##exc_lvl_srr1,r10; | 915 | mtspr SPRN_##exc_lvl_srr1,r10; |
| 916 | 916 | ||
| 917 | #if defined(CONFIG_FSL_BOOKE) | 917 | #if defined(CONFIG_PPC_BOOK3E_MMU) |
| 918 | #ifdef CONFIG_PHYS_64BIT | 918 | #ifdef CONFIG_PHYS_64BIT |
| 919 | #define RESTORE_MAS7 \ | 919 | #define RESTORE_MAS7 \ |
| 920 | lwz r11,MAS7(r1); \ | 920 | lwz r11,MAS7(r1); \ |
| @@ -956,7 +956,7 @@ ret_from_crit_exc: | |||
| 956 | lwz r10,crit_srr1@l(r10); | 956 | lwz r10,crit_srr1@l(r10); |
| 957 | mtspr SPRN_SRR0,r9; | 957 | mtspr SPRN_SRR0,r9; |
| 958 | mtspr SPRN_SRR1,r10; | 958 | mtspr SPRN_SRR1,r10; |
| 959 | RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, RFCI) | 959 | RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, PPC_RFCI) |
| 960 | #endif /* CONFIG_40x */ | 960 | #endif /* CONFIG_40x */ |
| 961 | 961 | ||
| 962 | #ifdef CONFIG_BOOKE | 962 | #ifdef CONFIG_BOOKE |
| @@ -967,7 +967,7 @@ ret_from_crit_exc: | |||
| 967 | stw r10,KSP_LIMIT(r9) | 967 | stw r10,KSP_LIMIT(r9) |
| 968 | RESTORE_xSRR(SRR0,SRR1); | 968 | RESTORE_xSRR(SRR0,SRR1); |
| 969 | RESTORE_MMU_REGS; | 969 | RESTORE_MMU_REGS; |
| 970 | RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, RFCI) | 970 | RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, PPC_RFCI) |
| 971 | 971 | ||
| 972 | .globl ret_from_debug_exc | 972 | .globl ret_from_debug_exc |
| 973 | ret_from_debug_exc: | 973 | ret_from_debug_exc: |
| @@ -981,7 +981,7 @@ ret_from_debug_exc: | |||
| 981 | RESTORE_xSRR(SRR0,SRR1); | 981 | RESTORE_xSRR(SRR0,SRR1); |
| 982 | RESTORE_xSRR(CSRR0,CSRR1); | 982 | RESTORE_xSRR(CSRR0,CSRR1); |
| 983 | RESTORE_MMU_REGS; | 983 | RESTORE_MMU_REGS; |
| 984 | RET_FROM_EXC_LEVEL(SPRN_DSRR0, SPRN_DSRR1, RFDI) | 984 | RET_FROM_EXC_LEVEL(SPRN_DSRR0, SPRN_DSRR1, PPC_RFDI) |
| 985 | 985 | ||
| 986 | .globl ret_from_mcheck_exc | 986 | .globl ret_from_mcheck_exc |
| 987 | ret_from_mcheck_exc: | 987 | ret_from_mcheck_exc: |
| @@ -992,7 +992,7 @@ ret_from_mcheck_exc: | |||
| 992 | RESTORE_xSRR(CSRR0,CSRR1); | 992 | RESTORE_xSRR(CSRR0,CSRR1); |
| 993 | RESTORE_xSRR(DSRR0,DSRR1); | 993 | RESTORE_xSRR(DSRR0,DSRR1); |
| 994 | RESTORE_MMU_REGS; | 994 | RESTORE_MMU_REGS; |
| 995 | RET_FROM_EXC_LEVEL(SPRN_MCSRR0, SPRN_MCSRR1, RFMCI) | 995 | RET_FROM_EXC_LEVEL(SPRN_MCSRR0, SPRN_MCSRR1, PPC_RFMCI) |
| 996 | #endif /* CONFIG_BOOKE */ | 996 | #endif /* CONFIG_BOOKE */ |
| 997 | 997 | ||
| 998 | /* | 998 | /* |
| @@ -1176,59 +1176,27 @@ _GLOBAL(_mcount) | |||
| 1176 | bctr | 1176 | bctr |
| 1177 | 1177 | ||
| 1178 | _GLOBAL(ftrace_caller) | 1178 | _GLOBAL(ftrace_caller) |
| 1179 | /* Based off of objdump optput from glibc */ | 1179 | MCOUNT_SAVE_FRAME |
| 1180 | stwu r1,-48(r1) | 1180 | /* r3 ends up with link register */ |
| 1181 | stw r3, 12(r1) | ||
| 1182 | stw r4, 16(r1) | ||
| 1183 | stw r5, 20(r1) | ||
| 1184 | stw r6, 24(r1) | ||
| 1185 | mflr r3 | ||
| 1186 | lwz r4, 52(r1) | ||
| 1187 | mfcr r5 | ||
| 1188 | stw r7, 28(r1) | ||
| 1189 | stw r8, 32(r1) | ||
| 1190 | stw r9, 36(r1) | ||
| 1191 | stw r10,40(r1) | ||
| 1192 | stw r3, 44(r1) | ||
| 1193 | stw r5, 8(r1) | ||
| 1194 | subi r3, r3, MCOUNT_INSN_SIZE | 1181 | subi r3, r3, MCOUNT_INSN_SIZE |
| 1195 | .globl ftrace_call | 1182 | .globl ftrace_call |
| 1196 | ftrace_call: | 1183 | ftrace_call: |
| 1197 | bl ftrace_stub | 1184 | bl ftrace_stub |
| 1198 | nop | 1185 | nop |
| 1199 | lwz r6, 8(r1) | 1186 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
| 1200 | lwz r0, 44(r1) | 1187 | .globl ftrace_graph_call |
| 1201 | lwz r3, 12(r1) | 1188 | ftrace_graph_call: |
| 1202 | mtctr r0 | 1189 | b ftrace_graph_stub |
| 1203 | lwz r4, 16(r1) | 1190 | _GLOBAL(ftrace_graph_stub) |
| 1204 | mtcr r6 | 1191 | #endif |
| 1205 | lwz r5, 20(r1) | 1192 | MCOUNT_RESTORE_FRAME |
| 1206 | lwz r6, 24(r1) | 1193 | /* old link register ends up in ctr reg */ |
| 1207 | lwz r0, 52(r1) | ||
| 1208 | lwz r7, 28(r1) | ||
| 1209 | lwz r8, 32(r1) | ||
| 1210 | mtlr r0 | ||
| 1211 | lwz r9, 36(r1) | ||
| 1212 | lwz r10,40(r1) | ||
| 1213 | addi r1, r1, 48 | ||
| 1214 | bctr | 1194 | bctr |
| 1215 | #else | 1195 | #else |
| 1216 | _GLOBAL(mcount) | 1196 | _GLOBAL(mcount) |
| 1217 | _GLOBAL(_mcount) | 1197 | _GLOBAL(_mcount) |
| 1218 | stwu r1,-48(r1) | 1198 | |
| 1219 | stw r3, 12(r1) | 1199 | MCOUNT_SAVE_FRAME |
| 1220 | stw r4, 16(r1) | ||
| 1221 | stw r5, 20(r1) | ||
| 1222 | stw r6, 24(r1) | ||
| 1223 | mflr r3 | ||
| 1224 | lwz r4, 52(r1) | ||
| 1225 | mfcr r5 | ||
| 1226 | stw r7, 28(r1) | ||
| 1227 | stw r8, 32(r1) | ||
| 1228 | stw r9, 36(r1) | ||
| 1229 | stw r10,40(r1) | ||
| 1230 | stw r3, 44(r1) | ||
| 1231 | stw r5, 8(r1) | ||
| 1232 | 1200 | ||
| 1233 | subi r3, r3, MCOUNT_INSN_SIZE | 1201 | subi r3, r3, MCOUNT_INSN_SIZE |
| 1234 | LOAD_REG_ADDR(r5, ftrace_trace_function) | 1202 | LOAD_REG_ADDR(r5, ftrace_trace_function) |
| @@ -1236,28 +1204,55 @@ _GLOBAL(_mcount) | |||
| 1236 | 1204 | ||
| 1237 | mtctr r5 | 1205 | mtctr r5 |
| 1238 | bctrl | 1206 | bctrl |
| 1239 | |||
| 1240 | nop | 1207 | nop |
| 1241 | 1208 | ||
| 1242 | lwz r6, 8(r1) | 1209 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
| 1243 | lwz r0, 44(r1) | 1210 | b ftrace_graph_caller |
| 1244 | lwz r3, 12(r1) | 1211 | #endif |
| 1245 | mtctr r0 | 1212 | MCOUNT_RESTORE_FRAME |
| 1246 | lwz r4, 16(r1) | ||
| 1247 | mtcr r6 | ||
| 1248 | lwz r5, 20(r1) | ||
| 1249 | lwz r6, 24(r1) | ||
| 1250 | lwz r0, 52(r1) | ||
| 1251 | lwz r7, 28(r1) | ||
| 1252 | lwz r8, 32(r1) | ||
| 1253 | mtlr r0 | ||
| 1254 | lwz r9, 36(r1) | ||
| 1255 | lwz r10,40(r1) | ||
| 1256 | addi r1, r1, 48 | ||
| 1257 | bctr | 1213 | bctr |
| 1258 | #endif | 1214 | #endif |
| 1259 | 1215 | ||
| 1260 | _GLOBAL(ftrace_stub) | 1216 | _GLOBAL(ftrace_stub) |
| 1261 | blr | 1217 | blr |
| 1262 | 1218 | ||
| 1219 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
| 1220 | _GLOBAL(ftrace_graph_caller) | ||
| 1221 | /* load r4 with local address */ | ||
| 1222 | lwz r4, 44(r1) | ||
| 1223 | subi r4, r4, MCOUNT_INSN_SIZE | ||
| 1224 | |||
| 1225 | /* get the parent address */ | ||
| 1226 | addi r3, r1, 52 | ||
| 1227 | |||
| 1228 | bl prepare_ftrace_return | ||
| 1229 | nop | ||
| 1230 | |||
| 1231 | MCOUNT_RESTORE_FRAME | ||
| 1232 | /* old link register ends up in ctr reg */ | ||
| 1233 | bctr | ||
| 1234 | |||
| 1235 | _GLOBAL(return_to_handler) | ||
| 1236 | /* need to save return values */ | ||
| 1237 | stwu r1, -32(r1) | ||
| 1238 | stw r3, 20(r1) | ||
| 1239 | stw r4, 16(r1) | ||
| 1240 | stw r31, 12(r1) | ||
| 1241 | mr r31, r1 | ||
| 1242 | |||
| 1243 | bl ftrace_return_to_handler | ||
| 1244 | nop | ||
| 1245 | |||
| 1246 | /* return value has real return address */ | ||
| 1247 | mtlr r3 | ||
| 1248 | |||
| 1249 | lwz r3, 20(r1) | ||
| 1250 | lwz r4, 16(r1) | ||
| 1251 | lwz r31,12(r1) | ||
| 1252 | lwz r1, 0(r1) | ||
| 1253 | |||
| 1254 | /* Jump back to real return address */ | ||
| 1255 | blr | ||
| 1256 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
| 1257 | |||
| 1263 | #endif /* CONFIG_MCOUNT */ | 1258 | #endif /* CONFIG_MCOUNT */ |
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index f30b4e553c53..43e073477c34 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S | |||
| @@ -917,6 +917,12 @@ _GLOBAL(ftrace_caller) | |||
| 917 | ftrace_call: | 917 | ftrace_call: |
| 918 | bl ftrace_stub | 918 | bl ftrace_stub |
| 919 | nop | 919 | nop |
| 920 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
| 921 | .globl ftrace_graph_call | ||
| 922 | ftrace_graph_call: | ||
| 923 | b ftrace_graph_stub | ||
| 924 | _GLOBAL(ftrace_graph_stub) | ||
| 925 | #endif | ||
| 920 | ld r0, 128(r1) | 926 | ld r0, 128(r1) |
| 921 | mtlr r0 | 927 | mtlr r0 |
| 922 | addi r1, r1, 112 | 928 | addi r1, r1, 112 |
| @@ -940,13 +946,90 @@ _GLOBAL(_mcount) | |||
| 940 | ld r5,0(r5) | 946 | ld r5,0(r5) |
| 941 | mtctr r5 | 947 | mtctr r5 |
| 942 | bctrl | 948 | bctrl |
| 943 | |||
| 944 | nop | 949 | nop |
| 950 | |||
| 951 | |||
| 952 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
| 953 | b ftrace_graph_caller | ||
| 954 | #endif | ||
| 945 | ld r0, 128(r1) | 955 | ld r0, 128(r1) |
| 946 | mtlr r0 | 956 | mtlr r0 |
| 947 | addi r1, r1, 112 | 957 | addi r1, r1, 112 |
| 948 | _GLOBAL(ftrace_stub) | 958 | _GLOBAL(ftrace_stub) |
| 949 | blr | 959 | blr |
| 950 | 960 | ||
| 951 | #endif | 961 | #endif /* CONFIG_DYNAMIC_FTRACE */ |
| 952 | #endif | 962 | |
| 963 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
| 964 | _GLOBAL(ftrace_graph_caller) | ||
| 965 | /* load r4 with local address */ | ||
| 966 | ld r4, 128(r1) | ||
| 967 | subi r4, r4, MCOUNT_INSN_SIZE | ||
| 968 | |||
| 969 | /* get the parent address */ | ||
| 970 | ld r11, 112(r1) | ||
| 971 | addi r3, r11, 16 | ||
| 972 | |||
| 973 | bl .prepare_ftrace_return | ||
| 974 | nop | ||
| 975 | |||
| 976 | ld r0, 128(r1) | ||
| 977 | mtlr r0 | ||
| 978 | addi r1, r1, 112 | ||
| 979 | blr | ||
| 980 | |||
| 981 | _GLOBAL(return_to_handler) | ||
| 982 | /* need to save return values */ | ||
| 983 | std r4, -24(r1) | ||
| 984 | std r3, -16(r1) | ||
| 985 | std r31, -8(r1) | ||
| 986 | mr r31, r1 | ||
| 987 | stdu r1, -112(r1) | ||
| 988 | |||
| 989 | bl .ftrace_return_to_handler | ||
| 990 | nop | ||
| 991 | |||
| 992 | /* return value has real return address */ | ||
| 993 | mtlr r3 | ||
| 994 | |||
| 995 | ld r1, 0(r1) | ||
| 996 | ld r4, -24(r1) | ||
| 997 | ld r3, -16(r1) | ||
| 998 | ld r31, -8(r1) | ||
| 999 | |||
| 1000 | /* Jump back to real return address */ | ||
| 1001 | blr | ||
| 1002 | |||
| 1003 | _GLOBAL(mod_return_to_handler) | ||
| 1004 | /* need to save return values */ | ||
| 1005 | std r4, -32(r1) | ||
| 1006 | std r3, -24(r1) | ||
| 1007 | /* save TOC */ | ||
| 1008 | std r2, -16(r1) | ||
| 1009 | std r31, -8(r1) | ||
| 1010 | mr r31, r1 | ||
| 1011 | stdu r1, -112(r1) | ||
| 1012 | |||
| 1013 | /* | ||
| 1014 | * We are in a module using the module's TOC. | ||
| 1015 | * Switch to our TOC to run inside the core kernel. | ||
| 1016 | */ | ||
| 1017 | LOAD_REG_IMMEDIATE(r4,ftrace_return_to_handler) | ||
| 1018 | ld r2, 8(r4) | ||
| 1019 | |||
| 1020 | bl .ftrace_return_to_handler | ||
| 1021 | nop | ||
| 1022 | |||
| 1023 | /* return value has real return address */ | ||
| 1024 | mtlr r3 | ||
| 1025 | |||
| 1026 | ld r1, 0(r1) | ||
| 1027 | ld r4, -32(r1) | ||
| 1028 | ld r3, -24(r1) | ||
| 1029 | ld r2, -16(r1) | ||
| 1030 | ld r31, -8(r1) | ||
| 1031 | |||
| 1032 | /* Jump back to real return address */ | ||
| 1033 | blr | ||
| 1034 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
| 1035 | #endif /* CONFIG_FUNCTION_TRACER */ | ||
diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c index 60c60ccf5e3c..5455943f16aa 100644 --- a/arch/powerpc/kernel/ftrace.c +++ b/arch/powerpc/kernel/ftrace.c | |||
| @@ -5,6 +5,9 @@ | |||
| 5 | * | 5 | * |
| 6 | * Thanks goes out to P.A. Semi, Inc for supplying me with a PPC64 box. | 6 | * Thanks goes out to P.A. Semi, Inc for supplying me with a PPC64 box. |
| 7 | * | 7 | * |
| 8 | * Added function graph tracer code, taken from x86 that was written | ||
| 9 | * by Frederic Weisbecker, and ported to PPC by Steven Rostedt. | ||
| 10 | * | ||
| 8 | */ | 11 | */ |
| 9 | 12 | ||
| 10 | #include <linux/spinlock.h> | 13 | #include <linux/spinlock.h> |
| @@ -20,14 +23,6 @@ | |||
| 20 | #include <asm/code-patching.h> | 23 | #include <asm/code-patching.h> |
| 21 | #include <asm/ftrace.h> | 24 | #include <asm/ftrace.h> |
| 22 | 25 | ||
| 23 | #if 0 | ||
| 24 | #define DEBUGP printk | ||
| 25 | #else | ||
| 26 | #define DEBUGP(fmt , ...) do { } while (0) | ||
| 27 | #endif | ||
| 28 | |||
| 29 | static unsigned int ftrace_nop = PPC_NOP_INSTR; | ||
| 30 | |||
| 31 | #ifdef CONFIG_PPC32 | 26 | #ifdef CONFIG_PPC32 |
| 32 | # define GET_ADDR(addr) addr | 27 | # define GET_ADDR(addr) addr |
| 33 | #else | 28 | #else |
| @@ -35,37 +30,23 @@ static unsigned int ftrace_nop = PPC_NOP_INSTR; | |||
| 35 | # define GET_ADDR(addr) (*(unsigned long *)addr) | 30 | # define GET_ADDR(addr) (*(unsigned long *)addr) |
| 36 | #endif | 31 | #endif |
| 37 | 32 | ||
| 38 | 33 | #ifdef CONFIG_DYNAMIC_FTRACE | |
| 39 | static unsigned int ftrace_calc_offset(long ip, long addr) | 34 | static unsigned int ftrace_nop_replace(void) |
| 40 | { | 35 | { |
| 41 | return (int)(addr - ip); | 36 | return PPC_INST_NOP; |
| 42 | } | 37 | } |
| 43 | 38 | ||
| 44 | static unsigned char *ftrace_nop_replace(void) | 39 | static unsigned int |
| 40 | ftrace_call_replace(unsigned long ip, unsigned long addr, int link) | ||
| 45 | { | 41 | { |
| 46 | return (char *)&ftrace_nop; | 42 | unsigned int op; |
| 47 | } | ||
| 48 | |||
| 49 | static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) | ||
| 50 | { | ||
| 51 | static unsigned int op; | ||
| 52 | 43 | ||
| 53 | /* | ||
| 54 | * It would be nice to just use create_function_call, but that will | ||
| 55 | * update the code itself. Here we need to just return the | ||
| 56 | * instruction that is going to be modified, without modifying the | ||
| 57 | * code. | ||
| 58 | */ | ||
| 59 | addr = GET_ADDR(addr); | 44 | addr = GET_ADDR(addr); |
| 60 | 45 | ||
| 61 | /* Set to "bl addr" */ | 46 | /* if (link) set op to 'bl' else 'b' */ |
| 62 | op = 0x48000001 | (ftrace_calc_offset(ip, addr) & 0x03fffffc); | 47 | op = create_branch((unsigned int *)ip, addr, link ? 1 : 0); |
| 63 | 48 | ||
| 64 | /* | 49 | return op; |
| 65 | * No locking needed, this must be called via kstop_machine | ||
| 66 | * which in essence is like running on a uniprocessor machine. | ||
| 67 | */ | ||
| 68 | return (unsigned char *)&op; | ||
| 69 | } | 50 | } |
| 70 | 51 | ||
| 71 | #ifdef CONFIG_PPC64 | 52 | #ifdef CONFIG_PPC64 |
| @@ -77,10 +58,9 @@ static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) | |||
| 77 | #endif | 58 | #endif |
| 78 | 59 | ||
| 79 | static int | 60 | static int |
| 80 | ftrace_modify_code(unsigned long ip, unsigned char *old_code, | 61 | ftrace_modify_code(unsigned long ip, unsigned int old, unsigned int new) |
| 81 | unsigned char *new_code) | ||
| 82 | { | 62 | { |
| 83 | unsigned char replaced[MCOUNT_INSN_SIZE]; | 63 | unsigned int replaced; |
| 84 | 64 | ||
| 85 | /* | 65 | /* |
| 86 | * Note: Due to modules and __init, code can | 66 | * Note: Due to modules and __init, code can |
| @@ -93,15 +73,15 @@ ftrace_modify_code(unsigned long ip, unsigned char *old_code, | |||
| 93 | */ | 73 | */ |
| 94 | 74 | ||
| 95 | /* read the text we want to modify */ | 75 | /* read the text we want to modify */ |
| 96 | if (probe_kernel_read(replaced, (void *)ip, MCOUNT_INSN_SIZE)) | 76 | if (probe_kernel_read(&replaced, (void *)ip, MCOUNT_INSN_SIZE)) |
| 97 | return -EFAULT; | 77 | return -EFAULT; |
| 98 | 78 | ||
| 99 | /* Make sure it is what we expect it to be */ | 79 | /* Make sure it is what we expect it to be */ |
| 100 | if (memcmp(replaced, old_code, MCOUNT_INSN_SIZE) != 0) | 80 | if (replaced != old) |
| 101 | return -EINVAL; | 81 | return -EINVAL; |
| 102 | 82 | ||
| 103 | /* replace the text with the new text */ | 83 | /* replace the text with the new text */ |
| 104 | if (probe_kernel_write((void *)ip, new_code, MCOUNT_INSN_SIZE)) | 84 | if (probe_kernel_write((void *)ip, &new, MCOUNT_INSN_SIZE)) |
| 105 | return -EPERM; | 85 | return -EPERM; |
| 106 | 86 | ||
| 107 | flush_icache_range(ip, ip + 8); | 87 | flush_icache_range(ip, ip + 8); |
| @@ -119,6 +99,8 @@ static int test_24bit_addr(unsigned long ip, unsigned long addr) | |||
| 119 | return create_branch((unsigned int *)ip, addr, 0); | 99 | return create_branch((unsigned int *)ip, addr, 0); |
| 120 | } | 100 | } |
| 121 | 101 | ||
| 102 | #ifdef CONFIG_MODULES | ||
| 103 | |||
| 122 | static int is_bl_op(unsigned int op) | 104 | static int is_bl_op(unsigned int op) |
| 123 | { | 105 | { |
| 124 | return (op & 0xfc000003) == 0x48000001; | 106 | return (op & 0xfc000003) == 0x48000001; |
| @@ -175,7 +157,7 @@ __ftrace_make_nop(struct module *mod, | |||
| 175 | * 0xe8, 0x4c, 0x00, 0x28, ld r2,40(r12) | 157 | * 0xe8, 0x4c, 0x00, 0x28, ld r2,40(r12) |
| 176 | */ | 158 | */ |
| 177 | 159 | ||
| 178 | DEBUGP("ip:%lx jumps to %lx r2: %lx", ip, tramp, mod->arch.toc); | 160 | pr_debug("ip:%lx jumps to %lx r2: %lx", ip, tramp, mod->arch.toc); |
| 179 | 161 | ||
| 180 | /* Find where the trampoline jumps to */ | 162 | /* Find where the trampoline jumps to */ |
| 181 | if (probe_kernel_read(jmp, (void *)tramp, sizeof(jmp))) { | 163 | if (probe_kernel_read(jmp, (void *)tramp, sizeof(jmp))) { |
| @@ -183,7 +165,7 @@ __ftrace_make_nop(struct module *mod, | |||
| 183 | return -EFAULT; | 165 | return -EFAULT; |
| 184 | } | 166 | } |
| 185 | 167 | ||
| 186 | DEBUGP(" %08x %08x", jmp[0], jmp[1]); | 168 | pr_debug(" %08x %08x", jmp[0], jmp[1]); |
| 187 | 169 | ||
| 188 | /* verify that this is what we expect it to be */ | 170 | /* verify that this is what we expect it to be */ |
| 189 | if (((jmp[0] & 0xffff0000) != 0x3d820000) || | 171 | if (((jmp[0] & 0xffff0000) != 0x3d820000) || |
| @@ -199,18 +181,18 @@ __ftrace_make_nop(struct module *mod, | |||
| 199 | offset = ((unsigned)((unsigned short)jmp[0]) << 16) + | 181 | offset = ((unsigned)((unsigned short)jmp[0]) << 16) + |
| 200 | (int)((short)jmp[1]); | 182 | (int)((short)jmp[1]); |
| 201 | 183 | ||
| 202 | DEBUGP(" %x ", offset); | 184 | pr_debug(" %x ", offset); |
| 203 | 185 | ||
| 204 | /* get the address this jumps too */ | 186 | /* get the address this jumps too */ |
| 205 | tramp = mod->arch.toc + offset + 32; | 187 | tramp = mod->arch.toc + offset + 32; |
| 206 | DEBUGP("toc: %lx", tramp); | 188 | pr_debug("toc: %lx", tramp); |
| 207 | 189 | ||
| 208 | if (probe_kernel_read(jmp, (void *)tramp, 8)) { | 190 | if (probe_kernel_read(jmp, (void *)tramp, 8)) { |
| 209 | printk(KERN_ERR "Failed to read %lx\n", tramp); | 191 | printk(KERN_ERR "Failed to read %lx\n", tramp); |
| 210 | return -EFAULT; | 192 | return -EFAULT; |
| 211 | } | 193 | } |
| 212 | 194 | ||
| 213 | DEBUGP(" %08x %08x\n", jmp[0], jmp[1]); | 195 | pr_debug(" %08x %08x\n", jmp[0], jmp[1]); |
| 214 | 196 | ||
| 215 | ptr = ((unsigned long)jmp[0] << 32) + jmp[1]; | 197 | ptr = ((unsigned long)jmp[0] << 32) + jmp[1]; |
| 216 | 198 | ||
| @@ -287,7 +269,7 @@ __ftrace_make_nop(struct module *mod, | |||
| 287 | * 0x4e, 0x80, 0x04, 0x20 bctr | 269 | * 0x4e, 0x80, 0x04, 0x20 bctr |
| 288 | */ | 270 | */ |
| 289 | 271 | ||
| 290 | DEBUGP("ip:%lx jumps to %lx", ip, tramp); | 272 | pr_debug("ip:%lx jumps to %lx", ip, tramp); |
| 291 | 273 | ||
| 292 | /* Find where the trampoline jumps to */ | 274 | /* Find where the trampoline jumps to */ |
| 293 | if (probe_kernel_read(jmp, (void *)tramp, sizeof(jmp))) { | 275 | if (probe_kernel_read(jmp, (void *)tramp, sizeof(jmp))) { |
| @@ -295,7 +277,7 @@ __ftrace_make_nop(struct module *mod, | |||
| 295 | return -EFAULT; | 277 | return -EFAULT; |
| 296 | } | 278 | } |
| 297 | 279 | ||
| 298 | DEBUGP(" %08x %08x ", jmp[0], jmp[1]); | 280 | pr_debug(" %08x %08x ", jmp[0], jmp[1]); |
| 299 | 281 | ||
| 300 | /* verify that this is what we expect it to be */ | 282 | /* verify that this is what we expect it to be */ |
| 301 | if (((jmp[0] & 0xffff0000) != 0x3d600000) || | 283 | if (((jmp[0] & 0xffff0000) != 0x3d600000) || |
| @@ -311,7 +293,7 @@ __ftrace_make_nop(struct module *mod, | |||
| 311 | if (tramp & 0x8000) | 293 | if (tramp & 0x8000) |
| 312 | tramp -= 0x10000; | 294 | tramp -= 0x10000; |
| 313 | 295 | ||
| 314 | DEBUGP(" %x ", tramp); | 296 | pr_debug(" %x ", tramp); |
| 315 | 297 | ||
| 316 | if (tramp != addr) { | 298 | if (tramp != addr) { |
| 317 | printk(KERN_ERR | 299 | printk(KERN_ERR |
| @@ -320,7 +302,7 @@ __ftrace_make_nop(struct module *mod, | |||
| 320 | return -EINVAL; | 302 | return -EINVAL; |
| 321 | } | 303 | } |
| 322 | 304 | ||
| 323 | op = PPC_NOP_INSTR; | 305 | op = PPC_INST_NOP; |
| 324 | 306 | ||
| 325 | if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE)) | 307 | if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE)) |
| 326 | return -EPERM; | 308 | return -EPERM; |
| @@ -330,12 +312,13 @@ __ftrace_make_nop(struct module *mod, | |||
| 330 | return 0; | 312 | return 0; |
| 331 | } | 313 | } |
| 332 | #endif /* PPC64 */ | 314 | #endif /* PPC64 */ |
| 315 | #endif /* CONFIG_MODULES */ | ||
| 333 | 316 | ||
| 334 | int ftrace_make_nop(struct module *mod, | 317 | int ftrace_make_nop(struct module *mod, |
| 335 | struct dyn_ftrace *rec, unsigned long addr) | 318 | struct dyn_ftrace *rec, unsigned long addr) |
| 336 | { | 319 | { |
| 337 | unsigned char *old, *new; | ||
| 338 | unsigned long ip = rec->ip; | 320 | unsigned long ip = rec->ip; |
| 321 | unsigned int old, new; | ||
| 339 | 322 | ||
| 340 | /* | 323 | /* |
| 341 | * If the calling address is more that 24 bits away, | 324 | * If the calling address is more that 24 bits away, |
| @@ -344,11 +327,12 @@ int ftrace_make_nop(struct module *mod, | |||
| 344 | */ | 327 | */ |
| 345 | if (test_24bit_addr(ip, addr)) { | 328 | if (test_24bit_addr(ip, addr)) { |
| 346 | /* within range */ | 329 | /* within range */ |
| 347 | old = ftrace_call_replace(ip, addr); | 330 | old = ftrace_call_replace(ip, addr, 1); |
| 348 | new = ftrace_nop_replace(); | 331 | new = ftrace_nop_replace(); |
| 349 | return ftrace_modify_code(ip, old, new); | 332 | return ftrace_modify_code(ip, old, new); |
| 350 | } | 333 | } |
| 351 | 334 | ||
| 335 | #ifdef CONFIG_MODULES | ||
| 352 | /* | 336 | /* |
| 353 | * Out of range jumps are called from modules. | 337 | * Out of range jumps are called from modules. |
| 354 | * We should either already have a pointer to the module | 338 | * We should either already have a pointer to the module |
| @@ -373,9 +357,13 @@ int ftrace_make_nop(struct module *mod, | |||
| 373 | mod = rec->arch.mod; | 357 | mod = rec->arch.mod; |
| 374 | 358 | ||
| 375 | return __ftrace_make_nop(mod, rec, addr); | 359 | return __ftrace_make_nop(mod, rec, addr); |
| 376 | 360 | #else | |
| 361 | /* We should not get here without modules */ | ||
| 362 | return -EINVAL; | ||
| 363 | #endif /* CONFIG_MODULES */ | ||
| 377 | } | 364 | } |
| 378 | 365 | ||
| 366 | #ifdef CONFIG_MODULES | ||
| 379 | #ifdef CONFIG_PPC64 | 367 | #ifdef CONFIG_PPC64 |
| 380 | static int | 368 | static int |
| 381 | __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | 369 | __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) |
| @@ -392,7 +380,7 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | |||
| 392 | * b +8; ld r2,40(r1) | 380 | * b +8; ld r2,40(r1) |
| 393 | */ | 381 | */ |
| 394 | if (((op[0] != 0x48000008) || (op[1] != 0xe8410028)) && | 382 | if (((op[0] != 0x48000008) || (op[1] != 0xe8410028)) && |
| 395 | ((op[0] != PPC_NOP_INSTR) || (op[1] != PPC_NOP_INSTR))) { | 383 | ((op[0] != PPC_INST_NOP) || (op[1] != PPC_INST_NOP))) { |
| 396 | printk(KERN_ERR "Expected NOPs but have %x %x\n", op[0], op[1]); | 384 | printk(KERN_ERR "Expected NOPs but have %x %x\n", op[0], op[1]); |
| 397 | return -EINVAL; | 385 | return -EINVAL; |
| 398 | } | 386 | } |
| @@ -414,7 +402,7 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | |||
| 414 | /* ld r2,40(r1) */ | 402 | /* ld r2,40(r1) */ |
| 415 | op[1] = 0xe8410028; | 403 | op[1] = 0xe8410028; |
| 416 | 404 | ||
| 417 | DEBUGP("write to %lx\n", rec->ip); | 405 | pr_debug("write to %lx\n", rec->ip); |
| 418 | 406 | ||
| 419 | if (probe_kernel_write((void *)ip, op, MCOUNT_INSN_SIZE * 2)) | 407 | if (probe_kernel_write((void *)ip, op, MCOUNT_INSN_SIZE * 2)) |
| 420 | return -EPERM; | 408 | return -EPERM; |
| @@ -435,7 +423,7 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | |||
| 435 | return -EFAULT; | 423 | return -EFAULT; |
| 436 | 424 | ||
| 437 | /* It should be pointing to a nop */ | 425 | /* It should be pointing to a nop */ |
| 438 | if (op != PPC_NOP_INSTR) { | 426 | if (op != PPC_INST_NOP) { |
| 439 | printk(KERN_ERR "Expected NOP but have %x\n", op); | 427 | printk(KERN_ERR "Expected NOP but have %x\n", op); |
| 440 | return -EINVAL; | 428 | return -EINVAL; |
| 441 | } | 429 | } |
| @@ -454,7 +442,7 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | |||
| 454 | return -EINVAL; | 442 | return -EINVAL; |
| 455 | } | 443 | } |
| 456 | 444 | ||
| 457 | DEBUGP("write to %lx\n", rec->ip); | 445 | pr_debug("write to %lx\n", rec->ip); |
| 458 | 446 | ||
| 459 | if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE)) | 447 | if (probe_kernel_write((void *)ip, &op, MCOUNT_INSN_SIZE)) |
| 460 | return -EPERM; | 448 | return -EPERM; |
| @@ -464,11 +452,12 @@ __ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | |||
| 464 | return 0; | 452 | return 0; |
| 465 | } | 453 | } |
| 466 | #endif /* CONFIG_PPC64 */ | 454 | #endif /* CONFIG_PPC64 */ |
| 455 | #endif /* CONFIG_MODULES */ | ||
| 467 | 456 | ||
| 468 | int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | 457 | int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) |
| 469 | { | 458 | { |
| 470 | unsigned char *old, *new; | ||
| 471 | unsigned long ip = rec->ip; | 459 | unsigned long ip = rec->ip; |
| 460 | unsigned int old, new; | ||
| 472 | 461 | ||
| 473 | /* | 462 | /* |
| 474 | * If the calling address is more that 24 bits away, | 463 | * If the calling address is more that 24 bits away, |
| @@ -478,10 +467,11 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | |||
| 478 | if (test_24bit_addr(ip, addr)) { | 467 | if (test_24bit_addr(ip, addr)) { |
| 479 | /* within range */ | 468 | /* within range */ |
| 480 | old = ftrace_nop_replace(); | 469 | old = ftrace_nop_replace(); |
| 481 | new = ftrace_call_replace(ip, addr); | 470 | new = ftrace_call_replace(ip, addr, 1); |
| 482 | return ftrace_modify_code(ip, old, new); | 471 | return ftrace_modify_code(ip, old, new); |
| 483 | } | 472 | } |
| 484 | 473 | ||
| 474 | #ifdef CONFIG_MODULES | ||
| 485 | /* | 475 | /* |
| 486 | * Out of range jumps are called from modules. | 476 | * Out of range jumps are called from modules. |
| 487 | * Being that we are converting from nop, it had better | 477 | * Being that we are converting from nop, it had better |
| @@ -493,16 +483,20 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | |||
| 493 | } | 483 | } |
| 494 | 484 | ||
| 495 | return __ftrace_make_call(rec, addr); | 485 | return __ftrace_make_call(rec, addr); |
| 486 | #else | ||
| 487 | /* We should not get here without modules */ | ||
| 488 | return -EINVAL; | ||
| 489 | #endif /* CONFIG_MODULES */ | ||
| 496 | } | 490 | } |
| 497 | 491 | ||
| 498 | int ftrace_update_ftrace_func(ftrace_func_t func) | 492 | int ftrace_update_ftrace_func(ftrace_func_t func) |
| 499 | { | 493 | { |
| 500 | unsigned long ip = (unsigned long)(&ftrace_call); | 494 | unsigned long ip = (unsigned long)(&ftrace_call); |
| 501 | unsigned char old[MCOUNT_INSN_SIZE], *new; | 495 | unsigned int old, new; |
| 502 | int ret; | 496 | int ret; |
| 503 | 497 | ||
| 504 | memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE); | 498 | old = *(unsigned int *)&ftrace_call; |
| 505 | new = ftrace_call_replace(ip, (unsigned long)func); | 499 | new = ftrace_call_replace(ip, (unsigned long)func, 1); |
| 506 | ret = ftrace_modify_code(ip, old, new); | 500 | ret = ftrace_modify_code(ip, old, new); |
| 507 | 501 | ||
| 508 | return ret; | 502 | return ret; |
| @@ -517,3 +511,111 @@ int __init ftrace_dyn_arch_init(void *data) | |||
| 517 | 511 | ||
| 518 | return 0; | 512 | return 0; |
| 519 | } | 513 | } |
| 514 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
| 515 | |||
| 516 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
| 517 | |||
| 518 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
| 519 | extern void ftrace_graph_call(void); | ||
| 520 | extern void ftrace_graph_stub(void); | ||
| 521 | |||
| 522 | int ftrace_enable_ftrace_graph_caller(void) | ||
| 523 | { | ||
| 524 | unsigned long ip = (unsigned long)(&ftrace_graph_call); | ||
| 525 | unsigned long addr = (unsigned long)(&ftrace_graph_caller); | ||
| 526 | unsigned long stub = (unsigned long)(&ftrace_graph_stub); | ||
| 527 | unsigned int old, new; | ||
| 528 | |||
| 529 | old = ftrace_call_replace(ip, stub, 0); | ||
| 530 | new = ftrace_call_replace(ip, addr, 0); | ||
| 531 | |||
| 532 | return ftrace_modify_code(ip, old, new); | ||
| 533 | } | ||
| 534 | |||
| 535 | int ftrace_disable_ftrace_graph_caller(void) | ||
| 536 | { | ||
| 537 | unsigned long ip = (unsigned long)(&ftrace_graph_call); | ||
| 538 | unsigned long addr = (unsigned long)(&ftrace_graph_caller); | ||
| 539 | unsigned long stub = (unsigned long)(&ftrace_graph_stub); | ||
| 540 | unsigned int old, new; | ||
| 541 | |||
| 542 | old = ftrace_call_replace(ip, addr, 0); | ||
| 543 | new = ftrace_call_replace(ip, stub, 0); | ||
| 544 | |||
| 545 | return ftrace_modify_code(ip, old, new); | ||
| 546 | } | ||
| 547 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
| 548 | |||
| 549 | #ifdef CONFIG_PPC64 | ||
| 550 | extern void mod_return_to_handler(void); | ||
| 551 | #endif | ||
| 552 | |||
| 553 | /* | ||
| 554 | * Hook the return address and push it in the stack of return addrs | ||
| 555 | * in current thread info. | ||
| 556 | */ | ||
| 557 | void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) | ||
| 558 | { | ||
| 559 | unsigned long old; | ||
| 560 | int faulted; | ||
| 561 | struct ftrace_graph_ent trace; | ||
| 562 | unsigned long return_hooker = (unsigned long)&return_to_handler; | ||
| 563 | |||
| 564 | if (unlikely(atomic_read(¤t->tracing_graph_pause))) | ||
| 565 | return; | ||
| 566 | |||
| 567 | #if CONFIG_PPC64 | ||
| 568 | /* non core kernel code needs to save and restore the TOC */ | ||
| 569 | if (REGION_ID(self_addr) != KERNEL_REGION_ID) | ||
| 570 | return_hooker = (unsigned long)&mod_return_to_handler; | ||
| 571 | #endif | ||
| 572 | |||
| 573 | return_hooker = GET_ADDR(return_hooker); | ||
| 574 | |||
| 575 | /* | ||
| 576 | * Protect against fault, even if it shouldn't | ||
| 577 | * happen. This tool is too much intrusive to | ||
| 578 | * ignore such a protection. | ||
| 579 | */ | ||
| 580 | asm volatile( | ||
| 581 | "1: " PPC_LL "%[old], 0(%[parent])\n" | ||
| 582 | "2: " PPC_STL "%[return_hooker], 0(%[parent])\n" | ||
| 583 | " li %[faulted], 0\n" | ||
| 584 | "3:\n" | ||
| 585 | |||
| 586 | ".section .fixup, \"ax\"\n" | ||
| 587 | "4: li %[faulted], 1\n" | ||
| 588 | " b 3b\n" | ||
| 589 | ".previous\n" | ||
| 590 | |||
| 591 | ".section __ex_table,\"a\"\n" | ||
| 592 | PPC_LONG_ALIGN "\n" | ||
| 593 | PPC_LONG "1b,4b\n" | ||
| 594 | PPC_LONG "2b,4b\n" | ||
| 595 | ".previous" | ||
| 596 | |||
| 597 | : [old] "=r" (old), [faulted] "=r" (faulted) | ||
| 598 | : [parent] "r" (parent), [return_hooker] "r" (return_hooker) | ||
| 599 | : "memory" | ||
| 600 | ); | ||
| 601 | |||
| 602 | if (unlikely(faulted)) { | ||
| 603 | ftrace_graph_stop(); | ||
| 604 | WARN_ON(1); | ||
| 605 | return; | ||
| 606 | } | ||
| 607 | |||
| 608 | if (ftrace_push_return_trace(old, self_addr, &trace.depth) == -EBUSY) { | ||
| 609 | *parent = old; | ||
| 610 | return; | ||
| 611 | } | ||
| 612 | |||
| 613 | trace.func = self_addr; | ||
| 614 | |||
| 615 | /* Only trace if the calling function expects to */ | ||
| 616 | if (!ftrace_graph_entry(&trace)) { | ||
| 617 | current->curr_ret_stack--; | ||
| 618 | *parent = old; | ||
| 619 | } | ||
| 620 | } | ||
| 621 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index a1c4cfd25ded..54e68c11ae15 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S | |||
| @@ -108,18 +108,21 @@ __start: | |||
| 108 | * because OF may have I/O devices mapped into that area | 108 | * because OF may have I/O devices mapped into that area |
| 109 | * (particularly on CHRP). | 109 | * (particularly on CHRP). |
| 110 | */ | 110 | */ |
| 111 | #ifdef CONFIG_PPC_MULTIPLATFORM | ||
| 112 | cmpwi 0,r5,0 | 111 | cmpwi 0,r5,0 |
| 113 | beq 1f | 112 | beq 1f |
| 114 | 113 | ||
| 114 | #ifdef CONFIG_PPC_OF_BOOT_TRAMPOLINE | ||
| 115 | /* find out where we are now */ | 115 | /* find out where we are now */ |
| 116 | bcl 20,31,$+4 | 116 | bcl 20,31,$+4 |
| 117 | 0: mflr r8 /* r8 = runtime addr here */ | 117 | 0: mflr r8 /* r8 = runtime addr here */ |
| 118 | addis r8,r8,(_stext - 0b)@ha | 118 | addis r8,r8,(_stext - 0b)@ha |
| 119 | addi r8,r8,(_stext - 0b)@l /* current runtime base addr */ | 119 | addi r8,r8,(_stext - 0b)@l /* current runtime base addr */ |
| 120 | bl prom_init | 120 | bl prom_init |
| 121 | #endif /* CONFIG_PPC_OF_BOOT_TRAMPOLINE */ | ||
| 122 | |||
| 123 | /* We never return. We also hit that trap if trying to boot | ||
| 124 | * from OF while CONFIG_PPC_OF_BOOT_TRAMPOLINE isn't selected */ | ||
| 121 | trap | 125 | trap |
| 122 | #endif | ||
| 123 | 126 | ||
| 124 | /* | 127 | /* |
| 125 | * Check for BootX signature when supporting PowerMac and branch to | 128 | * Check for BootX signature when supporting PowerMac and branch to |
| @@ -472,12 +475,11 @@ SystemCall: | |||
| 472 | . = 0x1000 | 475 | . = 0x1000 |
| 473 | InstructionTLBMiss: | 476 | InstructionTLBMiss: |
| 474 | /* | 477 | /* |
| 475 | * r0: stored ctr | 478 | * r0: scratch |
| 476 | * r1: linux style pte ( later becomes ppc hardware pte ) | 479 | * r1: linux style pte ( later becomes ppc hardware pte ) |
| 477 | * r2: ptr to linux-style pte | 480 | * r2: ptr to linux-style pte |
| 478 | * r3: scratch | 481 | * r3: scratch |
| 479 | */ | 482 | */ |
| 480 | mfctr r0 | ||
| 481 | /* Get PTE (linux-style) and check access */ | 483 | /* Get PTE (linux-style) and check access */ |
| 482 | mfspr r3,SPRN_IMISS | 484 | mfspr r3,SPRN_IMISS |
| 483 | lis r1,PAGE_OFFSET@h /* check if kernel address */ | 485 | lis r1,PAGE_OFFSET@h /* check if kernel address */ |
| @@ -496,25 +498,27 @@ InstructionTLBMiss: | |||
| 496 | rlwinm. r2,r2,0,0,19 /* extract address of pte page */ | 498 | rlwinm. r2,r2,0,0,19 /* extract address of pte page */ |
| 497 | beq- InstructionAddressInvalid /* return if no mapping */ | 499 | beq- InstructionAddressInvalid /* return if no mapping */ |
| 498 | rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ | 500 | rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ |
| 499 | lwz r3,0(r2) /* get linux-style pte */ | 501 | lwz r0,0(r2) /* get linux-style pte */ |
| 500 | andc. r1,r1,r3 /* check access & ~permission */ | 502 | andc. r1,r1,r0 /* check access & ~permission */ |
| 501 | bne- InstructionAddressInvalid /* return if access not permitted */ | 503 | bne- InstructionAddressInvalid /* return if access not permitted */ |
| 502 | ori r3,r3,_PAGE_ACCESSED /* set _PAGE_ACCESSED in pte */ | 504 | ori r0,r0,_PAGE_ACCESSED /* set _PAGE_ACCESSED in pte */ |
| 503 | /* | 505 | /* |
| 504 | * NOTE! We are assuming this is not an SMP system, otherwise | 506 | * NOTE! We are assuming this is not an SMP system, otherwise |
| 505 | * we would need to update the pte atomically with lwarx/stwcx. | 507 | * we would need to update the pte atomically with lwarx/stwcx. |
| 506 | */ | 508 | */ |
| 507 | stw r3,0(r2) /* update PTE (accessed bit) */ | 509 | stw r0,0(r2) /* update PTE (accessed bit) */ |
| 508 | /* Convert linux-style PTE to low word of PPC-style PTE */ | 510 | /* Convert linux-style PTE to low word of PPC-style PTE */ |
| 509 | rlwinm r1,r3,32-10,31,31 /* _PAGE_RW -> PP lsb */ | 511 | rlwinm r1,r0,32-10,31,31 /* _PAGE_RW -> PP lsb */ |
| 510 | rlwinm r2,r3,32-7,31,31 /* _PAGE_DIRTY -> PP lsb */ | 512 | rlwinm r2,r0,32-7,31,31 /* _PAGE_DIRTY -> PP lsb */ |
| 511 | and r1,r1,r2 /* writable if _RW and _DIRTY */ | 513 | and r1,r1,r2 /* writable if _RW and _DIRTY */ |
| 512 | rlwimi r3,r3,32-1,30,30 /* _PAGE_USER -> PP msb */ | 514 | rlwimi r0,r0,32-1,30,30 /* _PAGE_USER -> PP msb */ |
| 513 | rlwimi r3,r3,32-1,31,31 /* _PAGE_USER -> PP lsb */ | 515 | rlwimi r0,r0,32-1,31,31 /* _PAGE_USER -> PP lsb */ |
| 514 | ori r1,r1,0xe14 /* clear out reserved bits and M */ | 516 | ori r1,r1,0xe04 /* clear out reserved bits */ |
| 515 | andc r1,r3,r1 /* PP = user? (rw&dirty? 2: 3): 0 */ | 517 | andc r1,r0,r1 /* PP = user? (rw&dirty? 2: 3): 0 */ |
| 518 | BEGIN_FTR_SECTION | ||
| 519 | rlwinm r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */ | ||
| 520 | END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT) | ||
| 516 | mtspr SPRN_RPA,r1 | 521 | mtspr SPRN_RPA,r1 |
| 517 | mfspr r3,SPRN_IMISS | ||
| 518 | tlbli r3 | 522 | tlbli r3 |
| 519 | mfspr r3,SPRN_SRR1 /* Need to restore CR0 */ | 523 | mfspr r3,SPRN_SRR1 /* Need to restore CR0 */ |
| 520 | mtcrf 0x80,r3 | 524 | mtcrf 0x80,r3 |
| @@ -525,7 +529,6 @@ InstructionAddressInvalid: | |||
| 525 | 529 | ||
| 526 | addis r1,r1,0x2000 | 530 | addis r1,r1,0x2000 |
| 527 | mtspr SPRN_DSISR,r1 /* (shouldn't be needed) */ | 531 | mtspr SPRN_DSISR,r1 /* (shouldn't be needed) */ |
| 528 | mtctr r0 /* Restore CTR */ | ||
| 529 | andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */ | 532 | andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */ |
| 530 | or r2,r2,r1 | 533 | or r2,r2,r1 |
| 531 | mtspr SPRN_SRR1,r2 | 534 | mtspr SPRN_SRR1,r2 |
| @@ -546,12 +549,11 @@ InstructionAddressInvalid: | |||
| 546 | . = 0x1100 | 549 | . = 0x1100 |
| 547 | DataLoadTLBMiss: | 550 | DataLoadTLBMiss: |
| 548 | /* | 551 | /* |
| 549 | * r0: stored ctr | 552 | * r0: scratch |
| 550 | * r1: linux style pte ( later becomes ppc hardware pte ) | 553 | * r1: linux style pte ( later becomes ppc hardware pte ) |
| 551 | * r2: ptr to linux-style pte | 554 | * r2: ptr to linux-style pte |
| 552 | * r3: scratch | 555 | * r3: scratch |
| 553 | */ | 556 | */ |
| 554 | mfctr r0 | ||
| 555 | /* Get PTE (linux-style) and check access */ | 557 | /* Get PTE (linux-style) and check access */ |
| 556 | mfspr r3,SPRN_DMISS | 558 | mfspr r3,SPRN_DMISS |
| 557 | lis r1,PAGE_OFFSET@h /* check if kernel address */ | 559 | lis r1,PAGE_OFFSET@h /* check if kernel address */ |
| @@ -570,35 +572,48 @@ DataLoadTLBMiss: | |||
| 570 | rlwinm. r2,r2,0,0,19 /* extract address of pte page */ | 572 | rlwinm. r2,r2,0,0,19 /* extract address of pte page */ |
| 571 | beq- DataAddressInvalid /* return if no mapping */ | 573 | beq- DataAddressInvalid /* return if no mapping */ |
| 572 | rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ | 574 | rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ |
| 573 | lwz r3,0(r2) /* get linux-style pte */ | 575 | lwz r0,0(r2) /* get linux-style pte */ |
| 574 | andc. r1,r1,r3 /* check access & ~permission */ | 576 | andc. r1,r1,r0 /* check access & ~permission */ |
| 575 | bne- DataAddressInvalid /* return if access not permitted */ | 577 | bne- DataAddressInvalid /* return if access not permitted */ |
| 576 | ori r3,r3,_PAGE_ACCESSED /* set _PAGE_ACCESSED in pte */ | 578 | ori r0,r0,_PAGE_ACCESSED /* set _PAGE_ACCESSED in pte */ |
| 577 | /* | 579 | /* |
| 578 | * NOTE! We are assuming this is not an SMP system, otherwise | 580 | * NOTE! We are assuming this is not an SMP system, otherwise |
| 579 | * we would need to update the pte atomically with lwarx/stwcx. | 581 | * we would need to update the pte atomically with lwarx/stwcx. |
| 580 | */ | 582 | */ |
| 581 | stw r3,0(r2) /* update PTE (accessed bit) */ | 583 | stw r0,0(r2) /* update PTE (accessed bit) */ |
| 582 | /* Convert linux-style PTE to low word of PPC-style PTE */ | 584 | /* Convert linux-style PTE to low word of PPC-style PTE */ |
| 583 | rlwinm r1,r3,32-10,31,31 /* _PAGE_RW -> PP lsb */ | 585 | rlwinm r1,r0,32-10,31,31 /* _PAGE_RW -> PP lsb */ |
| 584 | rlwinm r2,r3,32-7,31,31 /* _PAGE_DIRTY -> PP lsb */ | 586 | rlwinm r2,r0,32-7,31,31 /* _PAGE_DIRTY -> PP lsb */ |
| 585 | and r1,r1,r2 /* writable if _RW and _DIRTY */ | 587 | and r1,r1,r2 /* writable if _RW and _DIRTY */ |
| 586 | rlwimi r3,r3,32-1,30,30 /* _PAGE_USER -> PP msb */ | 588 | rlwimi r0,r0,32-1,30,30 /* _PAGE_USER -> PP msb */ |
| 587 | rlwimi r3,r3,32-1,31,31 /* _PAGE_USER -> PP lsb */ | 589 | rlwimi r0,r0,32-1,31,31 /* _PAGE_USER -> PP lsb */ |
| 588 | ori r1,r1,0xe14 /* clear out reserved bits and M */ | 590 | ori r1,r1,0xe04 /* clear out reserved bits */ |
| 589 | andc r1,r3,r1 /* PP = user? (rw&dirty? 2: 3): 0 */ | 591 | andc r1,r0,r1 /* PP = user? (rw&dirty? 2: 3): 0 */ |
| 592 | BEGIN_FTR_SECTION | ||
| 593 | rlwinm r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */ | ||
| 594 | END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT) | ||
| 590 | mtspr SPRN_RPA,r1 | 595 | mtspr SPRN_RPA,r1 |
| 591 | mfspr r3,SPRN_DMISS | 596 | mfspr r2,SPRN_SRR1 /* Need to restore CR0 */ |
| 597 | mtcrf 0x80,r2 | ||
| 598 | BEGIN_MMU_FTR_SECTION | ||
| 599 | li r0,1 | ||
| 600 | mfspr r1,SPRN_SPRG4 | ||
| 601 | rlwinm r2,r3,20,27,31 /* Get Address bits 15:19 */ | ||
| 602 | slw r0,r0,r2 | ||
| 603 | xor r1,r0,r1 | ||
| 604 | srw r0,r1,r2 | ||
| 605 | mtspr SPRN_SPRG4,r1 | ||
| 606 | mfspr r2,SPRN_SRR1 | ||
| 607 | rlwimi r2,r0,31-14,14,14 | ||
| 608 | mtspr SPRN_SRR1,r2 | ||
| 609 | END_MMU_FTR_SECTION_IFSET(MMU_FTR_NEED_DTLB_SW_LRU) | ||
| 592 | tlbld r3 | 610 | tlbld r3 |
| 593 | mfspr r3,SPRN_SRR1 /* Need to restore CR0 */ | ||
| 594 | mtcrf 0x80,r3 | ||
| 595 | rfi | 611 | rfi |
| 596 | DataAddressInvalid: | 612 | DataAddressInvalid: |
| 597 | mfspr r3,SPRN_SRR1 | 613 | mfspr r3,SPRN_SRR1 |
| 598 | rlwinm r1,r3,9,6,6 /* Get load/store bit */ | 614 | rlwinm r1,r3,9,6,6 /* Get load/store bit */ |
| 599 | addis r1,r1,0x2000 | 615 | addis r1,r1,0x2000 |
| 600 | mtspr SPRN_DSISR,r1 | 616 | mtspr SPRN_DSISR,r1 |
| 601 | mtctr r0 /* Restore CTR */ | ||
| 602 | andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */ | 617 | andi. r2,r3,0xFFFF /* Clear upper bits of SRR1 */ |
| 603 | mtspr SPRN_SRR1,r2 | 618 | mtspr SPRN_SRR1,r2 |
| 604 | mfspr r1,SPRN_DMISS /* Get failing address */ | 619 | mfspr r1,SPRN_DMISS /* Get failing address */ |
| @@ -618,12 +633,11 @@ DataAddressInvalid: | |||
| 618 | . = 0x1200 | 633 | . = 0x1200 |
| 619 | DataStoreTLBMiss: | 634 | DataStoreTLBMiss: |
| 620 | /* | 635 | /* |
| 621 | * r0: stored ctr | 636 | * r0: scratch |
| 622 | * r1: linux style pte ( later becomes ppc hardware pte ) | 637 | * r1: linux style pte ( later becomes ppc hardware pte ) |
| 623 | * r2: ptr to linux-style pte | 638 | * r2: ptr to linux-style pte |
| 624 | * r3: scratch | 639 | * r3: scratch |
| 625 | */ | 640 | */ |
| 626 | mfctr r0 | ||
| 627 | /* Get PTE (linux-style) and check access */ | 641 | /* Get PTE (linux-style) and check access */ |
| 628 | mfspr r3,SPRN_DMISS | 642 | mfspr r3,SPRN_DMISS |
| 629 | lis r1,PAGE_OFFSET@h /* check if kernel address */ | 643 | lis r1,PAGE_OFFSET@h /* check if kernel address */ |
| @@ -642,24 +656,38 @@ DataStoreTLBMiss: | |||
| 642 | rlwinm. r2,r2,0,0,19 /* extract address of pte page */ | 656 | rlwinm. r2,r2,0,0,19 /* extract address of pte page */ |
| 643 | beq- DataAddressInvalid /* return if no mapping */ | 657 | beq- DataAddressInvalid /* return if no mapping */ |
| 644 | rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ | 658 | rlwimi r2,r3,22,20,29 /* insert next 10 bits of address */ |
| 645 | lwz r3,0(r2) /* get linux-style pte */ | 659 | lwz r0,0(r2) /* get linux-style pte */ |
| 646 | andc. r1,r1,r3 /* check access & ~permission */ | 660 | andc. r1,r1,r0 /* check access & ~permission */ |
| 647 | bne- DataAddressInvalid /* return if access not permitted */ | 661 | bne- DataAddressInvalid /* return if access not permitted */ |
| 648 | ori r3,r3,_PAGE_ACCESSED|_PAGE_DIRTY | 662 | ori r0,r0,_PAGE_ACCESSED|_PAGE_DIRTY |
| 649 | /* | 663 | /* |
| 650 | * NOTE! We are assuming this is not an SMP system, otherwise | 664 | * NOTE! We are assuming this is not an SMP system, otherwise |
| 651 | * we would need to update the pte atomically with lwarx/stwcx. | 665 | * we would need to update the pte atomically with lwarx/stwcx. |
| 652 | */ | 666 | */ |
| 653 | stw r3,0(r2) /* update PTE (accessed/dirty bits) */ | 667 | stw r0,0(r2) /* update PTE (accessed/dirty bits) */ |
| 654 | /* Convert linux-style PTE to low word of PPC-style PTE */ | 668 | /* Convert linux-style PTE to low word of PPC-style PTE */ |
| 655 | rlwimi r3,r3,32-1,30,30 /* _PAGE_USER -> PP msb */ | 669 | rlwimi r0,r0,32-1,30,30 /* _PAGE_USER -> PP msb */ |
| 656 | li r1,0xe15 /* clear out reserved bits and M */ | 670 | li r1,0xe05 /* clear out reserved bits & PP lsb */ |
| 657 | andc r1,r3,r1 /* PP = user? 2: 0 */ | 671 | andc r1,r0,r1 /* PP = user? 2: 0 */ |
| 672 | BEGIN_FTR_SECTION | ||
| 673 | rlwinm r1,r1,0,~_PAGE_COHERENT /* clear M (coherence not required) */ | ||
| 674 | END_FTR_SECTION_IFCLR(CPU_FTR_NEED_COHERENT) | ||
| 658 | mtspr SPRN_RPA,r1 | 675 | mtspr SPRN_RPA,r1 |
| 659 | mfspr r3,SPRN_DMISS | 676 | mfspr r2,SPRN_SRR1 /* Need to restore CR0 */ |
| 677 | mtcrf 0x80,r2 | ||
| 678 | BEGIN_MMU_FTR_SECTION | ||
| 679 | li r0,1 | ||
| 680 | mfspr r1,SPRN_SPRG4 | ||
| 681 | rlwinm r2,r3,20,27,31 /* Get Address bits 15:19 */ | ||
| 682 | slw r0,r0,r2 | ||
| 683 | xor r1,r0,r1 | ||
| 684 | srw r0,r1,r2 | ||
| 685 | mtspr SPRN_SPRG4,r1 | ||
| 686 | mfspr r2,SPRN_SRR1 | ||
| 687 | rlwimi r2,r0,31-14,14,14 | ||
| 688 | mtspr SPRN_SRR1,r2 | ||
| 689 | END_MMU_FTR_SECTION_IFSET(MMU_FTR_NEED_DTLB_SW_LRU) | ||
| 660 | tlbld r3 | 690 | tlbld r3 |
| 661 | mfspr r3,SPRN_SRR1 /* Need to restore CR0 */ | ||
| 662 | mtcrf 0x80,r3 | ||
| 663 | rfi | 691 | rfi |
| 664 | 692 | ||
| 665 | #ifndef CONFIG_ALTIVEC | 693 | #ifndef CONFIG_ALTIVEC |
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index ebaedafc8e67..50ef505b8fb6 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S | |||
| @@ -1360,6 +1360,7 @@ _GLOBAL(__start_initialization_multiplatform) | |||
| 1360 | b .__after_prom_start | 1360 | b .__after_prom_start |
| 1361 | 1361 | ||
| 1362 | _INIT_STATIC(__boot_from_prom) | 1362 | _INIT_STATIC(__boot_from_prom) |
| 1363 | #ifdef CONFIG_PPC_OF_BOOT_TRAMPOLINE | ||
| 1363 | /* Save parameters */ | 1364 | /* Save parameters */ |
| 1364 | mr r31,r3 | 1365 | mr r31,r3 |
| 1365 | mr r30,r4 | 1366 | mr r30,r4 |
| @@ -1390,7 +1391,10 @@ _INIT_STATIC(__boot_from_prom) | |||
| 1390 | /* Do all of the interaction with OF client interface */ | 1391 | /* Do all of the interaction with OF client interface */ |
| 1391 | mr r8,r26 | 1392 | mr r8,r26 |
| 1392 | bl .prom_init | 1393 | bl .prom_init |
| 1393 | /* We never return */ | 1394 | #endif /* #CONFIG_PPC_OF_BOOT_TRAMPOLINE */ |
| 1395 | |||
| 1396 | /* We never return. We also hit that trap if trying to boot | ||
| 1397 | * from OF while CONFIG_PPC_OF_BOOT_TRAMPOLINE isn't selected */ | ||
| 1394 | trap | 1398 | trap |
| 1395 | 1399 | ||
| 1396 | _STATIC(__after_prom_start) | 1400 | _STATIC(__after_prom_start) |
diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h index fce2df988504..95f39f1e68d4 100644 --- a/arch/powerpc/kernel/head_booke.h +++ b/arch/powerpc/kernel/head_booke.h | |||
| @@ -10,6 +10,15 @@ | |||
| 10 | mtspr SPRN_IVOR##vector_number,r26; \ | 10 | mtspr SPRN_IVOR##vector_number,r26; \ |
| 11 | sync | 11 | sync |
| 12 | 12 | ||
| 13 | #if (THREAD_SHIFT < 15) | ||
| 14 | #define ALLOC_STACK_FRAME(reg, val) \ | ||
| 15 | addi reg,reg,val | ||
| 16 | #else | ||
| 17 | #define ALLOC_STACK_FRAME(reg, val) \ | ||
| 18 | addis reg,reg,val@ha; \ | ||
| 19 | addi reg,reg,val@l | ||
| 20 | #endif | ||
| 21 | |||
| 13 | #define NORMAL_EXCEPTION_PROLOG \ | 22 | #define NORMAL_EXCEPTION_PROLOG \ |
| 14 | mtspr SPRN_SPRG0,r10; /* save two registers to work with */\ | 23 | mtspr SPRN_SPRG0,r10; /* save two registers to work with */\ |
| 15 | mtspr SPRN_SPRG1,r11; \ | 24 | mtspr SPRN_SPRG1,r11; \ |
| @@ -20,7 +29,7 @@ | |||
| 20 | beq 1f; \ | 29 | beq 1f; \ |
| 21 | mfspr r1,SPRN_SPRG3; /* if from user, start at top of */\ | 30 | mfspr r1,SPRN_SPRG3; /* if from user, start at top of */\ |
| 22 | lwz r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack */\ | 31 | lwz r1,THREAD_INFO-THREAD(r1); /* this thread's kernel stack */\ |
| 23 | addi r1,r1,THREAD_SIZE; \ | 32 | ALLOC_STACK_FRAME(r1, THREAD_SIZE); \ |
| 24 | 1: subi r1,r1,INT_FRAME_SIZE; /* Allocate an exception frame */\ | 33 | 1: subi r1,r1,INT_FRAME_SIZE; /* Allocate an exception frame */\ |
| 25 | mr r11,r1; \ | 34 | mr r11,r1; \ |
| 26 | stw r10,_CCR(r11); /* save various registers */\ | 35 | stw r10,_CCR(r11); /* save various registers */\ |
| @@ -70,10 +79,10 @@ | |||
| 70 | 79 | ||
| 71 | /* only on e500mc/e200 */ | 80 | /* only on e500mc/e200 */ |
| 72 | #define DEBUG_STACK_BASE dbgirq_ctx | 81 | #define DEBUG_STACK_BASE dbgirq_ctx |
| 73 | #ifdef CONFIG_PPC_E500MC | 82 | #ifdef CONFIG_E200 |
| 74 | #define DEBUG_SPRG SPRN_SPRG9 | ||
| 75 | #else | ||
| 76 | #define DEBUG_SPRG SPRN_SPRG6W | 83 | #define DEBUG_SPRG SPRN_SPRG6W |
| 84 | #else | ||
| 85 | #define DEBUG_SPRG SPRN_SPRG9 | ||
| 77 | #endif | 86 | #endif |
| 78 | 87 | ||
| 79 | #define EXC_LVL_FRAME_OVERHEAD (THREAD_SIZE - INT_FRAME_SIZE - EXC_LVL_SIZE) | 88 | #define EXC_LVL_FRAME_OVERHEAD (THREAD_SIZE - INT_FRAME_SIZE - EXC_LVL_SIZE) |
| @@ -279,7 +288,7 @@ label: | |||
| 279 | lwz r11,GPR11(r8); \ | 288 | lwz r11,GPR11(r8); \ |
| 280 | mfspr r8,DEBUG_SPRG; \ | 289 | mfspr r8,DEBUG_SPRG; \ |
| 281 | \ | 290 | \ |
| 282 | RFDI; \ | 291 | PPC_RFDI; \ |
| 283 | b .; \ | 292 | b .; \ |
| 284 | \ | 293 | \ |
| 285 | /* continue normal handling for a debug exception... */ \ | 294 | /* continue normal handling for a debug exception... */ \ |
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index 36ffb3504a4f..4c22620d009b 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S | |||
| @@ -103,10 +103,15 @@ invstr: mflr r6 /* Make it accessible */ | |||
| 103 | or r7,r7,r4 | 103 | or r7,r7,r4 |
| 104 | mtspr SPRN_MAS6,r7 | 104 | mtspr SPRN_MAS6,r7 |
| 105 | tlbsx 0,r6 /* search MSR[IS], SPID=PID0 */ | 105 | tlbsx 0,r6 /* search MSR[IS], SPID=PID0 */ |
| 106 | #ifndef CONFIG_E200 | ||
| 107 | mfspr r7,SPRN_MAS1 | 106 | mfspr r7,SPRN_MAS1 |
| 108 | andis. r7,r7,MAS1_VALID@h | 107 | andis. r7,r7,MAS1_VALID@h |
| 109 | bne match_TLB | 108 | bne match_TLB |
| 109 | |||
| 110 | mfspr r7,SPRN_MMUCFG | ||
| 111 | rlwinm r7,r7,21,28,31 /* extract MMUCFG[NPIDS] */ | ||
| 112 | cmpwi r7,3 | ||
| 113 | bne match_TLB /* skip if NPIDS != 3 */ | ||
| 114 | |||
| 110 | mfspr r7,SPRN_PID1 | 115 | mfspr r7,SPRN_PID1 |
| 111 | slwi r7,r7,16 | 116 | slwi r7,r7,16 |
| 112 | or r7,r7,r4 | 117 | or r7,r7,r4 |
| @@ -120,7 +125,7 @@ invstr: mflr r6 /* Make it accessible */ | |||
| 120 | or r7,r7,r4 | 125 | or r7,r7,r4 |
| 121 | mtspr SPRN_MAS6,r7 | 126 | mtspr SPRN_MAS6,r7 |
| 122 | tlbsx 0,r6 /* Fall through, we had to match */ | 127 | tlbsx 0,r6 /* Fall through, we had to match */ |
| 123 | #endif | 128 | |
| 124 | match_TLB: | 129 | match_TLB: |
| 125 | mfspr r7,SPRN_MAS0 | 130 | mfspr r7,SPRN_MAS0 |
| 126 | rlwinm r3,r7,16,20,31 /* Extract MAS0(Entry) */ | 131 | rlwinm r3,r7,16,20,31 /* Extract MAS0(Entry) */ |
| @@ -168,7 +173,7 @@ skpinv: addi r6,r6,1 /* Increment */ | |||
| 168 | 173 | ||
| 169 | /* grab and fixup the RPN */ | 174 | /* grab and fixup the RPN */ |
| 170 | mfspr r6,SPRN_MAS1 /* extract MAS1[SIZE] */ | 175 | mfspr r6,SPRN_MAS1 /* extract MAS1[SIZE] */ |
| 171 | rlwinm r6,r6,25,27,30 | 176 | rlwinm r6,r6,25,27,31 |
| 172 | li r8,-1 | 177 | li r8,-1 |
| 173 | addi r6,r6,10 | 178 | addi r6,r6,10 |
| 174 | slw r6,r8,r6 /* convert to mask */ | 179 | slw r6,r8,r6 /* convert to mask */ |
| @@ -194,7 +199,7 @@ skpinv: addi r6,r6,1 /* Increment */ | |||
| 194 | xori r6,r4,1 /* Setup TMP mapping in the other Address space */ | 199 | xori r6,r4,1 /* Setup TMP mapping in the other Address space */ |
| 195 | slwi r6,r6,12 | 200 | slwi r6,r6,12 |
| 196 | oris r6,r6,(MAS1_VALID|MAS1_IPROT)@h | 201 | oris r6,r6,(MAS1_VALID|MAS1_IPROT)@h |
| 197 | ori r6,r6,(MAS1_TSIZE(BOOKE_PAGESZ_4K))@l | 202 | ori r6,r6,(MAS1_TSIZE(BOOK3E_PAGESZ_4K))@l |
| 198 | mtspr SPRN_MAS1,r6 | 203 | mtspr SPRN_MAS1,r6 |
| 199 | mfspr r6,SPRN_MAS2 | 204 | mfspr r6,SPRN_MAS2 |
| 200 | li r7,0 /* temp EPN = 0 */ | 205 | li r7,0 /* temp EPN = 0 */ |
| @@ -215,14 +220,19 @@ skpinv: addi r6,r6,1 /* Increment */ | |||
| 215 | 220 | ||
| 216 | /* 4. Clear out PIDs & Search info */ | 221 | /* 4. Clear out PIDs & Search info */ |
| 217 | li r6,0 | 222 | li r6,0 |
| 223 | mtspr SPRN_MAS6,r6 | ||
| 218 | mtspr SPRN_PID0,r6 | 224 | mtspr SPRN_PID0,r6 |
| 219 | #ifndef CONFIG_E200 | 225 | |
| 226 | mfspr r7,SPRN_MMUCFG | ||
| 227 | rlwinm r7,r7,21,28,31 /* extract MMUCFG[NPIDS] */ | ||
| 228 | cmpwi r7,3 | ||
| 229 | bne 2f /* skip if NPIDS != 3 */ | ||
| 230 | |||
| 220 | mtspr SPRN_PID1,r6 | 231 | mtspr SPRN_PID1,r6 |
| 221 | mtspr SPRN_PID2,r6 | 232 | mtspr SPRN_PID2,r6 |
| 222 | #endif | ||
| 223 | mtspr SPRN_MAS6,r6 | ||
| 224 | 233 | ||
| 225 | /* 5. Invalidate mapping we started in */ | 234 | /* 5. Invalidate mapping we started in */ |
| 235 | 2: | ||
| 226 | lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ | 236 | lis r7,0x1000 /* Set MAS0(TLBSEL) = 1 */ |
| 227 | rlwimi r7,r3,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */ | 237 | rlwimi r7,r3,16,4,15 /* Setup MAS0 = TLBSEL | ESEL(r3) */ |
| 228 | mtspr SPRN_MAS0,r7 | 238 | mtspr SPRN_MAS0,r7 |
| @@ -247,10 +257,10 @@ skpinv: addi r6,r6,1 /* Increment */ | |||
| 247 | lis r6,0x1000 /* Set MAS0(TLBSEL) = TLB1(1), ESEL = 0 */ | 257 | lis r6,0x1000 /* Set MAS0(TLBSEL) = TLB1(1), ESEL = 0 */ |
| 248 | mtspr SPRN_MAS0,r6 | 258 | mtspr SPRN_MAS0,r6 |
| 249 | lis r6,(MAS1_VALID|MAS1_IPROT)@h | 259 | lis r6,(MAS1_VALID|MAS1_IPROT)@h |
| 250 | ori r6,r6,(MAS1_TSIZE(BOOKE_PAGESZ_64M))@l | 260 | ori r6,r6,(MAS1_TSIZE(BOOK3E_PAGESZ_64M))@l |
| 251 | mtspr SPRN_MAS1,r6 | 261 | mtspr SPRN_MAS1,r6 |
| 252 | lis r6,MAS2_VAL(PAGE_OFFSET, BOOKE_PAGESZ_64M, M_IF_SMP)@h | 262 | lis r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@h |
| 253 | ori r6,r6,MAS2_VAL(PAGE_OFFSET, BOOKE_PAGESZ_64M, M_IF_SMP)@l | 263 | ori r6,r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@l |
| 254 | mtspr SPRN_MAS2,r6 | 264 | mtspr SPRN_MAS2,r6 |
| 255 | mtspr SPRN_MAS3,r8 | 265 | mtspr SPRN_MAS3,r8 |
| 256 | tlbwe | 266 | tlbwe |
| @@ -298,26 +308,14 @@ skpinv: addi r6,r6,1 /* Increment */ | |||
| 298 | SET_IVOR(12, WatchdogTimer); | 308 | SET_IVOR(12, WatchdogTimer); |
| 299 | SET_IVOR(13, DataTLBError); | 309 | SET_IVOR(13, DataTLBError); |
| 300 | SET_IVOR(14, InstructionTLBError); | 310 | SET_IVOR(14, InstructionTLBError); |
| 301 | SET_IVOR(15, DebugDebug); | ||
| 302 | #if defined(CONFIG_E500) && !defined(CONFIG_PPC_E500MC) | ||
| 303 | SET_IVOR(15, DebugCrit); | 311 | SET_IVOR(15, DebugCrit); |
| 304 | #endif | ||
| 305 | SET_IVOR(32, SPEUnavailable); | ||
| 306 | SET_IVOR(33, SPEFloatingPointData); | ||
| 307 | SET_IVOR(34, SPEFloatingPointRound); | ||
| 308 | #ifndef CONFIG_E200 | ||
| 309 | SET_IVOR(35, PerformanceMonitor); | ||
| 310 | #endif | ||
| 311 | #ifdef CONFIG_PPC_E500MC | ||
| 312 | SET_IVOR(36, Doorbell); | ||
| 313 | #endif | ||
| 314 | 312 | ||
| 315 | /* Establish the interrupt vector base */ | 313 | /* Establish the interrupt vector base */ |
| 316 | lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */ | 314 | lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */ |
| 317 | mtspr SPRN_IVPR,r4 | 315 | mtspr SPRN_IVPR,r4 |
| 318 | 316 | ||
| 319 | /* Setup the defaults for TLB entries */ | 317 | /* Setup the defaults for TLB entries */ |
| 320 | li r2,(MAS4_TSIZED(BOOKE_PAGESZ_4K))@l | 318 | li r2,(MAS4_TSIZED(BOOK3E_PAGESZ_4K))@l |
| 321 | #ifdef CONFIG_E200 | 319 | #ifdef CONFIG_E200 |
| 322 | oris r2,r2,MAS4_TLBSELD(1)@h | 320 | oris r2,r2,MAS4_TLBSELD(1)@h |
| 323 | #endif | 321 | #endif |
| @@ -329,12 +327,6 @@ skpinv: addi r6,r6,1 /* Increment */ | |||
| 329 | oris r2,r2,HID0_DOZE@h | 327 | oris r2,r2,HID0_DOZE@h |
| 330 | mtspr SPRN_HID0, r2 | 328 | mtspr SPRN_HID0, r2 |
| 331 | #endif | 329 | #endif |
| 332 | #ifdef CONFIG_E200 | ||
| 333 | /* enable dedicated debug exception handling resources (Debug APU) */ | ||
| 334 | mfspr r2,SPRN_HID0 | ||
| 335 | ori r2,r2,HID0_DAPUEN@l | ||
| 336 | mtspr SPRN_HID0,r2 | ||
| 337 | #endif | ||
| 338 | 330 | ||
| 339 | #if !defined(CONFIG_BDI_SWITCH) | 331 | #if !defined(CONFIG_BDI_SWITCH) |
| 340 | /* | 332 | /* |
| @@ -706,15 +698,13 @@ interrupt_base: | |||
| 706 | /* Performance Monitor */ | 698 | /* Performance Monitor */ |
| 707 | EXCEPTION(0x2060, PerformanceMonitor, performance_monitor_exception, EXC_XFER_STD) | 699 | EXCEPTION(0x2060, PerformanceMonitor, performance_monitor_exception, EXC_XFER_STD) |
| 708 | 700 | ||
| 709 | #ifdef CONFIG_PPC_E500MC | 701 | EXCEPTION(0x2070, Doorbell, doorbell_exception, EXC_XFER_STD) |
| 710 | EXCEPTION(0x2070, Doorbell, unknown_exception, EXC_XFER_STD) | 702 | |
| 711 | #endif | 703 | CRITICAL_EXCEPTION(0x2080, CriticalDoorbell, unknown_exception) |
| 712 | 704 | ||
| 713 | /* Debug Interrupt */ | 705 | /* Debug Interrupt */ |
| 714 | DEBUG_DEBUG_EXCEPTION | 706 | DEBUG_DEBUG_EXCEPTION |
| 715 | #if defined(CONFIG_E500) && !defined(CONFIG_PPC_E500MC) | ||
| 716 | DEBUG_CRIT_EXCEPTION | 707 | DEBUG_CRIT_EXCEPTION |
| 717 | #endif | ||
| 718 | 708 | ||
| 719 | /* | 709 | /* |
| 720 | * Local functions | 710 | * Local functions |
| @@ -897,6 +887,47 @@ KernelSPE: | |||
| 897 | * Global functions | 887 | * Global functions |
| 898 | */ | 888 | */ |
| 899 | 889 | ||
| 890 | /* Adjust or setup IVORs for e200 */ | ||
| 891 | _GLOBAL(__setup_e200_ivors) | ||
| 892 | li r3,DebugDebug@l | ||
| 893 | mtspr SPRN_IVOR15,r3 | ||
| 894 | li r3,SPEUnavailable@l | ||
| 895 | mtspr SPRN_IVOR32,r3 | ||
| 896 | li r3,SPEFloatingPointData@l | ||
| 897 | mtspr SPRN_IVOR33,r3 | ||
| 898 | li r3,SPEFloatingPointRound@l | ||
| 899 | mtspr SPRN_IVOR34,r3 | ||
| 900 | sync | ||
| 901 | blr | ||
| 902 | |||
| 903 | /* Adjust or setup IVORs for e500v1/v2 */ | ||
| 904 | _GLOBAL(__setup_e500_ivors) | ||
| 905 | li r3,DebugCrit@l | ||
| 906 | mtspr SPRN_IVOR15,r3 | ||
| 907 | li r3,SPEUnavailable@l | ||
| 908 | mtspr SPRN_IVOR32,r3 | ||
| 909 | li r3,SPEFloatingPointData@l | ||
| 910 | mtspr SPRN_IVOR33,r3 | ||
| 911 | li r3,SPEFloatingPointRound@l | ||
| 912 | mtspr SPRN_IVOR34,r3 | ||
| 913 | li r3,PerformanceMonitor@l | ||
| 914 | mtspr SPRN_IVOR35,r3 | ||
| 915 | sync | ||
| 916 | blr | ||
| 917 | |||
| 918 | /* Adjust or setup IVORs for e500mc */ | ||
| 919 | _GLOBAL(__setup_e500mc_ivors) | ||
| 920 | li r3,DebugDebug@l | ||
| 921 | mtspr SPRN_IVOR15,r3 | ||
| 922 | li r3,PerformanceMonitor@l | ||
| 923 | mtspr SPRN_IVOR35,r3 | ||
| 924 | li r3,Doorbell@l | ||
| 925 | mtspr SPRN_IVOR36,r3 | ||
| 926 | li r3,CriticalDoorbell@l | ||
| 927 | mtspr SPRN_IVOR37,r3 | ||
| 928 | sync | ||
| 929 | blr | ||
| 930 | |||
| 900 | /* | 931 | /* |
| 901 | * extern void loadcam_entry(unsigned int index) | 932 | * extern void loadcam_entry(unsigned int index) |
| 902 | * | 933 | * |
| @@ -1089,7 +1120,7 @@ __secondary_start: | |||
| 1089 | mtspr SPRN_SPRG3,r4 | 1120 | mtspr SPRN_SPRG3,r4 |
| 1090 | 1121 | ||
| 1091 | /* Setup the defaults for TLB entries */ | 1122 | /* Setup the defaults for TLB entries */ |
| 1092 | li r4,(MAS4_TSIZED(BOOKE_PAGESZ_4K))@l | 1123 | li r4,(MAS4_TSIZED(BOOK3E_PAGESZ_4K))@l |
| 1093 | mtspr SPRN_MAS4,r4 | 1124 | mtspr SPRN_MAS4,r4 |
| 1094 | 1125 | ||
| 1095 | /* Jump to start_secondary */ | 1126 | /* Jump to start_secondary */ |
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 7f8e6a92c5a1..0d2e37c57738 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c | |||
| @@ -181,7 +181,7 @@ int show_interrupts(struct seq_file *p, void *v) | |||
| 181 | { | 181 | { |
| 182 | int i = *(loff_t *)v, j; | 182 | int i = *(loff_t *)v, j; |
| 183 | struct irqaction *action; | 183 | struct irqaction *action; |
| 184 | irq_desc_t *desc; | 184 | struct irq_desc *desc; |
| 185 | unsigned long flags; | 185 | unsigned long flags; |
| 186 | 186 | ||
| 187 | if (i == 0) { | 187 | if (i == 0) { |
| @@ -200,7 +200,7 @@ int show_interrupts(struct seq_file *p, void *v) | |||
| 200 | seq_printf(p, "%3d: ", i); | 200 | seq_printf(p, "%3d: ", i); |
| 201 | #ifdef CONFIG_SMP | 201 | #ifdef CONFIG_SMP |
| 202 | for_each_online_cpu(j) | 202 | for_each_online_cpu(j) |
| 203 | seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]); | 203 | seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); |
| 204 | #else | 204 | #else |
| 205 | seq_printf(p, "%10u ", kstat_irqs(i)); | 205 | seq_printf(p, "%10u ", kstat_irqs(i)); |
| 206 | #endif /* CONFIG_SMP */ | 206 | #endif /* CONFIG_SMP */ |
| @@ -1048,7 +1048,7 @@ arch_initcall(irq_late_init); | |||
| 1048 | static int virq_debug_show(struct seq_file *m, void *private) | 1048 | static int virq_debug_show(struct seq_file *m, void *private) |
| 1049 | { | 1049 | { |
| 1050 | unsigned long flags; | 1050 | unsigned long flags; |
| 1051 | irq_desc_t *desc; | 1051 | struct irq_desc *desc; |
| 1052 | const char *p; | 1052 | const char *p; |
| 1053 | char none[] = "none"; | 1053 | char none[] = "none"; |
| 1054 | int i; | 1054 | int i; |
diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index 8992b031a7b6..8fbb12508bf3 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c | |||
| @@ -329,7 +329,7 @@ static unsigned long stub_for_addr(Elf64_Shdr *sechdrs, | |||
| 329 | restore r2. */ | 329 | restore r2. */ |
| 330 | static int restore_r2(u32 *instruction, struct module *me) | 330 | static int restore_r2(u32 *instruction, struct module *me) |
| 331 | { | 331 | { |
| 332 | if (*instruction != PPC_NOP_INSTR) { | 332 | if (*instruction != PPC_INST_NOP) { |
| 333 | printk("%s: Expect noop after relocate, got %08x\n", | 333 | printk("%s: Expect noop after relocate, got %08x\n", |
| 334 | me->name, *instruction); | 334 | me->name, *instruction); |
| 335 | return 0; | 335 | return 0; |
diff --git a/arch/powerpc/kernel/msi.c b/arch/powerpc/kernel/msi.c index 3bb7d3dd28be..8bbc12d20f5c 100644 --- a/arch/powerpc/kernel/msi.c +++ b/arch/powerpc/kernel/msi.c | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | 9 | ||
| 10 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
| 11 | #include <linux/msi.h> | 11 | #include <linux/msi.h> |
| 12 | #include <linux/pci.h> | ||
| 12 | 13 | ||
| 13 | #include <asm/machdep.h> | 14 | #include <asm/machdep.h> |
| 14 | 15 | ||
| @@ -19,6 +20,10 @@ int arch_msi_check_device(struct pci_dev* dev, int nvec, int type) | |||
| 19 | return -ENOSYS; | 20 | return -ENOSYS; |
| 20 | } | 21 | } |
| 21 | 22 | ||
| 23 | /* PowerPC doesn't support multiple MSI yet */ | ||
| 24 | if (type == PCI_CAP_ID_MSI && nvec > 1) | ||
| 25 | return 1; | ||
| 26 | |||
| 22 | if (ppc_md.msi_check_device) { | 27 | if (ppc_md.msi_check_device) { |
| 23 | pr_debug("msi: Using platform check routine.\n"); | 28 | pr_debug("msi: Using platform check routine.\n"); |
| 24 | return ppc_md.msi_check_device(dev, nvec, type); | 29 | return ppc_md.msi_check_device(dev, nvec, type); |
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 0f4181272311..9c69e7e145c5 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include <asm/eeh.h> | 38 | #include <asm/eeh.h> |
| 39 | 39 | ||
| 40 | static DEFINE_SPINLOCK(hose_spinlock); | 40 | static DEFINE_SPINLOCK(hose_spinlock); |
| 41 | LIST_HEAD(hose_list); | ||
| 41 | 42 | ||
| 42 | /* XXX kill that some day ... */ | 43 | /* XXX kill that some day ... */ |
| 43 | static int global_phb_number; /* Global phb counter */ | 44 | static int global_phb_number; /* Global phb counter */ |
| @@ -49,7 +50,7 @@ resource_size_t isa_mem_base; | |||
| 49 | unsigned int ppc_pci_flags = 0; | 50 | unsigned int ppc_pci_flags = 0; |
| 50 | 51 | ||
| 51 | 52 | ||
| 52 | static struct dma_mapping_ops *pci_dma_ops; | 53 | static struct dma_mapping_ops *pci_dma_ops = &dma_direct_ops; |
| 53 | 54 | ||
| 54 | void set_pci_dma_ops(struct dma_mapping_ops *dma_ops) | 55 | void set_pci_dma_ops(struct dma_mapping_ops *dma_ops) |
| 55 | { | 56 | { |
| @@ -113,19 +114,24 @@ void pcibios_free_controller(struct pci_controller *phb) | |||
| 113 | kfree(phb); | 114 | kfree(phb); |
| 114 | } | 115 | } |
| 115 | 116 | ||
| 117 | static resource_size_t pcibios_io_size(const struct pci_controller *hose) | ||
| 118 | { | ||
| 119 | #ifdef CONFIG_PPC64 | ||
| 120 | return hose->pci_io_size; | ||
| 121 | #else | ||
| 122 | return hose->io_resource.end - hose->io_resource.start + 1; | ||
| 123 | #endif | ||
| 124 | } | ||
| 125 | |||
| 116 | int pcibios_vaddr_is_ioport(void __iomem *address) | 126 | int pcibios_vaddr_is_ioport(void __iomem *address) |
| 117 | { | 127 | { |
| 118 | int ret = 0; | 128 | int ret = 0; |
| 119 | struct pci_controller *hose; | 129 | struct pci_controller *hose; |
| 120 | unsigned long size; | 130 | resource_size_t size; |
| 121 | 131 | ||
| 122 | spin_lock(&hose_spinlock); | 132 | spin_lock(&hose_spinlock); |
| 123 | list_for_each_entry(hose, &hose_list, list_node) { | 133 | list_for_each_entry(hose, &hose_list, list_node) { |
| 124 | #ifdef CONFIG_PPC64 | 134 | size = pcibios_io_size(hose); |
| 125 | size = hose->pci_io_size; | ||
| 126 | #else | ||
| 127 | size = hose->io_resource.end - hose->io_resource.start + 1; | ||
| 128 | #endif | ||
| 129 | if (address >= hose->io_base_virt && | 135 | if (address >= hose->io_base_virt && |
| 130 | address < (hose->io_base_virt + size)) { | 136 | address < (hose->io_base_virt + size)) { |
| 131 | ret = 1; | 137 | ret = 1; |
| @@ -136,6 +142,29 @@ int pcibios_vaddr_is_ioport(void __iomem *address) | |||
| 136 | return ret; | 142 | return ret; |
| 137 | } | 143 | } |
| 138 | 144 | ||
| 145 | unsigned long pci_address_to_pio(phys_addr_t address) | ||
| 146 | { | ||
| 147 | struct pci_controller *hose; | ||
| 148 | resource_size_t size; | ||
| 149 | unsigned long ret = ~0; | ||
| 150 | |||
| 151 | spin_lock(&hose_spinlock); | ||
| 152 | list_for_each_entry(hose, &hose_list, list_node) { | ||
| 153 | size = pcibios_io_size(hose); | ||
| 154 | if (address >= hose->io_base_phys && | ||
| 155 | address < (hose->io_base_phys + size)) { | ||
| 156 | unsigned long base = | ||
| 157 | (unsigned long)hose->io_base_virt - _IO_BASE; | ||
| 158 | ret = base + (address - hose->io_base_phys); | ||
| 159 | break; | ||
| 160 | } | ||
| 161 | } | ||
| 162 | spin_unlock(&hose_spinlock); | ||
| 163 | |||
| 164 | return ret; | ||
| 165 | } | ||
| 166 | EXPORT_SYMBOL_GPL(pci_address_to_pio); | ||
| 167 | |||
| 139 | /* | 168 | /* |
| 140 | * Return the domain number for this bus. | 169 | * Return the domain number for this bus. |
| 141 | */ | 170 | */ |
| @@ -1453,7 +1482,7 @@ void __init pcibios_resource_survey(void) | |||
| 1453 | * we proceed to assigning things that were left unassigned | 1482 | * we proceed to assigning things that were left unassigned |
| 1454 | */ | 1483 | */ |
| 1455 | if (!(ppc_pci_flags & PPC_PCI_PROBE_ONLY)) { | 1484 | if (!(ppc_pci_flags & PPC_PCI_PROBE_ONLY)) { |
| 1456 | pr_debug("PCI: Assigning unassigned resouces...\n"); | 1485 | pr_debug("PCI: Assigning unassigned resources...\n"); |
| 1457 | pci_assign_unassigned_resources(); | 1486 | pci_assign_unassigned_resources(); |
| 1458 | } | 1487 | } |
| 1459 | 1488 | ||
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c index 132cd80afa21..d473634e39e3 100644 --- a/arch/powerpc/kernel/pci_32.c +++ b/arch/powerpc/kernel/pci_32.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <asm/prom.h> | 20 | #include <asm/prom.h> |
| 21 | #include <asm/sections.h> | 21 | #include <asm/sections.h> |
| 22 | #include <asm/pci-bridge.h> | 22 | #include <asm/pci-bridge.h> |
| 23 | #include <asm/ppc-pci.h> | ||
| 23 | #include <asm/byteorder.h> | 24 | #include <asm/byteorder.h> |
| 24 | #include <asm/uaccess.h> | 25 | #include <asm/uaccess.h> |
| 25 | #include <asm/machdep.h> | 26 | #include <asm/machdep.h> |
| @@ -43,8 +44,6 @@ static u8* pci_to_OF_bus_map; | |||
| 43 | */ | 44 | */ |
| 44 | static int pci_assign_all_buses; | 45 | static int pci_assign_all_buses; |
| 45 | 46 | ||
| 46 | LIST_HEAD(hose_list); | ||
| 47 | |||
| 48 | static int pci_bus_count; | 47 | static int pci_bus_count; |
| 49 | 48 | ||
| 50 | /* This will remain NULL for now, until isa-bridge.c is made common | 49 | /* This will remain NULL for now, until isa-bridge.c is made common |
| @@ -219,16 +218,23 @@ scan_OF_pci_childs(struct device_node *parent, pci_OF_scan_iterator filter, void | |||
| 219 | static struct device_node *scan_OF_for_pci_dev(struct device_node *parent, | 218 | static struct device_node *scan_OF_for_pci_dev(struct device_node *parent, |
| 220 | unsigned int devfn) | 219 | unsigned int devfn) |
| 221 | { | 220 | { |
| 222 | struct device_node *np; | 221 | struct device_node *np, *cnp; |
| 223 | const u32 *reg; | 222 | const u32 *reg; |
| 224 | unsigned int psize; | 223 | unsigned int psize; |
| 225 | 224 | ||
| 226 | for_each_child_of_node(parent, np) { | 225 | for_each_child_of_node(parent, np) { |
| 227 | reg = of_get_property(np, "reg", &psize); | 226 | reg = of_get_property(np, "reg", &psize); |
| 228 | if (reg == NULL || psize < 4) | 227 | if (reg && psize >= 4 && ((reg[0] >> 8) & 0xff) == devfn) |
| 229 | continue; | ||
| 230 | if (((reg[0] >> 8) & 0xff) == devfn) | ||
| 231 | return np; | 228 | return np; |
| 229 | |||
| 230 | /* Note: some OFs create a parent node "multifunc-device" as | ||
| 231 | * a fake root for all functions of a multi-function device, | ||
| 232 | * we go down them as well. */ | ||
| 233 | if (!strcmp(np->name, "multifunc-device")) { | ||
| 234 | cnp = scan_OF_for_pci_dev(np, devfn); | ||
| 235 | if (cnp) | ||
| 236 | return cnp; | ||
| 237 | } | ||
| 232 | } | 238 | } |
| 233 | return NULL; | 239 | return NULL; |
| 234 | } | 240 | } |
| @@ -491,24 +497,6 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn) | |||
| 491 | return result; | 497 | return result; |
| 492 | } | 498 | } |
| 493 | 499 | ||
| 494 | unsigned long pci_address_to_pio(phys_addr_t address) | ||
| 495 | { | ||
| 496 | struct pci_controller *hose, *tmp; | ||
| 497 | |||
| 498 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { | ||
| 499 | unsigned int size = hose->io_resource.end - | ||
| 500 | hose->io_resource.start + 1; | ||
| 501 | if (address >= hose->io_base_phys && | ||
| 502 | address < (hose->io_base_phys + size)) { | ||
| 503 | unsigned long base = | ||
| 504 | (unsigned long)hose->io_base_virt - _IO_BASE; | ||
| 505 | return base + (address - hose->io_base_phys); | ||
| 506 | } | ||
| 507 | } | ||
| 508 | return (unsigned int)-1; | ||
| 509 | } | ||
| 510 | EXPORT_SYMBOL(pci_address_to_pio); | ||
| 511 | |||
| 512 | /* | 500 | /* |
| 513 | * Null PCI config access functions, for the case when we can't | 501 | * Null PCI config access functions, for the case when we can't |
| 514 | * find a hose. | 502 | * find a hose. |
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index ea8eda8c87cf..be574fc0d92f 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c | |||
| @@ -43,8 +43,6 @@ unsigned long pci_probe_only = 1; | |||
| 43 | unsigned long pci_io_base = ISA_IO_BASE; | 43 | unsigned long pci_io_base = ISA_IO_BASE; |
| 44 | EXPORT_SYMBOL(pci_io_base); | 44 | EXPORT_SYMBOL(pci_io_base); |
| 45 | 45 | ||
| 46 | LIST_HEAD(hose_list); | ||
| 47 | |||
| 48 | static void fixup_broken_pcnet32(struct pci_dev* dev) | 46 | static void fixup_broken_pcnet32(struct pci_dev* dev) |
| 49 | { | 47 | { |
| 50 | if ((dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET)) { | 48 | if ((dev->class>>8 == PCI_CLASS_NETWORK_ETHERNET)) { |
| @@ -524,23 +522,6 @@ int __devinit pcibios_map_io_space(struct pci_bus *bus) | |||
| 524 | } | 522 | } |
| 525 | EXPORT_SYMBOL_GPL(pcibios_map_io_space); | 523 | EXPORT_SYMBOL_GPL(pcibios_map_io_space); |
| 526 | 524 | ||
| 527 | unsigned long pci_address_to_pio(phys_addr_t address) | ||
| 528 | { | ||
| 529 | struct pci_controller *hose, *tmp; | ||
| 530 | |||
| 531 | list_for_each_entry_safe(hose, tmp, &hose_list, list_node) { | ||
| 532 | if (address >= hose->io_base_phys && | ||
| 533 | address < (hose->io_base_phys + hose->pci_io_size)) { | ||
| 534 | unsigned long base = | ||
| 535 | (unsigned long)hose->io_base_virt - _IO_BASE; | ||
| 536 | return base + (address - hose->io_base_phys); | ||
| 537 | } | ||
| 538 | } | ||
| 539 | return (unsigned int)-1; | ||
| 540 | } | ||
| 541 | EXPORT_SYMBOL_GPL(pci_address_to_pio); | ||
| 542 | |||
| 543 | |||
| 544 | #define IOBASE_BRIDGE_NUMBER 0 | 525 | #define IOBASE_BRIDGE_NUMBER 0 |
| 545 | #define IOBASE_MEMORY 1 | 526 | #define IOBASE_MEMORY 1 |
| 546 | #define IOBASE_IO 2 | 527 | #define IOBASE_IO 2 |
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index fb7049c054c0..7b44a33f03c2 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c | |||
| @@ -33,7 +33,10 @@ | |||
| 33 | #include <linux/mqueue.h> | 33 | #include <linux/mqueue.h> |
| 34 | #include <linux/hardirq.h> | 34 | #include <linux/hardirq.h> |
| 35 | #include <linux/utsname.h> | 35 | #include <linux/utsname.h> |
| 36 | #include <linux/ftrace.h> | ||
| 36 | #include <linux/kernel_stat.h> | 37 | #include <linux/kernel_stat.h> |
| 38 | #include <linux/personality.h> | ||
| 39 | #include <linux/random.h> | ||
| 37 | 40 | ||
| 38 | #include <asm/pgtable.h> | 41 | #include <asm/pgtable.h> |
| 39 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
| @@ -595,7 +598,7 @@ void prepare_to_copy(struct task_struct *tsk) | |||
| 595 | /* | 598 | /* |
| 596 | * Copy a thread.. | 599 | * Copy a thread.. |
| 597 | */ | 600 | */ |
| 598 | int copy_thread(int nr, unsigned long clone_flags, unsigned long usp, | 601 | int copy_thread(unsigned long clone_flags, unsigned long usp, |
| 599 | unsigned long unused, struct task_struct *p, | 602 | unsigned long unused, struct task_struct *p, |
| 600 | struct pt_regs *regs) | 603 | struct pt_regs *regs) |
| 601 | { | 604 | { |
| @@ -1008,6 +1011,14 @@ void show_stack(struct task_struct *tsk, unsigned long *stack) | |||
| 1008 | unsigned long sp, ip, lr, newsp; | 1011 | unsigned long sp, ip, lr, newsp; |
| 1009 | int count = 0; | 1012 | int count = 0; |
| 1010 | int firstframe = 1; | 1013 | int firstframe = 1; |
| 1014 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
| 1015 | int curr_frame = current->curr_ret_stack; | ||
| 1016 | extern void return_to_handler(void); | ||
| 1017 | unsigned long addr = (unsigned long)return_to_handler; | ||
| 1018 | #ifdef CONFIG_PPC64 | ||
| 1019 | addr = *(unsigned long*)addr; | ||
| 1020 | #endif | ||
| 1021 | #endif | ||
| 1011 | 1022 | ||
| 1012 | sp = (unsigned long) stack; | 1023 | sp = (unsigned long) stack; |
| 1013 | if (tsk == NULL) | 1024 | if (tsk == NULL) |
| @@ -1030,6 +1041,13 @@ void show_stack(struct task_struct *tsk, unsigned long *stack) | |||
| 1030 | ip = stack[STACK_FRAME_LR_SAVE]; | 1041 | ip = stack[STACK_FRAME_LR_SAVE]; |
| 1031 | if (!firstframe || ip != lr) { | 1042 | if (!firstframe || ip != lr) { |
| 1032 | printk("["REG"] ["REG"] %pS", sp, ip, (void *)ip); | 1043 | printk("["REG"] ["REG"] %pS", sp, ip, (void *)ip); |
| 1044 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
| 1045 | if (ip == addr && curr_frame >= 0) { | ||
| 1046 | printk(" (%pS)", | ||
| 1047 | (void *)current->ret_stack[curr_frame].ret); | ||
| 1048 | curr_frame--; | ||
| 1049 | } | ||
| 1050 | #endif | ||
| 1033 | if (firstframe) | 1051 | if (firstframe) |
| 1034 | printk(" (unreliable)"); | 1052 | printk(" (unreliable)"); |
| 1035 | printk("\n"); | 1053 | printk("\n"); |
| @@ -1122,3 +1140,43 @@ void thread_info_cache_init(void) | |||
| 1122 | } | 1140 | } |
| 1123 | 1141 | ||
| 1124 | #endif /* THREAD_SHIFT < PAGE_SHIFT */ | 1142 | #endif /* THREAD_SHIFT < PAGE_SHIFT */ |
| 1143 | |||
| 1144 | unsigned long arch_align_stack(unsigned long sp) | ||
| 1145 | { | ||
| 1146 | if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) | ||
| 1147 | sp -= get_random_int() & ~PAGE_MASK; | ||
| 1148 | return sp & ~0xf; | ||
| 1149 | } | ||
| 1150 | |||
| 1151 | static inline unsigned long brk_rnd(void) | ||
| 1152 | { | ||
| 1153 | unsigned long rnd = 0; | ||
| 1154 | |||
| 1155 | /* 8MB for 32bit, 1GB for 64bit */ | ||
| 1156 | if (is_32bit_task()) | ||
| 1157 | rnd = (long)(get_random_int() % (1<<(23-PAGE_SHIFT))); | ||
| 1158 | else | ||
| 1159 | rnd = (long)(get_random_int() % (1<<(30-PAGE_SHIFT))); | ||
| 1160 | |||
| 1161 | return rnd << PAGE_SHIFT; | ||
| 1162 | } | ||
| 1163 | |||
| 1164 | unsigned long arch_randomize_brk(struct mm_struct *mm) | ||
| 1165 | { | ||
| 1166 | unsigned long ret = PAGE_ALIGN(mm->brk + brk_rnd()); | ||
| 1167 | |||
| 1168 | if (ret < mm->brk) | ||
| 1169 | return mm->brk; | ||
| 1170 | |||
| 1171 | return ret; | ||
| 1172 | } | ||
| 1173 | |||
| 1174 | unsigned long randomize_et_dyn(unsigned long base) | ||
| 1175 | { | ||
| 1176 | unsigned long ret = PAGE_ALIGN(base + brk_rnd()); | ||
| 1177 | |||
| 1178 | if (ret < base) | ||
| 1179 | return base; | ||
| 1180 | |||
| 1181 | return ret; | ||
| 1182 | } | ||
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index f00f83109ab3..5ec6a9e23933 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
| @@ -1075,11 +1075,6 @@ static void __init early_reserve_mem(void) | |||
| 1075 | DBG("reserving: %llx -> %llx\n", base, size); | 1075 | DBG("reserving: %llx -> %llx\n", base, size); |
| 1076 | lmb_reserve(base, size); | 1076 | lmb_reserve(base, size); |
| 1077 | } | 1077 | } |
| 1078 | |||
| 1079 | #if 0 | ||
| 1080 | DBG("memory reserved, lmbs :\n"); | ||
| 1081 | lmb_dump_all(); | ||
| 1082 | #endif | ||
| 1083 | } | 1078 | } |
| 1084 | 1079 | ||
| 1085 | #ifdef CONFIG_PHYP_DUMP | 1080 | #ifdef CONFIG_PHYP_DUMP |
| @@ -1221,6 +1216,7 @@ void __init early_init_devtree(void *params) | |||
| 1221 | lmb_enforce_memory_limit(limit); | 1216 | lmb_enforce_memory_limit(limit); |
| 1222 | 1217 | ||
| 1223 | lmb_analyze(); | 1218 | lmb_analyze(); |
| 1219 | lmb_dump_all(); | ||
| 1224 | 1220 | ||
| 1225 | DBG("Phys. mem: %lx\n", lmb_phys_mem_size()); | 1221 | DBG("Phys. mem: %lx\n", lmb_phys_mem_size()); |
| 1226 | 1222 | ||
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index 7f1b33d5e30d..2e026c0407d4 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c | |||
| @@ -2283,6 +2283,8 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, | |||
| 2283 | */ | 2283 | */ |
| 2284 | prom_init_stdout(); | 2284 | prom_init_stdout(); |
| 2285 | 2285 | ||
| 2286 | prom_printf("Preparing to boot %s", RELOC(linux_banner)); | ||
| 2287 | |||
| 2286 | /* | 2288 | /* |
| 2287 | * Get default machine type. At this point, we do not differentiate | 2289 | * Get default machine type. At this point, we do not differentiate |
| 2288 | * between pSeries SMP and pSeries LPAR | 2290 | * between pSeries SMP and pSeries LPAR |
diff --git a/arch/powerpc/kernel/prom_init_check.sh b/arch/powerpc/kernel/prom_init_check.sh index ea3a2ec03ffa..1ac136b128f0 100644 --- a/arch/powerpc/kernel/prom_init_check.sh +++ b/arch/powerpc/kernel/prom_init_check.sh | |||
| @@ -20,7 +20,7 @@ WHITELIST="add_reloc_offset __bss_start __bss_stop copy_and_flush | |||
| 20 | _end enter_prom memcpy memset reloc_offset __secondary_hold | 20 | _end enter_prom memcpy memset reloc_offset __secondary_hold |
| 21 | __secondary_hold_acknowledge __secondary_hold_spinloop __start | 21 | __secondary_hold_acknowledge __secondary_hold_spinloop __start |
| 22 | strcmp strcpy strlcpy strlen strncmp strstr logo_linux_clut224 | 22 | strcmp strcpy strlcpy strlen strncmp strstr logo_linux_clut224 |
| 23 | reloc_got2 kernstart_addr memstart_addr" | 23 | reloc_got2 kernstart_addr memstart_addr linux_banner" |
| 24 | 24 | ||
| 25 | NM="$1" | 25 | NM="$1" |
| 26 | OBJ="$2" | 26 | OBJ="$2" |
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index fdfe14c4bdef..ee4c7609b649 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c | |||
| @@ -46,6 +46,7 @@ EXPORT_SYMBOL(rtas); | |||
| 46 | 46 | ||
| 47 | struct rtas_suspend_me_data { | 47 | struct rtas_suspend_me_data { |
| 48 | atomic_t working; /* number of cpus accessing this struct */ | 48 | atomic_t working; /* number of cpus accessing this struct */ |
| 49 | atomic_t done; | ||
| 49 | int token; /* ibm,suspend-me */ | 50 | int token; /* ibm,suspend-me */ |
| 50 | int error; | 51 | int error; |
| 51 | struct completion *complete; /* wait on this until working == 0 */ | 52 | struct completion *complete; /* wait on this until working == 0 */ |
| @@ -689,7 +690,7 @@ static int ibm_suspend_me_token = RTAS_UNKNOWN_SERVICE; | |||
| 689 | #ifdef CONFIG_PPC_PSERIES | 690 | #ifdef CONFIG_PPC_PSERIES |
| 690 | static void rtas_percpu_suspend_me(void *info) | 691 | static void rtas_percpu_suspend_me(void *info) |
| 691 | { | 692 | { |
| 692 | long rc; | 693 | long rc = H_SUCCESS; |
| 693 | unsigned long msr_save; | 694 | unsigned long msr_save; |
| 694 | int cpu; | 695 | int cpu; |
| 695 | struct rtas_suspend_me_data *data = | 696 | struct rtas_suspend_me_data *data = |
| @@ -701,7 +702,8 @@ static void rtas_percpu_suspend_me(void *info) | |||
| 701 | msr_save = mfmsr(); | 702 | msr_save = mfmsr(); |
| 702 | mtmsr(msr_save & ~(MSR_EE)); | 703 | mtmsr(msr_save & ~(MSR_EE)); |
| 703 | 704 | ||
| 704 | rc = plpar_hcall_norets(H_JOIN); | 705 | while (rc == H_SUCCESS && !atomic_read(&data->done)) |
| 706 | rc = plpar_hcall_norets(H_JOIN); | ||
| 705 | 707 | ||
| 706 | mtmsr(msr_save); | 708 | mtmsr(msr_save); |
| 707 | 709 | ||
| @@ -724,6 +726,9 @@ static void rtas_percpu_suspend_me(void *info) | |||
| 724 | smp_processor_id(), rc); | 726 | smp_processor_id(), rc); |
| 725 | data->error = rc; | 727 | data->error = rc; |
| 726 | } | 728 | } |
| 729 | |||
| 730 | atomic_set(&data->done, 1); | ||
| 731 | |||
| 727 | /* This cpu did the suspend or got an error; in either case, | 732 | /* This cpu did the suspend or got an error; in either case, |
| 728 | * we need to prod all other other cpus out of join state. | 733 | * we need to prod all other other cpus out of join state. |
| 729 | * Extra prods are harmless. | 734 | * Extra prods are harmless. |
| @@ -766,6 +771,7 @@ static int rtas_ibm_suspend_me(struct rtas_args *args) | |||
| 766 | } | 771 | } |
| 767 | 772 | ||
| 768 | atomic_set(&data.working, 0); | 773 | atomic_set(&data.working, 0); |
| 774 | atomic_set(&data.done, 0); | ||
| 769 | data.token = rtas_token("ibm,suspend-me"); | 775 | data.token = rtas_token("ibm,suspend-me"); |
| 770 | data.error = 0; | 776 | data.error = 0; |
| 771 | data.complete = &done; | 777 | data.complete = &done; |
diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c index 149cb112cd1a..13011a96a977 100644 --- a/arch/powerpc/kernel/rtas_flash.c +++ b/arch/powerpc/kernel/rtas_flash.c | |||
| @@ -669,7 +669,6 @@ static void remove_flash_pde(struct proc_dir_entry *dp) | |||
| 669 | { | 669 | { |
| 670 | if (dp) { | 670 | if (dp) { |
| 671 | kfree(dp->data); | 671 | kfree(dp->data); |
| 672 | dp->owner = NULL; | ||
| 673 | remove_proc_entry(dp->name, dp->parent); | 672 | remove_proc_entry(dp->name, dp->parent); |
| 674 | } | 673 | } |
| 675 | } | 674 | } |
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 705fc4bf3800..9774f9fed96e 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c | |||
| @@ -35,6 +35,8 @@ | |||
| 35 | #include <linux/debugfs.h> | 35 | #include <linux/debugfs.h> |
| 36 | #include <linux/percpu.h> | 36 | #include <linux/percpu.h> |
| 37 | #include <linux/lmb.h> | 37 | #include <linux/lmb.h> |
| 38 | #include <linux/of_platform.h> | ||
| 39 | #include <linux/platform_device.h> | ||
| 38 | #include <asm/io.h> | 40 | #include <asm/io.h> |
| 39 | #include <asm/prom.h> | 41 | #include <asm/prom.h> |
| 40 | #include <asm/processor.h> | 42 | #include <asm/processor.h> |
| @@ -669,3 +671,37 @@ static int powerpc_debugfs_init(void) | |||
| 669 | } | 671 | } |
| 670 | arch_initcall(powerpc_debugfs_init); | 672 | arch_initcall(powerpc_debugfs_init); |
| 671 | #endif | 673 | #endif |
| 674 | |||
| 675 | static int ppc_dflt_bus_notify(struct notifier_block *nb, | ||
| 676 | unsigned long action, void *data) | ||
| 677 | { | ||
| 678 | struct device *dev = data; | ||
| 679 | |||
| 680 | /* We are only intereted in device addition */ | ||
| 681 | if (action != BUS_NOTIFY_ADD_DEVICE) | ||
| 682 | return 0; | ||
| 683 | |||
| 684 | set_dma_ops(dev, &dma_direct_ops); | ||
| 685 | |||
| 686 | return NOTIFY_DONE; | ||
| 687 | } | ||
| 688 | |||
| 689 | static struct notifier_block ppc_dflt_plat_bus_notifier = { | ||
| 690 | .notifier_call = ppc_dflt_bus_notify, | ||
| 691 | .priority = INT_MAX, | ||
| 692 | }; | ||
| 693 | |||
| 694 | static struct notifier_block ppc_dflt_of_bus_notifier = { | ||
| 695 | .notifier_call = ppc_dflt_bus_notify, | ||
| 696 | .priority = INT_MAX, | ||
| 697 | }; | ||
| 698 | |||
| 699 | static int __init setup_bus_notifier(void) | ||
| 700 | { | ||
| 701 | bus_register_notifier(&platform_bus_type, &ppc_dflt_plat_bus_notifier); | ||
| 702 | bus_register_notifier(&of_platform_bus_type, &ppc_dflt_of_bus_notifier); | ||
| 703 | |||
| 704 | return 0; | ||
| 705 | } | ||
| 706 | |||
| 707 | arch_initcall(setup_bus_notifier); | ||
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index 2d34196bba8c..c410c606955d 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c | |||
| @@ -202,8 +202,6 @@ void __init early_setup(unsigned long dt_ptr) | |||
| 202 | 202 | ||
| 203 | /* Fix up paca fields required for the boot cpu */ | 203 | /* Fix up paca fields required for the boot cpu */ |
| 204 | get_paca()->cpu_start = 1; | 204 | get_paca()->cpu_start = 1; |
| 205 | get_paca()->stab_real = __pa((u64)&initial_stab); | ||
| 206 | get_paca()->stab_addr = (u64)&initial_stab; | ||
| 207 | 205 | ||
| 208 | /* Probe the machine type */ | 206 | /* Probe the machine type */ |
| 209 | probe_machine(); | 207 | probe_machine(); |
| @@ -212,20 +210,8 @@ void __init early_setup(unsigned long dt_ptr) | |||
| 212 | 210 | ||
| 213 | DBG("Found, Initializing memory management...\n"); | 211 | DBG("Found, Initializing memory management...\n"); |
| 214 | 212 | ||
| 215 | /* | 213 | /* Initialize the hash table or TLB handling */ |
| 216 | * Initialize the MMU Hash table and create the linear mapping | 214 | early_init_mmu(); |
| 217 | * of memory. Has to be done before stab/slb initialization as | ||
| 218 | * this is currently where the page size encoding is obtained | ||
| 219 | */ | ||
| 220 | htab_initialize(); | ||
| 221 | |||
| 222 | /* | ||
| 223 | * Initialize stab / SLB management except on iSeries | ||
| 224 | */ | ||
| 225 | if (cpu_has_feature(CPU_FTR_SLB)) | ||
| 226 | slb_initialize(); | ||
| 227 | else if (!firmware_has_feature(FW_FEATURE_ISERIES)) | ||
| 228 | stab_initialize(get_paca()->stab_real); | ||
| 229 | 215 | ||
| 230 | DBG(" <- early_setup()\n"); | 216 | DBG(" <- early_setup()\n"); |
| 231 | } | 217 | } |
| @@ -233,22 +219,11 @@ void __init early_setup(unsigned long dt_ptr) | |||
| 233 | #ifdef CONFIG_SMP | 219 | #ifdef CONFIG_SMP |
| 234 | void early_setup_secondary(void) | 220 | void early_setup_secondary(void) |
| 235 | { | 221 | { |
| 236 | struct paca_struct *lpaca = get_paca(); | ||
| 237 | |||
| 238 | /* Mark interrupts enabled in PACA */ | 222 | /* Mark interrupts enabled in PACA */ |
| 239 | lpaca->soft_enabled = 0; | 223 | get_paca()->soft_enabled = 0; |
| 240 | 224 | ||
| 241 | /* Initialize hash table for that CPU */ | 225 | /* Initialize the hash table or TLB handling */ |
| 242 | htab_initialize_secondary(); | 226 | early_init_mmu_secondary(); |
| 243 | |||
| 244 | /* Initialize STAB/SLB. We use a virtual address as it works | ||
| 245 | * in real mode on pSeries and we want a virutal address on | ||
| 246 | * iSeries anyway | ||
| 247 | */ | ||
| 248 | if (cpu_has_feature(CPU_FTR_SLB)) | ||
| 249 | slb_initialize(); | ||
| 250 | else | ||
| 251 | stab_initialize(lpaca->stab_addr); | ||
| 252 | } | 227 | } |
| 253 | 228 | ||
| 254 | #endif /* CONFIG_SMP */ | 229 | #endif /* CONFIG_SMP */ |
| @@ -578,13 +553,6 @@ void ppc64_boot_msg(unsigned int src, const char *msg) | |||
| 578 | printk("[boot]%04x %s\n", src, msg); | 553 | printk("[boot]%04x %s\n", src, msg); |
| 579 | } | 554 | } |
| 580 | 555 | ||
| 581 | /* Print a termination message (print only -- does not stop the kernel) */ | ||
| 582 | void ppc64_terminate_msg(unsigned int src, const char *msg) | ||
| 583 | { | ||
| 584 | ppc64_do_msg(PPC64_LINUX_FUNCTION|PPC64_TERM_MESSAGE|src, msg); | ||
| 585 | printk("[terminate]%04x %s\n", src, msg); | ||
| 586 | } | ||
| 587 | |||
| 588 | void cpu_die(void) | 556 | void cpu_die(void) |
| 589 | { | 557 | { |
| 590 | if (ppc_md.cpu_die) | 558 | if (ppc_md.cpu_die) |
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index a54405ebd7b0..00b5078da9a3 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c | |||
| @@ -26,12 +26,12 @@ int show_unhandled_signals = 0; | |||
| 26 | * Allocate space for the signal frame | 26 | * Allocate space for the signal frame |
| 27 | */ | 27 | */ |
| 28 | void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | 28 | void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, |
| 29 | size_t frame_size) | 29 | size_t frame_size, int is_32) |
| 30 | { | 30 | { |
| 31 | unsigned long oldsp, newsp; | 31 | unsigned long oldsp, newsp; |
| 32 | 32 | ||
| 33 | /* Default to using normal stack */ | 33 | /* Default to using normal stack */ |
| 34 | oldsp = regs->gpr[1]; | 34 | oldsp = get_clean_sp(regs, is_32); |
| 35 | 35 | ||
| 36 | /* Check for alt stack */ | 36 | /* Check for alt stack */ |
| 37 | if ((ka->sa.sa_flags & SA_ONSTACK) && | 37 | if ((ka->sa.sa_flags & SA_ONSTACK) && |
diff --git a/arch/powerpc/kernel/signal.h b/arch/powerpc/kernel/signal.h index b427bf8e1d8f..6c0ddfc0603e 100644 --- a/arch/powerpc/kernel/signal.h +++ b/arch/powerpc/kernel/signal.h | |||
| @@ -15,7 +15,7 @@ | |||
| 15 | extern void do_signal(struct pt_regs *regs, unsigned long thread_info_flags); | 15 | extern void do_signal(struct pt_regs *regs, unsigned long thread_info_flags); |
| 16 | 16 | ||
| 17 | extern void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | 17 | extern void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, |
| 18 | size_t frame_size); | 18 | size_t frame_size, int is_32); |
| 19 | extern void restore_sigmask(sigset_t *set); | 19 | extern void restore_sigmask(sigset_t *set); |
| 20 | 20 | ||
| 21 | extern int handle_signal32(unsigned long sig, struct k_sigaction *ka, | 21 | extern int handle_signal32(unsigned long sig, struct k_sigaction *ka, |
| @@ -39,22 +39,12 @@ extern unsigned long copy_vsx_from_user(struct task_struct *task, | |||
| 39 | 39 | ||
| 40 | #ifdef CONFIG_PPC64 | 40 | #ifdef CONFIG_PPC64 |
| 41 | 41 | ||
| 42 | static inline int is_32bit_task(void) | ||
| 43 | { | ||
| 44 | return test_thread_flag(TIF_32BIT); | ||
| 45 | } | ||
| 46 | |||
| 47 | extern int handle_rt_signal64(int signr, struct k_sigaction *ka, | 42 | extern int handle_rt_signal64(int signr, struct k_sigaction *ka, |
| 48 | siginfo_t *info, sigset_t *set, | 43 | siginfo_t *info, sigset_t *set, |
| 49 | struct pt_regs *regs); | 44 | struct pt_regs *regs); |
| 50 | 45 | ||
| 51 | #else /* CONFIG_PPC64 */ | 46 | #else /* CONFIG_PPC64 */ |
| 52 | 47 | ||
| 53 | static inline int is_32bit_task(void) | ||
| 54 | { | ||
| 55 | return 1; | ||
| 56 | } | ||
| 57 | |||
| 58 | static inline int handle_rt_signal64(int signr, struct k_sigaction *ka, | 48 | static inline int handle_rt_signal64(int signr, struct k_sigaction *ka, |
| 59 | siginfo_t *info, sigset_t *set, | 49 | siginfo_t *info, sigset_t *set, |
| 60 | struct pt_regs *regs) | 50 | struct pt_regs *regs) |
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index b13abf305996..d670429a1608 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c | |||
| @@ -836,7 +836,7 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka, | |||
| 836 | 836 | ||
| 837 | /* Set up Signal Frame */ | 837 | /* Set up Signal Frame */ |
| 838 | /* Put a Real Time Context onto stack */ | 838 | /* Put a Real Time Context onto stack */ |
| 839 | rt_sf = get_sigframe(ka, regs, sizeof(*rt_sf)); | 839 | rt_sf = get_sigframe(ka, regs, sizeof(*rt_sf), 1); |
| 840 | addr = rt_sf; | 840 | addr = rt_sf; |
| 841 | if (unlikely(rt_sf == NULL)) | 841 | if (unlikely(rt_sf == NULL)) |
| 842 | goto badframe; | 842 | goto badframe; |
| @@ -1182,7 +1182,7 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka, | |||
| 1182 | unsigned long newsp = 0; | 1182 | unsigned long newsp = 0; |
| 1183 | 1183 | ||
| 1184 | /* Set up Signal Frame */ | 1184 | /* Set up Signal Frame */ |
| 1185 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 1185 | frame = get_sigframe(ka, regs, sizeof(*frame), 1); |
| 1186 | if (unlikely(frame == NULL)) | 1186 | if (unlikely(frame == NULL)) |
| 1187 | goto badframe; | 1187 | goto badframe; |
| 1188 | sc = (struct sigcontext __user *) &frame->sctx; | 1188 | sc = (struct sigcontext __user *) &frame->sctx; |
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index e132891d3cea..2fe6fc64b614 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c | |||
| @@ -402,7 +402,7 @@ int handle_rt_signal64(int signr, struct k_sigaction *ka, siginfo_t *info, | |||
| 402 | unsigned long newsp = 0; | 402 | unsigned long newsp = 0; |
| 403 | long err = 0; | 403 | long err = 0; |
| 404 | 404 | ||
| 405 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 405 | frame = get_sigframe(ka, regs, sizeof(*frame), 0); |
| 406 | if (unlikely(frame == NULL)) | 406 | if (unlikely(frame == NULL)) |
| 407 | goto badframe; | 407 | goto badframe; |
| 408 | 408 | ||
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index 4a2ee08af6a7..f41aec85aa49 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c | |||
| @@ -134,44 +134,23 @@ void ppc_enable_pmcs(void) | |||
| 134 | } | 134 | } |
| 135 | EXPORT_SYMBOL(ppc_enable_pmcs); | 135 | EXPORT_SYMBOL(ppc_enable_pmcs); |
| 136 | 136 | ||
| 137 | #if defined(CONFIG_6xx) || defined(CONFIG_PPC64) | ||
| 138 | /* XXX convert to rusty's on_one_cpu */ | ||
| 139 | static unsigned long run_on_cpu(unsigned long cpu, | ||
| 140 | unsigned long (*func)(unsigned long), | ||
| 141 | unsigned long arg) | ||
| 142 | { | ||
| 143 | cpumask_t old_affinity = current->cpus_allowed; | ||
| 144 | unsigned long ret; | ||
| 145 | |||
| 146 | /* should return -EINVAL to userspace */ | ||
| 147 | if (set_cpus_allowed(current, cpumask_of_cpu(cpu))) | ||
| 148 | return 0; | ||
| 149 | |||
| 150 | ret = func(arg); | ||
| 151 | |||
| 152 | set_cpus_allowed(current, old_affinity); | ||
| 153 | |||
| 154 | return ret; | ||
| 155 | } | ||
| 156 | #endif | ||
| 157 | |||
| 158 | #define SYSFS_PMCSETUP(NAME, ADDRESS) \ | 137 | #define SYSFS_PMCSETUP(NAME, ADDRESS) \ |
| 159 | static unsigned long read_##NAME(unsigned long junk) \ | 138 | static void read_##NAME(void *val) \ |
| 160 | { \ | 139 | { \ |
| 161 | return mfspr(ADDRESS); \ | 140 | *(unsigned long *)val = mfspr(ADDRESS); \ |
| 162 | } \ | 141 | } \ |
| 163 | static unsigned long write_##NAME(unsigned long val) \ | 142 | static void write_##NAME(void *val) \ |
| 164 | { \ | 143 | { \ |
| 165 | ppc_enable_pmcs(); \ | 144 | ppc_enable_pmcs(); \ |
| 166 | mtspr(ADDRESS, val); \ | 145 | mtspr(ADDRESS, *(unsigned long *)val); \ |
| 167 | return 0; \ | ||
| 168 | } \ | 146 | } \ |
| 169 | static ssize_t show_##NAME(struct sys_device *dev, \ | 147 | static ssize_t show_##NAME(struct sys_device *dev, \ |
| 170 | struct sysdev_attribute *attr, \ | 148 | struct sysdev_attribute *attr, \ |
| 171 | char *buf) \ | 149 | char *buf) \ |
| 172 | { \ | 150 | { \ |
| 173 | struct cpu *cpu = container_of(dev, struct cpu, sysdev); \ | 151 | struct cpu *cpu = container_of(dev, struct cpu, sysdev); \ |
| 174 | unsigned long val = run_on_cpu(cpu->sysdev.id, read_##NAME, 0); \ | 152 | unsigned long val; \ |
| 153 | smp_call_function_single(cpu->sysdev.id, read_##NAME, &val, 1); \ | ||
| 175 | return sprintf(buf, "%lx\n", val); \ | 154 | return sprintf(buf, "%lx\n", val); \ |
| 176 | } \ | 155 | } \ |
| 177 | static ssize_t __used \ | 156 | static ssize_t __used \ |
| @@ -183,7 +162,7 @@ static ssize_t __used \ | |||
| 183 | int ret = sscanf(buf, "%lx", &val); \ | 162 | int ret = sscanf(buf, "%lx", &val); \ |
| 184 | if (ret != 1) \ | 163 | if (ret != 1) \ |
| 185 | return -EINVAL; \ | 164 | return -EINVAL; \ |
| 186 | run_on_cpu(cpu->sysdev.id, write_##NAME, val); \ | 165 | smp_call_function_single(cpu->sysdev.id, write_##NAME, &val, 1); \ |
| 187 | return count; \ | 166 | return count; \ |
| 188 | } | 167 | } |
| 189 | 168 | ||
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index c9564031a2a9..926ea864e34f 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c | |||
| @@ -1127,3 +1127,19 @@ void div128_by_32(u64 dividend_high, u64 dividend_low, | |||
| 1127 | dr->result_low = ((u64)y << 32) + z; | 1127 | dr->result_low = ((u64)y << 32) + z; |
| 1128 | 1128 | ||
| 1129 | } | 1129 | } |
| 1130 | |||
| 1131 | static int __init rtc_init(void) | ||
| 1132 | { | ||
| 1133 | struct platform_device *pdev; | ||
| 1134 | |||
| 1135 | if (!ppc_md.get_rtc_time) | ||
| 1136 | return -ENODEV; | ||
| 1137 | |||
| 1138 | pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0); | ||
| 1139 | if (IS_ERR(pdev)) | ||
| 1140 | return PTR_ERR(pdev); | ||
| 1141 | |||
| 1142 | return 0; | ||
| 1143 | } | ||
| 1144 | |||
| 1145 | module_init(rtc_init); | ||
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 5457e9575685..678fbff0d206 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
| @@ -52,6 +52,10 @@ | |||
| 52 | #include <asm/processor.h> | 52 | #include <asm/processor.h> |
| 53 | #endif | 53 | #endif |
| 54 | #include <asm/kexec.h> | 54 | #include <asm/kexec.h> |
| 55 | #include <asm/ppc-opcode.h> | ||
| 56 | #ifdef CONFIG_FSL_BOOKE | ||
| 57 | #include <asm/dbell.h> | ||
| 58 | #endif | ||
| 55 | 59 | ||
| 56 | #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) | 60 | #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) |
| 57 | int (*__debugger)(struct pt_regs *regs); | 61 | int (*__debugger)(struct pt_regs *regs); |
| @@ -637,29 +641,6 @@ static void parse_fpe(struct pt_regs *regs) | |||
| 637 | * bits is faster and easier. | 641 | * bits is faster and easier. |
| 638 | * | 642 | * |
| 639 | */ | 643 | */ |
| 640 | #define INST_MFSPR_PVR 0x7c1f42a6 | ||
| 641 | #define INST_MFSPR_PVR_MASK 0xfc1fffff | ||
| 642 | |||
| 643 | #define INST_DCBA 0x7c0005ec | ||
| 644 | #define INST_DCBA_MASK 0xfc0007fe | ||
| 645 | |||
| 646 | #define INST_MCRXR 0x7c000400 | ||
| 647 | #define INST_MCRXR_MASK 0xfc0007fe | ||
| 648 | |||
| 649 | #define INST_STRING 0x7c00042a | ||
| 650 | #define INST_STRING_MASK 0xfc0007fe | ||
| 651 | #define INST_STRING_GEN_MASK 0xfc00067e | ||
| 652 | #define INST_LSWI 0x7c0004aa | ||
| 653 | #define INST_LSWX 0x7c00042a | ||
| 654 | #define INST_STSWI 0x7c0005aa | ||
| 655 | #define INST_STSWX 0x7c00052a | ||
| 656 | |||
| 657 | #define INST_POPCNTB 0x7c0000f4 | ||
| 658 | #define INST_POPCNTB_MASK 0xfc0007fe | ||
| 659 | |||
| 660 | #define INST_ISEL 0x7c00001e | ||
| 661 | #define INST_ISEL_MASK 0xfc00003e | ||
| 662 | |||
| 663 | static int emulate_string_inst(struct pt_regs *regs, u32 instword) | 644 | static int emulate_string_inst(struct pt_regs *regs, u32 instword) |
| 664 | { | 645 | { |
| 665 | u8 rT = (instword >> 21) & 0x1f; | 646 | u8 rT = (instword >> 21) & 0x1f; |
| @@ -670,20 +651,20 @@ static int emulate_string_inst(struct pt_regs *regs, u32 instword) | |||
| 670 | int pos = 0; | 651 | int pos = 0; |
| 671 | 652 | ||
| 672 | /* Early out if we are an invalid form of lswx */ | 653 | /* Early out if we are an invalid form of lswx */ |
| 673 | if ((instword & INST_STRING_MASK) == INST_LSWX) | 654 | if ((instword & PPC_INST_STRING_MASK) == PPC_INST_LSWX) |
| 674 | if ((rT == rA) || (rT == NB_RB)) | 655 | if ((rT == rA) || (rT == NB_RB)) |
| 675 | return -EINVAL; | 656 | return -EINVAL; |
| 676 | 657 | ||
| 677 | EA = (rA == 0) ? 0 : regs->gpr[rA]; | 658 | EA = (rA == 0) ? 0 : regs->gpr[rA]; |
| 678 | 659 | ||
| 679 | switch (instword & INST_STRING_MASK) { | 660 | switch (instword & PPC_INST_STRING_MASK) { |
| 680 | case INST_LSWX: | 661 | case PPC_INST_LSWX: |
| 681 | case INST_STSWX: | 662 | case PPC_INST_STSWX: |
| 682 | EA += NB_RB; | 663 | EA += NB_RB; |
| 683 | num_bytes = regs->xer & 0x7f; | 664 | num_bytes = regs->xer & 0x7f; |
| 684 | break; | 665 | break; |
| 685 | case INST_LSWI: | 666 | case PPC_INST_LSWI: |
| 686 | case INST_STSWI: | 667 | case PPC_INST_STSWI: |
| 687 | num_bytes = (NB_RB == 0) ? 32 : NB_RB; | 668 | num_bytes = (NB_RB == 0) ? 32 : NB_RB; |
| 688 | break; | 669 | break; |
| 689 | default: | 670 | default: |
| @@ -695,9 +676,9 @@ static int emulate_string_inst(struct pt_regs *regs, u32 instword) | |||
| 695 | u8 val; | 676 | u8 val; |
| 696 | u32 shift = 8 * (3 - (pos & 0x3)); | 677 | u32 shift = 8 * (3 - (pos & 0x3)); |
| 697 | 678 | ||
| 698 | switch ((instword & INST_STRING_MASK)) { | 679 | switch ((instword & PPC_INST_STRING_MASK)) { |
| 699 | case INST_LSWX: | 680 | case PPC_INST_LSWX: |
| 700 | case INST_LSWI: | 681 | case PPC_INST_LSWI: |
| 701 | if (get_user(val, (u8 __user *)EA)) | 682 | if (get_user(val, (u8 __user *)EA)) |
| 702 | return -EFAULT; | 683 | return -EFAULT; |
| 703 | /* first time updating this reg, | 684 | /* first time updating this reg, |
| @@ -706,8 +687,8 @@ static int emulate_string_inst(struct pt_regs *regs, u32 instword) | |||
| 706 | regs->gpr[rT] = 0; | 687 | regs->gpr[rT] = 0; |
| 707 | regs->gpr[rT] |= val << shift; | 688 | regs->gpr[rT] |= val << shift; |
| 708 | break; | 689 | break; |
| 709 | case INST_STSWI: | 690 | case PPC_INST_STSWI: |
| 710 | case INST_STSWX: | 691 | case PPC_INST_STSWX: |
| 711 | val = regs->gpr[rT] >> shift; | 692 | val = regs->gpr[rT] >> shift; |
| 712 | if (put_user(val, (u8 __user *)EA)) | 693 | if (put_user(val, (u8 __user *)EA)) |
| 713 | return -EFAULT; | 694 | return -EFAULT; |
| @@ -775,18 +756,18 @@ static int emulate_instruction(struct pt_regs *regs) | |||
| 775 | return -EFAULT; | 756 | return -EFAULT; |
| 776 | 757 | ||
| 777 | /* Emulate the mfspr rD, PVR. */ | 758 | /* Emulate the mfspr rD, PVR. */ |
| 778 | if ((instword & INST_MFSPR_PVR_MASK) == INST_MFSPR_PVR) { | 759 | if ((instword & PPC_INST_MFSPR_PVR_MASK) == PPC_INST_MFSPR_PVR) { |
| 779 | rd = (instword >> 21) & 0x1f; | 760 | rd = (instword >> 21) & 0x1f; |
| 780 | regs->gpr[rd] = mfspr(SPRN_PVR); | 761 | regs->gpr[rd] = mfspr(SPRN_PVR); |
| 781 | return 0; | 762 | return 0; |
| 782 | } | 763 | } |
| 783 | 764 | ||
| 784 | /* Emulating the dcba insn is just a no-op. */ | 765 | /* Emulating the dcba insn is just a no-op. */ |
| 785 | if ((instword & INST_DCBA_MASK) == INST_DCBA) | 766 | if ((instword & PPC_INST_DCBA_MASK) == PPC_INST_DCBA) |
| 786 | return 0; | 767 | return 0; |
| 787 | 768 | ||
| 788 | /* Emulate the mcrxr insn. */ | 769 | /* Emulate the mcrxr insn. */ |
| 789 | if ((instword & INST_MCRXR_MASK) == INST_MCRXR) { | 770 | if ((instword & PPC_INST_MCRXR_MASK) == PPC_INST_MCRXR) { |
| 790 | int shift = (instword >> 21) & 0x1c; | 771 | int shift = (instword >> 21) & 0x1c; |
| 791 | unsigned long msk = 0xf0000000UL >> shift; | 772 | unsigned long msk = 0xf0000000UL >> shift; |
| 792 | 773 | ||
| @@ -796,16 +777,16 @@ static int emulate_instruction(struct pt_regs *regs) | |||
| 796 | } | 777 | } |
| 797 | 778 | ||
| 798 | /* Emulate load/store string insn. */ | 779 | /* Emulate load/store string insn. */ |
| 799 | if ((instword & INST_STRING_GEN_MASK) == INST_STRING) | 780 | if ((instword & PPC_INST_STRING_GEN_MASK) == PPC_INST_STRING) |
| 800 | return emulate_string_inst(regs, instword); | 781 | return emulate_string_inst(regs, instword); |
| 801 | 782 | ||
| 802 | /* Emulate the popcntb (Population Count Bytes) instruction. */ | 783 | /* Emulate the popcntb (Population Count Bytes) instruction. */ |
| 803 | if ((instword & INST_POPCNTB_MASK) == INST_POPCNTB) { | 784 | if ((instword & PPC_INST_POPCNTB_MASK) == PPC_INST_POPCNTB) { |
| 804 | return emulate_popcntb_inst(regs, instword); | 785 | return emulate_popcntb_inst(regs, instword); |
| 805 | } | 786 | } |
| 806 | 787 | ||
| 807 | /* Emulate isel (Integer Select) instruction */ | 788 | /* Emulate isel (Integer Select) instruction */ |
| 808 | if ((instword & INST_ISEL_MASK) == INST_ISEL) { | 789 | if ((instword & PPC_INST_ISEL_MASK) == PPC_INST_ISEL) { |
| 809 | return emulate_isel(regs, instword); | 790 | return emulate_isel(regs, instword); |
| 810 | } | 791 | } |
| 811 | 792 | ||
| @@ -1144,6 +1125,24 @@ void vsx_assist_exception(struct pt_regs *regs) | |||
| 1144 | #endif /* CONFIG_VSX */ | 1125 | #endif /* CONFIG_VSX */ |
| 1145 | 1126 | ||
| 1146 | #ifdef CONFIG_FSL_BOOKE | 1127 | #ifdef CONFIG_FSL_BOOKE |
| 1128 | |||
| 1129 | void doorbell_exception(struct pt_regs *regs) | ||
| 1130 | { | ||
| 1131 | #ifdef CONFIG_SMP | ||
| 1132 | int cpu = smp_processor_id(); | ||
| 1133 | int msg; | ||
| 1134 | |||
| 1135 | if (num_online_cpus() < 2) | ||
| 1136 | return; | ||
| 1137 | |||
| 1138 | for (msg = 0; msg < 4; msg++) | ||
| 1139 | if (test_and_clear_bit(msg, &dbell_smp_message[cpu])) | ||
| 1140 | smp_message_recv(msg); | ||
| 1141 | #else | ||
| 1142 | printk(KERN_WARNING "Received doorbell on non-smp system\n"); | ||
| 1143 | #endif | ||
| 1144 | } | ||
| 1145 | |||
| 1147 | void CacheLockingException(struct pt_regs *regs, unsigned long address, | 1146 | void CacheLockingException(struct pt_regs *regs, unsigned long address, |
| 1148 | unsigned long error_code) | 1147 | unsigned long error_code) |
| 1149 | { | 1148 | { |
diff --git a/arch/powerpc/kernel/udbg.c b/arch/powerpc/kernel/udbg.c index 7d6c9bb8c77f..fc9af47e2128 100644 --- a/arch/powerpc/kernel/udbg.c +++ b/arch/powerpc/kernel/udbg.c | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | #include <asm/udbg.h> | 18 | #include <asm/udbg.h> |
| 19 | 19 | ||
| 20 | void (*udbg_putc)(char c); | 20 | void (*udbg_putc)(char c); |
| 21 | void (*udbg_flush)(void); | ||
| 21 | int (*udbg_getc)(void); | 22 | int (*udbg_getc)(void); |
| 22 | int (*udbg_getc_poll)(void); | 23 | int (*udbg_getc_poll)(void); |
| 23 | 24 | ||
| @@ -76,6 +77,9 @@ void udbg_puts(const char *s) | |||
| 76 | while ((c = *s++) != '\0') | 77 | while ((c = *s++) != '\0') |
| 77 | udbg_putc(c); | 78 | udbg_putc(c); |
| 78 | } | 79 | } |
| 80 | |||
| 81 | if (udbg_flush) | ||
| 82 | udbg_flush(); | ||
| 79 | } | 83 | } |
| 80 | #if 0 | 84 | #if 0 |
| 81 | else { | 85 | else { |
| @@ -98,6 +102,9 @@ int udbg_write(const char *s, int n) | |||
| 98 | } | 102 | } |
| 99 | } | 103 | } |
| 100 | 104 | ||
| 105 | if (udbg_flush) | ||
| 106 | udbg_flush(); | ||
| 107 | |||
| 101 | return n - remain; | 108 | return n - remain; |
| 102 | } | 109 | } |
| 103 | 110 | ||
diff --git a/arch/powerpc/kernel/udbg_16550.c b/arch/powerpc/kernel/udbg_16550.c index 7b7da8cfd5e8..0362a891e54e 100644 --- a/arch/powerpc/kernel/udbg_16550.c +++ b/arch/powerpc/kernel/udbg_16550.c | |||
| @@ -48,14 +48,21 @@ struct NS16550 { | |||
| 48 | 48 | ||
| 49 | static struct NS16550 __iomem *udbg_comport; | 49 | static struct NS16550 __iomem *udbg_comport; |
| 50 | 50 | ||
| 51 | static void udbg_550_putc(char c) | 51 | static void udbg_550_flush(void) |
| 52 | { | 52 | { |
| 53 | if (udbg_comport) { | 53 | if (udbg_comport) { |
| 54 | while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0) | 54 | while ((in_8(&udbg_comport->lsr) & LSR_THRE) == 0) |
| 55 | /* wait for idle */; | 55 | /* wait for idle */; |
| 56 | out_8(&udbg_comport->thr, c); | 56 | } |
| 57 | } | ||
| 58 | |||
| 59 | static void udbg_550_putc(char c) | ||
| 60 | { | ||
| 61 | if (udbg_comport) { | ||
| 57 | if (c == '\n') | 62 | if (c == '\n') |
| 58 | udbg_550_putc('\r'); | 63 | udbg_550_putc('\r'); |
| 64 | udbg_550_flush(); | ||
| 65 | out_8(&udbg_comport->thr, c); | ||
| 59 | } | 66 | } |
| 60 | } | 67 | } |
| 61 | 68 | ||
| @@ -108,6 +115,7 @@ void udbg_init_uart(void __iomem *comport, unsigned int speed, | |||
| 108 | /* Clear & enable FIFOs */ | 115 | /* Clear & enable FIFOs */ |
| 109 | out_8(&udbg_comport->fcr ,0x07); | 116 | out_8(&udbg_comport->fcr ,0x07); |
| 110 | udbg_putc = udbg_550_putc; | 117 | udbg_putc = udbg_550_putc; |
| 118 | udbg_flush = udbg_550_flush; | ||
| 111 | udbg_getc = udbg_550_getc; | 119 | udbg_getc = udbg_550_getc; |
| 112 | udbg_getc_poll = udbg_550_getc_poll; | 120 | udbg_getc_poll = udbg_550_getc_poll; |
| 113 | } | 121 | } |
| @@ -149,14 +157,21 @@ unsigned int udbg_probe_uart_speed(void __iomem *comport, unsigned int clock) | |||
| 149 | } | 157 | } |
| 150 | 158 | ||
| 151 | #ifdef CONFIG_PPC_MAPLE | 159 | #ifdef CONFIG_PPC_MAPLE |
| 152 | void udbg_maple_real_putc(char c) | 160 | void udbg_maple_real_flush(void) |
| 153 | { | 161 | { |
| 154 | if (udbg_comport) { | 162 | if (udbg_comport) { |
| 155 | while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0) | 163 | while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0) |
| 156 | /* wait for idle */; | 164 | /* wait for idle */; |
| 157 | real_writeb(c, &udbg_comport->thr); eieio(); | 165 | } |
| 166 | } | ||
| 167 | |||
| 168 | void udbg_maple_real_putc(char c) | ||
| 169 | { | ||
| 170 | if (udbg_comport) { | ||
| 158 | if (c == '\n') | 171 | if (c == '\n') |
| 159 | udbg_maple_real_putc('\r'); | 172 | udbg_maple_real_putc('\r'); |
| 173 | udbg_maple_real_flush(); | ||
| 174 | real_writeb(c, &udbg_comport->thr); eieio(); | ||
| 160 | } | 175 | } |
| 161 | } | 176 | } |
| 162 | 177 | ||
| @@ -165,20 +180,28 @@ void __init udbg_init_maple_realmode(void) | |||
| 165 | udbg_comport = (struct NS16550 __iomem *)0xf40003f8; | 180 | udbg_comport = (struct NS16550 __iomem *)0xf40003f8; |
| 166 | 181 | ||
| 167 | udbg_putc = udbg_maple_real_putc; | 182 | udbg_putc = udbg_maple_real_putc; |
| 183 | udbg_flush = udbg_maple_real_flush; | ||
| 168 | udbg_getc = NULL; | 184 | udbg_getc = NULL; |
| 169 | udbg_getc_poll = NULL; | 185 | udbg_getc_poll = NULL; |
| 170 | } | 186 | } |
| 171 | #endif /* CONFIG_PPC_MAPLE */ | 187 | #endif /* CONFIG_PPC_MAPLE */ |
| 172 | 188 | ||
| 173 | #ifdef CONFIG_PPC_PASEMI | 189 | #ifdef CONFIG_PPC_PASEMI |
| 174 | void udbg_pas_real_putc(char c) | 190 | void udbg_pas_real_flush(void) |
| 175 | { | 191 | { |
| 176 | if (udbg_comport) { | 192 | if (udbg_comport) { |
| 177 | while ((real_205_readb(&udbg_comport->lsr) & LSR_THRE) == 0) | 193 | while ((real_205_readb(&udbg_comport->lsr) & LSR_THRE) == 0) |
| 178 | /* wait for idle */; | 194 | /* wait for idle */; |
| 179 | real_205_writeb(c, &udbg_comport->thr); eieio(); | 195 | } |
| 196 | } | ||
| 197 | |||
| 198 | void udbg_pas_real_putc(char c) | ||
| 199 | { | ||
| 200 | if (udbg_comport) { | ||
| 180 | if (c == '\n') | 201 | if (c == '\n') |
| 181 | udbg_pas_real_putc('\r'); | 202 | udbg_pas_real_putc('\r'); |
| 203 | udbg_pas_real_flush(); | ||
| 204 | real_205_writeb(c, &udbg_comport->thr); eieio(); | ||
| 182 | } | 205 | } |
| 183 | } | 206 | } |
| 184 | 207 | ||
| @@ -187,6 +210,7 @@ void udbg_init_pas_realmode(void) | |||
| 187 | udbg_comport = (struct NS16550 __iomem *)0xfcff03f8UL; | 210 | udbg_comport = (struct NS16550 __iomem *)0xfcff03f8UL; |
| 188 | 211 | ||
| 189 | udbg_putc = udbg_pas_real_putc; | 212 | udbg_putc = udbg_pas_real_putc; |
| 213 | udbg_flush = udbg_pas_real_flush; | ||
| 190 | udbg_getc = NULL; | 214 | udbg_getc = NULL; |
| 191 | udbg_getc_poll = NULL; | 215 | udbg_getc_poll = NULL; |
| 192 | } | 216 | } |
| @@ -195,14 +219,21 @@ void udbg_init_pas_realmode(void) | |||
| 195 | #ifdef CONFIG_PPC_EARLY_DEBUG_44x | 219 | #ifdef CONFIG_PPC_EARLY_DEBUG_44x |
| 196 | #include <platforms/44x/44x.h> | 220 | #include <platforms/44x/44x.h> |
| 197 | 221 | ||
| 198 | static void udbg_44x_as1_putc(char c) | 222 | static int udbg_44x_as1_flush(void) |
| 199 | { | 223 | { |
| 200 | if (udbg_comport) { | 224 | if (udbg_comport) { |
| 201 | while ((as1_readb(&udbg_comport->lsr) & LSR_THRE) == 0) | 225 | while ((as1_readb(&udbg_comport->lsr) & LSR_THRE) == 0) |
| 202 | /* wait for idle */; | 226 | /* wait for idle */; |
| 203 | as1_writeb(c, &udbg_comport->thr); eieio(); | 227 | } |
| 228 | } | ||
| 229 | |||
| 230 | static void udbg_44x_as1_putc(char c) | ||
| 231 | { | ||
| 232 | if (udbg_comport) { | ||
| 204 | if (c == '\n') | 233 | if (c == '\n') |
| 205 | udbg_44x_as1_putc('\r'); | 234 | udbg_44x_as1_putc('\r'); |
| 235 | udbg_44x_as1_flush(); | ||
| 236 | as1_writeb(c, &udbg_comport->thr); eieio(); | ||
| 206 | } | 237 | } |
| 207 | } | 238 | } |
| 208 | 239 | ||
| @@ -222,19 +253,27 @@ void __init udbg_init_44x_as1(void) | |||
| 222 | (struct NS16550 __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR; | 253 | (struct NS16550 __iomem *)PPC44x_EARLY_DEBUG_VIRTADDR; |
| 223 | 254 | ||
| 224 | udbg_putc = udbg_44x_as1_putc; | 255 | udbg_putc = udbg_44x_as1_putc; |
| 256 | udbg_flush = udbg_44x_as1_flush; | ||
| 225 | udbg_getc = udbg_44x_as1_getc; | 257 | udbg_getc = udbg_44x_as1_getc; |
| 226 | } | 258 | } |
| 227 | #endif /* CONFIG_PPC_EARLY_DEBUG_44x */ | 259 | #endif /* CONFIG_PPC_EARLY_DEBUG_44x */ |
| 228 | 260 | ||
| 229 | #ifdef CONFIG_PPC_EARLY_DEBUG_40x | 261 | #ifdef CONFIG_PPC_EARLY_DEBUG_40x |
| 230 | static void udbg_40x_real_putc(char c) | 262 | static void udbg_40x_real_flush(void) |
| 231 | { | 263 | { |
| 232 | if (udbg_comport) { | 264 | if (udbg_comport) { |
| 233 | while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0) | 265 | while ((real_readb(&udbg_comport->lsr) & LSR_THRE) == 0) |
| 234 | /* wait for idle */; | 266 | /* wait for idle */; |
| 235 | real_writeb(c, &udbg_comport->thr); eieio(); | 267 | } |
| 268 | } | ||
| 269 | |||
| 270 | static void udbg_40x_real_putc(char c) | ||
| 271 | { | ||
| 272 | if (udbg_comport) { | ||
| 236 | if (c == '\n') | 273 | if (c == '\n') |
| 237 | udbg_40x_real_putc('\r'); | 274 | udbg_40x_real_putc('\r'); |
| 275 | udbg_40x_real_flush(); | ||
| 276 | real_writeb(c, &udbg_comport->thr); eieio(); | ||
| 238 | } | 277 | } |
| 239 | } | 278 | } |
| 240 | 279 | ||
| @@ -254,6 +293,7 @@ void __init udbg_init_40x_realmode(void) | |||
| 254 | CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR; | 293 | CONFIG_PPC_EARLY_DEBUG_40x_PHYSADDR; |
| 255 | 294 | ||
| 256 | udbg_putc = udbg_40x_real_putc; | 295 | udbg_putc = udbg_40x_real_putc; |
| 296 | udbg_flush = udbg_40x_real_flush; | ||
| 257 | udbg_getc = udbg_40x_real_getc; | 297 | udbg_getc = udbg_40x_real_getc; |
| 258 | udbg_getc_poll = NULL; | 298 | udbg_getc_poll = NULL; |
| 259 | } | 299 | } |
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index d3694498f3af..819e59f6f7c7 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c | |||
| @@ -482,7 +482,7 @@ static void vio_cmo_balance(struct work_struct *work) | |||
| 482 | cmo->excess.size = cmo->entitled - cmo->reserve.size; | 482 | cmo->excess.size = cmo->entitled - cmo->reserve.size; |
| 483 | cmo->excess.free = cmo->excess.size - need; | 483 | cmo->excess.free = cmo->excess.size - need; |
| 484 | 484 | ||
| 485 | cancel_delayed_work(container_of(work, struct delayed_work, work)); | 485 | cancel_delayed_work(to_delayed_work(work)); |
| 486 | spin_unlock_irqrestore(&vio_cmo.lock, flags); | 486 | spin_unlock_irqrestore(&vio_cmo.lock, flags); |
| 487 | } | 487 | } |
| 488 | 488 | ||
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 295ccc5e86b1..b9ef1644a722 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S | |||
| @@ -58,6 +58,7 @@ SECTIONS | |||
| 58 | SCHED_TEXT | 58 | SCHED_TEXT |
| 59 | LOCK_TEXT | 59 | LOCK_TEXT |
| 60 | KPROBES_TEXT | 60 | KPROBES_TEXT |
| 61 | IRQENTRY_TEXT | ||
| 61 | 62 | ||
| 62 | #ifdef CONFIG_PPC32 | 63 | #ifdef CONFIG_PPC32 |
| 63 | *(.got1) | 64 | *(.got1) |
| @@ -181,14 +182,7 @@ SECTIONS | |||
| 181 | __initramfs_end = .; | 182 | __initramfs_end = .; |
| 182 | } | 183 | } |
| 183 | #endif | 184 | #endif |
| 184 | . = ALIGN(PAGE_SIZE); | 185 | PERCPU(PAGE_SIZE) |
| 185 | .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { | ||
| 186 | __per_cpu_start = .; | ||
| 187 | *(.data.percpu.page_aligned) | ||
| 188 | *(.data.percpu) | ||
| 189 | *(.data.percpu.shared_aligned) | ||
| 190 | __per_cpu_end = .; | ||
| 191 | } | ||
| 192 | 186 | ||
| 193 | . = ALIGN(8); | 187 | . = ALIGN(8); |
| 194 | .machine.desc : AT(ADDR(.machine.desc) - LOAD_OFFSET) { | 188 | .machine.desc : AT(ADDR(.machine.desc) - LOAD_OFFSET) { |
