HV: Generalize RDT infrastructure and fix RDT

cache configuration.

This patch creates a generic infrastructure for
RDT resources instead of just L2 or L3 cache. This
patch also fixes L3 CAT config overwrite by L2 in
cases where both L2 and L3 CAT are supported.

Tracked-On: #3715
Signed-off-by: Vijay Dhanraj <vijay.dhanraj@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Vijay Dhanraj 2020-02-17 12:50:19 -08:00 committed by wenlingz
parent 887e3813bc
commit d0665fe220
6 changed files with 146 additions and 69 deletions

View File

@ -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

View File

@ -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();

View File

@ -12,79 +12,141 @@
#include <errno.h>
#include <logmsg.h>
#include <rdt.h>
#include <bits.h>
#include <board.h>
#include <vm_config.h>
#include <msr.h>
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;
}

View File

@ -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)

View File

@ -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

View File

@ -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);