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