// 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_max10.h * \brief fpga metrics max10 functions */ #ifdef HAVE_CONFIG_H #include #endif // HAVE_CONFIG_H #include #include #include #ifndef _WIN32 #include #else #include #endif #include #include #include #include #include "common_int.h" #include "metrics_int.h" #include "types_int.h" #include "sysfs_int.h" #include "opae/metrics.h" #include "metrics/vector.h" #include "xfpga.h" #include "metrics/metrics_metadata.h" #include "metrics/max10_metadata.h" // Max10 Metric limits #define THERMAL_HIGH_LIMIT 300.00 #define THERMAL_LOW_LIMIT -273.00 #define POWER_HIGH_LIMIT 1000.00 #define POWER_LOW_LIMIT 0.00 #define VOLTAMP_HIGH_LIMIT 500.00 #define VOLTAMP_LOW_LIMIT 0.00 fpga_result read_sensor_sysfs_file(const char *sysfs, const char *file, void **buf, uint32_t *tot_bytes_ret) { char sysfspath[SYSFS_PATH_MAX] = { 0, }; struct stat stats; int fd = 0; fpga_result res = FPGA_OK; if (sysfs == NULL || file == NULL || buf == NULL || tot_bytes_ret == NULL) { OPAE_ERR("Invalid Input parameters"); return FPGA_INVALID_PARAM; } *buf = NULL; *tot_bytes_ret = 0; snprintf(sysfspath, sizeof(sysfspath), "%s/%s", sysfs, file); glob_t pglob; int gres = glob(sysfspath, GLOB_NOSORT, NULL, &pglob); if ((gres) || (1 != pglob.gl_pathc)) { globfree(&pglob); return FPGA_NOT_FOUND; } fd = open(pglob.gl_pathv[0], O_RDONLY); globfree(&pglob); if (fd < 0) { return FPGA_NOT_FOUND; } if (fstat(fd, &stats) != 0) { close(fd); return FPGA_NOT_FOUND; } // fstat for a sysfs file is not accurate for the BMC // Read the entire file into a temp buffer to get actual size of file *buf = (void *)calloc(stats.st_size, 1); int32_t tot_bytes = 0; int32_t bytes_read = 0; do { bytes_read = (int32_t)read(fd, *buf, stats.st_size); if (bytes_read < 0) { if (errno == EINTR) { bytes_read = 1; // Fool the while loop continue; } } tot_bytes += bytes_read; } while ((tot_bytes < stats.st_size) && (bytes_read > 0)); close(fd); if ((tot_bytes > stats.st_size) || (bytes_read < 0)) { res = FPGA_EXCEPTION; free(*buf); *buf = NULL; goto out; } *tot_bytes_ret = tot_bytes; out: return res; } fpga_result enum_max10_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; struct _fpga_token *_token = NULL; size_t i = 0; char *tmp = NULL; uint32_t tot_bytes = 0; enum fpga_metric_type metric_type = FPGA_METRIC_TYPE_POWER; char sysfspath[SYSFS_PATH_MAX] = { 0, }; char metrics_sysfs_path[SYSFS_PATH_MAX] = { 0, }; char metric_name[SYSFS_PATH_MAX] = { 0, }; char group_name[SYSFS_PATH_MAX] = { 0, }; char group_sysfs[SYSFS_PATH_MAX] = { 0, }; char qualifier_name[SYSFS_PATH_MAX] = { 0, }; char metric_units[SYSFS_PATH_MAX] = { 0, }; glob_t pglob; size_t len; if (_handle == NULL || vector == NULL || metric_num == NULL) { OPAE_ERR("Invalid Input parameters"); return FPGA_INVALID_PARAM; } _token = (struct _fpga_token *)_handle->token; if (_token == NULL) { OPAE_ERR("Invalid token within handle"); return FPGA_INVALID_PARAM; } // metrics group if (snprintf(sysfspath, sizeof(sysfspath), "%s/%s", _token->sysfspath, MAX10_SYSFS_PATH) < 0) { OPAE_ERR("snprintf failed"); return FPGA_EXCEPTION; } int gres = glob(sysfspath, GLOB_NOSORT, NULL, &pglob); if ((gres) || (1 != pglob.gl_pathc)) { OPAE_ERR("Failed pattern match %s: %s", sysfspath, strerror(errno)); globfree(&pglob); return FPGA_NOT_FOUND; } len = strnlen(pglob.gl_pathv[0], sizeof(group_sysfs) - 1); memcpy(group_sysfs, pglob.gl_pathv[0], len); group_sysfs[len] = '\0'; globfree(&pglob); // Enum sensors if (snprintf(sysfspath, sizeof(sysfspath), "%s/%s", _token->sysfspath, MAX10_SENSOR_SYSFS_PATH) < 0) { OPAE_ERR("snprintf failed"); return FPGA_EXCEPTION; } gres = glob(sysfspath, GLOB_NOSORT, NULL, &pglob); if (gres) { OPAE_ERR("Failed pattern match %s: %s", sysfspath, strerror(errno)); globfree(&pglob); return FPGA_NOT_FOUND; } // for loop for (i = 0; i < pglob.gl_pathc; i++) { // Sensor name result = read_sensor_sysfs_file(pglob.gl_pathv[i], SENSOR_SYSFS_NAME, (void **)&tmp, &tot_bytes); if (FPGA_OK != result || !tmp) { if (tmp) { free(tmp); } continue; } memset(&metric_name, 0, sizeof(metric_name)); len = strnlen(tmp, sizeof(metric_name) - 1); memcpy(metric_name, tmp, len); metric_name[len] = '\0'; if (tmp) { free(tmp); } // Metrics typw result = read_sensor_sysfs_file(pglob.gl_pathv[i], SENSOR_SYSFS_TYPE, (void **)&tmp, &tot_bytes); if (FPGA_OK != result || !tmp) { if (tmp) { free(tmp); continue; } } // Metrics group name and qualifier name if (tmp && (strstr(tmp, VOLTAGE) || strstr(tmp, CURRENT) || strstr(tmp, POWER))) { metric_type = FPGA_METRIC_TYPE_POWER; // group name len = strnlen(PWRMGMT, sizeof(group_name) - 1); memcpy(group_name, PWRMGMT, len); group_name[len] = '\0'; //qualifier name if (snprintf(qualifier_name, sizeof(qualifier_name), "%s:%s", PWRMGMT, metric_name) < 0) { OPAE_ERR("snprintf failed"); result = FPGA_EXCEPTION; if (tmp) free(tmp); goto out; } } else if (tmp && strstr(tmp, TEMPERATURE)) { metric_type = FPGA_METRIC_TYPE_THERMAL; // group name len = strnlen(THERLGMT, sizeof(group_name) - 1); memcpy(group_name, THERLGMT, len); group_name[len] = '\0'; //qualifier name if (snprintf(qualifier_name, sizeof(qualifier_name), "%s:%s", THERLGMT, metric_name) < 0) { OPAE_ERR("snprintf failed"); result = FPGA_EXCEPTION; if (tmp) free(tmp); goto out; } } else { printf("FPGA_METRIC_TYPE_UNKNOWN \n"); metric_type = FPGA_METRIC_TYPE_UNKNOWN; } if (tmp) { free(tmp); } // Metric Units if (strstr(metric_name, POWER)) { len = strnlen(POWER_UNITS, sizeof(metric_units) - 1); memcpy(metric_units, POWER_UNITS, len); metric_units[len] = '\0'; } else if (strstr(metric_name, VOLTAGE)) { len = strnlen(VOLTAGE_UNITS, sizeof(metric_units) - 1); memcpy(metric_units, VOLTAGE_UNITS, len); metric_units[len] = '\0'; } else if (strstr(metric_name, CURRENT)) { len = strnlen(CURRENT_UNITS, sizeof(metric_units) - 1); memcpy(metric_units, CURRENT_UNITS, len); metric_units[len] = '\0'; } else if (strstr(metric_name, TEMPERATURE)) { len = strnlen(TEMPERATURE_UNITS, sizeof(metric_units) - 1); memcpy(metric_units, TEMPERATURE_UNITS, len); metric_units[len] = '\0'; } else if (strstr(metric_name, CLOCK)) { len = strnlen(CLOCK_UNITS, sizeof(metric_units) - 1); memcpy(metric_units, CLOCK_UNITS, len); metric_units[len] = '\0'; } else { strncpy(metric_units, "N/A", 4); } // value sysfs path snprintf(metrics_sysfs_path, sizeof(metrics_sysfs_path), "%s/%s", pglob.gl_pathv[i], SENSOR_SYSFS_VALUE); result = add_metric_vector(vector, *metric_num, qualifier_name, group_name, group_sysfs, metric_name, metrics_sysfs_path, metric_units, FPGA_METRIC_DATATYPE_DOUBLE, metric_type, hw_type, 0); if (result != FPGA_OK) { OPAE_ERR("Failed to add metrics"); goto out; } *metric_num = *metric_num + 1; } // end for loop out: globfree(&pglob); return result; } fpga_result read_max10_value(struct _fpga_enum_metric *_fpga_enum_metric, double *dvalue) { fpga_result result = FPGA_OK; uint64_t value = 0; if (_fpga_enum_metric == NULL || dvalue == NULL) { OPAE_ERR("Invalid Input Parameters"); return FPGA_INVALID_PARAM; } result = sysfs_read_u64(_fpga_enum_metric->metric_sysfs, &value); if (result != FPGA_OK) { OPAE_MSG("Failed to read Metrics values"); return result; } *dvalue = ((double)value / MILLI); // Check for limits if (strstr(_fpga_enum_metric->metric_name, POWER)) { if (*dvalue < POWER_LOW_LIMIT || *dvalue > POWER_HIGH_LIMIT) result = FPGA_EXCEPTION; } else if (strstr(_fpga_enum_metric->metric_name, VOLTAGE)) { if (*dvalue < VOLTAMP_LOW_LIMIT || *dvalue > VOLTAMP_HIGH_LIMIT) result = FPGA_EXCEPTION; } else if (strstr(_fpga_enum_metric->metric_name, CURRENT)) { if (*dvalue < VOLTAMP_LOW_LIMIT || *dvalue > VOLTAMP_HIGH_LIMIT) result = FPGA_EXCEPTION; } else if (strstr(_fpga_enum_metric->metric_name, TEMPERATURE)) { if (*dvalue < THERMAL_LOW_LIMIT || *dvalue > THERMAL_HIGH_LIMIT) result = FPGA_EXCEPTION; } return result; }