[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [v2 1/3] x86: refactor psr implementation in hypervisor.
On Thu, Sep 22, 2016 at 10:15:20AM +0800, Yi Sun wrote: > Current psr.c is designed for supporting L3 CAT/CDP. It has many > limitations to add new feature. Considering to support more PSR > features, we need refactor PSR implementation to make it more > flexible and fulfill the principle, open for extension but closed > for modification. > > The core of the refactoring is to abstract the common actions and > encapsulate them into "struct feat_ops". The detailed steps to add > a new feature are described at the head of psr.c. > > Signed-off-by: Yi Sun <yi.y.sun@xxxxxxxxxxxxxxx> > > --- > Changed since v1: > * sysctl.c > - Interface change for abstraction requirement. > * psr.c > - Function and variables names are changed to express accurately. > - Fix code style issues. > - Fix imprecise comments. > - Add one callback function, get_cos_num(), to fulfill the > abstraction requirement. > - Divide get_old_set_new() callback functions into two functions: > get_old_val() and set_new_val() make it more primitive. > - Change feat_info type from an array to union. > - Adjust some functions to replace if to switch to make them > clearer. > - Replace custom list management to system. > - Use 'const' to make codes more safe. > * psr.h > - Change 'enum mask_type' to 'enum psr_val_type' to express > more accurate. > - Change parameters of psr_get_info() to fulfill abstraction > requirement. > --- > xen/arch/x86/domctl.c | 36 +- > xen/arch/x86/psr.c | 1105 > +++++++++++++++++++++++++++++++++++---------- Whoa. 1K changes. This is a dense patch. > xen/arch/x86/sysctl.c | 14 +- > xen/include/asm-x86/psr.h | 20 +- > 4 files changed, 903 insertions(+), 272 deletions(-) > > diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c > index 2a2fe04..c53d819 100644 > --- a/xen/arch/x86/domctl.c > +++ b/xen/arch/x86/domctl.c > @@ -1386,41 +1386,41 @@ long arch_do_domctl( > switch ( domctl->u.psr_cat_op.cmd ) > { > case XEN_DOMCTL_PSR_CAT_OP_SET_L3_CBM: > - ret = psr_set_l3_cbm(d, domctl->u.psr_cat_op.target, > - domctl->u.psr_cat_op.data, > - PSR_CBM_TYPE_L3); > + ret = psr_set_val(d, domctl->u.psr_cat_op.target, > + domctl->u.psr_cat_op.data, > + PSR_MASK_TYPE_L3_CBM); > break; > > case XEN_DOMCTL_PSR_CAT_OP_SET_L3_CODE: > - ret = psr_set_l3_cbm(d, domctl->u.psr_cat_op.target, > - domctl->u.psr_cat_op.data, > - PSR_CBM_TYPE_L3_CODE); > + ret = psr_set_val(d, domctl->u.psr_cat_op.target, > + domctl->u.psr_cat_op.data, > + PSR_MASK_TYPE_L3_CODE); > break; > > case XEN_DOMCTL_PSR_CAT_OP_SET_L3_DATA: > - ret = psr_set_l3_cbm(d, domctl->u.psr_cat_op.target, > - domctl->u.psr_cat_op.data, > - PSR_CBM_TYPE_L3_DATA); > + ret = psr_set_val(d, domctl->u.psr_cat_op.target, > + domctl->u.psr_cat_op.data, > + PSR_MASK_TYPE_L3_DATA); > break; > > case XEN_DOMCTL_PSR_CAT_OP_GET_L3_CBM: > - ret = psr_get_l3_cbm(d, domctl->u.psr_cat_op.target, > - &domctl->u.psr_cat_op.data, > - PSR_CBM_TYPE_L3); > + ret = psr_get_val(d, domctl->u.psr_cat_op.target, > + &domctl->u.psr_cat_op.data, > + PSR_MASK_TYPE_L3_CBM); > copyback = 1; > break; > > case XEN_DOMCTL_PSR_CAT_OP_GET_L3_CODE: > - ret = psr_get_l3_cbm(d, domctl->u.psr_cat_op.target, > - &domctl->u.psr_cat_op.data, > - PSR_CBM_TYPE_L3_CODE); > + ret = psr_get_val(d, domctl->u.psr_cat_op.target, > + &domctl->u.psr_cat_op.data, > + PSR_MASK_TYPE_L3_CODE); > copyback = 1; > break; > > case XEN_DOMCTL_PSR_CAT_OP_GET_L3_DATA: > - ret = psr_get_l3_cbm(d, domctl->u.psr_cat_op.target, > - &domctl->u.psr_cat_op.data, > - PSR_CBM_TYPE_L3_DATA); > + ret = psr_get_val(d, domctl->u.psr_cat_op.target, > + &domctl->u.psr_cat_op.data, > + PSR_MASK_TYPE_L3_DATA); > copyback = 1; > break; > > diff --git a/xen/arch/x86/psr.c b/xen/arch/x86/psr.c > index 0b5073c..99e4c78 100644 > --- a/xen/arch/x86/psr.c > +++ b/xen/arch/x86/psr.c > @@ -17,28 +17,159 @@ > #include <xen/cpu.h> > #include <xen/err.h> > #include <xen/sched.h> > +#include <xen/list.h> > #include <asm/psr.h> > > #define PSR_CMT (1<<0) > #define PSR_CAT (1<<1) > #define PSR_CDP (1<<2) > > -struct psr_cat_cbm { > +/* > + * To add a new PSR feature, please follow below steps: > + * 1. Implement feature specific callback functions listed in > + * "struct feat_ops"; > + * 2. Implement a feature specific "struct feat_ops" object and register > + * feature specific callback functions into it; > + * 3. Delcare feat_list object for the feature and malloc memory for it > + * in cpu_prepare_work(). Correspondingly, free them in > + * free_feature(); > + * 4. Add feature initialization codes in cpu_init_work(). > + */ > + > +struct feat_list; > +struct psr_socket_info; > + > +/* Every feature enabled should implement such ops and callback functions. */ should means it can choose to implement 0 of them. Perhaps MUST ? Or at least mention which ones MUST be implemented? > +struct feat_ops { > + /* > + * init_feature is used in cpu initialization process to do feature > + * specific initialization works. > + */ > + void (*init_feature)(unsigned int eax, unsigned int ebx, > + unsigned int ecx, unsigned int edx, > + struct feat_list *feat, > + struct psr_socket_info *info); > + /* > + * get_cos_num is used to get the COS registers number occupied by the Perhaps instead of 'number' use 'amount' > + * feature for one setting, like CDP occupies 2 COSs but CAT occupies 1. occupies? Perhaps uses? > + */ > + unsigned int (*get_cos_num)(const struct feat_list *feat); > + /* > + * get_old_val and set_new_val are a pair of functions called together. > + * The caller will traverse all features in list to and call both > functions s/in list/in the list/ > + * for every feature do below two things: s/do/to do/ > + * 1. get old_cos register value of all supported features and > + * 2. set the new value for appointed feature. Appointed? I am not sure what you mean by that? And what do you mean by 'set_new_value' As in what the COS value should be? > + * > + * All the values are set into value array according the traversal order, What value array? The COS array? > + * meaning the same order of feature list members. > + * > + * The return value of the function means the number of the value array s/number/amount/ perhaps? > + * member to skip or error. Perhaps: The return value is the amount of entries to skip in the value array? > + * 1 - one item in value array. > + * 2 - two items in value array, like CDP occupies two items. s/like/e.g./ > + * negative - error. > + */ > + int (*get_old_val)(uint64_t val[], > + const struct feat_list *feat, > + unsigned int old_cos, > + enum psr_val_type type); > + int (*set_new_val)(uint64_t val[], > + const struct feat_list *feat, > + unsigned int old_cos, > + enum psr_val_type type, > + uint64_t m); > + /* > + * compare_val is used to in set value process to compare if the 'to in set value process to' ? I am not sure what you mean? > + * input value array can match all the features' COS registers values > + * according to input cos id. > + * The return value of the function means the number of the value array > + * member to skip or error. Perhaps: The return value is the amount of entries to skip in the CoS array? > + * 1 - one item in value array. > + * 2 - two items in value array, like CDP occupies two items. Ditto > + * negative - error. > + */ > + int (*compare_val)(const uint64_t val[], const struct feat_list *feat, > + unsigned int cos, bool *found); > + /* > + * get_cos_max_from_type is used to get the cos_max value of the feature > + * according to input psr_val_type. > + */ > + unsigned int (*get_cos_max_from_type)(const struct feat_list *feat, > + enum psr_val_type type); > + /* > + * exceeds_cos_max is used to check if the input cos id exceeds the > + * feature's cos_max and if the input value is not the default one. > + * Even if the associated cos exceeds the cos_max, HW can work as default s/as default value/with default values/ > + * value. That is the reason we need check if input value is default one. And what is the reason? Based on the design document I would assume that the default value is to allow full usage. Please mention that. > + * If both criteria are fulfilled, that means the input exceeds the > + * range. > + * > + * The return value of the function means the number of the value array > + * member to skip or error. > + * 1 - one item in value array. > + * 2 - two items in value array, like CDP occupies two items. > + * 0 - error, exceed cos_max and value to set is not default. 'to set is not default' I think you mean that "the value is not set, and the default one is used. ' ? > + */ > + unsigned int (*exceeds_cos_max)(const uint64_t val[], > + const struct feat_list *feat, > + unsigned int cos); > + /* write_msr is used to write feature specific MSR registers. */ s/write/write out/ > + int (*write_msr)(unsigned int cos, const uint64_t val[], > + struct feat_list *feat); > + /* get_val is used to get feature specific COS register value. */ You mentioned examples previously. Would it make sense to enumerate it here too. > + int (*get_val)(const struct feat_list *feat, unsigned int cos, > + enum psr_val_type type, uint64_t *val); > + /* get_feat_info is used to get feature specific HW info. */ That sounds mysterious. I presume that 'dat' and 'array_len' are where the specific HW info is put. But nothing about the return code? > + int (*get_feat_info)(const struct feat_list *feat, enum psr_val_type > type, > + uint32_t dat[], uint32_t array_len); > + /* get_max_cos_max is used to get feature's cos_max. */ > + unsigned int (*get_max_cos_max)(const struct feat_list *feat); > +}; > + > +/* CAT/CDP info data structure. */ > +struct psr_cat_lvl_info { > + unsigned int cbm_len; > + unsigned int cos_max; > +}; > + > +struct feat_info { > union { > - uint64_t cbm; > - struct { > - uint64_t code; > - uint64_t data; > - }; > + struct psr_cat_lvl_info l3_info; > }; > +}; > + > +/* > + * Per spec, the maximum COS register number is 128 for all current PSR > + * features. > + */ > +#define MAX_COS_REG_NUM 128 > + > +struct feat_list { > + unsigned int feature; > + struct feat_ops ops; > + struct feat_info info; > + uint64_t cos_reg_val[MAX_COS_REG_NUM]; > + struct list_head list; > +}; > + > +struct psr_ref { > unsigned int ref; > }; > > -struct psr_cat_socket_info { > - unsigned int cbm_len; > - unsigned int cos_max; > - struct psr_cat_cbm *cos_to_cbm; > - spinlock_t cbm_lock; > +#define PSR_SOCKET_L3_CAT 0 > +#define PSR_SOCKET_L3_CDP 1 > + > +struct psr_socket_info { > + /* > + * bit 1~0: [01]->L3 CAT-only, [10]->L3 CDP > + */ > + unsigned int features; You can also use: unsigned int l3_cat:1 l3_cdp:1 and then you don't have to use a #define. But that is up to you. > + unsigned int nr_feat; > + struct list_head feat_list; > + struct psr_ref *cos_ref; > + spinlock_t mask_lock; Can you give a comment above this spinlock and say what it protects against? > }; > > struct psr_assoc { > @@ -48,9 +179,7 @@ struct psr_assoc { > > struct psr_cmt *__read_mostly psr_cmt; > > -static unsigned long *__read_mostly cat_socket_enable; > -static struct psr_cat_socket_info *__read_mostly cat_socket_info; > -static unsigned long *__read_mostly cdp_socket_enable; > +static struct psr_socket_info *__read_mostly socket_info; > > static unsigned int opt_psr; > static unsigned int __initdata opt_rmid_max = 255; > @@ -58,8 +187,410 @@ static unsigned int __read_mostly opt_cos_max = 255; > static uint64_t rmid_mask; > static DEFINE_PER_CPU(struct psr_assoc, psr_assoc); > > -static struct psr_cat_cbm *temp_cos_to_cbm; > +static struct psr_ref *temp_cos_ref; > +/* Every feature has its own object. */ Not sure I understand that. What object? The feat_l3 ? > +static struct feat_list *feat_l3; > + > +/* Common functions for supporting feature callback functions. */ > +static void free_feature(struct psr_socket_info *info) > +{ > + struct feat_list *feat_tmp; > + > + if ( !info ) > + return; > + > + list_for_each_entry(feat_tmp, &info->feat_list, list) > + { > + clear_bit(feat_tmp->feature, &info->features); > + list_del(&feat_tmp->list); > + xfree(feat_tmp); > + } > + > + /* Free feature which are not added into feat_list. */ > + if ( feat_l3 ) > + { > + xfree(feat_l3); > + feat_l3 = NULL; > + } > +} > + > +static bool psr_check_cbm(unsigned int cbm_len, uint64_t cbm) > +{ > + unsigned int first_bit, zero_bit; > + > + /* Set bits should only in the range of [0, cbm_len). */ > + if ( cbm & (~0ull << cbm_len) ) > + return false; > + > + /* At least one bit need to be set. */ > + if ( cbm == 0 ) > + return false; > + > + first_bit = find_first_bit(&cbm, cbm_len); > + zero_bit = find_next_zero_bit(&cbm, cbm_len, first_bit); > + > + /* Set bits should be contiguous. */ > + if ( zero_bit < cbm_len && > + find_next_bit(&cbm, cbm_len, zero_bit) < cbm_len ) > + return false; > + > + return true; > +} > + > +/* > + * Features specific implementations. > + */ > + > +/* L3 CAT/CDP callback functions implementation. */ > +static void l3_cat_init_feature(unsigned int eax, unsigned int ebx, > + unsigned int ecx, unsigned int edx, > + struct feat_list *feat, > + struct psr_socket_info *info) > +{ > + struct psr_cat_lvl_info l3_cat; > + unsigned int socket; > + uint64_t val; > + > + /* No valid value so do not enable feature. */ > + if ( 0 == eax || 0 == edx ) I am curious - how come you put the value before the variable? [I have been always putting the value _after_ the variable] > + return; > + > + l3_cat.cbm_len = (eax & 0x1f) + 1; > + l3_cat.cos_max = min(opt_cos_max, edx & 0xffff); > + > + /* cos=0 is reserved as default cbm(all ones). */ > + feat->cos_reg_val[0] = (1ull << l3_cat.cbm_len) - 1; > + > + feat->feature = PSR_SOCKET_L3_CAT; > + > + if ( (ecx & PSR_CAT_CDP_CAPABILITY) && (opt_psr & PSR_CDP) && > + !test_bit(PSR_SOCKET_L3_CDP, &info->features) ) > + { > + /* Data */ > + feat->cos_reg_val[0] = (1ull << l3_cat.cbm_len) - 1; > + /* Code */ > + feat->cos_reg_val[1] = (1ull << l3_cat.cbm_len) - 1; > + > + /* We only write mask1 since mask0 is always all ones by default. */ > + wrmsrl(MSR_IA32_PSR_L3_MASK(1), > + (1ull << l3_cat.cbm_len) - 1); > + rdmsrl(MSR_IA32_PSR_L3_QOS_CFG, val); > + wrmsrl(MSR_IA32_PSR_L3_QOS_CFG, val | (1 << > PSR_L3_QOS_CDP_ENABLE_BIT)); > + > + /* Cut half of cos_max when CDP is enabled. */ > + l3_cat.cos_max >>= 1; > + > + feat->feature = PSR_SOCKET_L3_CDP; > + __set_bit(PSR_SOCKET_L3_CDP, &info->features); > + } > + else > + __set_bit(PSR_SOCKET_L3_CAT, &info->features); > + > + feat->info.l3_info = l3_cat; > + > + info->nr_feat++; > + > + /* Add this feature into list. */ > + list_add_tail(&feat->list, &info->feat_list); > + > + socket = cpu_to_socket(smp_processor_id()); > + printk(XENLOG_INFO "L3 CAT: enabled on socket %u, cos_max:%u, > cbm_len:%u, CDP:%s\n", > + socket, feat->info.l3_info.cos_max, feat->info.l3_info.cbm_len, > + test_bit(PSR_SOCKET_L3_CDP, &info->features) ? "on" : "off"); > +} > + > +static int l3_cat_compare_val(const uint64_t val[], > + const struct feat_list *feat, > + unsigned int cos, bool *found) > +{ > + uint64_t l3_def_cbm; > + > + l3_def_cbm = (1ull << feat->info.l3_info.cbm_len) - 1; > + > + /* CDP */ > + if ( feat->feature == PSR_SOCKET_L3_CDP ) > + { > + if ( cos > feat->info.l3_info.cos_max ) > + { > + if ( val[0] != l3_def_cbm || > + val[1] != l3_def_cbm ) > + { > + *found = false; > + return -ENOENT; > + } > + *found = true; > + } > + else > + *found = (val[0] == feat->cos_reg_val[cos * 2] && > + val[1] == feat->cos_reg_val[cos * 2 + 1]); > + > + /* CDP occupies two COS, one for data, one for code. */ > + return 2; > + } > + > + /* CAT */ > + if ( cos > feat->info.l3_info.cos_max ) > + { > + if ( val[0] != l3_def_cbm ) > + { > + *found = false; > + return -ENOENT; > + } > + *found = true; > + } > + else > + *found = (val[0] == feat->cos_reg_val[cos]); > + > + /* L3 CAT occupies one COS. */ > + return 1; > +} > + > +static unsigned int l3_cat_get_cos_max_from_type(const struct feat_list > *feat, > + enum psr_val_type type) > +{ > + if ( type != PSR_MASK_TYPE_L3_DATA && > + type != PSR_MASK_TYPE_L3_CODE && > + type != PSR_MASK_TYPE_L3_CBM ) > + return 0; > + > + return feat->info.l3_info.cos_max; > +} > + > +static unsigned int l3_cat_exceeds_cos_max(const uint64_t val[], > + const struct feat_list *feat, > + unsigned int cos) > +{ > + uint64_t l3_def_cbm; > + > + l3_def_cbm = (1ull << feat->info.l3_info.cbm_len) - 1; > + > + /* CDP */ > + if ( feat->feature == PSR_SOCKET_L3_CDP ) > + { > + if ( cos > feat->info.l3_info.cos_max && > + (val[0] != l3_def_cbm || val[1] != l3_def_cbm) ) > + /* > + * Exceed cos_max and value to set is not default, > + * return error. > + */ > + return 0; > + > + /* CDP occupies two COS, one for data, one for code. */ > + return 2; > + } > + > + /* CAT */ > + if ( cos > feat->info.l3_info.cos_max && > + val[0] != l3_def_cbm ) > + /* > + * Exceed cos_max and value to set is not default, > + * return error. > + */ > + return 0; > + > + /* L3 CAT occupies one COS. */ > + return 1; > +} > + > +static int l3_cat_write_msr(unsigned int cos, const uint64_t val[], > + struct feat_list *feat) > +{ > + /* CDP */ > + if ( feat->feature == PSR_SOCKET_L3_CDP ) > + { > + /* > + * If input cos is more than the cos_max of the feature, we should > + * not set the value. > + */ > + if ( cos > feat->info.l3_info.cos_max ) > + /* CDP occupies two COS, one for data, one for code. */ > + return 2; > + > + /* Data */ > + feat->cos_reg_val[cos * 2] = val[0]; > + /* Code */ > + feat->cos_reg_val[cos * 2 + 1] = val[1]; > + > + wrmsrl(MSR_IA32_PSR_L3_MASK_DATA(cos), val[0]); > + wrmsrl(MSR_IA32_PSR_L3_MASK_CODE(cos), val[1]); > + /* CDP occupies two COS, one for data, one for code. */ > + return 2; > + } > + > + /* CAT */ > + if ( cos > feat->info.l3_info.cos_max ) > + /* L3 CAT occupies one COS. */ > + return 1; > + > + feat->cos_reg_val[cos] = val[0]; > + wrmsrl(MSR_IA32_PSR_L3_MASK(cos), val[0]); > + /* L3 CAT occupies one COS. */ > + return 1; > +} > + > +static unsigned int l3_cat_get_cos_num(const struct feat_list *feat) > +{ > + if ( feat->feature == PSR_SOCKET_L3_CDP ) > + return 2; > + > + return 1; > +} > + > +static int l3_cat_get_old_val(uint64_t val[], > + const struct feat_list *feat, > + unsigned int old_cos, > + enum psr_val_type type) > +{ > + if ( old_cos > feat->info.l3_info.cos_max ) > + /* Use default value. */ > + old_cos = 0; > + > + /* CDP */ > + if ( feat->feature == PSR_SOCKET_L3_CDP ) > + { > + /* Data */ > + val[0] = feat->cos_reg_val[old_cos * 2]; > + /* Code */ > + val[1] = feat->cos_reg_val[old_cos * 2 + 1]; > + > + /* CDP occupies two COS, one for data, one for code. */ > + return 2; > + } > + > + /* CAT */ > + val[0] = feat->cos_reg_val[old_cos]; > + > + /* L3 CAT occupies one COS. */ > + return 1; > +} > + > +static int l3_cat_set_new_val(uint64_t val[], > + const struct feat_list *feat, > + unsigned int old_cos, > + enum psr_val_type type, > + uint64_t m) > +{ > + /* L3 CAT occupies one COS. */ > + unsigned int ret = 1; > + > + switch (type) { > + /* CDP occupies two COS, one for data, one for code. */ > + case PSR_MASK_TYPE_L3_DATA: > + case PSR_MASK_TYPE_L3_CODE: > + if ( feat->feature != PSR_SOCKET_L3_CDP ) > + return -ENXIO; > + > + if ( !psr_check_cbm(feat->info.l3_info.cbm_len, m) ) > + return -EINVAL; > + > + if ( type == PSR_MASK_TYPE_L3_DATA ) > + val[0] = m; > + else > + val[1] = m; > + > + ret= 2; > + break; > + > + /* CAT */ > + case PSR_MASK_TYPE_L3_CBM: > + if ( !psr_check_cbm(feat->info.l3_info.cbm_len, m) ) > + return -EINVAL; > + > + val[0] = m; > + break; > + > + default: > + if ( feat->feature == PSR_SOCKET_L3_CDP ) > + /* CDP occupies two COS, one for data, one for code. */ > + ret = 2; > + break; > + } > + > + return ret; > +} > + > +static int l3_cat_get_val(const struct feat_list *feat, unsigned int cos, > + enum psr_val_type type, uint64_t *val) > +{ > + if ( cos > feat->info.l3_info.cos_max ) > + /* Use default value. */ > + cos = 0; > + > + switch (type) { > + /* CDP */ > + case PSR_MASK_TYPE_L3_DATA: > + case PSR_MASK_TYPE_L3_CODE: > + if ( feat->feature != PSR_SOCKET_L3_CDP ) > + return -ENXIO; > + > + if ( type == PSR_MASK_TYPE_L3_DATA ) > + *val = feat->cos_reg_val[cos * 2]; > + else > + *val = feat->cos_reg_val[cos * 2 + 1]; > + break; > + > + /* CAT */ > + case PSR_MASK_TYPE_L3_CBM: > + *val = feat->cos_reg_val[cos]; > + break; > + > + default: > + return 0; > + } > + > + return 1; > +} > + > +static int l3_cat_get_feat_info(const struct feat_list *feat, > + enum psr_val_type type, > + uint32_t dat[], uint32_t array_len) > +{ > + if ( !dat || 3 > array_len ) > + return 0; Not return -EINVAL? > + > + switch (type) { > + case PSR_MASK_TYPE_L3_CBM: > + case PSR_MASK_TYPE_L3_DATA: > + case PSR_MASK_TYPE_L3_CODE: > + if ( feat->feature == PSR_SOCKET_L3_CDP ) > + dat[2] |= XEN_SYSCTL_PSR_CAT_L3_CDP; > + else > + dat[2] = 0; > + break; > > + default: > + /* This feature is not requested feature. */ > + return 0; return -EOPNOTSUPPO? > + } > + > + dat[0] = feat->info.l3_info.cbm_len; > + dat[1] = feat->info.l3_info.cos_max; > + > + return 1; Not return 2 ? If this is just to return 0|1 why not use 'bool' ? > +} > + > +static unsigned int l3_cat_get_max_cos_max(const struct feat_list *feat) > +{ > + return feat->info.l3_info.cos_max; > +} > + > +struct feat_ops l3_cat_ops = { > + .init_feature = l3_cat_init_feature, > + .get_cos_num = l3_cat_get_cos_num, > + .get_old_val = l3_cat_get_old_val, > + .set_new_val = l3_cat_set_new_val, > + .compare_val = l3_cat_compare_val, > + .get_cos_max_from_type = l3_cat_get_cos_max_from_type, > + .exceeds_cos_max = l3_cat_exceeds_cos_max, > + .write_msr = l3_cat_write_msr, > + .get_val = l3_cat_get_val, > + .get_feat_info = l3_cat_get_feat_info, > + .get_max_cos_max = l3_cat_get_max_cos_max, > +}; > + > +/* > + * Common functions implementation > + */ > static unsigned int get_socket_cpu(unsigned int socket) > { > if ( likely(socket < nr_sockets) ) > @@ -209,17 +740,29 @@ void psr_free_rmid(struct domain *d) > d->arch.psr_rmid = 0; > } > > +static inline unsigned int get_max_cos_max(const struct psr_socket_info > *info) > +{ > + const struct feat_list *feat_tmp; > + unsigned int cos_max = 0; > + > + list_for_each_entry(feat_tmp, &info->feat_list, list) > + cos_max = max(feat_tmp->ops.get_max_cos_max(feat_tmp), cos_max); > + > + return cos_max; > +} > + > static inline void psr_assoc_init(void) > { > struct psr_assoc *psra = &this_cpu(psr_assoc); > > - if ( cat_socket_info ) > + if ( socket_info ) > { > unsigned int socket = cpu_to_socket(smp_processor_id()); > + const struct psr_socket_info *info = socket_info + socket; > + unsigned int cos_max = get_max_cos_max(info); > > - if ( test_bit(socket, cat_socket_enable) ) > - psra->cos_mask = ((1ull << get_count_order( > - cat_socket_info[socket].cos_max)) - 1) << 32; > + if ( info->features ) > + psra->cos_mask = ((1ull << get_count_order(cos_max)) - 1) << 32; > } > > if ( psr_cmt_enabled() || psra->cos_mask ) > @@ -256,270 +799,362 @@ void psr_ctxt_switch_to(struct domain *d) > psra->val = reg; > } > } > -static struct psr_cat_socket_info *get_cat_socket_info(unsigned int socket) > + > +static struct psr_socket_info *get_socket_info(unsigned int socket) > { > - if ( !cat_socket_info ) > + struct psr_socket_info *info; > + > + if ( !socket_info ) > return ERR_PTR(-ENODEV); > > if ( socket >= nr_sockets ) > return ERR_PTR(-ENOTSOCK); > > - if ( !test_bit(socket, cat_socket_enable) ) > - return ERR_PTR(-ENOENT); > + info = socket_info + socket; > > - return cat_socket_info + socket; > -} > + if ( !info->features ) > + return ERR_PTR(-ENOENT); > > -static inline bool_t cdp_is_enabled(unsigned int socket) > -{ > - return cdp_socket_enable && test_bit(socket, cdp_socket_enable); > + return info; > } > > -int psr_get_cat_l3_info(unsigned int socket, uint32_t *cbm_len, > - uint32_t *cos_max, uint32_t *flags) > +int psr_get_info(unsigned int socket, enum psr_val_type type, > + uint32_t dat[], uint32_t array_len) > { > - struct psr_cat_socket_info *info = get_cat_socket_info(socket); > + struct psr_socket_info *info = get_socket_info(socket); > + const struct feat_list *feat_tmp; > > if ( IS_ERR(info) ) > return PTR_ERR(info); > > - *cbm_len = info->cbm_len; > - *cos_max = info->cos_max; > + list_for_each_entry(feat_tmp, &info->feat_list, list) > + if ( feat_tmp->ops.get_feat_info(feat_tmp, type, dat, array_len) ) > + return 0; How about just using the regulard return values: 0 for succcess and other numbers are failures? > > - *flags = 0; > - if ( cdp_is_enabled(socket) ) > - *flags |= XEN_SYSCTL_PSR_CAT_L3_CDP; > + return -ENODEV; > +} > > - return 0; > +static unsigned int get_cos_num(const struct psr_socket_info *info) > +{ > + const struct feat_list *feat_tmp; > + unsigned int num = 0; > + > + list_for_each_entry(feat_tmp, &info->feat_list, list) > + num += feat_tmp->ops.get_cos_num(feat_tmp); > + > + return num; > } > > -int psr_get_l3_cbm(struct domain *d, unsigned int socket, > - uint64_t *cbm, enum cbm_type type) > +static int get_old_set_new(uint64_t *val, > + uint32_t array_len, > + const struct psr_socket_info *info, > + unsigned int old_cos, > + enum psr_val_type type, > + uint64_t m) > { > - struct psr_cat_socket_info *info = get_cat_socket_info(socket); > - bool_t cdp_enabled = cdp_is_enabled(socket); > + const struct feat_list *feat_tmp; > + int ret; > + uint64_t *val_tmp = val; > > - if ( IS_ERR(info) ) > - return PTR_ERR(info); > + if ( !val ) > + return -EINVAL; > > - switch ( type ) > + list_for_each_entry(feat_tmp, &info->feat_list, list) > { > - case PSR_CBM_TYPE_L3: > - if ( cdp_enabled ) > - return -EXDEV; > - *cbm = info->cos_to_cbm[d->arch.psr_cos_ids[socket]].cbm; > - break; > + /* value getting order is same as feature list */ > + ret = feat_tmp->ops.get_old_val(val_tmp, feat_tmp, old_cos, type); > > - case PSR_CBM_TYPE_L3_CODE: > - if ( !cdp_enabled ) > - *cbm = info->cos_to_cbm[d->arch.psr_cos_ids[socket]].cbm; > - else > - *cbm = info->cos_to_cbm[d->arch.psr_cos_ids[socket]].code; > - break; > - > - case PSR_CBM_TYPE_L3_DATA: > - if ( !cdp_enabled ) > - *cbm = info->cos_to_cbm[d->arch.psr_cos_ids[socket]].cbm; > - else > - *cbm = info->cos_to_cbm[d->arch.psr_cos_ids[socket]].data; > - break; > + val_tmp += ret; > + if ( val_tmp - val > array_len) > + return -EINVAL; > + } > > - default: > - ASSERT_UNREACHABLE(); > + val_tmp = val; > + list_for_each_entry(feat_tmp, &info->feat_list, list) > + { > + /* value setting order is same as feature list */ > + ret = feat_tmp->ops.set_new_val(val_tmp, feat_tmp, old_cos, type, m); > + if ( ret < 0 ) > + return ret; > + > + val_tmp += ret; > + if ( val_tmp - val > array_len) > + return -EINVAL; > } > > return 0; > } > > -static bool_t psr_check_cbm(unsigned int cbm_len, uint64_t cbm) > +int psr_get_val(struct domain *d, unsigned int socket, > + uint64_t *val, enum psr_val_type type) > { > - unsigned int first_bit, zero_bit; > + const struct psr_socket_info *info = get_socket_info(socket); > + unsigned int cos = d->arch.psr_cos_ids[socket]; > + const struct feat_list *feat_tmp; > + int ret; > > - /* Set bits should only in the range of [0, cbm_len). */ > - if ( cbm & (~0ull << cbm_len) ) > - return 0; > - > - /* At least one bit need to be set. */ > - if ( cbm == 0 ) > - return 0; > + if ( IS_ERR(info) ) > + return PTR_ERR(info); > > - first_bit = find_first_bit(&cbm, cbm_len); > - zero_bit = find_next_zero_bit(&cbm, cbm_len, first_bit); > + list_for_each_entry(feat_tmp, &info->feat_list, list) > + { > + ret = feat_tmp->ops.get_val(feat_tmp, cos, type, val); > + if ( ret < 0 ) > + return ret; > > - /* Set bits should be contiguous. */ > - if ( zero_bit < cbm_len && > - find_next_bit(&cbm, cbm_len, zero_bit) < cbm_len ) > - return 0; > + if ( ret > 0 ) > + /* Found */ > + break; > + } > > - return 1; > + return 0; > } > > -struct cos_cbm_info > +struct cos_mask_info > { > unsigned int cos; > - bool_t cdp; > - uint64_t cbm_code; > - uint64_t cbm_data; > + struct list_head *feat_list; > + const uint64_t *val; > }; > > -static void do_write_l3_cbm(void *data) > +static void do_write_psr_msr(void *data) > { > - struct cos_cbm_info *info = data; > + struct cos_mask_info *info = (struct cos_mask_info *)data; > + unsigned int cos = info->cos; > + struct list_head *feat_list= info->feat_list; > + const uint64_t *val = info->val; > + struct feat_list *feat_tmp; > + int ret; > + > + if ( !feat_list ) > + return; > > - if ( info->cdp ) > + list_for_each_entry(feat_tmp, feat_list, list) > { > - wrmsrl(MSR_IA32_PSR_L3_MASK_CODE(info->cos), info->cbm_code); > - wrmsrl(MSR_IA32_PSR_L3_MASK_DATA(info->cos), info->cbm_data); > + ret = feat_tmp->ops.write_msr(cos, val, feat_tmp); > + if ( ret <= 0) > + return; > + > + val += ret; > } > - else > - wrmsrl(MSR_IA32_PSR_L3_MASK(info->cos), info->cbm_code); > } > > -static int write_l3_cbm(unsigned int socket, unsigned int cos, > - uint64_t cbm_code, uint64_t cbm_data, bool_t cdp) > +static int write_psr_msr(unsigned int socket, unsigned int cos, > + const uint64_t *val) > { > - struct cos_cbm_info info = > + struct psr_socket_info *info = get_socket_info(socket); > + > + struct cos_mask_info data = > { > .cos = cos, > - .cbm_code = cbm_code, > - .cbm_data = cbm_data, > - .cdp = cdp, > + .feat_list = &info->feat_list, > + .val = val, > }; > > if ( socket == cpu_to_socket(smp_processor_id()) ) > - do_write_l3_cbm(&info); > + do_write_psr_msr(&data); > else > { > unsigned int cpu = get_socket_cpu(socket); > > if ( cpu >= nr_cpu_ids ) > return -ENOTSOCK; > - on_selected_cpus(cpumask_of(cpu), do_write_l3_cbm, &info, 1); > + on_selected_cpus(cpumask_of(cpu), do_write_psr_msr, &data, 1); > } > > return 0; > } > > -static int find_cos(struct psr_cat_cbm *map, unsigned int cos_max, > - uint64_t cbm_code, uint64_t cbm_data, bool_t cdp_enabled) > +static int find_cos(const uint64_t *val, uint32_t array_len, > + enum psr_val_type type, > + const struct psr_socket_info *info) > { > unsigned int cos; > + const struct psr_ref *map = info->cos_ref; > + const struct feat_list *feat_tmp; > + const uint64_t *val_tmp = val; > + int ret; > + bool found = false; > + unsigned int cos_max = 0; > + > + /* cos_max is the max COS of the feature to be set. */ > + list_for_each_entry(feat_tmp, &info->feat_list, list) > + { > + cos_max = feat_tmp->ops.get_cos_max_from_type(feat_tmp, type); > + if ( cos_max > 0 ) > + break; > + } > > for ( cos = 0; cos <= cos_max; cos++ ) > { > - if ( (map[cos].ref || cos == 0) && > - ((!cdp_enabled && map[cos].cbm == cbm_code) || > - (cdp_enabled && map[cos].code == cbm_code && > - map[cos].data == cbm_data)) ) > + if ( 0 != cos && 0 == map[cos].ref ) how about just: if ( cos && !map[cos].ref ) ? > + continue; > + > + /* Not found, need find again from beginning. */ > + val_tmp = val; > + list_for_each_entry(feat_tmp, &info->feat_list, list) > + { > + /* > + * Compare value according to feature list order. > + * We must follow this order because value array is assembled > + * as this order in get_old_set_new(). > + */ > + ret = feat_tmp->ops.compare_val(val_tmp, feat_tmp, cos, &found); > + if ( ret < 0 ) > + return ret; > + > + /* If fail to match, go to next cos to compare. */ > + if ( !found ) > + break; > + > + val_tmp += ret; > + if ( val_tmp - val > array_len ) > + return -EINVAL; > + } > + > + /* Every feature can match, this cos is what we find. */ I am not sure I understand the comment. > + if ( found ) > return cos; > } > > return -ENOENT; > } > > -static int pick_avail_cos(struct psr_cat_cbm *map, unsigned int cos_max, > - unsigned int old_cos) > +static bool exceeds_cos_max(const uint64_t *val, > + uint32_t array_len, > + const struct psr_socket_info *info, > + unsigned int cos) > +{ > + unsigned int ret; > + const uint64_t *val_tmp = val; > + const struct feat_list *feat_tmp; > + > + list_for_each_entry(feat_tmp, &info->feat_list, list) > + { > + ret = feat_tmp->ops.exceeds_cos_max(val_tmp, feat_tmp, cos); > + if ( 0 == ret ) How about if ( !ret ) return false; > + return false; > + > + val_tmp += ret; > + if ( val_tmp - val > array_len ) > + return false; > + } > + > + return true; > +} > + > +static int alloc_new_cos(const struct psr_socket_info *info, > + const uint64_t *val, uint32_t array_len, > + unsigned int old_cos, > + enum psr_val_type type) > { > unsigned int cos; > + unsigned int cos_max = 0; > + const struct feat_list *feat_tmp; > + const struct psr_ref *map = info->cos_ref; > + > + /* > + * cos_max is the max COS of the feature to be set. > + */ > + list_for_each_entry(feat_tmp, &info->feat_list, list) > + { > + cos_max = feat_tmp->ops.get_cos_max_from_type(feat_tmp, type); > + if ( cos_max > 0 ) > + break; > + } > + > + if ( !cos_max ) > + return -ENOENT; > > /* If old cos is referred only by the domain, then use it. */ > if ( map[old_cos].ref == 1 && old_cos != 0 ) > - return old_cos; > + if ( exceeds_cos_max(val, array_len, info, old_cos) ) > + return old_cos; > > /* Find an unused one other than cos0. */ > for ( cos = 1; cos <= cos_max; cos++ ) > + /* > + * ref is 0 means this COS is not occupied by other domain and > + * can be used for current setting. > + */ > if ( map[cos].ref == 0 ) > + { > + if ( !exceeds_cos_max(val, array_len, info, cos) ) > + return -ENOENT; > + > return cos; > + } > > return -ENOENT; > } > > -int psr_set_l3_cbm(struct domain *d, unsigned int socket, > - uint64_t cbm, enum cbm_type type) > +int psr_set_val(struct domain *d, unsigned int socket, > + uint64_t val, enum psr_val_type type) > { > - unsigned int old_cos, cos_max; > + unsigned int old_cos; > int cos, ret; > - uint64_t cbm_data, cbm_code; > - bool_t cdp_enabled = cdp_is_enabled(socket); > - struct psr_cat_cbm *map; > - struct psr_cat_socket_info *info = get_cat_socket_info(socket); > + struct psr_ref *map; > + uint64_t *val_array; > + struct psr_socket_info *info = get_socket_info(socket); > + uint32_t array_len; > > if ( IS_ERR(info) ) > return PTR_ERR(info); > > - if ( !psr_check_cbm(info->cbm_len, cbm) ) > - return -EINVAL; > - > - if ( !cdp_enabled && (type == PSR_CBM_TYPE_L3_CODE || > - type == PSR_CBM_TYPE_L3_DATA) ) > - return -ENXIO; > - > - cos_max = info->cos_max; > + map = info->cos_ref; > old_cos = d->arch.psr_cos_ids[socket]; > - map = info->cos_to_cbm; > > - switch ( type ) > - { > - case PSR_CBM_TYPE_L3: > - cbm_code = cbm; > - cbm_data = cbm; > - break; > - > - case PSR_CBM_TYPE_L3_CODE: > - cbm_code = cbm; > - cbm_data = map[old_cos].data; > - break; > - > - case PSR_CBM_TYPE_L3_DATA: > - cbm_code = map[old_cos].code; > - cbm_data = cbm; > - break; > + array_len = get_cos_num((const struct psr_socket_info *)info); > + val_array = xzalloc_array(uint64_t, array_len); > + if ( !val_array ) > + return -ENOMEM; > > - default: > - ASSERT_UNREACHABLE(); > - return -EINVAL; > - } > + if ( (ret = get_old_set_new(val_array, array_len, > + (const struct psr_socket_info *)info, > + old_cos, type, val)) != 0 ) > + return ret; You are leaking 'val_array'? That can't be good. > > - spin_lock(&info->cbm_lock); > - cos = find_cos(map, cos_max, cbm_code, cbm_data, cdp_enabled); > + spin_lock(&info->mask_lock); > + cos = find_cos((const uint64_t *)val_array, array_len, type, > + (const struct psr_socket_info *)info); > if ( cos >= 0 ) > { > if ( cos == old_cos ) > { > - spin_unlock(&info->cbm_lock); > + spin_unlock(&info->mask_lock); > + xfree(val_array); > return 0; > } > } > else > { > - cos = pick_avail_cos(map, cos_max, old_cos); > + cos = alloc_new_cos((const struct psr_socket_info *)info, > + (const uint64_t *)val_array, array_len, > + old_cos, type); > if ( cos < 0 ) > { > - spin_unlock(&info->cbm_lock); > + spin_unlock(&info->mask_lock); > + xfree(val_array); > return cos; > } > > - /* We try to avoid writing MSR. */ > - if ( (cdp_enabled && > - (map[cos].code != cbm_code || map[cos].data != cbm_data)) || > - (!cdp_enabled && map[cos].cbm != cbm_code) ) > + /* Write all features MSRs corresponding to the COS */ > + ret = write_psr_msr(socket, cos, (const uint64_t *)val_array); > + if ( ret ) > { > - ret = write_l3_cbm(socket, cos, cbm_code, cbm_data, cdp_enabled); > - if ( ret ) > - { > - spin_unlock(&info->cbm_lock); > - return ret; > - } > - map[cos].code = cbm_code; > - map[cos].data = cbm_data; > + spin_unlock(&info->mask_lock); > + xfree(val_array); > + return ret; > } > } > > map[cos].ref++; > map[old_cos].ref--; > - spin_unlock(&info->cbm_lock); > + > + spin_unlock(&info->mask_lock); > > d->arch.psr_cos_ids[socket] = cos; > + xfree(val_array); > > return 0; > } > @@ -529,20 +1164,23 @@ static void psr_free_cos(struct domain *d) > { > unsigned int socket; > unsigned int cos; > - struct psr_cat_socket_info *info; > + struct psr_socket_info *info; > > if( !d->arch.psr_cos_ids ) > return; > > - for_each_set_bit(socket, cat_socket_enable, nr_sockets) > + for( socket = 0; socket < nr_sockets; socket++) Wrong Style. You have the ( incorrectly and also the ++ needs a space after it. > { > if ( (cos = d->arch.psr_cos_ids[socket]) == 0 ) > continue; > > - info = cat_socket_info + socket; > - spin_lock(&info->cbm_lock); > - info->cos_to_cbm[cos].ref--; > - spin_unlock(&info->cbm_lock); > + info = get_socket_info(socket); > + if ( IS_ERR(info) ) > + continue; > + > + spin_lock(&info->mask_lock); > + info->cos_ref[cos].ref--; > + spin_unlock(&info->mask_lock); > } > > xfree(d->arch.psr_cos_ids); > @@ -551,7 +1189,7 @@ static void psr_free_cos(struct domain *d) > > int psr_domain_init(struct domain *d) > { > - if ( cat_socket_info ) > + if ( socket_info ) > { > d->arch.psr_cos_ids = xzalloc_array(unsigned int, nr_sockets); > if ( !d->arch.psr_cos_ids ) > @@ -567,137 +1205,126 @@ void psr_domain_free(struct domain *d) > psr_free_cos(d); > } > > -static int cat_cpu_prepare(unsigned int cpu) > +static int cpu_prepare_work(unsigned int cpu) > { > - if ( !cat_socket_info ) > + if ( !socket_info ) > return 0; > > - if ( temp_cos_to_cbm == NULL && > - (temp_cos_to_cbm = xzalloc_array(struct psr_cat_cbm, > + if ( temp_cos_ref == NULL && > + (temp_cos_ref = xzalloc_array(struct psr_ref, > opt_cos_max + 1UL)) == NULL ) > return -ENOMEM; > > + /* Malloc memory for the global feature head here. */ > + if ( feat_l3 == NULL && > + (feat_l3 = xzalloc(struct feat_list)) == NULL ) > + return -ENOMEM; .. and leak temp_cos_ref? > + > return 0; > } > > -static void cat_cpu_init(void) > +static void cpu_init_work(void) > { > unsigned int eax, ebx, ecx, edx; > - struct psr_cat_socket_info *info; > + struct psr_socket_info *info; > unsigned int socket; > unsigned int cpu = smp_processor_id(); > - uint64_t val; > const struct cpuinfo_x86 *c = cpu_data + cpu; > + struct feat_list *feat_tmp; > > if ( !cpu_has(c, X86_FEATURE_PQE) || c->cpuid_level < > PSR_CPUID_LEVEL_CAT ) > return; > > socket = cpu_to_socket(cpu); > - if ( test_bit(socket, cat_socket_enable) ) > + info = socket_info + socket; > + if ( info->features ) > return; > > + info->cos_ref = temp_cos_ref; > + temp_cos_ref = NULL; > + spin_lock_init(&info->mask_lock); > + > cpuid_count(PSR_CPUID_LEVEL_CAT, 0, &eax, &ebx, &ecx, &edx); > if ( ebx & PSR_RESOURCE_TYPE_L3 ) > { > - cpuid_count(PSR_CPUID_LEVEL_CAT, 1, &eax, &ebx, &ecx, &edx); > - info = cat_socket_info + socket; > - info->cbm_len = (eax & 0x1f) + 1; > - info->cos_max = min(opt_cos_max, edx & 0xffff); > - > - info->cos_to_cbm = temp_cos_to_cbm; > - temp_cos_to_cbm = NULL; > - /* cos=0 is reserved as default cbm(all ones). */ > - info->cos_to_cbm[0].cbm = (1ull << info->cbm_len) - 1; > + feat_tmp = feat_l3; > + feat_l3 = NULL; > > - spin_lock_init(&info->cbm_lock); > - > - set_bit(socket, cat_socket_enable); > - > - if ( (ecx & PSR_CAT_CDP_CAPABILITY) && (opt_psr & PSR_CDP) && > - cdp_socket_enable && !test_bit(socket, cdp_socket_enable) ) > - { > - info->cos_to_cbm[0].code = (1ull << info->cbm_len) - 1; > - info->cos_to_cbm[0].data = (1ull << info->cbm_len) - 1; > - > - /* We only write mask1 since mask0 is always all ones by > default. */ > - wrmsrl(MSR_IA32_PSR_L3_MASK(1), (1ull << info->cbm_len) - 1); > - > - rdmsrl(MSR_IA32_PSR_L3_QOS_CFG, val); > - wrmsrl(MSR_IA32_PSR_L3_QOS_CFG, val | (1 << > PSR_L3_QOS_CDP_ENABLE_BIT)); > - > - /* Cut half of cos_max when CDP is enabled. */ > - info->cos_max >>= 1; > - > - set_bit(socket, cdp_socket_enable); > - } > - printk(XENLOG_INFO "CAT: enabled on socket %u, cos_max:%u, > cbm_len:%u, CDP:%s\n", > - socket, info->cos_max, info->cbm_len, > - cdp_is_enabled(socket) ? "on" : "off"); > + /* Initialize this feature according to CPUID. */ > + cpuid_count(PSR_CPUID_LEVEL_CAT, 1, &eax, &ebx, &ecx, &edx); > + feat_tmp->ops = l3_cat_ops; > + feat_tmp->ops.init_feature(eax, ebx, ecx, edx, feat_tmp, info); > } > } > > -static void cat_cpu_fini(unsigned int cpu) > +static void cpu_fini_work(unsigned int cpu) > { > unsigned int socket = cpu_to_socket(cpu); > > if ( !socket_cpumask[socket] || cpumask_empty(socket_cpumask[socket]) ) > { > - struct psr_cat_socket_info *info = cat_socket_info + socket; > + struct psr_socket_info *info = get_socket_info(socket); > + > + free_feature(info); > > - if ( info->cos_to_cbm ) > + if ( info->cos_ref ) Um, just called 'free_feature' so the 'info' has garbage.. Pehraps you should call free_feature after you done with 'info' > { > - xfree(info->cos_to_cbm); > - info->cos_to_cbm = NULL; > + xfree(info->cos_ref); > + info->cos_ref = NULL; > } > - > - if ( cdp_is_enabled(socket) ) > - clear_bit(socket, cdp_socket_enable); > - > - clear_bit(socket, cat_socket_enable); > } > } > > -static void __init psr_cat_free(void) > +static void __init psr_free(void) > { > - xfree(cat_socket_enable); > - cat_socket_enable = NULL; > - xfree(cat_socket_info); > - cat_socket_info = NULL; > + unsigned int i; > + > + for ( i = 0; i < nr_sockets; i++ ) > + free_feature(&socket_info[i]); > + > + xfree(socket_info); > + socket_info = NULL; > } > > -static void __init init_psr_cat(void) > +static void __init init_psr(void) > { > + unsigned int i; > + > if ( opt_cos_max < 1 ) > { > printk(XENLOG_INFO "CAT: disabled, cos_max is too small\n"); > return; > } > > - cat_socket_enable = xzalloc_array(unsigned long, > BITS_TO_LONGS(nr_sockets)); > - cat_socket_info = xzalloc_array(struct psr_cat_socket_info, nr_sockets); > - cdp_socket_enable = xzalloc_array(unsigned long, > BITS_TO_LONGS(nr_sockets)); > + socket_info = xzalloc_array(struct psr_socket_info, nr_sockets); > + > + if ( !socket_info ) > + { > + printk(XENLOG_INFO "Fail to alloc socket_info!\n"); > + return; > + } > > - if ( !cat_socket_enable || !cat_socket_info ) > - psr_cat_free(); > + for ( i = 0; i < nr_sockets; i++ ) > + INIT_LIST_HEAD(&socket_info[i].feat_list); > } > > static int psr_cpu_prepare(unsigned int cpu) > { > - return cat_cpu_prepare(cpu); > + return cpu_prepare_work(cpu); > } > > static void psr_cpu_init(void) > { > - if ( cat_socket_info ) > - cat_cpu_init(); > + if ( socket_info ) > + cpu_init_work(); > > psr_assoc_init(); > } > > static void psr_cpu_fini(unsigned int cpu) > { > - if ( cat_socket_info ) > - cat_cpu_fini(cpu); > + if ( socket_info ) > + cpu_fini_work(cpu); > } > > static int cpu_callback( > @@ -739,13 +1366,13 @@ static int __init psr_presmp_init(void) > init_psr_cmt(opt_rmid_max); > > if ( opt_psr & PSR_CAT ) > - init_psr_cat(); > + init_psr(); > > if ( psr_cpu_prepare(0) ) > - psr_cat_free(); > + psr_free(); > > psr_cpu_init(); > - if ( psr_cmt_enabled() || cat_socket_info ) > + if ( psr_cmt_enabled() || socket_info ) > register_cpu_notifier(&cpu_nfb); > > return 0; > diff --git a/xen/arch/x86/sysctl.c b/xen/arch/x86/sysctl.c > index 14e7dc7..8e17a9a 100644 > --- a/xen/arch/x86/sysctl.c > +++ b/xen/arch/x86/sysctl.c > @@ -176,15 +176,19 @@ long arch_do_sysctl( > switch ( sysctl->u.psr_cat_op.cmd ) > { > case XEN_SYSCTL_PSR_CAT_get_l3_info: > - ret = psr_get_cat_l3_info(sysctl->u.psr_cat_op.target, > - > &sysctl->u.psr_cat_op.u.l3_info.cbm_len, > - > &sysctl->u.psr_cat_op.u.l3_info.cos_max, > - &sysctl->u.psr_cat_op.u.l3_info.flags); > + { > + uint32_t dat[3]; Perhaps a #define for it? > + ret = psr_get_info(sysctl->u.psr_cat_op.target, > + PSR_MASK_TYPE_L3_CBM, > + dat, 3); That way you can use that there. > + sysctl->u.psr_cat_op.u.l3_info.cbm_len = dat[0]; > + sysctl->u.psr_cat_op.u.l3_info.cos_max = dat[1]; > + sysctl->u.psr_cat_op.u.l3_info.flags = dat[2]; > > if ( !ret && __copy_field_to_guest(u_sysctl, sysctl, > u.psr_cat_op) ) > ret = -EFAULT; > break; > - > + } > default: > ret = -EOPNOTSUPP; > break; > diff --git a/xen/include/asm-x86/psr.h b/xen/include/asm-x86/psr.h > index 57f47e9..ef46d12 100644 > --- a/xen/include/asm-x86/psr.h > +++ b/xen/include/asm-x86/psr.h > @@ -46,10 +46,10 @@ struct psr_cmt { > struct psr_cmt_l3 l3; > }; > > -enum cbm_type { > - PSR_CBM_TYPE_L3, > - PSR_CBM_TYPE_L3_CODE, > - PSR_CBM_TYPE_L3_DATA, > +enum psr_val_type { > + PSR_MASK_TYPE_L3_CBM, > + PSR_MASK_TYPE_L3_CODE, > + PSR_MASK_TYPE_L3_DATA, > }; > > extern struct psr_cmt *psr_cmt; > @@ -63,12 +63,12 @@ int psr_alloc_rmid(struct domain *d); > void psr_free_rmid(struct domain *d); > void psr_ctxt_switch_to(struct domain *d); > > -int psr_get_cat_l3_info(unsigned int socket, uint32_t *cbm_len, > - uint32_t *cos_max, uint32_t *flags); > -int psr_get_l3_cbm(struct domain *d, unsigned int socket, > - uint64_t *cbm, enum cbm_type type); > -int psr_set_l3_cbm(struct domain *d, unsigned int socket, > - uint64_t cbm, enum cbm_type type); > +int psr_get_info(unsigned int socket, enum psr_val_type type, > + uint32_t dat[], uint32_t array_len); > +int psr_get_val(struct domain *d, unsigned int socket, > + uint64_t *val, enum psr_val_type type); > +int psr_set_val(struct domain *d, unsigned int socket, > + uint64_t val, enum psr_val_type type); > > int psr_domain_init(struct domain *d); > void psr_domain_free(struct domain *d); > -- > 2.7.4 > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@xxxxxxxxxxxxx > https://lists.xen.org/xen-devel _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |