* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
#include <sys/ioctl.h>
#include <dlfcn.h>
#ifdef CFG_FEATURE_SUPPORT_UB
#include "urma_types.h"
#include "urma_api.h"
#endif
#ifdef CFG_FEATURE_SUPPORT_MAMI
#include "mami_api.h"
#endif
#include "securec.h"
#include "devmng_common.h"
#include "dms_user_common.h"
#include "dms/dms_misc_interface.h"
#include "ascend_hal_error.h"
#include "ascend_hal.h"
#include "dms/dms_devdrv_info_comm.h"
#include "dsmi_common_interface.h"
#include "dms_cmd_def.h"
#include "dmc_user_interface.h"
#include "dms_device_info.h"
#ifndef STATIC
#define STATIC static
#endif
#define DMS_MAX_DEV_NUM (64 + 2)
struct dms_eid_query_info g_ub_dev_info[DMS_MAX_DEV_NUM] = {0};
pthread_mutex_t ub_dev_info_lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t ub_token_val_lock = PTHREAD_MUTEX_INITIALIZER;
int dms_get_urma_name_by_devid(u32 dev_id, char *name, u32 len)
{
struct dms_ioctl_arg ioarg = {0};
int ret;
if (!name || len == 0) {
DMS_ERR("Name is null or len is 0. (len=%u)\n", len);
return DRV_ERROR_PARA_ERROR;
}
ioarg.input = (void *)&dev_id;
ioarg.input_len = sizeof(u32);
ioarg.output = (void *)name;
ioarg.output_len = len;
ioarg.main_cmd = ASCEND_UB_CMD_BASIC;
ioarg.sub_cmd = ASCEND_UB_SUBCMD_GET_URMA_NAME;
ioarg.filter_len = 0;
ret = errno_to_user_errno(DmsIoctl(DMS_IOCTL_CMD, &ioarg));
if (ret == DRV_ERROR_NO_DEVICE) {
DMS_WARN("IOCTL no dev, please retry. (ret=%d)\n", ret);
return DRV_ERROR_NO_DEVICE;
} else if(ret != 0) {
DMS_EX_NOTSUPPORT_ERR(ret, "IOCTL failed. (ret=%d)\n", ret);
return ret;
}
return DRV_ERROR_NONE;
}
#ifdef CFG_FEATURE_SUPPORT_UB
void dms_copy_urma_eid_from_addr_info(urma_eid_t *eid, union dms_urma_addr_info *addr_info)
{
int i;
for (i = 0; i < URMA_EID_SIZE; i++) {
eid->raw[i] = addr_info->eid[i];
}
return;
}
STATIC int dms_cmp_urma_eid(urma_eid_t *eid1, urma_eid_t *eid2)
{
int i;
for (i = 0; i < URMA_EID_SIZE; i++) {
if (eid1->raw[i] != eid2->raw[i]) {
return DRV_ERROR_INVALID_VALUE;
}
}
return 0;
}
STATIC int dms_fill_eid_index_and_urma_dev(struct dms_eid_query_info *query_info, struct dms_ub_dev_info *eid_info,
uint32_t dev_id)
{
urma_device_t *urma_dev = NULL;
urma_eid_t eid;
urma_eid_info_t *eid_list;
uint32_t eid_cnt, i;
dms_copy_urma_eid_from_addr_info(&eid, &query_info->local_eid[query_info->min_idx]);
urma_dev = urma_get_device_by_eid(eid, URMA_TRANSPORT_UB);
if (urma_dev == NULL) {
DMS_ERR("urma_get_device_by_eid failed.(devid=%u)\n", dev_id);
return DRV_ERROR_NO_RESOURCES;
}
eid_list = urma_get_eid_list(urma_dev, &eid_cnt);
if (eid_list == NULL) {
DMS_ERR("urma_get_eid_list failed.(devid=%u)\n", dev_id);
return DRV_ERROR_NO_RESOURCES;
}
for (i = 0; i < eid_cnt; i++) {
if (dms_cmp_urma_eid(&eid_list[i].eid, &eid) == 0) {
eid_info->eid_index[0] = eid_list[i].eid_index;
break;
}
}
if (i == eid_cnt) {
DMS_ERR("urma_dev find eid_index failed.(devid=%u; eid="EID_FMT")\n", dev_id, EID_ARGS(eid));
urma_free_eid_list(eid_list);
return DRV_ERROR_NO_RESOURCES;
}
eid_info->urma_dev[0] = (void *)urma_dev;
urma_free_eid_list(eid_list);
return 0;
}
#endif
drvError_t dms_get_ub_dev_info(unsigned int dev_id, struct dms_ub_dev_info *eid_info, int *num)
{
#ifdef CFG_FEATURE_SUPPORT_UB
struct dms_eid_query_info query_info = {0};
struct urd_cmd_para cmd_para = {0};
struct urd_cmd cmd = {0};
int ret, i;
if ((eid_info == NULL) || (num == NULL)) {
DMS_ERR("eid_info or num is Null.(devid=%u)\n", dev_id);
return DRV_ERROR_PARA_ERROR;
}
if (dev_id >= DMS_MAX_DEV_NUM) {
DMS_ERR("dev_id is invalid.(devid=%u)\n", dev_id);
return DRV_ERROR_PARA_ERROR;
}
pthread_mutex_lock(&ub_dev_info_lock);
if (g_ub_dev_info[dev_id].num != 0) {
pthread_mutex_unlock(&ub_dev_info_lock);
goto FILL_EID_INFO;
}
urd_usr_cmd_fill(&cmd, ASCEND_UB_CMD_BASIC, ASCEND_UB_SUBCMD_GET_EID_INDEX, NULL, 0);
urd_usr_cmd_para_fill(&cmd_para, (void *)&dev_id, sizeof(unsigned int),
(void *)&query_info, sizeof(struct dms_eid_query_info));
ret = urd_dev_usr_cmd(dev_id, &cmd, &cmd_para);
if ((ret != 0) || (query_info.num > DMS_MAX_EID_PAIR_NUM) || (query_info.num <= 0) ||
(query_info.min_idx >= query_info.num)) {
pthread_mutex_unlock(&ub_dev_info_lock);
DMS_EX_NOTSUPPORT_ERR(ret, "Get ub dev info failed. (dev_id=%u; ret=%d; num=%d; min_idx=%d)\n", dev_id, ret,
query_info.num, query_info.min_idx);
*num = 0;
return DRV_ERROR_IOCRL_FAIL;
}
g_ub_dev_info[dev_id].num = query_info.num;
g_ub_dev_info[dev_id].min_idx = query_info.min_idx;
for (i = 0; i < query_info.num; i++) {
(void)memcpy_s(&g_ub_dev_info[dev_id].local_eid[i].eid, sizeof(union dms_urma_addr_info),
&query_info.local_eid[i].eid, sizeof(union dms_urma_addr_info));
}
pthread_mutex_unlock(&ub_dev_info_lock);
FILL_EID_INFO:
ret = dms_fill_eid_index_and_urma_dev(&g_ub_dev_info[dev_id], eid_info, dev_id);
ret == 0 ? (*num = 1) : (*num = 0);
return ret;
#else
(void)dev_id;
(void)eid_info;
(void)num;
return DRV_ERROR_NOT_SUPPORT;
#endif
}
unsigned int g_share_token_val[DMS_MAX_DEV_NUM] = {0};
#define DMS_INVALID_TOKEN_VAL 0
drvError_t dms_get_token_val(unsigned int dev_id, unsigned int type, unsigned int *val)
{
struct urd_cmd_para cmd_para = {0};
struct urd_cmd cmd = {0};
unsigned int tmp_val;
int ret;
if ((type >= TOKEN_VAL_TYPE_MAX) || (val == NULL)) {
DMS_ERR("Type is invalid or val is Null.(type=%u; devid=%u)\n", type, dev_id);
return DRV_ERROR_PARA_ERROR;
}
if (dev_id >= DMS_MAX_DEV_NUM) {
DMS_ERR("dev_id is invalid.(devid=%u)\n", dev_id);
return DRV_ERROR_PARA_ERROR;
}
pthread_mutex_lock(&ub_token_val_lock);
if ((g_share_token_val[dev_id] != DMS_INVALID_TOKEN_VAL) && (type == SHARED_TOKEN_VAL)) {
*val = g_share_token_val[dev_id];
pthread_mutex_unlock(&ub_token_val_lock);
return DRV_ERROR_NONE;
}
urd_usr_cmd_fill(&cmd, DMS_MAIN_CMD_BASIC, DMS_SUBCMD_GET_TOKEN_VAL, NULL, 0);
urd_usr_cmd_para_fill(&cmd_para, (void *)&dev_id, sizeof(unsigned int), (void *)&tmp_val, sizeof(unsigned int));
ret = urd_dev_usr_cmd(dev_id, &cmd, &cmd_para);
if (ret != 0) {
pthread_mutex_unlock(&ub_token_val_lock);
DMS_EX_NOTSUPPORT_ERR(ret, "Get token_val failed. (dev_id=%u; ret=%d)\n", dev_id, ret);
*val = 0;
return DRV_ERROR_IOCRL_FAIL;
}
if ((type == SHARED_TOKEN_VAL) && (g_share_token_val[dev_id] == DMS_INVALID_TOKEN_VAL)) {
g_share_token_val[dev_id] = tmp_val;
}
*val = tmp_val;
pthread_mutex_unlock(&ub_token_val_lock);
return DRV_ERROR_NONE;
}
drvError_t DmsGetUbInfo(unsigned int dev_id, int module_type, int info_type,
void *buf, unsigned int *size)
{
struct dms_hal_device_info_stru in = {0};
struct dms_filter_st filter = {0};
struct urd_cmd_para cmd_para = {0};
struct urd_cmd cmd = {0};
int ret;
if ((buf == NULL) || (size == NULL) || (*size == 0)) {
return DRV_ERROR_PARA_ERROR;
}
DMS_MAKE_UP_FILTER_HAL_DEV_INFO_EX(&filter, module_type, info_type);
in.dev_id = dev_id;
in.module_type = module_type;
in.info_type = info_type;
in.buff_size = 0;
urd_usr_cmd_fill(&cmd, DMS_GET_GET_DEVICE_INFO_CMD, ZERO_CMD, &filter.filter[0], filter.filter_len);
urd_usr_cmd_para_fill(&cmd_para, (void *)&in, DMS_HAL_DEV_INFO_HEAD_LEN, buf, *size);
ret = urd_dev_usr_cmd(dev_id, &cmd, &cmd_para);
if (ret != 0) {
DMS_EX_NOTSUPPORT_ERR(ret, "Get ub_info failed. (dev_id=%u; ret=%d)\n", dev_id, ret);
return ret;
}
return ret;
}
drvError_t dms_get_ub_info(uint32_t devId, int32_t infoType, void *buf, int32_t *size)
{
int ret;
switch (infoType) {
case INFO_TYPE_UB_STATUS:
ret = DmsHalGetDeviceInfoEx(devId, MODULE_TYPE_UB, infoType, buf, (unsigned int *)size);
break;
case INFO_TYPE_UB_PACKET_STATISTICS:
ret = DmsGetUbInfo(devId, MODULE_TYPE_UB, infoType, buf, (unsigned int *)size);
break;
case INFO_TYPE_UB_QOS_INFO:
ret = DmsGetUbInfo(devId, MODULE_TYPE_UB, infoType, buf, (unsigned int *)size);
break;
case INFO_TYPE_UB_CONFIG_INFO:
ret = DmsGetUbInfo(devId, MODULE_TYPE_UB, infoType, buf, (unsigned int *)size);
break;
default:
return DRV_ERROR_NOT_SUPPORT;
}
if (ret != 0) {
DEVDRV_DRV_EX_NOTSUPPORT_ERR(ret, "Failed to get ub info. (dev_id=%u, infoType=%d, ret=%d)\n",
devId, infoType, ret);
return ret;
}
return DRV_ERROR_NONE;
}
drvError_t dms_get_ub_d2d_eid(unsigned int dev_id, struct dms_ub_d2d_eid *d2d_eid)
{
#if (defined CFG_FEATURE_SUPPORT_UB) && (!defined DRV_HOST)
struct urd_cmd cmd = {0};
struct urd_cmd_para cmd_para = {0};
int ret;
if (d2d_eid == NULL) {
DMS_ERR("d2d_eid is Null.(devid=%u)\n", dev_id);
return DRV_ERROR_PARA_ERROR;
}
if (dev_id >= DMS_MAX_DEV_NUM) {
DMS_ERR("dev_id is invalid.(devid=%u)\n", dev_id);
return DRV_ERROR_PARA_ERROR;
}
urd_usr_cmd_fill(&cmd, ASCEND_UB_CMD_BASIC, ASCEND_UB_SUBCMD_GET_D2D_EID, NULL, 0);
urd_usr_cmd_para_fill(&cmd_para, (void *)&dev_id, sizeof(unsigned int),
(void *)d2d_eid, sizeof(struct dms_ub_d2d_eid));
ret = urd_dev_usr_cmd(dev_id, &cmd, &cmd_para);
if (ret != 0) {
DMS_EX_NOTSUPPORT_ERR(ret, "Get d2d_eid failed. (dev_id=%u; ret=%d)\n", dev_id, ret);
return DRV_ERROR_IOCRL_FAIL;
}
return DRV_ERROR_NONE;
#else
(void)dev_id;
(void)d2d_eid;
return DRV_ERROR_NOT_SUPPORT;
#endif
}
drvError_t dms_get_ub_bus_inst_eid(unsigned int dev_id, struct dms_ub_bus_inst_eid *bus_inst_eid)
{
#if (defined CFG_FEATURE_SUPPORT_UB) && (!defined DRV_HOST)
struct urd_cmd cmd = {0};
struct urd_cmd_para cmd_para = {0};
int ret;
if (bus_inst_eid == NULL) {
DMS_ERR("bus_inst_eid is Null.(devid=%u)\n", dev_id);
return DRV_ERROR_PARA_ERROR;
}
if (dev_id >= DMS_MAX_DEV_NUM) {
DMS_ERR("dev_id is invalid.(devid=%u)\n", dev_id);
return DRV_ERROR_PARA_ERROR;
}
urd_usr_cmd_fill(&cmd, ASCEND_UB_CMD_BASIC, ASCEND_UB_SUBCMD_GET_BUS_INST_EID, NULL, 0);
urd_usr_cmd_para_fill(&cmd_para, (void *)&dev_id, sizeof(unsigned int),
(void *)bus_inst_eid, sizeof(struct dms_ub_bus_inst_eid));
ret = urd_dev_usr_cmd(dev_id, &cmd, &cmd_para);
if (ret != 0) {
DMS_EX_NOTSUPPORT_ERR(ret, "Get bus_inst_eid failed. (dev_id=%u; ret=%d)\n", dev_id, ret);
return DRV_ERROR_IOCRL_FAIL;
}
return DRV_ERROR_NONE;
#else
(void)dev_id;
(void)bus_inst_eid;
return DRV_ERROR_NOT_SUPPORT;
#endif
}
drvError_t dms_get_ub_dev_id_info(unsigned int dev_id, struct dms_ubdev_id_info *id_info)
{
#if (defined CFG_FEATURE_SUPPORT_UB) && (defined DRV_HOST)
struct urd_cmd_para cmd_para = {0};
struct urd_cmd cmd = {0};
int ret;
if (id_info == NULL) {
DMS_ERR("id_info is Null.(devid=%u)\n", dev_id);
return DRV_ERROR_PARA_ERROR;
}
if (dev_id >= DMS_MAX_DEV_NUM) {
DMS_ERR("dev_id is invalid.(devid=%u)\n", dev_id);
return DRV_ERROR_PARA_ERROR;
}
urd_usr_cmd_fill(&cmd, ASCEND_UB_CMD_BASIC, ASCEND_UB_SUBCMD_GET_DEV_ID_INFO, NULL, 0);
urd_usr_cmd_para_fill(&cmd_para, (void *)&dev_id, sizeof(unsigned int),
(void *)id_info, sizeof(struct dms_ubdev_id_info));
ret = urd_dev_usr_cmd(dev_id, &cmd, &cmd_para);
if (ret != 0) {
DMS_EX_NOTSUPPORT_ERR(ret, "Get id_info failed. (dev_id=%u; ret=%d)\n", dev_id, ret);
return DRV_ERROR_IOCRL_FAIL;
}
return DRV_ERROR_NONE;
#else
(void)dev_id;
(void)id_info;
return DRV_ERROR_NOT_SUPPORT;
#endif
}
#ifdef CFG_FEATURE_SUPPORT_MAMI
#define MAMI_INPUT_MAX_SIZE 4096
typedef int (*mami_init)(void *);
typedef int (*mami_get_local_devid)(unsigned int *);
typedef int (*mami_open_device)(unsigned int, struct mamiOpenDevInfo *);
typedef int (*mami_get)(unsigned int, struct mamiCmdInfo *, unsigned char *, unsigned int);
STATIC int dms_mami_int(void *handle, unsigned int *mami_dev_id)
{
mami_init mami_init_func;
mami_get_local_devid mami_get_local_devid_func;
mami_open_device mami_open_device_func;
struct mamiOpenDevInfo info = {0};
int ret = 0;
mami_init_func = (mami_init)dlsym(handle, "mamiInit");
mami_get_local_devid_func = (mami_get_local_devid)dlsym(handle, "mamiGetLocalDevid");
mami_open_device_func = (mami_open_device)dlsym(handle, "mamiOpenDevice");
if ((mami_init_func == NULL) || (mami_get_local_devid_func == NULL) || (mami_open_device_func == NULL)) {
DMS_ERR("Unable to find the API for mami. (mami_init_is_NULL=%d; mami_get_local_devid_is_NULL=%d; "
"mami_open_device_is_NULL=%d)\n", (mami_init_func == NULL), (mami_get_local_devid_func == NULL),
(mami_open_device_func == NULL));
return DRV_ERROR_INNER_ERR;
}
ret = mami_init_func(NULL);
if (ret != 0) {
DMS_ERR("Failed to invoke mamiInit. (ret=%d)\n", ret);
return DRV_ERROR_INNER_ERR;
}
ret = mami_get_local_devid_func(mami_dev_id);
if (ret != 0) {
DMS_ERR("Failed to invoke mamiGetLocalDevid. (ret=%d)\n", ret);
return DRV_ERROR_INNER_ERR;
}
ret = mami_open_device_func(*mami_dev_id, &info);
if (ret != 0) {
DMS_ERR("Failed to invoke mamiOpenDevice. (mami_dev_id=%u; ret=%d)\n", *mami_dev_id, ret);
ret = DRV_ERROR_INNER_ERR;
}
return ret;
}
STATIC int dms_mami_get(void *handle, unsigned int mami_dev_id, struct mamiCmdInfo *cmd, void *buf, unsigned int size)
{
mami_get mami_get_func = NULL;
int ret;
mami_get_func = (mami_get)dlsym(handle, "mamiGet");
if (mami_get_func == NULL) {
DMS_ERR("Unable to find the mamiGet.\n");
return DRV_ERROR_INNER_ERR;
}
ret = mami_get_func(mami_dev_id, cmd, (unsigned char *)buf, size);
if (ret != 0) {
DMS_ERR("Failed to query the ub dfx info. (mami_dev_id=%u; major=%u; minor=%u; size=%u; ret=%d)\n",
mami_dev_id, cmd->major, cmd->minor, size, ret);
ret = DRV_ERROR_INNER_ERR;
}
return ret;
}
STATIC int dms_get_ub_dfx_info(unsigned int dev_id, void *buf, unsigned int *size)
{
struct dsmi_ub_dfx_input *input = (struct dsmi_ub_dfx_input *)buf;
unsigned char *input_buf = NULL;
struct mamiCmdInfo cmd = {0};
unsigned int mami_dev_id;
void *handle = NULL;
int ret = 0;
handle = dlopen("/usr/local/lib64/mami/libmami.so", RTLD_GLOBAL | RTLD_NOW);
if (handle == NULL) {
return DRV_ERROR_NOT_SUPPORT;
}
if (input->buf_size > MAMI_INPUT_MAX_SIZE) {
DMS_ERR("Invalid input buf size. (dev_id=%u; size=%u)\n", dev_id, input->buf_size);
dlclose(handle);
return DRV_ERROR_PARA_ERROR;
} else if (input->buf_size != 0 ) {
input_buf = (unsigned char *)malloc(input->buf_size);
if (input_buf == NULL) {
DMS_ERR("Failed to allocate memory. (dev_id=%u)", dev_id);
dlclose(handle);
return DRV_ERROR_OUT_OF_MEMORY;
}
ret = memcpy_s(input_buf, input->buf_size, input->buf, input->buf_size);
if (ret != 0) {
DMS_ERR("Failed to copy the input buf memory. (dev_id=%u; ret=%d)\n", dev_id, ret);
ret = DRV_ERROR_INNER_ERR;
goto UB_DFX_INFO_OUT;
}
}
ret = dms_mami_int(handle, &mami_dev_id);
if (ret != 0) {
goto UB_DFX_INFO_OUT;
}
cmd.major = input->major;
cmd.minor = input->minor;
cmd.size = input->buf_size;
cmd.buffer = input_buf;
ret = dms_mami_get(handle, mami_dev_id, &cmd, buf, *size);
UB_DFX_INFO_OUT:
dlclose(handle);
if (input_buf != NULL) {
free(input_buf);
input_buf = NULL;
}
return ret;
}
#else
STATIC int dms_get_ub_dfx_info(unsigned int dev_id, void *buf, unsigned int *size)
{
(void)dev_id;
(void)buf;
(void)size;
return DRV_ERROR_NOT_SUPPORT;
}
#endif
int dms_get_ub_info_by_dmp(unsigned int dev_id, unsigned int vfid, unsigned int sub_cmd, void *buf, unsigned int *size)
{
(void)vfid;
if (dev_id > DMS_MAX_DEV_NUM || buf == NULL || size == NULL) {
DMS_ERR("Invalid parameter. (dev_id=%u; buf_is_NULL=%d; size_is_NULL=%d)\n",
dev_id, (buf == NULL), (size == NULL));
return DRV_ERROR_PARA_ERROR;
}
if (sub_cmd == DSMI_UB_INFO_SUB_CMD_UB_DFX_INFO) {
return dms_get_ub_dfx_info(dev_id, buf, size);
}
return DRV_ERROR_NOT_SUPPORT;
}