[POWERPC] ps3: bind interrupt to cpu
[pandora-kernel.git] / arch / powerpc / platforms / ps3 / interrupt.c
1 /*
2  *  PS3 interrupt routines.
3  *
4  *  Copyright (C) 2006 Sony Computer Entertainment Inc.
5  *  Copyright 2006 Sony Corp.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; version 2 of the License.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <linux/irq.h>
24
25 #include <asm/machdep.h>
26 #include <asm/udbg.h>
27 #include <asm/ps3.h>
28 #include <asm/lv1call.h>
29
30 #include "platform.h"
31
32 #if defined(DEBUG)
33 #define DBG(fmt...) udbg_printf(fmt)
34 #else
35 #define DBG(fmt...) do{if(0)printk(fmt);}while(0)
36 #endif
37
38 /**
39  * struct ps3_bmp - a per cpu irq status and mask bitmap structure
40  * @status: 256 bit status bitmap indexed by plug
41  * @unused_1:
42  * @mask: 256 bit mask bitmap indexed by plug
43  * @unused_2:
44  * @lock:
45  * @ipi_debug_brk_mask:
46  *
47  * The HV mantains per SMT thread mappings of HV outlet to HV plug on
48  * behalf of the guest.  These mappings are implemented as 256 bit guest
49  * supplied bitmaps indexed by plug number.  The addresses of the bitmaps
50  * are registered with the HV through lv1_configure_irq_state_bitmap().
51  *
52  * The HV supports 256 plugs per thread, assigned as {0..255}, for a total
53  * of 512 plugs supported on a processor.  To simplify the logic this
54  * implementation equates HV plug value to Linux virq value, constrains each
55  * interrupt to have a system wide unique plug number, and limits the range
56  * of the plug values to map into the first dword of the bitmaps.  This
57  * gives a usable range of plug values of  {NUM_ISA_INTERRUPTS..63}.  Note
58  * that there is no constraint on how many in this set an individual thread
59  * can acquire.
60  */
61
62 struct ps3_bmp {
63         struct {
64                 u64 status;
65                 u64 unused_1[3];
66                 u64 mask;
67                 u64 unused_2[3];
68         };
69         u64 ipi_debug_brk_mask;
70         spinlock_t lock;
71 };
72
73 /**
74  * struct ps3_private - a per cpu data structure
75  * @bmp: ps3_bmp structure
76  * @node: HV logical_ppe_id
77  * @cpu: HV thread_id
78  */
79
80 struct ps3_private {
81         struct ps3_bmp bmp __attribute__ ((aligned (64)));
82         u64 node;
83         unsigned int cpu;
84 };
85
86 static DEFINE_PER_CPU(struct ps3_private, ps3_private);
87
88 static int ps3_connect_irq(enum ps3_cpu_binding cpu, unsigned long outlet,
89         unsigned int *virq)
90 {
91         int result;
92         struct ps3_private *pd;
93
94         /* This defines the default interrupt distribution policy. */
95
96         if (cpu == PS3_BINDING_CPU_ANY)
97                 cpu = 0;
98
99         pd = &per_cpu(ps3_private, cpu);
100
101         *virq = irq_create_mapping(NULL, outlet);
102
103         if (*virq == NO_IRQ) {
104                 pr_debug("%s:%d: irq_create_mapping failed: outlet %lu\n",
105                         __func__, __LINE__, outlet);
106                 result = -ENOMEM;
107                 goto fail_create;
108         }
109
110         /* Binds outlet to cpu + virq. */
111
112         result = lv1_connect_irq_plug_ext(pd->node, pd->cpu, *virq, outlet, 0);
113
114         if (result) {
115                 pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n",
116                 __func__, __LINE__, ps3_result(result));
117                 result = -EPERM;
118                 goto fail_connect;
119         }
120
121         pr_debug("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__,
122                 outlet, cpu, *virq);
123
124         result = set_irq_chip_data(*virq, pd);
125
126         if (result) {
127                 pr_debug("%s:%d: set_irq_chip_data failed\n",
128                         __func__, __LINE__);
129                 goto fail_set;
130         }
131
132         return result;
133
134 fail_set:
135         lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, *virq);
136 fail_connect:
137         irq_dispose_mapping(*virq);
138 fail_create:
139         return result;
140 }
141
142 static void ps3_disconnect_irq(unsigned int virq)
143 {
144         int result;
145         const struct ps3_private *pd = get_irq_chip_data(virq);
146
147         pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__,
148                 pd->node, pd->cpu, virq);
149
150         result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq);
151
152         if (result)
153                 pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n",
154                 __func__, __LINE__, ps3_result(result));
155
156         set_irq_chip_data(virq, NULL);
157         irq_dispose_mapping(virq);
158 }
159
160 /**
161  * ps3_alloc_io_irq - Assign a virq to a system bus device.
162  * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
163  * serviced on.
164  * @interrupt_id: The device interrupt id read from the system repository.
165  * @virq: The assigned Linux virq.
166  *
167  * An io irq represents a non-virtualized device interrupt.  interrupt_id
168  * coresponds to the interrupt number of the interrupt controller.
169  */
170
171 int ps3_alloc_io_irq(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
172         unsigned int *virq)
173 {
174         int result;
175         unsigned long outlet;
176
177         result = lv1_construct_io_irq_outlet(interrupt_id, &outlet);
178
179         if (result) {
180                 pr_debug("%s:%d: lv1_construct_io_irq_outlet failed: %s\n",
181                         __func__, __LINE__, ps3_result(result));
182                 return result;
183         }
184
185         result = ps3_connect_irq(cpu, outlet, virq);
186         BUG_ON(result);
187
188         return result;
189 }
190
191 int ps3_free_io_irq(unsigned int virq)
192 {
193         int result;
194
195         result = lv1_destruct_io_irq_outlet(virq_to_hw(virq));
196
197         if (result)
198                 pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n",
199                         __func__, __LINE__, ps3_result(result));
200
201         ps3_disconnect_irq(virq);
202
203         return result;
204 }
205
206 /**
207  * ps3_alloc_event_irq - Allocate a virq for use with a system event.
208  * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
209  * serviced on.
210  * @virq: The assigned Linux virq.
211  *
212  * The virq can be used with lv1_connect_interrupt_event_receive_port() to
213  * arrange to receive events, or with ps3_send_event_locally() to signal
214  * events.
215  */
216
217 int ps3_alloc_event_irq(enum ps3_cpu_binding cpu, unsigned int *virq)
218 {
219         int result;
220         unsigned long outlet;
221
222         result = lv1_construct_event_receive_port(&outlet);
223
224         if (result) {
225                 pr_debug("%s:%d: lv1_construct_event_receive_port failed: %s\n",
226                         __func__, __LINE__, ps3_result(result));
227                 *virq = NO_IRQ;
228                 return result;
229         }
230
231         result = ps3_connect_irq(cpu, outlet, virq);
232         BUG_ON(result);
233
234         return result;
235 }
236
237 int ps3_free_event_irq(unsigned int virq)
238 {
239         int result;
240
241         pr_debug(" -> %s:%d\n", __func__, __LINE__);
242
243         result = lv1_destruct_event_receive_port(virq_to_hw(virq));
244
245         if (result)
246                 pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n",
247                         __func__, __LINE__, ps3_result(result));
248
249         ps3_disconnect_irq(virq);
250
251         pr_debug(" <- %s:%d\n", __func__, __LINE__);
252         return result;
253 }
254
255 int ps3_send_event_locally(unsigned int virq)
256 {
257         return lv1_send_event_locally(virq_to_hw(virq));
258 }
259
260 /**
261  * ps3_connect_event_irq - Assign a virq to a system bus device.
262  * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
263  * serviced on.
264  * @did: The HV device identifier read from the system repository.
265  * @interrupt_id: The device interrupt id read from the system repository.
266  * @virq: The assigned Linux virq.
267  *
268  * An event irq represents a virtual device interrupt.  The interrupt_id
269  * coresponds to the software interrupt number.
270  */
271
272 int ps3_connect_event_irq(enum ps3_cpu_binding cpu,
273         const struct ps3_device_id *did, unsigned int interrupt_id,
274         unsigned int *virq)
275 {
276         int result;
277
278         result = ps3_alloc_event_irq(cpu, virq);
279
280         if (result)
281                 return result;
282
283         result = lv1_connect_interrupt_event_receive_port(did->bus_id,
284                 did->dev_id, virq_to_hw(*virq), interrupt_id);
285
286         if (result) {
287                 pr_debug("%s:%d: lv1_connect_interrupt_event_receive_port"
288                         " failed: %s\n", __func__, __LINE__,
289                         ps3_result(result));
290                 ps3_free_event_irq(*virq);
291                 *virq = NO_IRQ;
292                 return result;
293         }
294
295         pr_debug("%s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__,
296                 interrupt_id, *virq);
297
298         return 0;
299 }
300
301 int ps3_disconnect_event_irq(const struct ps3_device_id *did,
302         unsigned int interrupt_id, unsigned int virq)
303 {
304         int result;
305
306         pr_debug(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__,
307                 interrupt_id, virq);
308
309         result = lv1_disconnect_interrupt_event_receive_port(did->bus_id,
310                 did->dev_id, virq_to_hw(virq), interrupt_id);
311
312         if (result)
313                 pr_debug("%s:%d: lv1_disconnect_interrupt_event_receive_port"
314                         " failed: %s\n", __func__, __LINE__,
315                         ps3_result(result));
316
317         ps3_free_event_irq(virq);
318
319         pr_debug(" <- %s:%d\n", __func__, __LINE__);
320         return result;
321 }
322
323 /**
324  * ps3_alloc_vuart_irq - Configure the system virtual uart virq.
325  * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
326  * serviced on.
327  * @virt_addr_bmp: The caller supplied virtual uart interrupt bitmap.
328  * @virq: The assigned Linux virq.
329  *
330  * The system supports only a single virtual uart, so multiple calls without
331  * freeing the interrupt will return a wrong state error.
332  */
333
334 int ps3_alloc_vuart_irq(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
335         unsigned int *virq)
336 {
337         int result;
338         unsigned long outlet;
339         u64 lpar_addr;
340
341         BUG_ON(!is_kernel_addr((u64)virt_addr_bmp));
342
343         lpar_addr = ps3_mm_phys_to_lpar(__pa(virt_addr_bmp));
344
345         result = lv1_configure_virtual_uart_irq(lpar_addr, &outlet);
346
347         if (result) {
348                 pr_debug("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n",
349                         __func__, __LINE__, ps3_result(result));
350                 return result;
351         }
352
353         result = ps3_connect_irq(cpu, outlet, virq);
354         BUG_ON(result);
355
356         return result;
357 }
358
359 int ps3_free_vuart_irq(unsigned int virq)
360 {
361         int result;
362
363         result = lv1_deconfigure_virtual_uart_irq();
364
365         if (result) {
366                 pr_debug("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n",
367                         __func__, __LINE__, ps3_result(result));
368                 return result;
369         }
370
371         ps3_disconnect_irq(virq);
372
373         return result;
374 }
375
376 /**
377  * ps3_alloc_spe_irq - Configure an spe virq.
378  * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be
379  * serviced on.
380  * @spe_id: The spe_id returned from lv1_construct_logical_spe().
381  * @class: The spe interrupt class {0,1,2}.
382  * @virq: The assigned Linux virq.
383  *
384  */
385
386 int ps3_alloc_spe_irq(enum ps3_cpu_binding cpu, unsigned long spe_id,
387         unsigned int class, unsigned int *virq)
388 {
389         int result;
390         unsigned long outlet;
391
392         BUG_ON(class > 2);
393
394         result = lv1_get_spe_irq_outlet(spe_id, class, &outlet);
395
396         if (result) {
397                 pr_debug("%s:%d: lv1_get_spe_irq_outlet failed: %s\n",
398                         __func__, __LINE__, ps3_result(result));
399                 return result;
400         }
401
402         result = ps3_connect_irq(cpu, outlet, virq);
403         BUG_ON(result);
404
405         return result;
406 }
407
408 int ps3_free_spe_irq(unsigned int virq)
409 {
410         ps3_disconnect_irq(virq);
411         return 0;
412 }
413
414 #define PS3_INVALID_OUTLET ((irq_hw_number_t)-1)
415 #define PS3_PLUG_MAX 63
416
417 #if defined(DEBUG)
418 static void _dump_64_bmp(const char *header, const u64 *p, unsigned cpu,
419         const char* func, int line)
420 {
421         pr_debug("%s:%d: %s %u {%04lx_%04lx_%04lx_%04lx}\n",
422                 func, line, header, cpu,
423                 *p >> 48, (*p >> 32) & 0xffff, (*p >> 16) & 0xffff,
424                 *p & 0xffff);
425 }
426
427 static void __attribute__ ((unused)) _dump_256_bmp(const char *header,
428         const u64 *p, unsigned cpu, const char* func, int line)
429 {
430         pr_debug("%s:%d: %s %u {%016lx:%016lx:%016lx:%016lx}\n",
431                 func, line, header, cpu, p[0], p[1], p[2], p[3]);
432 }
433
434 #define dump_bmp(_x) _dump_bmp(_x, __func__, __LINE__)
435 static void _dump_bmp(struct ps3_private* pd, const char* func, int line)
436 {
437         unsigned long flags;
438
439         spin_lock_irqsave(&pd->bmp.lock, flags);
440         _dump_64_bmp("stat", &pd->bmp.status, pd->cpu, func, line);
441         _dump_64_bmp("mask", &pd->bmp.mask, pd->cpu, func, line);
442         spin_unlock_irqrestore(&pd->bmp.lock, flags);
443 }
444
445 #define dump_mask(_x) _dump_mask(_x, __func__, __LINE__)
446 static void __attribute__ ((unused)) _dump_mask(struct ps3_private* pd,
447         const char* func, int line)
448 {
449         unsigned long flags;
450
451         spin_lock_irqsave(&pd->bmp.lock, flags);
452         _dump_64_bmp("mask", &pd->bmp.mask, pd->cpu, func, line);
453         spin_unlock_irqrestore(&pd->bmp.lock, flags);
454 }
455 #else
456 static void dump_bmp(struct ps3_private* pd) {};
457 #endif /* defined(DEBUG) */
458
459 static void ps3_chip_mask(unsigned int virq)
460 {
461         struct ps3_private *pd = get_irq_chip_data(virq);
462         u64 bit = 0x8000000000000000UL >> virq;
463         u64 *p = &pd->bmp.mask;
464         u64 old;
465         unsigned long flags;
466
467         pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq);
468
469         local_irq_save(flags);
470         asm volatile(
471                      "1:        ldarx %0,0,%3\n"
472                      "andc      %0,%0,%2\n"
473                      "stdcx.    %0,0,%3\n"
474                      "bne-      1b"
475                      : "=&r" (old), "+m" (*p)
476                      : "r" (bit), "r" (p)
477                      : "cc" );
478
479         lv1_did_update_interrupt_mask(pd->node, pd->cpu);
480         local_irq_restore(flags);
481 }
482
483 static void ps3_chip_unmask(unsigned int virq)
484 {
485         struct ps3_private *pd = get_irq_chip_data(virq);
486         u64 bit = 0x8000000000000000UL >> virq;
487         u64 *p = &pd->bmp.mask;
488         u64 old;
489         unsigned long flags;
490
491         pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq);
492
493         local_irq_save(flags);
494         asm volatile(
495                      "1:        ldarx %0,0,%3\n"
496                      "or        %0,%0,%2\n"
497                      "stdcx.    %0,0,%3\n"
498                      "bne-      1b"
499                      : "=&r" (old), "+m" (*p)
500                      : "r" (bit), "r" (p)
501                      : "cc" );
502
503         lv1_did_update_interrupt_mask(pd->node, pd->cpu);
504         local_irq_restore(flags);
505 }
506
507 static void ps3_chip_eoi(unsigned int virq)
508 {
509         const struct ps3_private *pd = get_irq_chip_data(virq);
510         lv1_end_of_interrupt_ext(pd->node, pd->cpu, virq);
511 }
512
513 static struct irq_chip irq_chip = {
514         .typename = "ps3",
515         .mask = ps3_chip_mask,
516         .unmask = ps3_chip_unmask,
517         .eoi = ps3_chip_eoi,
518 };
519
520 static void ps3_host_unmap(struct irq_host *h, unsigned int virq)
521 {
522         set_irq_chip_data(virq, NULL);
523 }
524
525 static int ps3_host_map(struct irq_host *h, unsigned int virq,
526         irq_hw_number_t hwirq)
527 {
528         pr_debug("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq,
529                 virq);
530
531         set_irq_chip_and_handler(virq, &irq_chip, handle_fasteoi_irq);
532
533         return 0;
534 }
535
536 static struct irq_host_ops ps3_host_ops = {
537         .map = ps3_host_map,
538         .unmap = ps3_host_unmap,
539 };
540
541 void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq)
542 {
543         struct ps3_private *pd = &per_cpu(ps3_private, cpu);
544
545         pd->bmp.ipi_debug_brk_mask = 0x8000000000000000UL >> virq;
546
547         pr_debug("%s:%d: cpu %u, virq %u, mask %lxh\n", __func__, __LINE__,
548                 cpu, virq, pd->bmp.ipi_debug_brk_mask);
549 }
550
551 unsigned int ps3_get_irq(void)
552 {
553         struct ps3_private *pd = &__get_cpu_var(ps3_private);
554         u64 x = (pd->bmp.status & pd->bmp.mask);
555         unsigned int plug;
556
557         /* check for ipi break first to stop this cpu ASAP */
558
559         if (x & pd->bmp.ipi_debug_brk_mask)
560                 x &= pd->bmp.ipi_debug_brk_mask;
561
562         asm volatile("cntlzd %0,%1" : "=r" (plug) : "r" (x));
563         plug &= 0x3f;
564
565         if (unlikely(plug) == NO_IRQ) {
566                 pr_debug("%s:%d: no plug found: cpu %u\n", __func__, __LINE__,
567                         pd->cpu);
568                 dump_bmp(&per_cpu(ps3_private, 0));
569                 dump_bmp(&per_cpu(ps3_private, 1));
570                 return NO_IRQ;
571         }
572
573 #if defined(DEBUG)
574         if (unlikely(plug < NUM_ISA_INTERRUPTS || plug > PS3_PLUG_MAX)) {
575                 dump_bmp(&per_cpu(ps3_private, 0));
576                 dump_bmp(&per_cpu(ps3_private, 1));
577                 BUG();
578         }
579 #endif
580         return plug;
581 }
582
583 void __init ps3_init_IRQ(void)
584 {
585         int result;
586         unsigned cpu;
587         struct irq_host *host;
588
589         host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &ps3_host_ops,
590                 PS3_INVALID_OUTLET);
591         irq_set_default_host(host);
592         irq_set_virq_count(PS3_PLUG_MAX + 1);
593
594         for_each_possible_cpu(cpu) {
595                 struct ps3_private *pd = &per_cpu(ps3_private, cpu);
596
597                 lv1_get_logical_ppe_id(&pd->node);
598                 pd->cpu = get_hard_smp_processor_id(cpu);
599                 spin_lock_init(&pd->bmp.lock);
600
601                 pr_debug("%s:%d: node %lu, cpu %d, bmp %lxh\n", __func__,
602                         __LINE__, pd->node, pd->cpu,
603                         ps3_mm_phys_to_lpar(__pa(&pd->bmp)));
604
605                 result = lv1_configure_irq_state_bitmap(pd->node, pd->cpu,
606                         ps3_mm_phys_to_lpar(__pa(&pd->bmp)));
607
608                 if (result)
609                         pr_debug("%s:%d: lv1_configure_irq_state_bitmap failed:"
610                                 " %s\n", __func__, __LINE__,
611                                 ps3_result(result));
612         }
613
614         ppc_md.get_irq = ps3_get_irq;
615 }