diff options
-rw-r--r-- | arch/sparc64/kernel/entry.S | 8 | ||||
-rw-r--r-- | arch/sparc64/kernel/irq.c | 41 | ||||
-rw-r--r-- | arch/sparc64/kernel/sun4v_ivec.S | 8 | ||||
-rw-r--r-- | include/asm-sparc64/cpudata.h | 11 | ||||
-rw-r--r-- | include/asm-sparc64/irq.h | 2 |
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 |
444 | do_ivec_xcall: | 444 | do_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 | */ |
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 |
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))); |
86 | extern struct trap_per_cpu trap_block[NR_CPUS]; | 85 | extern 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, | |||
59 | extern void sun4u_destroy_msi(unsigned int virt_irq); | 59 | extern void sun4u_destroy_msi(unsigned int virt_irq); |
60 | extern unsigned int sbus_build_irq(void *sbus, unsigned int ino); | 60 | extern unsigned int sbus_build_irq(void *sbus, unsigned int ino); |
61 | 61 | ||
62 | extern unsigned char virt_irq_alloc(unsigned int real_irq); | 62 | extern unsigned char virt_irq_alloc(unsigned long real_irq); |
63 | #ifdef CONFIG_PCI_MSI | 63 | #ifdef CONFIG_PCI_MSI |
64 | extern void virt_irq_free(unsigned int virt_irq); | 64 | extern void virt_irq_free(unsigned int virt_irq); |
65 | #endif | 65 | #endif |