aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/sparc64/kernel/entry.S12
-rw-r--r--arch/sparc64/kernel/irq.c56
-rw-r--r--arch/sparc64/kernel/sun4v_ivec.S16
-rw-r--r--arch/sparc64/kernel/traps.c4
-rw-r--r--include/asm-sparc64/cpudata.h12
5 files changed, 55 insertions, 45 deletions
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index 9a785293203f..c9b0d7af64ae 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -429,16 +429,16 @@ do_ivec:
429 stxa %g0, [%g0] ASI_INTR_RECEIVE 429 stxa %g0, [%g0] ASI_INTR_RECEIVE
430 membar #Sync 430 membar #Sync
431 431
432 sethi %hi(ivector_table), %g2 432 sethi %hi(ivector_table_pa), %g2
433 ldx [%g2 + %lo(ivector_table_pa)], %g2
433 sllx %g3, 4, %g3 434 sllx %g3, 4, %g3
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_PA(%g6, %g1)
438 438
439 ldx [%g6], %g5 /* g5 = irq_work(cpu) */ 439 ldx [%g6], %g5
440 stx %g5, [%g3 + 0x00] /* bucket->irq_chain = g5 */ 440 stxa %g5, [%g3] ASI_PHYS_USE_EC
441 stx %g3, [%g6] /* irq_work(cpu) = bucket */ 441 stx %g3, [%g6]
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 4db4dd576210..26cdf47981c3 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -51,15 +51,12 @@
51 * To make processing these packets efficient and race free we use 51 * To make processing these packets efficient and race free we use
52 * an array of irq buckets below. The interrupt vector handler in 52 * an array of irq buckets below. The interrupt vector handler in
53 * entry.S feeds incoming packets into per-cpu pil-indexed lists. 53 * entry.S feeds incoming packets into per-cpu pil-indexed lists.
54 * The IVEC handler does not need to act atomically, the PIL dispatch
55 * code uses CAS to get an atomic snapshot of the list and clear it
56 * at the same time.
57 * 54 *
58 * If you make changes to ino_bucket, please update hand coded assembler 55 * If you make changes to ino_bucket, please update hand coded assembler
59 * of the vectored interrupt trap handler(s) in entry.S and sun4v_ivec.S 56 * of the vectored interrupt trap handler(s) in entry.S and sun4v_ivec.S
60 */ 57 */
61struct ino_bucket { 58struct ino_bucket {
62/*0x00*/unsigned long irq_chain; 59/*0x00*/unsigned long irq_chain_pa;
63 60
64 /* Virtual interrupt number assigned to this INO. */ 61 /* Virtual interrupt number assigned to this INO. */
65/*0x08*/unsigned int virt_irq; 62/*0x08*/unsigned int virt_irq;
@@ -68,20 +65,14 @@ struct ino_bucket {
68 65
69#define NUM_IVECS (IMAP_INR + 1) 66#define NUM_IVECS (IMAP_INR + 1)
70struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BYTES))); 67struct ino_bucket ivector_table[NUM_IVECS] __attribute__ ((aligned (SMP_CACHE_BYTES)));
68unsigned long ivector_table_pa;
71 69
72#define __irq_ino(irq) \ 70#define __irq_ino(irq) \
73 (((struct ino_bucket *)(irq)) - &ivector_table[0]) 71 (((struct ino_bucket *)(irq)) - &ivector_table[0])
74#define __bucket(irq) ((struct ino_bucket *)(irq)) 72#define __bucket(irq) ((struct ino_bucket *)(irq))
75#define __irq(bucket) ((unsigned long)(bucket)) 73#define __irq(bucket) ((unsigned long)(bucket))
76 74
77/* This has to be in the main kernel image, it cannot be 75#define irq_work_pa(__cpu) &(trap_block[(__cpu)].irq_worklist_pa)
78 * turned into per-cpu data. The reason is that the main
79 * kernel image is locked into the TLB and this structure
80 * is accessed from the vectored interrupt trap handler. If
81 * access to this structure takes a TLB miss it could cause
82 * the 5-level sparc v9 trap stack to overflow.
83 */
84#define irq_work(__cpu) &(trap_block[(__cpu)].irq_worklist)
85 76
86static struct { 77static struct {
87 unsigned long irq; 78 unsigned long irq;
@@ -689,9 +680,8 @@ void ack_bad_irq(unsigned int virt_irq)
689 680
690void handler_irq(int irq, struct pt_regs *regs) 681void handler_irq(int irq, struct pt_regs *regs)
691{ 682{
692 struct ino_bucket *bucket; 683 unsigned long pstate, bucket_pa;
693 struct pt_regs *old_regs; 684 struct pt_regs *old_regs;
694 unsigned long pstate;
695 685
696 clear_softint(1 << irq); 686 clear_softint(1 << irq);
697 687
@@ -704,18 +694,30 @@ void handler_irq(int irq, struct pt_regs *regs)
704 "ldx [%2], %1\n\t" 694 "ldx [%2], %1\n\t"
705 "stx %%g0, [%2]\n\t" 695 "stx %%g0, [%2]\n\t"
706 "wrpr %0, 0x0, %%pstate\n\t" 696 "wrpr %0, 0x0, %%pstate\n\t"
707 : "=&r" (pstate), "=&r" (bucket) 697 : "=&r" (pstate), "=&r" (bucket_pa)
708 : "r" (irq_work(smp_processor_id())), 698 : "r" (irq_work_pa(smp_processor_id())),
709 "i" (PSTATE_IE) 699 "i" (PSTATE_IE)
710 : "memory"); 700 : "memory");
711 701
712 while (bucket) { 702 while (bucket_pa) {
713 struct ino_bucket *next = __bucket(bucket->irq_chain); 703 unsigned long next_pa;
704 unsigned int virt_irq;
714 705
715 bucket->irq_chain = 0UL; 706 __asm__ __volatile__("ldxa [%2] %4, %0\n\t"
716 __do_IRQ(bucket->virt_irq); 707 "lduwa [%3] %4, %1\n\t"
708 "stxa %%g0, [%2] %4"
709 : "=&r" (next_pa), "=&r" (virt_irq)
710 : "r" (bucket_pa +
711 offsetof(struct ino_bucket,
712 irq_chain_pa)),
713 "r" (bucket_pa +
714 offsetof(struct ino_bucket,
715 virt_irq)),
716 "i" (ASI_PHYS_USE_EC));
717 717
718 bucket = next; 718 __do_IRQ(virt_irq);
719
720 bucket_pa = next_pa;
719 } 721 }
720 722
721 irq_exit(); 723 irq_exit();
@@ -815,7 +817,7 @@ void init_irqwork_curcpu(void)
815{ 817{
816 int cpu = hard_smp_processor_id(); 818 int cpu = hard_smp_processor_id();
817 819
818 trap_block[cpu].irq_worklist = 0UL; 820 trap_block[cpu].irq_worklist_pa = 0UL;
819} 821}
820 822
821/* Please be very careful with register_one_mondo() and 823/* Please be very careful with register_one_mondo() and
@@ -926,6 +928,14 @@ static struct irqaction timer_irq_action = {
926 .name = "timer", 928 .name = "timer",
927}; 929};
928 930
931/* XXX Belongs in a common location. XXX */
932static unsigned long kimage_addr_to_ra(void *p)
933{
934 unsigned long val = (unsigned long) p;
935
936 return kern_base + (val - KERNBASE);
937}
938
929/* Only invoked on boot processor. */ 939/* Only invoked on boot processor. */
930void __init init_IRQ(void) 940void __init init_IRQ(void)
931{ 941{
@@ -933,6 +943,8 @@ void __init init_IRQ(void)
933 kill_prom_timer(); 943 kill_prom_timer();
934 memset(&ivector_table[0], 0, sizeof(ivector_table)); 944 memset(&ivector_table[0], 0, sizeof(ivector_table));
935 945
946 ivector_table_pa = kimage_addr_to_ra(&ivector_table[0]);
947
936 if (tlb_type == hypervisor) 948 if (tlb_type == hypervisor)
937 sun4v_init_mondo_queues(); 949 sun4v_init_mondo_queues();
938 950
diff --git a/arch/sparc64/kernel/sun4v_ivec.S b/arch/sparc64/kernel/sun4v_ivec.S
index e3e9d4c1574b..16d306445912 100644
--- a/arch/sparc64/kernel/sun4v_ivec.S
+++ b/arch/sparc64/kernel/sun4v_ivec.S
@@ -96,19 +96,17 @@ sun4v_dev_mondo:
96 stxa %g2, [%g4] ASI_QUEUE 96 stxa %g2, [%g4] ASI_QUEUE
97 membar #Sync 97 membar #Sync
98 98
99 /* Get &__irq_work[smp_processor_id()] into %g1. */ 99 TRAP_LOAD_IRQ_WORK_PA(%g1, %g4)
100 TRAP_LOAD_IRQ_WORK(%g1, %g4)
101 100
102 /* Get &ivector_table[IVEC] into %g4. */ 101 /* Get __pa(&ivector_table[IVEC]) into %g4. */
103 sethi %hi(ivector_table), %g4 102 sethi %hi(ivector_table_pa), %g4
103 ldx [%g4 + %lo(ivector_table_pa)], %g4
104 sllx %g3, 4, %g3 104 sllx %g3, 4, %g3
105 or %g4, %lo(ivector_table), %g4
106 add %g4, %g3, %g4 105 add %g4, %g3, %g4
107 106
108 /* Insert ivector_table[] entry into __irq_work[] queue. */ 107 ldx [%g1], %g2
109 ldx [%g1], %g2 /* g2 = irq_work(cpu) */ 108 stxa %g2, [%g4] ASI_PHYS_USE_EC
110 stx %g2, [%g4 + 0x00] /* bucket->irq_chain = g2 */ 109 stx %g4, [%g1]
111 stx %g4, [%g1] /* irq_work(cpu) = bucket */
112 110
113 /* Signal the interrupt by setting (1 << pil) in %softint. */ 111 /* Signal the interrupt by setting (1 << pil) in %softint. */
114 wr %g0, 1 << PIL_DEVICE_IRQ, %set_softint 112 wr %g0, 1 << PIL_DEVICE_IRQ, %set_softint
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
index 6ef42b8e53d8..34573a55b6e5 100644
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -2569,8 +2569,8 @@ void __init trap_init(void)
2569 offsetof(struct trap_per_cpu, tsb_huge)) || 2569 offsetof(struct trap_per_cpu, tsb_huge)) ||
2570 (TRAP_PER_CPU_TSB_HUGE_TEMP != 2570 (TRAP_PER_CPU_TSB_HUGE_TEMP !=
2571 offsetof(struct trap_per_cpu, tsb_huge_temp)) || 2571 offsetof(struct trap_per_cpu, tsb_huge_temp)) ||
2572 (TRAP_PER_CPU_IRQ_WORKLIST != 2572 (TRAP_PER_CPU_IRQ_WORKLIST_PA !=
2573 offsetof(struct trap_per_cpu, irq_worklist)) || 2573 offsetof(struct trap_per_cpu, irq_worklist_pa)) ||
2574 (TRAP_PER_CPU_CPU_MONDO_QMASK != 2574 (TRAP_PER_CPU_CPU_MONDO_QMASK !=
2575 offsetof(struct trap_per_cpu, cpu_mondo_qmask)) || 2575 offsetof(struct trap_per_cpu, cpu_mondo_qmask)) ||
2576 (TRAP_PER_CPU_DEV_MONDO_QMASK != 2576 (TRAP_PER_CPU_DEV_MONDO_QMASK !=
diff --git a/include/asm-sparc64/cpudata.h b/include/asm-sparc64/cpudata.h
index 379c219c3b7a..542421460a12 100644
--- a/include/asm-sparc64/cpudata.h
+++ b/include/asm-sparc64/cpudata.h
@@ -75,7 +75,7 @@ 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 long irq_worklist; 78 unsigned long irq_worklist_pa;
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;
@@ -127,7 +127,7 @@ extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch,
127#define TRAP_PER_CPU_CPU_LIST_PA 0xc8 127#define TRAP_PER_CPU_CPU_LIST_PA 0xc8
128#define TRAP_PER_CPU_TSB_HUGE 0xd0 128#define TRAP_PER_CPU_TSB_HUGE 0xd0
129#define TRAP_PER_CPU_TSB_HUGE_TEMP 0xd8 129#define TRAP_PER_CPU_TSB_HUGE_TEMP 0xd8
130#define TRAP_PER_CPU_IRQ_WORKLIST 0xe0 130#define TRAP_PER_CPU_IRQ_WORKLIST_PA 0xe0
131#define TRAP_PER_CPU_CPU_MONDO_QMASK 0xe8 131#define TRAP_PER_CPU_CPU_MONDO_QMASK 0xe8
132#define TRAP_PER_CPU_DEV_MONDO_QMASK 0xec 132#define TRAP_PER_CPU_DEV_MONDO_QMASK 0xec
133#define TRAP_PER_CPU_RESUM_QMASK 0xf0 133#define TRAP_PER_CPU_RESUM_QMASK 0xf0
@@ -183,9 +183,9 @@ extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch,
183 ldx [DEST + TRAP_PER_CPU_PGD_PADDR], DEST; 183 ldx [DEST + TRAP_PER_CPU_PGD_PADDR], DEST;
184 184
185/* Clobbers TMP, loads local processor's IRQ work area into DEST. */ 185/* Clobbers TMP, loads local processor's IRQ work area into DEST. */
186#define TRAP_LOAD_IRQ_WORK(DEST, TMP) \ 186#define TRAP_LOAD_IRQ_WORK_PA(DEST, TMP) \
187 TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ 187 TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \
188 add DEST, TRAP_PER_CPU_IRQ_WORKLIST, DEST; 188 add DEST, TRAP_PER_CPU_IRQ_WORKLIST_PA, DEST;
189 189
190/* Clobbers TMP, loads DEST with current thread info pointer. */ 190/* Clobbers TMP, loads DEST with current thread info pointer. */
191#define TRAP_LOAD_THREAD_REG(DEST, TMP) \ 191#define TRAP_LOAD_THREAD_REG(DEST, TMP) \
@@ -222,9 +222,9 @@ extern struct sun4v_2insn_patch_entry __sun4v_2insn_patch,
222 ldx [DEST + TRAP_PER_CPU_PGD_PADDR], DEST; 222 ldx [DEST + TRAP_PER_CPU_PGD_PADDR], DEST;
223 223
224/* Clobbers TMP, loads local processor's IRQ work area into DEST. */ 224/* Clobbers TMP, loads local processor's IRQ work area into DEST. */
225#define TRAP_LOAD_IRQ_WORK(DEST, TMP) \ 225#define TRAP_LOAD_IRQ_WORK_PA(DEST, TMP) \
226 TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ 226 TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \
227 add DEST, TRAP_PER_CPU_IRQ_WORKLIST, DEST; 227 add DEST, TRAP_PER_CPU_IRQ_WORKLIST_PA, DEST;
228 228
229#define TRAP_LOAD_THREAD_REG(DEST, TMP) \ 229#define TRAP_LOAD_THREAD_REG(DEST, TMP) \
230 TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \ 230 TRAP_LOAD_TRAP_BLOCK(DEST, TMP) \