From: Paolo Bonzini <[email protected]>
Signed-off-by: Paolo Bonzini <[email protected]>
Co-developed-by: Joerg Roedel <[email protected]>
Signed-off-by: Joerg Roedel <[email protected]>
---
arch/x86/include/asm/kvm_host.h | 24 +++++------
arch/x86/kvm/i8254.c | 2 +-
arch/x86/kvm/lapic.c | 71 +++++++++++++++++----------------
arch/x86/kvm/x86.c | 18 +++++++--
4 files changed, 61 insertions(+), 54 deletions(-)
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 134bc02962fd..11e52f8bb2c2 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1418,16 +1418,17 @@ enum kvm_mmu_type {
};
/* Per-plane state of VM */
-struct kvm_arch_plane {};
+struct kvm_arch_plane {
+ atomic_t vapics_in_nmi_mode;
-static inline int kvm_arch_plane_init(struct kvm *kvm,
- struct kvm_plane *plane,
- unsigned plane_level)
-{
- return 0;
-}
+ struct mutex apic_map_lock;
+ struct kvm_apic_map __rcu *apic_map;
+ atomic_t apic_map_dirty;
+};
-static inline void kvm_arch_plane_destroy(struct kvm_plane *plane) {}
+int kvm_arch_plane_init(struct kvm *kvm, struct kvm_plane *plane,
+ unsigned plane_level);
+void kvm_arch_plane_destroy(struct kvm_plane *plane);
struct kvm_arch {
unsigned long n_used_mmu_pages;
@@ -1465,11 +1466,6 @@ struct kvm_arch {
struct kvm_ioapic *vioapic;
struct kvm_pit *vpit;
#endif
- atomic_t vapics_in_nmi_mode;
-
- struct mutex apic_map_lock;
- struct kvm_apic_map __rcu *apic_map;
- atomic_t apic_map_dirty;
bool apic_access_memslot_enabled;
bool apic_access_memslot_inhibited;
@@ -2458,7 +2454,7 @@ int kvm_cpu_get_extint(struct kvm_vcpu *v);
int kvm_cpu_get_interrupt(struct kvm_vcpu *v);
void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event);
-int kvm_pv_send_ipi(struct kvm *kvm, unsigned long ipi_bitmap_low,
+int kvm_pv_send_ipi(struct kvm_vcpu *kvm_vcpu, unsigned long ipi_bitmap_low,
unsigned long ipi_bitmap_high, u32 min,
unsigned long icr, int op_64_bit);
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index 1982b0077ddd..bfe590378bd2 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -260,7 +260,7 @@ static void pit_do_work(struct kthread_work *work)
* VCPUs and only when LVT0 is in NMI mode. The interrupt can
* also be simultaneously delivered through PIC and IOAPIC.
*/
- if (atomic_read(&kvm->arch.vapics_in_nmi_mode) > 0)
+ if (atomic_read(&kvm->planes[0]->arch.vapics_in_nmi_mode) > 0)
kvm_for_each_vcpu(i, vcpu, kvm)
kvm_apic_nmi_wd_deliver(vcpu);
}
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 1b763f164951..06a12b49fafa 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -403,36 +403,37 @@ enum {
DIRTY
};
-static void kvm_recalculate_apic_map(struct kvm *kvm)
+static void kvm_recalculate_apic_map(struct kvm_plane *plane)
{
struct kvm_apic_map *new, *old = NULL;
+ struct kvm *kvm = plane->kvm;
struct kvm_vcpu *vcpu;
unsigned long i;
u32 max_id = 255; /* enough space for any xAPIC ID */
bool xapic_id_mismatch;
int r;
- /* Read kvm->arch.apic_map_dirty before kvm->arch.apic_map. */
- if (atomic_read_acquire(&kvm->arch.apic_map_dirty) == CLEAN)
+ /* Read plane->arch.apic_map_dirty before plane->arch.apic_map. */
+ if (atomic_read_acquire(&plane->arch.apic_map_dirty) == CLEAN)
return;
- WARN_ONCE(!irqchip_in_kernel(kvm),
+ WARN_ONCE(!irqchip_in_kernel(plane->kvm),
"Dirty APIC map without an in-kernel local APIC");
- mutex_lock(&kvm->arch.apic_map_lock);
+ mutex_lock(&plane->arch.apic_map_lock);
retry:
/*
- * Read kvm->arch.apic_map_dirty before kvm->arch.apic_map (if clean)
+ * Read plane->arch.apic_map_dirty before plane->arch.apic_map (if
clean)
* or the APIC registers (if dirty). Note, on retry the map may have
* not yet been marked dirty by whatever task changed a vCPU's x2APIC
* ID, i.e. the map may still show up as in-progress. In that case
* this task still needs to retry and complete its calculation.
*/
- if (atomic_cmpxchg_acquire(&kvm->arch.apic_map_dirty,
+ if (atomic_cmpxchg_acquire(&plane->arch.apic_map_dirty,
DIRTY, UPDATE_IN_PROGRESS) == CLEAN) {
/* Someone else has updated the map. */
- mutex_unlock(&kvm->arch.apic_map_lock);
+ mutex_unlock(&plane->arch.apic_map_lock);
return;
}
@@ -445,7 +446,7 @@ static void kvm_recalculate_apic_map(struct kvm *kvm)
*/
xapic_id_mismatch = false;
- kvm_for_each_vcpu(i, vcpu, kvm)
+ plane_for_each_vcpu(i, vcpu, plane)
if (kvm_apic_present(vcpu))
max_id = max(max_id, kvm_x2apic_id(vcpu->arch.apic));
@@ -459,7 +460,7 @@ static void kvm_recalculate_apic_map(struct kvm *kvm)
new->max_apic_id = max_id;
new->logical_mode = KVM_APIC_MODE_SW_DISABLED;
- kvm_for_each_vcpu(i, vcpu, kvm) {
+ plane_for_each_vcpu(i, vcpu, plane) {
if (!kvm_apic_present(vcpu))
continue;
@@ -498,16 +499,16 @@ static void kvm_recalculate_apic_map(struct kvm *kvm)
else
kvm_clear_apicv_inhibit(kvm,
APICV_INHIBIT_REASON_APIC_ID_MODIFIED);
- old = rcu_dereference_protected(kvm->arch.apic_map,
- lockdep_is_held(&kvm->arch.apic_map_lock));
- rcu_assign_pointer(kvm->arch.apic_map, new);
+ old = rcu_dereference_protected(plane->arch.apic_map,
+ lockdep_is_held(&plane->arch.apic_map_lock));
+ rcu_assign_pointer(plane->arch.apic_map, new);
/*
- * Write kvm->arch.apic_map before clearing apic->apic_map_dirty.
+ * Write kvm->arch.apic_map before clearing plane->apic_map_dirty.
* If another update has come in, leave it DIRTY.
*/
- atomic_cmpxchg_release(&kvm->arch.apic_map_dirty,
+ atomic_cmpxchg_release(&plane->arch.apic_map_dirty,
UPDATE_IN_PROGRESS, CLEAN);
- mutex_unlock(&kvm->arch.apic_map_lock);
+ mutex_unlock(&plane->arch.apic_map_lock);
if (old)
kvfree_rcu(old, rcu);
@@ -528,7 +529,7 @@ static inline void apic_set_spiv(struct kvm_lapic *apic,
u32 val)
else
static_branch_inc(&apic_sw_disabled.key);
- atomic_set_release(&apic->vcpu->kvm->arch.apic_map_dirty,
DIRTY);
+ atomic_set_release(&apic->vcpu->plane->arch.apic_map_dirty,
DIRTY);
}
/* Check if there are APF page ready requests pending */
@@ -541,19 +542,19 @@ static inline void apic_set_spiv(struct kvm_lapic *apic,
u32 val)
static inline void kvm_apic_set_xapic_id(struct kvm_lapic *apic, u8 id)
{
kvm_lapic_set_reg(apic, APIC_ID, id << 24);
- atomic_set_release(&apic->vcpu->kvm->arch.apic_map_dirty, DIRTY);
+ atomic_set_release(&apic->vcpu->plane->arch.apic_map_dirty, DIRTY);
}
static inline void kvm_apic_set_ldr(struct kvm_lapic *apic, u32 id)
{
kvm_lapic_set_reg(apic, APIC_LDR, id);
- atomic_set_release(&apic->vcpu->kvm->arch.apic_map_dirty, DIRTY);
+ atomic_set_release(&apic->vcpu->plane->arch.apic_map_dirty, DIRTY);
}
static inline void kvm_apic_set_dfr(struct kvm_lapic *apic, u32 val)
{
kvm_lapic_set_reg(apic, APIC_DFR, val);
- atomic_set_release(&apic->vcpu->kvm->arch.apic_map_dirty, DIRTY);
+ atomic_set_release(&apic->vcpu->plane->arch.apic_map_dirty, DIRTY);
}
static inline void kvm_apic_set_x2apic_id(struct kvm_lapic *apic, u32 id)
@@ -564,7 +565,7 @@ static inline void kvm_apic_set_x2apic_id(struct kvm_lapic
*apic, u32 id)
kvm_lapic_set_reg(apic, APIC_ID, id);
kvm_lapic_set_reg(apic, APIC_LDR, ldr);
- atomic_set_release(&apic->vcpu->kvm->arch.apic_map_dirty, DIRTY);
+ atomic_set_release(&apic->vcpu->plane->arch.apic_map_dirty, DIRTY);
}
static inline int apic_lvt_enabled(struct kvm_lapic *apic, int lvt_type)
@@ -860,7 +861,7 @@ static int __pv_send_ipi(unsigned long *ipi_bitmap, struct
kvm_apic_map *map,
return count;
}
-int kvm_pv_send_ipi(struct kvm *kvm, unsigned long ipi_bitmap_low,
+int kvm_pv_send_ipi(struct kvm_vcpu *vcpu, unsigned long ipi_bitmap_low,
unsigned long ipi_bitmap_high, u32 min,
unsigned long icr, int op_64_bit)
{
@@ -878,7 +879,7 @@ int kvm_pv_send_ipi(struct kvm *kvm, unsigned long
ipi_bitmap_low,
irq.trig_mode = icr & APIC_INT_LEVELTRIG;
rcu_read_lock();
- map = rcu_dereference(kvm->arch.apic_map);
+ map = rcu_dereference(vcpu->plane->arch.apic_map);
count = -EOPNOTSUPP;
if (likely(map)) {
@@ -1240,7 +1241,7 @@ static bool __kvm_irq_delivery_to_apic_fast(struct kvm
*kvm, struct kvm_lapic *s
}
rcu_read_lock();
- map = rcu_dereference(kvm->arch.apic_map);
+ map = rcu_dereference(kvm->planes[0]->arch.apic_map);
ret = kvm_apic_map_get_dest_lapic(kvm, &src, irq, map, &dst, &bitmap);
if (ret) {
@@ -1290,7 +1291,7 @@ static bool kvm_intr_is_single_vcpu_fast(struct kvm *kvm,
return false;
rcu_read_lock();
- map = rcu_dereference(kvm->arch.apic_map);
+ map = rcu_dereference(kvm->planes[0]->arch.apic_map);
if (kvm_apic_map_get_dest_lapic(kvm, NULL, irq, map, &dst, &bitmap) &&
hweight16(bitmap) == 1) {
@@ -1511,7 +1512,7 @@ void kvm_bitmap_or_dest_vcpus(struct kvm *kvm, struct
kvm_lapic_irq *irq,
bool ret;
rcu_read_lock();
- map = rcu_dereference(kvm->arch.apic_map);
+ map = rcu_dereference(kvm->planes[0]->arch.apic_map);
ret = kvm_apic_map_get_dest_lapic(kvm, &src, irq, map, &dest_vcpu,
&bitmap);
@@ -2389,9 +2390,9 @@ static void apic_manage_nmi_watchdog(struct kvm_lapic
*apic, u32 lvt0_val)
if (apic->lvt0_in_nmi_mode != lvt0_in_nmi_mode) {
apic->lvt0_in_nmi_mode = lvt0_in_nmi_mode;
if (lvt0_in_nmi_mode) {
- atomic_inc(&apic->vcpu->kvm->arch.vapics_in_nmi_mode);
+ atomic_inc(&apic->vcpu->plane->arch.vapics_in_nmi_mode);
} else
- atomic_dec(&apic->vcpu->kvm->arch.vapics_in_nmi_mode);
+ atomic_dec(&apic->vcpu->plane->arch.vapics_in_nmi_mode);
}
}
@@ -2551,7 +2552,7 @@ static int kvm_lapic_reg_write(struct kvm_lapic *apic,
u32 reg, u32 val)
* was toggled, the APIC ID changed, etc... The maps are marked dirty
* on relevant changes, i.e. this is a nop for most writes.
*/
- kvm_recalculate_apic_map(apic->vcpu->kvm);
+ kvm_recalculate_apic_map(apic->vcpu->plane);
return ret;
}
@@ -2767,7 +2768,7 @@ static void __kvm_apic_set_base(struct kvm_vcpu *vcpu,
u64 value)
kvm_make_request(KVM_REQ_APF_READY, vcpu);
} else {
static_branch_inc(&apic_hw_disabled.key);
-
atomic_set_release(&apic->vcpu->kvm->arch.apic_map_dirty, DIRTY);
+
atomic_set_release(&apic->vcpu->plane->arch.apic_map_dirty, DIRTY);
}
}
@@ -2814,7 +2815,7 @@ int kvm_apic_set_base(struct kvm_vcpu *vcpu, u64 value,
bool host_initiated)
}
__kvm_apic_set_base(vcpu, value);
- kvm_recalculate_apic_map(vcpu->kvm);
+ kvm_recalculate_apic_map(vcpu->plane);
return 0;
}
EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_apic_set_base);
@@ -2983,7 +2984,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu, bool
init_event)
vcpu->arch.apic_arb_prio = 0;
vcpu->arch.apic_attention = 0;
- kvm_recalculate_apic_map(vcpu->kvm);
+ kvm_recalculate_apic_map(vcpu->plane);
}
/*
@@ -3271,13 +3272,13 @@ int kvm_apic_set_state(struct kvm_vcpu *vcpu, struct
kvm_lapic_state *s)
r = kvm_apic_state_fixup(vcpu, s, true);
if (r) {
- kvm_recalculate_apic_map(vcpu->kvm);
+ kvm_recalculate_apic_map(vcpu->plane);
return r;
}
memcpy(vcpu->arch.apic->regs, s->regs, sizeof(*s));
- atomic_set_release(&apic->vcpu->kvm->arch.apic_map_dirty, DIRTY);
- kvm_recalculate_apic_map(vcpu->kvm);
+ atomic_set_release(&apic->vcpu->plane->arch.apic_map_dirty, DIRTY);
+ kvm_recalculate_apic_map(vcpu->plane);
kvm_apic_set_version(vcpu);
apic_update_ppr(apic);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index a158740a6fc1..070f87ae23eb 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -10441,7 +10441,7 @@ static void kvm_sched_yield(struct kvm_vcpu *vcpu,
unsigned long dest_id)
goto no_yield;
rcu_read_lock();
- map = rcu_dereference(vcpu->kvm->arch.apic_map);
+ map = rcu_dereference(vcpu->plane->arch.apic_map);
if (likely(map) && dest_id <= map->max_apic_id) {
dest_id = array_index_nospec(dest_id, map->max_apic_id + 1);
@@ -10528,7 +10528,7 @@ int ____kvm_emulate_hypercall(struct kvm_vcpu *vcpu,
int cpl,
if (!guest_pv_has(vcpu, KVM_FEATURE_PV_SEND_IPI))
break;
- ret = kvm_pv_send_ipi(vcpu->kvm, a0, a1, a2, a3, op_64_bit);
+ ret = kvm_pv_send_ipi(vcpu, a0, a1, a2, a3, op_64_bit);
break;
case KVM_HC_SCHED_YIELD:
if (!guest_pv_has(vcpu, KVM_FEATURE_PV_SCHED_YIELD))
@@ -13397,6 +13397,18 @@ void kvm_arch_free_vm(struct kvm *kvm)
__kvm_arch_free_vm(kvm);
}
+int kvm_arch_plane_init(struct kvm *kvm, struct kvm_plane *plane,
+ unsigned plane_level)
+{
+ mutex_init(&plane->arch.apic_map_lock);
+
+ return 0;
+}
+
+void kvm_arch_plane_destroy(struct kvm_plane *plane)
+{
+ kvfree(rcu_dereference_check(plane->arch.apic_map, 1));
+}
int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
{
@@ -13429,7 +13441,6 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long
type)
atomic_set(&kvm->arch.noncoherent_dma_count, 0);
raw_spin_lock_init(&kvm->arch.tsc_write_lock);
- mutex_init(&kvm->arch.apic_map_lock);
seqcount_raw_spinlock_init(&kvm->arch.pvclock_sc,
&kvm->arch.tsc_write_lock);
ratelimit_state_init(&kvm->arch.kvmclock_update_rs, HZ, 10);
ratelimit_set_flags(&kvm->arch.kvmclock_update_rs,
RATELIMIT_MSG_ON_RELEASE);
@@ -13587,7 +13598,6 @@ void kvm_arch_destroy_vm(struct kvm *kvm)
kvm_pic_destroy(kvm);
kvm_ioapic_destroy(kvm);
#endif
- kvfree(rcu_dereference_check(kvm->arch.apic_map, 1));
kfree(srcu_dereference_check(kvm->arch.pmu_event_filter, &kvm->srcu,
1));
kvm_mmu_uninit_vm(kvm);
kvm_page_track_cleanup(kvm);
--
2.53.0