xref: /kvmtool/arm/gic.c (revision 7c0e8b0c5560ce2f500fa4d7ba7865e7360e7991)
1*7c0e8b0cSWill Deacon #include "kvm/fdt.h"
2*7c0e8b0cSWill Deacon #include "kvm/kvm.h"
3*7c0e8b0cSWill Deacon #include "kvm/virtio.h"
4*7c0e8b0cSWill Deacon 
5*7c0e8b0cSWill Deacon #include "arm-common/gic.h"
6*7c0e8b0cSWill Deacon 
7*7c0e8b0cSWill Deacon #include <linux/byteorder.h>
8*7c0e8b0cSWill Deacon #include <linux/kvm.h>
9*7c0e8b0cSWill Deacon 
10*7c0e8b0cSWill Deacon static int irq_ids;
11*7c0e8b0cSWill Deacon 
12*7c0e8b0cSWill Deacon int gic__alloc_irqnum(void)
13*7c0e8b0cSWill Deacon {
14*7c0e8b0cSWill Deacon 	int irq = GIC_SPI_IRQ_BASE + irq_ids++;
15*7c0e8b0cSWill Deacon 
16*7c0e8b0cSWill Deacon 	if (irq > GIC_MAX_IRQ)
17*7c0e8b0cSWill Deacon 		die("GIC IRQ limit %d reached!", GIC_MAX_IRQ);
18*7c0e8b0cSWill Deacon 
19*7c0e8b0cSWill Deacon 	return irq;
20*7c0e8b0cSWill Deacon }
21*7c0e8b0cSWill Deacon 
22*7c0e8b0cSWill Deacon int gic__init_irqchip(struct kvm *kvm)
23*7c0e8b0cSWill Deacon {
24*7c0e8b0cSWill Deacon 	int err;
25*7c0e8b0cSWill Deacon 	struct kvm_device_address gic_addr[] = {
26*7c0e8b0cSWill Deacon 		[0] = {
27*7c0e8b0cSWill Deacon 			.id = (KVM_ARM_DEVICE_VGIC_V2 << KVM_DEVICE_ID_SHIFT) |\
28*7c0e8b0cSWill Deacon 			       KVM_VGIC_V2_ADDR_TYPE_DIST,
29*7c0e8b0cSWill Deacon 			.addr = ARM_GIC_DIST_BASE,
30*7c0e8b0cSWill Deacon 		},
31*7c0e8b0cSWill Deacon 		[1] = {
32*7c0e8b0cSWill Deacon 			.id = (KVM_ARM_DEVICE_VGIC_V2 << KVM_DEVICE_ID_SHIFT) |\
33*7c0e8b0cSWill Deacon 			       KVM_VGIC_V2_ADDR_TYPE_CPU,
34*7c0e8b0cSWill Deacon 			.addr = ARM_GIC_CPUI_BASE,
35*7c0e8b0cSWill Deacon 		}
36*7c0e8b0cSWill Deacon 	};
37*7c0e8b0cSWill Deacon 
38*7c0e8b0cSWill Deacon 	if (kvm->nrcpus > GIC_MAX_CPUS) {
39*7c0e8b0cSWill Deacon 		pr_warning("%d CPUS greater than maximum of %d -- truncating\n",
40*7c0e8b0cSWill Deacon 				kvm->nrcpus, GIC_MAX_CPUS);
41*7c0e8b0cSWill Deacon 		kvm->nrcpus = GIC_MAX_CPUS;
42*7c0e8b0cSWill Deacon 	}
43*7c0e8b0cSWill Deacon 
44*7c0e8b0cSWill Deacon 	err = ioctl(kvm->vm_fd, KVM_CREATE_IRQCHIP);
45*7c0e8b0cSWill Deacon 	if (err)
46*7c0e8b0cSWill Deacon 		return err;
47*7c0e8b0cSWill Deacon 
48*7c0e8b0cSWill Deacon 	err = ioctl(kvm->vm_fd, KVM_SET_DEVICE_ADDRESS, &gic_addr[0]);
49*7c0e8b0cSWill Deacon 	if (err)
50*7c0e8b0cSWill Deacon 		return err;
51*7c0e8b0cSWill Deacon 
52*7c0e8b0cSWill Deacon 	err = ioctl(kvm->vm_fd, KVM_SET_DEVICE_ADDRESS, &gic_addr[1]);
53*7c0e8b0cSWill Deacon 	return err;
54*7c0e8b0cSWill Deacon }
55*7c0e8b0cSWill Deacon 
56*7c0e8b0cSWill Deacon void gic__generate_fdt_nodes(void *fdt, u32 phandle)
57*7c0e8b0cSWill Deacon {
58*7c0e8b0cSWill Deacon 	u64 reg_prop[] = {
59*7c0e8b0cSWill Deacon 		cpu_to_fdt64(ARM_GIC_DIST_BASE), cpu_to_fdt64(ARM_GIC_DIST_SIZE),
60*7c0e8b0cSWill Deacon 		cpu_to_fdt64(ARM_GIC_CPUI_BASE), cpu_to_fdt64(ARM_GIC_CPUI_SIZE),
61*7c0e8b0cSWill Deacon 	};
62*7c0e8b0cSWill Deacon 
63*7c0e8b0cSWill Deacon 	_FDT(fdt_begin_node(fdt, "intc"));
64*7c0e8b0cSWill Deacon 	_FDT(fdt_property_string(fdt, "compatible", "arm,cortex-a15-gic"));
65*7c0e8b0cSWill Deacon 	_FDT(fdt_property_cell(fdt, "#interrupt-cells", GIC_FDT_IRQ_NUM_CELLS));
66*7c0e8b0cSWill Deacon 	_FDT(fdt_property(fdt, "interrupt-controller", NULL, 0));
67*7c0e8b0cSWill Deacon 	_FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop)));
68*7c0e8b0cSWill Deacon 	_FDT(fdt_property_cell(fdt, "phandle", phandle));
69*7c0e8b0cSWill Deacon 	_FDT(fdt_end_node(fdt));
70*7c0e8b0cSWill Deacon }
71*7c0e8b0cSWill Deacon 
72*7c0e8b0cSWill Deacon #define KVM_IRQCHIP_IRQ(x) (KVM_ARM_IRQ_TYPE_SPI << KVM_ARM_IRQ_TYPE_SHIFT) |\
73*7c0e8b0cSWill Deacon 			   ((x) & KVM_ARM_IRQ_NUM_MASK)
74*7c0e8b0cSWill Deacon 
75*7c0e8b0cSWill Deacon void kvm__irq_line(struct kvm *kvm, int irq, int level)
76*7c0e8b0cSWill Deacon {
77*7c0e8b0cSWill Deacon 	struct kvm_irq_level irq_level = {
78*7c0e8b0cSWill Deacon 		.irq	= KVM_IRQCHIP_IRQ(irq),
79*7c0e8b0cSWill Deacon 		.level	= !!level,
80*7c0e8b0cSWill Deacon 	};
81*7c0e8b0cSWill Deacon 
82*7c0e8b0cSWill Deacon 	if (irq < GIC_SPI_IRQ_BASE || irq > GIC_MAX_IRQ)
83*7c0e8b0cSWill Deacon 		pr_warning("Ignoring invalid GIC IRQ %d", irq);
84*7c0e8b0cSWill Deacon 	else if (ioctl(kvm->vm_fd, KVM_IRQ_LINE, &irq_level) < 0)
85*7c0e8b0cSWill Deacon 		pr_warning("Could not KVM_IRQ_LINE for irq %d", irq);
86*7c0e8b0cSWill Deacon }
87*7c0e8b0cSWill Deacon 
88*7c0e8b0cSWill Deacon void kvm__irq_trigger(struct kvm *kvm, int irq)
89*7c0e8b0cSWill Deacon {
90*7c0e8b0cSWill Deacon 	kvm__irq_line(kvm, irq, VIRTIO_IRQ_HIGH);
91*7c0e8b0cSWill Deacon 	kvm__irq_line(kvm, irq, VIRTIO_IRQ_LOW);
92*7c0e8b0cSWill Deacon }
93