Commit 9ac5bce4 authored by Xianglai Li's avatar Xianglai Li
Browse files

LoongArch: KVM: Add EXTIOI device support

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



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

Added device model for EXTIOI interrupt controller,
implemented basic create destroy interface,
and registered device model to kvm device table.

Signed-off-by: default avatarTianrui Zhao <zhaotianrui@loongson.cn>
Signed-off-by: default avatarXianglai Li <lixianglai@loongson.cn>
parent a69d6833
Loading
Loading
Loading
Loading
+78 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Copyright (C) 2024 Loongson Technology Corporation Limited
 */

#ifndef LOONGARCH_EXTIOI_H
#define LOONGARCH_EXTIOI_H

#include <kvm/iodev.h>

#define EXTIOI_IRQS			256
#define EXTIOI_ROUTE_MAX_VCPUS		256
#define EXTIOI_IRQS_U8_NUMS		(EXTIOI_IRQS / 8)
#define EXTIOI_IRQS_U32_NUMS		(EXTIOI_IRQS_U8_NUMS / 4)
#define EXTIOI_IRQS_U64_NUMS		(EXTIOI_IRQS_U32_NUMS / 2)
/* map to ipnum per 32 irqs */
#define EXTIOI_IRQS_NODETYPE_COUNT	16

#define EXTIOI_BASE			0x1400
#define EXTIOI_SIZE			0x900

#define LS3A_INTC_IP			8

struct loongarch_extioi {
	spinlock_t lock;
	struct kvm *kvm;
	struct kvm_io_device device;
	/* hardware state */
	union nodetype {
		u64 reg_u64[EXTIOI_IRQS_NODETYPE_COUNT / 4];
		u32 reg_u32[EXTIOI_IRQS_NODETYPE_COUNT / 2];
		uint16_t reg_u16[EXTIOI_IRQS_NODETYPE_COUNT];
		u8 reg_u8[EXTIOI_IRQS_NODETYPE_COUNT * 2];
	} nodetype;

	/* one bit shows the state of one irq */
	union bounce {
		u64 reg_u64[EXTIOI_IRQS_U64_NUMS];
		u32 reg_u32[EXTIOI_IRQS_U32_NUMS];
		u8 reg_u8[EXTIOI_IRQS_U8_NUMS];
	} bounce;

	union isr {
		u64 reg_u64[EXTIOI_IRQS_U64_NUMS];
		u32 reg_u32[EXTIOI_IRQS_U32_NUMS];
		u8 reg_u8[EXTIOI_IRQS_U8_NUMS];
	} isr;
	union coreisr {
		u64 reg_u64[EXTIOI_ROUTE_MAX_VCPUS][EXTIOI_IRQS_U64_NUMS];
		u32 reg_u32[EXTIOI_ROUTE_MAX_VCPUS][EXTIOI_IRQS_U32_NUMS];
		u8 reg_u8[EXTIOI_ROUTE_MAX_VCPUS][EXTIOI_IRQS_U8_NUMS];
	} coreisr;
	union enable {
		u64 reg_u64[EXTIOI_IRQS_U64_NUMS];
		u32 reg_u32[EXTIOI_IRQS_U32_NUMS];
		u8 reg_u8[EXTIOI_IRQS_U8_NUMS];
	} enable;

	/* use one byte to config ipmap for 32 irqs at once */
	union ipmap {
		u64 reg_u64;
		u32 reg_u32[EXTIOI_IRQS_U32_NUMS / 4];
		u8 reg_u8[EXTIOI_IRQS_U8_NUMS / 4];
	} ipmap;
	/* use one byte to config coremap for one irq */
	union coremap {
		u64 reg_u64[EXTIOI_IRQS / 8];
		u32 reg_u32[EXTIOI_IRQS / 4];
		u8 reg_u8[EXTIOI_IRQS];
	} coremap;

	DECLARE_BITMAP(sw_coreisr[EXTIOI_ROUTE_MAX_VCPUS][LS3A_INTC_IP], EXTIOI_IRQS);
	uint8_t  sw_coremap[EXTIOI_IRQS];
};

void extioi_set_irq(struct loongarch_extioi *s, int irq, int level);
int kvm_loongarch_register_extioi_device(void);
#endif /* LOONGARCH_EXTIOI_H */
+2 −0
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <asm/kvm_mmu.h>
#include <asm/loongarch.h>
#include <asm/kvm_ipi.h>
#include <asm/kvm_extioi.h>

/* Loongarch KVM register ids */
#define KVM_GET_IOC_CSR_IDX(id)		((id & KVM_CSR_IDX_MASK) >> LOONGARCH_REG_SHIFT)
@@ -113,6 +114,7 @@ struct kvm_arch {
	s64 time_offset;
	struct kvm_context __percpu *vmcs;
	struct loongarch_ipi *ipi;
	struct loongarch_extioi *extioi;
};

#define CSR_MAX_NUMS		0x800
+1 −0
Original line number Diff line number Diff line
@@ -19,5 +19,6 @@ kvm-y += tlb.o
kvm-y += vcpu.o
kvm-y += vm.o
kvm-y += intc/ipi.o
kvm-y += intc/extioi.o

CFLAGS_exit.o	+= $(call cc-option,-Wno-override-init,)
+111 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2024 Loongson Technology Corporation Limited
 */

#include <asm/kvm_extioi.h>
#include <asm/kvm_vcpu.h>
#include <linux/count_zeros.h>

static int kvm_loongarch_extioi_write(struct kvm_vcpu *vcpu,
				struct kvm_io_device *dev,
				gpa_t addr, int len, const void *val)
{
	return 0;
}

static int kvm_loongarch_extioi_read(struct kvm_vcpu *vcpu,
				struct kvm_io_device *dev,
				gpa_t addr, int len, void *val)
{
	return 0;
}

static const struct kvm_io_device_ops kvm_loongarch_extioi_ops = {
	.read	= kvm_loongarch_extioi_read,
	.write	= kvm_loongarch_extioi_write,
};

static int kvm_loongarch_extioi_get_attr(struct kvm_device *dev,
				struct kvm_device_attr *attr)
{
	return 0;
}

static int kvm_loongarch_extioi_set_attr(struct kvm_device *dev,
				struct kvm_device_attr *attr)
{
	return 0;
}

static void kvm_loongarch_extioi_destroy(struct kvm_device *dev)
{
	struct kvm *kvm;
	struct loongarch_extioi *extioi;
	struct kvm_io_device *device;

	if (!dev)
		return;

	kvm = dev->kvm;
	if (!kvm)
		return;

	extioi = kvm->arch.extioi;
	if (!extioi)
		return;

	device = &extioi->device;
	kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, device);
	kfree(extioi);
}

static int kvm_loongarch_extioi_create(struct kvm_device *dev, u32 type)
{
	int ret;
	struct loongarch_extioi *s;
	struct kvm_io_device *device;
	struct kvm *kvm = dev->kvm;

	/* extioi has been created */
	if (kvm->arch.extioi)
		return -EINVAL;

	s = kzalloc(sizeof(struct loongarch_extioi), GFP_KERNEL);
	if (!s)
		return -ENOMEM;
	spin_lock_init(&s->lock);
	s->kvm = kvm;

	/*
	 * Initialize IOCSR device
	 */
	device = &s->device;
	kvm_iodevice_init(device, &kvm_loongarch_extioi_ops);
	mutex_lock(&kvm->slots_lock);
	ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS, EXTIOI_BASE, EXTIOI_SIZE, device);
	mutex_unlock(&kvm->slots_lock);
	if (ret < 0) {
		kfree(s);
		return -EFAULT;
	}

	kvm->arch.extioi = s;

	kvm_info("create extioi device successfully\n");
	return 0;
}

static struct kvm_device_ops kvm_loongarch_extioi_dev_ops = {
	.name = "kvm-loongarch-extioi",
	.create = kvm_loongarch_extioi_create,
	.destroy = kvm_loongarch_extioi_destroy,
	.set_attr = kvm_loongarch_extioi_set_attr,
	.get_attr = kvm_loongarch_extioi_get_attr,
};

int kvm_loongarch_register_extioi_device(void)
{
	return kvm_register_device_ops(&kvm_loongarch_extioi_dev_ops,
					KVM_DEV_TYPE_LA_EXTIOI);
}
+5 −1
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
#include <asm/cacheflush.h>
#include <asm/cpufeature.h>
#include <asm/kvm_csr.h>
#include <asm/kvm_extioi.h>
#include "trace.h"

unsigned long vpid_mask;
@@ -372,7 +373,10 @@ static int kvm_loongarch_env_init(void)
	if (ret)
		return ret;

	return 0;
	/* Register loongarch extioi interrupt controller interface. */
	ret = kvm_loongarch_register_extioi_device();

	return ret;
}

static void kvm_loongarch_env_exit(void)
Loading