LoongArch: KVM: Add EIOINTC device support

Add device model for EIOINTC interrupt controller, implement basic
create & destroy interfaces, and register device model to kvm device
table.

Signed-off-by: Tianrui Zhao <zhaotianrui@loongson.cn>
Signed-off-by: Xianglai Li <lixianglai@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
This commit is contained in:
Xianglai Li 2024-11-13 16:18:27 +08:00 committed by Huacai Chen
parent 8e3054261b
commit 2e8b9df826
6 changed files with 237 additions and 1 deletions

View File

@ -0,0 +1,93 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2024 Loongson Technology Corporation Limited
*/
#ifndef __ASM_KVM_EIOINTC_H
#define __ASM_KVM_EIOINTC_H
#include <kvm/iodev.h>
#define EIOINTC_IRQS 256
#define EIOINTC_ROUTE_MAX_VCPUS 256
#define EIOINTC_IRQS_U8_NUMS (EIOINTC_IRQS / 8)
#define EIOINTC_IRQS_U16_NUMS (EIOINTC_IRQS_U8_NUMS / 2)
#define EIOINTC_IRQS_U32_NUMS (EIOINTC_IRQS_U8_NUMS / 4)
#define EIOINTC_IRQS_U64_NUMS (EIOINTC_IRQS_U8_NUMS / 8)
/* map to ipnum per 32 irqs */
#define EIOINTC_IRQS_NODETYPE_COUNT 16
#define EIOINTC_BASE 0x1400
#define EIOINTC_SIZE 0x900
#define EIOINTC_VIRT_BASE (0x40000000)
#define EIOINTC_VIRT_SIZE (0x1000)
#define LOONGSON_IP_NUM 8
struct loongarch_eiointc {
spinlock_t lock;
struct kvm *kvm;
struct kvm_io_device device;
struct kvm_io_device device_vext;
uint32_t num_cpu;
uint32_t features;
uint32_t status;
/* hardware state */
union nodetype {
u64 reg_u64[EIOINTC_IRQS_NODETYPE_COUNT / 4];
u32 reg_u32[EIOINTC_IRQS_NODETYPE_COUNT / 2];
u16 reg_u16[EIOINTC_IRQS_NODETYPE_COUNT];
u8 reg_u8[EIOINTC_IRQS_NODETYPE_COUNT * 2];
} nodetype;
/* one bit shows the state of one irq */
union bounce {
u64 reg_u64[EIOINTC_IRQS_U64_NUMS];
u32 reg_u32[EIOINTC_IRQS_U32_NUMS];
u16 reg_u16[EIOINTC_IRQS_U16_NUMS];
u8 reg_u8[EIOINTC_IRQS_U8_NUMS];
} bounce;
union isr {
u64 reg_u64[EIOINTC_IRQS_U64_NUMS];
u32 reg_u32[EIOINTC_IRQS_U32_NUMS];
u16 reg_u16[EIOINTC_IRQS_U16_NUMS];
u8 reg_u8[EIOINTC_IRQS_U8_NUMS];
} isr;
union coreisr {
u64 reg_u64[EIOINTC_ROUTE_MAX_VCPUS][EIOINTC_IRQS_U64_NUMS];
u32 reg_u32[EIOINTC_ROUTE_MAX_VCPUS][EIOINTC_IRQS_U32_NUMS];
u16 reg_u16[EIOINTC_ROUTE_MAX_VCPUS][EIOINTC_IRQS_U16_NUMS];
u8 reg_u8[EIOINTC_ROUTE_MAX_VCPUS][EIOINTC_IRQS_U8_NUMS];
} coreisr;
union enable {
u64 reg_u64[EIOINTC_IRQS_U64_NUMS];
u32 reg_u32[EIOINTC_IRQS_U32_NUMS];
u16 reg_u16[EIOINTC_IRQS_U16_NUMS];
u8 reg_u8[EIOINTC_IRQS_U8_NUMS];
} enable;
/* use one byte to config ipmap for 32 irqs at once */
union ipmap {
u64 reg_u64;
u32 reg_u32[EIOINTC_IRQS_U32_NUMS / 4];
u16 reg_u16[EIOINTC_IRQS_U16_NUMS / 4];
u8 reg_u8[EIOINTC_IRQS_U8_NUMS / 4];
} ipmap;
/* use one byte to config coremap for one irq */
union coremap {
u64 reg_u64[EIOINTC_IRQS / 8];
u32 reg_u32[EIOINTC_IRQS / 4];
u16 reg_u16[EIOINTC_IRQS / 2];
u8 reg_u8[EIOINTC_IRQS];
} coremap;
DECLARE_BITMAP(sw_coreisr[EIOINTC_ROUTE_MAX_VCPUS][LOONGSON_IP_NUM], EIOINTC_IRQS);
uint8_t sw_coremap[EIOINTC_IRQS];
};
int kvm_loongarch_register_eiointc_device(void);
#endif /* __ASM_KVM_EIOINTC_H */

View File

@ -19,6 +19,7 @@
#include <asm/inst.h> #include <asm/inst.h>
#include <asm/kvm_mmu.h> #include <asm/kvm_mmu.h>
#include <asm/kvm_ipi.h> #include <asm/kvm_ipi.h>
#include <asm/kvm_eiointc.h>
#include <asm/loongarch.h> #include <asm/loongarch.h>
/* Loongarch KVM register ids */ /* Loongarch KVM register ids */
@ -87,7 +88,7 @@ struct kvm_world_switch {
* *
* For LOONGARCH_CSR_CPUID register, max CPUID size if 512 * For LOONGARCH_CSR_CPUID register, max CPUID size if 512
* For IPI hardware, max destination CPUID size 1024 * For IPI hardware, max destination CPUID size 1024
* For extioi interrupt controller, max destination CPUID size is 256 * For eiointc interrupt controller, max destination CPUID size is 256
* For msgint interrupt controller, max supported CPUID size is 65536 * For msgint interrupt controller, max supported CPUID size is 65536
* *
* Currently max CPUID is defined as 256 for KVM hypervisor, in future * Currently max CPUID is defined as 256 for KVM hypervisor, in future
@ -121,6 +122,7 @@ struct kvm_arch {
s64 time_offset; s64 time_offset;
struct kvm_context __percpu *vmcs; struct kvm_context __percpu *vmcs;
struct loongarch_ipi *ipi; struct loongarch_ipi *ipi;
struct loongarch_eiointc *eiointc;
}; };
#define CSR_MAX_NUMS 0x800 #define CSR_MAX_NUMS 0x800

View File

@ -19,5 +19,6 @@ kvm-y += tlb.o
kvm-y += vcpu.o kvm-y += vcpu.o
kvm-y += vm.o kvm-y += vm.o
kvm-y += intc/ipi.o kvm-y += intc/ipi.o
kvm-y += intc/eiointc.o
CFLAGS_exit.o += $(call cc-option,-Wno-override-init,) CFLAGS_exit.o += $(call cc-option,-Wno-override-init,)

View File

@ -0,0 +1,132 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2024 Loongson Technology Corporation Limited
*/
#include <asm/kvm_eiointc.h>
#include <asm/kvm_vcpu.h>
#include <linux/count_zeros.h>
static int kvm_eiointc_read(struct kvm_vcpu *vcpu,
struct kvm_io_device *dev,
gpa_t addr, int len, void *val)
{
return 0;
}
static int kvm_eiointc_write(struct kvm_vcpu *vcpu,
struct kvm_io_device *dev,
gpa_t addr, int len, const void *val)
{
return 0;
}
static const struct kvm_io_device_ops kvm_eiointc_ops = {
.read = kvm_eiointc_read,
.write = kvm_eiointc_write,
};
static int kvm_eiointc_virt_read(struct kvm_vcpu *vcpu,
struct kvm_io_device *dev,
gpa_t addr, int len, void *val)
{
return 0;
}
static int kvm_eiointc_virt_write(struct kvm_vcpu *vcpu,
struct kvm_io_device *dev,
gpa_t addr, int len, const void *val)
{
return 0;
}
static const struct kvm_io_device_ops kvm_eiointc_virt_ops = {
.read = kvm_eiointc_virt_read,
.write = kvm_eiointc_virt_write,
};
static int kvm_eiointc_get_attr(struct kvm_device *dev,
struct kvm_device_attr *attr)
{
return 0;
}
static int kvm_eiointc_set_attr(struct kvm_device *dev,
struct kvm_device_attr *attr)
{
return 0;
}
static int kvm_eiointc_create(struct kvm_device *dev, u32 type)
{
int ret;
struct loongarch_eiointc *s;
struct kvm_io_device *device, *device1;
struct kvm *kvm = dev->kvm;
/* eiointc has been created */
if (kvm->arch.eiointc)
return -EINVAL;
s = kzalloc(sizeof(struct loongarch_eiointc), 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_eiointc_ops);
mutex_lock(&kvm->slots_lock);
ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS,
EIOINTC_BASE, EIOINTC_SIZE, device);
mutex_unlock(&kvm->slots_lock);
if (ret < 0) {
kfree(s);
return ret;
}
device1 = &s->device_vext;
kvm_iodevice_init(device1, &kvm_eiointc_virt_ops);
ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS,
EIOINTC_VIRT_BASE, EIOINTC_VIRT_SIZE, device1);
if (ret < 0) {
kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &s->device);
kfree(s);
return ret;
}
kvm->arch.eiointc = s;
return 0;
}
static void kvm_eiointc_destroy(struct kvm_device *dev)
{
struct kvm *kvm;
struct loongarch_eiointc *eiointc;
if (!dev || !dev->kvm || !dev->kvm->arch.eiointc)
return;
kvm = dev->kvm;
eiointc = kvm->arch.eiointc;
kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &eiointc->device);
kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &eiointc->device_vext);
kfree(eiointc);
}
static struct kvm_device_ops kvm_eiointc_dev_ops = {
.name = "kvm-loongarch-eiointc",
.create = kvm_eiointc_create,
.destroy = kvm_eiointc_destroy,
.set_attr = kvm_eiointc_set_attr,
.get_attr = kvm_eiointc_get_attr,
};
int kvm_loongarch_register_eiointc_device(void)
{
return kvm_register_device_ops(&kvm_eiointc_dev_ops, KVM_DEV_TYPE_LOONGARCH_EIOINTC);
}

View File

@ -9,6 +9,7 @@
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#include <asm/cpufeature.h> #include <asm/cpufeature.h>
#include <asm/kvm_csr.h> #include <asm/kvm_csr.h>
#include <asm/kvm_eiointc.h>
#include "trace.h" #include "trace.h"
unsigned long vpid_mask; unsigned long vpid_mask;
@ -370,6 +371,11 @@ static int kvm_loongarch_env_init(void)
/* Register LoongArch IPI interrupt controller interface. */ /* Register LoongArch IPI interrupt controller interface. */
ret = kvm_loongarch_register_ipi_device(); ret = kvm_loongarch_register_ipi_device();
if (ret)
return ret;
/* Register LoongArch EIOINTC interrupt controller interface. */
ret = kvm_loongarch_register_eiointc_device();
return ret; return ret;
} }

View File

@ -1160,6 +1160,8 @@ enum kvm_device_type {
#define KVM_DEV_TYPE_RISCV_AIA KVM_DEV_TYPE_RISCV_AIA #define KVM_DEV_TYPE_RISCV_AIA KVM_DEV_TYPE_RISCV_AIA
KVM_DEV_TYPE_LOONGARCH_IPI, KVM_DEV_TYPE_LOONGARCH_IPI,
#define KVM_DEV_TYPE_LOONGARCH_IPI KVM_DEV_TYPE_LOONGARCH_IPI #define KVM_DEV_TYPE_LOONGARCH_IPI KVM_DEV_TYPE_LOONGARCH_IPI
KVM_DEV_TYPE_LOONGARCH_EIOINTC,
#define KVM_DEV_TYPE_LOONGARCH_EIOINTC KVM_DEV_TYPE_LOONGARCH_EIOINTC
KVM_DEV_TYPE_MAX, KVM_DEV_TYPE_MAX,