diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2007-10-12 05:59:40 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-14 00:53:15 -0400 |
commit | a650d3839e7a68321e5b76264398a63019b0928b (patch) | |
tree | e0500c57687c57bc22d0100b74485033a5738dbf /arch/sparc64/kernel/irq.c | |
parent | d060db63fd38a8a75f666576ef9999c28cdc31cf (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>
Diffstat (limited to 'arch/sparc64/kernel/irq.c')
-rw-r--r-- | arch/sparc64/kernel/irq.c | 41 |
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 | */ |
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 |