aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel/sun4m_irq.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2008-09-20 00:17:43 -0400
committerDavid S. Miller <davem@davemloft.net>2008-09-20 00:17:43 -0400
commit69c010b24560be5ca7667e94a352183e60ed205e (patch)
tree3a5d3cfa1d80323119baed6b3b022ef14b823b47 /arch/sparc/kernel/sun4m_irq.c
parent2e57572a50a4de41c6cbc879a4866a312d4cd316 (diff)
sparc32: Use PROM device probing for sun4m irq registers.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc/kernel/sun4m_irq.c')
-rw-r--r--arch/sparc/kernel/sun4m_irq.c163
1 files changed, 54 insertions, 109 deletions
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 @@
41 41
42#include "irq.h" 42#include "irq.h"
43 43
44/* On the sun4m, just like the timers, we have both per-cpu and master 44struct sun4m_irq_percpu {
45 * interrupt registers. 45 u32 pending;
46 */ 46 u32 clear;
47 47 u32 set;
48/* These registers are used for sending/receiving irqs from/to
49 * different cpu's.
50 */
51struct sun4m_intreg_percpu {
52 unsigned int tbt; /* Interrupts still pending for this cpu. */
53
54 /* These next two registers are WRITE-ONLY and are only
55 * "on bit" sensitive, "off bits" written have NO affect.
56 */
57 unsigned int clear; /* Clear this cpus irqs here. */
58 unsigned int set; /* Set this cpus irqs here. */
59 unsigned char space[PAGE_SIZE - 12];
60}; 48};
61 49
62/* 50struct sun4m_irq_global {
63 * djhr 51 u32 pending;
64 * Actually the clear and set fields in this struct are misleading.. 52 u32 mask;
65 * according to the SLAVIO manual (and the same applies for the SEC) 53 u32 mask_clear;
66 * the clear field clears bits in the mask which will ENABLE that IRQ 54 u32 mask_set;
67 * the set field sets bits in the mask to DISABLE the IRQ. 55 u32 interrupt_target;
68 *
69 * Also the undirected_xx address in the SLAVIO is defined as
70 * RESERVED and write only..
71 *
72 * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor
73 * sun4m machines, for MP the layout makes more sense.
74 */
75struct sun4m_intregs {
76 struct sun4m_intreg_percpu cpu_intregs[SUN4M_NCPUS];
77 unsigned int tbt; /* IRQ's that are still pending. */
78 unsigned int irqs; /* Master IRQ bits. */
79
80 /* Again, like the above, two these registers are WRITE-ONLY. */
81 unsigned int clear; /* Clear master IRQ's by setting bits here. */
82 unsigned int set; /* Set master IRQ's by setting bits here. */
83
84 /* This register is both READ and WRITE. */
85 unsigned int undirected_target; /* Which cpu gets undirected irqs. */
86}; 56};
87 57
88static unsigned long dummy; 58/* Code in entry.S needs to get at these register mappings. */
59struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS];
60struct sun4m_irq_global __iomem *sun4m_irq_global;
89 61
90struct sun4m_intregs *sun4m_interrupts; 62static unsigned long dummy;
91unsigned long *irq_rcvreg = &dummy; 63unsigned long *irq_rcvreg = &dummy;
92 64
93/* Dave Redman (djhr@tadpole.co.uk) 65/* Dave Redman (djhr@tadpole.co.uk)
@@ -182,9 +154,9 @@ static void sun4m_disable_irq(unsigned int irq_nr)
182 mask = sun4m_get_irqmask(irq_nr); 154 mask = sun4m_get_irqmask(irq_nr);
183 local_irq_save(flags); 155 local_irq_save(flags);
184 if (irq_nr > 15) 156 if (irq_nr > 15)
185 sun4m_interrupts->set = mask; 157 sbus_writel(mask, &sun4m_irq_global->mask_set);
186 else 158 else
187 sun4m_interrupts->cpu_intregs[cpu].set = mask; 159 sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
188 local_irq_restore(flags); 160 local_irq_restore(flags);
189} 161}
190 162
@@ -201,13 +173,13 @@ static void sun4m_enable_irq(unsigned int irq_nr)
201 mask = sun4m_get_irqmask(irq_nr); 173 mask = sun4m_get_irqmask(irq_nr);
202 local_irq_save(flags); 174 local_irq_save(flags);
203 if (irq_nr > 15) 175 if (irq_nr > 15)
204 sun4m_interrupts->clear = mask; 176 sbus_writel(mask, &sun4m_irq_global->mask_clear);
205 else 177 else
206 sun4m_interrupts->cpu_intregs[cpu].clear = mask; 178 sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
207 local_irq_restore(flags); 179 local_irq_restore(flags);
208 } else { 180 } else {
209 local_irq_save(flags); 181 local_irq_save(flags);
210 sun4m_interrupts->clear = SUN4M_INT_FLOPPY; 182 sbus_writel(SUN4M_INT_FLOPPY, &sun4m_irq_global->mask_clear);
211 local_irq_restore(flags); 183 local_irq_restore(flags);
212 } 184 }
213} 185}
@@ -236,34 +208,30 @@ static unsigned long cpu_pil_to_imask[16] = {
236 */ 208 */
237static void sun4m_disable_pil_irq(unsigned int pil) 209static void sun4m_disable_pil_irq(unsigned int pil)
238{ 210{
239 sun4m_interrupts->set = cpu_pil_to_imask[pil]; 211 sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_set);
240} 212}
241 213
242static void sun4m_enable_pil_irq(unsigned int pil) 214static void sun4m_enable_pil_irq(unsigned int pil)
243{ 215{
244 sun4m_interrupts->clear = cpu_pil_to_imask[pil]; 216 sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_clear);
245} 217}
246 218
247#ifdef CONFIG_SMP 219#ifdef CONFIG_SMP
248static void sun4m_send_ipi(int cpu, int level) 220static void sun4m_send_ipi(int cpu, int level)
249{ 221{
250 unsigned long mask; 222 unsigned long mask = sun4m_get_irqmask(level);
251 223 sbus_writel(mask, &sun4m_irq_percpu[cpu]->set);
252 mask = sun4m_get_irqmask(level);
253 sun4m_interrupts->cpu_intregs[cpu].set = mask;
254} 224}
255 225
256static void sun4m_clear_ipi(int cpu, int level) 226static void sun4m_clear_ipi(int cpu, int level)
257{ 227{
258 unsigned long mask; 228 unsigned long mask = sun4m_get_irqmask(level);
259 229 sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear);
260 mask = sun4m_get_irqmask(level);
261 sun4m_interrupts->cpu_intregs[cpu].clear = mask;
262} 230}
263 231
264static void sun4m_set_udt(int cpu) 232static void sun4m_set_udt(int cpu)
265{ 233{
266 sun4m_interrupts->undirected_target = cpu; 234 sbus_writel(cpu, &sun4m_irq_global->interrupt_target);
267} 235}
268#endif 236#endif
269 237
@@ -347,7 +315,7 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
347 for (i = 0; i < num_cpu_timers; i++) 315 for (i = 0; i < num_cpu_timers; i++)
348 sbus_writel(0, &timers_percpu[i]->l14_limit); 316 sbus_writel(0, &timers_percpu[i]->l14_limit);
349 if (num_cpu_timers == 4) 317 if (num_cpu_timers == 4)
350 sbus_writel(SUN4M_INT_E14, &sun4m_interrupts->set); 318 sbus_writel(SUN4M_INT_E14, &sun4m_irq_global->mask_set);
351 319
352#ifdef CONFIG_SMP 320#ifdef CONFIG_SMP
353 { 321 {
@@ -372,62 +340,38 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn)
372 340
373void __init sun4m_init_IRQ(void) 341void __init sun4m_init_IRQ(void)
374{ 342{
375 int ie_node,i; 343 struct device_node *dp = of_find_node_by_name(NULL, "interrupt");
376 struct linux_prom_registers int_regs[PROMREG_MAX]; 344 int len, i, mid, num_cpu_iregs;
377 int num_regs; 345 const u32 *addr;
378 struct resource r; 346
379 int mid; 347 if (!dp) {
380 348 printk(KERN_ERR "sun4m_init_IRQ: No 'interrupt' node.\n");
381 local_irq_disable(); 349 return;
382 if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
383 (ie_node = prom_getchild (ie_node)) == 0 ||
384 (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) {
385 prom_printf("Cannot find /obio/interrupt node\n");
386 prom_halt();
387 } 350 }
388 num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs, 351
389 sizeof(int_regs)); 352 addr = of_get_property(dp, "address", &len);
390 num_regs = (num_regs/sizeof(struct linux_prom_registers)); 353 if (!addr) {
391 354 printk(KERN_ERR "sun4m_init_IRQ: No 'address' prop.\n");
392 /* Apply the obio ranges to these registers. */ 355 return;
393 prom_apply_obio_ranges(int_regs, num_regs);
394
395 int_regs[4].phys_addr = int_regs[num_regs-1].phys_addr;
396 int_regs[4].reg_size = int_regs[num_regs-1].reg_size;
397 int_regs[4].which_io = int_regs[num_regs-1].which_io;
398 for(ie_node = 1; ie_node < 4; ie_node++) {
399 int_regs[ie_node].phys_addr = int_regs[ie_node-1].phys_addr + PAGE_SIZE;
400 int_regs[ie_node].reg_size = int_regs[ie_node-1].reg_size;
401 int_regs[ie_node].which_io = int_regs[ie_node-1].which_io;
402 } 356 }
403 357
404 memset((char *)&r, 0, sizeof(struct resource)); 358 num_cpu_iregs = (len / sizeof(u32)) - 1;
405 /* Map the interrupt registers for all possible cpus. */ 359 for (i = 0; i < num_cpu_iregs; i++) {
406 r.flags = int_regs[0].which_io; 360 sun4m_irq_percpu[i] = (void __iomem *)
407 r.start = int_regs[0].phys_addr; 361 (unsigned long) addr[i];
408 sun4m_interrupts = (struct sun4m_intregs *) of_ioremap(&r, 0, 362 }
409 PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu"); 363 sun4m_irq_global = (void __iomem *)
364 (unsigned long) addr[num_cpu_iregs];
410 365
411 /* Map the system interrupt control registers. */ 366 local_irq_disable();
412 r.flags = int_regs[4].which_io;
413 r.start = int_regs[4].phys_addr;
414 of_ioremap(&r, 0, int_regs[4].reg_size, "interrupts_system");
415 367
416 sun4m_interrupts->set = ~SUN4M_INT_MASKALL; 368 sbus_writel(~SUN4M_INT_MASKALL, &sun4m_irq_global->mask_set);
417 for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++) 369 for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++)
418 sun4m_interrupts->cpu_intregs[mid].clear = ~0x17fff; 370 sbus_writel(~0x17fff, &sun4m_irq_percpu[mid]->clear);
419 371
420 if (!cpu_find_by_instance(1, NULL, NULL)) { 372 if (num_cpu_iregs == 4) {
421 /* system wide interrupts go to cpu 0, this should always 373 irq_rcvreg = (unsigned long *) &sun4m_irq_global->interrupt_target;
422 * be safe because it is guaranteed to be fitted or OBP doesn't 374 sbus_writel(0, &sun4m_irq_global->interrupt_target);
423 * come up
424 *
425 * Not sure, but writing here on SLAVIO systems may puke
426 * so I don't do it unless there is more than 1 cpu.
427 */
428 irq_rcvreg = (unsigned long *)
429 &sun4m_interrupts->undirected_target;
430 sun4m_interrupts->undirected_target = 0;
431 } 375 }
432 BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM); 376 BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM);
433 BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM); 377 BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM);
@@ -442,5 +386,6 @@ void __init sun4m_init_IRQ(void)
442 BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM); 386 BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM);
443 BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM); 387 BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM);
444#endif 388#endif
389
445 /* Cannot enable interrupts until OBP ticker is disabled. */ 390 /* Cannot enable interrupts until OBP ticker is disabled. */
446} 391}