clocksource: arm_arch_timer: rework PPI selection
authorFu Wei <fu.wei@linaro.org>
Wed, 18 Jan 2017 13:25:30 +0000 (21:25 +0800)
committerMark Rutland <mark.rutland@arm.com>
Mon, 10 Apr 2017 13:29:54 +0000 (14:29 +0100)
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>
drivers/clocksource/arm_arch_timer.c

index 15059c9..94de018 100644 (file)
@@ -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);