[SPARC64]: Sun4v cross-call sending support.
[firefly-linux-kernel-4.4.55.git] / arch / sparc64 / kernel / irq.c
index 233526ba3abe23d7a684143b56cbc4a9aa36c503..c80d2531ec46528264ebacd75f461edd17e4593d 100644 (file)
@@ -39,6 +39,7 @@
 #include <asm/cache.h>
 #include <asm/cpudata.h>
 #include <asm/auxio.h>
+#include <asm/head.h>
 
 #ifdef CONFIG_SMP
 static void distribute_irqs(void);
@@ -153,7 +154,8 @@ void enable_irq(unsigned int irq)
                unsigned long ver;
 
                __asm__ ("rdpr %%ver, %0" : "=r" (ver));
-               if ((ver >> 32) == 0x003e0016) {
+               if ((ver >> 32) == __JALAPENO_ID ||
+                   (ver >> 32) == __SERRANO_ID) {
                        /* We set it to our JBUS ID. */
                        __asm__ __volatile__("ldxa [%%g0] %1, %0"
                                             : "=r" (tid)
@@ -694,7 +696,7 @@ irqreturn_t sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
                val = readb(auxio_register);
                val |= AUXIO_AUX1_FTCNT;
                writeb(val, auxio_register);
-               val &= AUXIO_AUX1_FTCNT;
+               val &= ~AUXIO_AUX1_FTCNT;
                writeb(val, auxio_register);
 
                doing_pdma = 0;
@@ -848,33 +850,90 @@ static void kill_prom_timer(void)
 
 void init_irqwork_curcpu(void)
 {
-       register struct irq_work_struct *workp asm("o2");
-       register unsigned long tmp asm("o3");
        int cpu = hard_smp_processor_id();
 
-       memset(__irq_work + cpu, 0, sizeof(*workp));
-
-       /* Make sure we are called with PSTATE_IE disabled.  */
-       __asm__ __volatile__("rdpr      %%pstate, %0\n\t"
-                            : "=r" (tmp));
-       if (tmp & PSTATE_IE) {
-               prom_printf("BUG: init_irqwork_curcpu() called with "
-                           "PSTATE_IE enabled, bailing.\n");
-               __asm__ __volatile__("mov       %%i7, %0\n\t"
-                                    : "=r" (tmp));
-               prom_printf("BUG: Called from %lx\n", tmp);
+       memset(__irq_work + cpu, 0, sizeof(struct irq_work_struct));
+}
+
+static void __cpuinit init_one_mondo(unsigned long *pa_ptr, unsigned long type)
+{
+       register unsigned long func __asm__("%o0");
+       register unsigned long arg0 __asm__("%o1");
+       register unsigned long arg1 __asm__("%o2");
+       register unsigned long arg2 __asm__("%o3");
+       unsigned long page = get_zeroed_page(GFP_ATOMIC);
+
+       if (!page) {
+               prom_printf("SUN4V: Error, cannot allocate mondo queue.\n");
                prom_halt();
        }
 
-       /* Set interrupt globals.  */
-       workp = &__irq_work[cpu];
-       __asm__ __volatile__(
-       "rdpr   %%pstate, %0\n\t"
-       "wrpr   %0, %1, %%pstate\n\t"
-       "mov    %2, %%g6\n\t"
-       "wrpr   %0, 0x0, %%pstate\n\t"
-       : "=&r" (tmp)
-       : "i" (PSTATE_IG), "r" (workp));
+       *pa_ptr = __pa(page);
+
+       func = HV_FAST_CPU_QCONF;
+       arg0 = type;
+       arg1 = *pa_ptr;
+       arg2 = 128; /* XXX Implied by Niagara queue offsets. XXX */
+       __asm__ __volatile__("ta        %8"
+                            : "=&r" (func), "=&r" (arg0),
+                              "=&r" (arg1), "=&r" (arg2)
+                            : "0" (func), "1" (arg0),
+                              "2" (arg1), "3" (arg2),
+                              "i" (HV_FAST_TRAP));
+
+       if (func != HV_EOK) {
+               prom_printf("SUN4V: cpu_qconf(%lu) failed with error %lu\n",
+                           type, func);
+               prom_halt();
+       }
+}
+
+static void __cpuinit init_one_kbuf(unsigned long *pa_ptr)
+{
+       unsigned long page = get_zeroed_page(GFP_ATOMIC);
+
+       if (!page) {
+               prom_printf("SUN4V: Error, cannot allocate kbuf page.\n");
+               prom_halt();
+       }
+
+       *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)
+{
+       int cpu = hard_smp_processor_id();
+       struct trap_per_cpu *tb = &trap_block[cpu];
+
+       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. */
@@ -884,6 +943,9 @@ void __init init_IRQ(void)
        kill_prom_timer();
        memset(&ivector_table[0], 0, sizeof(ivector_table));
 
+       if (tlb_type == hypervisor)
+               sun4v_init_mondo_queues();
+
        /* We need to clear any IRQ's pending in the soft interrupt
         * registers, a spurious one could be left around from the
         * PROM timer which we just disabled.