1 /*
2 * Copyright (C) 2014 Intel Corporation
3 * Author Dongxiao Xu <dongxiao.xu@intel.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published
7 * by the Free Software Foundation; version 2.1 only. with the special
8 * exception on linking described in file LICENSE.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 */
15
16 #include "libxl_osdeps.h" /* must come before any other headers */
17 #include "libxl_internal.h"
18
19 #include <xen-tools/libs.h>
20
21 #define IA32_QM_CTR_ERROR_MASK (0x3ul << 62)
22
libxl__psr_log_err_msg(libxl__gc * gc,int err)23 static void libxl__psr_log_err_msg(libxl__gc *gc, int err)
24 {
25 char *msg;
26
27 switch (err) {
28 case ENOSYS:
29 case EOPNOTSUPP:
30 msg = "unsupported operation";
31 break;
32 case ESRCH:
33 msg = "invalid domain ID";
34 break;
35 case ENOTSOCK:
36 msg = "socket is not supported";
37 break;
38 case EFAULT:
39 msg = "failed to exchange data with Xen";
40 break;
41 default:
42 msg = "unknown error";
43 break;
44 }
45
46 LOGE(ERROR, "%s", msg);
47 }
48
libxl__psr_cmt_log_err_msg(libxl__gc * gc,int err)49 static void libxl__psr_cmt_log_err_msg(libxl__gc *gc, int err)
50 {
51 char *msg;
52
53 switch (err) {
54 case ENODEV:
55 msg = "CMT is not supported in this system";
56 break;
57 case EEXIST:
58 msg = "CMT is already attached to this domain";
59 break;
60 case ENOENT:
61 msg = "CMT is not attached to this domain";
62 break;
63 case EOVERFLOW:
64 msg = "no free RMID available";
65 break;
66 default:
67 libxl__psr_log_err_msg(gc, err);
68 return;
69 }
70
71 LOGE(ERROR, "%s", msg);
72 }
73
libxl__psr_alloc_log_err_msg(libxl__gc * gc,int err,libxl_psr_type type)74 static void libxl__psr_alloc_log_err_msg(libxl__gc *gc,
75 int err,
76 libxl_psr_type type)
77 {
78 /*
79 * Index is 'libxl_psr_type' so we set two 'CDP' to correspond to
80 * DATA and CODE.
81 */
82 const char * const feat_name[] = {
83 [LIBXL_PSR_CBM_TYPE_UNKNOWN] = "UNKNOWN",
84 [LIBXL_PSR_CBM_TYPE_L3_CBM] = "L3 CAT",
85 [LIBXL_PSR_CBM_TYPE_L3_CBM_CODE...LIBXL_PSR_CBM_TYPE_L3_CBM_DATA] =
86 "CDP",
87 [LIBXL_PSR_CBM_TYPE_L2_CBM] = "L2 CAT",
88 [LIBXL_PSR_CBM_TYPE_MBA_THRTL] = "MBA",
89 };
90 char *msg;
91
92 switch (err) {
93 case ENODEV:
94 msg = "is not supported in this system";
95 break;
96 case ENOENT:
97 msg = "is not enabled on the socket";
98 break;
99 case EOVERFLOW:
100 msg = "no free COS available";
101 break;
102 case EEXIST:
103 msg = "The same CBM is already set to this domain";
104 break;
105 case ENXIO:
106 msg = "Unable to set code or data CBM when CDP is disabled";
107 break;
108 case EINVAL:
109 msg = "Invalid input or some internal values are not expected";
110 break;
111 case ERANGE:
112 msg = "Socket number is wrong";
113 break;
114 case ENOSPC:
115 msg = "Value array exceeds the range";
116 break;
117
118 default:
119 libxl__psr_log_err_msg(gc, err);
120 return;
121 }
122
123 LOG(ERROR, "%s: %s", feat_name[type], msg);
124 }
125
libxl__pick_socket_cpu(libxl__gc * gc,uint32_t socketid)126 static int libxl__pick_socket_cpu(libxl__gc *gc, uint32_t socketid)
127 {
128 int i, nr_cpus;
129 libxl_cputopology *topology;
130 int cpu = ERROR_FAIL;
131
132 topology = libxl_get_cpu_topology(CTX, &nr_cpus);
133 if (!topology)
134 return ERROR_FAIL;
135
136 for (i = 0; i < nr_cpus; i++)
137 if (topology[i].socket == socketid) {
138 cpu = i;
139 break;
140 }
141
142 libxl_cputopology_list_free(topology, nr_cpus);
143 return cpu;
144 }
145
libxl_psr_cmt_attach(libxl_ctx * ctx,uint32_t domid)146 int libxl_psr_cmt_attach(libxl_ctx *ctx, uint32_t domid)
147 {
148 GC_INIT(ctx);
149 int rc;
150
151 rc = xc_psr_cmt_attach(ctx->xch, domid);
152 if (rc < 0) {
153 libxl__psr_cmt_log_err_msg(gc, errno);
154 rc = ERROR_FAIL;
155 }
156
157 GC_FREE;
158 return rc;
159 }
160
libxl_psr_cmt_detach(libxl_ctx * ctx,uint32_t domid)161 int libxl_psr_cmt_detach(libxl_ctx *ctx, uint32_t domid)
162 {
163 GC_INIT(ctx);
164 int rc;
165
166 rc = xc_psr_cmt_detach(ctx->xch, domid);
167 if (rc < 0) {
168 libxl__psr_cmt_log_err_msg(gc, errno);
169 rc = ERROR_FAIL;
170 }
171
172 GC_FREE;
173 return rc;
174 }
175
libxl_psr_cmt_domain_attached(libxl_ctx * ctx,uint32_t domid)176 int libxl_psr_cmt_domain_attached(libxl_ctx *ctx, uint32_t domid)
177 {
178 int rc;
179 uint32_t rmid;
180
181 rc = xc_psr_cmt_get_domain_rmid(ctx->xch, domid, &rmid);
182 if (rc < 0)
183 return 0;
184
185 return !!rmid;
186 }
187
libxl_psr_cmt_enabled(libxl_ctx * ctx)188 int libxl_psr_cmt_enabled(libxl_ctx *ctx)
189 {
190 return xc_psr_cmt_enabled(ctx->xch);
191 }
192
libxl_psr_cmt_get_total_rmid(libxl_ctx * ctx,uint32_t * total_rmid)193 int libxl_psr_cmt_get_total_rmid(libxl_ctx *ctx, uint32_t *total_rmid)
194 {
195 GC_INIT(ctx);
196 int rc;
197
198 rc = xc_psr_cmt_get_total_rmid(ctx->xch, total_rmid);
199 if (rc < 0) {
200 libxl__psr_cmt_log_err_msg(gc, errno);
201 rc = ERROR_FAIL;
202 }
203
204 GC_FREE;
205 return rc;
206 }
207
libxl_psr_cmt_get_l3_cache_size(libxl_ctx * ctx,uint32_t socketid,uint32_t * l3_cache_size)208 int libxl_psr_cmt_get_l3_cache_size(libxl_ctx *ctx,
209 uint32_t socketid,
210 uint32_t *l3_cache_size)
211 {
212 GC_INIT(ctx);
213
214 int rc;
215 int cpu = libxl__pick_socket_cpu(gc, socketid);
216
217 if (cpu < 0) {
218 LOGE(ERROR, "failed to get socket cpu");
219 rc = ERROR_FAIL;
220 goto out;
221 }
222
223 rc = xc_psr_cmt_get_l3_cache_size(ctx->xch, cpu, l3_cache_size);
224 if (rc < 0) {
225 libxl__psr_cmt_log_err_msg(gc, errno);
226 rc = ERROR_FAIL;
227 }
228
229 out:
230 GC_FREE;
231 return rc;
232 }
233
libxl_psr_cmt_type_supported(libxl_ctx * ctx,libxl_psr_cmt_type type)234 int libxl_psr_cmt_type_supported(libxl_ctx *ctx, libxl_psr_cmt_type type)
235 {
236 GC_INIT(ctx);
237 uint32_t event_mask;
238 int rc;
239
240 rc = xc_psr_cmt_get_l3_event_mask(ctx->xch, &event_mask);
241 if (rc < 0) {
242 libxl__psr_cmt_log_err_msg(gc, errno);
243 rc = 0;
244 } else {
245 rc = event_mask & (1 << (type - 1));
246 }
247
248 GC_FREE;
249 return rc;
250 }
251
libxl_psr_cmt_get_sample(libxl_ctx * ctx,uint32_t domid,libxl_psr_cmt_type type,uint64_t scope,uint64_t * sample_r,uint64_t * tsc_r)252 int libxl_psr_cmt_get_sample(libxl_ctx *ctx,
253 uint32_t domid,
254 libxl_psr_cmt_type type,
255 uint64_t scope,
256 uint64_t *sample_r,
257 uint64_t *tsc_r)
258 {
259 GC_INIT(ctx);
260 unsigned int rmid;
261 uint32_t upscaling_factor;
262 uint64_t monitor_data;
263 int cpu, rc;
264
265 rc = xc_psr_cmt_get_domain_rmid(ctx->xch, domid, &rmid);
266 if (rc < 0 || rmid == 0) {
267 LOGED(ERROR, domid, "fail to get the domain rmid, "
268 "or domain is not attached with platform QoS monitoring service");
269 rc = ERROR_FAIL;
270 goto out;
271 }
272
273 cpu = libxl__pick_socket_cpu(gc, scope);
274 if (cpu < 0) {
275 LOGED(ERROR, domid, "failed to get socket cpu");
276 rc = ERROR_FAIL;
277 goto out;
278 }
279
280 rc = xc_psr_cmt_get_data(ctx->xch, rmid, cpu, type - 1,
281 &monitor_data, tsc_r);
282 if (rc < 0) {
283 LOGED(ERROR, domid, "failed to get monitoring data");
284 rc = ERROR_FAIL;
285 goto out;
286 }
287
288 rc = xc_psr_cmt_get_l3_upscaling_factor(ctx->xch, &upscaling_factor);
289 if (rc < 0) {
290 LOGED(ERROR, domid, "failed to get L3 upscaling factor");
291 rc = ERROR_FAIL;
292 goto out;
293 }
294
295 *sample_r = monitor_data * upscaling_factor;
296 out:
297 GC_FREE;
298 return rc;
299 }
300
libxl_psr_cmt_get_cache_occupancy(libxl_ctx * ctx,uint32_t domid,uint32_t socketid,uint32_t * l3_cache_occupancy)301 int libxl_psr_cmt_get_cache_occupancy(libxl_ctx *ctx,
302 uint32_t domid,
303 uint32_t socketid,
304 uint32_t *l3_cache_occupancy)
305 {
306 uint64_t data;
307 int rc;
308
309 rc = libxl_psr_cmt_get_sample(ctx, domid,
310 LIBXL_PSR_CMT_TYPE_CACHE_OCCUPANCY,
311 socketid, &data, NULL);
312 if (rc < 0)
313 goto out;
314
315 *l3_cache_occupancy = data / 1024;
316 out:
317 return rc;
318 }
319
libxl__psr_type_to_libxc_psr_type(libxl_psr_type type)320 static inline xc_psr_type libxl__psr_type_to_libxc_psr_type(
321 libxl_psr_type type)
322 {
323 BUILD_BUG_ON(sizeof(libxl_psr_type) != sizeof(xc_psr_type));
324 return (xc_psr_type)type;
325 }
326
libxl_psr_cat_set_cbm(libxl_ctx * ctx,uint32_t domid,libxl_psr_cbm_type type,libxl_bitmap * target_map,uint64_t cbm)327 int libxl_psr_cat_set_cbm(libxl_ctx *ctx, uint32_t domid,
328 libxl_psr_cbm_type type, libxl_bitmap *target_map,
329 uint64_t cbm)
330 {
331 return libxl_psr_set_val(ctx, domid, type, target_map, cbm);
332 }
333
libxl_psr_cat_get_cbm(libxl_ctx * ctx,uint32_t domid,libxl_psr_cbm_type type,uint32_t target,uint64_t * cbm_r)334 int libxl_psr_cat_get_cbm(libxl_ctx *ctx, uint32_t domid,
335 libxl_psr_cbm_type type, uint32_t target,
336 uint64_t *cbm_r)
337 {
338 return libxl_psr_get_val(ctx, domid, type, target, cbm_r);
339 }
340
libxl__feat_type_to_libxc_feat_type(libxl_psr_feat_type type,unsigned int lvl)341 static xc_psr_feat_type libxl__feat_type_to_libxc_feat_type(
342 libxl_psr_feat_type type, unsigned int lvl)
343 {
344 xc_psr_feat_type xc_type;
345
346 switch (type) {
347 case LIBXL_PSR_FEAT_TYPE_CAT:
348 assert(lvl == 3 || lvl == 2);
349
350 if (lvl == 3)
351 xc_type = XC_PSR_CAT_L3;
352 if (lvl == 2)
353 xc_type = XC_PSR_CAT_L2;
354 break;
355 case LIBXL_PSR_FEAT_TYPE_MBA:
356 xc_type = XC_PSR_MBA;
357 break;
358 default:
359 /* Could not happen */
360 assert(0);
361 }
362
363 return xc_type;
364 }
365
libxl__hw_info_to_libxl_cat_info(libxl_psr_feat_type type,libxl_psr_hw_info * hw_info,libxl_psr_cat_info * cat_info)366 static void libxl__hw_info_to_libxl_cat_info(
367 libxl_psr_feat_type type, libxl_psr_hw_info *hw_info,
368 libxl_psr_cat_info *cat_info)
369 {
370 assert(type == LIBXL_PSR_FEAT_TYPE_CAT);
371
372 cat_info->id = hw_info->id;
373 cat_info->cos_max = hw_info->u.cat.cos_max;
374 cat_info->cbm_len = hw_info->u.cat.cbm_len;
375 cat_info->cdp_enabled = hw_info->u.cat.cdp_enabled;
376 }
377
libxl_psr_cat_get_info(libxl_ctx * ctx,libxl_psr_cat_info ** info,unsigned int * nr,unsigned int lvl)378 int libxl_psr_cat_get_info(libxl_ctx *ctx, libxl_psr_cat_info **info,
379 unsigned int *nr, unsigned int lvl)
380 {
381 GC_INIT(ctx);
382 int rc;
383 unsigned int i;
384 libxl_psr_hw_info *hw_info;
385 libxl_psr_cat_info *ptr;
386
387 rc = libxl_psr_get_hw_info(ctx, LIBXL_PSR_FEAT_TYPE_CAT, lvl, nr, &hw_info);
388 if (rc)
389 goto out;
390
391 ptr = libxl__malloc(NOGC, *nr * sizeof(libxl_psr_cat_info));
392
393 for (i = 0; i < *nr; i++)
394 libxl__hw_info_to_libxl_cat_info(LIBXL_PSR_FEAT_TYPE_CAT,
395 &hw_info[i],
396 &ptr[i]);
397
398 *info = ptr;
399 libxl_psr_hw_info_list_free(hw_info, *nr);
400 out:
401 GC_FREE;
402 return rc;
403 }
404
libxl_psr_cat_get_l3_info(libxl_ctx * ctx,libxl_psr_cat_info ** info,int * nr)405 int libxl_psr_cat_get_l3_info(libxl_ctx *ctx, libxl_psr_cat_info **info,
406 int *nr)
407 {
408 int rc;
409 unsigned int num;
410
411 rc = libxl_psr_cat_get_info(ctx, info, &num, 3);
412 if (!rc)
413 *nr = num;
414
415 return rc;
416 }
417
libxl_psr_cat_info_list_free(libxl_psr_cat_info * list,int nr)418 void libxl_psr_cat_info_list_free(libxl_psr_cat_info *list, int nr)
419 {
420 int i;
421
422 for (i = 0; i < nr; i++)
423 libxl_psr_cat_info_dispose(&list[i]);
424 free(list);
425 }
426
libxl_psr_set_val(libxl_ctx * ctx,uint32_t domid,libxl_psr_type type,libxl_bitmap * target_map,uint64_t val)427 int libxl_psr_set_val(libxl_ctx *ctx, uint32_t domid,
428 libxl_psr_type type, libxl_bitmap *target_map,
429 uint64_t val)
430 {
431 GC_INIT(ctx);
432 int rc, socketid, nr_sockets;
433 xc_psr_type xc_type = libxl__psr_type_to_libxc_psr_type(type);
434
435 rc = libxl__count_physical_sockets(gc, &nr_sockets);
436 if (rc) {
437 LOG(ERROR, "failed to get system socket count");
438 goto out;
439 }
440
441 libxl_for_each_set_bit(socketid, *target_map) {
442 if (socketid >= nr_sockets)
443 break;
444
445 if (xc_psr_set_domain_data(ctx->xch, domid, xc_type,
446 socketid, val)) {
447 libxl__psr_alloc_log_err_msg(gc, errno, type);
448 rc = ERROR_FAIL;
449 }
450 }
451
452 out:
453 GC_FREE;
454 return rc;
455 }
456
libxl_psr_get_val(libxl_ctx * ctx,uint32_t domid,libxl_psr_type type,unsigned int target,uint64_t * val)457 int libxl_psr_get_val(libxl_ctx *ctx, uint32_t domid,
458 libxl_psr_type type, unsigned int target,
459 uint64_t *val)
460 {
461 GC_INIT(ctx);
462 int rc = 0;
463 xc_psr_type xc_type = libxl__psr_type_to_libxc_psr_type(type);
464
465 if (xc_psr_get_domain_data(ctx->xch, domid, xc_type,
466 target, val)) {
467 libxl__psr_alloc_log_err_msg(gc, errno, type);
468 rc = ERROR_FAIL;
469 }
470
471 GC_FREE;
472 return rc;
473 }
474
libxl__xc_hw_info_to_libxl_hw_info(libxl_psr_feat_type type,xc_psr_hw_info * xc_info,libxl_psr_hw_info * xl_info)475 static void libxl__xc_hw_info_to_libxl_hw_info(
476 libxl_psr_feat_type type, xc_psr_hw_info *xc_info,
477 libxl_psr_hw_info *xl_info)
478 {
479 switch (type) {
480 case LIBXL_PSR_FEAT_TYPE_CAT:
481 xl_info->u.cat.cos_max = xc_info->cat.cos_max;
482 xl_info->u.cat.cbm_len = xc_info->cat.cbm_len;
483 xl_info->u.cat.cdp_enabled = xc_info->cat.cdp_enabled;
484 break;
485 case LIBXL_PSR_FEAT_TYPE_MBA:
486 xl_info->u.mba.cos_max = xc_info->mba.cos_max;
487 xl_info->u.mba.thrtl_max = xc_info->mba.thrtl_max;
488 xl_info->u.mba.linear = xc_info->mba.linear;
489 break;
490 default:
491 assert(0);
492 }
493 }
494
libxl_psr_get_hw_info(libxl_ctx * ctx,libxl_psr_feat_type type,unsigned int lvl,unsigned int * nr,libxl_psr_hw_info ** info)495 int libxl_psr_get_hw_info(libxl_ctx *ctx, libxl_psr_feat_type type,
496 unsigned int lvl, unsigned int *nr,
497 libxl_psr_hw_info **info)
498 {
499 GC_INIT(ctx);
500 int rc, nr_sockets;
501 unsigned int i = 0, socketid;
502 libxl_bitmap socketmap;
503 libxl_psr_hw_info *ptr;
504 xc_psr_feat_type xc_type;
505 xc_psr_hw_info hw_info;
506
507 libxl_bitmap_init(&socketmap);
508
509 xc_type = libxl__feat_type_to_libxc_feat_type(type, lvl);
510
511 rc = libxl__count_physical_sockets(gc, &nr_sockets);
512 if (rc) {
513 LOG(ERROR, "failed to get system socket count");
514 goto out;
515 }
516
517 libxl_socket_bitmap_alloc(ctx, &socketmap, nr_sockets);
518 rc = libxl_get_online_socketmap(ctx, &socketmap);
519 if (rc) {
520 LOGE(ERROR, "failed to get available sockets");
521 goto out;
522 }
523
524 ptr = libxl__malloc(NOGC, nr_sockets * sizeof(libxl_psr_hw_info));
525
526 libxl_for_each_set_bit(socketid, socketmap) {
527 ptr[i].id = socketid;
528 if (xc_psr_get_hw_info(ctx->xch, socketid, xc_type, &hw_info)) {
529 rc = ERROR_FAIL;
530 free(ptr);
531 goto out;
532 }
533
534 libxl__xc_hw_info_to_libxl_hw_info(type, &hw_info, &ptr[i]);
535
536 i++;
537 }
538
539 *info = ptr;
540 *nr = i;
541 out:
542 libxl_bitmap_dispose(&socketmap);
543 GC_FREE;
544 return rc;
545 }
546
libxl_psr_hw_info_list_free(libxl_psr_hw_info * list,unsigned int nr)547 void libxl_psr_hw_info_list_free(libxl_psr_hw_info *list, unsigned int nr)
548 {
549 unsigned int i;
550
551 for (i = 0; i < nr; i++)
552 libxl_psr_hw_info_dispose(&list[i]);
553 free(list);
554 }
555
556 /*
557 * Local variables:
558 * mode: C
559 * c-basic-offset: 4
560 * indent-tabs-mode: nil
561 * End:
562 */
563