diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2006-02-08 19:41:20 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-03-20 04:12:02 -0500 |
commit | 1d2f1f90a1e004b0c1b8a73ed4394a93f09104b3 (patch) | |
tree | 2fcc0840b52218631020311d7b6d785e9a15db6a /arch/sparc64/kernel/smp.c | |
parent | 5b0c0572fcd6204675c5f7ddfa572b5017f817dd (diff) |
[SPARC64]: Sun4v cross-call sending support.
Technically the hypervisor call supports sending in a list
of all cpus to get the cross-call, but I only pass in one
cpu at a time for now.
The multi-cpu support is there, just ifdef'd out so it's easy to
enable or delete it later.
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 | 125 |
1 files changed, 124 insertions, 1 deletions
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 223cc6bd369a..c10a3a8639e8 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c | |||
@@ -531,10 +531,133 @@ retry: | |||
531 | } | 531 | } |
532 | } | 532 | } |
533 | 533 | ||
534 | #if 0 | ||
535 | /* Multi-cpu list version. */ | ||
536 | static int init_cpu_list(u16 *list, cpumask_t mask) | ||
537 | { | ||
538 | int i, cnt; | ||
539 | |||
540 | cnt = 0; | ||
541 | for_each_cpu_mask(i, mask) | ||
542 | list[cnt++] = i; | ||
543 | |||
544 | return cnt; | ||
545 | } | ||
546 | |||
547 | static int update_cpu_list(u16 *list, int orig_cnt, cpumask_t mask) | ||
548 | { | ||
549 | int i; | ||
550 | |||
551 | for (i = 0; i < orig_cnt; i++) { | ||
552 | if (list[i] == 0xffff) | ||
553 | cpu_clear(i, mask); | ||
554 | } | ||
555 | |||
556 | return init_cpu_list(list, mask); | ||
557 | } | ||
558 | |||
559 | static void hypervisor_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask) | ||
560 | { | ||
561 | int this_cpu = get_cpu(); | ||
562 | struct trap_per_cpu *tb = &trap_block[this_cpu]; | ||
563 | u64 *mondo = __va(tb->cpu_mondo_block_pa); | ||
564 | u16 *cpu_list = __va(tb->cpu_list_pa); | ||
565 | int cnt, retries; | ||
566 | |||
567 | mondo[0] = data0; | ||
568 | mondo[1] = data1; | ||
569 | mondo[2] = data2; | ||
570 | wmb(); | ||
571 | |||
572 | retries = 0; | ||
573 | cnt = init_cpu_list(cpu_list, mask); | ||
574 | do { | ||
575 | register unsigned long func __asm__("%o0"); | ||
576 | register unsigned long arg0 __asm__("%o1"); | ||
577 | register unsigned long arg1 __asm__("%o2"); | ||
578 | register unsigned long arg2 __asm__("%o3"); | ||
579 | |||
580 | func = HV_FAST_CPU_MONDO_SEND; | ||
581 | arg0 = cnt; | ||
582 | arg1 = tb->cpu_list_pa; | ||
583 | arg2 = tb->cpu_mondo_block_pa; | ||
584 | |||
585 | __asm__ __volatile__("ta %8" | ||
586 | : "=&r" (func), "=&r" (arg0), | ||
587 | "=&r" (arg1), "=&r" (arg2) | ||
588 | : "0" (func), "1" (arg0), | ||
589 | "2" (arg1), "3" (arg2), | ||
590 | "i" (HV_FAST_TRAP) | ||
591 | : "memory"); | ||
592 | if (likely(func == HV_EOK)) | ||
593 | break; | ||
594 | |||
595 | if (unlikely(++retries > 100)) { | ||
596 | printk("CPU[%d]: sun4v mondo error %lu\n", | ||
597 | this_cpu, func); | ||
598 | break; | ||
599 | } | ||
600 | |||
601 | cnt = update_cpu_list(cpu_list, cnt, mask); | ||
602 | |||
603 | udelay(2 * cnt); | ||
604 | } while (1); | ||
605 | |||
606 | put_cpu(); | ||
607 | } | ||
608 | #else | ||
609 | /* Single-cpu list version. */ | ||
534 | static void hypervisor_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask) | 610 | static void hypervisor_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask) |
535 | { | 611 | { |
536 | /* XXX implement me */ | 612 | int this_cpu = get_cpu(); |
613 | struct trap_per_cpu *tb = &trap_block[this_cpu]; | ||
614 | u64 *mondo = __va(tb->cpu_mondo_block_pa); | ||
615 | u16 *cpu_list = __va(tb->cpu_list_pa); | ||
616 | int i; | ||
617 | |||
618 | mondo[0] = data0; | ||
619 | mondo[1] = data1; | ||
620 | mondo[2] = data2; | ||
621 | wmb(); | ||
622 | |||
623 | for_each_cpu_mask(i, mask) { | ||
624 | int retries = 0; | ||
625 | |||
626 | do { | ||
627 | register unsigned long func __asm__("%o0"); | ||
628 | register unsigned long arg0 __asm__("%o1"); | ||
629 | register unsigned long arg1 __asm__("%o2"); | ||
630 | register unsigned long arg2 __asm__("%o3"); | ||
631 | |||
632 | cpu_list[0] = i; | ||
633 | func = HV_FAST_CPU_MONDO_SEND; | ||
634 | arg0 = 1; | ||
635 | arg1 = tb->cpu_list_pa; | ||
636 | arg2 = tb->cpu_mondo_block_pa; | ||
637 | |||
638 | __asm__ __volatile__("ta %8" | ||
639 | : "=&r" (func), "=&r" (arg0), | ||
640 | "=&r" (arg1), "=&r" (arg2) | ||
641 | : "0" (func), "1" (arg0), | ||
642 | "2" (arg1), "3" (arg2), | ||
643 | "i" (HV_FAST_TRAP) | ||
644 | : "memory"); | ||
645 | if (likely(func == HV_EOK)) | ||
646 | break; | ||
647 | |||
648 | if (unlikely(++retries > 100)) { | ||
649 | printk("CPU[%d]: sun4v mondo error %lu\n", | ||
650 | this_cpu, func); | ||
651 | break; | ||
652 | } | ||
653 | |||
654 | udelay(2 * i); | ||
655 | } while (1); | ||
656 | } | ||
657 | |||
658 | put_cpu(); | ||
537 | } | 659 | } |
660 | #endif | ||
538 | 661 | ||
539 | /* Send cross call to all processors mentioned in MASK | 662 | /* Send cross call to all processors mentioned in MASK |
540 | * except self. | 663 | * except self. |