Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1a6e4a8c authored by Gleb Natapov's avatar Gleb Natapov Committed by Avi Kivity
Browse files

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: default avatarGleb Natapov <gleb@redhat.com>
Signed-off-by: default avatarAvi Kivity <avi@redhat.com>
parent 79c727d4
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -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;
};

+1 −0
Original line number Diff line number Diff line
@@ -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);
+1 −1
Original line number Diff line number Diff line
@@ -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;
+1 −0
Original line number Diff line number Diff line
@@ -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);
+36 −23
Original line number Diff line number Diff line
@@ -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);
}