0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/kernel.h>
0010 #include <linux/export.h>
0011 #include <linux/irq.h>
0012 #include <linux/irqdomain.h>
0013
0014 #include <asm/machdep.h>
0015 #include <asm/udbg.h>
0016 #include <asm/lv1call.h>
0017 #include <asm/smp.h>
0018
0019 #include "platform.h"
0020
0021 #if defined(DEBUG)
0022 #define DBG udbg_printf
0023 #define FAIL udbg_printf
0024 #else
0025 #define DBG pr_devel
0026 #define FAIL pr_debug
0027 #endif
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056 #define PS3_BMP_MINALIGN 64
0057
0058 struct ps3_bmp {
0059 struct {
0060 u64 status;
0061 u64 unused_1[3];
0062 unsigned long mask;
0063 u64 unused_2[3];
0064 };
0065 };
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077 struct ps3_private {
0078 struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN)));
0079 spinlock_t bmp_lock;
0080 u64 ppe_id;
0081 u64 thread_id;
0082 unsigned long ipi_debug_brk_mask;
0083 unsigned long ipi_mask;
0084 };
0085
0086 static DEFINE_PER_CPU(struct ps3_private, ps3_private);
0087
0088
0089
0090
0091
0092
0093
0094
0095 static void ps3_chip_mask(struct irq_data *d)
0096 {
0097 struct ps3_private *pd = irq_data_get_irq_chip_data(d);
0098 unsigned long flags;
0099
0100 DBG("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__,
0101 pd->thread_id, d->irq);
0102
0103 local_irq_save(flags);
0104 clear_bit(63 - d->irq, &pd->bmp.mask);
0105 lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id);
0106 local_irq_restore(flags);
0107 }
0108
0109
0110
0111
0112
0113
0114
0115
0116 static void ps3_chip_unmask(struct irq_data *d)
0117 {
0118 struct ps3_private *pd = irq_data_get_irq_chip_data(d);
0119 unsigned long flags;
0120
0121 DBG("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__,
0122 pd->thread_id, d->irq);
0123
0124 local_irq_save(flags);
0125 set_bit(63 - d->irq, &pd->bmp.mask);
0126 lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id);
0127 local_irq_restore(flags);
0128 }
0129
0130
0131
0132
0133
0134
0135
0136
0137 static void ps3_chip_eoi(struct irq_data *d)
0138 {
0139 const struct ps3_private *pd = irq_data_get_irq_chip_data(d);
0140
0141
0142
0143 if (!test_bit(63 - d->irq, &pd->ipi_mask))
0144 lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, d->irq);
0145 }
0146
0147
0148
0149
0150
0151 static struct irq_chip ps3_irq_chip = {
0152 .name = "ps3",
0153 .irq_mask = ps3_chip_mask,
0154 .irq_unmask = ps3_chip_unmask,
0155 .irq_eoi = ps3_chip_eoi,
0156 };
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169 static int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
0170 unsigned int *virq)
0171 {
0172 int result;
0173 struct ps3_private *pd;
0174
0175
0176
0177 if (cpu == PS3_BINDING_CPU_ANY)
0178 cpu = 0;
0179
0180 pd = &per_cpu(ps3_private, cpu);
0181
0182 *virq = irq_create_mapping(NULL, outlet);
0183
0184 if (!*virq) {
0185 FAIL("%s:%d: irq_create_mapping failed: outlet %lu\n",
0186 __func__, __LINE__, outlet);
0187 result = -ENOMEM;
0188 goto fail_create;
0189 }
0190
0191 DBG("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__,
0192 outlet, cpu, *virq);
0193
0194 result = irq_set_chip_data(*virq, pd);
0195
0196 if (result) {
0197 FAIL("%s:%d: irq_set_chip_data failed\n",
0198 __func__, __LINE__);
0199 goto fail_set;
0200 }
0201
0202 ps3_chip_mask(irq_get_irq_data(*virq));
0203
0204 return result;
0205
0206 fail_set:
0207 irq_dispose_mapping(*virq);
0208 fail_create:
0209 return result;
0210 }
0211
0212
0213
0214
0215
0216
0217
0218
0219 static int ps3_virq_destroy(unsigned int virq)
0220 {
0221 const struct ps3_private *pd = irq_get_chip_data(virq);
0222
0223 DBG("%s:%d: ppe_id %llu, thread_id %llu, virq %u\n", __func__,
0224 __LINE__, pd->ppe_id, pd->thread_id, virq);
0225
0226 irq_set_chip_data(virq, NULL);
0227 irq_dispose_mapping(virq);
0228
0229 DBG("%s:%d <-\n", __func__, __LINE__);
0230 return 0;
0231 }
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243 int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet,
0244 unsigned int *virq)
0245 {
0246 int result;
0247 struct ps3_private *pd;
0248
0249 result = ps3_virq_setup(cpu, outlet, virq);
0250
0251 if (result) {
0252 FAIL("%s:%d: ps3_virq_setup failed\n", __func__, __LINE__);
0253 goto fail_setup;
0254 }
0255
0256 pd = irq_get_chip_data(*virq);
0257
0258
0259
0260 result = lv1_connect_irq_plug_ext(pd->ppe_id, pd->thread_id, *virq,
0261 outlet, 0);
0262
0263 if (result) {
0264 FAIL("%s:%d: lv1_connect_irq_plug_ext failed: %s\n",
0265 __func__, __LINE__, ps3_result(result));
0266 result = -EPERM;
0267 goto fail_connect;
0268 }
0269
0270 return result;
0271
0272 fail_connect:
0273 ps3_virq_destroy(*virq);
0274 fail_setup:
0275 return result;
0276 }
0277 EXPORT_SYMBOL_GPL(ps3_irq_plug_setup);
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288 int ps3_irq_plug_destroy(unsigned int virq)
0289 {
0290 int result;
0291 const struct ps3_private *pd = irq_get_chip_data(virq);
0292
0293 DBG("%s:%d: ppe_id %llu, thread_id %llu, virq %u\n", __func__,
0294 __LINE__, pd->ppe_id, pd->thread_id, virq);
0295
0296 ps3_chip_mask(irq_get_irq_data(virq));
0297
0298 result = lv1_disconnect_irq_plug_ext(pd->ppe_id, pd->thread_id, virq);
0299
0300 if (result)
0301 FAIL("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n",
0302 __func__, __LINE__, ps3_result(result));
0303
0304 ps3_virq_destroy(virq);
0305
0306 return result;
0307 }
0308 EXPORT_SYMBOL_GPL(ps3_irq_plug_destroy);
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321 int ps3_event_receive_port_setup(enum ps3_cpu_binding cpu, unsigned int *virq)
0322 {
0323 int result;
0324 u64 outlet;
0325
0326 result = lv1_construct_event_receive_port(&outlet);
0327
0328 if (result) {
0329 FAIL("%s:%d: lv1_construct_event_receive_port failed: %s\n",
0330 __func__, __LINE__, ps3_result(result));
0331 *virq = 0;
0332 return result;
0333 }
0334
0335 result = ps3_irq_plug_setup(cpu, outlet, virq);
0336 BUG_ON(result);
0337
0338 return result;
0339 }
0340 EXPORT_SYMBOL_GPL(ps3_event_receive_port_setup);
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351 int ps3_event_receive_port_destroy(unsigned int virq)
0352 {
0353 int result;
0354
0355 DBG(" -> %s:%d virq %u\n", __func__, __LINE__, virq);
0356
0357 ps3_chip_mask(irq_get_irq_data(virq));
0358
0359 result = lv1_destruct_event_receive_port(virq_to_hw(virq));
0360
0361 if (result)
0362 FAIL("%s:%d: lv1_destruct_event_receive_port failed: %s\n",
0363 __func__, __LINE__, ps3_result(result));
0364
0365
0366
0367
0368
0369
0370 DBG(" <- %s:%d\n", __func__, __LINE__);
0371 return result;
0372 }
0373
0374 int ps3_send_event_locally(unsigned int virq)
0375 {
0376 return lv1_send_event_locally(virq_to_hw(virq));
0377 }
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387
0388
0389
0390 int ps3_sb_event_receive_port_setup(struct ps3_system_bus_device *dev,
0391 enum ps3_cpu_binding cpu, unsigned int *virq)
0392 {
0393
0394
0395 int result;
0396
0397 result = ps3_event_receive_port_setup(cpu, virq);
0398
0399 if (result)
0400 return result;
0401
0402 result = lv1_connect_interrupt_event_receive_port(dev->bus_id,
0403 dev->dev_id, virq_to_hw(*virq), dev->interrupt_id);
0404
0405 if (result) {
0406 FAIL("%s:%d: lv1_connect_interrupt_event_receive_port"
0407 " failed: %s\n", __func__, __LINE__,
0408 ps3_result(result));
0409 ps3_event_receive_port_destroy(*virq);
0410 *virq = 0;
0411 return result;
0412 }
0413
0414 DBG("%s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__,
0415 dev->interrupt_id, *virq);
0416
0417 return 0;
0418 }
0419 EXPORT_SYMBOL(ps3_sb_event_receive_port_setup);
0420
0421 int ps3_sb_event_receive_port_destroy(struct ps3_system_bus_device *dev,
0422 unsigned int virq)
0423 {
0424
0425
0426 int result;
0427
0428 DBG(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__,
0429 dev->interrupt_id, virq);
0430
0431 result = lv1_disconnect_interrupt_event_receive_port(dev->bus_id,
0432 dev->dev_id, virq_to_hw(virq), dev->interrupt_id);
0433
0434 if (result)
0435 FAIL("%s:%d: lv1_disconnect_interrupt_event_receive_port"
0436 " failed: %s\n", __func__, __LINE__,
0437 ps3_result(result));
0438
0439 result = ps3_event_receive_port_destroy(virq);
0440 BUG_ON(result);
0441
0442
0443
0444
0445
0446
0447 result = ps3_virq_destroy(virq);
0448 BUG_ON(result);
0449
0450 DBG(" <- %s:%d\n", __func__, __LINE__);
0451 return result;
0452 }
0453 EXPORT_SYMBOL(ps3_sb_event_receive_port_destroy);
0454
0455
0456
0457
0458
0459
0460
0461
0462
0463
0464
0465
0466 int ps3_io_irq_setup(enum ps3_cpu_binding cpu, unsigned int interrupt_id,
0467 unsigned int *virq)
0468 {
0469 int result;
0470 u64 outlet;
0471
0472 result = lv1_construct_io_irq_outlet(interrupt_id, &outlet);
0473
0474 if (result) {
0475 FAIL("%s:%d: lv1_construct_io_irq_outlet failed: %s\n",
0476 __func__, __LINE__, ps3_result(result));
0477 return result;
0478 }
0479
0480 result = ps3_irq_plug_setup(cpu, outlet, virq);
0481 BUG_ON(result);
0482
0483 return result;
0484 }
0485 EXPORT_SYMBOL_GPL(ps3_io_irq_setup);
0486
0487 int ps3_io_irq_destroy(unsigned int virq)
0488 {
0489 int result;
0490 unsigned long outlet = virq_to_hw(virq);
0491
0492 ps3_chip_mask(irq_get_irq_data(virq));
0493
0494
0495
0496
0497
0498
0499 result = ps3_irq_plug_destroy(virq);
0500 BUG_ON(result);
0501
0502 result = lv1_destruct_io_irq_outlet(outlet);
0503
0504 if (result)
0505 FAIL("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n",
0506 __func__, __LINE__, ps3_result(result));
0507
0508 return result;
0509 }
0510 EXPORT_SYMBOL_GPL(ps3_io_irq_destroy);
0511
0512
0513
0514
0515
0516
0517
0518
0519
0520
0521
0522
0523 int ps3_vuart_irq_setup(enum ps3_cpu_binding cpu, void* virt_addr_bmp,
0524 unsigned int *virq)
0525 {
0526 int result;
0527 u64 outlet;
0528 u64 lpar_addr;
0529
0530 BUG_ON(!is_kernel_addr((u64)virt_addr_bmp));
0531
0532 lpar_addr = ps3_mm_phys_to_lpar(__pa(virt_addr_bmp));
0533
0534 result = lv1_configure_virtual_uart_irq(lpar_addr, &outlet);
0535
0536 if (result) {
0537 FAIL("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n",
0538 __func__, __LINE__, ps3_result(result));
0539 return result;
0540 }
0541
0542 result = ps3_irq_plug_setup(cpu, outlet, virq);
0543 BUG_ON(result);
0544
0545 return result;
0546 }
0547 EXPORT_SYMBOL_GPL(ps3_vuart_irq_setup);
0548
0549 int ps3_vuart_irq_destroy(unsigned int virq)
0550 {
0551 int result;
0552
0553 ps3_chip_mask(irq_get_irq_data(virq));
0554 result = lv1_deconfigure_virtual_uart_irq();
0555
0556 if (result) {
0557 FAIL("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n",
0558 __func__, __LINE__, ps3_result(result));
0559 return result;
0560 }
0561
0562 result = ps3_irq_plug_destroy(virq);
0563 BUG_ON(result);
0564
0565 return result;
0566 }
0567 EXPORT_SYMBOL_GPL(ps3_vuart_irq_destroy);
0568
0569
0570
0571
0572
0573
0574
0575
0576
0577
0578
0579 int ps3_spe_irq_setup(enum ps3_cpu_binding cpu, unsigned long spe_id,
0580 unsigned int class, unsigned int *virq)
0581 {
0582 int result;
0583 u64 outlet;
0584
0585 BUG_ON(class > 2);
0586
0587 result = lv1_get_spe_irq_outlet(spe_id, class, &outlet);
0588
0589 if (result) {
0590 FAIL("%s:%d: lv1_get_spe_irq_outlet failed: %s\n",
0591 __func__, __LINE__, ps3_result(result));
0592 return result;
0593 }
0594
0595 result = ps3_irq_plug_setup(cpu, outlet, virq);
0596 BUG_ON(result);
0597
0598 return result;
0599 }
0600
0601 int ps3_spe_irq_destroy(unsigned int virq)
0602 {
0603 int result;
0604
0605 ps3_chip_mask(irq_get_irq_data(virq));
0606
0607 result = ps3_irq_plug_destroy(virq);
0608 BUG_ON(result);
0609
0610 return result;
0611 }
0612
0613
0614 #define PS3_INVALID_OUTLET ((irq_hw_number_t)-1)
0615 #define PS3_PLUG_MAX 63
0616
0617 #if defined(DEBUG)
0618 static void _dump_64_bmp(const char *header, const u64 *p, unsigned cpu,
0619 const char* func, int line)
0620 {
0621 pr_debug("%s:%d: %s %u {%04llx_%04llx_%04llx_%04llx}\n",
0622 func, line, header, cpu,
0623 *p >> 48, (*p >> 32) & 0xffff, (*p >> 16) & 0xffff,
0624 *p & 0xffff);
0625 }
0626
0627 static void __maybe_unused _dump_256_bmp(const char *header,
0628 const u64 *p, unsigned cpu, const char* func, int line)
0629 {
0630 pr_debug("%s:%d: %s %u {%016llx:%016llx:%016llx:%016llx}\n",
0631 func, line, header, cpu, p[0], p[1], p[2], p[3]);
0632 }
0633
0634 #define dump_bmp(_x) _dump_bmp(_x, __func__, __LINE__)
0635 static void _dump_bmp(struct ps3_private* pd, const char* func, int line)
0636 {
0637 unsigned long flags;
0638
0639 spin_lock_irqsave(&pd->bmp_lock, flags);
0640 _dump_64_bmp("stat", &pd->bmp.status, pd->thread_id, func, line);
0641 _dump_64_bmp("mask", (u64*)&pd->bmp.mask, pd->thread_id, func, line);
0642 spin_unlock_irqrestore(&pd->bmp_lock, flags);
0643 }
0644
0645 #define dump_mask(_x) _dump_mask(_x, __func__, __LINE__)
0646 static void __maybe_unused _dump_mask(struct ps3_private *pd,
0647 const char* func, int line)
0648 {
0649 unsigned long flags;
0650
0651 spin_lock_irqsave(&pd->bmp_lock, flags);
0652 _dump_64_bmp("mask", (u64*)&pd->bmp.mask, pd->thread_id, func, line);
0653 spin_unlock_irqrestore(&pd->bmp_lock, flags);
0654 }
0655 #else
0656 static void dump_bmp(struct ps3_private* pd) {};
0657 #endif
0658
0659 static int ps3_host_map(struct irq_domain *h, unsigned int virq,
0660 irq_hw_number_t hwirq)
0661 {
0662 DBG("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq,
0663 virq);
0664
0665 irq_set_chip_and_handler(virq, &ps3_irq_chip, handle_fasteoi_irq);
0666
0667 return 0;
0668 }
0669
0670 static int ps3_host_match(struct irq_domain *h, struct device_node *np,
0671 enum irq_domain_bus_token bus_token)
0672 {
0673
0674 return 1;
0675 }
0676
0677 static const struct irq_domain_ops ps3_host_ops = {
0678 .map = ps3_host_map,
0679 .match = ps3_host_match,
0680 };
0681
0682 void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq)
0683 {
0684 struct ps3_private *pd = &per_cpu(ps3_private, cpu);
0685
0686 set_bit(63 - virq, &pd->ipi_debug_brk_mask);
0687
0688 DBG("%s:%d: cpu %u, virq %u, mask %lxh\n", __func__, __LINE__,
0689 cpu, virq, pd->ipi_debug_brk_mask);
0690 }
0691
0692 void __init ps3_register_ipi_irq(unsigned int cpu, unsigned int virq)
0693 {
0694 struct ps3_private *pd = &per_cpu(ps3_private, cpu);
0695
0696 set_bit(63 - virq, &pd->ipi_mask);
0697
0698 DBG("%s:%d: cpu %u, virq %u, ipi_mask %lxh\n", __func__, __LINE__,
0699 cpu, virq, pd->ipi_mask);
0700 }
0701
0702 static unsigned int ps3_get_irq(void)
0703 {
0704 struct ps3_private *pd = this_cpu_ptr(&ps3_private);
0705 u64 x = (pd->bmp.status & pd->bmp.mask);
0706 unsigned int plug;
0707
0708
0709
0710 if (x & pd->ipi_debug_brk_mask)
0711 x &= pd->ipi_debug_brk_mask;
0712
0713 asm volatile("cntlzd %0,%1" : "=r" (plug) : "r" (x));
0714 plug &= 0x3f;
0715
0716 if (unlikely(!plug)) {
0717 DBG("%s:%d: no plug found: thread_id %llu\n", __func__,
0718 __LINE__, pd->thread_id);
0719 dump_bmp(&per_cpu(ps3_private, 0));
0720 dump_bmp(&per_cpu(ps3_private, 1));
0721 return 0;
0722 }
0723
0724 #if defined(DEBUG)
0725 if (unlikely(plug < NR_IRQS_LEGACY || plug > PS3_PLUG_MAX)) {
0726 dump_bmp(&per_cpu(ps3_private, 0));
0727 dump_bmp(&per_cpu(ps3_private, 1));
0728 BUG();
0729 }
0730 #endif
0731
0732
0733
0734 if (test_bit(63 - plug, &pd->ipi_mask))
0735 lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, plug);
0736
0737 return plug;
0738 }
0739
0740 void __init ps3_init_IRQ(void)
0741 {
0742 int result;
0743 unsigned cpu;
0744 struct irq_domain *host;
0745
0746 host = irq_domain_add_nomap(NULL, PS3_PLUG_MAX + 1, &ps3_host_ops, NULL);
0747 irq_set_default_host(host);
0748
0749 for_each_possible_cpu(cpu) {
0750 struct ps3_private *pd = &per_cpu(ps3_private, cpu);
0751
0752 lv1_get_logical_ppe_id(&pd->ppe_id);
0753 pd->thread_id = get_hard_smp_processor_id(cpu);
0754 spin_lock_init(&pd->bmp_lock);
0755
0756 DBG("%s:%d: ppe_id %llu, thread_id %llu, bmp %lxh\n",
0757 __func__, __LINE__, pd->ppe_id, pd->thread_id,
0758 ps3_mm_phys_to_lpar(__pa(&pd->bmp)));
0759
0760 result = lv1_configure_irq_state_bitmap(pd->ppe_id,
0761 pd->thread_id, ps3_mm_phys_to_lpar(__pa(&pd->bmp)));
0762
0763 if (result)
0764 FAIL("%s:%d: lv1_configure_irq_state_bitmap failed:"
0765 " %s\n", __func__, __LINE__,
0766 ps3_result(result));
0767 }
0768
0769 ppc_md.get_irq = ps3_get_irq;
0770 }
0771
0772 void ps3_shutdown_IRQ(int cpu)
0773 {
0774 int result;
0775 u64 ppe_id;
0776 u64 thread_id = get_hard_smp_processor_id(cpu);
0777
0778 lv1_get_logical_ppe_id(&ppe_id);
0779 result = lv1_configure_irq_state_bitmap(ppe_id, thread_id, 0);
0780
0781 DBG("%s:%d: lv1_configure_irq_state_bitmap (%llu:%llu/%d) %s\n", __func__,
0782 __LINE__, ppe_id, thread_id, cpu, ps3_result(result));
0783 }