diff options
| author | Paul Mackerras <paulus@samba.org> | 2006-08-31 01:45:48 -0400 |
|---|---|---|
| committer | Paul Mackerras <paulus@samba.org> | 2006-08-31 01:45:48 -0400 |
| commit | aa43f77939c97bf9d3580c6a5e71a5a40290e451 (patch) | |
| tree | 095c0b8b3da4b6554a3f8ef4b39240a5d9216d4d /arch/powerpc/kernel/irq.c | |
| parent | 2818c5dec5e28d65d52afbb7695bbbafe6377ee5 (diff) | |
| parent | 4c15343167b5febe7bb0ba96aad5bef42ae94d3b (diff) | |
Merge branch 'merge'
Diffstat (limited to 'arch/powerpc/kernel/irq.c')
| -rw-r--r-- | arch/powerpc/kernel/irq.c | 84 |
1 files changed, 66 insertions, 18 deletions
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index fd4ddb858dbd..b4432332341f 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c | |||
| @@ -323,7 +323,8 @@ EXPORT_SYMBOL(do_softirq); | |||
| 323 | 323 | ||
| 324 | static LIST_HEAD(irq_hosts); | 324 | static LIST_HEAD(irq_hosts); |
| 325 | static spinlock_t irq_big_lock = SPIN_LOCK_UNLOCKED; | 325 | static spinlock_t irq_big_lock = SPIN_LOCK_UNLOCKED; |
| 326 | 326 | static DEFINE_PER_CPU(unsigned int, irq_radix_reader); | |
| 327 | static unsigned int irq_radix_writer; | ||
| 327 | struct irq_map_entry irq_map[NR_IRQS]; | 328 | struct irq_map_entry irq_map[NR_IRQS]; |
| 328 | static unsigned int irq_virq_count = NR_IRQS; | 329 | static unsigned int irq_virq_count = NR_IRQS; |
| 329 | static struct irq_host *irq_default_host; | 330 | static struct irq_host *irq_default_host; |
| @@ -456,6 +457,58 @@ void irq_set_virq_count(unsigned int count) | |||
| 456 | irq_virq_count = count; | 457 | irq_virq_count = count; |
| 457 | } | 458 | } |
| 458 | 459 | ||
| 460 | /* radix tree not lockless safe ! we use a brlock-type mecanism | ||
| 461 | * for now, until we can use a lockless radix tree | ||
| 462 | */ | ||
| 463 | static void irq_radix_wrlock(unsigned long *flags) | ||
| 464 | { | ||
| 465 | unsigned int cpu, ok; | ||
| 466 | |||
| 467 | spin_lock_irqsave(&irq_big_lock, *flags); | ||
| 468 | irq_radix_writer = 1; | ||
| 469 | smp_mb(); | ||
| 470 | do { | ||
| 471 | barrier(); | ||
| 472 | ok = 1; | ||
| 473 | for_each_possible_cpu(cpu) { | ||
| 474 | if (per_cpu(irq_radix_reader, cpu)) { | ||
| 475 | ok = 0; | ||
| 476 | break; | ||
| 477 | } | ||
| 478 | } | ||
| 479 | if (!ok) | ||
| 480 | cpu_relax(); | ||
| 481 | } while(!ok); | ||
| 482 | } | ||
| 483 | |||
| 484 | static void irq_radix_wrunlock(unsigned long flags) | ||
| 485 | { | ||
| 486 | smp_wmb(); | ||
| 487 | irq_radix_writer = 0; | ||
| 488 | spin_unlock_irqrestore(&irq_big_lock, flags); | ||
| 489 | } | ||
| 490 | |||
| 491 | static void irq_radix_rdlock(unsigned long *flags) | ||
| 492 | { | ||
| 493 | local_irq_save(*flags); | ||
| 494 | __get_cpu_var(irq_radix_reader) = 1; | ||
| 495 | smp_mb(); | ||
| 496 | if (likely(irq_radix_writer == 0)) | ||
| 497 | return; | ||
| 498 | __get_cpu_var(irq_radix_reader) = 0; | ||
| 499 | smp_wmb(); | ||
| 500 | spin_lock(&irq_big_lock); | ||
| 501 | __get_cpu_var(irq_radix_reader) = 1; | ||
| 502 | spin_unlock(&irq_big_lock); | ||
| 503 | } | ||
| 504 | |||
| 505 | static void irq_radix_rdunlock(unsigned long flags) | ||
| 506 | { | ||
| 507 | __get_cpu_var(irq_radix_reader) = 0; | ||
| 508 | local_irq_restore(flags); | ||
| 509 | } | ||
| 510 | |||
| 511 | |||
| 459 | unsigned int irq_create_mapping(struct irq_host *host, | 512 | unsigned int irq_create_mapping(struct irq_host *host, |
| 460 | irq_hw_number_t hwirq) | 513 | irq_hw_number_t hwirq) |
| 461 | { | 514 | { |
| @@ -605,13 +658,9 @@ void irq_dispose_mapping(unsigned int virq) | |||
| 605 | /* Check if radix tree allocated yet */ | 658 | /* Check if radix tree allocated yet */ |
| 606 | if (host->revmap_data.tree.gfp_mask == 0) | 659 | if (host->revmap_data.tree.gfp_mask == 0) |
| 607 | break; | 660 | break; |
| 608 | /* XXX radix tree not safe ! remove lock whem it becomes safe | 661 | irq_radix_wrlock(&flags); |
| 609 | * and use some RCU sync to make sure everything is ok before we | ||
| 610 | * can re-use that map entry | ||
| 611 | */ | ||
| 612 | spin_lock_irqsave(&irq_big_lock, flags); | ||
| 613 | radix_tree_delete(&host->revmap_data.tree, hwirq); | 662 | radix_tree_delete(&host->revmap_data.tree, hwirq); |
| 614 | spin_unlock_irqrestore(&irq_big_lock, flags); | 663 | irq_radix_wrunlock(flags); |
| 615 | break; | 664 | break; |
| 616 | } | 665 | } |
| 617 | 666 | ||
| @@ -678,25 +727,24 @@ unsigned int irq_radix_revmap(struct irq_host *host, | |||
| 678 | if (tree->gfp_mask == 0) | 727 | if (tree->gfp_mask == 0) |
| 679 | return irq_find_mapping(host, hwirq); | 728 | return irq_find_mapping(host, hwirq); |
| 680 | 729 | ||
| 681 | /* XXX Current radix trees are NOT SMP safe !!! Remove that lock | ||
| 682 | * when that is fixed (when Nick's patch gets in | ||
| 683 | */ | ||
| 684 | spin_lock_irqsave(&irq_big_lock, flags); | ||
| 685 | |||
| 686 | /* Now try to resolve */ | 730 | /* Now try to resolve */ |
| 731 | irq_radix_rdlock(&flags); | ||
| 687 | ptr = radix_tree_lookup(tree, hwirq); | 732 | ptr = radix_tree_lookup(tree, hwirq); |
| 733 | irq_radix_rdunlock(flags); | ||
| 734 | |||
| 688 | /* Found it, return */ | 735 | /* Found it, return */ |
| 689 | if (ptr) { | 736 | if (ptr) { |
| 690 | virq = ptr - irq_map; | 737 | virq = ptr - irq_map; |
| 691 | goto bail; | 738 | return virq; |
| 692 | } | 739 | } |
| 693 | 740 | ||
| 694 | /* If not there, try to insert it */ | 741 | /* If not there, try to insert it */ |
| 695 | virq = irq_find_mapping(host, hwirq); | 742 | virq = irq_find_mapping(host, hwirq); |
| 696 | if (virq != NO_IRQ) | 743 | if (virq != NO_IRQ) { |
| 744 | irq_radix_wrlock(&flags); | ||
| 697 | radix_tree_insert(tree, hwirq, &irq_map[virq]); | 745 | radix_tree_insert(tree, hwirq, &irq_map[virq]); |
| 698 | bail: | 746 | irq_radix_wrunlock(flags); |
| 699 | spin_unlock_irqrestore(&irq_big_lock, flags); | 747 | } |
| 700 | return virq; | 748 | return virq; |
| 701 | } | 749 | } |
| 702 | 750 | ||
| @@ -807,12 +855,12 @@ static int irq_late_init(void) | |||
| 807 | struct irq_host *h; | 855 | struct irq_host *h; |
| 808 | unsigned long flags; | 856 | unsigned long flags; |
| 809 | 857 | ||
| 810 | spin_lock_irqsave(&irq_big_lock, flags); | 858 | irq_radix_wrlock(&flags); |
| 811 | list_for_each_entry(h, &irq_hosts, link) { | 859 | list_for_each_entry(h, &irq_hosts, link) { |
| 812 | if (h->revmap_type == IRQ_HOST_MAP_TREE) | 860 | if (h->revmap_type == IRQ_HOST_MAP_TREE) |
| 813 | INIT_RADIX_TREE(&h->revmap_data.tree, GFP_ATOMIC); | 861 | INIT_RADIX_TREE(&h->revmap_data.tree, GFP_ATOMIC); |
| 814 | } | 862 | } |
| 815 | spin_unlock_irqrestore(&irq_big_lock, flags); | 863 | irq_radix_wrunlock(flags); |
| 816 | 864 | ||
| 817 | return 0; | 865 | return 0; |
| 818 | } | 866 | } |
