diff options
-rw-r--r-- | arch/sparc/Kconfig | 3 | ||||
-rw-r--r-- | arch/sparc/Kconfig.debug | 5 | ||||
-rw-r--r-- | arch/sparc/include/asm/cpudata_64.h | 2 | ||||
-rw-r--r-- | arch/sparc/include/asm/irqflags_64.h | 14 | ||||
-rw-r--r-- | arch/sparc/kernel/Makefile | 10 | ||||
-rw-r--r-- | arch/sparc/kernel/ftrace.c | 60 | ||||
-rw-r--r-- | arch/sparc/kernel/irq_64.c | 11 | ||||
-rw-r--r-- | arch/sparc/kernel/kgdb_64.c | 3 | ||||
-rw-r--r-- | arch/sparc/kernel/nmi.c | 3 | ||||
-rw-r--r-- | arch/sparc/kernel/pci_common.c | 11 | ||||
-rw-r--r-- | arch/sparc/kernel/pcr.c | 3 | ||||
-rw-r--r-- | arch/sparc/kernel/smp_64.c | 11 | ||||
-rw-r--r-- | arch/sparc/kernel/time_64.c | 4 | ||||
-rw-r--r-- | arch/sparc/kernel/traps_64.c | 26 | ||||
-rw-r--r-- | arch/sparc/kernel/vmlinux.lds.S | 5 | ||||
-rw-r--r-- | arch/sparc/lib/mcount.S | 159 | ||||
-rw-r--r-- | lib/Kconfig.debug | 2 |
17 files changed, 198 insertions, 134 deletions
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig index 6db513674050..9908d477ccd9 100644 --- a/arch/sparc/Kconfig +++ b/arch/sparc/Kconfig | |||
@@ -37,6 +37,9 @@ config SPARC64 | |||
37 | def_bool 64BIT | 37 | def_bool 64BIT |
38 | select ARCH_SUPPORTS_MSI | 38 | select ARCH_SUPPORTS_MSI |
39 | select HAVE_FUNCTION_TRACER | 39 | select HAVE_FUNCTION_TRACER |
40 | select HAVE_FUNCTION_GRAPH_TRACER | ||
41 | select HAVE_FUNCTION_GRAPH_FP_TEST | ||
42 | select HAVE_FUNCTION_TRACE_MCOUNT_TEST | ||
40 | select HAVE_KRETPROBES | 43 | select HAVE_KRETPROBES |
41 | select HAVE_KPROBES | 44 | select HAVE_KPROBES |
42 | select HAVE_LMB | 45 | select HAVE_LMB |
diff --git a/arch/sparc/Kconfig.debug b/arch/sparc/Kconfig.debug index 9d3c889718ac..1b4a831565f9 100644 --- a/arch/sparc/Kconfig.debug +++ b/arch/sparc/Kconfig.debug | |||
@@ -19,13 +19,10 @@ config DEBUG_DCFLUSH | |||
19 | bool "D-cache flush debugging" | 19 | bool "D-cache flush debugging" |
20 | depends on SPARC64 && DEBUG_KERNEL | 20 | depends on SPARC64 && DEBUG_KERNEL |
21 | 21 | ||
22 | config STACK_DEBUG | ||
23 | bool "Stack Overflow Detection Support" | ||
24 | |||
25 | config MCOUNT | 22 | config MCOUNT |
26 | bool | 23 | bool |
27 | depends on SPARC64 | 24 | depends on SPARC64 |
28 | depends on STACK_DEBUG || FUNCTION_TRACER | 25 | depends on FUNCTION_TRACER |
29 | default y | 26 | default y |
30 | 27 | ||
31 | config FRAME_POINTER | 28 | config FRAME_POINTER |
diff --git a/arch/sparc/include/asm/cpudata_64.h b/arch/sparc/include/asm/cpudata_64.h index 926397d345ff..050ef35b9dcf 100644 --- a/arch/sparc/include/asm/cpudata_64.h +++ b/arch/sparc/include/asm/cpudata_64.h | |||
@@ -17,7 +17,7 @@ typedef struct { | |||
17 | unsigned int __nmi_count; | 17 | unsigned int __nmi_count; |
18 | unsigned long clock_tick; /* %tick's per second */ | 18 | unsigned long clock_tick; /* %tick's per second */ |
19 | unsigned long __pad; | 19 | unsigned long __pad; |
20 | unsigned int __pad1; | 20 | unsigned int irq0_irqs; |
21 | unsigned int __pad2; | 21 | unsigned int __pad2; |
22 | 22 | ||
23 | /* Dcache line 2, rarely used */ | 23 | /* Dcache line 2, rarely used */ |
diff --git a/arch/sparc/include/asm/irqflags_64.h b/arch/sparc/include/asm/irqflags_64.h index 8b49bf920df3..a16e94c4b149 100644 --- a/arch/sparc/include/asm/irqflags_64.h +++ b/arch/sparc/include/asm/irqflags_64.h | |||
@@ -76,9 +76,19 @@ static inline int raw_irqs_disabled(void) | |||
76 | */ | 76 | */ |
77 | static inline unsigned long __raw_local_irq_save(void) | 77 | static inline unsigned long __raw_local_irq_save(void) |
78 | { | 78 | { |
79 | unsigned long flags = __raw_local_save_flags(); | 79 | unsigned long flags, tmp; |
80 | 80 | ||
81 | raw_local_irq_disable(); | 81 | /* Disable interrupts to PIL_NORMAL_MAX unless we already |
82 | * are using PIL_NMI, in which case PIL_NMI is retained. | ||
83 | */ | ||
84 | __asm__ __volatile__( | ||
85 | "rdpr %%pil, %0\n\t" | ||
86 | "or %0, %2, %1\n\t" | ||
87 | "wrpr %1, 0x0, %%pil" | ||
88 | : "=r" (flags), "=r" (tmp) | ||
89 | : "i" (PIL_NORMAL_MAX) | ||
90 | : "memory" | ||
91 | ); | ||
82 | 92 | ||
83 | return flags; | 93 | return flags; |
84 | } | 94 | } |
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index c6316142db4e..0c2dc1f24a9a 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile | |||
@@ -13,6 +13,14 @@ extra-y += init_task.o | |||
13 | CPPFLAGS_vmlinux.lds := -Usparc -m$(BITS) | 13 | CPPFLAGS_vmlinux.lds := -Usparc -m$(BITS) |
14 | extra-y += vmlinux.lds | 14 | extra-y += vmlinux.lds |
15 | 15 | ||
16 | ifdef CONFIG_FUNCTION_TRACER | ||
17 | # Do not profile debug and lowlevel utilities | ||
18 | CFLAGS_REMOVE_ftrace.o := -pg | ||
19 | CFLAGS_REMOVE_time_$(BITS).o := -pg | ||
20 | CFLAGS_REMOVE_perf_event.o := -pg | ||
21 | CFLAGS_REMOVE_pcr.o := -pg | ||
22 | endif | ||
23 | |||
16 | obj-$(CONFIG_SPARC32) += entry.o wof.o wuf.o | 24 | obj-$(CONFIG_SPARC32) += entry.o wof.o wuf.o |
17 | obj-$(CONFIG_SPARC32) += etrap_32.o | 25 | obj-$(CONFIG_SPARC32) += etrap_32.o |
18 | obj-$(CONFIG_SPARC32) += rtrap_32.o | 26 | obj-$(CONFIG_SPARC32) += rtrap_32.o |
@@ -85,7 +93,7 @@ obj-$(CONFIG_KGDB) += kgdb_$(BITS).o | |||
85 | 93 | ||
86 | 94 | ||
87 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o | 95 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o |
88 | CFLAGS_REMOVE_ftrace.o := -pg | 96 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o |
89 | 97 | ||
90 | obj-$(CONFIG_EARLYFB) += btext.o | 98 | obj-$(CONFIG_EARLYFB) += btext.o |
91 | obj-$(CONFIG_STACKTRACE) += stacktrace.o | 99 | obj-$(CONFIG_STACKTRACE) += stacktrace.o |
diff --git a/arch/sparc/kernel/ftrace.c b/arch/sparc/kernel/ftrace.c index 9103a56b39e8..03ab022e51c5 100644 --- a/arch/sparc/kernel/ftrace.c +++ b/arch/sparc/kernel/ftrace.c | |||
@@ -13,7 +13,7 @@ static const u32 ftrace_nop = 0x01000000; | |||
13 | 13 | ||
14 | static u32 ftrace_call_replace(unsigned long ip, unsigned long addr) | 14 | static u32 ftrace_call_replace(unsigned long ip, unsigned long addr) |
15 | { | 15 | { |
16 | static u32 call; | 16 | u32 call; |
17 | s32 off; | 17 | s32 off; |
18 | 18 | ||
19 | off = ((s32)addr - (s32)ip); | 19 | off = ((s32)addr - (s32)ip); |
@@ -91,3 +91,61 @@ int __init ftrace_dyn_arch_init(void *data) | |||
91 | return 0; | 91 | return 0; |
92 | } | 92 | } |
93 | #endif | 93 | #endif |
94 | |||
95 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
96 | |||
97 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
98 | extern void ftrace_graph_call(void); | ||
99 | |||
100 | int ftrace_enable_ftrace_graph_caller(void) | ||
101 | { | ||
102 | unsigned long ip = (unsigned long)(&ftrace_graph_call); | ||
103 | u32 old, new; | ||
104 | |||
105 | old = *(u32 *) &ftrace_graph_call; | ||
106 | new = ftrace_call_replace(ip, (unsigned long) &ftrace_graph_caller); | ||
107 | return ftrace_modify_code(ip, old, new); | ||
108 | } | ||
109 | |||
110 | int ftrace_disable_ftrace_graph_caller(void) | ||
111 | { | ||
112 | unsigned long ip = (unsigned long)(&ftrace_graph_call); | ||
113 | u32 old, new; | ||
114 | |||
115 | old = *(u32 *) &ftrace_graph_call; | ||
116 | new = ftrace_call_replace(ip, (unsigned long) &ftrace_stub); | ||
117 | |||
118 | return ftrace_modify_code(ip, old, new); | ||
119 | } | ||
120 | |||
121 | #endif /* !CONFIG_DYNAMIC_FTRACE */ | ||
122 | |||
123 | /* | ||
124 | * Hook the return address and push it in the stack of return addrs | ||
125 | * in current thread info. | ||
126 | */ | ||
127 | unsigned long prepare_ftrace_return(unsigned long parent, | ||
128 | unsigned long self_addr, | ||
129 | unsigned long frame_pointer) | ||
130 | { | ||
131 | unsigned long return_hooker = (unsigned long) &return_to_handler; | ||
132 | struct ftrace_graph_ent trace; | ||
133 | |||
134 | if (unlikely(atomic_read(¤t->tracing_graph_pause))) | ||
135 | return parent + 8UL; | ||
136 | |||
137 | if (ftrace_push_return_trace(parent, self_addr, &trace.depth, | ||
138 | frame_pointer) == -EBUSY) | ||
139 | return parent + 8UL; | ||
140 | |||
141 | trace.func = self_addr; | ||
142 | |||
143 | /* Only trace if the calling function expects to */ | ||
144 | if (!ftrace_graph_entry(&trace)) { | ||
145 | current->curr_ret_stack--; | ||
146 | return parent + 8UL; | ||
147 | } | ||
148 | |||
149 | return return_hooker; | ||
150 | } | ||
151 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c index e1cbdb94d97b..454ce3a25273 100644 --- a/arch/sparc/kernel/irq_64.c +++ b/arch/sparc/kernel/irq_64.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
21 | #include <linux/proc_fs.h> | 21 | #include <linux/proc_fs.h> |
22 | #include <linux/seq_file.h> | 22 | #include <linux/seq_file.h> |
23 | #include <linux/ftrace.h> | ||
23 | #include <linux/irq.h> | 24 | #include <linux/irq.h> |
24 | 25 | ||
25 | #include <asm/ptrace.h> | 26 | #include <asm/ptrace.h> |
@@ -647,6 +648,14 @@ unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino) | |||
647 | bucket = kzalloc(sizeof(struct ino_bucket), GFP_ATOMIC); | 648 | bucket = kzalloc(sizeof(struct ino_bucket), GFP_ATOMIC); |
648 | if (unlikely(!bucket)) | 649 | if (unlikely(!bucket)) |
649 | return 0; | 650 | return 0; |
651 | |||
652 | /* The only reference we store to the IRQ bucket is | ||
653 | * by physical address which kmemleak can't see, tell | ||
654 | * it that this object explicitly is not a leak and | ||
655 | * should be scanned. | ||
656 | */ | ||
657 | kmemleak_not_leak(bucket); | ||
658 | |||
650 | __flush_dcache_range((unsigned long) bucket, | 659 | __flush_dcache_range((unsigned long) bucket, |
651 | ((unsigned long) bucket + | 660 | ((unsigned long) bucket + |
652 | sizeof(struct ino_bucket))); | 661 | sizeof(struct ino_bucket))); |
@@ -721,7 +730,7 @@ static __attribute__((always_inline)) void restore_hardirq_stack(void *orig_sp) | |||
721 | __asm__ __volatile__("mov %0, %%sp" : : "r" (orig_sp)); | 730 | __asm__ __volatile__("mov %0, %%sp" : : "r" (orig_sp)); |
722 | } | 731 | } |
723 | 732 | ||
724 | void handler_irq(int irq, struct pt_regs *regs) | 733 | void __irq_entry handler_irq(int irq, struct pt_regs *regs) |
725 | { | 734 | { |
726 | unsigned long pstate, bucket_pa; | 735 | unsigned long pstate, bucket_pa; |
727 | struct pt_regs *old_regs; | 736 | struct pt_regs *old_regs; |
diff --git a/arch/sparc/kernel/kgdb_64.c b/arch/sparc/kernel/kgdb_64.c index f5a0fd490b59..0a2bd0f99fc1 100644 --- a/arch/sparc/kernel/kgdb_64.c +++ b/arch/sparc/kernel/kgdb_64.c | |||
@@ -5,6 +5,7 @@ | |||
5 | 5 | ||
6 | #include <linux/kgdb.h> | 6 | #include <linux/kgdb.h> |
7 | #include <linux/kdebug.h> | 7 | #include <linux/kdebug.h> |
8 | #include <linux/ftrace.h> | ||
8 | 9 | ||
9 | #include <asm/kdebug.h> | 10 | #include <asm/kdebug.h> |
10 | #include <asm/ptrace.h> | 11 | #include <asm/ptrace.h> |
@@ -108,7 +109,7 @@ void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs) | |||
108 | } | 109 | } |
109 | 110 | ||
110 | #ifdef CONFIG_SMP | 111 | #ifdef CONFIG_SMP |
111 | void smp_kgdb_capture_client(int irq, struct pt_regs *regs) | 112 | void __irq_entry smp_kgdb_capture_client(int irq, struct pt_regs *regs) |
112 | { | 113 | { |
113 | unsigned long flags; | 114 | unsigned long flags; |
114 | 115 | ||
diff --git a/arch/sparc/kernel/nmi.c b/arch/sparc/kernel/nmi.c index b287b62c7ea3..75a3d1a25356 100644 --- a/arch/sparc/kernel/nmi.c +++ b/arch/sparc/kernel/nmi.c | |||
@@ -92,7 +92,6 @@ static void die_nmi(const char *str, struct pt_regs *regs, int do_panic) | |||
92 | notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) | 92 | notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) |
93 | { | 93 | { |
94 | unsigned int sum, touched = 0; | 94 | unsigned int sum, touched = 0; |
95 | int cpu = smp_processor_id(); | ||
96 | 95 | ||
97 | clear_softint(1 << irq); | 96 | clear_softint(1 << irq); |
98 | 97 | ||
@@ -106,7 +105,7 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) | |||
106 | else | 105 | else |
107 | pcr_ops->write(PCR_PIC_PRIV); | 106 | pcr_ops->write(PCR_PIC_PRIV); |
108 | 107 | ||
109 | sum = kstat_irqs_cpu(0, cpu); | 108 | sum = local_cpu_data().irq0_irqs; |
110 | if (__get_cpu_var(nmi_touch)) { | 109 | if (__get_cpu_var(nmi_touch)) { |
111 | __get_cpu_var(nmi_touch) = 0; | 110 | __get_cpu_var(nmi_touch) = 0; |
112 | touched = 1; | 111 | touched = 1; |
diff --git a/arch/sparc/kernel/pci_common.c b/arch/sparc/kernel/pci_common.c index b775658a927d..8a000583b5cf 100644 --- a/arch/sparc/kernel/pci_common.c +++ b/arch/sparc/kernel/pci_common.c | |||
@@ -371,14 +371,19 @@ static void pci_register_iommu_region(struct pci_pbm_info *pbm) | |||
371 | struct resource *rp = kzalloc(sizeof(*rp), GFP_KERNEL); | 371 | struct resource *rp = kzalloc(sizeof(*rp), GFP_KERNEL); |
372 | 372 | ||
373 | if (!rp) { | 373 | if (!rp) { |
374 | prom_printf("Cannot allocate IOMMU resource.\n"); | 374 | pr_info("%s: Cannot allocate IOMMU resource.\n", |
375 | prom_halt(); | 375 | pbm->name); |
376 | return; | ||
376 | } | 377 | } |
377 | rp->name = "IOMMU"; | 378 | rp->name = "IOMMU"; |
378 | rp->start = pbm->mem_space.start + (unsigned long) vdma[0]; | 379 | rp->start = pbm->mem_space.start + (unsigned long) vdma[0]; |
379 | rp->end = rp->start + (unsigned long) vdma[1] - 1UL; | 380 | rp->end = rp->start + (unsigned long) vdma[1] - 1UL; |
380 | rp->flags = IORESOURCE_BUSY; | 381 | rp->flags = IORESOURCE_BUSY; |
381 | request_resource(&pbm->mem_space, rp); | 382 | if (request_resource(&pbm->mem_space, rp)) { |
383 | pr_info("%s: Unable to request IOMMU resource.\n", | ||
384 | pbm->name); | ||
385 | kfree(rp); | ||
386 | } | ||
382 | } | 387 | } |
383 | } | 388 | } |
384 | 389 | ||
diff --git a/arch/sparc/kernel/pcr.c b/arch/sparc/kernel/pcr.c index 2d94e7a03af5..c4a6a50b4849 100644 --- a/arch/sparc/kernel/pcr.c +++ b/arch/sparc/kernel/pcr.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/irq.h> | 8 | #include <linux/irq.h> |
9 | 9 | ||
10 | #include <linux/perf_event.h> | 10 | #include <linux/perf_event.h> |
11 | #include <linux/ftrace.h> | ||
11 | 12 | ||
12 | #include <asm/pil.h> | 13 | #include <asm/pil.h> |
13 | #include <asm/pcr.h> | 14 | #include <asm/pcr.h> |
@@ -34,7 +35,7 @@ unsigned int picl_shift; | |||
34 | * Therefore in such situations we defer the work by signalling | 35 | * Therefore in such situations we defer the work by signalling |
35 | * a lower level cpu IRQ. | 36 | * a lower level cpu IRQ. |
36 | */ | 37 | */ |
37 | void deferred_pcr_work_irq(int irq, struct pt_regs *regs) | 38 | void __irq_entry deferred_pcr_work_irq(int irq, struct pt_regs *regs) |
38 | { | 39 | { |
39 | struct pt_regs *old_regs; | 40 | struct pt_regs *old_regs; |
40 | 41 | ||
diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index 4c5334528109..b6a2b8f47040 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/profile.h> | 22 | #include <linux/profile.h> |
23 | #include <linux/bootmem.h> | 23 | #include <linux/bootmem.h> |
24 | #include <linux/vmalloc.h> | 24 | #include <linux/vmalloc.h> |
25 | #include <linux/ftrace.h> | ||
25 | #include <linux/cpu.h> | 26 | #include <linux/cpu.h> |
26 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
27 | 28 | ||
@@ -823,13 +824,13 @@ void arch_send_call_function_single_ipi(int cpu) | |||
823 | &cpumask_of_cpu(cpu)); | 824 | &cpumask_of_cpu(cpu)); |
824 | } | 825 | } |
825 | 826 | ||
826 | void smp_call_function_client(int irq, struct pt_regs *regs) | 827 | void __irq_entry smp_call_function_client(int irq, struct pt_regs *regs) |
827 | { | 828 | { |
828 | clear_softint(1 << irq); | 829 | clear_softint(1 << irq); |
829 | generic_smp_call_function_interrupt(); | 830 | generic_smp_call_function_interrupt(); |
830 | } | 831 | } |
831 | 832 | ||
832 | void smp_call_function_single_client(int irq, struct pt_regs *regs) | 833 | void __irq_entry smp_call_function_single_client(int irq, struct pt_regs *regs) |
833 | { | 834 | { |
834 | clear_softint(1 << irq); | 835 | clear_softint(1 << irq); |
835 | generic_smp_call_function_single_interrupt(); | 836 | generic_smp_call_function_single_interrupt(); |
@@ -965,7 +966,7 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page) | |||
965 | put_cpu(); | 966 | put_cpu(); |
966 | } | 967 | } |
967 | 968 | ||
968 | void smp_new_mmu_context_version_client(int irq, struct pt_regs *regs) | 969 | void __irq_entry smp_new_mmu_context_version_client(int irq, struct pt_regs *regs) |
969 | { | 970 | { |
970 | struct mm_struct *mm; | 971 | struct mm_struct *mm; |
971 | unsigned long flags; | 972 | unsigned long flags; |
@@ -1149,7 +1150,7 @@ void smp_release(void) | |||
1149 | */ | 1150 | */ |
1150 | extern void prom_world(int); | 1151 | extern void prom_world(int); |
1151 | 1152 | ||
1152 | void smp_penguin_jailcell(int irq, struct pt_regs *regs) | 1153 | void __irq_entry smp_penguin_jailcell(int irq, struct pt_regs *regs) |
1153 | { | 1154 | { |
1154 | clear_softint(1 << irq); | 1155 | clear_softint(1 << irq); |
1155 | 1156 | ||
@@ -1365,7 +1366,7 @@ void smp_send_reschedule(int cpu) | |||
1365 | &cpumask_of_cpu(cpu)); | 1366 | &cpumask_of_cpu(cpu)); |
1366 | } | 1367 | } |
1367 | 1368 | ||
1368 | void smp_receive_signal_client(int irq, struct pt_regs *regs) | 1369 | void __irq_entry smp_receive_signal_client(int irq, struct pt_regs *regs) |
1369 | { | 1370 | { |
1370 | clear_softint(1 << irq); | 1371 | clear_softint(1 << irq); |
1371 | } | 1372 | } |
diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c index 67e165102885..c7bbe6cf7b85 100644 --- a/arch/sparc/kernel/time_64.c +++ b/arch/sparc/kernel/time_64.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/clocksource.h> | 35 | #include <linux/clocksource.h> |
36 | #include <linux/of_device.h> | 36 | #include <linux/of_device.h> |
37 | #include <linux/platform_device.h> | 37 | #include <linux/platform_device.h> |
38 | #include <linux/ftrace.h> | ||
38 | 39 | ||
39 | #include <asm/oplib.h> | 40 | #include <asm/oplib.h> |
40 | #include <asm/timer.h> | 41 | #include <asm/timer.h> |
@@ -717,7 +718,7 @@ static struct clock_event_device sparc64_clockevent = { | |||
717 | }; | 718 | }; |
718 | static DEFINE_PER_CPU(struct clock_event_device, sparc64_events); | 719 | static DEFINE_PER_CPU(struct clock_event_device, sparc64_events); |
719 | 720 | ||
720 | void timer_interrupt(int irq, struct pt_regs *regs) | 721 | void __irq_entry timer_interrupt(int irq, struct pt_regs *regs) |
721 | { | 722 | { |
722 | struct pt_regs *old_regs = set_irq_regs(regs); | 723 | struct pt_regs *old_regs = set_irq_regs(regs); |
723 | unsigned long tick_mask = tick_ops->softint_mask; | 724 | unsigned long tick_mask = tick_ops->softint_mask; |
@@ -728,6 +729,7 @@ void timer_interrupt(int irq, struct pt_regs *regs) | |||
728 | 729 | ||
729 | irq_enter(); | 730 | irq_enter(); |
730 | 731 | ||
732 | local_cpu_data().irq0_irqs++; | ||
731 | kstat_incr_irqs_this_cpu(0, irq_to_desc(0)); | 733 | kstat_incr_irqs_this_cpu(0, irq_to_desc(0)); |
732 | 734 | ||
733 | if (unlikely(!evt->event_handler)) { | 735 | if (unlikely(!evt->event_handler)) { |
diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c index 837dfc2390d6..9da57f032983 100644 --- a/arch/sparc/kernel/traps_64.c +++ b/arch/sparc/kernel/traps_64.c | |||
@@ -2203,27 +2203,6 @@ void dump_stack(void) | |||
2203 | 2203 | ||
2204 | EXPORT_SYMBOL(dump_stack); | 2204 | EXPORT_SYMBOL(dump_stack); |
2205 | 2205 | ||
2206 | static inline int is_kernel_stack(struct task_struct *task, | ||
2207 | struct reg_window *rw) | ||
2208 | { | ||
2209 | unsigned long rw_addr = (unsigned long) rw; | ||
2210 | unsigned long thread_base, thread_end; | ||
2211 | |||
2212 | if (rw_addr < PAGE_OFFSET) { | ||
2213 | if (task != &init_task) | ||
2214 | return 0; | ||
2215 | } | ||
2216 | |||
2217 | thread_base = (unsigned long) task_stack_page(task); | ||
2218 | thread_end = thread_base + sizeof(union thread_union); | ||
2219 | if (rw_addr >= thread_base && | ||
2220 | rw_addr < thread_end && | ||
2221 | !(rw_addr & 0x7UL)) | ||
2222 | return 1; | ||
2223 | |||
2224 | return 0; | ||
2225 | } | ||
2226 | |||
2227 | static inline struct reg_window *kernel_stack_up(struct reg_window *rw) | 2206 | static inline struct reg_window *kernel_stack_up(struct reg_window *rw) |
2228 | { | 2207 | { |
2229 | unsigned long fp = rw->ins[6]; | 2208 | unsigned long fp = rw->ins[6]; |
@@ -2252,6 +2231,7 @@ void die_if_kernel(char *str, struct pt_regs *regs) | |||
2252 | show_regs(regs); | 2231 | show_regs(regs); |
2253 | add_taint(TAINT_DIE); | 2232 | add_taint(TAINT_DIE); |
2254 | if (regs->tstate & TSTATE_PRIV) { | 2233 | if (regs->tstate & TSTATE_PRIV) { |
2234 | struct thread_info *tp = current_thread_info(); | ||
2255 | struct reg_window *rw = (struct reg_window *) | 2235 | struct reg_window *rw = (struct reg_window *) |
2256 | (regs->u_regs[UREG_FP] + STACK_BIAS); | 2236 | (regs->u_regs[UREG_FP] + STACK_BIAS); |
2257 | 2237 | ||
@@ -2259,8 +2239,8 @@ void die_if_kernel(char *str, struct pt_regs *regs) | |||
2259 | * find some badly aligned kernel stack. | 2239 | * find some badly aligned kernel stack. |
2260 | */ | 2240 | */ |
2261 | while (rw && | 2241 | while (rw && |
2262 | count++ < 30&& | 2242 | count++ < 30 && |
2263 | is_kernel_stack(current, rw)) { | 2243 | kstack_valid(tp, (unsigned long) rw)) { |
2264 | printk("Caller[%016lx]: %pS\n", rw->ins[7], | 2244 | printk("Caller[%016lx]: %pS\n", rw->ins[7], |
2265 | (void *) rw->ins[7]); | 2245 | (void *) rw->ins[7]); |
2266 | 2246 | ||
diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S index 4e5992593967..0c1e6783657f 100644 --- a/arch/sparc/kernel/vmlinux.lds.S +++ b/arch/sparc/kernel/vmlinux.lds.S | |||
@@ -46,11 +46,16 @@ SECTIONS | |||
46 | SCHED_TEXT | 46 | SCHED_TEXT |
47 | LOCK_TEXT | 47 | LOCK_TEXT |
48 | KPROBES_TEXT | 48 | KPROBES_TEXT |
49 | IRQENTRY_TEXT | ||
49 | *(.gnu.warning) | 50 | *(.gnu.warning) |
50 | } = 0 | 51 | } = 0 |
51 | _etext = .; | 52 | _etext = .; |
52 | 53 | ||
53 | RO_DATA(PAGE_SIZE) | 54 | RO_DATA(PAGE_SIZE) |
55 | |||
56 | /* Start of data section */ | ||
57 | _sdata = .; | ||
58 | |||
54 | .data1 : { | 59 | .data1 : { |
55 | *(.data1) | 60 | *(.data1) |
56 | } | 61 | } |
diff --git a/arch/sparc/lib/mcount.S b/arch/sparc/lib/mcount.S index 24b8b12deed2..3753e3c6e176 100644 --- a/arch/sparc/lib/mcount.S +++ b/arch/sparc/lib/mcount.S | |||
@@ -7,26 +7,11 @@ | |||
7 | 7 | ||
8 | #include <linux/linkage.h> | 8 | #include <linux/linkage.h> |
9 | 9 | ||
10 | #include <asm/ptrace.h> | ||
11 | #include <asm/thread_info.h> | ||
12 | |||
13 | /* | 10 | /* |
14 | * This is the main variant and is called by C code. GCC's -pg option | 11 | * This is the main variant and is called by C code. GCC's -pg option |
15 | * automatically instruments every C function with a call to this. | 12 | * automatically instruments every C function with a call to this. |
16 | */ | 13 | */ |
17 | 14 | ||
18 | #ifdef CONFIG_STACK_DEBUG | ||
19 | |||
20 | #define OVSTACKSIZE 4096 /* lets hope this is enough */ | ||
21 | |||
22 | .data | ||
23 | .align 8 | ||
24 | panicstring: | ||
25 | .asciz "Stack overflow\n" | ||
26 | .align 8 | ||
27 | ovstack: | ||
28 | .skip OVSTACKSIZE | ||
29 | #endif | ||
30 | .text | 15 | .text |
31 | .align 32 | 16 | .align 32 |
32 | .globl _mcount | 17 | .globl _mcount |
@@ -35,84 +20,48 @@ ovstack: | |||
35 | .type mcount,#function | 20 | .type mcount,#function |
36 | _mcount: | 21 | _mcount: |
37 | mcount: | 22 | mcount: |
38 | #ifdef CONFIG_STACK_DEBUG | ||
39 | /* | ||
40 | * Check whether %sp is dangerously low. | ||
41 | */ | ||
42 | ldub [%g6 + TI_FPDEPTH], %g1 | ||
43 | srl %g1, 1, %g3 | ||
44 | add %g3, 1, %g3 | ||
45 | sllx %g3, 8, %g3 ! each fpregs frame is 256b | ||
46 | add %g3, 192, %g3 | ||
47 | add %g6, %g3, %g3 ! where does task_struct+frame end? | ||
48 | sub %g3, STACK_BIAS, %g3 | ||
49 | cmp %sp, %g3 | ||
50 | bg,pt %xcc, 1f | ||
51 | nop | ||
52 | lduh [%g6 + TI_CPU], %g1 | ||
53 | sethi %hi(hardirq_stack), %g3 | ||
54 | or %g3, %lo(hardirq_stack), %g3 | ||
55 | sllx %g1, 3, %g1 | ||
56 | ldx [%g3 + %g1], %g7 | ||
57 | sub %g7, STACK_BIAS, %g7 | ||
58 | cmp %sp, %g7 | ||
59 | bleu,pt %xcc, 2f | ||
60 | sethi %hi(THREAD_SIZE), %g3 | ||
61 | add %g7, %g3, %g7 | ||
62 | cmp %sp, %g7 | ||
63 | blu,pn %xcc, 1f | ||
64 | 2: sethi %hi(softirq_stack), %g3 | ||
65 | or %g3, %lo(softirq_stack), %g3 | ||
66 | ldx [%g3 + %g1], %g7 | ||
67 | sub %g7, STACK_BIAS, %g7 | ||
68 | cmp %sp, %g7 | ||
69 | bleu,pt %xcc, 3f | ||
70 | sethi %hi(THREAD_SIZE), %g3 | ||
71 | add %g7, %g3, %g7 | ||
72 | cmp %sp, %g7 | ||
73 | blu,pn %xcc, 1f | ||
74 | nop | ||
75 | /* If we are already on ovstack, don't hop onto it | ||
76 | * again, we are already trying to output the stack overflow | ||
77 | * message. | ||
78 | */ | ||
79 | 3: sethi %hi(ovstack), %g7 ! cant move to panic stack fast enough | ||
80 | or %g7, %lo(ovstack), %g7 | ||
81 | add %g7, OVSTACKSIZE, %g3 | ||
82 | sub %g3, STACK_BIAS + 192, %g3 | ||
83 | sub %g7, STACK_BIAS, %g7 | ||
84 | cmp %sp, %g7 | ||
85 | blu,pn %xcc, 2f | ||
86 | cmp %sp, %g3 | ||
87 | bleu,pn %xcc, 1f | ||
88 | nop | ||
89 | 2: mov %g3, %sp | ||
90 | sethi %hi(panicstring), %g3 | ||
91 | call prom_printf | ||
92 | or %g3, %lo(panicstring), %o0 | ||
93 | call prom_halt | ||
94 | nop | ||
95 | 1: | ||
96 | #endif | ||
97 | #ifdef CONFIG_FUNCTION_TRACER | 23 | #ifdef CONFIG_FUNCTION_TRACER |
98 | #ifdef CONFIG_DYNAMIC_FTRACE | 24 | #ifdef CONFIG_DYNAMIC_FTRACE |
99 | mov %o7, %o0 | 25 | /* Do nothing, the retl/nop below is all we need. */ |
100 | .globl mcount_call | ||
101 | mcount_call: | ||
102 | call ftrace_stub | ||
103 | mov %o0, %o7 | ||
104 | #else | 26 | #else |
105 | sethi %hi(ftrace_trace_function), %g1 | 27 | sethi %hi(function_trace_stop), %g1 |
28 | lduw [%g1 + %lo(function_trace_stop)], %g2 | ||
29 | brnz,pn %g2, 2f | ||
30 | sethi %hi(ftrace_trace_function), %g1 | ||
106 | sethi %hi(ftrace_stub), %g2 | 31 | sethi %hi(ftrace_stub), %g2 |
107 | ldx [%g1 + %lo(ftrace_trace_function)], %g1 | 32 | ldx [%g1 + %lo(ftrace_trace_function)], %g1 |
108 | or %g2, %lo(ftrace_stub), %g2 | 33 | or %g2, %lo(ftrace_stub), %g2 |
109 | cmp %g1, %g2 | 34 | cmp %g1, %g2 |
110 | be,pn %icc, 1f | 35 | be,pn %icc, 1f |
111 | mov %i7, %o1 | 36 | mov %i7, %g3 |
112 | jmpl %g1, %g0 | 37 | save %sp, -128, %sp |
113 | mov %o7, %o0 | 38 | mov %g3, %o1 |
39 | jmpl %g1, %o7 | ||
40 | mov %i7, %o0 | ||
41 | ret | ||
42 | restore | ||
114 | /* not reached */ | 43 | /* not reached */ |
115 | 1: | 44 | 1: |
45 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
46 | sethi %hi(ftrace_graph_return), %g1 | ||
47 | ldx [%g1 + %lo(ftrace_graph_return)], %g3 | ||
48 | cmp %g2, %g3 | ||
49 | bne,pn %xcc, 5f | ||
50 | sethi %hi(ftrace_graph_entry_stub), %g2 | ||
51 | sethi %hi(ftrace_graph_entry), %g1 | ||
52 | or %g2, %lo(ftrace_graph_entry_stub), %g2 | ||
53 | ldx [%g1 + %lo(ftrace_graph_entry)], %g1 | ||
54 | cmp %g1, %g2 | ||
55 | be,pt %xcc, 2f | ||
56 | nop | ||
57 | 5: mov %i7, %g2 | ||
58 | mov %fp, %g3 | ||
59 | save %sp, -128, %sp | ||
60 | mov %g2, %l0 | ||
61 | ba,pt %xcc, ftrace_graph_caller | ||
62 | mov %g3, %l1 | ||
63 | #endif | ||
64 | 2: | ||
116 | #endif | 65 | #endif |
117 | #endif | 66 | #endif |
118 | retl | 67 | retl |
@@ -131,14 +80,50 @@ ftrace_stub: | |||
131 | .globl ftrace_caller | 80 | .globl ftrace_caller |
132 | .type ftrace_caller,#function | 81 | .type ftrace_caller,#function |
133 | ftrace_caller: | 82 | ftrace_caller: |
134 | mov %i7, %o1 | 83 | sethi %hi(function_trace_stop), %g1 |
135 | mov %o7, %o0 | 84 | mov %i7, %g2 |
85 | lduw [%g1 + %lo(function_trace_stop)], %g1 | ||
86 | brnz,pn %g1, ftrace_stub | ||
87 | mov %fp, %g3 | ||
88 | save %sp, -128, %sp | ||
89 | mov %g2, %o1 | ||
90 | mov %g2, %l0 | ||
91 | mov %g3, %l1 | ||
136 | .globl ftrace_call | 92 | .globl ftrace_call |
137 | ftrace_call: | 93 | ftrace_call: |
138 | call ftrace_stub | 94 | call ftrace_stub |
139 | mov %o0, %o7 | 95 | mov %i7, %o0 |
140 | retl | 96 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
97 | .globl ftrace_graph_call | ||
98 | ftrace_graph_call: | ||
99 | call ftrace_stub | ||
141 | nop | 100 | nop |
101 | #endif | ||
102 | ret | ||
103 | restore | ||
104 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
105 | .size ftrace_graph_call,.-ftrace_graph_call | ||
106 | #endif | ||
107 | .size ftrace_call,.-ftrace_call | ||
142 | .size ftrace_caller,.-ftrace_caller | 108 | .size ftrace_caller,.-ftrace_caller |
143 | #endif | 109 | #endif |
144 | #endif | 110 | #endif |
111 | |||
112 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
113 | ENTRY(ftrace_graph_caller) | ||
114 | mov %l0, %o0 | ||
115 | mov %i7, %o1 | ||
116 | call prepare_ftrace_return | ||
117 | mov %l1, %o2 | ||
118 | ret | ||
119 | restore %o0, -8, %i7 | ||
120 | END(ftrace_graph_caller) | ||
121 | |||
122 | ENTRY(return_to_handler) | ||
123 | save %sp, -128, %sp | ||
124 | call ftrace_return_to_handler | ||
125 | mov %fp, %o0 | ||
126 | jmpl %o0 + 8, %g0 | ||
127 | restore | ||
128 | END(return_to_handler) | ||
129 | #endif | ||
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index ff017108700d..935248bdbc47 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
@@ -356,7 +356,7 @@ config SLUB_STATS | |||
356 | config DEBUG_KMEMLEAK | 356 | config DEBUG_KMEMLEAK |
357 | bool "Kernel memory leak detector" | 357 | bool "Kernel memory leak detector" |
358 | depends on DEBUG_KERNEL && EXPERIMENTAL && !MEMORY_HOTPLUG && \ | 358 | depends on DEBUG_KERNEL && EXPERIMENTAL && !MEMORY_HOTPLUG && \ |
359 | (X86 || ARM || PPC || S390 || SUPERH || MICROBLAZE) | 359 | (X86 || ARM || PPC || S390 || SPARC64 || SUPERH || MICROBLAZE) |
360 | 360 | ||
361 | select DEBUG_FS if SYSFS | 361 | select DEBUG_FS if SYSFS |
362 | select STACKTRACE if STACKTRACE_SUPPORT | 362 | select STACKTRACE if STACKTRACE_SUPPORT |