diff options
Diffstat (limited to 'arch/sparc/kernel/sun4d_irq.c')
-rw-r--r-- | arch/sparc/kernel/sun4d_irq.c | 126 |
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 | ||
298 | unsigned 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 | |||
327 | err_out: | ||
328 | return irq; | ||
329 | } | ||
330 | |||
331 | |||
332 | |||
302 | unsigned int sun4d_build_device_irq(struct platform_device *op, | 333 | unsigned 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 | |||
370 | err_out: | 392 | err_out: |
371 | return real_irq; | 393 | return irq; |
372 | } | 394 | } |
373 | 395 | ||
396 | unsigned 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 | |||
374 | static void __init sun4d_fixup_trap_table(void) | 402 | static 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", |