Commit 69c010b2 authored by David S. Miller's avatar David S. Miller

sparc32: Use PROM device probing for sun4m irq registers.

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2e57572a
...@@ -272,17 +272,18 @@ smp4m_ticker: ...@@ -272,17 +272,18 @@ smp4m_ticker:
*/ */
maybe_smp4m_msg: maybe_smp4m_msg:
GET_PROCESSOR4M_ID(o3) GET_PROCESSOR4M_ID(o3)
set sun4m_interrupts, %l5 sethi %hi(sun4m_irq_percpu), %l5
ld [%l5], %o5 sll %o3, 2, %o3
or %l5, %lo(sun4m_irq_percpu), %o5
sethi %hi(0x40000000), %o2 sethi %hi(0x40000000), %o2
sll %o3, 12, %o3
ld [%o5 + %o3], %o1 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 be,a smp4m_ticker
cmp %l7, 14 cmp %l7, 14
st %o2, [%o5 + 0x4] st %o2, [%o1 + 0x04] ! sun4m_irq_percpu[cpu]->clear=0x40000000
WRITE_PAUSE WRITE_PAUSE
ld [%o5], %g0 ld [%o1 + 0x00], %g0 ! sun4m_irq_percpu[cpu]->pending
WRITE_PAUSE WRITE_PAUSE
or %l0, PSR_PIL, %l4 or %l0, PSR_PIL, %l4
wr %l4, 0x0, %psr wr %l4, 0x0, %psr
...@@ -300,16 +301,16 @@ linux_trap_ipi15_sun4m: ...@@ -300,16 +301,16 @@ linux_trap_ipi15_sun4m:
SAVE_ALL SAVE_ALL
sethi %hi(0x80000000), %o2 sethi %hi(0x80000000), %o2
GET_PROCESSOR4M_ID(o0) GET_PROCESSOR4M_ID(o0)
set sun4m_interrupts, %l5 sethi %hi(sun4m_irq_percpu), %l5
ld [%l5], %o5 or %l5, %lo(sun4m_irq_percpu), %o5
sll %o0, 12, %o0 sll %o0, 2, %o0
add %o5, %o0, %o5 ld [%o5 + %o0], %o5
ld [%o5], %o3 ld [%o5 + 0x00], %o3 ! sun4m_irq_percpu[cpu]->pending
andcc %o3, %o2, %g0 andcc %o3, %o2, %g0
be 1f ! Must be an NMI async memory error 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 WRITE_PAUSE
ld [%o5], %g0 ld [%o5 + 0x00], %g0 ! sun4m_irq_percpu[cpu]->pending
WRITE_PAUSE WRITE_PAUSE
or %l0, PSR_PIL, %l4 or %l0, PSR_PIL, %l4
wr %l4, 0x0, %psr wr %l4, 0x0, %psr
...@@ -323,12 +324,11 @@ linux_trap_ipi15_sun4m: ...@@ -323,12 +324,11 @@ linux_trap_ipi15_sun4m:
1: 1:
/* NMI async memory error handling. */ /* NMI async memory error handling. */
sethi %hi(0x80000000), %l4 sethi %hi(0x80000000), %l4
sethi %hi(0x4000), %o3 sethi %hi(sun4m_irq_global), %o5
sub %o5, %o0, %o5 ld [%o5 + %lo(sun4m_irq_global)], %l5
add %o5, %o3, %l5 st %l4, [%l5 + 0x0c] ! sun4m_irq_global->mask_set=0x80000000
st %l4, [%l5 + 0xc]
WRITE_PAUSE WRITE_PAUSE
ld [%l5], %g0 ld [%l5 + 0x00], %g0 ! sun4m_irq_global->pending
WRITE_PAUSE WRITE_PAUSE
or %l0, PSR_PIL, %l4 or %l0, PSR_PIL, %l4
wr %l4, 0x0, %psr wr %l4, 0x0, %psr
...@@ -337,9 +337,9 @@ linux_trap_ipi15_sun4m: ...@@ -337,9 +337,9 @@ linux_trap_ipi15_sun4m:
WRITE_PAUSE WRITE_PAUSE
call sun4m_nmi call sun4m_nmi
nop nop
st %l4, [%l5 + 0x8] st %l4, [%l5 + 0x08] ! sun4m_irq_global->mask_clear=0x80000000
WRITE_PAUSE WRITE_PAUSE
ld [%l5], %g0 ld [%l5 + 0x00], %g0 ! sun4m_irq_global->pending
WRITE_PAUSE WRITE_PAUSE
RESTORE_ALL RESTORE_ALL
......
...@@ -41,53 +41,25 @@ ...@@ -41,53 +41,25 @@
#include "irq.h" #include "irq.h"
/* On the sun4m, just like the timers, we have both per-cpu and master struct sun4m_irq_percpu {
* interrupt registers. u32 pending;
*/ u32 clear;
u32 set;
/* 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_global {
* djhr u32 pending;
* Actually the clear and set fields in this struct are misleading.. u32 mask;
* according to the SLAVIO manual (and the same applies for the SEC) u32 mask_clear;
* the clear field clears bits in the mask which will ENABLE that IRQ u32 mask_set;
* the set field sets bits in the mask to DISABLE the IRQ. u32 interrupt_target;
*
* 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. */
}; };
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; unsigned long *irq_rcvreg = &dummy;
/* Dave Redman (djhr@tadpole.co.uk) /* Dave Redman (djhr@tadpole.co.uk)
...@@ -182,9 +154,9 @@ static void sun4m_disable_irq(unsigned int irq_nr) ...@@ -182,9 +154,9 @@ static void sun4m_disable_irq(unsigned int irq_nr)
mask = sun4m_get_irqmask(irq_nr); mask = sun4m_get_irqmask(irq_nr);
local_irq_save(flags); local_irq_save(flags);
if (irq_nr > 15) if (irq_nr > 15)
sun4m_interrupts->set = mask; sbus_writel(mask, &sun4m_irq_global->mask_set);
else else
sun4m_interrupts->cpu_intregs[cpu].set = mask; sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
local_irq_restore(flags); local_irq_restore(flags);
} }
...@@ -201,13 +173,13 @@ static void sun4m_enable_irq(unsigned int irq_nr) ...@@ -201,13 +173,13 @@ static void sun4m_enable_irq(unsigned int irq_nr)
mask = sun4m_get_irqmask(irq_nr); mask = sun4m_get_irqmask(irq_nr);
local_irq_save(flags); local_irq_save(flags);
if (irq_nr > 15) if (irq_nr > 15)
sun4m_interrupts->clear = mask; sbus_writel(mask, &sun4m_irq_global->mask_clear);
else else
sun4m_interrupts->cpu_intregs[cpu].clear = mask; sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
local_irq_restore(flags); local_irq_restore(flags);
} else { } else {
local_irq_save(flags); local_irq_save(flags);
sun4m_interrupts->clear = SUN4M_INT_FLOPPY; sbus_writel(SUN4M_INT_FLOPPY, &sun4m_irq_global->mask_clear);
local_irq_restore(flags); local_irq_restore(flags);
} }
} }
...@@ -236,34 +208,30 @@ static unsigned long cpu_pil_to_imask[16] = { ...@@ -236,34 +208,30 @@ static unsigned long cpu_pil_to_imask[16] = {
*/ */
static void sun4m_disable_pil_irq(unsigned int pil) 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) 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 #ifdef CONFIG_SMP
static void sun4m_send_ipi(int cpu, int level) static void sun4m_send_ipi(int cpu, int level)
{ {
unsigned long mask; unsigned long mask = sun4m_get_irqmask(level);
sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
mask = sun4m_get_irqmask(level);
sun4m_interrupts->cpu_intregs[cpu].set = mask;
} }
static void sun4m_clear_ipi(int cpu, int level) static void sun4m_clear_ipi(int cpu, int level)
{ {
unsigned long mask; unsigned long mask = sun4m_get_irqmask(level);
sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
mask = sun4m_get_irqmask(level);
sun4m_interrupts->cpu_intregs[cpu].clear = mask;
} }
static void sun4m_set_udt(int cpu) static void sun4m_set_udt(int cpu)
{ {
sun4m_interrupts->undirected_target = cpu; sbus_writel(cpu, &sun4m_irq_global->interrupt_target);
} }
#endif #endif
...@@ -347,7 +315,7 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn) ...@@ -347,7 +315,7 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
for (i = 0; i < num_cpu_timers; i++) for (i = 0; i < num_cpu_timers; i++)
sbus_writel(0, &timers_percpu[i]->l14_limit); sbus_writel(0, &timers_percpu[i]->l14_limit);
if (num_cpu_timers == 4) 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 #ifdef CONFIG_SMP
{ {
...@@ -372,62 +340,38 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn) ...@@ -372,62 +340,38 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
void __init sun4m_init_IRQ(void) void __init sun4m_init_IRQ(void)
{ {
int ie_node,i; struct device_node *dp = of_find_node_by_name(NULL, "interrupt");
struct linux_prom_registers int_regs[PROMREG_MAX]; int len, i, mid, num_cpu_iregs;
int num_regs; const u32 *addr;
struct resource r;
int mid; if (!dp) {
printk(KERN_ERR "sun4m_init_IRQ: No 'interrupt' node.\n");
local_irq_disable(); return;
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();
} }
num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs,
sizeof(int_regs)); addr = of_get_property(dp, "address", &len);
num_regs = (num_regs/sizeof(struct linux_prom_registers)); if (!addr) {
printk(KERN_ERR "sun4m_init_IRQ: No 'address' prop.\n");
/* Apply the obio ranges to these registers. */ return;
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;
} }
memset((char *)&r, 0, sizeof(struct resource)); num_cpu_iregs = (len / sizeof(u32)) - 1;
/* Map the interrupt registers for all possible cpus. */ for (i = 0; i < num_cpu_iregs; i++) {
r.flags = int_regs[0].which_io; sun4m_irq_percpu[i] = (void __iomem *)
r.start = int_regs[0].phys_addr; (unsigned long) addr[i];
sun4m_interrupts = (struct sun4m_intregs *) of_ioremap(&r, 0, }
PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu"); sun4m_irq_global = (void __iomem *)
(unsigned long) addr[num_cpu_iregs];
/* Map the system interrupt control registers. */ local_irq_disable();
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");
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++) for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++)
sun4m_interrupts->cpu_intregs[mid].clear = ~0x17fff; sbus_writel(~0x17fff, &sun4m_irq_percpu[mid]->clear);
if (!cpu_find_by_instance(1, NULL, NULL)) { if (num_cpu_iregs == 4) {
/* system wide interrupts go to cpu 0, this should always irq_rcvreg = (unsigned long *) &sun4m_irq_global->interrupt_target;
* be safe because it is guaranteed to be fitted or OBP doesn't sbus_writel(0, &sun4m_irq_global->interrupt_target);
* 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(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM);
...@@ -442,5 +386,6 @@ void __init sun4m_init_IRQ(void) ...@@ -442,5 +386,6 @@ void __init sun4m_init_IRQ(void)
BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM);
#endif #endif
/* Cannot enable interrupts until OBP ticker is disabled. */ /* Cannot enable interrupts until OBP ticker is disabled. */
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment