@@ -113,6 +113,9 @@ static const struct feat_props {
/* get_feat_info is used to return feature HW info through sysctl. */
bool (*get_feat_info)(const struct feat_node *feat,
uint32_t data[], unsigned int array_len);
+
+ /* write_msr is used to write out feature MSR register. */
+ void (*write_msr)(unsigned int cos, uint32_t val, enum cbm_type type);
} *feat_props[FEAT_TYPE_NUM];
/*
@@ -289,11 +292,17 @@ static bool cat_get_feat_info(const struct feat_node *feat,
}
/* L3 CAT props */
+static void l3_cat_write_msr(unsigned int cos, uint32_t val, enum cbm_type type)
+{
+ wrmsrl(MSR_IA32_PSR_L3_MASK(cos), val);
+}
+
static const struct feat_props l3_cat_props = {
.cos_num = 1,
.type[0] = PSR_CBM_TYPE_L3,
.alt_type = PSR_CBM_TYPE_UNKNOWN,
.get_feat_info = cat_get_feat_info,
+ .write_msr = l3_cat_write_msr,
};
static void __init parse_psr_bool(char *s, char *value, char *feature,
@@ -947,11 +956,79 @@ static int pick_avail_cos(const struct psr_socket_info *info,
return -EOVERFLOW;
}
+static unsigned int get_socket_cpu(unsigned int socket)
+{
+ if ( likely(socket < nr_sockets) )
+ return cpumask_any(socket_cpumask[socket]);
+
+ return nr_cpu_ids;
+}
+
+struct cos_write_info
+{
+ unsigned int cos;
+ struct feat_node *feature;
+ const uint32_t *val;
+ const struct feat_props *props;
+};
+
+static void do_write_psr_msrs(void *data)
+{
+ const struct cos_write_info *info = data;
+ struct feat_node *feat = info->feature;
+ const struct feat_props *props = info->props;
+ unsigned int i, cos = info->cos, cos_num = props->cos_num;
+
+ for ( i = 0; i < cos_num; i++ )
+ {
+ if ( feat->cos_reg_val[cos * cos_num + i] != info->val[i] )
+ {
+ feat->cos_reg_val[cos * cos_num + i] = info->val[i];
+ props->write_msr(cos, info->val[i], props->type[i]);
+ }
+ }
+}
+
static int write_psr_msrs(unsigned int socket, unsigned int cos,
const uint32_t val[], unsigned int array_len,
enum psr_feat_type feat_type)
{
- return -ENOENT;
+ int ret;
+ struct psr_socket_info *info = get_socket_info(socket);
+ struct cos_write_info data =
+ {
+ .cos = cos,
+ .feature = info->features[feat_type],
+ .props = feat_props[feat_type],
+ };
+
+ if ( cos > info->features[feat_type]->cos_max )
+ return -EINVAL;
+
+ /* Skip to the feature's value head. */
+ ret = skip_prior_features(&array_len, feat_type);
+ if ( ret < 0 )
+ return ret;
+
+ val += ret;
+
+ if ( array_len < feat_props[feat_type]->cos_num )
+ return -ENOSPC;
+
+ data.val = val;
+
+ if ( socket == cpu_to_socket(smp_processor_id()) )
+ do_write_psr_msrs(&data);
+ else
+ {
+ unsigned int cpu = get_socket_cpu(socket);
+
+ if ( cpu >= nr_cpu_ids )
+ return -ENOTSOCK;
+ on_selected_cpus(cpumask_of(cpu), do_write_psr_msrs, &data, 1);
+ }
+
+ return 0;
}
int psr_set_val(struct domain *d, unsigned int socket,