aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource/sh_cmt.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2010-02-25 02:37:46 -0500
committerPaul Mundt <lethal@linux-sh.org>2010-02-25 02:37:46 -0500
commitda64c2a8dee66ca03f4f3e15d84be7bedf73db3d (patch)
tree8de9d4de358447a80f731a49a689c84bca42abf5 /drivers/clocksource/sh_cmt.c
parent29463c28a553e1959ec45cc8ad9d2eb434663cdf (diff)
clocksource: Fix up a registration/IRQ race in the sh drivers.
All of the SH clocksource drivers follow the scheme that the IRQ is setup prior to registering the clockevent. The interrupt handler in the clockevent cases looks to the event handler function pointer being filled in by the registration code, permitting us to get in to situations where asserted IRQs step in to the handler before registration has had a chance to complete and hitting a NULL pointer deref. In practice this is not an issue for most platforms, but some of them with fairly special loaders (or that are chain-loading from another kernel) may enter in to this situation. This fixes up the oops reported by Rafael on hp6xx. Reported-and-tested-by: Rafael Ignacio Zurita <rafaelignacio.zurita@gmail.com> Cc: stable@kernel.org Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'drivers/clocksource/sh_cmt.c')
-rw-r--r--drivers/clocksource/sh_cmt.c32
1 files changed, 19 insertions, 13 deletions
diff --git a/drivers/clocksource/sh_cmt.c b/drivers/clocksource/sh_cmt.c
index 6b3e0c2f33e2..6fe4f7701188 100644
--- a/drivers/clocksource/sh_cmt.c
+++ b/drivers/clocksource/sh_cmt.c
@@ -603,18 +603,13 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
603 p->irqaction.handler = sh_cmt_interrupt; 603 p->irqaction.handler = sh_cmt_interrupt;
604 p->irqaction.dev_id = p; 604 p->irqaction.dev_id = p;
605 p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL; 605 p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL;
606 ret = setup_irq(irq, &p->irqaction);
607 if (ret) {
608 pr_err("sh_cmt: failed to request irq %d\n", irq);
609 goto err1;
610 }
611 606
612 /* get hold of clock */ 607 /* get hold of clock */
613 p->clk = clk_get(&p->pdev->dev, cfg->clk); 608 p->clk = clk_get(&p->pdev->dev, cfg->clk);
614 if (IS_ERR(p->clk)) { 609 if (IS_ERR(p->clk)) {
615 pr_err("sh_cmt: cannot get clock \"%s\"\n", cfg->clk); 610 pr_err("sh_cmt: cannot get clock \"%s\"\n", cfg->clk);
616 ret = PTR_ERR(p->clk); 611 ret = PTR_ERR(p->clk);
617 goto err2; 612 goto err1;
618 } 613 }
619 614
620 if (resource_size(res) == 6) { 615 if (resource_size(res) == 6) {
@@ -627,14 +622,25 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
627 p->clear_bits = ~0xc000; 622 p->clear_bits = ~0xc000;
628 } 623 }
629 624
630 return sh_cmt_register(p, cfg->name, 625 ret = sh_cmt_register(p, cfg->name,
631 cfg->clockevent_rating, 626 cfg->clockevent_rating,
632 cfg->clocksource_rating); 627 cfg->clocksource_rating);
633 err2: 628 if (ret) {
634 remove_irq(irq, &p->irqaction); 629 pr_err("sh_cmt: registration failed\n");
635 err1: 630 goto err1;
631 }
632
633 ret = setup_irq(irq, &p->irqaction);
634 if (ret) {
635 pr_err("sh_cmt: failed to request irq %d\n", irq);
636 goto err1;
637 }
638
639 return 0;
640
641err1:
636 iounmap(p->mapbase); 642 iounmap(p->mapbase);
637 err0: 643err0:
638 return ret; 644 return ret;
639} 645}
640 646