Commit bd254ad9 authored by Xianglai Li's avatar Xianglai Li
Browse files

LoongArch: KVM: Add irqfd support

LoongArch inclusion
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IB8FOC



------------------------------------------

Enable the KVM_IRQ_ROUTING KVM_IRQCHIP KVM_MSI configuration item,
increase the KVM_CAP_IRQCHIP capability, and implement the query
interface of the kernel irqchip.

Signed-off-by: default avatarXianglai Li <lixianglai@loongson.cn>
parent 9a0f37dc
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -115,6 +115,8 @@ struct kvm_iocsr_entry {
#define KVM_IRQCHIP_NUM_PINS	64
#define KVM_MAX_CORES		256

#define KVM_LOONGARCH_VM_HAVE_IRQCHIP		0x40000001

#define KVM_DEV_LOONGARCH_IPI_GRP_REGS		0x40000002

#define KVM_DEV_LOONGARCH_EXTIOI_GRP_REGS	0x40000003
+4 −0
Original line number Diff line number Diff line
@@ -24,6 +24,10 @@ config KVM
	select HAVE_KVM_DIRTY_RING_ACQ_REL
	select HAVE_KVM_EVENTFD
	select HAVE_KVM_VCPU_ASYNC_IOCTL
	select HAVE_KVM_IRQ_ROUTING
	select HAVE_KVM_IRQCHIP
	select HAVE_KVM_IRQFD
	select HAVE_KVM_MSI
	select KVM_GENERIC_DIRTYLOG_READ_PROTECT
	select KVM_GENERIC_HARDWARE_ENABLING
	select KVM_MMIO
+1 −0
Original line number Diff line number Diff line
@@ -21,5 +21,6 @@ kvm-y += vm.o
kvm-y += intc/ipi.o
kvm-y += intc/extioi.o
kvm-y += intc/pch_pic.o
kvm-y += irqfd.o

CFLAGS_exit.o	+= $(call cc-option,-Wno-override-init,)
+28 −0
Original line number Diff line number Diff line
@@ -451,6 +451,29 @@ static int kvm_loongarch_pch_pic_set_attr(struct kvm_device *dev,
	return ret;
}

static int kvm_setup_default_irq_routing(struct kvm *kvm)
{
	struct kvm_irq_routing_entry *entries;

	u32 nr = KVM_IRQCHIP_NUM_PINS;
	int i, ret;

	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 0;
}

static void kvm_loongarch_pch_pic_destroy(struct kvm_device *dev)
{
	struct kvm *kvm;
@@ -476,6 +499,7 @@ static void kvm_loongarch_pch_pic_destroy(struct kvm_device *dev)

static int kvm_loongarch_pch_pic_create(struct kvm_device *dev, u32 type)
{
	int ret;
	struct loongarch_pch_pic *s;
	struct kvm *kvm = dev->kvm;

@@ -483,6 +507,10 @@ static int kvm_loongarch_pch_pic_create(struct kvm_device *dev, u32 type)
	if (kvm->arch.pch_pic)
		return -EINVAL;

	ret = kvm_setup_default_irq_routing(kvm);
	if (ret)
		return -ENOMEM;

	s = kzalloc(sizeof(struct loongarch_pch_pic), GFP_KERNEL);
	if (!s)
		return -ENOMEM;
+87 −0
Original line number Diff line number Diff line
// 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_ioapic_irq(struct kvm_kernel_irq_routing_entry *e,
					struct kvm *kvm, int irq_source_id,
					int level, bool line_status)
{
	/* ioapic pin (0 ~ 64) <---> gsi(0 ~ 64) */
	pch_pic_set_irq(kvm->arch.pch_pic, e->irqchip.pin, 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)
{
	int r = -EINVAL;

	switch (ue->type) {
	case KVM_IRQ_ROUTING_IRQCHIP:
		e->set = kvm_set_ioapic_irq;

		e->irqchip.irqchip = ue->u.irqchip.irqchip;
		e->irqchip.pin = ue->u.irqchip.pin;

		if (e->irqchip.pin >= KVM_IRQCHIP_NUM_PINS)
			goto out;
		break;
	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;
		break;
	default:
		goto out;
	}
	r = 0;
out:
	return r;
}

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)
{
	if (e->type == KVM_IRQ_ROUTING_MSI) {
		pch_msi_set_irq(kvm, e->msi.data, 1);
		return 0;
	}

	return -EWOULDBLOCK;
}

/**
 * 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;
}
Loading