LoongArch: KVM: Add IPI device support
authorXianglai Li <lixianglai@loongson.cn>
Wed, 13 Nov 2024 08:18:27 +0000 (16:18 +0800)
committerHuacai Chen <chenhuacai@loongson.cn>
Wed, 13 Nov 2024 08:18:27 +0000 (16:18 +0800)
Add device model for IPI 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>
arch/loongarch/include/asm/kvm_host.h
arch/loongarch/include/asm/kvm_ipi.h [new file with mode: 0644]
arch/loongarch/kvm/Makefile
arch/loongarch/kvm/intc/ipi.c [new file with mode: 0644]
arch/loongarch/kvm/main.c
arch/loongarch/kvm/vcpu.c
include/uapi/linux/kvm.h

index d6bb724..8e5393d 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <asm/inst.h>
 #include <asm/kvm_mmu.h>
+#include <asm/kvm_ipi.h>
 #include <asm/loongarch.h>
 
 /* Loongarch KVM register ids */
@@ -117,6 +118,7 @@ struct kvm_arch {
 
        s64 time_offset;
        struct kvm_context __percpu *vmcs;
+       struct loongarch_ipi *ipi;
 };
 
 #define CSR_MAX_NUMS           0x800
@@ -221,6 +223,8 @@ struct kvm_vcpu_arch {
        int last_sched_cpu;
        /* mp state */
        struct kvm_mp_state mp_state;
+       /* ipi state */
+       struct ipi_state ipi_state;
        /* cpucfg */
        u32 cpucfg[KVM_MAX_CPUCFG_REGS];
 
diff --git a/arch/loongarch/include/asm/kvm_ipi.h b/arch/loongarch/include/asm/kvm_ipi.h
new file mode 100644 (file)
index 0000000..baaa625
--- /dev/null
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2024 Loongson Technology Corporation Limited
+ */
+
+#ifndef __ASM_KVM_IPI_H
+#define __ASM_KVM_IPI_H
+
+#include <kvm/iodev.h>
+
+#define LARCH_INT_IPI                  12
+
+struct loongarch_ipi {
+       spinlock_t lock;
+       struct kvm *kvm;
+       struct kvm_io_device device;
+};
+
+struct ipi_state {
+       spinlock_t lock;
+       uint32_t status;
+       uint32_t en;
+       uint32_t set;
+       uint32_t clear;
+       uint64_t buf[4];
+};
+
+#define IOCSR_IPI_BASE         0x1000
+#define IOCSR_IPI_SIZE         0x160
+
+int kvm_loongarch_register_ipi_device(void);
+
+#endif
index b2f4cbe..36c3009 100644 (file)
@@ -18,5 +18,6 @@ kvm-y += timer.o
 kvm-y += tlb.o
 kvm-y += vcpu.o
 kvm-y += vm.o
+kvm-y += intc/ipi.o
 
 CFLAGS_exit.o  += $(call cc-option,-Wno-override-init,)
diff --git a/arch/loongarch/kvm/intc/ipi.c b/arch/loongarch/kvm/intc/ipi.c
new file mode 100644 (file)
index 0000000..9e45571
--- /dev/null
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2024 Loongson Technology Corporation Limited
+ */
+
+#include <linux/kvm_host.h>
+#include <asm/kvm_ipi.h>
+#include <asm/kvm_vcpu.h>
+
+static int kvm_ipi_read(struct kvm_vcpu *vcpu,
+                       struct kvm_io_device *dev,
+                       gpa_t addr, int len, void *val)
+{
+       return 0;
+}
+
+static int kvm_ipi_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_ipi_ops = {
+       .read   = kvm_ipi_read,
+       .write  = kvm_ipi_write,
+};
+
+static int kvm_ipi_get_attr(struct kvm_device *dev,
+                       struct kvm_device_attr *attr)
+{
+       return 0;
+}
+
+static int kvm_ipi_set_attr(struct kvm_device *dev,
+                       struct kvm_device_attr *attr)
+{
+       return 0;
+}
+
+static int kvm_ipi_create(struct kvm_device *dev, u32 type)
+{
+       int ret;
+       struct kvm *kvm;
+       struct kvm_io_device *device;
+       struct loongarch_ipi *s;
+
+       if (!dev) {
+               kvm_err("%s: kvm_device ptr is invalid!\n", __func__);
+               return -EINVAL;
+       }
+
+       kvm = dev->kvm;
+       if (kvm->arch.ipi) {
+               kvm_err("%s: LoongArch IPI has already been created!\n", __func__);
+               return -EINVAL;
+       }
+
+       s = kzalloc(sizeof(struct loongarch_ipi), 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_ipi_ops);
+       mutex_lock(&kvm->slots_lock);
+       ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS, IOCSR_IPI_BASE, IOCSR_IPI_SIZE, device);
+       mutex_unlock(&kvm->slots_lock);
+       if (ret < 0) {
+               kvm_err("%s: Initialize IOCSR dev failed, ret = %d\n", __func__, ret);
+               goto err;
+       }
+
+       kvm->arch.ipi = s;
+       return 0;
+
+err:
+       kfree(s);
+       return -EFAULT;
+}
+
+static void kvm_ipi_destroy(struct kvm_device *dev)
+{
+       struct kvm *kvm;
+       struct loongarch_ipi *ipi;
+
+       if (!dev || !dev->kvm || !dev->kvm->arch.ipi)
+               return;
+
+       kvm = dev->kvm;
+       ipi = kvm->arch.ipi;
+       kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &ipi->device);
+       kfree(ipi);
+}
+
+static struct kvm_device_ops kvm_ipi_dev_ops = {
+       .name = "kvm-loongarch-ipi",
+       .create = kvm_ipi_create,
+       .destroy = kvm_ipi_destroy,
+       .set_attr = kvm_ipi_set_attr,
+       .get_attr = kvm_ipi_get_attr,
+};
+
+int kvm_loongarch_register_ipi_device(void)
+{
+       return kvm_register_device_ops(&kvm_ipi_dev_ops, KVM_DEV_TYPE_LOONGARCH_IPI);
+}
index 27e9b94..14f3f69 100644 (file)
@@ -313,7 +313,7 @@ void kvm_arch_disable_virtualization_cpu(void)
 
 static int kvm_loongarch_env_init(void)
 {
-       int cpu, order;
+       int cpu, order, ret;
        void *addr;
        struct kvm_context *context;
 
@@ -368,7 +368,10 @@ static int kvm_loongarch_env_init(void)
 
        kvm_init_gcsr_flag();
 
-       return 0;
+       /* Register LoongArch IPI interrupt controller interface. */
+       ret = kvm_loongarch_register_ipi_device();
+
+       return ret;
 }
 
 static void kvm_loongarch_env_exit(void)
index 174734a..cab1818 100644 (file)
@@ -1475,6 +1475,9 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
        /* Init */
        vcpu->arch.last_sched_cpu = -1;
 
+       /* Init ipi_state lock */
+       spin_lock_init(&vcpu->arch.ipi_state.lock);
+
        /*
         * Initialize guest register state to valid architectural reset state.
         */
index 637efc0..9fff439 100644 (file)
@@ -1158,7 +1158,11 @@ enum kvm_device_type {
 #define KVM_DEV_TYPE_ARM_PV_TIME       KVM_DEV_TYPE_ARM_PV_TIME
        KVM_DEV_TYPE_RISCV_AIA,
 #define KVM_DEV_TYPE_RISCV_AIA         KVM_DEV_TYPE_RISCV_AIA
+       KVM_DEV_TYPE_LOONGARCH_IPI,
+#define KVM_DEV_TYPE_LOONGARCH_IPI     KVM_DEV_TYPE_LOONGARCH_IPI
+
        KVM_DEV_TYPE_MAX,
+
 };
 
 struct kvm_vfio_spapr_tce {