// Copyright(c) 2018-2020, Intel Corporation
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of Intel Corporation nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
/**
* \file metrics_utils.c
* \brief fpga metrics utils functions
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif // HAVE_CONFIG_H
#include <string.h>
#include <glob.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <uuid/uuid.h>
#include <dlfcn.h>
#include "common_int.h"
#include "metrics_int.h"
#include "types_int.h"
#include "opae/metrics.h"
#include "metrics/vector.h"
#include "xfpga.h"
#include "metrics/bmc/bmc.h"
#include "metrics/metrics_metadata.h"
#include "mcp_metadata.h"
#include "metrics_max10.h"
fpga_result metric_sysfs_path_is_dir(const char *path)
{
struct stat astats;
if (path == NULL) {
return FPGA_INVALID_PARAM;
}
if ((stat(path, &astats)) != 0) {
return FPGA_NOT_FOUND;
}
if (S_ISDIR(astats.st_mode)) {
return FPGA_OK;
}
return FPGA_NOT_FOUND;
}
fpga_result metric_sysfs_path_is_file(const char *path)
{
struct stat astats;
if (path == NULL) {
return FPGA_INVALID_PARAM;
}
if ((stat(path, &astats)) != 0) {
return FPGA_NOT_FOUND;
}
if (S_ISREG(astats.st_mode)) {
return FPGA_OK;
}
return FPGA_NOT_FOUND;
}
// Adds Metrics info to vector
fpga_result add_metric_vector(fpga_metric_vector *vector,
uint64_t metric_num,
const char *qualifier_name,
const char *group_name,
const char *group_sysfs,
const char *metric_name,
const char *metric_sysfs,
const char *metric_units,
enum fpga_metric_datatype metric_datatype,
enum fpga_metric_type metric_type,
enum fpga_hw_type hw_type,
uint64_t mmio_offset)
{
fpga_result result = FPGA_OK;
struct _fpga_enum_metric *fpga_enum_metric = NULL;
size_t len;
if (vector == NULL ||
group_name == NULL ||
group_sysfs == NULL ||
metric_name == NULL ||
metric_sysfs == NULL ||
qualifier_name == NULL ||
metric_units == NULL) {
OPAE_ERR("Invalid Input parameters");
return FPGA_INVALID_PARAM;
}
fpga_enum_metric = (struct _fpga_enum_metric *)malloc(sizeof(struct _fpga_enum_metric));
if (fpga_enum_metric == NULL) {
OPAE_ERR("Failed to allocate memory");
return FPGA_NO_MEMORY;
}
len = strnlen(group_name, SYSFS_PATH_MAX - 1);
memcpy(fpga_enum_metric->group_name, group_name, len);
fpga_enum_metric->group_name[len] = '\0';
len = strnlen(group_sysfs, SYSFS_PATH_MAX - 1);
memcpy(fpga_enum_metric->group_sysfs, group_sysfs, len);
fpga_enum_metric->group_sysfs[len] = '\0';
len = strnlen(metric_name, SYSFS_PATH_MAX - 1);
memcpy(fpga_enum_metric->metric_name, metric_name, len);
fpga_enum_metric->metric_name[len] = '\0';
len = strnlen(metric_sysfs, SYSFS_PATH_MAX - 1);
memcpy(fpga_enum_metric->metric_sysfs, metric_sysfs, len);
fpga_enum_metric->metric_sysfs[len] = '\0';
len = strnlen(qualifier_name, SYSFS_PATH_MAX - 1);
memcpy(fpga_enum_metric->qualifier_name, qualifier_name, len);
fpga_enum_metric->qualifier_name[len] = '\0';
len = strnlen(metric_units, SYSFS_PATH_MAX - 1);
memcpy(fpga_enum_metric->metric_units, metric_units, len);
fpga_enum_metric->metric_units[len] = '\0';
fpga_enum_metric->metric_type = metric_type;
fpga_enum_metric->metric_datatype = metric_datatype;
fpga_enum_metric->hw_type = hw_type;
fpga_enum_metric->metric_num = metric_num;
fpga_enum_metric->mmio_offset = mmio_offset;
fpga_vector_push(vector, fpga_enum_metric);
return result;
}
fpga_result get_metric_data_info(const char *group_name,
const char *metric_name,
fpga_metric_metadata *metric_data_serach,
uint64_t size,
fpga_metric_metadata *metric_data)
{
fpga_result result = FPGA_OK;
uint64_t i = 0;
int group_indicator = 0;
int metric_indicator = 0;
if (group_name == NULL ||
metric_name == NULL ||
metric_data_serach == NULL ||
metric_data == NULL) {
OPAE_ERR("Invalid Input Paramters");
return FPGA_INVALID_PARAM;
}
for (i = 0; i < size; i++) {
group_indicator = strcasecmp(metric_data_serach[i].group_name,
group_name);
metric_indicator = strcasecmp(metric_data_serach[i].metric_name,
metric_name);
if (group_indicator == 0 &&
metric_indicator == 0) {
*metric_data = (struct fpga_metric_metadata)metric_data_serach[i];
return result;
}
}
return FPGA_NOT_SUPPORTED;
}
// enumerates thermal metrics info
fpga_result enum_thermalmgmt_metrics(fpga_metric_vector *vector,
uint64_t *metric_num,
const char *sysfspath,
enum fpga_hw_type hw_type)
{
fpga_result result = FPGA_OK;
fpga_metric_metadata metric_data;
size_t i = 0;
glob_t pglob;
memset(&metric_data, 0, sizeof(metric_data));
if (vector == NULL ||
sysfspath == NULL ||
metric_num == NULL) {
OPAE_ERR("Invalid Input parameters");
return FPGA_INVALID_PARAM;
}
int gres = glob(sysfspath, GLOB_NOSORT, NULL, &pglob);
if (gres) {
OPAE_ERR("Failed pattern match %s: %s", sysfspath, strerror(errno));
//TODO refactor to common function
switch (gres) {
case GLOB_NOSPACE:
result = FPGA_NO_MEMORY;
break;
case GLOB_NOMATCH:
result = FPGA_NOT_FOUND;
break;
default:
result = FPGA_EXCEPTION;
}
if (pglob.gl_pathv) {
globfree(&pglob);
}
return result;
}
for (i = 0; i < pglob.gl_pathc; i++) {
if (!pglob.gl_pathv) {
OPAE_ERR("No matching pattern");
break;
}
char *dir_name = strrchr(pglob.gl_pathv[i], '/');
if (!dir_name)
continue;
if (!strcmp((dir_name + 1), REVISION))
continue;
result = get_metric_data_info(THERLGMT, (dir_name + 1), mcp_metric_metadata, MCP_MDATA_SIZE, &metric_data);
if (result != FPGA_OK) {
OPAE_MSG("Failed to get metric metadata ");
}
result = add_metric_vector(vector, *metric_num, THERLGMT, THERLGMT, sysfspath, (dir_name + 1), pglob.gl_pathv[i], metric_data.metric_units,
FPGA_METRIC_DATATYPE_INT, FPGA_METRIC_TYPE_THERMAL, hw_type, 0);
if (result != FPGA_OK) {
OPAE_MSG("Failed to add metrics");
if (pglob.gl_pathv) {
globfree(&pglob);
}
return result;
}
*metric_num = *metric_num + 1;
}
if (pglob.gl_pathv) {
globfree(&pglob);
}
return result;
}
// enumerates power metrics info
fpga_result enum_powermgmt_metrics(fpga_metric_vector *vector,
uint64_t *metric_num,
const char *sysfspath,
enum fpga_hw_type hw_type)
{
fpga_result result = FPGA_OK;
size_t i = 0;
fpga_metric_metadata metric_data;
glob_t pglob;
memset(&metric_data, 0, sizeof(metric_data));
if (vector == NULL ||
sysfspath == NULL ||
metric_num == NULL) {
OPAE_ERR("Invalid Input parameters");
return FPGA_INVALID_PARAM;
}
int gres = glob(sysfspath, GLOB_NOSORT, NULL, &pglob);
if (gres) {
OPAE_ERR("Failed pattern match %s: %s", sysfspath, strerror(errno));
//TODO refactor to common function
switch (gres) {
case GLOB_NOSPACE:
result = FPGA_NO_MEMORY;
break;
case GLOB_NOMATCH:
result = FPGA_NOT_FOUND;
break;
default:
result = FPGA_EXCEPTION;
}
if (pglob.gl_pathv) {
globfree(&pglob);
}
return result;
}
for (i = 0; i < pglob.gl_pathc; i++) {
if (!pglob.gl_pathv) {
OPAE_ERR("No matching pattern");
break;
}
char *dir_name = strrchr(pglob.gl_pathv[i], '/');
if (!dir_name)
continue;
if (!strcmp((dir_name + 1), REVISION))
continue;
result = get_metric_data_info(PWRMGMT, (dir_name + 1), mcp_metric_metadata, MCP_MDATA_SIZE, &metric_data);
if (result != FPGA_OK) {
OPAE_MSG("Failed to get metric metadata ");
}
result = add_metric_vector(vector, *metric_num, PWRMGMT, PWRMGMT, sysfspath, (dir_name + 1), pglob.gl_pathv[i], metric_data.metric_units,
FPGA_METRIC_DATATYPE_INT, FPGA_METRIC_TYPE_POWER, hw_type, 0);
if (result != FPGA_OK) {
OPAE_MSG("Failed to add metrics");
if (pglob.gl_pathv) {
globfree(&pglob);
}
return result;
}
*metric_num = *metric_num + 1;
}
if (pglob.gl_pathv) {
globfree(&pglob);
}
return result;
}
// enumerates performance counters metrics info
fpga_result enum_perf_counter_items(fpga_metric_vector *vector,
uint64_t *metric_num,
const char *qualifier_name,
const char *sysfspath,
const char *sysfs_name,
enum fpga_metric_type metric_type,
enum fpga_hw_type hw_type)
{
fpga_result result = FPGA_OK;
DIR *dir = NULL;
struct dirent *dirent = NULL;
char sysfs_path[SYSFS_PATH_MAX] = { 0, };
char metric_sysfs[SYSFS_PATH_MAX] = { 0, };
char qname[SYSFS_PATH_MAX] = { 0, };
if (vector == NULL ||
sysfspath == NULL ||
sysfs_name == NULL ||
qualifier_name == NULL ||
metric_num == NULL) {
OPAE_ERR("Invalid Input parameters");
return FPGA_INVALID_PARAM;
}
snprintf(sysfs_path, sizeof(sysfs_path),
"%s/%s", sysfspath, sysfs_name);
dir = opendir(sysfs_path);
if (NULL == dir) {
OPAE_MSG("can't find dir %s ", strerror(errno));
return FPGA_NOT_FOUND;
}
while ((dirent = readdir(dir)) != NULL) {
if (!strcmp(dirent->d_name, "."))
continue;
if (!strcmp(dirent->d_name, ".."))
continue;
if (!strcmp(dirent->d_name, PERF_ENABLE))
continue;
if (!strcmp(dirent->d_name, PERF_FREEZE))
continue;
if (dirent->d_type == DT_DIR) {
if (snprintf(qname, sizeof(qname),
"%s:%s", qualifier_name, dirent->d_name) < 0) {
OPAE_ERR("snprintf buffer overflow");
continue;
}
result = enum_perf_counter_items(vector, metric_num, qname, sysfs_path, dirent->d_name, metric_type, hw_type);
if (result != FPGA_OK) {
OPAE_MSG("Failed to add metrics");
}
continue;
}
if (snprintf(metric_sysfs, sizeof(metric_sysfs),
"%s/%s", sysfs_path, dirent->d_name) < 0) {
OPAE_ERR("snprintf buffer overflow");
closedir(dir);
return FPGA_EXCEPTION;
}
result = add_metric_vector(vector, *metric_num, qualifier_name, "performance", sysfs_path, dirent->d_name,
metric_sysfs, "", FPGA_METRIC_DATATYPE_INT, metric_type, hw_type, 0);
if (result != FPGA_OK) {
OPAE_MSG("Failed to add metrics");
closedir(dir);
return result;
}
*metric_num = *metric_num + 1;
}
closedir(dir);
return result;
}
// enumerates performance counters metrics info
fpga_result enum_perf_counter_metrics(fpga_metric_vector *vector,
uint64_t *metric_num,
const char *sysfspath,
enum fpga_hw_type hw_type)
{
fpga_result result = FPGA_OK;
DIR *dir = NULL;
struct dirent *dirent = NULL;
char sysfs_path[SYSFS_PATH_MAX] = { 0, };
char qualifier_name[SYSFS_PATH_MAX] = { 0, };
glob_t pglob;
size_t len;
if (vector == NULL ||
sysfspath == NULL ||
metric_num == NULL) {
OPAE_ERR("Invalid Input parameters");
return FPGA_INVALID_PARAM;
}
int gres = glob(sysfspath, GLOB_NOSORT, NULL, &pglob);
if (gres) {
OPAE_ERR("Failed pattern match %s: %s", sysfspath, strerror(errno));
if (pglob.gl_pathv) {
globfree(&pglob);
}
return FPGA_NOT_FOUND;
}
len = strnlen(pglob.gl_pathv[0], sizeof(sysfs_path) - 1);
memcpy(sysfs_path, pglob.gl_pathv[0], len);
sysfs_path[len] = '\0';
globfree(&pglob);
dir = opendir(sysfs_path);
if (NULL == dir) {
OPAE_MSG("can't find dirt %s ", strerror(errno));
return FPGA_NOT_FOUND;
}
while ((dirent = readdir(dir)) != NULL) {
if (!strcmp(dirent->d_name, "."))
continue;
if (!strcmp(dirent->d_name, ".."))
continue;
if (!strcmp(dirent->d_name, REVISION))
continue;
if (strcmp(dirent->d_name, PERF_CACHE) == 0) {
snprintf(qualifier_name, sizeof(qualifier_name),
"%s:%s", PERFORMANCE, PERF_CACHE);
result = enum_perf_counter_items(vector,
metric_num, qualifier_name,
sysfs_path, dirent->d_name,
FPGA_METRIC_TYPE_PERFORMANCE_CTR, hw_type);
if (result != FPGA_OK) {
OPAE_MSG("Failed to add metrics");
}
}
if (strcmp(dirent->d_name, PERF_FABRIC) == 0) {
snprintf(qualifier_name, sizeof(qualifier_name),
"%s:%s", PERFORMANCE, PERF_FABRIC);
result = enum_perf_counter_items(vector, metric_num,
qualifier_name, sysfs_path,
dirent->d_name, FPGA_METRIC_TYPE_PERFORMANCE_CTR, hw_type);
if (result != FPGA_OK) {
OPAE_MSG("Failed to add metrics");
}
}
if (strcmp(dirent->d_name, PERF_IOMMU) == 0) {
snprintf(qualifier_name, sizeof(qualifier_name),
"%s:%s", PERFORMANCE, PERF_IOMMU);
result = enum_perf_counter_items(vector, metric_num,
qualifier_name, sysfs_path, dirent->d_name,
FPGA_METRIC_TYPE_PERFORMANCE_CTR, hw_type);
if (result != FPGA_OK) {
OPAE_MSG("Failed to add metrics");
}
}
}
closedir(dir);
return result;
}
fpga_result xfpga_bmcLoadSDRs(struct _fpga_handle *_handle,
bmc_sdr_handle *records,
uint32_t *num_sensors)
{
fpga_result result = FPGA_NOT_FOUND;
fpga_result(*bmcLoadSDRs)(fpga_token token, bmc_sdr_handle *records,
uint32_t *num_sensors);
if (_handle->bmc_handle != NULL) {
bmcLoadSDRs = dlsym(_handle->bmc_handle, "bmcLoadSDRs");
if (bmcLoadSDRs)
result = bmcLoadSDRs(_handle->token, records, num_sensors);
else
result = FPGA_EXCEPTION;
}
return result;
}
fpga_result xfpga_bmcDestroySDRs(struct _fpga_handle *_handle,
bmc_sdr_handle *records)
{
fpga_result result = FPGA_NOT_FOUND;
fpga_result(*bmcDestroySDRs)(bmc_sdr_handle *records);
if (_handle->bmc_handle != NULL) {
bmcDestroySDRs = dlsym(_handle->bmc_handle, "bmcDestroySDRs");
if (bmcDestroySDRs)
result = bmcDestroySDRs(records);
else
result = FPGA_EXCEPTION;
}
return result;
}
fpga_result xfpga_bmcReadSensorValues(struct _fpga_handle *_handle,
bmc_sdr_handle records,
bmc_values_handle *values,
uint32_t *num_values)
{
fpga_result result = FPGA_NOT_FOUND;
fpga_result(*bmcReadSensorValues)(bmc_sdr_handle records, bmc_values_handle *values, uint32_t *num_values);
if (_handle->bmc_handle != NULL) {
bmcReadSensorValues = dlsym(_handle->bmc_handle, "bmcReadSensorValues");
if (bmcReadSensorValues)
result = bmcReadSensorValues(records, values, num_values);
else
result = FPGA_EXCEPTION;
}
return result;
}
fpga_result xfpga_bmcDestroySensorValues(struct _fpga_handle *_handle,
bmc_values_handle *values)
{
fpga_result result = FPGA_NOT_FOUND;
fpga_result(*bmcDestroySensorValues)(bmc_values_handle *values);
if (_handle->bmc_handle != NULL) {
bmcDestroySensorValues = dlsym(_handle->bmc_handle, "bmcDestroySensorValues");
if (bmcDestroySensorValues)
result = bmcDestroySensorValues(values);
else
result = FPGA_EXCEPTION;
}
return result;
}
fpga_result xfpga_bmcGetSensorReading(struct _fpga_handle *_handle,
bmc_values_handle values,
uint32_t sensor_number,
uint32_t *is_valid,
double *value)
{
fpga_result result = FPGA_NOT_FOUND;
fpga_result(*bmcGetSensorReading)(bmc_values_handle values,
uint32_t sensor_number, uint32_t *is_valid,
double *value);
if (_handle->bmc_handle != NULL) {
bmcGetSensorReading = dlsym(_handle->bmc_handle, "bmcGetSensorReading");
if (bmcGetSensorReading)
result = bmcGetSensorReading(values, sensor_number, is_valid, value);
else
result = FPGA_EXCEPTION;
}
return result;
}
fpga_result xfpga_bmcGetSDRDetails(struct _fpga_handle *_handle,
bmc_values_handle values,
uint32_t sensor_number,
sdr_details *details)
{
fpga_result result = FPGA_NOT_FOUND;
fpga_result(*bmcGetSDRDetails)(bmc_values_handle values, uint32_t sensor_number,
sdr_details *details);
if (_handle->bmc_handle != NULL) {
bmcGetSDRDetails = dlsym(_handle->bmc_handle, "bmcGetSDRDetails");
if (bmcGetSDRDetails)
result = bmcGetSDRDetails(values, sensor_number, details);
else
result = FPGA_EXCEPTION;
}
return result;
}
// enumerates bmc power & theraml metrics info
fpga_result enum_bmc_metrics_info(struct _fpga_handle *_handle,
fpga_metric_vector *vector,
uint64_t *metric_num,
enum fpga_hw_type hw_type)
{
fpga_result result = FPGA_OK;
uint32_t x = 0;
uint32_t num_sensors = 0;
uint32_t num_values = 0;
enum fpga_metric_type metric_type = FPGA_METRIC_TYPE_POWER;
char group_name[SYSFS_PATH_MAX] = { 0, };
char qualifier_name[SYSFS_PATH_MAX] = { 0, };
char units[SYSFS_PATH_MAX] = { 0, };
sdr_details details;
bmc_sdr_handle records;
bmc_values_handle values;
size_t len;
if (vector == NULL ||
metric_num == NULL) {
OPAE_ERR("Invalid input");
return result;
}
result = xfpga_bmcLoadSDRs(_handle, &records, &num_sensors);
if (result != FPGA_OK) {
OPAE_ERR("Failed to load BMC SDR.");
return result;
}
result = xfpga_bmcReadSensorValues(_handle, records, &values, &num_values);
if (result != FPGA_OK) {
OPAE_ERR("Failed to read BMC sensor values.");
return result;
}
for (x = 0; x < num_sensors; x++) {
result = xfpga_bmcGetSDRDetails(_handle, values, x, &details);
if (details.sensor_type == BMC_THERMAL) {
metric_type = FPGA_METRIC_TYPE_THERMAL;
len = strnlen(THERLGMT, sizeof(group_name) - 1);
memcpy(group_name, THERLGMT, len);
group_name[len] = '\0';
len = strnlen(TEMP, sizeof(units) - 1);
memcpy(units, TEMP, len);
units[len] = '\0';
snprintf(qualifier_name, sizeof(qualifier_name),
"%s:%s", THERLGMT, details.name);
} else if (details.sensor_type == BMC_POWER) {
metric_type = FPGA_METRIC_TYPE_POWER;
len = strnlen(PWRMGMT, sizeof(group_name) - 1);
memcpy(group_name, PWRMGMT, len);
group_name[len] = '\0';
snprintf(qualifier_name, sizeof(qualifier_name),
"%s:%s", PWRMGMT, details.name);
snprintf(units, sizeof(units), "%ls", details.units);
} else {
continue;
}
result = add_metric_vector(vector, *metric_num,
qualifier_name, group_name, "",
details.name, "", units, FPGA_METRIC_DATATYPE_DOUBLE,
metric_type, hw_type, 0);
if (result != FPGA_OK) {
OPAE_MSG("Failed to add metrics");
return result;
}
*metric_num = *metric_num + 1;
}
result = xfpga_bmcDestroySensorValues(_handle, &values);
if (result != FPGA_OK) {
OPAE_MSG("Failed to Destroy Sensor value.");
}
result = xfpga_bmcDestroySDRs(_handle, &records);
if (result != FPGA_OK) {
OPAE_ERR("Failed to Destroy SDR.");
return result;
}
return result;
}
// frees metrics info vector
fpga_result free_fpga_enum_metrics_vector(struct _fpga_handle *_handle)
{
fpga_result result = FPGA_OK;
uint64_t i = 0;
uint64_t num_enun_metrics = 0;
if (_handle == NULL) {
OPAE_ERR("Invalid handle ");
return FPGA_INVALID_PARAM;
}
if (_handle->magic != FPGA_HANDLE_MAGIC) {
OPAE_MSG("Invalid handle");
return FPGA_INVALID_PARAM;
}
result = fpga_vector_total(&(_handle->fpga_enum_metric_vector), &num_enun_metrics);
if (result != FPGA_OK) {
OPAE_MSG("Failed to get metric total");
return FPGA_INVALID_PARAM;
}
for (i = 0; i < num_enun_metrics; i++) {
fpga_vector_delete(&(_handle->fpga_enum_metric_vector), i);
}
fpga_vector_free(&(_handle->fpga_enum_metric_vector));
if (_handle->bmc_handle) {
dlclose(_handle->bmc_handle);
_handle->bmc_handle = NULL;
}
clear_cached_values(_handle);
_handle->metric_enum_status = false;
return result;
}
// retrives fpga object type
fpga_result get_fpga_object_type(fpga_handle handle,
fpga_objtype *objtype)
{
fpga_result result = FPGA_OK;
fpga_result resval = FPGA_OK;
fpga_properties prop;
result = xfpga_fpgaGetPropertiesFromHandle(handle, &prop);
if (result != FPGA_OK) {
OPAE_ERR("Failed to get properties");
return result;
}
result = fpgaPropertiesGetObjectType(prop, objtype);
if (result != FPGA_OK) {
OPAE_ERR("Failed to object type.");
}
resval = (result != FPGA_OK) ? result : resval;
result = fpgaDestroyProperties(&prop);
if (result != FPGA_OK) {
OPAE_ERR("Failed to destroy properties");
}
resval = (result != FPGA_OK) ? result : resval;
return resval;
}
void *metrics_load_bmc_lib(void)
{
char plugin_path[PATH_MAX] = { 0, };
const char *search_paths[] = { OPAE_MODULE_SEARCH_PATHS };
unsigned i;
void *dl_handle;
for (i = 0 ;
i < sizeof(search_paths) / sizeof(search_paths[0]) ;
++i) {
snprintf(plugin_path, sizeof(plugin_path),
"%s%s", search_paths[i], BMC_LIB);
dl_handle = dlopen(plugin_path, RTLD_LAZY | RTLD_LOCAL);
if (dl_handle)
return dl_handle;
}
return NULL;
}
// enumerates FME & AFU metrics info
fpga_result enum_fpga_metrics(fpga_handle handle)
{
fpga_result result = FPGA_OK;
struct _fpga_token *_token = NULL;
enum fpga_hw_type hw_type = FPGA_HW_UNKNOWN;
uint64_t mmio_offset = 0;
uint64_t metric_num = 0;
char metrics_path[SYSFS_PATH_MAX] = { 0 };
fpga_objtype objtype;
struct _fpga_handle *_handle = (struct _fpga_handle *)handle;
if (_handle == NULL) {
OPAE_ERR("Invalid handle ");
return FPGA_INVALID_PARAM;
}
if (_handle->metric_enum_status)
return FPGA_OK;
_token = (struct _fpga_token *)_handle->token;
if (_token == NULL) {
OPAE_ERR("Invalid token within handle");
return FPGA_INVALID_PARAM;
}
result = get_fpga_object_type(handle, &objtype);
if (result != FPGA_OK) {
OPAE_ERR("Failed to init vector");
return result;
}
// Init vector
result = fpga_vector_init(&(_handle->fpga_enum_metric_vector));
if (result != FPGA_OK) {
OPAE_ERR("Failed to init vector");
return result;
}
if (objtype == FPGA_ACCELERATOR) {
// enum AFU
result = discover_afu_metrics_feature(handle, &mmio_offset);
if (result != FPGA_OK) {
OPAE_ERR("Failed to discover AFU Metrics BBB");
return result;
}
result = enum_afu_metrics(handle,
&(_handle->fpga_enum_metric_vector),
&metric_num,
mmio_offset);
if (result != FPGA_OK) {
OPAE_ERR("Failed to enum AFU metrics BBB");
return result;
}
} else if (objtype == FPGA_DEVICE) {
// enum FME
// get fpga hw type.
result = get_fpga_hw_type(_handle, &hw_type);
if (result != FPGA_OK) {
OPAE_ERR("Failed to discover hardware type.");
return result;
}
switch (hw_type) {
// MCP
case FPGA_HW_MCP: {
memset(metrics_path, 0, SYSFS_PATH_MAX);
if (sysfs_get_fme_pwr_path(_token, metrics_path) == FPGA_OK) {
result = enum_powermgmt_metrics(&(_handle->fpga_enum_metric_vector), &metric_num, metrics_path, FPGA_HW_MCP);
if (result != FPGA_OK) {
OPAE_ERR("Failed to Enum Power metrics.");
}
}
memset(metrics_path, 0, SYSFS_PATH_MAX);
if (sysfs_get_fme_temp_path(_token, metrics_path) == FPGA_OK) {
result = enum_thermalmgmt_metrics(&(_handle->fpga_enum_metric_vector), &metric_num, metrics_path, FPGA_HW_MCP);
if (result != FPGA_OK) {
OPAE_ERR("Failed to Enum Thermal metrics.");
}
}
memset(metrics_path, 0, SYSFS_PATH_MAX);
if (sysfs_get_fme_perf_path(_token, metrics_path) == FPGA_OK) {
result = enum_perf_counter_metrics(&(_handle->fpga_enum_metric_vector), &metric_num, metrics_path, FPGA_HW_MCP);
if (result != FPGA_OK) {
OPAE_ERR("Failed to Enum Performance metrics.");
}
}
}
break;
// DCP RC
case FPGA_HW_DCP_RC: {
memset(metrics_path, 0, SYSFS_PATH_MAX);
if (sysfs_get_fme_perf_path(_token, metrics_path) == FPGA_OK) {
result = enum_perf_counter_metrics(&(_handle->fpga_enum_metric_vector), &metric_num, metrics_path, FPGA_HW_DCP_RC);
if (result != FPGA_OK) {
OPAE_ERR("Failed to Enum Performance metrics.");
}
}
memset(metrics_path, 0, SYSFS_PATH_MAX);
if (sysfs_get_bmc_path(_token, metrics_path) == FPGA_OK) {
if (_handle->bmc_handle == NULL)
_handle->bmc_handle = metrics_load_bmc_lib();
if (_handle->bmc_handle) {
result = enum_bmc_metrics_info(_handle, &(_handle->fpga_enum_metric_vector), &metric_num, FPGA_HW_DCP_RC);
if (result != FPGA_OK) {
OPAE_ERR("Failed to enumerate BMC metrics.");
}
}
}
}
break;
// DCP VC DC
case FPGA_HW_DCP_DC:
case FPGA_HW_DCP_VC: {
memset(metrics_path, 0, SYSFS_PATH_MAX);
if (sysfs_get_max10_path(_token, metrics_path) == FPGA_OK) {
// Max10 Power & Thermal
result = enum_max10_metrics_info(_handle,
&(_handle->fpga_enum_metric_vector),
&metric_num,
hw_type);
if (result != FPGA_OK) {
OPAE_ERR("Failed to Enum Power and Thermal metrics.");
}
}
memset(metrics_path, 0, SYSFS_PATH_MAX);
if (sysfs_get_fme_perf_path(_token, metrics_path) == FPGA_OK) {
// Perf Counters
result = enum_perf_counter_metrics(&(_handle->fpga_enum_metric_vector), &metric_num, _token->sysfspath, hw_type);
if (result != FPGA_OK) {
OPAE_ERR("Failed to Enum Performance metrics.");
}
}
}
break;
default:
OPAE_MSG("Unknown hardware type.");
result = FPGA_EXCEPTION;
}
} // if Object type
if (result != FPGA_OK)
free_fpga_enum_metrics_vector(_handle);
_handle->metric_enum_status = true;
return result;
}
fpga_result add_metric_info(struct _fpga_enum_metric *_enum_metrics,
struct fpga_metric_info *fpga_metric_info)
{
fpga_result result = FPGA_OK;
size_t len;
if (_enum_metrics == NULL ||
fpga_metric_info == NULL) {
OPAE_ERR("Invalid Input Paramters");
return FPGA_INVALID_PARAM;
}
len = strnlen(_enum_metrics->group_name, SYSFS_PATH_MAX - 1);
memcpy(fpga_metric_info->group_name, _enum_metrics->group_name, len);
fpga_metric_info->group_name[len] = '\0';
len = strnlen(_enum_metrics->metric_name, SYSFS_PATH_MAX - 1);
memcpy(fpga_metric_info->metric_name, _enum_metrics->metric_name, len);
fpga_metric_info->metric_name[len] = '\0';
len = strnlen(_enum_metrics->qualifier_name, SYSFS_PATH_MAX - 1);
memcpy(fpga_metric_info->qualifier_name, _enum_metrics->qualifier_name, len);
fpga_metric_info->qualifier_name[len] = '\0';
len = strnlen(_enum_metrics->metric_units, SYSFS_PATH_MAX - 1);
memcpy(fpga_metric_info->metric_units, _enum_metrics->metric_units, len);
fpga_metric_info->metric_units[len] = '\0';
fpga_metric_info->metric_num = _enum_metrics->metric_num;
fpga_metric_info->metric_type = _enum_metrics->metric_type;
fpga_metric_info->metric_datatype = _enum_metrics->metric_datatype;
return result;
}
// Reads bmc metric value
fpga_result get_bmc_metrics_values(fpga_handle handle,
struct _fpga_enum_metric *_fpga_enum_metric,
struct fpga_metric *fpga_metric)
{
fpga_result result = FPGA_OK;
uint32_t num_sensors = 0;
uint32_t num_values = 0;
uint32_t x = 0;
uint32_t is_valid = 0;
double tmp = 0;
int metric_indicator = 0;
bmc_sdr_handle records;
bmc_values_handle values;
sdr_details details;
size_t len;
struct _fpga_handle *_handle = (struct _fpga_handle *)handle;
if (_handle->_bmc_metric_cache_value) {
for (x = 0; x < _handle->num_bmc_metric; x++) {
metric_indicator = strcasecmp(_handle->_bmc_metric_cache_value[x].metric_name,
_fpga_enum_metric->metric_name);
if (metric_indicator == 0) {
fpga_metric->value.dvalue = _handle->_bmc_metric_cache_value[x].fpga_metric.value.dvalue;
return result;
}
}
return FPGA_NOT_FOUND;
}
result = xfpga_bmcLoadSDRs(_handle, &records, &num_sensors);
if (result != FPGA_OK) {
OPAE_ERR("Failed to load BMC SDR.");
return result;
}
if (_handle->_bmc_metric_cache_value == NULL) {
_handle->_bmc_metric_cache_value = calloc(sizeof(struct _fpga_bmc_metric), num_sensors);
if (_handle->_bmc_metric_cache_value == NULL) {
OPAE_ERR("Failed to allocate memory");
result = FPGA_NO_MEMORY;
goto out_destroy;
}
_handle->num_bmc_metric = num_sensors;
}
result = xfpga_bmcReadSensorValues(_handle, records, &values, &num_values);
if (result != FPGA_OK) {
OPAE_ERR("Failed to read BMC sensor values.");
goto out_destroy;
}
for (x = 0; x < num_sensors; x++) {
result = xfpga_bmcGetSDRDetails(_handle, values, x, &details);
if (result != FPGA_OK) {
OPAE_MSG("Failed to get SDR details.");
}
result = xfpga_bmcGetSensorReading(_handle, values, x, &is_valid, &tmp);
if (result != FPGA_OK) {
OPAE_MSG("Failed to read sensor readings.");
continue;
}
if (!is_valid) {
continue;
}
len = strnlen(details.name, sizeof(_handle->_bmc_metric_cache_value[x].metric_name) - 1);
memcpy(_handle->_bmc_metric_cache_value[x].metric_name, details.name, len);
_handle->_bmc_metric_cache_value[x].metric_name[len] = '\0';
_handle->_bmc_metric_cache_value[x].fpga_metric.value.dvalue = tmp;
metric_indicator = strcasecmp(details.name, _fpga_enum_metric->metric_name);
if (metric_indicator == 0) {
fpga_metric->value.dvalue = tmp;
}
}
result = xfpga_bmcDestroySensorValues(_handle, &values);
if (result != FPGA_OK) {
OPAE_MSG("Failed to Destroy Sensor value.");
}
out_destroy:
result = xfpga_bmcDestroySDRs(_handle, &records);
if (result != FPGA_OK) {
OPAE_ERR("Failed to Destroy SDR.");
return result;
}
return result;
}
// Reads mcp power & thermal metric value
fpga_result get_pwr_thermal_max10_value(const char *sysfs_path,
double *dvalue)
{
fpga_result result = FPGA_OK;
uint64_t value;
if (sysfs_path == NULL ||
dvalue == NULL) {
OPAE_ERR("Invalid Input Paramters");
return FPGA_INVALID_PARAM;
}
result = sysfs_read_u64(sysfs_path, &value);
if (result != FPGA_OK) {
OPAE_MSG("Failed to read Metrics values");
return result;
}
*dvalue = ((double)value / MILLI);
return result;
}
// Reads mcp power & thermal metric value
fpga_result get_pwr_thermal_value(const char *sysfs_path,
uint64_t *value)
{
fpga_result result = FPGA_OK;
char *ptr = NULL;
if (sysfs_path == NULL ||
value == NULL) {
OPAE_ERR("Invalid Input Paramters");
return FPGA_INVALID_PARAM;
}
result = sysfs_read_u64(sysfs_path, value);
if (result != FPGA_OK) {
OPAE_ERR("Failed to read Metrics values");
return result;
}
ptr = strstr(sysfs_path, FPGA_LIMIT);
if (ptr)
*value = *value / 8;
ptr = NULL;
ptr = strstr(sysfs_path, XEON_LIMIT);
if (ptr)
*value = *value / 8;
return result;
}
// Reads mcp power & thermal metric value
fpga_result get_performance_counter_value(const char *group_sysfs,
const char *metric_sysfs,
uint64_t *value)
{
fpga_result result = FPGA_OK;
char sysfs_path[SYSFS_PATH_MAX] = { 0, };
uint64_t val = 0;
if (group_sysfs == NULL ||
metric_sysfs == NULL ||
value == NULL) {
OPAE_ERR("Invalid Input Paramters");
return FPGA_INVALID_PARAM;
}
snprintf(sysfs_path, sizeof(sysfs_path),
"%s/%s", group_sysfs, PERF_ENABLE);
result = metric_sysfs_path_is_file(sysfs_path);
if (result == FPGA_OK) {
result = sysfs_read_u64(sysfs_path, &val);
if (result != FPGA_OK) {
OPAE_ERR("Failed to read perf fabric enable");
}
if (val == 0x0) {
// Writer Fabric Enable
result = sysfs_write_u64_decimal(sysfs_path, 1);;
if (result != FPGA_OK) {
OPAE_ERR("Failed to read perf fabric enable");
}
}
}
snprintf(sysfs_path, sizeof(sysfs_path),
"%s/%s", group_sysfs, PERF_FREEZE);
result = metric_sysfs_path_is_file(sysfs_path);
if (result == FPGA_OK) {
result = sysfs_read_u64(sysfs_path, &val);
if (result != FPGA_OK) {
OPAE_ERR("Failed to read perf fabric freeze");
}
if (val != 0x1) {
// Write Fabric Freeze
result = sysfs_write_u64(sysfs_path, 1);
if (result != FPGA_OK) {
OPAE_ERR("Failed to write perf fabric freeze");
}
}
}
*value = 0;
result = sysfs_read_u64(metric_sysfs, value);
if (result != FPGA_OK) {
OPAE_ERR("--Failed to read Metrics values");
return result;
}
snprintf(sysfs_path, sizeof(sysfs_path),
"%s/%s", group_sysfs, PERF_FREEZE);
result = metric_sysfs_path_is_file(sysfs_path);
if (result == FPGA_OK) {
result = sysfs_read_u64(sysfs_path, &val);
if (result != FPGA_OK) {
OPAE_ERR("Failed to read perf fabric freeze");
}
if (val == 0x1) {
// Write Fabric Freeze
result = sysfs_write_u64(sysfs_path, 0);
if (result != FPGA_OK) {
OPAE_ERR("Failed to write perf fabric freeze");
}
}
}
result = FPGA_OK;
return result;
}
// Reads fme metric value
fpga_result get_fme_metric_value(fpga_handle handle,
fpga_metric_vector *enum_vector,
uint64_t metric_num,
struct fpga_metric *fpga_metric)
{
fpga_result result = FPGA_OK;
uint64_t index = 0;
struct _fpga_enum_metric *_fpga_enum_metric = NULL;
uint64_t num_enun_metrics = 0;
metric_value value = {0};
if (enum_vector == NULL ||
fpga_metric == NULL) {
OPAE_ERR("Invalid Input Paramters");
return FPGA_INVALID_PARAM;
}
result = fpga_vector_total(enum_vector, &num_enun_metrics);
if (result != FPGA_OK) {
OPAE_ERR("Failed to get metric total");
return FPGA_NOT_FOUND;
}
fpga_metric->isvalid = false;
result = FPGA_NOT_FOUND;
for (index = 0; index < num_enun_metrics ; index++) {
_fpga_enum_metric = (struct _fpga_enum_metric *) fpga_vector_get(enum_vector, index);
if (metric_num == _fpga_enum_metric->metric_num) {
// Found Metic
memset(&value, 0, sizeof(value));
// DCP Power & Thermal
if ((_fpga_enum_metric->hw_type == FPGA_HW_DCP_RC) &&
((_fpga_enum_metric->metric_type == FPGA_METRIC_TYPE_POWER) ||
(_fpga_enum_metric->metric_type == FPGA_METRIC_TYPE_THERMAL))) {
result = get_bmc_metrics_values(handle, _fpga_enum_metric, fpga_metric);
if (result != FPGA_OK) {
OPAE_MSG("Failed to get BMC metric value");
} else {
fpga_metric->isvalid = true;
}
fpga_metric->metric_num = metric_num;
}
if ((_fpga_enum_metric->hw_type == FPGA_HW_MCP) &&
((_fpga_enum_metric->metric_type == FPGA_METRIC_TYPE_POWER) ||
(_fpga_enum_metric->metric_type == FPGA_METRIC_TYPE_THERMAL))) {
result = get_pwr_thermal_value(_fpga_enum_metric->metric_sysfs, &value.ivalue);
if (result != FPGA_OK) {
OPAE_MSG("Failed to get BMC metric value");
} else {
fpga_metric->isvalid = true;
}
fpga_metric->value = value;
fpga_metric->metric_num = metric_num;
}
// Read power theraml values from Max10
if (((_fpga_enum_metric->hw_type == FPGA_HW_DCP_DC) ||
(_fpga_enum_metric->hw_type == FPGA_HW_DCP_VC)) &&
((_fpga_enum_metric->metric_type == FPGA_METRIC_TYPE_POWER) ||
(_fpga_enum_metric->metric_type == FPGA_METRIC_TYPE_THERMAL))) {
result = read_max10_value(_fpga_enum_metric, &value.dvalue);
if (result != FPGA_OK) {
OPAE_MSG("Failed to get Max10 metric value");
} else {
fpga_metric->isvalid = true;
}
fpga_metric->value = value;
fpga_metric->metric_num = metric_num;
}
if (_fpga_enum_metric->metric_type == FPGA_METRIC_TYPE_PERFORMANCE_CTR) {
result = get_performance_counter_value(_fpga_enum_metric->group_sysfs, _fpga_enum_metric->metric_sysfs, &value.ivalue);
if (result != FPGA_OK) {
OPAE_MSG("Failed to get perf metric value");
} else {
fpga_metric->isvalid = true;
}
fpga_metric->value = value;
fpga_metric->metric_num = metric_num;
}
break;
}
}
return result;
}
// parses metric name strings
fpga_result parse_metric_num_name(const char *search_string,
fpga_metric_vector *fpga_enum_metrics_vector,
uint64_t *metric_num)
{
fpga_result result = FPGA_OK;
char *str = NULL;
char *str_last = NULL;
uint64_t i = 0;
struct _fpga_enum_metric *fpga_enum_metric = NULL;
char qualifier_name[SYSFS_PATH_MAX] = { 0, };
char metrics_name[SYSFS_PATH_MAX] = { 0, };
int qualifier_indicator = 0;
int metric_indicator = 0;
uint64_t num_enun_metrics = 0;
size_t len;
if (search_string == NULL ||
fpga_enum_metrics_vector == NULL ||
metric_num == NULL) {
OPAE_ERR("Invalid Input Paramters");
return FPGA_INVALID_PARAM;
}
str = strrchr(search_string, ':');
if (!str) {
OPAE_ERR("Invalid Input Paramters");
return FPGA_INVALID_PARAM;
}
// Metric Name
len = strnlen(str + 1, FPGA_METRIC_STR_SIZE - 1);
memcpy(metrics_name, str + 1, len);
metrics_name[len] = '\0';
// qualifier_name
str_last = strrchr(search_string, ':');
if (!str_last) {
OPAE_ERR("Invalid Input Paramters");
return FPGA_INVALID_PARAM;
}
memcpy(qualifier_name, search_string, str_last - search_string);
qualifier_name[str_last - search_string] = '\0';
result = fpga_vector_total(fpga_enum_metrics_vector, &num_enun_metrics);
if (result != FPGA_OK) {
OPAE_ERR("Failed to get metric total");
return FPGA_NOT_FOUND;
}
for (i = 0; i < num_enun_metrics; i++) {
fpga_enum_metric = (struct _fpga_enum_metric *) fpga_vector_get(fpga_enum_metrics_vector, i);
qualifier_indicator = strcasecmp(fpga_enum_metric->qualifier_name, qualifier_name);
metric_indicator = strcasecmp(fpga_enum_metric->metric_name, metrics_name);
if (qualifier_indicator == 0 &&
metric_indicator == 0) {
*metric_num = fpga_enum_metric->metric_num;
return result;
}
} // end of for loop
return FPGA_NOT_FOUND;
}
// clears BMC values
fpga_result clear_cached_values(fpga_handle handle)
{
struct _fpga_handle *_handle = (struct _fpga_handle *)handle;
fpga_result result = FPGA_OK;
if (_handle->_bmc_metric_cache_value) {
free(_handle->_bmc_metric_cache_value);
_handle->_bmc_metric_cache_value = NULL;
}
_handle->num_bmc_metric = 0;
return result;
}