Re: [PATCH V3 09/14] KVM: MIPS: Add more types of virtual interrupts

Aleksandar Markovic
2020-05-08T11:48:16Z

нед, 3. мај 2020. у 12:13 Huacai Chen <chenhc@lemote.com> је написао/ла:
>
> In current implementation, MIPS KVM uses IP2, IP3, IP4 and IP7 for
> external interrupt, two kinds of IPIs and timer interrupt respectively,
> but Loongson-3 based machines prefer to use IP2, IP3, IP6 and IP7 for
> two kinds of external interrupts, IPI and timer interrupt. So we define
> two priority-irq mapping tables: kvm_loongson3_priority_to_irq[] for
> Loongson-3, and kvm_default_priority_to_irq[] for others. The virtual
> interrupt infrastructure is updated to deliver all types of interrupts
> from IP2, IP3, IP4, IP6 and IP7.
>
> Signed-off-by: Huacai Chen <chenhc@lemote.com>
> Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
> ---
> arch/mips/kvm/interrupt.c | 93 +++++++----------------------------------------
> arch/mips/kvm/interrupt.h | 14 ++++---
> arch/mips/kvm/mips.c | 40 ++++++++++++++++++--
> arch/mips/kvm/vz.c | 53 ++++-----------------------
> 4 files changed, 67 insertions(+), 133 deletions(-)
>
> diff --git a/arch/mips/kvm/interrupt.c b/arch/mips/kvm/interrupt.c
> index 7257e8b6..d28c2c9c 100644
> --- a/arch/mips/kvm/interrupt.c
> +++ b/arch/mips/kvm/interrupt.c
> @@ -61,27 +61,8 @@ void kvm_mips_queue_io_int_cb(struct kvm_vcpu *vcpu,
> * the EXC code will be set when we are actually
> * delivering the interrupt:
> */
> - switch (intr) {
> - case 2:
> - kvm_set_c0_guest_cause(vcpu->arch.cop0, (C_IRQ0));
> - /* Queue up an INT exception for the core */
> - kvm_mips_queue_irq(vcpu, MIPS_EXC_INT_IO);
> - break;
> -
> - case 3:
> - kvm_set_c0_guest_cause(vcpu->arch.cop0, (C_IRQ1));
> - kvm_mips_queue_irq(vcpu, MIPS_EXC_INT_IPI_1);
> - break;
> -
> - case 4:
> - kvm_set_c0_guest_cause(vcpu->arch.cop0, (C_IRQ2));
> - kvm_mips_queue_irq(vcpu, MIPS_EXC_INT_IPI_2);
> - break;
> -
> - default:
> - break;
> - }
> -
> + kvm_set_c0_guest_cause(vcpu->arch.cop0, 1 << (intr + 8));
> + kvm_mips_queue_irq(vcpu, kvm_irq_to_priority(intr));
> }
>
> void kvm_mips_dequeue_io_int_cb(struct kvm_vcpu *vcpu,
> @@ -89,26 +70,8 @@ void kvm_mips_dequeue_io_int_cb(struct kvm_vcpu *vcpu,
> {
> int intr = (int)irq->irq;
>
> - switch (intr) {
> - case -2:
> - kvm_clear_c0_guest_cause(vcpu->arch.cop0, (C_IRQ0));
> - kvm_mips_dequeue_irq(vcpu, MIPS_EXC_INT_IO);
> - break;
> -
> - case -3:
> - kvm_clear_c0_guest_cause(vcpu->arch.cop0, (C_IRQ1));
> - kvm_mips_dequeue_irq(vcpu, MIPS_EXC_INT_IPI_1);
> - break;
> -
> - case -4:
> - kvm_clear_c0_guest_cause(vcpu->arch.cop0, (C_IRQ2));
> - kvm_mips_dequeue_irq(vcpu, MIPS_EXC_INT_IPI_2);
> - break;
> -
> - default:
> - break;
> - }
> -
> + kvm_clear_c0_guest_cause(vcpu->arch.cop0, 1 << (-intr + 8));
> + kvm_mips_dequeue_irq(vcpu, kvm_irq_to_priority(-intr));
> }
>
> /* Deliver the interrupt of the corresponding priority, if possible. */
> @@ -116,50 +79,20 @@ int kvm_mips_irq_deliver_cb(struct kvm_vcpu *vcpu, unsigned int priority,
> u32 cause)
> {
> int allowed = 0;
> - u32 exccode;
> + u32 exccode, ie;
>
> struct kvm_vcpu_arch *arch = &vcpu->arch;
> struct mips_coproc *cop0 = vcpu->arch.cop0;
>
> - switch (priority) {
> - case MIPS_EXC_INT_TIMER:
> - if ((kvm_read_c0_guest_status(cop0) & ST0_IE)
> - && (!(kvm_read_c0_guest_status(cop0) & (ST0_EXL | ST0_ERL)))
> - && (kvm_read_c0_guest_status(cop0) & IE_IRQ5)) {
> - allowed = 1;
> - exccode = EXCCODE_INT;
> - }
> - break;
> -
> - case MIPS_EXC_INT_IO:
> - if ((kvm_read_c0_guest_status(cop0) & ST0_IE)
> - && (!(kvm_read_c0_guest_status(cop0) & (ST0_EXL | ST0_ERL)))
> - && (kvm_read_c0_guest_status(cop0) & IE_IRQ0)) {
> - allowed = 1;
> - exccode = EXCCODE_INT;
> - }
> - break;
> -
> - case MIPS_EXC_INT_IPI_1:
> - if ((kvm_read_c0_guest_status(cop0) & ST0_IE)
> - && (!(kvm_read_c0_guest_status(cop0) & (ST0_EXL | ST0_ERL)))
> - && (kvm_read_c0_guest_status(cop0) & IE_IRQ1)) {
> - allowed = 1;
> - exccode = EXCCODE_INT;
> - }
> - break;
> -
> - case MIPS_EXC_INT_IPI_2:
> - if ((kvm_read_c0_guest_status(cop0) & ST0_IE)
> - && (!(kvm_read_c0_guest_status(cop0) & (ST0_EXL | ST0_ERL)))
> - && (kvm_read_c0_guest_status(cop0) & IE_IRQ2)) {
> - allowed = 1;
> - exccode = EXCCODE_INT;
> - }
> - break;
> + if (priority == MIPS_EXC_MAX)
> + return 0;
>
> - default:
> - break;
> + ie = 1 << (kvm_priority_to_irq[priority] + 8);
> + if ((kvm_read_c0_guest_status(cop0) & ST0_IE)
> + && (!(kvm_read_c0_guest_status(cop0) & (ST0_EXL | ST0_ERL)))
> + && (kvm_read_c0_guest_status(cop0) & ie)) {
> + allowed = 1;
> + exccode = EXCCODE_INT;
> }
>
> /* Are we allowed to deliver the interrupt ??? */
> diff --git a/arch/mips/kvm/interrupt.h b/arch/mips/kvm/interrupt.h
> index 3bf0a49..c3e878c 100644
> --- a/arch/mips/kvm/interrupt.h
> +++ b/arch/mips/kvm/interrupt.h
> @@ -21,11 +21,12 @@
> #define MIPS_EXC_NMI 5
> #define MIPS_EXC_MCHK 6
> #define MIPS_EXC_INT_TIMER 7
> -#define MIPS_EXC_INT_IO 8
> -#define MIPS_EXC_EXECUTE 9
> -#define MIPS_EXC_INT_IPI_1 10
> -#define MIPS_EXC_INT_IPI_2 11
> -#define MIPS_EXC_MAX 12
> +#define MIPS_EXC_INT_IO_1 8
> +#define MIPS_EXC_INT_IO_2 9
> +#define MIPS_EXC_EXECUTE 10
> +#define MIPS_EXC_INT_IPI_1 11
> +#define MIPS_EXC_INT_IPI_2 12
> +#define MIPS_EXC_MAX 13
> /* XXXSL More to follow */
>
> #define C_TI (_ULCAST_(1) << 30)
> @@ -38,6 +39,9 @@
> #define KVM_MIPS_IRQ_CLEAR_ALL_AT_ONCE (0)
> #endif
>
> +extern u32 *kvm_priority_to_irq;
> +u32 kvm_irq_to_priority(u32 irq);
> +
> void kvm_mips_queue_irq(struct kvm_vcpu *vcpu, unsigned int priority);
> void kvm_mips_dequeue_irq(struct kvm_vcpu *vcpu, unsigned int priority);
> int kvm_mips_pending_timer(struct kvm_vcpu *vcpu);
> diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c
> index 8f05dd0..5ca122c 100644
> --- a/arch/mips/kvm/mips.c
> +++ b/arch/mips/kvm/mips.c
> @@ -489,7 +489,10 @@ int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
> int intr = (int)irq->irq;
> struct kvm_vcpu *dvcpu = NULL;
>
> - if (intr == 3 || intr == -3 || intr == 4 || intr == -4)
> + if (intr == kvm_priority_to_irq[MIPS_EXC_INT_IPI_1] ||
> + intr == kvm_priority_to_irq[MIPS_EXC_INT_IPI_2] ||
> + intr == (-kvm_priority_to_irq[MIPS_EXC_INT_IPI_1]) ||
> + intr == (-kvm_priority_to_irq[MIPS_EXC_INT_IPI_2]))
> kvm_debug("%s: CPU: %d, INTR: %d\n", __func__, irq->cpu,
> (int)intr);
>
> @@ -498,10 +501,10 @@ int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
> else
> dvcpu = vcpu->kvm->vcpus[irq->cpu];
>
> - if (intr == 2 || intr == 3 || intr == 4) {
> + if (intr == 2 || intr == 3 || intr == 4 || intr == 6) {
> kvm_mips_callbacks->queue_io_int(dvcpu, irq);
>
> - } else if (intr == -2 || intr == -3 || intr == -4) {
> + } else if (intr == -2 || intr == -3 || intr == -4 || intr == -6) {
> kvm_mips_callbacks->dequeue_io_int(dvcpu, irq);
> } else {
> kvm_err("%s: invalid interrupt ioctl (%d:%d)\n", __func__,
> @@ -1620,6 +1623,34 @@ static struct notifier_block kvm_mips_csr_die_notifier = {
> .notifier_call = kvm_mips_csr_die_notify,
> };
>
> +static u32 kvm_default_priority_to_irq[MIPS_EXC_MAX] = {
> + [MIPS_EXC_INT_TIMER] = C_IRQ5,
> + [MIPS_EXC_INT_IO_1] = C_IRQ0,
> + [MIPS_EXC_INT_IPI_1] = C_IRQ1,
> + [MIPS_EXC_INT_IPI_2] = C_IRQ2,
> +};
> +
> +static u32 kvm_loongson3_priority_to_irq[MIPS_EXC_MAX] = {
> + [MIPS_EXC_INT_TIMER] = C_IRQ5,
> + [MIPS_EXC_INT_IO_1] = C_IRQ0,
> + [MIPS_EXC_INT_IO_2] = C_IRQ1,
> + [MIPS_EXC_INT_IPI_1] = C_IRQ4,
> +};
> +
> +u32 *kvm_priority_to_irq = kvm_default_priority_to_irq;
> +
> +u32 kvm_irq_to_priority(u32 irq)
> +{
> + int i;
> +
> + for (i = MIPS_EXC_INT_TIMER; i < MIPS_EXC_MAX; i++) {
> + if (kvm_priority_to_irq[i] == (1 << (irq + 8)))
> + return i;
> + }
> +
> + return MIPS_EXC_MAX;
> +}
> +
> static int __init kvm_mips_init(void)
> {
> int ret;
> @@ -1638,6 +1669,9 @@ static int __init kvm_mips_init(void)
> if (ret)
> return ret;
>
> + if (boot_cpu_type() == CPU_LOONGSON64)
> + kvm_priority_to_irq = kvm_loongson3_priority_to_irq;
> +
> register_die_notifier(&kvm_mips_csr_die_notifier);
>
> return 0;
> diff --git a/arch/mips/kvm/vz.c b/arch/mips/kvm/vz.c
> index ab320f0..63d5b35 100644
> --- a/arch/mips/kvm/vz.c
> +++ b/arch/mips/kvm/vz.c
> @@ -225,23 +225,7 @@ static void kvm_vz_queue_io_int_cb(struct kvm_vcpu *vcpu,
> * interrupts are asynchronous to vcpu execution therefore defer guest
> * cp0 accesses
> */
> - switch (intr) {
> - case 2:
> - kvm_vz_queue_irq(vcpu, MIPS_EXC_INT_IO);
> - break;
> -
> - case 3:
> - kvm_vz_queue_irq(vcpu, MIPS_EXC_INT_IPI_1);
> - break;
> -
> - case 4:
> - kvm_vz_queue_irq(vcpu, MIPS_EXC_INT_IPI_2);
> - break;
> -
> - default:
> - break;
> - }
> -
> + kvm_vz_queue_irq(vcpu, kvm_irq_to_priority(intr));
> }
>
> static void kvm_vz_dequeue_io_int_cb(struct kvm_vcpu *vcpu,
> @@ -253,44 +237,22 @@ static void kvm_vz_dequeue_io_int_cb(struct kvm_vcpu *vcpu,
> * interrupts are asynchronous to vcpu execution therefore defer guest
> * cp0 accesses
> */
> - switch (intr) {
> - case -2:
> - kvm_vz_dequeue_irq(vcpu, MIPS_EXC_INT_IO);
> - break;
> -
> - case -3:
> - kvm_vz_dequeue_irq(vcpu, MIPS_EXC_INT_IPI_1);
> - break;
> -
> - case -4:
> - kvm_vz_dequeue_irq(vcpu, MIPS_EXC_INT_IPI_2);
> - break;
> -
> - default:
> - break;
> - }
> -
> + kvm_vz_dequeue_irq(vcpu, kvm_irq_to_priority(-intr));
> }
>
> -static u32 kvm_vz_priority_to_irq[MIPS_EXC_MAX] = {
> - [MIPS_EXC_INT_TIMER] = C_IRQ5,
> - [MIPS_EXC_INT_IO] = C_IRQ0,
> - [MIPS_EXC_INT_IPI_1] = C_IRQ1,
> - [MIPS_EXC_INT_IPI_2] = C_IRQ2,
> -};
> -
> static int kvm_vz_irq_deliver_cb(struct kvm_vcpu *vcpu, unsigned int priority,
> u32 cause)
> {
> u32 irq = (priority < MIPS_EXC_MAX) ?
> - kvm_vz_priority_to_irq[priority] : 0;
> + kvm_priority_to_irq[priority] : 0;
>
> switch (priority) {
> case MIPS_EXC_INT_TIMER:
> set_gc0_cause(C_TI);
> break;
>
> - case MIPS_EXC_INT_IO:
> + case MIPS_EXC_INT_IO_1:
> + case MIPS_EXC_INT_IO_2:
> case MIPS_EXC_INT_IPI_1:
> case MIPS_EXC_INT_IPI_2:
> if (cpu_has_guestctl2)
> @@ -311,7 +273,7 @@ static int kvm_vz_irq_clear_cb(struct kvm_vcpu *vcpu, unsigned int priority,
> u32 cause)
> {
> u32 irq = (priority < MIPS_EXC_MAX) ?
> - kvm_vz_priority_to_irq[priority] : 0;
> + kvm_priority_to_irq[priority] : 0;
>
> switch (priority) {
> case MIPS_EXC_INT_TIMER:
> @@ -329,7 +291,8 @@ static int kvm_vz_irq_clear_cb(struct kvm_vcpu *vcpu, unsigned int priority,
> }
> break;
>
> - case MIPS_EXC_INT_IO:
> + case MIPS_EXC_INT_IO_1:
> + case MIPS_EXC_INT_IO_2:
> case MIPS_EXC_INT_IPI_1:
> case MIPS_EXC_INT_IPI_2:
> /* Clear GuestCtl2.VIP irq if not using Hardware Clear */
> --
> 2.7.0
>

Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>