diff options
author | Robin Murphy <robin.murphy@arm.com> | 2016-02-01 07:00:48 -0500 |
---|---|---|
committer | Daniel Lezcano <daniel.lezcano@linaro.org> | 2016-02-25 08:30:15 -0500 |
commit | e392d603f61767cb2de4d82bb55a035918f8342c (patch) | |
tree | 1051148f6bec4a0bea199d2302858621a9ce9c5d /drivers/clocksource/arm_arch_timer.c | |
parent | bbf66d897adf2bb0c310db96c97e8db6369f39e1 (diff) |
clocksource/drivers/arm_arch_timer: Enable and verify MMIO access
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>
Diffstat (limited to 'drivers/clocksource/arm_arch_timer.c')
-rw-r--r-- | drivers/clocksource/arm_arch_timer.c | 36 |
1 files changed, 28 insertions, 8 deletions
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index c64d543d64bf..7c567f0c87f5 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c | |||
@@ -32,6 +32,14 @@ | |||
32 | #define CNTTIDR 0x08 | 32 | #define CNTTIDR 0x08 |
33 | #define CNTTIDR_VIRT(n) (BIT(1) << ((n) * 4)) | 33 | #define CNTTIDR_VIRT(n) (BIT(1) << ((n) * 4)) |
34 | 34 | ||
35 | #define CNTACR(n) (0x40 + ((n) * 4)) | ||
36 | #define CNTACR_RPCT BIT(0) | ||
37 | #define CNTACR_RVCT BIT(1) | ||
38 | #define CNTACR_RFRQ BIT(2) | ||
39 | #define CNTACR_RVOFF BIT(3) | ||
40 | #define CNTACR_RWVT BIT(4) | ||
41 | #define CNTACR_RWPT BIT(5) | ||
42 | |||
35 | #define CNTVCT_LO 0x08 | 43 | #define CNTVCT_LO 0x08 |
36 | #define CNTVCT_HI 0x0c | 44 | #define CNTVCT_HI 0x0c |
37 | #define CNTFRQ 0x10 | 45 | #define CNTFRQ 0x10 |
@@ -757,7 +765,6 @@ static void __init arch_timer_mem_init(struct device_node *np) | |||
757 | } | 765 | } |
758 | 766 | ||
759 | cnttidr = readl_relaxed(cntctlbase + CNTTIDR); | 767 | cnttidr = readl_relaxed(cntctlbase + CNTTIDR); |
760 | iounmap(cntctlbase); | ||
761 | 768 | ||
762 | /* | 769 | /* |
763 | * Try to find a virtual capable frame. Otherwise fall back to a | 770 | * Try to find a virtual capable frame. Otherwise fall back to a |
@@ -765,20 +772,31 @@ static void __init arch_timer_mem_init(struct device_node *np) | |||
765 | */ | 772 | */ |
766 | for_each_available_child_of_node(np, frame) { | 773 | for_each_available_child_of_node(np, frame) { |
767 | int n; | 774 | int n; |
775 | u32 cntacr; | ||
768 | 776 | ||
769 | if (of_property_read_u32(frame, "frame-number", &n)) { | 777 | if (of_property_read_u32(frame, "frame-number", &n)) { |
770 | pr_err("arch_timer: Missing frame-number\n"); | 778 | pr_err("arch_timer: Missing frame-number\n"); |
771 | of_node_put(best_frame); | ||
772 | of_node_put(frame); | 779 | of_node_put(frame); |
773 | return; | 780 | goto out; |
774 | } | 781 | } |
775 | 782 | ||
776 | if (cnttidr & CNTTIDR_VIRT(n)) { | 783 | /* Try enabling everything, and see what sticks */ |
784 | cntacr = CNTACR_RFRQ | CNTACR_RWPT | CNTACR_RPCT | | ||
785 | CNTACR_RWVT | CNTACR_RVOFF | CNTACR_RVCT; | ||
786 | writel_relaxed(cntacr, cntctlbase + CNTACR(n)); | ||
787 | cntacr = readl_relaxed(cntctlbase + CNTACR(n)); | ||
788 | |||
789 | if ((cnttidr & CNTTIDR_VIRT(n)) && | ||
790 | !(~cntacr & (CNTACR_RWVT | CNTACR_RVCT))) { | ||
777 | of_node_put(best_frame); | 791 | of_node_put(best_frame); |
778 | best_frame = frame; | 792 | best_frame = frame; |
779 | arch_timer_mem_use_virtual = true; | 793 | arch_timer_mem_use_virtual = true; |
780 | break; | 794 | break; |
781 | } | 795 | } |
796 | |||
797 | if (~cntacr & (CNTACR_RWPT | CNTACR_RPCT)) | ||
798 | continue; | ||
799 | |||
782 | of_node_put(best_frame); | 800 | of_node_put(best_frame); |
783 | best_frame = of_node_get(frame); | 801 | best_frame = of_node_get(frame); |
784 | } | 802 | } |
@@ -786,24 +804,26 @@ static void __init arch_timer_mem_init(struct device_node *np) | |||
786 | base = arch_counter_base = of_iomap(best_frame, 0); | 804 | base = arch_counter_base = of_iomap(best_frame, 0); |
787 | if (!base) { | 805 | if (!base) { |
788 | pr_err("arch_timer: Can't map frame's registers\n"); | 806 | pr_err("arch_timer: Can't map frame's registers\n"); |
789 | of_node_put(best_frame); | 807 | goto out; |
790 | return; | ||
791 | } | 808 | } |
792 | 809 | ||
793 | if (arch_timer_mem_use_virtual) | 810 | if (arch_timer_mem_use_virtual) |
794 | irq = irq_of_parse_and_map(best_frame, 1); | 811 | irq = irq_of_parse_and_map(best_frame, 1); |
795 | else | 812 | else |
796 | irq = irq_of_parse_and_map(best_frame, 0); | 813 | irq = irq_of_parse_and_map(best_frame, 0); |
797 | of_node_put(best_frame); | 814 | |
798 | if (!irq) { | 815 | if (!irq) { |
799 | pr_err("arch_timer: Frame missing %s irq", | 816 | pr_err("arch_timer: Frame missing %s irq", |
800 | arch_timer_mem_use_virtual ? "virt" : "phys"); | 817 | arch_timer_mem_use_virtual ? "virt" : "phys"); |
801 | return; | 818 | goto out; |
802 | } | 819 | } |
803 | 820 | ||
804 | arch_timer_detect_rate(base, np); | 821 | arch_timer_detect_rate(base, np); |
805 | arch_timer_mem_register(base, irq); | 822 | arch_timer_mem_register(base, irq); |
806 | arch_timer_common_init(); | 823 | arch_timer_common_init(); |
824 | out: | ||
825 | iounmap(cntctlbase); | ||
826 | of_node_put(best_frame); | ||
807 | } | 827 | } |
808 | CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", | 828 | CLOCKSOURCE_OF_DECLARE(armv7_arch_timer_mem, "arm,armv7-timer-mem", |
809 | arch_timer_mem_init); | 829 | arch_timer_mem_init); |