diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c index c1d016be20..e9a72c8283 100644 --- a/xen/arch/x86/domctl.c +++ b/xen/arch/x86/domctl.c @@ -1442,6 +1442,8 @@ long arch_do_domctl( case XEN_DOMCTL_psr_cat_op: switch ( domctl->u.psr_cat_op.cmd ) { + uint32_t val32; + 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, @@ -1461,23 +1463,23 @@ long arch_do_domctl( 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, + &val32, PSR_CBM_TYPE_L3); + domctl->u.psr_cat_op.data = val32; copyback = true; 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, + &val32, PSR_CBM_TYPE_L3_CODE); + domctl->u.psr_cat_op.data = val32; copyback = true; 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, + &val32, PSR_CBM_TYPE_L3_DATA); + domctl->u.psr_cat_op.data = val32; copyback = true; break; diff --git a/xen/arch/x86/psr.c b/xen/arch/x86/psr.c index 20d083e6d7..0fe63dda9d 100644 --- a/xen/arch/x86/psr.c +++ b/xen/arch/x86/psr.c @@ -524,10 +524,55 @@ int psr_get_info(unsigned int socket, enum cbm_type type, return -EINVAL; } -int psr_get_l3_cbm(struct domain *d, unsigned int socket, - uint64_t *cbm, enum cbm_type type) +int psr_get_val(struct domain *d, unsigned int socket, + uint32_t *val, enum cbm_type type) { - return 0; + const struct psr_socket_info *info = get_socket_info(socket); + const struct feat_node *feat; + enum psr_feat_type feat_type; + unsigned int cos, i; + + ASSERT(val); + + if ( IS_ERR(info) ) + return PTR_ERR(info); + + feat_type = psr_cbm_type_to_feat_type(type); + if ( feat_type >= ARRAY_SIZE(info->features) ) + return -ENOENT; + + feat = info->features[feat_type]; + if ( !feat ) + return -ENOENT; + + if ( !feat_props[feat_type] ) + { + ASSERT_UNREACHABLE(); + return -ENOENT; + } + + cos = d->arch.psr_cos_ids[socket]; + /* + * If input cos exceeds current feature's cos_max, we should return its + * default value which is stored in cos 0. This case only happens + * when more than two features enabled concurrently and at least one + * features's cos_max is bigger than others. When a domain's working cos + * id is bigger than some features' cos_max, HW automatically works as + * default value for those features which cos_max is smaller. + */ + if ( cos > feat->cos_max ) + cos = 0; + + for ( i = 0; i < feat_props[feat_type]->cos_num; i++ ) + { + if ( type == feat_props[feat_type]->type[i] ) + { + *val = feat->cos_reg_val[cos * feat_props[feat_type]->cos_num + i]; + return 0; + } + } + + return -EINVAL; } int psr_set_l3_cbm(struct domain *d, unsigned int socket, diff --git a/xen/include/asm-x86/psr.h b/xen/include/asm-x86/psr.h index 8d15328faa..0e960bf76a 100644 --- a/xen/include/asm-x86/psr.h +++ b/xen/include/asm-x86/psr.h @@ -72,8 +72,8 @@ void psr_ctxt_switch_to(struct domain *d); int psr_get_info(unsigned int socket, enum cbm_type type, uint32_t data[], unsigned int array_len); -int psr_get_l3_cbm(struct domain *d, unsigned int socket, - uint64_t *cbm, enum cbm_type type); +int psr_get_val(struct domain *d, unsigned int socket, + uint32_t *val, enum cbm_type type); int psr_set_l3_cbm(struct domain *d, unsigned int socket, uint64_t cbm, enum cbm_type type);