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