diff options
Diffstat (limited to 'arch/powerpc/platforms/ps3/interrupt.c')
-rw-r--r-- | arch/powerpc/platforms/ps3/interrupt.c | 272 |
1 files changed, 158 insertions, 114 deletions
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index ec9030dbb5f1..67e32ec9b37e 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c | |||
@@ -30,9 +30,9 @@ | |||
30 | #include "platform.h" | 30 | #include "platform.h" |
31 | 31 | ||
32 | #if defined(DEBUG) | 32 | #if defined(DEBUG) |
33 | #define DBG(fmt...) udbg_printf(fmt) | 33 | #define DBG udbg_printf |
34 | #else | 34 | #else |
35 | #define DBG(fmt...) do{if(0)printk(fmt);}while(0) | 35 | #define DBG pr_debug |
36 | #endif | 36 | #endif |
37 | 37 | ||
38 | /** | 38 | /** |
@@ -78,19 +78,85 @@ struct ps3_bmp { | |||
78 | /** | 78 | /** |
79 | * struct ps3_private - a per cpu data structure | 79 | * struct ps3_private - a per cpu data structure |
80 | * @bmp: ps3_bmp structure | 80 | * @bmp: ps3_bmp structure |
81 | * @node: HV logical_ppe_id | 81 | * @ppe_id: HV logical_ppe_id |
82 | * @cpu: HV thread_id | 82 | * @thread_id: HV thread_id |
83 | */ | 83 | */ |
84 | 84 | ||
85 | struct ps3_private { | 85 | struct ps3_private { |
86 | struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN))); | 86 | struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN))); |
87 | u64 node; | 87 | u64 ppe_id; |
88 | unsigned int cpu; | 88 | u64 thread_id; |
89 | }; | 89 | }; |
90 | 90 | ||
91 | static DEFINE_PER_CPU(struct ps3_private, ps3_private); | 91 | static DEFINE_PER_CPU(struct ps3_private, ps3_private); |
92 | 92 | ||
93 | /** | 93 | /** |
94 | * ps3_chip_mask - Set an interrupt mask bit in ps3_bmp. | ||
95 | * @virq: The assigned Linux virq. | ||
96 | * | ||
97 | * Sets ps3_bmp.mask and calls lv1_did_update_interrupt_mask(). | ||
98 | */ | ||
99 | |||
100 | static void ps3_chip_mask(unsigned int virq) | ||
101 | { | ||
102 | struct ps3_private *pd = get_irq_chip_data(virq); | ||
103 | unsigned long flags; | ||
104 | |||
105 | pr_debug("%s:%d: thread_id %lu, virq %d\n", __func__, __LINE__, | ||
106 | pd->thread_id, virq); | ||
107 | |||
108 | local_irq_save(flags); | ||
109 | clear_bit(63 - virq, &pd->bmp.mask); | ||
110 | lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id); | ||
111 | local_irq_restore(flags); | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * ps3_chip_unmask - Clear an interrupt mask bit in ps3_bmp. | ||
116 | * @virq: The assigned Linux virq. | ||
117 | * | ||
118 | * Clears ps3_bmp.mask and calls lv1_did_update_interrupt_mask(). | ||
119 | */ | ||
120 | |||
121 | static void ps3_chip_unmask(unsigned int virq) | ||
122 | { | ||
123 | struct ps3_private *pd = get_irq_chip_data(virq); | ||
124 | unsigned long flags; | ||
125 | |||
126 | pr_debug("%s:%d: thread_id %lu, virq %d\n", __func__, __LINE__, | ||
127 | pd->thread_id, virq); | ||
128 | |||
129 | local_irq_save(flags); | ||
130 | set_bit(63 - virq, &pd->bmp.mask); | ||
131 | lv1_did_update_interrupt_mask(pd->ppe_id, pd->thread_id); | ||
132 | local_irq_restore(flags); | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * ps3_chip_eoi - HV end-of-interrupt. | ||
137 | * @virq: The assigned Linux virq. | ||
138 | * | ||
139 | * Calls lv1_end_of_interrupt_ext(). | ||
140 | */ | ||
141 | |||
142 | static void ps3_chip_eoi(unsigned int virq) | ||
143 | { | ||
144 | const struct ps3_private *pd = get_irq_chip_data(virq); | ||
145 | lv1_end_of_interrupt_ext(pd->ppe_id, pd->thread_id, virq); | ||
146 | } | ||
147 | |||
148 | /** | ||
149 | * ps3_irq_chip - Represents the ps3_bmp as a Linux struct irq_chip. | ||
150 | */ | ||
151 | |||
152 | static struct irq_chip ps3_irq_chip = { | ||
153 | .typename = "ps3", | ||
154 | .mask = ps3_chip_mask, | ||
155 | .unmask = ps3_chip_unmask, | ||
156 | .eoi = ps3_chip_eoi, | ||
157 | }; | ||
158 | |||
159 | /** | ||
94 | * ps3_virq_setup - virq related setup. | 160 | * ps3_virq_setup - virq related setup. |
95 | * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be | 161 | * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be |
96 | * serviced on. | 162 | * serviced on. |
@@ -134,6 +200,8 @@ int ps3_virq_setup(enum ps3_cpu_binding cpu, unsigned long outlet, | |||
134 | goto fail_set; | 200 | goto fail_set; |
135 | } | 201 | } |
136 | 202 | ||
203 | ps3_chip_mask(*virq); | ||
204 | |||
137 | return result; | 205 | return result; |
138 | 206 | ||
139 | fail_set: | 207 | fail_set: |
@@ -153,8 +221,8 @@ int ps3_virq_destroy(unsigned int virq) | |||
153 | { | 221 | { |
154 | const struct ps3_private *pd = get_irq_chip_data(virq); | 222 | const struct ps3_private *pd = get_irq_chip_data(virq); |
155 | 223 | ||
156 | pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__, | 224 | pr_debug("%s:%d: ppe_id %lu, thread_id %lu, virq %u\n", __func__, |
157 | pd->node, pd->cpu, virq); | 225 | __LINE__, pd->ppe_id, pd->thread_id, virq); |
158 | 226 | ||
159 | set_irq_chip_data(virq, NULL); | 227 | set_irq_chip_data(virq, NULL); |
160 | irq_dispose_mapping(virq); | 228 | irq_dispose_mapping(virq); |
@@ -190,7 +258,8 @@ int ps3_irq_plug_setup(enum ps3_cpu_binding cpu, unsigned long outlet, | |||
190 | 258 | ||
191 | /* Binds outlet to cpu + virq. */ | 259 | /* Binds outlet to cpu + virq. */ |
192 | 260 | ||
193 | result = lv1_connect_irq_plug_ext(pd->node, pd->cpu, *virq, outlet, 0); | 261 | result = lv1_connect_irq_plug_ext(pd->ppe_id, pd->thread_id, *virq, |
262 | outlet, 0); | ||
194 | 263 | ||
195 | if (result) { | 264 | if (result) { |
196 | pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n", | 265 | pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n", |
@@ -222,10 +291,12 @@ int ps3_irq_plug_destroy(unsigned int virq) | |||
222 | int result; | 291 | int result; |
223 | const struct ps3_private *pd = get_irq_chip_data(virq); | 292 | const struct ps3_private *pd = get_irq_chip_data(virq); |
224 | 293 | ||
225 | pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__, | 294 | pr_debug("%s:%d: ppe_id %lu, thread_id %lu, virq %u\n", __func__, |
226 | pd->node, pd->cpu, virq); | 295 | __LINE__, pd->ppe_id, pd->thread_id, virq); |
296 | |||
297 | ps3_chip_mask(virq); | ||
227 | 298 | ||
228 | result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq); | 299 | result = lv1_disconnect_irq_plug_ext(pd->ppe_id, pd->thread_id, virq); |
229 | 300 | ||
230 | if (result) | 301 | if (result) |
231 | pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n", | 302 | pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n", |
@@ -282,7 +353,9 @@ int ps3_event_receive_port_destroy(unsigned int virq) | |||
282 | { | 353 | { |
283 | int result; | 354 | int result; |
284 | 355 | ||
285 | pr_debug(" -> %s:%d virq: %u\n", __func__, __LINE__, virq); | 356 | pr_debug(" -> %s:%d virq %u\n", __func__, __LINE__, virq); |
357 | |||
358 | ps3_chip_mask(virq); | ||
286 | 359 | ||
287 | result = lv1_destruct_event_receive_port(virq_to_hw(virq)); | 360 | result = lv1_destruct_event_receive_port(virq_to_hw(virq)); |
288 | 361 | ||
@@ -290,17 +363,14 @@ int ps3_event_receive_port_destroy(unsigned int virq) | |||
290 | pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n", | 363 | pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n", |
291 | __func__, __LINE__, ps3_result(result)); | 364 | __func__, __LINE__, ps3_result(result)); |
292 | 365 | ||
293 | /* lv1_destruct_event_receive_port() destroys the IRQ plug, | 366 | /* |
294 | * so don't call ps3_irq_plug_destroy() here. | 367 | * Don't call ps3_virq_destroy() here since ps3_smp_cleanup_cpu() |
368 | * calls from interrupt context (smp_call_function) when kexecing. | ||
295 | */ | 369 | */ |
296 | 370 | ||
297 | result = ps3_virq_destroy(virq); | ||
298 | BUG_ON(result); | ||
299 | |||
300 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | 371 | pr_debug(" <- %s:%d\n", __func__, __LINE__); |
301 | return result; | 372 | return result; |
302 | } | 373 | } |
303 | EXPORT_SYMBOL_GPL(ps3_event_receive_port_destroy); | ||
304 | 374 | ||
305 | int ps3_send_event_locally(unsigned int virq) | 375 | int ps3_send_event_locally(unsigned int virq) |
306 | { | 376 | { |
@@ -311,17 +381,15 @@ int ps3_send_event_locally(unsigned int virq) | |||
311 | * ps3_sb_event_receive_port_setup - Setup a system bus event receive port. | 381 | * ps3_sb_event_receive_port_setup - Setup a system bus event receive port. |
312 | * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be | 382 | * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be |
313 | * serviced on. | 383 | * serviced on. |
314 | * @did: The HV device identifier read from the system repository. | 384 | * @dev: The system bus device instance. |
315 | * @interrupt_id: The device interrupt id read from the system repository. | ||
316 | * @virq: The assigned Linux virq. | 385 | * @virq: The assigned Linux virq. |
317 | * | 386 | * |
318 | * An event irq represents a virtual device interrupt. The interrupt_id | 387 | * An event irq represents a virtual device interrupt. The interrupt_id |
319 | * coresponds to the software interrupt number. | 388 | * coresponds to the software interrupt number. |
320 | */ | 389 | */ |
321 | 390 | ||
322 | int ps3_sb_event_receive_port_setup(enum ps3_cpu_binding cpu, | 391 | int ps3_sb_event_receive_port_setup(struct ps3_system_bus_device *dev, |
323 | const struct ps3_device_id *did, unsigned int interrupt_id, | 392 | enum ps3_cpu_binding cpu, unsigned int *virq) |
324 | unsigned int *virq) | ||
325 | { | 393 | { |
326 | /* this should go in system-bus.c */ | 394 | /* this should go in system-bus.c */ |
327 | 395 | ||
@@ -332,8 +400,8 @@ int ps3_sb_event_receive_port_setup(enum ps3_cpu_binding cpu, | |||
332 | if (result) | 400 | if (result) |
333 | return result; | 401 | return result; |
334 | 402 | ||
335 | result = lv1_connect_interrupt_event_receive_port(did->bus_id, | 403 | result = lv1_connect_interrupt_event_receive_port(dev->bus_id, |
336 | did->dev_id, virq_to_hw(*virq), interrupt_id); | 404 | dev->dev_id, virq_to_hw(*virq), dev->interrupt_id); |
337 | 405 | ||
338 | if (result) { | 406 | if (result) { |
339 | pr_debug("%s:%d: lv1_connect_interrupt_event_receive_port" | 407 | pr_debug("%s:%d: lv1_connect_interrupt_event_receive_port" |
@@ -345,24 +413,24 @@ int ps3_sb_event_receive_port_setup(enum ps3_cpu_binding cpu, | |||
345 | } | 413 | } |
346 | 414 | ||
347 | pr_debug("%s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, | 415 | pr_debug("%s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, |
348 | interrupt_id, *virq); | 416 | dev->interrupt_id, *virq); |
349 | 417 | ||
350 | return 0; | 418 | return 0; |
351 | } | 419 | } |
352 | EXPORT_SYMBOL(ps3_sb_event_receive_port_setup); | 420 | EXPORT_SYMBOL(ps3_sb_event_receive_port_setup); |
353 | 421 | ||
354 | int ps3_sb_event_receive_port_destroy(const struct ps3_device_id *did, | 422 | int ps3_sb_event_receive_port_destroy(struct ps3_system_bus_device *dev, |
355 | unsigned int interrupt_id, unsigned int virq) | 423 | unsigned int virq) |
356 | { | 424 | { |
357 | /* this should go in system-bus.c */ | 425 | /* this should go in system-bus.c */ |
358 | 426 | ||
359 | int result; | 427 | int result; |
360 | 428 | ||
361 | pr_debug(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, | 429 | pr_debug(" -> %s:%d: interrupt_id %u, virq %u\n", __func__, __LINE__, |
362 | interrupt_id, virq); | 430 | dev->interrupt_id, virq); |
363 | 431 | ||
364 | result = lv1_disconnect_interrupt_event_receive_port(did->bus_id, | 432 | result = lv1_disconnect_interrupt_event_receive_port(dev->bus_id, |
365 | did->dev_id, virq_to_hw(virq), interrupt_id); | 433 | dev->dev_id, virq_to_hw(virq), dev->interrupt_id); |
366 | 434 | ||
367 | if (result) | 435 | if (result) |
368 | pr_debug("%s:%d: lv1_disconnect_interrupt_event_receive_port" | 436 | pr_debug("%s:%d: lv1_disconnect_interrupt_event_receive_port" |
@@ -372,6 +440,14 @@ int ps3_sb_event_receive_port_destroy(const struct ps3_device_id *did, | |||
372 | result = ps3_event_receive_port_destroy(virq); | 440 | result = ps3_event_receive_port_destroy(virq); |
373 | BUG_ON(result); | 441 | BUG_ON(result); |
374 | 442 | ||
443 | /* | ||
444 | * ps3_event_receive_port_destroy() destroys the IRQ plug, | ||
445 | * so don't call ps3_irq_plug_destroy() here. | ||
446 | */ | ||
447 | |||
448 | result = ps3_virq_destroy(virq); | ||
449 | BUG_ON(result); | ||
450 | |||
375 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | 451 | pr_debug(" <- %s:%d\n", __func__, __LINE__); |
376 | return result; | 452 | return result; |
377 | } | 453 | } |
@@ -412,16 +488,24 @@ EXPORT_SYMBOL_GPL(ps3_io_irq_setup); | |||
412 | int ps3_io_irq_destroy(unsigned int virq) | 488 | int ps3_io_irq_destroy(unsigned int virq) |
413 | { | 489 | { |
414 | int result; | 490 | int result; |
491 | unsigned long outlet = virq_to_hw(virq); | ||
415 | 492 | ||
416 | result = lv1_destruct_io_irq_outlet(virq_to_hw(virq)); | 493 | ps3_chip_mask(virq); |
417 | 494 | ||
418 | if (result) | 495 | /* |
419 | pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", | 496 | * lv1_destruct_io_irq_outlet() will destroy the IRQ plug, |
420 | __func__, __LINE__, ps3_result(result)); | 497 | * so call ps3_irq_plug_destroy() first. |
498 | */ | ||
421 | 499 | ||
422 | result = ps3_irq_plug_destroy(virq); | 500 | result = ps3_irq_plug_destroy(virq); |
423 | BUG_ON(result); | 501 | BUG_ON(result); |
424 | 502 | ||
503 | result = lv1_destruct_io_irq_outlet(outlet); | ||
504 | |||
505 | if (result) | ||
506 | pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", | ||
507 | __func__, __LINE__, ps3_result(result)); | ||
508 | |||
425 | return result; | 509 | return result; |
426 | } | 510 | } |
427 | EXPORT_SYMBOL_GPL(ps3_io_irq_destroy); | 511 | EXPORT_SYMBOL_GPL(ps3_io_irq_destroy); |
@@ -461,11 +545,13 @@ int ps3_vuart_irq_setup(enum ps3_cpu_binding cpu, void* virt_addr_bmp, | |||
461 | 545 | ||
462 | return result; | 546 | return result; |
463 | } | 547 | } |
548 | EXPORT_SYMBOL_GPL(ps3_vuart_irq_setup); | ||
464 | 549 | ||
465 | int ps3_vuart_irq_destroy(unsigned int virq) | 550 | int ps3_vuart_irq_destroy(unsigned int virq) |
466 | { | 551 | { |
467 | int result; | 552 | int result; |
468 | 553 | ||
554 | ps3_chip_mask(virq); | ||
469 | result = lv1_deconfigure_virtual_uart_irq(); | 555 | result = lv1_deconfigure_virtual_uart_irq(); |
470 | 556 | ||
471 | if (result) { | 557 | if (result) { |
@@ -479,6 +565,7 @@ int ps3_vuart_irq_destroy(unsigned int virq) | |||
479 | 565 | ||
480 | return result; | 566 | return result; |
481 | } | 567 | } |
568 | EXPORT_SYMBOL_GPL(ps3_vuart_irq_destroy); | ||
482 | 569 | ||
483 | /** | 570 | /** |
484 | * ps3_spe_irq_setup - Setup an spe virq. | 571 | * ps3_spe_irq_setup - Setup an spe virq. |
@@ -514,9 +601,14 @@ int ps3_spe_irq_setup(enum ps3_cpu_binding cpu, unsigned long spe_id, | |||
514 | 601 | ||
515 | int ps3_spe_irq_destroy(unsigned int virq) | 602 | int ps3_spe_irq_destroy(unsigned int virq) |
516 | { | 603 | { |
517 | int result = ps3_irq_plug_destroy(virq); | 604 | int result; |
605 | |||
606 | ps3_chip_mask(virq); | ||
607 | |||
608 | result = ps3_irq_plug_destroy(virq); | ||
518 | BUG_ON(result); | 609 | BUG_ON(result); |
519 | return 0; | 610 | |
611 | return result; | ||
520 | } | 612 | } |
521 | 613 | ||
522 | 614 | ||
@@ -533,7 +625,7 @@ static void _dump_64_bmp(const char *header, const u64 *p, unsigned cpu, | |||
533 | *p & 0xffff); | 625 | *p & 0xffff); |
534 | } | 626 | } |
535 | 627 | ||
536 | static void __attribute__ ((unused)) _dump_256_bmp(const char *header, | 628 | static void __maybe_unused _dump_256_bmp(const char *header, |
537 | const u64 *p, unsigned cpu, const char* func, int line) | 629 | const u64 *p, unsigned cpu, const char* func, int line) |
538 | { | 630 | { |
539 | pr_debug("%s:%d: %s %u {%016lx:%016lx:%016lx:%016lx}\n", | 631 | pr_debug("%s:%d: %s %u {%016lx:%016lx:%016lx:%016lx}\n", |
@@ -546,86 +638,25 @@ static void _dump_bmp(struct ps3_private* pd, const char* func, int line) | |||
546 | unsigned long flags; | 638 | unsigned long flags; |
547 | 639 | ||
548 | spin_lock_irqsave(&pd->bmp.lock, flags); | 640 | spin_lock_irqsave(&pd->bmp.lock, flags); |
549 | _dump_64_bmp("stat", &pd->bmp.status, pd->cpu, func, line); | 641 | _dump_64_bmp("stat", &pd->bmp.status, pd->thread_id, func, line); |
550 | _dump_64_bmp("mask", &pd->bmp.mask, pd->cpu, func, line); | 642 | _dump_64_bmp("mask", &pd->bmp.mask, pd->thread_id, func, line); |
551 | spin_unlock_irqrestore(&pd->bmp.lock, flags); | 643 | spin_unlock_irqrestore(&pd->bmp.lock, flags); |
552 | } | 644 | } |
553 | 645 | ||
554 | #define dump_mask(_x) _dump_mask(_x, __func__, __LINE__) | 646 | #define dump_mask(_x) _dump_mask(_x, __func__, __LINE__) |
555 | static void __attribute__ ((unused)) _dump_mask(struct ps3_private* pd, | 647 | static void __maybe_unused _dump_mask(struct ps3_private *pd, |
556 | const char* func, int line) | 648 | const char* func, int line) |
557 | { | 649 | { |
558 | unsigned long flags; | 650 | unsigned long flags; |
559 | 651 | ||
560 | spin_lock_irqsave(&pd->bmp.lock, flags); | 652 | spin_lock_irqsave(&pd->bmp.lock, flags); |
561 | _dump_64_bmp("mask", &pd->bmp.mask, pd->cpu, func, line); | 653 | _dump_64_bmp("mask", &pd->bmp.mask, pd->thread_id, func, line); |
562 | spin_unlock_irqrestore(&pd->bmp.lock, flags); | 654 | spin_unlock_irqrestore(&pd->bmp.lock, flags); |
563 | } | 655 | } |
564 | #else | 656 | #else |
565 | static void dump_bmp(struct ps3_private* pd) {}; | 657 | static void dump_bmp(struct ps3_private* pd) {}; |
566 | #endif /* defined(DEBUG) */ | 658 | #endif /* defined(DEBUG) */ |
567 | 659 | ||
568 | static void ps3_chip_mask(unsigned int virq) | ||
569 | { | ||
570 | struct ps3_private *pd = get_irq_chip_data(virq); | ||
571 | u64 bit = 0x8000000000000000UL >> virq; | ||
572 | u64 *p = &pd->bmp.mask; | ||
573 | u64 old; | ||
574 | unsigned long flags; | ||
575 | |||
576 | pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); | ||
577 | |||
578 | local_irq_save(flags); | ||
579 | asm volatile( | ||
580 | "1: ldarx %0,0,%3\n" | ||
581 | "andc %0,%0,%2\n" | ||
582 | "stdcx. %0,0,%3\n" | ||
583 | "bne- 1b" | ||
584 | : "=&r" (old), "+m" (*p) | ||
585 | : "r" (bit), "r" (p) | ||
586 | : "cc" ); | ||
587 | |||
588 | lv1_did_update_interrupt_mask(pd->node, pd->cpu); | ||
589 | local_irq_restore(flags); | ||
590 | } | ||
591 | |||
592 | static void ps3_chip_unmask(unsigned int virq) | ||
593 | { | ||
594 | struct ps3_private *pd = get_irq_chip_data(virq); | ||
595 | u64 bit = 0x8000000000000000UL >> virq; | ||
596 | u64 *p = &pd->bmp.mask; | ||
597 | u64 old; | ||
598 | unsigned long flags; | ||
599 | |||
600 | pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); | ||
601 | |||
602 | local_irq_save(flags); | ||
603 | asm volatile( | ||
604 | "1: ldarx %0,0,%3\n" | ||
605 | "or %0,%0,%2\n" | ||
606 | "stdcx. %0,0,%3\n" | ||
607 | "bne- 1b" | ||
608 | : "=&r" (old), "+m" (*p) | ||
609 | : "r" (bit), "r" (p) | ||
610 | : "cc" ); | ||
611 | |||
612 | lv1_did_update_interrupt_mask(pd->node, pd->cpu); | ||
613 | local_irq_restore(flags); | ||
614 | } | ||
615 | |||
616 | static void ps3_chip_eoi(unsigned int virq) | ||
617 | { | ||
618 | const struct ps3_private *pd = get_irq_chip_data(virq); | ||
619 | lv1_end_of_interrupt_ext(pd->node, pd->cpu, virq); | ||
620 | } | ||
621 | |||
622 | static struct irq_chip irq_chip = { | ||
623 | .typename = "ps3", | ||
624 | .mask = ps3_chip_mask, | ||
625 | .unmask = ps3_chip_unmask, | ||
626 | .eoi = ps3_chip_eoi, | ||
627 | }; | ||
628 | |||
629 | static void ps3_host_unmap(struct irq_host *h, unsigned int virq) | 660 | static void ps3_host_unmap(struct irq_host *h, unsigned int virq) |
630 | { | 661 | { |
631 | set_irq_chip_data(virq, NULL); | 662 | set_irq_chip_data(virq, NULL); |
@@ -637,7 +668,7 @@ static int ps3_host_map(struct irq_host *h, unsigned int virq, | |||
637 | pr_debug("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq, | 668 | pr_debug("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq, |
638 | virq); | 669 | virq); |
639 | 670 | ||
640 | set_irq_chip_and_handler(virq, &irq_chip, handle_fasteoi_irq); | 671 | set_irq_chip_and_handler(virq, &ps3_irq_chip, handle_fasteoi_irq); |
641 | 672 | ||
642 | return 0; | 673 | return 0; |
643 | } | 674 | } |
@@ -657,7 +688,7 @@ void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq) | |||
657 | cpu, virq, pd->bmp.ipi_debug_brk_mask); | 688 | cpu, virq, pd->bmp.ipi_debug_brk_mask); |
658 | } | 689 | } |
659 | 690 | ||
660 | unsigned int ps3_get_irq(void) | 691 | static unsigned int ps3_get_irq(void) |
661 | { | 692 | { |
662 | struct ps3_private *pd = &__get_cpu_var(ps3_private); | 693 | struct ps3_private *pd = &__get_cpu_var(ps3_private); |
663 | u64 x = (pd->bmp.status & pd->bmp.mask); | 694 | u64 x = (pd->bmp.status & pd->bmp.mask); |
@@ -672,8 +703,8 @@ unsigned int ps3_get_irq(void) | |||
672 | plug &= 0x3f; | 703 | plug &= 0x3f; |
673 | 704 | ||
674 | if (unlikely(plug) == NO_IRQ) { | 705 | if (unlikely(plug) == NO_IRQ) { |
675 | pr_debug("%s:%d: no plug found: cpu %u\n", __func__, __LINE__, | 706 | pr_debug("%s:%d: no plug found: thread_id %lu\n", __func__, |
676 | pd->cpu); | 707 | __LINE__, pd->thread_id); |
677 | dump_bmp(&per_cpu(ps3_private, 0)); | 708 | dump_bmp(&per_cpu(ps3_private, 0)); |
678 | dump_bmp(&per_cpu(ps3_private, 1)); | 709 | dump_bmp(&per_cpu(ps3_private, 1)); |
679 | return NO_IRQ; | 710 | return NO_IRQ; |
@@ -703,16 +734,16 @@ void __init ps3_init_IRQ(void) | |||
703 | for_each_possible_cpu(cpu) { | 734 | for_each_possible_cpu(cpu) { |
704 | struct ps3_private *pd = &per_cpu(ps3_private, cpu); | 735 | struct ps3_private *pd = &per_cpu(ps3_private, cpu); |
705 | 736 | ||
706 | lv1_get_logical_ppe_id(&pd->node); | 737 | lv1_get_logical_ppe_id(&pd->ppe_id); |
707 | pd->cpu = get_hard_smp_processor_id(cpu); | 738 | pd->thread_id = get_hard_smp_processor_id(cpu); |
708 | spin_lock_init(&pd->bmp.lock); | 739 | spin_lock_init(&pd->bmp.lock); |
709 | 740 | ||
710 | pr_debug("%s:%d: node %lu, cpu %d, bmp %lxh\n", __func__, | 741 | pr_debug("%s:%d: ppe_id %lu, thread_id %lu, bmp %lxh\n", |
711 | __LINE__, pd->node, pd->cpu, | 742 | __func__, __LINE__, pd->ppe_id, pd->thread_id, |
712 | ps3_mm_phys_to_lpar(__pa(&pd->bmp))); | 743 | ps3_mm_phys_to_lpar(__pa(&pd->bmp))); |
713 | 744 | ||
714 | result = lv1_configure_irq_state_bitmap(pd->node, pd->cpu, | 745 | result = lv1_configure_irq_state_bitmap(pd->ppe_id, |
715 | ps3_mm_phys_to_lpar(__pa(&pd->bmp))); | 746 | pd->thread_id, ps3_mm_phys_to_lpar(__pa(&pd->bmp))); |
716 | 747 | ||
717 | if (result) | 748 | if (result) |
718 | pr_debug("%s:%d: lv1_configure_irq_state_bitmap failed:" | 749 | pr_debug("%s:%d: lv1_configure_irq_state_bitmap failed:" |
@@ -722,3 +753,16 @@ void __init ps3_init_IRQ(void) | |||
722 | 753 | ||
723 | ppc_md.get_irq = ps3_get_irq; | 754 | ppc_md.get_irq = ps3_get_irq; |
724 | } | 755 | } |
756 | |||
757 | void ps3_shutdown_IRQ(int cpu) | ||
758 | { | ||
759 | int result; | ||
760 | u64 ppe_id; | ||
761 | u64 thread_id = get_hard_smp_processor_id(cpu); | ||
762 | |||
763 | lv1_get_logical_ppe_id(&ppe_id); | ||
764 | result = lv1_configure_irq_state_bitmap(ppe_id, thread_id, 0); | ||
765 | |||
766 | DBG("%s:%d: lv1_configure_irq_state_bitmap (%lu:%lu/%d) %s\n", __func__, | ||
767 | __LINE__, ppe_id, thread_id, cpu, ps3_result(result)); | ||
768 | } | ||