diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2006-07-03 05:32:51 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-07-03 05:55:12 -0400 |
commit | b9e5b4e6a991a5a6d521f2e20a65835404b4169f (patch) | |
tree | a0ac972faae4bf9133f576d842667bb134190341 | |
parent | 5a43a066b11ac2fe84cf67307f20b83bea390f83 (diff) |
[POWERPC] Use the genirq framework
This adapts the generic powerpc interrupt handling code, and all of
the platforms except for the embedded 6xx machines, to use the new
genirq framework.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r-- | arch/powerpc/kernel/irq.c | 30 | ||||
-rw-r--r-- | arch/powerpc/kernel/misc_64.S | 10 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/interrupt.c | 111 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/interrupt.h | 4 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/setup.c | 12 | ||||
-rw-r--r-- | arch/powerpc/platforms/cell/spider-pic.c | 173 | ||||
-rw-r--r-- | arch/powerpc/platforms/chrp/setup.c | 17 | ||||
-rw-r--r-- | arch/powerpc/platforms/iseries/irq.c | 17 | ||||
-rw-r--r-- | arch/powerpc/platforms/powermac/pic.c | 170 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/setup.c | 26 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/xics.c | 443 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/xics.h | 17 | ||||
-rw-r--r-- | arch/powerpc/sysdev/i8259.c | 30 | ||||
-rw-r--r-- | arch/powerpc/sysdev/mpic.c | 193 | ||||
-rw-r--r-- | include/asm-powerpc/i8259.h | 3 | ||||
-rw-r--r-- | include/asm-powerpc/irq.h | 8 | ||||
-rw-r--r-- | include/asm-powerpc/mpic.h | 25 |
17 files changed, 673 insertions, 616 deletions
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 525baab45d2d..91248559099a 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c | |||
@@ -62,28 +62,27 @@ | |||
62 | #endif | 62 | #endif |
63 | 63 | ||
64 | int __irq_offset_value; | 64 | int __irq_offset_value; |
65 | #ifdef CONFIG_PPC32 | ||
66 | EXPORT_SYMBOL(__irq_offset_value); | ||
67 | #endif | ||
68 | |||
69 | static int ppc_spurious_interrupts; | 65 | static int ppc_spurious_interrupts; |
70 | 66 | ||
71 | #ifdef CONFIG_PPC32 | 67 | #ifdef CONFIG_PPC32 |
72 | #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) | 68 | EXPORT_SYMBOL(__irq_offset_value); |
69 | atomic_t ppc_n_lost_interrupts; | ||
73 | 70 | ||
71 | #ifndef CONFIG_PPC_MERGE | ||
72 | #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) | ||
74 | unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; | 73 | unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; |
75 | atomic_t ppc_n_lost_interrupts; | 74 | #endif |
76 | 75 | ||
77 | #ifdef CONFIG_TAU_INT | 76 | #ifdef CONFIG_TAU_INT |
78 | extern int tau_initialized; | 77 | extern int tau_initialized; |
79 | extern int tau_interrupts(int); | 78 | extern int tau_interrupts(int); |
80 | #endif | 79 | #endif |
80 | #endif /* CONFIG_PPC32 */ | ||
81 | 81 | ||
82 | #if defined(CONFIG_SMP) && !defined(CONFIG_PPC_MERGE) | 82 | #if defined(CONFIG_SMP) && !defined(CONFIG_PPC_MERGE) |
83 | extern atomic_t ipi_recv; | 83 | extern atomic_t ipi_recv; |
84 | extern atomic_t ipi_sent; | 84 | extern atomic_t ipi_sent; |
85 | #endif | 85 | #endif |
86 | #endif /* CONFIG_PPC32 */ | ||
87 | 86 | ||
88 | #ifdef CONFIG_PPC64 | 87 | #ifdef CONFIG_PPC64 |
89 | EXPORT_SYMBOL(irq_desc); | 88 | EXPORT_SYMBOL(irq_desc); |
@@ -219,15 +218,19 @@ void do_IRQ(struct pt_regs *regs) | |||
219 | curtp = current_thread_info(); | 218 | curtp = current_thread_info(); |
220 | irqtp = hardirq_ctx[smp_processor_id()]; | 219 | irqtp = hardirq_ctx[smp_processor_id()]; |
221 | if (curtp != irqtp) { | 220 | if (curtp != irqtp) { |
221 | struct irq_desc *desc = irq_desc + irq; | ||
222 | void *handler = desc->handle_irq; | ||
223 | if (handler == NULL) | ||
224 | handler = &__do_IRQ; | ||
222 | irqtp->task = curtp->task; | 225 | irqtp->task = curtp->task; |
223 | irqtp->flags = 0; | 226 | irqtp->flags = 0; |
224 | call___do_IRQ(irq, regs, irqtp); | 227 | call_handle_irq(irq, desc, regs, irqtp, handler); |
225 | irqtp->task = NULL; | 228 | irqtp->task = NULL; |
226 | if (irqtp->flags) | 229 | if (irqtp->flags) |
227 | set_bits(irqtp->flags, &curtp->flags); | 230 | set_bits(irqtp->flags, &curtp->flags); |
228 | } else | 231 | } else |
229 | #endif | 232 | #endif |
230 | __do_IRQ(irq, regs); | 233 | generic_handle_irq(irq, regs); |
231 | } else if (irq != -2) | 234 | } else if (irq != -2) |
232 | /* That's not SMP safe ... but who cares ? */ | 235 | /* That's not SMP safe ... but who cares ? */ |
233 | ppc_spurious_interrupts++; | 236 | ppc_spurious_interrupts++; |
@@ -245,15 +248,6 @@ void do_IRQ(struct pt_regs *regs) | |||
245 | 248 | ||
246 | void __init init_IRQ(void) | 249 | void __init init_IRQ(void) |
247 | { | 250 | { |
248 | #ifdef CONFIG_PPC64 | ||
249 | static int once = 0; | ||
250 | |||
251 | if (once) | ||
252 | return; | ||
253 | |||
254 | once++; | ||
255 | |||
256 | #endif | ||
257 | ppc_md.init_IRQ(); | 251 | ppc_md.init_IRQ(); |
258 | #ifdef CONFIG_PPC64 | 252 | #ifdef CONFIG_PPC64 |
259 | irq_ctx_init(); | 253 | irq_ctx_init(); |
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S index 0c3c70d115c6..bfb407fc1aa1 100644 --- a/arch/powerpc/kernel/misc_64.S +++ b/arch/powerpc/kernel/misc_64.S | |||
@@ -51,12 +51,14 @@ _GLOBAL(call_do_softirq) | |||
51 | mtlr r0 | 51 | mtlr r0 |
52 | blr | 52 | blr |
53 | 53 | ||
54 | _GLOBAL(call___do_IRQ) | 54 | _GLOBAL(call_handle_irq) |
55 | ld r8,0(r7) | ||
55 | mflr r0 | 56 | mflr r0 |
56 | std r0,16(r1) | 57 | std r0,16(r1) |
57 | stdu r1,THREAD_SIZE-112(r5) | 58 | mtctr r8 |
58 | mr r1,r5 | 59 | stdu r1,THREAD_SIZE-112(r6) |
59 | bl .__do_IRQ | 60 | mr r1,r6 |
61 | bctrl | ||
60 | ld r1,0(r1) | 62 | ld r1,0(r1) |
61 | ld r0,16(r1) | 63 | ld r0,16(r1) |
62 | mtlr r0 | 64 | mtlr r0 |
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 22da1335445a..97936f547f19 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c | |||
@@ -37,64 +37,51 @@ | |||
37 | struct iic { | 37 | struct iic { |
38 | struct cbe_iic_thread_regs __iomem *regs; | 38 | struct cbe_iic_thread_regs __iomem *regs; |
39 | u8 target_id; | 39 | u8 target_id; |
40 | u8 eoi_stack[16]; | ||
41 | int eoi_ptr; | ||
40 | }; | 42 | }; |
41 | 43 | ||
42 | static DEFINE_PER_CPU(struct iic, iic); | 44 | static DEFINE_PER_CPU(struct iic, iic); |
43 | 45 | ||
44 | void iic_local_enable(void) | 46 | static void iic_mask(unsigned int irq) |
45 | { | 47 | { |
46 | struct iic *iic = &__get_cpu_var(iic); | ||
47 | u64 tmp; | ||
48 | |||
49 | /* | ||
50 | * There seems to be a bug that is present in DD2.x CPUs | ||
51 | * and still only partially fixed in DD3.1. | ||
52 | * This bug causes a value written to the priority register | ||
53 | * not to make it there, resulting in a system hang unless we | ||
54 | * write it again. | ||
55 | * Masking with 0xf0 is done because the Cell BE does not | ||
56 | * implement the lower four bits of the interrupt priority, | ||
57 | * they always read back as zeroes, although future CPUs | ||
58 | * might implement different bits. | ||
59 | */ | ||
60 | do { | ||
61 | out_be64(&iic->regs->prio, 0xff); | ||
62 | tmp = in_be64(&iic->regs->prio); | ||
63 | } while ((tmp & 0xf0) != 0xf0); | ||
64 | } | ||
65 | |||
66 | void iic_local_disable(void) | ||
67 | { | ||
68 | out_be64(&__get_cpu_var(iic).regs->prio, 0x0); | ||
69 | } | ||
70 | |||
71 | static unsigned int iic_startup(unsigned int irq) | ||
72 | { | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static void iic_enable(unsigned int irq) | ||
77 | { | ||
78 | iic_local_enable(); | ||
79 | } | 48 | } |
80 | 49 | ||
81 | static void iic_disable(unsigned int irq) | 50 | static void iic_unmask(unsigned int irq) |
82 | { | 51 | { |
83 | } | 52 | } |
84 | 53 | ||
85 | static void iic_end(unsigned int irq) | 54 | static void iic_eoi(unsigned int irq) |
86 | { | 55 | { |
87 | iic_local_enable(); | 56 | struct iic *iic = &__get_cpu_var(iic); |
57 | out_be64(&iic->regs->prio, iic->eoi_stack[--iic->eoi_ptr]); | ||
58 | BUG_ON(iic->eoi_ptr < 0); | ||
88 | } | 59 | } |
89 | 60 | ||
90 | static struct hw_interrupt_type iic_pic = { | 61 | static struct irq_chip iic_chip = { |
91 | .typename = " CELL-IIC ", | 62 | .typename = " CELL-IIC ", |
92 | .startup = iic_startup, | 63 | .mask = iic_mask, |
93 | .enable = iic_enable, | 64 | .unmask = iic_unmask, |
94 | .disable = iic_disable, | 65 | .eoi = iic_eoi, |
95 | .end = iic_end, | ||
96 | }; | 66 | }; |
97 | 67 | ||
68 | /* XXX All of this has to be reworked completely. We need to assign a real | ||
69 | * interrupt numbers to the external interrupts and remove all the hard coded | ||
70 | * interrupt maps (rely on the device-tree whenever possible). | ||
71 | * | ||
72 | * Basically, my scheme is to define the "pendings" bits to be the HW interrupt | ||
73 | * number (ignoring the data and flags here). That means we can sort-of split | ||
74 | * external sources based on priority, and we can use request_irq() on pretty | ||
75 | * much anything. | ||
76 | * | ||
77 | * For spider or axon, they have their own interrupt space. spider will just have | ||
78 | * local "hardward" interrupts 0...xx * node stride. The node stride is not | ||
79 | * necessary (separate interrupt chips will have separate HW number space), but | ||
80 | * will allow to be compatible with existing device-trees. | ||
81 | * | ||
82 | * All of thise little world will get a standard remapping scheme to map those HW | ||
83 | * numbers into the linux flat irq number space. | ||
84 | */ | ||
98 | static int iic_external_get_irq(struct cbe_iic_pending_bits pending) | 85 | static int iic_external_get_irq(struct cbe_iic_pending_bits pending) |
99 | { | 86 | { |
100 | int irq; | 87 | int irq; |
@@ -118,9 +105,10 @@ static int iic_external_get_irq(struct cbe_iic_pending_bits pending) | |||
118 | */ | 105 | */ |
119 | if (pending.class != 2) | 106 | if (pending.class != 2) |
120 | break; | 107 | break; |
121 | irq = IIC_EXT_OFFSET | 108 | /* TODO: We might want to silently ignore cascade interrupts |
122 | + spider_get_irq(node) | 109 | * when no cascade handler exist yet |
123 | + node * IIC_NODE_STRIDE; | 110 | */ |
111 | irq = IIC_EXT_CASCADE + node * IIC_NODE_STRIDE; | ||
124 | break; | 112 | break; |
125 | case 0x01 ... 0x04: | 113 | case 0x01 ... 0x04: |
126 | case 0x07 ... 0x0a: | 114 | case 0x07 ... 0x0a: |
@@ -152,6 +140,8 @@ int iic_get_irq(struct pt_regs *regs) | |||
152 | iic = &__get_cpu_var(iic); | 140 | iic = &__get_cpu_var(iic); |
153 | *(unsigned long *) &pending = | 141 | *(unsigned long *) &pending = |
154 | in_be64((unsigned long __iomem *) &iic->regs->pending_destr); | 142 | in_be64((unsigned long __iomem *) &iic->regs->pending_destr); |
143 | iic->eoi_stack[++iic->eoi_ptr] = pending.prio; | ||
144 | BUG_ON(iic->eoi_ptr > 15); | ||
155 | 145 | ||
156 | irq = -1; | 146 | irq = -1; |
157 | if (pending.flags & CBE_IIC_IRQ_VALID) { | 147 | if (pending.flags & CBE_IIC_IRQ_VALID) { |
@@ -172,7 +162,7 @@ int iic_get_irq(struct pt_regs *regs) | |||
172 | 162 | ||
173 | /* hardcoded part to be compatible with older firmware */ | 163 | /* hardcoded part to be compatible with older firmware */ |
174 | 164 | ||
175 | static int setup_iic_hardcoded(void) | 165 | static int __init setup_iic_hardcoded(void) |
176 | { | 166 | { |
177 | struct device_node *np; | 167 | struct device_node *np; |
178 | int nodeid, cpu; | 168 | int nodeid, cpu; |
@@ -207,12 +197,13 @@ static int setup_iic_hardcoded(void) | |||
207 | printk(KERN_INFO "IIC for CPU %d at %lx\n", cpu, regs); | 197 | printk(KERN_INFO "IIC for CPU %d at %lx\n", cpu, regs); |
208 | iic->regs = ioremap(regs, sizeof(struct cbe_iic_thread_regs)); | 198 | iic->regs = ioremap(regs, sizeof(struct cbe_iic_thread_regs)); |
209 | iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe); | 199 | iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe); |
200 | iic->eoi_stack[0] = 0xff; | ||
210 | } | 201 | } |
211 | 202 | ||
212 | return 0; | 203 | return 0; |
213 | } | 204 | } |
214 | 205 | ||
215 | static int setup_iic(void) | 206 | static int __init setup_iic(void) |
216 | { | 207 | { |
217 | struct device_node *dn; | 208 | struct device_node *dn; |
218 | unsigned long *regs; | 209 | unsigned long *regs; |
@@ -248,11 +239,14 @@ static int setup_iic(void) | |||
248 | iic = &per_cpu(iic, np[0]); | 239 | iic = &per_cpu(iic, np[0]); |
249 | iic->regs = ioremap(regs[0], sizeof(struct cbe_iic_thread_regs)); | 240 | iic->regs = ioremap(regs[0], sizeof(struct cbe_iic_thread_regs)); |
250 | iic->target_id = ((np[0] & 2) << 3) + ((np[0] & 1) ? 0xf : 0xe); | 241 | iic->target_id = ((np[0] & 2) << 3) + ((np[0] & 1) ? 0xf : 0xe); |
242 | iic->eoi_stack[0] = 0xff; | ||
251 | printk("IIC for CPU %d at %lx mapped to %p\n", np[0], regs[0], iic->regs); | 243 | printk("IIC for CPU %d at %lx mapped to %p\n", np[0], regs[0], iic->regs); |
252 | 244 | ||
253 | iic = &per_cpu(iic, np[1]); | 245 | iic = &per_cpu(iic, np[1]); |
254 | iic->regs = ioremap(regs[2], sizeof(struct cbe_iic_thread_regs)); | 246 | iic->regs = ioremap(regs[2], sizeof(struct cbe_iic_thread_regs)); |
255 | iic->target_id = ((np[1] & 2) << 3) + ((np[1] & 1) ? 0xf : 0xe); | 247 | iic->target_id = ((np[1] & 2) << 3) + ((np[1] & 1) ? 0xf : 0xe); |
248 | iic->eoi_stack[0] = 0xff; | ||
249 | |||
256 | printk("IIC for CPU %d at %lx mapped to %p\n", np[1], regs[2], iic->regs); | 250 | printk("IIC for CPU %d at %lx mapped to %p\n", np[1], regs[2], iic->regs); |
257 | 251 | ||
258 | found++; | 252 | found++; |
@@ -304,10 +298,10 @@ static void iic_request_ipi(int ipi, const char *name) | |||
304 | int irq; | 298 | int irq; |
305 | 299 | ||
306 | irq = iic_ipi_to_irq(ipi); | 300 | irq = iic_ipi_to_irq(ipi); |
301 | |||
307 | /* IPIs are marked IRQF_DISABLED as they must run with irqs | 302 | /* IPIs are marked IRQF_DISABLED as they must run with irqs |
308 | * disabled */ | 303 | * disabled */ |
309 | get_irq_desc(irq)->chip = &iic_pic; | 304 | set_irq_chip_and_handler(irq, &iic_chip, handle_percpu_irq); |
310 | get_irq_desc(irq)->status |= IRQ_PER_CPU; | ||
311 | request_irq(irq, iic_ipi_action, IRQF_DISABLED, name, NULL); | 305 | request_irq(irq, iic_ipi_action, IRQF_DISABLED, name, NULL); |
312 | } | 306 | } |
313 | 307 | ||
@@ -321,20 +315,26 @@ void iic_request_IPIs(void) | |||
321 | } | 315 | } |
322 | #endif /* CONFIG_SMP */ | 316 | #endif /* CONFIG_SMP */ |
323 | 317 | ||
324 | static void iic_setup_spe_handlers(void) | 318 | static void __init iic_setup_builtin_handlers(void) |
325 | { | 319 | { |
326 | int be, isrc; | 320 | int be, isrc; |
327 | 321 | ||
328 | /* Assume two threads per BE are present */ | 322 | /* XXX FIXME: Assume two threads per BE are present */ |
329 | for (be=0; be < num_present_cpus() / 2; be++) { | 323 | for (be=0; be < num_present_cpus() / 2; be++) { |
324 | int irq; | ||
325 | |||
326 | /* setup SPE chip and handlers */ | ||
330 | for (isrc = 0; isrc < IIC_CLASS_STRIDE * 3; isrc++) { | 327 | for (isrc = 0; isrc < IIC_CLASS_STRIDE * 3; isrc++) { |
331 | int irq = IIC_NODE_STRIDE * be + IIC_SPE_OFFSET + isrc; | 328 | irq = IIC_NODE_STRIDE * be + IIC_SPE_OFFSET + isrc; |
332 | get_irq_desc(irq)->chip = &iic_pic; | 329 | set_irq_chip_and_handler(irq, &iic_chip, handle_fasteoi_irq); |
333 | } | 330 | } |
331 | /* setup cascade chip */ | ||
332 | irq = IIC_EXT_CASCADE + be * IIC_NODE_STRIDE; | ||
333 | set_irq_chip_and_handler(irq, &iic_chip, handle_fasteoi_irq); | ||
334 | } | 334 | } |
335 | } | 335 | } |
336 | 336 | ||
337 | void iic_init_IRQ(void) | 337 | void __init iic_init_IRQ(void) |
338 | { | 338 | { |
339 | int cpu, irq_offset; | 339 | int cpu, irq_offset; |
340 | struct iic *iic; | 340 | struct iic *iic; |
@@ -348,5 +348,6 @@ void iic_init_IRQ(void) | |||
348 | if (iic->regs) | 348 | if (iic->regs) |
349 | out_be64(&iic->regs->prio, 0xff); | 349 | out_be64(&iic->regs->prio, 0xff); |
350 | } | 350 | } |
351 | iic_setup_spe_handlers(); | 351 | iic_setup_builtin_handlers(); |
352 | |||
352 | } | 353 | } |
diff --git a/arch/powerpc/platforms/cell/interrupt.h b/arch/powerpc/platforms/cell/interrupt.h index 799f77d98f96..c74515aeb630 100644 --- a/arch/powerpc/platforms/cell/interrupt.h +++ b/arch/powerpc/platforms/cell/interrupt.h | |||
@@ -38,6 +38,7 @@ | |||
38 | 38 | ||
39 | enum { | 39 | enum { |
40 | IIC_EXT_OFFSET = 0x00, /* Start of south bridge IRQs */ | 40 | IIC_EXT_OFFSET = 0x00, /* Start of south bridge IRQs */ |
41 | IIC_EXT_CASCADE = 0x20, /* There is no interrupt 32 on spider */ | ||
41 | IIC_NUM_EXT = 0x40, /* Number of south bridge IRQs */ | 42 | IIC_NUM_EXT = 0x40, /* Number of south bridge IRQs */ |
42 | IIC_SPE_OFFSET = 0x40, /* Start of SPE interrupts */ | 43 | IIC_SPE_OFFSET = 0x40, /* Start of SPE interrupts */ |
43 | IIC_CLASS_STRIDE = 0x10, /* SPE IRQs per class */ | 44 | IIC_CLASS_STRIDE = 0x10, /* SPE IRQs per class */ |
@@ -51,13 +52,10 @@ extern int iic_get_irq(struct pt_regs *regs); | |||
51 | extern void iic_cause_IPI(int cpu, int mesg); | 52 | extern void iic_cause_IPI(int cpu, int mesg); |
52 | extern void iic_request_IPIs(void); | 53 | extern void iic_request_IPIs(void); |
53 | extern void iic_setup_cpu(void); | 54 | extern void iic_setup_cpu(void); |
54 | extern void iic_local_enable(void); | ||
55 | extern void iic_local_disable(void); | ||
56 | 55 | ||
57 | extern u8 iic_get_target_id(int cpu); | 56 | extern u8 iic_get_target_id(int cpu); |
58 | 57 | ||
59 | extern void spider_init_IRQ(void); | 58 | extern void spider_init_IRQ(void); |
60 | extern int spider_get_irq(int node); | ||
61 | 59 | ||
62 | #endif | 60 | #endif |
63 | #endif /* ASM_CELL_PIC_H */ | 61 | #endif /* ASM_CELL_PIC_H */ |
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index 01ec39431fb0..70a4e903f7e2 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c | |||
@@ -80,10 +80,14 @@ static void cell_progress(char *s, unsigned short hex) | |||
80 | printk("*** %04x : %s\n", hex, s ? s : ""); | 80 | printk("*** %04x : %s\n", hex, s ? s : ""); |
81 | } | 81 | } |
82 | 82 | ||
83 | static void __init cell_init_irq(void) | ||
84 | { | ||
85 | iic_init_IRQ(); | ||
86 | spider_init_IRQ(); | ||
87 | } | ||
88 | |||
83 | static void __init cell_setup_arch(void) | 89 | static void __init cell_setup_arch(void) |
84 | { | 90 | { |
85 | ppc_md.init_IRQ = iic_init_IRQ; | ||
86 | ppc_md.get_irq = iic_get_irq; | ||
87 | #ifdef CONFIG_SPU_BASE | 91 | #ifdef CONFIG_SPU_BASE |
88 | spu_priv1_ops = &spu_priv1_mmio_ops; | 92 | spu_priv1_ops = &spu_priv1_mmio_ops; |
89 | #endif | 93 | #endif |
@@ -109,7 +113,6 @@ static void __init cell_setup_arch(void) | |||
109 | /* Find and initialize PCI host bridges */ | 113 | /* Find and initialize PCI host bridges */ |
110 | init_pci_config_tokens(); | 114 | init_pci_config_tokens(); |
111 | find_and_init_phbs(); | 115 | find_and_init_phbs(); |
112 | spider_init_IRQ(); | ||
113 | cbe_pervasive_init(); | 116 | cbe_pervasive_init(); |
114 | #ifdef CONFIG_DUMMY_CONSOLE | 117 | #ifdef CONFIG_DUMMY_CONSOLE |
115 | conswitchp = &dummy_con; | 118 | conswitchp = &dummy_con; |
@@ -174,6 +177,9 @@ define_machine(cell) { | |||
174 | .calibrate_decr = generic_calibrate_decr, | 177 | .calibrate_decr = generic_calibrate_decr, |
175 | .check_legacy_ioport = cell_check_legacy_ioport, | 178 | .check_legacy_ioport = cell_check_legacy_ioport, |
176 | .progress = cell_progress, | 179 | .progress = cell_progress, |
180 | .init_IRQ = cell_init_irq, | ||
181 | .get_irq = iic_get_irq, | ||
182 | |||
177 | #ifdef CONFIG_KEXEC | 183 | #ifdef CONFIG_KEXEC |
178 | .machine_kexec = default_machine_kexec, | 184 | .machine_kexec = default_machine_kexec, |
179 | .machine_kexec_prepare = default_machine_kexec_prepare, | 185 | .machine_kexec_prepare = default_machine_kexec_prepare, |
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index 7c3a0b6d34fd..98425acb6cda 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c | |||
@@ -82,17 +82,20 @@ static void __iomem *spider_get_irq_config(int irq) | |||
82 | return pic + TIR_CFGA + 8 * spider_get_nr(irq); | 82 | return pic + TIR_CFGA + 8 * spider_get_nr(irq); |
83 | } | 83 | } |
84 | 84 | ||
85 | static void spider_enable_irq(unsigned int irq) | 85 | static void spider_unmask_irq(unsigned int irq) |
86 | { | 86 | { |
87 | int nodeid = (irq / IIC_NODE_STRIDE) * 0x10; | 87 | int nodeid = (irq / IIC_NODE_STRIDE) * 0x10; |
88 | void __iomem *cfg = spider_get_irq_config(irq); | 88 | void __iomem *cfg = spider_get_irq_config(irq); |
89 | irq = spider_get_nr(irq); | 89 | irq = spider_get_nr(irq); |
90 | 90 | ||
91 | /* FIXME: Most of that is configuration and has nothing to do with enabling/disable, | ||
92 | * besides, it's also partially bogus. | ||
93 | */ | ||
91 | out_be32(cfg, (in_be32(cfg) & ~0xf0)| 0x3107000eu | nodeid); | 94 | out_be32(cfg, (in_be32(cfg) & ~0xf0)| 0x3107000eu | nodeid); |
92 | out_be32(cfg + 4, in_be32(cfg + 4) | 0x00020000u | irq); | 95 | out_be32(cfg + 4, in_be32(cfg + 4) | 0x00020000u | irq); |
93 | } | 96 | } |
94 | 97 | ||
95 | static void spider_disable_irq(unsigned int irq) | 98 | static void spider_mask_irq(unsigned int irq) |
96 | { | 99 | { |
97 | void __iomem *cfg = spider_get_irq_config(irq); | 100 | void __iomem *cfg = spider_get_irq_config(irq); |
98 | irq = spider_get_nr(irq); | 101 | irq = spider_get_nr(irq); |
@@ -100,39 +103,21 @@ static void spider_disable_irq(unsigned int irq) | |||
100 | out_be32(cfg, in_be32(cfg) & ~0x30000000u); | 103 | out_be32(cfg, in_be32(cfg) & ~0x30000000u); |
101 | } | 104 | } |
102 | 105 | ||
103 | static unsigned int spider_startup_irq(unsigned int irq) | ||
104 | { | ||
105 | spider_enable_irq(irq); | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static void spider_shutdown_irq(unsigned int irq) | ||
110 | { | ||
111 | spider_disable_irq(irq); | ||
112 | } | ||
113 | |||
114 | static void spider_end_irq(unsigned int irq) | ||
115 | { | ||
116 | spider_enable_irq(irq); | ||
117 | } | ||
118 | |||
119 | static void spider_ack_irq(unsigned int irq) | 106 | static void spider_ack_irq(unsigned int irq) |
120 | { | 107 | { |
121 | spider_disable_irq(irq); | 108 | /* Should reset edge detection logic but we don't configure any edge interrupt |
122 | iic_local_enable(); | 109 | * at the moment. |
110 | */ | ||
123 | } | 111 | } |
124 | 112 | ||
125 | static struct hw_interrupt_type spider_pic = { | 113 | static struct irq_chip spider_pic = { |
126 | .typename = " SPIDER ", | 114 | .typename = " SPIDER ", |
127 | .startup = spider_startup_irq, | 115 | .unmask = spider_unmask_irq, |
128 | .shutdown = spider_shutdown_irq, | 116 | .mask = spider_mask_irq, |
129 | .enable = spider_enable_irq, | ||
130 | .disable = spider_disable_irq, | ||
131 | .ack = spider_ack_irq, | 117 | .ack = spider_ack_irq, |
132 | .end = spider_end_irq, | ||
133 | }; | 118 | }; |
134 | 119 | ||
135 | int spider_get_irq(int node) | 120 | static int spider_get_irq(int node) |
136 | { | 121 | { |
137 | unsigned long cs; | 122 | unsigned long cs; |
138 | void __iomem *regs = spider_pics[node]; | 123 | void __iomem *regs = spider_pics[node]; |
@@ -145,95 +130,89 @@ int spider_get_irq(int node) | |||
145 | return cs; | 130 | return cs; |
146 | } | 131 | } |
147 | 132 | ||
133 | static void spider_irq_cascade(unsigned int irq, struct irq_desc *desc, | ||
134 | struct pt_regs *regs) | ||
135 | { | ||
136 | int node = (int)(long)desc->handler_data; | ||
137 | int cascade_irq; | ||
138 | |||
139 | cascade_irq = spider_get_irq(node); | ||
140 | generic_handle_irq(cascade_irq, regs); | ||
141 | desc->chip->eoi(irq); | ||
142 | } | ||
143 | |||
148 | /* hardcoded part to be compatible with older firmware */ | 144 | /* hardcoded part to be compatible with older firmware */ |
149 | 145 | ||
150 | void spider_init_IRQ_hardcoded(void) | 146 | static void __init spider_init_one(int node, unsigned long addr) |
151 | { | 147 | { |
152 | int node; | 148 | int n, irq; |
153 | long spiderpic; | 149 | |
154 | long pics[] = { 0x24000008000, 0x34000008000 }; | 150 | spider_pics[node] = ioremap(addr, 0x800); |
155 | int n; | 151 | if (spider_pics[node] == NULL) |
156 | 152 | panic("spider_pic: can't map registers !"); | |
157 | pr_debug("%s(%d): Using hardcoded defaults\n", __FUNCTION__, __LINE__); | 153 | |
158 | 154 | printk(KERN_INFO "spider_pic: mapped for node %d, addr: 0x%lx mapped to %p\n", | |
159 | for (node = 0; node < num_present_cpus()/2; node++) { | 155 | node, addr, spider_pics[node]); |
160 | spiderpic = pics[node]; | 156 | |
161 | printk(KERN_DEBUG "SPIDER addr: %lx\n", spiderpic); | 157 | for (n = 0; n < IIC_NUM_EXT; n++) { |
162 | spider_pics[node] = ioremap(spiderpic, 0x800); | 158 | if (n == IIC_EXT_CASCADE) |
163 | for (n = 0; n < IIC_NUM_EXT; n++) { | 159 | continue; |
164 | int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE; | 160 | irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE; |
165 | get_irq_desc(irq)->chip = &spider_pic; | 161 | set_irq_chip_and_handler(irq, &spider_pic, handle_level_irq); |
166 | } | 162 | get_irq_desc(irq)->status |= IRQ_LEVEL; |
167 | |||
168 | /* do not mask any interrupts because of level */ | ||
169 | out_be32(spider_pics[node] + TIR_MSK, 0x0); | ||
170 | |||
171 | /* disable edge detection clear */ | ||
172 | /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */ | ||
173 | |||
174 | /* enable interrupt packets to be output */ | ||
175 | out_be32(spider_pics[node] + TIR_PIEN, | ||
176 | in_be32(spider_pics[node] + TIR_PIEN) | 0x1); | ||
177 | |||
178 | /* Enable the interrupt detection enable bit. Do this last! */ | ||
179 | out_be32(spider_pics[node] + TIR_DEN, | ||
180 | in_be32(spider_pics[node] + TIR_DEN) | 0x1); | ||
181 | } | 163 | } |
164 | |||
165 | /* do not mask any interrupts because of level */ | ||
166 | out_be32(spider_pics[node] + TIR_MSK, 0x0); | ||
167 | |||
168 | /* disable edge detection clear */ | ||
169 | /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */ | ||
170 | |||
171 | /* enable interrupt packets to be output */ | ||
172 | out_be32(spider_pics[node] + TIR_PIEN, | ||
173 | in_be32(spider_pics[node] + TIR_PIEN) | 0x1); | ||
174 | |||
175 | /* Hook up cascade */ | ||
176 | irq = IIC_EXT_CASCADE + node * IIC_NODE_STRIDE; | ||
177 | set_irq_data(irq, (void *)(long)node); | ||
178 | set_irq_chained_handler(irq, spider_irq_cascade); | ||
179 | |||
180 | /* Enable the interrupt detection enable bit. Do this last! */ | ||
181 | out_be32(spider_pics[node] + TIR_DEN, | ||
182 | in_be32(spider_pics[node] + TIR_DEN) | 0x1); | ||
182 | } | 183 | } |
183 | 184 | ||
184 | void spider_init_IRQ(void) | 185 | void __init spider_init_IRQ(void) |
185 | { | 186 | { |
186 | long spider_reg; | 187 | unsigned long *spider_reg; |
187 | struct device_node *dn; | 188 | struct device_node *dn; |
188 | char *compatible; | 189 | char *compatible; |
189 | int n, node = 0; | 190 | int node = 0; |
190 | 191 | ||
192 | /* XXX node numbers are totally bogus. We _hope_ we get the device nodes in the right | ||
193 | * order here but that's definitely not guaranteed, we need to get the node from the | ||
194 | * device tree instead. There is currently no proper property for it (but our whole | ||
195 | * device-tree is bogus anyway) so all we can do is pray or maybe test the address | ||
196 | * and deduce the node-id | ||
197 | */ | ||
191 | for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) { | 198 | for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) { |
192 | compatible = (char *)get_property(dn, "compatible", NULL); | 199 | compatible = (char *)get_property(dn, "compatible", NULL); |
193 | 200 | ||
194 | if (!compatible) | 201 | if (!compatible) |
195 | continue; | 202 | continue; |
196 | 203 | ||
197 | if (strstr(compatible, "CBEA,platform-spider-pic")) | 204 | if (strstr(compatible, "CBEA,platform-spider-pic")) |
198 | spider_reg = *(long *)get_property(dn,"reg", NULL); | 205 | spider_reg = (unsigned long *)get_property(dn, "reg", NULL); |
199 | else if (strstr(compatible, "sti,platform-spider-pic")) { | 206 | else if (strstr(compatible, "sti,platform-spider-pic") && (node < 2)) { |
200 | spider_init_IRQ_hardcoded(); | 207 | static long hard_coded_pics[] = { 0x24000008000, 0x34000008000 }; |
201 | return; | 208 | spider_reg = &hard_coded_pics[node]; |
202 | } else | 209 | } else |
203 | continue; | 210 | continue; |
204 | 211 | ||
205 | if (!spider_reg) | 212 | if (spider_reg == NULL) |
206 | printk("interrupt controller does not have reg property !\n"); | 213 | printk(KERN_ERR "spider_pic: No address for node %d\n", node); |
207 | |||
208 | n = prom_n_addr_cells(dn); | ||
209 | |||
210 | if ( n != 2) | ||
211 | printk("reg property with invalid number of elements \n"); | ||
212 | |||
213 | spider_pics[node] = ioremap(spider_reg, 0x800); | ||
214 | |||
215 | printk("SPIDER addr: %lx with %i addr_cells mapped to %p\n", | ||
216 | spider_reg, n, spider_pics[node]); | ||
217 | |||
218 | for (n = 0; n < IIC_NUM_EXT; n++) { | ||
219 | int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE; | ||
220 | get_irq_desc(irq)->chip = &spider_pic; | ||
221 | } | ||
222 | |||
223 | /* do not mask any interrupts because of level */ | ||
224 | out_be32(spider_pics[node] + TIR_MSK, 0x0); | ||
225 | |||
226 | /* disable edge detection clear */ | ||
227 | /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */ | ||
228 | |||
229 | /* enable interrupt packets to be output */ | ||
230 | out_be32(spider_pics[node] + TIR_PIEN, | ||
231 | in_be32(spider_pics[node] + TIR_PIEN) | 0x1); | ||
232 | |||
233 | /* Enable the interrupt detection enable bit. Do this last! */ | ||
234 | out_be32(spider_pics[node] + TIR_DEN, | ||
235 | in_be32(spider_pics[node] + TIR_DEN) | 0x1); | ||
236 | 214 | ||
215 | spider_init_one(node, *spider_reg); | ||
237 | node++; | 216 | node++; |
238 | } | 217 | } |
239 | } | 218 | } |
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index 1f1771b212b4..a5dffc8d93a9 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c | |||
@@ -315,6 +315,21 @@ chrp_event_scan(unsigned long unused) | |||
315 | jiffies + event_scan_interval); | 315 | jiffies + event_scan_interval); |
316 | } | 316 | } |
317 | 317 | ||
318 | void chrp_8259_cascade(unsigned int irq, struct irq_desc *desc, | ||
319 | struct pt_regs *regs) | ||
320 | { | ||
321 | unsigned int max = 100; | ||
322 | |||
323 | while(max--) { | ||
324 | int irq = i8259_irq(regs); | ||
325 | if (max == 99) | ||
326 | desc->chip->eoi(irq); | ||
327 | if (irq < 0) | ||
328 | break; | ||
329 | generic_handle_irq(irq, regs); | ||
330 | }; | ||
331 | } | ||
332 | |||
318 | /* | 333 | /* |
319 | * Finds the open-pic node and sets up the mpic driver. | 334 | * Finds the open-pic node and sets up the mpic driver. |
320 | */ | 335 | */ |
@@ -402,7 +417,7 @@ static void __init chrp_find_openpic(void) | |||
402 | } | 417 | } |
403 | 418 | ||
404 | mpic_init(chrp_mpic); | 419 | mpic_init(chrp_mpic); |
405 | mpic_setup_cascade(NUM_ISA_INTERRUPTS, i8259_irq_cascade, NULL); | 420 | set_irq_chained_handler(NUM_ISA_INTERRUPTS, chrp_8259_cascade); |
406 | } | 421 | } |
407 | 422 | ||
408 | #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) | 423 | #if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(XMON) |
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index f70e820e7304..7fb6a08786c0 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c | |||
@@ -297,13 +297,13 @@ static void iseries_end_IRQ(unsigned int irq) | |||
297 | (REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq)); | 297 | (REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq)); |
298 | } | 298 | } |
299 | 299 | ||
300 | static hw_irq_controller iSeries_IRQ_handler = { | 300 | static struct irq_chip iseries_pic = { |
301 | .typename = "iSeries irq controller", | 301 | .typename = "iSeries irq controller", |
302 | .startup = iseries_startup_IRQ, | 302 | .startup = iseries_startup_IRQ, |
303 | .shutdown = iseries_shutdown_IRQ, | 303 | .shutdown = iseries_shutdown_IRQ, |
304 | .enable = iseries_enable_IRQ, | 304 | .unmask = iseries_enable_IRQ, |
305 | .disable = iseries_disable_IRQ, | 305 | .mask = iseries_disable_IRQ, |
306 | .end = iseries_end_IRQ | 306 | .eoi = iseries_end_IRQ |
307 | }; | 307 | }; |
308 | 308 | ||
309 | /* | 309 | /* |
@@ -322,8 +322,7 @@ int __init iSeries_allocate_IRQ(HvBusNumber bus, | |||
322 | realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3) | 322 | realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3) |
323 | + function; | 323 | + function; |
324 | virtirq = virt_irq_create_mapping(realirq); | 324 | virtirq = virt_irq_create_mapping(realirq); |
325 | 325 | set_irq_chip_and_handler(virtirq, &iseries_pic, handle_fasteoi_irq); | |
326 | irq_desc[virtirq].chip = &iSeries_IRQ_handler; | ||
327 | return virtirq; | 326 | return virtirq; |
328 | } | 327 | } |
329 | 328 | ||
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index c9b09a9e6050..58a4c7b90b8b 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c | |||
@@ -70,18 +70,19 @@ static struct interrupt_info gatwick_int_pool[GATWICK_IRQ_POOL_SIZE]; | |||
70 | 70 | ||
71 | #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) | 71 | #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) |
72 | static unsigned long ppc_lost_interrupts[NR_MASK_WORDS]; | 72 | static unsigned long ppc_lost_interrupts[NR_MASK_WORDS]; |
73 | static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; | ||
74 | static int pmac_irq_cascade = -1; | ||
73 | 75 | ||
74 | /* | 76 | static void __pmac_retrigger(unsigned int irq_nr) |
75 | * Mark an irq as "lost". This is only used on the pmac | ||
76 | * since it can lose interrupts (see pmac_set_irq_mask). | ||
77 | * -- Cort | ||
78 | */ | ||
79 | void __set_lost(unsigned long irq_nr, int nokick) | ||
80 | { | 77 | { |
81 | if (!test_and_set_bit(irq_nr, ppc_lost_interrupts)) { | 78 | if (irq_nr >= max_real_irqs && pmac_irq_cascade > 0) { |
79 | __set_bit(irq_nr, ppc_lost_interrupts); | ||
80 | irq_nr = pmac_irq_cascade; | ||
81 | mb(); | ||
82 | } | ||
83 | if (!__test_and_set_bit(irq_nr, ppc_lost_interrupts)) { | ||
82 | atomic_inc(&ppc_n_lost_interrupts); | 84 | atomic_inc(&ppc_n_lost_interrupts); |
83 | if (!nokick) | 85 | set_dec(1); |
84 | set_dec(1); | ||
85 | } | 86 | } |
86 | } | 87 | } |
87 | 88 | ||
@@ -94,10 +95,10 @@ static void pmac_mask_and_ack_irq(unsigned int irq_nr) | |||
94 | if ((unsigned)irq_nr >= max_irqs) | 95 | if ((unsigned)irq_nr >= max_irqs) |
95 | return; | 96 | return; |
96 | 97 | ||
97 | clear_bit(irq_nr, ppc_cached_irq_mask); | ||
98 | if (test_and_clear_bit(irq_nr, ppc_lost_interrupts)) | ||
99 | atomic_dec(&ppc_n_lost_interrupts); | ||
100 | spin_lock_irqsave(&pmac_pic_lock, flags); | 98 | spin_lock_irqsave(&pmac_pic_lock, flags); |
99 | __clear_bit(irq_nr, ppc_cached_irq_mask); | ||
100 | if (__test_and_clear_bit(irq_nr, ppc_lost_interrupts)) | ||
101 | atomic_dec(&ppc_n_lost_interrupts); | ||
101 | out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]); | 102 | out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]); |
102 | out_le32(&pmac_irq_hw[i]->ack, bit); | 103 | out_le32(&pmac_irq_hw[i]->ack, bit); |
103 | do { | 104 | do { |
@@ -109,7 +110,7 @@ static void pmac_mask_and_ack_irq(unsigned int irq_nr) | |||
109 | spin_unlock_irqrestore(&pmac_pic_lock, flags); | 110 | spin_unlock_irqrestore(&pmac_pic_lock, flags); |
110 | } | 111 | } |
111 | 112 | ||
112 | static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost) | 113 | static void pmac_ack_irq(unsigned int irq_nr) |
113 | { | 114 | { |
114 | unsigned long bit = 1UL << (irq_nr & 0x1f); | 115 | unsigned long bit = 1UL << (irq_nr & 0x1f); |
115 | int i = irq_nr >> 5; | 116 | int i = irq_nr >> 5; |
@@ -118,7 +119,22 @@ static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost) | |||
118 | if ((unsigned)irq_nr >= max_irqs) | 119 | if ((unsigned)irq_nr >= max_irqs) |
119 | return; | 120 | return; |
120 | 121 | ||
121 | spin_lock_irqsave(&pmac_pic_lock, flags); | 122 | spin_lock_irqsave(&pmac_pic_lock, flags); |
123 | if (__test_and_clear_bit(irq_nr, ppc_lost_interrupts)) | ||
124 | atomic_dec(&ppc_n_lost_interrupts); | ||
125 | out_le32(&pmac_irq_hw[i]->ack, bit); | ||
126 | (void)in_le32(&pmac_irq_hw[i]->ack); | ||
127 | spin_unlock_irqrestore(&pmac_pic_lock, flags); | ||
128 | } | ||
129 | |||
130 | static void __pmac_set_irq_mask(unsigned int irq_nr, int nokicklost) | ||
131 | { | ||
132 | unsigned long bit = 1UL << (irq_nr & 0x1f); | ||
133 | int i = irq_nr >> 5; | ||
134 | |||
135 | if ((unsigned)irq_nr >= max_irqs) | ||
136 | return; | ||
137 | |||
122 | /* enable unmasked interrupts */ | 138 | /* enable unmasked interrupts */ |
123 | out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]); | 139 | out_le32(&pmac_irq_hw[i]->enable, ppc_cached_irq_mask[i]); |
124 | 140 | ||
@@ -135,8 +151,7 @@ static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost) | |||
135 | * the bit in the flag register or request another interrupt. | 151 | * the bit in the flag register or request another interrupt. |
136 | */ | 152 | */ |
137 | if (bit & ppc_cached_irq_mask[i] & in_le32(&pmac_irq_hw[i]->level)) | 153 | if (bit & ppc_cached_irq_mask[i] & in_le32(&pmac_irq_hw[i]->level)) |
138 | __set_lost((ulong)irq_nr, nokicklost); | 154 | __pmac_retrigger(irq_nr); |
139 | spin_unlock_irqrestore(&pmac_pic_lock, flags); | ||
140 | } | 155 | } |
141 | 156 | ||
142 | /* When an irq gets requested for the first client, if it's an | 157 | /* When an irq gets requested for the first client, if it's an |
@@ -144,62 +159,67 @@ static void pmac_set_irq_mask(unsigned int irq_nr, int nokicklost) | |||
144 | */ | 159 | */ |
145 | static unsigned int pmac_startup_irq(unsigned int irq_nr) | 160 | static unsigned int pmac_startup_irq(unsigned int irq_nr) |
146 | { | 161 | { |
162 | unsigned long flags; | ||
147 | unsigned long bit = 1UL << (irq_nr & 0x1f); | 163 | unsigned long bit = 1UL << (irq_nr & 0x1f); |
148 | int i = irq_nr >> 5; | 164 | int i = irq_nr >> 5; |
149 | 165 | ||
166 | spin_lock_irqsave(&pmac_pic_lock, flags); | ||
150 | if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0) | 167 | if ((irq_desc[irq_nr].status & IRQ_LEVEL) == 0) |
151 | out_le32(&pmac_irq_hw[i]->ack, bit); | 168 | out_le32(&pmac_irq_hw[i]->ack, bit); |
152 | set_bit(irq_nr, ppc_cached_irq_mask); | 169 | __set_bit(irq_nr, ppc_cached_irq_mask); |
153 | pmac_set_irq_mask(irq_nr, 0); | 170 | __pmac_set_irq_mask(irq_nr, 0); |
171 | spin_unlock_irqrestore(&pmac_pic_lock, flags); | ||
154 | 172 | ||
155 | return 0; | 173 | return 0; |
156 | } | 174 | } |
157 | 175 | ||
158 | static void pmac_mask_irq(unsigned int irq_nr) | 176 | static void pmac_mask_irq(unsigned int irq_nr) |
159 | { | 177 | { |
160 | clear_bit(irq_nr, ppc_cached_irq_mask); | 178 | unsigned long flags; |
161 | pmac_set_irq_mask(irq_nr, 0); | 179 | |
162 | mb(); | 180 | spin_lock_irqsave(&pmac_pic_lock, flags); |
181 | __clear_bit(irq_nr, ppc_cached_irq_mask); | ||
182 | __pmac_set_irq_mask(irq_nr, 0); | ||
183 | spin_unlock_irqrestore(&pmac_pic_lock, flags); | ||
163 | } | 184 | } |
164 | 185 | ||
165 | static void pmac_unmask_irq(unsigned int irq_nr) | 186 | static void pmac_unmask_irq(unsigned int irq_nr) |
166 | { | 187 | { |
167 | set_bit(irq_nr, ppc_cached_irq_mask); | 188 | unsigned long flags; |
168 | pmac_set_irq_mask(irq_nr, 0); | 189 | |
190 | spin_lock_irqsave(&pmac_pic_lock, flags); | ||
191 | __set_bit(irq_nr, ppc_cached_irq_mask); | ||
192 | __pmac_set_irq_mask(irq_nr, 0); | ||
193 | spin_unlock_irqrestore(&pmac_pic_lock, flags); | ||
169 | } | 194 | } |
170 | 195 | ||
171 | static void pmac_end_irq(unsigned int irq_nr) | 196 | static int pmac_retrigger(unsigned int irq_nr) |
172 | { | 197 | { |
173 | if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)) | 198 | unsigned long flags; |
174 | && irq_desc[irq_nr].action) { | ||
175 | set_bit(irq_nr, ppc_cached_irq_mask); | ||
176 | pmac_set_irq_mask(irq_nr, 1); | ||
177 | } | ||
178 | } | ||
179 | 199 | ||
200 | spin_lock_irqsave(&pmac_pic_lock, flags); | ||
201 | __pmac_retrigger(irq_nr); | ||
202 | spin_unlock_irqrestore(&pmac_pic_lock, flags); | ||
203 | return 1; | ||
204 | } | ||
180 | 205 | ||
181 | struct hw_interrupt_type pmac_pic = { | 206 | static struct irq_chip pmac_pic = { |
182 | .typename = " PMAC-PIC ", | 207 | .typename = " PMAC-PIC ", |
183 | .startup = pmac_startup_irq, | 208 | .startup = pmac_startup_irq, |
184 | .enable = pmac_unmask_irq, | 209 | .mask = pmac_mask_irq, |
185 | .disable = pmac_mask_irq, | 210 | .ack = pmac_ack_irq, |
186 | .ack = pmac_mask_and_ack_irq, | 211 | .mask_ack = pmac_mask_and_ack_irq, |
187 | .end = pmac_end_irq, | 212 | .unmask = pmac_unmask_irq, |
188 | }; | 213 | .retrigger = pmac_retrigger, |
189 | |||
190 | struct hw_interrupt_type gatwick_pic = { | ||
191 | .typename = " GATWICK ", | ||
192 | .startup = pmac_startup_irq, | ||
193 | .enable = pmac_unmask_irq, | ||
194 | .disable = pmac_mask_irq, | ||
195 | .ack = pmac_mask_and_ack_irq, | ||
196 | .end = pmac_end_irq, | ||
197 | }; | 214 | }; |
198 | 215 | ||
199 | static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs) | 216 | static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs) |
200 | { | 217 | { |
218 | unsigned long flags; | ||
201 | int irq, bits; | 219 | int irq, bits; |
220 | int rc = IRQ_NONE; | ||
202 | 221 | ||
222 | spin_lock_irqsave(&pmac_pic_lock, flags); | ||
203 | for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) { | 223 | for (irq = max_irqs; (irq -= 32) >= max_real_irqs; ) { |
204 | int i = irq >> 5; | 224 | int i = irq >> 5; |
205 | bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i]; | 225 | bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i]; |
@@ -209,17 +229,20 @@ static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs) | |||
209 | if (bits == 0) | 229 | if (bits == 0) |
210 | continue; | 230 | continue; |
211 | irq += __ilog2(bits); | 231 | irq += __ilog2(bits); |
232 | spin_unlock_irqrestore(&pmac_pic_lock, flags); | ||
212 | __do_IRQ(irq, regs); | 233 | __do_IRQ(irq, regs); |
213 | return IRQ_HANDLED; | 234 | spin_lock_irqsave(&pmac_pic_lock, flags); |
235 | rc = IRQ_HANDLED; | ||
214 | } | 236 | } |
215 | printk("gatwick irq not from gatwick pic\n"); | 237 | spin_unlock_irqrestore(&pmac_pic_lock, flags); |
216 | return IRQ_NONE; | 238 | return rc; |
217 | } | 239 | } |
218 | 240 | ||
219 | static int pmac_get_irq(struct pt_regs *regs) | 241 | static int pmac_get_irq(struct pt_regs *regs) |
220 | { | 242 | { |
221 | int irq; | 243 | int irq; |
222 | unsigned long bits = 0; | 244 | unsigned long bits = 0; |
245 | unsigned long flags; | ||
223 | 246 | ||
224 | #ifdef CONFIG_SMP | 247 | #ifdef CONFIG_SMP |
225 | void psurge_smp_message_recv(struct pt_regs *); | 248 | void psurge_smp_message_recv(struct pt_regs *); |
@@ -230,6 +253,7 @@ static int pmac_get_irq(struct pt_regs *regs) | |||
230 | return -2; /* ignore, already handled */ | 253 | return -2; /* ignore, already handled */ |
231 | } | 254 | } |
232 | #endif /* CONFIG_SMP */ | 255 | #endif /* CONFIG_SMP */ |
256 | spin_lock_irqsave(&pmac_pic_lock, flags); | ||
233 | for (irq = max_real_irqs; (irq -= 32) >= 0; ) { | 257 | for (irq = max_real_irqs; (irq -= 32) >= 0; ) { |
234 | int i = irq >> 5; | 258 | int i = irq >> 5; |
235 | bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i]; | 259 | bits = in_le32(&pmac_irq_hw[i]->event) | ppc_lost_interrupts[i]; |
@@ -241,6 +265,7 @@ static int pmac_get_irq(struct pt_regs *regs) | |||
241 | irq += __ilog2(bits); | 265 | irq += __ilog2(bits); |
242 | break; | 266 | break; |
243 | } | 267 | } |
268 | spin_unlock_irqrestore(&pmac_pic_lock, flags); | ||
244 | 269 | ||
245 | return irq; | 270 | return irq; |
246 | } | 271 | } |
@@ -389,7 +414,6 @@ static struct irqaction gatwick_cascade_action = { | |||
389 | static void __init pmac_pic_probe_oldstyle(void) | 414 | static void __init pmac_pic_probe_oldstyle(void) |
390 | { | 415 | { |
391 | int i; | 416 | int i; |
392 | int irq_cascade = -1; | ||
393 | struct device_node *master = NULL; | 417 | struct device_node *master = NULL; |
394 | struct device_node *slave = NULL; | 418 | struct device_node *slave = NULL; |
395 | u8 __iomem *addr; | 419 | u8 __iomem *addr; |
@@ -443,9 +467,16 @@ static void __init pmac_pic_probe_oldstyle(void) | |||
443 | } | 467 | } |
444 | BUG_ON(master == NULL); | 468 | BUG_ON(master == NULL); |
445 | 469 | ||
446 | /* Set the handler for the main PIC */ | 470 | /* Mark level interrupts and set handlers */ |
447 | for ( i = 0; i < max_real_irqs ; i++ ) | 471 | for (i = 0; i < max_irqs; i++) { |
448 | irq_desc[i].chip = &pmac_pic; | 472 | int level = !!(level_mask[i >> 5] & (1UL << (i & 0x1f))); |
473 | if (level) | ||
474 | irq_desc[i].status |= IRQ_LEVEL; | ||
475 | else | ||
476 | irq_desc[i].status |= IRQ_DELAYED_DISABLE; | ||
477 | set_irq_chip_and_handler(i, &pmac_pic, level ? | ||
478 | handle_level_irq : handle_edge_irq); | ||
479 | } | ||
449 | 480 | ||
450 | /* Get addresses of first controller if we have a node for it */ | 481 | /* Get addresses of first controller if we have a node for it */ |
451 | BUG_ON(of_address_to_resource(master, 0, &r)); | 482 | BUG_ON(of_address_to_resource(master, 0, &r)); |
@@ -472,29 +503,22 @@ static void __init pmac_pic_probe_oldstyle(void) | |||
472 | pmac_irq_hw[i++] = | 503 | pmac_irq_hw[i++] = |
473 | (volatile struct pmac_irq_hw __iomem *) | 504 | (volatile struct pmac_irq_hw __iomem *) |
474 | (addr + 0x10); | 505 | (addr + 0x10); |
475 | irq_cascade = slave->intrs[0].line; | 506 | pmac_irq_cascade = slave->intrs[0].line; |
476 | 507 | ||
477 | printk(KERN_INFO "irq: Found slave Apple PIC %s for %d irqs" | 508 | printk(KERN_INFO "irq: Found slave Apple PIC %s for %d irqs" |
478 | " cascade: %d\n", slave->full_name, | 509 | " cascade: %d\n", slave->full_name, |
479 | max_irqs - max_real_irqs, irq_cascade); | 510 | max_irqs - max_real_irqs, pmac_irq_cascade); |
480 | } | 511 | } |
481 | of_node_put(slave); | 512 | of_node_put(slave); |
482 | 513 | ||
483 | /* disable all interrupts in all controllers */ | 514 | /* Disable all interrupts in all controllers */ |
484 | for (i = 0; i * 32 < max_irqs; ++i) | 515 | for (i = 0; i * 32 < max_irqs; ++i) |
485 | out_le32(&pmac_irq_hw[i]->enable, 0); | 516 | out_le32(&pmac_irq_hw[i]->enable, 0); |
486 | 517 | ||
487 | /* mark level interrupts */ | 518 | /* Hookup cascade irq */ |
488 | for (i = 0; i < max_irqs; i++) | 519 | if (slave) |
489 | if (level_mask[i >> 5] & (1UL << (i & 0x1f))) | 520 | setup_irq(pmac_irq_cascade, &gatwick_cascade_action); |
490 | irq_desc[i].status = IRQ_LEVEL; | ||
491 | 521 | ||
492 | /* Setup handlers for secondary controller and hook cascade irq*/ | ||
493 | if (slave) { | ||
494 | for ( i = max_real_irqs ; i < max_irqs ; i++ ) | ||
495 | irq_desc[i].chip = &gatwick_pic; | ||
496 | setup_irq(irq_cascade, &gatwick_cascade_action); | ||
497 | } | ||
498 | printk(KERN_INFO "irq: System has %d possible interrupts\n", max_irqs); | 522 | printk(KERN_INFO "irq: System has %d possible interrupts\n", max_irqs); |
499 | #ifdef CONFIG_XMON | 523 | #ifdef CONFIG_XMON |
500 | setup_irq(20, &xmon_action); | 524 | setup_irq(20, &xmon_action); |
@@ -502,9 +526,20 @@ static void __init pmac_pic_probe_oldstyle(void) | |||
502 | } | 526 | } |
503 | #endif /* CONFIG_PPC32 */ | 527 | #endif /* CONFIG_PPC32 */ |
504 | 528 | ||
505 | static int pmac_u3_cascade(struct pt_regs *regs, void *data) | 529 | static void pmac_u3_cascade(unsigned int irq, struct irq_desc *desc, |
530 | struct pt_regs *regs) | ||
506 | { | 531 | { |
507 | return mpic_get_one_irq((struct mpic *)data, regs); | 532 | struct mpic *mpic = desc->handler_data; |
533 | unsigned int max = 100; | ||
534 | |||
535 | while(max--) { | ||
536 | int cascade_irq = mpic_get_one_irq(mpic, regs); | ||
537 | if (max == 99) | ||
538 | desc->chip->eoi(irq); | ||
539 | if (irq < 0) | ||
540 | break; | ||
541 | generic_handle_irq(cascade_irq, regs); | ||
542 | }; | ||
508 | } | 543 | } |
509 | 544 | ||
510 | static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic) | 545 | static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic) |
@@ -612,7 +647,8 @@ static int __init pmac_pic_probe_mpic(void) | |||
612 | of_node_put(slave); | 647 | of_node_put(slave); |
613 | return 0; | 648 | return 0; |
614 | } | 649 | } |
615 | mpic_setup_cascade(slave->intrs[0].line, pmac_u3_cascade, mpic2); | 650 | set_irq_data(slave->intrs[0].line, mpic2); |
651 | set_irq_chained_handler(slave->intrs[0].line, pmac_u3_cascade); | ||
616 | 652 | ||
617 | of_node_put(slave); | 653 | of_node_put(slave); |
618 | return 0; | 654 | return 0; |
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 999509d28af8..476b564a208b 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c | |||
@@ -118,6 +118,21 @@ static void __init fwnmi_init(void) | |||
118 | fwnmi_active = 1; | 118 | fwnmi_active = 1; |
119 | } | 119 | } |
120 | 120 | ||
121 | void pSeries_8259_cascade(unsigned int irq, struct irq_desc *desc, | ||
122 | struct pt_regs *regs) | ||
123 | { | ||
124 | unsigned int max = 100; | ||
125 | |||
126 | while(max--) { | ||
127 | int cascade_irq = i8259_irq(regs); | ||
128 | if (max == 99) | ||
129 | desc->chip->eoi(irq); | ||
130 | if (cascade_irq < 0) | ||
131 | break; | ||
132 | generic_handle_irq(cascade_irq, regs); | ||
133 | }; | ||
134 | } | ||
135 | |||
121 | static void __init pSeries_init_mpic(void) | 136 | static void __init pSeries_init_mpic(void) |
122 | { | 137 | { |
123 | unsigned int *addrp; | 138 | unsigned int *addrp; |
@@ -140,7 +155,7 @@ static void __init pSeries_init_mpic(void) | |||
140 | i8259_init(intack, 0); | 155 | i8259_init(intack, 0); |
141 | 156 | ||
142 | /* Hook cascade to mpic */ | 157 | /* Hook cascade to mpic */ |
143 | mpic_setup_cascade(NUM_ISA_INTERRUPTS, i8259_irq_cascade, NULL); | 158 | set_irq_chained_handler(NUM_ISA_INTERRUPTS, pSeries_8259_cascade); |
144 | } | 159 | } |
145 | 160 | ||
146 | static void __init pSeries_setup_mpic(void) | 161 | static void __init pSeries_setup_mpic(void) |
@@ -201,10 +216,8 @@ static void __init pSeries_setup_arch(void) | |||
201 | /* Allocate the mpic now, so that find_and_init_phbs() can | 216 | /* Allocate the mpic now, so that find_and_init_phbs() can |
202 | * fill the ISUs */ | 217 | * fill the ISUs */ |
203 | pSeries_setup_mpic(); | 218 | pSeries_setup_mpic(); |
204 | } else { | 219 | } else |
205 | ppc_md.init_IRQ = xics_init_IRQ; | 220 | ppc_md.init_IRQ = xics_init_IRQ; |
206 | ppc_md.get_irq = xics_get_irq; | ||
207 | } | ||
208 | 221 | ||
209 | #ifdef CONFIG_SMP | 222 | #ifdef CONFIG_SMP |
210 | smp_init_pSeries(); | 223 | smp_init_pSeries(); |
@@ -291,10 +304,7 @@ static void pSeries_mach_cpu_die(void) | |||
291 | { | 304 | { |
292 | local_irq_disable(); | 305 | local_irq_disable(); |
293 | idle_task_exit(); | 306 | idle_task_exit(); |
294 | /* Some hardware requires clearing the CPPR, while other hardware does not | 307 | xics_teardown_cpu(0); |
295 | * it is safe either way | ||
296 | */ | ||
297 | pSeriesLP_cppr_info(0, 0); | ||
298 | rtas_stop_self(); | 308 | rtas_stop_self(); |
299 | /* Should never get here... */ | 309 | /* Should never get here... */ |
300 | BUG(); | 310 | BUG(); |
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 2ffebe31cb2d..c7f04420066d 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c | |||
@@ -31,23 +31,6 @@ | |||
31 | 31 | ||
32 | #include "xics.h" | 32 | #include "xics.h" |
33 | 33 | ||
34 | static unsigned int xics_startup(unsigned int irq); | ||
35 | static void xics_enable_irq(unsigned int irq); | ||
36 | static void xics_disable_irq(unsigned int irq); | ||
37 | static void xics_mask_and_ack_irq(unsigned int irq); | ||
38 | static void xics_end_irq(unsigned int irq); | ||
39 | static void xics_set_affinity(unsigned int irq_nr, cpumask_t cpumask); | ||
40 | |||
41 | static struct hw_interrupt_type xics_pic = { | ||
42 | .typename = " XICS ", | ||
43 | .startup = xics_startup, | ||
44 | .enable = xics_enable_irq, | ||
45 | .disable = xics_disable_irq, | ||
46 | .ack = xics_mask_and_ack_irq, | ||
47 | .end = xics_end_irq, | ||
48 | .set_affinity = xics_set_affinity | ||
49 | }; | ||
50 | |||
51 | /* This is used to map real irq numbers to virtual */ | 34 | /* This is used to map real irq numbers to virtual */ |
52 | static struct radix_tree_root irq_map = RADIX_TREE_INIT(GFP_ATOMIC); | 35 | static struct radix_tree_root irq_map = RADIX_TREE_INIT(GFP_ATOMIC); |
53 | 36 | ||
@@ -98,47 +81,33 @@ static int ibm_set_xive; | |||
98 | static int ibm_int_on; | 81 | static int ibm_int_on; |
99 | static int ibm_int_off; | 82 | static int ibm_int_off; |
100 | 83 | ||
101 | typedef struct { | ||
102 | int (*xirr_info_get)(int cpu); | ||
103 | void (*xirr_info_set)(int cpu, int val); | ||
104 | void (*cppr_info)(int cpu, u8 val); | ||
105 | void (*qirr_info)(int cpu, u8 val); | ||
106 | } xics_ops; | ||
107 | 84 | ||
85 | /* Direct HW low level accessors */ | ||
108 | 86 | ||
109 | /* SMP */ | ||
110 | 87 | ||
111 | static int pSeries_xirr_info_get(int n_cpu) | 88 | static inline int direct_xirr_info_get(int n_cpu) |
112 | { | 89 | { |
113 | return in_be32(&xics_per_cpu[n_cpu]->xirr.word); | 90 | return in_be32(&xics_per_cpu[n_cpu]->xirr.word); |
114 | } | 91 | } |
115 | 92 | ||
116 | static void pSeries_xirr_info_set(int n_cpu, int value) | 93 | static inline void direct_xirr_info_set(int n_cpu, int value) |
117 | { | 94 | { |
118 | out_be32(&xics_per_cpu[n_cpu]->xirr.word, value); | 95 | out_be32(&xics_per_cpu[n_cpu]->xirr.word, value); |
119 | } | 96 | } |
120 | 97 | ||
121 | static void pSeries_cppr_info(int n_cpu, u8 value) | 98 | static inline void direct_cppr_info(int n_cpu, u8 value) |
122 | { | 99 | { |
123 | out_8(&xics_per_cpu[n_cpu]->xirr.bytes[0], value); | 100 | out_8(&xics_per_cpu[n_cpu]->xirr.bytes[0], value); |
124 | } | 101 | } |
125 | 102 | ||
126 | static void pSeries_qirr_info(int n_cpu, u8 value) | 103 | static inline void direct_qirr_info(int n_cpu, u8 value) |
127 | { | 104 | { |
128 | out_8(&xics_per_cpu[n_cpu]->qirr.bytes[0], value); | 105 | out_8(&xics_per_cpu[n_cpu]->qirr.bytes[0], value); |
129 | } | 106 | } |
130 | 107 | ||
131 | static xics_ops pSeries_ops = { | ||
132 | pSeries_xirr_info_get, | ||
133 | pSeries_xirr_info_set, | ||
134 | pSeries_cppr_info, | ||
135 | pSeries_qirr_info | ||
136 | }; | ||
137 | |||
138 | static xics_ops *ops = &pSeries_ops; | ||
139 | 108 | ||
109 | /* LPAR low level accessors */ | ||
140 | 110 | ||
141 | /* LPAR */ | ||
142 | 111 | ||
143 | static inline long plpar_eoi(unsigned long xirr) | 112 | static inline long plpar_eoi(unsigned long xirr) |
144 | { | 113 | { |
@@ -161,7 +130,7 @@ static inline long plpar_xirr(unsigned long *xirr_ret) | |||
161 | return plpar_hcall(H_XIRR, 0, 0, 0, 0, xirr_ret, &dummy, &dummy); | 130 | return plpar_hcall(H_XIRR, 0, 0, 0, 0, xirr_ret, &dummy, &dummy); |
162 | } | 131 | } |
163 | 132 | ||
164 | static int pSeriesLP_xirr_info_get(int n_cpu) | 133 | static inline int lpar_xirr_info_get(int n_cpu) |
165 | { | 134 | { |
166 | unsigned long lpar_rc; | 135 | unsigned long lpar_rc; |
167 | unsigned long return_value; | 136 | unsigned long return_value; |
@@ -172,7 +141,7 @@ static int pSeriesLP_xirr_info_get(int n_cpu) | |||
172 | return (int)return_value; | 141 | return (int)return_value; |
173 | } | 142 | } |
174 | 143 | ||
175 | static void pSeriesLP_xirr_info_set(int n_cpu, int value) | 144 | static inline void lpar_xirr_info_set(int n_cpu, int value) |
176 | { | 145 | { |
177 | unsigned long lpar_rc; | 146 | unsigned long lpar_rc; |
178 | unsigned long val64 = value & 0xffffffff; | 147 | unsigned long val64 = value & 0xffffffff; |
@@ -183,7 +152,7 @@ static void pSeriesLP_xirr_info_set(int n_cpu, int value) | |||
183 | val64); | 152 | val64); |
184 | } | 153 | } |
185 | 154 | ||
186 | void pSeriesLP_cppr_info(int n_cpu, u8 value) | 155 | static inline void lpar_cppr_info(int n_cpu, u8 value) |
187 | { | 156 | { |
188 | unsigned long lpar_rc; | 157 | unsigned long lpar_rc; |
189 | 158 | ||
@@ -192,7 +161,7 @@ void pSeriesLP_cppr_info(int n_cpu, u8 value) | |||
192 | panic("bad return code cppr - rc = %lx\n", lpar_rc); | 161 | panic("bad return code cppr - rc = %lx\n", lpar_rc); |
193 | } | 162 | } |
194 | 163 | ||
195 | static void pSeriesLP_qirr_info(int n_cpu , u8 value) | 164 | static inline void lpar_qirr_info(int n_cpu , u8 value) |
196 | { | 165 | { |
197 | unsigned long lpar_rc; | 166 | unsigned long lpar_rc; |
198 | 167 | ||
@@ -201,36 +170,9 @@ static void pSeriesLP_qirr_info(int n_cpu , u8 value) | |||
201 | panic("bad return code qirr - rc = %lx\n", lpar_rc); | 170 | panic("bad return code qirr - rc = %lx\n", lpar_rc); |
202 | } | 171 | } |
203 | 172 | ||
204 | xics_ops pSeriesLP_ops = { | ||
205 | pSeriesLP_xirr_info_get, | ||
206 | pSeriesLP_xirr_info_set, | ||
207 | pSeriesLP_cppr_info, | ||
208 | pSeriesLP_qirr_info | ||
209 | }; | ||
210 | 173 | ||
211 | static unsigned int xics_startup(unsigned int virq) | 174 | /* High level handlers and init code */ |
212 | { | ||
213 | unsigned int irq; | ||
214 | 175 | ||
215 | irq = irq_offset_down(virq); | ||
216 | if (radix_tree_insert(&irq_map, virt_irq_to_real(irq), | ||
217 | &virt_irq_to_real_map[irq]) == -ENOMEM) | ||
218 | printk(KERN_CRIT "Out of memory creating real -> virtual" | ||
219 | " IRQ mapping for irq %u (real 0x%x)\n", | ||
220 | virq, virt_irq_to_real(irq)); | ||
221 | xics_enable_irq(virq); | ||
222 | return 0; /* return value is ignored */ | ||
223 | } | ||
224 | |||
225 | static unsigned int real_irq_to_virt(unsigned int real_irq) | ||
226 | { | ||
227 | unsigned int *ptr; | ||
228 | |||
229 | ptr = radix_tree_lookup(&irq_map, real_irq); | ||
230 | if (ptr == NULL) | ||
231 | return NO_IRQ; | ||
232 | return ptr - virt_irq_to_real_map; | ||
233 | } | ||
234 | 176 | ||
235 | #ifdef CONFIG_SMP | 177 | #ifdef CONFIG_SMP |
236 | static int get_irq_server(unsigned int irq) | 178 | static int get_irq_server(unsigned int irq) |
@@ -264,17 +206,20 @@ static int get_irq_server(unsigned int irq) | |||
264 | } | 206 | } |
265 | #endif | 207 | #endif |
266 | 208 | ||
267 | static void xics_enable_irq(unsigned int virq) | 209 | |
210 | static void xics_unmask_irq(unsigned int virq) | ||
268 | { | 211 | { |
269 | unsigned int irq; | 212 | unsigned int irq; |
270 | int call_status; | 213 | int call_status; |
271 | unsigned int server; | 214 | unsigned int server; |
272 | 215 | ||
273 | irq = virt_irq_to_real(irq_offset_down(virq)); | 216 | irq = virt_irq_to_real(irq_offset_down(virq)); |
274 | if (irq == XICS_IPI) | 217 | WARN_ON(irq == NO_IRQ); |
218 | if (irq == XICS_IPI || irq == NO_IRQ) | ||
275 | return; | 219 | return; |
276 | 220 | ||
277 | server = get_irq_server(virq); | 221 | server = get_irq_server(virq); |
222 | |||
278 | call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, | 223 | call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server, |
279 | DEFAULT_PRIORITY); | 224 | DEFAULT_PRIORITY); |
280 | if (call_status != 0) { | 225 | if (call_status != 0) { |
@@ -293,7 +238,7 @@ static void xics_enable_irq(unsigned int virq) | |||
293 | } | 238 | } |
294 | } | 239 | } |
295 | 240 | ||
296 | static void xics_disable_real_irq(unsigned int irq) | 241 | static void xics_mask_real_irq(unsigned int irq) |
297 | { | 242 | { |
298 | int call_status; | 243 | int call_status; |
299 | unsigned int server; | 244 | unsigned int server; |
@@ -318,75 +263,104 @@ static void xics_disable_real_irq(unsigned int irq) | |||
318 | } | 263 | } |
319 | } | 264 | } |
320 | 265 | ||
321 | static void xics_disable_irq(unsigned int virq) | 266 | static void xics_mask_irq(unsigned int virq) |
322 | { | 267 | { |
323 | unsigned int irq; | 268 | unsigned int irq; |
324 | 269 | ||
325 | irq = virt_irq_to_real(irq_offset_down(virq)); | 270 | irq = virt_irq_to_real(irq_offset_down(virq)); |
326 | xics_disable_real_irq(irq); | 271 | WARN_ON(irq == NO_IRQ); |
272 | if (irq != NO_IRQ) | ||
273 | xics_mask_real_irq(irq); | ||
274 | } | ||
275 | |||
276 | static void xics_set_irq_revmap(unsigned int virq) | ||
277 | { | ||
278 | unsigned int irq; | ||
279 | |||
280 | irq = irq_offset_down(virq); | ||
281 | if (radix_tree_insert(&irq_map, virt_irq_to_real(irq), | ||
282 | &virt_irq_to_real_map[irq]) == -ENOMEM) | ||
283 | printk(KERN_CRIT "Out of memory creating real -> virtual" | ||
284 | " IRQ mapping for irq %u (real 0x%x)\n", | ||
285 | virq, virt_irq_to_real(irq)); | ||
327 | } | 286 | } |
328 | 287 | ||
329 | static void xics_end_irq(unsigned int irq) | 288 | static unsigned int xics_startup(unsigned int virq) |
289 | { | ||
290 | xics_set_irq_revmap(virq); | ||
291 | xics_unmask_irq(virq); | ||
292 | return 0; | ||
293 | } | ||
294 | |||
295 | static unsigned int real_irq_to_virt(unsigned int real_irq) | ||
296 | { | ||
297 | unsigned int *ptr; | ||
298 | |||
299 | ptr = radix_tree_lookup(&irq_map, real_irq); | ||
300 | if (ptr == NULL) | ||
301 | return NO_IRQ; | ||
302 | return ptr - virt_irq_to_real_map; | ||
303 | } | ||
304 | |||
305 | static void xics_eoi_direct(unsigned int irq) | ||
330 | { | 306 | { |
331 | int cpu = smp_processor_id(); | 307 | int cpu = smp_processor_id(); |
332 | 308 | ||
333 | iosync(); | 309 | iosync(); |
334 | ops->xirr_info_set(cpu, ((0xff << 24) | | 310 | direct_xirr_info_set(cpu, ((0xff << 24) | |
335 | (virt_irq_to_real(irq_offset_down(irq))))); | 311 | (virt_irq_to_real(irq_offset_down(irq))))); |
336 | |||
337 | } | 312 | } |
338 | 313 | ||
339 | static void xics_mask_and_ack_irq(unsigned int irq) | 314 | |
315 | static void xics_eoi_lpar(unsigned int irq) | ||
340 | { | 316 | { |
341 | int cpu = smp_processor_id(); | 317 | int cpu = smp_processor_id(); |
342 | 318 | ||
343 | if (irq < irq_offset_value()) { | 319 | iosync(); |
344 | i8259_pic.ack(irq); | 320 | lpar_xirr_info_set(cpu, ((0xff << 24) | |
345 | iosync(); | 321 | (virt_irq_to_real(irq_offset_down(irq))))); |
346 | ops->xirr_info_set(cpu, ((0xff<<24) | | 322 | |
347 | xics_irq_8259_cascade_real)); | ||
348 | iosync(); | ||
349 | } | ||
350 | } | 323 | } |
351 | 324 | ||
352 | int xics_get_irq(struct pt_regs *regs) | 325 | static inline int xics_remap_irq(int vec) |
353 | { | 326 | { |
354 | unsigned int cpu = smp_processor_id(); | ||
355 | unsigned int vec; | ||
356 | int irq; | 327 | int irq; |
357 | 328 | ||
358 | vec = ops->xirr_info_get(cpu); | ||
359 | /* (vec >> 24) == old priority */ | ||
360 | vec &= 0x00ffffff; | 329 | vec &= 0x00ffffff; |
361 | 330 | ||
362 | /* for sanity, this had better be < NR_IRQS - 16 */ | 331 | if (vec == XICS_IRQ_SPURIOUS) |
363 | if (vec == xics_irq_8259_cascade_real) { | 332 | return NO_IRQ; |
364 | irq = i8259_irq(regs); | 333 | |
365 | xics_end_irq(irq_offset_up(xics_irq_8259_cascade)); | 334 | irq = real_irq_to_virt(vec); |
366 | } else if (vec == XICS_IRQ_SPURIOUS) { | 335 | if (irq == NO_IRQ) |
367 | irq = -1; | 336 | irq = real_irq_to_virt_slowpath(vec); |
368 | } else { | 337 | if (likely(irq != NO_IRQ)) |
369 | irq = real_irq_to_virt(vec); | 338 | return irq_offset_up(irq); |
370 | if (irq == NO_IRQ) | 339 | |
371 | irq = real_irq_to_virt_slowpath(vec); | 340 | printk(KERN_ERR "Interrupt %u (real) is invalid," |
372 | if (irq == NO_IRQ) { | 341 | " disabling it.\n", vec); |
373 | printk(KERN_ERR "Interrupt %u (real) is invalid," | 342 | xics_mask_real_irq(vec); |
374 | " disabling it.\n", vec); | 343 | return NO_IRQ; |
375 | xics_disable_real_irq(vec); | ||
376 | } else | ||
377 | irq = irq_offset_up(irq); | ||
378 | } | ||
379 | return irq; | ||
380 | } | 344 | } |
381 | 345 | ||
382 | #ifdef CONFIG_SMP | 346 | static int xics_get_irq_direct(struct pt_regs *regs) |
347 | { | ||
348 | unsigned int cpu = smp_processor_id(); | ||
383 | 349 | ||
384 | static irqreturn_t xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs) | 350 | return xics_remap_irq(direct_xirr_info_get(cpu)); |
351 | } | ||
352 | |||
353 | static int xics_get_irq_lpar(struct pt_regs *regs) | ||
385 | { | 354 | { |
386 | int cpu = smp_processor_id(); | 355 | unsigned int cpu = smp_processor_id(); |
387 | 356 | ||
388 | ops->qirr_info(cpu, 0xff); | 357 | return xics_remap_irq(lpar_xirr_info_get(cpu)); |
358 | } | ||
359 | |||
360 | #ifdef CONFIG_SMP | ||
389 | 361 | ||
362 | static irqreturn_t xics_ipi_dispatch(int cpu, struct pt_regs *regs) | ||
363 | { | ||
390 | WARN_ON(cpu_is_offline(cpu)); | 364 | WARN_ON(cpu_is_offline(cpu)); |
391 | 365 | ||
392 | while (xics_ipi_message[cpu].value) { | 366 | while (xics_ipi_message[cpu].value) { |
@@ -418,18 +392,108 @@ static irqreturn_t xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs) | |||
418 | return IRQ_HANDLED; | 392 | return IRQ_HANDLED; |
419 | } | 393 | } |
420 | 394 | ||
395 | static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id, struct pt_regs *regs) | ||
396 | { | ||
397 | int cpu = smp_processor_id(); | ||
398 | |||
399 | direct_qirr_info(cpu, 0xff); | ||
400 | |||
401 | return xics_ipi_dispatch(cpu, regs); | ||
402 | } | ||
403 | |||
404 | static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id, struct pt_regs *regs) | ||
405 | { | ||
406 | int cpu = smp_processor_id(); | ||
407 | |||
408 | lpar_qirr_info(cpu, 0xff); | ||
409 | |||
410 | return xics_ipi_dispatch(cpu, regs); | ||
411 | } | ||
412 | |||
421 | void xics_cause_IPI(int cpu) | 413 | void xics_cause_IPI(int cpu) |
422 | { | 414 | { |
423 | ops->qirr_info(cpu, IPI_PRIORITY); | 415 | if (firmware_has_feature(FW_FEATURE_LPAR)) |
416 | lpar_qirr_info(cpu, IPI_PRIORITY); | ||
417 | else | ||
418 | direct_qirr_info(cpu, IPI_PRIORITY); | ||
424 | } | 419 | } |
420 | |||
425 | #endif /* CONFIG_SMP */ | 421 | #endif /* CONFIG_SMP */ |
426 | 422 | ||
423 | static void xics_set_cpu_priority(int cpu, unsigned char cppr) | ||
424 | { | ||
425 | if (firmware_has_feature(FW_FEATURE_LPAR)) | ||
426 | lpar_cppr_info(cpu, cppr); | ||
427 | else | ||
428 | direct_cppr_info(cpu, cppr); | ||
429 | iosync(); | ||
430 | } | ||
431 | |||
432 | static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) | ||
433 | { | ||
434 | unsigned int irq; | ||
435 | int status; | ||
436 | int xics_status[2]; | ||
437 | unsigned long newmask; | ||
438 | cpumask_t tmp = CPU_MASK_NONE; | ||
439 | |||
440 | irq = virt_irq_to_real(irq_offset_down(virq)); | ||
441 | if (irq == XICS_IPI || irq == NO_IRQ) | ||
442 | return; | ||
443 | |||
444 | status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq); | ||
445 | |||
446 | if (status) { | ||
447 | printk(KERN_ERR "xics_set_affinity: irq=%u ibm,get-xive " | ||
448 | "returns %d\n", irq, status); | ||
449 | return; | ||
450 | } | ||
451 | |||
452 | /* For the moment only implement delivery to all cpus or one cpu */ | ||
453 | if (cpus_equal(cpumask, CPU_MASK_ALL)) { | ||
454 | newmask = default_distrib_server; | ||
455 | } else { | ||
456 | cpus_and(tmp, cpu_online_map, cpumask); | ||
457 | if (cpus_empty(tmp)) | ||
458 | return; | ||
459 | newmask = get_hard_smp_processor_id(first_cpu(tmp)); | ||
460 | } | ||
461 | |||
462 | status = rtas_call(ibm_set_xive, 3, 1, NULL, | ||
463 | irq, newmask, xics_status[1]); | ||
464 | |||
465 | if (status) { | ||
466 | printk(KERN_ERR "xics_set_affinity: irq=%u ibm,set-xive " | ||
467 | "returns %d\n", irq, status); | ||
468 | return; | ||
469 | } | ||
470 | } | ||
471 | |||
472 | static struct irq_chip xics_pic_direct = { | ||
473 | .typename = " XICS ", | ||
474 | .startup = xics_startup, | ||
475 | .mask = xics_mask_irq, | ||
476 | .unmask = xics_unmask_irq, | ||
477 | .eoi = xics_eoi_direct, | ||
478 | .set_affinity = xics_set_affinity | ||
479 | }; | ||
480 | |||
481 | |||
482 | static struct irq_chip xics_pic_lpar = { | ||
483 | .typename = " XICS ", | ||
484 | .startup = xics_startup, | ||
485 | .mask = xics_mask_irq, | ||
486 | .unmask = xics_unmask_irq, | ||
487 | .eoi = xics_eoi_lpar, | ||
488 | .set_affinity = xics_set_affinity | ||
489 | }; | ||
490 | |||
491 | |||
427 | void xics_setup_cpu(void) | 492 | void xics_setup_cpu(void) |
428 | { | 493 | { |
429 | int cpu = smp_processor_id(); | 494 | int cpu = smp_processor_id(); |
430 | 495 | ||
431 | ops->cppr_info(cpu, 0xff); | 496 | xics_set_cpu_priority(cpu, 0xff); |
432 | iosync(); | ||
433 | 497 | ||
434 | /* | 498 | /* |
435 | * Put the calling processor into the GIQ. This is really only | 499 | * Put the calling processor into the GIQ. This is really only |
@@ -453,6 +517,7 @@ void xics_init_IRQ(void) | |||
453 | unsigned long addr; | 517 | unsigned long addr; |
454 | unsigned long size; | 518 | unsigned long size; |
455 | } intnodes[NR_CPUS]; | 519 | } intnodes[NR_CPUS]; |
520 | struct irq_chip *chip; | ||
456 | 521 | ||
457 | ppc64_boot_msg(0x20, "XICS Init"); | 522 | ppc64_boot_msg(0x20, "XICS Init"); |
458 | 523 | ||
@@ -519,26 +584,10 @@ nextnode: | |||
519 | intr_base = intnodes[0].addr; | 584 | intr_base = intnodes[0].addr; |
520 | intr_size = intnodes[0].size; | 585 | intr_size = intnodes[0].size; |
521 | 586 | ||
522 | np = of_find_node_by_type(NULL, "interrupt-controller"); | 587 | if (firmware_has_feature(FW_FEATURE_LPAR)) { |
523 | if (!np) { | 588 | ppc_md.get_irq = xics_get_irq_lpar; |
524 | printk(KERN_DEBUG "xics: no ISA interrupt controller\n"); | 589 | chip = &xics_pic_lpar; |
525 | xics_irq_8259_cascade_real = -1; | 590 | } else { |
526 | xics_irq_8259_cascade = -1; | ||
527 | } else { | ||
528 | ireg = (uint *) get_property(np, "interrupts", NULL); | ||
529 | if (!ireg) | ||
530 | panic("xics_init_IRQ: can't find ISA interrupts property"); | ||
531 | |||
532 | xics_irq_8259_cascade_real = *ireg; | ||
533 | xics_irq_8259_cascade | ||
534 | = virt_irq_create_mapping(xics_irq_8259_cascade_real); | ||
535 | i8259_init(0, 0); | ||
536 | of_node_put(np); | ||
537 | } | ||
538 | |||
539 | if (firmware_has_feature(FW_FEATURE_LPAR)) | ||
540 | ops = &pSeriesLP_ops; | ||
541 | else { | ||
542 | #ifdef CONFIG_SMP | 591 | #ifdef CONFIG_SMP |
543 | for_each_possible_cpu(i) { | 592 | for_each_possible_cpu(i) { |
544 | int hard_id; | 593 | int hard_id; |
@@ -554,32 +603,54 @@ nextnode: | |||
554 | #else | 603 | #else |
555 | xics_per_cpu[0] = ioremap(intr_base, intr_size); | 604 | xics_per_cpu[0] = ioremap(intr_base, intr_size); |
556 | #endif /* CONFIG_SMP */ | 605 | #endif /* CONFIG_SMP */ |
606 | ppc_md.get_irq = xics_get_irq_direct; | ||
607 | chip = &xics_pic_direct; | ||
608 | |||
557 | } | 609 | } |
558 | 610 | ||
559 | for (i = irq_offset_value(); i < NR_IRQS; ++i) | 611 | for (i = irq_offset_value(); i < NR_IRQS; ++i) { |
560 | get_irq_desc(i)->chip = &xics_pic; | 612 | /* All IRQs on XICS are level for now. MSI code may want to modify |
613 | * that for reporting purposes | ||
614 | */ | ||
615 | get_irq_desc(i)->status |= IRQ_LEVEL; | ||
616 | set_irq_chip_and_handler(i, chip, handle_fasteoi_irq); | ||
617 | } | ||
561 | 618 | ||
562 | xics_setup_cpu(); | 619 | xics_setup_cpu(); |
563 | 620 | ||
564 | ppc64_boot_msg(0x21, "XICS Done"); | 621 | ppc64_boot_msg(0x21, "XICS Done"); |
565 | } | 622 | } |
566 | 623 | ||
567 | /* | 624 | static int xics_setup_8259_cascade(void) |
568 | * We cant do this in init_IRQ because we need the memory subsystem up for | 625 | { |
569 | * request_irq() | 626 | struct device_node *np; |
570 | */ | 627 | uint *ireg; |
571 | static int __init xics_setup_i8259(void) | 628 | |
572 | { | 629 | np = of_find_node_by_type(NULL, "interrupt-controller"); |
573 | if (ppc64_interrupt_controller == IC_PPC_XIC && | 630 | if (np == NULL) { |
574 | xics_irq_8259_cascade != -1) { | 631 | printk(KERN_WARNING "xics: no ISA interrupt controller\n"); |
575 | if (request_irq(irq_offset_up(xics_irq_8259_cascade), | 632 | xics_irq_8259_cascade_real = -1; |
576 | no_action, 0, "8259 cascade", NULL)) | 633 | xics_irq_8259_cascade = -1; |
577 | printk(KERN_ERR "xics_setup_i8259: couldn't get 8259 " | 634 | return 0; |
578 | "cascade\n"); | ||
579 | } | 635 | } |
636 | |||
637 | ireg = (uint *) get_property(np, "interrupts", NULL); | ||
638 | if (!ireg) | ||
639 | panic("xics_init_IRQ: can't find ISA interrupts property"); | ||
640 | |||
641 | xics_irq_8259_cascade_real = *ireg; | ||
642 | xics_irq_8259_cascade = irq_offset_up | ||
643 | (virt_irq_create_mapping(xics_irq_8259_cascade_real)); | ||
644 | i8259_init(0, 0); | ||
645 | of_node_put(np); | ||
646 | |||
647 | xics_set_irq_revmap(xics_irq_8259_cascade); | ||
648 | set_irq_chained_handler(xics_irq_8259_cascade, pSeries_8259_cascade); | ||
649 | |||
580 | return 0; | 650 | return 0; |
581 | } | 651 | } |
582 | arch_initcall(xics_setup_i8259); | 652 | arch_initcall(xics_setup_8259_cascade); |
653 | |||
583 | 654 | ||
584 | #ifdef CONFIG_SMP | 655 | #ifdef CONFIG_SMP |
585 | void xics_request_IPIs(void) | 656 | void xics_request_IPIs(void) |
@@ -590,61 +661,22 @@ void xics_request_IPIs(void) | |||
590 | * IPIs are marked IRQF_DISABLED as they must run with irqs | 661 | * IPIs are marked IRQF_DISABLED as they must run with irqs |
591 | * disabled | 662 | * disabled |
592 | */ | 663 | */ |
593 | request_irq(irq_offset_up(XICS_IPI), xics_ipi_action, | 664 | set_irq_handler(irq_offset_up(XICS_IPI), handle_percpu_irq); |
594 | IRQF_DISABLED, "IPI", NULL); | 665 | if (firmware_has_feature(FW_FEATURE_LPAR)) |
595 | get_irq_desc(irq_offset_up(XICS_IPI))->status |= IRQ_PER_CPU; | 666 | request_irq(irq_offset_up(XICS_IPI), xics_ipi_action_lpar, |
596 | } | 667 | SA_INTERRUPT, "IPI", NULL); |
597 | #endif | 668 | else |
598 | 669 | request_irq(irq_offset_up(XICS_IPI), xics_ipi_action_direct, | |
599 | static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) | 670 | SA_INTERRUPT, "IPI", NULL); |
600 | { | ||
601 | unsigned int irq; | ||
602 | int status; | ||
603 | int xics_status[2]; | ||
604 | unsigned long newmask; | ||
605 | cpumask_t tmp = CPU_MASK_NONE; | ||
606 | |||
607 | irq = virt_irq_to_real(irq_offset_down(virq)); | ||
608 | if (irq == XICS_IPI || irq == NO_IRQ) | ||
609 | return; | ||
610 | |||
611 | status = rtas_call(ibm_get_xive, 1, 3, xics_status, irq); | ||
612 | |||
613 | if (status) { | ||
614 | printk(KERN_ERR "xics_set_affinity: irq=%u ibm,get-xive " | ||
615 | "returns %d\n", irq, status); | ||
616 | return; | ||
617 | } | ||
618 | |||
619 | /* For the moment only implement delivery to all cpus or one cpu */ | ||
620 | if (cpus_equal(cpumask, CPU_MASK_ALL)) { | ||
621 | newmask = default_distrib_server; | ||
622 | } else { | ||
623 | cpus_and(tmp, cpu_online_map, cpumask); | ||
624 | if (cpus_empty(tmp)) | ||
625 | return; | ||
626 | newmask = get_hard_smp_processor_id(first_cpu(tmp)); | ||
627 | } | ||
628 | |||
629 | status = rtas_call(ibm_set_xive, 3, 1, NULL, | ||
630 | irq, newmask, xics_status[1]); | ||
631 | |||
632 | if (status) { | ||
633 | printk(KERN_ERR "xics_set_affinity: irq=%u ibm,set-xive " | ||
634 | "returns %d\n", irq, status); | ||
635 | return; | ||
636 | } | ||
637 | } | 671 | } |
672 | #endif /* CONFIG_SMP */ | ||
638 | 673 | ||
639 | void xics_teardown_cpu(int secondary) | 674 | void xics_teardown_cpu(int secondary) |
640 | { | 675 | { |
676 | struct irq_desc *desc = get_irq_desc(irq_offset_up(XICS_IPI)); | ||
641 | int cpu = smp_processor_id(); | 677 | int cpu = smp_processor_id(); |
642 | 678 | ||
643 | ops->cppr_info(cpu, 0x00); | 679 | xics_set_cpu_priority(cpu, 0); |
644 | iosync(); | ||
645 | |||
646 | /* Clear IPI */ | ||
647 | ops->qirr_info(cpu, 0xff); | ||
648 | 680 | ||
649 | /* | 681 | /* |
650 | * we need to EOI the IPI if we got here from kexec down IPI | 682 | * we need to EOI the IPI if we got here from kexec down IPI |
@@ -653,7 +685,8 @@ void xics_teardown_cpu(int secondary) | |||
653 | * should we be flagging idle loop instead? | 685 | * should we be flagging idle loop instead? |
654 | * or creating some task to be scheduled? | 686 | * or creating some task to be scheduled? |
655 | */ | 687 | */ |
656 | ops->xirr_info_set(cpu, XICS_IPI); | 688 | if (desc->chip && desc->chip->eoi) |
689 | desc->chip->eoi(XICS_IPI); | ||
657 | 690 | ||
658 | /* | 691 | /* |
659 | * Some machines need to have at least one cpu in the GIQ, | 692 | * Some machines need to have at least one cpu in the GIQ, |
@@ -674,8 +707,7 @@ void xics_migrate_irqs_away(void) | |||
674 | unsigned int irq, virq, cpu = smp_processor_id(); | 707 | unsigned int irq, virq, cpu = smp_processor_id(); |
675 | 708 | ||
676 | /* Reject any interrupt that was queued to us... */ | 709 | /* Reject any interrupt that was queued to us... */ |
677 | ops->cppr_info(cpu, 0); | 710 | xics_set_cpu_priority(cpu, 0); |
678 | iosync(); | ||
679 | 711 | ||
680 | /* remove ourselves from the global interrupt queue */ | 712 | /* remove ourselves from the global interrupt queue */ |
681 | status = rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE, | 713 | status = rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE, |
@@ -683,11 +715,10 @@ void xics_migrate_irqs_away(void) | |||
683 | WARN_ON(status < 0); | 715 | WARN_ON(status < 0); |
684 | 716 | ||
685 | /* Allow IPIs again... */ | 717 | /* Allow IPIs again... */ |
686 | ops->cppr_info(cpu, DEFAULT_PRIORITY); | 718 | xics_set_cpu_priority(cpu, DEFAULT_PRIORITY); |
687 | iosync(); | ||
688 | 719 | ||
689 | for_each_irq(virq) { | 720 | for_each_irq(virq) { |
690 | irq_desc_t *desc; | 721 | struct irq_desc *desc; |
691 | int xics_status[2]; | 722 | int xics_status[2]; |
692 | unsigned long flags; | 723 | unsigned long flags; |
693 | 724 | ||
diff --git a/arch/powerpc/platforms/pseries/xics.h b/arch/powerpc/platforms/pseries/xics.h index e14c70868f1d..67dedf3514ec 100644 --- a/arch/powerpc/platforms/pseries/xics.h +++ b/arch/powerpc/platforms/pseries/xics.h | |||
@@ -14,13 +14,12 @@ | |||
14 | 14 | ||
15 | #include <linux/cache.h> | 15 | #include <linux/cache.h> |
16 | 16 | ||
17 | void xics_init_IRQ(void); | 17 | extern void xics_init_IRQ(void); |
18 | int xics_get_irq(struct pt_regs *); | 18 | extern void xics_setup_cpu(void); |
19 | void xics_setup_cpu(void); | 19 | extern void xics_teardown_cpu(int secondary); |
20 | void xics_teardown_cpu(int secondary); | 20 | extern void xics_cause_IPI(int cpu); |
21 | void xics_cause_IPI(int cpu); | 21 | extern void xics_request_IPIs(void); |
22 | void xics_request_IPIs(void); | 22 | extern void xics_migrate_irqs_away(void); |
23 | void xics_migrate_irqs_away(void); | ||
24 | 23 | ||
25 | /* first argument is ignored for now*/ | 24 | /* first argument is ignored for now*/ |
26 | void pSeriesLP_cppr_info(int n_cpu, u8 value); | 25 | void pSeriesLP_cppr_info(int n_cpu, u8 value); |
@@ -31,4 +30,8 @@ struct xics_ipi_struct { | |||
31 | 30 | ||
32 | extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; | 31 | extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned; |
33 | 32 | ||
33 | struct irq_desc; | ||
34 | extern void pSeries_8259_cascade(unsigned int irq, struct irq_desc *desc, | ||
35 | struct pt_regs *regs); | ||
36 | |||
34 | #endif /* _POWERPC_KERNEL_XICS_H */ | 37 | #endif /* _POWERPC_KERNEL_XICS_H */ |
diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c index 1a3ef1ab9d6e..c2e9465871aa 100644 --- a/arch/powerpc/sysdev/i8259.c +++ b/arch/powerpc/sysdev/i8259.c | |||
@@ -69,11 +69,6 @@ int i8259_irq(struct pt_regs *regs) | |||
69 | return irq + i8259_pic_irq_offset; | 69 | return irq + i8259_pic_irq_offset; |
70 | } | 70 | } |
71 | 71 | ||
72 | int i8259_irq_cascade(struct pt_regs *regs, void *unused) | ||
73 | { | ||
74 | return i8259_irq(regs); | ||
75 | } | ||
76 | |||
77 | static void i8259_mask_and_ack_irq(unsigned int irq_nr) | 72 | static void i8259_mask_and_ack_irq(unsigned int irq_nr) |
78 | { | 73 | { |
79 | unsigned long flags; | 74 | unsigned long flags; |
@@ -129,19 +124,11 @@ static void i8259_unmask_irq(unsigned int irq_nr) | |||
129 | spin_unlock_irqrestore(&i8259_lock, flags); | 124 | spin_unlock_irqrestore(&i8259_lock, flags); |
130 | } | 125 | } |
131 | 126 | ||
132 | static void i8259_end_irq(unsigned int irq) | 127 | static struct irq_chip i8259_pic = { |
133 | { | 128 | .typename = " i8259 ", |
134 | if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) | 129 | .mask = i8259_mask_irq, |
135 | && irq_desc[irq].action) | 130 | .unmask = i8259_unmask_irq, |
136 | i8259_unmask_irq(irq); | 131 | .mask_ack = i8259_mask_and_ack_irq, |
137 | } | ||
138 | |||
139 | struct hw_interrupt_type i8259_pic = { | ||
140 | .typename = " i8259 ", | ||
141 | .enable = i8259_unmask_irq, | ||
142 | .disable = i8259_mask_irq, | ||
143 | .ack = i8259_mask_and_ack_irq, | ||
144 | .end = i8259_end_irq, | ||
145 | }; | 132 | }; |
146 | 133 | ||
147 | static struct resource pic1_iores = { | 134 | static struct resource pic1_iores = { |
@@ -207,8 +194,11 @@ void __init i8259_init(unsigned long intack_addr, int offset) | |||
207 | 194 | ||
208 | spin_unlock_irqrestore(&i8259_lock, flags); | 195 | spin_unlock_irqrestore(&i8259_lock, flags); |
209 | 196 | ||
210 | for (i = 0; i < NUM_ISA_INTERRUPTS; ++i) | 197 | for (i = 0; i < NUM_ISA_INTERRUPTS; ++i) { |
211 | irq_desc[offset + i].chip = &i8259_pic; | 198 | set_irq_chip_and_handler(offset + i, &i8259_pic, |
199 | handle_level_irq); | ||
200 | irq_desc[offset + i].status |= IRQ_LEVEL; | ||
201 | } | ||
212 | 202 | ||
213 | /* reserve our resources */ | 203 | /* reserve our resources */ |
214 | setup_irq(offset + 2, &i8259_irqaction); | 204 | setup_irq(offset + 2, &i8259_irqaction); |
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 7e469358895f..9a95f16c19a5 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c | |||
@@ -100,8 +100,8 @@ static inline u32 _mpic_cpu_read(struct mpic *mpic, unsigned int reg) | |||
100 | 100 | ||
101 | if (mpic->flags & MPIC_PRIMARY) | 101 | if (mpic->flags & MPIC_PRIMARY) |
102 | cpu = hard_smp_processor_id(); | 102 | cpu = hard_smp_processor_id(); |
103 | 103 | return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, | |
104 | return _mpic_read(mpic->flags & MPIC_BIG_ENDIAN, mpic->cpuregs[cpu], reg); | 104 | mpic->cpuregs[cpu], reg); |
105 | } | 105 | } |
106 | 106 | ||
107 | static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value) | 107 | static inline void _mpic_cpu_write(struct mpic *mpic, unsigned int reg, u32 value) |
@@ -378,14 +378,14 @@ static inline u32 mpic_physmask(u32 cpumask) | |||
378 | /* Get the mpic structure from the IPI number */ | 378 | /* Get the mpic structure from the IPI number */ |
379 | static inline struct mpic * mpic_from_ipi(unsigned int ipi) | 379 | static inline struct mpic * mpic_from_ipi(unsigned int ipi) |
380 | { | 380 | { |
381 | return container_of(irq_desc[ipi].chip, struct mpic, hc_ipi); | 381 | return irq_desc[ipi].chip_data; |
382 | } | 382 | } |
383 | #endif | 383 | #endif |
384 | 384 | ||
385 | /* Get the mpic structure from the irq number */ | 385 | /* Get the mpic structure from the irq number */ |
386 | static inline struct mpic * mpic_from_irq(unsigned int irq) | 386 | static inline struct mpic * mpic_from_irq(unsigned int irq) |
387 | { | 387 | { |
388 | return container_of(irq_desc[irq].chip, struct mpic, hc_irq); | 388 | return irq_desc[irq].chip_data; |
389 | } | 389 | } |
390 | 390 | ||
391 | /* Send an EOI */ | 391 | /* Send an EOI */ |
@@ -410,7 +410,7 @@ static irqreturn_t mpic_ipi_action(int irq, void *dev_id, struct pt_regs *regs) | |||
410 | */ | 410 | */ |
411 | 411 | ||
412 | 412 | ||
413 | static void mpic_enable_irq(unsigned int irq) | 413 | static void mpic_unmask_irq(unsigned int irq) |
414 | { | 414 | { |
415 | unsigned int loops = 100000; | 415 | unsigned int loops = 100000; |
416 | struct mpic *mpic = mpic_from_irq(irq); | 416 | struct mpic *mpic = mpic_from_irq(irq); |
@@ -429,35 +429,9 @@ static void mpic_enable_irq(unsigned int irq) | |||
429 | break; | 429 | break; |
430 | } | 430 | } |
431 | } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK); | 431 | } while(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK); |
432 | |||
433 | #ifdef CONFIG_MPIC_BROKEN_U3 | ||
434 | if (mpic->flags & MPIC_BROKEN_U3) { | ||
435 | unsigned int src = irq - mpic->irq_offset; | ||
436 | if (mpic_is_ht_interrupt(mpic, src) && | ||
437 | (irq_desc[irq].status & IRQ_LEVEL)) | ||
438 | mpic_ht_end_irq(mpic, src); | ||
439 | } | ||
440 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
441 | } | ||
442 | |||
443 | static unsigned int mpic_startup_irq(unsigned int irq) | ||
444 | { | ||
445 | #ifdef CONFIG_MPIC_BROKEN_U3 | ||
446 | struct mpic *mpic = mpic_from_irq(irq); | ||
447 | unsigned int src = irq - mpic->irq_offset; | ||
448 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
449 | |||
450 | mpic_enable_irq(irq); | ||
451 | |||
452 | #ifdef CONFIG_MPIC_BROKEN_U3 | ||
453 | if (mpic_is_ht_interrupt(mpic, src)) | ||
454 | mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status); | ||
455 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
456 | |||
457 | return 0; | ||
458 | } | 432 | } |
459 | 433 | ||
460 | static void mpic_disable_irq(unsigned int irq) | 434 | static void mpic_mask_irq(unsigned int irq) |
461 | { | 435 | { |
462 | unsigned int loops = 100000; | 436 | unsigned int loops = 100000; |
463 | struct mpic *mpic = mpic_from_irq(irq); | 437 | struct mpic *mpic = mpic_from_irq(irq); |
@@ -478,23 +452,58 @@ static void mpic_disable_irq(unsigned int irq) | |||
478 | } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK)); | 452 | } while(!(mpic_irq_read(src, MPIC_IRQ_VECTOR_PRI) & MPIC_VECPRI_MASK)); |
479 | } | 453 | } |
480 | 454 | ||
481 | static void mpic_shutdown_irq(unsigned int irq) | 455 | static void mpic_end_irq(unsigned int irq) |
482 | { | 456 | { |
457 | struct mpic *mpic = mpic_from_irq(irq); | ||
458 | |||
459 | #ifdef DEBUG_IRQ | ||
460 | DBG("%s: end_irq: %d\n", mpic->name, irq); | ||
461 | #endif | ||
462 | /* We always EOI on end_irq() even for edge interrupts since that | ||
463 | * should only lower the priority, the MPIC should have properly | ||
464 | * latched another edge interrupt coming in anyway | ||
465 | */ | ||
466 | |||
467 | mpic_eoi(mpic); | ||
468 | } | ||
469 | |||
483 | #ifdef CONFIG_MPIC_BROKEN_U3 | 470 | #ifdef CONFIG_MPIC_BROKEN_U3 |
471 | |||
472 | static void mpic_unmask_ht_irq(unsigned int irq) | ||
473 | { | ||
484 | struct mpic *mpic = mpic_from_irq(irq); | 474 | struct mpic *mpic = mpic_from_irq(irq); |
485 | unsigned int src = irq - mpic->irq_offset; | 475 | unsigned int src = irq - mpic->irq_offset; |
486 | 476 | ||
487 | if (mpic_is_ht_interrupt(mpic, src)) | 477 | mpic_unmask_irq(irq); |
488 | mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status); | ||
489 | 478 | ||
490 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | 479 | if (irq_desc[irq].status & IRQ_LEVEL) |
480 | mpic_ht_end_irq(mpic, src); | ||
481 | } | ||
482 | |||
483 | static unsigned int mpic_startup_ht_irq(unsigned int irq) | ||
484 | { | ||
485 | struct mpic *mpic = mpic_from_irq(irq); | ||
486 | unsigned int src = irq - mpic->irq_offset; | ||
491 | 487 | ||
492 | mpic_disable_irq(irq); | 488 | mpic_unmask_irq(irq); |
489 | mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status); | ||
490 | |||
491 | return 0; | ||
493 | } | 492 | } |
494 | 493 | ||
495 | static void mpic_end_irq(unsigned int irq) | 494 | static void mpic_shutdown_ht_irq(unsigned int irq) |
495 | { | ||
496 | struct mpic *mpic = mpic_from_irq(irq); | ||
497 | unsigned int src = irq - mpic->irq_offset; | ||
498 | |||
499 | mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status); | ||
500 | mpic_mask_irq(irq); | ||
501 | } | ||
502 | |||
503 | static void mpic_end_ht_irq(unsigned int irq) | ||
496 | { | 504 | { |
497 | struct mpic *mpic = mpic_from_irq(irq); | 505 | struct mpic *mpic = mpic_from_irq(irq); |
506 | unsigned int src = irq - mpic->irq_offset; | ||
498 | 507 | ||
499 | #ifdef DEBUG_IRQ | 508 | #ifdef DEBUG_IRQ |
500 | DBG("%s: end_irq: %d\n", mpic->name, irq); | 509 | DBG("%s: end_irq: %d\n", mpic->name, irq); |
@@ -504,21 +513,16 @@ static void mpic_end_irq(unsigned int irq) | |||
504 | * latched another edge interrupt coming in anyway | 513 | * latched another edge interrupt coming in anyway |
505 | */ | 514 | */ |
506 | 515 | ||
507 | #ifdef CONFIG_MPIC_BROKEN_U3 | 516 | if (irq_desc[irq].status & IRQ_LEVEL) |
508 | if (mpic->flags & MPIC_BROKEN_U3) { | 517 | mpic_ht_end_irq(mpic, src); |
509 | unsigned int src = irq - mpic->irq_offset; | ||
510 | if (mpic_is_ht_interrupt(mpic, src) && | ||
511 | (irq_desc[irq].status & IRQ_LEVEL)) | ||
512 | mpic_ht_end_irq(mpic, src); | ||
513 | } | ||
514 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
515 | |||
516 | mpic_eoi(mpic); | 518 | mpic_eoi(mpic); |
517 | } | 519 | } |
518 | 520 | ||
521 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
522 | |||
519 | #ifdef CONFIG_SMP | 523 | #ifdef CONFIG_SMP |
520 | 524 | ||
521 | static void mpic_enable_ipi(unsigned int irq) | 525 | static void mpic_unmask_ipi(unsigned int irq) |
522 | { | 526 | { |
523 | struct mpic *mpic = mpic_from_ipi(irq); | 527 | struct mpic *mpic = mpic_from_ipi(irq); |
524 | unsigned int src = irq - mpic->ipi_offset; | 528 | unsigned int src = irq - mpic->ipi_offset; |
@@ -527,7 +531,7 @@ static void mpic_enable_ipi(unsigned int irq) | |||
527 | mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); | 531 | mpic_ipi_write(src, mpic_ipi_read(src) & ~MPIC_VECPRI_MASK); |
528 | } | 532 | } |
529 | 533 | ||
530 | static void mpic_disable_ipi(unsigned int irq) | 534 | static void mpic_mask_ipi(unsigned int irq) |
531 | { | 535 | { |
532 | /* NEVER disable an IPI... that's just plain wrong! */ | 536 | /* NEVER disable an IPI... that's just plain wrong! */ |
533 | } | 537 | } |
@@ -560,6 +564,30 @@ static void mpic_set_affinity(unsigned int irq, cpumask_t cpumask) | |||
560 | mpic_physmask(cpus_addr(tmp)[0])); | 564 | mpic_physmask(cpus_addr(tmp)[0])); |
561 | } | 565 | } |
562 | 566 | ||
567 | static struct irq_chip mpic_irq_chip = { | ||
568 | .mask = mpic_mask_irq, | ||
569 | .unmask = mpic_unmask_irq, | ||
570 | .eoi = mpic_end_irq, | ||
571 | }; | ||
572 | |||
573 | #ifdef CONFIG_SMP | ||
574 | static struct irq_chip mpic_ipi_chip = { | ||
575 | .mask = mpic_mask_ipi, | ||
576 | .unmask = mpic_unmask_ipi, | ||
577 | .eoi = mpic_end_ipi, | ||
578 | }; | ||
579 | #endif /* CONFIG_SMP */ | ||
580 | |||
581 | #ifdef CONFIG_MPIC_BROKEN_U3 | ||
582 | static struct irq_chip mpic_irq_ht_chip = { | ||
583 | .startup = mpic_startup_ht_irq, | ||
584 | .shutdown = mpic_shutdown_ht_irq, | ||
585 | .mask = mpic_mask_irq, | ||
586 | .unmask = mpic_unmask_ht_irq, | ||
587 | .eoi = mpic_end_ht_irq, | ||
588 | }; | ||
589 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
590 | |||
563 | 591 | ||
564 | /* | 592 | /* |
565 | * Exported functions | 593 | * Exported functions |
@@ -589,19 +617,19 @@ struct mpic * __init mpic_alloc(unsigned long phys_addr, | |||
589 | memset(mpic, 0, sizeof(struct mpic)); | 617 | memset(mpic, 0, sizeof(struct mpic)); |
590 | mpic->name = name; | 618 | mpic->name = name; |
591 | 619 | ||
620 | mpic->hc_irq = mpic_irq_chip; | ||
592 | mpic->hc_irq.typename = name; | 621 | mpic->hc_irq.typename = name; |
593 | mpic->hc_irq.startup = mpic_startup_irq; | ||
594 | mpic->hc_irq.shutdown = mpic_shutdown_irq; | ||
595 | mpic->hc_irq.enable = mpic_enable_irq; | ||
596 | mpic->hc_irq.disable = mpic_disable_irq; | ||
597 | mpic->hc_irq.end = mpic_end_irq; | ||
598 | if (flags & MPIC_PRIMARY) | 622 | if (flags & MPIC_PRIMARY) |
599 | mpic->hc_irq.set_affinity = mpic_set_affinity; | 623 | mpic->hc_irq.set_affinity = mpic_set_affinity; |
624 | #ifdef CONFIG_MPIC_BROKEN_U3 | ||
625 | mpic->hc_ht_irq = mpic_irq_ht_chip; | ||
626 | mpic->hc_ht_irq.typename = name; | ||
627 | if (flags & MPIC_PRIMARY) | ||
628 | mpic->hc_ht_irq.set_affinity = mpic_set_affinity; | ||
629 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
600 | #ifdef CONFIG_SMP | 630 | #ifdef CONFIG_SMP |
601 | mpic->hc_ipi.typename = name; | 631 | mpic->hc_ipi.typename = name; |
602 | mpic->hc_ipi.enable = mpic_enable_ipi; | 632 | mpic->hc_ipi = mpic_ipi_chip; |
603 | mpic->hc_ipi.disable = mpic_disable_ipi; | ||
604 | mpic->hc_ipi.end = mpic_end_ipi; | ||
605 | #endif /* CONFIG_SMP */ | 633 | #endif /* CONFIG_SMP */ |
606 | 634 | ||
607 | mpic->flags = flags; | 635 | mpic->flags = flags; |
@@ -697,28 +725,6 @@ void __init mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, | |||
697 | mpic->num_sources = isu_first + mpic->isu_size; | 725 | mpic->num_sources = isu_first + mpic->isu_size; |
698 | } | 726 | } |
699 | 727 | ||
700 | void __init mpic_setup_cascade(unsigned int irq, mpic_cascade_t handler, | ||
701 | void *data) | ||
702 | { | ||
703 | struct mpic *mpic = mpic_find(irq, NULL); | ||
704 | unsigned long flags; | ||
705 | |||
706 | /* Synchronization here is a bit dodgy, so don't try to replace cascade | ||
707 | * interrupts on the fly too often ... but normally it's set up at boot. | ||
708 | */ | ||
709 | spin_lock_irqsave(&mpic_lock, flags); | ||
710 | if (mpic->cascade) | ||
711 | mpic_disable_irq(mpic->cascade_vec + mpic->irq_offset); | ||
712 | mpic->cascade = NULL; | ||
713 | wmb(); | ||
714 | mpic->cascade_vec = irq - mpic->irq_offset; | ||
715 | mpic->cascade_data = data; | ||
716 | wmb(); | ||
717 | mpic->cascade = handler; | ||
718 | mpic_enable_irq(irq); | ||
719 | spin_unlock_irqrestore(&mpic_lock, flags); | ||
720 | } | ||
721 | |||
722 | void __init mpic_init(struct mpic *mpic) | 728 | void __init mpic_init(struct mpic *mpic) |
723 | { | 729 | { |
724 | int i; | 730 | int i; |
@@ -750,8 +756,10 @@ void __init mpic_init(struct mpic *mpic) | |||
750 | #ifdef CONFIG_SMP | 756 | #ifdef CONFIG_SMP |
751 | if (!(mpic->flags & MPIC_PRIMARY)) | 757 | if (!(mpic->flags & MPIC_PRIMARY)) |
752 | continue; | 758 | continue; |
753 | irq_desc[mpic->ipi_offset+i].status |= IRQ_PER_CPU; | 759 | set_irq_chip_data(mpic->ipi_offset+i, mpic); |
754 | irq_desc[mpic->ipi_offset+i].chip = &mpic->hc_ipi; | 760 | set_irq_chip_and_handler(mpic->ipi_offset+i, |
761 | &mpic->hc_ipi, | ||
762 | handle_percpu_irq); | ||
755 | #endif /* CONFIG_SMP */ | 763 | #endif /* CONFIG_SMP */ |
756 | } | 764 | } |
757 | 765 | ||
@@ -763,7 +771,7 @@ void __init mpic_init(struct mpic *mpic) | |||
763 | /* Do the HT PIC fixups on U3 broken mpic */ | 771 | /* Do the HT PIC fixups on U3 broken mpic */ |
764 | DBG("MPIC flags: %x\n", mpic->flags); | 772 | DBG("MPIC flags: %x\n", mpic->flags); |
765 | if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY)) | 773 | if ((mpic->flags & MPIC_BROKEN_U3) && (mpic->flags & MPIC_PRIMARY)) |
766 | mpic_scan_ht_pics(mpic); | 774 | mpic_scan_ht_pics(mpic); |
767 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | 775 | #endif /* CONFIG_MPIC_BROKEN_U3 */ |
768 | 776 | ||
769 | for (i = 0; i < mpic->num_sources; i++) { | 777 | for (i = 0; i < mpic->num_sources; i++) { |
@@ -811,8 +819,17 @@ void __init mpic_init(struct mpic *mpic) | |||
811 | 819 | ||
812 | /* init linux descriptors */ | 820 | /* init linux descriptors */ |
813 | if (i < mpic->irq_count) { | 821 | if (i < mpic->irq_count) { |
814 | irq_desc[mpic->irq_offset+i].status = level ? IRQ_LEVEL : 0; | 822 | struct irq_chip *chip = &mpic->hc_irq; |
815 | irq_desc[mpic->irq_offset+i].chip = &mpic->hc_irq; | 823 | |
824 | irq_desc[mpic->irq_offset+i].status |= | ||
825 | level ? IRQ_LEVEL : 0; | ||
826 | #ifdef CONFIG_MPIC_BROKEN_U3 | ||
827 | if (mpic_is_ht_interrupt(mpic, i)) | ||
828 | chip = &mpic->hc_ht_irq; | ||
829 | #endif /* CONFIG_MPIC_BROKEN_U3 */ | ||
830 | set_irq_chip_data(mpic->irq_offset+i, mpic); | ||
831 | set_irq_chip_and_handler(mpic->irq_offset+i, chip, | ||
832 | handle_fasteoi_irq); | ||
816 | } | 833 | } |
817 | } | 834 | } |
818 | 835 | ||
@@ -986,14 +1003,6 @@ int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs) | |||
986 | #ifdef DEBUG_LOW | 1003 | #ifdef DEBUG_LOW |
987 | DBG("%s: get_one_irq(): %d\n", mpic->name, irq); | 1004 | DBG("%s: get_one_irq(): %d\n", mpic->name, irq); |
988 | #endif | 1005 | #endif |
989 | if (mpic->cascade && irq == mpic->cascade_vec) { | ||
990 | #ifdef DEBUG_LOW | ||
991 | DBG("%s: cascading ...\n", mpic->name); | ||
992 | #endif | ||
993 | irq = mpic->cascade(regs, mpic->cascade_data); | ||
994 | mpic_eoi(mpic); | ||
995 | return irq; | ||
996 | } | ||
997 | if (unlikely(irq == MPIC_VEC_SPURRIOUS)) | 1006 | if (unlikely(irq == MPIC_VEC_SPURRIOUS)) |
998 | return -1; | 1007 | return -1; |
999 | if (irq < MPIC_VEC_IPI_0) { | 1008 | if (irq < MPIC_VEC_IPI_0) { |
diff --git a/include/asm-powerpc/i8259.h b/include/asm-powerpc/i8259.h index 0392159e16e4..ff31cb90325f 100644 --- a/include/asm-powerpc/i8259.h +++ b/include/asm-powerpc/i8259.h | |||
@@ -4,11 +4,8 @@ | |||
4 | 4 | ||
5 | #include <linux/irq.h> | 5 | #include <linux/irq.h> |
6 | 6 | ||
7 | extern struct hw_interrupt_type i8259_pic; | ||
8 | |||
9 | extern void i8259_init(unsigned long intack_addr, int offset); | 7 | extern void i8259_init(unsigned long intack_addr, int offset); |
10 | extern int i8259_irq(struct pt_regs *regs); | 8 | extern int i8259_irq(struct pt_regs *regs); |
11 | extern int i8259_irq_cascade(struct pt_regs *regs, void *unused); | ||
12 | 9 | ||
13 | #endif /* __KERNEL__ */ | 10 | #endif /* __KERNEL__ */ |
14 | #endif /* _ASM_POWERPC_I8259_H */ | 11 | #endif /* _ASM_POWERPC_I8259_H */ |
diff --git a/include/asm-powerpc/irq.h b/include/asm-powerpc/irq.h index eb5f33e1977a..13fa2ef38dc7 100644 --- a/include/asm-powerpc/irq.h +++ b/include/asm-powerpc/irq.h | |||
@@ -514,9 +514,12 @@ extern u64 ppc64_interrupt_controller; | |||
514 | 514 | ||
515 | #endif | 515 | #endif |
516 | 516 | ||
517 | #ifndef CONFIG_PPC_MERGE | ||
517 | #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) | 518 | #define NR_MASK_WORDS ((NR_IRQS + 31) / 32) |
518 | /* pedantic: these are long because they are used with set_bit --RR */ | 519 | /* pedantic: these are long because they are used with set_bit --RR */ |
519 | extern unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; | 520 | extern unsigned long ppc_cached_irq_mask[NR_MASK_WORDS]; |
521 | #endif | ||
522 | |||
520 | extern atomic_t ppc_n_lost_interrupts; | 523 | extern atomic_t ppc_n_lost_interrupts; |
521 | 524 | ||
522 | #define virt_irq_create_mapping(x) (x) | 525 | #define virt_irq_create_mapping(x) (x) |
@@ -579,9 +582,8 @@ extern struct thread_info *softirq_ctx[NR_CPUS]; | |||
579 | 582 | ||
580 | extern void irq_ctx_init(void); | 583 | extern void irq_ctx_init(void); |
581 | extern void call_do_softirq(struct thread_info *tp); | 584 | extern void call_do_softirq(struct thread_info *tp); |
582 | extern int call___do_IRQ(int irq, struct pt_regs *regs, | 585 | extern int call_handle_irq(int irq, void *p1, void *p2, |
583 | struct thread_info *tp); | 586 | struct thread_info *tp, void *func); |
584 | |||
585 | #else | 587 | #else |
586 | #define irq_ctx_init() | 588 | #define irq_ctx_init() |
587 | 589 | ||
diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h index f0d22ac34b96..a2277cb77ddc 100644 --- a/include/asm-powerpc/mpic.h +++ b/include/asm-powerpc/mpic.h | |||
@@ -114,9 +114,6 @@ | |||
114 | #define MPIC_VEC_TIMER_1 248 | 114 | #define MPIC_VEC_TIMER_1 248 |
115 | #define MPIC_VEC_TIMER_0 247 | 115 | #define MPIC_VEC_TIMER_0 247 |
116 | 116 | ||
117 | /* Type definition of the cascade handler */ | ||
118 | typedef int (*mpic_cascade_t)(struct pt_regs *regs, void *data); | ||
119 | |||
120 | #ifdef CONFIG_MPIC_BROKEN_U3 | 117 | #ifdef CONFIG_MPIC_BROKEN_U3 |
121 | /* Fixup table entry */ | 118 | /* Fixup table entry */ |
122 | struct mpic_irq_fixup | 119 | struct mpic_irq_fixup |
@@ -133,9 +130,12 @@ struct mpic_irq_fixup | |||
133 | struct mpic | 130 | struct mpic |
134 | { | 131 | { |
135 | /* The "linux" controller struct */ | 132 | /* The "linux" controller struct */ |
136 | hw_irq_controller hc_irq; | 133 | struct irq_chip hc_irq; |
134 | #ifdef CONFIG_MPIC_BROKEN_U3 | ||
135 | struct irq_chip hc_ht_irq; | ||
136 | #endif | ||
137 | #ifdef CONFIG_SMP | 137 | #ifdef CONFIG_SMP |
138 | hw_irq_controller hc_ipi; | 138 | struct irq_chip hc_ipi; |
139 | #endif | 139 | #endif |
140 | const char *name; | 140 | const char *name; |
141 | /* Flags */ | 141 | /* Flags */ |
@@ -153,10 +153,6 @@ struct mpic | |||
153 | unsigned int num_sources; | 153 | unsigned int num_sources; |
154 | /* Number of CPUs */ | 154 | /* Number of CPUs */ |
155 | unsigned int num_cpus; | 155 | unsigned int num_cpus; |
156 | /* cascade handler */ | ||
157 | mpic_cascade_t cascade; | ||
158 | void *cascade_data; | ||
159 | unsigned int cascade_vec; | ||
160 | /* senses array */ | 156 | /* senses array */ |
161 | unsigned char *senses; | 157 | unsigned char *senses; |
162 | unsigned int senses_count; | 158 | unsigned int senses_count; |
@@ -237,17 +233,6 @@ extern void mpic_assign_isu(struct mpic *mpic, unsigned int isu_num, | |||
237 | */ | 233 | */ |
238 | extern void mpic_init(struct mpic *mpic); | 234 | extern void mpic_init(struct mpic *mpic); |
239 | 235 | ||
240 | /* Setup a cascade. Currently, only one cascade is supported this | ||
241 | * way, though you can always do a normal request_irq() and add | ||
242 | * other cascades this way. You should call this _after_ having | ||
243 | * added all the ISUs | ||
244 | * | ||
245 | * @irq_no: "linux" irq number of the cascade (that is offset'ed vector) | ||
246 | * @handler: cascade handler function | ||
247 | */ | ||
248 | extern void mpic_setup_cascade(unsigned int irq_no, mpic_cascade_t hanlder, | ||
249 | void *data); | ||
250 | |||
251 | /* | 236 | /* |
252 | * All of the following functions must only be used after the | 237 | * All of the following functions must only be used after the |
253 | * ISUs have been assigned and the controller fully initialized | 238 | * ISUs have been assigned and the controller fully initialized |