17c0e8b0cSWill Deacon #include "kvm/fdt.h" 27c0e8b0cSWill Deacon #include "kvm/kvm.h" 37c0e8b0cSWill Deacon #include "kvm/virtio.h" 47c0e8b0cSWill Deacon 57c0e8b0cSWill Deacon #include "arm-common/gic.h" 67c0e8b0cSWill Deacon 77c0e8b0cSWill Deacon #include <linux/byteorder.h> 87c0e8b0cSWill Deacon #include <linux/kvm.h> 97c0e8b0cSWill Deacon 10*69b9a17aSMarc Zyngier static int gic_fd = -1; 11*69b9a17aSMarc Zyngier 12*69b9a17aSMarc Zyngier static int gic__create_device(struct kvm *kvm) 13*69b9a17aSMarc Zyngier { 14*69b9a17aSMarc Zyngier int err; 15*69b9a17aSMarc Zyngier u64 cpu_if_addr = ARM_GIC_CPUI_BASE; 16*69b9a17aSMarc Zyngier u64 dist_addr = ARM_GIC_DIST_BASE; 17*69b9a17aSMarc Zyngier struct kvm_create_device gic_device = { 18*69b9a17aSMarc Zyngier .type = KVM_DEV_TYPE_ARM_VGIC_V2, 19*69b9a17aSMarc Zyngier }; 20*69b9a17aSMarc Zyngier struct kvm_device_attr cpu_if_attr = { 21*69b9a17aSMarc Zyngier .group = KVM_DEV_ARM_VGIC_GRP_ADDR, 22*69b9a17aSMarc Zyngier .attr = KVM_VGIC_V2_ADDR_TYPE_CPU, 23*69b9a17aSMarc Zyngier .addr = (u64)(unsigned long)&cpu_if_addr, 24*69b9a17aSMarc Zyngier }; 25*69b9a17aSMarc Zyngier struct kvm_device_attr dist_attr = { 26*69b9a17aSMarc Zyngier .group = KVM_DEV_ARM_VGIC_GRP_ADDR, 27*69b9a17aSMarc Zyngier .attr = KVM_VGIC_V2_ADDR_TYPE_DIST, 28*69b9a17aSMarc Zyngier .addr = (u64)(unsigned long)&dist_addr, 29*69b9a17aSMarc Zyngier }; 30*69b9a17aSMarc Zyngier 31*69b9a17aSMarc Zyngier err = ioctl(kvm->vm_fd, KVM_CREATE_DEVICE, &gic_device); 32*69b9a17aSMarc Zyngier if (err) 33*69b9a17aSMarc Zyngier return err; 34*69b9a17aSMarc Zyngier 35*69b9a17aSMarc Zyngier gic_fd = gic_device.fd; 36*69b9a17aSMarc Zyngier 37*69b9a17aSMarc Zyngier err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &cpu_if_attr); 38*69b9a17aSMarc Zyngier if (err) 39*69b9a17aSMarc Zyngier goto out_err; 40*69b9a17aSMarc Zyngier 41*69b9a17aSMarc Zyngier err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &dist_attr); 42*69b9a17aSMarc Zyngier if (err) 43*69b9a17aSMarc Zyngier goto out_err; 44*69b9a17aSMarc Zyngier 45*69b9a17aSMarc Zyngier return 0; 46*69b9a17aSMarc Zyngier 47*69b9a17aSMarc Zyngier out_err: 48*69b9a17aSMarc Zyngier close(gic_fd); 49*69b9a17aSMarc Zyngier gic_fd = -1; 50*69b9a17aSMarc Zyngier return err; 51*69b9a17aSMarc Zyngier } 52*69b9a17aSMarc Zyngier 53*69b9a17aSMarc Zyngier static int gic__create_irqchip(struct kvm *kvm) 547c0e8b0cSWill Deacon { 557c0e8b0cSWill Deacon int err; 56aa7a0e79SWill Deacon struct kvm_arm_device_addr gic_addr[] = { 577c0e8b0cSWill Deacon [0] = { 58aa7a0e79SWill Deacon .id = KVM_VGIC_V2_ADDR_TYPE_DIST | 59aa7a0e79SWill Deacon (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT), 607c0e8b0cSWill Deacon .addr = ARM_GIC_DIST_BASE, 617c0e8b0cSWill Deacon }, 627c0e8b0cSWill Deacon [1] = { 63aa7a0e79SWill Deacon .id = KVM_VGIC_V2_ADDR_TYPE_CPU | 64aa7a0e79SWill Deacon (KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT), 657c0e8b0cSWill Deacon .addr = ARM_GIC_CPUI_BASE, 667c0e8b0cSWill Deacon } 677c0e8b0cSWill Deacon }; 687c0e8b0cSWill Deacon 697c0e8b0cSWill Deacon err = ioctl(kvm->vm_fd, KVM_CREATE_IRQCHIP); 707c0e8b0cSWill Deacon if (err) 717c0e8b0cSWill Deacon return err; 727c0e8b0cSWill Deacon 73aa7a0e79SWill Deacon err = ioctl(kvm->vm_fd, KVM_ARM_SET_DEVICE_ADDR, &gic_addr[0]); 747c0e8b0cSWill Deacon if (err) 757c0e8b0cSWill Deacon return err; 767c0e8b0cSWill Deacon 77aa7a0e79SWill Deacon err = ioctl(kvm->vm_fd, KVM_ARM_SET_DEVICE_ADDR, &gic_addr[1]); 787c0e8b0cSWill Deacon return err; 797c0e8b0cSWill Deacon } 807c0e8b0cSWill Deacon 81*69b9a17aSMarc Zyngier int gic__create(struct kvm *kvm) 82*69b9a17aSMarc Zyngier { 83*69b9a17aSMarc Zyngier int err; 84*69b9a17aSMarc Zyngier 85*69b9a17aSMarc Zyngier if (kvm->nrcpus > GIC_MAX_CPUS) { 86*69b9a17aSMarc Zyngier pr_warning("%d CPUS greater than maximum of %d -- truncating\n", 87*69b9a17aSMarc Zyngier kvm->nrcpus, GIC_MAX_CPUS); 88*69b9a17aSMarc Zyngier kvm->nrcpus = GIC_MAX_CPUS; 89*69b9a17aSMarc Zyngier } 90*69b9a17aSMarc Zyngier 91*69b9a17aSMarc Zyngier /* Try the new way first, and fallback on legacy method otherwise */ 92*69b9a17aSMarc Zyngier err = gic__create_device(kvm); 93*69b9a17aSMarc Zyngier if (err) 94*69b9a17aSMarc Zyngier err = gic__create_irqchip(kvm); 95*69b9a17aSMarc Zyngier 96*69b9a17aSMarc Zyngier return err; 97*69b9a17aSMarc Zyngier } 98*69b9a17aSMarc Zyngier 997c0e8b0cSWill Deacon void gic__generate_fdt_nodes(void *fdt, u32 phandle) 1007c0e8b0cSWill Deacon { 1017c0e8b0cSWill Deacon u64 reg_prop[] = { 1027c0e8b0cSWill Deacon cpu_to_fdt64(ARM_GIC_DIST_BASE), cpu_to_fdt64(ARM_GIC_DIST_SIZE), 1037c0e8b0cSWill Deacon cpu_to_fdt64(ARM_GIC_CPUI_BASE), cpu_to_fdt64(ARM_GIC_CPUI_SIZE), 1047c0e8b0cSWill Deacon }; 1057c0e8b0cSWill Deacon 1067c0e8b0cSWill Deacon _FDT(fdt_begin_node(fdt, "intc")); 1077c0e8b0cSWill Deacon _FDT(fdt_property_string(fdt, "compatible", "arm,cortex-a15-gic")); 1087c0e8b0cSWill Deacon _FDT(fdt_property_cell(fdt, "#interrupt-cells", GIC_FDT_IRQ_NUM_CELLS)); 1097c0e8b0cSWill Deacon _FDT(fdt_property(fdt, "interrupt-controller", NULL, 0)); 1107c0e8b0cSWill Deacon _FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop))); 1117c0e8b0cSWill Deacon _FDT(fdt_property_cell(fdt, "phandle", phandle)); 1127c0e8b0cSWill Deacon _FDT(fdt_end_node(fdt)); 1137c0e8b0cSWill Deacon } 1147c0e8b0cSWill Deacon 1157c0e8b0cSWill Deacon #define KVM_IRQCHIP_IRQ(x) (KVM_ARM_IRQ_TYPE_SPI << KVM_ARM_IRQ_TYPE_SHIFT) |\ 1167c0e8b0cSWill Deacon ((x) & KVM_ARM_IRQ_NUM_MASK) 1177c0e8b0cSWill Deacon 1187c0e8b0cSWill Deacon void kvm__irq_line(struct kvm *kvm, int irq, int level) 1197c0e8b0cSWill Deacon { 1207c0e8b0cSWill Deacon struct kvm_irq_level irq_level = { 1217c0e8b0cSWill Deacon .irq = KVM_IRQCHIP_IRQ(irq), 1227c0e8b0cSWill Deacon .level = !!level, 1237c0e8b0cSWill Deacon }; 1247c0e8b0cSWill Deacon 1257c0e8b0cSWill Deacon if (irq < GIC_SPI_IRQ_BASE || irq > GIC_MAX_IRQ) 1267c0e8b0cSWill Deacon pr_warning("Ignoring invalid GIC IRQ %d", irq); 1277c0e8b0cSWill Deacon else if (ioctl(kvm->vm_fd, KVM_IRQ_LINE, &irq_level) < 0) 1287c0e8b0cSWill Deacon pr_warning("Could not KVM_IRQ_LINE for irq %d", irq); 1297c0e8b0cSWill Deacon } 1307c0e8b0cSWill Deacon 1317c0e8b0cSWill Deacon void kvm__irq_trigger(struct kvm *kvm, int irq) 1327c0e8b0cSWill Deacon { 1337c0e8b0cSWill Deacon kvm__irq_line(kvm, irq, VIRTIO_IRQ_HIGH); 1347c0e8b0cSWill Deacon kvm__irq_line(kvm, irq, VIRTIO_IRQ_LOW); 1357c0e8b0cSWill Deacon } 136