Skip to content

Commit

Permalink
clocksource/drivers/arm_arch_timer: Enable and verify MMIO access
Browse files Browse the repository at this point in the history
So far, we have been blindly assuming that having access to a
memory-mapped timer frame implies that the individual elements of that
frame frame are already enabled. Whilst it's the firmware's job to give
us non-secure access to frames in the first place, we should not rely
on implementations always being generous enough to also configure CNTACR
for those non-secure frames (e.g. [1]).

Explicitly enable feature-level access per-frame, and verify that the
access we want is really implemented before trying to make use of it.

[1]:https://github.com/ARM-software/tf-issues/issues/170

Acked-by: Mark Rutland <mark.rutland@arm.com>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
Tested-by: Stephen Boyd <sboyd@codeaurora.org>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Robin Murphy <robin.murphy@arm.com>
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
  • Loading branch information
Robin Murphy authored and Daniel Lezcano committed Feb 25, 2016
1 parent bbf66d8 commit e392d60
Showing 1 changed file with 28 additions and 8 deletions.
36 changes: 28 additions & 8 deletions drivers/clocksource/arm_arch_timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@
#define CNTTIDR 0x08
#define CNTTIDR_VIRT(n) (BIT(1) << ((n) * 4))

#define CNTACR(n) (0x40 + ((n) * 4))
#define CNTACR_RPCT BIT(0)
#define CNTACR_RVCT BIT(1)
#define CNTACR_RFRQ BIT(2)
#define CNTACR_RVOFF BIT(3)
#define CNTACR_RWVT BIT(4)
#define CNTACR_RWPT BIT(5)

#define CNTVCT_LO 0x08
#define CNTVCT_HI 0x0c
#define CNTFRQ 0x10
Expand Down Expand Up @@ -757,53 +765,65 @@ static void __init arch_timer_mem_init(struct device_node *np)
}

cnttidr = readl_relaxed(cntctlbase + CNTTIDR);
iounmap(cntctlbase);

/*
* Try to find a virtual capable frame. Otherwise fall back to a
* physical capable frame.
*/
for_each_available_child_of_node(np, frame) {
int n;
u32 cntacr;

if (of_property_read_u32(frame, "frame-number", &n)) {
pr_err("arch_timer: Missing frame-number\n");
of_node_put(best_frame);
of_node_put(frame);
return;
goto out;
}

if (cnttidr & CNTTIDR_VIRT(n)) {
/* Try enabling everything, and see what sticks */
cntacr = CNTACR_RFRQ | CNTACR_RWPT | CNTACR_RPCT |
CNTACR_RWVT | CNTACR_RVOFF | CNTACR_RVCT;
writel_relaxed(cntacr, cntctlbase + CNTACR(n));
cntacr = readl_relaxed(cntctlbase + CNTACR(n));

if ((cnttidr & CNTTIDR_VIRT(n)) &&
!(~cntacr & (CNTACR_RWVT | CNTACR_RVCT))) {
of_node_put(best_frame);
best_frame = frame;
arch_timer_mem_use_virtual = true;
break;
}

if (~cntacr & (CNTACR_RWPT | CNTACR_RPCT))
continue;

of_node_put(best_frame);
best_frame = of_node_get(frame);
}

base = arch_counter_base = of_iomap(best_frame, 0);
if (!base) {
pr_err("arch_timer: Can't map frame's registers\n");
of_node_put(best_frame);
return;
goto out;
}

if (arch_timer_mem_use_virtual)
irq = irq_of_parse_and_map(best_frame, 1);
else
irq = irq_of_parse_and_map(best_frame, 0);
of_node_put(best_frame);

if (!irq) {
pr_err("arch_timer: Frame missing %s irq",
arch_timer_mem_use_virtual ? "virt" : "phys");
return;
goto out;
}

arch_timer_detect_rate(base, np);
arch_timer_mem_register(base, irq);
arch_timer_common_init();
out:
iounmap(cntctlbase);
of_node_put(best_frame);
}
CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem",
arch_timer_mem_init);
Expand Down

0 comments on commit e392d60

Please sign in to comment.