]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/powerpc/platforms/cell/interrupt.c
97936f547f1956d9249668100adc49ee0caf1967
[linux-2.6-omap-h63xx.git] / arch / powerpc / platforms / cell / interrupt.c
1 /*
2  * Cell Internal Interrupt Controller
3  *
4  * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
5  *
6  * Author: Arnd Bergmann <arndb@de.ibm.com>
7  *
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)
11  * any later version.
12  *
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.
17  *
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.
21  */
22
23 #include <linux/interrupt.h>
24 #include <linux/irq.h>
25 #include <linux/module.h>
26 #include <linux/percpu.h>
27 #include <linux/types.h>
28
29 #include <asm/io.h>
30 #include <asm/pgtable.h>
31 #include <asm/prom.h>
32 #include <asm/ptrace.h>
33
34 #include "interrupt.h"
35 #include "cbe_regs.h"
36
37 struct iic {
38         struct cbe_iic_thread_regs __iomem *regs;
39         u8 target_id;
40         u8 eoi_stack[16];
41         int eoi_ptr;
42 };
43
44 static DEFINE_PER_CPU(struct iic, iic);
45
46 static void iic_mask(unsigned int irq)
47 {
48 }
49
50 static void iic_unmask(unsigned int irq)
51 {
52 }
53
54 static void iic_eoi(unsigned int irq)
55 {
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);
59 }
60
61 static struct irq_chip iic_chip = {
62         .typename = " CELL-IIC ",
63         .mask = iic_mask,
64         .unmask = iic_unmask,
65         .eoi = iic_eoi,
66 };
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 */
85 static int iic_external_get_irq(struct cbe_iic_pending_bits pending)
86 {
87         int irq;
88         unsigned char node, unit;
89
90         node = pending.source >> 4;
91         unit = pending.source & 0xf;
92         irq = -1;
93
94         /*
95          * This mapping is specific to the Cell Broadband
96          * Engine. We might need to get the numbers
97          * from the device tree to support future CPUs.
98          */
99         switch (unit) {
100         case 0x00:
101         case 0x0b:
102                 /*
103                  * One of these units can be connected
104                  * to an external interrupt controller.
105                  */
106                 if (pending.class != 2)
107                         break;
108                 /* TODO: We might want to silently ignore cascade interrupts
109                  * when no cascade handler exist yet
110                  */
111                 irq = IIC_EXT_CASCADE + node * IIC_NODE_STRIDE;
112                 break;
113         case 0x01 ... 0x04:
114         case 0x07 ... 0x0a:
115                 /*
116                  * These units are connected to the SPEs
117                  */
118                 if (pending.class > 2)
119                         break;
120                 irq = IIC_SPE_OFFSET
121                         + pending.class * IIC_CLASS_STRIDE
122                         + node * IIC_NODE_STRIDE
123                         + unit;
124                 break;
125         }
126         if (irq == -1)
127                 printk(KERN_WARNING "Unexpected interrupt class %02x, "
128                         "source %02x, prio %02x, cpu %02x\n", pending.class,
129                         pending.source, pending.prio, smp_processor_id());
130         return irq;
131 }
132
133 /* Get an IRQ number from the pending state register of the IIC */
134 int iic_get_irq(struct pt_regs *regs)
135 {
136         struct iic *iic;
137         int irq;
138         struct cbe_iic_pending_bits pending;
139
140         iic = &__get_cpu_var(iic);
141         *(unsigned long *) &pending = 
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);
145
146         irq = -1;
147         if (pending.flags & CBE_IIC_IRQ_VALID) {
148                 if (pending.flags & CBE_IIC_IRQ_IPI) {
149                         irq = IIC_IPI_OFFSET + (pending.prio >> 4);
150 /*
151                         if (irq > 0x80)
152                                 printk(KERN_WARNING "Unexpected IPI prio %02x"
153                                         "on CPU %02x\n", pending.prio,
154                                                         smp_processor_id());
155 */
156                 } else {
157                         irq = iic_external_get_irq(pending);
158                 }
159         }
160         return irq;
161 }
162
163 /* hardcoded part to be compatible with older firmware */
164
165 static int __init setup_iic_hardcoded(void)
166 {
167         struct device_node *np;
168         int nodeid, cpu;
169         unsigned long regs;
170         struct iic *iic;
171
172         for_each_possible_cpu(cpu) {
173                 iic = &per_cpu(iic, cpu);
174                 nodeid = cpu/2;
175
176                 for (np = of_find_node_by_type(NULL, "cpu");
177                      np;
178                      np = of_find_node_by_type(np, "cpu")) {
179                         if (nodeid == *(int *)get_property(np, "node-id", NULL))
180                                 break;
181                         }
182
183                 if (!np) {
184                         printk(KERN_WARNING "IIC: CPU %d not found\n", cpu);
185                         iic->regs = NULL;
186                         iic->target_id = 0xff;
187                         return -ENODEV;
188                         }
189
190                 regs = *(long *)get_property(np, "iic", NULL);
191
192                 /* hack until we have decided on the devtree info */
193                 regs += 0x400;
194                 if (cpu & 1)
195                         regs += 0x20;
196
197                 printk(KERN_INFO "IIC for CPU %d at %lx\n", cpu, regs);
198                 iic->regs = ioremap(regs, sizeof(struct cbe_iic_thread_regs));
199                 iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe);
200                 iic->eoi_stack[0] = 0xff;
201         }
202
203         return 0;
204 }
205
206 static int __init setup_iic(void)
207 {
208         struct device_node *dn;
209         unsigned long *regs;
210         char *compatible;
211         unsigned *np, found = 0;
212         struct iic *iic = NULL;
213
214         for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) {
215                 compatible = (char *)get_property(dn, "compatible", NULL);
216
217                 if (!compatible) {
218                         printk(KERN_WARNING "no compatible property found !\n");
219                         continue;
220                 }
221
222                 if (strstr(compatible, "IBM,CBEA-Internal-Interrupt-Controller"))
223                         regs = (unsigned long *)get_property(dn,"reg", NULL);
224                 else
225                         continue;
226
227                 if (!regs)
228                         printk(KERN_WARNING "IIC: no reg property\n");
229
230                 np = (unsigned int *)get_property(dn, "ibm,interrupt-server-ranges", NULL);
231
232                 if (!np) {
233                         printk(KERN_WARNING "IIC: CPU association not found\n");
234                         iic->regs = NULL;
235                         iic->target_id = 0xff;
236                         return -ENODEV;
237                 }
238
239                 iic = &per_cpu(iic, np[0]);
240                 iic->regs = ioremap(regs[0], sizeof(struct cbe_iic_thread_regs));
241                 iic->target_id = ((np[0] & 2) << 3) + ((np[0] & 1) ? 0xf : 0xe);
242                 iic->eoi_stack[0] = 0xff;
243                 printk("IIC for CPU %d at %lx mapped to %p\n", np[0], regs[0], iic->regs);
244
245                 iic = &per_cpu(iic, np[1]);
246                 iic->regs = ioremap(regs[2], sizeof(struct cbe_iic_thread_regs));
247                 iic->target_id = ((np[1] & 2) << 3) + ((np[1] & 1) ? 0xf : 0xe);
248                 iic->eoi_stack[0] = 0xff;
249
250                 printk("IIC for CPU %d at %lx mapped to %p\n", np[1], regs[2], iic->regs);
251
252                 found++;
253         }
254
255         if (found)
256                 return 0;
257         else
258                 return -ENODEV;
259 }
260
261 #ifdef CONFIG_SMP
262
263 /* Use the highest interrupt priorities for IPI */
264 static inline int iic_ipi_to_irq(int ipi)
265 {
266         return IIC_IPI_OFFSET + IIC_NUM_IPIS - 1 - ipi;
267 }
268
269 static inline int iic_irq_to_ipi(int irq)
270 {
271         return IIC_NUM_IPIS - 1 - (irq - IIC_IPI_OFFSET);
272 }
273
274 void iic_setup_cpu(void)
275 {
276         out_be64(&__get_cpu_var(iic).regs->prio, 0xff);
277 }
278
279 void iic_cause_IPI(int cpu, int mesg)
280 {
281         out_be64(&per_cpu(iic, cpu).regs->generate, (IIC_NUM_IPIS - 1 - mesg) << 4);
282 }
283
284 u8 iic_get_target_id(int cpu)
285 {
286         return per_cpu(iic, cpu).target_id;
287 }
288 EXPORT_SYMBOL_GPL(iic_get_target_id);
289
290 static irqreturn_t iic_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
291 {
292         smp_message_recv(iic_irq_to_ipi(irq), regs);
293         return IRQ_HANDLED;
294 }
295
296 static void iic_request_ipi(int ipi, const char *name)
297 {
298         int irq;
299
300         irq = iic_ipi_to_irq(ipi);
301
302         /* IPIs are marked IRQF_DISABLED as they must run with irqs
303          * disabled */
304         set_irq_chip_and_handler(irq, &iic_chip, handle_percpu_irq);
305         request_irq(irq, iic_ipi_action, IRQF_DISABLED, name, NULL);
306 }
307
308 void iic_request_IPIs(void)
309 {
310         iic_request_ipi(PPC_MSG_CALL_FUNCTION, "IPI-call");
311         iic_request_ipi(PPC_MSG_RESCHEDULE, "IPI-resched");
312 #ifdef CONFIG_DEBUGGER
313         iic_request_ipi(PPC_MSG_DEBUGGER_BREAK, "IPI-debug");
314 #endif /* CONFIG_DEBUGGER */
315 }
316 #endif /* CONFIG_SMP */
317
318 static void __init iic_setup_builtin_handlers(void)
319 {
320         int be, isrc;
321
322         /* XXX FIXME: Assume two threads per BE are present */
323         for (be=0; be < num_present_cpus() / 2; be++) {
324                 int irq;
325
326                 /* setup SPE chip and handlers */
327                 for (isrc = 0; isrc < IIC_CLASS_STRIDE * 3; isrc++) {
328                         irq = IIC_NODE_STRIDE * be + IIC_SPE_OFFSET + isrc;
329                         set_irq_chip_and_handler(irq, &iic_chip, handle_fasteoi_irq);
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         }
335 }
336
337 void __init iic_init_IRQ(void)
338 {
339         int cpu, irq_offset;
340         struct iic *iic;
341
342         if (setup_iic() < 0)
343                 setup_iic_hardcoded();
344
345         irq_offset = 0;
346         for_each_possible_cpu(cpu) {
347                 iic = &per_cpu(iic, cpu);
348                 if (iic->regs)
349                         out_be64(&iic->regs->prio, 0xff);
350         }
351         iic_setup_builtin_handlers();
352
353 }