From 69c010b24560be5ca7667e94a352183e60ed205e Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Fri, 19 Sep 2008 21:17:43 -0700 Subject: [PATCH] sparc32: Use PROM device probing for sun4m irq registers. Signed-off-by: David S. Miller --- arch/sparc/kernel/entry.S | 40 ++++----- arch/sparc/kernel/sun4m_irq.c | 163 +++++++++++----------------------- 2 files changed, 74 insertions(+), 129 deletions(-) diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index 68689facaaae..faf9ccd9ef5d 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S @@ -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 diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c index 5b17146f0c1f..39d40e96d396 100644 --- a/arch/sparc/kernel/sun4m_irq.c +++ b/arch/sparc/kernel/sun4m_irq.c @@ -41,53 +41,25 @@ #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. */ } -- 2.30.2