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

Commit 5550af4d authored by Sheng Yang's avatar Sheng Yang Committed by Avi Kivity
Browse files

KVM: Fix guest shared interrupt with in-kernel irqchip



Every call of kvm_set_irq() should offer an irq_source_id, which is
allocated by kvm_request_irq_source_id(). Based on irq_source_id, we
identify the irq source and implement logical OR for shared level
interrupts.

The allocated irq_source_id can be freed by kvm_free_irq_source_id().

Currently, we support at most sizeof(unsigned long) different irq sources.

[Amit: - rebase to kvm.git HEAD
       - move definition of KVM_USERSPACE_IRQ_SOURCE_ID to common file
       - move kvm_request_irq_source_id to the update_irq ioctl]

[Xiantao: - Add kvm/ia64 stuff and make it work for kvm/ia64 guests]

Signed-off-by: default avatarSheng Yang <sheng@linux.intel.com>
Signed-off-by: default avatarAmit Shah <amit.shah@redhat.com>
Signed-off-by: default avatarXiantao Zhang <xiantao.zhang@intel.com>
Signed-off-by: default avatarAvi Kivity <avi@redhat.com>
parent 6ad9f15c
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -417,6 +417,9 @@ struct kvm_arch {
	struct list_head assigned_dev_head;
	struct dmar_domain *intel_iommu_domain;
	struct hlist_head irq_ack_notifier_list;

	unsigned long irq_sources_bitmap;
	unsigned long irq_states[KVM_IOAPIC_NUM_PINS];
};

union cpuid3_t {
+5 −3
Original line number Diff line number Diff line
@@ -778,6 +778,9 @@ static void kvm_init_vm(struct kvm *kvm)
	kvm_build_io_pmt(kvm);

	INIT_LIST_HEAD(&kvm->arch.assigned_dev_head);

	/* Reserve bit 0 of irq_sources_bitmap for userspace irq source */
	set_bit(KVM_USERSPACE_IRQ_SOURCE_ID, &kvm->arch.irq_sources_bitmap);
}

struct  kvm *kvm_arch_create_vm(void)
@@ -941,9 +944,8 @@ long kvm_arch_vm_ioctl(struct file *filp,
			goto out;
		if (irqchip_in_kernel(kvm)) {
			mutex_lock(&kvm->lock);
			kvm_ioapic_set_irq(kvm->arch.vioapic,
						irq_event.irq,
						irq_event.level);
			kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
				    irq_event.irq, irq_event.level);
			mutex_unlock(&kvm->lock);
			r = 0;
		}
+3 −0
Original line number Diff line number Diff line
@@ -364,6 +364,9 @@ struct kvm_arch{

	struct page *ept_identity_pagetable;
	bool ept_identity_pagetable_done;

	unsigned long irq_sources_bitmap;
	unsigned long irq_states[KVM_IOAPIC_NUM_PINS];
};

struct kvm_vm_stat {
+9 −2
Original line number Diff line number Diff line
@@ -545,6 +545,12 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm)
	if (!pit)
		return NULL;

	mutex_lock(&kvm->lock);
	pit->irq_source_id = kvm_request_irq_source_id(kvm);
	mutex_unlock(&kvm->lock);
	if (pit->irq_source_id < 0)
		return NULL;

	mutex_init(&pit->pit_state.lock);
	mutex_lock(&pit->pit_state.lock);
	spin_lock_init(&pit->pit_state.inject_lock);
@@ -587,6 +593,7 @@ void kvm_free_pit(struct kvm *kvm)
		mutex_lock(&kvm->arch.vpit->pit_state.lock);
		timer = &kvm->arch.vpit->pit_state.pit_timer.timer;
		hrtimer_cancel(timer);
		kvm_free_irq_source_id(kvm, kvm->arch.vpit->irq_source_id);
		mutex_unlock(&kvm->arch.vpit->pit_state.lock);
		kfree(kvm->arch.vpit);
	}
@@ -595,8 +602,8 @@ void kvm_free_pit(struct kvm *kvm)
static void __inject_pit_timer_intr(struct kvm *kvm)
{
	mutex_lock(&kvm->lock);
	kvm_set_irq(kvm, 0, 1);
	kvm_set_irq(kvm, 0, 0);
	kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 1);
	kvm_set_irq(kvm, kvm->arch.vpit->irq_source_id, 0, 0);
	mutex_unlock(&kvm->lock);
}

+1 −0
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ struct kvm_pit {
	struct kvm_io_device speaker_dev;
	struct kvm *kvm;
	struct kvm_kpit_state pit_state;
	int irq_source_id;
};

#define KVM_PIT_BASE_ADDRESS	    0x40
Loading