aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel/irq.c')
-rw-r--r--arch/sparc64/kernel/irq.c41
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 */
61struct ino_bucket { 61struct 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)
73struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BYTES))); 70struct 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
89static struct { 86static 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];
94static DEFINE_SPINLOCK(virt_irq_alloc_lock); 91static DEFINE_SPINLOCK(virt_irq_alloc_lock);
95 92
96unsigned char virt_irq_alloc(unsigned int real_irq) 93unsigned 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
137static unsigned int virt_to_real_irq(unsigned char virt_irq) 134static 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
228static inline struct ino_bucket *virt_irq_to_bucket(unsigned int virt_irq) 225static 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