mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-22 17:44:52 +07:00
394457a928
KVM does not deliver x2APIC broadcast messages with physical mode. Intel SDM (10.12.9 ICR Operation in x2APIC Mode) states: "A destination ID value of FFFF_FFFFH is used for broadcast of interrupts in both logical destination and physical destination modes." In addition, the local-apic enables cluster mode broadcast. As Intel SDM 10.6.2.2 says: "Broadcast to all local APICs is achieved by setting all destination bits to one." This patch enables cluster mode broadcast. The fix tries to combine broadcast in different modes through a unified code. One rare case occurs when the source of IPI has its APIC disabled. In such case, the source can still issue IPIs, but since the source is not obliged to have the same LAPIC mode as the enabled ones, we cannot rely on it. Since it is a rare case, it is unoptimized and done on the slow-path. Signed-off-by: Nadav Amit <namit@cs.technion.ac.il> Reviewed-by: Radim Krčmář <rkrcmar@redhat.com> Reviewed-by: Wanpeng Li <wanpeng.li@linux.intel.com> [As per Radim's review, use unsigned int for X2APIC_BROADCAST, return bool from kvm_apic_broadcast. - Paolo] Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
174 lines
5.2 KiB
C
174 lines
5.2 KiB
C
#ifndef __KVM_X86_LAPIC_H
|
|
#define __KVM_X86_LAPIC_H
|
|
|
|
#include "iodev.h"
|
|
|
|
#include <linux/kvm_host.h>
|
|
|
|
#define KVM_APIC_INIT 0
|
|
#define KVM_APIC_SIPI 1
|
|
|
|
struct kvm_timer {
|
|
struct hrtimer timer;
|
|
s64 period; /* unit: ns */
|
|
u32 timer_mode_mask;
|
|
u64 tscdeadline;
|
|
atomic_t pending; /* accumulated triggered timers */
|
|
};
|
|
|
|
struct kvm_lapic {
|
|
unsigned long base_address;
|
|
struct kvm_io_device dev;
|
|
struct kvm_timer lapic_timer;
|
|
u32 divide_count;
|
|
struct kvm_vcpu *vcpu;
|
|
bool irr_pending;
|
|
/* Number of bits set in ISR. */
|
|
s16 isr_count;
|
|
/* The highest vector set in ISR; if -1 - invalid, must scan ISR. */
|
|
int highest_isr_cache;
|
|
/**
|
|
* APIC register page. The layout matches the register layout seen by
|
|
* the guest 1:1, because it is accessed by the vmx microcode.
|
|
* Note: Only one register, the TPR, is used by the microcode.
|
|
*/
|
|
void *regs;
|
|
gpa_t vapic_addr;
|
|
struct gfn_to_hva_cache vapic_cache;
|
|
unsigned long pending_events;
|
|
unsigned int sipi_vector;
|
|
};
|
|
int kvm_create_lapic(struct kvm_vcpu *vcpu);
|
|
void kvm_free_lapic(struct kvm_vcpu *vcpu);
|
|
|
|
int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu);
|
|
int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu);
|
|
int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu);
|
|
void kvm_apic_accept_events(struct kvm_vcpu *vcpu);
|
|
void kvm_lapic_reset(struct kvm_vcpu *vcpu);
|
|
u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu);
|
|
void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8);
|
|
void kvm_lapic_set_eoi(struct kvm_vcpu *vcpu);
|
|
void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value);
|
|
u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu);
|
|
void kvm_apic_set_version(struct kvm_vcpu *vcpu);
|
|
|
|
void kvm_apic_update_tmr(struct kvm_vcpu *vcpu, u32 *tmr);
|
|
void kvm_apic_update_irr(struct kvm_vcpu *vcpu, u32 *pir);
|
|
int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u32 dest);
|
|
int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u32 mda);
|
|
int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq,
|
|
unsigned long *dest_map);
|
|
int kvm_apic_local_deliver(struct kvm_lapic *apic, int lvt_type);
|
|
|
|
bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src,
|
|
struct kvm_lapic_irq *irq, int *r, unsigned long *dest_map);
|
|
|
|
u64 kvm_get_apic_base(struct kvm_vcpu *vcpu);
|
|
int kvm_set_apic_base(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
|
|
void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
|
|
struct kvm_lapic_state *s);
|
|
int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
|
|
|
|
u64 kvm_get_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu);
|
|
void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, u64 data);
|
|
|
|
void kvm_apic_write_nodecode(struct kvm_vcpu *vcpu, u32 offset);
|
|
void kvm_apic_set_eoi_accelerated(struct kvm_vcpu *vcpu, int vector);
|
|
|
|
int kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr);
|
|
void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu);
|
|
void kvm_lapic_sync_to_vapic(struct kvm_vcpu *vcpu);
|
|
|
|
int kvm_x2apic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data);
|
|
int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
|
|
|
|
int kvm_hv_vapic_msr_write(struct kvm_vcpu *vcpu, u32 msr, u64 data);
|
|
int kvm_hv_vapic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data);
|
|
|
|
static inline bool kvm_hv_vapic_assist_page_enabled(struct kvm_vcpu *vcpu)
|
|
{
|
|
return vcpu->arch.hv_vapic & HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE;
|
|
}
|
|
|
|
int kvm_lapic_enable_pv_eoi(struct kvm_vcpu *vcpu, u64 data);
|
|
void kvm_lapic_init(void);
|
|
|
|
static inline u32 kvm_apic_get_reg(struct kvm_lapic *apic, int reg_off)
|
|
{
|
|
return *((u32 *) (apic->regs + reg_off));
|
|
}
|
|
|
|
extern struct static_key kvm_no_apic_vcpu;
|
|
|
|
static inline bool kvm_vcpu_has_lapic(struct kvm_vcpu *vcpu)
|
|
{
|
|
if (static_key_false(&kvm_no_apic_vcpu))
|
|
return vcpu->arch.apic;
|
|
return true;
|
|
}
|
|
|
|
extern struct static_key_deferred apic_hw_disabled;
|
|
|
|
static inline int kvm_apic_hw_enabled(struct kvm_lapic *apic)
|
|
{
|
|
if (static_key_false(&apic_hw_disabled.key))
|
|
return apic->vcpu->arch.apic_base & MSR_IA32_APICBASE_ENABLE;
|
|
return MSR_IA32_APICBASE_ENABLE;
|
|
}
|
|
|
|
extern struct static_key_deferred apic_sw_disabled;
|
|
|
|
static inline int kvm_apic_sw_enabled(struct kvm_lapic *apic)
|
|
{
|
|
if (static_key_false(&apic_sw_disabled.key))
|
|
return kvm_apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_APIC_ENABLED;
|
|
return APIC_SPIV_APIC_ENABLED;
|
|
}
|
|
|
|
static inline bool kvm_apic_present(struct kvm_vcpu *vcpu)
|
|
{
|
|
return kvm_vcpu_has_lapic(vcpu) && kvm_apic_hw_enabled(vcpu->arch.apic);
|
|
}
|
|
|
|
static inline int kvm_lapic_enabled(struct kvm_vcpu *vcpu)
|
|
{
|
|
return kvm_apic_present(vcpu) && kvm_apic_sw_enabled(vcpu->arch.apic);
|
|
}
|
|
|
|
static inline int apic_x2apic_mode(struct kvm_lapic *apic)
|
|
{
|
|
return apic->vcpu->arch.apic_base & X2APIC_ENABLE;
|
|
}
|
|
|
|
static inline bool kvm_apic_vid_enabled(struct kvm *kvm)
|
|
{
|
|
return kvm_x86_ops->vm_has_apicv(kvm);
|
|
}
|
|
|
|
static inline u16 apic_cluster_id(struct kvm_apic_map *map, u32 ldr)
|
|
{
|
|
u16 cid;
|
|
ldr >>= 32 - map->ldr_bits;
|
|
cid = (ldr >> map->cid_shift) & map->cid_mask;
|
|
|
|
BUG_ON(cid >= ARRAY_SIZE(map->logical_map));
|
|
|
|
return cid;
|
|
}
|
|
|
|
static inline u16 apic_logical_id(struct kvm_apic_map *map, u32 ldr)
|
|
{
|
|
ldr >>= (32 - map->ldr_bits);
|
|
return ldr & map->lid_mask;
|
|
}
|
|
|
|
static inline bool kvm_apic_has_events(struct kvm_vcpu *vcpu)
|
|
{
|
|
return vcpu->arch.apic->pending_events;
|
|
}
|
|
|
|
bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector);
|
|
|
|
#endif
|