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 | |
| 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>
| -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(); |
