xref: /kvmtool/arm/gic.c (revision 72e13944777a6c60fbcd78ef97e06ffd00969d77)
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 
1369ae77c5SAndre Przywara #define IRQCHIP_GIC 0
1469ae77c5SAndre Przywara 
1569b9a17aSMarc Zyngier static int gic_fd = -1;
16bfb2c703SAndre Przywara static u64 gic_redists_base;
17bfb2c703SAndre Przywara static u64 gic_redists_size;
1812ca1401SAndre Przywara static u64 gic_msi_base;
1912ca1401SAndre Przywara static u64 gic_msi_size = 0;
20e59679d2SJean-Philippe Brucker static bool vgic_is_init = false;
21e59679d2SJean-Philippe Brucker 
22e59679d2SJean-Philippe Brucker struct kvm_irqfd_line {
23e59679d2SJean-Philippe Brucker 	unsigned int		gsi;
24e59679d2SJean-Philippe Brucker 	int			trigger_fd;
25e59679d2SJean-Philippe Brucker 	int			resample_fd;
26e59679d2SJean-Philippe Brucker 	struct list_head	list;
27e59679d2SJean-Philippe Brucker };
28e59679d2SJean-Philippe Brucker 
29e59679d2SJean-Philippe Brucker static LIST_HEAD(irqfd_lines);
3069b9a17aSMarc Zyngier 
irqchip_parser(const struct option * opt,const char * arg,int unset)3143d2781cSAndre Przywara int irqchip_parser(const struct option *opt, const char *arg, int unset)
3243d2781cSAndre Przywara {
3343d2781cSAndre Przywara 	enum irqchip_type *type = opt->value;
3443d2781cSAndre Przywara 
3543d2781cSAndre Przywara 	if (!strcmp(arg, "gicv2")) {
3643d2781cSAndre Przywara 		*type = IRQCHIP_GICV2;
37f6108d72SJean-Philippe Brucker 	} else if (!strcmp(arg, "gicv2m")) {
38f6108d72SJean-Philippe Brucker 		*type = IRQCHIP_GICV2M;
3943d2781cSAndre Przywara 	} else if (!strcmp(arg, "gicv3")) {
4043d2781cSAndre Przywara 		*type = IRQCHIP_GICV3;
4176392d29SAndre Przywara 	} else if (!strcmp(arg, "gicv3-its")) {
4276392d29SAndre Przywara 		*type = IRQCHIP_GICV3_ITS;
4343d2781cSAndre Przywara 	} else {
4443d2781cSAndre Przywara 		pr_err("irqchip: unknown type \"%s\"\n", arg);
4543d2781cSAndre Przywara 		return -1;
4643d2781cSAndre Przywara 	}
4743d2781cSAndre Przywara 
4843d2781cSAndre Przywara 	return 0;
4943d2781cSAndre Przywara }
5043d2781cSAndre Przywara 
irq__setup_irqfd_lines(struct kvm * kvm)51e59679d2SJean-Philippe Brucker static int irq__setup_irqfd_lines(struct kvm *kvm)
52e59679d2SJean-Philippe Brucker {
53e59679d2SJean-Philippe Brucker 	int ret;
54e59679d2SJean-Philippe Brucker 	struct kvm_irqfd_line *line, *tmp;
55e59679d2SJean-Philippe Brucker 
56e59679d2SJean-Philippe Brucker 	list_for_each_entry_safe(line, tmp, &irqfd_lines, list) {
57e59679d2SJean-Philippe Brucker 		ret = irq__common_add_irqfd(kvm, line->gsi, line->trigger_fd,
58e59679d2SJean-Philippe Brucker 					    line->resample_fd);
59e59679d2SJean-Philippe Brucker 		if (ret < 0) {
60e59679d2SJean-Philippe Brucker 			pr_err("Failed to register IRQFD");
61e59679d2SJean-Philippe Brucker 			return ret;
62e59679d2SJean-Philippe Brucker 		}
63e59679d2SJean-Philippe Brucker 
64e59679d2SJean-Philippe Brucker 		list_del(&line->list);
65e59679d2SJean-Philippe Brucker 		free(line);
66e59679d2SJean-Philippe Brucker 	}
67e59679d2SJean-Philippe Brucker 
68e59679d2SJean-Philippe Brucker 	return 0;
69e59679d2SJean-Philippe Brucker }
70e59679d2SJean-Philippe Brucker 
irq__routing_init(struct kvm * kvm)7169ae77c5SAndre Przywara static int irq__routing_init(struct kvm *kvm)
7269ae77c5SAndre Przywara {
7369ae77c5SAndre Przywara 	int r;
7469ae77c5SAndre Przywara 	int irqlines = ALIGN(irq__get_nr_allocated_lines(), 32);
7569ae77c5SAndre Przywara 
7669ae77c5SAndre Przywara 	/*
7769ae77c5SAndre Przywara 	 * This describes the default routing that the kernel uses without
7869ae77c5SAndre Przywara 	 * any routing explicitly set up via KVM_SET_GSI_ROUTING. So we
7969ae77c5SAndre Przywara 	 * don't need to commit these setting right now. The first actual
8069ae77c5SAndre Przywara 	 * user (MSI routing) will engage these mappings then.
8169ae77c5SAndre Przywara 	 */
8269ae77c5SAndre Przywara 	for (next_gsi = 0; next_gsi < irqlines; next_gsi++) {
8369ae77c5SAndre Przywara 		r = irq__allocate_routing_entry();
8469ae77c5SAndre Przywara 		if (r)
8569ae77c5SAndre Przywara 			return r;
8669ae77c5SAndre Przywara 
8769ae77c5SAndre Przywara 		irq_routing->entries[irq_routing->nr++] =
8869ae77c5SAndre Przywara 			(struct kvm_irq_routing_entry) {
8969ae77c5SAndre Przywara 				.gsi = next_gsi,
9069ae77c5SAndre Przywara 				.type = KVM_IRQ_ROUTING_IRQCHIP,
9169ae77c5SAndre Przywara 				.u.irqchip.irqchip = IRQCHIP_GIC,
9269ae77c5SAndre Przywara 				.u.irqchip.pin = next_gsi,
9369ae77c5SAndre Przywara 		};
9469ae77c5SAndre Przywara 	}
9569ae77c5SAndre Przywara 
9669ae77c5SAndre Przywara 	return 0;
9769ae77c5SAndre Przywara }
9869ae77c5SAndre Przywara 
gic__create_its_frame(struct kvm * kvm,u64 its_frame_addr)9912ca1401SAndre Przywara static int gic__create_its_frame(struct kvm *kvm, u64 its_frame_addr)
10012ca1401SAndre Przywara {
10112ca1401SAndre Przywara 	struct kvm_create_device its_device = {
10212ca1401SAndre Przywara 		.type = KVM_DEV_TYPE_ARM_VGIC_ITS,
10312ca1401SAndre Przywara 		.flags	= 0,
10412ca1401SAndre Przywara 	};
10512ca1401SAndre Przywara 	struct kvm_device_attr its_attr = {
10612ca1401SAndre Przywara 		.group	= KVM_DEV_ARM_VGIC_GRP_ADDR,
10712ca1401SAndre Przywara 		.attr	= KVM_VGIC_ITS_ADDR_TYPE,
10812ca1401SAndre Przywara 		.addr	= (u64)(unsigned long)&its_frame_addr,
10912ca1401SAndre Przywara 	};
11012ca1401SAndre Przywara 	struct kvm_device_attr its_init_attr = {
11112ca1401SAndre Przywara 		.group	= KVM_DEV_ARM_VGIC_GRP_CTRL,
11212ca1401SAndre Przywara 		.attr	= KVM_DEV_ARM_VGIC_CTRL_INIT,
11312ca1401SAndre Przywara 	};
11412ca1401SAndre Przywara 	int err;
11512ca1401SAndre Przywara 
11612ca1401SAndre Przywara 	err = ioctl(kvm->vm_fd, KVM_CREATE_DEVICE, &its_device);
11712ca1401SAndre Przywara 	if (err) {
118*72e13944SAlexandru Elisei 		pr_err("GICv3 ITS requested, but kernel does not support it.");
119*72e13944SAlexandru Elisei 		pr_err("Try --irqchip=gicv3 instead");
12012ca1401SAndre Przywara 		return err;
12112ca1401SAndre Przywara 	}
12212ca1401SAndre Przywara 
12312ca1401SAndre Przywara 	err = ioctl(its_device.fd, KVM_HAS_DEVICE_ATTR, &its_attr);
12412ca1401SAndre Przywara 	if (err) {
12512ca1401SAndre Przywara 		close(its_device.fd);
12612ca1401SAndre Przywara 		its_device.fd = -1;
12712ca1401SAndre Przywara 		return err;
12812ca1401SAndre Przywara 	}
12912ca1401SAndre Przywara 
13012ca1401SAndre Przywara 	err = ioctl(its_device.fd, KVM_SET_DEVICE_ATTR, &its_attr);
13112ca1401SAndre Przywara 	if (err)
13212ca1401SAndre Przywara 		return err;
13312ca1401SAndre Przywara 
13412ca1401SAndre Przywara 	return ioctl(its_device.fd, KVM_SET_DEVICE_ATTR, &its_init_attr);
13512ca1401SAndre Przywara }
13612ca1401SAndre Przywara 
gic__create_msi_frame(struct kvm * kvm,enum irqchip_type type,u64 msi_frame_addr)13712ca1401SAndre Przywara static int gic__create_msi_frame(struct kvm *kvm, enum irqchip_type type,
13812ca1401SAndre Przywara 				 u64 msi_frame_addr)
13912ca1401SAndre Przywara {
14012ca1401SAndre Przywara 	switch (type) {
141f6108d72SJean-Philippe Brucker 	case IRQCHIP_GICV2M:
142f6108d72SJean-Philippe Brucker 		return gic__create_gicv2m_frame(kvm, msi_frame_addr);
14312ca1401SAndre Przywara 	case IRQCHIP_GICV3_ITS:
14412ca1401SAndre Przywara 		return gic__create_its_frame(kvm, msi_frame_addr);
14512ca1401SAndre Przywara 	default:	/* No MSI frame needed */
14612ca1401SAndre Przywara 		return 0;
14712ca1401SAndre Przywara 	}
14812ca1401SAndre Przywara }
14912ca1401SAndre Przywara 
gic__create_device(struct kvm * kvm,enum irqchip_type type)15002017c1dSAndre Przywara static int gic__create_device(struct kvm *kvm, enum irqchip_type type)
15169b9a17aSMarc Zyngier {
15269b9a17aSMarc Zyngier 	int err;
15369b9a17aSMarc Zyngier 	u64 cpu_if_addr = ARM_GIC_CPUI_BASE;
15469b9a17aSMarc Zyngier 	u64 dist_addr = ARM_GIC_DIST_BASE;
15569b9a17aSMarc Zyngier 	struct kvm_create_device gic_device = {
15602017c1dSAndre Przywara 		.flags	= 0,
15769b9a17aSMarc Zyngier 	};
15869b9a17aSMarc Zyngier 	struct kvm_device_attr cpu_if_attr = {
15969b9a17aSMarc Zyngier 		.group	= KVM_DEV_ARM_VGIC_GRP_ADDR,
16069b9a17aSMarc Zyngier 		.attr	= KVM_VGIC_V2_ADDR_TYPE_CPU,
16169b9a17aSMarc Zyngier 		.addr	= (u64)(unsigned long)&cpu_if_addr,
16269b9a17aSMarc Zyngier 	};
16369b9a17aSMarc Zyngier 	struct kvm_device_attr dist_attr = {
16469b9a17aSMarc Zyngier 		.group	= KVM_DEV_ARM_VGIC_GRP_ADDR,
16569b9a17aSMarc Zyngier 		.addr	= (u64)(unsigned long)&dist_addr,
16669b9a17aSMarc Zyngier 	};
167bfb2c703SAndre Przywara 	struct kvm_device_attr redist_attr = {
168bfb2c703SAndre Przywara 		.group	= KVM_DEV_ARM_VGIC_GRP_ADDR,
169bfb2c703SAndre Przywara 		.attr	= KVM_VGIC_V3_ADDR_TYPE_REDIST,
170bfb2c703SAndre Przywara 		.addr	= (u64)(unsigned long)&gic_redists_base,
171bfb2c703SAndre Przywara 	};
17269b9a17aSMarc Zyngier 
17302017c1dSAndre Przywara 	switch (type) {
174f6108d72SJean-Philippe Brucker 	case IRQCHIP_GICV2M:
17502017c1dSAndre Przywara 	case IRQCHIP_GICV2:
17602017c1dSAndre Przywara 		gic_device.type = KVM_DEV_TYPE_ARM_VGIC_V2;
17702017c1dSAndre Przywara 		dist_attr.attr  = KVM_VGIC_V2_ADDR_TYPE_DIST;
17802017c1dSAndre Przywara 		break;
179bfb2c703SAndre Przywara 	case IRQCHIP_GICV3:
18012ca1401SAndre Przywara 	case IRQCHIP_GICV3_ITS:
181bfb2c703SAndre Przywara 		gic_device.type = KVM_DEV_TYPE_ARM_VGIC_V3;
182bfb2c703SAndre Przywara 		dist_attr.attr  = KVM_VGIC_V3_ADDR_TYPE_DIST;
183bfb2c703SAndre Przywara 		break;
184c57e001aSAndre Przywara 	case IRQCHIP_AUTO:
185c57e001aSAndre Przywara 		return -ENODEV;
18602017c1dSAndre Przywara 	}
18702017c1dSAndre Przywara 
18869b9a17aSMarc Zyngier 	err = ioctl(kvm->vm_fd, KVM_CREATE_DEVICE, &gic_device);
18969b9a17aSMarc Zyngier 	if (err)
19069b9a17aSMarc Zyngier 		return err;
19169b9a17aSMarc Zyngier 
19269b9a17aSMarc Zyngier 	gic_fd = gic_device.fd;
19369b9a17aSMarc Zyngier 
19402017c1dSAndre Przywara 	switch (type) {
195f6108d72SJean-Philippe Brucker 	case IRQCHIP_GICV2M:
19602017c1dSAndre Przywara 	case IRQCHIP_GICV2:
19769b9a17aSMarc Zyngier 		err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &cpu_if_attr);
19802017c1dSAndre Przywara 		break;
19912ca1401SAndre Przywara 	case IRQCHIP_GICV3_ITS:
200bfb2c703SAndre Przywara 	case IRQCHIP_GICV3:
201bfb2c703SAndre Przywara 		err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &redist_attr);
202bfb2c703SAndre Przywara 		break;
203c57e001aSAndre Przywara 	case IRQCHIP_AUTO:
204c57e001aSAndre Przywara 		return -ENODEV;
20502017c1dSAndre Przywara 	}
20669b9a17aSMarc Zyngier 	if (err)
20769b9a17aSMarc Zyngier 		goto out_err;
20869b9a17aSMarc Zyngier 
20969b9a17aSMarc Zyngier 	err = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &dist_attr);
21069b9a17aSMarc Zyngier 	if (err)
21169b9a17aSMarc Zyngier 		goto out_err;
21269b9a17aSMarc Zyngier 
21312ca1401SAndre Przywara 	err = gic__create_msi_frame(kvm, type, gic_msi_base);
21412ca1401SAndre Przywara 	if (err)
21512ca1401SAndre Przywara 		goto out_err;
21612ca1401SAndre Przywara 
21769b9a17aSMarc Zyngier 	return 0;
21869b9a17aSMarc Zyngier 
21969b9a17aSMarc Zyngier out_err:
22069b9a17aSMarc Zyngier 	close(gic_fd);
22169b9a17aSMarc Zyngier 	gic_fd = -1;
22269b9a17aSMarc Zyngier 	return err;
22369b9a17aSMarc Zyngier }
22469b9a17aSMarc Zyngier 
gic__create_irqchip(struct kvm * kvm)22569b9a17aSMarc Zyngier static int gic__create_irqchip(struct kvm *kvm)
2267c0e8b0cSWill Deacon {
2277c0e8b0cSWill Deacon 	int err;
228aa7a0e79SWill Deacon 	struct kvm_arm_device_addr gic_addr[] = {
2297c0e8b0cSWill Deacon 		[0] = {
230aa7a0e79SWill Deacon 			.id = KVM_VGIC_V2_ADDR_TYPE_DIST |
231aa7a0e79SWill Deacon 			(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT),
2327c0e8b0cSWill Deacon 			.addr = ARM_GIC_DIST_BASE,
2337c0e8b0cSWill Deacon 		},
2347c0e8b0cSWill Deacon 		[1] = {
235aa7a0e79SWill Deacon 			.id = KVM_VGIC_V2_ADDR_TYPE_CPU |
236aa7a0e79SWill Deacon 			(KVM_ARM_DEVICE_VGIC_V2 << KVM_ARM_DEVICE_ID_SHIFT),
2377c0e8b0cSWill Deacon 			.addr = ARM_GIC_CPUI_BASE,
2387c0e8b0cSWill Deacon 		}
2397c0e8b0cSWill Deacon 	};
2407c0e8b0cSWill Deacon 
2417c0e8b0cSWill Deacon 	err = ioctl(kvm->vm_fd, KVM_CREATE_IRQCHIP);
2427c0e8b0cSWill Deacon 	if (err)
2437c0e8b0cSWill Deacon 		return err;
2447c0e8b0cSWill Deacon 
245aa7a0e79SWill Deacon 	err = ioctl(kvm->vm_fd, KVM_ARM_SET_DEVICE_ADDR, &gic_addr[0]);
2467c0e8b0cSWill Deacon 	if (err)
2477c0e8b0cSWill Deacon 		return err;
2487c0e8b0cSWill Deacon 
249aa7a0e79SWill Deacon 	err = ioctl(kvm->vm_fd, KVM_ARM_SET_DEVICE_ADDR, &gic_addr[1]);
2507c0e8b0cSWill Deacon 	return err;
2517c0e8b0cSWill Deacon }
2527c0e8b0cSWill Deacon 
gic__create(struct kvm * kvm,enum irqchip_type type)25302017c1dSAndre Przywara int gic__create(struct kvm *kvm, enum irqchip_type type)
25469b9a17aSMarc Zyngier {
255c57e001aSAndre Przywara 	enum irqchip_type try;
25669b9a17aSMarc Zyngier 	int err;
25769b9a17aSMarc Zyngier 
25802017c1dSAndre Przywara 	switch (type) {
259c57e001aSAndre Przywara 	case IRQCHIP_AUTO:
260c57e001aSAndre Przywara 		for (try = IRQCHIP_GICV3_ITS; try >= IRQCHIP_GICV2; try--) {
261c57e001aSAndre Przywara 			err = gic__create(kvm, try);
262c57e001aSAndre Przywara 			if (!err)
263c57e001aSAndre Przywara 				break;
264c57e001aSAndre Przywara 		}
265c57e001aSAndre Przywara 		if (err)
266c57e001aSAndre Przywara 			return err;
267c57e001aSAndre Przywara 
268c57e001aSAndre Przywara 		kvm->cfg.arch.irqchip = try;
269c57e001aSAndre Przywara 		return 0;
270f6108d72SJean-Philippe Brucker 	case IRQCHIP_GICV2M:
271f6108d72SJean-Philippe Brucker 		gic_msi_size = KVM_VGIC_V2M_SIZE;
272a43b08e8SAndre Przywara 		gic_msi_base = ARM_GIC_CPUI_BASE - gic_msi_size;
273f6108d72SJean-Philippe Brucker 		break;
27402017c1dSAndre Przywara 	case IRQCHIP_GICV2:
27502017c1dSAndre Przywara 		break;
27612ca1401SAndre Przywara 	case IRQCHIP_GICV3_ITS:
277a5d36dd1SAndre Przywara 		/* The 64K page with the doorbell is included. */
278a5d36dd1SAndre Przywara 		gic_msi_size = KVM_VGIC_V3_ITS_SIZE;
27912ca1401SAndre Przywara 		/* fall through */
280bfb2c703SAndre Przywara 	case IRQCHIP_GICV3:
281bfb2c703SAndre Przywara 		gic_redists_size = kvm->cfg.nrcpus * ARM_GIC_REDIST_SIZE;
282bfb2c703SAndre Przywara 		gic_redists_base = ARM_GIC_DIST_BASE - gic_redists_size;
28312ca1401SAndre Przywara 		gic_msi_base = gic_redists_base - gic_msi_size;
284bfb2c703SAndre Przywara 		break;
28502017c1dSAndre Przywara 	default:
28602017c1dSAndre Przywara 		return -ENODEV;
28702017c1dSAndre Przywara 	}
28802017c1dSAndre Przywara 
28969b9a17aSMarc Zyngier 	/* Try the new way first, and fallback on legacy method otherwise */
29002017c1dSAndre Przywara 	err = gic__create_device(kvm, type);
29102017c1dSAndre Przywara 	if (err && type == IRQCHIP_GICV2)
29269b9a17aSMarc Zyngier 		err = gic__create_irqchip(kvm);
29369b9a17aSMarc Zyngier 
29469b9a17aSMarc Zyngier 	return err;
29569b9a17aSMarc Zyngier }
29669b9a17aSMarc Zyngier 
297b5790302SAndre Przywara /*
298b5790302SAndre Przywara  * Sets the number of used interrupts and finalizes the GIC init explicitly.
299b5790302SAndre Przywara  */
gic__init_gic(struct kvm * kvm)300bed2bd9eSMarc Zyngier static int gic__init_gic(struct kvm *kvm)
301bed2bd9eSMarc Zyngier {
302b5790302SAndre Przywara 	int ret;
303b5790302SAndre Przywara 
304bed2bd9eSMarc Zyngier 	int lines = irq__get_nr_allocated_lines();
305bed2bd9eSMarc Zyngier 	u32 nr_irqs = ALIGN(lines, 32) + GIC_SPI_IRQ_BASE;
306bed2bd9eSMarc Zyngier 	struct kvm_device_attr nr_irqs_attr = {
307bed2bd9eSMarc Zyngier 		.group	= KVM_DEV_ARM_VGIC_GRP_NR_IRQS,
308bed2bd9eSMarc Zyngier 		.addr	= (u64)(unsigned long)&nr_irqs,
309bed2bd9eSMarc Zyngier 	};
310b5790302SAndre Przywara 	struct kvm_device_attr vgic_init_attr = {
311b5790302SAndre Przywara 		.group	= KVM_DEV_ARM_VGIC_GRP_CTRL,
312b5790302SAndre Przywara 		.attr	= KVM_DEV_ARM_VGIC_CTRL_INIT,
313b5790302SAndre Przywara 	};
314bed2bd9eSMarc Zyngier 
315bed2bd9eSMarc Zyngier 	/*
316bed2bd9eSMarc Zyngier 	 * If we didn't use the KVM_CREATE_DEVICE method, KVM will
317b5790302SAndre Przywara 	 * give us some default number of interrupts. The GIC initialization
318b5790302SAndre Przywara 	 * will be done automatically in this case.
319bed2bd9eSMarc Zyngier 	 */
320bed2bd9eSMarc Zyngier 	if (gic_fd < 0)
321bed2bd9eSMarc Zyngier 		return 0;
322bed2bd9eSMarc Zyngier 
323b5790302SAndre Przywara 	if (!ioctl(gic_fd, KVM_HAS_DEVICE_ATTR, &nr_irqs_attr)) {
324b5790302SAndre Przywara 		ret = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &nr_irqs_attr);
325b5790302SAndre Przywara 		if (ret)
326b5790302SAndre Przywara 			return ret;
327b5790302SAndre Przywara 	}
328b5790302SAndre Przywara 
32969ae77c5SAndre Przywara 	irq__routing_init(kvm);
33069ae77c5SAndre Przywara 
331b5790302SAndre Przywara 	if (!ioctl(gic_fd, KVM_HAS_DEVICE_ATTR, &vgic_init_attr)) {
332b5790302SAndre Przywara 		ret = ioctl(gic_fd, KVM_SET_DEVICE_ATTR, &vgic_init_attr);
333b5790302SAndre Przywara 		if (ret)
334b5790302SAndre Przywara 			return ret;
335b5790302SAndre Przywara 	}
336bed2bd9eSMarc Zyngier 
337714ab9e6SAndre Przywara 	kvm->msix_needs_devid = kvm__supports_vm_extension(kvm,
338714ab9e6SAndre Przywara 							   KVM_CAP_MSI_DEVID);
339714ab9e6SAndre Przywara 
340e59679d2SJean-Philippe Brucker 	vgic_is_init = true;
341e59679d2SJean-Philippe Brucker 
342e59679d2SJean-Philippe Brucker 	return irq__setup_irqfd_lines(kvm);
343bed2bd9eSMarc Zyngier }
late_init(gic__init_gic)344bed2bd9eSMarc Zyngier late_init(gic__init_gic)
345bed2bd9eSMarc Zyngier 
3460063d50cSAndre Przywara void gic__generate_fdt_nodes(void *fdt, enum irqchip_type type)
3477c0e8b0cSWill Deacon {
34814421de9SAndre Przywara 	const char *compatible, *msi_compatible = NULL;
34914421de9SAndre Przywara 	u64 msi_prop[2];
3507c0e8b0cSWill Deacon 	u64 reg_prop[] = {
3517c0e8b0cSWill Deacon 		cpu_to_fdt64(ARM_GIC_DIST_BASE), cpu_to_fdt64(ARM_GIC_DIST_SIZE),
352bfb2c703SAndre Przywara 		0, 0,				/* to be filled */
3537c0e8b0cSWill Deacon 	};
3547c0e8b0cSWill Deacon 
35502017c1dSAndre Przywara 	switch (type) {
356f6108d72SJean-Philippe Brucker 	case IRQCHIP_GICV2M:
357f6108d72SJean-Philippe Brucker 		msi_compatible = "arm,gic-v2m-frame";
358f6108d72SJean-Philippe Brucker 		/* fall-through */
35902017c1dSAndre Przywara 	case IRQCHIP_GICV2:
36002017c1dSAndre Przywara 		compatible = "arm,cortex-a15-gic";
361bfb2c703SAndre Przywara 		reg_prop[2] = cpu_to_fdt64(ARM_GIC_CPUI_BASE);
362bfb2c703SAndre Przywara 		reg_prop[3] = cpu_to_fdt64(ARM_GIC_CPUI_SIZE);
363bfb2c703SAndre Przywara 		break;
36414421de9SAndre Przywara 	case IRQCHIP_GICV3_ITS:
36514421de9SAndre Przywara 		msi_compatible = "arm,gic-v3-its";
36614421de9SAndre Przywara 		/* fall-through */
367bfb2c703SAndre Przywara 	case IRQCHIP_GICV3:
368bfb2c703SAndre Przywara 		compatible = "arm,gic-v3";
369bfb2c703SAndre Przywara 		reg_prop[2] = cpu_to_fdt64(gic_redists_base);
370bfb2c703SAndre Przywara 		reg_prop[3] = cpu_to_fdt64(gic_redists_size);
37102017c1dSAndre Przywara 		break;
37202017c1dSAndre Przywara 	default:
37302017c1dSAndre Przywara 		return;
37402017c1dSAndre Przywara 	}
37502017c1dSAndre Przywara 
3767c0e8b0cSWill Deacon 	_FDT(fdt_begin_node(fdt, "intc"));
37702017c1dSAndre Przywara 	_FDT(fdt_property_string(fdt, "compatible", compatible));
3787c0e8b0cSWill Deacon 	_FDT(fdt_property_cell(fdt, "#interrupt-cells", GIC_FDT_IRQ_NUM_CELLS));
3797c0e8b0cSWill Deacon 	_FDT(fdt_property(fdt, "interrupt-controller", NULL, 0));
3807c0e8b0cSWill Deacon 	_FDT(fdt_property(fdt, "reg", reg_prop, sizeof(reg_prop)));
3810063d50cSAndre Przywara 	_FDT(fdt_property_cell(fdt, "phandle", PHANDLE_GIC));
38214421de9SAndre Przywara 	_FDT(fdt_property_cell(fdt, "#address-cells", 2));
38314421de9SAndre Przywara 	_FDT(fdt_property_cell(fdt, "#size-cells", 2));
38414421de9SAndre Przywara 
38514421de9SAndre Przywara 	if (msi_compatible) {
38614421de9SAndre Przywara 		_FDT(fdt_property(fdt, "ranges", NULL, 0));
38714421de9SAndre Przywara 
38814421de9SAndre Przywara 		_FDT(fdt_begin_node(fdt, "msic"));
38914421de9SAndre Przywara 		_FDT(fdt_property_string(fdt, "compatible", msi_compatible));
39014421de9SAndre Przywara 		_FDT(fdt_property(fdt, "msi-controller", NULL, 0));
39114421de9SAndre Przywara 		_FDT(fdt_property_cell(fdt, "phandle", PHANDLE_MSI));
39214421de9SAndre Przywara 		msi_prop[0] = cpu_to_fdt64(gic_msi_base);
39314421de9SAndre Przywara 		msi_prop[1] = cpu_to_fdt64(gic_msi_size);
39414421de9SAndre Przywara 		_FDT(fdt_property(fdt, "reg", msi_prop, sizeof(msi_prop)));
39514421de9SAndre Przywara 		_FDT(fdt_end_node(fdt));
39614421de9SAndre Przywara 	}
39714421de9SAndre Przywara 
3987c0e8b0cSWill Deacon 	_FDT(fdt_end_node(fdt));
3997c0e8b0cSWill Deacon }
4007c0e8b0cSWill Deacon 
gic__get_fdt_irq_cpumask(struct kvm * kvm)401d9fdaad0SAndre Przywara u32 gic__get_fdt_irq_cpumask(struct kvm *kvm)
402d9fdaad0SAndre Przywara {
403d9fdaad0SAndre Przywara 	/* Only for GICv2 */
404d9fdaad0SAndre Przywara 	if (kvm->cfg.arch.irqchip == IRQCHIP_GICV3 ||
405d9fdaad0SAndre Przywara 	    kvm->cfg.arch.irqchip == IRQCHIP_GICV3_ITS)
406d9fdaad0SAndre Przywara 		return 0;
407d9fdaad0SAndre Przywara 
408d9fdaad0SAndre Przywara 	if (kvm->nrcpus > 8)
409d9fdaad0SAndre Przywara 		return GIC_FDT_IRQ_PPI_CPU_MASK;
410d9fdaad0SAndre Przywara 
411d9fdaad0SAndre Przywara 	return ((1U << kvm->nrcpus) - 1) << GIC_FDT_IRQ_PPI_CPU_SHIFT;
412d9fdaad0SAndre Przywara }
413d9fdaad0SAndre Przywara 
4147c0e8b0cSWill Deacon #define KVM_IRQCHIP_IRQ(x) (KVM_ARM_IRQ_TYPE_SPI << KVM_ARM_IRQ_TYPE_SHIFT) |\
4157c0e8b0cSWill Deacon 			   ((x) & KVM_ARM_IRQ_NUM_MASK)
4167c0e8b0cSWill Deacon 
kvm__irq_line(struct kvm * kvm,int irq,int level)4177c0e8b0cSWill Deacon void kvm__irq_line(struct kvm *kvm, int irq, int level)
4187c0e8b0cSWill Deacon {
4197c0e8b0cSWill Deacon 	struct kvm_irq_level irq_level = {
4207c0e8b0cSWill Deacon 		.irq	= KVM_IRQCHIP_IRQ(irq),
4217c0e8b0cSWill Deacon 		.level	= !!level,
4227c0e8b0cSWill Deacon 	};
4237c0e8b0cSWill Deacon 
4247c0e8b0cSWill Deacon 	if (irq < GIC_SPI_IRQ_BASE || irq > GIC_MAX_IRQ)
4257c0e8b0cSWill Deacon 		pr_warning("Ignoring invalid GIC IRQ %d", irq);
4267c0e8b0cSWill Deacon 	else if (ioctl(kvm->vm_fd, KVM_IRQ_LINE, &irq_level) < 0)
4277c0e8b0cSWill Deacon 		pr_warning("Could not KVM_IRQ_LINE for irq %d", irq);
4287c0e8b0cSWill Deacon }
4297c0e8b0cSWill Deacon 
kvm__irq_trigger(struct kvm * kvm,int irq)4307c0e8b0cSWill Deacon void kvm__irq_trigger(struct kvm *kvm, int irq)
4317c0e8b0cSWill Deacon {
4327c0e8b0cSWill Deacon 	kvm__irq_line(kvm, irq, VIRTIO_IRQ_HIGH);
4337c0e8b0cSWill Deacon 	kvm__irq_line(kvm, irq, VIRTIO_IRQ_LOW);
4347c0e8b0cSWill Deacon }
435e59679d2SJean-Philippe Brucker 
gic__add_irqfd(struct kvm * kvm,unsigned int gsi,int trigger_fd,int resample_fd)436e59679d2SJean-Philippe Brucker int gic__add_irqfd(struct kvm *kvm, unsigned int gsi, int trigger_fd,
437e59679d2SJean-Philippe Brucker 		   int resample_fd)
438e59679d2SJean-Philippe Brucker {
439e59679d2SJean-Philippe Brucker 	struct kvm_irqfd_line *line;
440e59679d2SJean-Philippe Brucker 
441e59679d2SJean-Philippe Brucker 	if (vgic_is_init)
442e59679d2SJean-Philippe Brucker 		return irq__common_add_irqfd(kvm, gsi, trigger_fd, resample_fd);
443e59679d2SJean-Philippe Brucker 
444e59679d2SJean-Philippe Brucker 	/* Postpone the routing setup until we have a distributor */
445e59679d2SJean-Philippe Brucker 	line = malloc(sizeof(*line));
446e59679d2SJean-Philippe Brucker 	if (!line)
447e59679d2SJean-Philippe Brucker 		return -ENOMEM;
448e59679d2SJean-Philippe Brucker 
449e59679d2SJean-Philippe Brucker 	*line = (struct kvm_irqfd_line) {
450e59679d2SJean-Philippe Brucker 		.gsi		= gsi,
451e59679d2SJean-Philippe Brucker 		.trigger_fd	= trigger_fd,
452e59679d2SJean-Philippe Brucker 		.resample_fd	= resample_fd,
453e59679d2SJean-Philippe Brucker 	};
454e59679d2SJean-Philippe Brucker 	list_add(&line->list, &irqfd_lines);
455e59679d2SJean-Philippe Brucker 
456e59679d2SJean-Philippe Brucker 	return 0;
457e59679d2SJean-Philippe Brucker }
458e59679d2SJean-Philippe Brucker 
gic__del_irqfd(struct kvm * kvm,unsigned int gsi,int trigger_fd)459e59679d2SJean-Philippe Brucker void gic__del_irqfd(struct kvm *kvm, unsigned int gsi, int trigger_fd)
460e59679d2SJean-Philippe Brucker {
461e59679d2SJean-Philippe Brucker 	struct kvm_irqfd_line *line;
462e59679d2SJean-Philippe Brucker 
463e59679d2SJean-Philippe Brucker 	if (vgic_is_init) {
464e59679d2SJean-Philippe Brucker 		irq__common_del_irqfd(kvm, gsi, trigger_fd);
465e59679d2SJean-Philippe Brucker 		return;
466e59679d2SJean-Philippe Brucker 	}
467e59679d2SJean-Philippe Brucker 
468e59679d2SJean-Philippe Brucker 	list_for_each_entry(line, &irqfd_lines, list) {
469e59679d2SJean-Philippe Brucker 		if (line->gsi != gsi)
470e59679d2SJean-Philippe Brucker 			continue;
471e59679d2SJean-Philippe Brucker 
472e59679d2SJean-Philippe Brucker 		list_del(&line->list);
473e59679d2SJean-Philippe Brucker 		free(line);
474e59679d2SJean-Philippe Brucker 		break;
475e59679d2SJean-Philippe Brucker 	}
476e59679d2SJean-Philippe Brucker }
477