Commit f02b1bcc authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files

Merge tag 'kvm-x86-irqs-6.17' of https://github.com/kvm-x86/linux into HEAD

KVM IRQ changes for 6.17

 - Rework irqbypass to track/match producers and consumers via an xarray
   instead of a linked list.  Using a linked list leads to O(n^2) insertion
   times, which is hugely problematic for use cases that create large numbers
   of VMs.  Such use cases typically don't actually use irqbypass, but
   eliminating the pointless registration is a future problem to solve as it
   likely requires new uAPI.

 - Track irqbypass's "token" as "struct eventfd_ctx *" instead of a "void *",
   to avoid making a simple concept unnecessarily difficult to understand.

 - Add CONFIG_KVM_IOAPIC for x86 to allow disabling support for I/O APIC, PIC,
   and PIT emulation at compile time.

 - Drop x86's irq_comm.c, and move a pile of IRQ related code into irq.c.

 - Fix a variety of flaws and bugs in the AVIC device posted IRQ code.

 - Inhibited AVIC if a vCPU's ID is too big (relative to what hardware
   supports) instead of rejecting vCPU creation.

 - Extend enable_ipiv module param support to SVM, by simply leaving IsRunning
   clear in the vCPU's physical ID table entry.

 - Disable IPI virtualization, via enable_ipiv, if the CPU is affected by
   erratum #1235, to allow (safely) enabling AVIC on such CPUs.

 - Dedup x86's device posted IRQ code, as the vast majority of functionality
   can be shared verbatime between SVM and VMX.

 - Harden the device posted IRQ code against bugs and runtime errors.

 - Use vcpu_idx, not vcpu_id, for GA log tag/metadata, to make lookups O(1)
   instead of O(n).

 - Generate GA Log interrupts if and only if the target vCPU is blocking, i.e.
   only if KVM needs a notification in order to wake the vCPU.

 - Decouple device posted IRQs from VFIO device assignment, as binding a VM to
   a VFIO group is not a requirement for enabling device posted IRQs.

 - Clean up and document/comment the irqfd assignment code.

 - Disallow binding multiple irqfds to an eventfd with a priority waiter, i.e.
   ensure an eventfd is bound to at most one irqfd through the entire host,
   and add a selftest to verify eventfd:irqfd bindings are globally unique.
parents 65164fd0 81bf24f1
Loading
Loading
Loading
Loading
+8 −12
Original line number Diff line number Diff line
@@ -2765,19 +2765,15 @@ void kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons,
	kvm_vgic_v4_unset_forwarding(irqfd->kvm, prod->irq);
}

bool kvm_arch_irqfd_route_changed(struct kvm_kernel_irq_routing_entry *old,
void kvm_arch_update_irqfd_routing(struct kvm_kernel_irqfd *irqfd,
				   struct kvm_kernel_irq_routing_entry *old,
				   struct kvm_kernel_irq_routing_entry *new)
{
	if (old->type != KVM_IRQ_ROUTING_MSI ||
	    new->type != KVM_IRQ_ROUTING_MSI)
		return true;

	return memcmp(&old->msi, &new->msi, sizeof(new->msi));
}
	if (old->type == KVM_IRQ_ROUTING_MSI &&
	    new->type == KVM_IRQ_ROUTING_MSI &&
	    !memcmp(&old->msi, &new->msi, sizeof(new->msi)))
		return;

int kvm_arch_update_irqfd_routing(struct kvm *kvm, unsigned int host_irq,
				  uint32_t guest_irq, bool set)
{
	/*
	 * Remapping the vLPI requires taking the its_lock mutex to resolve
	 * the new translation. We're in spinlock land at this point, so no
@@ -2785,7 +2781,7 @@ int kvm_arch_update_irqfd_routing(struct kvm *kvm, unsigned int host_irq,
	 *
	 * Unmap the vLPI and fall back to software LPI injection.
	 */
	return kvm_vgic_v4_unset_forwarding(kvm, host_irq);
	return kvm_vgic_v4_unset_forwarding(irqfd->kvm, irqfd->producer->irq);
}

void kvm_arch_irq_bypass_stop(struct irq_bypass_consumer *cons)
+1 −1
Original line number Diff line number Diff line
@@ -758,7 +758,7 @@ static void its_free_ite(struct kvm *kvm, struct its_ite *ite)
	if (irq) {
		scoped_guard(raw_spinlock_irqsave, &irq->irq_lock) {
			if (irq->hw)
				WARN_ON(its_unmap_vlpi(ite->irq->host_irq));
				its_unmap_vlpi(ite->irq->host_irq);

			irq->hw = false;
		}
+4 −6
Original line number Diff line number Diff line
@@ -527,28 +527,26 @@ static struct vgic_irq *__vgic_host_irq_get_vlpi(struct kvm *kvm, int host_irq)
	return NULL;
}

int kvm_vgic_v4_unset_forwarding(struct kvm *kvm, int host_irq)
void kvm_vgic_v4_unset_forwarding(struct kvm *kvm, int host_irq)
{
	struct vgic_irq *irq;
	unsigned long flags;
	int ret = 0;

	if (!vgic_supports_direct_msis(kvm))
		return 0;
		return;

	irq = __vgic_host_irq_get_vlpi(kvm, host_irq);
	if (!irq)
		return 0;
		return;

	raw_spin_lock_irqsave(&irq->irq_lock, flags);
	WARN_ON(irq->hw && irq->host_irq != host_irq);
	if (irq->hw) {
		atomic_dec(&irq->target_vcpu->arch.vgic_cpu.vgic_v3.its_vpe.vlpi_count);
		irq->hw = false;
		ret = its_unmap_vlpi(host_irq);
		its_unmap_vlpi(host_irq);
	}

	raw_spin_unlock_irqrestore(&irq->irq_lock, flags);
	vgic_put_irq(kvm, irq);
	return ret;
}
+16 −1
Original line number Diff line number Diff line
@@ -26,7 +26,22 @@ enum {
	IRQ_REMAP_X2APIC_MODE,
};

struct vcpu_data {
/*
 * This is mainly used to communicate information back-and-forth
 * between SVM and IOMMU for setting up and tearing down posted
 * interrupt
 */
struct amd_iommu_pi_data {
	u64 vapic_addr;		/* Physical address of the vCPU's vAPIC. */
	u32 ga_tag;
	u32 vector;		/* Guest vector of the interrupt */
	int cpu;
	bool ga_log_intr;
	bool is_guest_mode;
	void *ir_data;
};

struct intel_iommu_pi_data {
	u64 pi_desc_addr;	/* Physical address of PI Descriptor */
	u32 vector;		/* Guest vector of the interrupt */
};
+1 −1
Original line number Diff line number Diff line
@@ -112,7 +112,7 @@ KVM_X86_OP_OPTIONAL(update_cpu_dirty_logging)
KVM_X86_OP_OPTIONAL(vcpu_blocking)
KVM_X86_OP_OPTIONAL(vcpu_unblocking)
KVM_X86_OP_OPTIONAL(pi_update_irte)
KVM_X86_OP_OPTIONAL(pi_start_assignment)
KVM_X86_OP_OPTIONAL(pi_start_bypass)
KVM_X86_OP_OPTIONAL(apicv_pre_state_restore)
KVM_X86_OP_OPTIONAL(apicv_post_state_restore)
KVM_X86_OP_OPTIONAL_RET0(dy_apicv_has_pending_interrupt)
Loading