Commit 3f51d8fc authored by Huacai Chen's avatar Huacai Chen Committed by Paolo Bonzini

KVM: MIPS: Add more types of virtual interrupts

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: default avatarAleksandar Markovic <aleksandar.qemu.devel@gmail.com>
Signed-off-by: default avatarHuacai Chen <chenhc@lemote.com>
Co-developed-by: default avatarJiaxun Yang <jiaxun.yang@flygoat.com>
Message-Id: <1590220602-3547-10-git-send-email-chenhc@lemote.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent 49bb9600
...@@ -61,27 +61,8 @@ void kvm_mips_queue_io_int_cb(struct kvm_vcpu *vcpu, ...@@ -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 * the EXC code will be set when we are actually
* delivering the interrupt: * delivering the interrupt:
*/ */
switch (intr) { kvm_set_c0_guest_cause(vcpu->arch.cop0, 1 << (intr + 8));
case 2: kvm_mips_queue_irq(vcpu, kvm_irq_to_priority(intr));
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;
}
} }
void kvm_mips_dequeue_io_int_cb(struct kvm_vcpu *vcpu, 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, ...@@ -89,26 +70,8 @@ void kvm_mips_dequeue_io_int_cb(struct kvm_vcpu *vcpu,
{ {
int intr = (int)irq->irq; int intr = (int)irq->irq;
switch (intr) { kvm_clear_c0_guest_cause(vcpu->arch.cop0, 1 << (-intr + 8));
case -2: kvm_mips_dequeue_irq(vcpu, kvm_irq_to_priority(-intr));
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;
}
} }
/* Deliver the interrupt of the corresponding priority, if possible. */ /* Deliver the interrupt of the corresponding priority, if possible. */
...@@ -116,51 +79,21 @@ int kvm_mips_irq_deliver_cb(struct kvm_vcpu *vcpu, unsigned int priority, ...@@ -116,51 +79,21 @@ int kvm_mips_irq_deliver_cb(struct kvm_vcpu *vcpu, unsigned int priority,
u32 cause) u32 cause)
{ {
int allowed = 0; int allowed = 0;
u32 exccode; u32 exccode, ie;
struct kvm_vcpu_arch *arch = &vcpu->arch; struct kvm_vcpu_arch *arch = &vcpu->arch;
struct mips_coproc *cop0 = vcpu->arch.cop0; struct mips_coproc *cop0 = vcpu->arch.cop0;
switch (priority) { if (priority == MIPS_EXC_MAX)
case MIPS_EXC_INT_TIMER: return 0;
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: ie = 1 << (kvm_priority_to_irq[priority] + 8);
if ((kvm_read_c0_guest_status(cop0) & ST0_IE) 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) & (ST0_EXL | ST0_ERL)))
&& (kvm_read_c0_guest_status(cop0) & IE_IRQ0)) { && (kvm_read_c0_guest_status(cop0) & ie)) {
allowed = 1; allowed = 1;
exccode = EXCCODE_INT; 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;
default:
break;
}
/* Are we allowed to deliver the interrupt ??? */ /* Are we allowed to deliver the interrupt ??? */
if (allowed) { if (allowed) {
......
...@@ -21,11 +21,12 @@ ...@@ -21,11 +21,12 @@
#define MIPS_EXC_NMI 5 #define MIPS_EXC_NMI 5
#define MIPS_EXC_MCHK 6 #define MIPS_EXC_MCHK 6
#define MIPS_EXC_INT_TIMER 7 #define MIPS_EXC_INT_TIMER 7
#define MIPS_EXC_INT_IO 8 #define MIPS_EXC_INT_IO_1 8
#define MIPS_EXC_EXECUTE 9 #define MIPS_EXC_INT_IO_2 9
#define MIPS_EXC_INT_IPI_1 10 #define MIPS_EXC_EXECUTE 10
#define MIPS_EXC_INT_IPI_2 11 #define MIPS_EXC_INT_IPI_1 11
#define MIPS_EXC_MAX 12 #define MIPS_EXC_INT_IPI_2 12
#define MIPS_EXC_MAX 13
/* XXXSL More to follow */ /* XXXSL More to follow */
#define C_TI (_ULCAST_(1) << 30) #define C_TI (_ULCAST_(1) << 30)
...@@ -38,6 +39,9 @@ ...@@ -38,6 +39,9 @@
#define KVM_MIPS_IRQ_CLEAR_ALL_AT_ONCE (0) #define KVM_MIPS_IRQ_CLEAR_ALL_AT_ONCE (0)
#endif #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_queue_irq(struct kvm_vcpu *vcpu, unsigned int priority);
void kvm_mips_dequeue_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); int kvm_mips_pending_timer(struct kvm_vcpu *vcpu);
......
...@@ -490,7 +490,10 @@ int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, ...@@ -490,7 +490,10 @@ int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
int intr = (int)irq->irq; int intr = (int)irq->irq;
struct kvm_vcpu *dvcpu = NULL; 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, kvm_debug("%s: CPU: %d, INTR: %d\n", __func__, irq->cpu,
(int)intr); (int)intr);
...@@ -499,10 +502,10 @@ int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, ...@@ -499,10 +502,10 @@ int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu,
else else
dvcpu = vcpu->kvm->vcpus[irq->cpu]; 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); 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); kvm_mips_callbacks->dequeue_io_int(dvcpu, irq);
} else { } else {
kvm_err("%s: invalid interrupt ioctl (%d:%d)\n", __func__, kvm_err("%s: invalid interrupt ioctl (%d:%d)\n", __func__,
...@@ -1620,6 +1623,34 @@ static struct notifier_block kvm_mips_csr_die_notifier = { ...@@ -1620,6 +1623,34 @@ static struct notifier_block kvm_mips_csr_die_notifier = {
.notifier_call = kvm_mips_csr_die_notify, .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) static int __init kvm_mips_init(void)
{ {
int ret; int ret;
...@@ -1638,6 +1669,9 @@ static int __init kvm_mips_init(void) ...@@ -1638,6 +1669,9 @@ static int __init kvm_mips_init(void)
if (ret) if (ret)
return 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); register_die_notifier(&kvm_mips_csr_die_notifier);
return 0; return 0;
......
...@@ -225,23 +225,7 @@ static void kvm_vz_queue_io_int_cb(struct kvm_vcpu *vcpu, ...@@ -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 * interrupts are asynchronous to vcpu execution therefore defer guest
* cp0 accesses * cp0 accesses
*/ */
switch (intr) { kvm_vz_queue_irq(vcpu, kvm_irq_to_priority(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;
}
} }
static void kvm_vz_dequeue_io_int_cb(struct kvm_vcpu *vcpu, 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, ...@@ -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 * interrupts are asynchronous to vcpu execution therefore defer guest
* cp0 accesses * cp0 accesses
*/ */
switch (intr) { kvm_vz_dequeue_irq(vcpu, kvm_irq_to_priority(-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;
}
} }
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, static int kvm_vz_irq_deliver_cb(struct kvm_vcpu *vcpu, unsigned int priority,
u32 cause) u32 cause)
{ {
u32 irq = (priority < MIPS_EXC_MAX) ? u32 irq = (priority < MIPS_EXC_MAX) ?
kvm_vz_priority_to_irq[priority] : 0; kvm_priority_to_irq[priority] : 0;
switch (priority) { switch (priority) {
case MIPS_EXC_INT_TIMER: case MIPS_EXC_INT_TIMER:
set_gc0_cause(C_TI); set_gc0_cause(C_TI);
break; 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_1:
case MIPS_EXC_INT_IPI_2: case MIPS_EXC_INT_IPI_2:
if (cpu_has_guestctl2) if (cpu_has_guestctl2)
...@@ -311,7 +273,7 @@ static int kvm_vz_irq_clear_cb(struct kvm_vcpu *vcpu, unsigned int priority, ...@@ -311,7 +273,7 @@ static int kvm_vz_irq_clear_cb(struct kvm_vcpu *vcpu, unsigned int priority,
u32 cause) u32 cause)
{ {
u32 irq = (priority < MIPS_EXC_MAX) ? u32 irq = (priority < MIPS_EXC_MAX) ?
kvm_vz_priority_to_irq[priority] : 0; kvm_priority_to_irq[priority] : 0;
switch (priority) { switch (priority) {
case MIPS_EXC_INT_TIMER: case MIPS_EXC_INT_TIMER:
...@@ -329,7 +291,8 @@ static int kvm_vz_irq_clear_cb(struct kvm_vcpu *vcpu, unsigned int priority, ...@@ -329,7 +291,8 @@ static int kvm_vz_irq_clear_cb(struct kvm_vcpu *vcpu, unsigned int priority,
} }
break; 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_1:
case MIPS_EXC_INT_IPI_2: case MIPS_EXC_INT_IPI_2:
/* Clear GuestCtl2.VIP irq if not using Hardware Clear */ /* Clear GuestCtl2.VIP irq if not using Hardware Clear */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment