diff options
Diffstat (limited to 'arch/sparc64/kernel/irq.c')
-rw-r--r-- | arch/sparc64/kernel/irq.c | 41 |
1 files changed, 24 insertions, 17 deletions
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index 045ab27d4271..4db4dd576210 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c | |||
@@ -59,23 +59,20 @@ | |||
59 | * of the vectored interrupt trap handler(s) in entry.S and sun4v_ivec.S | 59 | * of the vectored interrupt trap handler(s) in entry.S and sun4v_ivec.S |
60 | */ | 60 | */ |
61 | struct ino_bucket { | 61 | struct ino_bucket { |
62 | /* Next handler in per-CPU IRQ worklist. We know that | 62 | /*0x00*/unsigned long irq_chain; |
63 | * bucket pointers have the high 32-bits clear, so to | ||
64 | * save space we only store the bits we need. | ||
65 | */ | ||
66 | /*0x00*/unsigned int irq_chain; | ||
67 | 63 | ||
68 | /* Virtual interrupt number assigned to this INO. */ | 64 | /* Virtual interrupt number assigned to this INO. */ |
69 | /*0x04*/unsigned int virt_irq; | 65 | /*0x08*/unsigned int virt_irq; |
66 | /*0x0c*/unsigned int __pad; | ||
70 | }; | 67 | }; |
71 | 68 | ||
72 | #define NUM_IVECS (IMAP_INR + 1) | 69 | #define NUM_IVECS (IMAP_INR + 1) |
73 | struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BYTES))); | 70 | struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BYTES))); |
74 | 71 | ||
75 | #define __irq_ino(irq) \ | 72 | #define __irq_ino(irq) \ |
76 | (((struct ino_bucket *)(unsigned long)(irq)) - &ivector_table[0]) | 73 | (((struct ino_bucket *)(irq)) - &ivector_table[0]) |
77 | #define __bucket(irq) ((struct ino_bucket *)(unsigned long)(irq)) | 74 | #define __bucket(irq) ((struct ino_bucket *)(irq)) |
78 | #define __irq(bucket) ((unsigned int)(unsigned long)(bucket)) | 75 | #define __irq(bucket) ((unsigned long)(bucket)) |
79 | 76 | ||
80 | /* This has to be in the main kernel image, it cannot be | 77 | /* This has to be in the main kernel image, it cannot be |
81 | * turned into per-cpu data. The reason is that the main | 78 | * turned into per-cpu data. The reason is that the main |
@@ -87,13 +84,13 @@ struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BY | |||
87 | #define irq_work(__cpu) &(trap_block[(__cpu)].irq_worklist) | 84 | #define irq_work(__cpu) &(trap_block[(__cpu)].irq_worklist) |
88 | 85 | ||
89 | static struct { | 86 | static struct { |
90 | unsigned int irq; | 87 | unsigned long irq; |
91 | unsigned int dev_handle; | 88 | unsigned int dev_handle; |
92 | unsigned int dev_ino; | 89 | unsigned int dev_ino; |
93 | } virt_to_real_irq_table[NR_IRQS]; | 90 | } virt_to_real_irq_table[NR_IRQS]; |
94 | static DEFINE_SPINLOCK(virt_irq_alloc_lock); | 91 | static DEFINE_SPINLOCK(virt_irq_alloc_lock); |
95 | 92 | ||
96 | unsigned char virt_irq_alloc(unsigned int real_irq) | 93 | unsigned char virt_irq_alloc(unsigned long real_irq) |
97 | { | 94 | { |
98 | unsigned long flags; | 95 | unsigned long flags; |
99 | unsigned char ent; | 96 | unsigned char ent; |
@@ -134,7 +131,7 @@ void virt_irq_free(unsigned int virt_irq) | |||
134 | } | 131 | } |
135 | #endif | 132 | #endif |
136 | 133 | ||
137 | static unsigned int virt_to_real_irq(unsigned char virt_irq) | 134 | static unsigned long virt_to_real_irq(unsigned char virt_irq) |
138 | { | 135 | { |
139 | return virt_to_real_irq_table[virt_irq].irq; | 136 | return virt_to_real_irq_table[virt_irq].irq; |
140 | } | 137 | } |
@@ -227,7 +224,7 @@ struct irq_handler_data { | |||
227 | 224 | ||
228 | static inline struct ino_bucket *virt_irq_to_bucket(unsigned int virt_irq) | 225 | static inline struct ino_bucket *virt_irq_to_bucket(unsigned int virt_irq) |
229 | { | 226 | { |
230 | unsigned int real_irq = virt_to_real_irq(virt_irq); | 227 | unsigned long real_irq = virt_to_real_irq(virt_irq); |
231 | struct ino_bucket *bucket = NULL; | 228 | struct ino_bucket *bucket = NULL; |
232 | 229 | ||
233 | if (likely(real_irq)) | 230 | if (likely(real_irq)) |
@@ -694,18 +691,28 @@ void handler_irq(int irq, struct pt_regs *regs) | |||
694 | { | 691 | { |
695 | struct ino_bucket *bucket; | 692 | struct ino_bucket *bucket; |
696 | struct pt_regs *old_regs; | 693 | struct pt_regs *old_regs; |
694 | unsigned long pstate; | ||
697 | 695 | ||
698 | clear_softint(1 << irq); | 696 | clear_softint(1 << irq); |
699 | 697 | ||
700 | old_regs = set_irq_regs(regs); | 698 | old_regs = set_irq_regs(regs); |
701 | irq_enter(); | 699 | irq_enter(); |
702 | 700 | ||
703 | /* Sliiiick... */ | 701 | /* Grab an atomic snapshot of the pending IVECs. */ |
704 | bucket = __bucket(xchg32(irq_work(smp_processor_id()), 0)); | 702 | __asm__ __volatile__("rdpr %%pstate, %0\n\t" |
703 | "wrpr %0, %3, %%pstate\n\t" | ||
704 | "ldx [%2], %1\n\t" | ||
705 | "stx %%g0, [%2]\n\t" | ||
706 | "wrpr %0, 0x0, %%pstate\n\t" | ||
707 | : "=&r" (pstate), "=&r" (bucket) | ||
708 | : "r" (irq_work(smp_processor_id())), | ||
709 | "i" (PSTATE_IE) | ||
710 | : "memory"); | ||
711 | |||
705 | while (bucket) { | 712 | while (bucket) { |
706 | struct ino_bucket *next = __bucket(bucket->irq_chain); | 713 | struct ino_bucket *next = __bucket(bucket->irq_chain); |
707 | 714 | ||
708 | bucket->irq_chain = 0; | 715 | bucket->irq_chain = 0UL; |
709 | __do_IRQ(bucket->virt_irq); | 716 | __do_IRQ(bucket->virt_irq); |
710 | 717 | ||
711 | bucket = next; | 718 | bucket = next; |
@@ -808,7 +815,7 @@ void init_irqwork_curcpu(void) | |||
808 | { | 815 | { |
809 | int cpu = hard_smp_processor_id(); | 816 | int cpu = hard_smp_processor_id(); |
810 | 817 | ||
811 | trap_block[cpu].irq_worklist = 0; | 818 | trap_block[cpu].irq_worklist = 0UL; |
812 | } | 819 | } |
813 | 820 | ||
814 | /* Please be very careful with register_one_mondo() and | 821 | /* Please be very careful with register_one_mondo() and |