diff options
Diffstat (limited to 'arch/sparc64/kernel/smp.c')
-rw-r--r-- | arch/sparc64/kernel/smp.c | 453 |
1 files changed, 330 insertions, 123 deletions
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 1f7ad8a69052..7dc28a484268 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <asm/timer.h> | 38 | #include <asm/timer.h> |
39 | #include <asm/starfire.h> | 39 | #include <asm/starfire.h> |
40 | #include <asm/tlb.h> | 40 | #include <asm/tlb.h> |
41 | #include <asm/sections.h> | ||
41 | 42 | ||
42 | extern void calibrate_delay(void); | 43 | extern void calibrate_delay(void); |
43 | 44 | ||
@@ -46,6 +47,8 @@ static unsigned char boot_cpu_id; | |||
46 | 47 | ||
47 | cpumask_t cpu_online_map __read_mostly = CPU_MASK_NONE; | 48 | cpumask_t cpu_online_map __read_mostly = CPU_MASK_NONE; |
48 | cpumask_t phys_cpu_present_map __read_mostly = CPU_MASK_NONE; | 49 | cpumask_t phys_cpu_present_map __read_mostly = CPU_MASK_NONE; |
50 | cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly = | ||
51 | { [0 ... NR_CPUS-1] = CPU_MASK_NONE }; | ||
49 | static cpumask_t smp_commenced_mask; | 52 | static cpumask_t smp_commenced_mask; |
50 | static cpumask_t cpu_callout_map; | 53 | static cpumask_t cpu_callout_map; |
51 | 54 | ||
@@ -54,30 +57,26 @@ void smp_info(struct seq_file *m) | |||
54 | int i; | 57 | int i; |
55 | 58 | ||
56 | seq_printf(m, "State:\n"); | 59 | seq_printf(m, "State:\n"); |
57 | for (i = 0; i < NR_CPUS; i++) { | 60 | for_each_online_cpu(i) |
58 | if (cpu_online(i)) | 61 | seq_printf(m, "CPU%d:\t\tonline\n", i); |
59 | seq_printf(m, | ||
60 | "CPU%d:\t\tonline\n", i); | ||
61 | } | ||
62 | } | 62 | } |
63 | 63 | ||
64 | void smp_bogo(struct seq_file *m) | 64 | void smp_bogo(struct seq_file *m) |
65 | { | 65 | { |
66 | int i; | 66 | int i; |
67 | 67 | ||
68 | for (i = 0; i < NR_CPUS; i++) | 68 | for_each_online_cpu(i) |
69 | if (cpu_online(i)) | 69 | seq_printf(m, |
70 | seq_printf(m, | 70 | "Cpu%dBogo\t: %lu.%02lu\n" |
71 | "Cpu%dBogo\t: %lu.%02lu\n" | 71 | "Cpu%dClkTck\t: %016lx\n", |
72 | "Cpu%dClkTck\t: %016lx\n", | 72 | i, cpu_data(i).udelay_val / (500000/HZ), |
73 | i, cpu_data(i).udelay_val / (500000/HZ), | 73 | (cpu_data(i).udelay_val / (5000/HZ)) % 100, |
74 | (cpu_data(i).udelay_val / (5000/HZ)) % 100, | 74 | i, cpu_data(i).clock_tick); |
75 | i, cpu_data(i).clock_tick); | ||
76 | } | 75 | } |
77 | 76 | ||
78 | void __init smp_store_cpu_info(int id) | 77 | void __init smp_store_cpu_info(int id) |
79 | { | 78 | { |
80 | int cpu_node; | 79 | int cpu_node, def; |
81 | 80 | ||
82 | /* multiplier and counter set by | 81 | /* multiplier and counter set by |
83 | smp_setup_percpu_timer() */ | 82 | smp_setup_percpu_timer() */ |
@@ -87,24 +86,32 @@ void __init smp_store_cpu_info(int id) | |||
87 | cpu_data(id).clock_tick = prom_getintdefault(cpu_node, | 86 | cpu_data(id).clock_tick = prom_getintdefault(cpu_node, |
88 | "clock-frequency", 0); | 87 | "clock-frequency", 0); |
89 | 88 | ||
90 | cpu_data(id).pgcache_size = 0; | 89 | def = ((tlb_type == hypervisor) ? (8 * 1024) : (16 * 1024)); |
91 | cpu_data(id).pte_cache[0] = NULL; | ||
92 | cpu_data(id).pte_cache[1] = NULL; | ||
93 | cpu_data(id).pgd_cache = NULL; | ||
94 | cpu_data(id).idle_volume = 1; | ||
95 | |||
96 | cpu_data(id).dcache_size = prom_getintdefault(cpu_node, "dcache-size", | 90 | cpu_data(id).dcache_size = prom_getintdefault(cpu_node, "dcache-size", |
97 | 16 * 1024); | 91 | def); |
92 | |||
93 | def = 32; | ||
98 | cpu_data(id).dcache_line_size = | 94 | cpu_data(id).dcache_line_size = |
99 | prom_getintdefault(cpu_node, "dcache-line-size", 32); | 95 | prom_getintdefault(cpu_node, "dcache-line-size", def); |
96 | |||
97 | def = 16 * 1024; | ||
100 | cpu_data(id).icache_size = prom_getintdefault(cpu_node, "icache-size", | 98 | cpu_data(id).icache_size = prom_getintdefault(cpu_node, "icache-size", |
101 | 16 * 1024); | 99 | def); |
100 | |||
101 | def = 32; | ||
102 | cpu_data(id).icache_line_size = | 102 | cpu_data(id).icache_line_size = |
103 | prom_getintdefault(cpu_node, "icache-line-size", 32); | 103 | prom_getintdefault(cpu_node, "icache-line-size", def); |
104 | |||
105 | def = ((tlb_type == hypervisor) ? | ||
106 | (3 * 1024 * 1024) : | ||
107 | (4 * 1024 * 1024)); | ||
104 | cpu_data(id).ecache_size = prom_getintdefault(cpu_node, "ecache-size", | 108 | cpu_data(id).ecache_size = prom_getintdefault(cpu_node, "ecache-size", |
105 | 4 * 1024 * 1024); | 109 | def); |
110 | |||
111 | def = 64; | ||
106 | cpu_data(id).ecache_line_size = | 112 | cpu_data(id).ecache_line_size = |
107 | prom_getintdefault(cpu_node, "ecache-line-size", 64); | 113 | prom_getintdefault(cpu_node, "ecache-line-size", def); |
114 | |||
108 | printk("CPU[%d]: Caches " | 115 | printk("CPU[%d]: Caches " |
109 | "D[sz(%d):line_sz(%d)] " | 116 | "D[sz(%d):line_sz(%d)] " |
110 | "I[sz(%d):line_sz(%d)] " | 117 | "I[sz(%d):line_sz(%d)] " |
@@ -119,27 +126,16 @@ static void smp_setup_percpu_timer(void); | |||
119 | 126 | ||
120 | static volatile unsigned long callin_flag = 0; | 127 | static volatile unsigned long callin_flag = 0; |
121 | 128 | ||
122 | extern void inherit_locked_prom_mappings(int save_p); | ||
123 | |||
124 | static inline void cpu_setup_percpu_base(unsigned long cpu_id) | ||
125 | { | ||
126 | __asm__ __volatile__("mov %0, %%g5\n\t" | ||
127 | "stxa %0, [%1] %2\n\t" | ||
128 | "membar #Sync" | ||
129 | : /* no outputs */ | ||
130 | : "r" (__per_cpu_offset(cpu_id)), | ||
131 | "r" (TSB_REG), "i" (ASI_IMMU)); | ||
132 | } | ||
133 | |||
134 | void __init smp_callin(void) | 129 | void __init smp_callin(void) |
135 | { | 130 | { |
136 | int cpuid = hard_smp_processor_id(); | 131 | int cpuid = hard_smp_processor_id(); |
137 | 132 | ||
138 | inherit_locked_prom_mappings(0); | 133 | __local_per_cpu_offset = __per_cpu_offset(cpuid); |
139 | 134 | ||
140 | __flush_tlb_all(); | 135 | if (tlb_type == hypervisor) |
136 | sun4v_ktsb_register(); | ||
141 | 137 | ||
142 | cpu_setup_percpu_base(cpuid); | 138 | __flush_tlb_all(); |
143 | 139 | ||
144 | smp_setup_percpu_timer(); | 140 | smp_setup_percpu_timer(); |
145 | 141 | ||
@@ -316,6 +312,8 @@ static void smp_synchronize_one_tick(int cpu) | |||
316 | spin_unlock_irqrestore(&itc_sync_lock, flags); | 312 | spin_unlock_irqrestore(&itc_sync_lock, flags); |
317 | } | 313 | } |
318 | 314 | ||
315 | extern void sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int load); | ||
316 | |||
319 | extern unsigned long sparc64_cpu_startup; | 317 | extern unsigned long sparc64_cpu_startup; |
320 | 318 | ||
321 | /* The OBP cpu startup callback truncates the 3rd arg cookie to | 319 | /* The OBP cpu startup callback truncates the 3rd arg cookie to |
@@ -331,21 +329,31 @@ static int __devinit smp_boot_one_cpu(unsigned int cpu) | |||
331 | unsigned long cookie = | 329 | unsigned long cookie = |
332 | (unsigned long)(&cpu_new_thread); | 330 | (unsigned long)(&cpu_new_thread); |
333 | struct task_struct *p; | 331 | struct task_struct *p; |
334 | int timeout, ret, cpu_node; | 332 | int timeout, ret; |
335 | 333 | ||
336 | p = fork_idle(cpu); | 334 | p = fork_idle(cpu); |
337 | callin_flag = 0; | 335 | callin_flag = 0; |
338 | cpu_new_thread = task_thread_info(p); | 336 | cpu_new_thread = task_thread_info(p); |
339 | cpu_set(cpu, cpu_callout_map); | 337 | cpu_set(cpu, cpu_callout_map); |
340 | 338 | ||
341 | cpu_find_by_mid(cpu, &cpu_node); | 339 | if (tlb_type == hypervisor) { |
342 | prom_startcpu(cpu_node, entry, cookie); | 340 | /* Alloc the mondo queues, cpu will load them. */ |
341 | sun4v_init_mondo_queues(0, cpu, 1, 0); | ||
342 | |||
343 | prom_startcpu_cpuid(cpu, entry, cookie); | ||
344 | } else { | ||
345 | int cpu_node; | ||
346 | |||
347 | cpu_find_by_mid(cpu, &cpu_node); | ||
348 | prom_startcpu(cpu_node, entry, cookie); | ||
349 | } | ||
343 | 350 | ||
344 | for (timeout = 0; timeout < 5000000; timeout++) { | 351 | for (timeout = 0; timeout < 5000000; timeout++) { |
345 | if (callin_flag) | 352 | if (callin_flag) |
346 | break; | 353 | break; |
347 | udelay(100); | 354 | udelay(100); |
348 | } | 355 | } |
356 | |||
349 | if (callin_flag) { | 357 | if (callin_flag) { |
350 | ret = 0; | 358 | ret = 0; |
351 | } else { | 359 | } else { |
@@ -441,7 +449,7 @@ static __inline__ void spitfire_xcall_deliver(u64 data0, u64 data1, u64 data2, c | |||
441 | static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask) | 449 | static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask) |
442 | { | 450 | { |
443 | u64 pstate, ver; | 451 | u64 pstate, ver; |
444 | int nack_busy_id, is_jalapeno; | 452 | int nack_busy_id, is_jbus; |
445 | 453 | ||
446 | if (cpus_empty(mask)) | 454 | if (cpus_empty(mask)) |
447 | return; | 455 | return; |
@@ -451,7 +459,8 @@ static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mas | |||
451 | * derivative processor. | 459 | * derivative processor. |
452 | */ | 460 | */ |
453 | __asm__ ("rdpr %%ver, %0" : "=r" (ver)); | 461 | __asm__ ("rdpr %%ver, %0" : "=r" (ver)); |
454 | is_jalapeno = ((ver >> 32) == 0x003e0016); | 462 | is_jbus = ((ver >> 32) == __JALAPENO_ID || |
463 | (ver >> 32) == __SERRANO_ID); | ||
455 | 464 | ||
456 | __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); | 465 | __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); |
457 | 466 | ||
@@ -476,7 +485,7 @@ retry: | |||
476 | for_each_cpu_mask(i, mask) { | 485 | for_each_cpu_mask(i, mask) { |
477 | u64 target = (i << 14) | 0x70; | 486 | u64 target = (i << 14) | 0x70; |
478 | 487 | ||
479 | if (!is_jalapeno) | 488 | if (!is_jbus) |
480 | target |= (nack_busy_id << 24); | 489 | target |= (nack_busy_id << 24); |
481 | __asm__ __volatile__( | 490 | __asm__ __volatile__( |
482 | "stxa %%g0, [%0] %1\n\t" | 491 | "stxa %%g0, [%0] %1\n\t" |
@@ -529,7 +538,7 @@ retry: | |||
529 | for_each_cpu_mask(i, mask) { | 538 | for_each_cpu_mask(i, mask) { |
530 | u64 check_mask; | 539 | u64 check_mask; |
531 | 540 | ||
532 | if (is_jalapeno) | 541 | if (is_jbus) |
533 | check_mask = (0x2UL << (2*i)); | 542 | check_mask = (0x2UL << (2*i)); |
534 | else | 543 | else |
535 | check_mask = (0x2UL << | 544 | check_mask = (0x2UL << |
@@ -544,6 +553,155 @@ retry: | |||
544 | } | 553 | } |
545 | } | 554 | } |
546 | 555 | ||
556 | /* Multi-cpu list version. */ | ||
557 | static void hypervisor_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask) | ||
558 | { | ||
559 | struct trap_per_cpu *tb; | ||
560 | u16 *cpu_list; | ||
561 | u64 *mondo; | ||
562 | cpumask_t error_mask; | ||
563 | unsigned long flags, status; | ||
564 | int cnt, retries, this_cpu, prev_sent, i; | ||
565 | |||
566 | /* We have to do this whole thing with interrupts fully disabled. | ||
567 | * Otherwise if we send an xcall from interrupt context it will | ||
568 | * corrupt both our mondo block and cpu list state. | ||
569 | * | ||
570 | * One consequence of this is that we cannot use timeout mechanisms | ||
571 | * that depend upon interrupts being delivered locally. So, for | ||
572 | * example, we cannot sample jiffies and expect it to advance. | ||
573 | * | ||
574 | * Fortunately, udelay() uses %stick/%tick so we can use that. | ||
575 | */ | ||
576 | local_irq_save(flags); | ||
577 | |||
578 | this_cpu = smp_processor_id(); | ||
579 | tb = &trap_block[this_cpu]; | ||
580 | |||
581 | mondo = __va(tb->cpu_mondo_block_pa); | ||
582 | mondo[0] = data0; | ||
583 | mondo[1] = data1; | ||
584 | mondo[2] = data2; | ||
585 | wmb(); | ||
586 | |||
587 | cpu_list = __va(tb->cpu_list_pa); | ||
588 | |||
589 | /* Setup the initial cpu list. */ | ||
590 | cnt = 0; | ||
591 | for_each_cpu_mask(i, mask) | ||
592 | cpu_list[cnt++] = i; | ||
593 | |||
594 | cpus_clear(error_mask); | ||
595 | retries = 0; | ||
596 | prev_sent = 0; | ||
597 | do { | ||
598 | int forward_progress, n_sent; | ||
599 | |||
600 | status = sun4v_cpu_mondo_send(cnt, | ||
601 | tb->cpu_list_pa, | ||
602 | tb->cpu_mondo_block_pa); | ||
603 | |||
604 | /* HV_EOK means all cpus received the xcall, we're done. */ | ||
605 | if (likely(status == HV_EOK)) | ||
606 | break; | ||
607 | |||
608 | /* First, see if we made any forward progress. | ||
609 | * | ||
610 | * The hypervisor indicates successful sends by setting | ||
611 | * cpu list entries to the value 0xffff. | ||
612 | */ | ||
613 | n_sent = 0; | ||
614 | for (i = 0; i < cnt; i++) { | ||
615 | if (likely(cpu_list[i] == 0xffff)) | ||
616 | n_sent++; | ||
617 | } | ||
618 | |||
619 | forward_progress = 0; | ||
620 | if (n_sent > prev_sent) | ||
621 | forward_progress = 1; | ||
622 | |||
623 | prev_sent = n_sent; | ||
624 | |||
625 | /* If we get a HV_ECPUERROR, then one or more of the cpus | ||
626 | * in the list are in error state. Use the cpu_state() | ||
627 | * hypervisor call to find out which cpus are in error state. | ||
628 | */ | ||
629 | if (unlikely(status == HV_ECPUERROR)) { | ||
630 | for (i = 0; i < cnt; i++) { | ||
631 | long err; | ||
632 | u16 cpu; | ||
633 | |||
634 | cpu = cpu_list[i]; | ||
635 | if (cpu == 0xffff) | ||
636 | continue; | ||
637 | |||
638 | err = sun4v_cpu_state(cpu); | ||
639 | if (err >= 0 && | ||
640 | err == HV_CPU_STATE_ERROR) { | ||
641 | cpu_list[i] = 0xffff; | ||
642 | cpu_set(cpu, error_mask); | ||
643 | } | ||
644 | } | ||
645 | } else if (unlikely(status != HV_EWOULDBLOCK)) | ||
646 | goto fatal_mondo_error; | ||
647 | |||
648 | /* Don't bother rewriting the CPU list, just leave the | ||
649 | * 0xffff and non-0xffff entries in there and the | ||
650 | * hypervisor will do the right thing. | ||
651 | * | ||
652 | * Only advance timeout state if we didn't make any | ||
653 | * forward progress. | ||
654 | */ | ||
655 | if (unlikely(!forward_progress)) { | ||
656 | if (unlikely(++retries > 10000)) | ||
657 | goto fatal_mondo_timeout; | ||
658 | |||
659 | /* Delay a little bit to let other cpus catch up | ||
660 | * on their cpu mondo queue work. | ||
661 | */ | ||
662 | udelay(2 * cnt); | ||
663 | } | ||
664 | } while (1); | ||
665 | |||
666 | local_irq_restore(flags); | ||
667 | |||
668 | if (unlikely(!cpus_empty(error_mask))) | ||
669 | goto fatal_mondo_cpu_error; | ||
670 | |||
671 | return; | ||
672 | |||
673 | fatal_mondo_cpu_error: | ||
674 | printk(KERN_CRIT "CPU[%d]: SUN4V mondo cpu error, some target cpus " | ||
675 | "were in error state\n", | ||
676 | this_cpu); | ||
677 | printk(KERN_CRIT "CPU[%d]: Error mask [ ", this_cpu); | ||
678 | for_each_cpu_mask(i, error_mask) | ||
679 | printk("%d ", i); | ||
680 | printk("]\n"); | ||
681 | return; | ||
682 | |||
683 | fatal_mondo_timeout: | ||
684 | local_irq_restore(flags); | ||
685 | printk(KERN_CRIT "CPU[%d]: SUN4V mondo timeout, no forward " | ||
686 | " progress after %d retries.\n", | ||
687 | this_cpu, retries); | ||
688 | goto dump_cpu_list_and_out; | ||
689 | |||
690 | fatal_mondo_error: | ||
691 | local_irq_restore(flags); | ||
692 | printk(KERN_CRIT "CPU[%d]: Unexpected SUN4V mondo error %lu\n", | ||
693 | this_cpu, status); | ||
694 | printk(KERN_CRIT "CPU[%d]: Args were cnt(%d) cpulist_pa(%lx) " | ||
695 | "mondo_block_pa(%lx)\n", | ||
696 | this_cpu, cnt, tb->cpu_list_pa, tb->cpu_mondo_block_pa); | ||
697 | |||
698 | dump_cpu_list_and_out: | ||
699 | printk(KERN_CRIT "CPU[%d]: CPU list [ ", this_cpu); | ||
700 | for (i = 0; i < cnt; i++) | ||
701 | printk("%u ", cpu_list[i]); | ||
702 | printk("]\n"); | ||
703 | } | ||
704 | |||
547 | /* Send cross call to all processors mentioned in MASK | 705 | /* Send cross call to all processors mentioned in MASK |
548 | * except self. | 706 | * except self. |
549 | */ | 707 | */ |
@@ -557,8 +715,10 @@ static void smp_cross_call_masked(unsigned long *func, u32 ctx, u64 data1, u64 d | |||
557 | 715 | ||
558 | if (tlb_type == spitfire) | 716 | if (tlb_type == spitfire) |
559 | spitfire_xcall_deliver(data0, data1, data2, mask); | 717 | spitfire_xcall_deliver(data0, data1, data2, mask); |
560 | else | 718 | else if (tlb_type == cheetah || tlb_type == cheetah_plus) |
561 | cheetah_xcall_deliver(data0, data1, data2, mask); | 719 | cheetah_xcall_deliver(data0, data1, data2, mask); |
720 | else | ||
721 | hypervisor_xcall_deliver(data0, data1, data2, mask); | ||
562 | /* NOTE: Caller runs local copy on master. */ | 722 | /* NOTE: Caller runs local copy on master. */ |
563 | 723 | ||
564 | put_cpu(); | 724 | put_cpu(); |
@@ -594,16 +754,13 @@ extern unsigned long xcall_call_function; | |||
594 | * You must not call this function with disabled interrupts or from a | 754 | * You must not call this function with disabled interrupts or from a |
595 | * hardware interrupt handler or from a bottom half handler. | 755 | * hardware interrupt handler or from a bottom half handler. |
596 | */ | 756 | */ |
597 | int smp_call_function(void (*func)(void *info), void *info, | 757 | static int smp_call_function_mask(void (*func)(void *info), void *info, |
598 | int nonatomic, int wait) | 758 | int nonatomic, int wait, cpumask_t mask) |
599 | { | 759 | { |
600 | struct call_data_struct data; | 760 | struct call_data_struct data; |
601 | int cpus = num_online_cpus() - 1; | 761 | int cpus; |
602 | long timeout; | 762 | long timeout; |
603 | 763 | ||
604 | if (!cpus) | ||
605 | return 0; | ||
606 | |||
607 | /* Can deadlock when called with interrupts disabled */ | 764 | /* Can deadlock when called with interrupts disabled */ |
608 | WARN_ON(irqs_disabled()); | 765 | WARN_ON(irqs_disabled()); |
609 | 766 | ||
@@ -614,9 +771,14 @@ int smp_call_function(void (*func)(void *info), void *info, | |||
614 | 771 | ||
615 | spin_lock(&call_lock); | 772 | spin_lock(&call_lock); |
616 | 773 | ||
774 | cpu_clear(smp_processor_id(), mask); | ||
775 | cpus = cpus_weight(mask); | ||
776 | if (!cpus) | ||
777 | goto out_unlock; | ||
778 | |||
617 | call_data = &data; | 779 | call_data = &data; |
618 | 780 | ||
619 | smp_cross_call(&xcall_call_function, 0, 0, 0); | 781 | smp_cross_call_masked(&xcall_call_function, 0, 0, 0, mask); |
620 | 782 | ||
621 | /* | 783 | /* |
622 | * Wait for other cpus to complete function or at | 784 | * Wait for other cpus to complete function or at |
@@ -630,18 +792,25 @@ int smp_call_function(void (*func)(void *info), void *info, | |||
630 | udelay(1); | 792 | udelay(1); |
631 | } | 793 | } |
632 | 794 | ||
795 | out_unlock: | ||
633 | spin_unlock(&call_lock); | 796 | spin_unlock(&call_lock); |
634 | 797 | ||
635 | return 0; | 798 | return 0; |
636 | 799 | ||
637 | out_timeout: | 800 | out_timeout: |
638 | spin_unlock(&call_lock); | 801 | spin_unlock(&call_lock); |
639 | printk("XCALL: Remote cpus not responding, ncpus=%ld finished=%ld\n", | 802 | printk("XCALL: Remote cpus not responding, ncpus=%d finished=%d\n", |
640 | (long) num_online_cpus() - 1L, | 803 | cpus, atomic_read(&data.finished)); |
641 | (long) atomic_read(&data.finished)); | ||
642 | return 0; | 804 | return 0; |
643 | } | 805 | } |
644 | 806 | ||
807 | int smp_call_function(void (*func)(void *info), void *info, | ||
808 | int nonatomic, int wait) | ||
809 | { | ||
810 | return smp_call_function_mask(func, info, nonatomic, wait, | ||
811 | cpu_online_map); | ||
812 | } | ||
813 | |||
645 | void smp_call_function_client(int irq, struct pt_regs *regs) | 814 | void smp_call_function_client(int irq, struct pt_regs *regs) |
646 | { | 815 | { |
647 | void (*func) (void *info) = call_data->func; | 816 | void (*func) (void *info) = call_data->func; |
@@ -659,13 +828,25 @@ void smp_call_function_client(int irq, struct pt_regs *regs) | |||
659 | } | 828 | } |
660 | } | 829 | } |
661 | 830 | ||
831 | static void tsb_sync(void *info) | ||
832 | { | ||
833 | struct mm_struct *mm = info; | ||
834 | |||
835 | if (current->active_mm == mm) | ||
836 | tsb_context_switch(mm); | ||
837 | } | ||
838 | |||
839 | void smp_tsb_sync(struct mm_struct *mm) | ||
840 | { | ||
841 | smp_call_function_mask(tsb_sync, mm, 0, 1, mm->cpu_vm_mask); | ||
842 | } | ||
843 | |||
662 | extern unsigned long xcall_flush_tlb_mm; | 844 | extern unsigned long xcall_flush_tlb_mm; |
663 | extern unsigned long xcall_flush_tlb_pending; | 845 | extern unsigned long xcall_flush_tlb_pending; |
664 | extern unsigned long xcall_flush_tlb_kernel_range; | 846 | extern unsigned long xcall_flush_tlb_kernel_range; |
665 | extern unsigned long xcall_flush_tlb_all_spitfire; | ||
666 | extern unsigned long xcall_flush_tlb_all_cheetah; | ||
667 | extern unsigned long xcall_report_regs; | 847 | extern unsigned long xcall_report_regs; |
668 | extern unsigned long xcall_receive_signal; | 848 | extern unsigned long xcall_receive_signal; |
849 | extern unsigned long xcall_new_mmu_context_version; | ||
669 | 850 | ||
670 | #ifdef DCACHE_ALIASING_POSSIBLE | 851 | #ifdef DCACHE_ALIASING_POSSIBLE |
671 | extern unsigned long xcall_flush_dcache_page_cheetah; | 852 | extern unsigned long xcall_flush_dcache_page_cheetah; |
@@ -693,11 +874,17 @@ static __inline__ void __local_flush_dcache_page(struct page *page) | |||
693 | void smp_flush_dcache_page_impl(struct page *page, int cpu) | 874 | void smp_flush_dcache_page_impl(struct page *page, int cpu) |
694 | { | 875 | { |
695 | cpumask_t mask = cpumask_of_cpu(cpu); | 876 | cpumask_t mask = cpumask_of_cpu(cpu); |
696 | int this_cpu = get_cpu(); | 877 | int this_cpu; |
878 | |||
879 | if (tlb_type == hypervisor) | ||
880 | return; | ||
697 | 881 | ||
698 | #ifdef CONFIG_DEBUG_DCFLUSH | 882 | #ifdef CONFIG_DEBUG_DCFLUSH |
699 | atomic_inc(&dcpage_flushes); | 883 | atomic_inc(&dcpage_flushes); |
700 | #endif | 884 | #endif |
885 | |||
886 | this_cpu = get_cpu(); | ||
887 | |||
701 | if (cpu == this_cpu) { | 888 | if (cpu == this_cpu) { |
702 | __local_flush_dcache_page(page); | 889 | __local_flush_dcache_page(page); |
703 | } else if (cpu_online(cpu)) { | 890 | } else if (cpu_online(cpu)) { |
@@ -713,7 +900,7 @@ void smp_flush_dcache_page_impl(struct page *page, int cpu) | |||
713 | __pa(pg_addr), | 900 | __pa(pg_addr), |
714 | (u64) pg_addr, | 901 | (u64) pg_addr, |
715 | mask); | 902 | mask); |
716 | } else { | 903 | } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { |
717 | #ifdef DCACHE_ALIASING_POSSIBLE | 904 | #ifdef DCACHE_ALIASING_POSSIBLE |
718 | data0 = | 905 | data0 = |
719 | ((u64)&xcall_flush_dcache_page_cheetah); | 906 | ((u64)&xcall_flush_dcache_page_cheetah); |
@@ -735,7 +922,12 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page) | |||
735 | void *pg_addr = page_address(page); | 922 | void *pg_addr = page_address(page); |
736 | cpumask_t mask = cpu_online_map; | 923 | cpumask_t mask = cpu_online_map; |
737 | u64 data0; | 924 | u64 data0; |
738 | int this_cpu = get_cpu(); | 925 | int this_cpu; |
926 | |||
927 | if (tlb_type == hypervisor) | ||
928 | return; | ||
929 | |||
930 | this_cpu = get_cpu(); | ||
739 | 931 | ||
740 | cpu_clear(this_cpu, mask); | 932 | cpu_clear(this_cpu, mask); |
741 | 933 | ||
@@ -752,7 +944,7 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page) | |||
752 | __pa(pg_addr), | 944 | __pa(pg_addr), |
753 | (u64) pg_addr, | 945 | (u64) pg_addr, |
754 | mask); | 946 | mask); |
755 | } else { | 947 | } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { |
756 | #ifdef DCACHE_ALIASING_POSSIBLE | 948 | #ifdef DCACHE_ALIASING_POSSIBLE |
757 | data0 = ((u64)&xcall_flush_dcache_page_cheetah); | 949 | data0 = ((u64)&xcall_flush_dcache_page_cheetah); |
758 | cheetah_xcall_deliver(data0, | 950 | cheetah_xcall_deliver(data0, |
@@ -769,38 +961,58 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page) | |||
769 | put_cpu(); | 961 | put_cpu(); |
770 | } | 962 | } |
771 | 963 | ||
964 | static void __smp_receive_signal_mask(cpumask_t mask) | ||
965 | { | ||
966 | smp_cross_call_masked(&xcall_receive_signal, 0, 0, 0, mask); | ||
967 | } | ||
968 | |||
772 | void smp_receive_signal(int cpu) | 969 | void smp_receive_signal(int cpu) |
773 | { | 970 | { |
774 | cpumask_t mask = cpumask_of_cpu(cpu); | 971 | cpumask_t mask = cpumask_of_cpu(cpu); |
775 | 972 | ||
776 | if (cpu_online(cpu)) { | 973 | if (cpu_online(cpu)) |
777 | u64 data0 = (((u64)&xcall_receive_signal) & 0xffffffff); | 974 | __smp_receive_signal_mask(mask); |
778 | |||
779 | if (tlb_type == spitfire) | ||
780 | spitfire_xcall_deliver(data0, 0, 0, mask); | ||
781 | else | ||
782 | cheetah_xcall_deliver(data0, 0, 0, mask); | ||
783 | } | ||
784 | } | 975 | } |
785 | 976 | ||
786 | void smp_receive_signal_client(int irq, struct pt_regs *regs) | 977 | void smp_receive_signal_client(int irq, struct pt_regs *regs) |
787 | { | 978 | { |
788 | /* Just return, rtrap takes care of the rest. */ | ||
789 | clear_softint(1 << irq); | 979 | clear_softint(1 << irq); |
790 | } | 980 | } |
791 | 981 | ||
792 | void smp_report_regs(void) | 982 | void smp_new_mmu_context_version_client(int irq, struct pt_regs *regs) |
793 | { | 983 | { |
794 | smp_cross_call(&xcall_report_regs, 0, 0, 0); | 984 | struct mm_struct *mm; |
985 | unsigned long flags; | ||
986 | |||
987 | clear_softint(1 << irq); | ||
988 | |||
989 | /* See if we need to allocate a new TLB context because | ||
990 | * the version of the one we are using is now out of date. | ||
991 | */ | ||
992 | mm = current->active_mm; | ||
993 | if (unlikely(!mm || (mm == &init_mm))) | ||
994 | return; | ||
995 | |||
996 | spin_lock_irqsave(&mm->context.lock, flags); | ||
997 | |||
998 | if (unlikely(!CTX_VALID(mm->context))) | ||
999 | get_new_mmu_context(mm); | ||
1000 | |||
1001 | spin_unlock_irqrestore(&mm->context.lock, flags); | ||
1002 | |||
1003 | load_secondary_context(mm); | ||
1004 | __flush_tlb_mm(CTX_HWBITS(mm->context), | ||
1005 | SECONDARY_CONTEXT); | ||
795 | } | 1006 | } |
796 | 1007 | ||
797 | void smp_flush_tlb_all(void) | 1008 | void smp_new_mmu_context_version(void) |
798 | { | 1009 | { |
799 | if (tlb_type == spitfire) | 1010 | smp_cross_call(&xcall_new_mmu_context_version, 0, 0, 0); |
800 | smp_cross_call(&xcall_flush_tlb_all_spitfire, 0, 0, 0); | 1011 | } |
801 | else | 1012 | |
802 | smp_cross_call(&xcall_flush_tlb_all_cheetah, 0, 0, 0); | 1013 | void smp_report_regs(void) |
803 | __flush_tlb_all(); | 1014 | { |
1015 | smp_cross_call(&xcall_report_regs, 0, 0, 0); | ||
804 | } | 1016 | } |
805 | 1017 | ||
806 | /* We know that the window frames of the user have been flushed | 1018 | /* We know that the window frames of the user have been flushed |
@@ -944,24 +1156,19 @@ void smp_release(void) | |||
944 | * can service tlb flush xcalls... | 1156 | * can service tlb flush xcalls... |
945 | */ | 1157 | */ |
946 | extern void prom_world(int); | 1158 | extern void prom_world(int); |
947 | extern void save_alternate_globals(unsigned long *); | 1159 | |
948 | extern void restore_alternate_globals(unsigned long *); | ||
949 | void smp_penguin_jailcell(int irq, struct pt_regs *regs) | 1160 | void smp_penguin_jailcell(int irq, struct pt_regs *regs) |
950 | { | 1161 | { |
951 | unsigned long global_save[24]; | ||
952 | |||
953 | clear_softint(1 << irq); | 1162 | clear_softint(1 << irq); |
954 | 1163 | ||
955 | preempt_disable(); | 1164 | preempt_disable(); |
956 | 1165 | ||
957 | __asm__ __volatile__("flushw"); | 1166 | __asm__ __volatile__("flushw"); |
958 | save_alternate_globals(global_save); | ||
959 | prom_world(1); | 1167 | prom_world(1); |
960 | atomic_inc(&smp_capture_registry); | 1168 | atomic_inc(&smp_capture_registry); |
961 | membar_storeload_storestore(); | 1169 | membar_storeload_storestore(); |
962 | while (penguins_are_doing_time) | 1170 | while (penguins_are_doing_time) |
963 | rmb(); | 1171 | rmb(); |
964 | restore_alternate_globals(global_save); | ||
965 | atomic_dec(&smp_capture_registry); | 1172 | atomic_dec(&smp_capture_registry); |
966 | prom_world(0); | 1173 | prom_world(0); |
967 | 1174 | ||
@@ -1071,7 +1278,7 @@ int setup_profiling_timer(unsigned int multiplier) | |||
1071 | return -EINVAL; | 1278 | return -EINVAL; |
1072 | 1279 | ||
1073 | spin_lock_irqsave(&prof_setup_lock, flags); | 1280 | spin_lock_irqsave(&prof_setup_lock, flags); |
1074 | for (i = 0; i < NR_CPUS; i++) | 1281 | for_each_cpu(i) |
1075 | prof_multiplier(i) = multiplier; | 1282 | prof_multiplier(i) = multiplier; |
1076 | current_tick_offset = (timer_tick_offset / multiplier); | 1283 | current_tick_offset = (timer_tick_offset / multiplier); |
1077 | spin_unlock_irqrestore(&prof_setup_lock, flags); | 1284 | spin_unlock_irqrestore(&prof_setup_lock, flags); |
@@ -1082,6 +1289,8 @@ int setup_profiling_timer(unsigned int multiplier) | |||
1082 | /* Constrain the number of cpus to max_cpus. */ | 1289 | /* Constrain the number of cpus to max_cpus. */ |
1083 | void __init smp_prepare_cpus(unsigned int max_cpus) | 1290 | void __init smp_prepare_cpus(unsigned int max_cpus) |
1084 | { | 1291 | { |
1292 | int i; | ||
1293 | |||
1085 | if (num_possible_cpus() > max_cpus) { | 1294 | if (num_possible_cpus() > max_cpus) { |
1086 | int instance, mid; | 1295 | int instance, mid; |
1087 | 1296 | ||
@@ -1089,6 +1298,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus) | |||
1089 | while (!cpu_find_by_instance(instance, NULL, &mid)) { | 1298 | while (!cpu_find_by_instance(instance, NULL, &mid)) { |
1090 | if (mid != boot_cpu_id) { | 1299 | if (mid != boot_cpu_id) { |
1091 | cpu_clear(mid, phys_cpu_present_map); | 1300 | cpu_clear(mid, phys_cpu_present_map); |
1301 | cpu_clear(mid, cpu_present_map); | ||
1092 | if (num_possible_cpus() <= max_cpus) | 1302 | if (num_possible_cpus() <= max_cpus) |
1093 | break; | 1303 | break; |
1094 | } | 1304 | } |
@@ -1096,6 +1306,20 @@ void __init smp_prepare_cpus(unsigned int max_cpus) | |||
1096 | } | 1306 | } |
1097 | } | 1307 | } |
1098 | 1308 | ||
1309 | for_each_cpu(i) { | ||
1310 | if (tlb_type == hypervisor) { | ||
1311 | int j; | ||
1312 | |||
1313 | /* XXX get this mapping from machine description */ | ||
1314 | for_each_cpu(j) { | ||
1315 | if ((j >> 2) == (i >> 2)) | ||
1316 | cpu_set(j, cpu_sibling_map[i]); | ||
1317 | } | ||
1318 | } else { | ||
1319 | cpu_set(i, cpu_sibling_map[i]); | ||
1320 | } | ||
1321 | } | ||
1322 | |||
1099 | smp_store_cpu_info(boot_cpu_id); | 1323 | smp_store_cpu_info(boot_cpu_id); |
1100 | } | 1324 | } |
1101 | 1325 | ||
@@ -1109,20 +1333,25 @@ void __init smp_setup_cpu_possible_map(void) | |||
1109 | 1333 | ||
1110 | instance = 0; | 1334 | instance = 0; |
1111 | while (!cpu_find_by_instance(instance, NULL, &mid)) { | 1335 | while (!cpu_find_by_instance(instance, NULL, &mid)) { |
1112 | if (mid < NR_CPUS) | 1336 | if (mid < NR_CPUS) { |
1113 | cpu_set(mid, phys_cpu_present_map); | 1337 | cpu_set(mid, phys_cpu_present_map); |
1338 | cpu_set(mid, cpu_present_map); | ||
1339 | } | ||
1114 | instance++; | 1340 | instance++; |
1115 | } | 1341 | } |
1116 | } | 1342 | } |
1117 | 1343 | ||
1118 | void __devinit smp_prepare_boot_cpu(void) | 1344 | void __devinit smp_prepare_boot_cpu(void) |
1119 | { | 1345 | { |
1120 | if (hard_smp_processor_id() >= NR_CPUS) { | 1346 | int cpu = hard_smp_processor_id(); |
1347 | |||
1348 | if (cpu >= NR_CPUS) { | ||
1121 | prom_printf("Serious problem, boot cpu id >= NR_CPUS\n"); | 1349 | prom_printf("Serious problem, boot cpu id >= NR_CPUS\n"); |
1122 | prom_halt(); | 1350 | prom_halt(); |
1123 | } | 1351 | } |
1124 | 1352 | ||
1125 | current_thread_info()->cpu = hard_smp_processor_id(); | 1353 | current_thread_info()->cpu = cpu; |
1354 | __local_per_cpu_offset = __per_cpu_offset(cpu); | ||
1126 | 1355 | ||
1127 | cpu_set(smp_processor_id(), cpu_online_map); | 1356 | cpu_set(smp_processor_id(), cpu_online_map); |
1128 | cpu_set(smp_processor_id(), phys_cpu_present_map); | 1357 | cpu_set(smp_processor_id(), phys_cpu_present_map); |
@@ -1139,7 +1368,11 @@ int __devinit __cpu_up(unsigned int cpu) | |||
1139 | if (!cpu_isset(cpu, cpu_online_map)) { | 1368 | if (!cpu_isset(cpu, cpu_online_map)) { |
1140 | ret = -ENODEV; | 1369 | ret = -ENODEV; |
1141 | } else { | 1370 | } else { |
1142 | smp_synchronize_one_tick(cpu); | 1371 | /* On SUN4V, writes to %tick and %stick are |
1372 | * not allowed. | ||
1373 | */ | ||
1374 | if (tlb_type != hypervisor) | ||
1375 | smp_synchronize_one_tick(cpu); | ||
1143 | } | 1376 | } |
1144 | } | 1377 | } |
1145 | return ret; | 1378 | return ret; |
@@ -1150,10 +1383,8 @@ void __init smp_cpus_done(unsigned int max_cpus) | |||
1150 | unsigned long bogosum = 0; | 1383 | unsigned long bogosum = 0; |
1151 | int i; | 1384 | int i; |
1152 | 1385 | ||
1153 | for (i = 0; i < NR_CPUS; i++) { | 1386 | for_each_online_cpu(i) |
1154 | if (cpu_online(i)) | 1387 | bogosum += cpu_data(i).udelay_val; |
1155 | bogosum += cpu_data(i).udelay_val; | ||
1156 | } | ||
1157 | printk("Total of %ld processors activated " | 1388 | printk("Total of %ld processors activated " |
1158 | "(%lu.%02lu BogoMIPS).\n", | 1389 | "(%lu.%02lu BogoMIPS).\n", |
1159 | (long) num_online_cpus(), | 1390 | (long) num_online_cpus(), |
@@ -1183,12 +1414,9 @@ void __init setup_per_cpu_areas(void) | |||
1183 | { | 1414 | { |
1184 | unsigned long goal, size, i; | 1415 | unsigned long goal, size, i; |
1185 | char *ptr; | 1416 | char *ptr; |
1186 | /* Created by linker magic */ | ||
1187 | extern char __per_cpu_start[], __per_cpu_end[]; | ||
1188 | 1417 | ||
1189 | /* Copy section for each CPU (we discard the original) */ | 1418 | /* Copy section for each CPU (we discard the original) */ |
1190 | goal = ALIGN(__per_cpu_end - __per_cpu_start, PAGE_SIZE); | 1419 | goal = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES); |
1191 | |||
1192 | #ifdef CONFIG_MODULES | 1420 | #ifdef CONFIG_MODULES |
1193 | if (goal < PERCPU_ENOUGH_ROOM) | 1421 | if (goal < PERCPU_ENOUGH_ROOM) |
1194 | goal = PERCPU_ENOUGH_ROOM; | 1422 | goal = PERCPU_ENOUGH_ROOM; |
@@ -1197,31 +1425,10 @@ void __init setup_per_cpu_areas(void) | |||
1197 | for (size = 1UL; size < goal; size <<= 1UL) | 1425 | for (size = 1UL; size < goal; size <<= 1UL) |
1198 | __per_cpu_shift++; | 1426 | __per_cpu_shift++; |
1199 | 1427 | ||
1200 | /* Make sure the resulting __per_cpu_base value | 1428 | ptr = alloc_bootmem(size * NR_CPUS); |
1201 | * will fit in the 43-bit sign extended IMMU | ||
1202 | * TSB register. | ||
1203 | */ | ||
1204 | ptr = __alloc_bootmem(size * NR_CPUS, PAGE_SIZE, | ||
1205 | (unsigned long) __per_cpu_start); | ||
1206 | 1429 | ||
1207 | __per_cpu_base = ptr - __per_cpu_start; | 1430 | __per_cpu_base = ptr - __per_cpu_start; |
1208 | 1431 | ||
1209 | if ((__per_cpu_shift < PAGE_SHIFT) || | ||
1210 | (__per_cpu_base & ~PAGE_MASK) || | ||
1211 | (__per_cpu_base != (((long) __per_cpu_base << 20) >> 20))) { | ||
1212 | prom_printf("PER_CPU: Invalid layout, " | ||
1213 | "ptr[%p] shift[%lx] base[%lx]\n", | ||
1214 | ptr, __per_cpu_shift, __per_cpu_base); | ||
1215 | prom_halt(); | ||
1216 | } | ||
1217 | |||
1218 | for (i = 0; i < NR_CPUS; i++, ptr += size) | 1432 | for (i = 0; i < NR_CPUS; i++, ptr += size) |
1219 | memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); | 1433 | memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); |
1220 | |||
1221 | /* Finally, load in the boot cpu's base value. | ||
1222 | * We abuse the IMMU TSB register for trap handler | ||
1223 | * entry and exit loading of %g5. That is why it | ||
1224 | * has to be page aligned. | ||
1225 | */ | ||
1226 | cpu_setup_percpu_base(hard_smp_processor_id()); | ||
1227 | } | 1434 | } |