73c54e1fd0
Also, don't return an error for empty sysfs files. The reserved memory page file will often have no lines. We don't want it to appear that this function is not supported if the file is empty. Change-Id: I1d28bb184ea587bb578fe71dd75adc2a812d09a8
2630 líneas
65 KiB
C++
Archivo Ejecutable
2630 líneas
65 KiB
C++
Archivo Ejecutable
/*
|
|
* =============================================================================
|
|
* The University of Illinois/NCSA
|
|
* Open Source License (NCSA)
|
|
*
|
|
* Copyright (c) 2017, Advanced Micro Devices, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* Developed by:
|
|
*
|
|
* AMD Research and AMD ROC Software Development
|
|
*
|
|
* Advanced Micro Devices, Inc.
|
|
*
|
|
* www.amd.com
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to
|
|
* deal with the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* - Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimers.
|
|
* - Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimers in
|
|
* the documentation and/or other materials provided with the distribution.
|
|
* - Neither the names of <Name of Development Group, Name of Institution>,
|
|
* nor the names of its contributors may be used to endorse or promote
|
|
* products derived from this Software without specific prior written
|
|
* permission.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS WITH THE SOFTWARE.
|
|
*
|
|
*/
|
|
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <sys/utsname.h>
|
|
#include <pthread.h>
|
|
|
|
#include <sstream>
|
|
#include <algorithm>
|
|
#include <cerrno>
|
|
#include <bitset>
|
|
#include <cstdint>
|
|
#include <unordered_map>
|
|
#include <map>
|
|
#include <fstream>
|
|
#include <iostream>
|
|
|
|
#include "rocm_smi/rocm_smi.h"
|
|
#include "rocm_smi/rocm_smi_main.h"
|
|
#include "rocm_smi/rocm_smi_device.h"
|
|
#include "rocm_smi/rocm_smi_utils.h"
|
|
#include "rocm_smi/rocm_smi_exception.h"
|
|
#include "rocm_smi/rocm_smi_counters.h"
|
|
#include "rocm_smi/rocm_smi_kfd.h"
|
|
|
|
#include "rocm_smi/rocm_smi64Config.h"
|
|
|
|
static const uint32_t kMaxOverdriveLevel = 20;
|
|
|
|
static rsmi_status_t handleException() {
|
|
try {
|
|
throw;
|
|
} catch (const std::bad_alloc& e) {
|
|
debug_print("RSMI exception: BadAlloc\n");
|
|
return RSMI_STATUS_OUT_OF_RESOURCES;
|
|
} catch (const amd::smi::rsmi_exception& e) {
|
|
debug_print("Exception caught: %s.\n", e.what());
|
|
return e.error_code();
|
|
return RSMI_STATUS_INTERNAL_EXCEPTION;
|
|
} catch (const std::exception& e) {
|
|
debug_print("Unhandled exception: %s\n", e.what());
|
|
assert(false && "Unhandled exception.");
|
|
return RSMI_STATUS_INTERNAL_EXCEPTION;
|
|
} catch (const std::nested_exception& e) {
|
|
debug_print("Callback threw, forwarding.\n");
|
|
e.rethrow_nested();
|
|
return RSMI_STATUS_INTERNAL_EXCEPTION;
|
|
} catch (...) {
|
|
assert(false && "Unhandled exception.");
|
|
abort();
|
|
return RSMI_STATUS_INTERNAL_EXCEPTION;
|
|
}
|
|
}
|
|
|
|
#define TRY try {
|
|
#define CATCH } catch (...) {return handleException();}
|
|
|
|
#define CHECK_DV_IND_RANGE \
|
|
amd::smi::RocmSMI& smi = amd::smi::RocmSMI::getInstance(); \
|
|
if (dv_ind >= smi.monitor_devices().size()) { \
|
|
return RSMI_STATUS_INVALID_ARGS; \
|
|
} \
|
|
|
|
#define GET_DEV_FROM_INDX \
|
|
CHECK_DV_IND_RANGE \
|
|
std::shared_ptr<amd::smi::Device> dev = smi.monitor_devices()[dv_ind]; \
|
|
assert(dev != nullptr);
|
|
|
|
#define REQUIRE_ROOT_ACCESS \
|
|
if (amd::smi::RocmSMI::getInstance().euid()) { \
|
|
return RSMI_STATUS_PERMISSION; \
|
|
}
|
|
|
|
#define DEVICE_MUTEX \
|
|
amd::smi::pthread_wrap _pw(*get_mutex(dv_ind)); \
|
|
amd::smi::ScopedPthread _lock(_pw);
|
|
|
|
static pthread_mutex_t *get_mutex(uint32_t dv_ind) {
|
|
amd::smi::RocmSMI& smi = amd::smi::RocmSMI::getInstance();
|
|
|
|
if (dv_ind >= smi.monitor_devices().size()) {
|
|
return nullptr;
|
|
}
|
|
std::shared_ptr<amd::smi::Device> dev = smi.monitor_devices()[dv_ind];
|
|
assert(dev != nullptr);
|
|
|
|
return dev->mutex();
|
|
}
|
|
|
|
static rsmi_status_t errno_to_rsmi_status(uint32_t err) {
|
|
switch (err) {
|
|
case 0: return RSMI_STATUS_SUCCESS;
|
|
case ESRCH: return RSMI_STATUS_NOT_FOUND;
|
|
case EACCES: return RSMI_STATUS_PERMISSION;
|
|
case EPERM:
|
|
case ENOENT: return RSMI_STATUS_NOT_SUPPORTED;
|
|
case EBADF:
|
|
case EISDIR: return RSMI_STATUS_FILE_ERROR;
|
|
case EINTR: return RSMI_STATUS_INTERRUPT;
|
|
case EIO: return RSMI_STATUS_UNEXPECTED_SIZE;
|
|
default: return RSMI_STATUS_UNKNOWN_ERROR;
|
|
}
|
|
}
|
|
|
|
static uint64_t get_multiplier_from_str(char units_char) {
|
|
uint32_t multiplier = 0;
|
|
|
|
switch (units_char) {
|
|
case 'G': // GT or GHz
|
|
multiplier = 1000000000;
|
|
break;
|
|
|
|
case 'M': // MT or MHz
|
|
multiplier = 1000000;
|
|
break;
|
|
|
|
case 'K': // KT or KHz
|
|
case 'V': // default unit for voltage is mV
|
|
multiplier = 1000;
|
|
break;
|
|
|
|
case 'T': // Transactions
|
|
case 'H': // Hertz
|
|
case 'm': // mV (we will make mV the default unit for voltage)
|
|
multiplier = 1;
|
|
break;
|
|
|
|
default:
|
|
assert(!"Unexpected units for frequency");
|
|
}
|
|
return multiplier;
|
|
}
|
|
|
|
/**
|
|
* Parse a string of the form:
|
|
* "<int index>: <int freq><freq. unit string> <|*>"
|
|
*/
|
|
static uint64_t freq_string_to_int(const std::vector<std::string> &freq_lines,
|
|
bool *is_curr, uint32_t lanes[], int i) {
|
|
std::istringstream fs(freq_lines[i]);
|
|
|
|
uint32_t ind;
|
|
long double freq;
|
|
std::string junk;
|
|
std::string units_str;
|
|
std::string star_str;
|
|
|
|
fs >> ind;
|
|
fs >> junk; // colon
|
|
fs >> freq;
|
|
fs >> units_str;
|
|
fs >> star_str;
|
|
|
|
if (is_curr != nullptr) {
|
|
if (freq_lines[i].find("*") != std::string::npos) {
|
|
*is_curr = true;
|
|
} else {
|
|
*is_curr = false;
|
|
}
|
|
}
|
|
uint32_t multiplier = get_multiplier_from_str(units_str[0]);
|
|
|
|
if (star_str[0] == 'x') {
|
|
assert(lanes != nullptr && "Lanes are provided but null lanes pointer");
|
|
if (lanes) {
|
|
lanes[i] = std::stoi(star_str.substr(1), nullptr);
|
|
}
|
|
}
|
|
return freq*multiplier;
|
|
}
|
|
|
|
static void freq_volt_string_to_point(std::string in_line,
|
|
rsmi_od_vddc_point_t *pt) {
|
|
std::istringstream fs_vlt(in_line);
|
|
|
|
assert(pt != nullptr);
|
|
|
|
uint32_t ind;
|
|
long double freq;
|
|
long double volts;
|
|
std::string junk;
|
|
std::string freq_units_str;
|
|
std::string volts_units_str;
|
|
|
|
fs_vlt >> ind;
|
|
fs_vlt >> junk; // colon
|
|
fs_vlt >> freq;
|
|
fs_vlt >> freq_units_str;
|
|
fs_vlt >> volts;
|
|
fs_vlt >> volts_units_str;
|
|
|
|
uint32_t multiplier = get_multiplier_from_str(freq_units_str[0]);
|
|
|
|
pt->frequency = freq*multiplier;
|
|
|
|
multiplier = get_multiplier_from_str(volts_units_str[0]);
|
|
pt->voltage = volts*multiplier;
|
|
|
|
return;
|
|
}
|
|
|
|
static void od_value_pair_str_to_range(std::string in_line, rsmi_range_t *rg) {
|
|
std::istringstream fs_rng(in_line);
|
|
|
|
assert(rg != nullptr);
|
|
|
|
std::string clk;
|
|
uint64_t lo;
|
|
uint64_t hi;
|
|
std::string lo_units_str;
|
|
std::string hi_units_str;
|
|
|
|
fs_rng >> clk; // This is clk + colon; e.g., "SCLK:"
|
|
fs_rng >> lo;
|
|
fs_rng >> lo_units_str;
|
|
fs_rng >> hi;
|
|
fs_rng >> hi_units_str;
|
|
|
|
uint32_t multiplier = get_multiplier_from_str(lo_units_str[0]);
|
|
|
|
rg->lower_bound = lo*multiplier;
|
|
|
|
multiplier = get_multiplier_from_str(hi_units_str[0]);
|
|
rg->upper_bound = hi*multiplier;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/**
|
|
* Parse a string of the form "<int index> <mode name string> <|*>"
|
|
*/
|
|
static rsmi_power_profile_preset_masks
|
|
power_prof_string_to_int(std::string pow_prof_line, bool *is_curr,
|
|
uint32_t *prof_ind) {
|
|
std::istringstream fs(pow_prof_line);
|
|
std::string mode;
|
|
size_t tmp;
|
|
|
|
rsmi_power_profile_preset_masks_t ret = RSMI_PWR_PROF_PRST_INVALID;
|
|
|
|
fs >> *prof_ind;
|
|
fs >> mode;
|
|
|
|
while (1) {
|
|
tmp = mode.find_last_of("* :");
|
|
if (tmp == std::string::npos) {
|
|
break;
|
|
}
|
|
mode = mode.substr(0, tmp);
|
|
}
|
|
|
|
if (is_curr != nullptr) {
|
|
if (pow_prof_line.find("*") != std::string::npos) {
|
|
*is_curr = true;
|
|
} else {
|
|
*is_curr = false;
|
|
}
|
|
}
|
|
|
|
const std::unordered_map<std::string, std::function<void()>> mode_map {
|
|
{"BOOTUP_DEFAULT", [&](){ ret = RSMI_PWR_PROF_PRST_BOOTUP_DEFAULT; }},
|
|
{"3D_FULL_SCREEN", [&](){ ret = RSMI_PWR_PROF_PRST_3D_FULL_SCR_MASK; }},
|
|
{"POWER_SAVING", [&](){ ret = RSMI_PWR_PROF_PRST_POWER_SAVING_MASK; }},
|
|
{"VIDEO", [&](){ ret = RSMI_PWR_PROF_PRST_VIDEO_MASK; }},
|
|
{"VR", [&](){ ret = RSMI_PWR_PROF_PRST_VR_MASK; }},
|
|
{"COMPUTE", [&](){ ret = RSMI_PWR_PROF_PRST_COMPUTE_MASK; }},
|
|
{"CUSTOM", [&](){ ret = RSMI_PWR_PROF_PRST_CUSTOM_MASK; }},
|
|
};
|
|
auto mode_iter = mode_map.find(mode);
|
|
|
|
if (mode_iter != mode_map.end()) {
|
|
mode_iter->second();
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static rsmi_status_t get_dev_value_str(amd::smi::DevInfoTypes type,
|
|
uint32_t dv_ind, std::string *val_str) {
|
|
GET_DEV_FROM_INDX
|
|
int ret = dev->readDevInfo(type, val_str);
|
|
|
|
return errno_to_rsmi_status(ret);
|
|
}
|
|
static rsmi_status_t get_dev_value_int(amd::smi::DevInfoTypes type,
|
|
uint32_t dv_ind, uint64_t *val_int) {
|
|
GET_DEV_FROM_INDX
|
|
int ret = dev->readDevInfo(type, val_int);
|
|
|
|
return errno_to_rsmi_status(ret);
|
|
}
|
|
|
|
static rsmi_status_t get_dev_value_line(amd::smi::DevInfoTypes type,
|
|
uint32_t dv_ind, std::string *val_str) {
|
|
GET_DEV_FROM_INDX
|
|
int ret = dev->readDevInfoLine(type, val_str);
|
|
|
|
return errno_to_rsmi_status(ret);
|
|
}
|
|
|
|
static rsmi_status_t set_dev_value(amd::smi::DevInfoTypes type,
|
|
uint32_t dv_ind, uint64_t val) {
|
|
GET_DEV_FROM_INDX
|
|
|
|
int ret = dev->writeDevInfo(type, val);
|
|
return errno_to_rsmi_status(ret);
|
|
}
|
|
|
|
static rsmi_status_t get_dev_mon_value(amd::smi::MonitorTypes type,
|
|
uint32_t dv_ind, uint32_t sensor_ind, int64_t *val) {
|
|
GET_DEV_FROM_INDX
|
|
|
|
assert(dev->monitor() != nullptr);
|
|
|
|
std::string val_str;
|
|
|
|
int ret = dev->monitor()->readMonitor(type, sensor_ind, &val_str);
|
|
if (ret) {
|
|
return errno_to_rsmi_status(ret);
|
|
}
|
|
|
|
*val = std::stoi(val_str);
|
|
|
|
return RSMI_STATUS_SUCCESS;
|
|
}
|
|
|
|
static rsmi_status_t get_dev_mon_value(amd::smi::MonitorTypes type,
|
|
uint32_t dv_ind, uint32_t sensor_ind, uint64_t *val) {
|
|
GET_DEV_FROM_INDX
|
|
|
|
assert(dev->monitor() != nullptr);
|
|
|
|
std::string val_str;
|
|
|
|
int ret = dev->monitor()->readMonitor(type, sensor_ind, &val_str);
|
|
if (ret) {
|
|
return errno_to_rsmi_status(ret);
|
|
}
|
|
|
|
*val = std::stoul(val_str);
|
|
|
|
return RSMI_STATUS_SUCCESS;
|
|
}
|
|
|
|
template <typename T>
|
|
static rsmi_status_t set_dev_mon_value(amd::smi::MonitorTypes type,
|
|
uint32_t dv_ind, int32_t sensor_ind, T val) {
|
|
GET_DEV_FROM_INDX
|
|
|
|
assert(dev->monitor() != nullptr);
|
|
|
|
int ret = dev->monitor()->writeMonitor(type, sensor_ind,
|
|
std::to_string(val));
|
|
|
|
return errno_to_rsmi_status(ret);
|
|
}
|
|
|
|
static rsmi_status_t get_power_mon_value(amd::smi::PowerMonTypes type,
|
|
uint32_t dv_ind, uint64_t *val) {
|
|
amd::smi::RocmSMI& smi = amd::smi::RocmSMI::getInstance();
|
|
|
|
if (dv_ind >= smi.monitor_devices().size() || val == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
uint32_t ret = smi.DiscoverAMDPowerMonitors();
|
|
if (ret == EACCES) {
|
|
return RSMI_STATUS_PERMISSION;
|
|
} else if (ret != 0) {
|
|
return RSMI_STATUS_FILE_ERROR;
|
|
}
|
|
|
|
std::shared_ptr<amd::smi::Device> dev = smi.monitor_devices()[dv_ind];
|
|
assert(dev != nullptr);
|
|
assert(dev->monitor() != nullptr);
|
|
|
|
ret = dev->power_monitor()->readPowerValue(type, val);
|
|
|
|
return errno_to_rsmi_status(ret);
|
|
}
|
|
|
|
static rsmi_status_t get_dev_value_vec(amd::smi::DevInfoTypes type,
|
|
uint32_t dv_ind, std::vector<std::string> *val_vec) {
|
|
GET_DEV_FROM_INDX
|
|
|
|
int ret = dev->readDevInfo(type, val_vec);
|
|
return errno_to_rsmi_status(ret);
|
|
}
|
|
static bool is_power_of_2(uint64_t n) {
|
|
return n && !(n & (n - 1));
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_init(uint64_t flags) {
|
|
TRY
|
|
|
|
amd::smi::RocmSMI& smi = amd::smi::RocmSMI::getInstance();
|
|
smi.Initialize(flags);
|
|
|
|
return RSMI_STATUS_SUCCESS;
|
|
CATCH
|
|
}
|
|
|
|
// A call to rsmi_shut_down is not technically necessary at this time,
|
|
// but may be in the future.
|
|
rsmi_status_t
|
|
rsmi_shut_down(void) {
|
|
TRY
|
|
|
|
amd::smi::RocmSMI& smi = amd::smi::RocmSMI::getInstance();
|
|
|
|
smi.Cleanup();
|
|
|
|
return RSMI_STATUS_SUCCESS;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_num_monitor_devices(uint32_t *num_devices) {
|
|
TRY
|
|
if (num_devices == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
amd::smi::RocmSMI& smi = amd::smi::RocmSMI::getInstance();
|
|
|
|
*num_devices = smi.monitor_devices().size();
|
|
return RSMI_STATUS_SUCCESS;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t rsmi_dev_ecc_enabled_get(uint32_t dv_ind,
|
|
uint64_t *enabled_mask) {
|
|
TRY
|
|
rsmi_status_t ret;
|
|
|
|
if (enabled_mask == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
DEVICE_MUTEX
|
|
|
|
std::vector<std::string> val_vec;
|
|
|
|
ret = get_dev_value_vec(amd::smi::kDevErrCntFeatures, dv_ind, &val_vec);
|
|
|
|
if (ret == RSMI_STATUS_FILE_ERROR) {
|
|
return RSMI_STATUS_NOT_SUPPORTED;
|
|
}
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
std::string junk;
|
|
std::istringstream fs1(val_vec[0]);
|
|
std::string mask_str;
|
|
|
|
fs1 >> junk;
|
|
assert(junk == "feature");
|
|
fs1 >> junk;
|
|
assert(junk == "mask:");
|
|
fs1 >> mask_str;
|
|
|
|
errno = 0;
|
|
*enabled_mask = strtoul(mask_str.c_str(), nullptr, 16);
|
|
assert(errno == 0);
|
|
|
|
return errno_to_rsmi_status(errno);
|
|
|
|
CATCH
|
|
}
|
|
|
|
|
|
static const char *kRSMIGpuBlkUMCFName = "umc";
|
|
static const char *kRSMIGpuBlkSDMAFName = "sdma";
|
|
static const char *kRSMIGpuBlkGFXFName = "gfx";
|
|
|
|
static const std::map<rsmi_gpu_block_t, const char *> kRocmSMIBlockMap = {
|
|
{RSMI_GPU_BLOCK_UMC, kRSMIGpuBlkUMCFName},
|
|
{RSMI_GPU_BLOCK_SDMA, kRSMIGpuBlkSDMAFName},
|
|
{RSMI_GPU_BLOCK_GFX, kRSMIGpuBlkGFXFName},
|
|
};
|
|
static_assert(RSMI_GPU_BLOCK_LAST == RSMI_GPU_BLOCK_GFX,
|
|
"rsmi_gpu_block_t and/or above name map need to be updated"
|
|
" and then this assert");
|
|
|
|
static const std::map<std::string, rsmi_ras_err_state_t> kRocmSMIStateMap = {
|
|
{"none", RSMI_RAS_ERR_STATE_NONE},
|
|
{"disabled", RSMI_RAS_ERR_STATE_DISABLED},
|
|
{"parity", RSMI_RAS_ERR_STATE_PARITY},
|
|
{"single_correctable", RSMI_RAS_ERR_STATE_SING_C},
|
|
{"multi_uncorrectable", RSMI_RAS_ERR_STATE_MULT_UC},
|
|
{"poison", RSMI_RAS_ERR_STATE_POISON},
|
|
};
|
|
static_assert(RSMI_RAS_ERR_STATE_LAST == RSMI_RAS_ERR_STATE_POISON,
|
|
"rsmi_gpu_block_t and/or above name map need to be updated"
|
|
" and then this assert");
|
|
|
|
rsmi_status_t rsmi_dev_ecc_status_get(uint32_t dv_ind, rsmi_gpu_block_t block,
|
|
rsmi_ras_err_state_t *state) {
|
|
TRY
|
|
if (state == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
if (!is_power_of_2(block)) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
rsmi_status_t ret;
|
|
std::vector<std::string> val_vec;
|
|
|
|
DEVICE_MUTEX
|
|
|
|
ret = get_dev_value_vec(amd::smi::kDevErrCntFeatures, dv_ind, &val_vec);
|
|
|
|
if (ret == RSMI_STATUS_FILE_ERROR) {
|
|
return RSMI_STATUS_NOT_SUPPORTED;
|
|
}
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
std::string blk_line;
|
|
std::string search_str = kRocmSMIBlockMap.at(block);
|
|
std::string state_str;
|
|
|
|
search_str += ":";
|
|
|
|
for (uint32_t i = 1; i < val_vec.size(); ++i) { // Skip features line
|
|
std::istringstream fs1(val_vec[i]);
|
|
|
|
fs1 >> blk_line;
|
|
|
|
if (blk_line == search_str) {
|
|
fs1 >> state_str;
|
|
assert(kRocmSMIStateMap.count(state_str));
|
|
*state = kRocmSMIStateMap.at(state_str);
|
|
return RSMI_STATUS_SUCCESS;
|
|
}
|
|
}
|
|
assert(!"Block was not found");
|
|
*state = RSMI_RAS_ERR_STATE_INVALID;
|
|
return RSMI_STATUS_NOT_FOUND;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_ecc_count_get(uint32_t dv_ind, rsmi_gpu_block_t block,
|
|
rsmi_error_count_t *ec) {
|
|
std::vector<std::string> val_vec;
|
|
rsmi_status_t ret;
|
|
|
|
TRY
|
|
if (ec == nullptr || block > RSMI_GPU_BLOCK_LAST) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
amd::smi::DevInfoTypes type;
|
|
switch (block) {
|
|
case RSMI_GPU_BLOCK_UMC:
|
|
type = amd::smi::kDevErrCntUMC;
|
|
break;
|
|
|
|
case RSMI_GPU_BLOCK_SDMA:
|
|
type = amd::smi::kDevErrCntSDMA;
|
|
break;
|
|
|
|
case RSMI_GPU_BLOCK_GFX:
|
|
type = amd::smi::kDevErrCntGFX;
|
|
break;
|
|
|
|
default:
|
|
return RSMI_STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
DEVICE_MUTEX
|
|
|
|
ret = get_dev_value_vec(type, dv_ind, &val_vec);
|
|
|
|
if (ret == RSMI_STATUS_FILE_ERROR) {
|
|
return RSMI_STATUS_NOT_SUPPORTED;
|
|
}
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
assert(val_vec.size() == 2);
|
|
|
|
std::string junk;
|
|
std::istringstream fs1(val_vec[0]);
|
|
|
|
fs1 >> junk;
|
|
assert(junk == "ue:");
|
|
fs1 >> ec->uncorrectable_err;
|
|
|
|
std::istringstream fs2(val_vec[1]);
|
|
|
|
fs2 >> junk;
|
|
assert(junk == "ce:");
|
|
fs2 >> ec->correctable_err;
|
|
|
|
return ret;
|
|
CATCH
|
|
}
|
|
rsmi_status_t
|
|
rsmi_dev_pci_id_get(uint32_t dv_ind, uint64_t *bdfid) {
|
|
TRY
|
|
|
|
if (bdfid == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
GET_DEV_FROM_INDX
|
|
|
|
DEVICE_MUTEX
|
|
|
|
*bdfid = dev->get_bdfid();
|
|
return RSMI_STATUS_SUCCESS;
|
|
CATCH
|
|
}
|
|
|
|
static rsmi_status_t
|
|
get_id(uint32_t dv_ind, amd::smi::DevInfoTypes typ, uint16_t *id) {
|
|
TRY
|
|
std::string val_str;
|
|
|
|
DEVICE_MUTEX
|
|
|
|
rsmi_status_t ret = get_dev_value_str(typ, dv_ind, &val_str);
|
|
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
errno = 0;
|
|
*id = strtoul(val_str.c_str(), nullptr, 16);
|
|
assert(errno == 0);
|
|
|
|
return errno_to_rsmi_status(errno);
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_id_get(uint32_t dv_ind, uint16_t *id) {
|
|
DEVICE_MUTEX
|
|
return get_id(dv_ind, amd::smi::kDevDevID, id);
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_subsystem_id_get(uint32_t dv_ind, uint16_t *id) {
|
|
DEVICE_MUTEX
|
|
return get_id(dv_ind, amd::smi::kDevSubSysDevID, id);
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_vendor_id_get(uint32_t dv_ind, uint16_t *id) {
|
|
DEVICE_MUTEX
|
|
return get_id(dv_ind, amd::smi::kDevVendorID, id);
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_subsystem_vendor_id_get(uint32_t dv_ind, uint16_t *id) {
|
|
DEVICE_MUTEX
|
|
return get_id(dv_ind, amd::smi::kDevSubSysVendorID, id);
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_perf_level_get(uint32_t dv_ind, rsmi_dev_perf_level_t *perf) {
|
|
TRY
|
|
std::string val_str;
|
|
DEVICE_MUTEX
|
|
|
|
rsmi_status_t ret = get_dev_value_str(amd::smi::kDevPerfLevel, dv_ind,
|
|
&val_str);
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
*perf = amd::smi::Device::perfLvlStrToEnum(val_str);
|
|
|
|
return ret;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_overdrive_level_get(uint32_t dv_ind, uint32_t *od) {
|
|
TRY
|
|
std::string val_str;
|
|
DEVICE_MUTEX
|
|
|
|
rsmi_status_t ret = get_dev_value_str(amd::smi::kDevOverDriveLevel, dv_ind,
|
|
&val_str);
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
errno = 0;
|
|
*od = strtoul(val_str.c_str(), nullptr, 10);
|
|
assert(errno == 0);
|
|
|
|
return RSMI_STATUS_SUCCESS;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_overdrive_level_set(int32_t dv_ind, uint32_t od) {
|
|
TRY
|
|
REQUIRE_ROOT_ACCESS
|
|
|
|
if (od > kMaxOverdriveLevel) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
DEVICE_MUTEX
|
|
return set_dev_value(amd::smi::kDevOverDriveLevel, dv_ind, od);
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_perf_level_set(int32_t dv_ind, rsmi_dev_perf_level_t perf_level) {
|
|
TRY
|
|
REQUIRE_ROOT_ACCESS
|
|
|
|
if (perf_level > RSMI_DEV_PERF_LEVEL_LAST) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
DEVICE_MUTEX
|
|
return set_dev_value(amd::smi::kDevPerfLevel, dv_ind, perf_level);
|
|
CATCH
|
|
}
|
|
|
|
static rsmi_status_t get_frequencies(amd::smi::DevInfoTypes type,
|
|
uint32_t dv_ind, rsmi_frequencies_t *f, uint32_t *lanes = nullptr) {
|
|
TRY
|
|
std::vector<std::string> val_vec;
|
|
rsmi_status_t ret;
|
|
|
|
if (f == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
ret = get_dev_value_vec(type, dv_ind, &val_vec);
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
assert(val_vec.size() <= RSMI_MAX_NUM_FREQUENCIES);
|
|
|
|
if (val_vec.size() == 0) {
|
|
return RSMI_STATUS_NOT_YET_IMPLEMENTED;
|
|
}
|
|
|
|
f->num_supported = val_vec.size();
|
|
bool current = false;
|
|
f->current = RSMI_MAX_NUM_FREQUENCIES + 1; // init to an invalid value
|
|
|
|
for (uint32_t i = 0; i < f->num_supported; ++i) {
|
|
f->frequency[i] = freq_string_to_int(val_vec, ¤t, lanes, i);
|
|
|
|
// Our assumption is that frequencies are read in from lowest to highest.
|
|
// Check that that is true.
|
|
if (i > 0) {
|
|
assert(f->frequency[i-1] <= f->frequency[i]);
|
|
}
|
|
if (current) {
|
|
// Should only be 1 current frequency
|
|
assert(f->current == RSMI_MAX_NUM_FREQUENCIES + 1);
|
|
f->current = i;
|
|
}
|
|
}
|
|
|
|
// Some older drivers will not have the current frequency set
|
|
// assert(f->current < f->num_supported);
|
|
if (f->current >= f->num_supported) {
|
|
return RSMI_STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
return RSMI_STATUS_SUCCESS;
|
|
CATCH
|
|
}
|
|
|
|
static rsmi_status_t get_power_profiles(uint32_t dv_ind,
|
|
rsmi_power_profile_status_t *p,
|
|
std::map<rsmi_power_profile_preset_masks_t, uint32_t> *ind_map) {
|
|
TRY
|
|
std::vector<std::string> val_vec;
|
|
rsmi_status_t ret;
|
|
|
|
if (p == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
ret = get_dev_value_vec(amd::smi::kDevPowerProfileMode, dv_ind, &val_vec);
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
assert(val_vec.size() <= RSMI_MAX_NUM_POWER_PROFILES);
|
|
|
|
p->num_profiles = val_vec.size() - 1; // -1 for the header line
|
|
bool current = false;
|
|
p->current = RSMI_PWR_PROF_PRST_INVALID; // init to an invalid value
|
|
p->available_profiles = 0;
|
|
|
|
rsmi_power_profile_preset_masks_t prof;
|
|
uint32_t prof_ind;
|
|
|
|
for (uint32_t i = 1; i < val_vec.size(); ++i) {
|
|
prof = power_prof_string_to_int(val_vec[i], ¤t, &prof_ind);
|
|
|
|
if (prof == RSMI_PWR_PROF_PRST_INVALID) {
|
|
continue;
|
|
}
|
|
|
|
if (ind_map != nullptr) {
|
|
(*ind_map)[prof] = prof_ind;
|
|
}
|
|
|
|
p->available_profiles |= prof;
|
|
if (current) {
|
|
// Should only be 1 current profile
|
|
assert(p->current == RSMI_PWR_PROF_PRST_INVALID);
|
|
p->current = prof;
|
|
}
|
|
}
|
|
|
|
assert(p->current != RSMI_PWR_PROF_PRST_INVALID);
|
|
return RSMI_STATUS_SUCCESS;
|
|
CATCH
|
|
}
|
|
|
|
/* We expect the format of the the pp_od_clk_voltage file to look like this:
|
|
OD_SCLK:
|
|
0: 872Mhz
|
|
1: 1837Mhz
|
|
OD_MCLK:
|
|
1: 1000Mhz
|
|
OD_VDDC_CURVE:
|
|
0: 872Mhz 736mV
|
|
1: 1354Mhz 860mV
|
|
2: 1837Mhz 1186mV
|
|
OD_RANGE:
|
|
SCLK: 872Mhz 1900Mhz
|
|
MCLK: 168Mhz 1200Mhz
|
|
VDDC_CURVE_SCLK[0]: 872Mhz 1900Mhz
|
|
VDDC_CURVE_VOLT[0]: 737mV 1137mV
|
|
VDDC_CURVE_SCLK[1]: 872Mhz 1900Mhz
|
|
VDDC_CURVE_VOLT[1]: 737mV 1137mV
|
|
VDDC_CURVE_SCLK[2]: 872Mhz 1900Mhz
|
|
VDDC_CURVE_VOLT[2]: 737mV 1137mV
|
|
*/
|
|
static const uint32_t kOD_SCLK_label_array_index = 0;
|
|
static const uint32_t kOD_MCLK_label_array_index =
|
|
kOD_SCLK_label_array_index + 3;
|
|
static const uint32_t kOD_VDDC_CURVE_label_array_index =
|
|
kOD_MCLK_label_array_index + 2;
|
|
static const uint32_t kOD_OD_RANGE_label_array_index =
|
|
kOD_VDDC_CURVE_label_array_index + 4;
|
|
static const uint32_t kOD_VDDC_CURVE_start_index =
|
|
kOD_OD_RANGE_label_array_index + 3;
|
|
static const uint32_t kOD_VDDC_CURVE_num_lines =
|
|
kOD_VDDC_CURVE_start_index + 4;
|
|
|
|
static rsmi_status_t get_od_clk_volt_info(uint32_t dv_ind,
|
|
rsmi_od_volt_freq_data_t *p) {
|
|
TRY
|
|
std::vector<std::string> val_vec;
|
|
rsmi_status_t ret;
|
|
|
|
assert(p != nullptr);
|
|
|
|
ret = get_dev_value_vec(amd::smi::kDevPowerODVoltage, dv_ind, &val_vec);
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
// This is a work-around to handle systems where kDevPowerODVoltage is not
|
|
// fully supported yet.
|
|
if (val_vec.size() < 2) {
|
|
return RSMI_STATUS_NOT_YET_IMPLEMENTED;
|
|
}
|
|
|
|
assert(val_vec[kOD_SCLK_label_array_index] == "OD_SCLK:");
|
|
|
|
p->curr_sclk_range.lower_bound = freq_string_to_int(val_vec, nullptr,
|
|
nullptr, kOD_SCLK_label_array_index + 1);
|
|
p->curr_sclk_range.upper_bound = freq_string_to_int(val_vec, nullptr,
|
|
nullptr, kOD_SCLK_label_array_index + 2);
|
|
|
|
|
|
// The condition below indicates old style format, which is not supported
|
|
if (val_vec[kOD_MCLK_label_array_index] != "OD_MCLK:") {
|
|
return RSMI_STATUS_NOT_YET_IMPLEMENTED;
|
|
}
|
|
p->curr_mclk_range.lower_bound = 0;
|
|
|
|
p->curr_mclk_range.upper_bound = freq_string_to_int(val_vec, nullptr,
|
|
nullptr, kOD_MCLK_label_array_index + 1);
|
|
|
|
assert(val_vec[kOD_VDDC_CURVE_label_array_index] == "OD_VDDC_CURVE:");
|
|
|
|
uint32_t tmp = kOD_VDDC_CURVE_label_array_index + 1;
|
|
for (uint32_t i = 0; i < RSMI_NUM_VOLTAGE_CURVE_POINTS; ++i) {
|
|
freq_volt_string_to_point(val_vec[tmp + i], &(p->curve.vc_points[i]));
|
|
}
|
|
|
|
assert(val_vec[kOD_OD_RANGE_label_array_index] == "OD_RANGE:");
|
|
od_value_pair_str_to_range(val_vec[kOD_OD_RANGE_label_array_index + 1],
|
|
&(p->sclk_freq_limits));
|
|
od_value_pair_str_to_range(val_vec[kOD_OD_RANGE_label_array_index + 2],
|
|
&(p->mclk_freq_limits));
|
|
|
|
assert((val_vec.size() - kOD_VDDC_CURVE_start_index)%2 == 0);
|
|
p->num_regions = (val_vec.size() - kOD_VDDC_CURVE_start_index) / 2;
|
|
|
|
return RSMI_STATUS_SUCCESS;
|
|
CATCH
|
|
}
|
|
|
|
static void get_vc_region(uint32_t start_ind,
|
|
std::vector<std::string> *val_vec, rsmi_freq_volt_region_t *p) {
|
|
assert(p != nullptr);
|
|
assert(val_vec != nullptr);
|
|
// There must be at least 1 region to read in
|
|
assert(val_vec->size() >= kOD_OD_RANGE_label_array_index + 2);
|
|
assert((*val_vec)[kOD_OD_RANGE_label_array_index] == "OD_RANGE:");
|
|
|
|
od_value_pair_str_to_range((*val_vec)[start_ind], &p->freq_range);
|
|
od_value_pair_str_to_range((*val_vec)[start_ind + 1], &p->volt_range);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* num_regions [inout] on calling, the number of regions requested to be read
|
|
* in. At completion, the number of regions actually read in
|
|
*
|
|
* p [inout] point to pre-allocated memory where function will write region
|
|
* values. Caller must make sure there is enough space for at least
|
|
* *num_regions regions. On
|
|
*/
|
|
static rsmi_status_t get_od_clk_volt_curve_regions(uint32_t dv_ind,
|
|
uint32_t *num_regions, rsmi_freq_volt_region_t *p) {
|
|
TRY
|
|
std::vector<std::string> val_vec;
|
|
rsmi_status_t ret;
|
|
|
|
assert(num_regions != nullptr);
|
|
assert(p != nullptr);
|
|
|
|
ret = get_dev_value_vec(amd::smi::kDevPowerODVoltage, dv_ind, &val_vec);
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
// This is a work-around to handle systems where kDevPowerODVoltage is not
|
|
// fully supported yet.
|
|
if (val_vec.size() < 2) {
|
|
return RSMI_STATUS_NOT_YET_IMPLEMENTED;
|
|
}
|
|
|
|
uint32_t val_vec_size = val_vec.size();
|
|
assert((val_vec_size - kOD_VDDC_CURVE_start_index) > 0);
|
|
assert((val_vec_size - kOD_VDDC_CURVE_start_index)%2 == 0);
|
|
*num_regions = std::min((val_vec_size - kOD_VDDC_CURVE_start_index) / 2,
|
|
*num_regions);
|
|
|
|
for (uint32_t i=0; i < *num_regions; ++i) {
|
|
get_vc_region(kOD_VDDC_CURVE_start_index + i*2, &val_vec, p + i);
|
|
}
|
|
|
|
return RSMI_STATUS_SUCCESS;
|
|
CATCH
|
|
}
|
|
static rsmi_status_t set_power_profile(uint32_t dv_ind,
|
|
rsmi_power_profile_preset_masks_t profile) {
|
|
TRY
|
|
|
|
rsmi_status_t ret;
|
|
rsmi_power_profile_status_t avail_profiles =
|
|
{0, RSMI_PWR_PROF_PRST_INVALID, 0};
|
|
|
|
// Determine if the provided profile is valid
|
|
if (!is_power_of_2(profile)) {
|
|
return RSMI_STATUS_INPUT_OUT_OF_BOUNDS;
|
|
}
|
|
|
|
std::map<rsmi_power_profile_preset_masks_t, uint32_t> ind_map;
|
|
ret = get_power_profiles(dv_ind, &avail_profiles, &ind_map);
|
|
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
if (!(profile & avail_profiles.available_profiles)) {
|
|
return RSMI_STATUS_INPUT_OUT_OF_BOUNDS;
|
|
}
|
|
assert(ind_map.find(profile) != ind_map.end());
|
|
|
|
// Set perf. level to manual so that we can then set the power profile
|
|
ret = rsmi_dev_perf_level_set(dv_ind, RSMI_DEV_PERF_LEVEL_MANUAL);
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
// Write the new profile
|
|
ret = set_dev_value(amd::smi::kDevPowerProfileMode, dv_ind,
|
|
ind_map[profile]);
|
|
|
|
return ret;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_gpu_clk_freq_get(uint32_t dv_ind, rsmi_clk_type_t clk_type,
|
|
rsmi_frequencies_t *f) {
|
|
TRY
|
|
amd::smi::DevInfoTypes dev_type;
|
|
|
|
switch (clk_type) {
|
|
case RSMI_CLK_TYPE_SYS:
|
|
dev_type = amd::smi::kDevGPUSClk;
|
|
break;
|
|
case RSMI_CLK_TYPE_MEM:
|
|
dev_type = amd::smi::kDevGPUMClk;
|
|
break;
|
|
case RSMI_CLK_TYPE_DF:
|
|
dev_type = amd::smi::kDevFClk;
|
|
break;
|
|
case RSMI_CLK_TYPE_DCEF:
|
|
dev_type = amd::smi::kDevDCEFClk;
|
|
break;
|
|
case RSMI_CLK_TYPE_SOC:
|
|
dev_type = amd::smi::kDevSOCClk;
|
|
break;
|
|
default:
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
DEVICE_MUTEX
|
|
|
|
return get_frequencies(dev_type, dv_ind, f);
|
|
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_firmware_version_get(uint32_t dv_ind, rsmi_fw_block_t block,
|
|
uint64_t *fw_version) {
|
|
rsmi_status_t ret;
|
|
|
|
if (fw_version == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
TRY
|
|
GET_DEV_FROM_INDX
|
|
|
|
std::string val_str;
|
|
amd::smi::DevInfoTypes dev_type;
|
|
|
|
switch (block) {
|
|
case RSMI_FW_BLOCK_ASD:
|
|
dev_type = amd::smi::kDevFwVersionAsd;
|
|
break;
|
|
case RSMI_FW_BLOCK_CE:
|
|
dev_type = amd::smi::kDevFwVersionCe;
|
|
break;
|
|
case RSMI_FW_BLOCK_DMCU:
|
|
dev_type = amd::smi::kDevFwVersionDmcu;
|
|
break;
|
|
case RSMI_FW_BLOCK_MC:
|
|
dev_type = amd::smi::kDevFwVersionMc;
|
|
break;
|
|
case RSMI_FW_BLOCK_ME:
|
|
dev_type = amd::smi::kDevFwVersionMe;
|
|
break;
|
|
case RSMI_FW_BLOCK_MEC:
|
|
dev_type = amd::smi::kDevFwVersionMec;
|
|
break;
|
|
case RSMI_FW_BLOCK_MEC2:
|
|
dev_type = amd::smi::kDevFwVersionMec2;
|
|
break;
|
|
case RSMI_FW_BLOCK_PFP:
|
|
dev_type = amd::smi::kDevFwVersionPfp;
|
|
break;
|
|
case RSMI_FW_BLOCK_RLC:
|
|
dev_type = amd::smi::kDevFwVersionRlc;
|
|
break;
|
|
case RSMI_FW_BLOCK_RLC_SRLC:
|
|
dev_type = amd::smi::kDevFwVersionRlcSrlc;
|
|
break;
|
|
case RSMI_FW_BLOCK_RLC_SRLG:
|
|
dev_type = amd::smi::kDevFwVersionRlcSrlg;
|
|
break;
|
|
case RSMI_FW_BLOCK_RLC_SRLS:
|
|
dev_type = amd::smi::kDevFwVersionRlcSrls;
|
|
break;
|
|
case RSMI_FW_BLOCK_SDMA:
|
|
dev_type = amd::smi::kDevFwVersionSdma;
|
|
break;
|
|
case RSMI_FW_BLOCK_SDMA2:
|
|
dev_type = amd::smi::kDevFwVersionSdma2;
|
|
break;
|
|
case RSMI_FW_BLOCK_SMC:
|
|
dev_type = amd::smi::kDevFwVersionSmc;
|
|
break;
|
|
case RSMI_FW_BLOCK_SOS:
|
|
dev_type = amd::smi::kDevFwVersionSos;
|
|
break;
|
|
case RSMI_FW_BLOCK_TA_RAS:
|
|
dev_type = amd::smi::kDevFwVersionTaRas;
|
|
break;
|
|
case RSMI_FW_BLOCK_TA_XGMI:
|
|
dev_type = amd::smi::kDevFwVersionTaXgmi;
|
|
break;
|
|
case RSMI_FW_BLOCK_UVD:
|
|
dev_type = amd::smi::kDevFwVersionUvd;
|
|
break;
|
|
case RSMI_FW_BLOCK_VCE:
|
|
dev_type = amd::smi::kDevFwVersionVce;
|
|
break;
|
|
case RSMI_FW_BLOCK_VCN:
|
|
dev_type = amd::smi::kDevFwVersionVcn;
|
|
break;
|
|
}
|
|
ret = get_dev_value_int(dev_type, dv_ind, fw_version);
|
|
if (ret != 0) {
|
|
return errno_to_rsmi_status(ret);
|
|
}
|
|
|
|
return RSMI_STATUS_SUCCESS;
|
|
CATCH
|
|
}
|
|
|
|
static std::string bitfield_to_freq_string(uint64_t bitf,
|
|
uint32_t num_supported) {
|
|
std::string bf_str("");
|
|
std::bitset<RSMI_MAX_NUM_FREQUENCIES> bs(bitf);
|
|
|
|
for (uint32_t i = 0; i < num_supported; ++i) {
|
|
if (bs[i]) {
|
|
bf_str += std::to_string(i);
|
|
bf_str += " ";
|
|
}
|
|
}
|
|
return bf_str;
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_gpu_clk_freq_set(uint32_t dv_ind,
|
|
rsmi_clk_type_t clk_type, uint64_t freq_bitmask) {
|
|
rsmi_status_t ret;
|
|
rsmi_frequencies_t freqs;
|
|
|
|
TRY
|
|
REQUIRE_ROOT_ACCESS
|
|
DEVICE_MUTEX
|
|
|
|
ret = rsmi_dev_gpu_clk_freq_get(dv_ind, clk_type, &freqs);
|
|
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
assert(freqs.num_supported <= RSMI_MAX_NUM_FREQUENCIES);
|
|
|
|
amd::smi::RocmSMI& smi = amd::smi::RocmSMI::getInstance();
|
|
|
|
// Above call to rsmi_dev_get_gpu_clk_freq should have emitted an error if
|
|
// assert below is not true
|
|
assert(dv_ind < smi.monitor_devices().size());
|
|
|
|
std::string freq_enable_str =
|
|
bitfield_to_freq_string(freq_bitmask, freqs.num_supported);
|
|
|
|
|
|
std::shared_ptr<amd::smi::Device> dev = smi.monitor_devices()[dv_ind];
|
|
assert(dev != nullptr);
|
|
|
|
ret = rsmi_dev_perf_level_set(dv_ind, RSMI_DEV_PERF_LEVEL_MANUAL);
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
int ret_i;
|
|
amd::smi::DevInfoTypes dev_type;
|
|
|
|
switch (clk_type) {
|
|
case RSMI_CLK_TYPE_SYS:
|
|
dev_type = amd::smi::kDevGPUSClk;
|
|
break;
|
|
case RSMI_CLK_TYPE_MEM:
|
|
dev_type = amd::smi::kDevGPUMClk;
|
|
break;
|
|
case RSMI_CLK_TYPE_DF:
|
|
dev_type = amd::smi::kDevFClk;
|
|
break;
|
|
case RSMI_CLK_TYPE_SOC:
|
|
dev_type = amd::smi::kDevSOCClk;
|
|
break;
|
|
case RSMI_CLK_TYPE_DCEF:
|
|
dev_type = amd::smi::kDevDCEFClk;
|
|
break;
|
|
default:
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
ret_i = dev->writeDevInfo(dev_type, freq_enable_str);
|
|
return errno_to_rsmi_status(ret_i);
|
|
|
|
CATCH
|
|
}
|
|
static std::vector<std::string> pci_name_files = {
|
|
"/usr/share/misc/pci.ids",
|
|
"/usr/share/hwdata/pci.ids",
|
|
"/usr/share/pci.ids",
|
|
"/var/lib/pciutils/pci.ids"
|
|
};
|
|
|
|
|
|
enum eNameStrType {
|
|
NAME_STR_VENDOR = 0,
|
|
NAME_STR_DEVICE,
|
|
NAME_STR_SUBSYS
|
|
};
|
|
|
|
static std::string
|
|
get_id_name_str_from_line(uint64_t id, std::string ln,
|
|
std::istringstream *ln_str) {
|
|
std::string token1;
|
|
std::string ret_str;
|
|
|
|
assert(ln_str != nullptr);
|
|
|
|
*ln_str >> token1;
|
|
if (std::stoul(token1, nullptr, 16) == id) {
|
|
int64_t pos = ln_str->tellg();
|
|
|
|
pos = ln.find_first_not_of("\t ", pos);
|
|
ret_str = ln.substr(pos);
|
|
}
|
|
return ret_str;
|
|
}
|
|
|
|
static rsmi_status_t get_backup_name(uint16_t id, char *name, size_t len) {
|
|
std::string name_str;
|
|
|
|
name_str += "0x";
|
|
|
|
std::stringstream strm;
|
|
strm << std::hex << id;
|
|
name_str += strm.str();
|
|
|
|
name[0] = '\0';
|
|
size_t ct = name_str.copy(name, len);
|
|
|
|
name[std::min(len - 1, ct)] = '\0';
|
|
|
|
if (len < (name_str.size() + 1)) {
|
|
return RSMI_STATUS_INSUFFICIENT_SIZE;
|
|
}
|
|
return RSMI_STATUS_SUCCESS;
|
|
}
|
|
|
|
// Parse pci.ids files. Comment lines have # in first column. Otherwise,
|
|
// Syntax:
|
|
// vendor vendor_name
|
|
// device device_name <-- single tab
|
|
// subvendor subdevice subsystem_name <-- two tabs
|
|
static rsmi_status_t get_dev_name_from_id(uint32_t dv_ind, char *name,
|
|
size_t len, eNameStrType typ) {
|
|
std::string ln;
|
|
std::string token1;
|
|
rsmi_status_t ret;
|
|
uint16_t device_id;
|
|
uint16_t vendor_id;
|
|
uint16_t subsys_vend_id;
|
|
uint16_t subsys_id;
|
|
bool found_device_vendor = false;
|
|
std::string val_str;
|
|
|
|
assert(name != nullptr);
|
|
assert(len > 0);
|
|
|
|
name[0] = '\0';
|
|
|
|
ret = rsmi_dev_vendor_id_get(dv_ind, &vendor_id);
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
if (typ != NAME_STR_VENDOR) {
|
|
ret = rsmi_dev_id_get(dv_ind, &device_id);
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
if (typ != NAME_STR_DEVICE) {
|
|
ret = rsmi_dev_subsystem_vendor_id_get(dv_ind, &subsys_vend_id);
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
ret = rsmi_dev_subsystem_id_get(dv_ind, &subsys_id);
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (auto fl : pci_name_files) {
|
|
std::ifstream id_file_strm(fl);
|
|
|
|
while (std::getline(id_file_strm, ln)) {
|
|
std::istringstream ln_str(ln);
|
|
// parse line
|
|
if (ln[0] == '#' || ln.size() == 0) {
|
|
continue;
|
|
}
|
|
|
|
if (ln[0] == '\t') {
|
|
if (found_device_vendor) {
|
|
if (ln[1] == '\t') {
|
|
// This is a subsystem line
|
|
if (typ == NAME_STR_SUBSYS) {
|
|
val_str = get_id_name_str_from_line(subsys_vend_id, ln, &ln_str);
|
|
|
|
if (val_str.size() > 0) {
|
|
// We've chopped the subsys_vend ID, now we need to get the
|
|
// subsys description
|
|
val_str = get_id_name_str_from_line(subsys_id, ln, &ln_str);
|
|
|
|
if (val_str.size() > 0) {
|
|
break;
|
|
} else {
|
|
val_str.clear();
|
|
}
|
|
}
|
|
}
|
|
} else if (typ == NAME_STR_DEVICE) { // ln[1] != '\t'
|
|
// This is a device line
|
|
val_str = get_id_name_str_from_line(device_id, ln, &ln_str);
|
|
|
|
if (val_str.size() > 0) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} else { // ln[0] != '\t'; Vendor line
|
|
if (found_device_vendor) {
|
|
assert(typ != NAME_STR_VENDOR);
|
|
// We already found the vendor but didn't find the device or
|
|
// subsystem we were looking for, so bail out.
|
|
val_str.clear();
|
|
|
|
return get_backup_name(typ == NAME_STR_DEVICE ?
|
|
device_id : subsys_id, name, len);
|
|
}
|
|
|
|
val_str = get_id_name_str_from_line(vendor_id, ln, &ln_str);
|
|
|
|
if (val_str.size() > 0) {
|
|
if (typ == NAME_STR_VENDOR) {
|
|
break;
|
|
} else {
|
|
val_str.clear();
|
|
found_device_vendor = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (val_str.size() > 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (val_str.size() == 0) {
|
|
// We should have already returned if we were looking for
|
|
// device or subdivce
|
|
assert(typ == NAME_STR_VENDOR);
|
|
return get_backup_name(vendor_id, name, len);
|
|
}
|
|
size_t ct = val_str.copy(name, len);
|
|
|
|
name[std::min(len - 1, ct)] = '\0';
|
|
|
|
if (len < (val_str.size() + 1)) {
|
|
return RSMI_STATUS_INSUFFICIENT_SIZE;
|
|
}
|
|
|
|
return RSMI_STATUS_SUCCESS;
|
|
}
|
|
|
|
static rsmi_status_t
|
|
get_dev_drm_render_minor(uint32_t dv_ind, uint32_t *minor) {
|
|
GET_DEV_FROM_INDX
|
|
|
|
*minor = dev->drm_render_minor();
|
|
if (*minor)
|
|
return RSMI_STATUS_SUCCESS;
|
|
|
|
return RSMI_STATUS_INIT_ERROR;
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_name_get(uint32_t dv_ind, char *name, size_t len) {
|
|
rsmi_status_t ret;
|
|
|
|
TRY
|
|
if (name == nullptr || len == 0) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
DEVICE_MUTEX
|
|
|
|
ret = get_dev_name_from_id(dv_ind, name, len, NAME_STR_DEVICE);
|
|
|
|
return ret;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_subsystem_name_get(uint32_t dv_ind, char *name, size_t len) {
|
|
rsmi_status_t ret;
|
|
|
|
TRY
|
|
if (name == nullptr || len == 0) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
DEVICE_MUTEX
|
|
|
|
ret = get_dev_name_from_id(dv_ind, name, len, NAME_STR_SUBSYS);
|
|
return ret;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_drm_render_minor_get(uint32_t dv_ind, uint32_t *minor) {
|
|
rsmi_status_t ret;
|
|
|
|
TRY
|
|
if (minor == nullptr)
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
|
|
DEVICE_MUTEX
|
|
ret = get_dev_drm_render_minor(dv_ind, minor);
|
|
return ret;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_vendor_name_get(uint32_t dv_ind, char *name, size_t len) {
|
|
rsmi_status_t ret;
|
|
|
|
TRY
|
|
if (name == nullptr || len == 0) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
DEVICE_MUTEX
|
|
ret = get_dev_name_from_id(dv_ind, name, len, NAME_STR_VENDOR);
|
|
return ret;
|
|
CATCH
|
|
}
|
|
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_pci_bandwidth_get(uint32_t dv_ind, rsmi_pcie_bandwidth_t *b) {
|
|
TRY
|
|
assert(b != nullptr);
|
|
|
|
if (b == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
DEVICE_MUTEX
|
|
|
|
return get_frequencies(amd::smi::kDevPCIEClk, dv_ind,
|
|
&b->transfer_rate, b->lanes);
|
|
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_pci_bandwidth_set(uint32_t dv_ind, uint64_t bw_bitmask) {
|
|
rsmi_status_t ret;
|
|
rsmi_pcie_bandwidth_t bws;
|
|
|
|
TRY
|
|
REQUIRE_ROOT_ACCESS
|
|
DEVICE_MUTEX
|
|
ret = rsmi_dev_pci_bandwidth_get(dv_ind, &bws);
|
|
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
assert(bws.transfer_rate.num_supported <= RSMI_MAX_NUM_FREQUENCIES);
|
|
|
|
amd::smi::RocmSMI& smi = amd::smi::RocmSMI::getInstance();
|
|
|
|
// Above call to rsmi_dev_pci_bandwidth_get() should have emitted an error
|
|
// if assert below is not true
|
|
assert(dv_ind < smi.monitor_devices().size());
|
|
|
|
std::string freq_enable_str =
|
|
bitfield_to_freq_string(bw_bitmask, bws.transfer_rate.num_supported);
|
|
|
|
std::shared_ptr<amd::smi::Device> dev = smi.monitor_devices()[dv_ind];
|
|
assert(dev != nullptr);
|
|
|
|
ret = rsmi_dev_perf_level_set(dv_ind, RSMI_DEV_PERF_LEVEL_MANUAL);
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
uint32_t ret_i;
|
|
ret_i = dev->writeDevInfo(amd::smi::kDevPCIEClk, freq_enable_str);
|
|
|
|
return errno_to_rsmi_status(ret_i);
|
|
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_pci_throughput_get(uint32_t dv_ind, uint64_t *sent,
|
|
uint64_t *received, uint64_t *max_pkt_sz) {
|
|
TRY
|
|
rsmi_status_t ret;
|
|
|
|
std::string val_str;
|
|
|
|
DEVICE_MUTEX
|
|
|
|
ret = get_dev_value_line(amd::smi::kDevPCIEThruPut, dv_ind, &val_str);
|
|
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
std::istringstream fs_rng(val_str);
|
|
|
|
if (sent) {
|
|
fs_rng >> *sent;
|
|
}
|
|
if (received) {
|
|
fs_rng >> *received;
|
|
}
|
|
if (max_pkt_sz) {
|
|
fs_rng >> *max_pkt_sz;
|
|
}
|
|
|
|
return RSMI_STATUS_SUCCESS;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_temp_metric_get(uint32_t dv_ind, uint32_t sensor_type,
|
|
rsmi_temperature_metric_t metric, int64_t *temperature) {
|
|
TRY
|
|
|
|
if (temperature == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
rsmi_status_t ret;
|
|
amd::smi::MonitorTypes mon_type;
|
|
|
|
switch (metric) {
|
|
case RSMI_TEMP_CURRENT:
|
|
mon_type = amd::smi::kMonTemp;
|
|
break;
|
|
case RSMI_TEMP_MAX:
|
|
mon_type = amd::smi::kMonTempMax;
|
|
break;
|
|
case RSMI_TEMP_MIN:
|
|
mon_type = amd::smi::kMonTempMin;
|
|
break;
|
|
case RSMI_TEMP_MAX_HYST:
|
|
mon_type = amd::smi::kMonTempMaxHyst;
|
|
break;
|
|
case RSMI_TEMP_MIN_HYST:
|
|
mon_type = amd::smi::kMonTempMinHyst;
|
|
break;
|
|
case RSMI_TEMP_CRITICAL:
|
|
mon_type = amd::smi::kMonTempCritical;
|
|
break;
|
|
case RSMI_TEMP_CRITICAL_HYST:
|
|
mon_type = amd::smi::kMonTempCriticalHyst;
|
|
break;
|
|
case RSMI_TEMP_EMERGENCY:
|
|
mon_type = amd::smi::kMonTempEmergency;
|
|
break;
|
|
case RSMI_TEMP_EMERGENCY_HYST:
|
|
mon_type = amd::smi::kMonTempEmergencyHyst;
|
|
break;
|
|
case RSMI_TEMP_CRIT_MIN:
|
|
mon_type = amd::smi::kMonTempCritMin;
|
|
break;
|
|
case RSMI_TEMP_CRIT_MIN_HYST:
|
|
mon_type = amd::smi::kMonTempCritMinHyst;
|
|
break;
|
|
case RSMI_TEMP_OFFSET:
|
|
mon_type = amd::smi::kMonTempOffset;
|
|
break;
|
|
case RSMI_TEMP_LOWEST:
|
|
mon_type = amd::smi::kMonTempLowest;
|
|
break;
|
|
case RSMI_TEMP_HIGHEST:
|
|
mon_type = amd::smi::kMonTempHighest;
|
|
break;
|
|
default:
|
|
mon_type = amd::smi::kMonInvalid;
|
|
}
|
|
|
|
DEVICE_MUTEX
|
|
|
|
GET_DEV_FROM_INDX
|
|
|
|
assert(dev->monitor() != nullptr);
|
|
std::shared_ptr<amd::smi::Monitor> m = dev->monitor();
|
|
|
|
uint32_t err = m->setSensorLabelMap();
|
|
if (err) {
|
|
return errno_to_rsmi_status(err);
|
|
}
|
|
|
|
uint32_t sensor_index =
|
|
m->getSensorIndex(static_cast<rsmi_temperature_type_t>(sensor_type));
|
|
ret = get_dev_mon_value(mon_type, dv_ind, sensor_index, temperature);
|
|
|
|
return ret;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_fan_speed_get(uint32_t dv_ind, uint32_t sensor_ind, int64_t *speed) {
|
|
TRY
|
|
|
|
if (speed == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
rsmi_status_t ret;
|
|
|
|
++sensor_ind; // fan sysfs files have 1-based indices
|
|
|
|
DEVICE_MUTEX
|
|
|
|
ret = get_dev_mon_value(amd::smi::kMonFanSpeed, dv_ind, sensor_ind, speed);
|
|
|
|
return ret;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_fan_rpms_get(uint32_t dv_ind, uint32_t sensor_ind, int64_t *speed) {
|
|
TRY
|
|
|
|
if (speed == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
++sensor_ind; // fan sysfs files have 1-based indices
|
|
|
|
rsmi_status_t ret;
|
|
|
|
DEVICE_MUTEX
|
|
|
|
ret = get_dev_mon_value(amd::smi::kMonFanRPMs, dv_ind, sensor_ind, speed);
|
|
|
|
return ret;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_fan_reset(uint32_t dv_ind, uint32_t sensor_ind) {
|
|
TRY
|
|
|
|
rsmi_status_t ret;
|
|
|
|
++sensor_ind; // fan sysfs files have 1-based indices
|
|
|
|
DEVICE_MUTEX
|
|
|
|
ret = set_dev_mon_value<uint64_t>(amd::smi::kMonFanCntrlEnable,
|
|
dv_ind, sensor_ind, 2);
|
|
|
|
return ret;
|
|
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_fan_speed_set(uint32_t dv_ind, uint32_t sensor_ind, uint64_t speed) {
|
|
TRY
|
|
|
|
rsmi_status_t ret;
|
|
uint64_t max_speed;
|
|
|
|
REQUIRE_ROOT_ACCESS
|
|
DEVICE_MUTEX
|
|
|
|
ret = rsmi_dev_fan_speed_max_get(dv_ind, sensor_ind, &max_speed);
|
|
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
if (speed > max_speed) {
|
|
return RSMI_STATUS_INPUT_OUT_OF_BOUNDS;
|
|
}
|
|
|
|
++sensor_ind; // fan sysfs files have 1-based indices
|
|
|
|
// First need to set fan mode (pwm1_enable) to 1 (aka, "manual")
|
|
ret = set_dev_mon_value<uint64_t>(amd::smi::kMonFanCntrlEnable, dv_ind,
|
|
sensor_ind, 1);
|
|
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
ret = set_dev_mon_value<uint64_t>(amd::smi::kMonFanSpeed, dv_ind,
|
|
sensor_ind, speed);
|
|
|
|
return ret;
|
|
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_fan_speed_max_get(uint32_t dv_ind, uint32_t sensor_ind,
|
|
uint64_t *max_speed) {
|
|
TRY
|
|
|
|
if (max_speed == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
++sensor_ind; // fan sysfs files have 1-based indices
|
|
|
|
rsmi_status_t ret;
|
|
|
|
DEVICE_MUTEX
|
|
|
|
ret = get_dev_mon_value(amd::smi::kMonMaxFanSpeed, dv_ind, sensor_ind,
|
|
reinterpret_cast<int64_t *>(max_speed));
|
|
|
|
return ret;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_od_volt_info_get(uint32_t dv_ind, rsmi_od_volt_freq_data_t *odv) {
|
|
TRY
|
|
DEVICE_MUTEX
|
|
|
|
rsmi_status_t ret = get_od_clk_volt_info(dv_ind, odv);
|
|
|
|
return ret;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t rsmi_dev_od_volt_curve_regions_get(uint32_t dv_ind,
|
|
uint32_t *num_regions, rsmi_freq_volt_region_t *buffer) {
|
|
TRY
|
|
|
|
if (buffer == nullptr || num_regions == nullptr || *num_regions == 0) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
DEVICE_MUTEX
|
|
rsmi_status_t ret = get_od_clk_volt_curve_regions(dv_ind, num_regions,
|
|
buffer);
|
|
return ret;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_power_max_get(uint32_t dv_ind, uint32_t sensor_ind, uint64_t *power) {
|
|
TRY
|
|
|
|
if (power == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
(void)sensor_ind; // Not used yet
|
|
// ++sensor_ind; // power sysfs files have 1-based indices
|
|
|
|
rsmi_status_t ret;
|
|
|
|
DEVICE_MUTEX
|
|
ret = get_power_mon_value(amd::smi::kPowerMaxGPUPower, dv_ind, power);
|
|
|
|
return ret;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_power_ave_get(uint32_t dv_ind, uint32_t sensor_ind, uint64_t *power) {
|
|
TRY
|
|
|
|
if (power == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
++sensor_ind; // power sysfs files have 1-based indices
|
|
|
|
rsmi_status_t ret;
|
|
|
|
DEVICE_MUTEX
|
|
ret = get_dev_mon_value(amd::smi::kMonPowerAve, dv_ind, sensor_ind, power);
|
|
|
|
return ret;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_power_cap_get(uint32_t dv_ind, uint32_t sensor_ind, uint64_t *cap) {
|
|
TRY
|
|
|
|
if (cap == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
++sensor_ind; // power sysfs files have 1-based indices
|
|
|
|
rsmi_status_t ret;
|
|
|
|
DEVICE_MUTEX
|
|
ret = get_dev_mon_value(amd::smi::kMonPowerCap, dv_ind, sensor_ind, cap);
|
|
|
|
return ret;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_power_cap_range_get(uint32_t dv_ind, uint32_t sensor_ind,
|
|
uint64_t *max, uint64_t *min) {
|
|
TRY
|
|
|
|
if (max == nullptr || min == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
++sensor_ind; // power sysfs files have 1-based indices
|
|
|
|
rsmi_status_t ret;
|
|
|
|
DEVICE_MUTEX
|
|
ret = get_dev_mon_value(amd::smi::kMonPowerCapMax, dv_ind, sensor_ind, max);
|
|
|
|
if (ret == RSMI_STATUS_SUCCESS) {
|
|
ret = get_dev_mon_value(amd::smi::kMonPowerCapMin, dv_ind,
|
|
sensor_ind, min);
|
|
}
|
|
|
|
return ret;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_power_cap_set(uint32_t dv_ind, uint32_t sensor_ind, uint64_t cap) {
|
|
TRY
|
|
rsmi_status_t ret;
|
|
uint64_t min, max;
|
|
|
|
REQUIRE_ROOT_ACCESS
|
|
DEVICE_MUTEX
|
|
|
|
ret = rsmi_dev_power_cap_range_get(dv_ind, sensor_ind, &max, &min);
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
// All rsmi_* calls that use sensor_ind should use the 0-based value,
|
|
// so increment this after the call above.
|
|
++sensor_ind; // power sysfs files have 1-based indices
|
|
|
|
if (cap > max || cap < min) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
ret = set_dev_mon_value<uint64_t>(amd::smi::kMonPowerCap, dv_ind,
|
|
sensor_ind, cap);
|
|
|
|
return ret;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_power_profile_presets_get(uint32_t dv_ind, uint32_t sensor_ind,
|
|
rsmi_power_profile_status_t *status) {
|
|
TRY
|
|
|
|
++sensor_ind; // power sysfs files have 1-based indices
|
|
|
|
DEVICE_MUTEX
|
|
rsmi_status_t ret = get_power_profiles(dv_ind, status, nullptr);
|
|
return ret;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_power_profile_set(uint32_t dv_ind, uint32_t sensor_ind,
|
|
rsmi_power_profile_preset_masks_t profile) {
|
|
TRY
|
|
REQUIRE_ROOT_ACCESS
|
|
|
|
++sensor_ind; // power sysfs files have 1-based indices
|
|
|
|
DEVICE_MUTEX
|
|
rsmi_status_t ret = set_power_profile(dv_ind, profile);
|
|
return ret;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_memory_total_get(uint32_t dv_ind, rsmi_memory_type_t mem_type,
|
|
uint64_t *total) {
|
|
TRY
|
|
rsmi_status_t ret;
|
|
amd::smi::DevInfoTypes mem_type_file;
|
|
|
|
if (total == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
switch (mem_type) {
|
|
case RSMI_MEM_TYPE_GTT:
|
|
mem_type_file = amd::smi::kDevMemTotGTT;
|
|
break;
|
|
|
|
case RSMI_MEM_TYPE_VIS_VRAM:
|
|
mem_type_file = amd::smi::kDevMemTotVisVRAM;
|
|
break;
|
|
|
|
case RSMI_MEM_TYPE_VRAM:
|
|
mem_type_file = amd::smi::kDevMemTotVRAM;
|
|
break;
|
|
|
|
default:
|
|
assert(!"Unexpected memory type");
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
DEVICE_MUTEX
|
|
ret = get_dev_value_int(mem_type_file, dv_ind, total);
|
|
|
|
return ret;
|
|
CATCH
|
|
}
|
|
rsmi_status_t
|
|
rsmi_dev_memory_usage_get(uint32_t dv_ind, rsmi_memory_type_t mem_type,
|
|
uint64_t *used) {
|
|
TRY
|
|
rsmi_status_t ret;
|
|
amd::smi::DevInfoTypes mem_type_file;
|
|
|
|
if (used == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
switch (mem_type) {
|
|
case RSMI_MEM_TYPE_GTT:
|
|
mem_type_file = amd::smi::kDevMemUsedGTT;
|
|
break;
|
|
|
|
case RSMI_MEM_TYPE_VIS_VRAM:
|
|
mem_type_file = amd::smi::kDevMemUsedVisVRAM;
|
|
break;
|
|
|
|
case RSMI_MEM_TYPE_VRAM:
|
|
mem_type_file = amd::smi::kDevMemUsedVRAM;
|
|
break;
|
|
|
|
default:
|
|
assert(!"Unexpected memory type");
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
DEVICE_MUTEX
|
|
ret = get_dev_value_int(mem_type_file, dv_ind, used);
|
|
|
|
return ret;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_memory_busy_percent_get(uint32_t dv_ind, uint32_t *busy_percent) {
|
|
TRY
|
|
rsmi_status_t ret;
|
|
|
|
if (busy_percent == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
uint64_t tmp_util = 0;
|
|
|
|
DEVICE_MUTEX
|
|
ret = get_dev_value_int(amd::smi::kDevMemBusyPercent, dv_ind, &tmp_util);
|
|
|
|
*busy_percent = static_cast<uint32_t>(tmp_util);
|
|
return ret;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_status_string(rsmi_status_t status, const char **status_string) {
|
|
TRY
|
|
if (status_string == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
const size_t status_u = static_cast<size_t>(status);
|
|
switch (status_u) {
|
|
case RSMI_STATUS_SUCCESS:
|
|
*status_string = "RSMI_STATUS_SUCCESS: The function has been executed"
|
|
" successfully.";
|
|
break;
|
|
|
|
case RSMI_STATUS_INVALID_ARGS:
|
|
*status_string =
|
|
"RSMI_STATUS_INVALID_ARGS: The provided arguments do not"
|
|
" meet the preconditions required for calling this function.";
|
|
break;
|
|
|
|
case RSMI_STATUS_NOT_SUPPORTED:
|
|
*status_string = "RSMI_STATUS_NOT_SUPPORTED: This function is not"
|
|
" supported in the current environment.";
|
|
break;
|
|
|
|
case RSMI_STATUS_FILE_ERROR:
|
|
*status_string =
|
|
"RSMI_STATUS_FILE_ERROR: There was an error in finding or"
|
|
" opening a file or directory. The operation may not be supported by "
|
|
"this Linux kernel version.";
|
|
break;
|
|
|
|
case RSMI_STATUS_PERMISSION:
|
|
*status_string = "RSMI_STATUS_PERMISSION: The user ID of the calling"
|
|
" process does not have sufficient permission to execute a command."
|
|
" Often this is fixed by running as root (sudo).";
|
|
break;
|
|
|
|
case RSMI_STATUS_OUT_OF_RESOURCES:
|
|
*status_string = "Unable to acquire memory or other resource";
|
|
break;
|
|
|
|
case RSMI_STATUS_INTERNAL_EXCEPTION:
|
|
*status_string = "An internal exception was caught";
|
|
break;
|
|
|
|
case RSMI_STATUS_INPUT_OUT_OF_BOUNDS:
|
|
*status_string = "The provided input is out of allowable or safe range";
|
|
break;
|
|
|
|
case RSMI_STATUS_INIT_ERROR:
|
|
*status_string = "An error occurred during initialization, during "
|
|
"monitor discovery or when when initializing internal data structures";
|
|
break;
|
|
|
|
case RSMI_STATUS_NOT_YET_IMPLEMENTED:
|
|
*status_string = "The called function has not been implemented in this "
|
|
"system for this device type";
|
|
break;
|
|
|
|
case RSMI_STATUS_NOT_FOUND:
|
|
*status_string = "An item required to complete the call was not found";
|
|
break;
|
|
|
|
case RSMI_STATUS_INSUFFICIENT_SIZE:
|
|
*status_string = "Not enough resources were available to fully execute"
|
|
" the call";
|
|
break;
|
|
|
|
case RSMI_STATUS_UNKNOWN_ERROR:
|
|
*status_string = "An unknown error prevented the call from completing"
|
|
" successfully";
|
|
break;
|
|
|
|
case RSMI_STATUS_INTERRUPT:
|
|
*status_string = "An interrupt occurred while executing the function";
|
|
break;
|
|
|
|
default:
|
|
*status_string = "An unknown error occurred";
|
|
return RSMI_STATUS_UNKNOWN_ERROR;
|
|
}
|
|
return RSMI_STATUS_SUCCESS;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_busy_percent_get(uint32_t dv_ind, uint32_t *busy_percent) {
|
|
TRY
|
|
std::string val_str;
|
|
|
|
DEVICE_MUTEX
|
|
rsmi_status_t ret = get_dev_value_str(amd::smi::kDevUsage, dv_ind,
|
|
&val_str);
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
errno = 0;
|
|
*busy_percent = strtoul(val_str.c_str(), nullptr, 10);
|
|
assert(errno == 0);
|
|
|
|
return RSMI_STATUS_SUCCESS;
|
|
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_vbios_version_get(uint32_t dv_ind, char *vbios, uint32_t len) {
|
|
if (vbios == nullptr || len == 0) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
TRY
|
|
GET_DEV_FROM_INDX
|
|
std::string val_str;
|
|
|
|
DEVICE_MUTEX
|
|
int ret = dev->readDevInfo(amd::smi::kDevVBiosVer, &val_str);
|
|
|
|
if (ret != 0) {
|
|
return errno_to_rsmi_status(ret);
|
|
}
|
|
|
|
uint32_t ln = val_str.copy(vbios, len);
|
|
|
|
vbios[std::min(len - 1, ln)] = '\0';
|
|
|
|
if (len < (val_str.size() + 1)) {
|
|
return RSMI_STATUS_INSUFFICIENT_SIZE;
|
|
}
|
|
return RSMI_STATUS_SUCCESS;
|
|
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_version_get(rsmi_version_t *version) {
|
|
TRY
|
|
|
|
if (version == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
version->major = rocm_smi_VERSION_MAJOR;
|
|
version->minor = rocm_smi_VERSION_MINOR;
|
|
version->patch = rocm_smi_VERSION_PATCH;
|
|
version->build = rocm_smi_VERSION_BUILD;
|
|
|
|
return RSMI_STATUS_SUCCESS;
|
|
|
|
CATCH
|
|
}
|
|
|
|
static const char *kROCmDriverVersionPath = "/sys/module/amdgpu/version";
|
|
|
|
rsmi_status_t
|
|
rsmi_version_str_get(rsmi_sw_component_t component, char *ver_str,
|
|
uint32_t len) {
|
|
if (ver_str == nullptr || len == 0) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
TRY
|
|
|
|
int err;
|
|
std::string val_str;
|
|
std::string ver_path;
|
|
|
|
switch (component) {
|
|
case RSMI_SW_COMP_DRIVER:
|
|
ver_path = kROCmDriverVersionPath;
|
|
break;
|
|
|
|
default:
|
|
assert(!"Unexpected component type provided");
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
err = amd::smi::ReadSysfsStr(ver_path, &val_str);
|
|
|
|
if (err != 0) {
|
|
struct utsname buf;
|
|
err = uname(&buf);
|
|
|
|
if (err != 0) {
|
|
return errno_to_rsmi_status(err);
|
|
}
|
|
|
|
val_str = buf.release;
|
|
}
|
|
|
|
uint32_t ln = val_str.copy(ver_str, len);
|
|
|
|
ver_str[std::min(len - 1, ln)] = '\0';
|
|
|
|
if (len < (val_str.size() + 1)) {
|
|
return RSMI_STATUS_INSUFFICIENT_SIZE;
|
|
}
|
|
return RSMI_STATUS_SUCCESS;
|
|
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t rsmi_dev_serial_number_get(uint32_t dv_ind,
|
|
char *serial_num, uint32_t len) {
|
|
if (serial_num == nullptr || len == 0) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
TRY
|
|
|
|
std::string val_str;
|
|
rsmi_status_t ret = get_dev_value_str(amd::smi::kDevSerialNumber,
|
|
dv_ind, &val_str);
|
|
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
uint32_t ln = val_str.copy(serial_num, len);
|
|
|
|
serial_num[std::min(len - 1, ln)] = '\0';
|
|
|
|
if (len < (val_str.size() + 1)) {
|
|
return RSMI_STATUS_INSUFFICIENT_SIZE;
|
|
}
|
|
return RSMI_STATUS_SUCCESS;
|
|
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_pci_replay_counter_get(uint32_t dv_ind, uint64_t *counter) {
|
|
TRY
|
|
DEVICE_MUTEX
|
|
rsmi_status_t ret;
|
|
|
|
ret = get_dev_value_int(amd::smi::kDevPCIEReplayCount, dv_ind, counter);
|
|
return ret;
|
|
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_unique_id_get(uint32_t dv_ind, uint64_t *unique_id) {
|
|
TRY
|
|
DEVICE_MUTEX
|
|
rsmi_status_t ret;
|
|
|
|
if (unique_id == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
ret = get_dev_value_int(amd::smi::kDevUniqueId, dv_ind, unique_id);
|
|
return ret;
|
|
|
|
CATCH
|
|
}
|
|
rsmi_status_t
|
|
rsmi_dev_counter_create(uint32_t dv_ind, rsmi_event_type_t type,
|
|
rsmi_event_handle_t *evnt_handle) {
|
|
TRY
|
|
DEVICE_MUTEX
|
|
REQUIRE_ROOT_ACCESS
|
|
CHECK_DV_IND_RANGE
|
|
|
|
if (evnt_handle == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
if (type < RSMI_EVNT_FIRST || type > RSMI_EVNT_LAST) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
*evnt_handle = reinterpret_cast<uintptr_t>(
|
|
new amd::smi::evt::Event(type, dv_ind));
|
|
|
|
if (evnt_handle == nullptr) {
|
|
return RSMI_STATUS_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
return RSMI_STATUS_SUCCESS;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_counter_destroy(rsmi_event_handle_t evnt_handle) {
|
|
TRY
|
|
|
|
if (evnt_handle == 0) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
amd::smi::evt::Event *evt =
|
|
reinterpret_cast<amd::smi::evt::Event *>(evnt_handle);
|
|
uint32_t dv_ind = evt->dev_ind();
|
|
DEVICE_MUTEX
|
|
REQUIRE_ROOT_ACCESS
|
|
|
|
delete evt;
|
|
return RSMI_STATUS_SUCCESS;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_counter_control(rsmi_event_handle_t evt_handle,
|
|
rsmi_counter_command_t cmd, void *cmd_args) {
|
|
TRY
|
|
|
|
amd::smi::evt::Event *evt =
|
|
reinterpret_cast<amd::smi::evt::Event *>(evt_handle);
|
|
amd::smi::pthread_wrap _pw(*get_mutex(evt->dev_ind()));
|
|
amd::smi::ScopedPthread _lock(_pw);
|
|
|
|
REQUIRE_ROOT_ACCESS
|
|
|
|
uint32_t ret;
|
|
|
|
// This is for future command args. This would work in conjunction with a
|
|
// new function to set perf attributes.
|
|
(void) cmd_args;
|
|
|
|
if (evt_handle == 0) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
switch (cmd) {
|
|
case RSMI_CNTR_CMD_START:
|
|
ret = evt->startCounter();
|
|
break;
|
|
|
|
case RSMI_CNTR_CMD_STOP:
|
|
ret = evt->stopCounter();
|
|
break;
|
|
|
|
default:
|
|
assert(!"Unexpected perf counter command");
|
|
}
|
|
return errno_to_rsmi_status(ret);
|
|
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_counter_read(rsmi_event_handle_t evt_handle,
|
|
rsmi_counter_value_t *value) {
|
|
TRY
|
|
|
|
if (value == nullptr || evt_handle == 0) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
amd::smi::evt::Event *evt =
|
|
reinterpret_cast<amd::smi::evt::Event *>(evt_handle);
|
|
|
|
uint32_t dv_ind = evt->dev_ind();
|
|
DEVICE_MUTEX
|
|
REQUIRE_ROOT_ACCESS
|
|
|
|
uint32_t ret;
|
|
|
|
ret = evt->getValue(value);
|
|
|
|
return errno_to_rsmi_status(ret);
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_counter_available_counters_get(uint32_t dv_ind,
|
|
rsmi_event_group_t grp, uint32_t *available) {
|
|
rsmi_status_t ret;
|
|
|
|
TRY
|
|
if (available == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
DEVICE_MUTEX
|
|
uint64_t val;
|
|
|
|
switch (grp) {
|
|
case RSMI_EVNT_GRP_XGMI:
|
|
ret = get_dev_value_int(amd::smi::kDevDFCountersAvailable, dv_ind, &val);
|
|
assert(val < UINT32_MAX);
|
|
*available = static_cast<uint32_t>(val);
|
|
break;
|
|
|
|
default:
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
return ret;
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_counter_group_supported(uint32_t dv_ind, rsmi_event_group_t group) {
|
|
TRY
|
|
DEVICE_MUTEX
|
|
GET_DEV_FROM_INDX
|
|
|
|
amd::smi::evt::dev_evt_grp_set_t *grp = dev->supported_event_groups();
|
|
|
|
if (grp->find(group) == grp->end()) {
|
|
return RSMI_STATUS_NOT_SUPPORTED;
|
|
} else {
|
|
return RSMI_STATUS_SUCCESS;
|
|
}
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_compute_process_info_get(rsmi_process_info_t *procs,
|
|
uint32_t *num_items) {
|
|
TRY
|
|
|
|
if (num_items == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
uint32_t procs_found = 0;
|
|
|
|
int err = amd::smi:: GetProcessInfo(procs, *num_items, &procs_found);
|
|
|
|
if (err) {
|
|
return errno_to_rsmi_status(err);
|
|
}
|
|
|
|
if (procs && *num_items < procs_found) {
|
|
return RSMI_STATUS_INSUFFICIENT_SIZE;
|
|
}
|
|
if (procs == nullptr || *num_items > procs_found) {
|
|
*num_items = procs_found;
|
|
}
|
|
|
|
return RSMI_STATUS_SUCCESS;
|
|
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_memory_reserved_pages_get(uint32_t dv_ind, uint32_t *num_pages,
|
|
rsmi_retired_page_record_t *records) {
|
|
TRY
|
|
|
|
rsmi_status_t ret;
|
|
|
|
if (num_pages == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
std::vector<std::string> val_vec;
|
|
|
|
ret = get_dev_value_vec(amd::smi::kDevMemPageBad, dv_ind, &val_vec);
|
|
|
|
if (ret == RSMI_STATUS_FILE_ERROR) {
|
|
return RSMI_STATUS_NOT_SUPPORTED;
|
|
}
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
if (records == nullptr || *num_pages > val_vec.size()) {
|
|
*num_pages = val_vec.size();
|
|
}
|
|
if (records == nullptr) {
|
|
return RSMI_STATUS_SUCCESS;
|
|
}
|
|
|
|
// Fill in records
|
|
char status_code;
|
|
rsmi_memory_page_status_t tmp_stat;
|
|
std::string junk;
|
|
|
|
for (uint32_t i = 0; i < *num_pages; ++i) {
|
|
std::istringstream fs1(val_vec[i]);
|
|
|
|
fs1 >> std::hex >> records[i].page_address;
|
|
fs1 >> junk;
|
|
assert(junk == ":");
|
|
fs1 >> std::hex >> records[i].page_size;
|
|
fs1 >> junk;
|
|
assert(junk == ":");
|
|
fs1 >> status_code;
|
|
|
|
switch (status_code) {
|
|
case 'P':
|
|
tmp_stat = RSMI_MEM_PAGE_STATUS_PENDING;
|
|
break;
|
|
|
|
case 'F':
|
|
tmp_stat = RSMI_MEM_PAGE_STATUS_UNRESERVABLE;
|
|
break;
|
|
|
|
case 'R':
|
|
tmp_stat = RSMI_MEM_PAGE_STATUS_RESERVED;
|
|
break;
|
|
default:
|
|
assert(!"Unexpected retired memory page status code read");
|
|
return RSMI_STATUS_UNKNOWN_ERROR;
|
|
}
|
|
records[i].status = tmp_stat;
|
|
}
|
|
if (*num_pages < val_vec.size()) {
|
|
return RSMI_STATUS_INSUFFICIENT_SIZE;
|
|
}
|
|
|
|
return RSMI_STATUS_SUCCESS;
|
|
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_compute_process_info_by_pid_get(uint32_t pid,
|
|
rsmi_process_info_t *proc) {
|
|
TRY
|
|
|
|
if (proc == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
int err = amd::smi::GetProcessInfoForPID(pid, proc);
|
|
|
|
if (err) {
|
|
return errno_to_rsmi_status(err);
|
|
}
|
|
|
|
return RSMI_STATUS_SUCCESS;
|
|
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_xgmi_error_status(uint32_t dv_ind, rsmi_xgmi_status_t *status) {
|
|
TRY
|
|
DEVICE_MUTEX
|
|
|
|
if (status == nullptr) {
|
|
return RSMI_STATUS_INVALID_ARGS;
|
|
}
|
|
|
|
rsmi_status_t ret;
|
|
uint64_t status_code;
|
|
|
|
ret = get_dev_value_int(amd::smi::kDevXGMIError, dv_ind, &status_code);
|
|
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
switch (status_code) {
|
|
case 0:
|
|
*status = RSMI_XGMI_STATUS_NO_ERRORS;
|
|
break;
|
|
|
|
case 1:
|
|
*status = RSMI_XGMI_STATUS_ERROR;
|
|
break;
|
|
|
|
case 2:
|
|
*status = RSMI_XGMI_STATUS_MULTIPLE_ERRORS;
|
|
break;
|
|
|
|
default:
|
|
assert(!"Unexpected XGMI error status read");
|
|
return RSMI_STATUS_UNKNOWN_ERROR;
|
|
}
|
|
return RSMI_STATUS_SUCCESS;
|
|
|
|
CATCH
|
|
}
|
|
|
|
rsmi_status_t
|
|
rsmi_dev_xgmi_error_reset(uint32_t dv_ind) {
|
|
TRY
|
|
DEVICE_MUTEX
|
|
|
|
rsmi_status_t ret;
|
|
uint64_t status_code;
|
|
|
|
ret = get_dev_value_int(amd::smi::kDevXGMIError, dv_ind, &status_code);
|
|
|
|
if (ret != RSMI_STATUS_SUCCESS) {
|
|
return ret;
|
|
}
|
|
|
|
return RSMI_STATUS_SUCCESS;
|
|
|
|
CATCH
|
|
}
|