lkml.org 
[lkml]   [2023]   [Aug]   [31]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v20 12/30] LoongArch: KVM: Implement vcpu interrupt operations
    Date
    Implement vcpu interrupt operations such as vcpu set irq and
    vcpu clear irq, using set_gcsr_estat to set irq which is
    parsed by the irq bitmap.

    Reviewed-by: Bibo Mao <maobibo@loongson.cn>
    Signed-off-by: Tianrui Zhao <zhaotianrui@loongson.cn>
    ---
    arch/loongarch/kvm/interrupt.c | 113 +++++++++++++++++++++++++++++++++
    arch/loongarch/kvm/vcpu.c | 37 +++++++++++
    2 files changed, 150 insertions(+)
    create mode 100644 arch/loongarch/kvm/interrupt.c

    diff --git a/arch/loongarch/kvm/interrupt.c b/arch/loongarch/kvm/interrupt.c
    new file mode 100644
    index 0000000000..14e19653b2
    --- /dev/null
    +++ b/arch/loongarch/kvm/interrupt.c
    @@ -0,0 +1,113 @@
    +// SPDX-License-Identifier: GPL-2.0
    +/*
    + * Copyright (C) 2020-2023 Loongson Technology Corporation Limited
    + */
    +
    +#include <linux/errno.h>
    +#include <linux/err.h>
    +#include <asm/kvm_vcpu.h>
    +#include <asm/kvm_csr.h>
    +
    +static unsigned int int_to_coreint[EXCCODE_INT_NUM] = {
    + [INT_TI] = CPU_TIMER,
    + [INT_IPI] = CPU_IPI,
    + [INT_SWI0] = CPU_SIP0,
    + [INT_SWI1] = CPU_SIP1,
    + [INT_HWI0] = CPU_IP0,
    + [INT_HWI1] = CPU_IP1,
    + [INT_HWI2] = CPU_IP2,
    + [INT_HWI3] = CPU_IP3,
    + [INT_HWI4] = CPU_IP4,
    + [INT_HWI5] = CPU_IP5,
    + [INT_HWI6] = CPU_IP6,
    + [INT_HWI7] = CPU_IP7,
    +};
    +
    +static int _kvm_irq_deliver(struct kvm_vcpu *vcpu, unsigned int priority)
    +{
    + unsigned int irq = 0;
    +
    + clear_bit(priority, &vcpu->arch.irq_pending);
    + if (priority < EXCCODE_INT_NUM)
    + irq = int_to_coreint[priority];
    +
    + switch (priority) {
    + case INT_TI:
    + case INT_IPI:
    + case INT_SWI0:
    + case INT_SWI1:
    + set_gcsr_estat(irq);
    + break;
    +
    + case INT_HWI0 ... INT_HWI7:
    + set_csr_gintc(irq);
    + break;
    +
    + default:
    + break;
    + }
    +
    + return 1;
    +}
    +
    +static int _kvm_irq_clear(struct kvm_vcpu *vcpu, unsigned int priority)
    +{
    + unsigned int irq = 0;
    +
    + clear_bit(priority, &vcpu->arch.irq_clear);
    + if (priority < EXCCODE_INT_NUM)
    + irq = int_to_coreint[priority];
    +
    + switch (priority) {
    + case INT_TI:
    + case INT_IPI:
    + case INT_SWI0:
    + case INT_SWI1:
    + clear_gcsr_estat(irq);
    + break;
    +
    + case INT_HWI0 ... INT_HWI7:
    + clear_csr_gintc(irq);
    + break;
    +
    + default:
    + break;
    + }
    +
    + return 1;
    +}
    +
    +void _kvm_deliver_intr(struct kvm_vcpu *vcpu)
    +{
    + unsigned long *pending = &vcpu->arch.irq_pending;
    + unsigned long *pending_clr = &vcpu->arch.irq_clear;
    + unsigned int priority;
    +
    + if (!(*pending) && !(*pending_clr))
    + return;
    +
    + if (*pending_clr) {
    + priority = __ffs(*pending_clr);
    + while (priority <= INT_IPI) {
    + _kvm_irq_clear(vcpu, priority);
    + priority = find_next_bit(pending_clr,
    + BITS_PER_BYTE * sizeof(*pending_clr),
    + priority + 1);
    + }
    + }
    +
    + if (*pending) {
    + priority = __ffs(*pending);
    + while (priority <= INT_IPI) {
    + _kvm_irq_deliver(vcpu, priority);
    + priority = find_next_bit(pending,
    + BITS_PER_BYTE * sizeof(*pending),
    + priority + 1);
    + }
    + }
    +}
    +
    +int _kvm_pending_timer(struct kvm_vcpu *vcpu)
    +{
    + return test_bit(INT_TI, &vcpu->arch.irq_pending);
    +}
    diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c
    index 2094afcfcd..9e36482c53 100644
    --- a/arch/loongarch/kvm/vcpu.c
    +++ b/arch/loongarch/kvm/vcpu.c
    @@ -298,6 +298,43 @@ void kvm_lose_fpu(struct kvm_vcpu *vcpu)
    preempt_enable();
    }

    +int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq)
    +{
    + int intr = (int)irq->irq;
    +
    + if (intr > 0)
    + _kvm_queue_irq(vcpu, intr);
    + else if (intr < 0)
    + _kvm_dequeue_irq(vcpu, -intr);
    + else {
    + kvm_err("%s: invalid interrupt ioctl %d\n", __func__, irq->irq);
    + return -EINVAL;
    + }
    +
    + kvm_vcpu_kick(vcpu);
    + return 0;
    +}
    +
    +long kvm_arch_vcpu_async_ioctl(struct file *filp,
    + unsigned int ioctl, unsigned long arg)
    +{
    + struct kvm_vcpu *vcpu = filp->private_data;
    + void __user *argp = (void __user *)arg;
    +
    + if (ioctl == KVM_INTERRUPT) {
    + struct kvm_interrupt irq;
    +
    + if (copy_from_user(&irq, argp, sizeof(irq)))
    + return -EFAULT;
    +
    + kvm_debug("[%d] %s: irq: %d\n", vcpu->vcpu_id, __func__, irq.irq);
    +
    + return kvm_vcpu_ioctl_interrupt(vcpu, &irq);
    + }
    +
    + return -ENOIOCTLCMD;
    +}
    +
    int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
    {
    return 0;
    --
    2.27.0
    \
     
     \ /
      Last update: 2023-08-31 10:31    [W:4.163 / U:0.136 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site