diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2007-01-26 22:08:05 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-02-06 22:03:18 -0500 |
commit | 9cf9e19667f6ce01bd509a154157270069f836f9 (patch) | |
tree | c45ff1f25d608017b1ba2c83a1f6b934fc8e8acd /arch | |
parent | 407e24a0c78f585c228ec7e1152a9b23e262b200 (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.c | 85 |
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 | ||
381 | static void ps3_chip_mask(unsigned int virq) | 381 | static 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 | ||
397 | static void ps3_chip_unmask(unsigned int virq) | 405 | static 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 | ||
413 | static void ps3_chip_eoi(unsigned int virq) | 429 | static 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 | ||
484 | static int bmp_get_and_clear_status_bit(struct ps3_bmp *m) | 500 | unsigned 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 | |||
515 | unsigned 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(); |