sparc32: Use PROM device probing for sun4m irq registers.
authorDavid S. Miller <davem@davemloft.net>
Sat, 20 Sep 2008 04:17:43 +0000 (21:17 -0700)
committerDavid S. Miller <davem@davemloft.net>
Sat, 20 Sep 2008 04:17:43 +0000 (21:17 -0700)
Signed-off-by: David S. Miller <davem@davemloft.net>
arch/sparc/kernel/entry.S
arch/sparc/kernel/sun4m_irq.c

index 68689facaaae5a701e5e4eb11f08ecf2d796aa1d..faf9ccd9ef5dfc32f41da7c3b9b1d74f564669bc 100644 (file)
@@ -272,17 +272,18 @@ smp4m_ticker:
         */
 maybe_smp4m_msg:
        GET_PROCESSOR4M_ID(o3)
-       set     sun4m_interrupts, %l5
-       ld      [%l5], %o5
+       sethi   %hi(sun4m_irq_percpu), %l5
+       sll     %o3, 2, %o3
+       or      %l5, %lo(sun4m_irq_percpu), %o5
        sethi   %hi(0x40000000), %o2
-       sll     %o3, 12, %o3
        ld      [%o5 + %o3], %o1
-       andcc   %o1, %o2, %g0
+       ld      [%o1 + 0x00], %o3       ! sun4m_irq_percpu[cpu]->pending
+       andcc   %o3, %o2, %g0
        be,a    smp4m_ticker
         cmp    %l7, 14
-       st      %o2, [%o5 + 0x4]
+       st      %o2, [%o1 + 0x04]       ! sun4m_irq_percpu[cpu]->clear=0x40000000
        WRITE_PAUSE
-       ld      [%o5], %g0
+       ld      [%o1 + 0x00], %g0       ! sun4m_irq_percpu[cpu]->pending
        WRITE_PAUSE
        or      %l0, PSR_PIL, %l4
        wr      %l4, 0x0, %psr
@@ -300,16 +301,16 @@ linux_trap_ipi15_sun4m:
        SAVE_ALL
        sethi   %hi(0x80000000), %o2
        GET_PROCESSOR4M_ID(o0)
-       set     sun4m_interrupts, %l5
-       ld      [%l5], %o5
-       sll     %o0, 12, %o0
-       add     %o5, %o0, %o5
-       ld      [%o5], %o3
+       sethi   %hi(sun4m_irq_percpu), %l5
+       or      %l5, %lo(sun4m_irq_percpu), %o5
+       sll     %o0, 2, %o0
+       ld      [%o5 + %o0], %o5
+       ld      [%o5 + 0x00], %o3       ! sun4m_irq_percpu[cpu]->pending
        andcc   %o3, %o2, %g0
        be      1f                      ! Must be an NMI async memory error
-        st     %o2, [%o5 + 4]
+        st     %o2, [%o5 + 0x04]       ! sun4m_irq_percpu[cpu]->clear=0x80000000
        WRITE_PAUSE
-       ld      [%o5], %g0
+       ld      [%o5 + 0x00], %g0       ! sun4m_irq_percpu[cpu]->pending
        WRITE_PAUSE
        or      %l0, PSR_PIL, %l4
        wr      %l4, 0x0, %psr
@@ -323,12 +324,11 @@ linux_trap_ipi15_sun4m:
 1:
        /* NMI async memory error handling. */
        sethi   %hi(0x80000000), %l4
-       sethi   %hi(0x4000), %o3
-       sub     %o5, %o0, %o5
-       add     %o5, %o3, %l5
-       st      %l4, [%l5 + 0xc]
+       sethi   %hi(sun4m_irq_global), %o5
+       ld      [%o5 + %lo(sun4m_irq_global)], %l5
+       st      %l4, [%l5 + 0x0c]       ! sun4m_irq_global->mask_set=0x80000000
        WRITE_PAUSE
-       ld      [%l5], %g0
+       ld      [%l5 + 0x00], %g0       ! sun4m_irq_global->pending
        WRITE_PAUSE
        or      %l0, PSR_PIL, %l4
        wr      %l4, 0x0, %psr
@@ -337,9 +337,9 @@ linux_trap_ipi15_sun4m:
        WRITE_PAUSE
        call    sun4m_nmi
         nop
-       st      %l4, [%l5 + 0x8]
+       st      %l4, [%l5 + 0x08]       ! sun4m_irq_global->mask_clear=0x80000000
        WRITE_PAUSE
-       ld      [%l5], %g0
+       ld      [%l5 + 0x00], %g0       ! sun4m_irq_global->pending
        WRITE_PAUSE
        RESTORE_ALL
 
index 5b17146f0c1f7951a0c33a0204f62221c6d00585..39d40e96d3961a47c068b77c7703f0e9618bd27b 100644 (file)
 
 #include "irq.h"
 
-/* On the sun4m, just like the timers, we have both per-cpu and master
- * interrupt registers.
- */
-
-/* These registers are used for sending/receiving irqs from/to
- * different cpu's.
- */
-struct sun4m_intreg_percpu {
-       unsigned int tbt;        /* Interrupts still pending for this cpu. */
-
-       /* These next two registers are WRITE-ONLY and are only
-        * "on bit" sensitive, "off bits" written have NO affect.
-        */
-       unsigned int clear;  /* Clear this cpus irqs here. */
-       unsigned int set;    /* Set this cpus irqs here. */
-       unsigned char space[PAGE_SIZE - 12];
+struct sun4m_irq_percpu {
+       u32             pending;
+       u32             clear;
+       u32             set;
 };
 
-/*
- * djhr
- * Actually the clear and set fields in this struct are misleading..
- * according to the SLAVIO manual (and the same applies for the SEC)
- * the clear field clears bits in the mask which will ENABLE that IRQ
- * the set field sets bits in the mask to DISABLE the IRQ.
- *
- * Also the undirected_xx address in the SLAVIO is defined as
- * RESERVED and write only..
- *
- * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor
- *             sun4m machines, for MP the layout makes more sense.
- */
-struct sun4m_intregs {
-       struct sun4m_intreg_percpu cpu_intregs[SUN4M_NCPUS];
-       unsigned int tbt;                /* IRQ's that are still pending. */
-       unsigned int irqs;               /* Master IRQ bits. */
-
-       /* Again, like the above, two these registers are WRITE-ONLY. */
-       unsigned int clear;              /* Clear master IRQ's by setting bits here. */
-       unsigned int set;                /* Set master IRQ's by setting bits here. */
-
-       /* This register is both READ and WRITE. */
-       unsigned int undirected_target;  /* Which cpu gets undirected irqs. */
+struct sun4m_irq_global {
+       u32             pending;
+       u32             mask;
+       u32             mask_clear;
+       u32             mask_set;
+       u32             interrupt_target;
 };
 
-static unsigned long dummy;
+/* 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;
 
-struct sun4m_intregs *sun4m_interrupts;
+static unsigned long dummy;
 unsigned long *irq_rcvreg = &dummy;
 
 /* Dave Redman (djhr@tadpole.co.uk)
@@ -182,9 +154,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);    
 }
 
@@ -201,13 +173,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);
        }
 }
@@ -236,34 +208,30 @@ 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
 
@@ -347,7 +315,7 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
        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_interrupts->set);
+               sbus_writel(SUN4M_INT_E14, &sun4m_irq_global->mask_set);
 
 #ifdef CONFIG_SMP
        {
@@ -372,62 +340,38 @@ 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);
+       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 *) of_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;
-       of_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;
+               sbus_writel(~0x17fff, &sun4m_irq_percpu[mid]->clear);
+
+       if (num_cpu_iregs == 4) {
+               irq_rcvreg = (unsigned long *) &sun4m_irq_global->interrupt_target;
+               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);
@@ -442,5 +386,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. */
 }