diff options
| -rw-r--r-- | arch/sparc/kernel/irq_64.c | 19 | ||||
| -rw-r--r-- | arch/sparc/kernel/kstack.h | 19 | ||||
| -rw-r--r-- | arch/sparc/kernel/nmi.c | 7 |
3 files changed, 27 insertions, 18 deletions
diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c index 2b04c722cc3e..830d70a3e20b 100644 --- a/arch/sparc/kernel/irq_64.c +++ b/arch/sparc/kernel/irq_64.c | |||
| @@ -47,6 +47,7 @@ | |||
| 47 | 47 | ||
| 48 | #include "entry.h" | 48 | #include "entry.h" |
| 49 | #include "cpumap.h" | 49 | #include "cpumap.h" |
| 50 | #include "kstack.h" | ||
| 50 | 51 | ||
| 51 | #define NUM_IVECS (IMAP_INR + 1) | 52 | #define NUM_IVECS (IMAP_INR + 1) |
| 52 | 53 | ||
| @@ -713,24 +714,6 @@ void ack_bad_irq(unsigned int virt_irq) | |||
| 713 | void *hardirq_stack[NR_CPUS]; | 714 | void *hardirq_stack[NR_CPUS]; |
| 714 | void *softirq_stack[NR_CPUS]; | 715 | void *softirq_stack[NR_CPUS]; |
| 715 | 716 | ||
| 716 | static __attribute__((always_inline)) void *set_hardirq_stack(void) | ||
| 717 | { | ||
| 718 | void *orig_sp, *sp = hardirq_stack[smp_processor_id()]; | ||
| 719 | |||
| 720 | __asm__ __volatile__("mov %%sp, %0" : "=r" (orig_sp)); | ||
| 721 | if (orig_sp < sp || | ||
| 722 | orig_sp > (sp + THREAD_SIZE)) { | ||
| 723 | sp += THREAD_SIZE - 192 - STACK_BIAS; | ||
| 724 | __asm__ __volatile__("mov %0, %%sp" : : "r" (sp)); | ||
| 725 | } | ||
| 726 | |||
| 727 | return orig_sp; | ||
| 728 | } | ||
| 729 | static __attribute__((always_inline)) void restore_hardirq_stack(void *orig_sp) | ||
| 730 | { | ||
| 731 | __asm__ __volatile__("mov %0, %%sp" : : "r" (orig_sp)); | ||
| 732 | } | ||
| 733 | |||
| 734 | void __irq_entry handler_irq(int irq, struct pt_regs *regs) | 717 | void __irq_entry handler_irq(int irq, struct pt_regs *regs) |
| 735 | { | 718 | { |
| 736 | unsigned long pstate, bucket_pa; | 719 | unsigned long pstate, bucket_pa; |
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 75a3d1a25356..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,6 +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; |
| 97 | void *orig_sp; | ||
| 95 | 98 | ||
| 96 | clear_softint(1 << irq); | 99 | clear_softint(1 << irq); |
| 97 | 100 | ||
| @@ -99,6 +102,8 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) | |||
| 99 | 102 | ||
| 100 | nmi_enter(); | 103 | nmi_enter(); |
| 101 | 104 | ||
| 105 | orig_sp = set_hardirq_stack(); | ||
| 106 | |||
| 102 | if (notify_die(DIE_NMI, "nmi", regs, 0, | 107 | if (notify_die(DIE_NMI, "nmi", regs, 0, |
| 103 | pt_regs_trap_type(regs), SIGINT) == NOTIFY_STOP) | 108 | pt_regs_trap_type(regs), SIGINT) == NOTIFY_STOP) |
| 104 | touched = 1; | 109 | touched = 1; |
| @@ -124,6 +129,8 @@ notrace __kprobes void perfctr_irq(int irq, struct pt_regs *regs) | |||
| 124 | pcr_ops->write(pcr_enable); | 129 | pcr_ops->write(pcr_enable); |
| 125 | } | 130 | } |
| 126 | 131 | ||
| 132 | restore_hardirq_stack(orig_sp); | ||
| 133 | |||
| 127 | nmi_exit(); | 134 | nmi_exit(); |
| 128 | } | 135 | } |
| 129 | 136 | ||
