diff options
Diffstat (limited to 'arch/sparc64/kernel/smp.c')
-rw-r--r-- | arch/sparc64/kernel/smp.c | 418 |
1 files changed, 314 insertions, 104 deletions
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 1f7ad8a69052..373a701c90a5 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 | ||
@@ -77,7 +80,7 @@ void smp_bogo(struct seq_file *m) | |||
77 | 80 | ||
78 | void __init smp_store_cpu_info(int id) | 81 | void __init smp_store_cpu_info(int id) |
79 | { | 82 | { |
80 | int cpu_node; | 83 | int cpu_node, def; |
81 | 84 | ||
82 | /* multiplier and counter set by | 85 | /* multiplier and counter set by |
83 | smp_setup_percpu_timer() */ | 86 | smp_setup_percpu_timer() */ |
@@ -87,24 +90,32 @@ void __init smp_store_cpu_info(int id) | |||
87 | cpu_data(id).clock_tick = prom_getintdefault(cpu_node, | 90 | cpu_data(id).clock_tick = prom_getintdefault(cpu_node, |
88 | "clock-frequency", 0); | 91 | "clock-frequency", 0); |
89 | 92 | ||
90 | cpu_data(id).pgcache_size = 0; | 93 | 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", | 94 | cpu_data(id).dcache_size = prom_getintdefault(cpu_node, "dcache-size", |
97 | 16 * 1024); | 95 | def); |
96 | |||
97 | def = 32; | ||
98 | cpu_data(id).dcache_line_size = | 98 | cpu_data(id).dcache_line_size = |
99 | prom_getintdefault(cpu_node, "dcache-line-size", 32); | 99 | prom_getintdefault(cpu_node, "dcache-line-size", def); |
100 | |||
101 | def = 16 * 1024; | ||
100 | cpu_data(id).icache_size = prom_getintdefault(cpu_node, "icache-size", | 102 | cpu_data(id).icache_size = prom_getintdefault(cpu_node, "icache-size", |
101 | 16 * 1024); | 103 | def); |
104 | |||
105 | def = 32; | ||
102 | cpu_data(id).icache_line_size = | 106 | cpu_data(id).icache_line_size = |
103 | prom_getintdefault(cpu_node, "icache-line-size", 32); | 107 | prom_getintdefault(cpu_node, "icache-line-size", def); |
108 | |||
109 | def = ((tlb_type == hypervisor) ? | ||
110 | (3 * 1024 * 1024) : | ||
111 | (4 * 1024 * 1024)); | ||
104 | cpu_data(id).ecache_size = prom_getintdefault(cpu_node, "ecache-size", | 112 | cpu_data(id).ecache_size = prom_getintdefault(cpu_node, "ecache-size", |
105 | 4 * 1024 * 1024); | 113 | def); |
114 | |||
115 | def = 64; | ||
106 | cpu_data(id).ecache_line_size = | 116 | cpu_data(id).ecache_line_size = |
107 | prom_getintdefault(cpu_node, "ecache-line-size", 64); | 117 | prom_getintdefault(cpu_node, "ecache-line-size", def); |
118 | |||
108 | printk("CPU[%d]: Caches " | 119 | printk("CPU[%d]: Caches " |
109 | "D[sz(%d):line_sz(%d)] " | 120 | "D[sz(%d):line_sz(%d)] " |
110 | "I[sz(%d):line_sz(%d)] " | 121 | "I[sz(%d):line_sz(%d)] " |
@@ -119,27 +130,16 @@ static void smp_setup_percpu_timer(void); | |||
119 | 130 | ||
120 | static volatile unsigned long callin_flag = 0; | 131 | static volatile unsigned long callin_flag = 0; |
121 | 132 | ||
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) | 133 | void __init smp_callin(void) |
135 | { | 134 | { |
136 | int cpuid = hard_smp_processor_id(); | 135 | int cpuid = hard_smp_processor_id(); |
137 | 136 | ||
138 | inherit_locked_prom_mappings(0); | 137 | __local_per_cpu_offset = __per_cpu_offset(cpuid); |
139 | 138 | ||
140 | __flush_tlb_all(); | 139 | if (tlb_type == hypervisor) |
140 | sun4v_ktsb_register(); | ||
141 | 141 | ||
142 | cpu_setup_percpu_base(cpuid); | 142 | __flush_tlb_all(); |
143 | 143 | ||
144 | smp_setup_percpu_timer(); | 144 | smp_setup_percpu_timer(); |
145 | 145 | ||
@@ -316,6 +316,8 @@ static void smp_synchronize_one_tick(int cpu) | |||
316 | spin_unlock_irqrestore(&itc_sync_lock, flags); | 316 | spin_unlock_irqrestore(&itc_sync_lock, flags); |
317 | } | 317 | } |
318 | 318 | ||
319 | extern void sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int load); | ||
320 | |||
319 | extern unsigned long sparc64_cpu_startup; | 321 | extern unsigned long sparc64_cpu_startup; |
320 | 322 | ||
321 | /* The OBP cpu startup callback truncates the 3rd arg cookie to | 323 | /* The OBP cpu startup callback truncates the 3rd arg cookie to |
@@ -331,21 +333,31 @@ static int __devinit smp_boot_one_cpu(unsigned int cpu) | |||
331 | unsigned long cookie = | 333 | unsigned long cookie = |
332 | (unsigned long)(&cpu_new_thread); | 334 | (unsigned long)(&cpu_new_thread); |
333 | struct task_struct *p; | 335 | struct task_struct *p; |
334 | int timeout, ret, cpu_node; | 336 | int timeout, ret; |
335 | 337 | ||
336 | p = fork_idle(cpu); | 338 | p = fork_idle(cpu); |
337 | callin_flag = 0; | 339 | callin_flag = 0; |
338 | cpu_new_thread = task_thread_info(p); | 340 | cpu_new_thread = task_thread_info(p); |
339 | cpu_set(cpu, cpu_callout_map); | 341 | cpu_set(cpu, cpu_callout_map); |
340 | 342 | ||
341 | cpu_find_by_mid(cpu, &cpu_node); | 343 | if (tlb_type == hypervisor) { |
342 | prom_startcpu(cpu_node, entry, cookie); | 344 | /* Alloc the mondo queues, cpu will load them. */ |
345 | sun4v_init_mondo_queues(0, cpu, 1, 0); | ||
346 | |||
347 | prom_startcpu_cpuid(cpu, entry, cookie); | ||
348 | } else { | ||
349 | int cpu_node; | ||
350 | |||
351 | cpu_find_by_mid(cpu, &cpu_node); | ||
352 | prom_startcpu(cpu_node, entry, cookie); | ||
353 | } | ||
343 | 354 | ||
344 | for (timeout = 0; timeout < 5000000; timeout++) { | 355 | for (timeout = 0; timeout < 5000000; timeout++) { |
345 | if (callin_flag) | 356 | if (callin_flag) |
346 | break; | 357 | break; |
347 | udelay(100); | 358 | udelay(100); |
348 | } | 359 | } |
360 | |||
349 | if (callin_flag) { | 361 | if (callin_flag) { |
350 | ret = 0; | 362 | ret = 0; |
351 | } else { | 363 | } else { |
@@ -441,7 +453,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) | 453 | static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask) |
442 | { | 454 | { |
443 | u64 pstate, ver; | 455 | u64 pstate, ver; |
444 | int nack_busy_id, is_jalapeno; | 456 | int nack_busy_id, is_jbus; |
445 | 457 | ||
446 | if (cpus_empty(mask)) | 458 | if (cpus_empty(mask)) |
447 | return; | 459 | return; |
@@ -451,7 +463,8 @@ static void cheetah_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mas | |||
451 | * derivative processor. | 463 | * derivative processor. |
452 | */ | 464 | */ |
453 | __asm__ ("rdpr %%ver, %0" : "=r" (ver)); | 465 | __asm__ ("rdpr %%ver, %0" : "=r" (ver)); |
454 | is_jalapeno = ((ver >> 32) == 0x003e0016); | 466 | is_jbus = ((ver >> 32) == __JALAPENO_ID || |
467 | (ver >> 32) == __SERRANO_ID); | ||
455 | 468 | ||
456 | __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); | 469 | __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); |
457 | 470 | ||
@@ -476,7 +489,7 @@ retry: | |||
476 | for_each_cpu_mask(i, mask) { | 489 | for_each_cpu_mask(i, mask) { |
477 | u64 target = (i << 14) | 0x70; | 490 | u64 target = (i << 14) | 0x70; |
478 | 491 | ||
479 | if (!is_jalapeno) | 492 | if (!is_jbus) |
480 | target |= (nack_busy_id << 24); | 493 | target |= (nack_busy_id << 24); |
481 | __asm__ __volatile__( | 494 | __asm__ __volatile__( |
482 | "stxa %%g0, [%0] %1\n\t" | 495 | "stxa %%g0, [%0] %1\n\t" |
@@ -529,7 +542,7 @@ retry: | |||
529 | for_each_cpu_mask(i, mask) { | 542 | for_each_cpu_mask(i, mask) { |
530 | u64 check_mask; | 543 | u64 check_mask; |
531 | 544 | ||
532 | if (is_jalapeno) | 545 | if (is_jbus) |
533 | check_mask = (0x2UL << (2*i)); | 546 | check_mask = (0x2UL << (2*i)); |
534 | else | 547 | else |
535 | check_mask = (0x2UL << | 548 | check_mask = (0x2UL << |
@@ -544,6 +557,155 @@ retry: | |||
544 | } | 557 | } |
545 | } | 558 | } |
546 | 559 | ||
560 | /* Multi-cpu list version. */ | ||
561 | static void hypervisor_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask) | ||
562 | { | ||
563 | struct trap_per_cpu *tb; | ||
564 | u16 *cpu_list; | ||
565 | u64 *mondo; | ||
566 | cpumask_t error_mask; | ||
567 | unsigned long flags, status; | ||
568 | int cnt, retries, this_cpu, prev_sent, i; | ||
569 | |||
570 | /* We have to do this whole thing with interrupts fully disabled. | ||
571 | * Otherwise if we send an xcall from interrupt context it will | ||
572 | * corrupt both our mondo block and cpu list state. | ||
573 | * | ||
574 | * One consequence of this is that we cannot use timeout mechanisms | ||
575 | * that depend upon interrupts being delivered locally. So, for | ||
576 | * example, we cannot sample jiffies and expect it to advance. | ||
577 | * | ||
578 | * Fortunately, udelay() uses %stick/%tick so we can use that. | ||
579 | */ | ||
580 | local_irq_save(flags); | ||
581 | |||
582 | this_cpu = smp_processor_id(); | ||
583 | tb = &trap_block[this_cpu]; | ||
584 | |||
585 | mondo = __va(tb->cpu_mondo_block_pa); | ||
586 | mondo[0] = data0; | ||
587 | mondo[1] = data1; | ||
588 | mondo[2] = data2; | ||
589 | wmb(); | ||
590 | |||
591 | cpu_list = __va(tb->cpu_list_pa); | ||
592 | |||
593 | /* Setup the initial cpu list. */ | ||
594 | cnt = 0; | ||
595 | for_each_cpu_mask(i, mask) | ||
596 | cpu_list[cnt++] = i; | ||
597 | |||
598 | cpus_clear(error_mask); | ||
599 | retries = 0; | ||
600 | prev_sent = 0; | ||
601 | do { | ||
602 | int forward_progress, n_sent; | ||
603 | |||
604 | status = sun4v_cpu_mondo_send(cnt, | ||
605 | tb->cpu_list_pa, | ||
606 | tb->cpu_mondo_block_pa); | ||
607 | |||
608 | /* HV_EOK means all cpus received the xcall, we're done. */ | ||
609 | if (likely(status == HV_EOK)) | ||
610 | break; | ||
611 | |||
612 | /* First, see if we made any forward progress. | ||
613 | * | ||
614 | * The hypervisor indicates successful sends by setting | ||
615 | * cpu list entries to the value 0xffff. | ||
616 | */ | ||
617 | n_sent = 0; | ||
618 | for (i = 0; i < cnt; i++) { | ||
619 | if (likely(cpu_list[i] == 0xffff)) | ||
620 | n_sent++; | ||
621 | } | ||
622 | |||
623 | forward_progress = 0; | ||
624 | if (n_sent > prev_sent) | ||
625 | forward_progress = 1; | ||
626 | |||
627 | prev_sent = n_sent; | ||
628 | |||
629 | /* If we get a HV_ECPUERROR, then one or more of the cpus | ||
630 | * in the list are in error state. Use the cpu_state() | ||
631 | * hypervisor call to find out which cpus are in error state. | ||
632 | */ | ||
633 | if (unlikely(status == HV_ECPUERROR)) { | ||
634 | for (i = 0; i < cnt; i++) { | ||
635 | long err; | ||
636 | u16 cpu; | ||
637 | |||
638 | cpu = cpu_list[i]; | ||
639 | if (cpu == 0xffff) | ||
640 | continue; | ||
641 | |||
642 | err = sun4v_cpu_state(cpu); | ||
643 | if (err >= 0 && | ||
644 | err == HV_CPU_STATE_ERROR) { | ||
645 | cpu_list[i] = 0xffff; | ||
646 | cpu_set(cpu, error_mask); | ||
647 | } | ||
648 | } | ||
649 | } else if (unlikely(status != HV_EWOULDBLOCK)) | ||
650 | goto fatal_mondo_error; | ||
651 | |||
652 | /* Don't bother rewriting the CPU list, just leave the | ||
653 | * 0xffff and non-0xffff entries in there and the | ||
654 | * hypervisor will do the right thing. | ||
655 | * | ||
656 | * Only advance timeout state if we didn't make any | ||
657 | * forward progress. | ||
658 | */ | ||
659 | if (unlikely(!forward_progress)) { | ||
660 | if (unlikely(++retries > 10000)) | ||
661 | goto fatal_mondo_timeout; | ||
662 | |||
663 | /* Delay a little bit to let other cpus catch up | ||
664 | * on their cpu mondo queue work. | ||
665 | */ | ||
666 | udelay(2 * cnt); | ||
667 | } | ||
668 | } while (1); | ||
669 | |||
670 | local_irq_restore(flags); | ||
671 | |||
672 | if (unlikely(!cpus_empty(error_mask))) | ||
673 | goto fatal_mondo_cpu_error; | ||
674 | |||
675 | return; | ||
676 | |||
677 | fatal_mondo_cpu_error: | ||
678 | printk(KERN_CRIT "CPU[%d]: SUN4V mondo cpu error, some target cpus " | ||
679 | "were in error state\n", | ||
680 | this_cpu); | ||
681 | printk(KERN_CRIT "CPU[%d]: Error mask [ ", this_cpu); | ||
682 | for_each_cpu_mask(i, error_mask) | ||
683 | printk("%d ", i); | ||
684 | printk("]\n"); | ||
685 | return; | ||
686 | |||
687 | fatal_mondo_timeout: | ||
688 | local_irq_restore(flags); | ||
689 | printk(KERN_CRIT "CPU[%d]: SUN4V mondo timeout, no forward " | ||
690 | " progress after %d retries.\n", | ||
691 | this_cpu, retries); | ||
692 | goto dump_cpu_list_and_out; | ||
693 | |||
694 | fatal_mondo_error: | ||
695 | local_irq_restore(flags); | ||
696 | printk(KERN_CRIT "CPU[%d]: Unexpected SUN4V mondo error %lu\n", | ||
697 | this_cpu, status); | ||
698 | printk(KERN_CRIT "CPU[%d]: Args were cnt(%d) cpulist_pa(%lx) " | ||
699 | "mondo_block_pa(%lx)\n", | ||
700 | this_cpu, cnt, tb->cpu_list_pa, tb->cpu_mondo_block_pa); | ||
701 | |||
702 | dump_cpu_list_and_out: | ||
703 | printk(KERN_CRIT "CPU[%d]: CPU list [ ", this_cpu); | ||
704 | for (i = 0; i < cnt; i++) | ||
705 | printk("%u ", cpu_list[i]); | ||
706 | printk("]\n"); | ||
707 | } | ||
708 | |||
547 | /* Send cross call to all processors mentioned in MASK | 709 | /* Send cross call to all processors mentioned in MASK |
548 | * except self. | 710 | * except self. |
549 | */ | 711 | */ |
@@ -557,8 +719,10 @@ static void smp_cross_call_masked(unsigned long *func, u32 ctx, u64 data1, u64 d | |||
557 | 719 | ||
558 | if (tlb_type == spitfire) | 720 | if (tlb_type == spitfire) |
559 | spitfire_xcall_deliver(data0, data1, data2, mask); | 721 | spitfire_xcall_deliver(data0, data1, data2, mask); |
560 | else | 722 | else if (tlb_type == cheetah || tlb_type == cheetah_plus) |
561 | cheetah_xcall_deliver(data0, data1, data2, mask); | 723 | cheetah_xcall_deliver(data0, data1, data2, mask); |
724 | else | ||
725 | hypervisor_xcall_deliver(data0, data1, data2, mask); | ||
562 | /* NOTE: Caller runs local copy on master. */ | 726 | /* NOTE: Caller runs local copy on master. */ |
563 | 727 | ||
564 | put_cpu(); | 728 | put_cpu(); |
@@ -594,16 +758,13 @@ extern unsigned long xcall_call_function; | |||
594 | * You must not call this function with disabled interrupts or from a | 758 | * You must not call this function with disabled interrupts or from a |
595 | * hardware interrupt handler or from a bottom half handler. | 759 | * hardware interrupt handler or from a bottom half handler. |
596 | */ | 760 | */ |
597 | int smp_call_function(void (*func)(void *info), void *info, | 761 | static int smp_call_function_mask(void (*func)(void *info), void *info, |
598 | int nonatomic, int wait) | 762 | int nonatomic, int wait, cpumask_t mask) |
599 | { | 763 | { |
600 | struct call_data_struct data; | 764 | struct call_data_struct data; |
601 | int cpus = num_online_cpus() - 1; | 765 | int cpus; |
602 | long timeout; | 766 | long timeout; |
603 | 767 | ||
604 | if (!cpus) | ||
605 | return 0; | ||
606 | |||
607 | /* Can deadlock when called with interrupts disabled */ | 768 | /* Can deadlock when called with interrupts disabled */ |
608 | WARN_ON(irqs_disabled()); | 769 | WARN_ON(irqs_disabled()); |
609 | 770 | ||
@@ -614,9 +775,14 @@ int smp_call_function(void (*func)(void *info), void *info, | |||
614 | 775 | ||
615 | spin_lock(&call_lock); | 776 | spin_lock(&call_lock); |
616 | 777 | ||
778 | cpu_clear(smp_processor_id(), mask); | ||
779 | cpus = cpus_weight(mask); | ||
780 | if (!cpus) | ||
781 | goto out_unlock; | ||
782 | |||
617 | call_data = &data; | 783 | call_data = &data; |
618 | 784 | ||
619 | smp_cross_call(&xcall_call_function, 0, 0, 0); | 785 | smp_cross_call_masked(&xcall_call_function, 0, 0, 0, mask); |
620 | 786 | ||
621 | /* | 787 | /* |
622 | * Wait for other cpus to complete function or at | 788 | * Wait for other cpus to complete function or at |
@@ -630,18 +796,25 @@ int smp_call_function(void (*func)(void *info), void *info, | |||
630 | udelay(1); | 796 | udelay(1); |
631 | } | 797 | } |
632 | 798 | ||
799 | out_unlock: | ||
633 | spin_unlock(&call_lock); | 800 | spin_unlock(&call_lock); |
634 | 801 | ||
635 | return 0; | 802 | return 0; |
636 | 803 | ||
637 | out_timeout: | 804 | out_timeout: |
638 | spin_unlock(&call_lock); | 805 | spin_unlock(&call_lock); |
639 | printk("XCALL: Remote cpus not responding, ncpus=%ld finished=%ld\n", | 806 | printk("XCALL: Remote cpus not responding, ncpus=%d finished=%d\n", |
640 | (long) num_online_cpus() - 1L, | 807 | cpus, atomic_read(&data.finished)); |
641 | (long) atomic_read(&data.finished)); | ||
642 | return 0; | 808 | return 0; |
643 | } | 809 | } |
644 | 810 | ||
811 | int smp_call_function(void (*func)(void *info), void *info, | ||
812 | int nonatomic, int wait) | ||
813 | { | ||
814 | return smp_call_function_mask(func, info, nonatomic, wait, | ||
815 | cpu_online_map); | ||
816 | } | ||
817 | |||
645 | void smp_call_function_client(int irq, struct pt_regs *regs) | 818 | void smp_call_function_client(int irq, struct pt_regs *regs) |
646 | { | 819 | { |
647 | void (*func) (void *info) = call_data->func; | 820 | void (*func) (void *info) = call_data->func; |
@@ -659,13 +832,25 @@ void smp_call_function_client(int irq, struct pt_regs *regs) | |||
659 | } | 832 | } |
660 | } | 833 | } |
661 | 834 | ||
835 | static void tsb_sync(void *info) | ||
836 | { | ||
837 | struct mm_struct *mm = info; | ||
838 | |||
839 | if (current->active_mm == mm) | ||
840 | tsb_context_switch(mm); | ||
841 | } | ||
842 | |||
843 | void smp_tsb_sync(struct mm_struct *mm) | ||
844 | { | ||
845 | smp_call_function_mask(tsb_sync, mm, 0, 1, mm->cpu_vm_mask); | ||
846 | } | ||
847 | |||
662 | extern unsigned long xcall_flush_tlb_mm; | 848 | extern unsigned long xcall_flush_tlb_mm; |
663 | extern unsigned long xcall_flush_tlb_pending; | 849 | extern unsigned long xcall_flush_tlb_pending; |
664 | extern unsigned long xcall_flush_tlb_kernel_range; | 850 | 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; | 851 | extern unsigned long xcall_report_regs; |
668 | extern unsigned long xcall_receive_signal; | 852 | extern unsigned long xcall_receive_signal; |
853 | extern unsigned long xcall_new_mmu_context_version; | ||
669 | 854 | ||
670 | #ifdef DCACHE_ALIASING_POSSIBLE | 855 | #ifdef DCACHE_ALIASING_POSSIBLE |
671 | extern unsigned long xcall_flush_dcache_page_cheetah; | 856 | extern unsigned long xcall_flush_dcache_page_cheetah; |
@@ -693,11 +878,17 @@ static __inline__ void __local_flush_dcache_page(struct page *page) | |||
693 | void smp_flush_dcache_page_impl(struct page *page, int cpu) | 878 | void smp_flush_dcache_page_impl(struct page *page, int cpu) |
694 | { | 879 | { |
695 | cpumask_t mask = cpumask_of_cpu(cpu); | 880 | cpumask_t mask = cpumask_of_cpu(cpu); |
696 | int this_cpu = get_cpu(); | 881 | int this_cpu; |
882 | |||
883 | if (tlb_type == hypervisor) | ||
884 | return; | ||
697 | 885 | ||
698 | #ifdef CONFIG_DEBUG_DCFLUSH | 886 | #ifdef CONFIG_DEBUG_DCFLUSH |
699 | atomic_inc(&dcpage_flushes); | 887 | atomic_inc(&dcpage_flushes); |
700 | #endif | 888 | #endif |
889 | |||
890 | this_cpu = get_cpu(); | ||
891 | |||
701 | if (cpu == this_cpu) { | 892 | if (cpu == this_cpu) { |
702 | __local_flush_dcache_page(page); | 893 | __local_flush_dcache_page(page); |
703 | } else if (cpu_online(cpu)) { | 894 | } else if (cpu_online(cpu)) { |
@@ -713,7 +904,7 @@ void smp_flush_dcache_page_impl(struct page *page, int cpu) | |||
713 | __pa(pg_addr), | 904 | __pa(pg_addr), |
714 | (u64) pg_addr, | 905 | (u64) pg_addr, |
715 | mask); | 906 | mask); |
716 | } else { | 907 | } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { |
717 | #ifdef DCACHE_ALIASING_POSSIBLE | 908 | #ifdef DCACHE_ALIASING_POSSIBLE |
718 | data0 = | 909 | data0 = |
719 | ((u64)&xcall_flush_dcache_page_cheetah); | 910 | ((u64)&xcall_flush_dcache_page_cheetah); |
@@ -735,7 +926,12 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page) | |||
735 | void *pg_addr = page_address(page); | 926 | void *pg_addr = page_address(page); |
736 | cpumask_t mask = cpu_online_map; | 927 | cpumask_t mask = cpu_online_map; |
737 | u64 data0; | 928 | u64 data0; |
738 | int this_cpu = get_cpu(); | 929 | int this_cpu; |
930 | |||
931 | if (tlb_type == hypervisor) | ||
932 | return; | ||
933 | |||
934 | this_cpu = get_cpu(); | ||
739 | 935 | ||
740 | cpu_clear(this_cpu, mask); | 936 | cpu_clear(this_cpu, mask); |
741 | 937 | ||
@@ -752,7 +948,7 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page) | |||
752 | __pa(pg_addr), | 948 | __pa(pg_addr), |
753 | (u64) pg_addr, | 949 | (u64) pg_addr, |
754 | mask); | 950 | mask); |
755 | } else { | 951 | } else if (tlb_type == cheetah || tlb_type == cheetah_plus) { |
756 | #ifdef DCACHE_ALIASING_POSSIBLE | 952 | #ifdef DCACHE_ALIASING_POSSIBLE |
757 | data0 = ((u64)&xcall_flush_dcache_page_cheetah); | 953 | data0 = ((u64)&xcall_flush_dcache_page_cheetah); |
758 | cheetah_xcall_deliver(data0, | 954 | cheetah_xcall_deliver(data0, |
@@ -769,38 +965,58 @@ void flush_dcache_page_all(struct mm_struct *mm, struct page *page) | |||
769 | put_cpu(); | 965 | put_cpu(); |
770 | } | 966 | } |
771 | 967 | ||
968 | static void __smp_receive_signal_mask(cpumask_t mask) | ||
969 | { | ||
970 | smp_cross_call_masked(&xcall_receive_signal, 0, 0, 0, mask); | ||
971 | } | ||
972 | |||
772 | void smp_receive_signal(int cpu) | 973 | void smp_receive_signal(int cpu) |
773 | { | 974 | { |
774 | cpumask_t mask = cpumask_of_cpu(cpu); | 975 | cpumask_t mask = cpumask_of_cpu(cpu); |
775 | 976 | ||
776 | if (cpu_online(cpu)) { | 977 | if (cpu_online(cpu)) |
777 | u64 data0 = (((u64)&xcall_receive_signal) & 0xffffffff); | 978 | __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 | } | 979 | } |
785 | 980 | ||
786 | void smp_receive_signal_client(int irq, struct pt_regs *regs) | 981 | void smp_receive_signal_client(int irq, struct pt_regs *regs) |
787 | { | 982 | { |
788 | /* Just return, rtrap takes care of the rest. */ | ||
789 | clear_softint(1 << irq); | 983 | clear_softint(1 << irq); |
790 | } | 984 | } |
791 | 985 | ||
792 | void smp_report_regs(void) | 986 | void smp_new_mmu_context_version_client(int irq, struct pt_regs *regs) |
793 | { | 987 | { |
794 | smp_cross_call(&xcall_report_regs, 0, 0, 0); | 988 | struct mm_struct *mm; |
989 | unsigned long flags; | ||
990 | |||
991 | clear_softint(1 << irq); | ||
992 | |||
993 | /* See if we need to allocate a new TLB context because | ||
994 | * the version of the one we are using is now out of date. | ||
995 | */ | ||
996 | mm = current->active_mm; | ||
997 | if (unlikely(!mm || (mm == &init_mm))) | ||
998 | return; | ||
999 | |||
1000 | spin_lock_irqsave(&mm->context.lock, flags); | ||
1001 | |||
1002 | if (unlikely(!CTX_VALID(mm->context))) | ||
1003 | get_new_mmu_context(mm); | ||
1004 | |||
1005 | spin_unlock_irqrestore(&mm->context.lock, flags); | ||
1006 | |||
1007 | load_secondary_context(mm); | ||
1008 | __flush_tlb_mm(CTX_HWBITS(mm->context), | ||
1009 | SECONDARY_CONTEXT); | ||
795 | } | 1010 | } |
796 | 1011 | ||
797 | void smp_flush_tlb_all(void) | 1012 | void smp_new_mmu_context_version(void) |
798 | { | 1013 | { |
799 | if (tlb_type == spitfire) | 1014 | smp_cross_call(&xcall_new_mmu_context_version, 0, 0, 0); |
800 | smp_cross_call(&xcall_flush_tlb_all_spitfire, 0, 0, 0); | 1015 | } |
801 | else | 1016 | |
802 | smp_cross_call(&xcall_flush_tlb_all_cheetah, 0, 0, 0); | 1017 | void smp_report_regs(void) |
803 | __flush_tlb_all(); | 1018 | { |
1019 | smp_cross_call(&xcall_report_regs, 0, 0, 0); | ||
804 | } | 1020 | } |
805 | 1021 | ||
806 | /* We know that the window frames of the user have been flushed | 1022 | /* We know that the window frames of the user have been flushed |
@@ -944,24 +1160,19 @@ void smp_release(void) | |||
944 | * can service tlb flush xcalls... | 1160 | * can service tlb flush xcalls... |
945 | */ | 1161 | */ |
946 | extern void prom_world(int); | 1162 | extern void prom_world(int); |
947 | extern void save_alternate_globals(unsigned long *); | 1163 | |
948 | extern void restore_alternate_globals(unsigned long *); | ||
949 | void smp_penguin_jailcell(int irq, struct pt_regs *regs) | 1164 | void smp_penguin_jailcell(int irq, struct pt_regs *regs) |
950 | { | 1165 | { |
951 | unsigned long global_save[24]; | ||
952 | |||
953 | clear_softint(1 << irq); | 1166 | clear_softint(1 << irq); |
954 | 1167 | ||
955 | preempt_disable(); | 1168 | preempt_disable(); |
956 | 1169 | ||
957 | __asm__ __volatile__("flushw"); | 1170 | __asm__ __volatile__("flushw"); |
958 | save_alternate_globals(global_save); | ||
959 | prom_world(1); | 1171 | prom_world(1); |
960 | atomic_inc(&smp_capture_registry); | 1172 | atomic_inc(&smp_capture_registry); |
961 | membar_storeload_storestore(); | 1173 | membar_storeload_storestore(); |
962 | while (penguins_are_doing_time) | 1174 | while (penguins_are_doing_time) |
963 | rmb(); | 1175 | rmb(); |
964 | restore_alternate_globals(global_save); | ||
965 | atomic_dec(&smp_capture_registry); | 1176 | atomic_dec(&smp_capture_registry); |
966 | prom_world(0); | 1177 | prom_world(0); |
967 | 1178 | ||
@@ -1082,6 +1293,8 @@ int setup_profiling_timer(unsigned int multiplier) | |||
1082 | /* Constrain the number of cpus to max_cpus. */ | 1293 | /* Constrain the number of cpus to max_cpus. */ |
1083 | void __init smp_prepare_cpus(unsigned int max_cpus) | 1294 | void __init smp_prepare_cpus(unsigned int max_cpus) |
1084 | { | 1295 | { |
1296 | int i; | ||
1297 | |||
1085 | if (num_possible_cpus() > max_cpus) { | 1298 | if (num_possible_cpus() > max_cpus) { |
1086 | int instance, mid; | 1299 | int instance, mid; |
1087 | 1300 | ||
@@ -1096,6 +1309,20 @@ void __init smp_prepare_cpus(unsigned int max_cpus) | |||
1096 | } | 1309 | } |
1097 | } | 1310 | } |
1098 | 1311 | ||
1312 | for_each_cpu(i) { | ||
1313 | if (tlb_type == hypervisor) { | ||
1314 | int j; | ||
1315 | |||
1316 | /* XXX get this mapping from machine description */ | ||
1317 | for_each_cpu(j) { | ||
1318 | if ((j >> 2) == (i >> 2)) | ||
1319 | cpu_set(j, cpu_sibling_map[i]); | ||
1320 | } | ||
1321 | } else { | ||
1322 | cpu_set(i, cpu_sibling_map[i]); | ||
1323 | } | ||
1324 | } | ||
1325 | |||
1099 | smp_store_cpu_info(boot_cpu_id); | 1326 | smp_store_cpu_info(boot_cpu_id); |
1100 | } | 1327 | } |
1101 | 1328 | ||
@@ -1117,12 +1344,15 @@ void __init smp_setup_cpu_possible_map(void) | |||
1117 | 1344 | ||
1118 | void __devinit smp_prepare_boot_cpu(void) | 1345 | void __devinit smp_prepare_boot_cpu(void) |
1119 | { | 1346 | { |
1120 | if (hard_smp_processor_id() >= NR_CPUS) { | 1347 | int cpu = hard_smp_processor_id(); |
1348 | |||
1349 | if (cpu >= NR_CPUS) { | ||
1121 | prom_printf("Serious problem, boot cpu id >= NR_CPUS\n"); | 1350 | prom_printf("Serious problem, boot cpu id >= NR_CPUS\n"); |
1122 | prom_halt(); | 1351 | prom_halt(); |
1123 | } | 1352 | } |
1124 | 1353 | ||
1125 | current_thread_info()->cpu = hard_smp_processor_id(); | 1354 | current_thread_info()->cpu = cpu; |
1355 | __local_per_cpu_offset = __per_cpu_offset(cpu); | ||
1126 | 1356 | ||
1127 | cpu_set(smp_processor_id(), cpu_online_map); | 1357 | cpu_set(smp_processor_id(), cpu_online_map); |
1128 | cpu_set(smp_processor_id(), phys_cpu_present_map); | 1358 | cpu_set(smp_processor_id(), phys_cpu_present_map); |
@@ -1139,7 +1369,11 @@ int __devinit __cpu_up(unsigned int cpu) | |||
1139 | if (!cpu_isset(cpu, cpu_online_map)) { | 1369 | if (!cpu_isset(cpu, cpu_online_map)) { |
1140 | ret = -ENODEV; | 1370 | ret = -ENODEV; |
1141 | } else { | 1371 | } else { |
1142 | smp_synchronize_one_tick(cpu); | 1372 | /* On SUN4V, writes to %tick and %stick are |
1373 | * not allowed. | ||
1374 | */ | ||
1375 | if (tlb_type != hypervisor) | ||
1376 | smp_synchronize_one_tick(cpu); | ||
1143 | } | 1377 | } |
1144 | } | 1378 | } |
1145 | return ret; | 1379 | return ret; |
@@ -1183,12 +1417,9 @@ void __init setup_per_cpu_areas(void) | |||
1183 | { | 1417 | { |
1184 | unsigned long goal, size, i; | 1418 | unsigned long goal, size, i; |
1185 | char *ptr; | 1419 | char *ptr; |
1186 | /* Created by linker magic */ | ||
1187 | extern char __per_cpu_start[], __per_cpu_end[]; | ||
1188 | 1420 | ||
1189 | /* Copy section for each CPU (we discard the original) */ | 1421 | /* Copy section for each CPU (we discard the original) */ |
1190 | goal = ALIGN(__per_cpu_end - __per_cpu_start, PAGE_SIZE); | 1422 | goal = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES); |
1191 | |||
1192 | #ifdef CONFIG_MODULES | 1423 | #ifdef CONFIG_MODULES |
1193 | if (goal < PERCPU_ENOUGH_ROOM) | 1424 | if (goal < PERCPU_ENOUGH_ROOM) |
1194 | goal = PERCPU_ENOUGH_ROOM; | 1425 | goal = PERCPU_ENOUGH_ROOM; |
@@ -1197,31 +1428,10 @@ void __init setup_per_cpu_areas(void) | |||
1197 | for (size = 1UL; size < goal; size <<= 1UL) | 1428 | for (size = 1UL; size < goal; size <<= 1UL) |
1198 | __per_cpu_shift++; | 1429 | __per_cpu_shift++; |
1199 | 1430 | ||
1200 | /* Make sure the resulting __per_cpu_base value | 1431 | 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 | 1432 | ||
1207 | __per_cpu_base = ptr - __per_cpu_start; | 1433 | __per_cpu_base = ptr - __per_cpu_start; |
1208 | 1434 | ||
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) | 1435 | for (i = 0; i < NR_CPUS; i++, ptr += size) |
1219 | memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); | 1436 | 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 | } | 1437 | } |