/root/src/xen/xen/arch/x86/psr.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * psr.c: Platform Shared Resource related service for guest. |
3 | | * |
4 | | * Copyright (c) 2014, Intel Corporation |
5 | | * Author: Dongxiao Xu <dongxiao.xu@intel.com> |
6 | | * |
7 | | * This program is free software; you can redistribute it and/or modify it |
8 | | * under the terms and conditions of the GNU General Public License, |
9 | | * version 2, as published by the Free Software Foundation. |
10 | | * |
11 | | * This program is distributed in the hope it will be useful, but WITHOUT |
12 | | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
14 | | * more details. |
15 | | */ |
16 | | #include <xen/cpu.h> |
17 | | #include <xen/err.h> |
18 | | #include <xen/init.h> |
19 | | #include <xen/sched.h> |
20 | | #include <asm/psr.h> |
21 | | |
22 | | /* |
23 | | * Terminology: |
24 | | * - CAT Cache Allocation Technology |
25 | | * - CBM Capacity BitMasks |
26 | | * - CDP Code and Data Prioritization |
27 | | * - CMT Cache Monitoring Technology |
28 | | * - COS/CLOS Class of Service. Also mean COS registers. |
29 | | * - COS_MAX Max number of COS for the feature (minus 1) |
30 | | * - MSRs Machine Specific Registers |
31 | | * - PSR Intel Platform Shared Resource |
32 | | */ |
33 | | |
34 | 1 | #define PSR_CMT (1u << 0) |
35 | 1 | #define PSR_CAT (1u << 1) |
36 | 1 | #define PSR_CDP (1u << 2) |
37 | | |
38 | 0 | #define CAT_CBM_LEN_MASK 0x1f |
39 | | #define CAT_COS_MAX_MASK 0xffff |
40 | | |
41 | | /* |
42 | | * Per SDM chapter 'Cache Allocation Technology: Cache Mask Configuration', |
43 | | * the MSRs ranging from 0C90H through 0D0FH (inclusive), enables support for |
44 | | * up to 128 L3 CAT Classes of Service. The COS_ID=[0,127]. |
45 | | * |
46 | | * The MSRs ranging from 0D10H through 0D4FH (inclusive), enables support for |
47 | | * up to 64 L2 CAT COS. The COS_ID=[0,63]. |
48 | | * |
49 | | * So, the maximum COS register count of one feature is 128. |
50 | | */ |
51 | | #define MAX_COS_REG_CNT 128 |
52 | | |
53 | 0 | #define ASSOC_REG_SHIFT 32 |
54 | | |
55 | | /* |
56 | | * Every PSR feature uses some COS registers for each COS ID, e.g. CDP uses 2 |
57 | | * COS registers (DATA and CODE) for one COS ID, but CAT uses 1 COS register. |
58 | | * We use below macro as the max number of COS registers used by all features. |
59 | | * So far, it is 2 which means CDP's COS registers number. |
60 | | */ |
61 | | #define MAX_COS_NUM 2 |
62 | | |
63 | | enum psr_feat_type { |
64 | | FEAT_TYPE_L3_CAT, |
65 | | FEAT_TYPE_L3_CDP, |
66 | | FEAT_TYPE_L2_CAT, |
67 | | FEAT_TYPE_NUM, |
68 | | FEAT_TYPE_UNKNOWN, |
69 | | }; |
70 | | |
71 | | /* |
72 | | * This structure represents one feature. |
73 | | * cos_max - The max COS registers number got through CPUID. |
74 | | * cbm_len - The length of CBM got through CPUID. |
75 | | * cos_reg_val - Array to store the values of COS registers. One entry stores |
76 | | * the value of one COS register. |
77 | | * For L3 CAT and L2 CAT, one entry corresponds to one COS_ID. |
78 | | * For CDP, two entries correspond to one COS_ID. E.g. |
79 | | * COS_ID=0 corresponds to cos_reg_val[0] (Data) and |
80 | | * cos_reg_val[1] (Code). |
81 | | */ |
82 | | struct feat_node { |
83 | | /* cos_max and cbm_len are common values for all features so far. */ |
84 | | unsigned int cos_max; |
85 | | unsigned int cbm_len; |
86 | | uint32_t cos_reg_val[MAX_COS_REG_CNT]; |
87 | | }; |
88 | | |
89 | | /* |
90 | | * This structure defines feature specific values, e.g. cos_num. |
91 | | * |
92 | | * Array 'feat_props' is defined to save every feature's properties. We use |
93 | | * 'enum psr_feat_type' as index. |
94 | | */ |
95 | | static const struct feat_props { |
96 | | /* |
97 | | * cos_num - COS registers number that feature uses for one COS ID. |
98 | | * It is defined in SDM. |
99 | | */ |
100 | | unsigned int cos_num; |
101 | | |
102 | | /* |
103 | | * An array to save all 'enum cbm_type' values of the feature. It is |
104 | | * used with cos_num together to get/write a feature's COS registers |
105 | | * values one by one. |
106 | | */ |
107 | | enum cbm_type type[MAX_COS_NUM]; |
108 | | |
109 | | /* |
110 | | * alt_type is 'alternative type'. When this 'alt_type' is input, the |
111 | | * feature does some special operations. |
112 | | */ |
113 | | enum cbm_type alt_type; |
114 | | |
115 | | /* get_feat_info is used to return feature HW info through sysctl. */ |
116 | | bool (*get_feat_info)(const struct feat_node *feat, |
117 | | uint32_t data[], unsigned int array_len); |
118 | | |
119 | | /* write_msr is used to write out feature MSR register. */ |
120 | | void (*write_msr)(unsigned int cos, uint32_t val, enum cbm_type type); |
121 | | } *feat_props[FEAT_TYPE_NUM]; |
122 | | |
123 | | /* |
124 | | * PSR features are managed per socket. Below structure defines the members |
125 | | * used to manage these features. |
126 | | * feat_init - Indicate if features on a socket have been initialized. |
127 | | * features - A feature node array used to manage all features enabled. |
128 | | * ref_lock - A lock to protect cos_ref. |
129 | | * cos_ref - A reference count array to record how many domains are using the |
130 | | * COS ID. Every entry of cos_ref corresponds to one COS ID. |
131 | | * dom_set - A bitmap to indicate which domain's cos id has been set. |
132 | | */ |
133 | | struct psr_socket_info { |
134 | | bool feat_init; |
135 | | /* Feature array's index is 'enum psr_feat_type' which is same as 'props' */ |
136 | | struct feat_node *features[FEAT_TYPE_NUM]; |
137 | | spinlock_t ref_lock; |
138 | | unsigned int cos_ref[MAX_COS_REG_CNT]; |
139 | | /* Every bit corresponds to a domain. Index is domain_id. */ |
140 | | DECLARE_BITMAP(dom_set, DOMID_IDLE + 1); |
141 | | }; |
142 | | |
143 | | struct psr_assoc { |
144 | | uint64_t val; |
145 | | uint64_t cos_mask; |
146 | | }; |
147 | | |
148 | | struct psr_cmt *__read_mostly psr_cmt; |
149 | | |
150 | | static struct psr_socket_info *__read_mostly socket_info; |
151 | | |
152 | | static unsigned int opt_psr; |
153 | | static unsigned int __initdata opt_rmid_max = 255; |
154 | | static unsigned int __read_mostly opt_cos_max = MAX_COS_REG_CNT; |
155 | | static uint64_t rmid_mask; |
156 | | static DEFINE_PER_CPU(struct psr_assoc, psr_assoc); |
157 | | |
158 | | /* |
159 | | * Declare global feature node for every feature to facilitate the feature |
160 | | * array creation. It is used to transiently store a spare node. |
161 | | */ |
162 | | static struct feat_node *feat_l3; |
163 | | static struct feat_node *feat_l2_cat; |
164 | | |
165 | | /* Common functions */ |
166 | 0 | #define cat_default_val(len) (0xffffffff >> (32 - (len))) |
167 | | |
168 | | /* |
169 | | * get_cdp_data - get DATA COS register value from input COS ID. |
170 | | * @feat: the feature node. |
171 | | * @cos: the COS ID. |
172 | | */ |
173 | | #define get_cdp_data(feat, cos) \ |
174 | 0 | ((feat)->cos_reg_val[(cos) * 2]) |
175 | | |
176 | | /* |
177 | | * get_cdp_code - get CODE COS register value from input COS ID. |
178 | | * @feat: the feature node. |
179 | | * @cos: the COS ID. |
180 | | */ |
181 | | #define get_cdp_code(feat, cos) \ |
182 | 0 | ((feat)->cos_reg_val[(cos) * 2 + 1]) |
183 | | |
184 | | /* |
185 | | * Use this function to check if any allocation feature has been enabled |
186 | | * in cmdline. |
187 | | */ |
188 | | static bool psr_alloc_feat_enabled(void) |
189 | 6 | { |
190 | 6 | return !!socket_info; |
191 | 6 | } |
192 | | |
193 | | static void free_socket_resources(unsigned int socket) |
194 | 0 | { |
195 | 0 | unsigned int i; |
196 | 0 | struct psr_socket_info *info = socket_info + socket; |
197 | 0 |
|
198 | 0 | ASSERT(socket_info); |
199 | 0 |
|
200 | 0 | /* |
201 | 0 | * Free resources of features. The global feature object, e.g. feat_l3, |
202 | 0 | * may not be freed here if it is not added into array. It is simply being |
203 | 0 | * kept until the next CPU online attempt. |
204 | 0 | */ |
205 | 0 | for ( i = 0; i < ARRAY_SIZE(info->features); i++ ) |
206 | 0 | { |
207 | 0 | xfree(info->features[i]); |
208 | 0 | info->features[i] = NULL; |
209 | 0 | } |
210 | 0 |
|
211 | 0 | info->feat_init = false; |
212 | 0 |
|
213 | 0 | memset(info->cos_ref, 0, MAX_COS_REG_CNT * sizeof(unsigned int)); |
214 | 0 |
|
215 | 0 | bitmap_zero(info->dom_set, DOMID_IDLE + 1); |
216 | 0 | } |
217 | | |
218 | | static enum psr_feat_type psr_cbm_type_to_feat_type(enum cbm_type type) |
219 | 0 | { |
220 | 0 | enum psr_feat_type feat_type = FEAT_TYPE_UNKNOWN; |
221 | 0 |
|
222 | 0 | switch ( type ) |
223 | 0 | { |
224 | 0 | case PSR_CBM_TYPE_L3: |
225 | 0 | feat_type = FEAT_TYPE_L3_CAT; |
226 | 0 |
|
227 | 0 | /* |
228 | 0 | * If type is L3 CAT but we cannot find it in feat_props array, |
229 | 0 | * try CDP. |
230 | 0 | */ |
231 | 0 | if ( !feat_props[feat_type] ) |
232 | 0 | feat_type = FEAT_TYPE_L3_CDP; |
233 | 0 |
|
234 | 0 | break; |
235 | 0 |
|
236 | 0 | case PSR_CBM_TYPE_L3_DATA: |
237 | 0 | case PSR_CBM_TYPE_L3_CODE: |
238 | 0 | feat_type = FEAT_TYPE_L3_CDP; |
239 | 0 | break; |
240 | 0 |
|
241 | 0 | case PSR_CBM_TYPE_L2: |
242 | 0 | feat_type = FEAT_TYPE_L2_CAT; |
243 | 0 | break; |
244 | 0 |
|
245 | 0 | default: |
246 | 0 | ASSERT_UNREACHABLE(); |
247 | 0 | } |
248 | 0 |
|
249 | 0 | return feat_type; |
250 | 0 | } |
251 | | |
252 | | static bool psr_check_cbm(unsigned int cbm_len, unsigned long cbm) |
253 | 0 | { |
254 | 0 | unsigned int first_bit, zero_bit; |
255 | 0 |
|
256 | 0 | /* Set bits should only in the range of [0, cbm_len]. */ |
257 | 0 | if ( cbm & (~0ul << cbm_len) ) |
258 | 0 | return false; |
259 | 0 |
|
260 | 0 | /* At least one bit need to be set. */ |
261 | 0 | if ( cbm == 0 ) |
262 | 0 | return false; |
263 | 0 |
|
264 | 0 | first_bit = find_first_bit(&cbm, cbm_len); |
265 | 0 | zero_bit = find_next_zero_bit(&cbm, cbm_len, first_bit); |
266 | 0 |
|
267 | 0 | /* Set bits should be contiguous. */ |
268 | 0 | if ( zero_bit < cbm_len && |
269 | 0 | find_next_bit(&cbm, cbm_len, zero_bit) < cbm_len ) |
270 | 0 | return false; |
271 | 0 |
|
272 | 0 | return true; |
273 | 0 | } |
274 | | |
275 | | /* CAT common functions implementation. */ |
276 | | static int cat_init_feature(const struct cpuid_leaf *regs, |
277 | | struct feat_node *feat, |
278 | | struct psr_socket_info *info, |
279 | | enum psr_feat_type type) |
280 | 0 | { |
281 | 0 | const char *const cat_feat_name[FEAT_TYPE_NUM] = { |
282 | 0 | [FEAT_TYPE_L3_CAT] = "L3 CAT", |
283 | 0 | [FEAT_TYPE_L3_CDP] = "L3 CDP", |
284 | 0 | [FEAT_TYPE_L2_CAT] = "L2 CAT", |
285 | 0 | }; |
286 | 0 |
|
287 | 0 | /* No valid value so do not enable feature. */ |
288 | 0 | if ( !regs->a || !regs->d ) |
289 | 0 | return -ENOENT; |
290 | 0 |
|
291 | 0 | feat->cbm_len = (regs->a & CAT_CBM_LEN_MASK) + 1; |
292 | 0 | feat->cos_max = min(opt_cos_max, regs->d & CAT_COS_MAX_MASK); |
293 | 0 |
|
294 | 0 | switch ( type ) |
295 | 0 | { |
296 | 0 | case FEAT_TYPE_L3_CAT: |
297 | 0 | case FEAT_TYPE_L2_CAT: |
298 | 0 | if ( feat->cos_max < 1 ) |
299 | 0 | return -ENOENT; |
300 | 0 |
|
301 | 0 | /* We reserve cos=0 as default cbm (all bits within cbm_len are 1). */ |
302 | 0 | feat->cos_reg_val[0] = cat_default_val(feat->cbm_len); |
303 | 0 |
|
304 | 0 | wrmsrl((type == FEAT_TYPE_L3_CAT ? |
305 | 0 | MSR_IA32_PSR_L3_MASK(0) : |
306 | 0 | MSR_IA32_PSR_L2_MASK(0)), |
307 | 0 | cat_default_val(feat->cbm_len)); |
308 | 0 |
|
309 | 0 | break; |
310 | 0 |
|
311 | 0 | case FEAT_TYPE_L3_CDP: |
312 | 0 | { |
313 | 0 | uint64_t val; |
314 | 0 |
|
315 | 0 | if ( feat->cos_max < 3 ) |
316 | 0 | return -ENOENT; |
317 | 0 |
|
318 | 0 | /* Cut half of cos_max when CDP is enabled. */ |
319 | 0 | feat->cos_max = (feat->cos_max - 1) >> 1; |
320 | 0 |
|
321 | 0 | /* We reserve cos=0 as default cbm (all bits within cbm_len are 1). */ |
322 | 0 | get_cdp_code(feat, 0) = cat_default_val(feat->cbm_len); |
323 | 0 | get_cdp_data(feat, 0) = cat_default_val(feat->cbm_len); |
324 | 0 |
|
325 | 0 | wrmsrl(MSR_IA32_PSR_L3_MASK(0), cat_default_val(feat->cbm_len)); |
326 | 0 | wrmsrl(MSR_IA32_PSR_L3_MASK(1), cat_default_val(feat->cbm_len)); |
327 | 0 | rdmsrl(MSR_IA32_PSR_L3_QOS_CFG, val); |
328 | 0 | wrmsrl(MSR_IA32_PSR_L3_QOS_CFG, |
329 | 0 | val | (1ull << PSR_L3_QOS_CDP_ENABLE_BIT)); |
330 | 0 |
|
331 | 0 | break; |
332 | 0 | } |
333 | 0 |
|
334 | 0 | default: |
335 | 0 | return -ENOENT; |
336 | 0 | } |
337 | 0 |
|
338 | 0 | /* Add this feature into array. */ |
339 | 0 | info->features[type] = feat; |
340 | 0 |
|
341 | 0 | if ( !opt_cpu_info ) |
342 | 0 | return 0; |
343 | 0 |
|
344 | 0 | printk(XENLOG_INFO "%s: enabled on socket %u, cos_max:%u, cbm_len:%u\n", |
345 | 0 | cat_feat_name[type], cpu_to_socket(smp_processor_id()), |
346 | 0 | feat->cos_max, feat->cbm_len); |
347 | 0 |
|
348 | 0 | return 0; |
349 | 0 | } |
350 | | |
351 | | static bool cat_get_feat_info(const struct feat_node *feat, |
352 | | uint32_t data[], unsigned int array_len) |
353 | 0 | { |
354 | 0 | if ( array_len != PSR_INFO_ARRAY_SIZE ) |
355 | 0 | return false; |
356 | 0 |
|
357 | 0 | data[PSR_INFO_IDX_COS_MAX] = feat->cos_max; |
358 | 0 | data[PSR_INFO_IDX_CAT_CBM_LEN] = feat->cbm_len; |
359 | 0 | data[PSR_INFO_IDX_CAT_FLAG] = 0; |
360 | 0 |
|
361 | 0 | return true; |
362 | 0 | } |
363 | | |
364 | | /* L3 CAT props */ |
365 | | static void l3_cat_write_msr(unsigned int cos, uint32_t val, enum cbm_type type) |
366 | 0 | { |
367 | 0 | wrmsrl(MSR_IA32_PSR_L3_MASK(cos), val); |
368 | 0 | } |
369 | | |
370 | | static const struct feat_props l3_cat_props = { |
371 | | .cos_num = 1, |
372 | | .type[0] = PSR_CBM_TYPE_L3, |
373 | | .alt_type = PSR_CBM_TYPE_UNKNOWN, |
374 | | .get_feat_info = cat_get_feat_info, |
375 | | .write_msr = l3_cat_write_msr, |
376 | | }; |
377 | | |
378 | | /* L3 CDP props */ |
379 | | static bool l3_cdp_get_feat_info(const struct feat_node *feat, |
380 | | uint32_t data[], uint32_t array_len) |
381 | 0 | { |
382 | 0 | if ( !cat_get_feat_info(feat, data, array_len) ) |
383 | 0 | return false; |
384 | 0 |
|
385 | 0 | data[PSR_INFO_IDX_CAT_FLAG] |= XEN_SYSCTL_PSR_CAT_L3_CDP; |
386 | 0 |
|
387 | 0 | return true; |
388 | 0 | } |
389 | | |
390 | | static void l3_cdp_write_msr(unsigned int cos, uint32_t val, enum cbm_type type) |
391 | 0 | { |
392 | 0 | wrmsrl(((type == PSR_CBM_TYPE_L3_DATA) ? |
393 | 0 | MSR_IA32_PSR_L3_MASK_DATA(cos) : |
394 | 0 | MSR_IA32_PSR_L3_MASK_CODE(cos)), |
395 | 0 | val); |
396 | 0 | } |
397 | | |
398 | | static const struct feat_props l3_cdp_props = { |
399 | | .cos_num = 2, |
400 | | .type[0] = PSR_CBM_TYPE_L3_DATA, |
401 | | .type[1] = PSR_CBM_TYPE_L3_CODE, |
402 | | .alt_type = PSR_CBM_TYPE_L3, |
403 | | .get_feat_info = l3_cdp_get_feat_info, |
404 | | .write_msr = l3_cdp_write_msr, |
405 | | }; |
406 | | |
407 | | /* L2 CAT props */ |
408 | | static void l2_cat_write_msr(unsigned int cos, uint32_t val, enum cbm_type type) |
409 | 0 | { |
410 | 0 | wrmsrl(MSR_IA32_PSR_L2_MASK(cos), val); |
411 | 0 | } |
412 | | |
413 | | static const struct feat_props l2_cat_props = { |
414 | | .cos_num = 1, |
415 | | .type[0] = PSR_CBM_TYPE_L2, |
416 | | .alt_type = PSR_CBM_TYPE_UNKNOWN, |
417 | | .get_feat_info = cat_get_feat_info, |
418 | | .write_msr = l2_cat_write_msr, |
419 | | }; |
420 | | |
421 | | static bool __init parse_psr_bool(const char *s, const char *delim, |
422 | | const char *ss, const char *feature, |
423 | | unsigned int mask) |
424 | 0 | { |
425 | 0 | /* If cmdline is 'psr=', we need make sure delim != s */ |
426 | 0 | if ( delim != s && !strncmp(s, feature, delim - s) ) |
427 | 0 | { |
428 | 0 | if ( !*delim || *delim == ',' ) |
429 | 0 | opt_psr |= mask; |
430 | 0 | else |
431 | 0 | { |
432 | 0 | int val_int = parse_bool(delim + 1, ss); |
433 | 0 |
|
434 | 0 | if ( val_int == 0 ) |
435 | 0 | opt_psr &= ~mask; |
436 | 0 | else if ( val_int == 1 ) |
437 | 0 | opt_psr |= mask; |
438 | 0 | else |
439 | 0 | return false; |
440 | 0 | } |
441 | 0 | return true; |
442 | 0 | } |
443 | 0 | return false; |
444 | 0 | } |
445 | | |
446 | | static int __init parse_psr_param(const char *s) |
447 | 0 | { |
448 | 0 | const char *ss, *val_delim; |
449 | 0 | const char *q; |
450 | 0 | int rc = 0; |
451 | 0 |
|
452 | 0 | do { |
453 | 0 | ss = strchr(s, ','); |
454 | 0 | if ( !ss ) |
455 | 0 | ss = strchr(s, '\0'); |
456 | 0 |
|
457 | 0 | val_delim = strchr(s, ':'); |
458 | 0 | if ( !val_delim ) |
459 | 0 | val_delim = strchr(s, '\0'); |
460 | 0 |
|
461 | 0 | /* E.g. 'psr=cmt,rmid_max:200' */ |
462 | 0 | if ( val_delim > ss ) |
463 | 0 | val_delim = ss; |
464 | 0 |
|
465 | 0 | if ( *val_delim && !strncmp(s, "rmid_max", val_delim - s) ) |
466 | 0 | { |
467 | 0 | opt_rmid_max = simple_strtoul(val_delim + 1, &q, 0); |
468 | 0 | if ( *q && *q != ',' ) |
469 | 0 | rc = -EINVAL; |
470 | 0 | } |
471 | 0 | else if ( *val_delim && !strncmp(s, "cos_max", val_delim - s) ) |
472 | 0 | { |
473 | 0 | opt_cos_max = simple_strtoul(val_delim + 1, &q, 0); |
474 | 0 | if ( *q && *q != ',' ) |
475 | 0 | rc = -EINVAL; |
476 | 0 | } |
477 | 0 | else if ( !parse_psr_bool(s, val_delim, ss, "cmt", PSR_CMT) && |
478 | 0 | !parse_psr_bool(s, val_delim, ss, "cat", PSR_CAT) && |
479 | 0 | !parse_psr_bool(s, val_delim, ss, "cdp", PSR_CDP) ) |
480 | 0 | rc = -EINVAL; |
481 | 0 |
|
482 | 0 | s = ss + 1; |
483 | 0 | } while ( *ss ); |
484 | 0 |
|
485 | 0 | return rc; |
486 | 0 | } |
487 | | custom_param("psr", parse_psr_param); |
488 | | |
489 | | static void __init init_psr_cmt(unsigned int rmid_max) |
490 | 0 | { |
491 | 0 | unsigned int eax, ebx, ecx, edx; |
492 | 0 | unsigned int rmid; |
493 | 0 |
|
494 | 0 | if ( !boot_cpu_has(X86_FEATURE_PQM) ) |
495 | 0 | return; |
496 | 0 |
|
497 | 0 | cpuid_count(0xf, 0, &eax, &ebx, &ecx, &edx); |
498 | 0 | if ( !edx ) |
499 | 0 | return; |
500 | 0 |
|
501 | 0 | psr_cmt = xzalloc(struct psr_cmt); |
502 | 0 | if ( !psr_cmt ) |
503 | 0 | return; |
504 | 0 |
|
505 | 0 | psr_cmt->features = edx; |
506 | 0 | psr_cmt->rmid_max = min(rmid_max, ebx); |
507 | 0 | rmid_mask = ~(~0ull << get_count_order(ebx)); |
508 | 0 |
|
509 | 0 | if ( psr_cmt->features & PSR_RESOURCE_TYPE_L3 ) |
510 | 0 | { |
511 | 0 | cpuid_count(0xf, 1, &eax, &ebx, &ecx, &edx); |
512 | 0 | psr_cmt->l3.upscaling_factor = ebx; |
513 | 0 | psr_cmt->l3.rmid_max = ecx; |
514 | 0 | psr_cmt->l3.features = edx; |
515 | 0 | } |
516 | 0 |
|
517 | 0 | psr_cmt->rmid_max = min(psr_cmt->rmid_max, psr_cmt->l3.rmid_max); |
518 | 0 | psr_cmt->rmid_to_dom = xmalloc_array(domid_t, psr_cmt->rmid_max + 1UL); |
519 | 0 | if ( !psr_cmt->rmid_to_dom ) |
520 | 0 | { |
521 | 0 | xfree(psr_cmt); |
522 | 0 | psr_cmt = NULL; |
523 | 0 | return; |
524 | 0 | } |
525 | 0 |
|
526 | 0 | /* |
527 | 0 | * Once CMT is enabled each CPU will always require a RMID to associate |
528 | 0 | * with it. To reduce the waste of RMID, reserve RMID 0 for all CPUs that |
529 | 0 | * have no domain being monitored. |
530 | 0 | */ |
531 | 0 | psr_cmt->rmid_to_dom[0] = DOMID_XEN; |
532 | 0 | for ( rmid = 1; rmid <= psr_cmt->rmid_max; rmid++ ) |
533 | 0 | psr_cmt->rmid_to_dom[rmid] = DOMID_INVALID; |
534 | 0 |
|
535 | 0 | printk(XENLOG_INFO "Cache Monitoring Technology enabled\n"); |
536 | 0 | } |
537 | | |
538 | | /* Called with domain lock held, no psr specific lock needed */ |
539 | | int psr_alloc_rmid(struct domain *d) |
540 | 0 | { |
541 | 0 | unsigned int rmid; |
542 | 0 |
|
543 | 0 | ASSERT(psr_cmt_enabled()); |
544 | 0 |
|
545 | 0 | if ( d->arch.psr_rmid > 0 ) |
546 | 0 | return -EEXIST; |
547 | 0 |
|
548 | 0 | for ( rmid = 1; rmid <= psr_cmt->rmid_max; rmid++ ) |
549 | 0 | { |
550 | 0 | if ( psr_cmt->rmid_to_dom[rmid] != DOMID_INVALID ) |
551 | 0 | continue; |
552 | 0 |
|
553 | 0 | psr_cmt->rmid_to_dom[rmid] = d->domain_id; |
554 | 0 | break; |
555 | 0 | } |
556 | 0 |
|
557 | 0 | /* No RMID available, assign RMID=0 by default. */ |
558 | 0 | if ( rmid > psr_cmt->rmid_max ) |
559 | 0 | { |
560 | 0 | d->arch.psr_rmid = 0; |
561 | 0 | return -EOVERFLOW; |
562 | 0 | } |
563 | 0 |
|
564 | 0 | d->arch.psr_rmid = rmid; |
565 | 0 |
|
566 | 0 | return 0; |
567 | 0 | } |
568 | | |
569 | | /* Called with domain lock held, no psr specific lock needed */ |
570 | | void psr_free_rmid(struct domain *d) |
571 | 0 | { |
572 | 0 | unsigned int rmid; |
573 | 0 |
|
574 | 0 | rmid = d->arch.psr_rmid; |
575 | 0 | /* We do not free system reserved "RMID=0". */ |
576 | 0 | if ( rmid == 0 ) |
577 | 0 | return; |
578 | 0 |
|
579 | 0 | psr_cmt->rmid_to_dom[rmid] = DOMID_INVALID; |
580 | 0 | d->arch.psr_rmid = 0; |
581 | 0 | } |
582 | | |
583 | | static unsigned int get_max_cos_max(const struct psr_socket_info *info) |
584 | 0 | { |
585 | 0 | unsigned int cos_max = 0, i; |
586 | 0 |
|
587 | 0 | for ( i = 0; i < ARRAY_SIZE(info->features); i++ ) |
588 | 0 | { |
589 | 0 | const struct feat_node *feat = info->features[i]; |
590 | 0 |
|
591 | 0 | if ( feat ) |
592 | 0 | cos_max = max(feat->cos_max, cos_max); |
593 | 0 | } |
594 | 0 |
|
595 | 0 | return cos_max; |
596 | 0 | } |
597 | | |
598 | | static void psr_assoc_init(void) |
599 | 1 | { |
600 | 1 | struct psr_assoc *psra = &this_cpu(psr_assoc); |
601 | 1 | |
602 | 1 | if ( psr_alloc_feat_enabled() ) |
603 | 0 | { |
604 | 0 | unsigned int socket = cpu_to_socket(smp_processor_id()); |
605 | 0 | const struct psr_socket_info *info = socket_info + socket; |
606 | 0 | unsigned int cos_max = get_max_cos_max(info); |
607 | 0 |
|
608 | 0 | if ( info->feat_init ) |
609 | 0 | psra->cos_mask = ((1ull << get_count_order(cos_max)) - 1) << |
610 | 0 | ASSOC_REG_SHIFT; |
611 | 0 | } |
612 | 1 | |
613 | 1 | if ( psr_cmt_enabled() || psra->cos_mask ) |
614 | 0 | rdmsrl(MSR_IA32_PSR_ASSOC, psra->val); |
615 | 1 | } |
616 | | |
617 | | static inline void psr_assoc_rmid(uint64_t *reg, unsigned int rmid) |
618 | 0 | { |
619 | 0 | *reg = (*reg & ~rmid_mask) | (rmid & rmid_mask); |
620 | 0 | } |
621 | | |
622 | | static uint64_t psr_assoc_cos(uint64_t reg, unsigned int cos, |
623 | | uint64_t cos_mask) |
624 | 0 | { |
625 | 0 | return (reg & ~cos_mask) | |
626 | 0 | (((uint64_t)cos << ASSOC_REG_SHIFT) & cos_mask); |
627 | 0 | } |
628 | | |
629 | | void psr_ctxt_switch_to(struct domain *d) |
630 | 39.5k | { |
631 | 39.5k | struct psr_assoc *psra = &this_cpu(psr_assoc); |
632 | 39.5k | uint64_t reg = psra->val; |
633 | 39.5k | |
634 | 39.5k | if ( psr_cmt_enabled() ) |
635 | 0 | psr_assoc_rmid(®, d->arch.psr_rmid); |
636 | 39.5k | |
637 | 39.5k | /* |
638 | 39.5k | * If the domain is not set in 'dom_set' bitmap, that means the domain's |
639 | 39.5k | * cos id is not valid. So, we have to use default value (0) to set ASSOC |
640 | 39.5k | * register. Furthermore, if domain's 'psr_cos_ids' is NULL, we need |
641 | 39.5k | * default value for it too (for case that the domain's psr_cos_ids is not |
642 | 39.5k | * successfully allocated). |
643 | 39.5k | */ |
644 | 39.5k | if ( psra->cos_mask ) |
645 | 0 | { |
646 | 0 | unsigned int socket = cpu_to_socket(smp_processor_id()); |
647 | 0 | struct psr_socket_info *info = socket_info + socket; |
648 | 0 | unsigned int cos = 0; |
649 | 0 |
|
650 | 0 | if ( likely(test_bit(d->domain_id, info->dom_set)) && |
651 | 0 | d->arch.psr_cos_ids ) |
652 | 0 | cos = d->arch.psr_cos_ids[socket]; |
653 | 0 |
|
654 | 0 | reg = psr_assoc_cos(reg, cos, psra->cos_mask); |
655 | 0 | } |
656 | 39.5k | |
657 | 39.5k | if ( reg != psra->val ) |
658 | 0 | { |
659 | 0 | wrmsrl(MSR_IA32_PSR_ASSOC, reg); |
660 | 0 | psra->val = reg; |
661 | 0 | } |
662 | 39.5k | } |
663 | | |
664 | | static struct psr_socket_info *get_socket_info(unsigned int socket) |
665 | 0 | { |
666 | 0 | if ( !socket_info ) |
667 | 0 | return ERR_PTR(-ENODEV); |
668 | 0 |
|
669 | 0 | if ( socket >= nr_sockets ) |
670 | 0 | return ERR_PTR(-ERANGE); |
671 | 0 |
|
672 | 0 | if ( !socket_info[socket].feat_init ) |
673 | 0 | return ERR_PTR(-ENOENT); |
674 | 0 |
|
675 | 0 | return socket_info + socket; |
676 | 0 | } |
677 | | |
678 | | int psr_get_info(unsigned int socket, enum cbm_type type, |
679 | | uint32_t data[], unsigned int array_len) |
680 | 0 | { |
681 | 0 | const struct psr_socket_info *info = get_socket_info(socket); |
682 | 0 | const struct feat_node *feat; |
683 | 0 | enum psr_feat_type feat_type; |
684 | 0 |
|
685 | 0 | ASSERT(data); |
686 | 0 |
|
687 | 0 | if ( IS_ERR(info) ) |
688 | 0 | return PTR_ERR(info); |
689 | 0 |
|
690 | 0 | feat_type = psr_cbm_type_to_feat_type(type); |
691 | 0 | if ( feat_type >= ARRAY_SIZE(info->features) ) |
692 | 0 | return -ENOENT; |
693 | 0 |
|
694 | 0 | feat = info->features[feat_type]; |
695 | 0 | if ( !feat ) |
696 | 0 | return -ENOENT; |
697 | 0 |
|
698 | 0 | if ( !feat_props[feat_type] ) |
699 | 0 | { |
700 | 0 | ASSERT_UNREACHABLE(); |
701 | 0 | return -ENOENT; |
702 | 0 | } |
703 | 0 |
|
704 | 0 | if ( feat_props[feat_type]->get_feat_info(feat, data, array_len) ) |
705 | 0 | return 0; |
706 | 0 |
|
707 | 0 | return -EINVAL; |
708 | 0 | } |
709 | | |
710 | | int psr_get_val(struct domain *d, unsigned int socket, |
711 | | uint32_t *val, enum cbm_type type) |
712 | 0 | { |
713 | 0 | const struct psr_socket_info *info = get_socket_info(socket); |
714 | 0 | const struct feat_node *feat; |
715 | 0 | enum psr_feat_type feat_type; |
716 | 0 | unsigned int cos, i; |
717 | 0 |
|
718 | 0 | ASSERT(val); |
719 | 0 |
|
720 | 0 | if ( IS_ERR(info) ) |
721 | 0 | return PTR_ERR(info); |
722 | 0 |
|
723 | 0 | feat_type = psr_cbm_type_to_feat_type(type); |
724 | 0 | if ( feat_type >= ARRAY_SIZE(info->features) ) |
725 | 0 | return -ENOENT; |
726 | 0 |
|
727 | 0 | feat = info->features[feat_type]; |
728 | 0 | if ( !feat ) |
729 | 0 | return -ENOENT; |
730 | 0 |
|
731 | 0 | if ( !feat_props[feat_type] ) |
732 | 0 | { |
733 | 0 | ASSERT_UNREACHABLE(); |
734 | 0 | return -ENOENT; |
735 | 0 | } |
736 | 0 |
|
737 | 0 | domain_lock(d); |
738 | 0 | if ( !test_and_set_bit(d->domain_id, socket_info[socket].dom_set) ) |
739 | 0 | d->arch.psr_cos_ids[socket] = 0; |
740 | 0 |
|
741 | 0 | cos = d->arch.psr_cos_ids[socket]; |
742 | 0 | domain_unlock(d); |
743 | 0 |
|
744 | 0 | /* |
745 | 0 | * If input cos exceeds current feature's cos_max, we should return its |
746 | 0 | * default value which is stored in cos 0. This case only happens |
747 | 0 | * when more than two features enabled concurrently and at least one |
748 | 0 | * features's cos_max is bigger than others. When a domain's working cos |
749 | 0 | * id is bigger than some features' cos_max, HW automatically works as |
750 | 0 | * default value for those features which cos_max is smaller. |
751 | 0 | */ |
752 | 0 | if ( cos > feat->cos_max ) |
753 | 0 | cos = 0; |
754 | 0 |
|
755 | 0 | for ( i = 0; i < feat_props[feat_type]->cos_num; i++ ) |
756 | 0 | { |
757 | 0 | if ( type == feat_props[feat_type]->type[i] ) |
758 | 0 | { |
759 | 0 | *val = feat->cos_reg_val[cos * feat_props[feat_type]->cos_num + i]; |
760 | 0 | return 0; |
761 | 0 | } |
762 | 0 | } |
763 | 0 |
|
764 | 0 | return -EINVAL; |
765 | 0 | } |
766 | | |
767 | | /* Set value functions */ |
768 | | static unsigned int get_cos_num(void) |
769 | 0 | { |
770 | 0 | unsigned int num = 0, i; |
771 | 0 |
|
772 | 0 | /* Get all features total amount. */ |
773 | 0 | for ( i = 0; i < ARRAY_SIZE(feat_props); i++ ) |
774 | 0 | if ( feat_props[i] ) |
775 | 0 | num += feat_props[i]->cos_num; |
776 | 0 |
|
777 | 0 | return num; |
778 | 0 | } |
779 | | |
780 | | static int gather_val_array(uint32_t val[], |
781 | | unsigned int array_len, |
782 | | const struct psr_socket_info *info, |
783 | | unsigned int old_cos) |
784 | 0 | { |
785 | 0 | unsigned int i; |
786 | 0 |
|
787 | 0 | if ( !val ) |
788 | 0 | return -EINVAL; |
789 | 0 |
|
790 | 0 | /* Get all features current values according to old_cos. */ |
791 | 0 | for ( i = 0; i < ARRAY_SIZE(info->features); i++ ) |
792 | 0 | { |
793 | 0 | unsigned int cos = old_cos, j; |
794 | 0 | const struct feat_node *feat = info->features[i]; |
795 | 0 | const struct feat_props *props = feat_props[i]; |
796 | 0 |
|
797 | 0 | if ( !feat ) |
798 | 0 | continue; |
799 | 0 |
|
800 | 0 | if ( !props ) |
801 | 0 | { |
802 | 0 | ASSERT_UNREACHABLE(); |
803 | 0 | return -ENOENT; |
804 | 0 | } |
805 | 0 |
|
806 | 0 | if ( array_len < props->cos_num ) |
807 | 0 | return -ENOSPC; |
808 | 0 |
|
809 | 0 | /* |
810 | 0 | * If old_cos exceeds current feature's cos_max, we should get |
811 | 0 | * default value. So assign cos to 0 which stores default value. |
812 | 0 | */ |
813 | 0 | if ( cos > feat->cos_max ) |
814 | 0 | cos = 0; |
815 | 0 |
|
816 | 0 | /* Value getting order is same as feature array. */ |
817 | 0 | for ( j = 0; j < props->cos_num; j++ ) |
818 | 0 | val[j] = feat->cos_reg_val[cos * props->cos_num + j]; |
819 | 0 |
|
820 | 0 | array_len -= props->cos_num; |
821 | 0 | val += props->cos_num; |
822 | 0 | } |
823 | 0 |
|
824 | 0 | return 0; |
825 | 0 | } |
826 | | |
827 | | static int skip_prior_features(unsigned int *array_len, |
828 | | enum psr_feat_type feat_type) |
829 | 0 | { |
830 | 0 | unsigned int i, skip_len = 0; |
831 | 0 |
|
832 | 0 | for ( i = 0; i < feat_type; i++ ) |
833 | 0 | { |
834 | 0 | const struct feat_props *props = feat_props[i]; |
835 | 0 |
|
836 | 0 | if ( !props ) |
837 | 0 | continue; |
838 | 0 |
|
839 | 0 | if ( *array_len <= props->cos_num ) |
840 | 0 | return -ENOSPC; |
841 | 0 |
|
842 | 0 | *array_len -= props->cos_num; |
843 | 0 | skip_len += props->cos_num; |
844 | 0 | } |
845 | 0 |
|
846 | 0 | return skip_len; |
847 | 0 | } |
848 | | |
849 | | static int insert_val_into_array(uint32_t val[], |
850 | | unsigned int array_len, |
851 | | const struct psr_socket_info *info, |
852 | | enum psr_feat_type feat_type, |
853 | | enum cbm_type type, |
854 | | uint32_t new_val) |
855 | 0 | { |
856 | 0 | const struct feat_node *feat; |
857 | 0 | const struct feat_props *props; |
858 | 0 | unsigned int i; |
859 | 0 | int ret; |
860 | 0 |
|
861 | 0 | ASSERT(feat_type < FEAT_TYPE_NUM); |
862 | 0 |
|
863 | 0 | ret = skip_prior_features(&array_len, feat_type); |
864 | 0 | if ( ret < 0 ) |
865 | 0 | return ret; |
866 | 0 |
|
867 | 0 | val += ret; |
868 | 0 |
|
869 | 0 | feat = info->features[feat_type]; |
870 | 0 | if ( !feat ) |
871 | 0 | return -ENOENT; |
872 | 0 |
|
873 | 0 | props = feat_props[feat_type]; |
874 | 0 | if ( !props ) |
875 | 0 | { |
876 | 0 | ASSERT_UNREACHABLE(); |
877 | 0 | return -ENOENT; |
878 | 0 | } |
879 | 0 |
|
880 | 0 | if ( array_len < props->cos_num ) |
881 | 0 | return -ENOSPC; |
882 | 0 |
|
883 | 0 | if ( !psr_check_cbm(feat->cbm_len, new_val) ) |
884 | 0 | return -EINVAL; |
885 | 0 |
|
886 | 0 | /* |
887 | 0 | * Value setting position is same as feature array. |
888 | 0 | * For CDP, user may set both DATA and CODE to same value. For such case, |
889 | 0 | * user input 'PSR_CBM_TYPE_L3' as type. The alternative type of CDP is same |
890 | 0 | * as it. So we should set new_val to both of DATA and CODE under such case. |
891 | 0 | */ |
892 | 0 | for ( i = 0; i < props->cos_num; i++ ) |
893 | 0 | { |
894 | 0 | if ( type == props->type[i] ) |
895 | 0 | { |
896 | 0 | val[i] = new_val; |
897 | 0 | ret = 0; |
898 | 0 | break; |
899 | 0 | } |
900 | 0 | else if ( type == props->alt_type ) |
901 | 0 | val[i] = new_val; |
902 | 0 | else |
903 | 0 | ret = -EINVAL; |
904 | 0 | } |
905 | 0 |
|
906 | 0 | return ret; |
907 | 0 | } |
908 | | |
909 | | static int compare_val(const uint32_t val[], |
910 | | const struct feat_node *feat, |
911 | | const struct feat_props *props, |
912 | | unsigned int cos) |
913 | 0 | { |
914 | 0 | unsigned int i; |
915 | 0 |
|
916 | 0 | for ( i = 0; i < props->cos_num; i++ ) |
917 | 0 | { |
918 | 0 | uint32_t feat_val; |
919 | 0 |
|
920 | 0 | /* If cos is bigger than cos_max, we need compare default value. */ |
921 | 0 | if ( cos > feat->cos_max ) |
922 | 0 | { |
923 | 0 | /* |
924 | 0 | * COS ID 0 always stores the default value. |
925 | 0 | * For CDP: |
926 | 0 | * - DATA default value stored in cos_reg_val[0]; |
927 | 0 | * - CODE default value stored in cos_reg_val[1]. |
928 | 0 | */ |
929 | 0 | feat_val = feat->cos_reg_val[i]; |
930 | 0 |
|
931 | 0 | /* |
932 | 0 | * If cos is bigger than feature's cos_max, the val should be |
933 | 0 | * default value. Otherwise, it fails to find a COS ID. So we |
934 | 0 | * have to exit find flow. |
935 | 0 | */ |
936 | 0 | if ( val[i] != feat_val ) |
937 | 0 | return -EINVAL; |
938 | 0 | } |
939 | 0 | else |
940 | 0 | { |
941 | 0 | feat_val = feat->cos_reg_val[cos * props->cos_num + i]; |
942 | 0 | if ( val[i] != feat_val ) |
943 | 0 | return 0; |
944 | 0 | } |
945 | 0 | } |
946 | 0 |
|
947 | 0 | return 1; |
948 | 0 | } |
949 | | |
950 | | static int find_cos(const uint32_t val[], unsigned int array_len, |
951 | | enum psr_feat_type feat_type, |
952 | | const struct psr_socket_info *info) |
953 | 0 | { |
954 | 0 | unsigned int cos, cos_max; |
955 | 0 | const unsigned int *ref = info->cos_ref; |
956 | 0 | const struct feat_node *feat; |
957 | 0 |
|
958 | 0 | /* cos_max is the one of the feature which is being set. */ |
959 | 0 | feat = info->features[feat_type]; |
960 | 0 | if ( !feat ) |
961 | 0 | return -ENOENT; |
962 | 0 |
|
963 | 0 | cos_max = feat->cos_max; |
964 | 0 |
|
965 | 0 | for ( cos = 0; cos <= cos_max; cos++ ) |
966 | 0 | { |
967 | 0 | const uint32_t *val_ptr = val; |
968 | 0 | unsigned int len = array_len, i; |
969 | 0 | int rc = 0; |
970 | 0 |
|
971 | 0 | if ( cos && !ref[cos] ) |
972 | 0 | continue; |
973 | 0 |
|
974 | 0 | for ( i = 0; i < ARRAY_SIZE(info->features); i++ ) |
975 | 0 | { |
976 | 0 | const struct feat_props *props = feat_props[i]; |
977 | 0 |
|
978 | 0 | feat = info->features[i]; |
979 | 0 | if ( !feat ) |
980 | 0 | continue; |
981 | 0 |
|
982 | 0 | if ( !props ) |
983 | 0 | { |
984 | 0 | ASSERT_UNREACHABLE(); |
985 | 0 | return -ENOENT; |
986 | 0 | } |
987 | 0 |
|
988 | 0 | if ( len < props->cos_num ) |
989 | 0 | return -ENOSPC; |
990 | 0 |
|
991 | 0 | /* |
992 | 0 | * Compare value according to feature array order. |
993 | 0 | * We must follow this order because value array is assembled |
994 | 0 | * as this order. |
995 | 0 | */ |
996 | 0 | rc = compare_val(val_ptr, feat, props, cos); |
997 | 0 | if ( rc < 0 ) |
998 | 0 | return rc; |
999 | 0 |
|
1000 | 0 | /* If fail to match, go to next cos to compare. */ |
1001 | 0 | if ( !rc ) |
1002 | 0 | break; |
1003 | 0 |
|
1004 | 0 | len -= props->cos_num; |
1005 | 0 | val_ptr += props->cos_num; |
1006 | 0 | } |
1007 | 0 |
|
1008 | 0 | /* For this COS ID all entries in the values array do match. Use it. */ |
1009 | 0 | if ( rc ) |
1010 | 0 | return cos; |
1011 | 0 | } |
1012 | 0 |
|
1013 | 0 | return -ENOENT; |
1014 | 0 | } |
1015 | | |
1016 | | static bool fits_cos_max(const uint32_t val[], |
1017 | | uint32_t array_len, |
1018 | | const struct psr_socket_info *info, |
1019 | | unsigned int cos) |
1020 | 0 | { |
1021 | 0 | unsigned int i; |
1022 | 0 |
|
1023 | 0 | for ( i = 0; i < ARRAY_SIZE(info->features); i++ ) |
1024 | 0 | { |
1025 | 0 | const struct feat_node *feat = info->features[i]; |
1026 | 0 | const struct feat_props *props = feat_props[i]; |
1027 | 0 |
|
1028 | 0 | if ( !feat ) |
1029 | 0 | continue; |
1030 | 0 |
|
1031 | 0 | if ( !props ) |
1032 | 0 | { |
1033 | 0 | ASSERT_UNREACHABLE(); |
1034 | 0 | return false; |
1035 | 0 | } |
1036 | 0 |
|
1037 | 0 | if ( array_len < props->cos_num ) |
1038 | 0 | return false; |
1039 | 0 |
|
1040 | 0 | if ( cos > feat->cos_max ) |
1041 | 0 | { |
1042 | 0 | unsigned int j; |
1043 | 0 |
|
1044 | 0 | for ( j = 0; j < props->cos_num; j++ ) |
1045 | 0 | { |
1046 | 0 | /* Get default value, the COS ID of which is zero. */ |
1047 | 0 | uint32_t default_val = feat->cos_reg_val[j]; |
1048 | 0 |
|
1049 | 0 | if ( val[j] != default_val ) |
1050 | 0 | return false; |
1051 | 0 | } |
1052 | 0 | } |
1053 | 0 |
|
1054 | 0 | array_len -= props->cos_num; |
1055 | 0 | val += props->cos_num; |
1056 | 0 | } |
1057 | 0 |
|
1058 | 0 | return true; |
1059 | 0 | } |
1060 | | |
1061 | | static int pick_avail_cos(const struct psr_socket_info *info, |
1062 | | const uint32_t val[], unsigned int array_len, |
1063 | | unsigned int old_cos, |
1064 | | enum psr_feat_type feat_type) |
1065 | 0 | { |
1066 | 0 | unsigned int cos, cos_max = 0; |
1067 | 0 | const struct feat_node *feat; |
1068 | 0 | const unsigned int *ref = info->cos_ref; |
1069 | 0 |
|
1070 | 0 | /* cos_max is the one of the feature which is being set. */ |
1071 | 0 | feat = info->features[feat_type]; |
1072 | 0 | if ( !feat ) |
1073 | 0 | return -ENOENT; |
1074 | 0 |
|
1075 | 0 | cos_max = feat->cos_max; |
1076 | 0 | if ( !cos_max ) |
1077 | 0 | return -ENOENT; |
1078 | 0 |
|
1079 | 0 | /* We cannot use id 0 because it stores the default values. */ |
1080 | 0 | if ( old_cos && ref[old_cos] == 1 && |
1081 | 0 | fits_cos_max(val, array_len, info, old_cos) ) |
1082 | 0 | return old_cos; |
1083 | 0 |
|
1084 | 0 | /* Find an unused one other than cos0. */ |
1085 | 0 | for ( cos = 1; cos <= cos_max; cos++ ) |
1086 | 0 | { |
1087 | 0 | /* |
1088 | 0 | * ref is 0 means this COS is not used by other domain and |
1089 | 0 | * can be used for current setting. |
1090 | 0 | */ |
1091 | 0 | if ( !ref[cos] ) |
1092 | 0 | { |
1093 | 0 | if ( !fits_cos_max(val, array_len, info, cos) ) |
1094 | 0 | break; |
1095 | 0 |
|
1096 | 0 | return cos; |
1097 | 0 | } |
1098 | 0 | } |
1099 | 0 |
|
1100 | 0 | return -EOVERFLOW; |
1101 | 0 | } |
1102 | | |
1103 | | static unsigned int get_socket_cpu(unsigned int socket) |
1104 | 0 | { |
1105 | 0 | if ( likely(socket < nr_sockets) ) |
1106 | 0 | return cpumask_any(socket_cpumask[socket]); |
1107 | 0 |
|
1108 | 0 | return nr_cpu_ids; |
1109 | 0 | } |
1110 | | |
1111 | | struct cos_write_info |
1112 | | { |
1113 | | unsigned int cos; |
1114 | | unsigned int array_len; |
1115 | | const uint32_t *val; |
1116 | | }; |
1117 | | |
1118 | | static void do_write_psr_msrs(void *data) |
1119 | 0 | { |
1120 | 0 | const struct cos_write_info *info = data; |
1121 | 0 | unsigned int i, index, cos = info->cos; |
1122 | 0 | const struct psr_socket_info *socket_info = |
1123 | 0 | get_socket_info(cpu_to_socket(smp_processor_id())); |
1124 | 0 |
|
1125 | 0 | /* |
1126 | 0 | * Iterate all featuers to write different value (not same as MSR) for |
1127 | 0 | * each feature. |
1128 | 0 | */ |
1129 | 0 | for ( index = i = 0; i < ARRAY_SIZE(feat_props); i++ ) |
1130 | 0 | { |
1131 | 0 | struct feat_node *feat = socket_info->features[i]; |
1132 | 0 | const struct feat_props *props = feat_props[i]; |
1133 | 0 | unsigned int cos_num, j; |
1134 | 0 |
|
1135 | 0 | if ( !feat || !props ) |
1136 | 0 | continue; |
1137 | 0 |
|
1138 | 0 | cos_num = props->cos_num; |
1139 | 0 | ASSERT(info->array_len >= index + cos_num); |
1140 | 0 |
|
1141 | 0 | for ( j = 0; j < cos_num; j++, index++ ) |
1142 | 0 | { |
1143 | 0 | if ( feat->cos_reg_val[cos * cos_num + j] != info->val[index] ) |
1144 | 0 | { |
1145 | 0 | feat->cos_reg_val[cos * cos_num + j] = info->val[index]; |
1146 | 0 | props->write_msr(cos, info->val[index], props->type[j]); |
1147 | 0 | } |
1148 | 0 | } |
1149 | 0 | } |
1150 | 0 | } |
1151 | | |
1152 | | static int write_psr_msrs(unsigned int socket, unsigned int cos, |
1153 | | const uint32_t val[], unsigned int array_len, |
1154 | | enum psr_feat_type feat_type) |
1155 | 0 | { |
1156 | 0 | struct psr_socket_info *info = get_socket_info(socket); |
1157 | 0 | struct cos_write_info data = |
1158 | 0 | { |
1159 | 0 | .cos = cos, |
1160 | 0 | .val = val, |
1161 | 0 | .array_len = array_len, |
1162 | 0 | }; |
1163 | 0 |
|
1164 | 0 | if ( cos > info->features[feat_type]->cos_max ) |
1165 | 0 | return -EINVAL; |
1166 | 0 |
|
1167 | 0 | if ( socket == cpu_to_socket(smp_processor_id()) ) |
1168 | 0 | do_write_psr_msrs(&data); |
1169 | 0 | else |
1170 | 0 | { |
1171 | 0 | unsigned int cpu = get_socket_cpu(socket); |
1172 | 0 |
|
1173 | 0 | if ( cpu >= nr_cpu_ids ) |
1174 | 0 | return -ENOTSOCK; |
1175 | 0 | on_selected_cpus(cpumask_of(cpu), do_write_psr_msrs, &data, 1); |
1176 | 0 | } |
1177 | 0 |
|
1178 | 0 | return 0; |
1179 | 0 | } |
1180 | | |
1181 | | int psr_set_val(struct domain *d, unsigned int socket, |
1182 | | uint64_t new_val, enum cbm_type type) |
1183 | 0 | { |
1184 | 0 | unsigned int old_cos, array_len; |
1185 | 0 | int cos, ret; |
1186 | 0 | unsigned int *ref; |
1187 | 0 | uint32_t *val_array, val; |
1188 | 0 | struct psr_socket_info *info = get_socket_info(socket); |
1189 | 0 | enum psr_feat_type feat_type; |
1190 | 0 |
|
1191 | 0 | if ( IS_ERR(info) ) |
1192 | 0 | return PTR_ERR(info); |
1193 | 0 |
|
1194 | 0 | val = new_val; |
1195 | 0 | if ( new_val != val ) |
1196 | 0 | return -EINVAL; |
1197 | 0 |
|
1198 | 0 | feat_type = psr_cbm_type_to_feat_type(type); |
1199 | 0 | if ( feat_type >= ARRAY_SIZE(info->features) || |
1200 | 0 | !info->features[feat_type] ) |
1201 | 0 | return -ENOENT; |
1202 | 0 |
|
1203 | 0 | /* |
1204 | 0 | * Step 0: |
1205 | 0 | * old_cos means the COS ID current domain is using. By default, it is 0. |
1206 | 0 | * |
1207 | 0 | * For every COS ID, there is a reference count to record how many domains |
1208 | 0 | * are using the COS register corresponding to this COS ID. |
1209 | 0 | * - If ref[old_cos] is 0, that means this COS is not used by any domain. |
1210 | 0 | * - If ref[old_cos] is 1, that means this COS is only used by current |
1211 | 0 | * domain. |
1212 | 0 | * - If ref[old_cos] is more than 1, that mean multiple domains are using |
1213 | 0 | * this COS. |
1214 | 0 | */ |
1215 | 0 | domain_lock(d); |
1216 | 0 | if ( !test_and_set_bit(d->domain_id, info->dom_set) ) |
1217 | 0 | d->arch.psr_cos_ids[socket] = 0; |
1218 | 0 |
|
1219 | 0 | old_cos = d->arch.psr_cos_ids[socket]; |
1220 | 0 | domain_unlock(d); |
1221 | 0 |
|
1222 | 0 | ASSERT(old_cos < MAX_COS_REG_CNT); |
1223 | 0 |
|
1224 | 0 | ref = info->cos_ref; |
1225 | 0 |
|
1226 | 0 | /* |
1227 | 0 | * Step 1: |
1228 | 0 | * Gather a value array to store all features cos_reg_val[old_cos]. |
1229 | 0 | * And, set the input new val into array according to the feature's |
1230 | 0 | * position in array. |
1231 | 0 | */ |
1232 | 0 | array_len = get_cos_num(); |
1233 | 0 | val_array = xzalloc_array(uint32_t, array_len); |
1234 | 0 | if ( !val_array ) |
1235 | 0 | return -ENOMEM; |
1236 | 0 |
|
1237 | 0 | if ( (ret = gather_val_array(val_array, array_len, info, old_cos)) != 0 ) |
1238 | 0 | goto free_array; |
1239 | 0 |
|
1240 | 0 | if ( (ret = insert_val_into_array(val_array, array_len, info, |
1241 | 0 | feat_type, type, val)) != 0 ) |
1242 | 0 | goto free_array; |
1243 | 0 |
|
1244 | 0 | spin_lock(&info->ref_lock); |
1245 | 0 |
|
1246 | 0 | /* |
1247 | 0 | * Step 2: |
1248 | 0 | * Try to find if there is already a COS ID on which all features' values |
1249 | 0 | * are same as the array. Then, we can reuse this COS ID. |
1250 | 0 | */ |
1251 | 0 | cos = find_cos(val_array, array_len, feat_type, info); |
1252 | 0 | if ( cos == old_cos ) |
1253 | 0 | { |
1254 | 0 | ret = 0; |
1255 | 0 | goto unlock_free_array; |
1256 | 0 | } |
1257 | 0 |
|
1258 | 0 | /* |
1259 | 0 | * Step 3: |
1260 | 0 | * If fail to find, we need pick an available COS ID. |
1261 | 0 | * In fact, only COS ID which ref is 1 or 0 can be picked for current |
1262 | 0 | * domain. If old_cos is not 0 and its ref==1, that means only current |
1263 | 0 | * domain is using this old_cos ID. So, this old_cos ID certainly can |
1264 | 0 | * be reused by current domain. Ref==0 means there is no any domain |
1265 | 0 | * using this COS ID. So it can be used for current domain too. |
1266 | 0 | */ |
1267 | 0 | if ( cos < 0 ) |
1268 | 0 | { |
1269 | 0 | cos = pick_avail_cos(info, val_array, array_len, old_cos, feat_type); |
1270 | 0 | if ( cos < 0 ) |
1271 | 0 | { |
1272 | 0 | ret = cos; |
1273 | 0 | goto unlock_free_array; |
1274 | 0 | } |
1275 | 0 |
|
1276 | 0 | /* |
1277 | 0 | * Step 4: |
1278 | 0 | * Write the feature's MSRs according to the COS ID. |
1279 | 0 | */ |
1280 | 0 | ret = write_psr_msrs(socket, cos, val_array, array_len, feat_type); |
1281 | 0 | if ( ret ) |
1282 | 0 | goto unlock_free_array; |
1283 | 0 | } |
1284 | 0 |
|
1285 | 0 | /* |
1286 | 0 | * Step 5: |
1287 | 0 | * Find the COS ID (find_cos result is '>= 0' or an available COS ID is |
1288 | 0 | * picked, then update ref according to COS ID. |
1289 | 0 | */ |
1290 | 0 | ref[cos]++; |
1291 | 0 | ASSERT(!cos || ref[cos]); |
1292 | 0 | ASSERT(!old_cos || ref[old_cos]); |
1293 | 0 | ref[old_cos]--; |
1294 | 0 | spin_unlock(&info->ref_lock); |
1295 | 0 |
|
1296 | 0 | /* |
1297 | 0 | * Step 6: |
1298 | 0 | * Save the COS ID into current domain's psr_cos_ids[] so that we can know |
1299 | 0 | * which COS the domain is using on the socket. One domain can only use |
1300 | 0 | * one COS ID at same time on each socket. |
1301 | 0 | */ |
1302 | 0 | domain_lock(d); |
1303 | 0 | d->arch.psr_cos_ids[socket] = cos; |
1304 | 0 | domain_unlock(d); |
1305 | 0 |
|
1306 | 0 | goto free_array; |
1307 | 0 |
|
1308 | 0 | unlock_free_array: |
1309 | 0 | spin_unlock(&info->ref_lock); |
1310 | 0 |
|
1311 | 0 | free_array: |
1312 | 0 | xfree(val_array); |
1313 | 0 | return ret; |
1314 | 0 | } |
1315 | | |
1316 | | static void psr_free_cos(struct domain *d) |
1317 | 0 | { |
1318 | 0 | unsigned int socket, cos; |
1319 | 0 |
|
1320 | 0 | if ( !d->arch.psr_cos_ids ) |
1321 | 0 | return; |
1322 | 0 |
|
1323 | 0 | ASSERT(socket_info); |
1324 | 0 |
|
1325 | 0 | /* Domain is destroyed so its cos_ref should be decreased. */ |
1326 | 0 | for ( socket = 0; socket < nr_sockets; socket++ ) |
1327 | 0 | { |
1328 | 0 | struct psr_socket_info *info = socket_info + socket; |
1329 | 0 |
|
1330 | 0 | clear_bit(d->domain_id, info->dom_set); |
1331 | 0 |
|
1332 | 0 | /* cos 0 is default one which does not need be handled. */ |
1333 | 0 | cos = d->arch.psr_cos_ids[socket]; |
1334 | 0 | if ( cos == 0 ) |
1335 | 0 | continue; |
1336 | 0 |
|
1337 | 0 | spin_lock(&info->ref_lock); |
1338 | 0 | ASSERT(info->cos_ref[cos]); |
1339 | 0 | info->cos_ref[cos]--; |
1340 | 0 | spin_unlock(&info->ref_lock); |
1341 | 0 | } |
1342 | 0 |
|
1343 | 0 | xfree(d->arch.psr_cos_ids); |
1344 | 0 | d->arch.psr_cos_ids = NULL; |
1345 | 0 | } |
1346 | | |
1347 | | static void psr_alloc_cos(struct domain *d) |
1348 | 0 | { |
1349 | 0 | d->arch.psr_cos_ids = xzalloc_array(unsigned int, nr_sockets); |
1350 | 0 | if ( !d->arch.psr_cos_ids ) |
1351 | 0 | printk(XENLOG_WARNING "Failed to alloc psr_cos_ids!\n"); |
1352 | 0 | } |
1353 | | |
1354 | | void psr_domain_init(struct domain *d) |
1355 | 2 | { |
1356 | 2 | if ( psr_alloc_feat_enabled() ) |
1357 | 0 | psr_alloc_cos(d); |
1358 | 2 | } |
1359 | | |
1360 | | void psr_domain_free(struct domain *d) |
1361 | 0 | { |
1362 | 0 | psr_free_rmid(d); |
1363 | 0 | psr_free_cos(d); |
1364 | 0 | } |
1365 | | |
1366 | | static void __init init_psr(void) |
1367 | 0 | { |
1368 | 0 | if ( opt_cos_max < 1 ) |
1369 | 0 | { |
1370 | 0 | printk(XENLOG_INFO "CAT: disabled, cos_max is too small\n"); |
1371 | 0 | return; |
1372 | 0 | } |
1373 | 0 |
|
1374 | 0 | socket_info = xzalloc_array(struct psr_socket_info, nr_sockets); |
1375 | 0 |
|
1376 | 0 | if ( !socket_info ) |
1377 | 0 | { |
1378 | 0 | printk(XENLOG_WARNING "Failed to alloc socket_info!\n"); |
1379 | 0 | return; |
1380 | 0 | } |
1381 | 0 | } |
1382 | | |
1383 | | static void __init psr_free(void) |
1384 | 0 | { |
1385 | 0 | xfree(socket_info); |
1386 | 0 | socket_info = NULL; |
1387 | 0 | } |
1388 | | |
1389 | | static int psr_cpu_prepare(void) |
1390 | 1 | { |
1391 | 1 | if ( !psr_alloc_feat_enabled() ) |
1392 | 1 | return 0; |
1393 | 1 | |
1394 | 1 | /* Malloc memory for the global feature node here. */ |
1395 | 0 | if ( feat_l3 == NULL && |
1396 | 0 | (feat_l3 = xzalloc(struct feat_node)) == NULL ) |
1397 | 0 | return -ENOMEM; |
1398 | 0 |
|
1399 | 0 | if ( feat_l2_cat == NULL && |
1400 | 0 | (feat_l2_cat = xzalloc(struct feat_node)) == NULL ) |
1401 | 0 | return -ENOMEM; |
1402 | 0 |
|
1403 | 0 | return 0; |
1404 | 0 | } |
1405 | | |
1406 | | static void psr_cpu_init(void) |
1407 | 1 | { |
1408 | 1 | struct psr_socket_info *info; |
1409 | 1 | unsigned int socket, cpu = smp_processor_id(); |
1410 | 1 | struct feat_node *feat; |
1411 | 1 | struct cpuid_leaf regs; |
1412 | 1 | |
1413 | 1 | if ( !psr_alloc_feat_enabled() || !boot_cpu_has(X86_FEATURE_PQE) ) |
1414 | 1 | goto assoc_init; |
1415 | 1 | |
1416 | 0 | if ( boot_cpu_data.cpuid_level < PSR_CPUID_LEVEL_CAT ) |
1417 | 0 | { |
1418 | 0 | setup_clear_cpu_cap(X86_FEATURE_PQE); |
1419 | 0 | goto assoc_init; |
1420 | 0 | } |
1421 | 0 |
|
1422 | 0 | socket = cpu_to_socket(cpu); |
1423 | 0 | info = socket_info + socket; |
1424 | 0 | if ( info->feat_init ) |
1425 | 0 | goto assoc_init; |
1426 | 0 |
|
1427 | 0 | spin_lock_init(&info->ref_lock); |
1428 | 0 |
|
1429 | 0 | cpuid_count_leaf(PSR_CPUID_LEVEL_CAT, 0, ®s); |
1430 | 0 | if ( regs.b & PSR_RESOURCE_TYPE_L3 ) |
1431 | 0 | { |
1432 | 0 | cpuid_count_leaf(PSR_CPUID_LEVEL_CAT, 1, ®s); |
1433 | 0 |
|
1434 | 0 | feat = feat_l3; |
1435 | 0 | feat_l3 = NULL; |
1436 | 0 |
|
1437 | 0 | if ( (regs.c & PSR_CAT_CDP_CAPABILITY) && (opt_psr & PSR_CDP) && |
1438 | 0 | !cat_init_feature(®s, feat, info, FEAT_TYPE_L3_CDP) ) |
1439 | 0 | feat_props[FEAT_TYPE_L3_CDP] = &l3_cdp_props; |
1440 | 0 |
|
1441 | 0 | /* If CDP init fails, try to work as L3 CAT. */ |
1442 | 0 | if ( !feat_props[FEAT_TYPE_L3_CDP] ) |
1443 | 0 | { |
1444 | 0 | if ( !cat_init_feature(®s, feat, info, FEAT_TYPE_L3_CAT) ) |
1445 | 0 | feat_props[FEAT_TYPE_L3_CAT] = &l3_cat_props; |
1446 | 0 | else |
1447 | 0 | feat_l3 = feat; |
1448 | 0 | } |
1449 | 0 | } |
1450 | 0 |
|
1451 | 0 | cpuid_count_leaf(PSR_CPUID_LEVEL_CAT, 0, ®s); |
1452 | 0 | if ( regs.b & PSR_RESOURCE_TYPE_L2 ) |
1453 | 0 | { |
1454 | 0 | cpuid_count_leaf(PSR_CPUID_LEVEL_CAT, 2, ®s); |
1455 | 0 |
|
1456 | 0 | feat = feat_l2_cat; |
1457 | 0 | feat_l2_cat = NULL; |
1458 | 0 | if ( !cat_init_feature(®s, feat, info, FEAT_TYPE_L2_CAT) ) |
1459 | 0 | feat_props[FEAT_TYPE_L2_CAT] = &l2_cat_props; |
1460 | 0 | else |
1461 | 0 | feat_l2_cat = feat; |
1462 | 0 | } |
1463 | 0 |
|
1464 | 0 | info->feat_init = true; |
1465 | 0 |
|
1466 | 1 | assoc_init: |
1467 | 1 | psr_assoc_init(); |
1468 | 1 | } |
1469 | | |
1470 | | static void psr_cpu_fini(unsigned int cpu) |
1471 | 0 | { |
1472 | 0 | unsigned int socket = cpu_to_socket(cpu); |
1473 | 0 |
|
1474 | 0 | if ( !psr_alloc_feat_enabled() ) |
1475 | 0 | return; |
1476 | 0 |
|
1477 | 0 | /* |
1478 | 0 | * We only free when we are the last CPU in the socket. The socket_cpumask |
1479 | 0 | * is cleared prior to this notification code by remove_siblinginfo(). |
1480 | 0 | */ |
1481 | 0 | if ( socket_cpumask[socket] && cpumask_empty(socket_cpumask[socket]) ) |
1482 | 0 | free_socket_resources(socket); |
1483 | 0 | } |
1484 | | |
1485 | | static int cpu_callback( |
1486 | | struct notifier_block *nfb, unsigned long action, void *hcpu) |
1487 | 0 | { |
1488 | 0 | int rc = 0; |
1489 | 0 | unsigned int cpu = (unsigned long)hcpu; |
1490 | 0 |
|
1491 | 0 | switch ( action ) |
1492 | 0 | { |
1493 | 0 | case CPU_UP_PREPARE: |
1494 | 0 | rc = psr_cpu_prepare(); |
1495 | 0 | break; |
1496 | 0 | case CPU_STARTING: |
1497 | 0 | psr_cpu_init(); |
1498 | 0 | break; |
1499 | 0 | case CPU_UP_CANCELED: |
1500 | 0 | case CPU_DEAD: |
1501 | 0 | psr_cpu_fini(cpu); |
1502 | 0 | break; |
1503 | 0 | } |
1504 | 0 |
|
1505 | 0 | return !rc ? NOTIFY_DONE : notifier_from_errno(rc); |
1506 | 0 | } |
1507 | | |
1508 | | static struct notifier_block cpu_nfb = { |
1509 | | .notifier_call = cpu_callback, |
1510 | | /* |
1511 | | * Ensure socket_cpumask is still valid in CPU_DEAD notification |
1512 | | * (E.g. our CPU_DEAD notification should be called ahead of |
1513 | | * cpu_smpboot_free). |
1514 | | */ |
1515 | | .priority = -1 |
1516 | | }; |
1517 | | |
1518 | | static int __init psr_presmp_init(void) |
1519 | 1 | { |
1520 | 1 | if ( (opt_psr & PSR_CMT) && opt_rmid_max ) |
1521 | 0 | init_psr_cmt(opt_rmid_max); |
1522 | 1 | |
1523 | 1 | if ( opt_psr & (PSR_CAT | PSR_CDP) ) |
1524 | 0 | init_psr(); |
1525 | 1 | |
1526 | 1 | if ( psr_cpu_prepare() ) |
1527 | 0 | psr_free(); |
1528 | 1 | |
1529 | 1 | psr_cpu_init(); |
1530 | 1 | if ( psr_cmt_enabled() || psr_alloc_feat_enabled() ) |
1531 | 0 | register_cpu_notifier(&cpu_nfb); |
1532 | 1 | |
1533 | 1 | return 0; |
1534 | 1 | } |
1535 | | presmp_initcall(psr_presmp_init); |
1536 | | |
1537 | | /* |
1538 | | * Local variables: |
1539 | | * mode: C |
1540 | | * c-file-style: "BSD" |
1541 | | * c-basic-offset: 4 |
1542 | | * tab-width: 4 |
1543 | | * indent-tabs-mode: nil |
1544 | | * End: |
1545 | | */ |