summaryrefslogtreecommitdiffstats
path: root/drivers/clocksource/arm_arch_timer.c
diff options
context:
space:
mode:
authorFu Wei <fu.wei@linaro.org>2017-01-18 14:25:30 +0100
committerMark Rutland <mark.rutland@arm.com>2017-04-10 15:29:54 +0200
commit4502b6bb720d7a519c4cea76cf68a2425b481a45 (patch)
tree6e184182d79ce4882691b30e5c638bde1f100082 /drivers/clocksource/arm_arch_timer.c
parentclocksource: arm_arch_timer: add a new enum for spi type (diff)
downloadlinux-4502b6bb720d7a519c4cea76cf68a2425b481a45.tar.xz
linux-4502b6bb720d7a519c4cea76cf68a2425b481a45.zip
clocksource: arm_arch_timer: rework PPI selection
Currently, the arch timer driver uses ARCH_TIMER_PHYS_SECURE_PPI to mean the driver will use the secure PPI *and* potentially also use the non-secure PPI. This is somewhat confusing. For arm64 it never makes sense to use the secure PPI, but we do anyway, inheriting this behaviour from 32-bit arm. For ACPI, we may not even have a valid secure PPI, so we need to be able to only request the non-secure PPI. To that end, this patch reworks the timer driver so that we can request the non-secure PPI alone. The PPI selection is split out into a new function, arch_timer_select_ppi(), and verification of the selected PPI is shifted out to callers (as DT may select the PPI by other means and must handle this anyway). We now consistently use arch_timer_has_nonsecure_ppi() to determine whether we must manage a non-secure PPI *in addition* to a secure PPI. When we only have a non-secure PPI, this returns false. Signed-off-by: Fu Wei <fu.wei@linaro.org> Tested-by: Xiongfeng Wang <wangxiongfeng2@huawei.com> [Mark: reword commit message] Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Diffstat (limited to 'drivers/clocksource/arm_arch_timer.c')
-rw-r--r--drivers/clocksource/arm_arch_timer.c77
1 files changed, 46 insertions, 31 deletions
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 15059c958be7..94de018c65d0 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -992,7 +992,7 @@ static int __init arch_timer_register(void)
case ARCH_TIMER_PHYS_NONSECURE_PPI:
err = request_percpu_irq(ppi, arch_timer_handler_phys,
"arch_timer", arch_timer_evt);
- if (!err && arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]) {
+ if (!err && arch_timer_has_nonsecure_ppi()) {
ppi = arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI];
err = request_percpu_irq(ppi, arch_timer_handler_phys,
"arch_timer", arch_timer_evt);
@@ -1114,39 +1114,41 @@ static int __init arch_timer_common_init(void)
return arch_timer_arch_init();
}
-static int __init arch_timer_init(void)
+/**
+ * arch_timer_select_ppi() - Select suitable PPI for the current system.
+ *
+ * If HYP mode is available, we know that the physical timer
+ * has been configured to be accessible from PL1. Use it, so
+ * that a guest can use the virtual timer instead.
+ *
+ * On ARMv8.1 with VH extensions, the kernel runs in HYP. VHE
+ * accesses to CNTP_*_EL1 registers are silently redirected to
+ * their CNTHP_*_EL2 counterparts, and use a different PPI
+ * number.
+ *
+ * If no interrupt provided for virtual timer, we'll have to
+ * stick to the physical timer. It'd better be accessible...
+ * For arm64 we never use the secure interrupt.
+ *
+ * Return: a suitable PPI type for the current system.
+ */
+static enum arch_timer_ppi_nr __init arch_timer_select_ppi(void)
{
- int ret;
- /*
- * If HYP mode is available, we know that the physical timer
- * has been configured to be accessible from PL1. Use it, so
- * that a guest can use the virtual timer instead.
- *
- * If no interrupt provided for virtual timer, we'll have to
- * stick to the physical timer. It'd better be accessible...
- *
- * On ARMv8.1 with VH extensions, the kernel runs in HYP. VHE
- * accesses to CNTP_*_EL1 registers are silently redirected to
- * their CNTHP_*_EL2 counterparts, and use a different PPI
- * number.
- */
- if (is_hyp_mode_available() || !arch_timer_ppi[ARCH_TIMER_VIRT_PPI]) {
- bool has_ppi;
+ if (is_kernel_in_hyp_mode())
+ return ARCH_TIMER_HYP_PPI;
- if (is_kernel_in_hyp_mode()) {
- arch_timer_uses_ppi = ARCH_TIMER_HYP_PPI;
- has_ppi = !!arch_timer_ppi[ARCH_TIMER_HYP_PPI];
- } else {
- arch_timer_uses_ppi = ARCH_TIMER_PHYS_SECURE_PPI;
- has_ppi = (!!arch_timer_ppi[ARCH_TIMER_PHYS_SECURE_PPI] ||
- !!arch_timer_ppi[ARCH_TIMER_PHYS_NONSECURE_PPI]);
- }
+ if (!is_hyp_mode_available() && arch_timer_ppi[ARCH_TIMER_VIRT_PPI])
+ return ARCH_TIMER_VIRT_PPI;
- if (!has_ppi) {
- pr_warn("No interrupt available, giving up\n");
- return -EINVAL;
- }
- }
+ if (IS_ENABLED(CONFIG_ARM64))
+ return ARCH_TIMER_PHYS_NONSECURE_PPI;
+
+ return ARCH_TIMER_PHYS_SECURE_PPI;
+}
+
+static int __init arch_timer_init(void)
+{
+ int ret;
ret = arch_timer_register();
if (ret)
@@ -1188,6 +1190,13 @@ static int __init arch_timer_of_init(struct device_node *np)
if (IS_ENABLED(CONFIG_ARM) &&
of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
arch_timer_uses_ppi = ARCH_TIMER_PHYS_SECURE_PPI;
+ else
+ arch_timer_uses_ppi = arch_timer_select_ppi();
+
+ if (!arch_timer_ppi[arch_timer_uses_ppi]) {
+ pr_err("No interrupt available, giving up\n");
+ return -EINVAL;
+ }
/* On some systems, the counter stops ticking when in suspend. */
arch_counter_suspend_stop = of_property_read_bool(np,
@@ -1333,6 +1342,12 @@ static int __init arch_timer_acpi_init(struct acpi_table_header *table)
/* Get the frequency from CNTFRQ */
arch_timer_detect_rate(NULL, NULL);
+ arch_timer_uses_ppi = arch_timer_select_ppi();
+ if (!arch_timer_ppi[arch_timer_uses_ppi]) {
+ pr_err("No interrupt available, giving up\n");
+ return -EINVAL;
+ }
+
/* Always-on capability */
arch_timer_c3stop = !(gtdt->non_secure_el1_flags & ACPI_GTDT_ALWAYS_ON);