diff options
author | oftedal <oftedal@gmail.com> | 2011-06-01 06:43:50 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-06-07 19:06:32 -0400 |
commit | 5fba17084e5d1b00bf24e17b2b580cfa7705e7be (patch) | |
tree | 522a070938752ceb822ce9b6b270df6bf7e6cfde /arch | |
parent | 8c47f8d07e16034dfbf736bb4478809aba8a53f1 (diff) |
Restructure sun4d_build_device_irq so that timer interrupts can be allocated
sun4d_build_device_irq was called without a valid platform_device when
the system timer was initialized on sun4d systems. This caused a NULL
pointer crash.
Josip Rodin suggested that the current sun4d_build_device_irq should be
split into two functions. So that the timer initialization could skip
the slot and sbus interface detection code in sun4d_build_device_irq, as
this does not make sence due to the timer interrupts not being generated
from a device located on sbus.
Signed-off-by: Kjetil Oftedal <oftedal@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/sparc/kernel/sun4d_irq.c | 78 |
1 files changed, 54 insertions, 24 deletions
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c index a9ea60eb2c10..487c1bb374f5 100644 --- a/arch/sparc/kernel/sun4d_irq.c +++ b/arch/sparc/kernel/sun4d_irq.c | |||
@@ -299,19 +299,53 @@ static void __init sun4d_load_profile_irqs(void) | |||
299 | } | 299 | } |
300 | } | 300 | } |
301 | 301 | ||
302 | unsigned int _sun4d_build_device_irq(unsigned int real_irq, | ||
303 | unsigned int pil, | ||
304 | unsigned int board) | ||
305 | { | ||
306 | struct sun4d_handler_data *handler_data; | ||
307 | unsigned int irq; | ||
308 | |||
309 | irq = irq_alloc(real_irq, pil); | ||
310 | if (irq == 0) { | ||
311 | prom_printf("IRQ: allocate for %d %d %d failed\n", | ||
312 | real_irq, pil, board); | ||
313 | goto err_out; | ||
314 | } | ||
315 | |||
316 | handler_data = irq_get_handler_data(irq); | ||
317 | if (unlikely(handler_data)) | ||
318 | goto err_out; | ||
319 | |||
320 | handler_data = kzalloc(sizeof(struct sun4d_handler_data), GFP_ATOMIC); | ||
321 | if (unlikely(!handler_data)) { | ||
322 | prom_printf("IRQ: kzalloc(sun4d_handler_data) failed.\n"); | ||
323 | prom_halt(); | ||
324 | } | ||
325 | handler_data->cpuid = board_to_cpu[board]; | ||
326 | handler_data->real_irq = real_irq; | ||
327 | irq_set_chip_and_handler_name(irq, &sun4d_irq, | ||
328 | handle_level_irq, "level"); | ||
329 | irq_set_handler_data(irq, handler_data); | ||
330 | |||
331 | err_out: | ||
332 | return irq; | ||
333 | } | ||
334 | |||
335 | |||
336 | |||
302 | unsigned int sun4d_build_device_irq(struct platform_device *op, | 337 | unsigned int sun4d_build_device_irq(struct platform_device *op, |
303 | unsigned int real_irq) | 338 | unsigned int real_irq) |
304 | { | 339 | { |
305 | struct device_node *dp = op->dev.of_node; | 340 | struct device_node *dp = op->dev.of_node; |
306 | struct device_node *io_unit, *sbi = dp->parent; | 341 | struct device_node *io_unit, *sbi = dp->parent; |
307 | const struct linux_prom_registers *regs; | 342 | const struct linux_prom_registers *regs; |
308 | struct sun4d_handler_data *handler_data; | ||
309 | unsigned int pil; | 343 | unsigned int pil; |
310 | unsigned int irq; | 344 | unsigned int irq; |
311 | int board, slot; | 345 | int board, slot; |
312 | int sbusl; | 346 | int sbusl; |
313 | 347 | ||
314 | irq = 0; | 348 | irq = real_irq; |
315 | while (sbi) { | 349 | while (sbi) { |
316 | if (!strcmp(sbi->name, "sbi")) | 350 | if (!strcmp(sbi->name, "sbi")) |
317 | break; | 351 | break; |
@@ -348,29 +382,17 @@ unsigned int sun4d_build_device_irq(struct platform_device *op, | |||
348 | else | 382 | else |
349 | pil = real_irq; | 383 | pil = real_irq; |
350 | 384 | ||
351 | irq = irq_alloc(real_irq, pil); | 385 | 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: | 386 | err_out: |
371 | return real_irq; | 387 | return irq; |
372 | } | 388 | } |
373 | 389 | ||
390 | unsigned int sun4d_build_timer_irq(unsigned int board, unsigned int real_irq) | ||
391 | { | ||
392 | return _sun4d_build_device_irq(real_irq, real_irq, board); | ||
393 | } | ||
394 | |||
395 | |||
374 | static void __init sun4d_fixup_trap_table(void) | 396 | static void __init sun4d_fixup_trap_table(void) |
375 | { | 397 | { |
376 | #ifdef CONFIG_SMP | 398 | #ifdef CONFIG_SMP |
@@ -402,6 +424,7 @@ static void __init sun4d_init_timers(irq_handler_t counter_fn) | |||
402 | unsigned int irq; | 424 | unsigned int irq; |
403 | const u32 *reg; | 425 | const u32 *reg; |
404 | int err; | 426 | int err; |
427 | int board; | ||
405 | 428 | ||
406 | dp = of_find_node_by_name(NULL, "cpu-unit"); | 429 | dp = of_find_node_by_name(NULL, "cpu-unit"); |
407 | if (!dp) { | 430 | if (!dp) { |
@@ -414,12 +437,19 @@ static void __init sun4d_init_timers(irq_handler_t counter_fn) | |||
414 | * bootbus. | 437 | * bootbus. |
415 | */ | 438 | */ |
416 | reg = of_get_property(dp, "reg", NULL); | 439 | reg = of_get_property(dp, "reg", NULL); |
417 | of_node_put(dp); | ||
418 | if (!reg) { | 440 | if (!reg) { |
419 | prom_printf("sun4d_init_timers: No reg property\n"); | 441 | prom_printf("sun4d_init_timers: No reg property\n"); |
420 | prom_halt(); | 442 | prom_halt(); |
421 | } | 443 | } |
422 | 444 | ||
445 | board = of_getintprop_default(dp, "board#", -1); | ||
446 | if (board == -1) { | ||
447 | prom_printf("sun4d_init_timers: No board# property on cpu-unit\n"); | ||
448 | prom_halt(); | ||
449 | } | ||
450 | |||
451 | of_node_put(dp); | ||
452 | |||
423 | res.start = reg[1]; | 453 | res.start = reg[1]; |
424 | res.end = reg[2] - 1; | 454 | res.end = reg[2] - 1; |
425 | res.flags = reg[0] & 0xff; | 455 | res.flags = reg[0] & 0xff; |
@@ -434,7 +464,7 @@ static void __init sun4d_init_timers(irq_handler_t counter_fn) | |||
434 | 464 | ||
435 | master_l10_counter = &sun4d_timers->l10_cur_count; | 465 | master_l10_counter = &sun4d_timers->l10_cur_count; |
436 | 466 | ||
437 | irq = sun4d_build_device_irq(NULL, SUN4D_TIMER_IRQ); | 467 | irq = sun4d_build_timer_irq(board, SUN4D_TIMER_IRQ); |
438 | err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL); | 468 | err = request_irq(irq, counter_fn, IRQF_TIMER, "timer", NULL); |
439 | if (err) { | 469 | if (err) { |
440 | prom_printf("sun4d_init_timers: request_irq() failed with %d\n", | 470 | prom_printf("sun4d_init_timers: request_irq() failed with %d\n", |