diff options
Diffstat (limited to 'arch/sparc64/kernel/smp.c')
-rw-r--r-- | arch/sparc64/kernel/smp.c | 50 |
1 files changed, 26 insertions, 24 deletions
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 7dc28a484268..90eaca3ec9a6 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c | |||
@@ -745,12 +745,21 @@ struct call_data_struct { | |||
745 | int wait; | 745 | int wait; |
746 | }; | 746 | }; |
747 | 747 | ||
748 | static DEFINE_SPINLOCK(call_lock); | 748 | static __cacheline_aligned_in_smp DEFINE_SPINLOCK(call_lock); |
749 | static struct call_data_struct *call_data; | 749 | static struct call_data_struct *call_data; |
750 | 750 | ||
751 | extern unsigned long xcall_call_function; | 751 | extern unsigned long xcall_call_function; |
752 | 752 | ||
753 | /* | 753 | /** |
754 | * smp_call_function(): Run a function on all other CPUs. | ||
755 | * @func: The function to run. This must be fast and non-blocking. | ||
756 | * @info: An arbitrary pointer to pass to the function. | ||
757 | * @nonatomic: currently unused. | ||
758 | * @wait: If true, wait (atomically) until function has completed on other CPUs. | ||
759 | * | ||
760 | * Returns 0 on success, else a negative status code. Does not return until | ||
761 | * remote CPUs are nearly ready to execute <<func>> or are or have executed. | ||
762 | * | ||
754 | * You must not call this function with disabled interrupts or from a | 763 | * You must not call this function with disabled interrupts or from a |
755 | * hardware interrupt handler or from a bottom half handler. | 764 | * hardware interrupt handler or from a bottom half handler. |
756 | */ | 765 | */ |
@@ -759,7 +768,6 @@ static int smp_call_function_mask(void (*func)(void *info), void *info, | |||
759 | { | 768 | { |
760 | struct call_data_struct data; | 769 | struct call_data_struct data; |
761 | int cpus; | 770 | int cpus; |
762 | long timeout; | ||
763 | 771 | ||
764 | /* Can deadlock when called with interrupts disabled */ | 772 | /* Can deadlock when called with interrupts disabled */ |
765 | WARN_ON(irqs_disabled()); | 773 | WARN_ON(irqs_disabled()); |
@@ -777,31 +785,18 @@ static int smp_call_function_mask(void (*func)(void *info), void *info, | |||
777 | goto out_unlock; | 785 | goto out_unlock; |
778 | 786 | ||
779 | call_data = &data; | 787 | call_data = &data; |
788 | mb(); | ||
780 | 789 | ||
781 | smp_cross_call_masked(&xcall_call_function, 0, 0, 0, mask); | 790 | smp_cross_call_masked(&xcall_call_function, 0, 0, 0, mask); |
782 | 791 | ||
783 | /* | 792 | /* Wait for response */ |
784 | * Wait for other cpus to complete function or at | 793 | while (atomic_read(&data.finished) != cpus) |
785 | * least snap the call data. | 794 | cpu_relax(); |
786 | */ | ||
787 | timeout = 1000000; | ||
788 | while (atomic_read(&data.finished) != cpus) { | ||
789 | if (--timeout <= 0) | ||
790 | goto out_timeout; | ||
791 | barrier(); | ||
792 | udelay(1); | ||
793 | } | ||
794 | 795 | ||
795 | out_unlock: | 796 | out_unlock: |
796 | spin_unlock(&call_lock); | 797 | spin_unlock(&call_lock); |
797 | 798 | ||
798 | return 0; | 799 | return 0; |
799 | |||
800 | out_timeout: | ||
801 | spin_unlock(&call_lock); | ||
802 | printk("XCALL: Remote cpus not responding, ncpus=%d finished=%d\n", | ||
803 | cpus, atomic_read(&data.finished)); | ||
804 | return 0; | ||
805 | } | 800 | } |
806 | 801 | ||
807 | int smp_call_function(void (*func)(void *info), void *info, | 802 | int smp_call_function(void (*func)(void *info), void *info, |
@@ -830,9 +825,16 @@ void smp_call_function_client(int irq, struct pt_regs *regs) | |||
830 | 825 | ||
831 | static void tsb_sync(void *info) | 826 | static void tsb_sync(void *info) |
832 | { | 827 | { |
828 | struct trap_per_cpu *tp = &trap_block[raw_smp_processor_id()]; | ||
833 | struct mm_struct *mm = info; | 829 | struct mm_struct *mm = info; |
834 | 830 | ||
835 | if (current->active_mm == mm) | 831 | /* It is not valid to test "currrent->active_mm == mm" here. |
832 | * | ||
833 | * The value of "current" is not changed atomically with | ||
834 | * switch_mm(). But that's OK, we just need to check the | ||
835 | * current cpu's trap block PGD physical address. | ||
836 | */ | ||
837 | if (tp->pgd_paddr == __pa(mm->pgd)) | ||
836 | tsb_context_switch(mm); | 838 | tsb_context_switch(mm); |
837 | } | 839 | } |
838 | 840 | ||
@@ -1278,7 +1280,7 @@ int setup_profiling_timer(unsigned int multiplier) | |||
1278 | return -EINVAL; | 1280 | return -EINVAL; |
1279 | 1281 | ||
1280 | spin_lock_irqsave(&prof_setup_lock, flags); | 1282 | spin_lock_irqsave(&prof_setup_lock, flags); |
1281 | for_each_cpu(i) | 1283 | for_each_possible_cpu(i) |
1282 | prof_multiplier(i) = multiplier; | 1284 | prof_multiplier(i) = multiplier; |
1283 | current_tick_offset = (timer_tick_offset / multiplier); | 1285 | current_tick_offset = (timer_tick_offset / multiplier); |
1284 | spin_unlock_irqrestore(&prof_setup_lock, flags); | 1286 | spin_unlock_irqrestore(&prof_setup_lock, flags); |
@@ -1306,12 +1308,12 @@ void __init smp_prepare_cpus(unsigned int max_cpus) | |||
1306 | } | 1308 | } |
1307 | } | 1309 | } |
1308 | 1310 | ||
1309 | for_each_cpu(i) { | 1311 | for_each_possible_cpu(i) { |
1310 | if (tlb_type == hypervisor) { | 1312 | if (tlb_type == hypervisor) { |
1311 | int j; | 1313 | int j; |
1312 | 1314 | ||
1313 | /* XXX get this mapping from machine description */ | 1315 | /* XXX get this mapping from machine description */ |
1314 | for_each_cpu(j) { | 1316 | for_each_possible_cpu(j) { |
1315 | if ((j >> 2) == (i >> 2)) | 1317 | if ((j >> 2) == (i >> 2)) |
1316 | cpu_set(j, cpu_sibling_map[i]); | 1318 | cpu_set(j, cpu_sibling_map[i]); |
1317 | } | 1319 | } |