mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
LoongArch: KVM: Add DMSINTC device support
Add device model for DMSINTC interrupt controller, implement basic create/destroy/set_attr interfaces, and register device model to kvm device table. Reviewed-by: Bibo Mao <maobibo@loongson.cn> Signed-off-by: Song Gao <gaosong@loongson.cn> Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
This commit is contained in:
24
arch/loongarch/include/asm/kvm_dmsintc.h
Normal file
24
arch/loongarch/include/asm/kvm_dmsintc.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2025 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#ifndef __ASM_KVM_DMSINTC_H
|
||||
#define __ASM_KVM_DMSINTC_H
|
||||
|
||||
#include <linux/kvm_types.h>
|
||||
|
||||
struct loongarch_dmsintc {
|
||||
struct kvm *kvm;
|
||||
uint64_t msg_addr_base;
|
||||
uint64_t msg_addr_size;
|
||||
uint32_t cpu_mask;
|
||||
};
|
||||
|
||||
struct dmsintc_state {
|
||||
atomic64_t vector_map[4];
|
||||
};
|
||||
|
||||
int kvm_loongarch_register_dmsintc_device(void);
|
||||
|
||||
#endif
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <asm/inst.h>
|
||||
#include <asm/kvm_mmu.h>
|
||||
#include <asm/kvm_ipi.h>
|
||||
#include <asm/kvm_dmsintc.h>
|
||||
#include <asm/kvm_eiointc.h>
|
||||
#include <asm/kvm_pch_pic.h>
|
||||
#include <asm/loongarch.h>
|
||||
@@ -133,6 +134,7 @@ struct kvm_arch {
|
||||
s64 time_offset;
|
||||
struct kvm_context __percpu *vmcs;
|
||||
struct loongarch_ipi *ipi;
|
||||
struct loongarch_dmsintc *dmsintc;
|
||||
struct loongarch_eiointc *eiointc;
|
||||
struct loongarch_pch_pic *pch_pic;
|
||||
};
|
||||
@@ -247,6 +249,7 @@ struct kvm_vcpu_arch {
|
||||
struct kvm_mp_state mp_state;
|
||||
/* ipi state */
|
||||
struct ipi_state ipi_state;
|
||||
struct dmsintc_state dmsintc_state;
|
||||
/* cpucfg */
|
||||
u32 cpucfg[KVM_MAX_CPUCFG_REGS];
|
||||
|
||||
|
||||
@@ -155,4 +155,8 @@ struct kvm_iocsr_entry {
|
||||
#define KVM_DEV_LOONGARCH_PCH_PIC_GRP_CTRL 0x40000006
|
||||
#define KVM_DEV_LOONGARCH_PCH_PIC_CTRL_INIT 0
|
||||
|
||||
#define KVM_DEV_LOONGARCH_DMSINTC_GRP_CTRL 0x40000007
|
||||
#define KVM_DEV_LOONGARCH_DMSINTC_MSG_ADDR_BASE 0x0
|
||||
#define KVM_DEV_LOONGARCH_DMSINTC_MSG_ADDR_SIZE 0x1
|
||||
|
||||
#endif /* __UAPI_ASM_LOONGARCH_KVM_H */
|
||||
|
||||
@@ -17,6 +17,7 @@ kvm-y += tlb.o
|
||||
kvm-y += vcpu.o
|
||||
kvm-y += vm.o
|
||||
kvm-y += intc/ipi.o
|
||||
kvm-y += intc/dmsintc.o
|
||||
kvm-y += intc/eiointc.o
|
||||
kvm-y += intc/pch_pic.o
|
||||
kvm-y += irqfd.o
|
||||
|
||||
108
arch/loongarch/kvm/intc/dmsintc.c
Normal file
108
arch/loongarch/kvm/intc/dmsintc.c
Normal file
@@ -0,0 +1,108 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2025 Loongson Technology Corporation Limited
|
||||
*/
|
||||
|
||||
#include <linux/kvm_host.h>
|
||||
#include <asm/kvm_dmsintc.h>
|
||||
#include <asm/kvm_vcpu.h>
|
||||
|
||||
static int kvm_dmsintc_ctrl_access(struct kvm_device *dev,
|
||||
struct kvm_device_attr *attr, bool is_write)
|
||||
{
|
||||
int addr = attr->attr;
|
||||
unsigned long cpu_bit, val;
|
||||
void __user *data = (void __user *)attr->addr;
|
||||
struct loongarch_dmsintc *s = dev->kvm->arch.dmsintc;
|
||||
|
||||
switch (addr) {
|
||||
case KVM_DEV_LOONGARCH_DMSINTC_MSG_ADDR_BASE:
|
||||
if (is_write) {
|
||||
if (copy_from_user(&val, data, sizeof(s->msg_addr_base)))
|
||||
return -EFAULT;
|
||||
if (s->msg_addr_base)
|
||||
return -EFAULT; /* Duplicate setting are not allowed. */
|
||||
if ((val & (BIT(AVEC_CPU_SHIFT) - 1)) != 0)
|
||||
return -EINVAL;
|
||||
s->msg_addr_base = val;
|
||||
cpu_bit = find_first_bit((unsigned long *)&(s->msg_addr_base), 64) - AVEC_CPU_SHIFT;
|
||||
cpu_bit = min(cpu_bit, AVEC_CPU_BIT);
|
||||
s->cpu_mask = GENMASK(cpu_bit - 1, 0) & AVEC_CPU_MASK;
|
||||
}
|
||||
break;
|
||||
case KVM_DEV_LOONGARCH_DMSINTC_MSG_ADDR_SIZE:
|
||||
if (is_write) {
|
||||
if (copy_from_user(&val, data, sizeof(s->msg_addr_size)))
|
||||
return -EFAULT;
|
||||
if (s->msg_addr_size)
|
||||
return -EFAULT; /*Duplicate setting are not allowed. */
|
||||
s->msg_addr_size = val;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
kvm_err("%s: unknown dmsintc register, addr = %d\n", __func__, addr);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kvm_dmsintc_set_attr(struct kvm_device *dev,
|
||||
struct kvm_device_attr *attr)
|
||||
{
|
||||
switch (attr->group) {
|
||||
case KVM_DEV_LOONGARCH_DMSINTC_GRP_CTRL:
|
||||
return kvm_dmsintc_ctrl_access(dev, attr, true);
|
||||
default:
|
||||
kvm_err("%s: unknown group (%d)\n", __func__, attr->group);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int kvm_dmsintc_create(struct kvm_device *dev, u32 type)
|
||||
{
|
||||
struct kvm *kvm;
|
||||
struct loongarch_dmsintc *s;
|
||||
|
||||
if (!dev) {
|
||||
kvm_err("%s: kvm_device ptr is invalid!\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
kvm = dev->kvm;
|
||||
if (kvm->arch.dmsintc) {
|
||||
kvm_err("%s: LoongArch DMSINTC has already been created!\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
s = kzalloc(sizeof(struct loongarch_dmsintc), GFP_KERNEL);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
s->kvm = kvm;
|
||||
kvm->arch.dmsintc = s;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void kvm_dmsintc_destroy(struct kvm_device *dev)
|
||||
{
|
||||
|
||||
if (!dev || !dev->kvm || !dev->kvm->arch.dmsintc)
|
||||
return;
|
||||
|
||||
kfree(dev->kvm->arch.dmsintc);
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
static struct kvm_device_ops kvm_dmsintc_dev_ops = {
|
||||
.name = "kvm-loongarch-dmsintc",
|
||||
.create = kvm_dmsintc_create,
|
||||
.destroy = kvm_dmsintc_destroy,
|
||||
.set_attr = kvm_dmsintc_set_attr,
|
||||
};
|
||||
|
||||
int kvm_loongarch_register_dmsintc_device(void)
|
||||
{
|
||||
return kvm_register_device_ops(&kvm_dmsintc_dev_ops, KVM_DEV_TYPE_LOONGARCH_DMSINTC);
|
||||
}
|
||||
@@ -416,6 +416,12 @@ static int kvm_loongarch_env_init(void)
|
||||
|
||||
/* Register LoongArch PCH-PIC interrupt controller interface. */
|
||||
ret = kvm_loongarch_register_pch_pic_device();
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Register LoongArch DMSINTC interrupt contrroller interface */
|
||||
if (cpu_has_msgint)
|
||||
ret = kvm_loongarch_register_dmsintc_device();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1224,6 +1224,8 @@ enum kvm_device_type {
|
||||
#define KVM_DEV_TYPE_LOONGARCH_EIOINTC KVM_DEV_TYPE_LOONGARCH_EIOINTC
|
||||
KVM_DEV_TYPE_LOONGARCH_PCHPIC,
|
||||
#define KVM_DEV_TYPE_LOONGARCH_PCHPIC KVM_DEV_TYPE_LOONGARCH_PCHPIC
|
||||
KVM_DEV_TYPE_LOONGARCH_DMSINTC,
|
||||
#define KVM_DEV_TYPE_LOONGARCH_DMSINTC KVM_DEV_TYPE_LOONGARCH_DMSINTC
|
||||
|
||||
KVM_DEV_TYPE_MAX,
|
||||
|
||||
|
||||
Reference in New Issue
Block a user