aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2007-01-26 22:08:05 -0500
committerPaul Mackerras <paulus@samba.org>2007-02-06 22:03:18 -0500
commit9cf9e19667f6ce01bd509a154157270069f836f9 (patch)
treec45ff1f25d608017b1ba2c83a1f6b934fc8e8acd /arch
parent407e24a0c78f585c228ec7e1152a9b23e262b200 (diff)
[POWERPC] ps3: cleanup interrupt bmp routines
Change the PS3 interrupt bitmask routines to be lockless. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com> Acked-by: Arnd Bergmann <arnd.bergmann@de.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/platforms/ps3/interrupt.c85
1 files changed, 38 insertions, 47 deletions
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c
index 7a4ca056dd3a..d3c97fbff7ef 100644
--- a/arch/powerpc/platforms/ps3/interrupt.c
+++ b/arch/powerpc/platforms/ps3/interrupt.c
@@ -380,34 +380,50 @@ static void dump_bmp(struct ps3_private* pd) {};
380 380
381static void ps3_chip_mask(unsigned int virq) 381static void ps3_chip_mask(unsigned int virq)
382{ 382{
383 unsigned long flags;
384 struct ps3_private *pd = get_irq_chip_data(virq); 383 struct ps3_private *pd = get_irq_chip_data(virq);
384 unsigned long bit = 0x8000000000000000UL >> virq;
385 unsigned long *p = &pd->bmp.mask;
386 unsigned long old;
387 unsigned long flags;
385 388
386 pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); 389 pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq);
387 390
388 BUG_ON(virq < NUM_ISA_INTERRUPTS); 391 local_irq_save(flags);
389 BUG_ON(virq > PS3_PLUG_MAX); 392 asm volatile(
393 "1: ldarx %0,0,%3\n"
394 "andc %0,%0,%2\n"
395 "stdcx. %0,0,%3\n"
396 "bne- 1b"
397 : "=&r" (old), "+m" (*p)
398 : "r" (bit), "r" (p)
399 : "cc" );
390 400
391 spin_lock_irqsave(&pd->bmp.lock, flags);
392 pd->bmp.mask &= ~(0x8000000000000000UL >> virq);
393 lv1_did_update_interrupt_mask(pd->node, pd->cpu); 401 lv1_did_update_interrupt_mask(pd->node, pd->cpu);
394 spin_unlock_irqrestore(&pd->bmp.lock, flags); 402 local_irq_restore(flags);
395} 403}
396 404
397static void ps3_chip_unmask(unsigned int virq) 405static void ps3_chip_unmask(unsigned int virq)
398{ 406{
399 unsigned long flags;
400 struct ps3_private *pd = get_irq_chip_data(virq); 407 struct ps3_private *pd = get_irq_chip_data(virq);
408 unsigned long bit = 0x8000000000000000UL >> virq;
409 unsigned long *p = &pd->bmp.mask;
410 unsigned long old;
411 unsigned long flags;
401 412
402 pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); 413 pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq);
403 414
404 BUG_ON(virq < NUM_ISA_INTERRUPTS); 415 local_irq_save(flags);
405 BUG_ON(virq > PS3_PLUG_MAX); 416 asm volatile(
417 "1: ldarx %0,0,%3\n"
418 "or %0,%0,%2\n"
419 "stdcx. %0,0,%3\n"
420 "bne- 1b"
421 : "=&r" (old), "+m" (*p)
422 : "r" (bit), "r" (p)
423 : "cc" );
406 424
407 spin_lock_irqsave(&pd->bmp.lock, flags);
408 pd->bmp.mask |= (0x8000000000000000UL >> virq);
409 lv1_did_update_interrupt_mask(pd->node, pd->cpu); 425 lv1_did_update_interrupt_mask(pd->node, pd->cpu);
410 spin_unlock_irqrestore(&pd->bmp.lock, flags); 426 local_irq_restore(flags);
411} 427}
412 428
413static void ps3_chip_eoi(unsigned int virq) 429static void ps3_chip_eoi(unsigned int virq)
@@ -481,46 +497,21 @@ void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq)
481 cpu, virq, pd->bmp.ipi_debug_brk_mask); 497 cpu, virq, pd->bmp.ipi_debug_brk_mask);
482} 498}
483 499
484static int bmp_get_and_clear_status_bit(struct ps3_bmp *m) 500unsigned int ps3_get_irq(void)
485{ 501{
486 unsigned long flags; 502 struct ps3_private *pd = &__get_cpu_var(ps3_private);
487 unsigned int bit; 503 unsigned long x = (pd->bmp.status & pd->bmp.mask);
488 unsigned long x; 504 unsigned int plug;
489
490 spin_lock_irqsave(&m->lock, flags);
491 505
492 /* check for ipi break first to stop this cpu ASAP */ 506 /* check for ipi break first to stop this cpu ASAP */
493 507
494 if (m->status & m->ipi_debug_brk_mask) { 508 if (x & pd->bmp.ipi_debug_brk_mask)
495 m->status &= ~m->ipi_debug_brk_mask; 509 x &= pd->bmp.ipi_debug_brk_mask;
496 spin_unlock_irqrestore(&m->lock, flags);
497 return __ilog2(m->ipi_debug_brk_mask);
498 }
499
500 x = (m->status & m->mask);
501
502 for (bit = NUM_ISA_INTERRUPTS, x <<= bit; x; bit++, x <<= 1)
503 if (x & 0x8000000000000000UL) {
504 m->status &= ~(0x8000000000000000UL >> bit);
505 spin_unlock_irqrestore(&m->lock, flags);
506 return bit;
507 }
508
509 spin_unlock_irqrestore(&m->lock, flags);
510
511 pr_debug("%s:%d: not found\n", __func__, __LINE__);
512 return -1;
513}
514
515unsigned int ps3_get_irq(void)
516{
517 int plug;
518
519 struct ps3_private *pd = &__get_cpu_var(ps3_private);
520 510
521 plug = bmp_get_and_clear_status_bit(&pd->bmp); 511 asm volatile("cntlzd %0,%1" : "=r" (plug) : "r" (x));
512 plug &= 0x3f;
522 513
523 if (plug < 1) { 514 if (unlikely(plug) == NO_IRQ) {
524 pr_debug("%s:%d: no plug found: cpu %u\n", __func__, __LINE__, 515 pr_debug("%s:%d: no plug found: cpu %u\n", __func__, __LINE__,
525 pd->cpu); 516 pd->cpu);
526 dump_bmp(&per_cpu(ps3_private, 0)); 517 dump_bmp(&per_cpu(ps3_private, 0));
@@ -529,7 +520,7 @@ unsigned int ps3_get_irq(void)
529 } 520 }
530 521
531#if defined(DEBUG) 522#if defined(DEBUG)
532 if (plug < NUM_ISA_INTERRUPTS || plug > PS3_PLUG_MAX) { 523 if (unlikely(plug < NUM_ISA_INTERRUPTS || plug > PS3_PLUG_MAX)) {
533 dump_bmp(&per_cpu(ps3_private, 0)); 524 dump_bmp(&per_cpu(ps3_private, 0));
534 dump_bmp(&per_cpu(ps3_private, 1)); 525 dump_bmp(&per_cpu(ps3_private, 1));
535 BUG(); 526 BUG();