diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2006-03-07 01:50:44 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-03-20 04:14:21 -0500 |
commit | ee29074d3bd23848905f52c515974e0cd0219faa (patch) | |
tree | d5306446b2e26d9e45f65467b4f3b3f3b0c8494c /arch/sparc64/kernel/smp.c | |
parent | a77754b4d0731321db266c6c60ffcd7c62757da5 (diff) |
[SPARC64]: Fix new context version SMP handling.
Don't piggy back the SMP receive signal code to do the
context version change handling.
Instead allocate another fixed PIL number for this
asynchronous cross-call. We can't use smp_call_function()
because this thing is invoked with interrupts disabled
and a few spinlocks held.
Also, fix smp_call_function_mask() to count "cpus" correctly.
There is no guarentee that the local cpu is in the mask
yet that is exactly what this code was assuming.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/kernel/smp.c')
-rw-r--r-- | arch/sparc64/kernel/smp.c | 39 |
1 files changed, 24 insertions, 15 deletions
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index c4548a88953c..cf56128097c8 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c | |||
@@ -760,12 +760,9 @@ static int smp_call_function_mask(void (*func)(void *info), void *info, | |||
760 | int nonatomic, int wait, cpumask_t mask) | 760 | int nonatomic, int wait, cpumask_t mask) |
761 | { | 761 | { |
762 | struct call_data_struct data; | 762 | struct call_data_struct data; |
763 | int cpus = cpus_weight(mask) - 1; | 763 | int cpus; |
764 | long timeout; | 764 | long timeout; |
765 | 765 | ||
766 | if (!cpus) | ||
767 | return 0; | ||
768 | |||
769 | /* Can deadlock when called with interrupts disabled */ | 766 | /* Can deadlock when called with interrupts disabled */ |
770 | WARN_ON(irqs_disabled()); | 767 | WARN_ON(irqs_disabled()); |
771 | 768 | ||
@@ -776,6 +773,11 @@ static int smp_call_function_mask(void (*func)(void *info), void *info, | |||
776 | 773 | ||
777 | spin_lock(&call_lock); | 774 | spin_lock(&call_lock); |
778 | 775 | ||
776 | cpu_clear(smp_processor_id(), mask); | ||
777 | cpus = cpus_weight(mask); | ||
778 | if (!cpus) | ||
779 | goto out_unlock; | ||
780 | |||
779 | call_data = &data; | 781 | call_data = &data; |
780 | 782 | ||
781 | smp_cross_call_masked(&xcall_call_function, 0, 0, 0, mask); | 783 | smp_cross_call_masked(&xcall_call_function, 0, 0, 0, mask); |
@@ -792,6 +794,7 @@ static int smp_call_function_mask(void (*func)(void *info), void *info, | |||
792 | udelay(1); | 794 | udelay(1); |
793 | } | 795 | } |
794 | 796 | ||
797 | out_unlock: | ||
795 | spin_unlock(&call_lock); | 798 | spin_unlock(&call_lock); |
796 | 799 | ||
797 | return 0; | 800 | return 0; |
@@ -845,6 +848,7 @@ extern unsigned long xcall_flush_tlb_pending; | |||
845 | extern unsigned long xcall_flush_tlb_kernel_range; | 848 | extern unsigned long xcall_flush_tlb_kernel_range; |
846 | extern unsigned long xcall_report_regs; | 849 | extern unsigned long xcall_report_regs; |
847 | extern unsigned long xcall_receive_signal; | 850 | extern unsigned long xcall_receive_signal; |
851 | extern unsigned long xcall_new_mmu_context_version; | ||
848 | 852 | ||
849 | #ifdef DCACHE_ALIASING_POSSIBLE | 853 | #ifdef DCACHE_ALIASING_POSSIBLE |
850 | extern unsigned long xcall_flush_dcache_page_cheetah; | 854 | extern unsigned long xcall_flush_dcache_page_cheetah; |
@@ -974,7 +978,13 @@ void smp_receive_signal(int cpu) | |||
974 | 978 | ||
975 | void smp_receive_signal_client(int irq, struct pt_regs *regs) | 979 | void smp_receive_signal_client(int irq, struct pt_regs *regs) |
976 | { | 980 | { |
981 | clear_softint(1 << irq); | ||
982 | } | ||
983 | |||
984 | void smp_new_mmu_context_version_client(int irq, struct pt_regs *regs) | ||
985 | { | ||
977 | struct mm_struct *mm; | 986 | struct mm_struct *mm; |
987 | unsigned long flags; | ||
978 | 988 | ||
979 | clear_softint(1 << irq); | 989 | clear_softint(1 << irq); |
980 | 990 | ||
@@ -982,25 +992,24 @@ void smp_receive_signal_client(int irq, struct pt_regs *regs) | |||
982 | * the version of the one we are using is now out of date. | 992 | * the version of the one we are using is now out of date. |
983 | */ | 993 | */ |
984 | mm = current->active_mm; | 994 | mm = current->active_mm; |
985 | if (likely(mm)) { | 995 | if (unlikely(!mm || (mm == &init_mm))) |
986 | unsigned long flags; | 996 | return; |
987 | 997 | ||
988 | spin_lock_irqsave(&mm->context.lock, flags); | 998 | spin_lock_irqsave(&mm->context.lock, flags); |
989 | 999 | ||
990 | if (unlikely(!CTX_VALID(mm->context))) | 1000 | if (unlikely(!CTX_VALID(mm->context))) |
991 | get_new_mmu_context(mm); | 1001 | get_new_mmu_context(mm); |
992 | 1002 | ||
993 | load_secondary_context(mm); | 1003 | spin_unlock_irqrestore(&mm->context.lock, flags); |
994 | __flush_tlb_mm(CTX_HWBITS(mm->context), | ||
995 | SECONDARY_CONTEXT); | ||
996 | 1004 | ||
997 | spin_unlock_irqrestore(&mm->context.lock, flags); | 1005 | load_secondary_context(mm); |
998 | } | 1006 | __flush_tlb_mm(CTX_HWBITS(mm->context), |
1007 | SECONDARY_CONTEXT); | ||
999 | } | 1008 | } |
1000 | 1009 | ||
1001 | void smp_new_mmu_context_version(void) | 1010 | void smp_new_mmu_context_version(void) |
1002 | { | 1011 | { |
1003 | __smp_receive_signal_mask(cpu_online_map); | 1012 | smp_cross_call(&xcall_new_mmu_context_version, 0, 0, 0); |
1004 | } | 1013 | } |
1005 | 1014 | ||
1006 | void smp_report_regs(void) | 1015 | void smp_report_regs(void) |