mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
LoongArch: KVM: Add irqfd support
Enable the KVM_IRQ_ROUTING/KVM_IRQCHIP/KVM_MSI configuration items, add the KVM_CAP_IRQCHIP capability, and implement the query interface of the in-kernel irqchip. Signed-off-by: Xianglai Li <lixianglai@loongson.cn> Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
This commit is contained in:
parent
d206d95148
commit
1928254c5c
|
|
@ -23,6 +23,8 @@
|
||||||
#include <asm/kvm_pch_pic.h>
|
#include <asm/kvm_pch_pic.h>
|
||||||
#include <asm/loongarch.h>
|
#include <asm/loongarch.h>
|
||||||
|
|
||||||
|
#define __KVM_HAVE_ARCH_INTC_INITIALIZED
|
||||||
|
|
||||||
/* Loongarch KVM register ids */
|
/* Loongarch KVM register ids */
|
||||||
#define KVM_GET_IOC_CSR_IDX(id) ((id & KVM_CSR_IDX_MASK) >> LOONGARCH_REG_SHIFT)
|
#define KVM_GET_IOC_CSR_IDX(id) ((id & KVM_CSR_IDX_MASK) >> LOONGARCH_REG_SHIFT)
|
||||||
#define KVM_GET_IOC_CPUCFG_IDX(id) ((id & KVM_CPUCFG_IDX_MASK) >> LOONGARCH_REG_SHIFT)
|
#define KVM_GET_IOC_CPUCFG_IDX(id) ((id & KVM_CPUCFG_IDX_MASK) >> LOONGARCH_REG_SHIFT)
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,8 @@
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
#define __KVM_HAVE_IRQ_LINE
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* KVM LoongArch specific structures and definitions.
|
* KVM LoongArch specific structures and definitions.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -21,13 +21,16 @@ config KVM
|
||||||
tristate "Kernel-based Virtual Machine (KVM) support"
|
tristate "Kernel-based Virtual Machine (KVM) support"
|
||||||
depends on AS_HAS_LVZ_EXTENSION
|
depends on AS_HAS_LVZ_EXTENSION
|
||||||
select HAVE_KVM_DIRTY_RING_ACQ_REL
|
select HAVE_KVM_DIRTY_RING_ACQ_REL
|
||||||
|
select HAVE_KVM_IRQ_ROUTING
|
||||||
|
select HAVE_KVM_IRQCHIP
|
||||||
|
select HAVE_KVM_MSI
|
||||||
|
select HAVE_KVM_READONLY_MEM
|
||||||
select HAVE_KVM_VCPU_ASYNC_IOCTL
|
select HAVE_KVM_VCPU_ASYNC_IOCTL
|
||||||
select KVM_COMMON
|
select KVM_COMMON
|
||||||
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
|
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
|
||||||
select KVM_GENERIC_HARDWARE_ENABLING
|
select KVM_GENERIC_HARDWARE_ENABLING
|
||||||
select KVM_GENERIC_MMU_NOTIFIER
|
select KVM_GENERIC_MMU_NOTIFIER
|
||||||
select KVM_MMIO
|
select KVM_MMIO
|
||||||
select HAVE_KVM_READONLY_MEM
|
|
||||||
select KVM_XFER_TO_GUEST_WORK
|
select KVM_XFER_TO_GUEST_WORK
|
||||||
select SCHED_INFO
|
select SCHED_INFO
|
||||||
help
|
help
|
||||||
|
|
|
||||||
|
|
@ -21,5 +21,6 @@ kvm-y += vm.o
|
||||||
kvm-y += intc/ipi.o
|
kvm-y += intc/ipi.o
|
||||||
kvm-y += intc/eiointc.o
|
kvm-y += intc/eiointc.o
|
||||||
kvm-y += intc/pch_pic.o
|
kvm-y += intc/pch_pic.o
|
||||||
|
kvm-y += irqfd.o
|
||||||
|
|
||||||
CFLAGS_exit.o += $(call cc-option,-Wno-override-init,)
|
CFLAGS_exit.o += $(call cc-option,-Wno-override-init,)
|
||||||
|
|
|
||||||
|
|
@ -443,8 +443,31 @@ static int kvm_pch_pic_set_attr(struct kvm_device *dev,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int kvm_setup_default_irq_routing(struct kvm *kvm)
|
||||||
|
{
|
||||||
|
int i, ret;
|
||||||
|
u32 nr = KVM_IRQCHIP_NUM_PINS;
|
||||||
|
struct kvm_irq_routing_entry *entries;
|
||||||
|
|
||||||
|
entries = kcalloc(nr, sizeof(*entries), GFP_KERNEL);
|
||||||
|
if (!entries)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
for (i = 0; i < nr; i++) {
|
||||||
|
entries[i].gsi = i;
|
||||||
|
entries[i].type = KVM_IRQ_ROUTING_IRQCHIP;
|
||||||
|
entries[i].u.irqchip.irqchip = 0;
|
||||||
|
entries[i].u.irqchip.pin = i;
|
||||||
|
}
|
||||||
|
ret = kvm_set_irq_routing(kvm, entries, nr, 0);
|
||||||
|
kfree(entries);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int kvm_pch_pic_create(struct kvm_device *dev, u32 type)
|
static int kvm_pch_pic_create(struct kvm_device *dev, u32 type)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
struct kvm *kvm = dev->kvm;
|
struct kvm *kvm = dev->kvm;
|
||||||
struct loongarch_pch_pic *s;
|
struct loongarch_pch_pic *s;
|
||||||
|
|
||||||
|
|
@ -452,6 +475,10 @@ static int kvm_pch_pic_create(struct kvm_device *dev, u32 type)
|
||||||
if (kvm->arch.pch_pic)
|
if (kvm->arch.pch_pic)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
ret = kvm_setup_default_irq_routing(kvm);
|
||||||
|
if (ret)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
s = kzalloc(sizeof(struct loongarch_pch_pic), GFP_KERNEL);
|
s = kzalloc(sizeof(struct loongarch_pch_pic), GFP_KERNEL);
|
||||||
if (!s)
|
if (!s)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
|
||||||
89
arch/loongarch/kvm/irqfd.c
Normal file
89
arch/loongarch/kvm/irqfd.c
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Loongson Technology Corporation Limited
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/kvm_host.h>
|
||||||
|
#include <trace/events/kvm.h>
|
||||||
|
#include <asm/kvm_pch_pic.h>
|
||||||
|
|
||||||
|
static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e,
|
||||||
|
struct kvm *kvm, int irq_source_id, int level, bool line_status)
|
||||||
|
{
|
||||||
|
/* PCH-PIC pin (0 ~ 64) <---> GSI (0 ~ 64) */
|
||||||
|
pch_pic_set_irq(kvm->arch.pch_pic, e->irqchip.pin, level);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* kvm_set_msi: inject the MSI corresponding to the
|
||||||
|
* MSI routing entry
|
||||||
|
*
|
||||||
|
* This is the entry point for irqfd MSI injection
|
||||||
|
* and userspace MSI injection.
|
||||||
|
*/
|
||||||
|
int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
|
||||||
|
struct kvm *kvm, int irq_source_id, int level, bool line_status)
|
||||||
|
{
|
||||||
|
if (!level)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
pch_msi_set_irq(kvm, e->msi.data, level);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* kvm_set_routing_entry: populate a kvm routing entry
|
||||||
|
* from a user routing entry
|
||||||
|
*
|
||||||
|
* @kvm: the VM this entry is applied to
|
||||||
|
* @e: kvm kernel routing entry handle
|
||||||
|
* @ue: user api routing entry handle
|
||||||
|
* return 0 on success, -EINVAL on errors.
|
||||||
|
*/
|
||||||
|
int kvm_set_routing_entry(struct kvm *kvm,
|
||||||
|
struct kvm_kernel_irq_routing_entry *e,
|
||||||
|
const struct kvm_irq_routing_entry *ue)
|
||||||
|
{
|
||||||
|
switch (ue->type) {
|
||||||
|
case KVM_IRQ_ROUTING_IRQCHIP:
|
||||||
|
e->set = kvm_set_pic_irq;
|
||||||
|
e->irqchip.irqchip = ue->u.irqchip.irqchip;
|
||||||
|
e->irqchip.pin = ue->u.irqchip.pin;
|
||||||
|
|
||||||
|
if (e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
case KVM_IRQ_ROUTING_MSI:
|
||||||
|
e->set = kvm_set_msi;
|
||||||
|
e->msi.address_lo = ue->u.msi.address_lo;
|
||||||
|
e->msi.address_hi = ue->u.msi.address_hi;
|
||||||
|
e->msi.data = ue->u.msi.data;
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int kvm_arch_set_irq_inatomic(struct kvm_kernel_irq_routing_entry *e,
|
||||||
|
struct kvm *kvm, int irq_source_id, int level, bool line_status)
|
||||||
|
{
|
||||||
|
switch (e->type) {
|
||||||
|
case KVM_IRQ_ROUTING_IRQCHIP:
|
||||||
|
pch_pic_set_irq(kvm->arch.pch_pic, e->irqchip.pin, level);
|
||||||
|
return 0;
|
||||||
|
case KVM_IRQ_ROUTING_MSI:
|
||||||
|
pch_msi_set_irq(kvm, e->msi.data, level);
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
return -EWOULDBLOCK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool kvm_arch_intc_initialized(struct kvm *kvm)
|
||||||
|
{
|
||||||
|
return kvm_arch_irqchip_in_kernel(kvm);
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,8 @@
|
||||||
#include <linux/kvm_host.h>
|
#include <linux/kvm_host.h>
|
||||||
#include <asm/kvm_mmu.h>
|
#include <asm/kvm_mmu.h>
|
||||||
#include <asm/kvm_vcpu.h>
|
#include <asm/kvm_vcpu.h>
|
||||||
|
#include <asm/kvm_eiointc.h>
|
||||||
|
#include <asm/kvm_pch_pic.h>
|
||||||
|
|
||||||
const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
|
const struct _kvm_stats_desc kvm_vm_stats_desc[] = {
|
||||||
KVM_GENERIC_VM_STATS(),
|
KVM_GENERIC_VM_STATS(),
|
||||||
|
|
@ -76,6 +78,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
switch (ext) {
|
switch (ext) {
|
||||||
|
case KVM_CAP_IRQCHIP:
|
||||||
case KVM_CAP_ONE_REG:
|
case KVM_CAP_ONE_REG:
|
||||||
case KVM_CAP_ENABLE_CAP:
|
case KVM_CAP_ENABLE_CAP:
|
||||||
case KVM_CAP_READONLY_MEM:
|
case KVM_CAP_READONLY_MEM:
|
||||||
|
|
@ -161,6 +164,8 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
|
||||||
struct kvm_device_attr attr;
|
struct kvm_device_attr attr;
|
||||||
|
|
||||||
switch (ioctl) {
|
switch (ioctl) {
|
||||||
|
case KVM_CREATE_IRQCHIP:
|
||||||
|
return 0;
|
||||||
case KVM_HAS_DEVICE_ATTR:
|
case KVM_HAS_DEVICE_ATTR:
|
||||||
if (copy_from_user(&attr, argp, sizeof(attr)))
|
if (copy_from_user(&attr, argp, sizeof(attr)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
@ -170,3 +175,19 @@ int kvm_arch_vm_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg)
|
||||||
return -ENOIOCTLCMD;
|
return -ENOIOCTLCMD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_event, bool line_status)
|
||||||
|
{
|
||||||
|
if (!kvm_arch_irqchip_in_kernel(kvm))
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
|
irq_event->status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
|
||||||
|
irq_event->irq, irq_event->level, line_status);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool kvm_arch_irqchip_in_kernel(struct kvm *kvm)
|
||||||
|
{
|
||||||
|
return (kvm->arch.ipi && kvm->arch.eiointc && kvm->arch.pch_pic);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user