mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 02:30:03 +01:00
This patch implements new generic set value interfaces in libxc and libxl. These interfaces are suitable for all allocation features. It also adds a new MBA set value command in xl. Signed-off-by: Yi Sun <yi.y.sun@linux.intel.com> Acked-by: Wei Liu <wei.liu2@citrix.com>
563 lines
14 KiB
C
563 lines
14 KiB
C
/*
|
|
* Copyright (C) 2014 Intel Corporation
|
|
* Author Dongxiao Xu <dongxiao.xu@intel.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published
|
|
* by the Free Software Foundation; version 2.1 only. with the special
|
|
* exception on linking described in file LICENSE.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*/
|
|
|
|
#include "libxl_osdeps.h" /* must come before any other headers */
|
|
#include "libxl_internal.h"
|
|
|
|
#include <xen-tools/libs.h>
|
|
|
|
#define IA32_QM_CTR_ERROR_MASK (0x3ul << 62)
|
|
|
|
static void libxl__psr_log_err_msg(libxl__gc *gc, int err)
|
|
{
|
|
char *msg;
|
|
|
|
switch (err) {
|
|
case ENOSYS:
|
|
case EOPNOTSUPP:
|
|
msg = "unsupported operation";
|
|
break;
|
|
case ESRCH:
|
|
msg = "invalid domain ID";
|
|
break;
|
|
case ENOTSOCK:
|
|
msg = "socket is not supported";
|
|
break;
|
|
case EFAULT:
|
|
msg = "failed to exchange data with Xen";
|
|
break;
|
|
default:
|
|
msg = "unknown error";
|
|
break;
|
|
}
|
|
|
|
LOGE(ERROR, "%s", msg);
|
|
}
|
|
|
|
static void libxl__psr_cmt_log_err_msg(libxl__gc *gc, int err)
|
|
{
|
|
char *msg;
|
|
|
|
switch (err) {
|
|
case ENODEV:
|
|
msg = "CMT is not supported in this system";
|
|
break;
|
|
case EEXIST:
|
|
msg = "CMT is already attached to this domain";
|
|
break;
|
|
case ENOENT:
|
|
msg = "CMT is not attached to this domain";
|
|
break;
|
|
case EOVERFLOW:
|
|
msg = "no free RMID available";
|
|
break;
|
|
default:
|
|
libxl__psr_log_err_msg(gc, err);
|
|
return;
|
|
}
|
|
|
|
LOGE(ERROR, "%s", msg);
|
|
}
|
|
|
|
static void libxl__psr_alloc_log_err_msg(libxl__gc *gc,
|
|
int err,
|
|
libxl_psr_type type)
|
|
{
|
|
/*
|
|
* Index is 'libxl_psr_type' so we set two 'CDP' to correspond to
|
|
* DATA and CODE.
|
|
*/
|
|
const char * const feat_name[] = {
|
|
[LIBXL_PSR_CBM_TYPE_UNKNOWN] = "UNKNOWN",
|
|
[LIBXL_PSR_CBM_TYPE_L3_CBM] = "L3 CAT",
|
|
[LIBXL_PSR_CBM_TYPE_L3_CBM_CODE...LIBXL_PSR_CBM_TYPE_L3_CBM_DATA] =
|
|
"CDP",
|
|
[LIBXL_PSR_CBM_TYPE_L2_CBM] = "L2 CAT",
|
|
[LIBXL_PSR_CBM_TYPE_MBA_THRTL] = "MBA",
|
|
};
|
|
char *msg;
|
|
|
|
switch (err) {
|
|
case ENODEV:
|
|
msg = "is not supported in this system";
|
|
break;
|
|
case ENOENT:
|
|
msg = "is not enabled on the socket";
|
|
break;
|
|
case EOVERFLOW:
|
|
msg = "no free COS available";
|
|
break;
|
|
case EEXIST:
|
|
msg = "The same CBM is already set to this domain";
|
|
break;
|
|
case ENXIO:
|
|
msg = "Unable to set code or data CBM when CDP is disabled";
|
|
break;
|
|
case EINVAL:
|
|
msg = "Invalid input or some internal values are not expected";
|
|
break;
|
|
case ERANGE:
|
|
msg = "Socket number is wrong";
|
|
break;
|
|
case ENOSPC:
|
|
msg = "Value array exceeds the range";
|
|
break;
|
|
|
|
default:
|
|
libxl__psr_log_err_msg(gc, err);
|
|
return;
|
|
}
|
|
|
|
LOG(ERROR, "%s: %s", feat_name[type], msg);
|
|
}
|
|
|
|
static int libxl__pick_socket_cpu(libxl__gc *gc, uint32_t socketid)
|
|
{
|
|
int i, nr_cpus;
|
|
libxl_cputopology *topology;
|
|
int cpu = ERROR_FAIL;
|
|
|
|
topology = libxl_get_cpu_topology(CTX, &nr_cpus);
|
|
if (!topology)
|
|
return ERROR_FAIL;
|
|
|
|
for (i = 0; i < nr_cpus; i++)
|
|
if (topology[i].socket == socketid) {
|
|
cpu = i;
|
|
break;
|
|
}
|
|
|
|
libxl_cputopology_list_free(topology, nr_cpus);
|
|
return cpu;
|
|
}
|
|
|
|
int libxl_psr_cmt_attach(libxl_ctx *ctx, uint32_t domid)
|
|
{
|
|
GC_INIT(ctx);
|
|
int rc;
|
|
|
|
rc = xc_psr_cmt_attach(ctx->xch, domid);
|
|
if (rc < 0) {
|
|
libxl__psr_cmt_log_err_msg(gc, errno);
|
|
rc = ERROR_FAIL;
|
|
}
|
|
|
|
GC_FREE;
|
|
return rc;
|
|
}
|
|
|
|
int libxl_psr_cmt_detach(libxl_ctx *ctx, uint32_t domid)
|
|
{
|
|
GC_INIT(ctx);
|
|
int rc;
|
|
|
|
rc = xc_psr_cmt_detach(ctx->xch, domid);
|
|
if (rc < 0) {
|
|
libxl__psr_cmt_log_err_msg(gc, errno);
|
|
rc = ERROR_FAIL;
|
|
}
|
|
|
|
GC_FREE;
|
|
return rc;
|
|
}
|
|
|
|
int libxl_psr_cmt_domain_attached(libxl_ctx *ctx, uint32_t domid)
|
|
{
|
|
int rc;
|
|
uint32_t rmid;
|
|
|
|
rc = xc_psr_cmt_get_domain_rmid(ctx->xch, domid, &rmid);
|
|
if (rc < 0)
|
|
return 0;
|
|
|
|
return !!rmid;
|
|
}
|
|
|
|
int libxl_psr_cmt_enabled(libxl_ctx *ctx)
|
|
{
|
|
return xc_psr_cmt_enabled(ctx->xch);
|
|
}
|
|
|
|
int libxl_psr_cmt_get_total_rmid(libxl_ctx *ctx, uint32_t *total_rmid)
|
|
{
|
|
GC_INIT(ctx);
|
|
int rc;
|
|
|
|
rc = xc_psr_cmt_get_total_rmid(ctx->xch, total_rmid);
|
|
if (rc < 0) {
|
|
libxl__psr_cmt_log_err_msg(gc, errno);
|
|
rc = ERROR_FAIL;
|
|
}
|
|
|
|
GC_FREE;
|
|
return rc;
|
|
}
|
|
|
|
int libxl_psr_cmt_get_l3_cache_size(libxl_ctx *ctx,
|
|
uint32_t socketid,
|
|
uint32_t *l3_cache_size)
|
|
{
|
|
GC_INIT(ctx);
|
|
|
|
int rc;
|
|
int cpu = libxl__pick_socket_cpu(gc, socketid);
|
|
|
|
if (cpu < 0) {
|
|
LOGE(ERROR, "failed to get socket cpu");
|
|
rc = ERROR_FAIL;
|
|
goto out;
|
|
}
|
|
|
|
rc = xc_psr_cmt_get_l3_cache_size(ctx->xch, cpu, l3_cache_size);
|
|
if (rc < 0) {
|
|
libxl__psr_cmt_log_err_msg(gc, errno);
|
|
rc = ERROR_FAIL;
|
|
}
|
|
|
|
out:
|
|
GC_FREE;
|
|
return rc;
|
|
}
|
|
|
|
int libxl_psr_cmt_type_supported(libxl_ctx *ctx, libxl_psr_cmt_type type)
|
|
{
|
|
GC_INIT(ctx);
|
|
uint32_t event_mask;
|
|
int rc;
|
|
|
|
rc = xc_psr_cmt_get_l3_event_mask(ctx->xch, &event_mask);
|
|
if (rc < 0) {
|
|
libxl__psr_cmt_log_err_msg(gc, errno);
|
|
rc = 0;
|
|
} else {
|
|
rc = event_mask & (1 << (type - 1));
|
|
}
|
|
|
|
GC_FREE;
|
|
return rc;
|
|
}
|
|
|
|
int 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)
|
|
{
|
|
GC_INIT(ctx);
|
|
unsigned int rmid;
|
|
uint32_t upscaling_factor;
|
|
uint64_t monitor_data;
|
|
int cpu, rc;
|
|
|
|
rc = xc_psr_cmt_get_domain_rmid(ctx->xch, domid, &rmid);
|
|
if (rc < 0 || rmid == 0) {
|
|
LOGED(ERROR, domid, "fail to get the domain rmid, "
|
|
"or domain is not attached with platform QoS monitoring service");
|
|
rc = ERROR_FAIL;
|
|
goto out;
|
|
}
|
|
|
|
cpu = libxl__pick_socket_cpu(gc, scope);
|
|
if (cpu < 0) {
|
|
LOGED(ERROR, domid, "failed to get socket cpu");
|
|
rc = ERROR_FAIL;
|
|
goto out;
|
|
}
|
|
|
|
rc = xc_psr_cmt_get_data(ctx->xch, rmid, cpu, type - 1,
|
|
&monitor_data, tsc_r);
|
|
if (rc < 0) {
|
|
LOGED(ERROR, domid, "failed to get monitoring data");
|
|
rc = ERROR_FAIL;
|
|
goto out;
|
|
}
|
|
|
|
rc = xc_psr_cmt_get_l3_upscaling_factor(ctx->xch, &upscaling_factor);
|
|
if (rc < 0) {
|
|
LOGED(ERROR, domid, "failed to get L3 upscaling factor");
|
|
rc = ERROR_FAIL;
|
|
goto out;
|
|
}
|
|
|
|
*sample_r = monitor_data * upscaling_factor;
|
|
out:
|
|
GC_FREE;
|
|
return rc;
|
|
}
|
|
|
|
int libxl_psr_cmt_get_cache_occupancy(libxl_ctx *ctx,
|
|
uint32_t domid,
|
|
uint32_t socketid,
|
|
uint32_t *l3_cache_occupancy)
|
|
{
|
|
uint64_t data;
|
|
int rc;
|
|
|
|
rc = libxl_psr_cmt_get_sample(ctx, domid,
|
|
LIBXL_PSR_CMT_TYPE_CACHE_OCCUPANCY,
|
|
socketid, &data, NULL);
|
|
if (rc < 0)
|
|
goto out;
|
|
|
|
*l3_cache_occupancy = data / 1024;
|
|
out:
|
|
return rc;
|
|
}
|
|
|
|
static inline xc_psr_type libxl__psr_type_to_libxc_psr_type(
|
|
libxl_psr_type type)
|
|
{
|
|
BUILD_BUG_ON(sizeof(libxl_psr_type) != sizeof(xc_psr_type));
|
|
return (xc_psr_type)type;
|
|
}
|
|
|
|
int libxl_psr_cat_set_cbm(libxl_ctx *ctx, uint32_t domid,
|
|
libxl_psr_cbm_type type, libxl_bitmap *target_map,
|
|
uint64_t cbm)
|
|
{
|
|
return libxl_psr_set_val(ctx, domid, type, target_map, cbm);
|
|
}
|
|
|
|
int libxl_psr_cat_get_cbm(libxl_ctx *ctx, uint32_t domid,
|
|
libxl_psr_cbm_type type, uint32_t target,
|
|
uint64_t *cbm_r)
|
|
{
|
|
return libxl_psr_get_val(ctx, domid, type, target, cbm_r);
|
|
}
|
|
|
|
static xc_psr_feat_type libxl__feat_type_to_libxc_feat_type(
|
|
libxl_psr_feat_type type, unsigned int lvl)
|
|
{
|
|
xc_psr_feat_type xc_type;
|
|
|
|
switch (type) {
|
|
case LIBXL_PSR_FEAT_TYPE_CAT:
|
|
assert(lvl == 3 || lvl == 2);
|
|
|
|
if (lvl == 3)
|
|
xc_type = XC_PSR_CAT_L3;
|
|
if (lvl == 2)
|
|
xc_type = XC_PSR_CAT_L2;
|
|
break;
|
|
case LIBXL_PSR_FEAT_TYPE_MBA:
|
|
xc_type = XC_PSR_MBA;
|
|
break;
|
|
default:
|
|
/* Could not happen */
|
|
assert(0);
|
|
}
|
|
|
|
return xc_type;
|
|
}
|
|
|
|
static void libxl__hw_info_to_libxl_cat_info(
|
|
libxl_psr_feat_type type, libxl_psr_hw_info *hw_info,
|
|
libxl_psr_cat_info *cat_info)
|
|
{
|
|
assert(type == LIBXL_PSR_FEAT_TYPE_CAT);
|
|
|
|
cat_info->id = hw_info->id;
|
|
cat_info->cos_max = hw_info->u.cat.cos_max;
|
|
cat_info->cbm_len = hw_info->u.cat.cbm_len;
|
|
cat_info->cdp_enabled = hw_info->u.cat.cdp_enabled;
|
|
}
|
|
|
|
int libxl_psr_cat_get_info(libxl_ctx *ctx, libxl_psr_cat_info **info,
|
|
unsigned int *nr, unsigned int lvl)
|
|
{
|
|
GC_INIT(ctx);
|
|
int rc;
|
|
unsigned int i;
|
|
libxl_psr_hw_info *hw_info;
|
|
libxl_psr_cat_info *ptr;
|
|
|
|
rc = libxl_psr_get_hw_info(ctx, LIBXL_PSR_FEAT_TYPE_CAT, lvl, nr, &hw_info);
|
|
if (rc)
|
|
goto out;
|
|
|
|
ptr = libxl__malloc(NOGC, *nr * sizeof(libxl_psr_cat_info));
|
|
|
|
for (i = 0; i < *nr; i++)
|
|
libxl__hw_info_to_libxl_cat_info(LIBXL_PSR_FEAT_TYPE_CAT,
|
|
&hw_info[i],
|
|
&ptr[i]);
|
|
|
|
*info = ptr;
|
|
libxl_psr_hw_info_list_free(hw_info, *nr);
|
|
out:
|
|
GC_FREE;
|
|
return rc;
|
|
}
|
|
|
|
int libxl_psr_cat_get_l3_info(libxl_ctx *ctx, libxl_psr_cat_info **info,
|
|
int *nr)
|
|
{
|
|
int rc;
|
|
unsigned int num;
|
|
|
|
rc = libxl_psr_cat_get_info(ctx, info, &num, 3);
|
|
if (!rc)
|
|
*nr = num;
|
|
|
|
return rc;
|
|
}
|
|
|
|
void libxl_psr_cat_info_list_free(libxl_psr_cat_info *list, int nr)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < nr; i++)
|
|
libxl_psr_cat_info_dispose(&list[i]);
|
|
free(list);
|
|
}
|
|
|
|
int libxl_psr_set_val(libxl_ctx *ctx, uint32_t domid,
|
|
libxl_psr_type type, libxl_bitmap *target_map,
|
|
uint64_t val)
|
|
{
|
|
GC_INIT(ctx);
|
|
int rc, socketid, nr_sockets;
|
|
xc_psr_type xc_type = libxl__psr_type_to_libxc_psr_type(type);
|
|
|
|
rc = libxl__count_physical_sockets(gc, &nr_sockets);
|
|
if (rc) {
|
|
LOG(ERROR, "failed to get system socket count");
|
|
goto out;
|
|
}
|
|
|
|
libxl_for_each_set_bit(socketid, *target_map) {
|
|
if (socketid >= nr_sockets)
|
|
break;
|
|
|
|
if (xc_psr_set_domain_data(ctx->xch, domid, xc_type,
|
|
socketid, val)) {
|
|
libxl__psr_alloc_log_err_msg(gc, errno, type);
|
|
rc = ERROR_FAIL;
|
|
}
|
|
}
|
|
|
|
out:
|
|
GC_FREE;
|
|
return rc;
|
|
}
|
|
|
|
int libxl_psr_get_val(libxl_ctx *ctx, uint32_t domid,
|
|
libxl_psr_type type, unsigned int target,
|
|
uint64_t *val)
|
|
{
|
|
GC_INIT(ctx);
|
|
int rc = 0;
|
|
xc_psr_type xc_type = libxl__psr_type_to_libxc_psr_type(type);
|
|
|
|
if (xc_psr_get_domain_data(ctx->xch, domid, xc_type,
|
|
target, val)) {
|
|
libxl__psr_alloc_log_err_msg(gc, errno, type);
|
|
rc = ERROR_FAIL;
|
|
}
|
|
|
|
GC_FREE;
|
|
return rc;
|
|
}
|
|
|
|
static void 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)
|
|
{
|
|
switch (type) {
|
|
case LIBXL_PSR_FEAT_TYPE_CAT:
|
|
xl_info->u.cat.cos_max = xc_info->cat.cos_max;
|
|
xl_info->u.cat.cbm_len = xc_info->cat.cbm_len;
|
|
xl_info->u.cat.cdp_enabled = xc_info->cat.cdp_enabled;
|
|
break;
|
|
case LIBXL_PSR_FEAT_TYPE_MBA:
|
|
xl_info->u.mba.cos_max = xc_info->mba.cos_max;
|
|
xl_info->u.mba.thrtl_max = xc_info->mba.thrtl_max;
|
|
xl_info->u.mba.linear = xc_info->mba.linear;
|
|
break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
int libxl_psr_get_hw_info(libxl_ctx *ctx, libxl_psr_feat_type type,
|
|
unsigned int lvl, unsigned int *nr,
|
|
libxl_psr_hw_info **info)
|
|
{
|
|
GC_INIT(ctx);
|
|
int rc, nr_sockets;
|
|
unsigned int i = 0, socketid;
|
|
libxl_bitmap socketmap;
|
|
libxl_psr_hw_info *ptr;
|
|
xc_psr_feat_type xc_type;
|
|
xc_psr_hw_info hw_info;
|
|
|
|
libxl_bitmap_init(&socketmap);
|
|
|
|
xc_type = libxl__feat_type_to_libxc_feat_type(type, lvl);
|
|
|
|
rc = libxl__count_physical_sockets(gc, &nr_sockets);
|
|
if (rc) {
|
|
LOG(ERROR, "failed to get system socket count");
|
|
goto out;
|
|
}
|
|
|
|
libxl_socket_bitmap_alloc(ctx, &socketmap, nr_sockets);
|
|
rc = libxl_get_online_socketmap(ctx, &socketmap);
|
|
if (rc) {
|
|
LOGE(ERROR, "failed to get available sockets");
|
|
goto out;
|
|
}
|
|
|
|
ptr = libxl__malloc(NOGC, nr_sockets * sizeof(libxl_psr_hw_info));
|
|
|
|
libxl_for_each_set_bit(socketid, socketmap) {
|
|
ptr[i].id = socketid;
|
|
if (xc_psr_get_hw_info(ctx->xch, socketid, xc_type, &hw_info)) {
|
|
rc = ERROR_FAIL;
|
|
free(ptr);
|
|
goto out;
|
|
}
|
|
|
|
libxl__xc_hw_info_to_libxl_hw_info(type, &hw_info, &ptr[i]);
|
|
|
|
i++;
|
|
}
|
|
|
|
*info = ptr;
|
|
*nr = i;
|
|
out:
|
|
libxl_bitmap_dispose(&socketmap);
|
|
GC_FREE;
|
|
return rc;
|
|
}
|
|
|
|
void libxl_psr_hw_info_list_free(libxl_psr_hw_info *list, unsigned int nr)
|
|
{
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < nr; i++)
|
|
libxl_psr_hw_info_dispose(&list[i]);
|
|
free(list);
|
|
}
|
|
|
|
/*
|
|
* Local variables:
|
|
* mode: C
|
|
* c-basic-offset: 4
|
|
* indent-tabs-mode: nil
|
|
* End:
|
|
*/
|