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