|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v3 04/15] x86: implement data structure and CPU init flow for MBA
On Tue, Sep 05, 2017 at 05:32:26PM +0800, Yi Sun wrote:
> This patch implements main data structures of MBA.
>
> Like CAT features, MBA HW info has cos_max which means the max thrtl
> register number, and thrtl_max which means the max throttle value
> (delay value). It also has a flag to represent if the throttle
> value is linear or not.
>
> One thrtl register of MBA stores a throttle value for one or more
> domains. The throttle value means the transaction time between L2
> cache and next level memory to be delayed.
"The throttle value contains the delay between L2 cache and the next
cache level."
Seems better, but I'm not a native speaker anyway.
>
> This patch also implements init flow for MBA and register stub
> callback functions.
>
> Signed-off-by: Yi Sun <yi.y.sun@xxxxxxxxxxxxxxx>
> ---
> v3:
> - replace 'psr_val_type' to 'psr_type'. Also, change 'PSR_VAL_TYPE_MBA' to
> 'PSR_TYPE_MBA_THRTL'.
> (suggested by Roger Pau Monné)
> - replace 'MBA_LINEAR' to 'MBA_LINEAR_MASK' to make the name more clear.
> (suggested by Roger Pau Monné)
> - replase 'cat_info'/'mba_info' to 'cat'/'mba' to make the names shorter.
> (suggested by Roger Pau Monné)
> - change type of 'linear' to 'bool'.
> (suggested by Roger Pau Monné)
> - make format string of printf in one line.
> (suggested by Roger Pau Monné)
> v2:
> - modify commit message to replace 'cos register' to 'thrtl register' to
> make it accurate.
> (suggested by Chao Peng)
> - restore the place of the sentence to assign value to 'feat->cbm_len'
> because the MBA init flow is splitted out as a separate function in v1.
> (suggested by Chao Peng)
> - add comment to explain what the MBA thrtl defaul value '0' stands for.
> (suggested by Chao Peng)
> - check 'thrtl_max' under linear mode. It could not be euqal or larger
> than
> 100.
> (suggested by Chao Peng)
> v1:
> - rebase codes onto L2 CAT v15.
> - move comment to appropriate place.
> (suggested by Chao Peng)
> - implement 'mba_init_feature' and keep 'cat_init_feature'.
> (suggested by Chao Peng)
> - keep 'regs.b' into a local variable to avoid reading CPUID every time.
> (suggested by Chao Peng)
> ---
> xen/arch/x86/psr.c | 140
> ++++++++++++++++++++++++++++++++++------
> xen/include/asm-x86/msr-index.h | 1 +
> xen/include/asm-x86/psr.h | 2 +
> 3 files changed, 125 insertions(+), 18 deletions(-)
>
> diff --git a/xen/arch/x86/psr.c b/xen/arch/x86/psr.c
> index 4166a1c..10776d2 100644
> --- a/xen/arch/x86/psr.c
> +++ b/xen/arch/x86/psr.c
> @@ -27,13 +27,16 @@
> * - CMT Cache Monitoring Technology
> * - COS/CLOS Class of Service. Also mean COS registers.
> * - COS_MAX Max number of COS for the feature (minus 1)
> + * - MBA Memory Bandwidth Allocation
> * - MSRs Machine Specific Registers
> * - PSR Intel Platform Shared Resource
> + * - THRTL_MAX Max throttle value (delay value) of MBA
> */
>
> #define PSR_CMT (1u << 0)
> #define PSR_CAT (1u << 1)
> #define PSR_CDP (1u << 2)
> +#define PSR_MBA (1u << 3)
>
> #define CAT_CBM_LEN_MASK 0x1f
> #define CAT_COS_MAX_MASK 0xffff
> @@ -60,10 +63,14 @@
> */
> #define MAX_COS_NUM 2
>
> +#define MBA_LINEAR_MASK (1u << 2)
> +#define MBA_THRTL_MAX_MASK 0xfff
> +
> enum psr_feat_type {
> FEAT_TYPE_L3_CAT,
> FEAT_TYPE_L3_CDP,
> FEAT_TYPE_L2_CAT,
> + FEAT_TYPE_MBA,
> FEAT_TYPE_NUM,
> FEAT_TYPE_UNKNOWN,
> };
> @@ -71,7 +78,6 @@ enum psr_feat_type {
> /*
> * This structure represents one feature.
> * cos_max - The max COS registers number got through CPUID.
> - * cbm_len - The length of CBM got through CPUID.
> * cos_reg_val - Array to store the values of COS registers. One entry stores
> * the value of one COS register.
> * For L3 CAT and L2 CAT, one entry corresponds to one COS_ID.
> @@ -80,9 +86,23 @@ enum psr_feat_type {
> * cos_reg_val[1] (Code).
> */
> struct feat_node {
> - /* cos_max and cbm_len are common values for all features so far. */
> + /* cos_max is common values for all features so far. */
...common among all features...
> unsigned int cos_max;
> - unsigned int cbm_len;
> +
> + /* Feature specific HW info. */
> + union {
> + struct {
> + /* The length of CBM got through CPUID. */
> + unsigned int cbm_len;
> + } cat;
> +
> + struct {
> + /* The max throttling value got through CPUID. */
> + unsigned int thrtl_max;
> + bool linear;
> + } mba;
> + };
> +
> uint32_t cos_reg_val[MAX_COS_REG_CNT];
> };
>
> @@ -161,6 +181,7 @@ static DEFINE_PER_CPU(struct psr_assoc, psr_assoc);
> */
> static struct feat_node *feat_l3;
> static struct feat_node *feat_l2_cat;
> +static struct feat_node *feat_mba;
>
> /* Common functions */
> #define cat_default_val(len) (0xffffffff >> (32 - (len)))
> @@ -272,7 +293,7 @@ static bool psr_check_cbm(unsigned int cbm_len, unsigned
> long cbm)
> return true;
> }
>
> -/* CAT common functions implementation. */
> +/* Implementation of allocation features' functions. */
> static int cat_init_feature(const struct cpuid_leaf *regs,
> struct feat_node *feat,
> struct psr_socket_info *info,
> @@ -288,8 +309,8 @@ static int cat_init_feature(const struct cpuid_leaf *regs,
> if ( !regs->a || !regs->d )
> return -ENOENT;
>
> - feat->cbm_len = (regs->a & CAT_CBM_LEN_MASK) + 1;
> feat->cos_max = min(opt_cos_max, regs->d & CAT_COS_MAX_MASK);
> + feat->cat.cbm_len = (regs->a & CAT_CBM_LEN_MASK) + 1;
>
> switch ( type )
> {
> @@ -299,12 +320,12 @@ static int cat_init_feature(const struct cpuid_leaf
> *regs,
> return -ENOENT;
>
> /* We reserve cos=0 as default cbm (all bits within cbm_len are 1).
> */
> - feat->cos_reg_val[0] = cat_default_val(feat->cbm_len);
> + feat->cos_reg_val[0] = cat_default_val(feat->cat.cbm_len);
>
> wrmsrl((type == FEAT_TYPE_L3_CAT ?
> MSR_IA32_PSR_L3_MASK(0) :
> MSR_IA32_PSR_L2_MASK(0)),
> - cat_default_val(feat->cbm_len));
> + cat_default_val(feat->cat.cbm_len));
>
> break;
>
> @@ -319,11 +340,13 @@ static int cat_init_feature(const struct cpuid_leaf
> *regs,
> feat->cos_max = (feat->cos_max - 1) >> 1;
>
> /* We reserve cos=0 as default cbm (all bits within cbm_len are 1).
> */
> - get_cdp_code(feat, 0) = cat_default_val(feat->cbm_len);
> - get_cdp_data(feat, 0) = cat_default_val(feat->cbm_len);
> + get_cdp_code(feat, 0) = cat_default_val(feat->cat.cbm_len);
> + get_cdp_data(feat, 0) = cat_default_val(feat->cat.cbm_len);
>
> - wrmsrl(MSR_IA32_PSR_L3_MASK(0), cat_default_val(feat->cbm_len));
> - wrmsrl(MSR_IA32_PSR_L3_MASK(1), cat_default_val(feat->cbm_len));
> + wrmsrl(MSR_IA32_PSR_L3_MASK(0),
> + cat_default_val(feat->cat.cbm_len));
> + wrmsrl(MSR_IA32_PSR_L3_MASK(1),
> + cat_default_val(feat->cat.cbm_len));
> rdmsrl(MSR_IA32_PSR_L3_QOS_CFG, val);
> wrmsrl(MSR_IA32_PSR_L3_QOS_CFG,
> val | (1ull << PSR_L3_QOS_CDP_ENABLE_BIT));
> @@ -343,7 +366,50 @@ static int cat_init_feature(const struct cpuid_leaf
> *regs,
>
> printk(XENLOG_INFO "%s: enabled on socket %u, cos_max:%u, cbm_len:%u\n",
> cat_feat_name[type], cpu_to_socket(smp_processor_id()),
> - feat->cos_max, feat->cbm_len);
> + feat->cos_max, feat->cat.cbm_len);
> +
> + return 0;
> +}
> +
> +static int mba_init_feature(const struct cpuid_leaf *regs,
> + struct feat_node *feat,
> + struct psr_socket_info *info,
> + enum psr_feat_type type)
> +{
> + /* No valid value so do not enable feature. */
> + if ( !regs->a || !regs->d )
> + return -ENOENT;
> +
> + if ( type != FEAT_TYPE_MBA )
> + return -ENOENT;
You can join the two checks above in a single if.
> +
> + feat->cos_max = min(opt_cos_max, regs->d & CAT_COS_MAX_MASK);
> + if ( feat->cos_max < 1 )
> + return -ENOENT;
> +
> + feat->mba.thrtl_max = (regs->a & MBA_THRTL_MAX_MASK) + 1;
> +
> + if ( regs->c & MBA_LINEAR_MASK )
> + {
> + feat->mba.linear = true;
> +
> + if ( feat->mba.thrtl_max >= 100 )
> + return -ENOENT;
> + }
> +
> + /* We reserve cos=0 as default thrtl (0) which means no delay. */
> + feat->cos_reg_val[0] = 0;
AFAICT feat is allocated using xzalloc, so this will already be 0.
> + wrmsrl(MSR_IA32_PSR_MBA_MASK(0), 0);
> +
> + /* Add this feature into array. */
> + info->features[type] = feat;
> +
> + if ( !opt_cpu_info )
> + return 0;
> +
> + printk(XENLOG_INFO "MBA: enabled on socket %u, cos_max:%u, thrtl_max:%u,
> linear:%u.\n",
> + cpu_to_socket(smp_processor_id()),
> + feat->cos_max, feat->mba.thrtl_max, feat->mba.linear);
>
> return 0;
> }
> @@ -355,7 +421,7 @@ static bool cat_get_feat_info(const struct feat_node
> *feat,
> return false;
>
> data[PSR_INFO_IDX_COS_MAX] = feat->cos_max;
> - data[PSR_INFO_IDX_CAT_CBM_LEN] = feat->cbm_len;
> + data[PSR_INFO_IDX_CAT_CBM_LEN] = feat->cat.cbm_len;
> data[PSR_INFO_IDX_CAT_FLAG] = 0;
>
> return true;
> @@ -421,6 +487,26 @@ static const struct feat_props l2_cat_props = {
> .write_msr = l2_cat_write_msr,
> };
>
> +/* MBA props */
> +static bool mba_get_feat_info(const struct feat_node *feat,
> + uint32_t data[], unsigned int array_len)
> +{
> + return false;
> +}
> +
> +static void mba_write_msr(unsigned int cos, uint32_t val,
> + enum psr_type type)
> +{
> +}
> +
> +static const struct feat_props mba_props = {
> + .cos_num = 1,
> + .type[0] = PSR_TYPE_MBA_THRTL,
> + .alt_type = PSR_TYPE_UNKNOWN,
> + .get_feat_info = mba_get_feat_info,
> + .write_msr = mba_write_msr,
> +};
> +
> static void __init parse_psr_bool(char *s, char *value, char *feature,
> unsigned int mask)
> {
> @@ -456,6 +542,7 @@ static void __init parse_psr_param(char *s)
> parse_psr_bool(s, val_str, "cmt", PSR_CMT);
> parse_psr_bool(s, val_str, "cat", PSR_CAT);
> parse_psr_bool(s, val_str, "cdp", PSR_CDP);
> + parse_psr_bool(s, val_str, "mba", PSR_MBA);
>
> if ( val_str && !strcmp(s, "rmid_max") )
> opt_rmid_max = simple_strtoul(val_str, NULL, 0);
> @@ -862,7 +949,7 @@ static int insert_val_into_array(uint32_t val[],
> if ( array_len < props->cos_num )
> return -ENOSPC;
>
> - if ( !psr_check_cbm(feat->cbm_len, new_val) )
> + if ( !psr_check_cbm(feat->cat.cbm_len, new_val) )
> return -EINVAL;
>
> /*
> @@ -1380,6 +1467,10 @@ static int psr_cpu_prepare(void)
> (feat_l2_cat = xzalloc(struct feat_node)) == NULL )
> return -ENOMEM;
>
> + if ( feat_mba == NULL &&
> + (feat_mba = xzalloc(struct feat_node)) == NULL )
> + return -ENOMEM;
> +
> return 0;
> }
>
> @@ -1389,6 +1480,7 @@ static void psr_cpu_init(void)
> unsigned int socket, cpu = smp_processor_id();
> struct feat_node *feat;
> struct cpuid_leaf regs;
> + uint32_t reg_b;
Not sure of the benefit between using regs.b or reg_b (it's only 1
char shorter).
>
> if ( !psr_alloc_feat_enabled() || !boot_cpu_has(X86_FEATURE_PQE) )
> goto assoc_init;
> @@ -1407,7 +1499,8 @@ static void psr_cpu_init(void)
> spin_lock_init(&info->ref_lock);
>
> cpuid_count_leaf(PSR_CPUID_LEVEL_CAT, 0, ®s);
> - if ( regs.b & PSR_RESOURCE_TYPE_L3 )
> + reg_b = regs.b;
> + if ( reg_b & PSR_RESOURCE_TYPE_L3 )
> {
> cpuid_count_leaf(PSR_CPUID_LEVEL_CAT, 1, ®s);
>
> @@ -1428,8 +1521,7 @@ static void psr_cpu_init(void)
> }
> }
>
> - cpuid_count_leaf(PSR_CPUID_LEVEL_CAT, 0, ®s);
> - if ( regs.b & PSR_RESOURCE_TYPE_L2 )
> + if ( reg_b & PSR_RESOURCE_TYPE_L2 )
> {
> cpuid_count_leaf(PSR_CPUID_LEVEL_CAT, 2, ®s);
>
> @@ -1441,6 +1533,18 @@ static void psr_cpu_init(void)
> feat_l2_cat = feat;
> }
>
> + if ( reg_b & PSR_RESOURCE_TYPE_MBA )
> + {
> + cpuid_count_leaf(PSR_CPUID_LEVEL_CAT, 3, ®s);
> +
> + feat = feat_mba;
> + feat_mba = NULL;
> + if ( !mba_init_feature(®s, feat, info, FEAT_TYPE_MBA) )
Seems kind of pointless that mba_init_feature returns an error code
when it's ignored by it's callers. You could switch it to bool if you
are going to use it like that.
Thanks, Roger.
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
https://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |