@@ -264,6 +264,54 @@ int vgic_v2_acpi_probe(struct acpi_madt_generic_interrupt *vgic_acpi,
const struct vgic_ops **ops,
const struct vgic_params **params)
{
- return -EINVAL;
+ struct vgic_params *vgic = &vgic_v2_params;
+ int irq_mode, ret;
+
+ /* IRQ trigger mode */
+ irq_mode = (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,
+ irq_mode, ACPI_ACTIVE_HIGH);
+ if (!vgic->maint_irq) {
+ kvm_err("Cannot register VGIC ACPI maintenance irq\n");
+ ret = -ENXIO;
+ goto out;
+ }
+
+ /* GICH resource */
+ vgic->vctrl_base = ioremap(vgic_acpi->gich_base_address, SZ_8K);
+ if (!vgic->vctrl_base) {
+ kvm_err("cannot ioremap GICH memory\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 + SZ_8K,
+ vgic_acpi->gich_base_address);
+ if (ret) {
+ kvm_err("Cannot map GICH into hyp\n");
+ goto out;
+ }
+
+ vgic->vcpu_base = vgic_acpi->gicv_base_address;
+ vgic->can_emulate_gicv2 = true;
+ kvm_register_device_ops(&kvm_arm_vgic_v2_ops, KVM_DEV_TYPE_ARM_VGIC_V2);
+
+ kvm_info("GICH base=0x%llx, GICV base=0x%llx, IRQ=%d\n",
+ (unsigned long long)vgic_acpi->gich_base_address,
+ (unsigned long long)vgic_acpi->gicv_base_address,
+ vgic->maint_irq);
+
+ vgic->type = VGIC_V2;
+ vgic->max_gic_vcpus = VGIC_V2_MAX_CPUS;
+ *ops = &vgic_v2_ops;
+ *params = vgic;
+
+out:
+ return ret;
}
#endif /* CONFIG_ACPI */