xref: /kvmtool/arm/gic.c (revision 02017c1d16d0a129e37472fc03788e48583f3a67)
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 
14*02017c1dSAndre Przywara static int gic__create_device(struct kvm *kvm, enum irqchip_type type)
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 = {
20*02017c1dSAndre Przywara 		.flags	= 0,
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 		.addr	= (u64)(unsigned long)&dist_addr,
3069b9a17aSMarc Zyngier 	};
3169b9a17aSMarc Zyngier 
32*02017c1dSAndre Przywara 	switch (type) {
33*02017c1dSAndre Przywara 	case IRQCHIP_GICV2:
34*02017c1dSAndre Przywara 		gic_device.type = KVM_DEV_TYPE_ARM_VGIC_V2;
35*02017c1dSAndre Przywara 		dist_attr.attr  = KVM_VGIC_V2_ADDR_TYPE_DIST;
36*02017c1dSAndre Przywara 		break;
37*02017c1dSAndre Przywara 	}
38*02017c1dSAndre Przywara 
3969b9a17aSMarc Zyngier 	err = ioctl(kvm->vm_fd, KVM_CREATE_DEVICE, &gic_device);
4069b9a17aSMarc Zyngier 	if (err)
4169b9a17aSMarc Zyngier 		return err;
4269b9a17aSMarc Zyngier 
4369b9a17aSMarc Zyngier 	gic_fd = gic_device.fd;
4469b9a17aSMarc Zyngier 
45*02017c1dSAndre Przywara 	switch (type) {
46*02017c1dSAndre Przywara 	case IRQCHIP_GICV2:
4769b9a17aSMarc Zyngier 		err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &cpu_if_attr);
48*02017c1dSAndre Przywara 		break;
49*02017c1dSAndre Przywara 	}
5069b9a17aSMarc Zyngier 	if (err)
5169b9a17aSMarc Zyngier 		goto out_err;
5269b9a17aSMarc Zyngier 
5369b9a17aSMarc Zyngier 	err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &dist_attr);
5469b9a17aSMarc Zyngier 	if (err)
5569b9a17aSMarc Zyngier 		goto out_err;
5669b9a17aSMarc Zyngier 
5769b9a17aSMarc Zyngier 	return 0;
5869b9a17aSMarc Zyngier 
5969b9a17aSMarc Zyngier out_err:
6069b9a17aSMarc Zyngier 	close(gic_fd);
6169b9a17aSMarc Zyngier 	gic_fd = -1;
6269b9a17aSMarc Zyngier 	return err;
6369b9a17aSMarc Zyngier }
6469b9a17aSMarc Zyngier 
6569b9a17aSMarc Zyngier static int gic__create_irqchip(struct kvm *kvm)
667c0e8b0cSWill Deacon {
677c0e8b0cSWill Deacon 	int err;
68aa7a0e79SWill Deacon 	struct kvm_arm_device_addr gic_addr[] = {
697c0e8b0cSWill Deacon 		[0] = {
70aa7a0e79SWill Deacon 			.id = KVM_VGIC_V2_ADDR_TYPE_DIST |
71aa7a0e79SWill Deacon 			(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT),
727c0e8b0cSWill Deacon 			.addr = ARM_GIC_DIST_BASE,
737c0e8b0cSWill Deacon 		},
747c0e8b0cSWill Deacon 		[1] = {
75aa7a0e79SWill Deacon 			.id = KVM_VGIC_V2_ADDR_TYPE_CPU |
76aa7a0e79SWill Deacon 			(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT),
777c0e8b0cSWill Deacon 			.addr = ARM_GIC_CPUI_BASE,
787c0e8b0cSWill Deacon 		}
797c0e8b0cSWill Deacon 	};
807c0e8b0cSWill Deacon 
817c0e8b0cSWill Deacon 	err = ioctl(kvm->vm_fd, KVM_CREATE_IRQCHIP);
827c0e8b0cSWill Deacon 	if (err)
837c0e8b0cSWill Deacon 		return err;
847c0e8b0cSWill Deacon 
85aa7a0e79SWill Deacon 	err = ioctl(kvm->vm_fd, KVM_ARM_SET_DEVICE_ADDR, &gic_addr[0]);
867c0e8b0cSWill Deacon 	if (err)
877c0e8b0cSWill Deacon 		return err;
887c0e8b0cSWill Deacon 
89aa7a0e79SWill Deacon 	err = ioctl(kvm->vm_fd, KVM_ARM_SET_DEVICE_ADDR, &gic_addr[1]);
907c0e8b0cSWill Deacon 	return err;
917c0e8b0cSWill Deacon }
927c0e8b0cSWill Deacon 
93*02017c1dSAndre Przywara int gic__create(struct kvm *kvm, enum irqchip_type type)
9469b9a17aSMarc Zyngier {
9569b9a17aSMarc Zyngier 	int err;
9669b9a17aSMarc Zyngier 
97*02017c1dSAndre Przywara 	switch (type) {
98*02017c1dSAndre Przywara 	case IRQCHIP_GICV2:
99*02017c1dSAndre Przywara 		break;
100*02017c1dSAndre Przywara 	default:
101*02017c1dSAndre Przywara 		return -ENODEV;
102*02017c1dSAndre Przywara 	}
103*02017c1dSAndre Przywara 
10469b9a17aSMarc Zyngier 	/* Try the new way first, and fallback on legacy method otherwise */
105*02017c1dSAndre Przywara 	err = gic__create_device(kvm, type);
106*02017c1dSAndre Przywara 	if (err && type == IRQCHIP_GICV2)
10769b9a17aSMarc Zyngier 		err = gic__create_irqchip(kvm);
10869b9a17aSMarc Zyngier 
10969b9a17aSMarc Zyngier 	return err;
11069b9a17aSMarc Zyngier }
11169b9a17aSMarc Zyngier 
112b5790302SAndre Przywara /*
113b5790302SAndre Przywara  * Sets the number of used interrupts and finalizes the GIC init explicitly.
114b5790302SAndre Przywara  */
115bed2bd9eSMarc Zyngier static int gic__init_gic(struct kvm *kvm)
116bed2bd9eSMarc Zyngier {
117b5790302SAndre Przywara 	int ret;
118b5790302SAndre Przywara 
119bed2bd9eSMarc Zyngier 	int lines = irq__get_nr_allocated_lines();
120bed2bd9eSMarc Zyngier 	u32 nr_irqs = ALIGN(lines, 32) + GIC_SPI_IRQ_BASE;
121bed2bd9eSMarc Zyngier 	struct kvm_device_attr nr_irqs_attr = {
122bed2bd9eSMarc Zyngier 		.group	= KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
123bed2bd9eSMarc Zyngier 		.addr	= (u64)(unsigned long)&nr_irqs,
124bed2bd9eSMarc Zyngier 	};
125b5790302SAndre Przywara 	struct kvm_device_attr vgic_init_attr = {
126b5790302SAndre Przywara 		.group	= KVM_DEV_ARM_VGIC_GRP_CTRL,
127b5790302SAndre Przywara 		.attr	= KVM_DEV_ARM_VGIC_CTRL_INIT,
128b5790302SAndre Przywara 	};
129bed2bd9eSMarc Zyngier 
130bed2bd9eSMarc Zyngier 	/*
131bed2bd9eSMarc Zyngier 	 * If we didn't use the KVM_CREATE_DEVICE method, KVM will
132b5790302SAndre Przywara 	 * give us some default number of interrupts. The GIC initialization
133b5790302SAndre Przywara 	 * will be done automatically in this case.
134bed2bd9eSMarc Zyngier 	 */
135bed2bd9eSMarc Zyngier 	if (gic_fd < 0)
136bed2bd9eSMarc Zyngier 		return 0;
137bed2bd9eSMarc Zyngier 
138b5790302SAndre Przywara 	if (!ioctl(gic_fd, KVM_HAS_DEVICE_ATTR, &nr_irqs_attr)) {
139b5790302SAndre Przywara 		ret = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &nr_irqs_attr);
140b5790302SAndre Przywara 		if (ret)
141b5790302SAndre Przywara 			return ret;
142b5790302SAndre Przywara 	}
143b5790302SAndre Przywara 
144b5790302SAndre Przywara 	if (!ioctl(gic_fd, KVM_HAS_DEVICE_ATTR, &vgic_init_attr)) {
145b5790302SAndre Przywara 		ret = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &vgic_init_attr);
146b5790302SAndre Przywara 		if (ret)
147b5790302SAndre Przywara 			return ret;
148b5790302SAndre Przywara 	}
149bed2bd9eSMarc Zyngier 
150bed2bd9eSMarc Zyngier 	return 0;
151bed2bd9eSMarc Zyngier }
152bed2bd9eSMarc Zyngier late_init(gic__init_gic)
153bed2bd9eSMarc Zyngier 
154*02017c1dSAndre Przywara void gic__generate_fdt_nodes(void *fdt, u32 phandle, enum irqchip_type type)
1557c0e8b0cSWill Deacon {
156*02017c1dSAndre Przywara 	const char *compatible;
1577c0e8b0cSWill Deacon 	u64 reg_prop[] = {
1587c0e8b0cSWill Deacon 		cpu_to_fdt64(ARM_GIC_DIST_BASE), cpu_to_fdt64(ARM_GIC_DIST_SIZE),
1597c0e8b0cSWill Deacon 		cpu_to_fdt64(ARM_GIC_CPUI_BASE), cpu_to_fdt64(ARM_GIC_CPUI_SIZE),
1607c0e8b0cSWill Deacon 	};
1617c0e8b0cSWill Deacon 
162*02017c1dSAndre Przywara 	switch (type) {
163*02017c1dSAndre Przywara 	case IRQCHIP_GICV2:
164*02017c1dSAndre Przywara 		compatible = "arm,cortex-a15-gic";
165*02017c1dSAndre Przywara 		break;
166*02017c1dSAndre Przywara 	default:
167*02017c1dSAndre Przywara 		return;
168*02017c1dSAndre Przywara 	}
169*02017c1dSAndre Przywara 
1707c0e8b0cSWill Deacon 	_FDT(fdt_begin_node(fdt, "intc"));
171*02017c1dSAndre Przywara 	_FDT(fdt_property_string(fdt, "compatible", compatible));
1727c0e8b0cSWill Deacon 	_FDT(fdt_property_cell(fdt, "#interrupt-cells", GIC_FDT_IRQ_NUM_CELLS));
1737c0e8b0cSWill Deacon 	_FDT(fdt_property(fdt, "interrupt-controller", NULL, 0));
1747c0e8b0cSWill Deacon 	_FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop)));
1757c0e8b0cSWill Deacon 	_FDT(fdt_property_cell(fdt, "phandle", phandle));
1767c0e8b0cSWill Deacon 	_FDT(fdt_end_node(fdt));
1777c0e8b0cSWill Deacon }
1787c0e8b0cSWill Deacon 
1797c0e8b0cSWill Deacon #define KVM_IRQCHIP_IRQ(x) (KVM_ARM_IRQ_TYPE_SPI << KVM_ARM_IRQ_TYPE_SHIFT) |\
1807c0e8b0cSWill Deacon 			   ((x) & KVM_ARM_IRQ_NUM_MASK)
1817c0e8b0cSWill Deacon 
1827c0e8b0cSWill Deacon void kvm__irq_line(struct kvm *kvm, int irq, int level)
1837c0e8b0cSWill Deacon {
1847c0e8b0cSWill Deacon 	struct kvm_irq_level irq_level = {
1857c0e8b0cSWill Deacon 		.irq	= KVM_IRQCHIP_IRQ(irq),
1867c0e8b0cSWill Deacon 		.level	= !!level,
1877c0e8b0cSWill Deacon 	};
1887c0e8b0cSWill Deacon 
1897c0e8b0cSWill Deacon 	if (irq < GIC_SPI_IRQ_BASE || irq > GIC_MAX_IRQ)
1907c0e8b0cSWill Deacon 		pr_warning("Ignoring invalid GIC IRQ %d", irq);
1917c0e8b0cSWill Deacon 	else if (ioctl(kvm->vm_fd, KVM_IRQ_LINE, &irq_level) < 0)
1927c0e8b0cSWill Deacon 		pr_warning("Could not KVM_IRQ_LINE for irq %d", irq);
1937c0e8b0cSWill Deacon }
1947c0e8b0cSWill Deacon 
1957c0e8b0cSWill Deacon void kvm__irq_trigger(struct kvm *kvm, int irq)
1967c0e8b0cSWill Deacon {
1977c0e8b0cSWill Deacon 	kvm__irq_line(kvm, irq, VIRTIO_IRQ_HIGH);
1987c0e8b0cSWill Deacon 	kvm__irq_line(kvm, irq, VIRTIO_IRQ_LOW);
1997c0e8b0cSWill Deacon }
200