Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clocksource/drivers/arm_arch_timer: Work around broken CVAL implementations

The Applied Micro XGene-1 SoC has a busted implementation of the
CVAL register: it looks like it is based on TVAL instead of the
other way around. The net effect of this implementation blunder
is that the maximum deadline you can program in the timer is
32bit wide.

Use a MIDR check to notice the broken CPU, and reduce the width
of the timer to 32bit.

Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20211017124225.3018098-10-maz@kernel.org
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>

authored by

Marc Zyngier and committed by
Daniel Lezcano
012f1885 30aa08da

+27 -1
+27 -1
drivers/clocksource/arm_arch_timer.c
··· 780 780 return 0; 781 781 } 782 782 783 + static u64 __arch_timer_check_delta(void) 784 + { 785 + #ifdef CONFIG_ARM64 786 + const struct midr_range broken_cval_midrs[] = { 787 + /* 788 + * XGene-1 implements CVAL in terms of TVAL, meaning 789 + * that the maximum timer range is 32bit. Shame on them. 790 + */ 791 + MIDR_ALL_VERSIONS(MIDR_CPU_MODEL(ARM_CPU_IMP_APM, 792 + APM_CPU_PART_POTENZA)), 793 + {}, 794 + }; 795 + 796 + if (is_midr_in_range_list(read_cpuid_id(), broken_cval_midrs)) { 797 + pr_warn_once("Broken CNTx_CVAL_EL1, limiting width to 32bits"); 798 + return CLOCKSOURCE_MASK(32); 799 + } 800 + #endif 801 + return CLOCKSOURCE_MASK(56); 802 + } 803 + 783 804 static void __arch_timer_setup(unsigned type, 784 805 struct clock_event_device *clk) 785 806 { 807 + u64 max_delta; 808 + 786 809 clk->features = CLOCK_EVT_FEAT_ONESHOT; 787 810 788 811 if (type == ARCH_TIMER_TYPE_CP15) { ··· 837 814 } 838 815 839 816 clk->set_next_event = sne; 817 + max_delta = __arch_timer_check_delta(); 840 818 } else { 841 819 clk->features |= CLOCK_EVT_FEAT_DYNIRQ; 842 820 clk->name = "arch_mem_timer"; ··· 854 830 clk->set_next_event = 855 831 arch_timer_set_next_event_phys_mem; 856 832 } 833 + 834 + max_delta = CLOCKSOURCE_MASK(56); 857 835 } 858 836 859 837 clk->set_state_shutdown(clk); 860 838 861 - clockevents_config_and_register(clk, arch_timer_rate, 0xf, CLOCKSOURCE_MASK(56)); 839 + clockevents_config_and_register(clk, arch_timer_rate, 0xf, max_delta); 862 840 } 863 841 864 842 static void arch_timer_evtstrm_enable(int divider)