KVM: Move irq sharing information to irqchip level
This removes assumptions that max GSIs is smaller than number of pins. Sharing is tracked on pin level not GSI level. [avi: no PIC on ia64] Signed-off-by: Gleb Natapov <gleb@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com>
This commit is contained in:
parent
79c727d437
commit
1a6e4a8c27
5 changed files with 39 additions and 25 deletions
|
@ -410,7 +410,6 @@ struct kvm_arch{
|
|||
gpa_t ept_identity_map_addr;
|
||||
|
||||
unsigned long irq_sources_bitmap;
|
||||
unsigned long irq_states[KVM_IOAPIC_NUM_PINS];
|
||||
u64 vm_init_tsc;
|
||||
};
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ struct kvm_pic {
|
|||
int output; /* intr from master PIC */
|
||||
struct kvm_io_device dev;
|
||||
void (*ack_notifier)(void *opaque, int irq);
|
||||
unsigned long irq_states[16];
|
||||
};
|
||||
|
||||
struct kvm_pic *kvm_create_pic(struct kvm *kvm);
|
||||
|
|
|
@ -120,7 +120,7 @@ struct kvm_kernel_irq_routing_entry {
|
|||
u32 gsi;
|
||||
u32 type;
|
||||
int (*set)(struct kvm_kernel_irq_routing_entry *e,
|
||||
struct kvm *kvm, int level);
|
||||
struct kvm *kvm, int irq_source_id, int level);
|
||||
union {
|
||||
struct {
|
||||
unsigned irqchip;
|
||||
|
|
|
@ -41,6 +41,7 @@ struct kvm_ioapic {
|
|||
u32 irr;
|
||||
u32 pad;
|
||||
union kvm_ioapic_redirect_entry redirtbl[IOAPIC_NUM_PINS];
|
||||
unsigned long irq_states[IOAPIC_NUM_PINS];
|
||||
struct kvm_io_device dev;
|
||||
struct kvm *kvm;
|
||||
void (*ack_notifier)(void *opaque, int irq);
|
||||
|
|
|
@ -31,20 +31,39 @@
|
|||
|
||||
#include "ioapic.h"
|
||||
|
||||
static inline int kvm_irq_line_state(unsigned long *irq_state,
|
||||
int irq_source_id, int level)
|
||||
{
|
||||
/* Logical OR for level trig interrupt */
|
||||
if (level)
|
||||
set_bit(irq_source_id, irq_state);
|
||||
else
|
||||
clear_bit(irq_source_id, irq_state);
|
||||
|
||||
return !!(*irq_state);
|
||||
}
|
||||
|
||||
static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e,
|
||||
struct kvm *kvm, int level)
|
||||
struct kvm *kvm, int irq_source_id, int level)
|
||||
{
|
||||
#ifdef CONFIG_X86
|
||||
return kvm_pic_set_irq(pic_irqchip(kvm), e->irqchip.pin, level);
|
||||
struct kvm_pic *pic = pic_irqchip(kvm);
|
||||
level = kvm_irq_line_state(&pic->irq_states[e->irqchip.pin],
|
||||
irq_source_id, level);
|
||||
return kvm_pic_set_irq(pic, e->irqchip.pin, level);
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e,
|
||||
struct kvm *kvm, int level)
|
||||
struct kvm *kvm, int irq_source_id, int level)
|
||||
{
|
||||
return kvm_ioapic_set_irq(kvm->arch.vioapic, e->irqchip.pin, level);
|
||||
struct kvm_ioapic *ioapic = kvm->arch.vioapic;
|
||||
level = kvm_irq_line_state(&ioapic->irq_states[e->irqchip.pin],
|
||||
irq_source_id, level);
|
||||
|
||||
return kvm_ioapic_set_irq(ioapic, e->irqchip.pin, level);
|
||||
}
|
||||
|
||||
inline static bool kvm_is_dm_lowest_prio(struct kvm_lapic_irq *irq)
|
||||
|
@ -96,10 +115,13 @@ int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src,
|
|||
}
|
||||
|
||||
static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
|
||||
struct kvm *kvm, int level)
|
||||
struct kvm *kvm, int irq_source_id, int level)
|
||||
{
|
||||
struct kvm_lapic_irq irq;
|
||||
|
||||
if (!level)
|
||||
return -1;
|
||||
|
||||
trace_kvm_msi_set_irq(e->msi.address_lo, e->msi.data);
|
||||
|
||||
irq.dest_id = (e->msi.address_lo &
|
||||
|
@ -125,34 +147,19 @@ static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
|
|||
int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level)
|
||||
{
|
||||
struct kvm_kernel_irq_routing_entry *e;
|
||||
unsigned long *irq_state, sig_level;
|
||||
int ret = -1;
|
||||
|
||||
trace_kvm_set_irq(irq, level, irq_source_id);
|
||||
|
||||
WARN_ON(!mutex_is_locked(&kvm->irq_lock));
|
||||
|
||||
if (irq < KVM_IOAPIC_NUM_PINS) {
|
||||
irq_state = (unsigned long *)&kvm->arch.irq_states[irq];
|
||||
|
||||
/* Logical OR for level trig interrupt */
|
||||
if (level)
|
||||
set_bit(irq_source_id, irq_state);
|
||||
else
|
||||
clear_bit(irq_source_id, irq_state);
|
||||
sig_level = !!(*irq_state);
|
||||
} else if (!level)
|
||||
return ret;
|
||||
else /* Deal with MSI/MSI-X */
|
||||
sig_level = 1;
|
||||
|
||||
/* Not possible to detect if the guest uses the PIC or the
|
||||
* IOAPIC. So set the bit in both. The guest will ignore
|
||||
* writes to the unused one.
|
||||
*/
|
||||
list_for_each_entry(e, &kvm->irq_routing, link)
|
||||
if (e->gsi == irq) {
|
||||
int r = e->set(e, kvm, sig_level);
|
||||
int r = e->set(e, kvm, irq_source_id, level);
|
||||
if (r < 0)
|
||||
continue;
|
||||
|
||||
|
@ -232,8 +239,14 @@ void kvm_free_irq_source_id(struct kvm *kvm, int irq_source_id)
|
|||
printk(KERN_ERR "kvm: IRQ source ID out of range!\n");
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < KVM_IOAPIC_NUM_PINS; i++)
|
||||
clear_bit(irq_source_id, &kvm->arch.irq_states[i]);
|
||||
for (i = 0; i < KVM_IOAPIC_NUM_PINS; i++) {
|
||||
clear_bit(irq_source_id, &kvm->arch.vioapic->irq_states[i]);
|
||||
if (i >= 16)
|
||||
continue;
|
||||
#ifdef CONFIG_X86
|
||||
clear_bit(irq_source_id, &pic_irqchip(kvm)->irq_states[i]);
|
||||
#endif
|
||||
}
|
||||
clear_bit(irq_source_id, &kvm->arch.irq_sources_bitmap);
|
||||
mutex_unlock(&kvm->irq_lock);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue