1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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/lv1call.h>
28#include <asm/smp.h>
29
30#include "platform.h"
31
32#if defined(DEBUG)
33#define DBG udbg_printf
34#else
35#define DBG pr_debug
36#endif
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67#define PS3_BMP_MINALIGN 64
68
69struct ps3_bmp {
70 struct {
71 u64 status;
72 u64 unused_1[3];
73 unsigned long mask;
74 u64 unused_2[3];
75 };
76 u64 ipi_debug_brk_mask;
77 spinlock_t lock;
78};
79
80
81
82
83
84
85
86
87struct ps3_private {
88 struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN)));
89 u64 ppe_id;
90 u64 thread_id;
91};
92
93static DEFINE_PER_CPU(struct ps3_private, ps3_private);
94
95
96
97
98
99
100
101
102static void ps3_chip_mask(struct irq_data *d)
103{
104 struct ps3_private *pd = irq_data_get_irq_chip_data(d);
105 unsigned long flags;
106
107 pr_debug("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__,
108 pd->thread_id, d->irq);
109
110 local_irq_save(flags);
111 clear_bit(63 - d->irq, &pd->bmp.mask);
112 lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id);
113 local_irq_restore(flags);
114}
115
116
117
118
119
120
121
122
123static void ps3_chip_unmask(struct irq_data *d)
124{
125 struct ps3_private *pd = irq_data_get_irq_chip_data(d);
126 unsigned long flags;
127
128 pr_debug("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__,
129 pd->thread_id, d->irq);
130
131 local_irq_save(flags);
132 set_bit(63 - d->irq, &pd->bmp.mask);
133 lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id);
134 local_irq_restore(flags);
135}
136
137
138
139
140
141
142
143
144static void ps3_chip_eoi(struct irq_data *d)
145{
146 const struct ps3_private *pd = irq_data_get_irq_chip_data(d);
147 lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, d->irq);
148}
149
150
151
152
153
154static struct irq_chip ps3_irq_chip = {
155 .name = "ps3",
156 .irq_mask = ps3_chip_mask,
157 .irq_unmask = ps3_chip_unmask,
158 .irq_eoi = ps3_chip_eoi,
159};
160
161
162
163
164
165
166
167
168
169
170
171
172static int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
173 unsigned int *virq)
174{
175 int result;
176 struct ps3_private *pd;
177
178
179
180 if (cpu == PS3_BINDING_CPU_ANY)
181 cpu = 0;
182
183 pd = &per_cpu(ps3_private, cpu);
184
185 *virq = irq_create_mapping(NULL, outlet);
186
187 if (*virq == NO_IRQ) {
188 pr_debug("%s:%d: irq_create_mapping failed: outlet %lu\n",
189 __func__, __LINE__, outlet);
190 result = -ENOMEM;
191 goto fail_create;
192 }
193
194 pr_debug("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__,
195 outlet, cpu, *virq);
196
197 result = irq_set_chip_data(*virq, pd);
198
199 if (result) {
200 pr_debug("%s:%d: irq_set_chip_data failed\n",
201 __func__, __LINE__);
202 goto fail_set;
203 }
204
205 ps3_chip_mask(irq_get_irq_data(*virq));
206
207 return result;
208
209fail_set:
210 irq_dispose_mapping(*virq);
211fail_create:
212 return result;
213}
214
215
216
217
218
219
220
221
222static int ps3_virq_destroy(unsigned int virq)
223{
224 const struct ps3_private *pd = irq_get_chip_data(virq);
225
226 pr_debug("%s:%d: ppe_id %llu, thread_id %llu, virq %u\n", __func__,
227 __LINE__, pd->ppe_id, pd->thread_id, virq);
228
229 irq_set_chip_data(virq, NULL);
230 irq_dispose_mapping(virq);
231
232 pr_debug("%s:%d <-\n", __func__, __LINE__);
233 return 0;
234}
235
236
237
238
239
240
241
242
243
244
245
246int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
247 unsigned int *virq)
248{
249 int result;
250 struct ps3_private *pd;
251
252 result = ps3_virq_setup(cpu, outlet, virq);
253
254 if (result) {
255 pr_debug("%s:%d: ps3_virq_setup failed\n", __func__, __LINE__);
256 goto fail_setup;
257 }
258
259 pd = irq_get_chip_data(*virq);
260
261
262
263 result = lv1_connect_irq_plug_ext(pd->ppe_id, pd->thread_id, *virq,
264 outlet, 0);
265
266 if (result) {
267 pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n",
268 __func__, __LINE__, ps3_result(result));
269 result = -EPERM;
270 goto fail_connect;
271 }
272
273 return result;
274
275fail_connect:
276 ps3_virq_destroy(*virq);
277fail_setup:
278 return result;
279}
280EXPORT_SYMBOL_GPL(ps3_irq_plug_setup);
281
282
283
284
285
286
287
288
289
290
291int ps3_irq_plug_destroy(unsigned int virq)
292{
293 int result;
294 const struct ps3_private *pd = irq_get_chip_data(virq);
295
296 pr_debug("%s:%d: ppe_id %llu, thread_id %llu, virq %u\n", __func__,
297 __LINE__, pd->ppe_id, pd->thread_id, virq);
298
299 ps3_chip_mask(irq_get_irq_data(virq));
300
301 result = lv1_disconnect_irq_plug_ext(pd->ppe_id, pd->thread_id, virq);
302
303 if (result)
304 pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n",
305 __func__, __LINE__, ps3_result(result));
306
307 ps3_virq_destroy(virq);
308
309 return result;
310}
311EXPORT_SYMBOL_GPL(ps3_irq_plug_destroy);
312
313
314
315
316
317
318
319
320
321
322
323
324int ps3_event_receive_port_setup(enum ps3_cpu_binding cpu, unsigned int *virq)
325{
326 int result;
327 u64 outlet;
328
329 result = lv1_construct_event_receive_port(&outlet);
330
331 if (result) {
332 pr_debug("%s:%d: lv1_construct_event_receive_port failed: %s\n",
333 __func__, __LINE__, ps3_result(result));
334 *virq = NO_IRQ;
335 return result;
336 }
337
338 result = ps3_irq_plug_setup(cpu, outlet, virq);
339 BUG_ON(result);
340
341 return result;
342}
343EXPORT_SYMBOL_GPL(ps3_event_receive_port_setup);
344
345
346
347
348
349
350
351
352
353
354int ps3_event_receive_port_destroy(unsigned int virq)
355{
356 int result;
357
358 pr_debug(" -> %s:%d virq %u\n", __func__, __LINE__, virq);
359
360 ps3_chip_mask(irq_get_irq_data(virq));
361
362 result = lv1_destruct_event_receive_port(virq_to_hw(virq));
363
364 if (result)
365 pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n",
366 __func__, __LINE__, ps3_result(result));
367
368
369
370
371
372
373 pr_debug(" <- %s:%d\n", __func__, __LINE__);
374 return result;
375}
376
377int ps3_send_event_locally(unsigned int virq)
378{
379 return lv1_send_event_locally(virq_to_hw(virq));
380}
381
382
383
384
385
386
387
388
389
390
391
392
393int ps3_sb_event_receive_port_setup(struct ps3_system_bus_device *dev,
394 enum ps3_cpu_binding cpu, unsigned int *virq)
395{
396
397
398 int result;
399
400 result = ps3_event_receive_port_setup(cpu, virq);
401
402 if (result)
403 return result;
404
405 result = lv1_connect_interrupt_event_receive_port(dev->bus_id,
406 dev->dev_id, virq_to_hw(*virq), dev->interrupt_id);
407
408 if (result) {
409 pr_debug("%s:%d: lv1_connect_interrupt_event_receive_port"
410 " failed: %s\n", __func__, __LINE__,
411 ps3_result(result));
412 ps3_event_receive_port_destroy(*virq);
413 *virq = NO_IRQ;
414 return result;
415 }
416
417 pr_debug("%s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__,
418 dev->interrupt_id, *virq);
419
420 return 0;
421}
422EXPORT_SYMBOL(ps3_sb_event_receive_port_setup);
423
424int ps3_sb_event_receive_port_destroy(struct ps3_system_bus_device *dev,
425 unsigned int virq)
426{
427
428
429 int result;
430
431 pr_debug(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__,
432 dev->interrupt_id, virq);
433
434 result = lv1_disconnect_interrupt_event_receive_port(dev->bus_id,
435 dev->dev_id, virq_to_hw(virq), dev->interrupt_id);
436
437 if (result)
438 pr_debug("%s:%d: lv1_disconnect_interrupt_event_receive_port"
439 " failed: %s\n", __func__, __LINE__,
440 ps3_result(result));
441
442 result = ps3_event_receive_port_destroy(virq);
443 BUG_ON(result);
444
445
446
447
448
449
450 result = ps3_virq_destroy(virq);
451 BUG_ON(result);
452
453 pr_debug(" <- %s:%d\n", __func__, __LINE__);
454 return result;
455}
456EXPORT_SYMBOL(ps3_sb_event_receive_port_destroy);
457
458
459
460
461
462
463
464
465
466
467
468
469int ps3_io_irq_setup(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
470 unsigned int *virq)
471{
472 int result;
473 u64 outlet;
474
475 result = lv1_construct_io_irq_outlet(interrupt_id, &outlet);
476
477 if (result) {
478 pr_debug("%s:%d: lv1_construct_io_irq_outlet failed: %s\n",
479 __func__, __LINE__, ps3_result(result));
480 return result;
481 }
482
483 result = ps3_irq_plug_setup(cpu, outlet, virq);
484 BUG_ON(result);
485
486 return result;
487}
488EXPORT_SYMBOL_GPL(ps3_io_irq_setup);
489
490int ps3_io_irq_destroy(unsigned int virq)
491{
492 int result;
493 unsigned long outlet = virq_to_hw(virq);
494
495 ps3_chip_mask(irq_get_irq_data(virq));
496
497
498
499
500
501
502 result = ps3_irq_plug_destroy(virq);
503 BUG_ON(result);
504
505 result = lv1_destruct_io_irq_outlet(outlet);
506
507 if (result)
508 pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n",
509 __func__, __LINE__, ps3_result(result));
510
511 return result;
512}
513EXPORT_SYMBOL_GPL(ps3_io_irq_destroy);
514
515
516
517
518
519
520
521
522
523
524
525
526int ps3_vuart_irq_setup(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
527 unsigned int *virq)
528{
529 int result;
530 u64 outlet;
531 u64 lpar_addr;
532
533 BUG_ON(!is_kernel_addr((u64)virt_addr_bmp));
534
535 lpar_addr = ps3_mm_phys_to_lpar(__pa(virt_addr_bmp));
536
537 result = lv1_configure_virtual_uart_irq(lpar_addr, &outlet);
538
539 if (result) {
540 pr_debug("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n",
541 __func__, __LINE__, ps3_result(result));
542 return result;
543 }
544
545 result = ps3_irq_plug_setup(cpu, outlet, virq);
546 BUG_ON(result);
547
548 return result;
549}
550EXPORT_SYMBOL_GPL(ps3_vuart_irq_setup);
551
552int ps3_vuart_irq_destroy(unsigned int virq)
553{
554 int result;
555
556 ps3_chip_mask(irq_get_irq_data(virq));
557 result = lv1_deconfigure_virtual_uart_irq();
558
559 if (result) {
560 pr_debug("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n",
561 __func__, __LINE__, ps3_result(result));
562 return result;
563 }
564
565 result = ps3_irq_plug_destroy(virq);
566 BUG_ON(result);
567
568 return result;
569}
570EXPORT_SYMBOL_GPL(ps3_vuart_irq_destroy);
571
572
573
574
575
576
577
578
579
580
581
582int ps3_spe_irq_setup(enum ps3_cpu_binding cpu, unsigned long spe_id,
583 unsigned int class, unsigned int *virq)
584{
585 int result;
586 u64 outlet;
587
588 BUG_ON(class > 2);
589
590 result = lv1_get_spe_irq_outlet(spe_id, class, &outlet);
591
592 if (result) {
593 pr_debug("%s:%d: lv1_get_spe_irq_outlet failed: %s\n",
594 __func__, __LINE__, ps3_result(result));
595 return result;
596 }
597
598 result = ps3_irq_plug_setup(cpu, outlet, virq);
599 BUG_ON(result);
600
601 return result;
602}
603
604int ps3_spe_irq_destroy(unsigned int virq)
605{
606 int result;
607
608 ps3_chip_mask(irq_get_irq_data(virq));
609
610 result = ps3_irq_plug_destroy(virq);
611 BUG_ON(result);
612
613 return result;
614}
615
616
617#define PS3_INVALID_OUTLET ((irq_hw_number_t)-1)
618#define PS3_PLUG_MAX 63
619
620#if defined(DEBUG)
621static void _dump_64_bmp(const char *header, const u64 *p, unsigned cpu,
622 const char* func, int line)
623{
624 pr_debug("%s:%d: %s %u {%04lx_%04lx_%04lx_%04lx}\n",
625 func, line, header, cpu,
626 *p >> 48, (*p >> 32) & 0xffff, (*p >> 16) & 0xffff,
627 *p & 0xffff);
628}
629
630static void __maybe_unused _dump_256_bmp(const char *header,
631 const u64 *p, unsigned cpu, const char* func, int line)
632{
633 pr_debug("%s:%d: %s %u {%016lx:%016lx:%016lx:%016lx}\n",
634 func, line, header, cpu, p[0], p[1], p[2], p[3]);
635}
636
637#define dump_bmp(_x) _dump_bmp(_x, __func__, __LINE__)
638static void _dump_bmp(struct ps3_private* pd, const char* func, int line)
639{
640 unsigned long flags;
641
642 spin_lock_irqsave(&pd->bmp.lock, flags);
643 _dump_64_bmp("stat", &pd->bmp.status, pd->thread_id, func, line);
644 _dump_64_bmp("mask", &pd->bmp.mask, pd->thread_id, func, line);
645 spin_unlock_irqrestore(&pd->bmp.lock, flags);
646}
647
648#define dump_mask(_x) _dump_mask(_x, __func__, __LINE__)
649static void __maybe_unused _dump_mask(struct ps3_private *pd,
650 const char* func, int line)
651{
652 unsigned long flags;
653
654 spin_lock_irqsave(&pd->bmp.lock, flags);
655 _dump_64_bmp("mask", &pd->bmp.mask, pd->thread_id, func, line);
656 spin_unlock_irqrestore(&pd->bmp.lock, flags);
657}
658#else
659static void dump_bmp(struct ps3_private* pd) {};
660#endif
661
662static int ps3_host_map(struct irq_host *h, unsigned int virq,
663 irq_hw_number_t hwirq)
664{
665 pr_debug("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq,
666 virq);
667
668 irq_set_chip_and_handler(virq, &ps3_irq_chip, handle_fasteoi_irq);
669
670 return 0;
671}
672
673static int ps3_host_match(struct irq_host *h, struct device_node *np)
674{
675
676 return 1;
677}
678
679static struct irq_host_ops ps3_host_ops = {
680 .map = ps3_host_map,
681 .match = ps3_host_match,
682};
683
684void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq)
685{
686 struct ps3_private *pd = &per_cpu(ps3_private, cpu);
687
688 pd->bmp.ipi_debug_brk_mask = 0x8000000000000000UL >> virq;
689
690 pr_debug("%s:%d: cpu %u, virq %u, mask %llxh\n", __func__, __LINE__,
691 cpu, virq, pd->bmp.ipi_debug_brk_mask);
692}
693
694static unsigned int ps3_get_irq(void)
695{
696 struct ps3_private *pd = &__get_cpu_var(ps3_private);
697 u64 x = (pd->bmp.status & pd->bmp.mask);
698 unsigned int plug;
699
700
701
702 if (x & pd->bmp.ipi_debug_brk_mask)
703 x &= pd->bmp.ipi_debug_brk_mask;
704
705 asm volatile("cntlzd %0,%1" : "=r" (plug) : "r" (x));
706 plug &= 0x3f;
707
708 if (unlikely(plug == NO_IRQ)) {
709 pr_debug("%s:%d: no plug found: thread_id %llu\n", __func__,
710 __LINE__, pd->thread_id);
711 dump_bmp(&per_cpu(ps3_private, 0));
712 dump_bmp(&per_cpu(ps3_private, 1));
713 return NO_IRQ;
714 }
715
716#if defined(DEBUG)
717 if (unlikely(plug < NUM_ISA_INTERRUPTS || plug > PS3_PLUG_MAX)) {
718 dump_bmp(&per_cpu(ps3_private, 0));
719 dump_bmp(&per_cpu(ps3_private, 1));
720 BUG();
721 }
722#endif
723 return plug;
724}
725
726void __init ps3_init_IRQ(void)
727{
728 int result;
729 unsigned cpu;
730 struct irq_host *host;
731
732 host = irq_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0, &ps3_host_ops,
733 PS3_INVALID_OUTLET);
734 irq_set_default_host(host);
735 irq_set_virq_count(PS3_PLUG_MAX + 1);
736
737 for_each_possible_cpu(cpu) {
738 struct ps3_private *pd = &per_cpu(ps3_private, cpu);
739
740 lv1_get_logical_ppe_id(&pd->ppe_id);
741 pd->thread_id = get_hard_smp_processor_id(cpu);
742 spin_lock_init(&pd->bmp.lock);
743
744 pr_debug("%s:%d: ppe_id %llu, thread_id %llu, bmp %lxh\n",
745 __func__, __LINE__, pd->ppe_id, pd->thread_id,
746 ps3_mm_phys_to_lpar(__pa(&pd->bmp)));
747
748 result = lv1_configure_irq_state_bitmap(pd->ppe_id,
749 pd->thread_id, ps3_mm_phys_to_lpar(__pa(&pd->bmp)));
750
751 if (result)
752 pr_debug("%s:%d: lv1_configure_irq_state_bitmap failed:"
753 " %s\n", __func__, __LINE__,
754 ps3_result(result));
755 }
756
757 ppc_md.get_irq = ps3_get_irq;
758}
759
760void ps3_shutdown_IRQ(int cpu)
761{
762 int result;
763 u64 ppe_id;
764 u64 thread_id = get_hard_smp_processor_id(cpu);
765
766 lv1_get_logical_ppe_id(&ppe_id);
767 result = lv1_configure_irq_state_bitmap(ppe_id, thread_id, 0);
768
769 DBG("%s:%d: lv1_configure_irq_state_bitmap (%llu:%llu/%d) %s\n", __func__,
770 __LINE__, ppe_id, thread_id, cpu, ps3_result(result));
771}
772