diff options
Diffstat (limited to 'arch/sparc')
| -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 | 23 | ||||
| -rw-r--r-- | arch/sparc/include/asm/thread_info_64.h | 2 | ||||
| -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 | 31 | ||||
| -rw-r--r-- | arch/sparc/kernel/kgdb_64.c | 3 | ||||
| -rw-r--r-- | arch/sparc/kernel/kstack.h | 19 | ||||
| -rw-r--r-- | arch/sparc/kernel/nmi.c | 10 | ||||
| -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/rtrap_64.S | 12 | ||||
| -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/unaligned_64.c | 6 | ||||
| -rw-r--r-- | arch/sparc/kernel/vmlinux.lds.S | 5 | ||||
| -rw-r--r-- | arch/sparc/lib/mcount.S | 159 |
20 files changed, 248 insertions, 157 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..bfa1ea45b4cd 100644 --- a/arch/sparc/include/asm/irqflags_64.h +++ b/arch/sparc/include/asm/irqflags_64.h | |||
| @@ -76,9 +76,26 @@ 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 | * The only values we ever program into the %pil are 0, | ||
| 85 | * PIL_NORMAL_MAX and PIL_NMI. | ||
| 86 | * | ||
| 87 | * Since PIL_NMI is the largest %pil value and all bits are | ||
| 88 | * set in it (0xf), it doesn't matter what PIL_NORMAL_MAX | ||
| 89 | * actually is. | ||
| 90 | */ | ||
| 91 | __asm__ __volatile__( | ||
| 92 | "rdpr %%pil, %0\n\t" | ||
| 93 | "or %0, %2, %1\n\t" | ||
| 94 | "wrpr %1, 0x0, %%pil" | ||
| 95 | : "=r" (flags), "=r" (tmp) | ||
| 96 | : "i" (PIL_NORMAL_MAX) | ||
| 97 | : "memory" | ||
| 98 | ); | ||
| 82 | 99 | ||
| 83 | return flags; | 100 | return flags; |
| 84 | } | 101 | } |
diff --git a/arch/sparc/include/asm/thread_info_64.h b/arch/sparc/include/asm/thread_info_64.h index 9e2d9447f2ad..4827a3aeac7f 100644 --- a/arch/sparc/include/asm/thread_info_64.h +++ b/arch/sparc/include/asm/thread_info_64.h | |||
| @@ -111,7 +111,7 @@ struct thread_info { | |||
| 111 | #define THREAD_SHIFT PAGE_SHIFT | 111 | #define THREAD_SHIFT PAGE_SHIFT |
| 112 | #endif /* PAGE_SHIFT == 13 */ | 112 | #endif /* PAGE_SHIFT == 13 */ |
| 113 | 113 | ||
| 114 | #define PREEMPT_ACTIVE 0x4000000 | 114 | #define PREEMPT_ACTIVE 0x10000000 |
| 115 | 115 | ||
| 116 | /* | 116 | /* |
| 117 | * macros/functions for gaining access to the thread information structure | 117 | * macros/functions for gaining access to the thread information structure |
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..830d70a3e20b 100644 --- a/arch/sparc/kernel/irq_64.c +++ b/arch/sparc/kernel/irq_64.c | |||
| @@ -20,7 +20,9 @@ | |||
| 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> |
| 25 | #include <linux/kmemleak.h> | ||
| 24 | 26 | ||
| 25 | #include <asm/ptrace.h> | 27 | #include <asm/ptrace.h> |
| 26 | #include <asm/processor.h> | 28 | #include <asm/processor.h> |
| @@ -45,6 +47,7 @@ | |||
| 45 | 47 | ||
| 46 | #include "entry.h" | 48 | #include "entry.h" |
| 47 | #include "cpumap.h" | 49 | #include "cpumap.h" |
| 50 | #include "kstack.h" | ||
| 48 | 51 | ||
| 49 | #define NUM_IVECS (IMAP_INR + 1) | 52 | #define NUM_IVECS (IMAP_INR + 1) |
| 50 | 53 | ||
| @@ -647,6 +650,14 @@ unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino) | |||
| 647 | bucket = kzalloc(sizeof(struct ino_bucket), GFP_ATOMIC); | 650 | bucket = kzalloc(sizeof(struct ino_bucket), GFP_ATOMIC); |
| 648 | if (unlikely(!bucket)) | 651 | if (unlikely(!bucket)) |
| 649 | return 0; | 652 | return 0; |
| 653 | |||
| 654 | /* The only reference we store to the IRQ bucket is | ||
| 655 | * by physical address which kmemleak can't see, tell | ||
| 656 | * it that this object explicitly is not a leak and | ||
| 657 | * should be scanned. | ||
| 658 | */ | ||
| 659 | kmemleak_not_leak(bucket); | ||
| 660 | |||
| 650 | __flush_dcache_range((unsigned long) bucket, | 661 | __flush_dcache_range((unsigned long) bucket, |
| 651 | ((unsigned long) bucket + | 662 | ((unsigned long) bucket + |
| 652 | sizeof(struct ino_bucket))); | 663 | sizeof(struct ino_bucket))); |
| @@ -703,25 +714,7 @@ void ack_bad_irq(unsigned int virt_irq) | |||
| 703 | void *hardirq_stack[NR_CPUS]; | 714 | void *hardirq_stack[NR_CPUS]; |
| 704 | void *softirq_stack[NR_CPUS]; | 715 | void *softirq_stack[NR_CPUS]; |
| 705 | 716 | ||
| 706 | static __attribute__((always_inline)) void *set_hardirq_stack(void) | 717 | void __irq_entry handler_irq(int irq, struct pt_regs *regs) |
| 707 | { | ||
| 708 | void *orig_sp, *sp = hardirq_stack[smp_processor_id()]; | ||
| 709 | |||
| 710 | __asm__ __volatile__("mov %%sp, %0" : "=r" (orig_sp)); | ||
| 711 | if (orig_sp < sp || | ||
| 712 | orig_sp > (sp + THREAD_SIZE)) { | ||
| 713 | sp += THREAD_SIZE - 192 - STACK_BIAS; | ||
| 714 | __asm__ __volatile__("mov %0, %%sp" : : "r" (sp)); | ||
| 715 | } | ||
| 716 | |||
| 717 | return orig_sp; | ||
| 718 | } | ||
| 719 | static __attribute__((always_inline)) void restore_hardirq_stack(void *orig_sp) | ||
| 720 | { | ||
| 721 | __asm__ __volatile__("mov %0, %%sp" : : "r" (orig_sp)); | ||
| 722 | } | ||
| 723 | |||
| 724 | void handler_irq(int irq, struct pt_regs *regs) | ||
| 725 | { | 718 | { |
| 726 | unsigned long pstate, bucket_pa; | 719 | unsigned long pstate, bucket_pa; |
| 727 | struct pt_regs *old_regs; | 720 | 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/kstack.h b/arch/sparc/kernel/kstack.h index 5247283d1c03..53dfb92e09fb 100644 --- a/arch/sparc/kernel/kstack.h +++ b/arch/sparc/kernel/kstack.h | |||
| @@ -61,4 +61,23 @@ check_magic: | |||
| 61 | 61 | ||
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | static inline __attribute__((always_inline)) void *set_hardirq_stack(void) | ||
| 65 | { | ||
| 66 | void *orig_sp, *sp = hardirq_stack[smp_processor_id()]; | ||
| 67 | |||
| 68 | __asm__ __volatile__("mov %%sp, %0" : "=r" (orig_sp)); | ||
| 69 | if (orig_sp < sp || | ||
| 70 | orig_sp > (sp + THREAD_SIZE)) { | ||
| 71 | sp += THREAD_SIZE - 192 - STACK_BIAS; | ||
| 72 | __asm__ __volatile__("mov %0, %%sp" : : "r" (sp)); | ||
| 73 | } | ||
| 74 | |||
| 75 | return orig_sp; | ||
| 76 | } | ||
| 77 | |||
| 78 | static inline __attribute__((always_inline)) void restore_hardirq_stack(void *orig_sp) | ||
| 79 | { | ||
| 80 | __asm__ __volatile__("mov %0, %%sp" : : "r" (orig_sp)); | ||
| 81 | } | ||
| 82 | |||
| 64 | #endif /* _KSTACK_H */ | 83 | #endif /* _KSTACK_H */ |
diff --git a/arch/sparc/kernel/nmi.c b/arch/sparc/kernel/nmi.c index b287b62c7ea3..a4bd7ba74c89 100644 --- a/arch/sparc/kernel/nmi.c +++ b/arch/sparc/kernel/nmi.c | |||
| @@ -23,6 +23,8 @@ | |||
| 23 | #include <asm/ptrace.h> | 23 | #include <asm/ptrace.h> |
| 24 | #include <asm/pcr.h> | 24 | #include <asm/pcr.h> |
| 25 | 25 | ||
| 26 | #include "kstack.h" | ||
| 27 | |||
| 26 | /* We don't have a real NMI on sparc64, but we can fake one | 28 | /* We don't have a real NMI on sparc64, but we can fake one |
| 27 | * up using profiling counter overflow interrupts and interrupt | 29 | * up using profiling counter overflow interrupts and interrupt |
| 28 | * levels. | 30 | * levels. |
| @@ -92,7 +94,7 @@ 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) | 94 | notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) |
| 93 | { | 95 | { |
| 94 | unsigned int sum, touched = 0; | 96 | unsigned int sum, touched = 0; |
| 95 | int cpu = smp_processor_id(); | 97 | void *orig_sp; |
| 96 | 98 | ||
| 97 | clear_softint(1 << irq); | 99 | clear_softint(1 << irq); |
| 98 | 100 | ||
| @@ -100,13 +102,15 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) | |||
| 100 | 102 | ||
| 101 | nmi_enter(); | 103 | nmi_enter(); |
| 102 | 104 | ||
| 105 | orig_sp = set_hardirq_stack(); | ||
| 106 | |||
| 103 | if (notify_die(DIE_NMI, "nmi", regs, 0, | 107 | if (notify_die(DIE_NMI, "nmi", regs, 0, |
| 104 | pt_regs_trap_type(regs), SIGINT) == NOTIFY_STOP) | 108 | pt_regs_trap_type(regs), SIGINT) == NOTIFY_STOP) |
| 105 | touched = 1; | 109 | touched = 1; |
| 106 | else | 110 | else |
| 107 | pcr_ops->write(PCR_PIC_PRIV); | 111 | pcr_ops->write(PCR_PIC_PRIV); |
| 108 | 112 | ||
| 109 | sum = kstat_irqs_cpu(0, cpu); | 113 | sum = local_cpu_data().irq0_irqs; |
| 110 | if (__get_cpu_var(nmi_touch)) { | 114 | if (__get_cpu_var(nmi_touch)) { |
| 111 | __get_cpu_var(nmi_touch) = 0; | 115 | __get_cpu_var(nmi_touch) = 0; |
| 112 | touched = 1; | 116 | touched = 1; |
| @@ -125,6 +129,8 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) | |||
| 125 | pcr_ops->write(pcr_enable); | 129 | pcr_ops->write(pcr_enable); |
| 126 | } | 130 | } |
| 127 | 131 | ||
| 132 | restore_hardirq_stack(orig_sp); | ||
| 133 | |||
| 128 | nmi_exit(); | 134 | nmi_exit(); |
| 129 | } | 135 | } |
| 130 | 136 | ||
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/rtrap_64.S b/arch/sparc/kernel/rtrap_64.S index 83f1873c6c13..090b9e9ad5e3 100644 --- a/arch/sparc/kernel/rtrap_64.S +++ b/arch/sparc/kernel/rtrap_64.S | |||
| @@ -130,7 +130,17 @@ rtrap_xcall: | |||
| 130 | nop | 130 | nop |
| 131 | call trace_hardirqs_on | 131 | call trace_hardirqs_on |
| 132 | nop | 132 | nop |
| 133 | wrpr %l4, %pil | 133 | /* Do not actually set the %pil here. We will do that |
| 134 | * below after we clear PSTATE_IE in the %pstate register. | ||
| 135 | * If we re-enable interrupts here, we can recurse down | ||
| 136 | * the hardirq stack potentially endlessly, causing a | ||
| 137 | * stack overflow. | ||
| 138 | * | ||
| 139 | * It is tempting to put this test and trace_hardirqs_on | ||
| 140 | * call at the 'rt_continue' label, but that will not work | ||
| 141 | * as that path hits unconditionally and we do not want to | ||
| 142 | * execute this in NMI return paths, for example. | ||
| 143 | */ | ||
| 134 | #endif | 144 | #endif |
| 135 | rtrap_no_irq_enable: | 145 | rtrap_no_irq_enable: |
| 136 | andcc %l1, TSTATE_PRIV, %l3 | 146 | andcc %l1, TSTATE_PRIV, %l3 |
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/unaligned_64.c b/arch/sparc/kernel/unaligned_64.c index ebce43018c49..c752c4c479bd 100644 --- a/arch/sparc/kernel/unaligned_64.c +++ b/arch/sparc/kernel/unaligned_64.c | |||
| @@ -50,7 +50,7 @@ static inline enum direction decode_direction(unsigned int insn) | |||
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | /* 16 = double-word, 8 = extra-word, 4 = word, 2 = half-word */ | 52 | /* 16 = double-word, 8 = extra-word, 4 = word, 2 = half-word */ |
| 53 | static inline int decode_access_size(unsigned int insn) | 53 | static inline int decode_access_size(struct pt_regs *regs, unsigned int insn) |
| 54 | { | 54 | { |
| 55 | unsigned int tmp; | 55 | unsigned int tmp; |
| 56 | 56 | ||
| @@ -66,7 +66,7 @@ static inline int decode_access_size(unsigned int insn) | |||
| 66 | return 2; | 66 | return 2; |
| 67 | else { | 67 | else { |
| 68 | printk("Impossible unaligned trap. insn=%08x\n", insn); | 68 | printk("Impossible unaligned trap. insn=%08x\n", insn); |
| 69 | die_if_kernel("Byte sized unaligned access?!?!", current_thread_info()->kregs); | 69 | die_if_kernel("Byte sized unaligned access?!?!", regs); |
| 70 | 70 | ||
| 71 | /* GCC should never warn that control reaches the end | 71 | /* GCC should never warn that control reaches the end |
| 72 | * of this function without returning a value because | 72 | * of this function without returning a value because |
| @@ -286,7 +286,7 @@ static void log_unaligned(struct pt_regs *regs) | |||
| 286 | asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) | 286 | asmlinkage void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn) |
| 287 | { | 287 | { |
| 288 | enum direction dir = decode_direction(insn); | 288 | enum direction dir = decode_direction(insn); |
| 289 | int size = decode_access_size(insn); | 289 | int size = decode_access_size(regs, insn); |
| 290 | int orig_asi, asi; | 290 | int orig_asi, asi; |
| 291 | 291 | ||
| 292 | current_thread_info()->kern_una_regs = regs; | 292 | current_thread_info()->kern_una_regs = regs; |
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..3ad6cbdc2163 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, -176, %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, -176, %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, -176, %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, -176, %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 | ||
