xref: /kvmtool/riscv/irq.c (revision 328f0879eeaee9ac167e3d00e4a9b5553e99d2f9)
1 #include "kvm/kvm.h"
2 #include "kvm/kvm-cpu.h"
3 #include "kvm/irq.h"
4 #include "kvm/fdt.h"
5 #include "kvm/virtio.h"
6 
7 enum irqchip_type riscv_irqchip = IRQCHIP_UNKNOWN;
8 bool riscv_irqchip_inkernel;
9 void (*riscv_irqchip_trigger)(struct kvm *kvm, int irq, int level, bool edge)
10 				= NULL;
11 void (*riscv_irqchip_generate_fdt_node)(void *fdt, struct kvm *kvm) = NULL;
12 u32 riscv_irqchip_phandle = PHANDLE_RESERVED;
13 u32 riscv_irqchip_msi_phandle = PHANDLE_RESERVED;
14 bool riscv_irqchip_line_sensing;
15 bool riscv_irqchip_irqfd_ready;
16 
kvm__irq_line(struct kvm * kvm,int irq,int level)17 void kvm__irq_line(struct kvm *kvm, int irq, int level)
18 {
19 	struct kvm_irq_level irq_level;
20 
21 	if (riscv_irqchip_inkernel) {
22 		irq_level.irq = irq;
23 		irq_level.level = !!level;
24 		if (ioctl(kvm->vm_fd, KVM_IRQ_LINE, &irq_level) < 0)
25 			pr_warning("%s: Could not KVM_IRQ_LINE for irq %d\n",
26 				   __func__, irq);
27 	} else {
28 		if (riscv_irqchip_trigger)
29 			riscv_irqchip_trigger(kvm, irq, level, false);
30 		else
31 			pr_warning("%s: Can't change level for irq %d\n",
32 				   __func__, irq);
33 	}
34 }
35 
kvm__irq_trigger(struct kvm * kvm,int irq)36 void kvm__irq_trigger(struct kvm *kvm, int irq)
37 {
38 	if (riscv_irqchip_inkernel) {
39 		kvm__irq_line(kvm, irq, VIRTIO_IRQ_HIGH);
40 		kvm__irq_line(kvm, irq, VIRTIO_IRQ_LOW);
41 	} else {
42 		if (riscv_irqchip_trigger)
43 			riscv_irqchip_trigger(kvm, irq, 1, true);
44 		else
45 			pr_warning("%s: Can't trigger irq %d\n",
46 				   __func__, irq);
47 	}
48 }
49 
50 struct riscv_irqfd_line {
51 	unsigned int		gsi;
52 	int			trigger_fd;
53 	int			resample_fd;
54 	struct list_head	list;
55 };
56 
57 static LIST_HEAD(irqfd_lines);
58 
riscv__add_irqfd(struct kvm * kvm,unsigned int gsi,int trigger_fd,int resample_fd)59 int riscv__add_irqfd(struct kvm *kvm, unsigned int gsi, int trigger_fd,
60 		     int resample_fd)
61 {
62 	struct riscv_irqfd_line *line;
63 
64 	if (riscv_irqchip_irqfd_ready)
65 		return irq__common_add_irqfd(kvm, gsi, trigger_fd,
66 					     resample_fd);
67 
68 	/* Postpone the routing setup until irqchip is initialized */
69 	line = malloc(sizeof(*line));
70 	if (!line)
71 		return -ENOMEM;
72 
73 	*line = (struct riscv_irqfd_line) {
74 		.gsi		= gsi,
75 		.trigger_fd	= trigger_fd,
76 		.resample_fd	= resample_fd,
77 	};
78 	list_add(&line->list, &irqfd_lines);
79 
80 	return 0;
81 }
82 
riscv__del_irqfd(struct kvm * kvm,unsigned int gsi,int trigger_fd)83 void riscv__del_irqfd(struct kvm *kvm, unsigned int gsi, int trigger_fd)
84 {
85 	struct riscv_irqfd_line *line;
86 
87 	if (riscv_irqchip_irqfd_ready) {
88 		irq__common_del_irqfd(kvm, gsi, trigger_fd);
89 		return;
90 	}
91 
92 	list_for_each_entry(line, &irqfd_lines, list) {
93 		if (line->gsi != gsi)
94 			continue;
95 
96 		list_del(&line->list);
97 		free(line);
98 		break;
99 	}
100 }
101 
riscv__setup_irqfd_lines(struct kvm * kvm)102 int riscv__setup_irqfd_lines(struct kvm *kvm)
103 {
104 	int ret;
105 	struct riscv_irqfd_line *line, *tmp;
106 
107 	list_for_each_entry_safe(line, tmp, &irqfd_lines, list) {
108 		ret = irq__common_add_irqfd(kvm, line->gsi, line->trigger_fd,
109 					    line->resample_fd);
110 		if (ret < 0) {
111 			pr_err("Failed to register IRQFD");
112 			return ret;
113 		}
114 
115 		list_del(&line->list);
116 		free(line);
117 	}
118 
119 	return 0;
120 }
121 
riscv__generate_irq_prop(void * fdt,u8 irq,enum irq_type irq_type)122 void riscv__generate_irq_prop(void *fdt, u8 irq, enum irq_type irq_type)
123 {
124 	u32 prop[2], size;
125 
126 	prop[0] = cpu_to_fdt32(irq);
127 	size = sizeof(u32);
128 	if (riscv_irqchip_line_sensing) {
129 		prop[1] = cpu_to_fdt32(irq_type);
130 		size += sizeof(u32);
131 	}
132 
133 	_FDT(fdt_property(fdt, "interrupts", prop, size));
134 }
135 
136 static void (*riscv__irqchip_create_funcs[])(struct kvm *kvm) = {
137 	aia__create,
138 	plic__create,
139 };
140 
riscv__irqchip_create(struct kvm * kvm)141 void riscv__irqchip_create(struct kvm *kvm)
142 {
143 	unsigned int i;
144 
145 	/* Try irqchip.create function one after another */
146 	for (i = 0; i < ARRAY_SIZE(riscv__irqchip_create_funcs); i++) {
147 		riscv__irqchip_create_funcs[i](kvm);
148 		if (riscv_irqchip != IRQCHIP_UNKNOWN)
149 			return;
150 	}
151 
152 	/* Fail since irqchip is unknown */
153 	die("No IRQCHIP found\n");
154 }
155