On 09/12/2014 05:56 PM, Alexander Spyridakis wrote:
If ACPI is still enabled during KVM initialization, VGIC cannot be probed with device tree information. Get the MADT table and probe VGIC with ACPI information instead (GICv2 support only).
Signed-off-by: Alexander Spyridakis a.spyridakis@virtualopensystems.com
include/kvm/arm_vgic.h | 6 ++++ virt/kvm/arm/vgic-v2.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++ virt/kvm/arm/vgic.c | 27 +++++++++------ 3 files changed, 114 insertions(+), 10 deletions(-)
diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h index 35b0c12..af652f2 100644 --- a/include/kvm/arm_vgic.h +++ b/include/kvm/arm_vgic.h @@ -35,6 +35,8 @@ #define VGIC_V2_MAX_LRS (1 << 6) #define VGIC_V3_MAX_LRS 16
+#define VGIC_CPU_INTERFACE_SIZE 0x2000
Given that GIC_CPU interface is well known, instead of defining VGIC_CPU_INTERFACE_SIZE, SZ_8K can be used directly below.
/* Sanity checks... */ #if (VGIC_MAX_CPUS > 8) #error Invalid number of CPU interfaces @@ -240,6 +242,10 @@ bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, int vgic_v2_probe(struct device_node *vgic_node, const struct vgic_ops **ops, const struct vgic_params **params); +#ifdef CONFIG_ACPI +int vgic_v2_acpi_probe(const struct vgic_ops **ops,
const struct vgic_params **params);
+#endif #ifdef CONFIG_ARM_GIC_V3 int vgic_v3_probe(struct device_node *vgic_node, const struct vgic_ops **ops, diff --git a/virt/kvm/arm/vgic-v2.c b/virt/kvm/arm/vgic-v2.c index 01124ef..5f023db 100644 --- a/virt/kvm/arm/vgic-v2.c +++ b/virt/kvm/arm/vgic-v2.c @@ -23,8 +23,10 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> +#include <linux/acpi.h>
#include <linux/irqchip/arm-gic.h> +#include <linux/irqchip/arm-gic-acpi.h>
#include <asm/kvm_emulate.h> #include <asm/kvm_arm.h> @@ -176,6 +178,95 @@ static const struct vgic_ops vgic_v2_ops = {
static struct vgic_params vgic_v2_params;
+#ifdef CONFIG_ACPI +struct acpi_madt_generic_interrupt *vgic_acpi;
+static void vgic_get_acpi_header(struct acpi_table_header *header) +{
- vgic_acpi = (struct acpi_madt_generic_interrupt *)header;
+}
+/**
- vgic_v2_acpi_probe - ACPI probe for a GICv2 compatible interrupt controller
- @ops: address of a pointer to the GICv2 operations
- @params: address of a pointer to HW-specific parameters
- Returns 0 if a GICv2 has been found, with the low level operations
- in *ops and the HW parameters in *params. Returns an error code
- otherwise.
- */
+int vgic_v2_acpi_probe(const struct vgic_ops **ops,
const struct vgic_params **params)
+{
- int ret, trigger;
- struct vgic_params *vgic = &vgic_v2_params;
- ret = acpi_table_parse_madt(ACPI_MADT_TYPE_GENERIC_INTERRUPT,
(acpi_tbl_entry_handler)vgic_get_acpi_header,
ACPI_MAX_GIC_CPU_INTERFACE_ENTRIES);
- if (!ret) {
pr_err("No GIC CPU interface entries present\n");
ret = -ENODEV;
goto out;
- }
- trigger = (vgic_acpi->flags & ACPI_MADT_VGIC_IRQ_MODE) ?
ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE;
- vgic->maint_irq = acpi_register_gsi(NULL,
vgic_acpi->vgic_interrupt, trigger, ACPI_ACTIVE_HIGH);
Unless I missed something, according to GIC-400 all PPIs are active-LOW, including maintenance interrupt.
- if (!vgic->maint_irq) {
kvm_err("error getting vgic maintenance irq from ACPI\n");
ret = -ENXIO;
goto out;
- }
- vgic->vctrl_base =
ioremap(vgic_acpi->gich_base_address, VGIC_CPU_INTERFACE_SIZE);
- if (!vgic->vctrl_base) {
kvm_err("Cannot ioremap GICH\n");
ret = -ENOMEM;
goto out;
- }
- vgic->nr_lr = readl_relaxed(vgic->vctrl_base + GICH_VTR);
- vgic->nr_lr = (vgic->nr_lr & 0x3f) + 1;
- ret = create_hyp_io_mappings(vgic->vctrl_base,
vgic->vctrl_base + VGIC_CPU_INTERFACE_SIZE,
vgic_acpi->gich_base_address);
- if (ret) {
kvm_err("Cannot map VCTRL into hyp\n");
goto out_unmap;
- }
- vgic->vcpu_base = vgic_acpi->gicv_base_address;
- if (!PAGE_ALIGNED(vgic->vcpu_base)) {
kvm_err("GICV physical address 0x%llx not page aligned\n",
(unsigned long long)vgic->vcpu_base);
ret = -ENXIO;
goto out_unmap;
- }
- kvm_info("interrupt-controller@%x IRQ%d\n",
(unsigned int)vgic_acpi->gich_base_address, vgic->maint_irq);
- vgic->type = VGIC_V2;
- *ops = &vgic_v2_ops;
- *params = &vgic_v2_params;
- goto out;
+out_unmap:
- iounmap(vgic->vctrl_base);
+out:
- return ret;
+} +#endif
- /**
- vgic_v2_probe - probe for a GICv2 compatible interrupt controller in DT
- @node: pointer to the DT node
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 73eba79..e704095 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c @@ -25,6 +25,7 @@ #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/uaccess.h> +#include <linux/acpi.h>
#include <linux/irqchip/arm-gic.h>
@@ -1562,17 +1563,23 @@ int kvm_vgic_hyp_init(void) struct device_node *vgic_node; int ret;
- vgic_node = of_find_matching_node_and_match(NULL,
vgic_ids, &matched_id);
- if (!vgic_node) {
kvm_err("error: no compatible GIC node found\n");
return -ENODEV;
- }
- if (acpi_disabled) {
vgic_node = of_find_matching_node_and_match(NULL,
vgic_ids, &matched_id);
if (!vgic_node) {
kvm_err("error: no compatible GIC node found\n");
return -ENODEV;
}
- vgic_probe = matched_id->data;
- ret = vgic_probe(vgic_node, &vgic_ops, &vgic);
- if (ret)
return ret;
vgic_probe = matched_id->data;
ret = vgic_probe(vgic_node, &vgic_ops, &vgic);
if (ret)
return ret;
} else {
ret = vgic_v2_acpi_probe(&vgic_ops, &vgic);
if (ret)
return ret;
}
ret = request_percpu_irq(vgic->maint_irq, vgic_maintenance_handler, "vgic", kvm_get_running_vcpus());