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_cat_log_err_msg(libxl__gc * gc,int err)74 static void libxl__psr_cat_log_err_msg(libxl__gc *gc, int err)
75 {
76     char *msg;
77 
78     switch (err) {
79     case ENODEV:
80         msg = "CAT is not supported in this system";
81         break;
82     case ENOENT:
83         msg = "CAT is not enabled on the socket";
84         break;
85     case EOVERFLOW:
86         msg = "no free COS available";
87         break;
88     case EEXIST:
89         msg = "The same CBM is already set to this domain";
90         break;
91     case ENXIO:
92         msg = "Unable to set code or data CBM when CDP is disabled";
93         break;
94     case EINVAL:
95         msg = "Invalid input or some internal values are not expected";
96         break;
97     case ERANGE:
98         msg = "Socket number is wrong";
99         break;
100     case ENOSPC:
101         msg = "Value array exceeds the range";
102         break;
103 
104     default:
105         libxl__psr_log_err_msg(gc, err);
106         return;
107     }
108 
109     LOGE(ERROR, "%s", msg);
110 }
111 
libxl__pick_socket_cpu(libxl__gc * gc,uint32_t socketid)112 static int libxl__pick_socket_cpu(libxl__gc *gc, uint32_t socketid)
113 {
114     int i, nr_cpus;
115     libxl_cputopology *topology;
116     int cpu = ERROR_FAIL;
117 
118     topology = libxl_get_cpu_topology(CTX, &nr_cpus);
119     if (!topology)
120         return ERROR_FAIL;
121 
122     for (i = 0; i < nr_cpus; i++)
123         if (topology[i].socket == socketid) {
124             cpu = i;
125             break;
126         }
127 
128     libxl_cputopology_list_free(topology, nr_cpus);
129     return cpu;
130 }
131 
libxl_psr_cmt_attach(libxl_ctx * ctx,uint32_t domid)132 int libxl_psr_cmt_attach(libxl_ctx *ctx, uint32_t domid)
133 {
134     GC_INIT(ctx);
135     int rc;
136 
137     rc = xc_psr_cmt_attach(ctx->xch, domid);
138     if (rc < 0) {
139         libxl__psr_cmt_log_err_msg(gc, errno);
140         rc = ERROR_FAIL;
141     }
142 
143     GC_FREE;
144     return rc;
145 }
146 
libxl_psr_cmt_detach(libxl_ctx * ctx,uint32_t domid)147 int libxl_psr_cmt_detach(libxl_ctx *ctx, uint32_t domid)
148 {
149     GC_INIT(ctx);
150     int rc;
151 
152     rc = xc_psr_cmt_detach(ctx->xch, domid);
153     if (rc < 0) {
154         libxl__psr_cmt_log_err_msg(gc, errno);
155         rc = ERROR_FAIL;
156     }
157 
158     GC_FREE;
159     return rc;
160 }
161 
libxl_psr_cmt_domain_attached(libxl_ctx * ctx,uint32_t domid)162 int libxl_psr_cmt_domain_attached(libxl_ctx *ctx, uint32_t domid)
163 {
164     int rc;
165     uint32_t rmid;
166 
167     rc = xc_psr_cmt_get_domain_rmid(ctx->xch, domid, &rmid);
168     if (rc < 0)
169         return 0;
170 
171     return !!rmid;
172 }
173 
libxl_psr_cmt_enabled(libxl_ctx * ctx)174 int libxl_psr_cmt_enabled(libxl_ctx *ctx)
175 {
176     return xc_psr_cmt_enabled(ctx->xch);
177 }
178 
libxl_psr_cmt_get_total_rmid(libxl_ctx * ctx,uint32_t * total_rmid)179 int libxl_psr_cmt_get_total_rmid(libxl_ctx *ctx, uint32_t *total_rmid)
180 {
181     GC_INIT(ctx);
182     int rc;
183 
184     rc = xc_psr_cmt_get_total_rmid(ctx->xch, total_rmid);
185     if (rc < 0) {
186         libxl__psr_cmt_log_err_msg(gc, errno);
187         rc = ERROR_FAIL;
188     }
189 
190     GC_FREE;
191     return rc;
192 }
193 
libxl_psr_cmt_get_l3_cache_size(libxl_ctx * ctx,uint32_t socketid,uint32_t * l3_cache_size)194 int libxl_psr_cmt_get_l3_cache_size(libxl_ctx *ctx,
195                                     uint32_t socketid,
196                                     uint32_t *l3_cache_size)
197 {
198     GC_INIT(ctx);
199 
200     int rc;
201     int cpu = libxl__pick_socket_cpu(gc, socketid);
202 
203     if (cpu < 0) {
204         LOGE(ERROR, "failed to get socket cpu");
205         rc = ERROR_FAIL;
206         goto out;
207     }
208 
209     rc = xc_psr_cmt_get_l3_cache_size(ctx->xch, cpu, l3_cache_size);
210     if (rc < 0) {
211         libxl__psr_cmt_log_err_msg(gc, errno);
212         rc = ERROR_FAIL;
213     }
214 
215 out:
216     GC_FREE;
217     return rc;
218 }
219 
libxl_psr_cmt_type_supported(libxl_ctx * ctx,libxl_psr_cmt_type type)220 int libxl_psr_cmt_type_supported(libxl_ctx *ctx, libxl_psr_cmt_type type)
221 {
222     GC_INIT(ctx);
223     uint32_t event_mask;
224     int rc;
225 
226     rc = xc_psr_cmt_get_l3_event_mask(ctx->xch, &event_mask);
227     if (rc < 0) {
228         libxl__psr_cmt_log_err_msg(gc, errno);
229         rc = 0;
230     } else {
231         rc = event_mask & (1 << (type - 1));
232     }
233 
234     GC_FREE;
235     return rc;
236 }
237 
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)238 int libxl_psr_cmt_get_sample(libxl_ctx *ctx,
239                              uint32_t domid,
240                              libxl_psr_cmt_type type,
241                              uint64_t scope,
242                              uint64_t *sample_r,
243                              uint64_t *tsc_r)
244 {
245     GC_INIT(ctx);
246     unsigned int rmid;
247     uint32_t upscaling_factor;
248     uint64_t monitor_data;
249     int cpu, rc;
250 
251     rc = xc_psr_cmt_get_domain_rmid(ctx->xch, domid, &rmid);
252     if (rc < 0 || rmid == 0) {
253         LOGED(ERROR, domid, "fail to get the domain rmid, "
254               "or domain is not attached with platform QoS monitoring service");
255         rc = ERROR_FAIL;
256         goto out;
257     }
258 
259     cpu = libxl__pick_socket_cpu(gc, scope);
260     if (cpu < 0) {
261         LOGED(ERROR, domid, "failed to get socket cpu");
262         rc = ERROR_FAIL;
263         goto out;
264     }
265 
266     rc = xc_psr_cmt_get_data(ctx->xch, rmid, cpu, type - 1,
267                              &monitor_data, tsc_r);
268     if (rc < 0) {
269         LOGED(ERROR, domid, "failed to get monitoring data");
270         rc = ERROR_FAIL;
271         goto out;
272     }
273 
274     rc = xc_psr_cmt_get_l3_upscaling_factor(ctx->xch, &upscaling_factor);
275     if (rc < 0) {
276         LOGED(ERROR, domid, "failed to get L3 upscaling factor");
277         rc = ERROR_FAIL;
278         goto out;
279     }
280 
281     *sample_r = monitor_data * upscaling_factor;
282 out:
283     GC_FREE;
284     return rc;
285 }
286 
libxl_psr_cmt_get_cache_occupancy(libxl_ctx * ctx,uint32_t domid,uint32_t socketid,uint32_t * l3_cache_occupancy)287 int libxl_psr_cmt_get_cache_occupancy(libxl_ctx *ctx,
288                                       uint32_t domid,
289                                       uint32_t socketid,
290                                       uint32_t *l3_cache_occupancy)
291 {
292     uint64_t data;
293     int rc;
294 
295     rc = libxl_psr_cmt_get_sample(ctx, domid,
296                                   LIBXL_PSR_CMT_TYPE_CACHE_OCCUPANCY,
297                                   socketid, &data, NULL);
298     if (rc < 0)
299         goto out;
300 
301     *l3_cache_occupancy = data / 1024;
302 out:
303     return rc;
304 }
305 
libxl__psr_cbm_type_to_libxc_psr_cat_type(libxl_psr_cbm_type type)306 static inline xc_psr_cat_type libxl__psr_cbm_type_to_libxc_psr_cat_type(
307     libxl_psr_cbm_type type)
308 {
309     BUILD_BUG_ON(sizeof(libxl_psr_cbm_type) != sizeof(xc_psr_cat_type));
310     return (xc_psr_cat_type)type;
311 }
312 
libxl_psr_cat_set_cbm(libxl_ctx * ctx,uint32_t domid,libxl_psr_cbm_type type,libxl_bitmap * target_map,uint64_t cbm)313 int libxl_psr_cat_set_cbm(libxl_ctx *ctx, uint32_t domid,
314                           libxl_psr_cbm_type type, libxl_bitmap *target_map,
315                           uint64_t cbm)
316 {
317     GC_INIT(ctx);
318     int rc;
319     int socketid, nr_sockets;
320 
321     rc = libxl__count_physical_sockets(gc, &nr_sockets);
322     if (rc) {
323         LOGED(ERROR, domid, "failed to get system socket count");
324         goto out;
325     }
326 
327     libxl_for_each_set_bit(socketid, *target_map) {
328         xc_psr_cat_type xc_type;
329 
330         if (socketid >= nr_sockets)
331             break;
332 
333         xc_type = libxl__psr_cbm_type_to_libxc_psr_cat_type(type);
334         if (xc_psr_cat_set_domain_data(ctx->xch, domid, xc_type,
335                                        socketid, cbm)) {
336             libxl__psr_cat_log_err_msg(gc, errno);
337             rc = ERROR_FAIL;
338         }
339     }
340 
341 out:
342     GC_FREE;
343     return rc;
344 }
345 
libxl_psr_cat_get_cbm(libxl_ctx * ctx,uint32_t domid,libxl_psr_cbm_type type,uint32_t target,uint64_t * cbm_r)346 int libxl_psr_cat_get_cbm(libxl_ctx *ctx, uint32_t domid,
347                           libxl_psr_cbm_type type, uint32_t target,
348                           uint64_t *cbm_r)
349 {
350     GC_INIT(ctx);
351     int rc = 0;
352     xc_psr_cat_type xc_type = libxl__psr_cbm_type_to_libxc_psr_cat_type(type);
353 
354     if (xc_psr_cat_get_domain_data(ctx->xch, domid, xc_type,
355                                    target, cbm_r)) {
356         libxl__psr_cat_log_err_msg(gc, errno);
357         rc = ERROR_FAIL;
358     }
359 
360     GC_FREE;
361     return rc;
362 }
363 
libxl_psr_cat_get_info(libxl_ctx * ctx,libxl_psr_cat_info ** info,unsigned int * nr,unsigned int lvl)364 int libxl_psr_cat_get_info(libxl_ctx *ctx, libxl_psr_cat_info **info,
365                            unsigned int *nr, unsigned int lvl)
366 {
367     GC_INIT(ctx);
368     int rc;
369     int i = 0, socketid, nr_sockets;
370     libxl_bitmap socketmap;
371     libxl_psr_cat_info *ptr;
372 
373     libxl_bitmap_init(&socketmap);
374 
375     rc = libxl__count_physical_sockets(gc, &nr_sockets);
376     if (rc) {
377         LOGE(ERROR, "failed to get system socket count");
378         goto out;
379     }
380 
381     libxl_socket_bitmap_alloc(ctx, &socketmap, nr_sockets);
382     rc = libxl_get_online_socketmap(ctx, &socketmap);
383     if (rc < 0) {
384         LOGE(ERROR, "failed to get available sockets");
385         goto out;
386     }
387 
388     ptr = libxl__malloc(NOGC, nr_sockets * sizeof(libxl_psr_cat_info));
389 
390     libxl_for_each_set_bit(socketid, socketmap) {
391         ptr[i].id = socketid;
392         if (xc_psr_cat_get_info(ctx->xch, socketid, lvl, &ptr[i].cos_max,
393                                 &ptr[i].cbm_len, &ptr[i].cdp_enabled)) {
394             rc = ERROR_FAIL;
395             free(ptr);
396             goto out;
397         }
398         i++;
399     }
400 
401     *info = ptr;
402     *nr = i;
403 out:
404     libxl_bitmap_dispose(&socketmap);
405     GC_FREE;
406     return rc;
407 }
408 
libxl_psr_cat_get_l3_info(libxl_ctx * ctx,libxl_psr_cat_info ** info,int * nr)409 int libxl_psr_cat_get_l3_info(libxl_ctx *ctx, libxl_psr_cat_info **info,
410                               int *nr)
411 {
412     int rc;
413     unsigned int num;
414 
415     rc = libxl_psr_cat_get_info(ctx, info, &num, 3);
416     if (!rc)
417         *nr = num;
418 
419     return rc;
420 }
421 
libxl_psr_cat_info_list_free(libxl_psr_cat_info * list,int nr)422 void libxl_psr_cat_info_list_free(libxl_psr_cat_info *list, int nr)
423 {
424     int i;
425 
426     for (i = 0; i < nr; i++)
427         libxl_psr_cat_info_dispose(&list[i]);
428     free(list);
429 }
430 
431 /*
432  * Local variables:
433  * mode: C
434  * c-basic-offset: 4
435  * indent-tabs-mode: nil
436  * End:
437  */
438