+/* Multi-cpu list version. */
+static int init_cpu_list(u16 *list, cpumask_t mask)
+{
+ int i, cnt;
+
+ cnt = 0;
+ for_each_cpu_mask(i, mask)
+ list[cnt++] = i;
+
+ return cnt;
+}
+
+static int update_cpu_list(u16 *list, int orig_cnt, cpumask_t mask)
+{
+ int i;
+
+ for (i = 0; i < orig_cnt; i++) {
+ if (list[i] == 0xffff)
+ cpu_clear(i, mask);
+ }
+
+ return init_cpu_list(list, mask);
+}
+
+static void hypervisor_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask)
+{
+ int this_cpu = get_cpu();
+ struct trap_per_cpu *tb = &trap_block[this_cpu];
+ u64 *mondo = __va(tb->cpu_mondo_block_pa);
+ u16 *cpu_list = __va(tb->cpu_list_pa);
+ int cnt, retries;
+
+ mondo[0] = data0;
+ mondo[1] = data1;
+ mondo[2] = data2;
+ wmb();
+
+ retries = 0;
+ cnt = init_cpu_list(cpu_list, mask);
+ do {
+ register unsigned long func __asm__("%o5");
+ register unsigned long arg0 __asm__("%o0");
+ register unsigned long arg1 __asm__("%o1");
+ register unsigned long arg2 __asm__("%o2");
+
+ func = HV_FAST_CPU_MONDO_SEND;
+ arg0 = cnt;
+ arg1 = tb->cpu_list_pa;
+ arg2 = tb->cpu_mondo_block_pa;
+
+ __asm__ __volatile__("ta %8"
+ : "=&r" (func), "=&r" (arg0),
+ "=&r" (arg1), "=&r" (arg2)
+ : "0" (func), "1" (arg0),
+ "2" (arg1), "3" (arg2),
+ "i" (HV_FAST_TRAP)
+ : "memory");
+ if (likely(arg0 == HV_EOK))
+ break;
+
+ if (unlikely(++retries > 100)) {
+ printk("CPU[%d]: sun4v mondo error %lu\n",
+ this_cpu, func);
+ break;
+ }
+
+ cnt = update_cpu_list(cpu_list, cnt, mask);
+
+ udelay(2 * cnt);
+ } while (1);
+
+ put_cpu();
+}
+