17c0e8b0cSWill Deacon #include "kvm/fdt.h" 2bed2bd9eSMarc Zyngier #include "kvm/irq.h" 37c0e8b0cSWill Deacon #include "kvm/kvm.h" 47c0e8b0cSWill Deacon #include "kvm/virtio.h" 57c0e8b0cSWill Deacon 67c0e8b0cSWill Deacon #include "arm-common/gic.h" 77c0e8b0cSWill Deacon 87c0e8b0cSWill Deacon #include <linux/byteorder.h> 9bed2bd9eSMarc Zyngier #include <linux/kernel.h> 107c0e8b0cSWill Deacon #include <linux/kvm.h> 117c0e8b0cSWill Deacon 1269b9a17aSMarc Zyngier static int gic_fd = -1; 1369b9a17aSMarc Zyngier 1469b9a17aSMarc Zyngier static int gic__create_device(struct kvm *kvm) 1569b9a17aSMarc Zyngier { 1669b9a17aSMarc Zyngier int err; 1769b9a17aSMarc Zyngier u64 cpu_if_addr = ARM_GIC_CPUI_BASE; 1869b9a17aSMarc Zyngier u64 dist_addr = ARM_GIC_DIST_BASE; 1969b9a17aSMarc Zyngier struct kvm_create_device gic_device = { 2069b9a17aSMarc Zyngier .type = KVM_DEV_TYPE_ARM_VGIC_V2, 2169b9a17aSMarc Zyngier }; 2269b9a17aSMarc Zyngier struct kvm_device_attr cpu_if_attr = { 2369b9a17aSMarc Zyngier .group = KVM_DEV_ARM_VGIC_GRP_ADDR, 2469b9a17aSMarc Zyngier .attr = KVM_VGIC_V2_ADDR_TYPE_CPU, 2569b9a17aSMarc Zyngier .addr = (u64)(unsigned long)&cpu_if_addr, 2669b9a17aSMarc Zyngier }; 2769b9a17aSMarc Zyngier struct kvm_device_attr dist_attr = { 2869b9a17aSMarc Zyngier .group = KVM_DEV_ARM_VGIC_GRP_ADDR, 2969b9a17aSMarc Zyngier .attr = KVM_VGIC_V2_ADDR_TYPE_DIST, 3069b9a17aSMarc Zyngier .addr = (u64)(unsigned long)&dist_addr, 3169b9a17aSMarc Zyngier }; 3269b9a17aSMarc Zyngier 3369b9a17aSMarc Zyngier err = ioctl(kvm->vm_fd, KVM_CREATE_DEVICE, &gic_device); 3469b9a17aSMarc Zyngier if (err) 3569b9a17aSMarc Zyngier return err; 3669b9a17aSMarc Zyngier 3769b9a17aSMarc Zyngier gic_fd = gic_device.fd; 3869b9a17aSMarc Zyngier 3969b9a17aSMarc Zyngier err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &cpu_if_attr); 4069b9a17aSMarc Zyngier if (err) 4169b9a17aSMarc Zyngier goto out_err; 4269b9a17aSMarc Zyngier 4369b9a17aSMarc Zyngier err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &dist_attr); 4469b9a17aSMarc Zyngier if (err) 4569b9a17aSMarc Zyngier goto out_err; 4669b9a17aSMarc Zyngier 4769b9a17aSMarc Zyngier return 0; 4869b9a17aSMarc Zyngier 4969b9a17aSMarc Zyngier out_err: 5069b9a17aSMarc Zyngier close(gic_fd); 5169b9a17aSMarc Zyngier gic_fd = -1; 5269b9a17aSMarc Zyngier return err; 5369b9a17aSMarc Zyngier } 5469b9a17aSMarc Zyngier 5569b9a17aSMarc Zyngier static int gic__create_irqchip(struct kvm *kvm) 567c0e8b0cSWill Deacon { 577c0e8b0cSWill Deacon int err; 58aa7a0e79SWill Deacon struct kvm_arm_device_addr gic_addr[] = { 597c0e8b0cSWill Deacon [0] = { 60aa7a0e79SWill Deacon .id = KVM_VGIC_V2_ADDR_TYPE_DIST | 61aa7a0e79SWill Deacon (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT), 627c0e8b0cSWill Deacon .addr = ARM_GIC_DIST_BASE, 637c0e8b0cSWill Deacon }, 647c0e8b0cSWill Deacon [1] = { 65aa7a0e79SWill Deacon .id = KVM_VGIC_V2_ADDR_TYPE_CPU | 66aa7a0e79SWill Deacon (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT), 677c0e8b0cSWill Deacon .addr = ARM_GIC_CPUI_BASE, 687c0e8b0cSWill Deacon } 697c0e8b0cSWill Deacon }; 707c0e8b0cSWill Deacon 717c0e8b0cSWill Deacon err = ioctl(kvm->vm_fd, KVM_CREATE_IRQCHIP); 727c0e8b0cSWill Deacon if (err) 737c0e8b0cSWill Deacon return err; 747c0e8b0cSWill Deacon 75aa7a0e79SWill Deacon err = ioctl(kvm->vm_fd, KVM_ARM_SET_DEVICE_ADDR, &gic_addr[0]); 767c0e8b0cSWill Deacon if (err) 777c0e8b0cSWill Deacon return err; 787c0e8b0cSWill Deacon 79aa7a0e79SWill Deacon err = ioctl(kvm->vm_fd, KVM_ARM_SET_DEVICE_ADDR, &gic_addr[1]); 807c0e8b0cSWill Deacon return err; 817c0e8b0cSWill Deacon } 827c0e8b0cSWill Deacon 8369b9a17aSMarc Zyngier int gic__create(struct kvm *kvm) 8469b9a17aSMarc Zyngier { 8569b9a17aSMarc Zyngier int err; 8669b9a17aSMarc Zyngier 8769b9a17aSMarc Zyngier if (kvm->nrcpus > GIC_MAX_CPUS) { 8869b9a17aSMarc Zyngier pr_warning("%d CPUS greater than maximum of %d -- truncating\n", 8969b9a17aSMarc Zyngier kvm->nrcpus, GIC_MAX_CPUS); 9069b9a17aSMarc Zyngier kvm->nrcpus = GIC_MAX_CPUS; 9169b9a17aSMarc Zyngier } 9269b9a17aSMarc Zyngier 9369b9a17aSMarc Zyngier /* Try the new way first, and fallback on legacy method otherwise */ 9469b9a17aSMarc Zyngier err = gic__create_device(kvm); 9569b9a17aSMarc Zyngier if (err) 9669b9a17aSMarc Zyngier err = gic__create_irqchip(kvm); 9769b9a17aSMarc Zyngier 9869b9a17aSMarc Zyngier return err; 9969b9a17aSMarc Zyngier } 10069b9a17aSMarc Zyngier 101*b5790302SAndre Przywara /* 102*b5790302SAndre Przywara * Sets the number of used interrupts and finalizes the GIC init explicitly. 103*b5790302SAndre Przywara */ 104bed2bd9eSMarc Zyngier static int gic__init_gic(struct kvm *kvm) 105bed2bd9eSMarc Zyngier { 106*b5790302SAndre Przywara int ret; 107*b5790302SAndre Przywara 108bed2bd9eSMarc Zyngier int lines = irq__get_nr_allocated_lines(); 109bed2bd9eSMarc Zyngier u32 nr_irqs = ALIGN(lines, 32) + GIC_SPI_IRQ_BASE; 110bed2bd9eSMarc Zyngier struct kvm_device_attr nr_irqs_attr = { 111bed2bd9eSMarc Zyngier .group = KVM_DEV_ARM_VGIC_GRP_NR_IRQS, 112bed2bd9eSMarc Zyngier .addr = (u64)(unsigned long)&nr_irqs, 113bed2bd9eSMarc Zyngier }; 114*b5790302SAndre Przywara struct kvm_device_attr vgic_init_attr = { 115*b5790302SAndre Przywara .group = KVM_DEV_ARM_VGIC_GRP_CTRL, 116*b5790302SAndre Przywara .attr = KVM_DEV_ARM_VGIC_CTRL_INIT, 117*b5790302SAndre Przywara }; 118bed2bd9eSMarc Zyngier 119bed2bd9eSMarc Zyngier /* 120bed2bd9eSMarc Zyngier * If we didn't use the KVM_CREATE_DEVICE method, KVM will 121*b5790302SAndre Przywara * give us some default number of interrupts. The GIC initialization 122*b5790302SAndre Przywara * will be done automatically in this case. 123bed2bd9eSMarc Zyngier */ 124bed2bd9eSMarc Zyngier if (gic_fd < 0) 125bed2bd9eSMarc Zyngier return 0; 126bed2bd9eSMarc Zyngier 127*b5790302SAndre Przywara if (!ioctl(gic_fd, KVM_HAS_DEVICE_ATTR, &nr_irqs_attr)) { 128*b5790302SAndre Przywara ret = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &nr_irqs_attr); 129*b5790302SAndre Przywara if (ret) 130*b5790302SAndre Przywara return ret; 131*b5790302SAndre Przywara } 132*b5790302SAndre Przywara 133*b5790302SAndre Przywara if (!ioctl(gic_fd, KVM_HAS_DEVICE_ATTR, &vgic_init_attr)) { 134*b5790302SAndre Przywara ret = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &vgic_init_attr); 135*b5790302SAndre Przywara if (ret) 136*b5790302SAndre Przywara return ret; 137*b5790302SAndre Przywara } 138bed2bd9eSMarc Zyngier 139bed2bd9eSMarc Zyngier return 0; 140bed2bd9eSMarc Zyngier } 141bed2bd9eSMarc Zyngier late_init(gic__init_gic) 142bed2bd9eSMarc Zyngier 1437c0e8b0cSWill Deacon void gic__generate_fdt_nodes(void *fdt, u32 phandle) 1447c0e8b0cSWill Deacon { 1457c0e8b0cSWill Deacon u64 reg_prop[] = { 1467c0e8b0cSWill Deacon cpu_to_fdt64(ARM_GIC_DIST_BASE), cpu_to_fdt64(ARM_GIC_DIST_SIZE), 1477c0e8b0cSWill Deacon cpu_to_fdt64(ARM_GIC_CPUI_BASE), cpu_to_fdt64(ARM_GIC_CPUI_SIZE), 1487c0e8b0cSWill Deacon }; 1497c0e8b0cSWill Deacon 1507c0e8b0cSWill Deacon _FDT(fdt_begin_node(fdt, "intc")); 1517c0e8b0cSWill Deacon _FDT(fdt_property_string(fdt, "compatible", "arm,cortex-a15-gic")); 1527c0e8b0cSWill Deacon _FDT(fdt_property_cell(fdt, "#interrupt-cells", GIC_FDT_IRQ_NUM_CELLS)); 1537c0e8b0cSWill Deacon _FDT(fdt_property(fdt, "interrupt-controller", NULL, 0)); 1547c0e8b0cSWill Deacon _FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop))); 1557c0e8b0cSWill Deacon _FDT(fdt_property_cell(fdt, "phandle", phandle)); 1567c0e8b0cSWill Deacon _FDT(fdt_end_node(fdt)); 1577c0e8b0cSWill Deacon } 1587c0e8b0cSWill Deacon 1597c0e8b0cSWill Deacon #define KVM_IRQCHIP_IRQ(x) (KVM_ARM_IRQ_TYPE_SPI << KVM_ARM_IRQ_TYPE_SHIFT) |\ 1607c0e8b0cSWill Deacon ((x) & KVM_ARM_IRQ_NUM_MASK) 1617c0e8b0cSWill Deacon 1627c0e8b0cSWill Deacon void kvm__irq_line(struct kvm *kvm, int irq, int level) 1637c0e8b0cSWill Deacon { 1647c0e8b0cSWill Deacon struct kvm_irq_level irq_level = { 1657c0e8b0cSWill Deacon .irq = KVM_IRQCHIP_IRQ(irq), 1667c0e8b0cSWill Deacon .level = !!level, 1677c0e8b0cSWill Deacon }; 1687c0e8b0cSWill Deacon 1697c0e8b0cSWill Deacon if (irq < GIC_SPI_IRQ_BASE || irq > GIC_MAX_IRQ) 1707c0e8b0cSWill Deacon pr_warning("Ignoring invalid GIC IRQ %d", irq); 1717c0e8b0cSWill Deacon else if (ioctl(kvm->vm_fd, KVM_IRQ_LINE, &irq_level) < 0) 1727c0e8b0cSWill Deacon pr_warning("Could not KVM_IRQ_LINE for irq %d", irq); 1737c0e8b0cSWill Deacon } 1747c0e8b0cSWill Deacon 1757c0e8b0cSWill Deacon void kvm__irq_trigger(struct kvm *kvm, int irq) 1767c0e8b0cSWill Deacon { 1777c0e8b0cSWill Deacon kvm__irq_line(kvm, irq, VIRTIO_IRQ_HIGH); 1787c0e8b0cSWill Deacon kvm__irq_line(kvm, irq, VIRTIO_IRQ_LOW); 1797c0e8b0cSWill Deacon } 180