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 | |
| 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>
| -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", |
