blob: 043b681d01a73417767b1f8c712359e20fae4047 [file] [log] [blame]
#include "kvm/kvm.h"
#include "kvm/kvm-cpu.h"
#include "kvm/irq.h"
#include "kvm/fdt.h"
#include "kvm/virtio.h"
enum irqchip_type riscv_irqchip = IRQCHIP_UNKNOWN;
bool riscv_irqchip_inkernel;
void (*riscv_irqchip_trigger)(struct kvm *kvm, int irq, int level, bool edge)
= NULL;
void (*riscv_irqchip_generate_fdt_node)(void *fdt, struct kvm *kvm) = NULL;
u32 riscv_irqchip_phandle = PHANDLE_RESERVED;
u32 riscv_irqchip_msi_phandle = PHANDLE_RESERVED;
bool riscv_irqchip_line_sensing;
void kvm__irq_line(struct kvm *kvm, int irq, int level)
{
struct kvm_irq_level irq_level;
if (riscv_irqchip_inkernel) {
irq_level.irq = irq;
irq_level.level = !!level;
if (ioctl(kvm->vm_fd, KVM_IRQ_LINE, &irq_level) < 0)
pr_warning("%s: Could not KVM_IRQ_LINE for irq %d\n",
__func__, irq);
} else {
if (riscv_irqchip_trigger)
riscv_irqchip_trigger(kvm, irq, level, false);
else
pr_warning("%s: Can't change level for irq %d\n",
__func__, irq);
}
}
void kvm__irq_trigger(struct kvm *kvm, int irq)
{
if (riscv_irqchip_inkernel) {
kvm__irq_line(kvm, irq, VIRTIO_IRQ_HIGH);
kvm__irq_line(kvm, irq, VIRTIO_IRQ_LOW);
} else {
if (riscv_irqchip_trigger)
riscv_irqchip_trigger(kvm, irq, 1, true);
else
pr_warning("%s: Can't trigger irq %d\n",
__func__, irq);
}
}
void riscv__generate_irq_prop(void *fdt, u8 irq, enum irq_type irq_type)
{
u32 prop[2], size;
prop[0] = cpu_to_fdt32(irq);
size = sizeof(u32);
if (riscv_irqchip_line_sensing) {
prop[1] = cpu_to_fdt32(irq_type);
size += sizeof(u32);
}
_FDT(fdt_property(fdt, "interrupts", prop, size));
}
void riscv__irqchip_create(struct kvm *kvm)
{
/* Try PLIC irqchip */
plic__create(kvm);
/* Fail if irqchip unknown */
if (riscv_irqchip == IRQCHIP_UNKNOWN)
die("No IRQCHIP found\n");
}