aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-10-12 05:59:40 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-14 00:53:15 -0400
commita650d3839e7a68321e5b76264398a63019b0928b (patch)
treee0500c57687c57bc22d0100b74485033a5738dbf
parentd060db63fd38a8a75f666576ef9999c28cdc31cf (diff)
[SPARC64]: Make IVEC pointers 64-bit.
Currently we chain IVEC entries using 32-bit "pointers" because we know that the ivector_table is in the main kernel image, thus below 4GB. This uses proper 64-bit pointers instead. Whilst this bloats up the kernel image size, this sets the infrastructure necessary to significantly shrink the kernel size by using physical addresses and dynamically allocating the ivector table. Signed-off-by: David S. Miller <davem@davemloft.net>
-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 8059531bf0a..9a785293203 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 045ab27d427..4db4dd57621 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 574bc248bca..e3e9d4c1574 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 98a6e609163..379c219c3b7 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 bad3c28cdee..24841c22e81 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