diff options
author | Geert Uytterhoeven <geert+renesas@glider.be> | 2015-02-23 10:37:24 -0500 |
---|---|---|
committer | Eduardo Valentin <edubezval@gmail.com> | 2015-02-24 13:56:42 -0500 |
commit | 0b37a83a91e885250c68546ce7271ce722120c99 (patch) | |
tree | 30af05e3cf65ae0ca9ecca44f02a473c55a40e2a | |
parent | 12ca7188468ee29c4e717f73db4bf43c90954fc7 (diff) |
thermal: rcar: Fix race condition between init and interrupt
As soon as the interrupt has been enabled by devm_request_irq(), the
interrupt routine may be called, depending on the current status of the
hardware.
However, at that point rcar_thermal_common hasn't been initialized
complely yet. E.g. rcar_thermal_common.base is still NULL, causing a
NULL pointer dereference:
Unable to handle kernel NULL pointer dereference at virtual address 0000000c
pgd = c0004000
[0000000c] *pgd=00000000
Internal error: Oops: 5 [#1] SMP ARM
CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.19.0-rc7-ape6evm-04564-gb6e46cb7cbe82389 #30
Hardware name: Generic R8A73A4 (Flattened Device Tree)
task: ee8953c0 ti: ee896000 task.ti: ee896000
PC is at rcar_thermal_irq+0x1c/0xf0
LR is at _raw_spin_lock_irqsave+0x48/0x54
Postpone the call to devm_request_irq() until all initialization has
been done to fix this.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Acked-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Eduardo Valentin <edubezval@gmail.com>
-rw-r--r-- | drivers/thermal/rcar_thermal.c | 22 |
1 files changed, 9 insertions, 13 deletions
diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c index 2580a4872f90..3c2c1720ba4a 100644 --- a/drivers/thermal/rcar_thermal.c +++ b/drivers/thermal/rcar_thermal.c | |||
@@ -387,21 +387,9 @@ static int rcar_thermal_probe(struct platform_device *pdev) | |||
387 | 387 | ||
388 | irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 388 | irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
389 | if (irq) { | 389 | if (irq) { |
390 | int ret; | ||
391 | |||
392 | /* | 390 | /* |
393 | * platform has IRQ support. | 391 | * platform has IRQ support. |
394 | * Then, driver uses common registers | 392 | * Then, driver uses common registers |
395 | */ | ||
396 | |||
397 | ret = devm_request_irq(dev, irq->start, rcar_thermal_irq, 0, | ||
398 | dev_name(dev), common); | ||
399 | if (ret) { | ||
400 | dev_err(dev, "irq request failed\n "); | ||
401 | return ret; | ||
402 | } | ||
403 | |||
404 | /* | ||
405 | * rcar_has_irq_support() will be enabled | 393 | * rcar_has_irq_support() will be enabled |
406 | */ | 394 | */ |
407 | res = platform_get_resource(pdev, IORESOURCE_MEM, mres++); | 395 | res = platform_get_resource(pdev, IORESOURCE_MEM, mres++); |
@@ -456,8 +444,16 @@ static int rcar_thermal_probe(struct platform_device *pdev) | |||
456 | } | 444 | } |
457 | 445 | ||
458 | /* enable temperature comparation */ | 446 | /* enable temperature comparation */ |
459 | if (irq) | 447 | if (irq) { |
448 | ret = devm_request_irq(dev, irq->start, rcar_thermal_irq, 0, | ||
449 | dev_name(dev), common); | ||
450 | if (ret) { | ||
451 | dev_err(dev, "irq request failed\n "); | ||
452 | goto error_unregister; | ||
453 | } | ||
454 | |||
460 | rcar_thermal_common_write(common, ENR, enr_bits); | 455 | rcar_thermal_common_write(common, ENR, enr_bits); |
456 | } | ||
461 | 457 | ||
462 | platform_set_drvdata(pdev, common); | 458 | platform_set_drvdata(pdev, common); |
463 | 459 | ||