diff --git a/hypervisor/arch/x86/Kconfig b/hypervisor/arch/x86/Kconfig index a25cca576..776d9c891 100644 --- a/hypervisor/arch/x86/Kconfig +++ b/hypervisor/arch/x86/Kconfig @@ -261,12 +261,12 @@ config HYPERV_ENABLED When set, the minimum set of TLFS functionality together with some performance enlightenments are enabled. -config CAT_ENABLED - bool "Enable CAT (Cache Allocation Technology)" +config RDT_ENABLED + bool "Enable RDT (Resource Director Technology)" default n help - When set in platforms that support CAT, hypervisor can allocate - various amount of last-level-cache (LLC) resources to VMs to achieve + When set in platforms that support RDT, hypervisor can allocate + various amount of HW resources such as L2 or/and L3 to VMs to achieve different Class of Service (COS, or CLOS). config GPU_SBDF diff --git a/hypervisor/arch/x86/cpu.c b/hypervisor/arch/x86/cpu.c index 7be1bb890..c05cbed31 100644 --- a/hypervisor/arch/x86/cpu.c +++ b/hypervisor/arch/x86/cpu.c @@ -153,10 +153,10 @@ void init_pcpu_pre(bool is_bsp) panic("System IOAPIC info is incorrect!"); } -#ifdef CONFIG_CAT_ENABLED - ret = init_cat_cap_info(); +#ifdef CONFIG_RDT_ENABLED + ret = init_rdt_cap_info(); if (ret != 0) { - panic("Platform CAT info is incorrect!"); + panic("Platform RDT info is incorrect!"); } #endif @@ -262,7 +262,9 @@ void init_pcpu_post(uint16_t pcpu_id) init_sched(pcpu_id); - setup_clos(pcpu_id); + if (!setup_clos(pcpu_id)) { + panic("CLOS resource MSRs setup incorrectly!"); + } enable_smep(); diff --git a/hypervisor/arch/x86/rdt.c b/hypervisor/arch/x86/rdt.c index 7beff71de..a002b56fe 100644 --- a/hypervisor/arch/x86/rdt.c +++ b/hypervisor/arch/x86/rdt.c @@ -12,79 +12,141 @@ #include #include #include +#include #include #include #include -struct cat_hw_info cat_cap_info = {false, 0U, 0U, 0U, 0U}; +static struct rdt_info res_cap_info[RDT_NUM_RESOURCES] = { + [RDT_RESOURCE_L3] = { + .bitmask = 0U, + .cbm_len = 0U, + .clos_max = 0U, + .res_id = RDT_RESID_L3, + .msr_base = MSR_IA32_L3_MASK_BASE, + .platform_clos_array = NULL + }, + [RDT_RESOURCE_L2] = { + .bitmask = 0U, + .cbm_len = 0U, + .clos_max = 0U, + .res_id = RDT_RESID_L2, + .msr_base = MSR_IA32_L2_MASK_BASE, + .platform_clos_array = NULL + }, +}; const uint16_t hv_clos = 0U; -uint16_t platform_clos_num = MAX_PLATFORM_CLOS_NUM; +/* RDT features can support different numbers of CLOS. Set the lowers numerical + * clos value (platform_clos_num) that is common between the resources as + * each resource's clos max value to have consistent allocation. + */ +const uint16_t platform_clos_num = MAX_PLATFORM_CLOS_NUM; -int32_t init_cat_cap_info(void) +static void rdt_read_cat_capability(int res) { uint32_t eax = 0U, ebx = 0U, ecx = 0U, edx = 0U; + + /* CPUID.(EAX=0x10,ECX=ResID):EAX[4:0] reports the length of CBM supported + * CPUID.(EAX=0x10,ECX=ResID):EBX[31:0] indicates shared cache mask bits + * that are used by other entities such as graphic and H/W outside processor. + * CPUID.(EAX=0x10,ECX=ResID):EDX[15:0] reports the maximun CLOS supported + */ + cpuid_subleaf(CPUID_RDT_ALLOCATION, res_cap_info[res].res_id, &eax, &ebx, &ecx, &edx); + res_cap_info[res].cbm_len = (uint16_t)((eax & 0xfU) + 1U); + res_cap_info[res].bitmask = ebx; + res_cap_info[res].clos_max = (uint16_t)(edx & 0xffffU) + 1; +} + +int32_t init_rdt_cap_info(void) +{ + uint8_t i; + uint32_t eax = 0U, ebx = 0U, ecx = 0U, edx = 0U; int32_t ret = 0; - if (pcpu_has_cap(X86_FEATURE_CAT)) { - cpuid_subleaf(CPUID_RSD_ALLOCATION, 0, &eax, &ebx, &ecx, &edx); - /* If support L3 CAT, EBX[1] is set */ + if (pcpu_has_cap(X86_FEATURE_RDT_A)) { + cpuid_subleaf(CPUID_RDT_ALLOCATION, 0, &eax, &ebx, &ecx, &edx); + + /* If HW supports L3 CAT, EBX[1] is set */ if ((ebx & 2U) != 0U) { - cat_cap_info.enabled = true; - cat_cap_info.res_id = CAT_RESID_L3; + rdt_read_cat_capability(RDT_RESOURCE_L3); } - /* If support L2 CAT, EBX[2] is set */ + /* If HW supports L2 CAT, EBX[2] is set */ if ((ebx & 4U) != 0U) { - cat_cap_info.enabled = true; - cat_cap_info.res_id = CAT_RESID_L2; + rdt_read_cat_capability(RDT_RESOURCE_L2); } - /* CPUID.(EAX=0x10,ECX=ResID):EAX[4:0] reports the length of CBM supported - * CPUID.(EAX=0x10,ECX=ResID):EBX[31:0] indicates the corresponding uints - * may be used by other entities such as graphic and H/W outside processor. - * CPUID.(EAX=0x10,ECX=ResID):EDX[15:0] reports the maximun CLOS supported - */ - cpuid_subleaf(CPUID_RSD_ALLOCATION, cat_cap_info.res_id, &eax, &ebx, &ecx, &edx); - cat_cap_info.cbm_len = (uint16_t)((eax & 0x1fU) + 1U); - cat_cap_info.bitmask = ebx; - cat_cap_info.clos_max = (uint16_t)(edx & 0xffffU); - - if ((platform_clos_num != 0U) && ((cat_cap_info.clos_max + 1U) != platform_clos_num)) { - pr_err("%s clos_max:%hu, platform_clos_num:%u\n", - __func__, cat_cap_info.clos_max, platform_clos_num); - ret = -EINVAL; + for (i = 0U; i < RDT_NUM_RESOURCES; i++) { + /* If clos_max == 0, the resource is not supported + * so skip checking and updating the clos_max + */ + if (res_cap_info[i].clos_max > 0U) { + if ((platform_clos_num == 0U) || (res_cap_info[i].clos_max < platform_clos_num)) { + pr_err("Invalid Res_ID %d clos max:platform_clos_max=%d, res_clos_max=%d\n", + res_cap_info[i].res_id, platform_clos_num, res_cap_info[i].clos_max); + ret = -EINVAL; + break; + } + /*Store user configured platform clos mask and MSR in the rdt_info struct*/ + if (res_cap_info[i].res_id == RDT_RESID_L3) { + res_cap_info[i].platform_clos_array = platform_l3_clos_array; + } else if (res_cap_info[i].res_id == RDT_RESID_L2) { + res_cap_info[i].platform_clos_array = platform_l2_clos_array; + } else { + res_cap_info[i].platform_clos_array = NULL; + } + } } } + return ret; +} + +static bool setup_res_clos_msr(uint16_t pcpu_id, struct platform_clos_info *res_clos_info) +{ + bool ret = true; + uint16_t i; + uint32_t msr_index; + uint64_t val; + + for (i = 0; i < platform_clos_num; i++) { + if ((fls32(res_clos_info->clos_mask) >= res_cap_info->cbm_len) || + (res_clos_info->msr_index != (res_cap_info->msr_base + i))) { + ret = false; + pr_err("Incorrect CLOS %d Mask=0x%x and(/or) MSR index=0x%x for Res_ID %d in board.c", + i, res_clos_info->clos_mask, res_clos_info->msr_index, res_cap_info[i].res_id); + break; + } + msr_index = res_clos_info->msr_index; + val = (uint64_t)res_clos_info->clos_mask; + msr_write_pcpu(msr_index, val, pcpu_id); + res_clos_info++; + } return ret; } -void setup_clos(uint16_t pcpu_id) +bool setup_clos(uint16_t pcpu_id) { + bool ret = true; uint16_t i; - uint32_t msr_index; - uint64_t val; - if (cat_cap_info.enabled) { - for (i = 0; i < platform_clos_num; i++) { - switch (cat_cap_info.res_id) { - case CAT_RESID_L2: - msr_index = platform_l2_clos_array[i].msr_index; - val = (uint64_t)platform_l2_clos_array[i].clos_mask; - msr_write_pcpu(msr_index, val, pcpu_id); + for (i = 0U; i < RDT_NUM_RESOURCES; i++) { + /* If clos_max == 0, the resource is not supported + * so skip setting up resource MSR. + */ + if (res_cap_info[i].clos_max > 0U) { + ret = setup_res_clos_msr(pcpu_id, res_cap_info[i].platform_clos_array); + if (!ret) break; - case CAT_RESID_L3: - msr_index = platform_l3_clos_array[i].msr_index; - val = (uint64_t)platform_l3_clos_array[i].clos_mask; - msr_write_pcpu(msr_index, val, pcpu_id); - break; - default: - pr_err("Invalid RDT resource configuration\n"); - } } - /* set hypervisor CAT clos */ + } + + if (ret) { + /* set hypervisor RDT resource clos */ msr_write_pcpu(MSR_IA32_PQR_ASSOC, clos2pqr_msr(hv_clos), pcpu_id); } + + return ret; } uint64_t clos2pqr_msr(uint16_t clos) @@ -99,5 +161,12 @@ uint64_t clos2pqr_msr(uint16_t clos) bool is_platform_rdt_capable(void) { - return cat_cap_info.enabled; + bool ret = false; + + if ((res_cap_info[RDT_RESOURCE_L3].clos_max > 0U) || + (res_cap_info[RDT_RESOURCE_L2].clos_max > 0U)) { + ret = true; + } + + return ret; } diff --git a/hypervisor/include/arch/x86/cpufeatures.h b/hypervisor/include/arch/x86/cpufeatures.h index 3cffd4225..6a7f87e49 100644 --- a/hypervisor/include/arch/x86/cpufeatures.h +++ b/hypervisor/include/arch/x86/cpufeatures.h @@ -74,7 +74,7 @@ #define X86_FEATURE_SMEP ((FEAT_7_0_EBX << 5U) + 7U) #define X86_FEATURE_ERMS ((FEAT_7_0_EBX << 5U) + 9U) #define X86_FEATURE_INVPCID ((FEAT_7_0_EBX << 5U) + 10U) -#define X86_FEATURE_CAT ((FEAT_7_0_EBX << 5U) + 15U) +#define X86_FEATURE_RDT_A ((FEAT_7_0_EBX << 5U) + 15U) #define X86_FEATURE_SMAP ((FEAT_7_0_EBX << 5U) + 20U) #define X86_FEATURE_CLFLUSHOPT ((FEAT_7_0_EBX << 5U) + 23U) diff --git a/hypervisor/include/arch/x86/cpuid.h b/hypervisor/include/arch/x86/cpuid.h index 329b05c40..130b37bd5 100644 --- a/hypervisor/include/arch/x86/cpuid.h +++ b/hypervisor/include/arch/x86/cpuid.h @@ -114,7 +114,7 @@ #define CPUID_SERIALNUM 3U #define CPUID_EXTEND_FEATURE 7U #define CPUID_XSAVE_FEATURES 0xDU -#define CPUID_RSD_ALLOCATION 0x10U +#define CPUID_RDT_ALLOCATION 0x10U #define CPUID_MAX_EXTENDED_FUNCTION 0x80000000U #define CPUID_EXTEND_FUNCTION_1 0x80000001U #define CPUID_EXTEND_FUNCTION_2 0x80000002U diff --git a/hypervisor/include/arch/x86/rdt.h b/hypervisor/include/arch/x86/rdt.h index bfde80a72..4c471231d 100644 --- a/hypervisor/include/arch/x86/rdt.h +++ b/hypervisor/include/arch/x86/rdt.h @@ -7,26 +7,32 @@ #ifndef RDT_H #define RDT_H -/* The intel Resource Director Tech(RDT) based Cache Allocation Tech support */ -struct cat_hw_info { - bool enabled; /* If L2/L3 CAT enabled */ - uint32_t bitmask; /* Used by other entities */ - uint16_t cbm_len; /* Length of Cache mask in bits */ - uint16_t clos_max; /* Maximum CLOS supported, the number of cache masks */ +enum { + RDT_RESOURCE_L3, + RDT_RESOURCE_L2, - uint32_t res_id; + /* Must be the last */ + RDT_NUM_RESOURCES, }; -extern struct cat_hw_info cat_cap_info; +#define RDT_RESID_L3 1U +#define RDT_RESID_L2 2U + extern const uint16_t hv_clos; -extern uint16_t platform_clos_num; -void setup_clos(uint16_t pcpu_id); +extern const uint16_t platform_clos_num; +/* The intel Resource Director Tech(RDT) based Allocation Tech support */ +struct rdt_info { + uint32_t bitmask; /* Shared CLOS bitmask used by other entities */ + uint16_t cbm_len; /* Length of Cache mask in bits */ + uint16_t clos_max; /* Maximum CLOS supported, 0 indicates resource is not supported.*/ + uint32_t res_id; + uint32_t msr_base; /* MSR base to program clos mask*/ + struct platform_clos_info *platform_clos_array; /* user configured mask and MSR info for each CLOS*/ +}; -#define CAT_RESID_L3 1U -#define CAT_RESID_L2 2U - -int32_t init_cat_cap_info(void); +int32_t init_rdt_cap_info(void); +bool setup_clos(uint16_t pcpu_id); uint64_t clos2pqr_msr(uint16_t clos); bool is_platform_rdt_capable(void);