lkml.org 
[lkml]   [2010]   [Mar]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[patch 021/123] clocksource: Fix up a registration/IRQ race in the sh drivers.
    2.6.33-stable review patch.  If anyone has any objections, please let me know.

    -----------------

    From: Paul Mundt <lethal@linux-sh.org>

    commit da64c2a8dee66ca03f4f3e15d84be7bedf73db3d upstream.

    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>
    Signed-off-by: Paul Mundt <lethal@linux-sh.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

    ---
    drivers/clocksource/sh_cmt.c | 32 +++++++++++++++++++-------------
    drivers/clocksource/sh_mtu2.c | 6 +++---
    drivers/clocksource/sh_tmu.c | 6 +++---
    3 files changed, 25 insertions(+), 19 deletions(-)

    --- a/drivers/clocksource/sh_cmt.c
    +++ b/drivers/clocksource/sh_cmt.c
    @@ -603,18 +603,13 @@ static int sh_cmt_setup(struct sh_cmt_pr
    p->irqaction.handler = sh_cmt_interrupt;
    p->irqaction.dev_id = p;
    p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL;
    - ret = setup_irq(irq, &p->irqaction);
    - if (ret) {
    - pr_err("sh_cmt: failed to request irq %d\n", irq);
    - goto err1;
    - }

    /* get hold of clock */
    p->clk = clk_get(&p->pdev->dev, cfg->clk);
    if (IS_ERR(p->clk)) {
    pr_err("sh_cmt: cannot get clock \"%s\"\n", cfg->clk);
    ret = PTR_ERR(p->clk);
    - goto err2;
    + goto err1;
    }

    if (resource_size(res) == 6) {
    @@ -627,14 +622,25 @@ static int sh_cmt_setup(struct sh_cmt_pr
    p->clear_bits = ~0xc000;
    }

    - return sh_cmt_register(p, cfg->name,
    - cfg->clockevent_rating,
    - cfg->clocksource_rating);
    - err2:
    - remove_irq(irq, &p->irqaction);
    - err1:
    + ret = sh_cmt_register(p, cfg->name,
    + cfg->clockevent_rating,
    + cfg->clocksource_rating);
    + if (ret) {
    + pr_err("sh_cmt: registration failed\n");
    + goto err1;
    + }
    +
    + ret = setup_irq(irq, &p->irqaction);
    + if (ret) {
    + pr_err("sh_cmt: failed to request irq %d\n", irq);
    + goto err1;
    + }
    +
    + return 0;
    +
    +err1:
    iounmap(p->mapbase);
    - err0:
    +err0:
    return ret;
    }

    --- a/drivers/clocksource/sh_mtu2.c
    +++ b/drivers/clocksource/sh_mtu2.c
    @@ -221,15 +221,15 @@ static void sh_mtu2_register_clockevent(
    ced->cpumask = cpumask_of(0);
    ced->set_mode = sh_mtu2_clock_event_mode;

    + pr_info("sh_mtu2: %s used for clock events\n", ced->name);
    + clockevents_register_device(ced);
    +
    ret = setup_irq(p->irqaction.irq, &p->irqaction);
    if (ret) {
    pr_err("sh_mtu2: failed to request irq %d\n",
    p->irqaction.irq);
    return;
    }
    -
    - pr_info("sh_mtu2: %s used for clock events\n", ced->name);
    - clockevents_register_device(ced);
    }

    static int sh_mtu2_register(struct sh_mtu2_priv *p, char *name,
    --- a/drivers/clocksource/sh_tmu.c
    +++ b/drivers/clocksource/sh_tmu.c
    @@ -323,15 +323,15 @@ static void sh_tmu_register_clockevent(s
    ced->set_next_event = sh_tmu_clock_event_next;
    ced->set_mode = sh_tmu_clock_event_mode;

    + pr_info("sh_tmu: %s used for clock events\n", ced->name);
    + clockevents_register_device(ced);
    +
    ret = setup_irq(p->irqaction.irq, &p->irqaction);
    if (ret) {
    pr_err("sh_tmu: failed to request irq %d\n",
    p->irqaction.irq);
    return;
    }
    -
    - pr_info("sh_tmu: %s used for clock events\n", ced->name);
    - clockevents_register_device(ced);
    }

    static int sh_tmu_register(struct sh_tmu_priv *p, char *name,



    \
     
     \ /
      Last update: 2010-03-13 02:35    [W:0.026 / U:30.848 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site