]> xenbits.xensource.com Git - people/julieng/linux-arm.git/commitdiff
ARM64 / ACPI: Point KVM to the virtual timer interrupt when booting with ACPI
authorTomasz Nowicki <tomasz.nowicki@linaro.org>
Tue, 24 Mar 2015 03:31:58 +0000 (20:31 -0700)
committerJulien Grall <julien.grall@citrix.com>
Mon, 28 Sep 2015 11:05:22 +0000 (12:05 +0100)
With ACPI enabled, kvm_timer_hyp_init can't access any device tree
information. Although registration of the virtual timer interrupt
already happened when architected timers were initialized, we need to
point KVM to the interrupt line used.

Signed-off-by: Alexander Spyridakis <a.spyridakis@virtualopensystems.com>
Signed-off-by: Tomasz Nowicki <tomasz.nowicki@linaro.org>
Signed-off-by: Robert Richter <rrichter@cavium.com>
Signed-off-by: Vadim Lomovtsev <Vadim.Lomovtsev@caviumnetworks.com>
virt/kvm/arm/arch_timer.c

index 98c95f2fcba4a63912fb81fbafd3854b08835e00..a26c8b82c564d508d68df0f0bd09289b274309dd 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/kvm.h>
 #include <linux/kvm_host.h>
 #include <linux/interrupt.h>
+#include <linux/acpi.h>
 
 #include <clocksource/arm_arch_timer.h>
 #include <asm/arch_timer.h>
@@ -274,15 +275,10 @@ static const struct of_device_id arch_timer_of_match[] = {
        {},
 };
 
-int kvm_timer_hyp_init(void)
+static int kvm_of_timer_hyp_init(unsigned int *ppi)
 {
        struct device_node *np;
-       unsigned int ppi;
-       int err;
-
-       timecounter = arch_timer_get_timecounter();
-       if (!timecounter)
-               return -ENODEV;
+       int err = 0;
 
        np = of_find_matching_node(NULL, arch_timer_of_match);
        if (!np) {
@@ -290,19 +286,70 @@ int kvm_timer_hyp_init(void)
                return -ENODEV;
        }
 
-       ppi = irq_of_parse_and_map(np, 2);
-       if (!ppi) {
+       *ppi = irq_of_parse_and_map(np, 2);
+       if (!(*ppi)) {
                kvm_err("kvm_arch_timer: no virtual timer interrupt\n");
                err = -EINVAL;
-               goto out;
-       }
+       } else
+               kvm_info("%s IRQ%d\n", np->name, *ppi);
+
+       of_node_put(np);
+       return err;
+}
+
+#ifdef CONFIG_ACPI
+static struct acpi_table_gtdt *gtdt_acpi;
+
+static int arch_timer_acpi_parse(struct acpi_table_header *table)
+{
+       gtdt_acpi = (struct acpi_table_gtdt *)table;
+       return 0;
+}
+
+static int kvm_acpi_timer_hyp_init(unsigned int *ppi)
+{
+       /* The virtual timer interrupt was already
+        * registered during initialization with ACPI.
+        * Get the interrupt number from the tables
+        * and point there.
+        */
+       acpi_table_parse(ACPI_SIG_GTDT, arch_timer_acpi_parse);
+       if (!gtdt_acpi)
+               return -ENODEV;
+       if (!gtdt_acpi->virtual_timer_interrupt)
+               return -EINVAL;
+
+       *ppi = gtdt_acpi->virtual_timer_interrupt;
+       kvm_info("timer IRQ%d\n", *ppi);
+       return 0;
+}
+#else
+static int kvm_acpi_timer_hyp_init(unsigned int *ppi)
+{
+       return -ENODEV;
+}
+#endif
+
+int kvm_timer_hyp_init(void)
+{
+       unsigned int ppi;
+       int err;
+
+       timecounter = arch_timer_get_timecounter();
+       if (!timecounter)
+               return -ENODEV;
+
+       err = acpi_disabled ? kvm_of_timer_hyp_init(&ppi) :
+                             kvm_acpi_timer_hyp_init(&ppi);
+       if (err)
+               return err;
 
        err = request_percpu_irq(ppi, kvm_arch_timer_handler,
                                 "kvm guest timer", kvm_get_running_vcpus());
        if (err) {
                kvm_err("kvm_arch_timer: can't request interrupt %d (%d)\n",
                        ppi, err);
-               goto out;
+               return err;
        }
 
        host_vtimer_irq = ppi;
@@ -319,14 +366,11 @@ int kvm_timer_hyp_init(void)
                goto out_free;
        }
 
-       kvm_info("%s IRQ%d\n", np->name, ppi);
        on_each_cpu(kvm_timer_init_interrupt, NULL, 1);
 
-       goto out;
+       return 0;
 out_free:
        free_percpu_irq(ppi, kvm_get_running_vcpus());
-out:
-       of_node_put(np);
        return err;
 }