aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel/sun4d_irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc/kernel/sun4d_irq.c')
-rw-r--r--arch/sparc/kernel/sun4d_irq.c126
1 files changed, 81 insertions, 45 deletions
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
index a9ea60eb2c10..1d13c5bda0b1 100644
--- a/arch/sparc/kernel/sun4d_irq.c
+++ b/arch/sparc/kernel/sun4d_irq.c
@@ -103,10 +103,9 @@ static void sun4d_sbus_handler_irq(int sbusl)
103 103
104 sbil = (sbusl << 2); 104 sbil = (sbusl << 2);
105 /* Loop for each pending SBI */ 105 /* Loop for each pending SBI */
106 for (sbino = 0; bus_mask; sbino++) { 106 for (sbino = 0; bus_mask; sbino++, bus_mask >>= 1) {
107 unsigned int idx, mask; 107 unsigned int idx, mask;
108 108
109 bus_mask >>= 1;
110 if (!(bus_mask & 1)) 109 if (!(bus_mask & 1))
111 continue; 110 continue;
112 /* XXX This seems to ACK the irq twice. acquire_sbi() 111 /* XXX This seems to ACK the irq twice. acquire_sbi()
@@ -118,19 +117,16 @@ static void sun4d_sbus_handler_irq(int sbusl)
118 mask &= (0xf << sbil); 117 mask &= (0xf << sbil);
119 118
120 /* Loop for each pending SBI slot */ 119 /* Loop for each pending SBI slot */
121 idx = 0;
122 slot = (1 << sbil); 120 slot = (1 << sbil);
123 while (mask != 0) { 121 for (idx = 0; mask != 0; idx++, slot <<= 1) {
124 unsigned int pil; 122 unsigned int pil;
125 struct irq_bucket *p; 123 struct irq_bucket *p;
126 124
127 idx++;
128 slot <<= 1;
129 if (!(mask & slot)) 125 if (!(mask & slot))
130 continue; 126 continue;
131 127
132 mask &= ~slot; 128 mask &= ~slot;
133 pil = sun4d_encode_irq(sbino, sbil, idx); 129 pil = sun4d_encode_irq(sbino, sbusl, idx);
134 130
135 p = irq_map[pil]; 131 p = irq_map[pil];
136 while (p) { 132 while (p) {
@@ -218,10 +214,10 @@ static void sun4d_unmask_irq(struct irq_data *data)
218 214
219#ifdef CONFIG_SMP 215#ifdef CONFIG_SMP
220 spin_lock_irqsave(&sun4d_imsk_lock, flags); 216 spin_lock_irqsave(&sun4d_imsk_lock, flags);
221 cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) | ~(1 << real_irq)); 217 cc_set_imsk_other(cpuid, cc_get_imsk_other(cpuid) & ~(1 << real_irq));
222 spin_unlock_irqrestore(&sun4d_imsk_lock, flags); 218 spin_unlock_irqrestore(&sun4d_imsk_lock, flags);
223#else 219#else
224 cc_set_imsk(cc_get_imsk() | ~(1 << real_irq)); 220 cc_set_imsk(cc_get_imsk() & ~(1 << real_irq));
225#endif 221#endif
226} 222}
227 223
@@ -299,26 +295,68 @@ static void __init sun4d_load_profile_irqs(void)
299 } 295 }
300} 296}
301 297
298unsigned int _sun4d_build_device_irq(unsigned int real_irq,
299 unsigned int pil,
300 unsigned int board)
301{
302 struct sun4d_handler_data *handler_data;
303 unsigned int irq;
304
305 irq = irq_alloc(real_irq, pil);
306 if (irq == 0) {
307 prom_printf("IRQ: allocate for %d %d %d failed\n",
308 real_irq, pil, board);
309 goto err_out;
310 }
311
312 handler_data = irq_get_handler_data(irq);
313 if (unlikely(handler_data))
314 goto err_out;
315
316 handler_data = kzalloc(sizeof(struct sun4d_handler_data), GFP_ATOMIC);
317 if (unlikely(!handler_data)) {
318 prom_printf("IRQ: kzalloc(sun4d_handler_data) failed.\n");
319 prom_halt();
320 }
321 handler_data->cpuid = board_to_cpu[board];
322 handler_data->real_irq = real_irq;
323 irq_set_chip_and_handler_name(irq, &sun4d_irq,
324 handle_level_irq, "level");
325 irq_set_handler_data(irq, handler_data);
326
327err_out:
328 return irq;
329}
330
331
332
302unsigned int sun4d_build_device_irq(struct platform_device *op, 333unsigned int sun4d_build_device_irq(struct platform_device *op,
303 unsigned int real_irq) 334 unsigned int real_irq)
304{ 335{
305 struct device_node *dp = op->dev.of_node; 336 struct device_node *dp = op->dev.of_node;
306 struct device_node *io_unit, *sbi = dp->parent; 337 struct device_node *board_parent, *bus = dp->parent;
338 char *bus_connection;
307 const struct linux_prom_registers *regs; 339 const struct linux_prom_registers *regs;
308 struct sun4d_handler_data *handler_data;
309 unsigned int pil; 340 unsigned int pil;
310 unsigned int irq; 341 unsigned int irq;
311 int board, slot; 342 int board, slot;
312 int sbusl; 343 int sbusl;
313 344
314 irq = 0; 345 irq = real_irq;
315 while (sbi) { 346 while (bus) {
316 if (!strcmp(sbi->name, "sbi")) 347 if (!strcmp(bus->name, "sbi")) {
348 bus_connection = "io-unit";
349 break;
350 }
351
352 if (!strcmp(bus->name, "bootbus")) {
353 bus_connection = "cpu-unit";
317 break; 354 break;
355 }
318 356
319 sbi = sbi->parent; 357 bus = bus->parent;
320 } 358 }
321 if (!sbi) 359 if (!bus)
322 goto err_out; 360 goto err_out;
323 361
324 regs = of_get_property(dp, "reg", NULL); 362 regs = of_get_property(dp, "reg", NULL);
@@ -328,17 +366,19 @@ unsigned int sun4d_build_device_irq(struct platform_device *op,
328 slot = regs->which_io; 366 slot = regs->which_io;
329 367
330 /* 368 /*
331 * If SBI's parent is not io-unit or the io-unit lacks 369 * If Bus nodes parent is not io-unit/cpu-unit or the io-unit/cpu-unit
332 * a "board#" property, something is very wrong. 370 * lacks a "board#" property, something is very wrong.
333 */ 371 */
334 if (!sbi->parent || strcmp(sbi->parent->name, "io-unit")) { 372 if (!bus->parent || strcmp(bus->parent->name, bus_connection)) {
335 printk("%s: Error, parent is not io-unit.\n", sbi->full_name); 373 printk(KERN_ERR "%s: Error, parent is not %s.\n",
374 bus->full_name, bus_connection);
336 goto err_out; 375 goto err_out;
337 } 376 }
338 io_unit = sbi->parent; 377 board_parent = bus->parent;
339 board = of_getintprop_default(io_unit, "board#", -1); 378 board = of_getintprop_default(board_parent, "board#", -1);
340 if (board == -1) { 379 if (board == -1) {
341 printk("%s: Error, lacks board# property.\n", io_unit->full_name); 380 printk(KERN_ERR "%s: Error, lacks board# property.\n",
381 board_parent->full_name);
342 goto err_out; 382 goto err_out;
343 } 383 }
344 384
@@ -348,29 +388,17 @@ unsigned int sun4d_build_device_irq(struct platform_device *op,
348 else 388 else
349 pil = real_irq; 389 pil = real_irq;
350 390
351 irq = irq_alloc(real_irq, pil); 391 irq = _sun4d_build_device_irq(real_irq, pil, board);
352 if (irq == 0)
353 goto err_out;
354
355 handler_data = irq_get_handler_data(irq);
356 if (unlikely(handler_data))
357 goto err_out;
358
359 handler_data = kzalloc(sizeof(struct sun4d_handler_data), GFP_ATOMIC);
360 if (unlikely(!handler_data)) {
361 prom_printf("IRQ: kzalloc(sun4d_handler_data) failed.\n");
362 prom_halt();
363 }
364 handler_data->cpuid = board_to_cpu[board];
365 handler_data->real_irq = real_irq;
366 irq_set_chip_and_handler_name(irq, &sun4d_irq,
367 handle_level_irq, "level");
368 irq_set_handler_data(irq, handler_data);
369
370err_out: 392err_out:
371 return real_irq; 393 return irq;
372} 394}
373 395
396unsigned int sun4d_build_timer_irq(unsigned int board, unsigned int real_irq)
397{
398 return _sun4d_build_device_irq(real_irq, real_irq, board);
399}
400
401
374static void __init sun4d_fixup_trap_table(void) 402static void __init sun4d_fixup_trap_table(void)
375{ 403{
376#ifdef CONFIG_SMP 404#ifdef CONFIG_SMP
@@ -402,6 +430,7 @@ static void __init sun4d_init_timers(irq_handler_t counter_fn)
402 unsigned int irq; 430 unsigned int irq;
403 const u32 *reg; 431 const u32 *reg;
404 int err; 432 int err;
433 int board;
405 434
406 dp = of_find_node_by_name(NULL, "cpu-unit"); 435 dp = of_find_node_by_name(NULL, "cpu-unit");
407 if (!dp) { 436 if (!dp) {
@@ -414,12 +443,19 @@ static void __init sun4d_init_timers(irq_handler_t counter_fn)
414 * bootbus. 443 * bootbus.
415 */ 444 */
416 reg = of_get_property(dp, "reg", NULL); 445 reg = of_get_property(dp, "reg", NULL);
417 of_node_put(dp);
418 if (!reg) { 446 if (!reg) {
419 prom_printf("sun4d_init_timers: No reg property\n"); 447 prom_printf("sun4d_init_timers: No reg property\n");
420 prom_halt(); 448 prom_halt();
421 } 449 }
422 450
451 board = of_getintprop_default(dp, "board#", -1);
452 if (board == -1) {
453 prom_printf("sun4d_init_timers: No board# property on cpu-unit\n");
454 prom_halt();
455 }
456
457 of_node_put(dp);
458
423 res.start = reg[1]; 459 res.start = reg[1];
424 res.end = reg[2] - 1; 460 res.end = reg[2] - 1;
425 res.flags = reg[0] & 0xff; 461 res.flags = reg[0] & 0xff;
@@ -434,7 +470,7 @@ static void __init sun4d_init_timers(irq_handler_t counter_fn)
434 470
435 master_l10_counter = &sun4d_timers->l10_cur_count; 471 master_l10_counter = &sun4d_timers->l10_cur_count;
436 472
437 irq = sun4d_build_device_irq(NULL, SUN4D_TIMER_IRQ); 473 irq = sun4d_build_timer_irq(board, SUN4D_TIMER_IRQ);
438 err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL); 474 err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL);
439 if (err) { 475 if (err) {
440 prom_printf("sun4d_init_timers: request_irq() failed with %d\n", 476 prom_printf("sun4d_init_timers: request_irq() failed with %d\n",