xref: /kvmtool/riscv/irq.c (revision 328f0879eeaee9ac167e3d00e4a9b5553e99d2f9)
12e996783SAnup Patel #include "kvm/kvm.h"
22e996783SAnup Patel #include "kvm/kvm-cpu.h"
32e996783SAnup Patel #include "kvm/irq.h"
40dff3501SAnup Patel #include "kvm/fdt.h"
50dff3501SAnup Patel #include "kvm/virtio.h"
60dff3501SAnup Patel 
70dff3501SAnup Patel enum irqchip_type riscv_irqchip = IRQCHIP_UNKNOWN;
80dff3501SAnup Patel bool riscv_irqchip_inkernel;
90dff3501SAnup Patel void (*riscv_irqchip_trigger)(struct kvm *kvm, int irq, int level, bool edge)
100dff3501SAnup Patel 				= NULL;
110dff3501SAnup Patel void (*riscv_irqchip_generate_fdt_node)(void *fdt, struct kvm *kvm) = NULL;
120dff3501SAnup Patel u32 riscv_irqchip_phandle = PHANDLE_RESERVED;
130dff3501SAnup Patel u32 riscv_irqchip_msi_phandle = PHANDLE_RESERVED;
140dff3501SAnup Patel bool riscv_irqchip_line_sensing;
1517aab306SAnup Patel bool riscv_irqchip_irqfd_ready;
162e996783SAnup Patel 
kvm__irq_line(struct kvm * kvm,int irq,int level)172e996783SAnup Patel void kvm__irq_line(struct kvm *kvm, int irq, int level)
182e996783SAnup Patel {
190dff3501SAnup Patel 	struct kvm_irq_level irq_level;
200dff3501SAnup Patel 
210dff3501SAnup Patel 	if (riscv_irqchip_inkernel) {
220dff3501SAnup Patel 		irq_level.irq = irq;
230dff3501SAnup Patel 		irq_level.level = !!level;
240dff3501SAnup Patel 		if (ioctl(kvm->vm_fd, KVM_IRQ_LINE, &irq_level) < 0)
250dff3501SAnup Patel 			pr_warning("%s: Could not KVM_IRQ_LINE for irq %d\n",
260dff3501SAnup Patel 				   __func__, irq);
270dff3501SAnup Patel 	} else {
280dff3501SAnup Patel 		if (riscv_irqchip_trigger)
290dff3501SAnup Patel 			riscv_irqchip_trigger(kvm, irq, level, false);
300dff3501SAnup Patel 		else
310dff3501SAnup Patel 			pr_warning("%s: Can't change level for irq %d\n",
320dff3501SAnup Patel 				   __func__, irq);
330dff3501SAnup Patel 	}
342e996783SAnup Patel }
352e996783SAnup Patel 
kvm__irq_trigger(struct kvm * kvm,int irq)362e996783SAnup Patel void kvm__irq_trigger(struct kvm *kvm, int irq)
372e996783SAnup Patel {
380dff3501SAnup Patel 	if (riscv_irqchip_inkernel) {
390dff3501SAnup Patel 		kvm__irq_line(kvm, irq, VIRTIO_IRQ_HIGH);
400dff3501SAnup Patel 		kvm__irq_line(kvm, irq, VIRTIO_IRQ_LOW);
410dff3501SAnup Patel 	} else {
420dff3501SAnup Patel 		if (riscv_irqchip_trigger)
430dff3501SAnup Patel 			riscv_irqchip_trigger(kvm, irq, 1, true);
440dff3501SAnup Patel 		else
450dff3501SAnup Patel 			pr_warning("%s: Can't trigger irq %d\n",
460dff3501SAnup Patel 				   __func__, irq);
470dff3501SAnup Patel 	}
480dff3501SAnup Patel }
490dff3501SAnup Patel 
5017aab306SAnup Patel struct riscv_irqfd_line {
5117aab306SAnup Patel 	unsigned int		gsi;
5217aab306SAnup Patel 	int			trigger_fd;
5317aab306SAnup Patel 	int			resample_fd;
5417aab306SAnup Patel 	struct list_head	list;
5517aab306SAnup Patel };
5617aab306SAnup Patel 
5717aab306SAnup Patel static LIST_HEAD(irqfd_lines);
5817aab306SAnup Patel 
riscv__add_irqfd(struct kvm * kvm,unsigned int gsi,int trigger_fd,int resample_fd)5917aab306SAnup Patel int riscv__add_irqfd(struct kvm *kvm, unsigned int gsi, int trigger_fd,
6017aab306SAnup Patel 		     int resample_fd)
6117aab306SAnup Patel {
6217aab306SAnup Patel 	struct riscv_irqfd_line *line;
6317aab306SAnup Patel 
6417aab306SAnup Patel 	if (riscv_irqchip_irqfd_ready)
6517aab306SAnup Patel 		return irq__common_add_irqfd(kvm, gsi, trigger_fd,
6617aab306SAnup Patel 					     resample_fd);
6717aab306SAnup Patel 
6817aab306SAnup Patel 	/* Postpone the routing setup until irqchip is initialized */
6917aab306SAnup Patel 	line = malloc(sizeof(*line));
7017aab306SAnup Patel 	if (!line)
7117aab306SAnup Patel 		return -ENOMEM;
7217aab306SAnup Patel 
7317aab306SAnup Patel 	*line = (struct riscv_irqfd_line) {
7417aab306SAnup Patel 		.gsi		= gsi,
7517aab306SAnup Patel 		.trigger_fd	= trigger_fd,
7617aab306SAnup Patel 		.resample_fd	= resample_fd,
7717aab306SAnup Patel 	};
7817aab306SAnup Patel 	list_add(&line->list, &irqfd_lines);
7917aab306SAnup Patel 
8017aab306SAnup Patel 	return 0;
8117aab306SAnup Patel }
8217aab306SAnup Patel 
riscv__del_irqfd(struct kvm * kvm,unsigned int gsi,int trigger_fd)8317aab306SAnup Patel void riscv__del_irqfd(struct kvm *kvm, unsigned int gsi, int trigger_fd)
8417aab306SAnup Patel {
8517aab306SAnup Patel 	struct riscv_irqfd_line *line;
8617aab306SAnup Patel 
8717aab306SAnup Patel 	if (riscv_irqchip_irqfd_ready) {
8817aab306SAnup Patel 		irq__common_del_irqfd(kvm, gsi, trigger_fd);
8917aab306SAnup Patel 		return;
9017aab306SAnup Patel 	}
9117aab306SAnup Patel 
9217aab306SAnup Patel 	list_for_each_entry(line, &irqfd_lines, list) {
9317aab306SAnup Patel 		if (line->gsi != gsi)
9417aab306SAnup Patel 			continue;
9517aab306SAnup Patel 
9617aab306SAnup Patel 		list_del(&line->list);
9717aab306SAnup Patel 		free(line);
9817aab306SAnup Patel 		break;
9917aab306SAnup Patel 	}
10017aab306SAnup Patel }
10117aab306SAnup Patel 
riscv__setup_irqfd_lines(struct kvm * kvm)10217aab306SAnup Patel int riscv__setup_irqfd_lines(struct kvm *kvm)
10317aab306SAnup Patel {
10417aab306SAnup Patel 	int ret;
10517aab306SAnup Patel 	struct riscv_irqfd_line *line, *tmp;
10617aab306SAnup Patel 
10717aab306SAnup Patel 	list_for_each_entry_safe(line, tmp, &irqfd_lines, list) {
10817aab306SAnup Patel 		ret = irq__common_add_irqfd(kvm, line->gsi, line->trigger_fd,
10917aab306SAnup Patel 					    line->resample_fd);
11017aab306SAnup Patel 		if (ret < 0) {
11117aab306SAnup Patel 			pr_err("Failed to register IRQFD");
11217aab306SAnup Patel 			return ret;
11317aab306SAnup Patel 		}
11417aab306SAnup Patel 
11517aab306SAnup Patel 		list_del(&line->list);
11617aab306SAnup Patel 		free(line);
11717aab306SAnup Patel 	}
11817aab306SAnup Patel 
11917aab306SAnup Patel 	return 0;
12017aab306SAnup Patel }
12117aab306SAnup Patel 
riscv__generate_irq_prop(void * fdt,u8 irq,enum irq_type irq_type)1220dff3501SAnup Patel void riscv__generate_irq_prop(void *fdt, u8 irq, enum irq_type irq_type)
1230dff3501SAnup Patel {
1240dff3501SAnup Patel 	u32 prop[2], size;
1250dff3501SAnup Patel 
1260dff3501SAnup Patel 	prop[0] = cpu_to_fdt32(irq);
1270dff3501SAnup Patel 	size = sizeof(u32);
1280dff3501SAnup Patel 	if (riscv_irqchip_line_sensing) {
1290dff3501SAnup Patel 		prop[1] = cpu_to_fdt32(irq_type);
1300dff3501SAnup Patel 		size += sizeof(u32);
1310dff3501SAnup Patel 	}
1320dff3501SAnup Patel 
1330dff3501SAnup Patel 	_FDT(fdt_property(fdt, "interrupts", prop, size));
1340dff3501SAnup Patel }
1350dff3501SAnup Patel 
136*328f0879SAnup Patel static void (*riscv__irqchip_create_funcs[])(struct kvm *kvm) = {
137*328f0879SAnup Patel 	aia__create,
138*328f0879SAnup Patel 	plic__create,
139*328f0879SAnup Patel };
140*328f0879SAnup Patel 
riscv__irqchip_create(struct kvm * kvm)1410dff3501SAnup Patel void riscv__irqchip_create(struct kvm *kvm)
1420dff3501SAnup Patel {
143*328f0879SAnup Patel 	unsigned int i;
1440dff3501SAnup Patel 
145*328f0879SAnup Patel 	/* Try irqchip.create function one after another */
146*328f0879SAnup Patel 	for (i = 0; i < ARRAY_SIZE(riscv__irqchip_create_funcs); i++) {
147*328f0879SAnup Patel 		riscv__irqchip_create_funcs[i](kvm);
148*328f0879SAnup Patel 		if (riscv_irqchip != IRQCHIP_UNKNOWN)
149*328f0879SAnup Patel 			return;
150*328f0879SAnup Patel 	}
151*328f0879SAnup Patel 
152*328f0879SAnup Patel 	/* Fail since irqchip is unknown */
1530dff3501SAnup Patel 	die("No IRQCHIP found\n");
1542e996783SAnup Patel }
155