KVM: MIPS: Add more types of virtual interrupts
authorHuacai Chen <chenhc@lemote.com>
Sat, 23 May 2020 07:56:36 +0000 (15:56 +0800)
committerPaolo Bonzini <pbonzini@redhat.com>
Thu, 4 Jun 2020 17:49:13 +0000 (13:49 -0400)
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.

Reviewed-by: Aleksandar Markovic <aleksandar.qemu.devel@gmail.com>
Signed-off-by: Huacai Chen <chenhc@lemote.com>
Co-developed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Message-Id: <1590220602-3547-10-git-send-email-chenhc@lemote.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/mips/kvm/interrupt.c
arch/mips/kvm/interrupt.h
arch/mips/kvm/mips.c
arch/mips/kvm/vz.c

index 7257e8b6f5a92c1ff9ba7449dccdb081cd762995..d28c2c9c343e750e09fa5ff0e4c37c276148669c 100644 (file)
@@ -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 ??? */
index 3bf0a49725e81ae4fb59081255595eed85f4fa43..c3e878ca3e07f10fd7eb3900546c4c9d8daf8c92 100644 (file)
 #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);
index 3b0148c99c0dfac480f1579a60a7dc3429a8b06c..6b435c6e5018add04ba9689532b97ba96fc9478e 100644 (file)
@@ -490,7 +490,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);
 
@@ -499,10 +502,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;
index 20f69855f164903aa8433bc6eccceaf2039f2bb2..45be0b7bc09048837fee2e0f140795a223a872a0 100644 (file)
@@ -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 */