[SPARC64]: Wire up cookie based sun4v interrupt registry.
authorDavid S. Miller <davem@sunset.davemloft.net>
Wed, 13 Jun 2007 07:01:04 +0000 (00:01 -0700)
committerDavid S. Miller <davem@sunset.davemloft.net>
Wed, 13 Jun 2007 07:01:04 +0000 (00:01 -0700)
This will be used for logical domain channel interrupts.

Signed-off-by: David S. Miller <davem@davemloft.net>
arch/sparc64/kernel/irq.c
include/asm-sparc64/irq.h

index a36f8dd0c0216e9244896736af33682a6ac7e889..e60d283f60bc518d87aa8ec08363d40d719b9ab8 100644 (file)
@@ -1,7 +1,6 @@
-/* $Id: irq.c,v 1.114 2002/01/11 08:45:38 davem Exp $
- * irq.c: UltraSparc IRQ handling/init/registry.
+/* irq.c: UltraSparc IRQ handling/init/registry.
  *
- * Copyright (C) 1997  David S. Miller  (davem@caip.rutgers.edu)
+ * Copyright (C) 1997, 2007  David S. Miller  (davem@davemloft.net)
  * Copyright (C) 1998  Eddie C. Dost    (ecd@skynet.be)
  * Copyright (C) 1998  Jakub Jelinek    (jj@ultra.linux.cz)
  */
@@ -43,6 +42,7 @@
 #include <asm/cpudata.h>
 #include <asm/auxio.h>
 #include <asm/head.h>
+#include <asm/hypervisor.h>
 
 /* UPA nodes send interrupt packet to UltraSparc with first data reg
  * value low 5 (7 on Starfire) bits holding the IRQ identifier being
@@ -380,6 +380,76 @@ static void sun4v_irq_end(unsigned int virt_irq)
        }
 }
 
+static void sun4v_virq_enable(unsigned int virt_irq)
+{
+       struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
+       unsigned int ino = bucket - &ivector_table[0];
+
+       if (likely(bucket)) {
+               unsigned long cpuid, dev_handle, dev_ino;
+               int err;
+
+               cpuid = irq_choose_cpu(virt_irq);
+
+               dev_handle = ino & IMAP_IGN;
+               dev_ino = ino & IMAP_INO;
+
+               err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
+               if (err != HV_EOK)
+                       printk("sun4v_vintr_set_target(%lx,%lx,%lu): "
+                              "err(%d)\n",
+                              dev_handle, dev_ino, cpuid, err);
+               err = sun4v_vintr_set_state(dev_handle, dev_ino,
+                                           HV_INTR_ENABLED);
+               if (err != HV_EOK)
+                       printk("sun4v_vintr_set_state(%lx,%lx,"
+                              "HV_INTR_ENABLED): err(%d)\n",
+                              dev_handle, dev_ino, err);
+       }
+}
+
+static void sun4v_virq_disable(unsigned int virt_irq)
+{
+       struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
+       unsigned int ino = bucket - &ivector_table[0];
+
+       if (likely(bucket)) {
+               unsigned long dev_handle, dev_ino;
+               int err;
+
+               dev_handle = ino & IMAP_IGN;
+               dev_ino = ino & IMAP_INO;
+
+               err = sun4v_vintr_set_state(dev_handle, dev_ino,
+                                           HV_INTR_DISABLED);
+               if (err != HV_EOK)
+                       printk("sun4v_vintr_set_state(%lx,%lx,"
+                              "HV_INTR_DISABLED): err(%d)\n",
+                              dev_handle, dev_ino, err);
+       }
+}
+
+static void sun4v_virq_end(unsigned int virt_irq)
+{
+       struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
+       unsigned int ino = bucket - &ivector_table[0];
+
+       if (likely(bucket)) {
+               unsigned long dev_handle, dev_ino;
+               int err;
+
+               dev_handle = ino & IMAP_IGN;
+               dev_ino = ino & IMAP_INO;
+
+               err = sun4v_vintr_set_state(dev_handle, dev_ino,
+                                           HV_INTR_STATE_IDLE);
+               if (err != HV_EOK)
+                       printk("sun4v_vintr_set_state(%lx,%lx,"
+                               "HV_INTR_STATE_IDLE): err(%d)\n",
+                              dev_handle, dev_ino, err);
+       }
+}
+
 static void run_pre_handler(unsigned int virt_irq)
 {
        struct ino_bucket *bucket = virt_irq_to_bucket(virt_irq);
@@ -434,6 +504,21 @@ static struct irq_chip sun4v_msi = {
 };
 #endif
 
+static struct irq_chip sun4v_virq = {
+       .typename       = "vsun4v",
+       .enable         = sun4v_virq_enable,
+       .disable        = sun4v_virq_disable,
+       .end            = sun4v_virq_end,
+};
+
+static struct irq_chip sun4v_virq_ack = {
+       .typename       = "vsun4v+ack",
+       .enable         = sun4v_virq_enable,
+       .disable        = sun4v_virq_disable,
+       .ack            = run_pre_handler,
+       .end            = sun4v_virq_end,
+};
+
 void irq_install_pre_handler(int virt_irq,
                             void (*func)(unsigned int, void *, void *),
                             void *arg1, void *arg2)
@@ -447,7 +532,8 @@ void irq_install_pre_handler(int virt_irq,
 
        chip = get_irq_chip(virt_irq);
        if (chip == &sun4u_irq_ack ||
-           chip == &sun4v_irq_ack
+           chip == &sun4v_irq_ack ||
+           chip == &sun4v_virq_ack
 #ifdef CONFIG_PCI_MSI
            || chip == &sun4v_msi
 #endif
@@ -455,7 +541,9 @@ void irq_install_pre_handler(int virt_irq,
                return;
 
        chip = (chip == &sun4u_irq ?
-               &sun4u_irq_ack : &sun4v_irq_ack);
+               &sun4u_irq_ack :
+               (chip == &sun4v_irq ?
+                &sun4v_irq_ack : &sun4v_virq_ack));
        set_irq_chip(virt_irq, chip);
 }
 
@@ -492,19 +580,18 @@ out:
        return bucket->virt_irq;
 }
 
-unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
+static unsigned int sun4v_build_common(unsigned long sysino,
+                                      struct irq_chip *chip)
 {
        struct ino_bucket *bucket;
        struct irq_handler_data *data;
-       unsigned long sysino;
 
        BUG_ON(tlb_type != hypervisor);
 
-       sysino = sun4v_devino_to_sysino(devhandle, devino);
        bucket = &ivector_table[sysino];
        if (!bucket->virt_irq) {
                bucket->virt_irq = virt_irq_alloc(__irq(bucket));
-               set_irq_chip(bucket->virt_irq, &sun4v_irq);
+               set_irq_chip(bucket->virt_irq, chip);
        }
 
        data = get_irq_chip_data(bucket->virt_irq);
@@ -529,6 +616,32 @@ out:
        return bucket->virt_irq;
 }
 
+unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
+{
+       unsigned long sysino = sun4v_devino_to_sysino(devhandle, devino);
+
+       return sun4v_build_common(sysino, &sun4v_irq);
+}
+
+unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
+{
+       unsigned long sysino, hv_err;
+
+       BUG_ON(devhandle & ~IMAP_IGN);
+       BUG_ON(devino & ~IMAP_INO);
+
+       sysino = devhandle | devino;
+
+       hv_err = sun4v_vintr_set_cookie(devhandle, devino, sysino);
+       if (hv_err) {
+               prom_printf("IRQ: Fatal, cannot set cookie for [%x:%x] "
+                           "err=%lu\n", devhandle, devino, hv_err);
+               prom_halt();
+       }
+
+       return sun4v_build_common(sysino, &sun4v_virq);
+}
+
 #ifdef CONFIG_PCI_MSI
 unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p,
                             unsigned int msi_start, unsigned int msi_end)
index 5d233b42fe135b87b51d9c2f3e1339554ce8e7f5..90781e34a95ca9b67bf1414ccd191466b9139300 100644 (file)
@@ -46,6 +46,7 @@ extern void irq_install_pre_handler(int virt_irq,
 #define irq_canonicalize(irq)  (irq)
 extern unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap);
 extern unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino);
+extern unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino);
 extern unsigned int sun4v_build_msi(u32 devhandle, unsigned int *virt_irq_p,
                                    unsigned int msi_devino_start,
                                    unsigned int msi_devino_end);