[SPARC64]: Make error codes available from sun4v_intr_get*().
[safe/jmp/linux-2.6] / arch / sparc64 / kernel / irq.c
index 51f6505..0d3b0ea 100644 (file)
@@ -152,7 +152,18 @@ void enable_irq(unsigned int irq)
        preempt_disable();
 
        if (tlb_type == hypervisor) {
-               /* XXX SUN4V: implement me... XXX */
+               unsigned int ino = __irq_ino(irq);
+               int cpu = hard_smp_processor_id();
+               int err;
+
+               err = sun4v_intr_settarget(ino, cpu);
+               if (err != HV_EOK)
+                       printk("sun4v_intr_settarget(%x,%d): err(%d)\n",
+                              ino, cpu, err);
+               sun4v_intr_setenabled(ino, HV_INTR_ENABLED);
+               if (err != HV_EOK)
+                       printk("sun4v_intr_setenabled(%x): err(%d)\n",
+                              ino, err);
        } else {
                if (tlb_type == cheetah || tlb_type == cheetah_plus) {
                        unsigned long ver;
@@ -210,16 +221,26 @@ void disable_irq(unsigned int irq)
 
        imap = bucket->imap;
        if (imap != 0UL) {
-               u32 tmp;
+               if (tlb_type == hypervisor) {
+                       unsigned int ino = __irq_ino(irq);
+                       int err;
+
+                       err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED);
+                       if (err != HV_EOK)
+                               printk("sun4v_intr_setenabled(%x): "
+                                      "err(%d)\n", ino, err);
+               } else {
+                       u32 tmp;
 
-               /* NOTE: We do not want to futz with the IRQ clear registers
-                *       and move the state to IDLE, the SCSI code does call
-                *       disable_irq() to assure atomicity in the queue cmd
-                *       SCSI adapter driver code.  Thus we'd lose interrupts.
-                */
-               tmp = upa_readl(imap);
-               tmp &= ~IMAP_VALID;
-               upa_writel(tmp, imap);
+                       /* NOTE: We do not want to futz with the IRQ clear registers
+                        *       and move the state to IDLE, the SCSI code does call
+                        *       disable_irq() to assure atomicity in the queue cmd
+                        *       SCSI adapter driver code.  Thus we'd lose interrupts.
+                        */
+                       tmp = upa_readl(imap);
+                       tmp &= ~IMAP_VALID;
+                       upa_writel(tmp, imap);
+               }
        }
 }
 
@@ -257,6 +278,8 @@ unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long
                return __irq(&pil0_dummy_bucket);
        }
 
+       BUG_ON(tlb_type == hypervisor);
+
        /* RULE: Both must be specified in all other cases. */
        if (iclr == 0UL || imap == 0UL) {
                prom_printf("Invalid build_irq %d %d %016lx %016lx\n",
@@ -303,6 +326,38 @@ out:
        return __irq(bucket);
 }
 
+unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino, int pil, unsigned char flags)
+{
+       struct ino_bucket *bucket;
+       unsigned long sysino;
+
+       sysino = sun4v_devino_to_sysino(devhandle, devino);
+
+       printk(KERN_INFO "sun4v_irq: Mapping (%x:%x) --> sysino[%lx]\n",
+              devhandle, devino, sysino);
+
+       bucket = &ivector_table[sysino];
+
+       /* Catch accidental accesses to these things.  IMAP/ICLR handling
+        * is done by hypervisor calls on sun4v platforms, not by direct
+        * register accesses.
+        */
+       bucket->imap = ~0UL;
+       bucket->iclr = ~0UL;
+
+       bucket->pil = pil;
+       bucket->flags = flags;
+
+       bucket->irq_info = kmalloc(sizeof(struct irq_desc), GFP_ATOMIC);
+       if (!bucket->irq_info) {
+               prom_printf("IRQ: Error, kmalloc(irq_desc) failed.\n");
+               prom_halt();
+       }
+       memset(bucket->irq_info, 0, sizeof(struct irq_desc));
+
+       return __irq(bucket);
+}
+
 static void atomic_bucket_insert(struct ino_bucket *bucket)
 {
        unsigned long pstate;
@@ -601,10 +656,20 @@ static void process_bucket(int irq, struct ino_bucket *bp, struct pt_regs *regs)
                        break;
        }
        if (bp->pil != 0) {
-               upa_writel(ICLR_IDLE, bp->iclr);
-               /* Test and add entropy */
-               if (random & SA_SAMPLE_RANDOM)
-                       add_interrupt_randomness(irq);
+               if (tlb_type == hypervisor) {
+                       unsigned int ino = __irq_ino(bp);
+                       int err;
+
+                       err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
+                       if (err != HV_EOK)
+                               printk("sun4v_intr_setstate(%x): "
+                                      "err(%d)\n", ino, err);
+               } else {
+                       upa_writel(ICLR_IDLE, bp->iclr);
+                       /* Test and add entropy */
+                       if (random & SA_SAMPLE_RANDOM)
+                               add_interrupt_randomness(irq);
+               }
        }
 out:
        bp->flags &= ~IBF_INPROGRESS;
@@ -737,24 +802,32 @@ static int retarget_one_irq(struct irqaction *p, int goal_cpu)
 {
        struct ino_bucket *bucket = get_ino_in_irqaction(p) + ivector_table;
        unsigned long imap = bucket->imap;
-       unsigned int tid;
 
        while (!cpu_online(goal_cpu)) {
                if (++goal_cpu >= NR_CPUS)
                        goal_cpu = 0;
        }
 
-       if (tlb_type == cheetah || tlb_type == cheetah_plus) {
-               tid = goal_cpu << 26;
-               tid &= IMAP_AID_SAFARI;
-       } else if (this_is_starfire == 0) {
-               tid = goal_cpu << 26;
-               tid &= IMAP_TID_UPA;
+       if (tlb_type == hypervisor) {
+               unsigned int ino = __irq_ino(bucket);
+
+               sun4v_intr_settarget(ino, goal_cpu);
+               sun4v_intr_setenabled(ino, HV_INTR_ENABLED);
        } else {
-               tid = (starfire_translate(imap, goal_cpu) << 26);
-               tid &= IMAP_TID_UPA;
+               unsigned int tid;
+
+               if (tlb_type == cheetah || tlb_type == cheetah_plus) {
+                       tid = goal_cpu << 26;
+                       tid &= IMAP_AID_SAFARI;
+               } else if (this_is_starfire == 0) {
+                       tid = goal_cpu << 26;
+                       tid &= IMAP_TID_UPA;
+               } else {
+                       tid = (starfire_translate(imap, goal_cpu) << 26);
+                       tid &= IMAP_TID_UPA;
+               }
+               upa_writel(tid | IMAP_VALID, imap);
        }
-       upa_writel(tid | IMAP_VALID, imap);
 
        do {
                if (++goal_cpu >= NR_CPUS)