aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/sparc64/kernel/entry.S8
-rw-r--r--arch/sparc64/kernel/irq.c41
-rw-r--r--arch/sparc64/kernel/sun4v_ivec.S8
-rw-r--r--include/asm-sparc64/cpudata.h11
-rw-r--r--include/asm-sparc64/irq.h2
5 files changed, 38 insertions, 32 deletions
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index 8059531bf0ac..9a785293203f 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -430,15 +430,15 @@ do_ivec:
430 membar #Sync 430 membar #Sync
431 431
432 sethi %hi(ivector_table), %g2 432 sethi %hi(ivector_table), %g2
433 sllx %g3, 3, %g3 433 sllx %g3, 4, %g3
434 or %g2, %lo(ivector_table), %g2 434 or %g2, %lo(ivector_table), %g2
435 add %g2, %g3, %g3 435 add %g2, %g3, %g3
436 436
437 TRAP_LOAD_IRQ_WORK(%g6, %g1) 437 TRAP_LOAD_IRQ_WORK(%g6, %g1)
438 438
439 lduw [%g6], %g5 /* g5 = irq_work(cpu) */ 439 ldx [%g6], %g5 /* g5 = irq_work(cpu) */
440 stw %g5, [%g3 + 0x00] /* bucket->irq_chain = g5 */ 440 stx %g5, [%g3 + 0x00] /* bucket->irq_chain = g5 */
441 stw %g3, [%g6] /* irq_work(cpu) = bucket */ 441 stx %g3, [%g6] /* irq_work(cpu) = bucket */
442 wr %g0, 1 << PIL_DEVICE_IRQ, %set_softint 442 wr %g0, 1 << PIL_DEVICE_IRQ, %set_softint
443 retry 443 retry
444do_ivec_xcall: 444do_ivec_xcall:
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
diff --git a/arch/sparc64/kernel/sun4v_ivec.S b/arch/sparc64/kernel/sun4v_ivec.S
index 574bc248bca6..e3e9d4c1574b 100644
--- a/arch/sparc64/kernel/sun4v_ivec.S
+++ b/arch/sparc64/kernel/sun4v_ivec.S
@@ -101,14 +101,14 @@ sun4v_dev_mondo:
101 101
102 /* Get &ivector_table[IVEC] into %g4. */ 102 /* Get &ivector_table[IVEC] into %g4. */
103 sethi %hi(ivector_table), %g4 103 sethi %hi(ivector_table), %g4
104 sllx %g3, 3, %g3 104 sllx %g3, 4, %g3
105 or %g4, %lo(ivector_table), %g4 105 or %g4, %lo(ivector_table), %g4
106 add %g4, %g3, %g4 106 add %g4, %g3, %g4
107 107
108 /* Insert ivector_table[] entry into __irq_work[] queue. */ 108 /* Insert ivector_table[] entry into __irq_work[] queue. */
109 lduw [%g1], %g2 /* g2 = irq_work(cpu) */ 109 ldx [%g1], %g2 /* g2 = irq_work(cpu) */
110 stw %g2, [%g4 + 0x00] /* bucket->irq_chain = g2 */ 110 stx %g2, [%g4 + 0x00] /* bucket->irq_chain = g2 */
111 stw %g4, [%g1] /* irq_work(cpu) = bucket */ 111 stx %g4, [%g1] /* irq_work(cpu) = bucket */
112 112
113 /* Signal the interrupt by setting (1 << pil) in %softint. */ 113 /* Signal the interrupt by setting (1 << pil) in %softint. */
114 wr %g0, 1 << PIL_DEVICE_IRQ, %set_softint 114 wr %g0, 1 << PIL_DEVICE_IRQ, %set_softint
diff --git a/include/asm-sparc64/cpudata.h b/include/asm-sparc64/cpudata.h
index 98a6e609163e..379c219c3b7a 100644
--- a/include/asm-sparc64/cpudata.h
+++ b/include/asm-sparc64/cpudata.h
@@ -75,12 +75,11 @@ struct trap_per_cpu {
75 unsigned long tsb_huge_temp; 75 unsigned long tsb_huge_temp;
76 76
77/* Dcache line 8: IRQ work list, and keep trap_block a power-of-2 in size. */ 77/* Dcache line 8: IRQ work list, and keep trap_block a power-of-2 in size. */
78 unsigned int irq_worklist; 78 unsigned long irq_worklist;
79 unsigned int cpu_mondo_qmask; 79 unsigned int cpu_mondo_qmask;
80 unsigned int dev_mondo_qmask; 80 unsigned int dev_mondo_qmask;
81 unsigned int resum_qmask; 81 unsigned int resum_qmask;
82 unsigned int nonresum_qmask; 82 unsigned int nonresum_qmask;
83 unsigned int __pad2[1];
84 void *hdesc; 83 void *hdesc;
85} __attribute__((aligned(64))); 84} __attribute__((aligned(64)));
86extern struct trap_per_cpu trap_block[NR_CPUS]; 85extern struct trap_per_cpu trap_block[NR_CPUS];
@@ -129,10 +128,10 @@ extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch,
129#define TRAP_PER_CPU_TSB_HUGE 0xd0 128#define TRAP_PER_CPU_TSB_HUGE 0xd0
130#define TRAP_PER_CPU_TSB_HUGE_TEMP 0xd8 129#define TRAP_PER_CPU_TSB_HUGE_TEMP 0xd8
131#define TRAP_PER_CPU_IRQ_WORKLIST 0xe0 130#define TRAP_PER_CPU_IRQ_WORKLIST 0xe0
132#define TRAP_PER_CPU_CPU_MONDO_QMASK 0xe4 131#define TRAP_PER_CPU_CPU_MONDO_QMASK 0xe8
133#define TRAP_PER_CPU_DEV_MONDO_QMASK 0xe8 132#define TRAP_PER_CPU_DEV_MONDO_QMASK 0xec
134#define TRAP_PER_CPU_RESUM_QMASK 0xec 133#define TRAP_PER_CPU_RESUM_QMASK 0xf0
135#define TRAP_PER_CPU_NONRESUM_QMASK 0xf0 134#define TRAP_PER_CPU_NONRESUM_QMASK 0xf4
136 135
137#define TRAP_BLOCK_SZ_SHIFT 8 136#define TRAP_BLOCK_SZ_SHIFT 8
138 137
diff --git a/include/asm-sparc64/irq.h b/include/asm-sparc64/irq.h
index bad3c28cdee8..24841c22e81b 100644
--- a/include/asm-sparc64/irq.h
+++ b/include/asm-sparc64/irq.h
@@ -59,7 +59,7 @@ extern unsigned int sun4u_build_msi(u32 portid, unsigned int *virt_irq_p,
59extern void sun4u_destroy_msi(unsigned int virt_irq); 59extern void sun4u_destroy_msi(unsigned int virt_irq);
60extern unsigned int sbus_build_irq(void *sbus, unsigned int ino); 60extern unsigned int sbus_build_irq(void *sbus, unsigned int ino);
61 61
62extern unsigned char virt_irq_alloc(unsigned int real_irq); 62extern unsigned char virt_irq_alloc(unsigned long real_irq);
63#ifdef CONFIG_PCI_MSI 63#ifdef CONFIG_PCI_MSI
64extern void virt_irq_free(unsigned int virt_irq); 64extern void virt_irq_free(unsigned int virt_irq);
65#endif 65#endif