xref: /kvmtool/arm/gic.c (revision 43d2781c273192b678b090f3e3c31edfbaeca54d)
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 
12bfb2c703SAndre Przywara /* Those names are not defined for ARM (yet) */
13bfb2c703SAndre Przywara #ifndef KVM_VGIC_V3_ADDR_TYPE_DIST
14bfb2c703SAndre Przywara #define KVM_VGIC_V3_ADDR_TYPE_DIST 2
15bfb2c703SAndre Przywara #endif
16bfb2c703SAndre Przywara 
17bfb2c703SAndre Przywara #ifndef KVM_VGIC_V3_ADDR_TYPE_REDIST
18bfb2c703SAndre Przywara #define KVM_VGIC_V3_ADDR_TYPE_REDIST 3
19bfb2c703SAndre Przywara #endif
20bfb2c703SAndre Przywara 
2169b9a17aSMarc Zyngier static int gic_fd = -1;
22bfb2c703SAndre Przywara static u64 gic_redists_base;
23bfb2c703SAndre Przywara static u64 gic_redists_size;
2469b9a17aSMarc Zyngier 
25*43d2781cSAndre Przywara int irqchip_parser(const struct option *opt, const char *arg, int unset)
26*43d2781cSAndre Przywara {
27*43d2781cSAndre Przywara 	enum irqchip_type *type = opt->value;
28*43d2781cSAndre Przywara 
29*43d2781cSAndre Przywara 	if (!strcmp(arg, "gicv2")) {
30*43d2781cSAndre Przywara 		*type = IRQCHIP_GICV2;
31*43d2781cSAndre Przywara 	} else if (!strcmp(arg, "gicv3")) {
32*43d2781cSAndre Przywara 		*type = IRQCHIP_GICV3;
33*43d2781cSAndre Przywara 	} else {
34*43d2781cSAndre Przywara 		pr_err("irqchip: unknown type \"%s\"\n", arg);
35*43d2781cSAndre Przywara 		return -1;
36*43d2781cSAndre Przywara 	}
37*43d2781cSAndre Przywara 
38*43d2781cSAndre Przywara 	return 0;
39*43d2781cSAndre Przywara }
40*43d2781cSAndre Przywara 
4102017c1dSAndre Przywara static int gic__create_device(struct kvm *kvm, enum irqchip_type type)
4269b9a17aSMarc Zyngier {
4369b9a17aSMarc Zyngier 	int err;
4469b9a17aSMarc Zyngier 	u64 cpu_if_addr = ARM_GIC_CPUI_BASE;
4569b9a17aSMarc Zyngier 	u64 dist_addr = ARM_GIC_DIST_BASE;
4669b9a17aSMarc Zyngier 	struct kvm_create_device gic_device = {
4702017c1dSAndre Przywara 		.flags	= 0,
4869b9a17aSMarc Zyngier 	};
4969b9a17aSMarc Zyngier 	struct kvm_device_attr cpu_if_attr = {
5069b9a17aSMarc Zyngier 		.group	= KVM_DEV_ARM_VGIC_GRP_ADDR,
5169b9a17aSMarc Zyngier 		.attr	= KVM_VGIC_V2_ADDR_TYPE_CPU,
5269b9a17aSMarc Zyngier 		.addr	= (u64)(unsigned long)&cpu_if_addr,
5369b9a17aSMarc Zyngier 	};
5469b9a17aSMarc Zyngier 	struct kvm_device_attr dist_attr = {
5569b9a17aSMarc Zyngier 		.group	= KVM_DEV_ARM_VGIC_GRP_ADDR,
5669b9a17aSMarc Zyngier 		.addr	= (u64)(unsigned long)&dist_addr,
5769b9a17aSMarc Zyngier 	};
58bfb2c703SAndre Przywara 	struct kvm_device_attr redist_attr = {
59bfb2c703SAndre Przywara 		.group	= KVM_DEV_ARM_VGIC_GRP_ADDR,
60bfb2c703SAndre Przywara 		.attr	= KVM_VGIC_V3_ADDR_TYPE_REDIST,
61bfb2c703SAndre Przywara 		.addr	= (u64)(unsigned long)&gic_redists_base,
62bfb2c703SAndre Przywara 	};
6369b9a17aSMarc Zyngier 
6402017c1dSAndre Przywara 	switch (type) {
6502017c1dSAndre Przywara 	case IRQCHIP_GICV2:
6602017c1dSAndre Przywara 		gic_device.type = KVM_DEV_TYPE_ARM_VGIC_V2;
6702017c1dSAndre Przywara 		dist_attr.attr  = KVM_VGIC_V2_ADDR_TYPE_DIST;
6802017c1dSAndre Przywara 		break;
69bfb2c703SAndre Przywara 	case IRQCHIP_GICV3:
70bfb2c703SAndre Przywara 		gic_device.type = KVM_DEV_TYPE_ARM_VGIC_V3;
71bfb2c703SAndre Przywara 		dist_attr.attr  = KVM_VGIC_V3_ADDR_TYPE_DIST;
72bfb2c703SAndre Przywara 		break;
7302017c1dSAndre Przywara 	}
7402017c1dSAndre Przywara 
7569b9a17aSMarc Zyngier 	err = ioctl(kvm->vm_fd, KVM_CREATE_DEVICE, &gic_device);
7669b9a17aSMarc Zyngier 	if (err)
7769b9a17aSMarc Zyngier 		return err;
7869b9a17aSMarc Zyngier 
7969b9a17aSMarc Zyngier 	gic_fd = gic_device.fd;
8069b9a17aSMarc Zyngier 
8102017c1dSAndre Przywara 	switch (type) {
8202017c1dSAndre Przywara 	case IRQCHIP_GICV2:
8369b9a17aSMarc Zyngier 		err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &cpu_if_attr);
8402017c1dSAndre Przywara 		break;
85bfb2c703SAndre Przywara 	case IRQCHIP_GICV3:
86bfb2c703SAndre Przywara 		err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &redist_attr);
87bfb2c703SAndre Przywara 		break;
8802017c1dSAndre Przywara 	}
8969b9a17aSMarc Zyngier 	if (err)
9069b9a17aSMarc Zyngier 		goto out_err;
9169b9a17aSMarc Zyngier 
9269b9a17aSMarc Zyngier 	err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &dist_attr);
9369b9a17aSMarc Zyngier 	if (err)
9469b9a17aSMarc Zyngier 		goto out_err;
9569b9a17aSMarc Zyngier 
9669b9a17aSMarc Zyngier 	return 0;
9769b9a17aSMarc Zyngier 
9869b9a17aSMarc Zyngier out_err:
9969b9a17aSMarc Zyngier 	close(gic_fd);
10069b9a17aSMarc Zyngier 	gic_fd = -1;
10169b9a17aSMarc Zyngier 	return err;
10269b9a17aSMarc Zyngier }
10369b9a17aSMarc Zyngier 
10469b9a17aSMarc Zyngier static int gic__create_irqchip(struct kvm *kvm)
1057c0e8b0cSWill Deacon {
1067c0e8b0cSWill Deacon 	int err;
107aa7a0e79SWill Deacon 	struct kvm_arm_device_addr gic_addr[] = {
1087c0e8b0cSWill Deacon 		[0] = {
109aa7a0e79SWill Deacon 			.id = KVM_VGIC_V2_ADDR_TYPE_DIST |
110aa7a0e79SWill Deacon 			(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT),
1117c0e8b0cSWill Deacon 			.addr = ARM_GIC_DIST_BASE,
1127c0e8b0cSWill Deacon 		},
1137c0e8b0cSWill Deacon 		[1] = {
114aa7a0e79SWill Deacon 			.id = KVM_VGIC_V2_ADDR_TYPE_CPU |
115aa7a0e79SWill Deacon 			(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT),
1167c0e8b0cSWill Deacon 			.addr = ARM_GIC_CPUI_BASE,
1177c0e8b0cSWill Deacon 		}
1187c0e8b0cSWill Deacon 	};
1197c0e8b0cSWill Deacon 
1207c0e8b0cSWill Deacon 	err = ioctl(kvm->vm_fd, KVM_CREATE_IRQCHIP);
1217c0e8b0cSWill Deacon 	if (err)
1227c0e8b0cSWill Deacon 		return err;
1237c0e8b0cSWill Deacon 
124aa7a0e79SWill Deacon 	err = ioctl(kvm->vm_fd, KVM_ARM_SET_DEVICE_ADDR, &gic_addr[0]);
1257c0e8b0cSWill Deacon 	if (err)
1267c0e8b0cSWill Deacon 		return err;
1277c0e8b0cSWill Deacon 
128aa7a0e79SWill Deacon 	err = ioctl(kvm->vm_fd, KVM_ARM_SET_DEVICE_ADDR, &gic_addr[1]);
1297c0e8b0cSWill Deacon 	return err;
1307c0e8b0cSWill Deacon }
1317c0e8b0cSWill Deacon 
13202017c1dSAndre Przywara int gic__create(struct kvm *kvm, enum irqchip_type type)
13369b9a17aSMarc Zyngier {
13469b9a17aSMarc Zyngier 	int err;
13569b9a17aSMarc Zyngier 
13602017c1dSAndre Przywara 	switch (type) {
13702017c1dSAndre Przywara 	case IRQCHIP_GICV2:
13802017c1dSAndre Przywara 		break;
139bfb2c703SAndre Przywara 	case IRQCHIP_GICV3:
140bfb2c703SAndre Przywara 		gic_redists_size = kvm->cfg.nrcpus * ARM_GIC_REDIST_SIZE;
141bfb2c703SAndre Przywara 		gic_redists_base = ARM_GIC_DIST_BASE - gic_redists_size;
142bfb2c703SAndre Przywara 		break;
14302017c1dSAndre Przywara 	default:
14402017c1dSAndre Przywara 		return -ENODEV;
14502017c1dSAndre Przywara 	}
14602017c1dSAndre Przywara 
14769b9a17aSMarc Zyngier 	/* Try the new way first, and fallback on legacy method otherwise */
14802017c1dSAndre Przywara 	err = gic__create_device(kvm, type);
14902017c1dSAndre Przywara 	if (err && type == IRQCHIP_GICV2)
15069b9a17aSMarc Zyngier 		err = gic__create_irqchip(kvm);
15169b9a17aSMarc Zyngier 
15269b9a17aSMarc Zyngier 	return err;
15369b9a17aSMarc Zyngier }
15469b9a17aSMarc Zyngier 
155b5790302SAndre Przywara /*
156b5790302SAndre Przywara  * Sets the number of used interrupts and finalizes the GIC init explicitly.
157b5790302SAndre Przywara  */
158bed2bd9eSMarc Zyngier static int gic__init_gic(struct kvm *kvm)
159bed2bd9eSMarc Zyngier {
160b5790302SAndre Przywara 	int ret;
161b5790302SAndre Przywara 
162bed2bd9eSMarc Zyngier 	int lines = irq__get_nr_allocated_lines();
163bed2bd9eSMarc Zyngier 	u32 nr_irqs = ALIGN(lines, 32) + GIC_SPI_IRQ_BASE;
164bed2bd9eSMarc Zyngier 	struct kvm_device_attr nr_irqs_attr = {
165bed2bd9eSMarc Zyngier 		.group	= KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
166bed2bd9eSMarc Zyngier 		.addr	= (u64)(unsigned long)&nr_irqs,
167bed2bd9eSMarc Zyngier 	};
168b5790302SAndre Przywara 	struct kvm_device_attr vgic_init_attr = {
169b5790302SAndre Przywara 		.group	= KVM_DEV_ARM_VGIC_GRP_CTRL,
170b5790302SAndre Przywara 		.attr	= KVM_DEV_ARM_VGIC_CTRL_INIT,
171b5790302SAndre Przywara 	};
172bed2bd9eSMarc Zyngier 
173bed2bd9eSMarc Zyngier 	/*
174bed2bd9eSMarc Zyngier 	 * If we didn't use the KVM_CREATE_DEVICE method, KVM will
175b5790302SAndre Przywara 	 * give us some default number of interrupts. The GIC initialization
176b5790302SAndre Przywara 	 * will be done automatically in this case.
177bed2bd9eSMarc Zyngier 	 */
178bed2bd9eSMarc Zyngier 	if (gic_fd < 0)
179bed2bd9eSMarc Zyngier 		return 0;
180bed2bd9eSMarc Zyngier 
181b5790302SAndre Przywara 	if (!ioctl(gic_fd, KVM_HAS_DEVICE_ATTR, &nr_irqs_attr)) {
182b5790302SAndre Przywara 		ret = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &nr_irqs_attr);
183b5790302SAndre Przywara 		if (ret)
184b5790302SAndre Przywara 			return ret;
185b5790302SAndre Przywara 	}
186b5790302SAndre Przywara 
187b5790302SAndre Przywara 	if (!ioctl(gic_fd, KVM_HAS_DEVICE_ATTR, &vgic_init_attr)) {
188b5790302SAndre Przywara 		ret = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &vgic_init_attr);
189b5790302SAndre Przywara 		if (ret)
190b5790302SAndre Przywara 			return ret;
191b5790302SAndre Przywara 	}
192bed2bd9eSMarc Zyngier 
193bed2bd9eSMarc Zyngier 	return 0;
194bed2bd9eSMarc Zyngier }
195bed2bd9eSMarc Zyngier late_init(gic__init_gic)
196bed2bd9eSMarc Zyngier 
19702017c1dSAndre Przywara void gic__generate_fdt_nodes(void *fdt, u32 phandle, enum irqchip_type type)
1987c0e8b0cSWill Deacon {
19902017c1dSAndre Przywara 	const char *compatible;
2007c0e8b0cSWill Deacon 	u64 reg_prop[] = {
2017c0e8b0cSWill Deacon 		cpu_to_fdt64(ARM_GIC_DIST_BASE), cpu_to_fdt64(ARM_GIC_DIST_SIZE),
202bfb2c703SAndre Przywara 		0, 0,				/* to be filled */
2037c0e8b0cSWill Deacon 	};
2047c0e8b0cSWill Deacon 
20502017c1dSAndre Przywara 	switch (type) {
20602017c1dSAndre Przywara 	case IRQCHIP_GICV2:
20702017c1dSAndre Przywara 		compatible = "arm,cortex-a15-gic";
208bfb2c703SAndre Przywara 		reg_prop[2] = cpu_to_fdt64(ARM_GIC_CPUI_BASE);
209bfb2c703SAndre Przywara 		reg_prop[3] = cpu_to_fdt64(ARM_GIC_CPUI_SIZE);
210bfb2c703SAndre Przywara 		break;
211bfb2c703SAndre Przywara 	case IRQCHIP_GICV3:
212bfb2c703SAndre Przywara 		compatible = "arm,gic-v3";
213bfb2c703SAndre Przywara 		reg_prop[2] = cpu_to_fdt64(gic_redists_base);
214bfb2c703SAndre Przywara 		reg_prop[3] = cpu_to_fdt64(gic_redists_size);
21502017c1dSAndre Przywara 		break;
21602017c1dSAndre Przywara 	default:
21702017c1dSAndre Przywara 		return;
21802017c1dSAndre Przywara 	}
21902017c1dSAndre Przywara 
2207c0e8b0cSWill Deacon 	_FDT(fdt_begin_node(fdt, "intc"));
22102017c1dSAndre Przywara 	_FDT(fdt_property_string(fdt, "compatible", compatible));
2227c0e8b0cSWill Deacon 	_FDT(fdt_property_cell(fdt, "#interrupt-cells", GIC_FDT_IRQ_NUM_CELLS));
2237c0e8b0cSWill Deacon 	_FDT(fdt_property(fdt, "interrupt-controller", NULL, 0));
2247c0e8b0cSWill Deacon 	_FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop)));
2257c0e8b0cSWill Deacon 	_FDT(fdt_property_cell(fdt, "phandle", phandle));
2267c0e8b0cSWill Deacon 	_FDT(fdt_end_node(fdt));
2277c0e8b0cSWill Deacon }
2287c0e8b0cSWill Deacon 
2297c0e8b0cSWill Deacon #define KVM_IRQCHIP_IRQ(x) (KVM_ARM_IRQ_TYPE_SPI << KVM_ARM_IRQ_TYPE_SHIFT) |\
2307c0e8b0cSWill Deacon 			   ((x) & KVM_ARM_IRQ_NUM_MASK)
2317c0e8b0cSWill Deacon 
2327c0e8b0cSWill Deacon void kvm__irq_line(struct kvm *kvm, int irq, int level)
2337c0e8b0cSWill Deacon {
2347c0e8b0cSWill Deacon 	struct kvm_irq_level irq_level = {
2357c0e8b0cSWill Deacon 		.irq	= KVM_IRQCHIP_IRQ(irq),
2367c0e8b0cSWill Deacon 		.level	= !!level,
2377c0e8b0cSWill Deacon 	};
2387c0e8b0cSWill Deacon 
2397c0e8b0cSWill Deacon 	if (irq < GIC_SPI_IRQ_BASE || irq > GIC_MAX_IRQ)
2407c0e8b0cSWill Deacon 		pr_warning("Ignoring invalid GIC IRQ %d", irq);
2417c0e8b0cSWill Deacon 	else if (ioctl(kvm->vm_fd, KVM_IRQ_LINE, &irq_level) < 0)
2427c0e8b0cSWill Deacon 		pr_warning("Could not KVM_IRQ_LINE for irq %d", irq);
2437c0e8b0cSWill Deacon }
2447c0e8b0cSWill Deacon 
2457c0e8b0cSWill Deacon void kvm__irq_trigger(struct kvm *kvm, int irq)
2467c0e8b0cSWill Deacon {
2477c0e8b0cSWill Deacon 	kvm__irq_line(kvm, irq, VIRTIO_IRQ_HIGH);
2487c0e8b0cSWill Deacon 	kvm__irq_line(kvm, irq, VIRTIO_IRQ_LOW);
2497c0e8b0cSWill Deacon }
250