Skip to content

Commit 11a6045

Browse files
committed
KVM: SVM: Use vcpu_idx, not vcpu_id, for GA log tag/metadata
Use a vCPU's index, not its ID, for the GA log tag/metadata that's used to find and kick vCPUs when a device posted interrupt serves as a wake event. Lookups on a vCPU index are O(fast) (not sure what xa_load() actually provides), whereas a vCPU ID lookup is O(n) if a vCPU's ID doesn't match its index. Unlike the Physical APIC Table, which is accessed by hardware when virtualizing IPIs, hardware doesn't consume the GA tag, i.e. KVM _must_ use APIC IDs to fill the Physical APIC Table, but KVM has free rein over the format/meaning of the GA tag. Tested-by: Sairaj Kodilkar <sarunkod@amd.com> Link: https://lore.kernel.org/r/20250611224604.313496-57-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent ce9d54f commit 11a6045

File tree

1 file changed

+20
-17
lines changed

1 file changed

+20
-17
lines changed

arch/x86/kvm/svm/avic.c

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,36 +30,39 @@
3030
#include "svm.h"
3131

3232
/*
33-
* Encode the arbitrary VM ID and the vCPU's default APIC ID, i.e the vCPU ID,
34-
* into the GATag so that KVM can retrieve the correct vCPU from a GALog entry
35-
* if an interrupt can't be delivered, e.g. because the vCPU isn't running.
33+
* Encode the arbitrary VM ID and the vCPU's _index_ into the GATag so that
34+
* KVM can retrieve the correct vCPU from a GALog entry if an interrupt can't
35+
* be delivered, e.g. because the vCPU isn't running. Use the vCPU's index
36+
* instead of its ID (a.k.a. its default APIC ID), as KVM is guaranteed a fast
37+
* lookup on the index, where as vCPUs whose index doesn't match their ID need
38+
* to walk the entire xarray of vCPUs in the worst case scenario.
3639
*
37-
* For the vCPU ID, use however many bits are currently allowed for the max
40+
* For the vCPU index, use however many bits are currently allowed for the max
3841
* guest physical APIC ID (limited by the size of the physical ID table), and
3942
* use whatever bits remain to assign arbitrary AVIC IDs to VMs. Note, the
4043
* size of the GATag is defined by hardware (32 bits), but is an opaque value
4144
* as far as hardware is concerned.
4245
*/
43-
#define AVIC_VCPU_ID_MASK AVIC_PHYSICAL_MAX_INDEX_MASK
46+
#define AVIC_VCPU_IDX_MASK AVIC_PHYSICAL_MAX_INDEX_MASK
4447

4548
#define AVIC_VM_ID_SHIFT HWEIGHT32(AVIC_PHYSICAL_MAX_INDEX_MASK)
4649
#define AVIC_VM_ID_MASK (GENMASK(31, AVIC_VM_ID_SHIFT) >> AVIC_VM_ID_SHIFT)
4750

4851
#define AVIC_GATAG_TO_VMID(x) ((x >> AVIC_VM_ID_SHIFT) & AVIC_VM_ID_MASK)
49-
#define AVIC_GATAG_TO_VCPUID(x) (x & AVIC_VCPU_ID_MASK)
52+
#define AVIC_GATAG_TO_VCPUIDX(x) (x & AVIC_VCPU_IDX_MASK)
5053

51-
#define __AVIC_GATAG(vm_id, vcpu_id) ((((vm_id) & AVIC_VM_ID_MASK) << AVIC_VM_ID_SHIFT) | \
52-
((vcpu_id) & AVIC_VCPU_ID_MASK))
53-
#define AVIC_GATAG(vm_id, vcpu_id) \
54+
#define __AVIC_GATAG(vm_id, vcpu_idx) ((((vm_id) & AVIC_VM_ID_MASK) << AVIC_VM_ID_SHIFT) | \
55+
((vcpu_idx) & AVIC_VCPU_IDX_MASK))
56+
#define AVIC_GATAG(vm_id, vcpu_idx) \
5457
({ \
55-
u32 ga_tag = __AVIC_GATAG(vm_id, vcpu_id); \
58+
u32 ga_tag = __AVIC_GATAG(vm_id, vcpu_idx); \
5659
\
57-
WARN_ON_ONCE(AVIC_GATAG_TO_VCPUID(ga_tag) != (vcpu_id)); \
60+
WARN_ON_ONCE(AVIC_GATAG_TO_VCPUIDX(ga_tag) != (vcpu_idx)); \
5861
WARN_ON_ONCE(AVIC_GATAG_TO_VMID(ga_tag) != (vm_id)); \
5962
ga_tag; \
6063
})
6164

62-
static_assert(__AVIC_GATAG(AVIC_VM_ID_MASK, AVIC_VCPU_ID_MASK) == -1u);
65+
static_assert(__AVIC_GATAG(AVIC_VM_ID_MASK, AVIC_VCPU_IDX_MASK) == -1u);
6366

6467
static bool force_avic;
6568
module_param_unsafe(force_avic, bool, 0444);
@@ -140,16 +143,16 @@ int avic_ga_log_notifier(u32 ga_tag)
140143
struct kvm_svm *kvm_svm;
141144
struct kvm_vcpu *vcpu = NULL;
142145
u32 vm_id = AVIC_GATAG_TO_VMID(ga_tag);
143-
u32 vcpu_id = AVIC_GATAG_TO_VCPUID(ga_tag);
146+
u32 vcpu_idx = AVIC_GATAG_TO_VCPUIDX(ga_tag);
144147

145-
pr_debug("SVM: %s: vm_id=%#x, vcpu_id=%#x\n", __func__, vm_id, vcpu_id);
146-
trace_kvm_avic_ga_log(vm_id, vcpu_id);
148+
pr_debug("SVM: %s: vm_id=%#x, vcpu_idx=%#x\n", __func__, vm_id, vcpu_idx);
149+
trace_kvm_avic_ga_log(vm_id, vcpu_idx);
147150

148151
spin_lock_irqsave(&svm_vm_data_hash_lock, flags);
149152
hash_for_each_possible(svm_vm_data_hash, kvm_svm, hnode, vm_id) {
150153
if (kvm_svm->avic_vm_id != vm_id)
151154
continue;
152-
vcpu = kvm_get_vcpu_by_id(&kvm_svm->kvm, vcpu_id);
155+
vcpu = kvm_get_vcpu(&kvm_svm->kvm, vcpu_idx);
153156
break;
154157
}
155158
spin_unlock_irqrestore(&svm_vm_data_hash_lock, flags);
@@ -786,7 +789,7 @@ int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
786789
*/
787790
struct amd_iommu_pi_data pi_data = {
788791
.ga_tag = AVIC_GATAG(to_kvm_svm(kvm)->avic_vm_id,
789-
vcpu->vcpu_id),
792+
vcpu->vcpu_idx),
790793
.is_guest_mode = kvm_vcpu_apicv_active(vcpu),
791794
.vapic_addr = avic_get_backing_page_address(to_svm(vcpu)),
792795
.vector = vector,

0 commit comments

Comments
 (0)