[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <2a573488-34ca-24c5-f165-658964b6f897@loongson.cn>
Date: Wed, 9 Jul 2025 17:10:09 +0800
From: Bibo Mao <maobibo@...ngson.cn>
To: Huacai Chen <chenhuacai@...nel.org>
Cc: Tianrui Zhao <zhaotianrui@...ngson.cn>,
Xianglai Li <lixianglai@...ngson.cn>, kvm@...r.kernel.org,
loongarch@...ts.linux.dev, linux-kernel@...r.kernel.org
Subject: Re: [PATCH v2] LoongArch: KVM: INTC: Add IOCSR MISC register
emulation
On 2025/7/9 下午4:59, Huacai Chen wrote:
> On Tue, Jul 1, 2025 at 7:40 PM Bibo Mao <maobibo@...ngson.cn> wrote:
>>
>>
>>
>> On 2025/7/1 下午5:20, Huacai Chen wrote:
>>> On Mon, Jun 30, 2025 at 4:44 PM Bibo Mao <maobibo@...ngson.cn> wrote:
>>>>
>>>>
>>>>
>>>> On 2025/6/30 下午4:04, Huacai Chen wrote:
>>>>> Hi, Bibo,
>>>>>
>>>>> On Thu, Jun 19, 2025 at 3:15 PM Bibo Mao <maobibo@...ngson.cn> wrote:
>>>>>>
>>>>>> 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.
>>>>> I found we can decouple the misc register and EIOINTC in addition:
>>>>> 1, Move misc.c out of intc directory;
>>>>> 2, Call kvm_loongarch_create_misc() in kvm_arch_init_vm();
>>>>> 3, Call kvm_loongarch_destroy_misc() in kvm_arch_destroy_vm();
>>>>> 4, Then maybe misc_created can be removed.
>>>> Now irqchip in kernel is optional, the same with misc register. Misc
>>>> register will be emulated in user VMM if kernel-irqchip option is off.
>>>>
>>>> There is no way to detect kernel-irqchip option when function
>>>> kvm_arch_init_vm() is called, and kvm_loongarch_create_misc() needs be
>>>> dynamically called from ioctl command.
>>> Can we use kvm_arch_irqchip_in_kernel() to detect?
>> No, it can not be used. kvm_arch_irqchip_in_kernel() is usable only when
>> irqchip is created in kernel, however kvm_arch_init_vm() is called when
>> VM is created.
>>
>> VM is created always before kernel irqchip is created. So
>> kvm_arch_irqchip_in_kernel() will return false if it is called in
>> kvm_arch_init_vm().
> What will happen if call kvm_loongarch_create_misc() in
> kvm_arch_init_vm() unconditionally?
If IOCSR misc is emualted in kernel unconditionally, however eiointc is
emulated in qemu. How does kernel misc emulate eiointc enabling command?
I really doubt whether you really understand KVM, please do not give
comments so easily if you do not understand.
Regards
Bibo Mao
>
> Huacai
>>
>> Regards
>> Bibo Mao
>>>
>>>
>>> Huacai
>>>
>>>>
>>>> Regards
>>>> Bibo Mao
>>>>>
>>>>> At last you can make this patch and others from another series to be a
>>>>> new series.
>>>>>
>>>>>
>>>>> Huacai
>>>>>
>>>>>>
>>>>>> 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