mirror of
https://gitee.com/bianbu-linux/linux-6.6
synced 2025-04-26 14:17:26 -04:00
KVM: irq ack notification
Based on a patch from: Ben-Ami Yassour <benami@il.ibm.com> which was based on a patch from: Amit Shah <amit.shah@qumranet.com> Notify IRQ acking on PIC/APIC emulation. The previous patch missed two things: - Edge triggered interrupts on IOAPIC - PIC reset with IRR/ISR set should be equivalent to ack (LAPIC probably needs something similar). Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> CC: Amit Shah <amit.shah@qumranet.com> CC: Ben-Ami Yassour <benami@il.ibm.com> Signed-off-by: Avi Kivity <avi@qumranet.com>
This commit is contained in:
parent
564f15378f
commit
f52447261b
6 changed files with 34 additions and 13 deletions
|
@ -159,9 +159,10 @@ static inline void pic_intack(struct kvm_kpic_state *s, int irq)
|
||||||
s->irr &= ~(1 << irq);
|
s->irr &= ~(1 << irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
int kvm_pic_read_irq(struct kvm_pic *s)
|
int kvm_pic_read_irq(struct kvm *kvm)
|
||||||
{
|
{
|
||||||
int irq, irq2, intno;
|
int irq, irq2, intno;
|
||||||
|
struct kvm_pic *s = pic_irqchip(kvm);
|
||||||
|
|
||||||
irq = pic_get_irq(&s->pics[0]);
|
irq = pic_get_irq(&s->pics[0]);
|
||||||
if (irq >= 0) {
|
if (irq >= 0) {
|
||||||
|
@ -187,12 +188,21 @@ int kvm_pic_read_irq(struct kvm_pic *s)
|
||||||
intno = s->pics[0].irq_base + irq;
|
intno = s->pics[0].irq_base + irq;
|
||||||
}
|
}
|
||||||
pic_update_irq(s);
|
pic_update_irq(s);
|
||||||
|
kvm_notify_acked_irq(kvm, irq);
|
||||||
|
|
||||||
return intno;
|
return intno;
|
||||||
}
|
}
|
||||||
|
|
||||||
void kvm_pic_reset(struct kvm_kpic_state *s)
|
void kvm_pic_reset(struct kvm_kpic_state *s)
|
||||||
{
|
{
|
||||||
|
int irq;
|
||||||
|
struct kvm *kvm = s->pics_state->irq_request_opaque;
|
||||||
|
|
||||||
|
for (irq = 0; irq < PIC_NUM_PINS; irq++) {
|
||||||
|
if (!(s->imr & (1 << irq)) && (s->irr & (1 << irq) ||
|
||||||
|
s->isr & (1 << irq)))
|
||||||
|
kvm_notify_acked_irq(kvm, irq);
|
||||||
|
}
|
||||||
s->last_irr = 0;
|
s->last_irr = 0;
|
||||||
s->irr = 0;
|
s->irr = 0;
|
||||||
s->imr = 0;
|
s->imr = 0;
|
||||||
|
|
|
@ -72,7 +72,7 @@ int kvm_cpu_get_interrupt(struct kvm_vcpu *v)
|
||||||
if (kvm_apic_accept_pic_intr(v)) {
|
if (kvm_apic_accept_pic_intr(v)) {
|
||||||
s = pic_irqchip(v->kvm);
|
s = pic_irqchip(v->kvm);
|
||||||
s->output = 0; /* PIC */
|
s->output = 0; /* PIC */
|
||||||
vector = kvm_pic_read_irq(s);
|
vector = kvm_pic_read_irq(v->kvm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return vector;
|
return vector;
|
||||||
|
|
|
@ -63,11 +63,12 @@ struct kvm_pic {
|
||||||
void *irq_request_opaque;
|
void *irq_request_opaque;
|
||||||
int output; /* intr from master PIC */
|
int output; /* intr from master PIC */
|
||||||
struct kvm_io_device dev;
|
struct kvm_io_device dev;
|
||||||
|
void (*ack_notifier)(void *opaque, int irq);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct kvm_pic *kvm_create_pic(struct kvm *kvm);
|
struct kvm_pic *kvm_create_pic(struct kvm *kvm);
|
||||||
void kvm_pic_set_irq(void *opaque, int irq, int level);
|
void kvm_pic_set_irq(void *opaque, int irq, int level);
|
||||||
int kvm_pic_read_irq(struct kvm_pic *s);
|
int kvm_pic_read_irq(struct kvm *kvm);
|
||||||
void kvm_pic_update_irq(struct kvm_pic *s);
|
void kvm_pic_update_irq(struct kvm_pic *s);
|
||||||
|
|
||||||
static inline struct kvm_pic *pic_irqchip(struct kvm *kvm)
|
static inline struct kvm_pic *pic_irqchip(struct kvm *kvm)
|
||||||
|
|
|
@ -439,7 +439,7 @@ struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector,
|
||||||
static void apic_set_eoi(struct kvm_lapic *apic)
|
static void apic_set_eoi(struct kvm_lapic *apic)
|
||||||
{
|
{
|
||||||
int vector = apic_find_highest_isr(apic);
|
int vector = apic_find_highest_isr(apic);
|
||||||
|
int trigger_mode;
|
||||||
/*
|
/*
|
||||||
* Not every write EOI will has corresponding ISR,
|
* Not every write EOI will has corresponding ISR,
|
||||||
* one example is when Kernel check timer on setup_IO_APIC
|
* one example is when Kernel check timer on setup_IO_APIC
|
||||||
|
@ -451,7 +451,10 @@ static void apic_set_eoi(struct kvm_lapic *apic)
|
||||||
apic_update_ppr(apic);
|
apic_update_ppr(apic);
|
||||||
|
|
||||||
if (apic_test_and_clear_vector(vector, apic->regs + APIC_TMR))
|
if (apic_test_and_clear_vector(vector, apic->regs + APIC_TMR))
|
||||||
kvm_ioapic_update_eoi(apic->vcpu->kvm, vector);
|
trigger_mode = IOAPIC_LEVEL_TRIG;
|
||||||
|
else
|
||||||
|
trigger_mode = IOAPIC_EDGE_TRIG;
|
||||||
|
kvm_ioapic_update_eoi(apic->vcpu->kvm, vector, trigger_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void apic_send_ipi(struct kvm_lapic *apic)
|
static void apic_send_ipi(struct kvm_lapic *apic)
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
|
|
||||||
#include "ioapic.h"
|
#include "ioapic.h"
|
||||||
#include "lapic.h"
|
#include "lapic.h"
|
||||||
|
#include "irq.h"
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
#define ioapic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg)
|
#define ioapic_debug(fmt,arg...) printk(KERN_WARNING fmt,##arg)
|
||||||
|
@ -285,26 +286,31 @@ void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int gsi)
|
static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int gsi,
|
||||||
|
int trigger_mode)
|
||||||
{
|
{
|
||||||
union ioapic_redir_entry *ent;
|
union ioapic_redir_entry *ent;
|
||||||
|
|
||||||
ent = &ioapic->redirtbl[gsi];
|
ent = &ioapic->redirtbl[gsi];
|
||||||
ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
|
|
||||||
|
|
||||||
ent->fields.remote_irr = 0;
|
kvm_notify_acked_irq(ioapic->kvm, gsi);
|
||||||
if (!ent->fields.mask && (ioapic->irr & (1 << gsi)))
|
|
||||||
ioapic_service(ioapic, gsi);
|
if (trigger_mode == IOAPIC_LEVEL_TRIG) {
|
||||||
|
ASSERT(ent->fields.trig_mode == IOAPIC_LEVEL_TRIG);
|
||||||
|
ent->fields.remote_irr = 0;
|
||||||
|
if (!ent->fields.mask && (ioapic->irr & (1 << gsi)))
|
||||||
|
ioapic_service(ioapic, gsi);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void kvm_ioapic_update_eoi(struct kvm *kvm, int vector)
|
void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode)
|
||||||
{
|
{
|
||||||
struct kvm_ioapic *ioapic = kvm->arch.vioapic;
|
struct kvm_ioapic *ioapic = kvm->arch.vioapic;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < IOAPIC_NUM_PINS; i++)
|
for (i = 0; i < IOAPIC_NUM_PINS; i++)
|
||||||
if (ioapic->redirtbl[i].fields.vector == vector)
|
if (ioapic->redirtbl[i].fields.vector == vector)
|
||||||
__kvm_ioapic_update_eoi(ioapic, i);
|
__kvm_ioapic_update_eoi(ioapic, i, trigger_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr,
|
static int ioapic_in_range(struct kvm_io_device *this, gpa_t addr,
|
||||||
|
|
|
@ -58,6 +58,7 @@ struct kvm_ioapic {
|
||||||
} redirtbl[IOAPIC_NUM_PINS];
|
} redirtbl[IOAPIC_NUM_PINS];
|
||||||
struct kvm_io_device dev;
|
struct kvm_io_device dev;
|
||||||
struct kvm *kvm;
|
struct kvm *kvm;
|
||||||
|
void (*ack_notifier)(void *opaque, int irq);
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
|
@ -87,7 +88,7 @@ static inline int irqchip_in_kernel(struct kvm *kvm)
|
||||||
|
|
||||||
struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector,
|
struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector,
|
||||||
unsigned long bitmap);
|
unsigned long bitmap);
|
||||||
void kvm_ioapic_update_eoi(struct kvm *kvm, int vector);
|
void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode);
|
||||||
int kvm_ioapic_init(struct kvm *kvm);
|
int kvm_ioapic_init(struct kvm *kvm);
|
||||||
void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);
|
void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);
|
||||||
void kvm_ioapic_reset(struct kvm_ioapic *ioapic);
|
void kvm_ioapic_reset(struct kvm_ioapic *ioapic);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue