diff options
Diffstat (limited to 'arch/sparc64/kernel/irq.c')
-rw-r--r-- | arch/sparc64/kernel/irq.c | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index ba43d85e8dde..9b6689d9d570 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c | |||
@@ -682,10 +682,32 @@ void ack_bad_irq(unsigned int virt_irq) | |||
682 | ino, virt_irq); | 682 | ino, virt_irq); |
683 | } | 683 | } |
684 | 684 | ||
685 | void *hardirq_stack[NR_CPUS]; | ||
686 | void *softirq_stack[NR_CPUS]; | ||
687 | |||
688 | static __attribute__((always_inline)) void *set_hardirq_stack(void) | ||
689 | { | ||
690 | void *orig_sp, *sp = hardirq_stack[smp_processor_id()]; | ||
691 | |||
692 | __asm__ __volatile__("mov %%sp, %0" : "=r" (orig_sp)); | ||
693 | if (orig_sp < sp || | ||
694 | orig_sp > (sp + THREAD_SIZE)) { | ||
695 | sp += THREAD_SIZE - 192 - STACK_BIAS; | ||
696 | __asm__ __volatile__("mov %0, %%sp" : : "r" (sp)); | ||
697 | } | ||
698 | |||
699 | return orig_sp; | ||
700 | } | ||
701 | static __attribute__((always_inline)) void restore_hardirq_stack(void *orig_sp) | ||
702 | { | ||
703 | __asm__ __volatile__("mov %0, %%sp" : : "r" (orig_sp)); | ||
704 | } | ||
705 | |||
685 | void handler_irq(int irq, struct pt_regs *regs) | 706 | void handler_irq(int irq, struct pt_regs *regs) |
686 | { | 707 | { |
687 | unsigned long pstate, bucket_pa; | 708 | unsigned long pstate, bucket_pa; |
688 | struct pt_regs *old_regs; | 709 | struct pt_regs *old_regs; |
710 | void *orig_sp; | ||
689 | 711 | ||
690 | clear_softint(1 << irq); | 712 | clear_softint(1 << irq); |
691 | 713 | ||
@@ -703,6 +725,8 @@ void handler_irq(int irq, struct pt_regs *regs) | |||
703 | "i" (PSTATE_IE) | 725 | "i" (PSTATE_IE) |
704 | : "memory"); | 726 | : "memory"); |
705 | 727 | ||
728 | orig_sp = set_hardirq_stack(); | ||
729 | |||
706 | while (bucket_pa) { | 730 | while (bucket_pa) { |
707 | struct irq_desc *desc; | 731 | struct irq_desc *desc; |
708 | unsigned long next_pa; | 732 | unsigned long next_pa; |
@@ -719,10 +743,38 @@ void handler_irq(int irq, struct pt_regs *regs) | |||
719 | bucket_pa = next_pa; | 743 | bucket_pa = next_pa; |
720 | } | 744 | } |
721 | 745 | ||
746 | restore_hardirq_stack(orig_sp); | ||
747 | |||
722 | irq_exit(); | 748 | irq_exit(); |
723 | set_irq_regs(old_regs); | 749 | set_irq_regs(old_regs); |
724 | } | 750 | } |
725 | 751 | ||
752 | void do_softirq(void) | ||
753 | { | ||
754 | unsigned long flags; | ||
755 | |||
756 | if (in_interrupt()) | ||
757 | return; | ||
758 | |||
759 | local_irq_save(flags); | ||
760 | |||
761 | if (local_softirq_pending()) { | ||
762 | void *orig_sp, *sp = softirq_stack[smp_processor_id()]; | ||
763 | |||
764 | sp += THREAD_SIZE - 192 - STACK_BIAS; | ||
765 | |||
766 | __asm__ __volatile__("mov %%sp, %0\n\t" | ||
767 | "mov %1, %%sp" | ||
768 | : "=&r" (orig_sp) | ||
769 | : "r" (sp)); | ||
770 | __do_softirq(); | ||
771 | __asm__ __volatile__("mov %0, %%sp" | ||
772 | : : "r" (orig_sp)); | ||
773 | } | ||
774 | |||
775 | local_irq_restore(flags); | ||
776 | } | ||
777 | |||
726 | #ifdef CONFIG_HOTPLUG_CPU | 778 | #ifdef CONFIG_HOTPLUG_CPU |
727 | void fixup_irqs(void) | 779 | void fixup_irqs(void) |
728 | { | 780 | { |