xref: /kvmtool/arm/gic.c (revision 14421de9e076ac4f22dd2b2715bfc878986dc66a)
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>
1112ca1401SAndre Przywara #include <linux/sizes.h>
127c0e8b0cSWill Deacon 
1369b9a17aSMarc Zyngier static int gic_fd = -1;
14bfb2c703SAndre Przywara static u64 gic_redists_base;
15bfb2c703SAndre Przywara static u64 gic_redists_size;
1612ca1401SAndre Przywara static u64 gic_msi_base;
1712ca1401SAndre Przywara static u64 gic_msi_size = 0;
1869b9a17aSMarc Zyngier 
1943d2781cSAndre Przywara int irqchip_parser(const struct option *opt, const char *arg, int unset)
2043d2781cSAndre Przywara {
2143d2781cSAndre Przywara 	enum irqchip_type *type = opt->value;
2243d2781cSAndre Przywara 
2343d2781cSAndre Przywara 	if (!strcmp(arg, "gicv2")) {
2443d2781cSAndre Przywara 		*type = IRQCHIP_GICV2;
2543d2781cSAndre Przywara 	} else if (!strcmp(arg, "gicv3")) {
2643d2781cSAndre Przywara 		*type = IRQCHIP_GICV3;
2743d2781cSAndre Przywara 	} else {
2843d2781cSAndre Przywara 		pr_err("irqchip: unknown type \"%s\"\n", arg);
2943d2781cSAndre Przywara 		return -1;
3043d2781cSAndre Przywara 	}
3143d2781cSAndre Przywara 
3243d2781cSAndre Przywara 	return 0;
3343d2781cSAndre Przywara }
3443d2781cSAndre Przywara 
3512ca1401SAndre Przywara static int gic__create_its_frame(struct kvm *kvm, u64 its_frame_addr)
3612ca1401SAndre Przywara {
3712ca1401SAndre Przywara 	struct kvm_create_device its_device = {
3812ca1401SAndre Przywara 		.type = KVM_DEV_TYPE_ARM_VGIC_ITS,
3912ca1401SAndre Przywara 		.flags	= 0,
4012ca1401SAndre Przywara 	};
4112ca1401SAndre Przywara 	struct kvm_device_attr its_attr = {
4212ca1401SAndre Przywara 		.group	= KVM_DEV_ARM_VGIC_GRP_ADDR,
4312ca1401SAndre Przywara 		.attr	= KVM_VGIC_ITS_ADDR_TYPE,
4412ca1401SAndre Przywara 		.addr	= (u64)(unsigned long)&its_frame_addr,
4512ca1401SAndre Przywara 	};
4612ca1401SAndre Przywara 	struct kvm_device_attr its_init_attr = {
4712ca1401SAndre Przywara 		.group	= KVM_DEV_ARM_VGIC_GRP_CTRL,
4812ca1401SAndre Przywara 		.attr	= KVM_DEV_ARM_VGIC_CTRL_INIT,
4912ca1401SAndre Przywara 	};
5012ca1401SAndre Przywara 	int err;
5112ca1401SAndre Przywara 
5212ca1401SAndre Przywara 	err = ioctl(kvm->vm_fd, KVM_CREATE_DEVICE, &its_device);
5312ca1401SAndre Przywara 	if (err) {
5412ca1401SAndre Przywara 		fprintf(stderr,
5512ca1401SAndre Przywara 			"GICv3 ITS requested, but kernel does not support it.\n");
5612ca1401SAndre Przywara 		fprintf(stderr, "Try --irqchip=gicv3 instead\n");
5712ca1401SAndre Przywara 		return err;
5812ca1401SAndre Przywara 	}
5912ca1401SAndre Przywara 
6012ca1401SAndre Przywara 	err = ioctl(its_device.fd, KVM_HAS_DEVICE_ATTR, &its_attr);
6112ca1401SAndre Przywara 	if (err) {
6212ca1401SAndre Przywara 		close(its_device.fd);
6312ca1401SAndre Przywara 		its_device.fd = -1;
6412ca1401SAndre Przywara 		return err;
6512ca1401SAndre Przywara 	}
6612ca1401SAndre Przywara 
6712ca1401SAndre Przywara 	err = ioctl(its_device.fd, KVM_SET_DEVICE_ATTR, &its_attr);
6812ca1401SAndre Przywara 	if (err)
6912ca1401SAndre Przywara 		return err;
7012ca1401SAndre Przywara 
7112ca1401SAndre Przywara 	return ioctl(its_device.fd, KVM_SET_DEVICE_ATTR, &its_init_attr);
7212ca1401SAndre Przywara }
7312ca1401SAndre Przywara 
7412ca1401SAndre Przywara static int gic__create_msi_frame(struct kvm *kvm, enum irqchip_type type,
7512ca1401SAndre Przywara 				 u64 msi_frame_addr)
7612ca1401SAndre Przywara {
7712ca1401SAndre Przywara 	switch (type) {
7812ca1401SAndre Przywara 	case IRQCHIP_GICV3_ITS:
7912ca1401SAndre Przywara 		return gic__create_its_frame(kvm, msi_frame_addr);
8012ca1401SAndre Przywara 	default:	/* No MSI frame needed */
8112ca1401SAndre Przywara 		return 0;
8212ca1401SAndre Przywara 	}
8312ca1401SAndre Przywara }
8412ca1401SAndre Przywara 
8502017c1dSAndre Przywara static int gic__create_device(struct kvm *kvm, enum irqchip_type type)
8669b9a17aSMarc Zyngier {
8769b9a17aSMarc Zyngier 	int err;
8869b9a17aSMarc Zyngier 	u64 cpu_if_addr = ARM_GIC_CPUI_BASE;
8969b9a17aSMarc Zyngier 	u64 dist_addr = ARM_GIC_DIST_BASE;
9069b9a17aSMarc Zyngier 	struct kvm_create_device gic_device = {
9102017c1dSAndre Przywara 		.flags	= 0,
9269b9a17aSMarc Zyngier 	};
9369b9a17aSMarc Zyngier 	struct kvm_device_attr cpu_if_attr = {
9469b9a17aSMarc Zyngier 		.group	= KVM_DEV_ARM_VGIC_GRP_ADDR,
9569b9a17aSMarc Zyngier 		.attr	= KVM_VGIC_V2_ADDR_TYPE_CPU,
9669b9a17aSMarc Zyngier 		.addr	= (u64)(unsigned long)&cpu_if_addr,
9769b9a17aSMarc Zyngier 	};
9869b9a17aSMarc Zyngier 	struct kvm_device_attr dist_attr = {
9969b9a17aSMarc Zyngier 		.group	= KVM_DEV_ARM_VGIC_GRP_ADDR,
10069b9a17aSMarc Zyngier 		.addr	= (u64)(unsigned long)&dist_addr,
10169b9a17aSMarc Zyngier 	};
102bfb2c703SAndre Przywara 	struct kvm_device_attr redist_attr = {
103bfb2c703SAndre Przywara 		.group	= KVM_DEV_ARM_VGIC_GRP_ADDR,
104bfb2c703SAndre Przywara 		.attr	= KVM_VGIC_V3_ADDR_TYPE_REDIST,
105bfb2c703SAndre Przywara 		.addr	= (u64)(unsigned long)&gic_redists_base,
106bfb2c703SAndre Przywara 	};
10769b9a17aSMarc Zyngier 
10802017c1dSAndre Przywara 	switch (type) {
10902017c1dSAndre Przywara 	case IRQCHIP_GICV2:
11002017c1dSAndre Przywara 		gic_device.type = KVM_DEV_TYPE_ARM_VGIC_V2;
11102017c1dSAndre Przywara 		dist_attr.attr  = KVM_VGIC_V2_ADDR_TYPE_DIST;
11202017c1dSAndre Przywara 		break;
113bfb2c703SAndre Przywara 	case IRQCHIP_GICV3:
11412ca1401SAndre Przywara 	case IRQCHIP_GICV3_ITS:
115bfb2c703SAndre Przywara 		gic_device.type = KVM_DEV_TYPE_ARM_VGIC_V3;
116bfb2c703SAndre Przywara 		dist_attr.attr  = KVM_VGIC_V3_ADDR_TYPE_DIST;
117bfb2c703SAndre Przywara 		break;
11802017c1dSAndre Przywara 	}
11902017c1dSAndre Przywara 
12069b9a17aSMarc Zyngier 	err = ioctl(kvm->vm_fd, KVM_CREATE_DEVICE, &gic_device);
12169b9a17aSMarc Zyngier 	if (err)
12269b9a17aSMarc Zyngier 		return err;
12369b9a17aSMarc Zyngier 
12469b9a17aSMarc Zyngier 	gic_fd = gic_device.fd;
12569b9a17aSMarc Zyngier 
12602017c1dSAndre Przywara 	switch (type) {
12702017c1dSAndre Przywara 	case IRQCHIP_GICV2:
12869b9a17aSMarc Zyngier 		err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &cpu_if_attr);
12902017c1dSAndre Przywara 		break;
13012ca1401SAndre Przywara 	case IRQCHIP_GICV3_ITS:
131bfb2c703SAndre Przywara 	case IRQCHIP_GICV3:
132bfb2c703SAndre Przywara 		err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &redist_attr);
133bfb2c703SAndre Przywara 		break;
13402017c1dSAndre Przywara 	}
13569b9a17aSMarc Zyngier 	if (err)
13669b9a17aSMarc Zyngier 		goto out_err;
13769b9a17aSMarc Zyngier 
13869b9a17aSMarc Zyngier 	err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &dist_attr);
13969b9a17aSMarc Zyngier 	if (err)
14069b9a17aSMarc Zyngier 		goto out_err;
14169b9a17aSMarc Zyngier 
14212ca1401SAndre Przywara 	err = gic__create_msi_frame(kvm, type, gic_msi_base);
14312ca1401SAndre Przywara 	if (err)
14412ca1401SAndre Przywara 		goto out_err;
14512ca1401SAndre Przywara 
14669b9a17aSMarc Zyngier 	return 0;
14769b9a17aSMarc Zyngier 
14869b9a17aSMarc Zyngier out_err:
14969b9a17aSMarc Zyngier 	close(gic_fd);
15069b9a17aSMarc Zyngier 	gic_fd = -1;
15169b9a17aSMarc Zyngier 	return err;
15269b9a17aSMarc Zyngier }
15369b9a17aSMarc Zyngier 
15469b9a17aSMarc Zyngier static int gic__create_irqchip(struct kvm *kvm)
1557c0e8b0cSWill Deacon {
1567c0e8b0cSWill Deacon 	int err;
157aa7a0e79SWill Deacon 	struct kvm_arm_device_addr gic_addr[] = {
1587c0e8b0cSWill Deacon 		[0] = {
159aa7a0e79SWill Deacon 			.id = KVM_VGIC_V2_ADDR_TYPE_DIST |
160aa7a0e79SWill Deacon 			(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT),
1617c0e8b0cSWill Deacon 			.addr = ARM_GIC_DIST_BASE,
1627c0e8b0cSWill Deacon 		},
1637c0e8b0cSWill Deacon 		[1] = {
164aa7a0e79SWill Deacon 			.id = KVM_VGIC_V2_ADDR_TYPE_CPU |
165aa7a0e79SWill Deacon 			(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT),
1667c0e8b0cSWill Deacon 			.addr = ARM_GIC_CPUI_BASE,
1677c0e8b0cSWill Deacon 		}
1687c0e8b0cSWill Deacon 	};
1697c0e8b0cSWill Deacon 
1707c0e8b0cSWill Deacon 	err = ioctl(kvm->vm_fd, KVM_CREATE_IRQCHIP);
1717c0e8b0cSWill Deacon 	if (err)
1727c0e8b0cSWill Deacon 		return err;
1737c0e8b0cSWill Deacon 
174aa7a0e79SWill Deacon 	err = ioctl(kvm->vm_fd, KVM_ARM_SET_DEVICE_ADDR, &gic_addr[0]);
1757c0e8b0cSWill Deacon 	if (err)
1767c0e8b0cSWill Deacon 		return err;
1777c0e8b0cSWill Deacon 
178aa7a0e79SWill Deacon 	err = ioctl(kvm->vm_fd, KVM_ARM_SET_DEVICE_ADDR, &gic_addr[1]);
1797c0e8b0cSWill Deacon 	return err;
1807c0e8b0cSWill Deacon }
1817c0e8b0cSWill Deacon 
18202017c1dSAndre Przywara int gic__create(struct kvm *kvm, enum irqchip_type type)
18369b9a17aSMarc Zyngier {
18469b9a17aSMarc Zyngier 	int err;
18569b9a17aSMarc Zyngier 
18602017c1dSAndre Przywara 	switch (type) {
18702017c1dSAndre Przywara 	case IRQCHIP_GICV2:
18802017c1dSAndre Przywara 		break;
18912ca1401SAndre Przywara 	case IRQCHIP_GICV3_ITS:
19012ca1401SAndre Przywara 		/* We reserve the 64K page with the doorbell as well. */
19112ca1401SAndre Przywara 		gic_msi_size = KVM_VGIC_V3_ITS_SIZE + SZ_64K;
19212ca1401SAndre Przywara 		/* fall through */
193bfb2c703SAndre Przywara 	case IRQCHIP_GICV3:
194bfb2c703SAndre Przywara 		gic_redists_size = kvm->cfg.nrcpus * ARM_GIC_REDIST_SIZE;
195bfb2c703SAndre Przywara 		gic_redists_base = ARM_GIC_DIST_BASE - gic_redists_size;
19612ca1401SAndre Przywara 		gic_msi_base = gic_redists_base - gic_msi_size;
197bfb2c703SAndre Przywara 		break;
19802017c1dSAndre Przywara 	default:
19902017c1dSAndre Przywara 		return -ENODEV;
20002017c1dSAndre Przywara 	}
20102017c1dSAndre Przywara 
20269b9a17aSMarc Zyngier 	/* Try the new way first, and fallback on legacy method otherwise */
20302017c1dSAndre Przywara 	err = gic__create_device(kvm, type);
20402017c1dSAndre Przywara 	if (err && type == IRQCHIP_GICV2)
20569b9a17aSMarc Zyngier 		err = gic__create_irqchip(kvm);
20669b9a17aSMarc Zyngier 
20769b9a17aSMarc Zyngier 	return err;
20869b9a17aSMarc Zyngier }
20969b9a17aSMarc Zyngier 
210b5790302SAndre Przywara /*
211b5790302SAndre Przywara  * Sets the number of used interrupts and finalizes the GIC init explicitly.
212b5790302SAndre Przywara  */
213bed2bd9eSMarc Zyngier static int gic__init_gic(struct kvm *kvm)
214bed2bd9eSMarc Zyngier {
215b5790302SAndre Przywara 	int ret;
216b5790302SAndre Przywara 
217bed2bd9eSMarc Zyngier 	int lines = irq__get_nr_allocated_lines();
218bed2bd9eSMarc Zyngier 	u32 nr_irqs = ALIGN(lines, 32) + GIC_SPI_IRQ_BASE;
219bed2bd9eSMarc Zyngier 	struct kvm_device_attr nr_irqs_attr = {
220bed2bd9eSMarc Zyngier 		.group	= KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
221bed2bd9eSMarc Zyngier 		.addr	= (u64)(unsigned long)&nr_irqs,
222bed2bd9eSMarc Zyngier 	};
223b5790302SAndre Przywara 	struct kvm_device_attr vgic_init_attr = {
224b5790302SAndre Przywara 		.group	= KVM_DEV_ARM_VGIC_GRP_CTRL,
225b5790302SAndre Przywara 		.attr	= KVM_DEV_ARM_VGIC_CTRL_INIT,
226b5790302SAndre Przywara 	};
227bed2bd9eSMarc Zyngier 
228bed2bd9eSMarc Zyngier 	/*
229bed2bd9eSMarc Zyngier 	 * If we didn't use the KVM_CREATE_DEVICE method, KVM will
230b5790302SAndre Przywara 	 * give us some default number of interrupts. The GIC initialization
231b5790302SAndre Przywara 	 * will be done automatically in this case.
232bed2bd9eSMarc Zyngier 	 */
233bed2bd9eSMarc Zyngier 	if (gic_fd < 0)
234bed2bd9eSMarc Zyngier 		return 0;
235bed2bd9eSMarc Zyngier 
236b5790302SAndre Przywara 	if (!ioctl(gic_fd, KVM_HAS_DEVICE_ATTR, &nr_irqs_attr)) {
237b5790302SAndre Przywara 		ret = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &nr_irqs_attr);
238b5790302SAndre Przywara 		if (ret)
239b5790302SAndre Przywara 			return ret;
240b5790302SAndre Przywara 	}
241b5790302SAndre Przywara 
242b5790302SAndre Przywara 	if (!ioctl(gic_fd, KVM_HAS_DEVICE_ATTR, &vgic_init_attr)) {
243b5790302SAndre Przywara 		ret = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &vgic_init_attr);
244b5790302SAndre Przywara 		if (ret)
245b5790302SAndre Przywara 			return ret;
246b5790302SAndre Przywara 	}
247bed2bd9eSMarc Zyngier 
248bed2bd9eSMarc Zyngier 	return 0;
249bed2bd9eSMarc Zyngier }
250bed2bd9eSMarc Zyngier late_init(gic__init_gic)
251bed2bd9eSMarc Zyngier 
2520063d50cSAndre Przywara void gic__generate_fdt_nodes(void *fdt, enum irqchip_type type)
2537c0e8b0cSWill Deacon {
254*14421de9SAndre Przywara 	const char *compatible, *msi_compatible = NULL;
255*14421de9SAndre Przywara 	u64 msi_prop[2];
2567c0e8b0cSWill Deacon 	u64 reg_prop[] = {
2577c0e8b0cSWill Deacon 		cpu_to_fdt64(ARM_GIC_DIST_BASE), cpu_to_fdt64(ARM_GIC_DIST_SIZE),
258bfb2c703SAndre Przywara 		0, 0,				/* to be filled */
2597c0e8b0cSWill Deacon 	};
2607c0e8b0cSWill Deacon 
26102017c1dSAndre Przywara 	switch (type) {
26202017c1dSAndre Przywara 	case IRQCHIP_GICV2:
26302017c1dSAndre Przywara 		compatible = "arm,cortex-a15-gic";
264bfb2c703SAndre Przywara 		reg_prop[2] = cpu_to_fdt64(ARM_GIC_CPUI_BASE);
265bfb2c703SAndre Przywara 		reg_prop[3] = cpu_to_fdt64(ARM_GIC_CPUI_SIZE);
266bfb2c703SAndre Przywara 		break;
267*14421de9SAndre Przywara 	case IRQCHIP_GICV3_ITS:
268*14421de9SAndre Przywara 		msi_compatible = "arm,gic-v3-its";
269*14421de9SAndre Przywara 		/* fall-through */
270bfb2c703SAndre Przywara 	case IRQCHIP_GICV3:
271bfb2c703SAndre Przywara 		compatible = "arm,gic-v3";
272bfb2c703SAndre Przywara 		reg_prop[2] = cpu_to_fdt64(gic_redists_base);
273bfb2c703SAndre Przywara 		reg_prop[3] = cpu_to_fdt64(gic_redists_size);
27402017c1dSAndre Przywara 		break;
27502017c1dSAndre Przywara 	default:
27602017c1dSAndre Przywara 		return;
27702017c1dSAndre Przywara 	}
27802017c1dSAndre Przywara 
2797c0e8b0cSWill Deacon 	_FDT(fdt_begin_node(fdt, "intc"));
28002017c1dSAndre Przywara 	_FDT(fdt_property_string(fdt, "compatible", compatible));
2817c0e8b0cSWill Deacon 	_FDT(fdt_property_cell(fdt, "#interrupt-cells", GIC_FDT_IRQ_NUM_CELLS));
2827c0e8b0cSWill Deacon 	_FDT(fdt_property(fdt, "interrupt-controller", NULL, 0));
2837c0e8b0cSWill Deacon 	_FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop)));
2840063d50cSAndre Przywara 	_FDT(fdt_property_cell(fdt, "phandle", PHANDLE_GIC));
285*14421de9SAndre Przywara 	_FDT(fdt_property_cell(fdt, "#address-cells", 2));
286*14421de9SAndre Przywara 	_FDT(fdt_property_cell(fdt, "#size-cells", 2));
287*14421de9SAndre Przywara 
288*14421de9SAndre Przywara 	if (msi_compatible) {
289*14421de9SAndre Przywara 		_FDT(fdt_property(fdt, "ranges", NULL, 0));
290*14421de9SAndre Przywara 
291*14421de9SAndre Przywara 		_FDT(fdt_begin_node(fdt, "msic"));
292*14421de9SAndre Przywara 		_FDT(fdt_property_string(fdt, "compatible", msi_compatible));
293*14421de9SAndre Przywara 		_FDT(fdt_property(fdt, "msi-controller", NULL, 0));
294*14421de9SAndre Przywara 		_FDT(fdt_property_cell(fdt, "phandle", PHANDLE_MSI));
295*14421de9SAndre Przywara 		msi_prop[0] = cpu_to_fdt64(gic_msi_base);
296*14421de9SAndre Przywara 		msi_prop[1] = cpu_to_fdt64(gic_msi_size);
297*14421de9SAndre Przywara 		_FDT(fdt_property(fdt, "reg", msi_prop, sizeof(msi_prop)));
298*14421de9SAndre Przywara 		_FDT(fdt_end_node(fdt));
299*14421de9SAndre Przywara 	}
300*14421de9SAndre Przywara 
3017c0e8b0cSWill Deacon 	_FDT(fdt_end_node(fdt));
3027c0e8b0cSWill Deacon }
3037c0e8b0cSWill Deacon 
3047c0e8b0cSWill Deacon #define KVM_IRQCHIP_IRQ(x) (KVM_ARM_IRQ_TYPE_SPI << KVM_ARM_IRQ_TYPE_SHIFT) |\
3057c0e8b0cSWill Deacon 			   ((x) & KVM_ARM_IRQ_NUM_MASK)
3067c0e8b0cSWill Deacon 
3077c0e8b0cSWill Deacon void kvm__irq_line(struct kvm *kvm, int irq, int level)
3087c0e8b0cSWill Deacon {
3097c0e8b0cSWill Deacon 	struct kvm_irq_level irq_level = {
3107c0e8b0cSWill Deacon 		.irq	= KVM_IRQCHIP_IRQ(irq),
3117c0e8b0cSWill Deacon 		.level	= !!level,
3127c0e8b0cSWill Deacon 	};
3137c0e8b0cSWill Deacon 
3147c0e8b0cSWill Deacon 	if (irq < GIC_SPI_IRQ_BASE || irq > GIC_MAX_IRQ)
3157c0e8b0cSWill Deacon 		pr_warning("Ignoring invalid GIC IRQ %d", irq);
3167c0e8b0cSWill Deacon 	else if (ioctl(kvm->vm_fd, KVM_IRQ_LINE, &irq_level) < 0)
3177c0e8b0cSWill Deacon 		pr_warning("Could not KVM_IRQ_LINE for irq %d", irq);
3187c0e8b0cSWill Deacon }
3197c0e8b0cSWill Deacon 
3207c0e8b0cSWill Deacon void kvm__irq_trigger(struct kvm *kvm, int irq)
3217c0e8b0cSWill Deacon {
3227c0e8b0cSWill Deacon 	kvm__irq_line(kvm, irq, VIRTIO_IRQ_HIGH);
3237c0e8b0cSWill Deacon 	kvm__irq_line(kvm, irq, VIRTIO_IRQ_LOW);
3247c0e8b0cSWill Deacon }
325