d588bb9be1
With IPI virtualization enabled, the processor emulates writes to APIC registers that would send IPIs. The processor sets the bit corresponding to the vector in target vCPU's PIR and may send a notification (IPI) specified by NDST and NV fields in target vCPU's Posted-Interrupt Descriptor (PID). It is similar to what IOMMU engine does when dealing with posted interrupt from devices. A PID-pointer table is used by the processor to locate the PID of a vCPU with the vCPU's APIC ID. The table size depends on maximum APIC ID assigned for current VM session from userspace. Allocating memory for PID-pointer table is deferred to vCPU creation, because irqchip mode and VM-scope maximum APIC ID is settled at that point. KVM can skip PID-pointer table allocation if !irqchip_in_kernel(). Like VT-d PI, if a vCPU goes to blocked state, VMM needs to switch its notification vector to wakeup vector. This can ensure that when an IPI for blocked vCPUs arrives, VMM can get control and wake up blocked vCPUs. And if a VCPU is preempted, its posted interrupt notification is suppressed. Note that IPI virtualization can only virualize physical-addressing, flat mode, unicast IPIs. Sending other IPIs would still cause a trap-like APIC-write VM-exit and need to be handled by VMM. Signed-off-by: Chao Gao <chao.gao@intel.com> Signed-off-by: Zeng Guang <guang.zeng@intel.com> Message-Id: <20220419154510.11938-1-guang.zeng@intel.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
107 lines
2.5 KiB
C
107 lines
2.5 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef __KVM_X86_VMX_POSTED_INTR_H
|
|
#define __KVM_X86_VMX_POSTED_INTR_H
|
|
|
|
#define POSTED_INTR_ON 0
|
|
#define POSTED_INTR_SN 1
|
|
|
|
#define PID_TABLE_ENTRY_VALID 1
|
|
|
|
/* Posted-Interrupt Descriptor */
|
|
struct pi_desc {
|
|
u32 pir[8]; /* Posted interrupt requested */
|
|
union {
|
|
struct {
|
|
/* bit 256 - Outstanding Notification */
|
|
u16 on : 1,
|
|
/* bit 257 - Suppress Notification */
|
|
sn : 1,
|
|
/* bit 271:258 - Reserved */
|
|
rsvd_1 : 14;
|
|
/* bit 279:272 - Notification Vector */
|
|
u8 nv;
|
|
/* bit 287:280 - Reserved */
|
|
u8 rsvd_2;
|
|
/* bit 319:288 - Notification Destination */
|
|
u32 ndst;
|
|
};
|
|
u64 control;
|
|
};
|
|
u32 rsvd[6];
|
|
} __aligned(64);
|
|
|
|
static inline bool pi_test_and_set_on(struct pi_desc *pi_desc)
|
|
{
|
|
return test_and_set_bit(POSTED_INTR_ON,
|
|
(unsigned long *)&pi_desc->control);
|
|
}
|
|
|
|
static inline bool pi_test_and_clear_on(struct pi_desc *pi_desc)
|
|
{
|
|
return test_and_clear_bit(POSTED_INTR_ON,
|
|
(unsigned long *)&pi_desc->control);
|
|
}
|
|
|
|
static inline bool pi_test_and_clear_sn(struct pi_desc *pi_desc)
|
|
{
|
|
return test_and_clear_bit(POSTED_INTR_SN,
|
|
(unsigned long *)&pi_desc->control);
|
|
}
|
|
|
|
static inline bool pi_test_and_set_pir(int vector, struct pi_desc *pi_desc)
|
|
{
|
|
return test_and_set_bit(vector, (unsigned long *)pi_desc->pir);
|
|
}
|
|
|
|
static inline bool pi_is_pir_empty(struct pi_desc *pi_desc)
|
|
{
|
|
return bitmap_empty((unsigned long *)pi_desc->pir, NR_VECTORS);
|
|
}
|
|
|
|
static inline void pi_set_sn(struct pi_desc *pi_desc)
|
|
{
|
|
set_bit(POSTED_INTR_SN,
|
|
(unsigned long *)&pi_desc->control);
|
|
}
|
|
|
|
static inline void pi_set_on(struct pi_desc *pi_desc)
|
|
{
|
|
set_bit(POSTED_INTR_ON,
|
|
(unsigned long *)&pi_desc->control);
|
|
}
|
|
|
|
static inline void pi_clear_on(struct pi_desc *pi_desc)
|
|
{
|
|
clear_bit(POSTED_INTR_ON,
|
|
(unsigned long *)&pi_desc->control);
|
|
}
|
|
|
|
static inline void pi_clear_sn(struct pi_desc *pi_desc)
|
|
{
|
|
clear_bit(POSTED_INTR_SN,
|
|
(unsigned long *)&pi_desc->control);
|
|
}
|
|
|
|
static inline bool pi_test_on(struct pi_desc *pi_desc)
|
|
{
|
|
return test_bit(POSTED_INTR_ON,
|
|
(unsigned long *)&pi_desc->control);
|
|
}
|
|
|
|
static inline bool pi_test_sn(struct pi_desc *pi_desc)
|
|
{
|
|
return test_bit(POSTED_INTR_SN,
|
|
(unsigned long *)&pi_desc->control);
|
|
}
|
|
|
|
void vmx_vcpu_pi_load(struct kvm_vcpu *vcpu, int cpu);
|
|
void vmx_vcpu_pi_put(struct kvm_vcpu *vcpu);
|
|
void pi_wakeup_handler(void);
|
|
void __init pi_init_cpu(int cpu);
|
|
bool pi_has_pending_interrupt(struct kvm_vcpu *vcpu);
|
|
int vmx_pi_update_irte(struct kvm *kvm, unsigned int host_irq,
|
|
uint32_t guest_irq, bool set);
|
|
void vmx_pi_start_assignment(struct kvm *kvm);
|
|
|
|
#endif /* __KVM_X86_VMX_POSTED_INTR_H */
|