From 14fa9c563c8f7be40b7c7b5e1003d3c4ad0a8936 Mon Sep 17 00:00:00 2001 From: dongshen Date: Thu, 19 Mar 2020 09:12:22 -0700 Subject: [PATCH] hv: define posted interrupt IRQs/vectors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a preparation patch for adding support for VT-d PI related vCPU scheduling. ACRN does not support vCPU migration, one vCPU always runs on the same pCPU, so PI's ndst is never changed after startup. VCPUs of a VM won’t share same pCPU. So the maximum possible number of VCPUs that can run on a pCPU is CONFIG_MAX_VM_NUM. Allocate unique Activation Notification Vectors (ANV) for each vCPU that belongs to the same pCPU, the ANVs need only be unique within each pCPU, not across all vCPUs. This reduces # of pre-allocated ANVs for posted interrupts to CONFIG_MAX_VM_NUM, and enables ACRN to avoid switching between active and wake-up vector values in the posted interrupt descriptor on vCPU scheduling state changes. A total of CONFIG_MAX_VM_NUM consecutive IRQs/vectors are reserved for posted interrupts use. The code first initializes vcpu->arch.pid.control.bits.nv dynamically (will be added in subsequent patch), the other code shall use vcpu->arch.pid.control.bits.nv instead of the hard-coded notification vectors. Rename some functions: apicv_post_intr --> apicv_trigger_pi_anv posted_intr_notification --> handle_pi_notification setup_posted_intr_notification --> setup_pi_notification Tracked-On: #4506 Signed-off-by: dongshen Reviewed-by: Eddie Dong --- hypervisor/arch/x86/cpu.c | 2 +- hypervisor/arch/x86/guest/vcpu.c | 2 +- hypervisor/arch/x86/guest/vlapic.c | 12 ++++----- hypervisor/arch/x86/guest/vmcs.c | 2 +- hypervisor/arch/x86/irq.c | 18 +++++++++++++- hypervisor/arch/x86/notify.c | 19 +++++++-------- hypervisor/include/arch/x86/irq.h | 39 +++++++++++++++++++++++++----- 7 files changed, 68 insertions(+), 26 deletions(-) diff --git a/hypervisor/arch/x86/cpu.c b/hypervisor/arch/x86/cpu.c index 1d48a3aaa..f06401056 100644 --- a/hypervisor/arch/x86/cpu.c +++ b/hypervisor/arch/x86/cpu.c @@ -229,7 +229,7 @@ void init_pcpu_post(uint16_t pcpu_id) timer_init(); setup_notification(); - setup_posted_intr_notification(); + setup_pi_notification(); if (init_iommu() != 0) { panic("failed to initialize iommu!"); diff --git a/hypervisor/arch/x86/guest/vcpu.c b/hypervisor/arch/x86/guest/vcpu.c index e5e469d8c..a7d10b44f 100644 --- a/hypervisor/arch/x86/guest/vcpu.c +++ b/hypervisor/arch/x86/guest/vcpu.c @@ -469,7 +469,7 @@ int32_t create_vcpu(uint16_t pcpu_id, struct acrn_vm *vm, struct acrn_vcpu **rtn * the "enable VPID" VM-execution control is 1, the current VPID * is the value of the VPID VM-execution control field in the VMCS. * - * This assignment guarantees a unique non-zero per vcpu vpid in runtime. + * This assignment guarantees a unique non-zero per vcpu vpid at runtime. */ vcpu->arch.vpid = 1U + (vm->vm_id * MAX_VCPUS_PER_VM) + vcpu->vcpu_id; diff --git a/hypervisor/arch/x86/guest/vlapic.c b/hypervisor/arch/x86/guest/vlapic.c index 510dda8d7..34dd3fa4a 100644 --- a/hypervisor/arch/x86/guest/vlapic.c +++ b/hypervisor/arch/x86/guest/vlapic.c @@ -95,10 +95,9 @@ static inline void vlapic_dump_isr(__unused const struct acrn_vlapic *vlapic, __ const struct acrn_apicv_ops *apicv_ops; -static bool -apicv_set_intr_ready(struct acrn_vlapic *vlapic, uint32_t vector); +static bool apicv_set_intr_ready(struct acrn_vlapic *vlapic, uint32_t vector); -static void apicv_post_intr(uint16_t dest_pcpu_id); +static void apicv_trigger_pi_anv(uint16_t dest_pcpu_id, uint32_t anv); static void vlapic_x2apic_self_ipi_handler(struct acrn_vlapic *vlapic); @@ -581,7 +580,7 @@ static void apicv_advanced_accept_intr(struct acrn_vlapic *vlapic, uint32_t vect bitmap_set_lock(ACRN_REQUEST_EVENT, &vcpu->arch.pending_req); if (get_pcpu_id() != pcpuid_from_vcpu(vcpu)) { - apicv_post_intr(pcpuid_from_vcpu(vcpu)); + apicv_trigger_pi_anv(pcpuid_from_vcpu(vcpu), (uint32_t)vcpu->arch.pid.control.bits.nv); } } } @@ -612,12 +611,13 @@ static void vlapic_accept_intr(struct acrn_vlapic *vlapic, uint32_t vector, bool * If pCPU in root-mode, virtual interrupt will be injected in next VM entry. * * @param[in] dest_pcpu_id Target CPU ID. + * @param[in] anv Activation Notification Vectors (ANV) * * @return None */ -static void apicv_post_intr(uint16_t dest_pcpu_id) +static void apicv_trigger_pi_anv(uint16_t dest_pcpu_id, uint32_t anv) { - send_single_ipi(dest_pcpu_id, POSTED_INTR_VECTOR); + send_single_ipi(dest_pcpu_id, anv); } /** diff --git a/hypervisor/arch/x86/guest/vmcs.c b/hypervisor/arch/x86/guest/vmcs.c index 9e2f0251d..28544e82d 100644 --- a/hypervisor/arch/x86/guest/vmcs.c +++ b/hypervisor/arch/x86/guest/vmcs.c @@ -352,7 +352,7 @@ static void init_exec_ctrl(struct acrn_vcpu *vcpu) exec_vmwrite64(VMX_EOI_EXIT3_FULL, 0UL); exec_vmwrite16(VMX_GUEST_INTR_STATUS, 0U); - exec_vmwrite16(VMX_POSTED_INTR_VECTOR, POSTED_INTR_VECTOR); + exec_vmwrite16(VMX_POSTED_INTR_VECTOR, (uint16_t)vcpu->arch.pid.control.bits.nv); exec_vmwrite64(VMX_PIR_DESC_ADDR_FULL, hva2hpa(get_pi_desc(vcpu))); } diff --git a/hypervisor/arch/x86/irq.c b/hypervisor/arch/x86/irq.c index dfe5b16c8..91193c59a 100644 --- a/hypervisor/arch/x86/irq.c +++ b/hypervisor/arch/x86/irq.c @@ -37,8 +37,10 @@ struct static_mapping_table { static struct static_mapping_table irq_static_mappings[NR_STATIC_MAPPINGS] = { {TIMER_IRQ, TIMER_VECTOR}, {NOTIFY_VCPU_IRQ, NOTIFY_VCPU_VECTOR}, - {POSTED_INTR_IRQ, POSTED_INTR_VECTOR}, {PMI_IRQ, PMI_VECTOR}, + + /* To be initialized at runtime in init_irq_descs() */ + [NR_STATIC_MAPPINGS_1 ... (NR_STATIC_MAPPINGS_1 + CONFIG_MAX_VM_NUM - 1U)] = {}, }; /* @@ -421,6 +423,20 @@ static void init_irq_descs(void) { uint32_t i; + /* + * Fill in #CONFIG_MAX_VM_NUM posted interrupt specific irq and vector pairs + * at runtime + */ + for (i = 0U; i < CONFIG_MAX_VM_NUM; i++) { + uint32_t idx = i + NR_STATIC_MAPPINGS_1; + + ASSERT(irq_static_mappings[idx].irq == 0U, ""); + ASSERT(irq_static_mappings[idx].vector == 0U, ""); + + irq_static_mappings[idx].irq = POSTED_INTR_IRQ + i; + irq_static_mappings[idx].vector = POSTED_INTR_VECTOR + i; + } + for (i = 0U; i < NR_IRQS; i++) { irq_desc_array[i].irq = i; irq_desc_array[i].vector = VECTOR_INVALID; diff --git a/hypervisor/arch/x86/notify.c b/hypervisor/arch/x86/notify.c index cbed7c7e3..4b031dace 100644 --- a/hypervisor/arch/x86/notify.c +++ b/hypervisor/arch/x86/notify.c @@ -98,21 +98,20 @@ void setup_notification(void) notification_irq, irq_to_vector(notification_irq)); } -static void posted_intr_notification(__unused uint32_t irq, __unused void *data) +static void handle_pi_notification(__unused uint32_t irq, __unused void *data) { - /* Dummy IRQ handler for case that Posted-Interrupt Notification - * is sent to vCPU in root mode(isn't running),interrupt will be - * picked up in next vmentry,do nothine here. - */ } /*pre-conditon: be called only by BSP initialization proccess*/ -void setup_posted_intr_notification(void) +void setup_pi_notification(void) { - if (request_irq(POSTED_INTR_IRQ, - posted_intr_notification, - NULL, IRQF_NONE) < 0) { - pr_err("Failed to setup posted-intr notification"); + uint32_t i; + + for (i = 0U; i < CONFIG_MAX_VM_NUM; i++) { + if (request_irq(POSTED_INTR_IRQ + i, handle_pi_notification, NULL, IRQF_NONE) < 0) { + pr_err("Failed to setup pi notification"); + break; + } } } diff --git a/hypervisor/include/arch/x86/irq.h b/hypervisor/include/arch/x86/irq.h index d0e6267fb..977ae0e3d 100644 --- a/hypervisor/include/arch/x86/irq.h +++ b/hypervisor/include/arch/x86/irq.h @@ -25,7 +25,24 @@ #define NR_IRQS 256U #define IRQ_INVALID 0xffffffffU -#define NR_STATIC_MAPPINGS (4U) +/* # of NR_STATIC_MAPPINGS_1 entries for timer, vcpu notify, and PMI */ +#define NR_STATIC_MAPPINGS_1 3U + +/* + * The static IRQ/Vector mapping table in irq.c consists of the following entries: + * # of NR_STATIC_MAPPINGS_1 entries for timer, vcpu notify, and PMI + * + * # of CONFIG_MAX_VM_NUM entries for posted interrupt notification, platform + * specific but known at build time: + * Allocate unique Activation Notification Vectors (ANV) for each vCPU that belongs + * to the same pCPU, the ANVs need only be unique within each pCPU, not across all + * vCPUs. The max numbers of vCPUs may be running on top of a pCPU is CONFIG_MAX_VM_NUM, + * since ACRN does not support 2 vCPUs of same VM running on top of same pCPU. + * This reduces # of pre-allocated ANVs for posted interrupts to CONFIG_MAX_VM_NUM, + * and enables ACRN to avoid switching between active and wake-up vector values + * in the posted interrupt descriptor on vCPU scheduling state changes. + */ +#define NR_STATIC_MAPPINGS (NR_STATIC_MAPPINGS_1 + CONFIG_MAX_VM_NUM) #define HYPERVISOR_CALLBACK_VHM_VECTOR 0xF3U @@ -39,13 +56,23 @@ #define TIMER_VECTOR (VECTOR_FIXED_START) #define NOTIFY_VCPU_VECTOR (VECTOR_FIXED_START + 1U) -#define POSTED_INTR_VECTOR (VECTOR_FIXED_START + 2U) -#define PMI_VECTOR (VECTOR_FIXED_START + 3U) +#define PMI_VECTOR (VECTOR_FIXED_START + 2U) +/* + * Starting vector for posted interrupts + * # of CONFIG_MAX_VM_NUM (POSTED_INTR_VECTOR ~ (POSTED_INTR_VECTOR + CONFIG_MAX_VM_NUM - 1U)) + * consecutive vectors reserved for posted interrupts + */ +#define POSTED_INTR_VECTOR (VECTOR_FIXED_START + NR_STATIC_MAPPINGS_1) #define TIMER_IRQ (NR_IRQS - 1U) #define NOTIFY_VCPU_IRQ (NR_IRQS - 2U) -#define POSTED_INTR_IRQ (NR_IRQS - 3U) -#define PMI_IRQ (NR_IRQS - 4U) +#define PMI_IRQ (NR_IRQS - 3U) +/* + * Starting IRQ for posted interrupts + * # of CONFIG_MAX_VM_NUM (POSTED_INTR_IRQ ~ (POSTED_INTR_IRQ + CONFIG_MAX_VM_NUM - 1U)) + * consecutive IRQs reserved for posted interrupts + */ +#define POSTED_INTR_IRQ (NR_IRQS - NR_STATIC_MAPPINGS_1 - CONFIG_MAX_VM_NUM) /* the maximum number of msi entry is 2048 according to PCI * local bus specification @@ -95,7 +122,7 @@ void init_default_irqs(uint16_t cpu_id); void dispatch_exception(struct intr_excp_ctx *ctx); void setup_notification(void); -void setup_posted_intr_notification(void); +void setup_pi_notification(void); typedef void (*spurious_handler_t)(uint32_t vector); extern spurious_handler_t spurious_handler;