diff options
Diffstat (limited to 'arch/mips/kernel')
61 files changed, 2602 insertions, 722 deletions
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 06f848299785..83bba332bbfc 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile | |||
| @@ -52,6 +52,7 @@ obj-$(CONFIG_CPU_TX39XX) += r2300_fpu.o r2300_switch.o | |||
| 52 | obj-$(CONFIG_CPU_TX49XX) += r4k_fpu.o r4k_switch.o | 52 | obj-$(CONFIG_CPU_TX49XX) += r4k_fpu.o r4k_switch.o |
| 53 | obj-$(CONFIG_CPU_VR41XX) += r4k_fpu.o r4k_switch.o | 53 | obj-$(CONFIG_CPU_VR41XX) += r4k_fpu.o r4k_switch.o |
| 54 | obj-$(CONFIG_CPU_CAVIUM_OCTEON) += octeon_switch.o | 54 | obj-$(CONFIG_CPU_CAVIUM_OCTEON) += octeon_switch.o |
| 55 | obj-$(CONFIG_CPU_XLR) += r4k_fpu.o r4k_switch.o | ||
| 55 | 56 | ||
| 56 | obj-$(CONFIG_SMP) += smp.o | 57 | obj-$(CONFIG_SMP) += smp.o |
| 57 | obj-$(CONFIG_SMP_UP) += smp-up.o | 58 | obj-$(CONFIG_SMP_UP) += smp-up.o |
| @@ -95,6 +96,9 @@ obj-$(CONFIG_GPIO_TXX9) += gpio_txx9.o | |||
| 95 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o | 96 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o |
| 96 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | 97 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
| 97 | obj-$(CONFIG_SPINLOCK_TEST) += spinlock_test.o | 98 | obj-$(CONFIG_SPINLOCK_TEST) += spinlock_test.o |
| 99 | obj-$(CONFIG_MIPS_MACHINE) += mips_machine.o | ||
| 100 | |||
| 101 | obj-$(CONFIG_OF) += prom.o | ||
| 98 | 102 | ||
| 99 | CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi) | 103 | CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi) |
| 100 | 104 | ||
| @@ -102,4 +106,8 @@ obj-$(CONFIG_HAVE_STD_PC_SERIAL_PORT) += 8250-platform.o | |||
| 102 | 106 | ||
| 103 | obj-$(CONFIG_MIPS_CPUFREQ) += cpufreq/ | 107 | obj-$(CONFIG_MIPS_CPUFREQ) += cpufreq/ |
| 104 | 108 | ||
| 109 | obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o | ||
| 110 | |||
| 111 | obj-$(CONFIG_JUMP_LABEL) += jump_label.o | ||
| 112 | |||
| 105 | CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS) | 113 | CPPFLAGS_vmlinux.lds := $(KBUILD_CFLAGS) |
diff --git a/arch/mips/kernel/cevt-bcm1480.c b/arch/mips/kernel/cevt-bcm1480.c index bfea327c636c..36c3898b76db 100644 --- a/arch/mips/kernel/cevt-bcm1480.c +++ b/arch/mips/kernel/cevt-bcm1480.c | |||
| @@ -19,6 +19,7 @@ | |||
| 19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
| 20 | #include <linux/percpu.h> | 20 | #include <linux/percpu.h> |
| 21 | #include <linux/smp.h> | 21 | #include <linux/smp.h> |
| 22 | #include <linux/irq.h> | ||
| 22 | 23 | ||
| 23 | #include <asm/addrspace.h> | 24 | #include <asm/addrspace.h> |
| 24 | #include <asm/io.h> | 25 | #include <asm/io.h> |
diff --git a/arch/mips/kernel/cevt-ds1287.c b/arch/mips/kernel/cevt-ds1287.c index 00a4da277cbb..939157e397b9 100644 --- a/arch/mips/kernel/cevt-ds1287.c +++ b/arch/mips/kernel/cevt-ds1287.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
| 22 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
| 23 | #include <linux/mc146818rtc.h> | 23 | #include <linux/mc146818rtc.h> |
| 24 | #include <linux/irq.h> | ||
| 24 | 25 | ||
| 25 | #include <asm/time.h> | 26 | #include <asm/time.h> |
| 26 | 27 | ||
diff --git a/arch/mips/kernel/cevt-gt641xx.c b/arch/mips/kernel/cevt-gt641xx.c index 392ef3756c56..339f3639b90e 100644 --- a/arch/mips/kernel/cevt-gt641xx.c +++ b/arch/mips/kernel/cevt-gt641xx.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
| 22 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
| 23 | #include <linux/spinlock.h> | 23 | #include <linux/spinlock.h> |
| 24 | #include <linux/irq.h> | ||
| 24 | 25 | ||
| 25 | #include <asm/gt64120.h> | 26 | #include <asm/gt64120.h> |
| 26 | #include <asm/time.h> | 27 | #include <asm/time.h> |
diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c index 2a4d50ff5e2c..98c5a9737c14 100644 --- a/arch/mips/kernel/cevt-r4k.c +++ b/arch/mips/kernel/cevt-r4k.c | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <linux/interrupt.h> | 10 | #include <linux/interrupt.h> |
| 11 | #include <linux/percpu.h> | 11 | #include <linux/percpu.h> |
| 12 | #include <linux/smp.h> | 12 | #include <linux/smp.h> |
| 13 | #include <linux/irq.h> | ||
| 13 | 14 | ||
| 14 | #include <asm/smtc_ipi.h> | 15 | #include <asm/smtc_ipi.h> |
| 15 | #include <asm/time.h> | 16 | #include <asm/time.h> |
| @@ -31,7 +32,7 @@ static int mips_next_event(unsigned long delta, | |||
| 31 | cnt = read_c0_count(); | 32 | cnt = read_c0_count(); |
| 32 | cnt += delta; | 33 | cnt += delta; |
| 33 | write_c0_compare(cnt); | 34 | write_c0_compare(cnt); |
| 34 | res = ((int)(read_c0_count() - cnt) > 0) ? -ETIME : 0; | 35 | res = ((int)(read_c0_count() - cnt) >= 0) ? -ETIME : 0; |
| 35 | return res; | 36 | return res; |
| 36 | } | 37 | } |
| 37 | 38 | ||
diff --git a/arch/mips/kernel/cevt-sb1250.c b/arch/mips/kernel/cevt-sb1250.c index da78eeaea6e8..590c54f28a81 100644 --- a/arch/mips/kernel/cevt-sb1250.c +++ b/arch/mips/kernel/cevt-sb1250.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | */ | 17 | */ |
| 18 | #include <linux/clockchips.h> | 18 | #include <linux/clockchips.h> |
| 19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
| 20 | #include <linux/irq.h> | ||
| 20 | #include <linux/percpu.h> | 21 | #include <linux/percpu.h> |
| 21 | #include <linux/smp.h> | 22 | #include <linux/smp.h> |
| 22 | 23 | ||
diff --git a/arch/mips/kernel/cevt-smtc.c b/arch/mips/kernel/cevt-smtc.c index b102e4f1630e..2e72d30b2f05 100644 --- a/arch/mips/kernel/cevt-smtc.c +++ b/arch/mips/kernel/cevt-smtc.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include <linux/interrupt.h> | 11 | #include <linux/interrupt.h> |
| 12 | #include <linux/percpu.h> | 12 | #include <linux/percpu.h> |
| 13 | #include <linux/smp.h> | 13 | #include <linux/smp.h> |
| 14 | #include <linux/irq.h> | ||
| 14 | 15 | ||
| 15 | #include <asm/smtc_ipi.h> | 16 | #include <asm/smtc_ipi.h> |
| 16 | #include <asm/time.h> | 17 | #include <asm/time.h> |
diff --git a/arch/mips/kernel/cevt-txx9.c b/arch/mips/kernel/cevt-txx9.c index 218ee6bda935..f0ab92a1b057 100644 --- a/arch/mips/kernel/cevt-txx9.c +++ b/arch/mips/kernel/cevt-txx9.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | */ | 13 | */ |
| 14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
| 15 | #include <linux/interrupt.h> | 15 | #include <linux/interrupt.h> |
| 16 | #include <linux/irq.h> | ||
| 16 | #include <asm/time.h> | 17 | #include <asm/time.h> |
| 17 | #include <asm/txx9tmr.h> | 18 | #include <asm/txx9tmr.h> |
| 18 | 19 | ||
| @@ -50,8 +51,7 @@ void __init txx9_clocksource_init(unsigned long baseaddr, | |||
| 50 | { | 51 | { |
| 51 | struct txx9_tmr_reg __iomem *tmrptr; | 52 | struct txx9_tmr_reg __iomem *tmrptr; |
| 52 | 53 | ||
| 53 | clocksource_set_clock(&txx9_clocksource.cs, TIMER_CLK(imbusclk)); | 54 | clocksource_register_hz(&txx9_clocksource.cs, TIMER_CLK(imbusclk)); |
| 54 | clocksource_register(&txx9_clocksource.cs); | ||
| 55 | 55 | ||
| 56 | tmrptr = ioremap(baseaddr, sizeof(struct txx9_tmr_reg)); | 56 | tmrptr = ioremap(baseaddr, sizeof(struct txx9_tmr_reg)); |
| 57 | __raw_writel(TCR_BASE, &tmrptr->tcr); | 57 | __raw_writel(TCR_BASE, &tmrptr->tcr); |
diff --git a/arch/mips/kernel/cpu-bugs64.c b/arch/mips/kernel/cpu-bugs64.c index b8bb8ba60869..f305ca14351b 100644 --- a/arch/mips/kernel/cpu-bugs64.c +++ b/arch/mips/kernel/cpu-bugs64.c | |||
| @@ -73,7 +73,7 @@ static inline void mult_sh_align_mod(long *v1, long *v2, long *w, | |||
| 73 | : "0" (5), "1" (8), "2" (5)); | 73 | : "0" (5), "1" (8), "2" (5)); |
| 74 | align_mod(align, mod); | 74 | align_mod(align, mod); |
| 75 | /* | 75 | /* |
| 76 | * The trailing nop is needed to fullfill the two-instruction | 76 | * The trailing nop is needed to fulfill the two-instruction |
| 77 | * requirement between reading hi/lo and staring a mult/div. | 77 | * requirement between reading hi/lo and staring a mult/div. |
| 78 | * Leaving it out may cause gas insert a nop itself breaking | 78 | * Leaving it out may cause gas insert a nop itself breaking |
| 79 | * the desired alignment of the next chunk. | 79 | * the desired alignment of the next chunk. |
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index b1b304ea2128..bb133d10b145 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c | |||
| @@ -25,6 +25,8 @@ | |||
| 25 | #include <asm/system.h> | 25 | #include <asm/system.h> |
| 26 | #include <asm/watch.h> | 26 | #include <asm/watch.h> |
| 27 | #include <asm/spram.h> | 27 | #include <asm/spram.h> |
| 28 | #include <asm/uaccess.h> | ||
| 29 | |||
| 28 | /* | 30 | /* |
| 29 | * Not all of the MIPS CPUs have the "wait" instruction available. Moreover, | 31 | * Not all of the MIPS CPUs have the "wait" instruction available. Moreover, |
| 30 | * the implementation of the "wait" feature differs between CPU families. This | 32 | * the implementation of the "wait" feature differs between CPU families. This |
| @@ -181,12 +183,13 @@ void __init check_wait(void) | |||
| 181 | case CPU_5KC: | 183 | case CPU_5KC: |
| 182 | case CPU_25KF: | 184 | case CPU_25KF: |
| 183 | case CPU_PR4450: | 185 | case CPU_PR4450: |
| 184 | case CPU_BCM3302: | 186 | case CPU_BMIPS3300: |
| 185 | case CPU_BCM6338: | 187 | case CPU_BMIPS4350: |
| 186 | case CPU_BCM6348: | 188 | case CPU_BMIPS4380: |
| 187 | case CPU_BCM6358: | 189 | case CPU_BMIPS5000: |
| 188 | case CPU_CAVIUM_OCTEON: | 190 | case CPU_CAVIUM_OCTEON: |
| 189 | case CPU_CAVIUM_OCTEON_PLUS: | 191 | case CPU_CAVIUM_OCTEON_PLUS: |
| 192 | case CPU_CAVIUM_OCTEON2: | ||
| 190 | case CPU_JZRISC: | 193 | case CPU_JZRISC: |
| 191 | cpu_wait = r4k_wait; | 194 | cpu_wait = r4k_wait; |
| 192 | break; | 195 | break; |
| @@ -288,6 +291,12 @@ static inline int cpu_has_confreg(void) | |||
| 288 | #endif | 291 | #endif |
| 289 | } | 292 | } |
| 290 | 293 | ||
| 294 | static inline void set_elf_platform(int cpu, const char *plat) | ||
| 295 | { | ||
| 296 | if (cpu == 0) | ||
| 297 | __elf_platform = plat; | ||
| 298 | } | ||
| 299 | |||
| 291 | /* | 300 | /* |
| 292 | * Get the FPU Implementation/Revision. | 301 | * Get the FPU Implementation/Revision. |
| 293 | */ | 302 | */ |
| @@ -611,6 +620,16 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu) | |||
| 611 | case PRID_IMP_LOONGSON2: | 620 | case PRID_IMP_LOONGSON2: |
| 612 | c->cputype = CPU_LOONGSON2; | 621 | c->cputype = CPU_LOONGSON2; |
| 613 | __cpu_name[cpu] = "ICT Loongson-2"; | 622 | __cpu_name[cpu] = "ICT Loongson-2"; |
| 623 | |||
| 624 | switch (c->processor_id & PRID_REV_MASK) { | ||
| 625 | case PRID_REV_LOONGSON2E: | ||
| 626 | set_elf_platform(cpu, "loongson2e"); | ||
| 627 | break; | ||
| 628 | case PRID_REV_LOONGSON2F: | ||
| 629 | set_elf_platform(cpu, "loongson2f"); | ||
| 630 | break; | ||
| 631 | } | ||
| 632 | |||
| 614 | c->isa_level = MIPS_CPU_ISA_III; | 633 | c->isa_level = MIPS_CPU_ISA_III; |
| 615 | c->options = R4K_OPTS | | 634 | c->options = R4K_OPTS | |
| 616 | MIPS_CPU_FPU | MIPS_CPU_LLSC | | 635 | MIPS_CPU_FPU | MIPS_CPU_LLSC | |
| @@ -736,6 +755,8 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c) | |||
| 736 | && cpu_has_tlb) | 755 | && cpu_has_tlb) |
| 737 | c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40; | 756 | c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40; |
| 738 | 757 | ||
| 758 | c->kscratch_mask = (config4 >> 16) & 0xff; | ||
| 759 | |||
| 739 | return config4 & MIPS_CONF_M; | 760 | return config4 & MIPS_CONF_M; |
| 740 | } | 761 | } |
| 741 | 762 | ||
| @@ -902,35 +923,41 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu) | |||
| 902 | { | 923 | { |
| 903 | decode_configs(c); | 924 | decode_configs(c); |
| 904 | switch (c->processor_id & 0xff00) { | 925 | switch (c->processor_id & 0xff00) { |
| 905 | case PRID_IMP_BCM3302: | 926 | case PRID_IMP_BMIPS32_REV4: |
| 906 | /* same as PRID_IMP_BCM6338 */ | 927 | case PRID_IMP_BMIPS32_REV8: |
| 907 | c->cputype = CPU_BCM3302; | 928 | c->cputype = CPU_BMIPS32; |
| 908 | __cpu_name[cpu] = "Broadcom BCM3302"; | 929 | __cpu_name[cpu] = "Broadcom BMIPS32"; |
| 909 | break; | 930 | set_elf_platform(cpu, "bmips32"); |
| 910 | case PRID_IMP_BCM4710: | 931 | break; |
| 911 | c->cputype = CPU_BCM4710; | 932 | case PRID_IMP_BMIPS3300: |
| 912 | __cpu_name[cpu] = "Broadcom BCM4710"; | 933 | case PRID_IMP_BMIPS3300_ALT: |
| 913 | break; | 934 | case PRID_IMP_BMIPS3300_BUG: |
| 914 | case PRID_IMP_BCM6345: | 935 | c->cputype = CPU_BMIPS3300; |
| 915 | c->cputype = CPU_BCM6345; | 936 | __cpu_name[cpu] = "Broadcom BMIPS3300"; |
| 916 | __cpu_name[cpu] = "Broadcom BCM6345"; | 937 | set_elf_platform(cpu, "bmips3300"); |
| 917 | break; | 938 | break; |
| 918 | case PRID_IMP_BCM6348: | 939 | case PRID_IMP_BMIPS43XX: { |
| 919 | c->cputype = CPU_BCM6348; | 940 | int rev = c->processor_id & 0xff; |
| 920 | __cpu_name[cpu] = "Broadcom BCM6348"; | 941 | |
| 921 | break; | 942 | if (rev >= PRID_REV_BMIPS4380_LO && |
| 922 | case PRID_IMP_BCM4350: | 943 | rev <= PRID_REV_BMIPS4380_HI) { |
| 923 | switch (c->processor_id & 0xf0) { | 944 | c->cputype = CPU_BMIPS4380; |
| 924 | case PRID_REV_BCM6358: | 945 | __cpu_name[cpu] = "Broadcom BMIPS4380"; |
| 925 | c->cputype = CPU_BCM6358; | 946 | set_elf_platform(cpu, "bmips4380"); |
| 926 | __cpu_name[cpu] = "Broadcom BCM6358"; | 947 | } else { |
| 927 | break; | 948 | c->cputype = CPU_BMIPS4350; |
| 928 | default: | 949 | __cpu_name[cpu] = "Broadcom BMIPS4350"; |
| 929 | c->cputype = CPU_UNKNOWN; | 950 | set_elf_platform(cpu, "bmips4350"); |
| 930 | break; | ||
| 931 | } | 951 | } |
| 932 | break; | 952 | break; |
| 933 | } | 953 | } |
| 954 | case PRID_IMP_BMIPS5000: | ||
| 955 | c->cputype = CPU_BMIPS5000; | ||
| 956 | __cpu_name[cpu] = "Broadcom BMIPS5000"; | ||
| 957 | set_elf_platform(cpu, "bmips5000"); | ||
| 958 | c->options |= MIPS_CPU_ULRI; | ||
| 959 | break; | ||
| 960 | } | ||
| 934 | } | 961 | } |
| 935 | 962 | ||
| 936 | static inline void cpu_probe_cavium(struct cpuinfo_mips *c, unsigned int cpu) | 963 | static inline void cpu_probe_cavium(struct cpuinfo_mips *c, unsigned int cpu) |
| @@ -950,8 +977,12 @@ static inline void cpu_probe_cavium(struct cpuinfo_mips *c, unsigned int cpu) | |||
| 950 | c->cputype = CPU_CAVIUM_OCTEON_PLUS; | 977 | c->cputype = CPU_CAVIUM_OCTEON_PLUS; |
| 951 | __cpu_name[cpu] = "Cavium Octeon+"; | 978 | __cpu_name[cpu] = "Cavium Octeon+"; |
| 952 | platform: | 979 | platform: |
| 953 | if (cpu == 0) | 980 | set_elf_platform(cpu, "octeon"); |
| 954 | __elf_platform = "octeon"; | 981 | break; |
| 982 | case PRID_IMP_CAVIUM_CN63XX: | ||
| 983 | c->cputype = CPU_CAVIUM_OCTEON2; | ||
| 984 | __cpu_name[cpu] = "Cavium Octeon II"; | ||
| 985 | set_elf_platform(cpu, "octeon2"); | ||
| 955 | break; | 986 | break; |
| 956 | default: | 987 | default: |
| 957 | printk(KERN_INFO "Unknown Octeon chip!\n"); | 988 | printk(KERN_INFO "Unknown Octeon chip!\n"); |
| @@ -976,6 +1007,65 @@ static inline void cpu_probe_ingenic(struct cpuinfo_mips *c, unsigned int cpu) | |||
| 976 | } | 1007 | } |
| 977 | } | 1008 | } |
| 978 | 1009 | ||
| 1010 | static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu) | ||
| 1011 | { | ||
| 1012 | decode_configs(c); | ||
| 1013 | |||
| 1014 | c->options = (MIPS_CPU_TLB | | ||
| 1015 | MIPS_CPU_4KEX | | ||
| 1016 | MIPS_CPU_COUNTER | | ||
| 1017 | MIPS_CPU_DIVEC | | ||
| 1018 | MIPS_CPU_WATCH | | ||
| 1019 | MIPS_CPU_EJTAG | | ||
| 1020 | MIPS_CPU_LLSC); | ||
| 1021 | |||
| 1022 | switch (c->processor_id & 0xff00) { | ||
| 1023 | case PRID_IMP_NETLOGIC_XLR732: | ||
| 1024 | case PRID_IMP_NETLOGIC_XLR716: | ||
| 1025 | case PRID_IMP_NETLOGIC_XLR532: | ||
| 1026 | case PRID_IMP_NETLOGIC_XLR308: | ||
| 1027 | case PRID_IMP_NETLOGIC_XLR532C: | ||
| 1028 | case PRID_IMP_NETLOGIC_XLR516C: | ||
| 1029 | case PRID_IMP_NETLOGIC_XLR508C: | ||
| 1030 | case PRID_IMP_NETLOGIC_XLR308C: | ||
| 1031 | c->cputype = CPU_XLR; | ||
| 1032 | __cpu_name[cpu] = "Netlogic XLR"; | ||
| 1033 | break; | ||
| 1034 | |||
| 1035 | case PRID_IMP_NETLOGIC_XLS608: | ||
| 1036 | case PRID_IMP_NETLOGIC_XLS408: | ||
| 1037 | case PRID_IMP_NETLOGIC_XLS404: | ||
| 1038 | case PRID_IMP_NETLOGIC_XLS208: | ||
| 1039 | case PRID_IMP_NETLOGIC_XLS204: | ||
| 1040 | case PRID_IMP_NETLOGIC_XLS108: | ||
| 1041 | case PRID_IMP_NETLOGIC_XLS104: | ||
| 1042 | case PRID_IMP_NETLOGIC_XLS616B: | ||
| 1043 | case PRID_IMP_NETLOGIC_XLS608B: | ||
| 1044 | case PRID_IMP_NETLOGIC_XLS416B: | ||
| 1045 | case PRID_IMP_NETLOGIC_XLS412B: | ||
| 1046 | case PRID_IMP_NETLOGIC_XLS408B: | ||
| 1047 | case PRID_IMP_NETLOGIC_XLS404B: | ||
| 1048 | c->cputype = CPU_XLR; | ||
| 1049 | __cpu_name[cpu] = "Netlogic XLS"; | ||
| 1050 | break; | ||
| 1051 | |||
| 1052 | default: | ||
| 1053 | printk(KERN_INFO "Unknown Netlogic chip id [%02x]!\n", | ||
| 1054 | c->processor_id); | ||
| 1055 | c->cputype = CPU_XLR; | ||
| 1056 | break; | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | c->isa_level = MIPS_CPU_ISA_M64R1; | ||
| 1060 | c->tlbsize = ((read_c0_config1() >> 25) & 0x3f) + 1; | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | #ifdef CONFIG_64BIT | ||
| 1064 | /* For use by uaccess.h */ | ||
| 1065 | u64 __ua_limit; | ||
| 1066 | EXPORT_SYMBOL(__ua_limit); | ||
| 1067 | #endif | ||
| 1068 | |||
| 979 | const char *__cpu_name[NR_CPUS]; | 1069 | const char *__cpu_name[NR_CPUS]; |
| 980 | const char *__elf_platform; | 1070 | const char *__elf_platform; |
| 981 | 1071 | ||
| @@ -1017,6 +1107,9 @@ __cpuinit void cpu_probe(void) | |||
| 1017 | case PRID_COMP_INGENIC: | 1107 | case PRID_COMP_INGENIC: |
| 1018 | cpu_probe_ingenic(c, cpu); | 1108 | cpu_probe_ingenic(c, cpu); |
| 1019 | break; | 1109 | break; |
| 1110 | case PRID_COMP_NETLOGIC: | ||
| 1111 | cpu_probe_netlogic(c, cpu); | ||
| 1112 | break; | ||
| 1020 | } | 1113 | } |
| 1021 | 1114 | ||
| 1022 | BUG_ON(!__cpu_name[cpu]); | 1115 | BUG_ON(!__cpu_name[cpu]); |
| @@ -1053,6 +1146,11 @@ __cpuinit void cpu_probe(void) | |||
| 1053 | c->srsets = 1; | 1146 | c->srsets = 1; |
| 1054 | 1147 | ||
| 1055 | cpu_probe_vmbits(c); | 1148 | cpu_probe_vmbits(c); |
| 1149 | |||
| 1150 | #ifdef CONFIG_64BIT | ||
| 1151 | if (cpu == 0) | ||
| 1152 | __ua_limit = ~((1ull << cpu_vmbits) - 1); | ||
| 1153 | #endif | ||
| 1056 | } | 1154 | } |
| 1057 | 1155 | ||
| 1058 | __cpuinit void cpu_report(void) | 1156 | __cpuinit void cpu_report(void) |
diff --git a/arch/mips/kernel/csrc-bcm1480.c b/arch/mips/kernel/csrc-bcm1480.c index 51489f8a825e..f96f99c794a3 100644 --- a/arch/mips/kernel/csrc-bcm1480.c +++ b/arch/mips/kernel/csrc-bcm1480.c | |||
| @@ -49,6 +49,5 @@ void __init sb1480_clocksource_init(void) | |||
| 49 | 49 | ||
| 50 | plldiv = G_BCM1480_SYS_PLL_DIV(__raw_readq(IOADDR(A_SCD_SYSTEM_CFG))); | 50 | plldiv = G_BCM1480_SYS_PLL_DIV(__raw_readq(IOADDR(A_SCD_SYSTEM_CFG))); |
| 51 | zbbus = ((plldiv >> 1) * 50000000) + ((plldiv & 1) * 25000000); | 51 | zbbus = ((plldiv >> 1) * 50000000) + ((plldiv & 1) * 25000000); |
| 52 | clocksource_set_clock(cs, zbbus); | 52 | clocksource_register_hz(cs, zbbus); |
| 53 | clocksource_register(cs); | ||
| 54 | } | 53 | } |
diff --git a/arch/mips/kernel/csrc-ioasic.c b/arch/mips/kernel/csrc-ioasic.c index 23da108506b0..46bd7fa98d6c 100644 --- a/arch/mips/kernel/csrc-ioasic.c +++ b/arch/mips/kernel/csrc-ioasic.c | |||
| @@ -59,7 +59,5 @@ void __init dec_ioasic_clocksource_init(void) | |||
| 59 | printk(KERN_INFO "I/O ASIC clock frequency %dHz\n", freq); | 59 | printk(KERN_INFO "I/O ASIC clock frequency %dHz\n", freq); |
| 60 | 60 | ||
| 61 | clocksource_dec.rating = 200 + freq / 10000000; | 61 | clocksource_dec.rating = 200 + freq / 10000000; |
| 62 | clocksource_set_clock(&clocksource_dec, freq); | 62 | clocksource_register_hz(&clocksource_dec, freq); |
| 63 | |||
| 64 | clocksource_register(&clocksource_dec); | ||
| 65 | } | 63 | } |
diff --git a/arch/mips/kernel/csrc-powertv.c b/arch/mips/kernel/csrc-powertv.c index a27c16c8690e..2e7c5232da8d 100644 --- a/arch/mips/kernel/csrc-powertv.c +++ b/arch/mips/kernel/csrc-powertv.c | |||
| @@ -78,9 +78,7 @@ static void __init powertv_c0_hpt_clocksource_init(void) | |||
| 78 | 78 | ||
| 79 | clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000; | 79 | clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000; |
| 80 | 80 | ||
| 81 | clocksource_set_clock(&clocksource_mips, mips_hpt_frequency); | 81 | clocksource_register_hz(&clocksource_mips, mips_hpt_frequency); |
| 82 | |||
| 83 | clocksource_register(&clocksource_mips); | ||
| 84 | } | 82 | } |
| 85 | 83 | ||
| 86 | /** | 84 | /** |
| @@ -130,43 +128,16 @@ static struct clocksource clocksource_tim_c = { | |||
| 130 | /** | 128 | /** |
| 131 | * powertv_tim_c_clocksource_init - set up a clock source for the TIM_C clock | 129 | * powertv_tim_c_clocksource_init - set up a clock source for the TIM_C clock |
| 132 | * | 130 | * |
| 133 | * The hard part here is coming up with a constant k and shift s such that | ||
| 134 | * the 48-bit TIM_C value multiplied by k doesn't overflow and that value, | ||
| 135 | * when shifted right by s, yields the corresponding number of nanoseconds. | ||
| 136 | * We know that TIM_C counts at 27 MHz/8, so each cycle corresponds to | 131 | * We know that TIM_C counts at 27 MHz/8, so each cycle corresponds to |
| 137 | * 1 / (27,000,000/8) seconds. Multiply that by a billion and you get the | 132 | * 1 / (27,000,000/8) seconds. |
| 138 | * number of nanoseconds. Since the TIM_C value has 48 bits and the math is | ||
| 139 | * done in 64 bits, avoiding an overflow means that k must be less than | ||
| 140 | * 64 - 48 = 16 bits. | ||
| 141 | */ | 133 | */ |
| 142 | static void __init powertv_tim_c_clocksource_init(void) | 134 | static void __init powertv_tim_c_clocksource_init(void) |
| 143 | { | 135 | { |
| 144 | int prescale; | ||
| 145 | unsigned long dividend; | ||
| 146 | unsigned long k; | ||
| 147 | int s; | ||
| 148 | const int max_k_bits = (64 - 48) - 1; | ||
| 149 | const unsigned long billion = 1000000000; | ||
| 150 | const unsigned long counts_per_second = 27000000 / 8; | 136 | const unsigned long counts_per_second = 27000000 / 8; |
| 151 | 137 | ||
| 152 | prescale = BITS_PER_LONG - ilog2(billion) - 1; | ||
| 153 | dividend = billion << prescale; | ||
| 154 | k = dividend / counts_per_second; | ||
| 155 | s = ilog2(k) - max_k_bits; | ||
| 156 | |||
| 157 | if (s < 0) | ||
| 158 | s = prescale; | ||
| 159 | |||
| 160 | else { | ||
| 161 | k >>= s; | ||
| 162 | s += prescale; | ||
| 163 | } | ||
| 164 | |||
| 165 | clocksource_tim_c.mult = k; | ||
| 166 | clocksource_tim_c.shift = s; | ||
| 167 | clocksource_tim_c.rating = 200; | 138 | clocksource_tim_c.rating = 200; |
| 168 | 139 | ||
| 169 | clocksource_register(&clocksource_tim_c); | 140 | clocksource_register_hz(&clocksource_tim_c, counts_per_second); |
| 170 | tim_c = (struct tim_c *) asic_reg_addr(tim_ch); | 141 | tim_c = (struct tim_c *) asic_reg_addr(tim_ch); |
| 171 | } | 142 | } |
| 172 | 143 | ||
diff --git a/arch/mips/kernel/csrc-r4k.c b/arch/mips/kernel/csrc-r4k.c index e95a3cd48eea..decd1fa38d55 100644 --- a/arch/mips/kernel/csrc-r4k.c +++ b/arch/mips/kernel/csrc-r4k.c | |||
| @@ -30,9 +30,7 @@ int __init init_r4k_clocksource(void) | |||
| 30 | /* Calculate a somewhat reasonable rating value */ | 30 | /* Calculate a somewhat reasonable rating value */ |
| 31 | clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000; | 31 | clocksource_mips.rating = 200 + mips_hpt_frequency / 10000000; |
| 32 | 32 | ||
| 33 | clocksource_set_clock(&clocksource_mips, mips_hpt_frequency); | 33 | clocksource_register_hz(&clocksource_mips, mips_hpt_frequency); |
| 34 | |||
| 35 | clocksource_register(&clocksource_mips); | ||
| 36 | 34 | ||
| 37 | return 0; | 35 | return 0; |
| 38 | } | 36 | } |
diff --git a/arch/mips/kernel/csrc-sb1250.c b/arch/mips/kernel/csrc-sb1250.c index d14d3d1907fa..e9606d907685 100644 --- a/arch/mips/kernel/csrc-sb1250.c +++ b/arch/mips/kernel/csrc-sb1250.c | |||
| @@ -65,6 +65,5 @@ void __init sb1250_clocksource_init(void) | |||
| 65 | IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, | 65 | IOADDR(A_SCD_TIMER_REGISTER(SB1250_HPT_NUM, |
| 66 | R_SCD_TIMER_CFG))); | 66 | R_SCD_TIMER_CFG))); |
| 67 | 67 | ||
| 68 | clocksource_set_clock(cs, V_SCD_TIMER_FREQ); | 68 | clocksource_register_hz(cs, V_SCD_TIMER_FREQ); |
| 69 | clocksource_register(cs); | ||
| 70 | } | 69 | } |
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S index ffa331029e08..37acfa036d44 100644 --- a/arch/mips/kernel/entry.S +++ b/arch/mips/kernel/entry.S | |||
| @@ -167,14 +167,13 @@ work_notifysig: # deal with pending signals and | |||
| 167 | FEXPORT(syscall_exit_work_partial) | 167 | FEXPORT(syscall_exit_work_partial) |
| 168 | SAVE_STATIC | 168 | SAVE_STATIC |
| 169 | syscall_exit_work: | 169 | syscall_exit_work: |
| 170 | li t0, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | 170 | li t0, _TIF_WORK_SYSCALL_EXIT |
| 171 | and t0, a2 # a2 is preloaded with TI_FLAGS | 171 | and t0, a2 # a2 is preloaded with TI_FLAGS |
| 172 | beqz t0, work_pending # trace bit set? | 172 | beqz t0, work_pending # trace bit set? |
| 173 | local_irq_enable # could let do_syscall_trace() | 173 | local_irq_enable # could let syscall_trace_leave() |
| 174 | # call schedule() instead | 174 | # call schedule() instead |
| 175 | move a0, sp | 175 | move a0, sp |
| 176 | li a1, 1 | 176 | jal syscall_trace_leave |
| 177 | jal do_syscall_trace | ||
| 178 | b resume_userspace | 177 | b resume_userspace |
| 179 | 178 | ||
| 180 | #if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_MIPS_MT) | 179 | #if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_MIPS_MT) |
diff --git a/arch/mips/kernel/ftrace.c b/arch/mips/kernel/ftrace.c index 5a84a1f11231..feb8021a305f 100644 --- a/arch/mips/kernel/ftrace.c +++ b/arch/mips/kernel/ftrace.c | |||
| @@ -17,29 +17,14 @@ | |||
| 17 | #include <asm/cacheflush.h> | 17 | #include <asm/cacheflush.h> |
| 18 | #include <asm/uasm.h> | 18 | #include <asm/uasm.h> |
| 19 | 19 | ||
| 20 | /* | 20 | #include <asm-generic/sections.h> |
| 21 | * If the Instruction Pointer is in module space (0xc0000000), return true; | ||
| 22 | * otherwise, it is in kernel space (0x80000000), return false. | ||
| 23 | * | ||
| 24 | * FIXME: This will not work when the kernel space and module space are the | ||
| 25 | * same. If they are the same, we need to modify scripts/recordmcount.pl, | ||
| 26 | * ftrace_make_nop/call() and the other related parts to ensure the | ||
| 27 | * enabling/disabling of the calling site to _mcount is right for both kernel | ||
| 28 | * and module. | ||
| 29 | */ | ||
| 30 | |||
| 31 | static inline int in_module(unsigned long ip) | ||
| 32 | { | ||
| 33 | return ip & 0x40000000; | ||
| 34 | } | ||
| 35 | 21 | ||
| 36 | #ifdef CONFIG_DYNAMIC_FTRACE | 22 | #ifdef CONFIG_DYNAMIC_FTRACE |
| 37 | 23 | ||
| 38 | #define JAL 0x0c000000 /* jump & link: ip --> ra, jump to target */ | 24 | #define JAL 0x0c000000 /* jump & link: ip --> ra, jump to target */ |
| 39 | #define ADDR_MASK 0x03ffffff /* op_code|addr : 31...26|25 ....0 */ | 25 | #define ADDR_MASK 0x03ffffff /* op_code|addr : 31...26|25 ....0 */ |
| 26 | #define JUMP_RANGE_MASK ((1UL << 28) - 1) | ||
| 40 | 27 | ||
| 41 | #define INSN_B_1F_4 0x10000004 /* b 1f; offset = 4 */ | ||
| 42 | #define INSN_B_1F_5 0x10000005 /* b 1f; offset = 5 */ | ||
| 43 | #define INSN_NOP 0x00000000 /* nop */ | 28 | #define INSN_NOP 0x00000000 /* nop */ |
| 44 | #define INSN_JAL(addr) \ | 29 | #define INSN_JAL(addr) \ |
| 45 | ((unsigned int)(JAL | (((addr) >> 2) & ADDR_MASK))) | 30 | ((unsigned int)(JAL | (((addr) >> 2) & ADDR_MASK))) |
| @@ -60,15 +45,29 @@ static inline void ftrace_dyn_arch_init_insns(void) | |||
| 60 | 45 | ||
| 61 | /* jal (ftrace_caller + 8), jump over the first two instruction */ | 46 | /* jal (ftrace_caller + 8), jump over the first two instruction */ |
| 62 | buf = (u32 *)&insn_jal_ftrace_caller; | 47 | buf = (u32 *)&insn_jal_ftrace_caller; |
| 63 | uasm_i_jal(&buf, (FTRACE_ADDR + 8)); | 48 | uasm_i_jal(&buf, (FTRACE_ADDR + 8) & JUMP_RANGE_MASK); |
| 64 | 49 | ||
| 65 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 50 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
| 66 | /* j ftrace_graph_caller */ | 51 | /* j ftrace_graph_caller */ |
| 67 | buf = (u32 *)&insn_j_ftrace_graph_caller; | 52 | buf = (u32 *)&insn_j_ftrace_graph_caller; |
| 68 | uasm_i_j(&buf, (unsigned long)ftrace_graph_caller); | 53 | uasm_i_j(&buf, (unsigned long)ftrace_graph_caller & JUMP_RANGE_MASK); |
| 69 | #endif | 54 | #endif |
| 70 | } | 55 | } |
| 71 | 56 | ||
| 57 | /* | ||
| 58 | * Check if the address is in kernel space | ||
| 59 | * | ||
| 60 | * Clone core_kernel_text() from kernel/extable.c, but doesn't call | ||
| 61 | * init_kernel_text() for Ftrace doesn't trace functions in init sections. | ||
| 62 | */ | ||
| 63 | static inline int in_kernel_space(unsigned long ip) | ||
| 64 | { | ||
| 65 | if (ip >= (unsigned long)_stext && | ||
| 66 | ip <= (unsigned long)_etext) | ||
| 67 | return 1; | ||
| 68 | return 0; | ||
| 69 | } | ||
| 70 | |||
| 72 | static int ftrace_modify_code(unsigned long ip, unsigned int new_code) | 71 | static int ftrace_modify_code(unsigned long ip, unsigned int new_code) |
| 73 | { | 72 | { |
| 74 | int faulted; | 73 | int faulted; |
| @@ -84,6 +83,42 @@ static int ftrace_modify_code(unsigned long ip, unsigned int new_code) | |||
| 84 | return 0; | 83 | return 0; |
| 85 | } | 84 | } |
| 86 | 85 | ||
| 86 | /* | ||
| 87 | * The details about the calling site of mcount on MIPS | ||
| 88 | * | ||
| 89 | * 1. For kernel: | ||
| 90 | * | ||
| 91 | * move at, ra | ||
| 92 | * jal _mcount --> nop | ||
| 93 | * | ||
| 94 | * 2. For modules: | ||
| 95 | * | ||
| 96 | * 2.1 For KBUILD_MCOUNT_RA_ADDRESS and CONFIG_32BIT | ||
| 97 | * | ||
| 98 | * lui v1, hi_16bit_of_mcount --> b 1f (0x10000005) | ||
| 99 | * addiu v1, v1, low_16bit_of_mcount | ||
| 100 | * move at, ra | ||
| 101 | * move $12, ra_address | ||
| 102 | * jalr v1 | ||
| 103 | * sub sp, sp, 8 | ||
| 104 | * 1: offset = 5 instructions | ||
| 105 | * 2.2 For the Other situations | ||
| 106 | * | ||
| 107 | * lui v1, hi_16bit_of_mcount --> b 1f (0x10000004) | ||
| 108 | * addiu v1, v1, low_16bit_of_mcount | ||
| 109 | * move at, ra | ||
| 110 | * jalr v1 | ||
| 111 | * nop | move $12, ra_address | sub sp, sp, 8 | ||
| 112 | * 1: offset = 4 instructions | ||
| 113 | */ | ||
| 114 | |||
| 115 | #if defined(KBUILD_MCOUNT_RA_ADDRESS) && defined(CONFIG_32BIT) | ||
| 116 | #define MCOUNT_OFFSET_INSNS 5 | ||
| 117 | #else | ||
| 118 | #define MCOUNT_OFFSET_INSNS 4 | ||
| 119 | #endif | ||
| 120 | #define INSN_B_1F (0x10000000 | MCOUNT_OFFSET_INSNS) | ||
| 121 | |||
| 87 | int ftrace_make_nop(struct module *mod, | 122 | int ftrace_make_nop(struct module *mod, |
| 88 | struct dyn_ftrace *rec, unsigned long addr) | 123 | struct dyn_ftrace *rec, unsigned long addr) |
| 89 | { | 124 | { |
| @@ -91,39 +126,11 @@ int ftrace_make_nop(struct module *mod, | |||
| 91 | unsigned long ip = rec->ip; | 126 | unsigned long ip = rec->ip; |
| 92 | 127 | ||
| 93 | /* | 128 | /* |
| 94 | * We have compiled module with -mlong-calls, but compiled the kernel | 129 | * If ip is in kernel space, no long call, otherwise, long call is |
| 95 | * without it, we need to cope with them respectively. | 130 | * needed. |
| 96 | */ | 131 | */ |
| 97 | if (in_module(ip)) { | 132 | new = in_kernel_space(ip) ? INSN_NOP : INSN_B_1F; |
| 98 | #if defined(KBUILD_MCOUNT_RA_ADDRESS) && defined(CONFIG_32BIT) | 133 | |
| 99 | /* | ||
| 100 | * lui v1, hi_16bit_of_mcount --> b 1f (0x10000005) | ||
| 101 | * addiu v1, v1, low_16bit_of_mcount | ||
| 102 | * move at, ra | ||
| 103 | * move $12, ra_address | ||
| 104 | * jalr v1 | ||
| 105 | * sub sp, sp, 8 | ||
| 106 | * 1: offset = 5 instructions | ||
| 107 | */ | ||
| 108 | new = INSN_B_1F_5; | ||
| 109 | #else | ||
| 110 | /* | ||
| 111 | * lui v1, hi_16bit_of_mcount --> b 1f (0x10000004) | ||
| 112 | * addiu v1, v1, low_16bit_of_mcount | ||
| 113 | * move at, ra | ||
| 114 | * jalr v1 | ||
| 115 | * nop | move $12, ra_address | sub sp, sp, 8 | ||
| 116 | * 1: offset = 4 instructions | ||
| 117 | */ | ||
| 118 | new = INSN_B_1F_4; | ||
| 119 | #endif | ||
| 120 | } else { | ||
| 121 | /* | ||
| 122 | * move at, ra | ||
| 123 | * jal _mcount --> nop | ||
| 124 | */ | ||
| 125 | new = INSN_NOP; | ||
| 126 | } | ||
| 127 | return ftrace_modify_code(ip, new); | 134 | return ftrace_modify_code(ip, new); |
| 128 | } | 135 | } |
| 129 | 136 | ||
| @@ -132,8 +139,8 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | |||
| 132 | unsigned int new; | 139 | unsigned int new; |
| 133 | unsigned long ip = rec->ip; | 140 | unsigned long ip = rec->ip; |
| 134 | 141 | ||
| 135 | /* ip, module: 0xc0000000, kernel: 0x80000000 */ | 142 | new = in_kernel_space(ip) ? insn_jal_ftrace_caller : |
| 136 | new = in_module(ip) ? insn_lui_v1_hi16_mcount : insn_jal_ftrace_caller; | 143 | insn_lui_v1_hi16_mcount; |
| 137 | 144 | ||
| 138 | return ftrace_modify_code(ip, new); | 145 | return ftrace_modify_code(ip, new); |
| 139 | } | 146 | } |
| @@ -190,29 +197,25 @@ int ftrace_disable_ftrace_graph_caller(void) | |||
| 190 | #define S_R_SP (0xafb0 << 16) /* s{d,w} R, offset(sp) */ | 197 | #define S_R_SP (0xafb0 << 16) /* s{d,w} R, offset(sp) */ |
| 191 | #define OFFSET_MASK 0xffff /* stack offset range: 0 ~ PT_SIZE */ | 198 | #define OFFSET_MASK 0xffff /* stack offset range: 0 ~ PT_SIZE */ |
| 192 | 199 | ||
| 193 | unsigned long ftrace_get_parent_addr(unsigned long self_addr, | 200 | unsigned long ftrace_get_parent_ra_addr(unsigned long self_ra, unsigned long |
| 194 | unsigned long parent, | 201 | old_parent_ra, unsigned long parent_ra_addr, unsigned long fp) |
| 195 | unsigned long parent_addr, | ||
| 196 | unsigned long fp) | ||
| 197 | { | 202 | { |
| 198 | unsigned long sp, ip, ra; | 203 | unsigned long sp, ip, tmp; |
| 199 | unsigned int code; | 204 | unsigned int code; |
| 200 | int faulted; | 205 | int faulted; |
| 201 | 206 | ||
| 202 | /* | 207 | /* |
| 203 | * For module, move the ip from calling site of mcount to the | 208 | * For module, move the ip from the return address after the |
| 204 | * instruction "lui v1, hi_16bit_of_mcount"(offset is 20), but for | 209 | * instruction "lui v1, hi_16bit_of_mcount"(offset is 24), but for |
| 205 | * kernel, move to the instruction "move ra, at"(offset is 12) | 210 | * kernel, move after the instruction "move ra, at"(offset is 16) |
| 206 | */ | 211 | */ |
| 207 | ip = self_addr - (in_module(self_addr) ? 20 : 12); | 212 | ip = self_ra - (in_kernel_space(self_ra) ? 16 : 24); |
| 208 | 213 | ||
| 209 | /* | 214 | /* |
| 210 | * search the text until finding the non-store instruction or "s{d,w} | 215 | * search the text until finding the non-store instruction or "s{d,w} |
| 211 | * ra, offset(sp)" instruction | 216 | * ra, offset(sp)" instruction |
| 212 | */ | 217 | */ |
| 213 | do { | 218 | do { |
| 214 | ip -= 4; | ||
| 215 | |||
| 216 | /* get the code at "ip": code = *(unsigned int *)ip; */ | 219 | /* get the code at "ip": code = *(unsigned int *)ip; */ |
| 217 | safe_load_code(code, ip, faulted); | 220 | safe_load_code(code, ip, faulted); |
| 218 | 221 | ||
| @@ -224,18 +227,20 @@ unsigned long ftrace_get_parent_addr(unsigned long self_addr, | |||
| 224 | * store the ra on the stack | 227 | * store the ra on the stack |
| 225 | */ | 228 | */ |
| 226 | if ((code & S_R_SP) != S_R_SP) | 229 | if ((code & S_R_SP) != S_R_SP) |
| 227 | return parent_addr; | 230 | return parent_ra_addr; |
| 228 | 231 | ||
| 229 | } while (((code & S_RA_SP) != S_RA_SP)); | 232 | /* Move to the next instruction */ |
| 233 | ip -= 4; | ||
| 234 | } while ((code & S_RA_SP) != S_RA_SP); | ||
| 230 | 235 | ||
| 231 | sp = fp + (code & OFFSET_MASK); | 236 | sp = fp + (code & OFFSET_MASK); |
| 232 | 237 | ||
| 233 | /* ra = *(unsigned long *)sp; */ | 238 | /* tmp = *(unsigned long *)sp; */ |
| 234 | safe_load_stack(ra, sp, faulted); | 239 | safe_load_stack(tmp, sp, faulted); |
| 235 | if (unlikely(faulted)) | 240 | if (unlikely(faulted)) |
| 236 | return 0; | 241 | return 0; |
| 237 | 242 | ||
| 238 | if (ra == parent) | 243 | if (tmp == old_parent_ra) |
| 239 | return sp; | 244 | return sp; |
| 240 | return 0; | 245 | return 0; |
| 241 | } | 246 | } |
| @@ -246,21 +251,21 @@ unsigned long ftrace_get_parent_addr(unsigned long self_addr, | |||
| 246 | * Hook the return address and push it in the stack of return addrs | 251 | * Hook the return address and push it in the stack of return addrs |
| 247 | * in current thread info. | 252 | * in current thread info. |
| 248 | */ | 253 | */ |
| 249 | void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, | 254 | void prepare_ftrace_return(unsigned long *parent_ra_addr, unsigned long self_ra, |
| 250 | unsigned long fp) | 255 | unsigned long fp) |
| 251 | { | 256 | { |
| 252 | unsigned long old; | 257 | unsigned long old_parent_ra; |
| 253 | struct ftrace_graph_ent trace; | 258 | struct ftrace_graph_ent trace; |
| 254 | unsigned long return_hooker = (unsigned long) | 259 | unsigned long return_hooker = (unsigned long) |
| 255 | &return_to_handler; | 260 | &return_to_handler; |
| 256 | int faulted; | 261 | int faulted, insns; |
| 257 | 262 | ||
| 258 | if (unlikely(atomic_read(¤t->tracing_graph_pause))) | 263 | if (unlikely(atomic_read(¤t->tracing_graph_pause))) |
| 259 | return; | 264 | return; |
| 260 | 265 | ||
| 261 | /* | 266 | /* |
| 262 | * "parent" is the stack address saved the return address of the caller | 267 | * "parent_ra_addr" is the stack address saved the return address of |
| 263 | * of _mcount. | 268 | * the caller of _mcount. |
| 264 | * | 269 | * |
| 265 | * if the gcc < 4.5, a leaf function does not save the return address | 270 | * if the gcc < 4.5, a leaf function does not save the return address |
| 266 | * in the stack address, so, we "emulate" one in _mcount's stack space, | 271 | * in the stack address, so, we "emulate" one in _mcount's stack space, |
| @@ -275,37 +280,44 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, | |||
| 275 | * do it in ftrace_graph_caller of mcount.S. | 280 | * do it in ftrace_graph_caller of mcount.S. |
| 276 | */ | 281 | */ |
| 277 | 282 | ||
| 278 | /* old = *parent; */ | 283 | /* old_parent_ra = *parent_ra_addr; */ |
| 279 | safe_load_stack(old, parent, faulted); | 284 | safe_load_stack(old_parent_ra, parent_ra_addr, faulted); |
| 280 | if (unlikely(faulted)) | 285 | if (unlikely(faulted)) |
| 281 | goto out; | 286 | goto out; |
| 282 | #ifndef KBUILD_MCOUNT_RA_ADDRESS | 287 | #ifndef KBUILD_MCOUNT_RA_ADDRESS |
| 283 | parent = (unsigned long *)ftrace_get_parent_addr(self_addr, old, | 288 | parent_ra_addr = (unsigned long *)ftrace_get_parent_ra_addr(self_ra, |
| 284 | (unsigned long)parent, fp); | 289 | old_parent_ra, (unsigned long)parent_ra_addr, fp); |
| 285 | /* | 290 | /* |
| 286 | * If fails when getting the stack address of the non-leaf function's | 291 | * If fails when getting the stack address of the non-leaf function's |
| 287 | * ra, stop function graph tracer and return | 292 | * ra, stop function graph tracer and return |
| 288 | */ | 293 | */ |
| 289 | if (parent == 0) | 294 | if (parent_ra_addr == 0) |
| 290 | goto out; | 295 | goto out; |
| 291 | #endif | 296 | #endif |
| 292 | /* *parent = return_hooker; */ | 297 | /* *parent_ra_addr = return_hooker; */ |
| 293 | safe_store_stack(return_hooker, parent, faulted); | 298 | safe_store_stack(return_hooker, parent_ra_addr, faulted); |
| 294 | if (unlikely(faulted)) | 299 | if (unlikely(faulted)) |
| 295 | goto out; | 300 | goto out; |
| 296 | 301 | ||
| 297 | if (ftrace_push_return_trace(old, self_addr, &trace.depth, fp) == | 302 | if (ftrace_push_return_trace(old_parent_ra, self_ra, &trace.depth, fp) |
| 298 | -EBUSY) { | 303 | == -EBUSY) { |
| 299 | *parent = old; | 304 | *parent_ra_addr = old_parent_ra; |
| 300 | return; | 305 | return; |
| 301 | } | 306 | } |
| 302 | 307 | ||
| 303 | trace.func = self_addr; | 308 | /* |
| 309 | * Get the recorded ip of the current mcount calling site in the | ||
| 310 | * __mcount_loc section, which will be used to filter the function | ||
| 311 | * entries configured through the tracing/set_graph_function interface. | ||
| 312 | */ | ||
| 313 | |||
| 314 | insns = in_kernel_space(self_ra) ? 2 : MCOUNT_OFFSET_INSNS + 1; | ||
| 315 | trace.func = self_ra - (MCOUNT_INSN_SIZE * insns); | ||
| 304 | 316 | ||
| 305 | /* Only trace if the calling function expects to */ | 317 | /* Only trace if the calling function expects to */ |
| 306 | if (!ftrace_graph_entry(&trace)) { | 318 | if (!ftrace_graph_entry(&trace)) { |
| 307 | current->curr_ret_stack--; | 319 | current->curr_ret_stack--; |
| 308 | *parent = old; | 320 | *parent_ra_addr = old_parent_ra; |
| 309 | } | 321 | } |
| 310 | return; | 322 | return; |
| 311 | out: | 323 | out: |
diff --git a/arch/mips/kernel/i8253.c b/arch/mips/kernel/i8253.c index 94794062a177..391221b6a6aa 100644 --- a/arch/mips/kernel/i8253.c +++ b/arch/mips/kernel/i8253.c | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <linux/module.h> | 9 | #include <linux/module.h> |
| 10 | #include <linux/smp.h> | 10 | #include <linux/smp.h> |
| 11 | #include <linux/spinlock.h> | 11 | #include <linux/spinlock.h> |
| 12 | #include <linux/irq.h> | ||
| 12 | 13 | ||
| 13 | #include <asm/delay.h> | 14 | #include <asm/delay.h> |
| 14 | #include <asm/i8253.h> | 15 | #include <asm/i8253.h> |
| @@ -124,87 +125,11 @@ void __init setup_pit_timer(void) | |||
| 124 | setup_irq(0, &irq0); | 125 | setup_irq(0, &irq0); |
| 125 | } | 126 | } |
| 126 | 127 | ||
| 127 | /* | ||
| 128 | * Since the PIT overflows every tick, its not very useful | ||
| 129 | * to just read by itself. So use jiffies to emulate a free | ||
| 130 | * running counter: | ||
| 131 | */ | ||
| 132 | static cycle_t pit_read(struct clocksource *cs) | ||
| 133 | { | ||
| 134 | unsigned long flags; | ||
| 135 | int count; | ||
| 136 | u32 jifs; | ||
| 137 | static int old_count; | ||
| 138 | static u32 old_jifs; | ||
| 139 | |||
| 140 | raw_spin_lock_irqsave(&i8253_lock, flags); | ||
| 141 | /* | ||
| 142 | * Although our caller may have the read side of xtime_lock, | ||
| 143 | * this is now a seqlock, and we are cheating in this routine | ||
| 144 | * by having side effects on state that we cannot undo if | ||
| 145 | * there is a collision on the seqlock and our caller has to | ||
| 146 | * retry. (Namely, old_jifs and old_count.) So we must treat | ||
| 147 | * jiffies as volatile despite the lock. We read jiffies | ||
| 148 | * before latching the timer count to guarantee that although | ||
| 149 | * the jiffies value might be older than the count (that is, | ||
| 150 | * the counter may underflow between the last point where | ||
| 151 | * jiffies was incremented and the point where we latch the | ||
| 152 | * count), it cannot be newer. | ||
| 153 | */ | ||
| 154 | jifs = jiffies; | ||
| 155 | outb_p(0x00, PIT_MODE); /* latch the count ASAP */ | ||
| 156 | count = inb_p(PIT_CH0); /* read the latched count */ | ||
| 157 | count |= inb_p(PIT_CH0) << 8; | ||
| 158 | |||
| 159 | /* VIA686a test code... reset the latch if count > max + 1 */ | ||
| 160 | if (count > LATCH) { | ||
| 161 | outb_p(0x34, PIT_MODE); | ||
| 162 | outb_p(LATCH & 0xff, PIT_CH0); | ||
| 163 | outb(LATCH >> 8, PIT_CH0); | ||
| 164 | count = LATCH - 1; | ||
| 165 | } | ||
| 166 | |||
| 167 | /* | ||
| 168 | * It's possible for count to appear to go the wrong way for a | ||
| 169 | * couple of reasons: | ||
| 170 | * | ||
| 171 | * 1. The timer counter underflows, but we haven't handled the | ||
| 172 | * resulting interrupt and incremented jiffies yet. | ||
| 173 | * 2. Hardware problem with the timer, not giving us continuous time, | ||
| 174 | * the counter does small "jumps" upwards on some Pentium systems, | ||
| 175 | * (see c't 95/10 page 335 for Neptun bug.) | ||
| 176 | * | ||
| 177 | * Previous attempts to handle these cases intelligently were | ||
| 178 | * buggy, so we just do the simple thing now. | ||
| 179 | */ | ||
| 180 | if (count > old_count && jifs == old_jifs) { | ||
| 181 | count = old_count; | ||
| 182 | } | ||
| 183 | old_count = count; | ||
| 184 | old_jifs = jifs; | ||
| 185 | |||
| 186 | raw_spin_unlock_irqrestore(&i8253_lock, flags); | ||
| 187 | |||
| 188 | count = (LATCH - 1) - count; | ||
| 189 | |||
| 190 | return (cycle_t)(jifs * LATCH) + count; | ||
| 191 | } | ||
| 192 | |||
| 193 | static struct clocksource clocksource_pit = { | ||
| 194 | .name = "pit", | ||
| 195 | .rating = 110, | ||
| 196 | .read = pit_read, | ||
| 197 | .mask = CLOCKSOURCE_MASK(32), | ||
| 198 | .mult = 0, | ||
| 199 | .shift = 20, | ||
| 200 | }; | ||
| 201 | |||
| 202 | static int __init init_pit_clocksource(void) | 128 | static int __init init_pit_clocksource(void) |
| 203 | { | 129 | { |
| 204 | if (num_possible_cpus() > 1) /* PIT does not scale! */ | 130 | if (num_possible_cpus() > 1) /* PIT does not scale! */ |
| 205 | return 0; | 131 | return 0; |
| 206 | 132 | ||
| 207 | clocksource_pit.mult = clocksource_hz2mult(CLOCK_TICK_RATE, 20); | 133 | return clocksource_i8253_init(); |
| 208 | return clocksource_register(&clocksource_pit); | ||
| 209 | } | 134 | } |
| 210 | arch_initcall(init_pit_clocksource); | 135 | arch_initcall(init_pit_clocksource); |
diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c index 27799113332c..5c74eb797f08 100644 --- a/arch/mips/kernel/i8259.c +++ b/arch/mips/kernel/i8259.c | |||
| @@ -14,7 +14,8 @@ | |||
| 14 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
| 15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
| 16 | #include <linux/spinlock.h> | 16 | #include <linux/spinlock.h> |
| 17 | #include <linux/sysdev.h> | 17 | #include <linux/syscore_ops.h> |
| 18 | #include <linux/irq.h> | ||
| 18 | 19 | ||
| 19 | #include <asm/i8259.h> | 20 | #include <asm/i8259.h> |
| 20 | #include <asm/io.h> | 21 | #include <asm/io.h> |
| @@ -30,19 +31,19 @@ | |||
| 30 | 31 | ||
| 31 | static int i8259A_auto_eoi = -1; | 32 | static int i8259A_auto_eoi = -1; |
| 32 | DEFINE_RAW_SPINLOCK(i8259A_lock); | 33 | DEFINE_RAW_SPINLOCK(i8259A_lock); |
| 33 | static void disable_8259A_irq(unsigned int irq); | 34 | static void disable_8259A_irq(struct irq_data *d); |
| 34 | static void enable_8259A_irq(unsigned int irq); | 35 | static void enable_8259A_irq(struct irq_data *d); |
| 35 | static void mask_and_ack_8259A(unsigned int irq); | 36 | static void mask_and_ack_8259A(struct irq_data *d); |
| 36 | static void init_8259A(int auto_eoi); | 37 | static void init_8259A(int auto_eoi); |
| 37 | 38 | ||
| 38 | static struct irq_chip i8259A_chip = { | 39 | static struct irq_chip i8259A_chip = { |
| 39 | .name = "XT-PIC", | 40 | .name = "XT-PIC", |
| 40 | .mask = disable_8259A_irq, | 41 | .irq_mask = disable_8259A_irq, |
| 41 | .disable = disable_8259A_irq, | 42 | .irq_disable = disable_8259A_irq, |
| 42 | .unmask = enable_8259A_irq, | 43 | .irq_unmask = enable_8259A_irq, |
| 43 | .mask_ack = mask_and_ack_8259A, | 44 | .irq_mask_ack = mask_and_ack_8259A, |
| 44 | #ifdef CONFIG_MIPS_MT_SMTC_IRQAFF | 45 | #ifdef CONFIG_MIPS_MT_SMTC_IRQAFF |
| 45 | .set_affinity = plat_set_irq_affinity, | 46 | .irq_set_affinity = plat_set_irq_affinity, |
| 46 | #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ | 47 | #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ |
| 47 | }; | 48 | }; |
| 48 | 49 | ||
| @@ -58,12 +59,11 @@ static unsigned int cached_irq_mask = 0xffff; | |||
| 58 | #define cached_master_mask (cached_irq_mask) | 59 | #define cached_master_mask (cached_irq_mask) |
| 59 | #define cached_slave_mask (cached_irq_mask >> 8) | 60 | #define cached_slave_mask (cached_irq_mask >> 8) |
| 60 | 61 | ||
| 61 | static void disable_8259A_irq(unsigned int irq) | 62 | static void disable_8259A_irq(struct irq_data *d) |
| 62 | { | 63 | { |
| 63 | unsigned int mask; | 64 | unsigned int mask, irq = d->irq - I8259A_IRQ_BASE; |
| 64 | unsigned long flags; | 65 | unsigned long flags; |
| 65 | 66 | ||
| 66 | irq -= I8259A_IRQ_BASE; | ||
| 67 | mask = 1 << irq; | 67 | mask = 1 << irq; |
| 68 | raw_spin_lock_irqsave(&i8259A_lock, flags); | 68 | raw_spin_lock_irqsave(&i8259A_lock, flags); |
| 69 | cached_irq_mask |= mask; | 69 | cached_irq_mask |= mask; |
| @@ -74,12 +74,11 @@ static void disable_8259A_irq(unsigned int irq) | |||
| 74 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); | 74 | raw_spin_unlock_irqrestore(&i8259A_lock, flags); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | static void enable_8259A_irq(unsigned int irq) | 77 | static void enable_8259A_irq(struct irq_data *d) |
| 78 | { | 78 | { |
| 79 | unsigned int mask; | 79 | unsigned int mask, irq = d->irq - I8259A_IRQ_BASE; |
| 80 | unsigned long flags; | 80 | unsigned long flags; |
| 81 | 81 | ||
| 82 | irq -= I8259A_IRQ_BASE; | ||
| 83 | mask = ~(1 << irq); | 82 | mask = ~(1 << irq); |
| 84 | raw_spin_lock_irqsave(&i8259A_lock, flags); | 83 | raw_spin_lock_irqsave(&i8259A_lock, flags); |
| 85 | cached_irq_mask &= mask; | 84 | cached_irq_mask &= mask; |
| @@ -111,7 +110,7 @@ int i8259A_irq_pending(unsigned int irq) | |||
| 111 | void make_8259A_irq(unsigned int irq) | 110 | void make_8259A_irq(unsigned int irq) |
| 112 | { | 111 | { |
| 113 | disable_irq_nosync(irq); | 112 | disable_irq_nosync(irq); |
| 114 | set_irq_chip_and_handler(irq, &i8259A_chip, handle_level_irq); | 113 | irq_set_chip_and_handler(irq, &i8259A_chip, handle_level_irq); |
| 115 | enable_irq(irq); | 114 | enable_irq(irq); |
| 116 | } | 115 | } |
| 117 | 116 | ||
| @@ -144,12 +143,11 @@ static inline int i8259A_irq_real(unsigned int irq) | |||
| 144 | * first, _then_ send the EOI, and the order of EOI | 143 | * first, _then_ send the EOI, and the order of EOI |
| 145 | * to the two 8259s is important! | 144 | * to the two 8259s is important! |
| 146 | */ | 145 | */ |
| 147 | static void mask_and_ack_8259A(unsigned int irq) | 146 | static void mask_and_ack_8259A(struct irq_data *d) |
| 148 | { | 147 | { |
| 149 | unsigned int irqmask; | 148 | unsigned int irqmask, irq = d->irq - I8259A_IRQ_BASE; |
| 150 | unsigned long flags; | 149 | unsigned long flags; |
| 151 | 150 | ||
| 152 | irq -= I8259A_IRQ_BASE; | ||
| 153 | irqmask = 1 << irq; | 151 | irqmask = 1 << irq; |
| 154 | raw_spin_lock_irqsave(&i8259A_lock, flags); | 152 | raw_spin_lock_irqsave(&i8259A_lock, flags); |
| 155 | /* | 153 | /* |
| @@ -217,14 +215,13 @@ spurious_8259A_irq: | |||
| 217 | } | 215 | } |
| 218 | } | 216 | } |
| 219 | 217 | ||
| 220 | static int i8259A_resume(struct sys_device *dev) | 218 | static void i8259A_resume(void) |
| 221 | { | 219 | { |
| 222 | if (i8259A_auto_eoi >= 0) | 220 | if (i8259A_auto_eoi >= 0) |
| 223 | init_8259A(i8259A_auto_eoi); | 221 | init_8259A(i8259A_auto_eoi); |
| 224 | return 0; | ||
| 225 | } | 222 | } |
| 226 | 223 | ||
| 227 | static int i8259A_shutdown(struct sys_device *dev) | 224 | static void i8259A_shutdown(void) |
| 228 | { | 225 | { |
| 229 | /* Put the i8259A into a quiescent state that | 226 | /* Put the i8259A into a quiescent state that |
| 230 | * the kernel initialization code can get it | 227 | * the kernel initialization code can get it |
| @@ -234,26 +231,17 @@ static int i8259A_shutdown(struct sys_device *dev) | |||
| 234 | outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ | 231 | outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ |
| 235 | outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-1 */ | 232 | outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-1 */ |
| 236 | } | 233 | } |
| 237 | return 0; | ||
| 238 | } | 234 | } |
| 239 | 235 | ||
| 240 | static struct sysdev_class i8259_sysdev_class = { | 236 | static struct syscore_ops i8259_syscore_ops = { |
| 241 | .name = "i8259", | ||
| 242 | .resume = i8259A_resume, | 237 | .resume = i8259A_resume, |
| 243 | .shutdown = i8259A_shutdown, | 238 | .shutdown = i8259A_shutdown, |
| 244 | }; | 239 | }; |
| 245 | 240 | ||
| 246 | static struct sys_device device_i8259A = { | ||
| 247 | .id = 0, | ||
| 248 | .cls = &i8259_sysdev_class, | ||
| 249 | }; | ||
| 250 | |||
| 251 | static int __init i8259A_init_sysfs(void) | 241 | static int __init i8259A_init_sysfs(void) |
| 252 | { | 242 | { |
| 253 | int error = sysdev_class_register(&i8259_sysdev_class); | 243 | register_syscore_ops(&i8259_syscore_ops); |
| 254 | if (!error) | 244 | return 0; |
| 255 | error = sysdev_register(&device_i8259A); | ||
| 256 | return error; | ||
| 257 | } | 245 | } |
| 258 | 246 | ||
| 259 | device_initcall(i8259A_init_sysfs); | 247 | device_initcall(i8259A_init_sysfs); |
| @@ -289,9 +277,9 @@ static void init_8259A(int auto_eoi) | |||
| 289 | * In AEOI mode we just have to mask the interrupt | 277 | * In AEOI mode we just have to mask the interrupt |
| 290 | * when acking. | 278 | * when acking. |
| 291 | */ | 279 | */ |
| 292 | i8259A_chip.mask_ack = disable_8259A_irq; | 280 | i8259A_chip.irq_mask_ack = disable_8259A_irq; |
| 293 | else | 281 | else |
| 294 | i8259A_chip.mask_ack = mask_and_ack_8259A; | 282 | i8259A_chip.irq_mask_ack = mask_and_ack_8259A; |
| 295 | 283 | ||
| 296 | udelay(100); /* wait for 8259A to initialize */ | 284 | udelay(100); /* wait for 8259A to initialize */ |
| 297 | 285 | ||
| @@ -338,8 +326,8 @@ void __init init_i8259_irqs(void) | |||
| 338 | init_8259A(0); | 326 | init_8259A(0); |
| 339 | 327 | ||
| 340 | for (i = I8259A_IRQ_BASE; i < I8259A_IRQ_BASE + 16; i++) { | 328 | for (i = I8259A_IRQ_BASE; i < I8259A_IRQ_BASE + 16; i++) { |
| 341 | set_irq_chip_and_handler(i, &i8259A_chip, handle_level_irq); | 329 | irq_set_chip_and_handler(i, &i8259A_chip, handle_level_irq); |
| 342 | set_irq_probe(i); | 330 | irq_set_probe(i); |
| 343 | } | 331 | } |
| 344 | 332 | ||
| 345 | setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2); | 333 | setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2); |
diff --git a/arch/mips/kernel/irq-gic.c b/arch/mips/kernel/irq-gic.c index 82ba9f62f49e..0c527f652196 100644 --- a/arch/mips/kernel/irq-gic.c +++ b/arch/mips/kernel/irq-gic.c | |||
| @@ -3,11 +3,11 @@ | |||
| 3 | #include <linux/bitmap.h> | 3 | #include <linux/bitmap.h> |
| 4 | #include <linux/init.h> | 4 | #include <linux/init.h> |
| 5 | #include <linux/smp.h> | 5 | #include <linux/smp.h> |
| 6 | #include <linux/irq.h> | ||
| 6 | 7 | ||
| 7 | #include <asm/io.h> | 8 | #include <asm/io.h> |
| 8 | #include <asm/gic.h> | 9 | #include <asm/gic.h> |
| 9 | #include <asm/gcmpregs.h> | 10 | #include <asm/gcmpregs.h> |
| 10 | #include <asm/irq.h> | ||
| 11 | #include <linux/hardirq.h> | 11 | #include <linux/hardirq.h> |
| 12 | #include <asm-generic/bitops/find.h> | 12 | #include <asm-generic/bitops/find.h> |
| 13 | 13 | ||
| @@ -87,17 +87,10 @@ unsigned int gic_get_int(void) | |||
| 87 | return i; | 87 | return i; |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | static unsigned int gic_irq_startup(unsigned int irq) | 90 | static void gic_irq_ack(struct irq_data *d) |
| 91 | { | 91 | { |
| 92 | irq -= _irqbase; | 92 | unsigned int irq = d->irq - _irqbase; |
| 93 | pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); | ||
| 94 | GIC_SET_INTR_MASK(irq); | ||
| 95 | return 0; | ||
| 96 | } | ||
| 97 | 93 | ||
| 98 | static void gic_irq_ack(unsigned int irq) | ||
| 99 | { | ||
| 100 | irq -= _irqbase; | ||
| 101 | pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); | 94 | pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); |
| 102 | GIC_CLR_INTR_MASK(irq); | 95 | GIC_CLR_INTR_MASK(irq); |
| 103 | 96 | ||
| @@ -105,16 +98,16 @@ static void gic_irq_ack(unsigned int irq) | |||
| 105 | GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq); | 98 | GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq); |
| 106 | } | 99 | } |
| 107 | 100 | ||
| 108 | static void gic_mask_irq(unsigned int irq) | 101 | static void gic_mask_irq(struct irq_data *d) |
| 109 | { | 102 | { |
| 110 | irq -= _irqbase; | 103 | unsigned int irq = d->irq - _irqbase; |
| 111 | pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); | 104 | pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); |
| 112 | GIC_CLR_INTR_MASK(irq); | 105 | GIC_CLR_INTR_MASK(irq); |
| 113 | } | 106 | } |
| 114 | 107 | ||
| 115 | static void gic_unmask_irq(unsigned int irq) | 108 | static void gic_unmask_irq(struct irq_data *d) |
| 116 | { | 109 | { |
| 117 | irq -= _irqbase; | 110 | unsigned int irq = d->irq - _irqbase; |
| 118 | pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); | 111 | pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq); |
| 119 | GIC_SET_INTR_MASK(irq); | 112 | GIC_SET_INTR_MASK(irq); |
| 120 | } | 113 | } |
| @@ -123,13 +116,14 @@ static void gic_unmask_irq(unsigned int irq) | |||
| 123 | 116 | ||
| 124 | static DEFINE_SPINLOCK(gic_lock); | 117 | static DEFINE_SPINLOCK(gic_lock); |
| 125 | 118 | ||
| 126 | static int gic_set_affinity(unsigned int irq, const struct cpumask *cpumask) | 119 | static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, |
| 120 | bool force) | ||
| 127 | { | 121 | { |
| 122 | unsigned int irq = d->irq - _irqbase; | ||
| 128 | cpumask_t tmp = CPU_MASK_NONE; | 123 | cpumask_t tmp = CPU_MASK_NONE; |
| 129 | unsigned long flags; | 124 | unsigned long flags; |
| 130 | int i; | 125 | int i; |
| 131 | 126 | ||
| 132 | irq -= _irqbase; | ||
| 133 | pr_debug("%s(%d) called\n", __func__, irq); | 127 | pr_debug("%s(%d) called\n", __func__, irq); |
| 134 | cpumask_and(&tmp, cpumask, cpu_online_mask); | 128 | cpumask_and(&tmp, cpumask, cpu_online_mask); |
| 135 | if (cpus_empty(tmp)) | 129 | if (cpus_empty(tmp)) |
| @@ -147,23 +141,22 @@ static int gic_set_affinity(unsigned int irq, const struct cpumask *cpumask) | |||
| 147 | set_bit(irq, pcpu_masks[first_cpu(tmp)].pcpu_mask); | 141 | set_bit(irq, pcpu_masks[first_cpu(tmp)].pcpu_mask); |
| 148 | 142 | ||
| 149 | } | 143 | } |
| 150 | cpumask_copy(irq_desc[irq].affinity, cpumask); | 144 | cpumask_copy(d->affinity, cpumask); |
| 151 | spin_unlock_irqrestore(&gic_lock, flags); | 145 | spin_unlock_irqrestore(&gic_lock, flags); |
| 152 | 146 | ||
| 153 | return 0; | 147 | return IRQ_SET_MASK_OK_NOCOPY; |
| 154 | } | 148 | } |
| 155 | #endif | 149 | #endif |
| 156 | 150 | ||
| 157 | static struct irq_chip gic_irq_controller = { | 151 | static struct irq_chip gic_irq_controller = { |
| 158 | .name = "MIPS GIC", | 152 | .name = "MIPS GIC", |
| 159 | .startup = gic_irq_startup, | 153 | .irq_ack = gic_irq_ack, |
| 160 | .ack = gic_irq_ack, | 154 | .irq_mask = gic_mask_irq, |
| 161 | .mask = gic_mask_irq, | 155 | .irq_mask_ack = gic_mask_irq, |
| 162 | .mask_ack = gic_mask_irq, | 156 | .irq_unmask = gic_unmask_irq, |
| 163 | .unmask = gic_unmask_irq, | 157 | .irq_eoi = gic_unmask_irq, |
| 164 | .eoi = gic_unmask_irq, | ||
| 165 | #ifdef CONFIG_SMP | 158 | #ifdef CONFIG_SMP |
| 166 | .set_affinity = gic_set_affinity, | 159 | .irq_set_affinity = gic_set_affinity, |
| 167 | #endif | 160 | #endif |
| 168 | }; | 161 | }; |
| 169 | 162 | ||
| @@ -236,7 +229,7 @@ static void __init gic_basic_init(int numintrs, int numvpes, | |||
| 236 | vpe_local_setup(numvpes); | 229 | vpe_local_setup(numvpes); |
| 237 | 230 | ||
| 238 | for (i = _irqbase; i < (_irqbase + numintrs); i++) | 231 | for (i = _irqbase; i < (_irqbase + numintrs); i++) |
| 239 | set_irq_chip(i, &gic_irq_controller); | 232 | irq_set_chip(i, &gic_irq_controller); |
| 240 | } | 233 | } |
| 241 | 234 | ||
| 242 | void __init gic_init(unsigned long gic_base_addr, | 235 | void __init gic_init(unsigned long gic_base_addr, |
diff --git a/arch/mips/kernel/irq-gt641xx.c b/arch/mips/kernel/irq-gt641xx.c index 42ef81461bfc..883fc6cead36 100644 --- a/arch/mips/kernel/irq-gt641xx.c +++ b/arch/mips/kernel/irq-gt641xx.c | |||
| @@ -29,64 +29,64 @@ | |||
| 29 | 29 | ||
| 30 | static DEFINE_RAW_SPINLOCK(gt641xx_irq_lock); | 30 | static DEFINE_RAW_SPINLOCK(gt641xx_irq_lock); |
| 31 | 31 | ||
| 32 | static void ack_gt641xx_irq(unsigned int irq) | 32 | static void ack_gt641xx_irq(struct irq_data *d) |
| 33 | { | 33 | { |
| 34 | unsigned long flags; | 34 | unsigned long flags; |
| 35 | u32 cause; | 35 | u32 cause; |
| 36 | 36 | ||
| 37 | raw_spin_lock_irqsave(>641xx_irq_lock, flags); | 37 | raw_spin_lock_irqsave(>641xx_irq_lock, flags); |
| 38 | cause = GT_READ(GT_INTRCAUSE_OFS); | 38 | cause = GT_READ(GT_INTRCAUSE_OFS); |
| 39 | cause &= ~GT641XX_IRQ_TO_BIT(irq); | 39 | cause &= ~GT641XX_IRQ_TO_BIT(d->irq); |
| 40 | GT_WRITE(GT_INTRCAUSE_OFS, cause); | 40 | GT_WRITE(GT_INTRCAUSE_OFS, cause); |
| 41 | raw_spin_unlock_irqrestore(>641xx_irq_lock, flags); | 41 | raw_spin_unlock_irqrestore(>641xx_irq_lock, flags); |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | static void mask_gt641xx_irq(unsigned int irq) | 44 | static void mask_gt641xx_irq(struct irq_data *d) |
| 45 | { | 45 | { |
| 46 | unsigned long flags; | 46 | unsigned long flags; |
| 47 | u32 mask; | 47 | u32 mask; |
| 48 | 48 | ||
| 49 | raw_spin_lock_irqsave(>641xx_irq_lock, flags); | 49 | raw_spin_lock_irqsave(>641xx_irq_lock, flags); |
| 50 | mask = GT_READ(GT_INTRMASK_OFS); | 50 | mask = GT_READ(GT_INTRMASK_OFS); |
| 51 | mask &= ~GT641XX_IRQ_TO_BIT(irq); | 51 | mask &= ~GT641XX_IRQ_TO_BIT(d->irq); |
| 52 | GT_WRITE(GT_INTRMASK_OFS, mask); | 52 | GT_WRITE(GT_INTRMASK_OFS, mask); |
| 53 | raw_spin_unlock_irqrestore(>641xx_irq_lock, flags); | 53 | raw_spin_unlock_irqrestore(>641xx_irq_lock, flags); |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | static void mask_ack_gt641xx_irq(unsigned int irq) | 56 | static void mask_ack_gt641xx_irq(struct irq_data *d) |
| 57 | { | 57 | { |
| 58 | unsigned long flags; | 58 | unsigned long flags; |
| 59 | u32 cause, mask; | 59 | u32 cause, mask; |
| 60 | 60 | ||
| 61 | raw_spin_lock_irqsave(>641xx_irq_lock, flags); | 61 | raw_spin_lock_irqsave(>641xx_irq_lock, flags); |
| 62 | mask = GT_READ(GT_INTRMASK_OFS); | 62 | mask = GT_READ(GT_INTRMASK_OFS); |
| 63 | mask &= ~GT641XX_IRQ_TO_BIT(irq); | 63 | mask &= ~GT641XX_IRQ_TO_BIT(d->irq); |
| 64 | GT_WRITE(GT_INTRMASK_OFS, mask); | 64 | GT_WRITE(GT_INTRMASK_OFS, mask); |
| 65 | 65 | ||
| 66 | cause = GT_READ(GT_INTRCAUSE_OFS); | 66 | cause = GT_READ(GT_INTRCAUSE_OFS); |
| 67 | cause &= ~GT641XX_IRQ_TO_BIT(irq); | 67 | cause &= ~GT641XX_IRQ_TO_BIT(d->irq); |
| 68 | GT_WRITE(GT_INTRCAUSE_OFS, cause); | 68 | GT_WRITE(GT_INTRCAUSE_OFS, cause); |
| 69 | raw_spin_unlock_irqrestore(>641xx_irq_lock, flags); | 69 | raw_spin_unlock_irqrestore(>641xx_irq_lock, flags); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | static void unmask_gt641xx_irq(unsigned int irq) | 72 | static void unmask_gt641xx_irq(struct irq_data *d) |
| 73 | { | 73 | { |
| 74 | unsigned long flags; | 74 | unsigned long flags; |
| 75 | u32 mask; | 75 | u32 mask; |
| 76 | 76 | ||
| 77 | raw_spin_lock_irqsave(>641xx_irq_lock, flags); | 77 | raw_spin_lock_irqsave(>641xx_irq_lock, flags); |
| 78 | mask = GT_READ(GT_INTRMASK_OFS); | 78 | mask = GT_READ(GT_INTRMASK_OFS); |
| 79 | mask |= GT641XX_IRQ_TO_BIT(irq); | 79 | mask |= GT641XX_IRQ_TO_BIT(d->irq); |
| 80 | GT_WRITE(GT_INTRMASK_OFS, mask); | 80 | GT_WRITE(GT_INTRMASK_OFS, mask); |
| 81 | raw_spin_unlock_irqrestore(>641xx_irq_lock, flags); | 81 | raw_spin_unlock_irqrestore(>641xx_irq_lock, flags); |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | static struct irq_chip gt641xx_irq_chip = { | 84 | static struct irq_chip gt641xx_irq_chip = { |
| 85 | .name = "GT641xx", | 85 | .name = "GT641xx", |
| 86 | .ack = ack_gt641xx_irq, | 86 | .irq_ack = ack_gt641xx_irq, |
| 87 | .mask = mask_gt641xx_irq, | 87 | .irq_mask = mask_gt641xx_irq, |
| 88 | .mask_ack = mask_ack_gt641xx_irq, | 88 | .irq_mask_ack = mask_ack_gt641xx_irq, |
| 89 | .unmask = unmask_gt641xx_irq, | 89 | .irq_unmask = unmask_gt641xx_irq, |
| 90 | }; | 90 | }; |
| 91 | 91 | ||
| 92 | void gt641xx_irq_dispatch(void) | 92 | void gt641xx_irq_dispatch(void) |
| @@ -126,6 +126,6 @@ void __init gt641xx_irq_init(void) | |||
| 126 | * bit31: logical or of bits[25:1]. | 126 | * bit31: logical or of bits[25:1]. |
| 127 | */ | 127 | */ |
| 128 | for (i = 1; i < 30; i++) | 128 | for (i = 1; i < 30; i++) |
| 129 | set_irq_chip_and_handler(GT641XX_IRQ_BASE + i, | 129 | irq_set_chip_and_handler(GT641XX_IRQ_BASE + i, |
| 130 | >641xx_irq_chip, handle_level_irq); | 130 | >641xx_irq_chip, handle_level_irq); |
| 131 | } | 131 | } |
diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c index 6a8cd28133d5..0c6afeed89d2 100644 --- a/arch/mips/kernel/irq-msc01.c +++ b/arch/mips/kernel/irq-msc01.c | |||
| @@ -28,8 +28,10 @@ static unsigned long _icctrl_msc; | |||
| 28 | static unsigned int irq_base; | 28 | static unsigned int irq_base; |
| 29 | 29 | ||
| 30 | /* mask off an interrupt */ | 30 | /* mask off an interrupt */ |
| 31 | static inline void mask_msc_irq(unsigned int irq) | 31 | static inline void mask_msc_irq(struct irq_data *d) |
| 32 | { | 32 | { |
| 33 | unsigned int irq = d->irq; | ||
| 34 | |||
| 33 | if (irq < (irq_base + 32)) | 35 | if (irq < (irq_base + 32)) |
| 34 | MSCIC_WRITE(MSC01_IC_DISL, 1<<(irq - irq_base)); | 36 | MSCIC_WRITE(MSC01_IC_DISL, 1<<(irq - irq_base)); |
| 35 | else | 37 | else |
| @@ -37,8 +39,10 @@ static inline void mask_msc_irq(unsigned int irq) | |||
| 37 | } | 39 | } |
| 38 | 40 | ||
| 39 | /* unmask an interrupt */ | 41 | /* unmask an interrupt */ |
| 40 | static inline void unmask_msc_irq(unsigned int irq) | 42 | static inline void unmask_msc_irq(struct irq_data *d) |
| 41 | { | 43 | { |
| 44 | unsigned int irq = d->irq; | ||
| 45 | |||
| 42 | if (irq < (irq_base + 32)) | 46 | if (irq < (irq_base + 32)) |
| 43 | MSCIC_WRITE(MSC01_IC_ENAL, 1<<(irq - irq_base)); | 47 | MSCIC_WRITE(MSC01_IC_ENAL, 1<<(irq - irq_base)); |
| 44 | else | 48 | else |
| @@ -48,9 +52,11 @@ static inline void unmask_msc_irq(unsigned int irq) | |||
| 48 | /* | 52 | /* |
| 49 | * Masks and ACKs an IRQ | 53 | * Masks and ACKs an IRQ |
| 50 | */ | 54 | */ |
| 51 | static void level_mask_and_ack_msc_irq(unsigned int irq) | 55 | static void level_mask_and_ack_msc_irq(struct irq_data *d) |
| 52 | { | 56 | { |
| 53 | mask_msc_irq(irq); | 57 | unsigned int irq = d->irq; |
| 58 | |||
| 59 | mask_msc_irq(d); | ||
| 54 | if (!cpu_has_veic) | 60 | if (!cpu_has_veic) |
| 55 | MSCIC_WRITE(MSC01_IC_EOI, 0); | 61 | MSCIC_WRITE(MSC01_IC_EOI, 0); |
| 56 | /* This actually needs to be a call into platform code */ | 62 | /* This actually needs to be a call into platform code */ |
| @@ -60,9 +66,11 @@ static void level_mask_and_ack_msc_irq(unsigned int irq) | |||
| 60 | /* | 66 | /* |
| 61 | * Masks and ACKs an IRQ | 67 | * Masks and ACKs an IRQ |
| 62 | */ | 68 | */ |
| 63 | static void edge_mask_and_ack_msc_irq(unsigned int irq) | 69 | static void edge_mask_and_ack_msc_irq(struct irq_data *d) |
| 64 | { | 70 | { |
| 65 | mask_msc_irq(irq); | 71 | unsigned int irq = d->irq; |
| 72 | |||
| 73 | mask_msc_irq(d); | ||
| 66 | if (!cpu_has_veic) | 74 | if (!cpu_has_veic) |
| 67 | MSCIC_WRITE(MSC01_IC_EOI, 0); | 75 | MSCIC_WRITE(MSC01_IC_EOI, 0); |
| 68 | else { | 76 | else { |
| @@ -75,15 +83,6 @@ static void edge_mask_and_ack_msc_irq(unsigned int irq) | |||
| 75 | } | 83 | } |
| 76 | 84 | ||
| 77 | /* | 85 | /* |
| 78 | * End IRQ processing | ||
| 79 | */ | ||
| 80 | static void end_msc_irq(unsigned int irq) | ||
| 81 | { | ||
| 82 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) | ||
| 83 | unmask_msc_irq(irq); | ||
| 84 | } | ||
| 85 | |||
| 86 | /* | ||
| 87 | * Interrupt handler for interrupts coming from SOC-it. | 86 | * Interrupt handler for interrupts coming from SOC-it. |
| 88 | */ | 87 | */ |
| 89 | void ll_msc_irq(void) | 88 | void ll_msc_irq(void) |
| @@ -107,22 +106,20 @@ static void msc_bind_eic_interrupt(int irq, int set) | |||
| 107 | 106 | ||
| 108 | static struct irq_chip msc_levelirq_type = { | 107 | static struct irq_chip msc_levelirq_type = { |
| 109 | .name = "SOC-it-Level", | 108 | .name = "SOC-it-Level", |
| 110 | .ack = level_mask_and_ack_msc_irq, | 109 | .irq_ack = level_mask_and_ack_msc_irq, |
| 111 | .mask = mask_msc_irq, | 110 | .irq_mask = mask_msc_irq, |
| 112 | .mask_ack = level_mask_and_ack_msc_irq, | 111 | .irq_mask_ack = level_mask_and_ack_msc_irq, |
| 113 | .unmask = unmask_msc_irq, | 112 | .irq_unmask = unmask_msc_irq, |
| 114 | .eoi = unmask_msc_irq, | 113 | .irq_eoi = unmask_msc_irq, |
| 115 | .end = end_msc_irq, | ||
| 116 | }; | 114 | }; |
| 117 | 115 | ||
| 118 | static struct irq_chip msc_edgeirq_type = { | 116 | static struct irq_chip msc_edgeirq_type = { |
| 119 | .name = "SOC-it-Edge", | 117 | .name = "SOC-it-Edge", |
| 120 | .ack = edge_mask_and_ack_msc_irq, | 118 | .irq_ack = edge_mask_and_ack_msc_irq, |
| 121 | .mask = mask_msc_irq, | 119 | .irq_mask = mask_msc_irq, |
| 122 | .mask_ack = edge_mask_and_ack_msc_irq, | 120 | .irq_mask_ack = edge_mask_and_ack_msc_irq, |
| 123 | .unmask = unmask_msc_irq, | 121 | .irq_unmask = unmask_msc_irq, |
| 124 | .eoi = unmask_msc_irq, | 122 | .irq_eoi = unmask_msc_irq, |
| 125 | .end = end_msc_irq, | ||
| 126 | }; | 123 | }; |
| 127 | 124 | ||
| 128 | 125 | ||
| @@ -140,16 +137,20 @@ void __init init_msc_irqs(unsigned long icubase, unsigned int irqbase, msc_irqma | |||
| 140 | 137 | ||
| 141 | switch (imp->im_type) { | 138 | switch (imp->im_type) { |
| 142 | case MSC01_IRQ_EDGE: | 139 | case MSC01_IRQ_EDGE: |
| 143 | set_irq_chip_and_handler_name(irqbase + n, | 140 | irq_set_chip_and_handler_name(irqbase + n, |
| 144 | &msc_edgeirq_type, handle_edge_irq, "edge"); | 141 | &msc_edgeirq_type, |
| 142 | handle_edge_irq, | ||
| 143 | "edge"); | ||
| 145 | if (cpu_has_veic) | 144 | if (cpu_has_veic) |
| 146 | MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT); | 145 | MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT); |
| 147 | else | 146 | else |
| 148 | MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT | imp->im_lvl); | 147 | MSCIC_WRITE(MSC01_IC_SUP+n*8, MSC01_IC_SUP_EDGE_BIT | imp->im_lvl); |
| 149 | break; | 148 | break; |
| 150 | case MSC01_IRQ_LEVEL: | 149 | case MSC01_IRQ_LEVEL: |
| 151 | set_irq_chip_and_handler_name(irqbase+n, | 150 | irq_set_chip_and_handler_name(irqbase + n, |
| 152 | &msc_levelirq_type, handle_level_irq, "level"); | 151 | &msc_levelirq_type, |
| 152 | handle_level_irq, | ||
| 153 | "level"); | ||
| 153 | if (cpu_has_veic) | 154 | if (cpu_has_veic) |
| 154 | MSCIC_WRITE(MSC01_IC_SUP+n*8, 0); | 155 | MSCIC_WRITE(MSC01_IC_SUP+n*8, 0); |
| 155 | else | 156 | else |
diff --git a/arch/mips/kernel/irq-rm7000.c b/arch/mips/kernel/irq-rm7000.c index fb50cc78b28b..a8a8977d5887 100644 --- a/arch/mips/kernel/irq-rm7000.c +++ b/arch/mips/kernel/irq-rm7000.c | |||
| @@ -11,29 +11,30 @@ | |||
| 11 | */ | 11 | */ |
| 12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
| 13 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
| 14 | #include <linux/irq.h> | ||
| 14 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
| 15 | 16 | ||
| 16 | #include <asm/irq_cpu.h> | 17 | #include <asm/irq_cpu.h> |
| 17 | #include <asm/mipsregs.h> | 18 | #include <asm/mipsregs.h> |
| 18 | #include <asm/system.h> | 19 | #include <asm/system.h> |
| 19 | 20 | ||
| 20 | static inline void unmask_rm7k_irq(unsigned int irq) | 21 | static inline void unmask_rm7k_irq(struct irq_data *d) |
| 21 | { | 22 | { |
| 22 | set_c0_intcontrol(0x100 << (irq - RM7K_CPU_IRQ_BASE)); | 23 | set_c0_intcontrol(0x100 << (d->irq - RM7K_CPU_IRQ_BASE)); |
| 23 | } | 24 | } |
| 24 | 25 | ||
| 25 | static inline void mask_rm7k_irq(unsigned int irq) | 26 | static inline void mask_rm7k_irq(struct irq_data *d) |
| 26 | { | 27 | { |
| 27 | clear_c0_intcontrol(0x100 << (irq - RM7K_CPU_IRQ_BASE)); | 28 | clear_c0_intcontrol(0x100 << (d->irq - RM7K_CPU_IRQ_BASE)); |
| 28 | } | 29 | } |
| 29 | 30 | ||
| 30 | static struct irq_chip rm7k_irq_controller = { | 31 | static struct irq_chip rm7k_irq_controller = { |
| 31 | .name = "RM7000", | 32 | .name = "RM7000", |
| 32 | .ack = mask_rm7k_irq, | 33 | .irq_ack = mask_rm7k_irq, |
| 33 | .mask = mask_rm7k_irq, | 34 | .irq_mask = mask_rm7k_irq, |
| 34 | .mask_ack = mask_rm7k_irq, | 35 | .irq_mask_ack = mask_rm7k_irq, |
| 35 | .unmask = unmask_rm7k_irq, | 36 | .irq_unmask = unmask_rm7k_irq, |
| 36 | .eoi = unmask_rm7k_irq | 37 | .irq_eoi = unmask_rm7k_irq |
| 37 | }; | 38 | }; |
| 38 | 39 | ||
| 39 | void __init rm7k_cpu_irq_init(void) | 40 | void __init rm7k_cpu_irq_init(void) |
| @@ -44,6 +45,6 @@ void __init rm7k_cpu_irq_init(void) | |||
| 44 | clear_c0_intcontrol(0x00000f00); /* Mask all */ | 45 | clear_c0_intcontrol(0x00000f00); /* Mask all */ |
| 45 | 46 | ||
| 46 | for (i = base; i < base + 4; i++) | 47 | for (i = base; i < base + 4; i++) |
| 47 | set_irq_chip_and_handler(i, &rm7k_irq_controller, | 48 | irq_set_chip_and_handler(i, &rm7k_irq_controller, |
| 48 | handle_percpu_irq); | 49 | handle_percpu_irq); |
| 49 | } | 50 | } |
diff --git a/arch/mips/kernel/irq-rm9000.c b/arch/mips/kernel/irq-rm9000.c index b47e4615ec12..38874a4b9255 100644 --- a/arch/mips/kernel/irq-rm9000.c +++ b/arch/mips/kernel/irq-rm9000.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | */ | 11 | */ |
| 12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
| 13 | #include <linux/interrupt.h> | 13 | #include <linux/interrupt.h> |
| 14 | #include <linux/irq.h> | ||
| 14 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
| 15 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 16 | 17 | ||
| @@ -18,22 +19,22 @@ | |||
| 18 | #include <asm/mipsregs.h> | 19 | #include <asm/mipsregs.h> |
| 19 | #include <asm/system.h> | 20 | #include <asm/system.h> |
| 20 | 21 | ||
| 21 | static inline void unmask_rm9k_irq(unsigned int irq) | 22 | static inline void unmask_rm9k_irq(struct irq_data *d) |
| 22 | { | 23 | { |
| 23 | set_c0_intcontrol(0x1000 << (irq - RM9K_CPU_IRQ_BASE)); | 24 | set_c0_intcontrol(0x1000 << (d->irq - RM9K_CPU_IRQ_BASE)); |
| 24 | } | 25 | } |
| 25 | 26 | ||
| 26 | static inline void mask_rm9k_irq(unsigned int irq) | 27 | static inline void mask_rm9k_irq(struct irq_data *d) |
| 27 | { | 28 | { |
| 28 | clear_c0_intcontrol(0x1000 << (irq - RM9K_CPU_IRQ_BASE)); | 29 | clear_c0_intcontrol(0x1000 << (d->irq - RM9K_CPU_IRQ_BASE)); |
| 29 | } | 30 | } |
| 30 | 31 | ||
| 31 | static inline void rm9k_cpu_irq_enable(unsigned int irq) | 32 | static inline void rm9k_cpu_irq_enable(struct irq_data *d) |
| 32 | { | 33 | { |
| 33 | unsigned long flags; | 34 | unsigned long flags; |
| 34 | 35 | ||
| 35 | local_irq_save(flags); | 36 | local_irq_save(flags); |
| 36 | unmask_rm9k_irq(irq); | 37 | unmask_rm9k_irq(d); |
| 37 | local_irq_restore(flags); | 38 | local_irq_restore(flags); |
| 38 | } | 39 | } |
| 39 | 40 | ||
| @@ -42,50 +43,47 @@ static inline void rm9k_cpu_irq_enable(unsigned int irq) | |||
| 42 | */ | 43 | */ |
| 43 | static void local_rm9k_perfcounter_irq_startup(void *args) | 44 | static void local_rm9k_perfcounter_irq_startup(void *args) |
| 44 | { | 45 | { |
| 45 | unsigned int irq = (unsigned int) args; | 46 | rm9k_cpu_irq_enable(args); |
| 46 | |||
| 47 | rm9k_cpu_irq_enable(irq); | ||
| 48 | } | 47 | } |
| 49 | 48 | ||
| 50 | static unsigned int rm9k_perfcounter_irq_startup(unsigned int irq) | 49 | static unsigned int rm9k_perfcounter_irq_startup(struct irq_data *d) |
| 51 | { | 50 | { |
| 52 | on_each_cpu(local_rm9k_perfcounter_irq_startup, (void *) irq, 1); | 51 | on_each_cpu(local_rm9k_perfcounter_irq_startup, d, 1); |
| 53 | 52 | ||
| 54 | return 0; | 53 | return 0; |
| 55 | } | 54 | } |
| 56 | 55 | ||
| 57 | static void local_rm9k_perfcounter_irq_shutdown(void *args) | 56 | static void local_rm9k_perfcounter_irq_shutdown(void *args) |
| 58 | { | 57 | { |
| 59 | unsigned int irq = (unsigned int) args; | ||
| 60 | unsigned long flags; | 58 | unsigned long flags; |
| 61 | 59 | ||
| 62 | local_irq_save(flags); | 60 | local_irq_save(flags); |
| 63 | mask_rm9k_irq(irq); | 61 | mask_rm9k_irq(args); |
| 64 | local_irq_restore(flags); | 62 | local_irq_restore(flags); |
| 65 | } | 63 | } |
| 66 | 64 | ||
| 67 | static void rm9k_perfcounter_irq_shutdown(unsigned int irq) | 65 | static void rm9k_perfcounter_irq_shutdown(struct irq_data *d) |
| 68 | { | 66 | { |
| 69 | on_each_cpu(local_rm9k_perfcounter_irq_shutdown, (void *) irq, 1); | 67 | on_each_cpu(local_rm9k_perfcounter_irq_shutdown, d, 1); |
| 70 | } | 68 | } |
| 71 | 69 | ||
| 72 | static struct irq_chip rm9k_irq_controller = { | 70 | static struct irq_chip rm9k_irq_controller = { |
| 73 | .name = "RM9000", | 71 | .name = "RM9000", |
| 74 | .ack = mask_rm9k_irq, | 72 | .irq_ack = mask_rm9k_irq, |
| 75 | .mask = mask_rm9k_irq, | 73 | .irq_mask = mask_rm9k_irq, |
| 76 | .mask_ack = mask_rm9k_irq, | 74 | .irq_mask_ack = mask_rm9k_irq, |
| 77 | .unmask = unmask_rm9k_irq, | 75 | .irq_unmask = unmask_rm9k_irq, |
| 78 | .eoi = unmask_rm9k_irq | 76 | .irq_eoi = unmask_rm9k_irq |
| 79 | }; | 77 | }; |
| 80 | 78 | ||
| 81 | static struct irq_chip rm9k_perfcounter_irq = { | 79 | static struct irq_chip rm9k_perfcounter_irq = { |
| 82 | .name = "RM9000", | 80 | .name = "RM9000", |
| 83 | .startup = rm9k_perfcounter_irq_startup, | 81 | .irq_startup = rm9k_perfcounter_irq_startup, |
| 84 | .shutdown = rm9k_perfcounter_irq_shutdown, | 82 | .irq_shutdown = rm9k_perfcounter_irq_shutdown, |
| 85 | .ack = mask_rm9k_irq, | 83 | .irq_ack = mask_rm9k_irq, |
| 86 | .mask = mask_rm9k_irq, | 84 | .irq_mask = mask_rm9k_irq, |
| 87 | .mask_ack = mask_rm9k_irq, | 85 | .irq_mask_ack = mask_rm9k_irq, |
| 88 | .unmask = unmask_rm9k_irq, | 86 | .irq_unmask = unmask_rm9k_irq, |
| 89 | }; | 87 | }; |
| 90 | 88 | ||
| 91 | unsigned int rm9000_perfcount_irq; | 89 | unsigned int rm9000_perfcount_irq; |
| @@ -100,10 +98,10 @@ void __init rm9k_cpu_irq_init(void) | |||
| 100 | clear_c0_intcontrol(0x0000f000); /* Mask all */ | 98 | clear_c0_intcontrol(0x0000f000); /* Mask all */ |
| 101 | 99 | ||
| 102 | for (i = base; i < base + 4; i++) | 100 | for (i = base; i < base + 4; i++) |
| 103 | set_irq_chip_and_handler(i, &rm9k_irq_controller, | 101 | irq_set_chip_and_handler(i, &rm9k_irq_controller, |
| 104 | handle_level_irq); | 102 | handle_level_irq); |
| 105 | 103 | ||
| 106 | rm9000_perfcount_irq = base + 1; | 104 | rm9000_perfcount_irq = base + 1; |
| 107 | set_irq_chip_and_handler(rm9000_perfcount_irq, &rm9k_perfcounter_irq, | 105 | irq_set_chip_and_handler(rm9000_perfcount_irq, &rm9k_perfcounter_irq, |
| 108 | handle_percpu_irq); | 106 | handle_percpu_irq); |
| 109 | } | 107 | } |
diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index c6345f579a8a..9b734d74ae8e 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c | |||
| @@ -81,48 +81,9 @@ void ack_bad_irq(unsigned int irq) | |||
| 81 | 81 | ||
| 82 | atomic_t irq_err_count; | 82 | atomic_t irq_err_count; |
| 83 | 83 | ||
| 84 | /* | 84 | int arch_show_interrupts(struct seq_file *p, int prec) |
| 85 | * Generic, controller-independent functions: | ||
| 86 | */ | ||
| 87 | |||
| 88 | int show_interrupts(struct seq_file *p, void *v) | ||
| 89 | { | 85 | { |
| 90 | int i = *(loff_t *) v, j; | 86 | seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count)); |
| 91 | struct irqaction * action; | ||
| 92 | unsigned long flags; | ||
| 93 | |||
| 94 | if (i == 0) { | ||
| 95 | seq_printf(p, " "); | ||
| 96 | for_each_online_cpu(j) | ||
| 97 | seq_printf(p, "CPU%d ", j); | ||
| 98 | seq_putc(p, '\n'); | ||
| 99 | } | ||
| 100 | |||
| 101 | if (i < NR_IRQS) { | ||
| 102 | raw_spin_lock_irqsave(&irq_desc[i].lock, flags); | ||
| 103 | action = irq_desc[i].action; | ||
| 104 | if (!action) | ||
| 105 | goto skip; | ||
| 106 | seq_printf(p, "%3d: ", i); | ||
| 107 | #ifndef CONFIG_SMP | ||
| 108 | seq_printf(p, "%10u ", kstat_irqs(i)); | ||
| 109 | #else | ||
| 110 | for_each_online_cpu(j) | ||
| 111 | seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); | ||
| 112 | #endif | ||
| 113 | seq_printf(p, " %14s", irq_desc[i].chip->name); | ||
| 114 | seq_printf(p, " %s", action->name); | ||
| 115 | |||
| 116 | for (action=action->next; action; action = action->next) | ||
| 117 | seq_printf(p, ", %s", action->name); | ||
| 118 | |||
| 119 | seq_putc(p, '\n'); | ||
| 120 | skip: | ||
| 121 | raw_spin_unlock_irqrestore(&irq_desc[i].lock, flags); | ||
| 122 | } else if (i == NR_IRQS) { | ||
| 123 | seq_putc(p, '\n'); | ||
| 124 | seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); | ||
| 125 | } | ||
| 126 | return 0; | 87 | return 0; |
| 127 | } | 88 | } |
| 128 | 89 | ||
| @@ -141,7 +102,7 @@ void __init init_IRQ(void) | |||
| 141 | #endif | 102 | #endif |
| 142 | 103 | ||
| 143 | for (i = 0; i < NR_IRQS; i++) | 104 | for (i = 0; i < NR_IRQS; i++) |
| 144 | set_irq_noprobe(i); | 105 | irq_set_noprobe(i); |
| 145 | 106 | ||
| 146 | arch_init_irq(); | 107 | arch_init_irq(); |
| 147 | 108 | ||
| @@ -151,6 +112,29 @@ void __init init_IRQ(void) | |||
| 151 | #endif | 112 | #endif |
| 152 | } | 113 | } |
| 153 | 114 | ||
| 115 | #ifdef DEBUG_STACKOVERFLOW | ||
| 116 | static inline void check_stack_overflow(void) | ||
| 117 | { | ||
| 118 | unsigned long sp; | ||
| 119 | |||
| 120 | __asm__ __volatile__("move %0, $sp" : "=r" (sp)); | ||
| 121 | sp &= THREAD_MASK; | ||
| 122 | |||
| 123 | /* | ||
| 124 | * Check for stack overflow: is there less than STACK_WARN free? | ||
| 125 | * STACK_WARN is defined as 1/8 of THREAD_SIZE by default. | ||
| 126 | */ | ||
| 127 | if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) { | ||
| 128 | printk("do_IRQ: stack overflow: %ld\n", | ||
| 129 | sp - sizeof(struct thread_info)); | ||
| 130 | dump_stack(); | ||
| 131 | } | ||
| 132 | } | ||
| 133 | #else | ||
| 134 | static inline void check_stack_overflow(void) {} | ||
| 135 | #endif | ||
| 136 | |||
| 137 | |||
| 154 | /* | 138 | /* |
| 155 | * do_IRQ handles all normal device IRQ's (the special | 139 | * do_IRQ handles all normal device IRQ's (the special |
| 156 | * SMP cross-CPU interrupts have their own specific | 140 | * SMP cross-CPU interrupts have their own specific |
| @@ -159,8 +143,9 @@ void __init init_IRQ(void) | |||
| 159 | void __irq_entry do_IRQ(unsigned int irq) | 143 | void __irq_entry do_IRQ(unsigned int irq) |
| 160 | { | 144 | { |
| 161 | irq_enter(); | 145 | irq_enter(); |
| 162 | __DO_IRQ_SMTC_HOOK(irq); | 146 | check_stack_overflow(); |
| 163 | generic_handle_irq(irq); | 147 | if (!smtc_handle_on_other_cpu(irq)) |
| 148 | generic_handle_irq(irq); | ||
| 164 | irq_exit(); | 149 | irq_exit(); |
| 165 | } | 150 | } |
| 166 | 151 | ||
| @@ -173,7 +158,7 @@ void __irq_entry do_IRQ(unsigned int irq) | |||
| 173 | void __irq_entry do_IRQ_no_affinity(unsigned int irq) | 158 | void __irq_entry do_IRQ_no_affinity(unsigned int irq) |
| 174 | { | 159 | { |
| 175 | irq_enter(); | 160 | irq_enter(); |
| 176 | __NO_AFFINITY_IRQ_SMTC_HOOK(irq); | 161 | smtc_im_backstop(irq); |
| 177 | generic_handle_irq(irq); | 162 | generic_handle_irq(irq); |
| 178 | irq_exit(); | 163 | irq_exit(); |
| 179 | } | 164 | } |
diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c index 55c8a3ca507b..6e71b284f6c9 100644 --- a/arch/mips/kernel/irq_cpu.c +++ b/arch/mips/kernel/irq_cpu.c | |||
| @@ -30,48 +30,45 @@ | |||
| 30 | #include <linux/init.h> | 30 | #include <linux/init.h> |
| 31 | #include <linux/interrupt.h> | 31 | #include <linux/interrupt.h> |
| 32 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
| 33 | #include <linux/irq.h> | ||
| 33 | 34 | ||
| 34 | #include <asm/irq_cpu.h> | 35 | #include <asm/irq_cpu.h> |
| 35 | #include <asm/mipsregs.h> | 36 | #include <asm/mipsregs.h> |
| 36 | #include <asm/mipsmtregs.h> | 37 | #include <asm/mipsmtregs.h> |
| 37 | #include <asm/system.h> | 38 | #include <asm/system.h> |
| 38 | 39 | ||
| 39 | static inline void unmask_mips_irq(unsigned int irq) | 40 | static inline void unmask_mips_irq(struct irq_data *d) |
| 40 | { | 41 | { |
| 41 | set_c0_status(0x100 << (irq - MIPS_CPU_IRQ_BASE)); | 42 | set_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); |
| 42 | irq_enable_hazard(); | 43 | irq_enable_hazard(); |
| 43 | } | 44 | } |
| 44 | 45 | ||
| 45 | static inline void mask_mips_irq(unsigned int irq) | 46 | static inline void mask_mips_irq(struct irq_data *d) |
| 46 | { | 47 | { |
| 47 | clear_c0_status(0x100 << (irq - MIPS_CPU_IRQ_BASE)); | 48 | clear_c0_status(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); |
| 48 | irq_disable_hazard(); | 49 | irq_disable_hazard(); |
| 49 | } | 50 | } |
| 50 | 51 | ||
| 51 | static struct irq_chip mips_cpu_irq_controller = { | 52 | static struct irq_chip mips_cpu_irq_controller = { |
| 52 | .name = "MIPS", | 53 | .name = "MIPS", |
| 53 | .ack = mask_mips_irq, | 54 | .irq_ack = mask_mips_irq, |
| 54 | .mask = mask_mips_irq, | 55 | .irq_mask = mask_mips_irq, |
| 55 | .mask_ack = mask_mips_irq, | 56 | .irq_mask_ack = mask_mips_irq, |
| 56 | .unmask = unmask_mips_irq, | 57 | .irq_unmask = unmask_mips_irq, |
| 57 | .eoi = unmask_mips_irq, | 58 | .irq_eoi = unmask_mips_irq, |
| 58 | }; | 59 | }; |
| 59 | 60 | ||
| 60 | /* | 61 | /* |
| 61 | * Basically the same as above but taking care of all the MT stuff | 62 | * Basically the same as above but taking care of all the MT stuff |
| 62 | */ | 63 | */ |
| 63 | 64 | ||
| 64 | #define unmask_mips_mt_irq unmask_mips_irq | 65 | static unsigned int mips_mt_cpu_irq_startup(struct irq_data *d) |
| 65 | #define mask_mips_mt_irq mask_mips_irq | ||
| 66 | |||
| 67 | static unsigned int mips_mt_cpu_irq_startup(unsigned int irq) | ||
| 68 | { | 66 | { |
| 69 | unsigned int vpflags = dvpe(); | 67 | unsigned int vpflags = dvpe(); |
| 70 | 68 | ||
| 71 | clear_c0_cause(0x100 << (irq - MIPS_CPU_IRQ_BASE)); | 69 | clear_c0_cause(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); |
| 72 | evpe(vpflags); | 70 | evpe(vpflags); |
| 73 | unmask_mips_mt_irq(irq); | 71 | unmask_mips_irq(d); |
| 74 | |||
| 75 | return 0; | 72 | return 0; |
| 76 | } | 73 | } |
| 77 | 74 | ||
| @@ -79,22 +76,22 @@ static unsigned int mips_mt_cpu_irq_startup(unsigned int irq) | |||
| 79 | * While we ack the interrupt interrupts are disabled and thus we don't need | 76 | * While we ack the interrupt interrupts are disabled and thus we don't need |
| 80 | * to deal with concurrency issues. Same for mips_cpu_irq_end. | 77 | * to deal with concurrency issues. Same for mips_cpu_irq_end. |
| 81 | */ | 78 | */ |
| 82 | static void mips_mt_cpu_irq_ack(unsigned int irq) | 79 | static void mips_mt_cpu_irq_ack(struct irq_data *d) |
| 83 | { | 80 | { |
| 84 | unsigned int vpflags = dvpe(); | 81 | unsigned int vpflags = dvpe(); |
| 85 | clear_c0_cause(0x100 << (irq - MIPS_CPU_IRQ_BASE)); | 82 | clear_c0_cause(0x100 << (d->irq - MIPS_CPU_IRQ_BASE)); |
| 86 | evpe(vpflags); | 83 | evpe(vpflags); |
| 87 | mask_mips_mt_irq(irq); | 84 | mask_mips_irq(d); |
| 88 | } | 85 | } |
| 89 | 86 | ||
| 90 | static struct irq_chip mips_mt_cpu_irq_controller = { | 87 | static struct irq_chip mips_mt_cpu_irq_controller = { |
| 91 | .name = "MIPS", | 88 | .name = "MIPS", |
| 92 | .startup = mips_mt_cpu_irq_startup, | 89 | .irq_startup = mips_mt_cpu_irq_startup, |
| 93 | .ack = mips_mt_cpu_irq_ack, | 90 | .irq_ack = mips_mt_cpu_irq_ack, |
| 94 | .mask = mask_mips_mt_irq, | 91 | .irq_mask = mask_mips_irq, |
| 95 | .mask_ack = mips_mt_cpu_irq_ack, | 92 | .irq_mask_ack = mips_mt_cpu_irq_ack, |
| 96 | .unmask = unmask_mips_mt_irq, | 93 | .irq_unmask = unmask_mips_irq, |
| 97 | .eoi = unmask_mips_mt_irq, | 94 | .irq_eoi = unmask_mips_irq, |
| 98 | }; | 95 | }; |
| 99 | 96 | ||
| 100 | void __init mips_cpu_irq_init(void) | 97 | void __init mips_cpu_irq_init(void) |
| @@ -112,10 +109,10 @@ void __init mips_cpu_irq_init(void) | |||
| 112 | */ | 109 | */ |
| 113 | if (cpu_has_mipsmt) | 110 | if (cpu_has_mipsmt) |
| 114 | for (i = irq_base; i < irq_base + 2; i++) | 111 | for (i = irq_base; i < irq_base + 2; i++) |
| 115 | set_irq_chip_and_handler(i, &mips_mt_cpu_irq_controller, | 112 | irq_set_chip_and_handler(i, &mips_mt_cpu_irq_controller, |
| 116 | handle_percpu_irq); | 113 | handle_percpu_irq); |
| 117 | 114 | ||
| 118 | for (i = irq_base + 2; i < irq_base + 8; i++) | 115 | for (i = irq_base + 2; i < irq_base + 8; i++) |
| 119 | set_irq_chip_and_handler(i, &mips_cpu_irq_controller, | 116 | irq_set_chip_and_handler(i, &mips_cpu_irq_controller, |
| 120 | handle_percpu_irq); | 117 | handle_percpu_irq); |
| 121 | } | 118 | } |
diff --git a/arch/mips/kernel/irq_txx9.c b/arch/mips/kernel/irq_txx9.c index 9b78029bea70..b0c55b50218e 100644 --- a/arch/mips/kernel/irq_txx9.c +++ b/arch/mips/kernel/irq_txx9.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
| 17 | #include <linux/interrupt.h> | 17 | #include <linux/interrupt.h> |
| 18 | #include <linux/types.h> | 18 | #include <linux/types.h> |
| 19 | #include <linux/irq.h> | ||
| 19 | #include <asm/txx9irq.h> | 20 | #include <asm/txx9irq.h> |
| 20 | 21 | ||
| 21 | struct txx9_irc_reg { | 22 | struct txx9_irc_reg { |
| @@ -62,9 +63,9 @@ static struct { | |||
| 62 | unsigned char mode; | 63 | unsigned char mode; |
| 63 | } txx9irq[TXx9_MAX_IR] __read_mostly; | 64 | } txx9irq[TXx9_MAX_IR] __read_mostly; |
| 64 | 65 | ||
| 65 | static void txx9_irq_unmask(unsigned int irq) | 66 | static void txx9_irq_unmask(struct irq_data *d) |
| 66 | { | 67 | { |
| 67 | unsigned int irq_nr = irq - TXX9_IRQ_BASE; | 68 | unsigned int irq_nr = d->irq - TXX9_IRQ_BASE; |
| 68 | u32 __iomem *ilrp = &txx9_ircptr->ilr[(irq_nr % 16 ) / 2]; | 69 | u32 __iomem *ilrp = &txx9_ircptr->ilr[(irq_nr % 16 ) / 2]; |
| 69 | int ofs = irq_nr / 16 * 16 + (irq_nr & 1) * 8; | 70 | int ofs = irq_nr / 16 * 16 + (irq_nr & 1) * 8; |
| 70 | 71 | ||
| @@ -78,9 +79,9 @@ static void txx9_irq_unmask(unsigned int irq) | |||
| 78 | #endif | 79 | #endif |
| 79 | } | 80 | } |
| 80 | 81 | ||
| 81 | static inline void txx9_irq_mask(unsigned int irq) | 82 | static inline void txx9_irq_mask(struct irq_data *d) |
| 82 | { | 83 | { |
| 83 | unsigned int irq_nr = irq - TXX9_IRQ_BASE; | 84 | unsigned int irq_nr = d->irq - TXX9_IRQ_BASE; |
| 84 | u32 __iomem *ilrp = &txx9_ircptr->ilr[(irq_nr % 16) / 2]; | 85 | u32 __iomem *ilrp = &txx9_ircptr->ilr[(irq_nr % 16) / 2]; |
| 85 | int ofs = irq_nr / 16 * 16 + (irq_nr & 1) * 8; | 86 | int ofs = irq_nr / 16 * 16 + (irq_nr & 1) * 8; |
| 86 | 87 | ||
| @@ -98,19 +99,19 @@ static inline void txx9_irq_mask(unsigned int irq) | |||
| 98 | #endif | 99 | #endif |
| 99 | } | 100 | } |
| 100 | 101 | ||
| 101 | static void txx9_irq_mask_ack(unsigned int irq) | 102 | static void txx9_irq_mask_ack(struct irq_data *d) |
| 102 | { | 103 | { |
| 103 | unsigned int irq_nr = irq - TXX9_IRQ_BASE; | 104 | unsigned int irq_nr = d->irq - TXX9_IRQ_BASE; |
| 104 | 105 | ||
| 105 | txx9_irq_mask(irq); | 106 | txx9_irq_mask(d); |
| 106 | /* clear edge detection */ | 107 | /* clear edge detection */ |
| 107 | if (unlikely(TXx9_IRCR_EDGE(txx9irq[irq_nr].mode))) | 108 | if (unlikely(TXx9_IRCR_EDGE(txx9irq[irq_nr].mode))) |
| 108 | __raw_writel(TXx9_IRSCR_EIClrE | irq_nr, &txx9_ircptr->scr); | 109 | __raw_writel(TXx9_IRSCR_EIClrE | irq_nr, &txx9_ircptr->scr); |
| 109 | } | 110 | } |
| 110 | 111 | ||
| 111 | static int txx9_irq_set_type(unsigned int irq, unsigned int flow_type) | 112 | static int txx9_irq_set_type(struct irq_data *d, unsigned int flow_type) |
| 112 | { | 113 | { |
| 113 | unsigned int irq_nr = irq - TXX9_IRQ_BASE; | 114 | unsigned int irq_nr = d->irq - TXX9_IRQ_BASE; |
| 114 | u32 cr; | 115 | u32 cr; |
| 115 | u32 __iomem *crp; | 116 | u32 __iomem *crp; |
| 116 | int ofs; | 117 | int ofs; |
| @@ -138,11 +139,11 @@ static int txx9_irq_set_type(unsigned int irq, unsigned int flow_type) | |||
| 138 | 139 | ||
| 139 | static struct irq_chip txx9_irq_chip = { | 140 | static struct irq_chip txx9_irq_chip = { |
| 140 | .name = "TXX9", | 141 | .name = "TXX9", |
| 141 | .ack = txx9_irq_mask_ack, | 142 | .irq_ack = txx9_irq_mask_ack, |
| 142 | .mask = txx9_irq_mask, | 143 | .irq_mask = txx9_irq_mask, |
| 143 | .mask_ack = txx9_irq_mask_ack, | 144 | .irq_mask_ack = txx9_irq_mask_ack, |
| 144 | .unmask = txx9_irq_unmask, | 145 | .irq_unmask = txx9_irq_unmask, |
| 145 | .set_type = txx9_irq_set_type, | 146 | .irq_set_type = txx9_irq_set_type, |
| 146 | }; | 147 | }; |
| 147 | 148 | ||
| 148 | void __init txx9_irq_init(unsigned long baseaddr) | 149 | void __init txx9_irq_init(unsigned long baseaddr) |
| @@ -153,8 +154,8 @@ void __init txx9_irq_init(unsigned long baseaddr) | |||
| 153 | for (i = 0; i < TXx9_MAX_IR; i++) { | 154 | for (i = 0; i < TXx9_MAX_IR; i++) { |
| 154 | txx9irq[i].level = 4; /* middle level */ | 155 | txx9irq[i].level = 4; /* middle level */ |
| 155 | txx9irq[i].mode = TXx9_IRCR_LOW; | 156 | txx9irq[i].mode = TXx9_IRCR_LOW; |
| 156 | set_irq_chip_and_handler(TXX9_IRQ_BASE + i, | 157 | irq_set_chip_and_handler(TXX9_IRQ_BASE + i, &txx9_irq_chip, |
| 157 | &txx9_irq_chip, handle_level_irq); | 158 | handle_level_irq); |
| 158 | } | 159 | } |
| 159 | 160 | ||
| 160 | /* mask all IRC interrupts */ | 161 | /* mask all IRC interrupts */ |
diff --git a/arch/mips/kernel/jump_label.c b/arch/mips/kernel/jump_label.c new file mode 100644 index 000000000000..6001610cfe55 --- /dev/null +++ b/arch/mips/kernel/jump_label.c | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | /* | ||
| 2 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 3 | * License. See the file "COPYING" in the main directory of this archive | ||
| 4 | * for more details. | ||
| 5 | * | ||
| 6 | * Copyright (c) 2010 Cavium Networks, Inc. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/jump_label.h> | ||
| 10 | #include <linux/kernel.h> | ||
| 11 | #include <linux/memory.h> | ||
| 12 | #include <linux/mutex.h> | ||
| 13 | #include <linux/types.h> | ||
| 14 | #include <linux/cpu.h> | ||
| 15 | |||
| 16 | #include <asm/cacheflush.h> | ||
| 17 | #include <asm/inst.h> | ||
| 18 | |||
| 19 | #ifdef HAVE_JUMP_LABEL | ||
| 20 | |||
| 21 | #define J_RANGE_MASK ((1ul << 28) - 1) | ||
| 22 | |||
| 23 | void arch_jump_label_transform(struct jump_entry *e, | ||
| 24 | enum jump_label_type type) | ||
| 25 | { | ||
| 26 | union mips_instruction insn; | ||
| 27 | union mips_instruction *insn_p = | ||
| 28 | (union mips_instruction *)(unsigned long)e->code; | ||
| 29 | |||
| 30 | /* Jump only works within a 256MB aligned region. */ | ||
| 31 | BUG_ON((e->target & ~J_RANGE_MASK) != (e->code & ~J_RANGE_MASK)); | ||
| 32 | |||
| 33 | /* Target must have 4 byte alignment. */ | ||
| 34 | BUG_ON((e->target & 3) != 0); | ||
| 35 | |||
| 36 | if (type == JUMP_LABEL_ENABLE) { | ||
| 37 | insn.j_format.opcode = j_op; | ||
| 38 | insn.j_format.target = (e->target & J_RANGE_MASK) >> 2; | ||
| 39 | } else { | ||
| 40 | insn.word = 0; /* nop */ | ||
| 41 | } | ||
| 42 | |||
| 43 | get_online_cpus(); | ||
| 44 | mutex_lock(&text_mutex); | ||
| 45 | *insn_p = insn; | ||
| 46 | |||
| 47 | flush_icache_range((unsigned long)insn_p, | ||
| 48 | (unsigned long)insn_p + sizeof(*insn_p)); | ||
| 49 | |||
| 50 | mutex_unlock(&text_mutex); | ||
| 51 | put_online_cpus(); | ||
| 52 | } | ||
| 53 | |||
| 54 | #endif /* HAVE_JUMP_LABEL */ | ||
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 6343b4a5b835..876a75cc376f 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c | |||
| @@ -251,14 +251,15 @@ SYSCALL_DEFINE5(n32_msgrcv, int, msqid, u32, msgp, size_t, msgsz, | |||
| 251 | 251 | ||
| 252 | SYSCALL_DEFINE1(32_personality, unsigned long, personality) | 252 | SYSCALL_DEFINE1(32_personality, unsigned long, personality) |
| 253 | { | 253 | { |
| 254 | unsigned int p = personality & 0xffffffff; | ||
| 254 | int ret; | 255 | int ret; |
| 255 | personality &= 0xffffffff; | 256 | |
| 256 | if (personality(current->personality) == PER_LINUX32 && | 257 | if (personality(current->personality) == PER_LINUX32 && |
| 257 | personality == PER_LINUX) | 258 | personality(p) == PER_LINUX) |
| 258 | personality = PER_LINUX32; | 259 | p = (p & ~PER_MASK) | PER_LINUX32; |
| 259 | ret = sys_personality(personality); | 260 | ret = sys_personality(p); |
| 260 | if (ret == PER_LINUX32) | 261 | if (ret != -1 && personality(ret) == PER_LINUX32) |
| 261 | ret = PER_LINUX; | 262 | ret = (ret & ~PER_MASK) | PER_LINUX; |
| 262 | return ret; | 263 | return ret; |
| 263 | } | 264 | } |
| 264 | 265 | ||
diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c index 2340f11dc29c..802e6160f37e 100644 --- a/arch/mips/kernel/mips-mt-fpaff.c +++ b/arch/mips/kernel/mips-mt-fpaff.c | |||
| @@ -103,7 +103,7 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len, | |||
| 103 | if (!check_same_owner(p) && !capable(CAP_SYS_NICE)) | 103 | if (!check_same_owner(p) && !capable(CAP_SYS_NICE)) |
| 104 | goto out_unlock; | 104 | goto out_unlock; |
| 105 | 105 | ||
| 106 | retval = security_task_setscheduler(p, 0, NULL); | 106 | retval = security_task_setscheduler(p); |
| 107 | if (retval) | 107 | if (retval) |
| 108 | goto out_unlock; | 108 | goto out_unlock; |
| 109 | 109 | ||
diff --git a/arch/mips/kernel/mips_machine.c b/arch/mips/kernel/mips_machine.c new file mode 100644 index 000000000000..411a058d2c53 --- /dev/null +++ b/arch/mips/kernel/mips_machine.c | |||
| @@ -0,0 +1,86 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms of the GNU General Public License version 2 as published | ||
| 6 | * by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | */ | ||
| 9 | #include <linux/mm.h> | ||
| 10 | #include <linux/string.h> | ||
| 11 | #include <linux/slab.h> | ||
| 12 | |||
| 13 | #include <asm/mips_machine.h> | ||
| 14 | |||
| 15 | static struct mips_machine *mips_machine __initdata; | ||
| 16 | static char *mips_machine_name = "Unknown"; | ||
| 17 | |||
| 18 | #define for_each_machine(mach) \ | ||
| 19 | for ((mach) = (struct mips_machine *)&__mips_machines_start; \ | ||
| 20 | (mach) && \ | ||
| 21 | (unsigned long)(mach) < (unsigned long)&__mips_machines_end; \ | ||
| 22 | (mach)++) | ||
| 23 | |||
| 24 | __init void mips_set_machine_name(const char *name) | ||
| 25 | { | ||
| 26 | char *p; | ||
| 27 | |||
| 28 | if (name == NULL) | ||
| 29 | return; | ||
| 30 | |||
| 31 | p = kstrdup(name, GFP_KERNEL); | ||
| 32 | if (!p) | ||
| 33 | pr_err("MIPS: no memory for machine_name\n"); | ||
| 34 | |||
| 35 | mips_machine_name = p; | ||
| 36 | } | ||
| 37 | |||
| 38 | char *mips_get_machine_name(void) | ||
| 39 | { | ||
| 40 | return mips_machine_name; | ||
| 41 | } | ||
| 42 | |||
| 43 | __init int mips_machtype_setup(char *id) | ||
| 44 | { | ||
| 45 | struct mips_machine *mach; | ||
| 46 | |||
| 47 | for_each_machine(mach) { | ||
| 48 | if (mach->mach_id == NULL) | ||
| 49 | continue; | ||
| 50 | |||
| 51 | if (strcmp(mach->mach_id, id) == 0) { | ||
| 52 | mips_machtype = mach->mach_type; | ||
| 53 | return 0; | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | pr_err("MIPS: no machine found for id '%s', supported machines:\n", id); | ||
| 58 | pr_err("%-24s %s\n", "id", "name"); | ||
| 59 | for_each_machine(mach) | ||
| 60 | pr_err("%-24s %s\n", mach->mach_id, mach->mach_name); | ||
| 61 | |||
| 62 | return 1; | ||
| 63 | } | ||
| 64 | |||
| 65 | __setup("machtype=", mips_machtype_setup); | ||
| 66 | |||
| 67 | __init void mips_machine_setup(void) | ||
| 68 | { | ||
| 69 | struct mips_machine *mach; | ||
| 70 | |||
| 71 | for_each_machine(mach) { | ||
| 72 | if (mips_machtype == mach->mach_type) { | ||
| 73 | mips_machine = mach; | ||
| 74 | break; | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | if (!mips_machine) | ||
| 79 | return; | ||
| 80 | |||
| 81 | mips_set_machine_name(mips_machine->mach_name); | ||
| 82 | pr_info("MIPS: machine is %s\n", mips_machine_name); | ||
| 83 | |||
| 84 | if (mips_machine->mach_setup) | ||
| 85 | mips_machine->mach_setup(); | ||
| 86 | } | ||
diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c index 6f51dda87fce..dd940b701963 100644 --- a/arch/mips/kernel/module.c +++ b/arch/mips/kernel/module.c | |||
| @@ -30,6 +30,8 @@ | |||
| 30 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
| 31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
| 32 | #include <linux/spinlock.h> | 32 | #include <linux/spinlock.h> |
| 33 | #include <linux/jump_label.h> | ||
| 34 | |||
| 33 | #include <asm/pgtable.h> /* MODULE_START */ | 35 | #include <asm/pgtable.h> /* MODULE_START */ |
| 34 | 36 | ||
| 35 | struct mips_hi16 { | 37 | struct mips_hi16 { |
| @@ -46,17 +48,9 @@ static DEFINE_SPINLOCK(dbe_lock); | |||
| 46 | void *module_alloc(unsigned long size) | 48 | void *module_alloc(unsigned long size) |
| 47 | { | 49 | { |
| 48 | #ifdef MODULE_START | 50 | #ifdef MODULE_START |
| 49 | struct vm_struct *area; | 51 | return __vmalloc_node_range(size, 1, MODULE_START, MODULE_END, |
| 50 | 52 | GFP_KERNEL, PAGE_KERNEL, -1, | |
| 51 | size = PAGE_ALIGN(size); | 53 | __builtin_return_address(0)); |
| 52 | if (!size) | ||
| 53 | return NULL; | ||
| 54 | |||
| 55 | area = __get_vm_area(size, VM_ALLOC, MODULE_START, MODULE_END); | ||
| 56 | if (!area) | ||
| 57 | return NULL; | ||
| 58 | |||
| 59 | return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL); | ||
| 60 | #else | 54 | #else |
| 61 | if (size == 0) | 55 | if (size == 0) |
| 62 | return NULL; | 56 | return NULL; |
| @@ -390,6 +384,9 @@ int module_finalize(const Elf_Ehdr *hdr, | |||
| 390 | const Elf_Shdr *s; | 384 | const Elf_Shdr *s; |
| 391 | char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; | 385 | char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; |
| 392 | 386 | ||
| 387 | /* Make jump label nops. */ | ||
| 388 | jump_label_apply_nops(me); | ||
| 389 | |||
| 393 | INIT_LIST_HEAD(&me->arch.dbe_list); | 390 | INIT_LIST_HEAD(&me->arch.dbe_list); |
| 394 | for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { | 391 | for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) { |
| 395 | if (strcmp("__dbe_table", secstrings + s->sh_name) != 0) | 392 | if (strcmp("__dbe_table", secstrings + s->sh_name) != 0) |
diff --git a/arch/mips/kernel/octeon_switch.S b/arch/mips/kernel/octeon_switch.S index dd18b26a358a..ce89c8061708 100644 --- a/arch/mips/kernel/octeon_switch.S +++ b/arch/mips/kernel/octeon_switch.S | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | * for more details. | 4 | * for more details. |
| 5 | * | 5 | * |
| 6 | * Copyright (C) 1994, 1995, 1996, 1998, 1999, 2002, 2003 Ralf Baechle | 6 | * Copyright (C) 1994, 1995, 1996, 1998, 1999, 2002, 2003 Ralf Baechle |
| 7 | * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) | 7 | * Copyright (C) 1996 David S. Miller (davem@davemloft.net) |
| 8 | * Copyright (C) 1994, 1995, 1996, by Andreas Busse | 8 | * Copyright (C) 1994, 1995, 1996, by Andreas Busse |
| 9 | * Copyright (C) 1999 Silicon Graphics, Inc. | 9 | * Copyright (C) 1999 Silicon Graphics, Inc. |
| 10 | * Copyright (C) 2000 MIPS Technologies, Inc. | 10 | * Copyright (C) 2000 MIPS Technologies, Inc. |
diff --git a/arch/mips/kernel/perf_event.c b/arch/mips/kernel/perf_event.c new file mode 100644 index 000000000000..a8244854d3dc --- /dev/null +++ b/arch/mips/kernel/perf_event.c | |||
| @@ -0,0 +1,588 @@ | |||
| 1 | /* | ||
| 2 | * Linux performance counter support for MIPS. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010 MIPS Technologies, Inc. | ||
| 5 | * Author: Deng-Cheng Zhu | ||
| 6 | * | ||
| 7 | * This code is based on the implementation for ARM, which is in turn | ||
| 8 | * based on the sparc64 perf event code and the x86 code. Performance | ||
| 9 | * counter access is based on the MIPS Oprofile code. And the callchain | ||
| 10 | * support references the code of MIPS stacktrace.c. | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or modify | ||
| 13 | * it under the terms of the GNU General Public License version 2 as | ||
| 14 | * published by the Free Software Foundation. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/cpumask.h> | ||
| 18 | #include <linux/interrupt.h> | ||
| 19 | #include <linux/smp.h> | ||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include <linux/perf_event.h> | ||
| 22 | #include <linux/uaccess.h> | ||
| 23 | |||
| 24 | #include <asm/irq.h> | ||
| 25 | #include <asm/irq_regs.h> | ||
| 26 | #include <asm/stacktrace.h> | ||
| 27 | #include <asm/time.h> /* For perf_irq */ | ||
| 28 | |||
| 29 | /* These are for 32bit counters. For 64bit ones, define them accordingly. */ | ||
| 30 | #define MAX_PERIOD ((1ULL << 32) - 1) | ||
| 31 | #define VALID_COUNT 0x7fffffff | ||
| 32 | #define TOTAL_BITS 32 | ||
| 33 | #define HIGHEST_BIT 31 | ||
| 34 | |||
| 35 | #define MIPS_MAX_HWEVENTS 4 | ||
| 36 | |||
| 37 | struct cpu_hw_events { | ||
| 38 | /* Array of events on this cpu. */ | ||
| 39 | struct perf_event *events[MIPS_MAX_HWEVENTS]; | ||
| 40 | |||
| 41 | /* | ||
| 42 | * Set the bit (indexed by the counter number) when the counter | ||
| 43 | * is used for an event. | ||
| 44 | */ | ||
| 45 | unsigned long used_mask[BITS_TO_LONGS(MIPS_MAX_HWEVENTS)]; | ||
| 46 | |||
| 47 | /* | ||
| 48 | * The borrowed MSB for the performance counter. A MIPS performance | ||
| 49 | * counter uses its bit 31 (for 32bit counters) or bit 63 (for 64bit | ||
| 50 | * counters) as a factor of determining whether a counter overflow | ||
| 51 | * should be signaled. So here we use a separate MSB for each | ||
| 52 | * counter to make things easy. | ||
| 53 | */ | ||
| 54 | unsigned long msbs[BITS_TO_LONGS(MIPS_MAX_HWEVENTS)]; | ||
| 55 | |||
| 56 | /* | ||
| 57 | * Software copy of the control register for each performance counter. | ||
| 58 | * MIPS CPUs vary in performance counters. They use this differently, | ||
| 59 | * and even may not use it. | ||
| 60 | */ | ||
| 61 | unsigned int saved_ctrl[MIPS_MAX_HWEVENTS]; | ||
| 62 | }; | ||
| 63 | DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events) = { | ||
| 64 | .saved_ctrl = {0}, | ||
| 65 | }; | ||
| 66 | |||
| 67 | /* The description of MIPS performance events. */ | ||
| 68 | struct mips_perf_event { | ||
| 69 | unsigned int event_id; | ||
| 70 | /* | ||
| 71 | * MIPS performance counters are indexed starting from 0. | ||
| 72 | * CNTR_EVEN indicates the indexes of the counters to be used are | ||
| 73 | * even numbers. | ||
| 74 | */ | ||
| 75 | unsigned int cntr_mask; | ||
| 76 | #define CNTR_EVEN 0x55555555 | ||
| 77 | #define CNTR_ODD 0xaaaaaaaa | ||
| 78 | #ifdef CONFIG_MIPS_MT_SMP | ||
| 79 | enum { | ||
| 80 | T = 0, | ||
| 81 | V = 1, | ||
| 82 | P = 2, | ||
| 83 | } range; | ||
| 84 | #else | ||
| 85 | #define T | ||
| 86 | #define V | ||
| 87 | #define P | ||
| 88 | #endif | ||
| 89 | }; | ||
| 90 | |||
| 91 | static struct mips_perf_event raw_event; | ||
| 92 | static DEFINE_MUTEX(raw_event_mutex); | ||
| 93 | |||
| 94 | #define UNSUPPORTED_PERF_EVENT_ID 0xffffffff | ||
| 95 | #define C(x) PERF_COUNT_HW_CACHE_##x | ||
| 96 | |||
| 97 | struct mips_pmu { | ||
| 98 | const char *name; | ||
| 99 | int irq; | ||
| 100 | irqreturn_t (*handle_irq)(int irq, void *dev); | ||
| 101 | int (*handle_shared_irq)(void); | ||
| 102 | void (*start)(void); | ||
| 103 | void (*stop)(void); | ||
| 104 | int (*alloc_counter)(struct cpu_hw_events *cpuc, | ||
| 105 | struct hw_perf_event *hwc); | ||
| 106 | u64 (*read_counter)(unsigned int idx); | ||
| 107 | void (*write_counter)(unsigned int idx, u64 val); | ||
| 108 | void (*enable_event)(struct hw_perf_event *evt, int idx); | ||
| 109 | void (*disable_event)(int idx); | ||
| 110 | const struct mips_perf_event *(*map_raw_event)(u64 config); | ||
| 111 | const struct mips_perf_event (*general_event_map)[PERF_COUNT_HW_MAX]; | ||
| 112 | const struct mips_perf_event (*cache_event_map) | ||
| 113 | [PERF_COUNT_HW_CACHE_MAX] | ||
| 114 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
| 115 | [PERF_COUNT_HW_CACHE_RESULT_MAX]; | ||
| 116 | unsigned int num_counters; | ||
| 117 | }; | ||
| 118 | |||
| 119 | static const struct mips_pmu *mipspmu; | ||
| 120 | |||
| 121 | static int | ||
| 122 | mipspmu_event_set_period(struct perf_event *event, | ||
| 123 | struct hw_perf_event *hwc, | ||
| 124 | int idx) | ||
| 125 | { | ||
| 126 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | ||
| 127 | s64 left = local64_read(&hwc->period_left); | ||
| 128 | s64 period = hwc->sample_period; | ||
| 129 | int ret = 0; | ||
| 130 | u64 uleft; | ||
| 131 | unsigned long flags; | ||
| 132 | |||
| 133 | if (unlikely(left <= -period)) { | ||
| 134 | left = period; | ||
| 135 | local64_set(&hwc->period_left, left); | ||
| 136 | hwc->last_period = period; | ||
| 137 | ret = 1; | ||
| 138 | } | ||
| 139 | |||
| 140 | if (unlikely(left <= 0)) { | ||
| 141 | left += period; | ||
| 142 | local64_set(&hwc->period_left, left); | ||
| 143 | hwc->last_period = period; | ||
| 144 | ret = 1; | ||
| 145 | } | ||
| 146 | |||
| 147 | if (left > (s64)MAX_PERIOD) | ||
| 148 | left = MAX_PERIOD; | ||
| 149 | |||
| 150 | local64_set(&hwc->prev_count, (u64)-left); | ||
| 151 | |||
| 152 | local_irq_save(flags); | ||
| 153 | uleft = (u64)(-left) & MAX_PERIOD; | ||
| 154 | uleft > VALID_COUNT ? | ||
| 155 | set_bit(idx, cpuc->msbs) : clear_bit(idx, cpuc->msbs); | ||
| 156 | mipspmu->write_counter(idx, (u64)(-left) & VALID_COUNT); | ||
| 157 | local_irq_restore(flags); | ||
| 158 | |||
| 159 | perf_event_update_userpage(event); | ||
| 160 | |||
| 161 | return ret; | ||
| 162 | } | ||
| 163 | |||
| 164 | static void mipspmu_event_update(struct perf_event *event, | ||
| 165 | struct hw_perf_event *hwc, | ||
| 166 | int idx) | ||
| 167 | { | ||
| 168 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | ||
| 169 | unsigned long flags; | ||
| 170 | int shift = 64 - TOTAL_BITS; | ||
| 171 | s64 prev_raw_count, new_raw_count; | ||
| 172 | u64 delta; | ||
| 173 | |||
| 174 | again: | ||
| 175 | prev_raw_count = local64_read(&hwc->prev_count); | ||
| 176 | local_irq_save(flags); | ||
| 177 | /* Make the counter value be a "real" one. */ | ||
| 178 | new_raw_count = mipspmu->read_counter(idx); | ||
| 179 | if (new_raw_count & (test_bit(idx, cpuc->msbs) << HIGHEST_BIT)) { | ||
| 180 | new_raw_count &= VALID_COUNT; | ||
| 181 | clear_bit(idx, cpuc->msbs); | ||
| 182 | } else | ||
| 183 | new_raw_count |= (test_bit(idx, cpuc->msbs) << HIGHEST_BIT); | ||
| 184 | local_irq_restore(flags); | ||
| 185 | |||
| 186 | if (local64_cmpxchg(&hwc->prev_count, prev_raw_count, | ||
| 187 | new_raw_count) != prev_raw_count) | ||
| 188 | goto again; | ||
| 189 | |||
| 190 | delta = (new_raw_count << shift) - (prev_raw_count << shift); | ||
| 191 | delta >>= shift; | ||
| 192 | |||
| 193 | local64_add(delta, &event->count); | ||
| 194 | local64_sub(delta, &hwc->period_left); | ||
| 195 | |||
| 196 | return; | ||
| 197 | } | ||
| 198 | |||
| 199 | static void mipspmu_start(struct perf_event *event, int flags) | ||
| 200 | { | ||
| 201 | struct hw_perf_event *hwc = &event->hw; | ||
| 202 | |||
| 203 | if (!mipspmu) | ||
| 204 | return; | ||
| 205 | |||
| 206 | if (flags & PERF_EF_RELOAD) | ||
| 207 | WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE)); | ||
| 208 | |||
| 209 | hwc->state = 0; | ||
| 210 | |||
| 211 | /* Set the period for the event. */ | ||
| 212 | mipspmu_event_set_period(event, hwc, hwc->idx); | ||
| 213 | |||
| 214 | /* Enable the event. */ | ||
| 215 | mipspmu->enable_event(hwc, hwc->idx); | ||
| 216 | } | ||
| 217 | |||
| 218 | static void mipspmu_stop(struct perf_event *event, int flags) | ||
| 219 | { | ||
| 220 | struct hw_perf_event *hwc = &event->hw; | ||
| 221 | |||
| 222 | if (!mipspmu) | ||
| 223 | return; | ||
| 224 | |||
| 225 | if (!(hwc->state & PERF_HES_STOPPED)) { | ||
| 226 | /* We are working on a local event. */ | ||
| 227 | mipspmu->disable_event(hwc->idx); | ||
| 228 | barrier(); | ||
| 229 | mipspmu_event_update(event, hwc, hwc->idx); | ||
| 230 | hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE; | ||
| 231 | } | ||
| 232 | } | ||
| 233 | |||
| 234 | static int mipspmu_add(struct perf_event *event, int flags) | ||
| 235 | { | ||
| 236 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | ||
| 237 | struct hw_perf_event *hwc = &event->hw; | ||
| 238 | int idx; | ||
| 239 | int err = 0; | ||
| 240 | |||
| 241 | perf_pmu_disable(event->pmu); | ||
| 242 | |||
| 243 | /* To look for a free counter for this event. */ | ||
| 244 | idx = mipspmu->alloc_counter(cpuc, hwc); | ||
| 245 | if (idx < 0) { | ||
| 246 | err = idx; | ||
| 247 | goto out; | ||
| 248 | } | ||
| 249 | |||
| 250 | /* | ||
| 251 | * If there is an event in the counter we are going to use then | ||
| 252 | * make sure it is disabled. | ||
| 253 | */ | ||
| 254 | event->hw.idx = idx; | ||
| 255 | mipspmu->disable_event(idx); | ||
| 256 | cpuc->events[idx] = event; | ||
| 257 | |||
| 258 | hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE; | ||
| 259 | if (flags & PERF_EF_START) | ||
| 260 | mipspmu_start(event, PERF_EF_RELOAD); | ||
| 261 | |||
| 262 | /* Propagate our changes to the userspace mapping. */ | ||
| 263 | perf_event_update_userpage(event); | ||
| 264 | |||
| 265 | out: | ||
| 266 | perf_pmu_enable(event->pmu); | ||
| 267 | return err; | ||
| 268 | } | ||
| 269 | |||
| 270 | static void mipspmu_del(struct perf_event *event, int flags) | ||
| 271 | { | ||
| 272 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | ||
| 273 | struct hw_perf_event *hwc = &event->hw; | ||
| 274 | int idx = hwc->idx; | ||
| 275 | |||
| 276 | WARN_ON(idx < 0 || idx >= mipspmu->num_counters); | ||
| 277 | |||
| 278 | mipspmu_stop(event, PERF_EF_UPDATE); | ||
| 279 | cpuc->events[idx] = NULL; | ||
| 280 | clear_bit(idx, cpuc->used_mask); | ||
| 281 | |||
| 282 | perf_event_update_userpage(event); | ||
| 283 | } | ||
| 284 | |||
| 285 | static void mipspmu_read(struct perf_event *event) | ||
| 286 | { | ||
| 287 | struct hw_perf_event *hwc = &event->hw; | ||
| 288 | |||
| 289 | /* Don't read disabled counters! */ | ||
| 290 | if (hwc->idx < 0) | ||
| 291 | return; | ||
| 292 | |||
| 293 | mipspmu_event_update(event, hwc, hwc->idx); | ||
| 294 | } | ||
| 295 | |||
| 296 | static void mipspmu_enable(struct pmu *pmu) | ||
| 297 | { | ||
| 298 | if (mipspmu) | ||
| 299 | mipspmu->start(); | ||
| 300 | } | ||
| 301 | |||
| 302 | static void mipspmu_disable(struct pmu *pmu) | ||
| 303 | { | ||
| 304 | if (mipspmu) | ||
| 305 | mipspmu->stop(); | ||
| 306 | } | ||
| 307 | |||
| 308 | static atomic_t active_events = ATOMIC_INIT(0); | ||
| 309 | static DEFINE_MUTEX(pmu_reserve_mutex); | ||
| 310 | static int (*save_perf_irq)(void); | ||
| 311 | |||
| 312 | static int mipspmu_get_irq(void) | ||
| 313 | { | ||
| 314 | int err; | ||
| 315 | |||
| 316 | if (mipspmu->irq >= 0) { | ||
| 317 | /* Request my own irq handler. */ | ||
| 318 | err = request_irq(mipspmu->irq, mipspmu->handle_irq, | ||
| 319 | IRQF_DISABLED | IRQF_NOBALANCING, | ||
| 320 | "mips_perf_pmu", NULL); | ||
| 321 | if (err) { | ||
| 322 | pr_warning("Unable to request IRQ%d for MIPS " | ||
| 323 | "performance counters!\n", mipspmu->irq); | ||
| 324 | } | ||
| 325 | } else if (cp0_perfcount_irq < 0) { | ||
| 326 | /* | ||
| 327 | * We are sharing the irq number with the timer interrupt. | ||
| 328 | */ | ||
| 329 | save_perf_irq = perf_irq; | ||
| 330 | perf_irq = mipspmu->handle_shared_irq; | ||
| 331 | err = 0; | ||
| 332 | } else { | ||
| 333 | pr_warning("The platform hasn't properly defined its " | ||
| 334 | "interrupt controller.\n"); | ||
| 335 | err = -ENOENT; | ||
| 336 | } | ||
| 337 | |||
| 338 | return err; | ||
| 339 | } | ||
| 340 | |||
| 341 | static void mipspmu_free_irq(void) | ||
| 342 | { | ||
| 343 | if (mipspmu->irq >= 0) | ||
| 344 | free_irq(mipspmu->irq, NULL); | ||
| 345 | else if (cp0_perfcount_irq < 0) | ||
| 346 | perf_irq = save_perf_irq; | ||
| 347 | } | ||
| 348 | |||
| 349 | /* | ||
| 350 | * mipsxx/rm9000/loongson2 have different performance counters, they have | ||
| 351 | * specific low-level init routines. | ||
| 352 | */ | ||
| 353 | static void reset_counters(void *arg); | ||
| 354 | static int __hw_perf_event_init(struct perf_event *event); | ||
| 355 | |||
| 356 | static void hw_perf_event_destroy(struct perf_event *event) | ||
| 357 | { | ||
| 358 | if (atomic_dec_and_mutex_lock(&active_events, | ||
| 359 | &pmu_reserve_mutex)) { | ||
| 360 | /* | ||
| 361 | * We must not call the destroy function with interrupts | ||
| 362 | * disabled. | ||
| 363 | */ | ||
| 364 | on_each_cpu(reset_counters, | ||
| 365 | (void *)(long)mipspmu->num_counters, 1); | ||
| 366 | mipspmu_free_irq(); | ||
| 367 | mutex_unlock(&pmu_reserve_mutex); | ||
| 368 | } | ||
| 369 | } | ||
| 370 | |||
| 371 | static int mipspmu_event_init(struct perf_event *event) | ||
| 372 | { | ||
| 373 | int err = 0; | ||
| 374 | |||
| 375 | switch (event->attr.type) { | ||
| 376 | case PERF_TYPE_RAW: | ||
| 377 | case PERF_TYPE_HARDWARE: | ||
| 378 | case PERF_TYPE_HW_CACHE: | ||
| 379 | break; | ||
| 380 | |||
| 381 | default: | ||
| 382 | return -ENOENT; | ||
| 383 | } | ||
| 384 | |||
| 385 | if (!mipspmu || event->cpu >= nr_cpumask_bits || | ||
| 386 | (event->cpu >= 0 && !cpu_online(event->cpu))) | ||
| 387 | return -ENODEV; | ||
| 388 | |||
| 389 | if (!atomic_inc_not_zero(&active_events)) { | ||
| 390 | if (atomic_read(&active_events) > MIPS_MAX_HWEVENTS) { | ||
| 391 | atomic_dec(&active_events); | ||
| 392 | return -ENOSPC; | ||
| 393 | } | ||
| 394 | |||
| 395 | mutex_lock(&pmu_reserve_mutex); | ||
| 396 | if (atomic_read(&active_events) == 0) | ||
| 397 | err = mipspmu_get_irq(); | ||
| 398 | |||
| 399 | if (!err) | ||
| 400 | atomic_inc(&active_events); | ||
| 401 | mutex_unlock(&pmu_reserve_mutex); | ||
| 402 | } | ||
| 403 | |||
| 404 | if (err) | ||
| 405 | return err; | ||
| 406 | |||
| 407 | err = __hw_perf_event_init(event); | ||
| 408 | if (err) | ||
| 409 | hw_perf_event_destroy(event); | ||
| 410 | |||
| 411 | return err; | ||
| 412 | } | ||
| 413 | |||
| 414 | static struct pmu pmu = { | ||
| 415 | .pmu_enable = mipspmu_enable, | ||
| 416 | .pmu_disable = mipspmu_disable, | ||
| 417 | .event_init = mipspmu_event_init, | ||
| 418 | .add = mipspmu_add, | ||
| 419 | .del = mipspmu_del, | ||
| 420 | .start = mipspmu_start, | ||
| 421 | .stop = mipspmu_stop, | ||
| 422 | .read = mipspmu_read, | ||
| 423 | }; | ||
| 424 | |||
| 425 | static inline unsigned int | ||
| 426 | mipspmu_perf_event_encode(const struct mips_perf_event *pev) | ||
| 427 | { | ||
| 428 | /* | ||
| 429 | * Top 8 bits for range, next 16 bits for cntr_mask, lowest 8 bits for | ||
| 430 | * event_id. | ||
| 431 | */ | ||
| 432 | #ifdef CONFIG_MIPS_MT_SMP | ||
| 433 | return ((unsigned int)pev->range << 24) | | ||
| 434 | (pev->cntr_mask & 0xffff00) | | ||
| 435 | (pev->event_id & 0xff); | ||
| 436 | #else | ||
| 437 | return (pev->cntr_mask & 0xffff00) | | ||
| 438 | (pev->event_id & 0xff); | ||
| 439 | #endif | ||
| 440 | } | ||
| 441 | |||
| 442 | static const struct mips_perf_event * | ||
| 443 | mipspmu_map_general_event(int idx) | ||
| 444 | { | ||
| 445 | const struct mips_perf_event *pev; | ||
| 446 | |||
| 447 | pev = ((*mipspmu->general_event_map)[idx].event_id == | ||
| 448 | UNSUPPORTED_PERF_EVENT_ID ? ERR_PTR(-EOPNOTSUPP) : | ||
| 449 | &(*mipspmu->general_event_map)[idx]); | ||
| 450 | |||
| 451 | return pev; | ||
| 452 | } | ||
| 453 | |||
| 454 | static const struct mips_perf_event * | ||
| 455 | mipspmu_map_cache_event(u64 config) | ||
| 456 | { | ||
| 457 | unsigned int cache_type, cache_op, cache_result; | ||
| 458 | const struct mips_perf_event *pev; | ||
| 459 | |||
| 460 | cache_type = (config >> 0) & 0xff; | ||
| 461 | if (cache_type >= PERF_COUNT_HW_CACHE_MAX) | ||
| 462 | return ERR_PTR(-EINVAL); | ||
| 463 | |||
| 464 | cache_op = (config >> 8) & 0xff; | ||
| 465 | if (cache_op >= PERF_COUNT_HW_CACHE_OP_MAX) | ||
| 466 | return ERR_PTR(-EINVAL); | ||
| 467 | |||
| 468 | cache_result = (config >> 16) & 0xff; | ||
| 469 | if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX) | ||
| 470 | return ERR_PTR(-EINVAL); | ||
| 471 | |||
| 472 | pev = &((*mipspmu->cache_event_map) | ||
| 473 | [cache_type] | ||
| 474 | [cache_op] | ||
| 475 | [cache_result]); | ||
| 476 | |||
| 477 | if (pev->event_id == UNSUPPORTED_PERF_EVENT_ID) | ||
| 478 | return ERR_PTR(-EOPNOTSUPP); | ||
| 479 | |||
| 480 | return pev; | ||
| 481 | |||
| 482 | } | ||
| 483 | |||
| 484 | static int validate_event(struct cpu_hw_events *cpuc, | ||
| 485 | struct perf_event *event) | ||
| 486 | { | ||
| 487 | struct hw_perf_event fake_hwc = event->hw; | ||
| 488 | |||
| 489 | /* Allow mixed event group. So return 1 to pass validation. */ | ||
| 490 | if (event->pmu != &pmu || event->state <= PERF_EVENT_STATE_OFF) | ||
| 491 | return 1; | ||
| 492 | |||
| 493 | return mipspmu->alloc_counter(cpuc, &fake_hwc) >= 0; | ||
| 494 | } | ||
| 495 | |||
| 496 | static int validate_group(struct perf_event *event) | ||
| 497 | { | ||
| 498 | struct perf_event *sibling, *leader = event->group_leader; | ||
| 499 | struct cpu_hw_events fake_cpuc; | ||
| 500 | |||
| 501 | memset(&fake_cpuc, 0, sizeof(fake_cpuc)); | ||
| 502 | |||
| 503 | if (!validate_event(&fake_cpuc, leader)) | ||
| 504 | return -ENOSPC; | ||
| 505 | |||
| 506 | list_for_each_entry(sibling, &leader->sibling_list, group_entry) { | ||
| 507 | if (!validate_event(&fake_cpuc, sibling)) | ||
| 508 | return -ENOSPC; | ||
| 509 | } | ||
| 510 | |||
| 511 | if (!validate_event(&fake_cpuc, event)) | ||
| 512 | return -ENOSPC; | ||
| 513 | |||
| 514 | return 0; | ||
| 515 | } | ||
| 516 | |||
| 517 | /* This is needed by specific irq handlers in perf_event_*.c */ | ||
| 518 | static void | ||
| 519 | handle_associated_event(struct cpu_hw_events *cpuc, | ||
| 520 | int idx, struct perf_sample_data *data, struct pt_regs *regs) | ||
| 521 | { | ||
| 522 | struct perf_event *event = cpuc->events[idx]; | ||
| 523 | struct hw_perf_event *hwc = &event->hw; | ||
| 524 | |||
| 525 | mipspmu_event_update(event, hwc, idx); | ||
| 526 | data->period = event->hw.last_period; | ||
| 527 | if (!mipspmu_event_set_period(event, hwc, idx)) | ||
| 528 | return; | ||
| 529 | |||
| 530 | if (perf_event_overflow(event, 0, data, regs)) | ||
| 531 | mipspmu->disable_event(idx); | ||
| 532 | } | ||
| 533 | |||
| 534 | #include "perf_event_mipsxx.c" | ||
| 535 | |||
| 536 | /* Callchain handling code. */ | ||
| 537 | |||
| 538 | /* | ||
| 539 | * Leave userspace callchain empty for now. When we find a way to trace | ||
| 540 | * the user stack callchains, we add here. | ||
| 541 | */ | ||
| 542 | void perf_callchain_user(struct perf_callchain_entry *entry, | ||
| 543 | struct pt_regs *regs) | ||
| 544 | { | ||
| 545 | } | ||
| 546 | |||
| 547 | static void save_raw_perf_callchain(struct perf_callchain_entry *entry, | ||
| 548 | unsigned long reg29) | ||
| 549 | { | ||
| 550 | unsigned long *sp = (unsigned long *)reg29; | ||
| 551 | unsigned long addr; | ||
| 552 | |||
| 553 | while (!kstack_end(sp)) { | ||
| 554 | addr = *sp++; | ||
| 555 | if (__kernel_text_address(addr)) { | ||
| 556 | perf_callchain_store(entry, addr); | ||
| 557 | if (entry->nr >= PERF_MAX_STACK_DEPTH) | ||
| 558 | break; | ||
| 559 | } | ||
| 560 | } | ||
| 561 | } | ||
| 562 | |||
| 563 | void perf_callchain_kernel(struct perf_callchain_entry *entry, | ||
| 564 | struct pt_regs *regs) | ||
| 565 | { | ||
| 566 | unsigned long sp = regs->regs[29]; | ||
| 567 | #ifdef CONFIG_KALLSYMS | ||
| 568 | unsigned long ra = regs->regs[31]; | ||
| 569 | unsigned long pc = regs->cp0_epc; | ||
| 570 | |||
| 571 | if (raw_show_trace || !__kernel_text_address(pc)) { | ||
| 572 | unsigned long stack_page = | ||
| 573 | (unsigned long)task_stack_page(current); | ||
| 574 | if (stack_page && sp >= stack_page && | ||
| 575 | sp <= stack_page + THREAD_SIZE - 32) | ||
| 576 | save_raw_perf_callchain(entry, sp); | ||
| 577 | return; | ||
| 578 | } | ||
| 579 | do { | ||
| 580 | perf_callchain_store(entry, pc); | ||
| 581 | if (entry->nr >= PERF_MAX_STACK_DEPTH) | ||
| 582 | break; | ||
| 583 | pc = unwind_stack(current, &sp, pc, &ra); | ||
| 584 | } while (pc); | ||
| 585 | #else | ||
| 586 | save_raw_perf_callchain(entry, sp); | ||
| 587 | #endif | ||
| 588 | } | ||
diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c new file mode 100644 index 000000000000..75266ff4cc33 --- /dev/null +++ b/arch/mips/kernel/perf_event_mipsxx.c | |||
| @@ -0,0 +1,1054 @@ | |||
| 1 | #if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64) || \ | ||
| 2 | defined(CONFIG_CPU_R10000) || defined(CONFIG_CPU_SB1) | ||
| 3 | |||
| 4 | #define M_CONFIG1_PC (1 << 4) | ||
| 5 | |||
| 6 | #define M_PERFCTL_EXL (1UL << 0) | ||
| 7 | #define M_PERFCTL_KERNEL (1UL << 1) | ||
| 8 | #define M_PERFCTL_SUPERVISOR (1UL << 2) | ||
| 9 | #define M_PERFCTL_USER (1UL << 3) | ||
| 10 | #define M_PERFCTL_INTERRUPT_ENABLE (1UL << 4) | ||
| 11 | #define M_PERFCTL_EVENT(event) (((event) & 0x3ff) << 5) | ||
| 12 | #define M_PERFCTL_VPEID(vpe) ((vpe) << 16) | ||
| 13 | #define M_PERFCTL_MT_EN(filter) ((filter) << 20) | ||
| 14 | #define M_TC_EN_ALL M_PERFCTL_MT_EN(0) | ||
| 15 | #define M_TC_EN_VPE M_PERFCTL_MT_EN(1) | ||
| 16 | #define M_TC_EN_TC M_PERFCTL_MT_EN(2) | ||
| 17 | #define M_PERFCTL_TCID(tcid) ((tcid) << 22) | ||
| 18 | #define M_PERFCTL_WIDE (1UL << 30) | ||
| 19 | #define M_PERFCTL_MORE (1UL << 31) | ||
| 20 | |||
| 21 | #define M_PERFCTL_COUNT_EVENT_WHENEVER (M_PERFCTL_EXL | \ | ||
| 22 | M_PERFCTL_KERNEL | \ | ||
| 23 | M_PERFCTL_USER | \ | ||
| 24 | M_PERFCTL_SUPERVISOR | \ | ||
| 25 | M_PERFCTL_INTERRUPT_ENABLE) | ||
| 26 | |||
| 27 | #ifdef CONFIG_MIPS_MT_SMP | ||
| 28 | #define M_PERFCTL_CONFIG_MASK 0x3fff801f | ||
| 29 | #else | ||
| 30 | #define M_PERFCTL_CONFIG_MASK 0x1f | ||
| 31 | #endif | ||
| 32 | #define M_PERFCTL_EVENT_MASK 0xfe0 | ||
| 33 | |||
| 34 | #define M_COUNTER_OVERFLOW (1UL << 31) | ||
| 35 | |||
| 36 | #ifdef CONFIG_MIPS_MT_SMP | ||
| 37 | static int cpu_has_mipsmt_pertccounters; | ||
| 38 | |||
| 39 | /* | ||
| 40 | * FIXME: For VSMP, vpe_id() is redefined for Perf-events, because | ||
| 41 | * cpu_data[cpuid].vpe_id reports 0 for _both_ CPUs. | ||
| 42 | */ | ||
| 43 | #if defined(CONFIG_HW_PERF_EVENTS) | ||
| 44 | #define vpe_id() (cpu_has_mipsmt_pertccounters ? \ | ||
| 45 | 0 : smp_processor_id()) | ||
| 46 | #else | ||
| 47 | #define vpe_id() (cpu_has_mipsmt_pertccounters ? \ | ||
| 48 | 0 : cpu_data[smp_processor_id()].vpe_id) | ||
| 49 | #endif | ||
| 50 | |||
| 51 | /* Copied from op_model_mipsxx.c */ | ||
| 52 | static inline unsigned int vpe_shift(void) | ||
| 53 | { | ||
| 54 | if (num_possible_cpus() > 1) | ||
| 55 | return 1; | ||
| 56 | |||
| 57 | return 0; | ||
| 58 | } | ||
| 59 | #else /* !CONFIG_MIPS_MT_SMP */ | ||
| 60 | #define vpe_id() 0 | ||
| 61 | |||
| 62 | static inline unsigned int vpe_shift(void) | ||
| 63 | { | ||
| 64 | return 0; | ||
| 65 | } | ||
| 66 | #endif /* CONFIG_MIPS_MT_SMP */ | ||
| 67 | |||
| 68 | static inline unsigned int | ||
| 69 | counters_total_to_per_cpu(unsigned int counters) | ||
| 70 | { | ||
| 71 | return counters >> vpe_shift(); | ||
| 72 | } | ||
| 73 | |||
| 74 | static inline unsigned int | ||
| 75 | counters_per_cpu_to_total(unsigned int counters) | ||
| 76 | { | ||
| 77 | return counters << vpe_shift(); | ||
| 78 | } | ||
| 79 | |||
| 80 | #define __define_perf_accessors(r, n, np) \ | ||
| 81 | \ | ||
| 82 | static inline unsigned int r_c0_ ## r ## n(void) \ | ||
| 83 | { \ | ||
| 84 | unsigned int cpu = vpe_id(); \ | ||
| 85 | \ | ||
| 86 | switch (cpu) { \ | ||
| 87 | case 0: \ | ||
| 88 | return read_c0_ ## r ## n(); \ | ||
| 89 | case 1: \ | ||
| 90 | return read_c0_ ## r ## np(); \ | ||
| 91 | default: \ | ||
| 92 | BUG(); \ | ||
| 93 | } \ | ||
| 94 | return 0; \ | ||
| 95 | } \ | ||
| 96 | \ | ||
| 97 | static inline void w_c0_ ## r ## n(unsigned int value) \ | ||
| 98 | { \ | ||
| 99 | unsigned int cpu = vpe_id(); \ | ||
| 100 | \ | ||
| 101 | switch (cpu) { \ | ||
| 102 | case 0: \ | ||
| 103 | write_c0_ ## r ## n(value); \ | ||
| 104 | return; \ | ||
| 105 | case 1: \ | ||
| 106 | write_c0_ ## r ## np(value); \ | ||
| 107 | return; \ | ||
| 108 | default: \ | ||
| 109 | BUG(); \ | ||
| 110 | } \ | ||
| 111 | return; \ | ||
| 112 | } \ | ||
| 113 | |||
| 114 | __define_perf_accessors(perfcntr, 0, 2) | ||
| 115 | __define_perf_accessors(perfcntr, 1, 3) | ||
| 116 | __define_perf_accessors(perfcntr, 2, 0) | ||
| 117 | __define_perf_accessors(perfcntr, 3, 1) | ||
| 118 | |||
| 119 | __define_perf_accessors(perfctrl, 0, 2) | ||
| 120 | __define_perf_accessors(perfctrl, 1, 3) | ||
| 121 | __define_perf_accessors(perfctrl, 2, 0) | ||
| 122 | __define_perf_accessors(perfctrl, 3, 1) | ||
| 123 | |||
| 124 | static inline int __n_counters(void) | ||
| 125 | { | ||
| 126 | if (!(read_c0_config1() & M_CONFIG1_PC)) | ||
| 127 | return 0; | ||
| 128 | if (!(read_c0_perfctrl0() & M_PERFCTL_MORE)) | ||
| 129 | return 1; | ||
| 130 | if (!(read_c0_perfctrl1() & M_PERFCTL_MORE)) | ||
| 131 | return 2; | ||
| 132 | if (!(read_c0_perfctrl2() & M_PERFCTL_MORE)) | ||
| 133 | return 3; | ||
| 134 | |||
| 135 | return 4; | ||
| 136 | } | ||
| 137 | |||
| 138 | static inline int n_counters(void) | ||
| 139 | { | ||
| 140 | int counters; | ||
| 141 | |||
| 142 | switch (current_cpu_type()) { | ||
| 143 | case CPU_R10000: | ||
| 144 | counters = 2; | ||
| 145 | break; | ||
| 146 | |||
| 147 | case CPU_R12000: | ||
| 148 | case CPU_R14000: | ||
| 149 | counters = 4; | ||
| 150 | break; | ||
| 151 | |||
| 152 | default: | ||
| 153 | counters = __n_counters(); | ||
| 154 | } | ||
| 155 | |||
| 156 | return counters; | ||
| 157 | } | ||
| 158 | |||
| 159 | static void reset_counters(void *arg) | ||
| 160 | { | ||
| 161 | int counters = (int)(long)arg; | ||
| 162 | switch (counters) { | ||
| 163 | case 4: | ||
| 164 | w_c0_perfctrl3(0); | ||
| 165 | w_c0_perfcntr3(0); | ||
| 166 | case 3: | ||
| 167 | w_c0_perfctrl2(0); | ||
| 168 | w_c0_perfcntr2(0); | ||
| 169 | case 2: | ||
| 170 | w_c0_perfctrl1(0); | ||
| 171 | w_c0_perfcntr1(0); | ||
| 172 | case 1: | ||
| 173 | w_c0_perfctrl0(0); | ||
| 174 | w_c0_perfcntr0(0); | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | static inline u64 | ||
| 179 | mipsxx_pmu_read_counter(unsigned int idx) | ||
| 180 | { | ||
| 181 | switch (idx) { | ||
| 182 | case 0: | ||
| 183 | return r_c0_perfcntr0(); | ||
| 184 | case 1: | ||
| 185 | return r_c0_perfcntr1(); | ||
| 186 | case 2: | ||
| 187 | return r_c0_perfcntr2(); | ||
| 188 | case 3: | ||
| 189 | return r_c0_perfcntr3(); | ||
| 190 | default: | ||
| 191 | WARN_ONCE(1, "Invalid performance counter number (%d)\n", idx); | ||
| 192 | return 0; | ||
| 193 | } | ||
| 194 | } | ||
| 195 | |||
| 196 | static inline void | ||
| 197 | mipsxx_pmu_write_counter(unsigned int idx, u64 val) | ||
| 198 | { | ||
| 199 | switch (idx) { | ||
| 200 | case 0: | ||
| 201 | w_c0_perfcntr0(val); | ||
| 202 | return; | ||
| 203 | case 1: | ||
| 204 | w_c0_perfcntr1(val); | ||
| 205 | return; | ||
| 206 | case 2: | ||
| 207 | w_c0_perfcntr2(val); | ||
| 208 | return; | ||
| 209 | case 3: | ||
| 210 | w_c0_perfcntr3(val); | ||
| 211 | return; | ||
| 212 | } | ||
| 213 | } | ||
| 214 | |||
| 215 | static inline unsigned int | ||
| 216 | mipsxx_pmu_read_control(unsigned int idx) | ||
| 217 | { | ||
| 218 | switch (idx) { | ||
| 219 | case 0: | ||
| 220 | return r_c0_perfctrl0(); | ||
| 221 | case 1: | ||
| 222 | return r_c0_perfctrl1(); | ||
| 223 | case 2: | ||
| 224 | return r_c0_perfctrl2(); | ||
| 225 | case 3: | ||
| 226 | return r_c0_perfctrl3(); | ||
| 227 | default: | ||
| 228 | WARN_ONCE(1, "Invalid performance counter number (%d)\n", idx); | ||
| 229 | return 0; | ||
| 230 | } | ||
| 231 | } | ||
| 232 | |||
| 233 | static inline void | ||
| 234 | mipsxx_pmu_write_control(unsigned int idx, unsigned int val) | ||
| 235 | { | ||
| 236 | switch (idx) { | ||
| 237 | case 0: | ||
| 238 | w_c0_perfctrl0(val); | ||
| 239 | return; | ||
| 240 | case 1: | ||
| 241 | w_c0_perfctrl1(val); | ||
| 242 | return; | ||
| 243 | case 2: | ||
| 244 | w_c0_perfctrl2(val); | ||
| 245 | return; | ||
| 246 | case 3: | ||
| 247 | w_c0_perfctrl3(val); | ||
| 248 | return; | ||
| 249 | } | ||
| 250 | } | ||
| 251 | |||
| 252 | #ifdef CONFIG_MIPS_MT_SMP | ||
| 253 | static DEFINE_RWLOCK(pmuint_rwlock); | ||
| 254 | #endif | ||
| 255 | |||
| 256 | /* 24K/34K/1004K cores can share the same event map. */ | ||
| 257 | static const struct mips_perf_event mipsxxcore_event_map | ||
| 258 | [PERF_COUNT_HW_MAX] = { | ||
| 259 | [PERF_COUNT_HW_CPU_CYCLES] = { 0x00, CNTR_EVEN | CNTR_ODD, P }, | ||
| 260 | [PERF_COUNT_HW_INSTRUCTIONS] = { 0x01, CNTR_EVEN | CNTR_ODD, T }, | ||
| 261 | [PERF_COUNT_HW_CACHE_REFERENCES] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 262 | [PERF_COUNT_HW_CACHE_MISSES] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 263 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = { 0x02, CNTR_EVEN, T }, | ||
| 264 | [PERF_COUNT_HW_BRANCH_MISSES] = { 0x02, CNTR_ODD, T }, | ||
| 265 | [PERF_COUNT_HW_BUS_CYCLES] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 266 | }; | ||
| 267 | |||
| 268 | /* 74K core has different branch event code. */ | ||
| 269 | static const struct mips_perf_event mipsxx74Kcore_event_map | ||
| 270 | [PERF_COUNT_HW_MAX] = { | ||
| 271 | [PERF_COUNT_HW_CPU_CYCLES] = { 0x00, CNTR_EVEN | CNTR_ODD, P }, | ||
| 272 | [PERF_COUNT_HW_INSTRUCTIONS] = { 0x01, CNTR_EVEN | CNTR_ODD, T }, | ||
| 273 | [PERF_COUNT_HW_CACHE_REFERENCES] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 274 | [PERF_COUNT_HW_CACHE_MISSES] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 275 | [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = { 0x27, CNTR_EVEN, T }, | ||
| 276 | [PERF_COUNT_HW_BRANCH_MISSES] = { 0x27, CNTR_ODD, T }, | ||
| 277 | [PERF_COUNT_HW_BUS_CYCLES] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 278 | }; | ||
| 279 | |||
| 280 | /* 24K/34K/1004K cores can share the same cache event map. */ | ||
| 281 | static const struct mips_perf_event mipsxxcore_cache_map | ||
| 282 | [PERF_COUNT_HW_CACHE_MAX] | ||
| 283 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
| 284 | [PERF_COUNT_HW_CACHE_RESULT_MAX] = { | ||
| 285 | [C(L1D)] = { | ||
| 286 | /* | ||
| 287 | * Like some other architectures (e.g. ARM), the performance | ||
| 288 | * counters don't differentiate between read and write | ||
| 289 | * accesses/misses, so this isn't strictly correct, but it's the | ||
| 290 | * best we can do. Writes and reads get combined. | ||
| 291 | */ | ||
| 292 | [C(OP_READ)] = { | ||
| 293 | [C(RESULT_ACCESS)] = { 0x0a, CNTR_EVEN, T }, | ||
| 294 | [C(RESULT_MISS)] = { 0x0b, CNTR_EVEN | CNTR_ODD, T }, | ||
| 295 | }, | ||
| 296 | [C(OP_WRITE)] = { | ||
| 297 | [C(RESULT_ACCESS)] = { 0x0a, CNTR_EVEN, T }, | ||
| 298 | [C(RESULT_MISS)] = { 0x0b, CNTR_EVEN | CNTR_ODD, T }, | ||
| 299 | }, | ||
| 300 | [C(OP_PREFETCH)] = { | ||
| 301 | [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 302 | [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 303 | }, | ||
| 304 | }, | ||
| 305 | [C(L1I)] = { | ||
| 306 | [C(OP_READ)] = { | ||
| 307 | [C(RESULT_ACCESS)] = { 0x09, CNTR_EVEN, T }, | ||
| 308 | [C(RESULT_MISS)] = { 0x09, CNTR_ODD, T }, | ||
| 309 | }, | ||
| 310 | [C(OP_WRITE)] = { | ||
| 311 | [C(RESULT_ACCESS)] = { 0x09, CNTR_EVEN, T }, | ||
| 312 | [C(RESULT_MISS)] = { 0x09, CNTR_ODD, T }, | ||
| 313 | }, | ||
| 314 | [C(OP_PREFETCH)] = { | ||
| 315 | [C(RESULT_ACCESS)] = { 0x14, CNTR_EVEN, T }, | ||
| 316 | /* | ||
| 317 | * Note that MIPS has only "hit" events countable for | ||
| 318 | * the prefetch operation. | ||
| 319 | */ | ||
| 320 | [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 321 | }, | ||
| 322 | }, | ||
| 323 | [C(LL)] = { | ||
| 324 | [C(OP_READ)] = { | ||
| 325 | [C(RESULT_ACCESS)] = { 0x15, CNTR_ODD, P }, | ||
| 326 | [C(RESULT_MISS)] = { 0x16, CNTR_EVEN, P }, | ||
| 327 | }, | ||
| 328 | [C(OP_WRITE)] = { | ||
| 329 | [C(RESULT_ACCESS)] = { 0x15, CNTR_ODD, P }, | ||
| 330 | [C(RESULT_MISS)] = { 0x16, CNTR_EVEN, P }, | ||
| 331 | }, | ||
| 332 | [C(OP_PREFETCH)] = { | ||
| 333 | [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 334 | [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 335 | }, | ||
| 336 | }, | ||
| 337 | [C(DTLB)] = { | ||
| 338 | [C(OP_READ)] = { | ||
| 339 | [C(RESULT_ACCESS)] = { 0x06, CNTR_EVEN, T }, | ||
| 340 | [C(RESULT_MISS)] = { 0x06, CNTR_ODD, T }, | ||
| 341 | }, | ||
| 342 | [C(OP_WRITE)] = { | ||
| 343 | [C(RESULT_ACCESS)] = { 0x06, CNTR_EVEN, T }, | ||
| 344 | [C(RESULT_MISS)] = { 0x06, CNTR_ODD, T }, | ||
| 345 | }, | ||
| 346 | [C(OP_PREFETCH)] = { | ||
| 347 | [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 348 | [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 349 | }, | ||
| 350 | }, | ||
| 351 | [C(ITLB)] = { | ||
| 352 | [C(OP_READ)] = { | ||
| 353 | [C(RESULT_ACCESS)] = { 0x05, CNTR_EVEN, T }, | ||
| 354 | [C(RESULT_MISS)] = { 0x05, CNTR_ODD, T }, | ||
| 355 | }, | ||
| 356 | [C(OP_WRITE)] = { | ||
| 357 | [C(RESULT_ACCESS)] = { 0x05, CNTR_EVEN, T }, | ||
| 358 | [C(RESULT_MISS)] = { 0x05, CNTR_ODD, T }, | ||
| 359 | }, | ||
| 360 | [C(OP_PREFETCH)] = { | ||
| 361 | [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 362 | [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 363 | }, | ||
| 364 | }, | ||
| 365 | [C(BPU)] = { | ||
| 366 | /* Using the same code for *HW_BRANCH* */ | ||
| 367 | [C(OP_READ)] = { | ||
| 368 | [C(RESULT_ACCESS)] = { 0x02, CNTR_EVEN, T }, | ||
| 369 | [C(RESULT_MISS)] = { 0x02, CNTR_ODD, T }, | ||
| 370 | }, | ||
| 371 | [C(OP_WRITE)] = { | ||
| 372 | [C(RESULT_ACCESS)] = { 0x02, CNTR_EVEN, T }, | ||
| 373 | [C(RESULT_MISS)] = { 0x02, CNTR_ODD, T }, | ||
| 374 | }, | ||
| 375 | [C(OP_PREFETCH)] = { | ||
| 376 | [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 377 | [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 378 | }, | ||
| 379 | }, | ||
| 380 | }; | ||
| 381 | |||
| 382 | /* 74K core has completely different cache event map. */ | ||
| 383 | static const struct mips_perf_event mipsxx74Kcore_cache_map | ||
| 384 | [PERF_COUNT_HW_CACHE_MAX] | ||
| 385 | [PERF_COUNT_HW_CACHE_OP_MAX] | ||
| 386 | [PERF_COUNT_HW_CACHE_RESULT_MAX] = { | ||
| 387 | [C(L1D)] = { | ||
| 388 | /* | ||
| 389 | * Like some other architectures (e.g. ARM), the performance | ||
| 390 | * counters don't differentiate between read and write | ||
| 391 | * accesses/misses, so this isn't strictly correct, but it's the | ||
| 392 | * best we can do. Writes and reads get combined. | ||
| 393 | */ | ||
| 394 | [C(OP_READ)] = { | ||
| 395 | [C(RESULT_ACCESS)] = { 0x17, CNTR_ODD, T }, | ||
| 396 | [C(RESULT_MISS)] = { 0x18, CNTR_ODD, T }, | ||
| 397 | }, | ||
| 398 | [C(OP_WRITE)] = { | ||
| 399 | [C(RESULT_ACCESS)] = { 0x17, CNTR_ODD, T }, | ||
| 400 | [C(RESULT_MISS)] = { 0x18, CNTR_ODD, T }, | ||
| 401 | }, | ||
| 402 | [C(OP_PREFETCH)] = { | ||
| 403 | [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 404 | [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 405 | }, | ||
| 406 | }, | ||
| 407 | [C(L1I)] = { | ||
| 408 | [C(OP_READ)] = { | ||
| 409 | [C(RESULT_ACCESS)] = { 0x06, CNTR_EVEN, T }, | ||
| 410 | [C(RESULT_MISS)] = { 0x06, CNTR_ODD, T }, | ||
| 411 | }, | ||
| 412 | [C(OP_WRITE)] = { | ||
| 413 | [C(RESULT_ACCESS)] = { 0x06, CNTR_EVEN, T }, | ||
| 414 | [C(RESULT_MISS)] = { 0x06, CNTR_ODD, T }, | ||
| 415 | }, | ||
| 416 | [C(OP_PREFETCH)] = { | ||
| 417 | [C(RESULT_ACCESS)] = { 0x34, CNTR_EVEN, T }, | ||
| 418 | /* | ||
| 419 | * Note that MIPS has only "hit" events countable for | ||
| 420 | * the prefetch operation. | ||
| 421 | */ | ||
| 422 | [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 423 | }, | ||
| 424 | }, | ||
| 425 | [C(LL)] = { | ||
| 426 | [C(OP_READ)] = { | ||
| 427 | [C(RESULT_ACCESS)] = { 0x1c, CNTR_ODD, P }, | ||
| 428 | [C(RESULT_MISS)] = { 0x1d, CNTR_EVEN | CNTR_ODD, P }, | ||
| 429 | }, | ||
| 430 | [C(OP_WRITE)] = { | ||
| 431 | [C(RESULT_ACCESS)] = { 0x1c, CNTR_ODD, P }, | ||
| 432 | [C(RESULT_MISS)] = { 0x1d, CNTR_EVEN | CNTR_ODD, P }, | ||
| 433 | }, | ||
| 434 | [C(OP_PREFETCH)] = { | ||
| 435 | [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 436 | [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 437 | }, | ||
| 438 | }, | ||
| 439 | [C(DTLB)] = { | ||
| 440 | /* 74K core does not have specific DTLB events. */ | ||
| 441 | [C(OP_READ)] = { | ||
| 442 | [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 443 | [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 444 | }, | ||
| 445 | [C(OP_WRITE)] = { | ||
| 446 | [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 447 | [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 448 | }, | ||
| 449 | [C(OP_PREFETCH)] = { | ||
| 450 | [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 451 | [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 452 | }, | ||
| 453 | }, | ||
| 454 | [C(ITLB)] = { | ||
| 455 | [C(OP_READ)] = { | ||
| 456 | [C(RESULT_ACCESS)] = { 0x04, CNTR_EVEN, T }, | ||
| 457 | [C(RESULT_MISS)] = { 0x04, CNTR_ODD, T }, | ||
| 458 | }, | ||
| 459 | [C(OP_WRITE)] = { | ||
| 460 | [C(RESULT_ACCESS)] = { 0x04, CNTR_EVEN, T }, | ||
| 461 | [C(RESULT_MISS)] = { 0x04, CNTR_ODD, T }, | ||
| 462 | }, | ||
| 463 | [C(OP_PREFETCH)] = { | ||
| 464 | [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 465 | [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 466 | }, | ||
| 467 | }, | ||
| 468 | [C(BPU)] = { | ||
| 469 | /* Using the same code for *HW_BRANCH* */ | ||
| 470 | [C(OP_READ)] = { | ||
| 471 | [C(RESULT_ACCESS)] = { 0x27, CNTR_EVEN, T }, | ||
| 472 | [C(RESULT_MISS)] = { 0x27, CNTR_ODD, T }, | ||
| 473 | }, | ||
| 474 | [C(OP_WRITE)] = { | ||
| 475 | [C(RESULT_ACCESS)] = { 0x27, CNTR_EVEN, T }, | ||
| 476 | [C(RESULT_MISS)] = { 0x27, CNTR_ODD, T }, | ||
| 477 | }, | ||
| 478 | [C(OP_PREFETCH)] = { | ||
| 479 | [C(RESULT_ACCESS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 480 | [C(RESULT_MISS)] = { UNSUPPORTED_PERF_EVENT_ID }, | ||
| 481 | }, | ||
| 482 | }, | ||
| 483 | }; | ||
| 484 | |||
| 485 | #ifdef CONFIG_MIPS_MT_SMP | ||
| 486 | static void | ||
| 487 | check_and_calc_range(struct perf_event *event, | ||
| 488 | const struct mips_perf_event *pev) | ||
| 489 | { | ||
| 490 | struct hw_perf_event *hwc = &event->hw; | ||
| 491 | |||
| 492 | if (event->cpu >= 0) { | ||
| 493 | if (pev->range > V) { | ||
| 494 | /* | ||
| 495 | * The user selected an event that is processor | ||
| 496 | * wide, while expecting it to be VPE wide. | ||
| 497 | */ | ||
| 498 | hwc->config_base |= M_TC_EN_ALL; | ||
| 499 | } else { | ||
| 500 | /* | ||
| 501 | * FIXME: cpu_data[event->cpu].vpe_id reports 0 | ||
| 502 | * for both CPUs. | ||
| 503 | */ | ||
| 504 | hwc->config_base |= M_PERFCTL_VPEID(event->cpu); | ||
| 505 | hwc->config_base |= M_TC_EN_VPE; | ||
| 506 | } | ||
| 507 | } else | ||
| 508 | hwc->config_base |= M_TC_EN_ALL; | ||
| 509 | } | ||
| 510 | #else | ||
| 511 | static void | ||
| 512 | check_and_calc_range(struct perf_event *event, | ||
| 513 | const struct mips_perf_event *pev) | ||
| 514 | { | ||
| 515 | } | ||
| 516 | #endif | ||
| 517 | |||
| 518 | static int __hw_perf_event_init(struct perf_event *event) | ||
| 519 | { | ||
| 520 | struct perf_event_attr *attr = &event->attr; | ||
| 521 | struct hw_perf_event *hwc = &event->hw; | ||
| 522 | const struct mips_perf_event *pev; | ||
| 523 | int err; | ||
| 524 | |||
| 525 | /* Returning MIPS event descriptor for generic perf event. */ | ||
| 526 | if (PERF_TYPE_HARDWARE == event->attr.type) { | ||
| 527 | if (event->attr.config >= PERF_COUNT_HW_MAX) | ||
| 528 | return -EINVAL; | ||
| 529 | pev = mipspmu_map_general_event(event->attr.config); | ||
| 530 | } else if (PERF_TYPE_HW_CACHE == event->attr.type) { | ||
| 531 | pev = mipspmu_map_cache_event(event->attr.config); | ||
| 532 | } else if (PERF_TYPE_RAW == event->attr.type) { | ||
| 533 | /* We are working on the global raw event. */ | ||
| 534 | mutex_lock(&raw_event_mutex); | ||
| 535 | pev = mipspmu->map_raw_event(event->attr.config); | ||
| 536 | } else { | ||
| 537 | /* The event type is not (yet) supported. */ | ||
| 538 | return -EOPNOTSUPP; | ||
| 539 | } | ||
| 540 | |||
| 541 | if (IS_ERR(pev)) { | ||
| 542 | if (PERF_TYPE_RAW == event->attr.type) | ||
| 543 | mutex_unlock(&raw_event_mutex); | ||
| 544 | return PTR_ERR(pev); | ||
| 545 | } | ||
| 546 | |||
| 547 | /* | ||
| 548 | * We allow max flexibility on how each individual counter shared | ||
| 549 | * by the single CPU operates (the mode exclusion and the range). | ||
| 550 | */ | ||
| 551 | hwc->config_base = M_PERFCTL_INTERRUPT_ENABLE; | ||
| 552 | |||
| 553 | /* Calculate range bits and validate it. */ | ||
| 554 | if (num_possible_cpus() > 1) | ||
| 555 | check_and_calc_range(event, pev); | ||
| 556 | |||
| 557 | hwc->event_base = mipspmu_perf_event_encode(pev); | ||
| 558 | if (PERF_TYPE_RAW == event->attr.type) | ||
| 559 | mutex_unlock(&raw_event_mutex); | ||
| 560 | |||
| 561 | if (!attr->exclude_user) | ||
| 562 | hwc->config_base |= M_PERFCTL_USER; | ||
| 563 | if (!attr->exclude_kernel) { | ||
| 564 | hwc->config_base |= M_PERFCTL_KERNEL; | ||
| 565 | /* MIPS kernel mode: KSU == 00b || EXL == 1 || ERL == 1 */ | ||
| 566 | hwc->config_base |= M_PERFCTL_EXL; | ||
| 567 | } | ||
| 568 | if (!attr->exclude_hv) | ||
| 569 | hwc->config_base |= M_PERFCTL_SUPERVISOR; | ||
| 570 | |||
| 571 | hwc->config_base &= M_PERFCTL_CONFIG_MASK; | ||
| 572 | /* | ||
| 573 | * The event can belong to another cpu. We do not assign a local | ||
| 574 | * counter for it for now. | ||
| 575 | */ | ||
| 576 | hwc->idx = -1; | ||
| 577 | hwc->config = 0; | ||
| 578 | |||
| 579 | if (!hwc->sample_period) { | ||
| 580 | hwc->sample_period = MAX_PERIOD; | ||
| 581 | hwc->last_period = hwc->sample_period; | ||
| 582 | local64_set(&hwc->period_left, hwc->sample_period); | ||
| 583 | } | ||
| 584 | |||
| 585 | err = 0; | ||
| 586 | if (event->group_leader != event) { | ||
| 587 | err = validate_group(event); | ||
| 588 | if (err) | ||
| 589 | return -EINVAL; | ||
| 590 | } | ||
| 591 | |||
| 592 | event->destroy = hw_perf_event_destroy; | ||
| 593 | |||
| 594 | return err; | ||
| 595 | } | ||
| 596 | |||
| 597 | static void pause_local_counters(void) | ||
| 598 | { | ||
| 599 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | ||
| 600 | int counters = mipspmu->num_counters; | ||
| 601 | unsigned long flags; | ||
| 602 | |||
| 603 | local_irq_save(flags); | ||
| 604 | switch (counters) { | ||
| 605 | case 4: | ||
| 606 | cpuc->saved_ctrl[3] = r_c0_perfctrl3(); | ||
| 607 | w_c0_perfctrl3(cpuc->saved_ctrl[3] & | ||
| 608 | ~M_PERFCTL_COUNT_EVENT_WHENEVER); | ||
| 609 | case 3: | ||
| 610 | cpuc->saved_ctrl[2] = r_c0_perfctrl2(); | ||
| 611 | w_c0_perfctrl2(cpuc->saved_ctrl[2] & | ||
| 612 | ~M_PERFCTL_COUNT_EVENT_WHENEVER); | ||
| 613 | case 2: | ||
| 614 | cpuc->saved_ctrl[1] = r_c0_perfctrl1(); | ||
| 615 | w_c0_perfctrl1(cpuc->saved_ctrl[1] & | ||
| 616 | ~M_PERFCTL_COUNT_EVENT_WHENEVER); | ||
| 617 | case 1: | ||
| 618 | cpuc->saved_ctrl[0] = r_c0_perfctrl0(); | ||
| 619 | w_c0_perfctrl0(cpuc->saved_ctrl[0] & | ||
| 620 | ~M_PERFCTL_COUNT_EVENT_WHENEVER); | ||
| 621 | } | ||
| 622 | local_irq_restore(flags); | ||
| 623 | } | ||
| 624 | |||
| 625 | static void resume_local_counters(void) | ||
| 626 | { | ||
| 627 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | ||
| 628 | int counters = mipspmu->num_counters; | ||
| 629 | unsigned long flags; | ||
| 630 | |||
| 631 | local_irq_save(flags); | ||
| 632 | switch (counters) { | ||
| 633 | case 4: | ||
| 634 | w_c0_perfctrl3(cpuc->saved_ctrl[3]); | ||
| 635 | case 3: | ||
| 636 | w_c0_perfctrl2(cpuc->saved_ctrl[2]); | ||
| 637 | case 2: | ||
| 638 | w_c0_perfctrl1(cpuc->saved_ctrl[1]); | ||
| 639 | case 1: | ||
| 640 | w_c0_perfctrl0(cpuc->saved_ctrl[0]); | ||
| 641 | } | ||
| 642 | local_irq_restore(flags); | ||
| 643 | } | ||
| 644 | |||
| 645 | static int mipsxx_pmu_handle_shared_irq(void) | ||
| 646 | { | ||
| 647 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | ||
| 648 | struct perf_sample_data data; | ||
| 649 | unsigned int counters = mipspmu->num_counters; | ||
| 650 | unsigned int counter; | ||
| 651 | int handled = IRQ_NONE; | ||
| 652 | struct pt_regs *regs; | ||
| 653 | |||
| 654 | if (cpu_has_mips_r2 && !(read_c0_cause() & (1 << 26))) | ||
| 655 | return handled; | ||
| 656 | |||
| 657 | /* | ||
| 658 | * First we pause the local counters, so that when we are locked | ||
| 659 | * here, the counters are all paused. When it gets locked due to | ||
| 660 | * perf_disable(), the timer interrupt handler will be delayed. | ||
| 661 | * | ||
| 662 | * See also mipsxx_pmu_start(). | ||
| 663 | */ | ||
| 664 | pause_local_counters(); | ||
| 665 | #ifdef CONFIG_MIPS_MT_SMP | ||
| 666 | read_lock(&pmuint_rwlock); | ||
| 667 | #endif | ||
| 668 | |||
| 669 | regs = get_irq_regs(); | ||
| 670 | |||
| 671 | perf_sample_data_init(&data, 0); | ||
| 672 | |||
| 673 | switch (counters) { | ||
| 674 | #define HANDLE_COUNTER(n) \ | ||
| 675 | case n + 1: \ | ||
| 676 | if (test_bit(n, cpuc->used_mask)) { \ | ||
| 677 | counter = r_c0_perfcntr ## n(); \ | ||
| 678 | if (counter & M_COUNTER_OVERFLOW) { \ | ||
| 679 | w_c0_perfcntr ## n(counter & \ | ||
| 680 | VALID_COUNT); \ | ||
| 681 | if (test_and_change_bit(n, cpuc->msbs)) \ | ||
| 682 | handle_associated_event(cpuc, \ | ||
| 683 | n, &data, regs); \ | ||
| 684 | handled = IRQ_HANDLED; \ | ||
| 685 | } \ | ||
| 686 | } | ||
| 687 | HANDLE_COUNTER(3) | ||
| 688 | HANDLE_COUNTER(2) | ||
| 689 | HANDLE_COUNTER(1) | ||
| 690 | HANDLE_COUNTER(0) | ||
| 691 | } | ||
| 692 | |||
| 693 | /* | ||
| 694 | * Do all the work for the pending perf events. We can do this | ||
| 695 | * in here because the performance counter interrupt is a regular | ||
| 696 | * interrupt, not NMI. | ||
| 697 | */ | ||
| 698 | if (handled == IRQ_HANDLED) | ||
| 699 | irq_work_run(); | ||
| 700 | |||
| 701 | #ifdef CONFIG_MIPS_MT_SMP | ||
| 702 | read_unlock(&pmuint_rwlock); | ||
| 703 | #endif | ||
| 704 | resume_local_counters(); | ||
| 705 | return handled; | ||
| 706 | } | ||
| 707 | |||
| 708 | static irqreturn_t | ||
| 709 | mipsxx_pmu_handle_irq(int irq, void *dev) | ||
| 710 | { | ||
| 711 | return mipsxx_pmu_handle_shared_irq(); | ||
| 712 | } | ||
| 713 | |||
| 714 | static void mipsxx_pmu_start(void) | ||
| 715 | { | ||
| 716 | #ifdef CONFIG_MIPS_MT_SMP | ||
| 717 | write_unlock(&pmuint_rwlock); | ||
| 718 | #endif | ||
| 719 | resume_local_counters(); | ||
| 720 | } | ||
| 721 | |||
| 722 | /* | ||
| 723 | * MIPS performance counters can be per-TC. The control registers can | ||
| 724 | * not be directly accessed across CPUs. Hence if we want to do global | ||
| 725 | * control, we need cross CPU calls. on_each_cpu() can help us, but we | ||
| 726 | * can not make sure this function is called with interrupts enabled. So | ||
| 727 | * here we pause local counters and then grab a rwlock and leave the | ||
| 728 | * counters on other CPUs alone. If any counter interrupt raises while | ||
| 729 | * we own the write lock, simply pause local counters on that CPU and | ||
| 730 | * spin in the handler. Also we know we won't be switched to another | ||
| 731 | * CPU after pausing local counters and before grabbing the lock. | ||
| 732 | */ | ||
| 733 | static void mipsxx_pmu_stop(void) | ||
| 734 | { | ||
| 735 | pause_local_counters(); | ||
| 736 | #ifdef CONFIG_MIPS_MT_SMP | ||
| 737 | write_lock(&pmuint_rwlock); | ||
| 738 | #endif | ||
| 739 | } | ||
| 740 | |||
| 741 | static int | ||
| 742 | mipsxx_pmu_alloc_counter(struct cpu_hw_events *cpuc, | ||
| 743 | struct hw_perf_event *hwc) | ||
| 744 | { | ||
| 745 | int i; | ||
| 746 | |||
| 747 | /* | ||
| 748 | * We only need to care the counter mask. The range has been | ||
| 749 | * checked definitely. | ||
| 750 | */ | ||
| 751 | unsigned long cntr_mask = (hwc->event_base >> 8) & 0xffff; | ||
| 752 | |||
| 753 | for (i = mipspmu->num_counters - 1; i >= 0; i--) { | ||
| 754 | /* | ||
| 755 | * Note that some MIPS perf events can be counted by both | ||
| 756 | * even and odd counters, wheresas many other are only by | ||
| 757 | * even _or_ odd counters. This introduces an issue that | ||
| 758 | * when the former kind of event takes the counter the | ||
| 759 | * latter kind of event wants to use, then the "counter | ||
| 760 | * allocation" for the latter event will fail. In fact if | ||
| 761 | * they can be dynamically swapped, they both feel happy. | ||
| 762 | * But here we leave this issue alone for now. | ||
| 763 | */ | ||
| 764 | if (test_bit(i, &cntr_mask) && | ||
| 765 | !test_and_set_bit(i, cpuc->used_mask)) | ||
| 766 | return i; | ||
| 767 | } | ||
| 768 | |||
| 769 | return -EAGAIN; | ||
| 770 | } | ||
| 771 | |||
| 772 | static void | ||
| 773 | mipsxx_pmu_enable_event(struct hw_perf_event *evt, int idx) | ||
| 774 | { | ||
| 775 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | ||
| 776 | unsigned long flags; | ||
| 777 | |||
| 778 | WARN_ON(idx < 0 || idx >= mipspmu->num_counters); | ||
| 779 | |||
| 780 | local_irq_save(flags); | ||
| 781 | cpuc->saved_ctrl[idx] = M_PERFCTL_EVENT(evt->event_base & 0xff) | | ||
| 782 | (evt->config_base & M_PERFCTL_CONFIG_MASK) | | ||
| 783 | /* Make sure interrupt enabled. */ | ||
| 784 | M_PERFCTL_INTERRUPT_ENABLE; | ||
| 785 | /* | ||
| 786 | * We do not actually let the counter run. Leave it until start(). | ||
| 787 | */ | ||
| 788 | local_irq_restore(flags); | ||
| 789 | } | ||
| 790 | |||
| 791 | static void | ||
| 792 | mipsxx_pmu_disable_event(int idx) | ||
| 793 | { | ||
| 794 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | ||
| 795 | unsigned long flags; | ||
| 796 | |||
| 797 | WARN_ON(idx < 0 || idx >= mipspmu->num_counters); | ||
| 798 | |||
| 799 | local_irq_save(flags); | ||
| 800 | cpuc->saved_ctrl[idx] = mipsxx_pmu_read_control(idx) & | ||
| 801 | ~M_PERFCTL_COUNT_EVENT_WHENEVER; | ||
| 802 | mipsxx_pmu_write_control(idx, cpuc->saved_ctrl[idx]); | ||
| 803 | local_irq_restore(flags); | ||
| 804 | } | ||
| 805 | |||
| 806 | /* 24K */ | ||
| 807 | #define IS_UNSUPPORTED_24K_EVENT(r, b) \ | ||
| 808 | ((b) == 12 || (r) == 151 || (r) == 152 || (b) == 26 || \ | ||
| 809 | (b) == 27 || (r) == 28 || (r) == 158 || (b) == 31 || \ | ||
| 810 | (b) == 32 || (b) == 34 || (b) == 36 || (r) == 168 || \ | ||
| 811 | (r) == 172 || (b) == 47 || ((b) >= 56 && (b) <= 63) || \ | ||
| 812 | ((b) >= 68 && (b) <= 127)) | ||
| 813 | #define IS_BOTH_COUNTERS_24K_EVENT(b) \ | ||
| 814 | ((b) == 0 || (b) == 1 || (b) == 11) | ||
| 815 | |||
| 816 | /* 34K */ | ||
| 817 | #define IS_UNSUPPORTED_34K_EVENT(r, b) \ | ||
| 818 | ((b) == 12 || (r) == 27 || (r) == 158 || (b) == 36 || \ | ||
| 819 | (b) == 38 || (r) == 175 || ((b) >= 56 && (b) <= 63) || \ | ||
| 820 | ((b) >= 68 && (b) <= 127)) | ||
| 821 | #define IS_BOTH_COUNTERS_34K_EVENT(b) \ | ||
| 822 | ((b) == 0 || (b) == 1 || (b) == 11) | ||
| 823 | #ifdef CONFIG_MIPS_MT_SMP | ||
| 824 | #define IS_RANGE_P_34K_EVENT(r, b) \ | ||
| 825 | ((b) == 0 || (r) == 18 || (b) == 21 || (b) == 22 || \ | ||
| 826 | (b) == 25 || (b) == 39 || (r) == 44 || (r) == 174 || \ | ||
| 827 | (r) == 176 || ((b) >= 50 && (b) <= 55) || \ | ||
| 828 | ((b) >= 64 && (b) <= 67)) | ||
| 829 | #define IS_RANGE_V_34K_EVENT(r) ((r) == 47) | ||
| 830 | #endif | ||
| 831 | |||
| 832 | /* 74K */ | ||
| 833 | #define IS_UNSUPPORTED_74K_EVENT(r, b) \ | ||
| 834 | ((r) == 5 || ((r) >= 135 && (r) <= 137) || \ | ||
| 835 | ((b) >= 10 && (b) <= 12) || (b) == 22 || (b) == 27 || \ | ||
| 836 | (b) == 33 || (b) == 34 || ((b) >= 47 && (b) <= 49) || \ | ||
| 837 | (r) == 178 || (b) == 55 || (b) == 57 || (b) == 60 || \ | ||
| 838 | (b) == 61 || (r) == 62 || (r) == 191 || \ | ||
| 839 | ((b) >= 64 && (b) <= 127)) | ||
| 840 | #define IS_BOTH_COUNTERS_74K_EVENT(b) \ | ||
| 841 | ((b) == 0 || (b) == 1) | ||
| 842 | |||
| 843 | /* 1004K */ | ||
| 844 | #define IS_UNSUPPORTED_1004K_EVENT(r, b) \ | ||
| 845 | ((b) == 12 || (r) == 27 || (r) == 158 || (b) == 38 || \ | ||
| 846 | (r) == 175 || (b) == 63 || ((b) >= 68 && (b) <= 127)) | ||
| 847 | #define IS_BOTH_COUNTERS_1004K_EVENT(b) \ | ||
| 848 | ((b) == 0 || (b) == 1 || (b) == 11) | ||
| 849 | #ifdef CONFIG_MIPS_MT_SMP | ||
| 850 | #define IS_RANGE_P_1004K_EVENT(r, b) \ | ||
| 851 | ((b) == 0 || (r) == 18 || (b) == 21 || (b) == 22 || \ | ||
| 852 | (b) == 25 || (b) == 36 || (b) == 39 || (r) == 44 || \ | ||
| 853 | (r) == 174 || (r) == 176 || ((b) >= 50 && (b) <= 59) || \ | ||
| 854 | (r) == 188 || (b) == 61 || (b) == 62 || \ | ||
| 855 | ((b) >= 64 && (b) <= 67)) | ||
| 856 | #define IS_RANGE_V_1004K_EVENT(r) ((r) == 47) | ||
| 857 | #endif | ||
| 858 | |||
| 859 | /* | ||
| 860 | * User can use 0-255 raw events, where 0-127 for the events of even | ||
| 861 | * counters, and 128-255 for odd counters. Note that bit 7 is used to | ||
| 862 | * indicate the parity. So, for example, when user wants to take the | ||
| 863 | * Event Num of 15 for odd counters (by referring to the user manual), | ||
| 864 | * then 128 needs to be added to 15 as the input for the event config, | ||
| 865 | * i.e., 143 (0x8F) to be used. | ||
| 866 | */ | ||
| 867 | static const struct mips_perf_event * | ||
| 868 | mipsxx_pmu_map_raw_event(u64 config) | ||
| 869 | { | ||
| 870 | unsigned int raw_id = config & 0xff; | ||
| 871 | unsigned int base_id = raw_id & 0x7f; | ||
| 872 | |||
| 873 | switch (current_cpu_type()) { | ||
| 874 | case CPU_24K: | ||
| 875 | if (IS_UNSUPPORTED_24K_EVENT(raw_id, base_id)) | ||
| 876 | return ERR_PTR(-EOPNOTSUPP); | ||
| 877 | raw_event.event_id = base_id; | ||
| 878 | if (IS_BOTH_COUNTERS_24K_EVENT(base_id)) | ||
| 879 | raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD; | ||
| 880 | else | ||
| 881 | raw_event.cntr_mask = | ||
| 882 | raw_id > 127 ? CNTR_ODD : CNTR_EVEN; | ||
| 883 | #ifdef CONFIG_MIPS_MT_SMP | ||
| 884 | /* | ||
| 885 | * This is actually doing nothing. Non-multithreading | ||
| 886 | * CPUs will not check and calculate the range. | ||
| 887 | */ | ||
| 888 | raw_event.range = P; | ||
| 889 | #endif | ||
| 890 | break; | ||
| 891 | case CPU_34K: | ||
| 892 | if (IS_UNSUPPORTED_34K_EVENT(raw_id, base_id)) | ||
| 893 | return ERR_PTR(-EOPNOTSUPP); | ||
| 894 | raw_event.event_id = base_id; | ||
| 895 | if (IS_BOTH_COUNTERS_34K_EVENT(base_id)) | ||
| 896 | raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD; | ||
| 897 | else | ||
| 898 | raw_event.cntr_mask = | ||
| 899 | raw_id > 127 ? CNTR_ODD : CNTR_EVEN; | ||
| 900 | #ifdef CONFIG_MIPS_MT_SMP | ||
| 901 | if (IS_RANGE_P_34K_EVENT(raw_id, base_id)) | ||
| 902 | raw_event.range = P; | ||
| 903 | else if (unlikely(IS_RANGE_V_34K_EVENT(raw_id))) | ||
| 904 | raw_event.range = V; | ||
| 905 | else | ||
| 906 | raw_event.range = T; | ||
| 907 | #endif | ||
| 908 | break; | ||
| 909 | case CPU_74K: | ||
| 910 | if (IS_UNSUPPORTED_74K_EVENT(raw_id, base_id)) | ||
| 911 | return ERR_PTR(-EOPNOTSUPP); | ||
| 912 | raw_event.event_id = base_id; | ||
| 913 | if (IS_BOTH_COUNTERS_74K_EVENT(base_id)) | ||
| 914 | raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD; | ||
| 915 | else | ||
| 916 | raw_event.cntr_mask = | ||
| 917 | raw_id > 127 ? CNTR_ODD : CNTR_EVEN; | ||
| 918 | #ifdef CONFIG_MIPS_MT_SMP | ||
| 919 | raw_event.range = P; | ||
| 920 | #endif | ||
| 921 | break; | ||
| 922 | case CPU_1004K: | ||
| 923 | if (IS_UNSUPPORTED_1004K_EVENT(raw_id, base_id)) | ||
| 924 | return ERR_PTR(-EOPNOTSUPP); | ||
| 925 | raw_event.event_id = base_id; | ||
| 926 | if (IS_BOTH_COUNTERS_1004K_EVENT(base_id)) | ||
| 927 | raw_event.cntr_mask = CNTR_EVEN | CNTR_ODD; | ||
| 928 | else | ||
| 929 | raw_event.cntr_mask = | ||
| 930 | raw_id > 127 ? CNTR_ODD : CNTR_EVEN; | ||
| 931 | #ifdef CONFIG_MIPS_MT_SMP | ||
| 932 | if (IS_RANGE_P_1004K_EVENT(raw_id, base_id)) | ||
| 933 | raw_event.range = P; | ||
| 934 | else if (unlikely(IS_RANGE_V_1004K_EVENT(raw_id))) | ||
| 935 | raw_event.range = V; | ||
| 936 | else | ||
| 937 | raw_event.range = T; | ||
| 938 | #endif | ||
| 939 | break; | ||
| 940 | } | ||
| 941 | |||
| 942 | return &raw_event; | ||
| 943 | } | ||
| 944 | |||
| 945 | static struct mips_pmu mipsxxcore_pmu = { | ||
| 946 | .handle_irq = mipsxx_pmu_handle_irq, | ||
| 947 | .handle_shared_irq = mipsxx_pmu_handle_shared_irq, | ||
| 948 | .start = mipsxx_pmu_start, | ||
| 949 | .stop = mipsxx_pmu_stop, | ||
| 950 | .alloc_counter = mipsxx_pmu_alloc_counter, | ||
| 951 | .read_counter = mipsxx_pmu_read_counter, | ||
| 952 | .write_counter = mipsxx_pmu_write_counter, | ||
| 953 | .enable_event = mipsxx_pmu_enable_event, | ||
| 954 | .disable_event = mipsxx_pmu_disable_event, | ||
| 955 | .map_raw_event = mipsxx_pmu_map_raw_event, | ||
| 956 | .general_event_map = &mipsxxcore_event_map, | ||
| 957 | .cache_event_map = &mipsxxcore_cache_map, | ||
| 958 | }; | ||
| 959 | |||
| 960 | static struct mips_pmu mipsxx74Kcore_pmu = { | ||
| 961 | .handle_irq = mipsxx_pmu_handle_irq, | ||
| 962 | .handle_shared_irq = mipsxx_pmu_handle_shared_irq, | ||
| 963 | .start = mipsxx_pmu_start, | ||
| 964 | .stop = mipsxx_pmu_stop, | ||
| 965 | .alloc_counter = mipsxx_pmu_alloc_counter, | ||
| 966 | .read_counter = mipsxx_pmu_read_counter, | ||
| 967 | .write_counter = mipsxx_pmu_write_counter, | ||
| 968 | .enable_event = mipsxx_pmu_enable_event, | ||
| 969 | .disable_event = mipsxx_pmu_disable_event, | ||
| 970 | .map_raw_event = mipsxx_pmu_map_raw_event, | ||
| 971 | .general_event_map = &mipsxx74Kcore_event_map, | ||
| 972 | .cache_event_map = &mipsxx74Kcore_cache_map, | ||
| 973 | }; | ||
| 974 | |||
| 975 | static int __init | ||
| 976 | init_hw_perf_events(void) | ||
| 977 | { | ||
| 978 | int counters, irq; | ||
| 979 | |||
| 980 | pr_info("Performance counters: "); | ||
| 981 | |||
| 982 | counters = n_counters(); | ||
| 983 | if (counters == 0) { | ||
| 984 | pr_cont("No available PMU.\n"); | ||
| 985 | return -ENODEV; | ||
| 986 | } | ||
| 987 | |||
| 988 | #ifdef CONFIG_MIPS_MT_SMP | ||
| 989 | cpu_has_mipsmt_pertccounters = read_c0_config7() & (1<<19); | ||
| 990 | if (!cpu_has_mipsmt_pertccounters) | ||
| 991 | counters = counters_total_to_per_cpu(counters); | ||
| 992 | #endif | ||
| 993 | |||
| 994 | #ifdef MSC01E_INT_BASE | ||
| 995 | if (cpu_has_veic) { | ||
| 996 | /* | ||
| 997 | * Using platform specific interrupt controller defines. | ||
| 998 | */ | ||
| 999 | irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR; | ||
| 1000 | } else { | ||
| 1001 | #endif | ||
| 1002 | if (cp0_perfcount_irq >= 0) | ||
| 1003 | irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; | ||
| 1004 | else | ||
| 1005 | irq = -1; | ||
| 1006 | #ifdef MSC01E_INT_BASE | ||
| 1007 | } | ||
| 1008 | #endif | ||
| 1009 | |||
| 1010 | on_each_cpu(reset_counters, (void *)(long)counters, 1); | ||
| 1011 | |||
| 1012 | switch (current_cpu_type()) { | ||
| 1013 | case CPU_24K: | ||
| 1014 | mipsxxcore_pmu.name = "mips/24K"; | ||
| 1015 | mipsxxcore_pmu.num_counters = counters; | ||
| 1016 | mipsxxcore_pmu.irq = irq; | ||
| 1017 | mipspmu = &mipsxxcore_pmu; | ||
| 1018 | break; | ||
| 1019 | case CPU_34K: | ||
| 1020 | mipsxxcore_pmu.name = "mips/34K"; | ||
| 1021 | mipsxxcore_pmu.num_counters = counters; | ||
| 1022 | mipsxxcore_pmu.irq = irq; | ||
| 1023 | mipspmu = &mipsxxcore_pmu; | ||
| 1024 | break; | ||
| 1025 | case CPU_74K: | ||
| 1026 | mipsxx74Kcore_pmu.name = "mips/74K"; | ||
| 1027 | mipsxx74Kcore_pmu.num_counters = counters; | ||
| 1028 | mipsxx74Kcore_pmu.irq = irq; | ||
| 1029 | mipspmu = &mipsxx74Kcore_pmu; | ||
| 1030 | break; | ||
| 1031 | case CPU_1004K: | ||
| 1032 | mipsxxcore_pmu.name = "mips/1004K"; | ||
| 1033 | mipsxxcore_pmu.num_counters = counters; | ||
| 1034 | mipsxxcore_pmu.irq = irq; | ||
| 1035 | mipspmu = &mipsxxcore_pmu; | ||
| 1036 | break; | ||
| 1037 | default: | ||
| 1038 | pr_cont("Either hardware does not support performance " | ||
| 1039 | "counters, or not yet implemented.\n"); | ||
| 1040 | return -ENODEV; | ||
| 1041 | } | ||
| 1042 | |||
| 1043 | if (mipspmu) | ||
| 1044 | pr_cont("%s PMU enabled, %d counters available to each " | ||
| 1045 | "CPU, irq %d%s\n", mipspmu->name, counters, irq, | ||
| 1046 | irq < 0 ? " (share with timer interrupt)" : ""); | ||
| 1047 | |||
| 1048 | perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW); | ||
| 1049 | |||
| 1050 | return 0; | ||
| 1051 | } | ||
| 1052 | early_initcall(init_hw_perf_events); | ||
| 1053 | |||
| 1054 | #endif /* defined(CONFIG_CPU_MIPS32)... */ | ||
diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c index 26109c4d5170..e309665b6c81 100644 --- a/arch/mips/kernel/proc.c +++ b/arch/mips/kernel/proc.c | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include <asm/cpu-features.h> | 12 | #include <asm/cpu-features.h> |
| 13 | #include <asm/mipsregs.h> | 13 | #include <asm/mipsregs.h> |
| 14 | #include <asm/processor.h> | 14 | #include <asm/processor.h> |
| 15 | #include <asm/mips_machine.h> | ||
| 15 | 16 | ||
| 16 | unsigned int vced_count, vcei_count; | 17 | unsigned int vced_count, vcei_count; |
| 17 | 18 | ||
| @@ -31,8 +32,12 @@ static int show_cpuinfo(struct seq_file *m, void *v) | |||
| 31 | /* | 32 | /* |
| 32 | * For the first processor also print the system type | 33 | * For the first processor also print the system type |
| 33 | */ | 34 | */ |
| 34 | if (n == 0) | 35 | if (n == 0) { |
| 35 | seq_printf(m, "system type\t\t: %s\n", get_system_type()); | 36 | seq_printf(m, "system type\t\t: %s\n", get_system_type()); |
| 37 | if (mips_get_machine_name()) | ||
| 38 | seq_printf(m, "machine\t\t\t: %s\n", | ||
| 39 | mips_get_machine_name()); | ||
| 40 | } | ||
| 36 | 41 | ||
| 37 | seq_printf(m, "processor\t\t: %ld\n", n); | 42 | seq_printf(m, "processor\t\t: %ld\n", n); |
| 38 | sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n", | 43 | sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n", |
| @@ -69,6 +74,8 @@ static int show_cpuinfo(struct seq_file *m, void *v) | |||
| 69 | ); | 74 | ); |
| 70 | seq_printf(m, "shadow register sets\t: %d\n", | 75 | seq_printf(m, "shadow register sets\t: %d\n", |
| 71 | cpu_data[n].srsets); | 76 | cpu_data[n].srsets); |
| 77 | seq_printf(m, "kscratch registers\t: %d\n", | ||
| 78 | hweight8(cpu_data[n].kscratch_mask)); | ||
| 72 | seq_printf(m, "core\t\t\t: %d\n", cpu_data[n].core); | 79 | seq_printf(m, "core\t\t\t: %d\n", cpu_data[n].core); |
| 73 | 80 | ||
| 74 | sprintf(fmt, "VCE%%c exceptions\t\t: %s\n", | 81 | sprintf(fmt, "VCE%%c exceptions\t\t: %s\n", |
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 99960940d4a4..d2112d3cf115 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c | |||
| @@ -142,7 +142,6 @@ int copy_thread(unsigned long clone_flags, unsigned long usp, | |||
| 142 | childregs->regs[7] = 0; /* Clear error flag */ | 142 | childregs->regs[7] = 0; /* Clear error flag */ |
| 143 | 143 | ||
| 144 | childregs->regs[2] = 0; /* Child gets zero as return value */ | 144 | childregs->regs[2] = 0; /* Child gets zero as return value */ |
| 145 | regs->regs[2] = p->pid; | ||
| 146 | 145 | ||
| 147 | if (childregs->cp0_status & ST0_CU0) { | 146 | if (childregs->cp0_status & ST0_CU0) { |
| 148 | childregs->regs[28] = (unsigned long) ti; | 147 | childregs->regs[28] = (unsigned long) ti; |
| @@ -411,7 +410,7 @@ unsigned long unwind_stack(struct task_struct *task, unsigned long *sp, | |||
| 411 | if (!kallsyms_lookup_size_offset(pc, &size, &ofs)) | 410 | if (!kallsyms_lookup_size_offset(pc, &size, &ofs)) |
| 412 | return 0; | 411 | return 0; |
| 413 | /* | 412 | /* |
| 414 | * Return ra if an exception occured at the first instruction | 413 | * Return ra if an exception occurred at the first instruction |
| 415 | */ | 414 | */ |
| 416 | if (unlikely(ofs == 0)) { | 415 | if (unlikely(ofs == 0)) { |
| 417 | pc = *ra; | 416 | pc = *ra; |
diff --git a/arch/mips/kernel/prom.c b/arch/mips/kernel/prom.c new file mode 100644 index 000000000000..5b7eade41fa3 --- /dev/null +++ b/arch/mips/kernel/prom.c | |||
| @@ -0,0 +1,111 @@ | |||
| 1 | /* | ||
| 2 | * MIPS support for CONFIG_OF device tree support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010 Cisco Systems Inc. <dediao@cisco.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/init.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/errno.h> | ||
| 14 | #include <linux/types.h> | ||
| 15 | #include <linux/bootmem.h> | ||
| 16 | #include <linux/initrd.h> | ||
| 17 | #include <linux/debugfs.h> | ||
| 18 | #include <linux/of.h> | ||
| 19 | #include <linux/of_fdt.h> | ||
| 20 | #include <linux/of_irq.h> | ||
| 21 | #include <linux/of_platform.h> | ||
| 22 | |||
| 23 | #include <asm/page.h> | ||
| 24 | #include <asm/prom.h> | ||
| 25 | |||
| 26 | int __init early_init_dt_scan_memory_arch(unsigned long node, | ||
| 27 | const char *uname, int depth, | ||
| 28 | void *data) | ||
| 29 | { | ||
| 30 | return early_init_dt_scan_memory(node, uname, depth, data); | ||
| 31 | } | ||
| 32 | |||
| 33 | void __init early_init_dt_add_memory_arch(u64 base, u64 size) | ||
| 34 | { | ||
| 35 | return add_memory_region(base, size, BOOT_MEM_RAM); | ||
| 36 | } | ||
| 37 | |||
| 38 | int __init reserve_mem_mach(unsigned long addr, unsigned long size) | ||
| 39 | { | ||
| 40 | return reserve_bootmem(addr, size, BOOTMEM_DEFAULT); | ||
| 41 | } | ||
| 42 | |||
| 43 | void __init free_mem_mach(unsigned long addr, unsigned long size) | ||
| 44 | { | ||
| 45 | return free_bootmem(addr, size); | ||
| 46 | } | ||
| 47 | |||
| 48 | void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) | ||
| 49 | { | ||
| 50 | return __alloc_bootmem(size, align, __pa(MAX_DMA_ADDRESS)); | ||
| 51 | } | ||
| 52 | |||
| 53 | #ifdef CONFIG_BLK_DEV_INITRD | ||
| 54 | void __init early_init_dt_setup_initrd_arch(unsigned long start, | ||
| 55 | unsigned long end) | ||
| 56 | { | ||
| 57 | initrd_start = (unsigned long)__va(start); | ||
| 58 | initrd_end = (unsigned long)__va(end); | ||
| 59 | initrd_below_start_ok = 1; | ||
| 60 | } | ||
| 61 | #endif | ||
| 62 | |||
| 63 | /* | ||
| 64 | * irq_create_of_mapping - Hook to resolve OF irq specifier into a Linux irq# | ||
| 65 | * | ||
| 66 | * Currently the mapping mechanism is trivial; simple flat hwirq numbers are | ||
| 67 | * mapped 1:1 onto Linux irq numbers. Cascaded irq controllers are not | ||
| 68 | * supported. | ||
| 69 | */ | ||
| 70 | unsigned int irq_create_of_mapping(struct device_node *controller, | ||
| 71 | const u32 *intspec, unsigned int intsize) | ||
| 72 | { | ||
| 73 | return intspec[0]; | ||
| 74 | } | ||
| 75 | EXPORT_SYMBOL_GPL(irq_create_of_mapping); | ||
| 76 | |||
| 77 | void __init early_init_devtree(void *params) | ||
| 78 | { | ||
| 79 | /* Setup flat device-tree pointer */ | ||
| 80 | initial_boot_params = params; | ||
| 81 | |||
| 82 | /* Retrieve various informations from the /chosen node of the | ||
| 83 | * device-tree, including the platform type, initrd location and | ||
| 84 | * size, and more ... | ||
| 85 | */ | ||
| 86 | of_scan_flat_dt(early_init_dt_scan_chosen, arcs_cmdline); | ||
| 87 | |||
| 88 | |||
| 89 | /* Scan memory nodes */ | ||
| 90 | of_scan_flat_dt(early_init_dt_scan_root, NULL); | ||
| 91 | of_scan_flat_dt(early_init_dt_scan_memory_arch, NULL); | ||
| 92 | } | ||
| 93 | |||
| 94 | void __init device_tree_init(void) | ||
| 95 | { | ||
| 96 | unsigned long base, size; | ||
| 97 | |||
| 98 | if (!initial_boot_params) | ||
| 99 | return; | ||
| 100 | |||
| 101 | base = virt_to_phys((void *)initial_boot_params); | ||
| 102 | size = be32_to_cpu(initial_boot_params->totalsize); | ||
| 103 | |||
| 104 | /* Before we do anything, lets reserve the dt blob */ | ||
| 105 | reserve_mem_mach(base, size); | ||
| 106 | |||
| 107 | unflatten_device_tree(); | ||
| 108 | |||
| 109 | /* free the space reserved for the dt blob */ | ||
| 110 | free_mem_mach(base, size); | ||
| 111 | } | ||
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index c8777333e198..4e6ea1ffad46 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c | |||
| @@ -255,9 +255,13 @@ int ptrace_set_watch_regs(struct task_struct *child, | |||
| 255 | return 0; | 255 | return 0; |
| 256 | } | 256 | } |
| 257 | 257 | ||
| 258 | long arch_ptrace(struct task_struct *child, long request, long addr, long data) | 258 | long arch_ptrace(struct task_struct *child, long request, |
| 259 | unsigned long addr, unsigned long data) | ||
| 259 | { | 260 | { |
| 260 | int ret; | 261 | int ret; |
| 262 | void __user *addrp = (void __user *) addr; | ||
| 263 | void __user *datavp = (void __user *) data; | ||
| 264 | unsigned long __user *datalp = (void __user *) data; | ||
| 261 | 265 | ||
| 262 | switch (request) { | 266 | switch (request) { |
| 263 | /* when I and D space are separate, these will need to be fixed. */ | 267 | /* when I and D space are separate, these will need to be fixed. */ |
| @@ -386,7 +390,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
| 386 | ret = -EIO; | 390 | ret = -EIO; |
| 387 | goto out; | 391 | goto out; |
| 388 | } | 392 | } |
| 389 | ret = put_user(tmp, (unsigned long __user *) data); | 393 | ret = put_user(tmp, datalp); |
| 390 | break; | 394 | break; |
| 391 | } | 395 | } |
| 392 | 396 | ||
| @@ -478,34 +482,31 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
| 478 | } | 482 | } |
| 479 | 483 | ||
| 480 | case PTRACE_GETREGS: | 484 | case PTRACE_GETREGS: |
| 481 | ret = ptrace_getregs(child, (__s64 __user *) data); | 485 | ret = ptrace_getregs(child, datavp); |
| 482 | break; | 486 | break; |
| 483 | 487 | ||
| 484 | case PTRACE_SETREGS: | 488 | case PTRACE_SETREGS: |
| 485 | ret = ptrace_setregs(child, (__s64 __user *) data); | 489 | ret = ptrace_setregs(child, datavp); |
| 486 | break; | 490 | break; |
| 487 | 491 | ||
| 488 | case PTRACE_GETFPREGS: | 492 | case PTRACE_GETFPREGS: |
| 489 | ret = ptrace_getfpregs(child, (__u32 __user *) data); | 493 | ret = ptrace_getfpregs(child, datavp); |
| 490 | break; | 494 | break; |
| 491 | 495 | ||
| 492 | case PTRACE_SETFPREGS: | 496 | case PTRACE_SETFPREGS: |
| 493 | ret = ptrace_setfpregs(child, (__u32 __user *) data); | 497 | ret = ptrace_setfpregs(child, datavp); |
| 494 | break; | 498 | break; |
| 495 | 499 | ||
| 496 | case PTRACE_GET_THREAD_AREA: | 500 | case PTRACE_GET_THREAD_AREA: |
| 497 | ret = put_user(task_thread_info(child)->tp_value, | 501 | ret = put_user(task_thread_info(child)->tp_value, datalp); |
| 498 | (unsigned long __user *) data); | ||
| 499 | break; | 502 | break; |
| 500 | 503 | ||
| 501 | case PTRACE_GET_WATCH_REGS: | 504 | case PTRACE_GET_WATCH_REGS: |
| 502 | ret = ptrace_get_watch_regs(child, | 505 | ret = ptrace_get_watch_regs(child, addrp); |
| 503 | (struct pt_watch_regs __user *) addr); | ||
| 504 | break; | 506 | break; |
| 505 | 507 | ||
| 506 | case PTRACE_SET_WATCH_REGS: | 508 | case PTRACE_SET_WATCH_REGS: |
| 507 | ret = ptrace_set_watch_regs(child, | 509 | ret = ptrace_set_watch_regs(child, addrp); |
| 508 | (struct pt_watch_regs __user *) addr); | ||
| 509 | break; | 510 | break; |
| 510 | 511 | ||
| 511 | default: | 512 | default: |
| @@ -532,15 +533,10 @@ static inline int audit_arch(void) | |||
| 532 | * Notification of system call entry/exit | 533 | * Notification of system call entry/exit |
| 533 | * - triggered by current->work.syscall_trace | 534 | * - triggered by current->work.syscall_trace |
| 534 | */ | 535 | */ |
| 535 | asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit) | 536 | asmlinkage void syscall_trace_enter(struct pt_regs *regs) |
| 536 | { | 537 | { |
| 537 | /* do the secure computing check first */ | 538 | /* do the secure computing check first */ |
| 538 | if (!entryexit) | 539 | secure_computing(regs->regs[2]); |
| 539 | secure_computing(regs->regs[2]); | ||
| 540 | |||
| 541 | if (unlikely(current->audit_context) && entryexit) | ||
| 542 | audit_syscall_exit(AUDITSC_RESULT(regs->regs[2]), | ||
| 543 | regs->regs[2]); | ||
| 544 | 540 | ||
| 545 | if (!(current->ptrace & PT_PTRACED)) | 541 | if (!(current->ptrace & PT_PTRACED)) |
| 546 | goto out; | 542 | goto out; |
| @@ -564,8 +560,40 @@ asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit) | |||
| 564 | } | 560 | } |
| 565 | 561 | ||
| 566 | out: | 562 | out: |
| 567 | if (unlikely(current->audit_context) && !entryexit) | 563 | if (unlikely(current->audit_context)) |
| 568 | audit_syscall_entry(audit_arch(), regs->regs[2], | 564 | audit_syscall_entry(audit_arch(), regs->regs[2], |
| 569 | regs->regs[4], regs->regs[5], | 565 | regs->regs[4], regs->regs[5], |
| 570 | regs->regs[6], regs->regs[7]); | 566 | regs->regs[6], regs->regs[7]); |
| 571 | } | 567 | } |
| 568 | |||
| 569 | /* | ||
| 570 | * Notification of system call entry/exit | ||
| 571 | * - triggered by current->work.syscall_trace | ||
| 572 | */ | ||
| 573 | asmlinkage void syscall_trace_leave(struct pt_regs *regs) | ||
| 574 | { | ||
| 575 | if (unlikely(current->audit_context)) | ||
| 576 | audit_syscall_exit(AUDITSC_RESULT(regs->regs[7]), | ||
| 577 | -regs->regs[2]); | ||
| 578 | |||
| 579 | if (!(current->ptrace & PT_PTRACED)) | ||
| 580 | return; | ||
| 581 | |||
| 582 | if (!test_thread_flag(TIF_SYSCALL_TRACE)) | ||
| 583 | return; | ||
| 584 | |||
| 585 | /* The 0x80 provides a way for the tracing parent to distinguish | ||
| 586 | between a syscall stop and SIGTRAP delivery */ | ||
| 587 | ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) ? | ||
| 588 | 0x80 : 0)); | ||
| 589 | |||
| 590 | /* | ||
| 591 | * this isn't the same as continuing with a signal, but it will do | ||
| 592 | * for normal use. strace only continues with a signal if the | ||
| 593 | * stopping signal is not SIGTRAP. -brl | ||
| 594 | */ | ||
| 595 | if (current->exit_code) { | ||
| 596 | send_sig(current->exit_code, current, 1); | ||
| 597 | current->exit_code = 0; | ||
| 598 | } | ||
| 599 | } | ||
diff --git a/arch/mips/kernel/r2300_fpu.S b/arch/mips/kernel/r2300_fpu.S index ac68e68339db..61c8a0f2a60c 100644 --- a/arch/mips/kernel/r2300_fpu.S +++ b/arch/mips/kernel/r2300_fpu.S | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | * Copyright (C) 1996, 1998 by Ralf Baechle | 6 | * Copyright (C) 1996, 1998 by Ralf Baechle |
| 7 | * | 7 | * |
| 8 | * Multi-arch abstraction and asm macros for easier reading: | 8 | * Multi-arch abstraction and asm macros for easier reading: |
| 9 | * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) | 9 | * Copyright (C) 1996 David S. Miller (davem@davemloft.net) |
| 10 | * | 10 | * |
| 11 | * Further modifications to make this work: | 11 | * Further modifications to make this work: |
| 12 | * Copyright (c) 1998 Harald Koerfgen | 12 | * Copyright (c) 1998 Harald Koerfgen |
diff --git a/arch/mips/kernel/r2300_switch.S b/arch/mips/kernel/r2300_switch.S index 698414b7a253..293898391e67 100644 --- a/arch/mips/kernel/r2300_switch.S +++ b/arch/mips/kernel/r2300_switch.S | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | * Copyright (C) 1994, 1995, 1996 by Andreas Busse | 5 | * Copyright (C) 1994, 1995, 1996 by Andreas Busse |
| 6 | * | 6 | * |
| 7 | * Multi-cpu abstraction and macros for easier reading: | 7 | * Multi-cpu abstraction and macros for easier reading: |
| 8 | * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) | 8 | * Copyright (C) 1996 David S. Miller (davem@davemloft.net) |
| 9 | * | 9 | * |
| 10 | * Further modifications to make this work: | 10 | * Further modifications to make this work: |
| 11 | * Copyright (c) 1998-2000 Harald Koerfgen | 11 | * Copyright (c) 1998-2000 Harald Koerfgen |
diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index dbd42adc52ed..55ffe149dae9 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | * Copyright (C) 1996, 98, 99, 2000, 01 Ralf Baechle | 6 | * Copyright (C) 1996, 98, 99, 2000, 01 Ralf Baechle |
| 7 | * | 7 | * |
| 8 | * Multi-arch abstraction and asm macros for easier reading: | 8 | * Multi-arch abstraction and asm macros for easier reading: |
| 9 | * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) | 9 | * Copyright (C) 1996 David S. Miller (davem@davemloft.net) |
| 10 | * | 10 | * |
| 11 | * Carsten Langgaard, carstenl@mips.com | 11 | * Carsten Langgaard, carstenl@mips.com |
| 12 | * Copyright (C) 2000 MIPS Technologies, Inc. | 12 | * Copyright (C) 2000 MIPS Technologies, Inc. |
diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index 8893ee1a2368..9414f9354469 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | * for more details. | 4 | * for more details. |
| 5 | * | 5 | * |
| 6 | * Copyright (C) 1994, 1995, 1996, 1998, 1999, 2002, 2003 Ralf Baechle | 6 | * Copyright (C) 1994, 1995, 1996, 1998, 1999, 2002, 2003 Ralf Baechle |
| 7 | * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) | 7 | * Copyright (C) 1996 David S. Miller (davem@davemloft.net) |
| 8 | * Copyright (C) 1994, 1995, 1996, by Andreas Busse | 8 | * Copyright (C) 1994, 1995, 1996, by Andreas Busse |
| 9 | * Copyright (C) 1999 Silicon Graphics, Inc. | 9 | * Copyright (C) 1999 Silicon Graphics, Inc. |
| 10 | * Copyright (C) 2000 MIPS Technologies, Inc. | 10 | * Copyright (C) 2000 MIPS Technologies, Inc. |
diff --git a/arch/mips/kernel/r6000_fpu.S b/arch/mips/kernel/r6000_fpu.S index 43cda53f5af6..da0fbe46d83b 100644 --- a/arch/mips/kernel/r6000_fpu.S +++ b/arch/mips/kernel/r6000_fpu.S | |||
| @@ -8,7 +8,7 @@ | |||
| 8 | * Copyright (C) 1996 by Ralf Baechle | 8 | * Copyright (C) 1996 by Ralf Baechle |
| 9 | * | 9 | * |
| 10 | * Multi-arch abstraction and asm macros for easier reading: | 10 | * Multi-arch abstraction and asm macros for easier reading: |
| 11 | * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com) | 11 | * Copyright (C) 1996 David S. Miller (davem@davemloft.net) |
| 12 | */ | 12 | */ |
| 13 | #include <asm/asm.h> | 13 | #include <asm/asm.h> |
| 14 | #include <asm/fpregdef.h> | 14 | #include <asm/fpregdef.h> |
diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c index 26f9b9ab19cc..557ef72472e0 100644 --- a/arch/mips/kernel/rtlx.c +++ b/arch/mips/kernel/rtlx.c | |||
| @@ -468,7 +468,8 @@ static const struct file_operations rtlx_fops = { | |||
| 468 | .release = file_release, | 468 | .release = file_release, |
| 469 | .write = file_write, | 469 | .write = file_write, |
| 470 | .read = file_read, | 470 | .read = file_read, |
| 471 | .poll = file_poll | 471 | .poll = file_poll, |
| 472 | .llseek = noop_llseek, | ||
| 472 | }; | 473 | }; |
| 473 | 474 | ||
| 474 | static struct irqaction rtlx_irq = { | 475 | static struct irqaction rtlx_irq = { |
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S index fbaabad0e6e2..99e656e425f3 100644 --- a/arch/mips/kernel/scall32-o32.S +++ b/arch/mips/kernel/scall32-o32.S | |||
| @@ -88,8 +88,7 @@ syscall_trace_entry: | |||
| 88 | SAVE_STATIC | 88 | SAVE_STATIC |
| 89 | move s0, t2 | 89 | move s0, t2 |
| 90 | move a0, sp | 90 | move a0, sp |
| 91 | li a1, 0 | 91 | jal syscall_trace_enter |
| 92 | jal do_syscall_trace | ||
| 93 | 92 | ||
| 94 | move t0, s0 | 93 | move t0, s0 |
| 95 | RESTORE_STATIC | 94 | RESTORE_STATIC |
| @@ -565,7 +564,7 @@ einval: li v0, -ENOSYS | |||
| 565 | sys sys_ioprio_get 2 /* 4315 */ | 564 | sys sys_ioprio_get 2 /* 4315 */ |
| 566 | sys sys_utimensat 4 | 565 | sys sys_utimensat 4 |
| 567 | sys sys_signalfd 3 | 566 | sys sys_signalfd 3 |
| 568 | sys sys_ni_syscall 0 | 567 | sys sys_ni_syscall 0 /* was timerfd */ |
| 569 | sys sys_eventfd 1 | 568 | sys sys_eventfd 1 |
| 570 | sys sys_fallocate 6 /* 4320 */ | 569 | sys sys_fallocate 6 /* 4320 */ |
| 571 | sys sys_timerfd_create 2 | 570 | sys sys_timerfd_create 2 |
| @@ -586,6 +585,11 @@ einval: li v0, -ENOSYS | |||
| 586 | sys sys_fanotify_init 2 | 585 | sys sys_fanotify_init 2 |
| 587 | sys sys_fanotify_mark 6 | 586 | sys sys_fanotify_mark 6 |
| 588 | sys sys_prlimit64 4 | 587 | sys sys_prlimit64 4 |
| 588 | sys sys_name_to_handle_at 5 | ||
| 589 | sys sys_open_by_handle_at 3 /* 4340 */ | ||
| 590 | sys sys_clock_adjtime 2 | ||
| 591 | sys sys_syncfs 1 | ||
| 592 | sys sys_setns 2 | ||
| 589 | .endm | 593 | .endm |
| 590 | 594 | ||
| 591 | /* We pre-compute the number of _instruction_ bytes needed to | 595 | /* We pre-compute the number of _instruction_ bytes needed to |
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S index 3f4179283207..fb0575f47f3d 100644 --- a/arch/mips/kernel/scall64-64.S +++ b/arch/mips/kernel/scall64-64.S | |||
| @@ -91,8 +91,7 @@ syscall_trace_entry: | |||
| 91 | SAVE_STATIC | 91 | SAVE_STATIC |
| 92 | move s0, t2 | 92 | move s0, t2 |
| 93 | move a0, sp | 93 | move a0, sp |
| 94 | li a1, 0 | 94 | jal syscall_trace_enter |
| 95 | jal do_syscall_trace | ||
| 96 | 95 | ||
| 97 | move t0, s0 | 96 | move t0, s0 |
| 98 | RESTORE_STATIC | 97 | RESTORE_STATIC |
| @@ -404,7 +403,7 @@ sys_call_table: | |||
| 404 | PTR sys_ioprio_get | 403 | PTR sys_ioprio_get |
| 405 | PTR sys_utimensat /* 5275 */ | 404 | PTR sys_utimensat /* 5275 */ |
| 406 | PTR sys_signalfd | 405 | PTR sys_signalfd |
| 407 | PTR sys_ni_syscall | 406 | PTR sys_ni_syscall /* was timerfd */ |
| 408 | PTR sys_eventfd | 407 | PTR sys_eventfd |
| 409 | PTR sys_fallocate | 408 | PTR sys_fallocate |
| 410 | PTR sys_timerfd_create /* 5280 */ | 409 | PTR sys_timerfd_create /* 5280 */ |
| @@ -425,4 +424,9 @@ sys_call_table: | |||
| 425 | PTR sys_fanotify_init /* 5295 */ | 424 | PTR sys_fanotify_init /* 5295 */ |
| 426 | PTR sys_fanotify_mark | 425 | PTR sys_fanotify_mark |
| 427 | PTR sys_prlimit64 | 426 | PTR sys_prlimit64 |
| 427 | PTR sys_name_to_handle_at | ||
| 428 | PTR sys_open_by_handle_at | ||
| 429 | PTR sys_clock_adjtime /* 5300 */ | ||
| 430 | PTR sys_syncfs | ||
| 431 | PTR sys_setns | ||
| 428 | .size sys_call_table,.-sys_call_table | 432 | .size sys_call_table,.-sys_call_table |
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S index f08ece6d8acc..4de0c5534e73 100644 --- a/arch/mips/kernel/scall64-n32.S +++ b/arch/mips/kernel/scall64-n32.S | |||
| @@ -89,8 +89,7 @@ n32_syscall_trace_entry: | |||
| 89 | SAVE_STATIC | 89 | SAVE_STATIC |
| 90 | move s0, t2 | 90 | move s0, t2 |
| 91 | move a0, sp | 91 | move a0, sp |
| 92 | li a1, 0 | 92 | jal syscall_trace_enter |
| 93 | jal do_syscall_trace | ||
| 94 | 93 | ||
| 95 | move t0, s0 | 94 | move t0, s0 |
| 96 | RESTORE_STATIC | 95 | RESTORE_STATIC |
| @@ -403,7 +402,7 @@ EXPORT(sysn32_call_table) | |||
| 403 | PTR sys_ioprio_get | 402 | PTR sys_ioprio_get |
| 404 | PTR compat_sys_utimensat | 403 | PTR compat_sys_utimensat |
| 405 | PTR compat_sys_signalfd /* 6280 */ | 404 | PTR compat_sys_signalfd /* 6280 */ |
| 406 | PTR sys_ni_syscall | 405 | PTR sys_ni_syscall /* was timerfd */ |
| 407 | PTR sys_eventfd | 406 | PTR sys_eventfd |
| 408 | PTR sys_fallocate | 407 | PTR sys_fallocate |
| 409 | PTR sys_timerfd_create | 408 | PTR sys_timerfd_create |
| @@ -425,4 +424,9 @@ EXPORT(sysn32_call_table) | |||
| 425 | PTR sys_fanotify_init /* 6300 */ | 424 | PTR sys_fanotify_init /* 6300 */ |
| 426 | PTR sys_fanotify_mark | 425 | PTR sys_fanotify_mark |
| 427 | PTR sys_prlimit64 | 426 | PTR sys_prlimit64 |
| 427 | PTR sys_name_to_handle_at | ||
| 428 | PTR sys_open_by_handle_at | ||
| 429 | PTR compat_sys_clock_adjtime /* 6305 */ | ||
| 430 | PTR sys_syncfs | ||
| 431 | PTR sys_setns | ||
| 428 | .size sysn32_call_table,.-sysn32_call_table | 432 | .size sysn32_call_table,.-sysn32_call_table |
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S index 78d768a3e19d..4a387de08bfa 100644 --- a/arch/mips/kernel/scall64-o32.S +++ b/arch/mips/kernel/scall64-o32.S | |||
| @@ -123,8 +123,7 @@ trace_a_syscall: | |||
| 123 | 123 | ||
| 124 | move s0, t2 # Save syscall pointer | 124 | move s0, t2 # Save syscall pointer |
| 125 | move a0, sp | 125 | move a0, sp |
| 126 | li a1, 0 | 126 | jal syscall_trace_enter |
| 127 | jal do_syscall_trace | ||
| 128 | 127 | ||
| 129 | move t0, s0 | 128 | move t0, s0 |
| 130 | RESTORE_STATIC | 129 | RESTORE_STATIC |
| @@ -522,7 +521,7 @@ sys_call_table: | |||
| 522 | PTR sys_ioprio_get /* 4315 */ | 521 | PTR sys_ioprio_get /* 4315 */ |
| 523 | PTR compat_sys_utimensat | 522 | PTR compat_sys_utimensat |
| 524 | PTR compat_sys_signalfd | 523 | PTR compat_sys_signalfd |
| 525 | PTR sys_ni_syscall | 524 | PTR sys_ni_syscall /* was timerfd */ |
| 526 | PTR sys_eventfd | 525 | PTR sys_eventfd |
| 527 | PTR sys32_fallocate /* 4320 */ | 526 | PTR sys32_fallocate /* 4320 */ |
| 528 | PTR sys_timerfd_create | 527 | PTR sys_timerfd_create |
| @@ -543,4 +542,9 @@ sys_call_table: | |||
| 543 | PTR sys_fanotify_init | 542 | PTR sys_fanotify_init |
| 544 | PTR sys_32_fanotify_mark | 543 | PTR sys_32_fanotify_mark |
| 545 | PTR sys_prlimit64 | 544 | PTR sys_prlimit64 |
| 545 | PTR sys_name_to_handle_at | ||
| 546 | PTR compat_sys_open_by_handle_at /* 4340 */ | ||
| 547 | PTR compat_sys_clock_adjtime | ||
| 548 | PTR sys_syncfs | ||
| 549 | PTR sys_setns | ||
| 546 | .size sys_call_table,.-sys_call_table | 550 | .size sys_call_table,.-sys_call_table |
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 85aef3fc6716..8ad1d5679f14 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <asm/setup.h> | 31 | #include <asm/setup.h> |
| 32 | #include <asm/smp-ops.h> | 32 | #include <asm/smp-ops.h> |
| 33 | #include <asm/system.h> | 33 | #include <asm/system.h> |
| 34 | #include <asm/prom.h> | ||
| 34 | 35 | ||
| 35 | struct cpuinfo_mips cpu_data[NR_CPUS] __read_mostly; | 36 | struct cpuinfo_mips cpu_data[NR_CPUS] __read_mostly; |
| 36 | 37 | ||
| @@ -69,7 +70,7 @@ static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE; | |||
| 69 | * mips_io_port_base is the begin of the address space to which x86 style | 70 | * mips_io_port_base is the begin of the address space to which x86 style |
| 70 | * I/O ports are mapped. | 71 | * I/O ports are mapped. |
| 71 | */ | 72 | */ |
| 72 | const unsigned long mips_io_port_base __read_mostly = -1; | 73 | const unsigned long mips_io_port_base = -1; |
| 73 | EXPORT_SYMBOL(mips_io_port_base); | 74 | EXPORT_SYMBOL(mips_io_port_base); |
| 74 | 75 | ||
| 75 | static struct resource code_resource = { .name = "Kernel code", }; | 76 | static struct resource code_resource = { .name = "Kernel code", }; |
| @@ -487,7 +488,9 @@ static void __init arch_mem_init(char **cmdline_p) | |||
| 487 | } | 488 | } |
| 488 | 489 | ||
| 489 | bootmem_init(); | 490 | bootmem_init(); |
| 491 | device_tree_init(); | ||
| 490 | sparse_init(); | 492 | sparse_init(); |
| 493 | plat_swiotlb_setup(); | ||
| 491 | paging_init(); | 494 | paging_init(); |
| 492 | } | 495 | } |
| 493 | 496 | ||
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 5922342bca39..dbbe0ce48d89 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c | |||
| @@ -84,7 +84,7 @@ static int protected_save_fp_context(struct sigcontext __user *sc) | |||
| 84 | 84 | ||
| 85 | static int protected_restore_fp_context(struct sigcontext __user *sc) | 85 | static int protected_restore_fp_context(struct sigcontext __user *sc) |
| 86 | { | 86 | { |
| 87 | int err, tmp; | 87 | int err, tmp __maybe_unused; |
| 88 | while (1) { | 88 | while (1) { |
| 89 | lock_fpu_owner(); | 89 | lock_fpu_owner(); |
| 90 | own_fpu_inatomic(0); | 90 | own_fpu_inatomic(0); |
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index a0ed0e052b2e..aae986613795 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c | |||
| @@ -115,7 +115,7 @@ static int protected_save_fp_context32(struct sigcontext32 __user *sc) | |||
| 115 | 115 | ||
| 116 | static int protected_restore_fp_context32(struct sigcontext32 __user *sc) | 116 | static int protected_restore_fp_context32(struct sigcontext32 __user *sc) |
| 117 | { | 117 | { |
| 118 | int err, tmp; | 118 | int err, tmp __maybe_unused; |
| 119 | while (1) { | 119 | while (1) { |
| 120 | lock_fpu_owner(); | 120 | lock_fpu_owner(); |
| 121 | own_fpu_inatomic(0); | 121 | own_fpu_inatomic(0); |
diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c index 43e7cdc5ded2..1ec56e635d04 100644 --- a/arch/mips/kernel/smp-mt.c +++ b/arch/mips/kernel/smp-mt.c | |||
| @@ -120,7 +120,7 @@ static void vsmp_send_ipi_single(int cpu, unsigned int action) | |||
| 120 | 120 | ||
| 121 | local_irq_save(flags); | 121 | local_irq_save(flags); |
| 122 | 122 | ||
| 123 | vpflags = dvpe(); /* cant access the other CPU's registers whilst MVPE enabled */ | 123 | vpflags = dvpe(); /* can't access the other CPU's registers whilst MVPE enabled */ |
| 124 | 124 | ||
| 125 | switch (action) { | 125 | switch (action) { |
| 126 | case SMP_CALL_FUNCTION: | 126 | case SMP_CALL_FUNCTION: |
| @@ -153,7 +153,7 @@ static void __cpuinit vsmp_init_secondary(void) | |||
| 153 | { | 153 | { |
| 154 | extern int gic_present; | 154 | extern int gic_present; |
| 155 | 155 | ||
| 156 | /* This is Malta specific: IPI,performance and timer inetrrupts */ | 156 | /* This is Malta specific: IPI,performance and timer interrupts */ |
| 157 | if (gic_present) | 157 | if (gic_present) |
| 158 | change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | | 158 | change_c0_status(ST0_IM, STATUSF_IP3 | STATUSF_IP4 | |
| 159 | STATUSF_IP6 | STATUSF_IP7); | 159 | STATUSF_IP6 | STATUSF_IP7); |
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 383aeb95cb49..32a256101082 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c | |||
| @@ -193,6 +193,22 @@ void __devinit smp_prepare_boot_cpu(void) | |||
| 193 | */ | 193 | */ |
| 194 | static struct task_struct *cpu_idle_thread[NR_CPUS]; | 194 | static struct task_struct *cpu_idle_thread[NR_CPUS]; |
| 195 | 195 | ||
| 196 | struct create_idle { | ||
| 197 | struct work_struct work; | ||
| 198 | struct task_struct *idle; | ||
| 199 | struct completion done; | ||
| 200 | int cpu; | ||
| 201 | }; | ||
| 202 | |||
| 203 | static void __cpuinit do_fork_idle(struct work_struct *work) | ||
| 204 | { | ||
| 205 | struct create_idle *c_idle = | ||
| 206 | container_of(work, struct create_idle, work); | ||
| 207 | |||
| 208 | c_idle->idle = fork_idle(c_idle->cpu); | ||
| 209 | complete(&c_idle->done); | ||
| 210 | } | ||
| 211 | |||
| 196 | int __cpuinit __cpu_up(unsigned int cpu) | 212 | int __cpuinit __cpu_up(unsigned int cpu) |
| 197 | { | 213 | { |
| 198 | struct task_struct *idle; | 214 | struct task_struct *idle; |
| @@ -203,8 +219,19 @@ int __cpuinit __cpu_up(unsigned int cpu) | |||
| 203 | * Linux can schedule processes on this slave. | 219 | * Linux can schedule processes on this slave. |
| 204 | */ | 220 | */ |
| 205 | if (!cpu_idle_thread[cpu]) { | 221 | if (!cpu_idle_thread[cpu]) { |
| 206 | idle = fork_idle(cpu); | 222 | /* |
| 207 | cpu_idle_thread[cpu] = idle; | 223 | * Schedule work item to avoid forking user task |
| 224 | * Ported from arch/x86/kernel/smpboot.c | ||
| 225 | */ | ||
| 226 | struct create_idle c_idle = { | ||
| 227 | .cpu = cpu, | ||
| 228 | .done = COMPLETION_INITIALIZER_ONSTACK(c_idle.done), | ||
| 229 | }; | ||
| 230 | |||
| 231 | INIT_WORK_ONSTACK(&c_idle.work, do_fork_idle); | ||
| 232 | schedule_work(&c_idle.work); | ||
| 233 | wait_for_completion(&c_idle.done); | ||
| 234 | idle = cpu_idle_thread[cpu] = c_idle.idle; | ||
| 208 | 235 | ||
| 209 | if (IS_ERR(idle)) | 236 | if (IS_ERR(idle)) |
| 210 | panic(KERN_ERR "Fork failed for CPU %d", cpu); | 237 | panic(KERN_ERR "Fork failed for CPU %d", cpu); |
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c index cfeb2c155896..cedac4633741 100644 --- a/arch/mips/kernel/smtc.c +++ b/arch/mips/kernel/smtc.c | |||
| @@ -677,8 +677,9 @@ void smtc_set_irq_affinity(unsigned int irq, cpumask_t affinity) | |||
| 677 | */ | 677 | */ |
| 678 | } | 678 | } |
| 679 | 679 | ||
| 680 | void smtc_forward_irq(unsigned int irq) | 680 | void smtc_forward_irq(struct irq_data *d) |
| 681 | { | 681 | { |
| 682 | unsigned int irq = d->irq; | ||
| 682 | int target; | 683 | int target; |
| 683 | 684 | ||
| 684 | /* | 685 | /* |
| @@ -692,7 +693,7 @@ void smtc_forward_irq(unsigned int irq) | |||
| 692 | * and efficiency, we just pick the easiest one to find. | 693 | * and efficiency, we just pick the easiest one to find. |
| 693 | */ | 694 | */ |
| 694 | 695 | ||
| 695 | target = cpumask_first(irq_desc[irq].affinity); | 696 | target = cpumask_first(d->affinity); |
| 696 | 697 | ||
| 697 | /* | 698 | /* |
| 698 | * We depend on the platform code to have correctly processed | 699 | * We depend on the platform code to have correctly processed |
| @@ -707,12 +708,10 @@ void smtc_forward_irq(unsigned int irq) | |||
| 707 | */ | 708 | */ |
| 708 | 709 | ||
| 709 | /* If no one is eligible, service locally */ | 710 | /* If no one is eligible, service locally */ |
| 710 | if (target >= NR_CPUS) { | 711 | if (target >= NR_CPUS) |
| 711 | do_IRQ_no_affinity(irq); | 712 | do_IRQ_no_affinity(irq); |
| 712 | return; | 713 | else |
| 713 | } | 714 | smtc_send_ipi(target, IRQ_AFFINITY_IPI, irq); |
| 714 | |||
| 715 | smtc_send_ipi(target, IRQ_AFFINITY_IPI, irq); | ||
| 716 | } | 715 | } |
| 717 | 716 | ||
| 718 | #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ | 717 | #endif /* CONFIG_MIPS_MT_SMTC_IRQAFF */ |
| @@ -930,7 +929,7 @@ static void post_direct_ipi(int cpu, struct smtc_ipi *pipi) | |||
| 930 | 929 | ||
| 931 | static void ipi_resched_interrupt(void) | 930 | static void ipi_resched_interrupt(void) |
| 932 | { | 931 | { |
| 933 | /* Return from interrupt should be enough to cause scheduler check */ | 932 | scheduler_ipi(); |
| 934 | } | 933 | } |
| 935 | 934 | ||
| 936 | static void ipi_call_interrupt(void) | 935 | static void ipi_call_interrupt(void) |
| @@ -1038,7 +1037,7 @@ void deferred_smtc_ipi(void) | |||
| 1038 | * but it's more efficient, given that we're already | 1037 | * but it's more efficient, given that we're already |
| 1039 | * running down the IPI queue. | 1038 | * running down the IPI queue. |
| 1040 | */ | 1039 | */ |
| 1041 | __raw_local_irq_restore(flags); | 1040 | __arch_local_irq_restore(flags); |
| 1042 | } | 1041 | } |
| 1043 | } | 1042 | } |
| 1044 | 1043 | ||
| @@ -1147,7 +1146,7 @@ static void setup_cross_vpe_interrupts(unsigned int nvpe) | |||
| 1147 | 1146 | ||
| 1148 | setup_irq_smtc(cpu_ipi_irq, &irq_ipi, (0x100 << MIPS_CPU_IPI_IRQ)); | 1147 | setup_irq_smtc(cpu_ipi_irq, &irq_ipi, (0x100 << MIPS_CPU_IPI_IRQ)); |
| 1149 | 1148 | ||
| 1150 | set_irq_handler(cpu_ipi_irq, handle_percpu_irq); | 1149 | irq_set_handler(cpu_ipi_irq, handle_percpu_irq); |
| 1151 | } | 1150 | } |
| 1152 | 1151 | ||
| 1153 | /* | 1152 | /* |
| @@ -1190,7 +1189,7 @@ void smtc_ipi_replay(void) | |||
| 1190 | /* | 1189 | /* |
| 1191 | ** But use a raw restore here to avoid recursion. | 1190 | ** But use a raw restore here to avoid recursion. |
| 1192 | */ | 1191 | */ |
| 1193 | __raw_local_irq_restore(flags); | 1192 | __arch_local_irq_restore(flags); |
| 1194 | 1193 | ||
| 1195 | if (pipi) { | 1194 | if (pipi) { |
| 1196 | self_ipi(pipi); | 1195 | self_ipi(pipi); |
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 1dc6edff45e0..d02765708ddb 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c | |||
| @@ -10,12 +10,9 @@ | |||
| 10 | #include <linux/capability.h> | 10 | #include <linux/capability.h> |
| 11 | #include <linux/errno.h> | 11 | #include <linux/errno.h> |
| 12 | #include <linux/linkage.h> | 12 | #include <linux/linkage.h> |
| 13 | #include <linux/mm.h> | ||
| 14 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
| 15 | #include <linux/smp.h> | 14 | #include <linux/smp.h> |
| 16 | #include <linux/mman.h> | ||
| 17 | #include <linux/ptrace.h> | 15 | #include <linux/ptrace.h> |
| 18 | #include <linux/sched.h> | ||
| 19 | #include <linux/string.h> | 16 | #include <linux/string.h> |
| 20 | #include <linux/syscalls.h> | 17 | #include <linux/syscalls.h> |
| 21 | #include <linux/file.h> | 18 | #include <linux/file.h> |
| @@ -25,11 +22,9 @@ | |||
| 25 | #include <linux/msg.h> | 22 | #include <linux/msg.h> |
| 26 | #include <linux/shm.h> | 23 | #include <linux/shm.h> |
| 27 | #include <linux/compiler.h> | 24 | #include <linux/compiler.h> |
| 28 | #include <linux/module.h> | ||
| 29 | #include <linux/ipc.h> | 25 | #include <linux/ipc.h> |
| 30 | #include <linux/uaccess.h> | 26 | #include <linux/uaccess.h> |
| 31 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
| 32 | #include <linux/random.h> | ||
| 33 | #include <linux/elf.h> | 28 | #include <linux/elf.h> |
| 34 | 29 | ||
| 35 | #include <asm/asm.h> | 30 | #include <asm/asm.h> |
| @@ -66,121 +61,6 @@ out: | |||
| 66 | return res; | 61 | return res; |
| 67 | } | 62 | } |
| 68 | 63 | ||
| 69 | unsigned long shm_align_mask = PAGE_SIZE - 1; /* Sane caches */ | ||
| 70 | |||
| 71 | EXPORT_SYMBOL(shm_align_mask); | ||
| 72 | |||
| 73 | #define COLOUR_ALIGN(addr,pgoff) \ | ||
| 74 | ((((addr) + shm_align_mask) & ~shm_align_mask) + \ | ||
| 75 | (((pgoff) << PAGE_SHIFT) & shm_align_mask)) | ||
| 76 | |||
| 77 | unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, | ||
| 78 | unsigned long len, unsigned long pgoff, unsigned long flags) | ||
| 79 | { | ||
| 80 | struct vm_area_struct * vmm; | ||
| 81 | int do_color_align; | ||
| 82 | unsigned long task_size; | ||
| 83 | |||
| 84 | #ifdef CONFIG_32BIT | ||
| 85 | task_size = TASK_SIZE; | ||
| 86 | #else /* Must be CONFIG_64BIT*/ | ||
| 87 | task_size = test_thread_flag(TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE; | ||
| 88 | #endif | ||
| 89 | |||
| 90 | if (len > task_size) | ||
| 91 | return -ENOMEM; | ||
| 92 | |||
| 93 | if (flags & MAP_FIXED) { | ||
| 94 | /* Even MAP_FIXED mappings must reside within task_size. */ | ||
| 95 | if (task_size - len < addr) | ||
| 96 | return -EINVAL; | ||
| 97 | |||
| 98 | /* | ||
| 99 | * We do not accept a shared mapping if it would violate | ||
| 100 | * cache aliasing constraints. | ||
| 101 | */ | ||
| 102 | if ((flags & MAP_SHARED) && | ||
| 103 | ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask)) | ||
| 104 | return -EINVAL; | ||
| 105 | return addr; | ||
| 106 | } | ||
| 107 | |||
| 108 | do_color_align = 0; | ||
| 109 | if (filp || (flags & MAP_SHARED)) | ||
| 110 | do_color_align = 1; | ||
| 111 | if (addr) { | ||
| 112 | if (do_color_align) | ||
| 113 | addr = COLOUR_ALIGN(addr, pgoff); | ||
| 114 | else | ||
| 115 | addr = PAGE_ALIGN(addr); | ||
| 116 | vmm = find_vma(current->mm, addr); | ||
| 117 | if (task_size - len >= addr && | ||
| 118 | (!vmm || addr + len <= vmm->vm_start)) | ||
| 119 | return addr; | ||
| 120 | } | ||
| 121 | addr = current->mm->mmap_base; | ||
| 122 | if (do_color_align) | ||
| 123 | addr = COLOUR_ALIGN(addr, pgoff); | ||
| 124 | else | ||
| 125 | addr = PAGE_ALIGN(addr); | ||
| 126 | |||
| 127 | for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { | ||
| 128 | /* At this point: (!vmm || addr < vmm->vm_end). */ | ||
| 129 | if (task_size - len < addr) | ||
| 130 | return -ENOMEM; | ||
| 131 | if (!vmm || addr + len <= vmm->vm_start) | ||
| 132 | return addr; | ||
| 133 | addr = vmm->vm_end; | ||
| 134 | if (do_color_align) | ||
| 135 | addr = COLOUR_ALIGN(addr, pgoff); | ||
| 136 | } | ||
| 137 | } | ||
| 138 | |||
| 139 | void arch_pick_mmap_layout(struct mm_struct *mm) | ||
| 140 | { | ||
| 141 | unsigned long random_factor = 0UL; | ||
| 142 | |||
| 143 | if (current->flags & PF_RANDOMIZE) { | ||
| 144 | random_factor = get_random_int(); | ||
| 145 | random_factor = random_factor << PAGE_SHIFT; | ||
| 146 | if (TASK_IS_32BIT_ADDR) | ||
| 147 | random_factor &= 0xfffffful; | ||
| 148 | else | ||
| 149 | random_factor &= 0xffffffful; | ||
| 150 | } | ||
| 151 | |||
| 152 | mm->mmap_base = TASK_UNMAPPED_BASE + random_factor; | ||
| 153 | mm->get_unmapped_area = arch_get_unmapped_area; | ||
| 154 | mm->unmap_area = arch_unmap_area; | ||
| 155 | } | ||
| 156 | |||
| 157 | static inline unsigned long brk_rnd(void) | ||
| 158 | { | ||
| 159 | unsigned long rnd = get_random_int(); | ||
| 160 | |||
| 161 | rnd = rnd << PAGE_SHIFT; | ||
| 162 | /* 8MB for 32bit, 256MB for 64bit */ | ||
| 163 | if (TASK_IS_32BIT_ADDR) | ||
| 164 | rnd = rnd & 0x7ffffful; | ||
| 165 | else | ||
| 166 | rnd = rnd & 0xffffffful; | ||
| 167 | |||
| 168 | return rnd; | ||
| 169 | } | ||
| 170 | |||
| 171 | unsigned long arch_randomize_brk(struct mm_struct *mm) | ||
| 172 | { | ||
| 173 | unsigned long base = mm->brk; | ||
| 174 | unsigned long ret; | ||
| 175 | |||
| 176 | ret = PAGE_ALIGN(base + brk_rnd()); | ||
| 177 | |||
| 178 | if (ret < mm->brk) | ||
| 179 | return mm->brk; | ||
| 180 | |||
| 181 | return ret; | ||
| 182 | } | ||
| 183 | |||
| 184 | SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len, | 64 | SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len, |
| 185 | unsigned long, prot, unsigned long, flags, unsigned long, | 65 | unsigned long, prot, unsigned long, flags, unsigned long, |
| 186 | fd, off_t, offset) | 66 | fd, off_t, offset) |
| @@ -383,12 +263,11 @@ save_static_function(sys_sysmips); | |||
| 383 | static int __used noinline | 263 | static int __used noinline |
| 384 | _sys_sysmips(nabi_no_regargs struct pt_regs regs) | 264 | _sys_sysmips(nabi_no_regargs struct pt_regs regs) |
| 385 | { | 265 | { |
| 386 | long cmd, arg1, arg2, arg3; | 266 | long cmd, arg1, arg2; |
| 387 | 267 | ||
| 388 | cmd = regs.regs[4]; | 268 | cmd = regs.regs[4]; |
| 389 | arg1 = regs.regs[5]; | 269 | arg1 = regs.regs[5]; |
| 390 | arg2 = regs.regs[6]; | 270 | arg2 = regs.regs[6]; |
| 391 | arg3 = regs.regs[7]; | ||
| 392 | 271 | ||
| 393 | switch (cmd) { | 272 | switch (cmd) { |
| 394 | case MIPS_ATOMIC_SET: | 273 | case MIPS_ATOMIC_SET: |
| @@ -405,7 +284,7 @@ _sys_sysmips(nabi_no_regargs struct pt_regs regs) | |||
| 405 | if (arg1 & 2) | 284 | if (arg1 & 2) |
| 406 | set_thread_flag(TIF_LOGADE); | 285 | set_thread_flag(TIF_LOGADE); |
| 407 | else | 286 | else |
| 408 | clear_thread_flag(TIF_FIXADE); | 287 | clear_thread_flag(TIF_LOGADE); |
| 409 | 288 | ||
| 410 | return 0; | 289 | return 0; |
| 411 | 290 | ||
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c index fb7497405510..1083ad4e1017 100644 --- a/arch/mips/kernel/time.c +++ b/arch/mips/kernel/time.c | |||
| @@ -102,7 +102,7 @@ static __init int cpu_has_mfc0_count_bug(void) | |||
| 102 | case CPU_R4400SC: | 102 | case CPU_R4400SC: |
| 103 | case CPU_R4400MC: | 103 | case CPU_R4400MC: |
| 104 | /* | 104 | /* |
| 105 | * The published errata for the R4400 upto 3.0 say the CPU | 105 | * The published errata for the R4400 up to 3.0 say the CPU |
| 106 | * has the mfc0 from count bug. | 106 | * has the mfc0 from count bug. |
| 107 | */ | 107 | */ |
| 108 | if ((current_cpu_data.processor_id & 0xff) <= 0x30) | 108 | if ((current_cpu_data.processor_id & 0xff) <= 0x30) |
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 03ec0019032b..e9b3af27d844 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
| @@ -28,6 +28,8 @@ | |||
| 28 | #include <linux/kprobes.h> | 28 | #include <linux/kprobes.h> |
| 29 | #include <linux/notifier.h> | 29 | #include <linux/notifier.h> |
| 30 | #include <linux/kdb.h> | 30 | #include <linux/kdb.h> |
| 31 | #include <linux/irq.h> | ||
| 32 | #include <linux/perf_event.h> | ||
| 31 | 33 | ||
| 32 | #include <asm/bootinfo.h> | 34 | #include <asm/bootinfo.h> |
| 33 | #include <asm/branch.h> | 35 | #include <asm/branch.h> |
| @@ -51,7 +53,6 @@ | |||
| 51 | #include <asm/mmu_context.h> | 53 | #include <asm/mmu_context.h> |
| 52 | #include <asm/types.h> | 54 | #include <asm/types.h> |
| 53 | #include <asm/stacktrace.h> | 55 | #include <asm/stacktrace.h> |
| 54 | #include <asm/irq.h> | ||
| 55 | #include <asm/uasm.h> | 56 | #include <asm/uasm.h> |
| 56 | 57 | ||
| 57 | extern void check_wait(void); | 58 | extern void check_wait(void); |
| @@ -82,7 +83,8 @@ extern asmlinkage void handle_mcheck(void); | |||
| 82 | extern asmlinkage void handle_reserved(void); | 83 | extern asmlinkage void handle_reserved(void); |
| 83 | 84 | ||
| 84 | extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, | 85 | extern int fpu_emulator_cop1Handler(struct pt_regs *xcp, |
| 85 | struct mips_fpu_struct *ctx, int has_fpu); | 86 | struct mips_fpu_struct *ctx, int has_fpu, |
| 87 | void *__user *fault_addr); | ||
| 86 | 88 | ||
| 87 | void (*board_be_init)(void); | 89 | void (*board_be_init)(void); |
| 88 | int (*board_be_handler)(struct pt_regs *regs, int is_fixup); | 90 | int (*board_be_handler)(struct pt_regs *regs, int is_fixup); |
| @@ -372,7 +374,8 @@ void __noreturn die(const char *str, struct pt_regs *regs) | |||
| 372 | unsigned long dvpret = dvpe(); | 374 | unsigned long dvpret = dvpe(); |
| 373 | #endif /* CONFIG_MIPS_MT_SMTC */ | 375 | #endif /* CONFIG_MIPS_MT_SMTC */ |
| 374 | 376 | ||
| 375 | notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), SIGSEGV); | 377 | if (notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), SIGSEGV) == NOTIFY_STOP) |
| 378 | sig = 0; | ||
| 376 | 379 | ||
| 377 | console_verbose(); | 380 | console_verbose(); |
| 378 | spin_lock_irq(&die_lock); | 381 | spin_lock_irq(&die_lock); |
| @@ -381,9 +384,6 @@ void __noreturn die(const char *str, struct pt_regs *regs) | |||
| 381 | mips_mt_regdump(dvpret); | 384 | mips_mt_regdump(dvpret); |
| 382 | #endif /* CONFIG_MIPS_MT_SMTC */ | 385 | #endif /* CONFIG_MIPS_MT_SMTC */ |
| 383 | 386 | ||
| 384 | if (notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), SIGSEGV) == NOTIFY_STOP) | ||
| 385 | sig = 0; | ||
| 386 | |||
| 387 | printk("%s[#%d]:\n", str, ++die_counter); | 387 | printk("%s[#%d]:\n", str, ++die_counter); |
| 388 | show_registers(regs); | 388 | show_registers(regs); |
| 389 | add_taint(TAINT_DIE); | 389 | add_taint(TAINT_DIE); |
| @@ -576,10 +576,16 @@ static inline int simulate_sc(struct pt_regs *regs, unsigned int opcode) | |||
| 576 | */ | 576 | */ |
| 577 | static int simulate_llsc(struct pt_regs *regs, unsigned int opcode) | 577 | static int simulate_llsc(struct pt_regs *regs, unsigned int opcode) |
| 578 | { | 578 | { |
| 579 | if ((opcode & OPCODE) == LL) | 579 | if ((opcode & OPCODE) == LL) { |
| 580 | perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, | ||
| 581 | 1, 0, regs, 0); | ||
| 580 | return simulate_ll(regs, opcode); | 582 | return simulate_ll(regs, opcode); |
| 581 | if ((opcode & OPCODE) == SC) | 583 | } |
| 584 | if ((opcode & OPCODE) == SC) { | ||
| 585 | perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, | ||
| 586 | 1, 0, regs, 0); | ||
| 582 | return simulate_sc(regs, opcode); | 587 | return simulate_sc(regs, opcode); |
| 588 | } | ||
| 583 | 589 | ||
| 584 | return -1; /* Must be something else ... */ | 590 | return -1; /* Must be something else ... */ |
| 585 | } | 591 | } |
| @@ -595,6 +601,8 @@ static int simulate_rdhwr(struct pt_regs *regs, unsigned int opcode) | |||
| 595 | if ((opcode & OPCODE) == SPEC3 && (opcode & FUNC) == RDHWR) { | 601 | if ((opcode & OPCODE) == SPEC3 && (opcode & FUNC) == RDHWR) { |
| 596 | int rd = (opcode & RD) >> 11; | 602 | int rd = (opcode & RD) >> 11; |
| 597 | int rt = (opcode & RT) >> 16; | 603 | int rt = (opcode & RT) >> 16; |
| 604 | perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, | ||
| 605 | 1, 0, regs, 0); | ||
| 598 | switch (rd) { | 606 | switch (rd) { |
| 599 | case 0: /* CPU number */ | 607 | case 0: /* CPU number */ |
| 600 | regs->regs[rt] = smp_processor_id(); | 608 | regs->regs[rt] = smp_processor_id(); |
| @@ -630,8 +638,11 @@ static int simulate_rdhwr(struct pt_regs *regs, unsigned int opcode) | |||
| 630 | 638 | ||
| 631 | static int simulate_sync(struct pt_regs *regs, unsigned int opcode) | 639 | static int simulate_sync(struct pt_regs *regs, unsigned int opcode) |
| 632 | { | 640 | { |
| 633 | if ((opcode & OPCODE) == SPEC0 && (opcode & FUNC) == SYNC) | 641 | if ((opcode & OPCODE) == SPEC0 && (opcode & FUNC) == SYNC) { |
| 642 | perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, | ||
| 643 | 1, 0, regs, 0); | ||
| 634 | return 0; | 644 | return 0; |
| 645 | } | ||
| 635 | 646 | ||
| 636 | return -1; /* Must be something else ... */ | 647 | return -1; /* Must be something else ... */ |
| 637 | } | 648 | } |
| @@ -649,12 +660,36 @@ asmlinkage void do_ov(struct pt_regs *regs) | |||
| 649 | force_sig_info(SIGFPE, &info, current); | 660 | force_sig_info(SIGFPE, &info, current); |
| 650 | } | 661 | } |
| 651 | 662 | ||
| 663 | static int process_fpemu_return(int sig, void __user *fault_addr) | ||
| 664 | { | ||
| 665 | if (sig == SIGSEGV || sig == SIGBUS) { | ||
| 666 | struct siginfo si = {0}; | ||
| 667 | si.si_addr = fault_addr; | ||
| 668 | si.si_signo = sig; | ||
| 669 | if (sig == SIGSEGV) { | ||
| 670 | if (find_vma(current->mm, (unsigned long)fault_addr)) | ||
| 671 | si.si_code = SEGV_ACCERR; | ||
| 672 | else | ||
| 673 | si.si_code = SEGV_MAPERR; | ||
| 674 | } else { | ||
| 675 | si.si_code = BUS_ADRERR; | ||
| 676 | } | ||
| 677 | force_sig_info(sig, &si, current); | ||
| 678 | return 1; | ||
| 679 | } else if (sig) { | ||
| 680 | force_sig(sig, current); | ||
| 681 | return 1; | ||
| 682 | } else { | ||
| 683 | return 0; | ||
| 684 | } | ||
| 685 | } | ||
| 686 | |||
| 652 | /* | 687 | /* |
| 653 | * XXX Delayed fp exceptions when doing a lazy ctx switch XXX | 688 | * XXX Delayed fp exceptions when doing a lazy ctx switch XXX |
| 654 | */ | 689 | */ |
| 655 | asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) | 690 | asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) |
| 656 | { | 691 | { |
| 657 | siginfo_t info; | 692 | siginfo_t info = {0}; |
| 658 | 693 | ||
| 659 | if (notify_die(DIE_FP, "FP exception", regs, 0, regs_to_trapnr(regs), SIGFPE) | 694 | if (notify_die(DIE_FP, "FP exception", regs, 0, regs_to_trapnr(regs), SIGFPE) |
| 660 | == NOTIFY_STOP) | 695 | == NOTIFY_STOP) |
| @@ -663,6 +698,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) | |||
| 663 | 698 | ||
| 664 | if (fcr31 & FPU_CSR_UNI_X) { | 699 | if (fcr31 & FPU_CSR_UNI_X) { |
| 665 | int sig; | 700 | int sig; |
| 701 | void __user *fault_addr = NULL; | ||
| 666 | 702 | ||
| 667 | /* | 703 | /* |
| 668 | * Unimplemented operation exception. If we've got the full | 704 | * Unimplemented operation exception. If we've got the full |
| @@ -678,7 +714,8 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) | |||
| 678 | lose_fpu(1); | 714 | lose_fpu(1); |
| 679 | 715 | ||
| 680 | /* Run the emulator */ | 716 | /* Run the emulator */ |
| 681 | sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1); | 717 | sig = fpu_emulator_cop1Handler(regs, ¤t->thread.fpu, 1, |
| 718 | &fault_addr); | ||
| 682 | 719 | ||
| 683 | /* | 720 | /* |
| 684 | * We can't allow the emulated instruction to leave any of | 721 | * We can't allow the emulated instruction to leave any of |
| @@ -690,8 +727,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) | |||
| 690 | own_fpu(1); /* Using the FPU again. */ | 727 | own_fpu(1); /* Using the FPU again. */ |
| 691 | 728 | ||
| 692 | /* If something went wrong, signal */ | 729 | /* If something went wrong, signal */ |
| 693 | if (sig) | 730 | process_fpemu_return(sig, fault_addr); |
| 694 | force_sig(sig, current); | ||
| 695 | 731 | ||
| 696 | return; | 732 | return; |
| 697 | } else if (fcr31 & FPU_CSR_INV_X) | 733 | } else if (fcr31 & FPU_CSR_INV_X) |
| @@ -984,11 +1020,11 @@ asmlinkage void do_cpu(struct pt_regs *regs) | |||
| 984 | 1020 | ||
| 985 | if (!raw_cpu_has_fpu) { | 1021 | if (!raw_cpu_has_fpu) { |
| 986 | int sig; | 1022 | int sig; |
| 1023 | void __user *fault_addr = NULL; | ||
| 987 | sig = fpu_emulator_cop1Handler(regs, | 1024 | sig = fpu_emulator_cop1Handler(regs, |
| 988 | ¤t->thread.fpu, 0); | 1025 | ¤t->thread.fpu, |
| 989 | if (sig) | 1026 | 0, &fault_addr); |
| 990 | force_sig(sig, current); | 1027 | if (!process_fpemu_return(sig, fault_addr)) |
| 991 | else | ||
| 992 | mt_ase_fp_affinity(); | 1028 | mt_ase_fp_affinity(); |
| 993 | } | 1029 | } |
| 994 | 1030 | ||
| @@ -1469,6 +1505,7 @@ void __cpuinit per_cpu_trap_init(void) | |||
| 1469 | { | 1505 | { |
| 1470 | unsigned int cpu = smp_processor_id(); | 1506 | unsigned int cpu = smp_processor_id(); |
| 1471 | unsigned int status_set = ST0_CU0; | 1507 | unsigned int status_set = ST0_CU0; |
| 1508 | unsigned int hwrena = cpu_hwrena_impl_bits; | ||
| 1472 | #ifdef CONFIG_MIPS_MT_SMTC | 1509 | #ifdef CONFIG_MIPS_MT_SMTC |
| 1473 | int secondaryTC = 0; | 1510 | int secondaryTC = 0; |
| 1474 | int bootTC = (cpu == 0); | 1511 | int bootTC = (cpu == 0); |
| @@ -1501,14 +1538,14 @@ void __cpuinit per_cpu_trap_init(void) | |||
| 1501 | change_c0_status(ST0_CU|ST0_MX|ST0_RE|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX, | 1538 | change_c0_status(ST0_CU|ST0_MX|ST0_RE|ST0_FR|ST0_BEV|ST0_TS|ST0_KX|ST0_SX|ST0_UX, |
| 1502 | status_set); | 1539 | status_set); |
| 1503 | 1540 | ||
| 1504 | if (cpu_has_mips_r2) { | 1541 | if (cpu_has_mips_r2) |
| 1505 | unsigned int enable = 0x0000000f | cpu_hwrena_impl_bits; | 1542 | hwrena |= 0x0000000f; |
| 1506 | 1543 | ||
| 1507 | if (!noulri && cpu_has_userlocal) | 1544 | if (!noulri && cpu_has_userlocal) |
| 1508 | enable |= (1 << 29); | 1545 | hwrena |= (1 << 29); |
| 1509 | 1546 | ||
| 1510 | write_c0_hwrena(enable); | 1547 | if (hwrena) |
| 1511 | } | 1548 | write_c0_hwrena(hwrena); |
| 1512 | 1549 | ||
| 1513 | #ifdef CONFIG_MIPS_MT_SMTC | 1550 | #ifdef CONFIG_MIPS_MT_SMTC |
| 1514 | if (!secondaryTC) { | 1551 | if (!secondaryTC) { |
| @@ -1553,7 +1590,6 @@ void __cpuinit per_cpu_trap_init(void) | |||
| 1553 | #endif /* CONFIG_MIPS_MT_SMTC */ | 1590 | #endif /* CONFIG_MIPS_MT_SMTC */ |
| 1554 | 1591 | ||
| 1555 | cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; | 1592 | cpu_data[cpu].asid_cache = ASID_FIRST_VERSION; |
| 1556 | TLBMISS_HANDLER_SETUP(); | ||
| 1557 | 1593 | ||
| 1558 | atomic_inc(&init_mm.mm_count); | 1594 | atomic_inc(&init_mm.mm_count); |
| 1559 | current->active_mm = &init_mm; | 1595 | current->active_mm = &init_mm; |
| @@ -1575,6 +1611,7 @@ void __cpuinit per_cpu_trap_init(void) | |||
| 1575 | write_c0_wired(0); | 1611 | write_c0_wired(0); |
| 1576 | } | 1612 | } |
| 1577 | #endif /* CONFIG_MIPS_MT_SMTC */ | 1613 | #endif /* CONFIG_MIPS_MT_SMTC */ |
| 1614 | TLBMISS_HANDLER_SETUP(); | ||
| 1578 | } | 1615 | } |
| 1579 | 1616 | ||
| 1580 | /* Install CPU exception handler */ | 1617 | /* Install CPU exception handler */ |
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index 33d5a5ce4a29..cfea1adfa153 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c | |||
| @@ -78,6 +78,8 @@ | |||
| 78 | #include <linux/smp.h> | 78 | #include <linux/smp.h> |
| 79 | #include <linux/sched.h> | 79 | #include <linux/sched.h> |
| 80 | #include <linux/debugfs.h> | 80 | #include <linux/debugfs.h> |
| 81 | #include <linux/perf_event.h> | ||
| 82 | |||
| 81 | #include <asm/asm.h> | 83 | #include <asm/asm.h> |
| 82 | #include <asm/branch.h> | 84 | #include <asm/branch.h> |
| 83 | #include <asm/byteorder.h> | 85 | #include <asm/byteorder.h> |
| @@ -109,6 +111,9 @@ static void emulate_load_store_insn(struct pt_regs *regs, | |||
| 109 | unsigned long value; | 111 | unsigned long value; |
| 110 | unsigned int res; | 112 | unsigned int res; |
| 111 | 113 | ||
| 114 | perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, | ||
| 115 | 1, 0, regs, 0); | ||
| 116 | |||
| 112 | /* | 117 | /* |
| 113 | * This load never faults. | 118 | * This load never faults. |
| 114 | */ | 119 | */ |
| @@ -511,6 +516,8 @@ asmlinkage void do_ade(struct pt_regs *regs) | |||
| 511 | unsigned int __user *pc; | 516 | unsigned int __user *pc; |
| 512 | mm_segment_t seg; | 517 | mm_segment_t seg; |
| 513 | 518 | ||
| 519 | perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, | ||
| 520 | 1, 0, regs, regs->cp0_badvaddr); | ||
| 514 | /* | 521 | /* |
| 515 | * Did we catch a fault trying to load an instruction? | 522 | * Did we catch a fault trying to load an instruction? |
| 516 | * Or are we running in MIPS16 mode? | 523 | * Or are we running in MIPS16 mode? |
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S index f25df73db923..a81176f44c74 100644 --- a/arch/mips/kernel/vmlinux.lds.S +++ b/arch/mips/kernel/vmlinux.lds.S | |||
| @@ -65,15 +65,18 @@ SECTIONS | |||
| 65 | NOTES :text :note | 65 | NOTES :text :note |
| 66 | .dummy : { *(.dummy) } :text | 66 | .dummy : { *(.dummy) } :text |
| 67 | 67 | ||
| 68 | _sdata = .; /* Start of data section */ | ||
| 68 | RODATA | 69 | RODATA |
| 69 | 70 | ||
| 70 | /* writeable */ | 71 | /* writeable */ |
| 72 | _sdata = .; /* Start of data section */ | ||
| 71 | .data : { /* Data */ | 73 | .data : { /* Data */ |
| 72 | . = . + DATAOFFSET; /* for CONFIG_MAPPED_KERNEL */ | 74 | . = . + DATAOFFSET; /* for CONFIG_MAPPED_KERNEL */ |
| 73 | 75 | ||
| 74 | INIT_TASK_DATA(PAGE_SIZE) | 76 | INIT_TASK_DATA(PAGE_SIZE) |
| 75 | NOSAVE_DATA | 77 | NOSAVE_DATA |
| 76 | CACHELINE_ALIGNED_DATA(1 << CONFIG_MIPS_L1_CACHE_SHIFT) | 78 | CACHELINE_ALIGNED_DATA(1 << CONFIG_MIPS_L1_CACHE_SHIFT) |
| 79 | READ_MOSTLY_DATA(1 << CONFIG_MIPS_L1_CACHE_SHIFT) | ||
| 77 | DATA_DATA | 80 | DATA_DATA |
| 78 | CONSTRUCTORS | 81 | CONSTRUCTORS |
| 79 | } | 82 | } |
| @@ -98,6 +101,13 @@ SECTIONS | |||
| 98 | INIT_TEXT_SECTION(PAGE_SIZE) | 101 | INIT_TEXT_SECTION(PAGE_SIZE) |
| 99 | INIT_DATA_SECTION(16) | 102 | INIT_DATA_SECTION(16) |
| 100 | 103 | ||
| 104 | . = ALIGN(4); | ||
| 105 | .mips.machines.init : AT(ADDR(.mips.machines.init) - LOAD_OFFSET) { | ||
| 106 | __mips_machines_start = .; | ||
| 107 | *(.mips.machines.init) | ||
| 108 | __mips_machines_end = .; | ||
| 109 | } | ||
| 110 | |||
| 101 | /* .exit.text is discarded at runtime, not link time, to deal with | 111 | /* .exit.text is discarded at runtime, not link time, to deal with |
| 102 | * references from .rodata | 112 | * references from .rodata |
| 103 | */ | 113 | */ |
| @@ -108,7 +118,7 @@ SECTIONS | |||
| 108 | EXIT_DATA | 118 | EXIT_DATA |
| 109 | } | 119 | } |
| 110 | 120 | ||
| 111 | PERCPU(PAGE_SIZE) | 121 | PERCPU_SECTION(1 << CONFIG_MIPS_L1_CACHE_SHIFT) |
| 112 | . = ALIGN(PAGE_SIZE); | 122 | . = ALIGN(PAGE_SIZE); |
| 113 | __init_end = .; | 123 | __init_end = .; |
| 114 | /* freed after init ends here */ | 124 | /* freed after init ends here */ |
diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index 2bd2151c586a..dbb6b408f001 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c | |||
| @@ -19,7 +19,7 @@ | |||
| 19 | * VPE support module | 19 | * VPE support module |
| 20 | * | 20 | * |
| 21 | * Provides support for loading a MIPS SP program on VPE1. | 21 | * Provides support for loading a MIPS SP program on VPE1. |
| 22 | * The SP enviroment is rather simple, no tlb's. It needs to be relocatable | 22 | * The SP environment is rather simple, no tlb's. It needs to be relocatable |
| 23 | * (or partially linked). You should initialise your stack in the startup | 23 | * (or partially linked). You should initialise your stack in the startup |
| 24 | * code. This loader looks for the symbol __start and sets up | 24 | * code. This loader looks for the symbol __start and sets up |
| 25 | * execution to resume from there. The MIPS SDE kit contains suitable examples. | 25 | * execution to resume from there. The MIPS SDE kit contains suitable examples. |
| @@ -148,9 +148,9 @@ struct { | |||
| 148 | spinlock_t tc_list_lock; | 148 | spinlock_t tc_list_lock; |
| 149 | struct list_head tc_list; /* Thread contexts */ | 149 | struct list_head tc_list; /* Thread contexts */ |
| 150 | } vpecontrol = { | 150 | } vpecontrol = { |
| 151 | .vpe_list_lock = SPIN_LOCK_UNLOCKED, | 151 | .vpe_list_lock = __SPIN_LOCK_UNLOCKED(vpe_list_lock), |
| 152 | .vpe_list = LIST_HEAD_INIT(vpecontrol.vpe_list), | 152 | .vpe_list = LIST_HEAD_INIT(vpecontrol.vpe_list), |
| 153 | .tc_list_lock = SPIN_LOCK_UNLOCKED, | 153 | .tc_list_lock = __SPIN_LOCK_UNLOCKED(tc_list_lock), |
| 154 | .tc_list = LIST_HEAD_INIT(vpecontrol.tc_list) | 154 | .tc_list = LIST_HEAD_INIT(vpecontrol.tc_list) |
| 155 | }; | 155 | }; |
| 156 | 156 | ||
| @@ -1092,6 +1092,10 @@ static int vpe_open(struct inode *inode, struct file *filp) | |||
| 1092 | 1092 | ||
| 1093 | /* this of-course trashes what was there before... */ | 1093 | /* this of-course trashes what was there before... */ |
| 1094 | v->pbuffer = vmalloc(P_SIZE); | 1094 | v->pbuffer = vmalloc(P_SIZE); |
| 1095 | if (!v->pbuffer) { | ||
| 1096 | pr_warning("VPE loader: unable to allocate memory\n"); | ||
| 1097 | return -ENOMEM; | ||
| 1098 | } | ||
| 1095 | v->plen = P_SIZE; | 1099 | v->plen = P_SIZE; |
| 1096 | v->load_addr = NULL; | 1100 | v->load_addr = NULL; |
| 1097 | v->len = 0; | 1101 | v->len = 0; |
| @@ -1149,10 +1153,9 @@ static int vpe_release(struct inode *inode, struct file *filp) | |||
| 1149 | if (ret < 0) | 1153 | if (ret < 0) |
| 1150 | v->shared_ptr = NULL; | 1154 | v->shared_ptr = NULL; |
| 1151 | 1155 | ||
| 1152 | // cleanup any temp buffers | 1156 | vfree(v->pbuffer); |
| 1153 | if (v->pbuffer) | ||
| 1154 | vfree(v->pbuffer); | ||
| 1155 | v->plen = 0; | 1157 | v->plen = 0; |
| 1158 | |||
| 1156 | return ret; | 1159 | return ret; |
| 1157 | } | 1160 | } |
| 1158 | 1161 | ||
| @@ -1169,11 +1172,6 @@ static ssize_t vpe_write(struct file *file, const char __user * buffer, | |||
| 1169 | if (v == NULL) | 1172 | if (v == NULL) |
| 1170 | return -ENODEV; | 1173 | return -ENODEV; |
| 1171 | 1174 | ||
| 1172 | if (v->pbuffer == NULL) { | ||
| 1173 | printk(KERN_ERR "VPE loader: no buffer for program\n"); | ||
| 1174 | return -ENOMEM; | ||
| 1175 | } | ||
| 1176 | |||
| 1177 | if ((count + v->len) > v->plen) { | 1175 | if ((count + v->len) > v->plen) { |
| 1178 | printk(KERN_WARNING | 1176 | printk(KERN_WARNING |
| 1179 | "VPE loader: elf size too big. Perhaps strip uneeded symbols\n"); | 1177 | "VPE loader: elf size too big. Perhaps strip uneeded symbols\n"); |
| @@ -1192,7 +1190,8 @@ static const struct file_operations vpe_fops = { | |||
| 1192 | .owner = THIS_MODULE, | 1190 | .owner = THIS_MODULE, |
| 1193 | .open = vpe_open, | 1191 | .open = vpe_open, |
| 1194 | .release = vpe_release, | 1192 | .release = vpe_release, |
| 1195 | .write = vpe_write | 1193 | .write = vpe_write, |
| 1194 | .llseek = noop_llseek, | ||
| 1196 | }; | 1195 | }; |
| 1197 | 1196 | ||
| 1198 | /* module wrapper entry points */ | 1197 | /* module wrapper entry points */ |
