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