From ddfcb8c3fc27e342002cf43a024a3c822d141f5f Mon Sep 17 00:00:00 2001 From: Zhangwei6 Date: Wed, 30 Aug 2023 08:18:24 +0800 Subject: [PATCH] hv: enable thermal lvt interrupt This patch can fetch the thermal lvt irq and propagate it to VM. At this stage we support the case that there is only one VM governing thermal. And we pass the hardware thermal irq to this VM. First, we register the handler for thermal lvt interrupt, its irq vector is THERMAL_VECTOR and the handler is thermal_irq_handler(). Then, when a thermal irq occurs, it flags the SOFTIRQ_THERMAL bit of softirq_pending, This bit triggers the thermal_softirq() function. And this function will inject the virtual thermal irq to VM. Tracked-On: #8595 Signed-off-by: Zhangwei6 Reviewed-by: Junjie Mao --- hypervisor/Makefile | 2 + hypervisor/arch/x86/cpu.c | 3 ++ hypervisor/arch/x86/guest/vcpu.c | 10 +++++ hypervisor/arch/x86/guest/virq.c | 8 ++++ hypervisor/arch/x86/hw_thermal.c | 39 ++++++++++++++++++++ hypervisor/arch/x86/irq.c | 1 + hypervisor/common/thermal.c | 35 ++++++++++++++++++ hypervisor/include/arch/x86/asm/cpu.h | 6 +++ hypervisor/include/arch/x86/asm/guest/virq.h | 11 ++++++ hypervisor/include/arch/x86/asm/irq.h | 4 +- hypervisor/include/common/softirq.h | 3 +- hypervisor/include/common/thermal.h | 17 +++++++++ hypervisor/include/hw/hw_thermal.h | 14 +++++++ 13 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 hypervisor/arch/x86/hw_thermal.c create mode 100644 hypervisor/common/thermal.c create mode 100644 hypervisor/include/common/thermal.h create mode 100644 hypervisor/include/hw/hw_thermal.h diff --git a/hypervisor/Makefile b/hypervisor/Makefile index 8614c307a..c59594fa3 100644 --- a/hypervisor/Makefile +++ b/hypervisor/Makefile @@ -219,6 +219,7 @@ HW_C_SRCS += arch/x86/exception.c HW_C_SRCS += arch/x86/irq.c HW_C_SRCS += arch/x86/tsc.c HW_C_SRCS += arch/x86/tsc_deadline_timer.c +HW_C_SRCS += arch/x86/hw_thermal.c HW_C_SRCS += arch/x86/vmx.c HW_C_SRCS += arch/x86/cpu_state_tbl.c HW_C_SRCS += arch/x86/pm.c @@ -230,6 +231,7 @@ HW_C_SRCS += arch/x86/sgx.c HW_C_SRCS += common/ticks.c HW_C_SRCS += common/delay.c HW_C_SRCS += common/timer.c +HW_C_SRCS += common/thermal.c HW_C_SRCS += common/irq.c HW_C_SRCS += common/softirq.c HW_C_SRCS += common/schedule.c diff --git a/hypervisor/arch/x86/cpu.c b/hypervisor/arch/x86/cpu.c index 9b68a8d98..a8ecd0d4d 100644 --- a/hypervisor/arch/x86/cpu.c +++ b/hypervisor/arch/x86/cpu.c @@ -37,6 +37,7 @@ #include #include #include +#include #define CPU_UP_TIMEOUT 100U /* millisecond */ #define CPU_DOWN_TIMEOUT 100U /* millisecond */ @@ -268,6 +269,7 @@ void init_pcpu_post(uint16_t pcpu_id) init_interrupt(BSP_CPU_ID); timer_init(); + thermal_init(); setup_notification(); setup_pi_notification(); @@ -309,6 +311,7 @@ void init_pcpu_post(uint16_t pcpu_id) init_interrupt(pcpu_id); timer_init(); + thermal_init(); ptdev_init(); } diff --git a/hypervisor/arch/x86/guest/vcpu.c b/hypervisor/arch/x86/guest/vcpu.c index bc48c4d95..8dcc833b5 100755 --- a/hypervisor/arch/x86/guest/vcpu.c +++ b/hypervisor/arch/x86/guest/vcpu.c @@ -572,6 +572,16 @@ int32_t create_vcpu(uint16_t pcpu_id, struct acrn_vm *vm, struct acrn_vcpu **rtn */ vcpu->arch.vpid = ALLOCATED_MIN_L1_VPID + (vm->vm_id * MAX_VCPUS_PER_VM) + vcpu->vcpu_id; + /* + * There are two locally independent writing operations, namely the + * assignment of vcpu->vm and vcpu_array[]. Compilers may optimize + * and reorder writing operations while users of vcpu_array[] may + * assume the presence of vcpu->vm. A compiler barrier is added here + * to prevent compiler reordering, ensuring that assignments to + * vcpu->vm precede vcpu_array[]. + */ + cpu_compiler_barrier(); + /* * ACRN uses the following approach to manage VT-d PI notification vectors: * Allocate unique Activation Notification Vectors (ANV) for each vCPU that diff --git a/hypervisor/arch/x86/guest/virq.c b/hypervisor/arch/x86/guest/virq.c index 8b8f5dd9f..b36ce6316 100644 --- a/hypervisor/arch/x86/guest/virq.c +++ b/hypervisor/arch/x86/guest/virq.c @@ -302,6 +302,14 @@ void vcpu_inject_ss(struct acrn_vcpu *vcpu) (void)vcpu_queue_exception(vcpu, IDT_SS, 0); } +/* Inject thermal sensor interrupt to guest */ +void vcpu_inject_thermal_interrupt(struct acrn_vcpu *vcpu) +{ + if (is_vtm_configured(vcpu->vm)) { + (void)vlapic_set_local_intr(vcpu->vm, vcpu->vcpu_id, APIC_LVT_THERMAL); + }; +} + int32_t interrupt_window_vmexit_handler(struct acrn_vcpu *vcpu) { TRACE_2L(TRACE_VMEXIT_INTERRUPT_WINDOW, 0UL, 0UL); diff --git a/hypervisor/arch/x86/hw_thermal.c b/hypervisor/arch/x86/hw_thermal.c new file mode 100644 index 000000000..a48f12b68 --- /dev/null +++ b/hypervisor/arch/x86/hw_thermal.c @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2023 Intel Corporation. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* run in interrupt context */ +static void thermal_irq_handler(__unused uint32_t irq, __unused void *data) +{ + fire_softirq(SOFTIRQ_THERMAL); +} + +void init_hw_thermal(void) +{ + int32_t retval = 0; + + if (get_pcpu_id() == BSP_CPU_ID) { + retval = request_irq(THERMAL_IRQ, thermal_irq_handler, NULL, IRQF_NONE); + if (retval < 0) { + pr_err("Thermal irq setup failed\n"); + } + } + + if (retval >= 0) { + uint32_t val = THERMAL_VECTOR; + + msr_write(MSR_IA32_EXT_APIC_LVT_THERMAL, val); + } +} diff --git a/hypervisor/arch/x86/irq.c b/hypervisor/arch/x86/irq.c index b2fee20d8..8f064bd9c 100644 --- a/hypervisor/arch/x86/irq.c +++ b/hypervisor/arch/x86/irq.c @@ -32,6 +32,7 @@ static struct { uint32_t vector; } irq_static_mappings[NR_STATIC_MAPPINGS] = { {TIMER_IRQ, TIMER_VECTOR}, + {THERMAL_IRQ, THERMAL_VECTOR}, {NOTIFY_VCPU_IRQ, NOTIFY_VCPU_VECTOR}, {PMI_IRQ, PMI_VECTOR}, diff --git a/hypervisor/common/thermal.c b/hypervisor/common/thermal.c new file mode 100644 index 000000000..ef9502333 --- /dev/null +++ b/hypervisor/common/thermal.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2023 Intel Corporation. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include +#include +#include +#include + +static void thermal_softirq(uint16_t pcpu_id) +{ + struct acrn_vcpu *vcpu; + uint32_t idx; + + for (idx = 0; idx < CONFIG_MAX_VM_NUM; idx++) { + vcpu = per_cpu(vcpu_array, pcpu_id)[idx]; + if (vcpu != NULL) { + vcpu_inject_thermal_interrupt(vcpu); + } + } +} + +void thermal_init(void) +{ + uint16_t pcpu_id = get_pcpu_id(); + + if (pcpu_id == BSP_CPU_ID) { + register_softirq(SOFTIRQ_THERMAL, thermal_softirq); + } + + init_hw_thermal(); +} diff --git a/hypervisor/include/arch/x86/asm/cpu.h b/hypervisor/include/arch/x86/asm/cpu.h index 7028384a1..2c14f794d 100755 --- a/hypervisor/include/arch/x86/asm/cpu.h +++ b/hypervisor/include/arch/x86/asm/cpu.h @@ -589,6 +589,12 @@ static inline void cpu_memory_barrier(void) asm volatile ("mfence\n" : : : "memory"); } +/* Prevents compilers from reordering read/write access across this barrier */ +static inline void cpu_compiler_barrier(void) +{ + asm volatile ("" : : : "memory"); +} + static inline void invlpg(unsigned long addr) { asm volatile("invlpg (%0)" ::"r" (addr) : "memory"); diff --git a/hypervisor/include/arch/x86/asm/guest/virq.h b/hypervisor/include/arch/x86/asm/guest/virq.h index aee60df4f..8836ae10a 100644 --- a/hypervisor/include/arch/x86/asm/guest/virq.h +++ b/hypervisor/include/arch/x86/asm/guest/virq.h @@ -90,6 +90,17 @@ void vcpu_inject_ud(struct acrn_vcpu *vcpu); * @pre vcpu != NULL */ void vcpu_inject_ss(struct acrn_vcpu *vcpu); + +/** + * @brief Inject thermal sensor interrupt to guest. + * + * @param[in] vcpu Pointer to vCPU. + * + * @return None + * + * @pre vcpu != NULL + */ +void vcpu_inject_thermal_interrupt(struct acrn_vcpu *vcpu); void vcpu_make_request(struct acrn_vcpu *vcpu, uint16_t eventid); /* diff --git a/hypervisor/include/arch/x86/asm/irq.h b/hypervisor/include/arch/x86/asm/irq.h index 2958848fe..51c373b82 100644 --- a/hypervisor/include/arch/x86/asm/irq.h +++ b/hypervisor/include/arch/x86/asm/irq.h @@ -22,7 +22,7 @@ #define VECTOR_INVALID (NR_MAX_VECTOR + 1U) /* # of NR_STATIC_MAPPINGS_1 entries for timer, vcpu notify, and PMI */ -#define NR_STATIC_MAPPINGS_1 3U +#define NR_STATIC_MAPPINGS_1 4U /* * The static IRQ/Vector mapping table in irq.c consists of the following entries: @@ -53,6 +53,7 @@ #define TIMER_VECTOR (VECTOR_FIXED_START) #define NOTIFY_VCPU_VECTOR (VECTOR_FIXED_START + 1U) #define PMI_VECTOR (VECTOR_FIXED_START + 2U) +#define THERMAL_VECTOR (VECTOR_FIXED_START + 3U) /* * Starting vector for posted interrupts * # of CONFIG_MAX_VM_NUM (POSTED_INTR_VECTOR ~ (POSTED_INTR_VECTOR + CONFIG_MAX_VM_NUM - 1U)) @@ -63,6 +64,7 @@ #define TIMER_IRQ (NR_IRQS - 1U) #define NOTIFY_VCPU_IRQ (NR_IRQS - 2U) #define PMI_IRQ (NR_IRQS - 3U) +#define THERMAL_IRQ (NR_IRQS - 4U) /* * Starting IRQ for posted interrupts * # of CONFIG_MAX_VM_NUM (POSTED_INTR_IRQ ~ (POSTED_INTR_IRQ + CONFIG_MAX_VM_NUM - 1U)) diff --git a/hypervisor/include/common/softirq.h b/hypervisor/include/common/softirq.h index cab6de392..27bfe7bf5 100644 --- a/hypervisor/include/common/softirq.h +++ b/hypervisor/include/common/softirq.h @@ -9,7 +9,8 @@ #define SOFTIRQ_TIMER 0U #define SOFTIRQ_PTDEV 1U -#define NR_SOFTIRQS 2U +#define SOFTIRQ_THERMAL 2U +#define NR_SOFTIRQS 3U typedef void (*softirq_handler)(uint16_t cpu_id); diff --git a/hypervisor/include/common/thermal.h b/hypervisor/include/common/thermal.h new file mode 100644 index 000000000..c9789788f --- /dev/null +++ b/hypervisor/include/common/thermal.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) 2023 Intel Corporation. + *- + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef COMMON_THERMAL_H +#define COMMON_THERMAL_H + +/** + * @brief Initialize thermal. + * + * @return None + */ +void thermal_init(void); + +#endif /* COMMON_THERMAL_H */ diff --git a/hypervisor/include/hw/hw_thermal.h b/hypervisor/include/hw/hw_thermal.h new file mode 100644 index 000000000..34a8b15ed --- /dev/null +++ b/hypervisor/include/hw/hw_thermal.h @@ -0,0 +1,14 @@ +/* + * Copyright (C) 2023 Intel Corporation. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef HW_THERMAL_H +#define HW_THERMAL_H + +#include + +void init_hw_thermal(void); + +#endif /* HW_THERMAL_H */