xref: /kvmtool/arm/gic.c (revision aa7a0e7915ba76f11611bc7e9f537010fc699754)
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 
107c0e8b0cSWill Deacon static int irq_ids;
117c0e8b0cSWill Deacon 
127c0e8b0cSWill Deacon int gic__alloc_irqnum(void)
137c0e8b0cSWill Deacon {
147c0e8b0cSWill Deacon 	int irq = GIC_SPI_IRQ_BASE + irq_ids++;
157c0e8b0cSWill Deacon 
167c0e8b0cSWill Deacon 	if (irq > GIC_MAX_IRQ)
177c0e8b0cSWill Deacon 		die("GIC IRQ limit %d reached!", GIC_MAX_IRQ);
187c0e8b0cSWill Deacon 
197c0e8b0cSWill Deacon 	return irq;
207c0e8b0cSWill Deacon }
217c0e8b0cSWill Deacon 
227c0e8b0cSWill Deacon int gic__init_irqchip(struct kvm *kvm)
237c0e8b0cSWill Deacon {
247c0e8b0cSWill Deacon 	int err;
25*aa7a0e79SWill Deacon 	struct kvm_arm_device_addr gic_addr[] = {
267c0e8b0cSWill Deacon 		[0] = {
27*aa7a0e79SWill Deacon 			.id = KVM_VGIC_V2_ADDR_TYPE_DIST |
28*aa7a0e79SWill Deacon 			(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT),
297c0e8b0cSWill Deacon 			.addr = ARM_GIC_DIST_BASE,
307c0e8b0cSWill Deacon 		},
317c0e8b0cSWill Deacon 		[1] = {
32*aa7a0e79SWill Deacon 			.id = KVM_VGIC_V2_ADDR_TYPE_CPU |
33*aa7a0e79SWill Deacon 			(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT),
347c0e8b0cSWill Deacon 			.addr = ARM_GIC_CPUI_BASE,
357c0e8b0cSWill Deacon 		}
367c0e8b0cSWill Deacon 	};
377c0e8b0cSWill Deacon 
387c0e8b0cSWill Deacon 	if (kvm->nrcpus > GIC_MAX_CPUS) {
397c0e8b0cSWill Deacon 		pr_warning("%d CPUS greater than maximum of %d -- truncating\n",
407c0e8b0cSWill Deacon 				kvm->nrcpus, GIC_MAX_CPUS);
417c0e8b0cSWill Deacon 		kvm->nrcpus = GIC_MAX_CPUS;
427c0e8b0cSWill Deacon 	}
437c0e8b0cSWill Deacon 
447c0e8b0cSWill Deacon 	err = ioctl(kvm->vm_fd, KVM_CREATE_IRQCHIP);
457c0e8b0cSWill Deacon 	if (err)
467c0e8b0cSWill Deacon 		return err;
477c0e8b0cSWill Deacon 
48*aa7a0e79SWill Deacon 	err = ioctl(kvm->vm_fd, KVM_ARM_SET_DEVICE_ADDR, &gic_addr[0]);
497c0e8b0cSWill Deacon 	if (err)
507c0e8b0cSWill Deacon 		return err;
517c0e8b0cSWill Deacon 
52*aa7a0e79SWill Deacon 	err = ioctl(kvm->vm_fd, KVM_ARM_SET_DEVICE_ADDR, &gic_addr[1]);
537c0e8b0cSWill Deacon 	return err;
547c0e8b0cSWill Deacon }
557c0e8b0cSWill Deacon 
567c0e8b0cSWill Deacon void gic__generate_fdt_nodes(void *fdt, u32 phandle)
577c0e8b0cSWill Deacon {
587c0e8b0cSWill Deacon 	u64 reg_prop[] = {
597c0e8b0cSWill Deacon 		cpu_to_fdt64(ARM_GIC_DIST_BASE), cpu_to_fdt64(ARM_GIC_DIST_SIZE),
607c0e8b0cSWill Deacon 		cpu_to_fdt64(ARM_GIC_CPUI_BASE), cpu_to_fdt64(ARM_GIC_CPUI_SIZE),
617c0e8b0cSWill Deacon 	};
627c0e8b0cSWill Deacon 
637c0e8b0cSWill Deacon 	_FDT(fdt_begin_node(fdt, "intc"));
647c0e8b0cSWill Deacon 	_FDT(fdt_property_string(fdt, "compatible", "arm,cortex-a15-gic"));
657c0e8b0cSWill Deacon 	_FDT(fdt_property_cell(fdt, "#interrupt-cells", GIC_FDT_IRQ_NUM_CELLS));
667c0e8b0cSWill Deacon 	_FDT(fdt_property(fdt, "interrupt-controller", NULL, 0));
677c0e8b0cSWill Deacon 	_FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop)));
687c0e8b0cSWill Deacon 	_FDT(fdt_property_cell(fdt, "phandle", phandle));
697c0e8b0cSWill Deacon 	_FDT(fdt_end_node(fdt));
707c0e8b0cSWill Deacon }
717c0e8b0cSWill Deacon 
727c0e8b0cSWill Deacon #define KVM_IRQCHIP_IRQ(x) (KVM_ARM_IRQ_TYPE_SPI << KVM_ARM_IRQ_TYPE_SHIFT) |\
737c0e8b0cSWill Deacon 			   ((x) & KVM_ARM_IRQ_NUM_MASK)
747c0e8b0cSWill Deacon 
757c0e8b0cSWill Deacon void kvm__irq_line(struct kvm *kvm, int irq, int level)
767c0e8b0cSWill Deacon {
777c0e8b0cSWill Deacon 	struct kvm_irq_level irq_level = {
787c0e8b0cSWill Deacon 		.irq	= KVM_IRQCHIP_IRQ(irq),
797c0e8b0cSWill Deacon 		.level	= !!level,
807c0e8b0cSWill Deacon 	};
817c0e8b0cSWill Deacon 
827c0e8b0cSWill Deacon 	if (irq < GIC_SPI_IRQ_BASE || irq > GIC_MAX_IRQ)
837c0e8b0cSWill Deacon 		pr_warning("Ignoring invalid GIC IRQ %d", irq);
847c0e8b0cSWill Deacon 	else if (ioctl(kvm->vm_fd, KVM_IRQ_LINE, &irq_level) < 0)
857c0e8b0cSWill Deacon 		pr_warning("Could not KVM_IRQ_LINE for irq %d", irq);
867c0e8b0cSWill Deacon }
877c0e8b0cSWill Deacon 
887c0e8b0cSWill Deacon void kvm__irq_trigger(struct kvm *kvm, int irq)
897c0e8b0cSWill Deacon {
907c0e8b0cSWill Deacon 	kvm__irq_line(kvm, irq, VIRTIO_IRQ_HIGH);
917c0e8b0cSWill Deacon 	kvm__irq_line(kvm, irq, VIRTIO_IRQ_LOW);
927c0e8b0cSWill Deacon }
93