2 * Cell Internal Interrupt Controller
4 * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
6 * Author: Arnd Bergmann <arndb@de.ibm.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include <linux/config.h>
24 #include <linux/interrupt.h>
25 #include <linux/irq.h>
26 #include <linux/module.h>
27 #include <linux/percpu.h>
28 #include <linux/types.h>
31 #include <asm/pgtable.h>
33 #include <asm/ptrace.h>
35 #include "interrupt.h"
37 struct iic_pending_bits
{
45 enum iic_pending_flags
{
51 struct iic_pending_bits pending
;
52 struct iic_pending_bits pending_destr
;
58 struct iic_regs __iomem
*regs
;
62 static DEFINE_PER_CPU(struct iic
, iic
);
64 void iic_local_enable(void)
66 struct iic
*iic
= &__get_cpu_var(iic
);
70 * There seems to be a bug that is present in DD2.x CPUs
71 * and still only partially fixed in DD3.1.
72 * This bug causes a value written to the priority register
73 * not to make it there, resulting in a system hang unless we
75 * Masking with 0xf0 is done because the Cell BE does not
76 * implement the lower four bits of the interrupt priority,
77 * they always read back as zeroes, although future CPUs
78 * might implement different bits.
81 out_be64(&iic
->regs
->prio
, 0xff);
82 tmp
= in_be64(&iic
->regs
->prio
);
83 } while ((tmp
& 0xf0) != 0xf0);
86 void iic_local_disable(void)
88 out_be64(&__get_cpu_var(iic
).regs
->prio
, 0x0);
91 static unsigned int iic_startup(unsigned int irq
)
96 static void iic_enable(unsigned int irq
)
101 static void iic_disable(unsigned int irq
)
105 static void iic_end(unsigned int irq
)
110 static struct hw_interrupt_type iic_pic
= {
111 .typename
= " CELL-IIC ",
112 .startup
= iic_startup
,
113 .enable
= iic_enable
,
114 .disable
= iic_disable
,
118 static int iic_external_get_irq(struct iic_pending_bits pending
)
121 unsigned char node
, unit
;
123 node
= pending
.source
>> 4;
124 unit
= pending
.source
& 0xf;
128 * This mapping is specific to the Cell Broadband
129 * Engine. We might need to get the numbers
130 * from the device tree to support future CPUs.
136 * One of these units can be connected
137 * to an external interrupt controller.
139 if (pending
.prio
> 0x3f ||
143 + spider_get_irq(node
)
144 + node
* IIC_NODE_STRIDE
;
149 * These units are connected to the SPEs
151 if (pending
.class > 2)
154 + pending
.class * IIC_CLASS_STRIDE
155 + node
* IIC_NODE_STRIDE
160 printk(KERN_WARNING
"Unexpected interrupt class %02x, "
161 "source %02x, prio %02x, cpu %02x\n", pending
.class,
162 pending
.source
, pending
.prio
, smp_processor_id());
166 /* Get an IRQ number from the pending state register of the IIC */
167 int iic_get_irq(struct pt_regs
*regs
)
171 struct iic_pending_bits pending
;
173 iic
= &__get_cpu_var(iic
);
174 *(unsigned long *) &pending
=
175 in_be64((unsigned long __iomem
*) &iic
->regs
->pending_destr
);
178 if (pending
.flags
& IIC_VALID
) {
179 if (pending
.flags
& IIC_IPI
) {
180 irq
= IIC_IPI_OFFSET
+ (pending
.prio
>> 4);
183 printk(KERN_WARNING "Unexpected IPI prio %02x"
184 "on CPU %02x\n", pending.prio,
188 irq
= iic_external_get_irq(pending
);
194 /* hardcoded part to be compatible with older firmware */
196 static int setup_iic_hardcoded(void)
198 struct device_node
*np
;
204 iic
= &per_cpu(iic
, cpu
);
207 for (np
= of_find_node_by_type(NULL
, "cpu");
209 np
= of_find_node_by_type(np
, "cpu")) {
210 if (nodeid
== *(int *)get_property(np
, "node-id", NULL
))
215 printk(KERN_WARNING
"IIC: CPU %d not found\n", cpu
);
217 iic
->target_id
= 0xff;
221 regs
= *(long *)get_property(np
, "iic", NULL
);
223 /* hack until we have decided on the devtree info */
228 printk(KERN_INFO
"IIC for CPU %d at %lx\n", cpu
, regs
);
229 iic
->regs
= ioremap(regs
, sizeof(struct iic_regs
));
230 iic
->target_id
= (nodeid
<< 4) + ((cpu
& 1) ? 0xf : 0xe);
236 static int setup_iic(void)
238 struct device_node
*dn
;
241 unsigned *np
, found
= 0;
242 struct iic
*iic
= NULL
;
244 for (dn
= NULL
; (dn
= of_find_node_by_name(dn
, "interrupt-controller"));) {
245 compatible
= (char *)get_property(dn
, "compatible", NULL
);
248 printk(KERN_WARNING
"no compatible property found !\n");
252 if (strstr(compatible
, "IBM,CBEA-Internal-Interrupt-Controller"))
253 regs
= (unsigned long *)get_property(dn
,"reg", NULL
);
258 printk(KERN_WARNING
"IIC: no reg property\n");
260 np
= (unsigned int *)get_property(dn
, "ibm,interrupt-server-ranges", NULL
);
263 printk(KERN_WARNING
"IIC: CPU association not found\n");
265 iic
->target_id
= 0xff;
269 iic
= &per_cpu(iic
, np
[0]);
270 iic
->regs
= ioremap(regs
[0], sizeof(struct iic_regs
));
271 iic
->target_id
= ((np
[0] & 2) << 3) + ((np
[0] & 1) ? 0xf : 0xe);
272 printk("IIC for CPU %d at %lx mapped to %p\n", np
[0], regs
[0], iic
->regs
);
274 iic
= &per_cpu(iic
, np
[1]);
275 iic
->regs
= ioremap(regs
[2], sizeof(struct iic_regs
));
276 iic
->target_id
= ((np
[1] & 2) << 3) + ((np
[1] & 1) ? 0xf : 0xe);
277 printk("IIC for CPU %d at %lx mapped to %p\n", np
[1], regs
[2], iic
->regs
);
290 /* Use the highest interrupt priorities for IPI */
291 static inline int iic_ipi_to_irq(int ipi
)
293 return IIC_IPI_OFFSET
+ IIC_NUM_IPIS
- 1 - ipi
;
296 static inline int iic_irq_to_ipi(int irq
)
298 return IIC_NUM_IPIS
- 1 - (irq
- IIC_IPI_OFFSET
);
301 void iic_setup_cpu(void)
303 out_be64(&__get_cpu_var(iic
).regs
->prio
, 0xff);
306 void iic_cause_IPI(int cpu
, int mesg
)
308 out_be64(&per_cpu(iic
, cpu
).regs
->generate
, (IIC_NUM_IPIS
- 1 - mesg
) << 4);
311 u8
iic_get_target_id(int cpu
)
313 return per_cpu(iic
, cpu
).target_id
;
315 EXPORT_SYMBOL_GPL(iic_get_target_id
);
317 static irqreturn_t
iic_ipi_action(int irq
, void *dev_id
, struct pt_regs
*regs
)
319 smp_message_recv(iic_irq_to_ipi(irq
), regs
);
323 static void iic_request_ipi(int ipi
, const char *name
)
327 irq
= iic_ipi_to_irq(ipi
);
328 /* IPIs are marked SA_INTERRUPT as they must run with irqs
330 get_irq_desc(irq
)->handler
= &iic_pic
;
331 get_irq_desc(irq
)->status
|= IRQ_PER_CPU
;
332 request_irq(irq
, iic_ipi_action
, SA_INTERRUPT
, name
, NULL
);
335 void iic_request_IPIs(void)
337 iic_request_ipi(PPC_MSG_CALL_FUNCTION
, "IPI-call");
338 iic_request_ipi(PPC_MSG_RESCHEDULE
, "IPI-resched");
339 #ifdef CONFIG_DEBUGGER
340 iic_request_ipi(PPC_MSG_DEBUGGER_BREAK
, "IPI-debug");
341 #endif /* CONFIG_DEBUGGER */
343 #endif /* CONFIG_SMP */
345 static void iic_setup_spe_handlers(void)
349 /* Assume two threads per BE are present */
350 for (be
=0; be
< num_present_cpus() / 2; be
++) {
351 for (isrc
= 0; isrc
< IIC_CLASS_STRIDE
* 3; isrc
++) {
352 int irq
= IIC_NODE_STRIDE
* be
+ IIC_SPE_OFFSET
+ isrc
;
353 get_irq_desc(irq
)->handler
= &iic_pic
;
358 void iic_init_IRQ(void)
364 setup_iic_hardcoded();
367 for_each_possible_cpu(cpu
) {
368 iic
= &per_cpu(iic
, cpu
);
370 out_be64(&iic
->regs
->prio
, 0xff);
372 iic_setup_spe_handlers();