*pa_ptr = __pa(page);
}
+static void __cpuinit init_cpu_send_mondo_info(struct trap_per_cpu *tb)
+{
+#ifdef CONFIG_SMP
+ unsigned long page;
+
+ BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > (PAGE_SIZE - 64));
+
+ page = get_zeroed_page(GFP_ATOMIC);
+ if (!page) {
+ prom_printf("SUN4V: Error, cannot allocate cpu mondo page.\n");
+ prom_halt();
+ }
+
+ tb->cpu_mondo_block_pa = __pa(page);
+ tb->cpu_list_pa = __pa(page + 64);
+#endif
+}
+
/* Allocate and init the mondo and error queues for this cpu. */
void __cpuinit sun4v_init_mondo_queues(void)
{
init_one_mondo(&tb->cpu_mondo_pa, HV_CPU_QUEUE_CPU_MONDO);
init_one_mondo(&tb->dev_mondo_pa, HV_CPU_QUEUE_DEVICE_MONDO);
+
init_one_mondo(&tb->resum_mondo_pa, HV_CPU_QUEUE_RES_ERROR);
init_one_kbuf(&tb->resum_kernel_buf_pa);
+
init_one_mondo(&tb->nonresum_mondo_pa, HV_CPU_QUEUE_NONRES_ERROR);
init_one_kbuf(&tb->nonresum_kernel_buf_pa);
+
+ init_cpu_send_mondo_info(tb);
}
/* Only invoked on boot processor. */
}
}
+#if 0
+/* 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__("%o0");
+ register unsigned long arg0 __asm__("%o1");
+ register unsigned long arg1 __asm__("%o2");
+ register unsigned long arg2 __asm__("%o3");
+
+ 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(func == 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();
+}
+#else
+/* Single-cpu list version. */
static void hypervisor_xcall_deliver(u64 data0, u64 data1, u64 data2, cpumask_t mask)
{
- /* XXX implement me */
+ 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 i;
+
+ mondo[0] = data0;
+ mondo[1] = data1;
+ mondo[2] = data2;
+ wmb();
+
+ for_each_cpu_mask(i, mask) {
+ int retries = 0;
+
+ do {
+ register unsigned long func __asm__("%o0");
+ register unsigned long arg0 __asm__("%o1");
+ register unsigned long arg1 __asm__("%o2");
+ register unsigned long arg2 __asm__("%o3");
+
+ cpu_list[0] = i;
+ func = HV_FAST_CPU_MONDO_SEND;
+ arg0 = 1;
+ 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(func == HV_EOK))
+ break;
+
+ if (unlikely(++retries > 100)) {
+ printk("CPU[%d]: sun4v mondo error %lu\n",
+ this_cpu, func);
+ break;
+ }
+
+ udelay(2 * i);
+ } while (1);
+ }
+
+ put_cpu();
}
+#endif
/* Send cross call to all processors mentioned in MASK
* except self.
(TRAP_PER_CPU_NONRESUM_KBUF_PA !=
offsetof(struct trap_per_cpu, nonresum_kernel_buf_pa)) ||
(TRAP_PER_CPU_FAULT_INFO !=
- offsetof(struct trap_per_cpu, fault_info)))
+ offsetof(struct trap_per_cpu, fault_info)) ||
+ (TRAP_PER_CPU_CPU_MONDO_BLOCK_PA !=
+ offsetof(struct trap_per_cpu, cpu_mondo_block_pa)) ||
+ (TRAP_PER_CPU_CPU_LIST_PA !=
+ offsetof(struct trap_per_cpu, cpu_list_pa)))
trap_per_cpu_offsets_are_bolixed_dave();
/* Attach to the address space of init_task. On SMP we
unsigned long nonresum_mondo_pa;
unsigned long nonresum_kernel_buf_pa;
-/* Dcache lines 3 and 4: Hypervisor Fault Status */
+/* Dcache lines 3, 4, 5, and 6: Hypervisor Fault Status */
struct hv_fault_status fault_info;
+
+/* Dcache line 7: Physical addresses of CPU send mondo block and CPU list. */
+ unsigned long cpu_mondo_block_pa;
+ unsigned long cpu_list_pa;
+ unsigned long __pad1[2];
+
+/* Dcache line 8: Unused, needed to keep trap_block a power-of-2 in size. */
+ unsigned long __pad2[4];
} __attribute__((aligned(64)));
extern struct trap_per_cpu trap_block[NR_CPUS];
extern void init_cur_cpu_trap(void);
#define TRAP_PER_CPU_NONRESUM_MONDO_PA 0x30
#define TRAP_PER_CPU_NONRESUM_KBUF_PA 0x38
#define TRAP_PER_CPU_FAULT_INFO 0x40
+#define TRAP_PER_CPU_CPU_MONDO_BLOCK_PA 0xc0
+#define TRAP_PER_CPU_CPU_LIST_PA 0xc8
-#define TRAP_BLOCK_SZ_SHIFT 7
+#define TRAP_BLOCK_SZ_SHIFT 8
#include <asm/scratchpad.h>