include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / arch / sparc / kernel / sun4m_irq.c
index a654c16..7f3b97f 100644 (file)
 #include <linux/ptrace.h>
 #include <linux/smp.h>
 #include <linux/interrupt.h>
-#include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
 #include <asm/smp.h>
 #include <asm/irq.h>
 #include <asm/io.h>
-#include <asm/sbus.h>
 #include <asm/cacheflush.h>
 
-static unsigned long dummy;
+#include "irq.h"
 
-struct sun4m_intregs *sun4m_interrupts;
-unsigned long *irq_rcvreg = &dummy;
+struct sun4m_irq_percpu {
+       u32             pending;
+       u32             clear;
+       u32             set;
+};
+
+struct sun4m_irq_global {
+       u32             pending;
+       u32             mask;
+       u32             mask_clear;
+       u32             mask_set;
+       u32             interrupt_target;
+};
+
+/* Code in entry.S needs to get at these register mappings.  */
+struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS];
+struct sun4m_irq_global __iomem *sun4m_irq_global;
 
-/* These tables only apply for interrupts greater than 15..
- * 
- * any intr value below 0x10 is considered to be a soft-int
- * this may be useful or it may not.. but that's how I've done it.
- * and it won't clash with what OBP is telling us about devices.
+/* Dave Redman (djhr@tadpole.co.uk)
+ * The sun4m interrupt registers.
+ */
+#define SUN4M_INT_ENABLE       0x80000000
+#define SUN4M_INT_E14          0x00000080
+#define SUN4M_INT_E10          0x00080000
+
+#define SUN4M_HARD_INT(x)      (0x000000001 << (x))
+#define SUN4M_SOFT_INT(x)      (0x000010000 << (x))
+
+#define        SUN4M_INT_MASKALL       0x80000000        /* mask all interrupts */
+#define        SUN4M_INT_MODULE_ERR    0x40000000        /* module error */
+#define        SUN4M_INT_M2S_WRITE_ERR 0x20000000        /* write buffer error */
+#define        SUN4M_INT_ECC_ERR       0x10000000        /* ecc memory error */
+#define        SUN4M_INT_VME_ERR       0x08000000        /* vme async error */
+#define        SUN4M_INT_FLOPPY        0x00400000        /* floppy disk */
+#define        SUN4M_INT_MODULE        0x00200000        /* module interrupt */
+#define        SUN4M_INT_VIDEO         0x00100000        /* onboard video */
+#define        SUN4M_INT_REALTIME      0x00080000        /* system timer */
+#define        SUN4M_INT_SCSI          0x00040000        /* onboard scsi */
+#define        SUN4M_INT_AUDIO         0x00020000        /* audio/isdn */
+#define        SUN4M_INT_ETHERNET      0x00010000        /* onboard ethernet */
+#define        SUN4M_INT_SERIAL        0x00008000        /* serial ports */
+#define        SUN4M_INT_KBDMS         0x00004000        /* keyboard/mouse */
+#define        SUN4M_INT_SBUSBITS      0x00003F80        /* sbus int bits */
+#define        SUN4M_INT_VMEBITS       0x0000007F        /* vme int bits */
+
+#define        SUN4M_INT_ERROR         (SUN4M_INT_MODULE_ERR |    \
+                                SUN4M_INT_M2S_WRITE_ERR | \
+                                SUN4M_INT_ECC_ERR |       \
+                                SUN4M_INT_VME_ERR)
+
+#define SUN4M_INT_SBUS(x)      (1 << (x+7))
+#define SUN4M_INT_VME(x)       (1 << (x))
+
+/* Interrupt levels used by OBP */
+#define        OBP_INT_LEVEL_SOFT      0x10
+#define        OBP_INT_LEVEL_ONBOARD   0x20
+#define        OBP_INT_LEVEL_SBUS      0x30
+#define        OBP_INT_LEVEL_VME       0x40
+
+/* Interrupt level assignment on sun4m:
+ *
+ *     level           source
+ * ------------------------------------------------------------
+ *        1            softint-1
+ *       2             softint-2, VME/SBUS level 1
+ *       3             softint-3, VME/SBUS level 2
+ *       4             softint-4, onboard SCSI
+ *       5             softint-5, VME/SBUS level 3
+ *       6             softint-6, onboard ETHERNET
+ *       7             softint-7, VME/SBUS level 4
+ *       8             softint-8, onboard VIDEO
+ *       9             softint-9, VME/SBUS level 5, Module Interrupt
+ *      10             softint-10, system counter/timer
+ *      11             softint-11, VME/SBUS level 6, Floppy
+ *      12             softint-12, Keyboard/Mouse, Serial
+ *      13             softint-13, VME/SBUS level 7, ISDN Audio
+ *      14             softint-14, per-processor counter/timer
+ *      15             softint-15, Asynchronous Errors (broadcast)
+ *
+ * Each interrupt source is masked distinctly in the sun4m interrupt
+ * registers.  The PIL level alone is therefore ambiguous, since multiple
+ * interrupt sources map to a single PIL.
+ *
+ * This ambiguity is resolved in the 'intr' property for device nodes
+ * in the OF device tree.  Each 'intr' property entry is composed of
+ * two 32-bit words.  The first word is the IRQ priority value, which
+ * is what we're intersted in.  The second word is the IRQ vector, which
+ * is unused.
  *
- * take an encoded intr value and lookup if it's valid
- * then get the mask bits that match from irq_mask
+ * The low 4 bits of the IRQ priority indicate the PIL, and the upper
+ * 4 bits indicate onboard vs. SBUS leveled vs. VME leveled.  0x20
+ * means onboard, 0x30 means SBUS leveled, and 0x40 means VME leveled.
  *
- * P3: Translation from irq 0x0d to mask 0x2000 is for MrCoffee.
+ * For example, an 'intr' IRQ priority value of 0x24 is onboard SCSI
+ * whereas a value of 0x33 is SBUS level 2.  Here are some sample
+ * 'intr' property IRQ priority values from ss4, ss5, ss10, ss20, and
+ * Tadpole S3 GX systems.
+ *
+ * esp:        0x24    onboard ESP SCSI
+ * le:         0x26    onboard Lance ETHERNET
+ * p9100:      0x32    SBUS level 1 P9100 video
+ * bpp:        0x33    SBUS level 2 BPP parallel port device
+ * DBRI:       0x39    SBUS level 5 DBRI ISDN audio
+ * SUNW,leo:   0x39    SBUS level 5 LEO video
+ * pcmcia:     0x3b    SBUS level 6 PCMCIA controller
+ * uctrl:      0x3b    SBUS level 6 UCTRL device
+ * modem:      0x3d    SBUS level 7 MODEM
+ * zs:         0x2c    onboard keyboard/mouse/serial
+ * floppy:     0x2b    onboard Floppy
+ * power:      0x22    onboard power device (XXX unknown mask bit XXX)
  */
-static unsigned char irq_xlate[32] = {
-    /*  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  a,  b,  c,  d,  e,  f */
-       0,  0,  0,  0,  1,  0,  2,  0,  3,  0,  4,  5,  6, 14,  0,  7,
-       0,  0,  8,  9,  0, 10,  0, 11,  0, 12,  0, 13,  0, 14,  0,  0
-};
 
-static unsigned long irq_mask[] = {
-       0,                                                /* illegal index */
-       SUN4M_INT_SCSI,                                   /*  1 irq 4 */
-       SUN4M_INT_ETHERNET,                               /*  2 irq 6 */
-       SUN4M_INT_VIDEO,                                  /*  3 irq 8 */
-       SUN4M_INT_REALTIME,                               /*  4 irq 10 */
-       SUN4M_INT_FLOPPY,                                 /*  5 irq 11 */
-       (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS),             /*  6 irq 12 */
-       SUN4M_INT_MODULE_ERR,                             /*  7 irq 15 */
-       SUN4M_INT_SBUS(0),                                /*  8 irq 2 */
-       SUN4M_INT_SBUS(1),                                /*  9 irq 3 */
-       SUN4M_INT_SBUS(2),                                /* 10 irq 5 */
-       SUN4M_INT_SBUS(3),                                /* 11 irq 7 */
-       SUN4M_INT_SBUS(4),                                /* 12 irq 9 */
-       SUN4M_INT_SBUS(5),                                /* 13 irq 11 */
-       SUN4M_INT_SBUS(6)                                 /* 14 irq 13 */
+static unsigned long irq_mask[0x50] = {
+       /* SMP */
+       0,  SUN4M_SOFT_INT(1),
+       SUN4M_SOFT_INT(2),  SUN4M_SOFT_INT(3),
+       SUN4M_SOFT_INT(4),  SUN4M_SOFT_INT(5),
+       SUN4M_SOFT_INT(6),  SUN4M_SOFT_INT(7),
+       SUN4M_SOFT_INT(8),  SUN4M_SOFT_INT(9),
+       SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11),
+       SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13),
+       SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15),
+       /* soft */
+       0,  SUN4M_SOFT_INT(1),
+       SUN4M_SOFT_INT(2),  SUN4M_SOFT_INT(3),
+       SUN4M_SOFT_INT(4),  SUN4M_SOFT_INT(5),
+       SUN4M_SOFT_INT(6),  SUN4M_SOFT_INT(7),
+       SUN4M_SOFT_INT(8),  SUN4M_SOFT_INT(9),
+       SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11),
+       SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13),
+       SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15),
+       /* onboard */
+       0, 0, 0, 0,
+       SUN4M_INT_SCSI,  0, SUN4M_INT_ETHERNET, 0,
+       SUN4M_INT_VIDEO, SUN4M_INT_MODULE,
+       SUN4M_INT_REALTIME, SUN4M_INT_FLOPPY,
+       (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS),
+       SUN4M_INT_AUDIO, 0, SUN4M_INT_MODULE_ERR,
+       /* sbus */
+       0, 0, SUN4M_INT_SBUS(0), SUN4M_INT_SBUS(1),
+       0, SUN4M_INT_SBUS(2), 0, SUN4M_INT_SBUS(3),
+       0, SUN4M_INT_SBUS(4), 0, SUN4M_INT_SBUS(5),
+       0, SUN4M_INT_SBUS(6), 0, 0,
+       /* vme */
+       0, 0, SUN4M_INT_VME(0), SUN4M_INT_VME(1),
+       0, SUN4M_INT_VME(2), 0, SUN4M_INT_VME(3),
+       0, SUN4M_INT_VME(4), 0, SUN4M_INT_VME(5),
+       0, SUN4M_INT_VME(6), 0, 0
 };
 
-static int sun4m_pil_map[] = { 0, 2, 3, 5, 7, 9, 11, 13 };
-
-unsigned int sun4m_sbint_to_irq(struct sbus_dev *sdev, unsigned int sbint) 
-{
-       if (sbint >= sizeof(sun4m_pil_map)) {
-               printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint);
-               BUG();
-       }
-       return sun4m_pil_map[sbint] | 0x30;
-}
-
-inline unsigned long sun4m_get_irqmask(unsigned int irq)
+static unsigned long sun4m_get_irqmask(unsigned int irq)
 {
        unsigned long mask;
     
-       if (irq > 0x20) {
-               /* OBIO/SBUS interrupts */
-               irq &= 0x1f;
-               mask = irq_mask[irq_xlate[irq]];
-               if (!mask)
-                       printk("sun4m_get_irqmask: IRQ%d has no valid mask!\n",irq);
-       } else {
-               /* Soft Interrupts will come here.
-                * Currently there is no way to trigger them but I'm sure
-                * something could be cooked up.
-                */
-               irq &= 0xf;
-               mask = SUN4M_SOFT_INT(irq);
-       }
+       if (irq < 0x50)
+               mask = irq_mask[irq];
+       else
+               mask = 0;
+
+       if (!mask)
+               printk(KERN_ERR "sun4m_get_irqmask: IRQ%d has no valid mask!\n",
+                      irq);
+
        return mask;
 }
 
@@ -118,9 +214,9 @@ static void sun4m_disable_irq(unsigned int irq_nr)
        mask = sun4m_get_irqmask(irq_nr);
        local_irq_save(flags);
        if (irq_nr > 15)
-               sun4m_interrupts->set = mask;
+               sbus_writel(mask, &sun4m_irq_global->mask_set);
        else
-               sun4m_interrupts->cpu_intregs[cpu].set = mask;
+               sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
        local_irq_restore(flags);    
 }
 
@@ -137,13 +233,13 @@ static void sun4m_enable_irq(unsigned int irq_nr)
                mask = sun4m_get_irqmask(irq_nr);
                local_irq_save(flags);
                if (irq_nr > 15)
-                       sun4m_interrupts->clear = mask;
+                       sbus_writel(mask, &sun4m_irq_global->mask_clear);
                else
-                       sun4m_interrupts->cpu_intregs[cpu].clear = mask;
+                       sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
                local_irq_restore(flags);    
        } else {
                local_irq_save(flags);
-               sun4m_interrupts->clear = SUN4M_INT_FLOPPY;
+               sbus_writel(SUN4M_INT_FLOPPY, &sun4m_irq_global->mask_clear);
                local_irq_restore(flags);
        }
 }
@@ -161,10 +257,10 @@ static unsigned long cpu_pil_to_imask[16] = {
 /*9*/  SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR,
 /*10*/ SUN4M_INT_REALTIME,
 /*11*/ SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY,
-/*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS,
-/*13*/ SUN4M_INT_AUDIO,
+/*12*/ SUN4M_INT_SERIAL  | SUN4M_INT_KBDMS,
+/*13*/ SUN4M_INT_SBUS(6) | SUN4M_INT_VME(6) | SUN4M_INT_AUDIO,
 /*14*/ SUN4M_INT_E14,
-/*15*/ 0x00000000
+/*15*/ SUN4M_INT_ERROR
 };
 
 /* We assume the caller has disabled local interrupts when these are called,
@@ -172,126 +268,142 @@ static unsigned long cpu_pil_to_imask[16] = {
  */
 static void sun4m_disable_pil_irq(unsigned int pil)
 {
-       sun4m_interrupts->set = cpu_pil_to_imask[pil];
+       sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_set);
 }
 
 static void sun4m_enable_pil_irq(unsigned int pil)
 {
-       sun4m_interrupts->clear = cpu_pil_to_imask[pil];
+       sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_clear);
 }
 
 #ifdef CONFIG_SMP
 static void sun4m_send_ipi(int cpu, int level)
 {
-       unsigned long mask;
-
-       mask = sun4m_get_irqmask(level);
-       sun4m_interrupts->cpu_intregs[cpu].set = mask;
+       unsigned long mask = sun4m_get_irqmask(level);
+       sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
 }
 
 static void sun4m_clear_ipi(int cpu, int level)
 {
-       unsigned long mask;
-
-       mask = sun4m_get_irqmask(level);
-       sun4m_interrupts->cpu_intregs[cpu].clear = mask;
+       unsigned long mask = sun4m_get_irqmask(level);
+       sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
 }
 
 static void sun4m_set_udt(int cpu)
 {
-       sun4m_interrupts->undirected_target = cpu;
+       sbus_writel(cpu, &sun4m_irq_global->interrupt_target);
 }
 #endif
 
-#define OBIO_INTR      0x20
-#define TIMER_IRQ      (OBIO_INTR | 10)
-#define PROFILE_IRQ    (OBIO_INTR | 14)
+struct sun4m_timer_percpu {
+       u32             l14_limit;
+       u32             l14_count;
+       u32             l14_limit_noclear;
+       u32             user_timer_start_stop;
+};
+
+static struct sun4m_timer_percpu __iomem *timers_percpu[SUN4M_NCPUS];
+
+struct sun4m_timer_global {
+       u32             l10_limit;
+       u32             l10_count;
+       u32             l10_limit_noclear;
+       u32             reserved;
+       u32             timer_config;
+};
+
+static struct sun4m_timer_global __iomem *timers_global;
+
+#define TIMER_IRQ      (OBP_INT_LEVEL_ONBOARD | 10)
 
-struct sun4m_timer_regs *sun4m_timers;
 unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10);
 
 static void sun4m_clear_clock_irq(void)
 {
-       volatile unsigned int clear_intr;
-       clear_intr = sun4m_timers->l10_timer_limit;
+       sbus_readl(&timers_global->l10_limit);
 }
 
-static void sun4m_clear_profile_irq(int cpu)
+void sun4m_nmi(struct pt_regs *regs)
 {
-       volatile unsigned int clear;
-    
-       clear = sun4m_timers->cpu_timers[cpu].l14_timer_limit;
+       unsigned long afsr, afar, si;
+
+       printk(KERN_ERR "Aieee: sun4m NMI received!\n");
+       /* XXX HyperSparc hack XXX */
+       __asm__ __volatile__("mov 0x500, %%g1\n\t"
+                            "lda [%%g1] 0x4, %0\n\t"
+                            "mov 0x600, %%g1\n\t"
+                            "lda [%%g1] 0x4, %1\n\t" :
+                            "=r" (afsr), "=r" (afar));
+       printk(KERN_ERR "afsr=%08lx afar=%08lx\n", afsr, afar);
+       si = sbus_readl(&sun4m_irq_global->pending);
+       printk(KERN_ERR "si=%08lx\n", si);
+       if (si & SUN4M_INT_MODULE_ERR)
+               printk(KERN_ERR "Module async error\n");
+       if (si & SUN4M_INT_M2S_WRITE_ERR)
+               printk(KERN_ERR "MBus/SBus async error\n");
+       if (si & SUN4M_INT_ECC_ERR)
+               printk(KERN_ERR "ECC memory error\n");
+       if (si & SUN4M_INT_VME_ERR)
+               printk(KERN_ERR "VME async error\n");
+       printk(KERN_ERR "you lose buddy boy...\n");
+       show_regs(regs);
+       prom_halt();
+}
+
+/* Exported for sun4m_smp.c */
+void sun4m_clear_profile_irq(int cpu)
+{
+       sbus_readl(&timers_percpu[cpu]->l14_limit);
 }
 
 static void sun4m_load_profile_irq(int cpu, unsigned int limit)
 {
-       sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit;
+       sbus_writel(limit, &timers_percpu[cpu]->l14_limit);
 }
 
 static void __init sun4m_init_timers(irq_handler_t counter_fn)
 {
-       int reg_count, irq, cpu;
-       struct linux_prom_registers cnt_regs[PROMREG_MAX];
-       int obio_node, cnt_node;
-       struct resource r;
-
-       cnt_node = 0;
-       if((obio_node =
-           prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 ||
-          (obio_node = prom_getchild (obio_node)) == 0 ||
-          (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) {
-               prom_printf("Cannot find /obio/counter node\n");
-               prom_halt();
+       struct device_node *dp = of_find_node_by_name(NULL, "counter");
+       int i, err, len, num_cpu_timers;
+       const u32 *addr;
+
+       if (!dp) {
+               printk(KERN_ERR "sun4m_init_timers: No 'counter' node.\n");
+               return;
        }
-       reg_count = prom_getproperty(cnt_node, "reg",
-                                    (void *) cnt_regs, sizeof(cnt_regs));
-       reg_count = (reg_count/sizeof(struct linux_prom_registers));
-    
-       /* Apply the obio ranges to the timer registers. */
-       prom_apply_obio_ranges(cnt_regs, reg_count);
-    
-       cnt_regs[4].phys_addr = cnt_regs[reg_count-1].phys_addr;
-       cnt_regs[4].reg_size = cnt_regs[reg_count-1].reg_size;
-       cnt_regs[4].which_io = cnt_regs[reg_count-1].which_io;
-       for(obio_node = 1; obio_node < 4; obio_node++) {
-               cnt_regs[obio_node].phys_addr =
-                       cnt_regs[obio_node-1].phys_addr + PAGE_SIZE;
-               cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size;
-               cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io;
+
+       addr = of_get_property(dp, "address", &len);
+       of_node_put(dp);
+       if (!addr) {
+               printk(KERN_ERR "sun4m_init_timers: No 'address' prop.\n");
+               return;
        }
 
-       memset((char*)&r, 0, sizeof(struct resource));
-       /* Map the per-cpu Counter registers. */
-       r.flags = cnt_regs[0].which_io;
-       r.start = cnt_regs[0].phys_addr;
-       sun4m_timers = (struct sun4m_timer_regs *) sbus_ioremap(&r, 0,
-           PAGE_SIZE*SUN4M_NCPUS, "sun4m_cpu_cnt");
-       /* Map the system Counter register. */
-       /* XXX Here we expect consequent calls to yeld adjusent maps. */
-       r.flags = cnt_regs[4].which_io;
-       r.start = cnt_regs[4].phys_addr;
-       sbus_ioremap(&r, 0, cnt_regs[4].reg_size, "sun4m_sys_cnt");
-
-       sun4m_timers->l10_timer_limit =  (((1000000/HZ) + 1) << 10);
-       master_l10_counter = &sun4m_timers->l10_cur_count;
-       master_l10_limit = &sun4m_timers->l10_timer_limit;
-
-       irq = request_irq(TIMER_IRQ,
-                         counter_fn,
-                         (IRQF_DISABLED | SA_STATIC_ALLOC),
-                         "timer", NULL);
-       if (irq) {
-               prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
-               prom_halt();
+       num_cpu_timers = (len / sizeof(u32)) - 1;
+       for (i = 0; i < num_cpu_timers; i++) {
+               timers_percpu[i] = (void __iomem *)
+                       (unsigned long) addr[i];
        }
-   
-       if (!cpu_find_by_instance(1, NULL, NULL)) {
-               for(cpu = 0; cpu < 4; cpu++)
-                       sun4m_timers->cpu_timers[cpu].l14_timer_limit = 0;
-               sun4m_interrupts->set = SUN4M_INT_E14;
-       } else {
-               sun4m_timers->cpu_timers[0].l14_timer_limit = 0;
+       timers_global = (void __iomem *)
+               (unsigned long) addr[num_cpu_timers];
+
+       sbus_writel((((1000000/HZ) + 1) << 10), &timers_global->l10_limit);
+
+       master_l10_counter = &timers_global->l10_count;
+
+       err = request_irq(TIMER_IRQ, counter_fn,
+                         (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL);
+       if (err) {
+               printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n",
+                       err);
+               return;
        }
+
+       for (i = 0; i < num_cpu_timers; i++)
+               sbus_writel(0, &timers_percpu[i]->l14_limit);
+       if (num_cpu_timers == 4)
+               sbus_writel(SUN4M_INT_E14, &sun4m_irq_global->mask_set);
+
 #ifdef CONFIG_SMP
        {
                unsigned long flags;
@@ -299,7 +411,7 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
                struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
 
                /* For SMP we use the level 14 ticker, however the bootup code
-                * has copied the firmwares level 14 vector into boot cpu's
+                * has copied the firmware's level 14 vector into the boot cpu's
                 * trap table, we must fix this now or we get squashed.
                 */
                local_irq_save(flags);
@@ -315,70 +427,44 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
 
 void __init sun4m_init_IRQ(void)
 {
-       int ie_node,i;
-       struct linux_prom_registers int_regs[PROMREG_MAX];
-       int num_regs;
-       struct resource r;
-       int mid;
-    
-       local_irq_disable();
-       if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
-          (ie_node = prom_getchild (ie_node)) == 0 ||
-          (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) {
-               prom_printf("Cannot find /obio/interrupt node\n");
-               prom_halt();
+       struct device_node *dp = of_find_node_by_name(NULL, "interrupt");
+       int len, i, mid, num_cpu_iregs;
+       const u32 *addr;
+
+       if (!dp) {
+               printk(KERN_ERR "sun4m_init_IRQ: No 'interrupt' node.\n");
+               return;
        }
-       num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs,
-                                   sizeof(int_regs));
-       num_regs = (num_regs/sizeof(struct linux_prom_registers));
-    
-       /* Apply the obio ranges to these registers. */
-       prom_apply_obio_ranges(int_regs, num_regs);
-    
-       int_regs[4].phys_addr = int_regs[num_regs-1].phys_addr;
-       int_regs[4].reg_size = int_regs[num_regs-1].reg_size;
-       int_regs[4].which_io = int_regs[num_regs-1].which_io;
-       for(ie_node = 1; ie_node < 4; ie_node++) {
-               int_regs[ie_node].phys_addr = int_regs[ie_node-1].phys_addr + PAGE_SIZE;
-               int_regs[ie_node].reg_size = int_regs[ie_node-1].reg_size;
-               int_regs[ie_node].which_io = int_regs[ie_node-1].which_io;
+
+       addr = of_get_property(dp, "address", &len);
+       of_node_put(dp);
+       if (!addr) {
+               printk(KERN_ERR "sun4m_init_IRQ: No 'address' prop.\n");
+               return;
        }
 
-       memset((char *)&r, 0, sizeof(struct resource));
-       /* Map the interrupt registers for all possible cpus. */
-       r.flags = int_regs[0].which_io;
-       r.start = int_regs[0].phys_addr;
-       sun4m_interrupts = (struct sun4m_intregs *) sbus_ioremap(&r, 0,
-           PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu");
+       num_cpu_iregs = (len / sizeof(u32)) - 1;
+       for (i = 0; i < num_cpu_iregs; i++) {
+               sun4m_irq_percpu[i] = (void __iomem *)
+                       (unsigned long) addr[i];
+       }
+       sun4m_irq_global = (void __iomem *)
+               (unsigned long) addr[num_cpu_iregs];
 
-       /* Map the system interrupt control registers. */
-       r.flags = int_regs[4].which_io;
-       r.start = int_regs[4].phys_addr;
-       sbus_ioremap(&r, 0, int_regs[4].reg_size, "interrupts_system");
+       local_irq_disable();
 
-       sun4m_interrupts->set = ~SUN4M_INT_MASKALL;
+       sbus_writel(~SUN4M_INT_MASKALL, &sun4m_irq_global->mask_set);
        for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++)
-               sun4m_interrupts->cpu_intregs[mid].clear = ~0x17fff;
-
-       if (!cpu_find_by_instance(1, NULL, NULL)) {
-               /* system wide interrupts go to cpu 0, this should always
-                * be safe because it is guaranteed to be fitted or OBP doesn't
-                * come up
-                *
-                * Not sure, but writing here on SLAVIO systems may puke
-                * so I don't do it unless there is more than 1 cpu.
-                */
-               irq_rcvreg = (unsigned long *)
-                               &sun4m_interrupts->undirected_target;
-               sun4m_interrupts->undirected_target = 0;
-       }
-       BTFIXUPSET_CALL(sbint_to_irq, sun4m_sbint_to_irq, BTFIXUPCALL_NORM);
+               sbus_writel(~0x17fff, &sun4m_irq_percpu[mid]->clear);
+
+       if (num_cpu_iregs == 4)
+               sbus_writel(0, &sun4m_irq_global->interrupt_target);
+
        BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM);
-       BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM);
        sparc_init_timers = sun4m_init_timers;
 #ifdef CONFIG_SMP
@@ -386,5 +472,6 @@ void __init sun4m_init_IRQ(void)
        BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM);
        BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM);
 #endif
+
        /* Cannot enable interrupts until OBP ticker is disabled. */
 }