Skip to content

Commit

Permalink
KVM: Move irq sharing information to irqchip level
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Gleb Natapov authored and Avi Kivity committed Dec 3, 2009
1 parent 79c727d commit 1a6e4a8
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 25 deletions.
1 change: 0 additions & 1 deletion arch/x86/include/asm/kvm_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down
1 change: 1 addition & 0 deletions arch/x86/kvm/irq.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion include/linux/kvm_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions virt/kvm/ioapic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
59 changes: 36 additions & 23 deletions virt/kvm/irq_comm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 &
Expand All @@ -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;

Expand Down Expand Up @@ -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);
}
Expand Down

0 comments on commit 1a6e4a8

Please sign in to comment.