interrupt.c (19512B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * PS3 interrupt routines. 4 * 5 * Copyright (C) 2006 Sony Computer Entertainment Inc. 6 * Copyright 2006 Sony Corp. 7 */ 8 9#include <linux/kernel.h> 10#include <linux/export.h> 11#include <linux/irq.h> 12#include <linux/irqdomain.h> 13 14#include <asm/machdep.h> 15#include <asm/udbg.h> 16#include <asm/lv1call.h> 17#include <asm/smp.h> 18 19#include "platform.h" 20 21#if defined(DEBUG) 22#define DBG udbg_printf 23#define FAIL udbg_printf 24#else 25#define DBG pr_devel 26#define FAIL pr_debug 27#endif 28 29/** 30 * struct ps3_bmp - a per cpu irq status and mask bitmap structure 31 * @status: 256 bit status bitmap indexed by plug 32 * @unused_1: Alignment 33 * @mask: 256 bit mask bitmap indexed by plug 34 * @unused_2: Alignment 35 * 36 * The HV maintains per SMT thread mappings of HV outlet to HV plug on 37 * behalf of the guest. These mappings are implemented as 256 bit guest 38 * supplied bitmaps indexed by plug number. The addresses of the bitmaps 39 * are registered with the HV through lv1_configure_irq_state_bitmap(). 40 * The HV requires that the 512 bits of status + mask not cross a page 41 * boundary. PS3_BMP_MINALIGN is used to define this minimal 64 byte 42 * alignment. 43 * 44 * The HV supports 256 plugs per thread, assigned as {0..255}, for a total 45 * of 512 plugs supported on a processor. To simplify the logic this 46 * implementation equates HV plug value to Linux virq value, constrains each 47 * interrupt to have a system wide unique plug number, and limits the range 48 * of the plug values to map into the first dword of the bitmaps. This 49 * gives a usable range of plug values of {NR_IRQS_LEGACY..63}. Note 50 * that there is no constraint on how many in this set an individual thread 51 * can acquire. 52 * 53 * The mask is declared as unsigned long so we can use set/clear_bit on it. 54 */ 55 56#define PS3_BMP_MINALIGN 64 57 58struct ps3_bmp { 59 struct { 60 u64 status; 61 u64 unused_1[3]; 62 unsigned long mask; 63 u64 unused_2[3]; 64 }; 65}; 66 67/** 68 * struct ps3_private - a per cpu data structure 69 * @bmp: ps3_bmp structure 70 * @bmp_lock: Synchronize access to bmp. 71 * @ipi_debug_brk_mask: Mask for debug break IPIs 72 * @ppe_id: HV logical_ppe_id 73 * @thread_id: HV thread_id 74 * @ipi_mask: Mask of IPI virqs 75 */ 76 77struct ps3_private { 78 struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN))); 79 spinlock_t bmp_lock; 80 u64 ppe_id; 81 u64 thread_id; 82 unsigned long ipi_debug_brk_mask; 83 unsigned long ipi_mask; 84}; 85 86static DEFINE_PER_CPU(struct ps3_private, ps3_private); 87 88/** 89 * ps3_chip_mask - Set an interrupt mask bit in ps3_bmp. 90 * @virq: The assigned Linux virq. 91 * 92 * Sets ps3_bmp.mask and calls lv1_did_update_interrupt_mask(). 93 */ 94 95static void ps3_chip_mask(struct irq_data *d) 96{ 97 struct ps3_private *pd = irq_data_get_irq_chip_data(d); 98 unsigned long flags; 99 100 DBG("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__, 101 pd->thread_id, d->irq); 102 103 local_irq_save(flags); 104 clear_bit(63 - d->irq, &pd->bmp.mask); 105 lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id); 106 local_irq_restore(flags); 107} 108 109/** 110 * ps3_chip_unmask - Clear an interrupt mask bit in ps3_bmp. 111 * @virq: The assigned Linux virq. 112 * 113 * Clears ps3_bmp.mask and calls lv1_did_update_interrupt_mask(). 114 */ 115 116static void ps3_chip_unmask(struct irq_data *d) 117{ 118 struct ps3_private *pd = irq_data_get_irq_chip_data(d); 119 unsigned long flags; 120 121 DBG("%s:%d: thread_id %llu, virq %d\n", __func__, __LINE__, 122 pd->thread_id, d->irq); 123 124 local_irq_save(flags); 125 set_bit(63 - d->irq, &pd->bmp.mask); 126 lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id); 127 local_irq_restore(flags); 128} 129 130/** 131 * ps3_chip_eoi - HV end-of-interrupt. 132 * @virq: The assigned Linux virq. 133 * 134 * Calls lv1_end_of_interrupt_ext(). 135 */ 136 137static void ps3_chip_eoi(struct irq_data *d) 138{ 139 const struct ps3_private *pd = irq_data_get_irq_chip_data(d); 140 141 /* non-IPIs are EOIed here. */ 142 143 if (!test_bit(63 - d->irq, &pd->ipi_mask)) 144 lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, d->irq); 145} 146 147/** 148 * ps3_irq_chip - Represents the ps3_bmp as a Linux struct irq_chip. 149 */ 150 151static struct irq_chip ps3_irq_chip = { 152 .name = "ps3", 153 .irq_mask = ps3_chip_mask, 154 .irq_unmask = ps3_chip_unmask, 155 .irq_eoi = ps3_chip_eoi, 156}; 157 158/** 159 * ps3_virq_setup - virq related setup. 160 * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be 161 * serviced on. 162 * @outlet: The HV outlet from the various create outlet routines. 163 * @virq: The assigned Linux virq. 164 * 165 * Calls irq_create_mapping() to get a virq and sets the chip data to 166 * ps3_private data. 167 */ 168 169static int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet, 170 unsigned int *virq) 171{ 172 int result; 173 struct ps3_private *pd; 174 175 /* This defines the default interrupt distribution policy. */ 176 177 if (cpu == PS3_BINDING_CPU_ANY) 178 cpu = 0; 179 180 pd = &per_cpu(ps3_private, cpu); 181 182 *virq = irq_create_mapping(NULL, outlet); 183 184 if (!*virq) { 185 FAIL("%s:%d: irq_create_mapping failed: outlet %lu\n", 186 __func__, __LINE__, outlet); 187 result = -ENOMEM; 188 goto fail_create; 189 } 190 191 DBG("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__, 192 outlet, cpu, *virq); 193 194 result = irq_set_chip_data(*virq, pd); 195 196 if (result) { 197 FAIL("%s:%d: irq_set_chip_data failed\n", 198 __func__, __LINE__); 199 goto fail_set; 200 } 201 202 ps3_chip_mask(irq_get_irq_data(*virq)); 203 204 return result; 205 206fail_set: 207 irq_dispose_mapping(*virq); 208fail_create: 209 return result; 210} 211 212/** 213 * ps3_virq_destroy - virq related teardown. 214 * @virq: The assigned Linux virq. 215 * 216 * Clears chip data and calls irq_dispose_mapping() for the virq. 217 */ 218 219static int ps3_virq_destroy(unsigned int virq) 220{ 221 const struct ps3_private *pd = irq_get_chip_data(virq); 222 223 DBG("%s:%d: ppe_id %llu, thread_id %llu, virq %u\n", __func__, 224 __LINE__, pd->ppe_id, pd->thread_id, virq); 225 226 irq_set_chip_data(virq, NULL); 227 irq_dispose_mapping(virq); 228 229 DBG("%s:%d <-\n", __func__, __LINE__); 230 return 0; 231} 232 233/** 234 * ps3_irq_plug_setup - Generic outlet and virq related setup. 235 * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be 236 * serviced on. 237 * @outlet: The HV outlet from the various create outlet routines. 238 * @virq: The assigned Linux virq. 239 * 240 * Sets up virq and connects the irq plug. 241 */ 242 243int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet, 244 unsigned int *virq) 245{ 246 int result; 247 struct ps3_private *pd; 248 249 result = ps3_virq_setup(cpu, outlet, virq); 250 251 if (result) { 252 FAIL("%s:%d: ps3_virq_setup failed\n", __func__, __LINE__); 253 goto fail_setup; 254 } 255 256 pd = irq_get_chip_data(*virq); 257 258 /* Binds outlet to cpu + virq. */ 259 260 result = lv1_connect_irq_plug_ext(pd->ppe_id, pd->thread_id, *virq, 261 outlet, 0); 262 263 if (result) { 264 FAIL("%s:%d: lv1_connect_irq_plug_ext failed: %s\n", 265 __func__, __LINE__, ps3_result(result)); 266 result = -EPERM; 267 goto fail_connect; 268 } 269 270 return result; 271 272fail_connect: 273 ps3_virq_destroy(*virq); 274fail_setup: 275 return result; 276} 277EXPORT_SYMBOL_GPL(ps3_irq_plug_setup); 278 279/** 280 * ps3_irq_plug_destroy - Generic outlet and virq related teardown. 281 * @virq: The assigned Linux virq. 282 * 283 * Disconnects the irq plug and tears down virq. 284 * Do not call for system bus event interrupts setup with 285 * ps3_sb_event_receive_port_setup(). 286 */ 287 288int ps3_irq_plug_destroy(unsigned int virq) 289{ 290 int result; 291 const struct ps3_private *pd = irq_get_chip_data(virq); 292 293 DBG("%s:%d: ppe_id %llu, thread_id %llu, virq %u\n", __func__, 294 __LINE__, pd->ppe_id, pd->thread_id, virq); 295 296 ps3_chip_mask(irq_get_irq_data(virq)); 297 298 result = lv1_disconnect_irq_plug_ext(pd->ppe_id, pd->thread_id, virq); 299 300 if (result) 301 FAIL("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n", 302 __func__, __LINE__, ps3_result(result)); 303 304 ps3_virq_destroy(virq); 305 306 return result; 307} 308EXPORT_SYMBOL_GPL(ps3_irq_plug_destroy); 309 310/** 311 * ps3_event_receive_port_setup - Setup an event receive port. 312 * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be 313 * serviced on. 314 * @virq: The assigned Linux virq. 315 * 316 * The virq can be used with lv1_connect_interrupt_event_receive_port() to 317 * arrange to receive interrupts from system-bus devices, or with 318 * ps3_send_event_locally() to signal events. 319 */ 320 321int ps3_event_receive_port_setup(enum ps3_cpu_binding cpu, unsigned int *virq) 322{ 323 int result; 324 u64 outlet; 325 326 result = lv1_construct_event_receive_port(&outlet); 327 328 if (result) { 329 FAIL("%s:%d: lv1_construct_event_receive_port failed: %s\n", 330 __func__, __LINE__, ps3_result(result)); 331 *virq = 0; 332 return result; 333 } 334 335 result = ps3_irq_plug_setup(cpu, outlet, virq); 336 BUG_ON(result); 337 338 return result; 339} 340EXPORT_SYMBOL_GPL(ps3_event_receive_port_setup); 341 342/** 343 * ps3_event_receive_port_destroy - Destroy an event receive port. 344 * @virq: The assigned Linux virq. 345 * 346 * Since ps3_event_receive_port_destroy destroys the receive port outlet, 347 * SB devices need to call disconnect_interrupt_event_receive_port() before 348 * this. 349 */ 350 351int ps3_event_receive_port_destroy(unsigned int virq) 352{ 353 int result; 354 355 DBG(" -> %s:%d virq %u\n", __func__, __LINE__, virq); 356 357 ps3_chip_mask(irq_get_irq_data(virq)); 358 359 result = lv1_destruct_event_receive_port(virq_to_hw(virq)); 360 361 if (result) 362 FAIL("%s:%d: lv1_destruct_event_receive_port failed: %s\n", 363 __func__, __LINE__, ps3_result(result)); 364 365 /* 366 * Don't call ps3_virq_destroy() here since ps3_smp_cleanup_cpu() 367 * calls from interrupt context (smp_call_function) when kexecing. 368 */ 369 370 DBG(" <- %s:%d\n", __func__, __LINE__); 371 return result; 372} 373 374int ps3_send_event_locally(unsigned int virq) 375{ 376 return lv1_send_event_locally(virq_to_hw(virq)); 377} 378 379/** 380 * ps3_sb_event_receive_port_setup - Setup a system bus event receive port. 381 * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be 382 * serviced on. 383 * @dev: The system bus device instance. 384 * @virq: The assigned Linux virq. 385 * 386 * An event irq represents a virtual device interrupt. The interrupt_id 387 * coresponds to the software interrupt number. 388 */ 389 390int ps3_sb_event_receive_port_setup(struct ps3_system_bus_device *dev, 391 enum ps3_cpu_binding cpu, unsigned int *virq) 392{ 393 /* this should go in system-bus.c */ 394 395 int result; 396 397 result = ps3_event_receive_port_setup(cpu, virq); 398 399 if (result) 400 return result; 401 402 result = lv1_connect_interrupt_event_receive_port(dev->bus_id, 403 dev->dev_id, virq_to_hw(*virq), dev->interrupt_id); 404 405 if (result) { 406 FAIL("%s:%d: lv1_connect_interrupt_event_receive_port" 407 " failed: %s\n", __func__, __LINE__, 408 ps3_result(result)); 409 ps3_event_receive_port_destroy(*virq); 410 *virq = 0; 411 return result; 412 } 413 414 DBG("%s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, 415 dev->interrupt_id, *virq); 416 417 return 0; 418} 419EXPORT_SYMBOL(ps3_sb_event_receive_port_setup); 420 421int ps3_sb_event_receive_port_destroy(struct ps3_system_bus_device *dev, 422 unsigned int virq) 423{ 424 /* this should go in system-bus.c */ 425 426 int result; 427 428 DBG(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, 429 dev->interrupt_id, virq); 430 431 result = lv1_disconnect_interrupt_event_receive_port(dev->bus_id, 432 dev->dev_id, virq_to_hw(virq), dev->interrupt_id); 433 434 if (result) 435 FAIL("%s:%d: lv1_disconnect_interrupt_event_receive_port" 436 " failed: %s\n", __func__, __LINE__, 437 ps3_result(result)); 438 439 result = ps3_event_receive_port_destroy(virq); 440 BUG_ON(result); 441 442 /* 443 * ps3_event_receive_port_destroy() destroys the IRQ plug, 444 * so don't call ps3_irq_plug_destroy() here. 445 */ 446 447 result = ps3_virq_destroy(virq); 448 BUG_ON(result); 449 450 DBG(" <- %s:%d\n", __func__, __LINE__); 451 return result; 452} 453EXPORT_SYMBOL(ps3_sb_event_receive_port_destroy); 454 455/** 456 * ps3_io_irq_setup - Setup a system bus io irq. 457 * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be 458 * serviced on. 459 * @interrupt_id: The device interrupt id read from the system repository. 460 * @virq: The assigned Linux virq. 461 * 462 * An io irq represents a non-virtualized device interrupt. interrupt_id 463 * coresponds to the interrupt number of the interrupt controller. 464 */ 465 466int ps3_io_irq_setup(enum ps3_cpu_binding cpu, unsigned int interrupt_id, 467 unsigned int *virq) 468{ 469 int result; 470 u64 outlet; 471 472 result = lv1_construct_io_irq_outlet(interrupt_id, &outlet); 473 474 if (result) { 475 FAIL("%s:%d: lv1_construct_io_irq_outlet failed: %s\n", 476 __func__, __LINE__, ps3_result(result)); 477 return result; 478 } 479 480 result = ps3_irq_plug_setup(cpu, outlet, virq); 481 BUG_ON(result); 482 483 return result; 484} 485EXPORT_SYMBOL_GPL(ps3_io_irq_setup); 486 487int ps3_io_irq_destroy(unsigned int virq) 488{ 489 int result; 490 unsigned long outlet = virq_to_hw(virq); 491 492 ps3_chip_mask(irq_get_irq_data(virq)); 493 494 /* 495 * lv1_destruct_io_irq_outlet() will destroy the IRQ plug, 496 * so call ps3_irq_plug_destroy() first. 497 */ 498 499 result = ps3_irq_plug_destroy(virq); 500 BUG_ON(result); 501 502 result = lv1_destruct_io_irq_outlet(outlet); 503 504 if (result) 505 FAIL("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", 506 __func__, __LINE__, ps3_result(result)); 507 508 return result; 509} 510EXPORT_SYMBOL_GPL(ps3_io_irq_destroy); 511 512/** 513 * ps3_vuart_irq_setup - Setup the system virtual uart virq. 514 * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be 515 * serviced on. 516 * @virt_addr_bmp: The caller supplied virtual uart interrupt bitmap. 517 * @virq: The assigned Linux virq. 518 * 519 * The system supports only a single virtual uart, so multiple calls without 520 * freeing the interrupt will return a wrong state error. 521 */ 522 523int ps3_vuart_irq_setup(enum ps3_cpu_binding cpu, void* virt_addr_bmp, 524 unsigned int *virq) 525{ 526 int result; 527 u64 outlet; 528 u64 lpar_addr; 529 530 BUG_ON(!is_kernel_addr((u64)virt_addr_bmp)); 531 532 lpar_addr = ps3_mm_phys_to_lpar(__pa(virt_addr_bmp)); 533 534 result = lv1_configure_virtual_uart_irq(lpar_addr, &outlet); 535 536 if (result) { 537 FAIL("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n", 538 __func__, __LINE__, ps3_result(result)); 539 return result; 540 } 541 542 result = ps3_irq_plug_setup(cpu, outlet, virq); 543 BUG_ON(result); 544 545 return result; 546} 547EXPORT_SYMBOL_GPL(ps3_vuart_irq_setup); 548 549int ps3_vuart_irq_destroy(unsigned int virq) 550{ 551 int result; 552 553 ps3_chip_mask(irq_get_irq_data(virq)); 554 result = lv1_deconfigure_virtual_uart_irq(); 555 556 if (result) { 557 FAIL("%s:%d: lv1_configure_virtual_uart_irq failed: %s\n", 558 __func__, __LINE__, ps3_result(result)); 559 return result; 560 } 561 562 result = ps3_irq_plug_destroy(virq); 563 BUG_ON(result); 564 565 return result; 566} 567EXPORT_SYMBOL_GPL(ps3_vuart_irq_destroy); 568 569/** 570 * ps3_spe_irq_setup - Setup an spe virq. 571 * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be 572 * serviced on. 573 * @spe_id: The spe_id returned from lv1_construct_logical_spe(). 574 * @class: The spe interrupt class {0,1,2}. 575 * @virq: The assigned Linux virq. 576 * 577 */ 578 579int ps3_spe_irq_setup(enum ps3_cpu_binding cpu, unsigned long spe_id, 580 unsigned int class, unsigned int *virq) 581{ 582 int result; 583 u64 outlet; 584 585 BUG_ON(class > 2); 586 587 result = lv1_get_spe_irq_outlet(spe_id, class, &outlet); 588 589 if (result) { 590 FAIL("%s:%d: lv1_get_spe_irq_outlet failed: %s\n", 591 __func__, __LINE__, ps3_result(result)); 592 return result; 593 } 594 595 result = ps3_irq_plug_setup(cpu, outlet, virq); 596 BUG_ON(result); 597 598 return result; 599} 600 601int ps3_spe_irq_destroy(unsigned int virq) 602{ 603 int result; 604 605 ps3_chip_mask(irq_get_irq_data(virq)); 606 607 result = ps3_irq_plug_destroy(virq); 608 BUG_ON(result); 609 610 return result; 611} 612 613 614#define PS3_INVALID_OUTLET ((irq_hw_number_t)-1) 615#define PS3_PLUG_MAX 63 616 617#if defined(DEBUG) 618static void _dump_64_bmp(const char *header, const u64 *p, unsigned cpu, 619 const char* func, int line) 620{ 621 pr_debug("%s:%d: %s %u {%04llx_%04llx_%04llx_%04llx}\n", 622 func, line, header, cpu, 623 *p >> 48, (*p >> 32) & 0xffff, (*p >> 16) & 0xffff, 624 *p & 0xffff); 625} 626 627static void __maybe_unused _dump_256_bmp(const char *header, 628 const u64 *p, unsigned cpu, const char* func, int line) 629{ 630 pr_debug("%s:%d: %s %u {%016llx:%016llx:%016llx:%016llx}\n", 631 func, line, header, cpu, p[0], p[1], p[2], p[3]); 632} 633 634#define dump_bmp(_x) _dump_bmp(_x, __func__, __LINE__) 635static void _dump_bmp(struct ps3_private* pd, const char* func, int line) 636{ 637 unsigned long flags; 638 639 spin_lock_irqsave(&pd->bmp_lock, flags); 640 _dump_64_bmp("stat", &pd->bmp.status, pd->thread_id, func, line); 641 _dump_64_bmp("mask", (u64*)&pd->bmp.mask, pd->thread_id, func, line); 642 spin_unlock_irqrestore(&pd->bmp_lock, flags); 643} 644 645#define dump_mask(_x) _dump_mask(_x, __func__, __LINE__) 646static void __maybe_unused _dump_mask(struct ps3_private *pd, 647 const char* func, int line) 648{ 649 unsigned long flags; 650 651 spin_lock_irqsave(&pd->bmp_lock, flags); 652 _dump_64_bmp("mask", (u64*)&pd->bmp.mask, pd->thread_id, func, line); 653 spin_unlock_irqrestore(&pd->bmp_lock, flags); 654} 655#else 656static void dump_bmp(struct ps3_private* pd) {}; 657#endif /* defined(DEBUG) */ 658 659static int ps3_host_map(struct irq_domain *h, unsigned int virq, 660 irq_hw_number_t hwirq) 661{ 662 DBG("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq, 663 virq); 664 665 irq_set_chip_and_handler(virq, &ps3_irq_chip, handle_fasteoi_irq); 666 667 return 0; 668} 669 670static int ps3_host_match(struct irq_domain *h, struct device_node *np, 671 enum irq_domain_bus_token bus_token) 672{ 673 /* Match all */ 674 return 1; 675} 676 677static const struct irq_domain_ops ps3_host_ops = { 678 .map = ps3_host_map, 679 .match = ps3_host_match, 680}; 681 682void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq) 683{ 684 struct ps3_private *pd = &per_cpu(ps3_private, cpu); 685 686 set_bit(63 - virq, &pd->ipi_debug_brk_mask); 687 688 DBG("%s:%d: cpu %u, virq %u, mask %lxh\n", __func__, __LINE__, 689 cpu, virq, pd->ipi_debug_brk_mask); 690} 691 692void __init ps3_register_ipi_irq(unsigned int cpu, unsigned int virq) 693{ 694 struct ps3_private *pd = &per_cpu(ps3_private, cpu); 695 696 set_bit(63 - virq, &pd->ipi_mask); 697 698 DBG("%s:%d: cpu %u, virq %u, ipi_mask %lxh\n", __func__, __LINE__, 699 cpu, virq, pd->ipi_mask); 700} 701 702static unsigned int ps3_get_irq(void) 703{ 704 struct ps3_private *pd = this_cpu_ptr(&ps3_private); 705 u64 x = (pd->bmp.status & pd->bmp.mask); 706 unsigned int plug; 707 708 /* check for ipi break first to stop this cpu ASAP */ 709 710 if (x & pd->ipi_debug_brk_mask) 711 x &= pd->ipi_debug_brk_mask; 712 713 asm volatile("cntlzd %0,%1" : "=r" (plug) : "r" (x)); 714 plug &= 0x3f; 715 716 if (unlikely(!plug)) { 717 DBG("%s:%d: no plug found: thread_id %llu\n", __func__, 718 __LINE__, pd->thread_id); 719 dump_bmp(&per_cpu(ps3_private, 0)); 720 dump_bmp(&per_cpu(ps3_private, 1)); 721 return 0; 722 } 723 724#if defined(DEBUG) 725 if (unlikely(plug < NR_IRQS_LEGACY || plug > PS3_PLUG_MAX)) { 726 dump_bmp(&per_cpu(ps3_private, 0)); 727 dump_bmp(&per_cpu(ps3_private, 1)); 728 BUG(); 729 } 730#endif 731 732 /* IPIs are EOIed here. */ 733 734 if (test_bit(63 - plug, &pd->ipi_mask)) 735 lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, plug); 736 737 return plug; 738} 739 740void __init ps3_init_IRQ(void) 741{ 742 int result; 743 unsigned cpu; 744 struct irq_domain *host; 745 746 host = irq_domain_add_nomap(NULL, PS3_PLUG_MAX + 1, &ps3_host_ops, NULL); 747 irq_set_default_host(host); 748 749 for_each_possible_cpu(cpu) { 750 struct ps3_private *pd = &per_cpu(ps3_private, cpu); 751 752 lv1_get_logical_ppe_id(&pd->ppe_id); 753 pd->thread_id = get_hard_smp_processor_id(cpu); 754 spin_lock_init(&pd->bmp_lock); 755 756 DBG("%s:%d: ppe_id %llu, thread_id %llu, bmp %lxh\n", 757 __func__, __LINE__, pd->ppe_id, pd->thread_id, 758 ps3_mm_phys_to_lpar(__pa(&pd->bmp))); 759 760 result = lv1_configure_irq_state_bitmap(pd->ppe_id, 761 pd->thread_id, ps3_mm_phys_to_lpar(__pa(&pd->bmp))); 762 763 if (result) 764 FAIL("%s:%d: lv1_configure_irq_state_bitmap failed:" 765 " %s\n", __func__, __LINE__, 766 ps3_result(result)); 767 } 768 769 ppc_md.get_irq = ps3_get_irq; 770} 771 772void ps3_shutdown_IRQ(int cpu) 773{ 774 int result; 775 u64 ppe_id; 776 u64 thread_id = get_hard_smp_processor_id(cpu); 777 778 lv1_get_logical_ppe_id(&ppe_id); 779 result = lv1_configure_irq_state_bitmap(ppe_id, thread_id, 0); 780 781 DBG("%s:%d: lv1_configure_irq_state_bitmap (%llu:%llu/%d) %s\n", __func__, 782 __LINE__, ppe_id, thread_id, cpu, ps3_result(result)); 783}