[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20250619071449.1714869-1-maobibo@loongson.cn>
Date: Thu, 19 Jun 2025 15:14:49 +0800
From: Bibo Mao <maobibo@...ngson.cn>
To: Tianrui Zhao <zhaotianrui@...ngson.cn>,
Huacai Chen <chenhuacai@...nel.org>,
Xianglai Li <lixianglai@...ngson.cn>
Cc: kvm@...r.kernel.org,
loongarch@...ts.linux.dev,
linux-kernel@...r.kernel.org
Subject: [PATCH v2] LoongArch: KVM: INTC: Add IOCSR MISC register emulation
IOCSR MISC register 0x420 controlls some features of eiointc, such as
BIT 48 enables eiointc and BIT 49 set interrupt encoding mode.
When kernel irqchip is set, IOCSR MISC register should be emulated in
kernel also. Here add IOCSR MISC register emulation in kernel side.
Signed-off-by: Bibo Mao <maobibo@...ngson.cn>
---
v1 ... v2:
1. Add separate file arch/loongarch/kvm/intc/misc.c for IOCSR MISC
register 0x420 emulation, since it controls feature about AVEC
irqchip also.
2. Define macro MISC_BASE as LOONGARCH_IOCSR_MISC_FUNC rather than
hard coded 0x420
---
arch/loongarch/include/asm/kvm_eiointc.h | 2 +
arch/loongarch/include/asm/kvm_host.h | 2 +
arch/loongarch/include/asm/kvm_misc.h | 17 +++
arch/loongarch/include/asm/loongarch.h | 1 +
arch/loongarch/kvm/Makefile | 1 +
arch/loongarch/kvm/intc/eiointc.c | 61 +++++++++++
arch/loongarch/kvm/intc/misc.c | 125 +++++++++++++++++++++++
7 files changed, 209 insertions(+)
create mode 100644 arch/loongarch/include/asm/kvm_misc.h
create mode 100644 arch/loongarch/kvm/intc/misc.c
diff --git a/arch/loongarch/include/asm/kvm_eiointc.h b/arch/loongarch/include/asm/kvm_eiointc.h
index a3a40aba8acf..2d1c183f2b1b 100644
--- a/arch/loongarch/include/asm/kvm_eiointc.h
+++ b/arch/loongarch/include/asm/kvm_eiointc.h
@@ -119,5 +119,7 @@ struct loongarch_eiointc {
int kvm_loongarch_register_eiointc_device(void);
void eiointc_set_irq(struct loongarch_eiointc *s, int irq, int level);
+int kvm_eiointc_get_status(struct kvm_vcpu *vcpu, unsigned long *value);
+int kvm_eiointc_update_status(struct kvm_vcpu *vcpu, unsigned long value, unsigned long mask);
#endif /* __ASM_KVM_EIOINTC_H */
diff --git a/arch/loongarch/include/asm/kvm_host.h b/arch/loongarch/include/asm/kvm_host.h
index a3c4cc46c892..f463ec52d86c 100644
--- a/arch/loongarch/include/asm/kvm_host.h
+++ b/arch/loongarch/include/asm/kvm_host.h
@@ -132,6 +132,8 @@ struct kvm_arch {
struct loongarch_ipi *ipi;
struct loongarch_eiointc *eiointc;
struct loongarch_pch_pic *pch_pic;
+ struct kvm_io_device misc;
+ bool misc_created;
};
#define CSR_MAX_NUMS 0x800
diff --git a/arch/loongarch/include/asm/kvm_misc.h b/arch/loongarch/include/asm/kvm_misc.h
new file mode 100644
index 000000000000..621e4228dea2
--- /dev/null
+++ b/arch/loongarch/include/asm/kvm_misc.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2025 Loongson Technology Corporation Limited
+ */
+
+#ifndef __ASM_KVM_MISC_H
+#define __ASM_KVM_MISC_H
+
+#include <asm/loongarch.h>
+
+#define MISC_BASE LOONGARCH_IOCSR_MISC_FUNC
+#define MISC_SIZE 0x8
+
+int kvm_loongarch_create_misc(struct kvm *kvm);
+void kvm_loongarch_destroy_misc(struct kvm *kvm);
+
+#endif /* __ASM_KVM_MISC_H */
diff --git a/arch/loongarch/include/asm/loongarch.h b/arch/loongarch/include/asm/loongarch.h
index d84dac88a584..e30d330d497e 100644
--- a/arch/loongarch/include/asm/loongarch.h
+++ b/arch/loongarch/include/asm/loongarch.h
@@ -1141,6 +1141,7 @@
#define IOCSR_MISC_FUNC_SOFT_INT BIT_ULL(10)
#define IOCSR_MISC_FUNC_TIMER_RESET BIT_ULL(21)
#define IOCSR_MISC_FUNC_EXT_IOI_EN BIT_ULL(48)
+#define IOCSR_MISC_FUNC_INT_ENCODE BIT_ULL(49)
#define IOCSR_MISC_FUNC_AVEC_EN BIT_ULL(51)
#define LOONGARCH_IOCSR_CPUTEMP 0x428
diff --git a/arch/loongarch/kvm/Makefile b/arch/loongarch/kvm/Makefile
index cb41d9265662..25fa3866613d 100644
--- a/arch/loongarch/kvm/Makefile
+++ b/arch/loongarch/kvm/Makefile
@@ -18,6 +18,7 @@ kvm-y += vcpu.o
kvm-y += vm.o
kvm-y += intc/ipi.o
kvm-y += intc/eiointc.o
+kvm-y += intc/misc.o
kvm-y += intc/pch_pic.o
kvm-y += irqfd.o
diff --git a/arch/loongarch/kvm/intc/eiointc.c b/arch/loongarch/kvm/intc/eiointc.c
index f39929d7bf8a..87d01521e92f 100644
--- a/arch/loongarch/kvm/intc/eiointc.c
+++ b/arch/loongarch/kvm/intc/eiointc.c
@@ -4,6 +4,7 @@
*/
#include <asm/kvm_eiointc.h>
+#include <asm/kvm_misc.h>
#include <asm/kvm_vcpu.h>
#include <linux/count_zeros.h>
@@ -708,6 +709,56 @@ static const struct kvm_io_device_ops kvm_eiointc_ops = {
.write = kvm_eiointc_write,
};
+int kvm_eiointc_get_status(struct kvm_vcpu *vcpu, unsigned long *value)
+{
+ unsigned long data, flags;
+ struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc;
+
+ if (!eiointc) {
+ kvm_err("%s: eiointc irqchip not valid!\n", __func__);
+ return -EINVAL;
+ }
+
+ data = 0;
+ spin_lock_irqsave(&eiointc->lock, flags);
+ if (eiointc->status & BIT(EIOINTC_ENABLE))
+ data |= IOCSR_MISC_FUNC_EXT_IOI_EN;
+
+ if (eiointc->status & BIT(EIOINTC_ENABLE_INT_ENCODE))
+ data |= IOCSR_MISC_FUNC_INT_ENCODE;
+ spin_unlock_irqrestore(&eiointc->lock, flags);
+
+ *value = data;
+ return 0;
+}
+
+int kvm_eiointc_update_status(struct kvm_vcpu *vcpu, unsigned long value, unsigned long mask)
+{
+ struct loongarch_eiointc *eiointc = vcpu->kvm->arch.eiointc;
+ unsigned long old, flags;
+
+ if (!eiointc) {
+ kvm_err("%s: eiointc irqchip not valid!\n", __func__);
+ return -EINVAL;
+ }
+
+ old = 0;
+ spin_lock_irqsave(&eiointc->lock, flags);
+ if (eiointc->status & BIT(EIOINTC_ENABLE))
+ old |= IOCSR_MISC_FUNC_EXT_IOI_EN;
+ if (eiointc->status & BIT(EIOINTC_ENABLE_INT_ENCODE))
+ old |= IOCSR_MISC_FUNC_INT_ENCODE;
+
+ value |= (old & ~mask);
+ eiointc->status &= ~(BIT(EIOINTC_ENABLE_INT_ENCODE) | BIT(EIOINTC_ENABLE));
+ if (value & IOCSR_MISC_FUNC_INT_ENCODE)
+ eiointc->status |= BIT(EIOINTC_ENABLE_INT_ENCODE);
+ if (value & IOCSR_MISC_FUNC_EXT_IOI_EN)
+ eiointc->status |= BIT(EIOINTC_ENABLE);
+ spin_unlock_irqrestore(&eiointc->lock, flags);
+ return 0;
+}
+
static int kvm_eiointc_virt_read(struct kvm_vcpu *vcpu,
struct kvm_io_device *dev,
gpa_t addr, int len, void *val)
@@ -993,6 +1044,15 @@ static int kvm_eiointc_create(struct kvm_device *dev, u32 type)
kfree(s);
return ret;
}
+
+ ret = kvm_loongarch_create_misc(kvm);
+ if (ret < 0) {
+ kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &s->device);
+ kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, &s->device_vext);
+ kfree(s);
+ return ret;
+ }
+
kvm->arch.eiointc = s;
return 0;
@@ -1010,6 +1070,7 @@ static void kvm_eiointc_destroy(struct kvm_device *dev)
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);
+ kvm_loongarch_destroy_misc(kvm);
kfree(eiointc);
}
diff --git a/arch/loongarch/kvm/intc/misc.c b/arch/loongarch/kvm/intc/misc.c
new file mode 100644
index 000000000000..edee66afa36e
--- /dev/null
+++ b/arch/loongarch/kvm/intc/misc.c
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2025 Loongson Technology Corporation Limited
+ */
+#include <asm/kvm_vcpu.h>
+#include <asm/kvm_eiointc.h>
+#include <asm/kvm_misc.h>
+
+static int kvm_misc_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+ gpa_t addr, int len, void *val)
+{
+ unsigned long data;
+ unsigned int ret;
+
+ addr -= MISC_BASE;
+ if (addr & (len - 1)) {
+ kvm_err("%s: eiointc not aligned addr %llx len %d\n", __func__, addr, len);
+ return -EINVAL;
+ }
+
+ ret = kvm_eiointc_get_status(vcpu, &data);
+ if (ret)
+ return ret;
+
+ data = data >> ((addr & 7) * 8);
+ switch (len) {
+ case 1:
+ *(unsigned char *)val = (unsigned char)data;
+ break;
+
+ case 2:
+ *(unsigned short *)val = (unsigned short)data;
+ break;
+
+ case 4:
+ *(unsigned int *)val = (unsigned int)data;
+ break;
+
+ default:
+ *(unsigned long *)val = data;
+ break;
+ }
+
+ return 0;
+}
+
+static int kvm_misc_write(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
+ gpa_t addr, int len, const void *val)
+{
+ unsigned long data, mask;
+ unsigned int shift;
+
+ addr -= MISC_BASE;
+ if (addr & (len - 1)) {
+ kvm_err("%s: eiointc not aligned addr %llx len %d\n", __func__, addr, len);
+ return -EINVAL;
+ }
+
+ shift = (addr & 7) * 8;
+ switch (len) {
+ case 1:
+ data = *(unsigned char *)val;
+ mask = 0xFF;
+ mask = mask << shift;
+ data = data << shift;
+ break;
+
+ case 2:
+ data = *(unsigned short *)val;
+ mask = 0xFFFF;
+ mask = mask << shift;
+ data = data << shift;
+ break;
+
+ case 4:
+ data = *(unsigned int *)val;
+ mask = UINT_MAX;
+ mask = mask << shift;
+ data = data << shift;
+ break;
+
+ default:
+ data = *(unsigned long *)val;
+ mask = ULONG_MAX;
+ mask = mask << shift;
+ data = data << shift;
+ break;
+ }
+
+ return kvm_eiointc_update_status(vcpu, data, mask);
+}
+
+static const struct kvm_io_device_ops kvm_misc_ops = {
+ .read = kvm_misc_read,
+ .write = kvm_misc_write,
+};
+
+int kvm_loongarch_create_misc(struct kvm *kvm)
+{
+ struct kvm_io_device *device;
+ int ret;
+
+ if (kvm->arch.misc_created)
+ return 0;
+
+ device = &kvm->arch.misc;
+ kvm_iodevice_init(device, &kvm_misc_ops);
+ ret = kvm_io_bus_register_dev(kvm, KVM_IOCSR_BUS, MISC_BASE, MISC_SIZE, device);
+ if (ret < 0)
+ return ret;
+
+ kvm->arch.misc_created = true;
+ return 0;
+}
+
+void kvm_loongarch_destroy_misc(struct kvm *kvm)
+{
+ struct kvm_io_device *device;
+
+ if (kvm->arch.misc_created) {
+ device = &kvm->arch.misc;
+ kvm_io_bus_unregister_dev(kvm, KVM_IOCSR_BUS, device);
+ kvm->arch.misc_created = false;
+ }
+}
base-commit: 52da431bf03b5506203bca27fe14a97895c80faf
--
2.39.3
Powered by blists - more mailing lists