lkml.org 
[lkml]   [2017]   [Oct]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 13/17] clocksource/drivers/arm_arch_timer: Validate CNTFRQ after enabling frame
    Date
    From: Ard Biesheuvel <ard.biesheuvel@linaro.org>

    The ACPI GTDT code validates the CNTFRQ field of each MMIO timer
    frame against the CNTFRQ system register of the current CPU, to
    ensure that they are equal, which is mandated by the architecture.

    However, reading the CNTFRQ field of a frame is not possible until
    the RFRQ bit in the frame's CNTACRn register is set, and doing so
    before that willl produce the following error:

    arch_timer: [Firmware Bug]: CNTFRQ mismatch: frame @ 0x00000000e0be0000: (0x00000000), CPU: (0x0ee6b280)
    arch_timer: Disabling MMIO timers due to CNTFRQ mismatch
    arch_timer: Failed to initialize memory-mapped timer.

    The reason is that the CNTFRQ field is RES0 if access is not enabled.

    So move the validation of CNTFRQ into the loop that iterates over the
    timers to find the best frame, but defer it until after we have selected
    the best frame, which should also have enabled the RFRQ bit.

    Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
    Signed-off-by: Mark Rutland <mark.rutland@arm.com>
    Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
    ---
    drivers/clocksource/arm_arch_timer.c | 38 ++++++++++++++++++++----------------
    1 file changed, 21 insertions(+), 17 deletions(-)

    diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
    index fd4b7f6..14e2419 100644
    --- a/drivers/clocksource/arm_arch_timer.c
    +++ b/drivers/clocksource/arm_arch_timer.c
    @@ -1268,10 +1268,6 @@ arch_timer_mem_find_best_frame(struct arch_timer_mem *timer_mem)

    iounmap(cntctlbase);

    - if (!best_frame)
    - pr_err("Unable to find a suitable frame in timer @ %pa\n",
    - &timer_mem->cntctlbase);
    -
    return best_frame;
    }

    @@ -1372,6 +1368,8 @@ static int __init arch_timer_mem_of_init(struct device_node *np)

    frame = arch_timer_mem_find_best_frame(timer_mem);
    if (!frame) {
    + pr_err("Unable to find a suitable frame in timer @ %pa\n",
    + &timer_mem->cntctlbase);
    ret = -EINVAL;
    goto out;
    }
    @@ -1420,7 +1418,7 @@ arch_timer_mem_verify_cntfrq(struct arch_timer_mem *timer_mem)
    static int __init arch_timer_mem_acpi_init(int platform_timer_count)
    {
    struct arch_timer_mem *timers, *timer;
    - struct arch_timer_mem_frame *frame;
    + struct arch_timer_mem_frame *frame, *best_frame = NULL;
    int timer_count, i, ret = 0;

    timers = kcalloc(platform_timer_count, sizeof(*timers),
    @@ -1432,14 +1430,6 @@ static int __init arch_timer_mem_acpi_init(int platform_timer_count)
    if (ret || !timer_count)
    goto out;

    - for (i = 0; i < timer_count; i++) {
    - ret = arch_timer_mem_verify_cntfrq(&timers[i]);
    - if (ret) {
    - pr_err("Disabling MMIO timers due to CNTFRQ mismatch\n");
    - goto out;
    - }
    - }
    -
    /*
    * While unlikely, it's theoretically possible that none of the frames
    * in a timer expose the combination of feature we want.
    @@ -1448,12 +1438,26 @@ static int __init arch_timer_mem_acpi_init(int platform_timer_count)
    timer = &timers[i];

    frame = arch_timer_mem_find_best_frame(timer);
    - if (frame)
    - break;
    + if (!best_frame)
    + best_frame = frame;
    +
    + ret = arch_timer_mem_verify_cntfrq(timer);
    + if (ret) {
    + pr_err("Disabling MMIO timers due to CNTFRQ mismatch\n");
    + goto out;
    + }
    +
    + if (!best_frame) /* implies !frame */
    + /*
    + * Only complain about missing suitable frames if we
    + * haven't already found one in a previous iteration.
    + */
    + pr_err("Unable to find a suitable frame in timer @ %pa\n",
    + &timer->cntctlbase);
    }

    - if (frame)
    - ret = arch_timer_mem_frame_register(frame);
    + if (best_frame)
    + ret = arch_timer_mem_frame_register(best_frame);
    out:
    kfree(timers);
    return ret;
    --
    2.7.4
    \
     
     \ /
      Last update: 2017-10-29 22:26    [W:4.261 / U:0.220 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site