* Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "ka_memory_pub.h"
#include "ka_kernel_def_pub.h"
#include "ka_task_pub.h"
#include "ka_common_pub.h"
#include "ka_base_pub.h"
#include "uda_dev_adapt.h"
#include "uda_notifier.h"
#include "pbl_mem_alloc_interface.h"
#include "uda_dev.h"
static ka_mutex_t uda_dev_mutex;
static ka_rwlock_t uda_dev_lock;
static struct uda_dev_inst *dev_insts[UDA_UDEV_MAX_NUM];
struct uda_reorder_insts reorder_insts;
struct udevid_reorder_para *reorder_para = NULL;
void __ka_mm_iomem *g_reorder_para_addr[UDA_UDEV_MAX_NUM] = {NULL};
static bool uda_udevid_reorder_flag = false;
void uda_type_to_string(struct uda_dev_type *type, char buf[], u32 buf_len)
{
int ret = 0;
static const char *uda_hw_name[UDA_HW_MAX] = {
[UDA_DAVINCI] = "davinci",
[UDA_KUNPENG] = "kunpeng",
};
static const char *uda_obj_name[UDA_OBJECT_MAX] = {
[UDA_ENTITY] = "entity",
[UDA_AGENT] = "agent",
};
static const char *uda_loc_name[UDA_LOCATION_MAX] = {
[UDA_LOCAL] = "local",
[UDA_NEAR] = "near",
[UDA_REMOTE] = "remote",
};
static const char *uda_prop_name[UDA_PROP_MAX] = {
[UDA_REAL] = "real",
[UDA_VIRTUAL] = "virtual",
[UDA_REAL_SEC_EH] = "real_sec_eh",
};
ret = sprintf_s(buf, buf_len, "%s %s %s %s",
uda_hw_name[type->hw], uda_obj_name[type->object], uda_loc_name[type->location], uda_prop_name[type->prop]);
if (ret <= 0) {
uda_err("Invoke sprintf_s error.\n");
}
}
u32 uda_get_udev_max_num(void)
{
return UDA_UDEV_MAX_NUM;
}
KA_EXPORT_SYMBOL(uda_get_udev_max_num);
u32 uda_get_remote_udev_max_num(void)
{
return UDA_REMOTE_UDEV_MAX_NUM;
}
KA_EXPORT_SYMBOL(uda_get_remote_udev_max_num);
bool hal_kernel_uda_is_phy_dev(u32 udevid)
{
return uda_is_phy_dev(udevid);
}
KA_EXPORT_SYMBOL(hal_kernel_uda_is_phy_dev);
bool uda_is_phy_dev(u32 udevid)
{
return (udevid < UDA_MAX_PHY_DEV_NUM);
}
KA_EXPORT_SYMBOL(uda_is_phy_dev);
void uda_set_udevid_reorder_flag(bool flag)
{
uda_udevid_reorder_flag = flag;
}
KA_EXPORT_SYMBOL(uda_set_udevid_reorder_flag);
bool uda_udevid_is_reorder(void)
{
return uda_udevid_reorder_flag;
}
KA_EXPORT_SYMBOL(uda_udevid_is_reorder);
bool uda_is_pf_dev(u32 udevid)
{
struct uda_dev_inst *dev_inst = NULL;
bool is_pf = true;
if (udevid >= UDA_MAX_PHY_DEV_NUM) {
return false;
}
dev_inst = uda_dev_inst_get(udevid);
if (dev_inst == NULL) {
uda_err("Invalid udevid. (udevid=%u)\n", udevid);
return false;
}
is_pf = dev_inst->para.pf_flag == 1 ? true : false;
uda_dev_inst_put(dev_inst);
return is_pf;
}
KA_EXPORT_SYMBOL(uda_is_pf_dev);
int uda_udevid_to_logic_id(u32 udevid, u32 *logic_id)
{
struct uda_dev_inst *dev_inst = uda_dev_inst_get(udevid);
if (dev_inst == NULL) {
uda_err("Invalid udevid. (udevid=%u)\n", udevid);
return -EINVAL;
}
*logic_id = dev_inst->para.logic_id;
return 0;
}
KA_EXPORT_SYMBOL(uda_udevid_to_logic_id);
static int uda_alloc_udevid(u32 start, u32 end, u32 *udevid)
{
u32 i;
for (i = start; i < end; i++) {
if (dev_insts[i] == NULL) {
*udevid = i;
return 0;
}
}
return -ENOSPC;
}
u32 uda_make_udevid(struct uda_mia_dev_para *mia_para)
{
return mia_para->phy_devid * UDA_SUB_DEV_MAX_NUM + mia_para->sub_devid + UDA_MIA_UDEV_OFFSET;
}
KA_EXPORT_SYMBOL(uda_make_udevid);
static struct uda_dev_inst *uda_create_dev_inst(struct uda_dev_type *type, struct uda_dev_para *para)
{
static u32 inst_id = 0;
struct uda_dev_inst *dev_inst = dbl_kzalloc(sizeof(struct uda_dev_inst), KA_GFP_KERNEL | __KA_GFP_ACCOUNT);
if (dev_inst == NULL) {
uda_err("Out of memory.\n");
return NULL;
}
dev_inst->type = *type;
dev_inst->para = *para;
dev_inst->agent_flag = 0;
dev_inst->inst_id = inst_id++;
ka_base_kref_init(&dev_inst->ref);
return dev_inst;
}
static void uda_destroy_dev_inst(struct uda_dev_inst *dev_inst)
{
dbl_kfree(dev_inst);
}
struct uda_dev_inst *uda_dev_inst_get(u32 udevid)
{
struct uda_dev_inst *dev_inst = NULL;
if (udevid >= UDA_UDEV_MAX_NUM) {
return NULL;
}
ka_task_read_lock_bh(&uda_dev_lock);
dev_inst = dev_insts[udevid];
if (dev_inst != NULL) {
ka_base_kref_get(&dev_inst->ref);
}
ka_task_read_unlock_bh(&uda_dev_lock);
return dev_inst;
}
struct uda_dev_inst *uda_dev_inst_get_ex(u32 udevid)
{
struct uda_dev_inst *dev_inst = NULL;
if (udevid >= UDA_UDEV_MAX_NUM) {
return NULL;
}
ka_task_read_lock_irq(&uda_dev_lock);
dev_inst = dev_insts[udevid];
if (dev_inst != NULL) {
ka_base_kref_get(&dev_inst->ref);
}
ka_task_read_unlock_irq(&uda_dev_lock);
return dev_inst;
}
static void uda_dev_inst_release(ka_kref_t *kref)
{
struct uda_dev_inst *dev_inst = ka_container_of(kref, struct uda_dev_inst, ref);
uda_info("Remove dev success. (udevid=%u; agent_flag=%u)\n", dev_inst->udevid, dev_inst->agent_flag);
uda_destroy_dev_inst(dev_inst);
}
void uda_dev_inst_put(struct uda_dev_inst *dev_inst)
{
ka_base_kref_put(&dev_inst->ref, uda_dev_inst_release);
}
static int _uda_add_dev_ex(struct uda_dev_type *type, struct uda_dev_para *para,
struct uda_mia_dev_para *mia_para, u32 *udevid)
{
struct uda_dev_inst *dev_inst = NULL;
int ret;
if (type->object == UDA_ENTITY) {
if ((para->udevid != UDA_INVALID_UDEVID) || (mia_para != NULL)) {
*udevid = (mia_para == NULL) ? para->udevid : uda_make_udevid(mia_para);
if (dev_insts[*udevid] != NULL) {
uda_warn("Has add entity dev. (udevid=%u)\n", *udevid);
dev_insts[*udevid]->para.dev = para->dev;
dev_insts[*udevid]->status = 0;
return 0;
}
} else {
ret = uda_alloc_udevid(0, UDA_MIA_UDEV_OFFSET, udevid);
if (ret != 0) {
uda_err("No udevid res\n");
return ret;
}
}
} else {
*udevid = para->udevid;
if (dev_insts[para->udevid] == NULL) {
uda_err("No entity dev. (udevid=%u)\n", para->udevid);
return -EINVAL;
}
if (dev_insts[para->udevid]->agent_dev != NULL) {
uda_warn("Has add agent dev. (udevid=%u)\n", para->udevid);
((struct uda_dev_inst *)dev_insts[para->udevid]->agent_dev)->para.dev = para->dev;
((struct uda_dev_inst *)dev_insts[para->udevid]->agent_dev)->status = 0;
return 0;
}
}
dev_inst = uda_create_dev_inst(type, para);
if (dev_inst == NULL) {
return -ENOMEM;
}
dev_inst->udevid = *udevid;
if (mia_para != NULL) {
dev_inst->mia_para = *mia_para;
}
if (type->object == UDA_ENTITY) {
if (dev_inst->para.char_flag == UDA_ENABLE_CHAR_NUMBERING) {
ret = uda_access_add_dev(dev_inst->udevid, dev_inst->para.logic_id, &dev_inst->access);
} else {
ret = uda_access_add_dev(dev_inst->udevid, UDA_INVALID_UDEVID, &dev_inst->access);
}
if (ret != 0) {
uda_destroy_dev_inst(dev_inst);
return ret;
}
dev_insts[*udevid] = dev_inst;
} else {
dev_inst->agent_flag = 1;
dev_insts[para->udevid]->agent_dev = dev_inst;
if (dev_inst->para.remote_udevid != UDA_INVALID_UDEVID) {
dev_insts[para->udevid]->para.remote_udevid = dev_inst->para.remote_udevid;
}
}
uda_info("Add dev success. (udevid=%u; agent_flag=%u)\n", *udevid, dev_inst->agent_flag);
uda_show_type("Add", type);
return 0;
}
int uda_guid_compare(u32 *guid, u32 *other_guid)
{
int i;
for (i = 0; i < UDA_GUID_LEN; i++) {
if (guid[UDA_GUID_LEN - i - 1] != other_guid[UDA_GUID_LEN - i - 1]) {
if (guid[UDA_GUID_LEN - i - 1] > other_guid[UDA_GUID_LEN - i - 1]) {
return 1;
} else {
return -1;
}
}
}
return 0;
}
void uda_module_id_sort(unsigned int start, unsigned int end)
{
struct uda_dev_para tmp_para;
unsigned int module_id1 = 0;
unsigned int module_id2 = 0;
unsigned int i, j;
if (end > reorder_insts.dev_add_num) {
return;
}
for (i = start; i < end - 1; i++) {
for (j = start; j < end - 1 - i + start; j++) {
module_id1 = reorder_para[reorder_insts.dev_para[j].add_id].module_id;
module_id2 = reorder_para[reorder_insts.dev_para[j + 1].add_id].module_id;
if (module_id1 > module_id2) {
tmp_para = reorder_insts.dev_para[j];
reorder_insts.dev_para[j] = reorder_insts.dev_para[j + 1];
reorder_insts.dev_para[j + 1] = tmp_para;
}
}
}
}
static void _uda_udevid_reorder(void)
{
struct uda_dev_para tmp_para;
unsigned int ub_link_count = 0;
unsigned int group_dev_num = 1;
unsigned int *guid = NULL;
unsigned int tmp_index = 0;
unsigned int i, j;
for (i = 0; i < reorder_insts.dev_add_num;) {
tmp_index = i + 1;
ub_link_count = 0;
if ((reorder_para[reorder_insts.dev_para[i].add_id].group_dev_num <= UDA_REORDER_GROUP_DEV_MAX_NUM) &&
(reorder_para[reorder_insts.dev_para[i].add_id].group_dev_num != 0)) {
group_dev_num = reorder_para[reorder_insts.dev_para[i].add_id].group_dev_num;
} else {
uda_warn("The set group device number is invalid. (set_group_dev_num=%u)\n",
reorder_para[reorder_insts.dev_para[i].add_id].group_dev_num);
group_dev_num = 1;
}
if (reorder_para[reorder_insts.dev_para[i].add_id].ub_link_status == 1) {
ub_link_count++;
}
for (j = tmp_index; j < reorder_insts.dev_add_num; j++) {
guid = reorder_para[reorder_insts.dev_para[j].add_id].guid;
if ((uda_guid_compare(guid, reorder_para[reorder_insts.dev_para[i].add_id].guid1) == 0) ||
(uda_guid_compare(guid, reorder_para[reorder_insts.dev_para[i].add_id].guid2) == 0) ||
(uda_guid_compare(guid, reorder_para[reorder_insts.dev_para[i].add_id].guid3) == 0)) {
tmp_para = reorder_insts.dev_para[tmp_index];
reorder_insts.dev_para[tmp_index] = reorder_insts.dev_para[j];
reorder_insts.dev_para[j] = tmp_para;
tmp_index++;
if (reorder_para[reorder_insts.dev_para[j].add_id].ub_link_status == 1) {
ub_link_count++;
}
}
if ((tmp_index - i) == group_dev_num) {
break;
}
}
if (ub_link_count == group_dev_num) {
uda_module_id_sort(i, i + group_dev_num);
for (j = i; j < group_dev_num; j++) {
reorder_insts.dev_para[j].udevid = reorder_insts.udevid;
reorder_insts.dev_para[j].logic_id = reorder_insts.logic_id;
reorder_insts.udevid++;
reorder_insts.logic_id++;
}
}
i = tmp_index;
}
for (i = 0; i < reorder_insts.dev_add_num; i++) {
if (reorder_insts.dev_para[i].udevid == UDA_INVALID_UDEVID) {
reorder_insts.dev_para[i].udevid = reorder_insts.udevid;
reorder_insts.dev_para[i].logic_id = reorder_insts.logic_id;
reorder_insts.udevid++;
reorder_insts.logic_id++;
}
}
}
static void _uda_master_id_reorder(void)
{
unsigned int i, j;
for (i = 0; i < reorder_insts.dev_add_num; i++) {
for (j = 0; j < reorder_insts.dev_add_num; j++) {
if (reorder_insts.dev_para[i].master_id == reorder_insts.dev_para[j].add_id) {
reorder_insts.dev_para[i].master_id = reorder_insts.dev_para[j].udevid;
break;
}
}
}
}
STATIC void uda_allocate_logic_id(void)
{
struct uda_dev_para tmp_para;
unsigned int i, j;
for (i = 0; i < reorder_insts.dev_add_num - 1; i++) {
for (j = 0; j < reorder_insts.dev_add_num - 1 - i; j++) {
if (reorder_insts.dev_para[j].add_id > reorder_insts.dev_para[j + 1].add_id) {
tmp_para = reorder_insts.dev_para[j];
reorder_insts.dev_para[j] = reorder_insts.dev_para[j + 1];
reorder_insts.dev_para[j + 1] = tmp_para;
}
}
}
for (i = 0; i < reorder_insts.dev_add_num; i++) {
reorder_insts.dev_para[i].logic_id = i;
reorder_insts.dev_para[i].udevid = reorder_insts.dev_para[i].add_id;
}
reorder_insts.logic_id = i;
}
#ifdef EMU_ST
#define UDA_ALL_DEV_UP_WAIT_CNT 1
#else
#define UDA_ALL_DEV_UP_WAIT_CNT 300
#endif
#define UDA_ALL_DEV_UP_WAIT_TIME 1000
#define UDA_UB_PORT_ALL_LINK 1
#define UDA_UB_PORT_NOT_LINK 3
static bool uda_all_dev_is_up(void)
{
unsigned int link_all_count = 0;
unsigned int add_id;
unsigned int i;
if (uda_udevid_reorder_flag) {
link_all_count = 0;
for (i = 0; i < reorder_insts.dev_add_num; i++) {
add_id = reorder_insts.dev_para[i].add_id;
ka_mm_memcpy_fromio(&reorder_para[add_id], g_reorder_para_addr[add_id], sizeof(struct udevid_reorder_para));
if ((reorder_para[add_id].ub_link_status == UDA_UB_PORT_ALL_LINK) ||
(reorder_para[add_id].ub_link_status == UDA_UB_PORT_NOT_LINK)) {
link_all_count++;
}
}
if (link_all_count == uda_get_detected_phy_dev_num()) {
return true;
}
} else {
if (reorder_insts.dev_add_num == uda_get_detected_phy_dev_num()) {
return true;
}
}
return false;
}
static void uda_wait_all_dev_up_work(ka_work_struct_t *work)
{
unsigned int udevid = 0;
unsigned int i;
int wait_cnt = 0;
int ret;
while (wait_cnt < UDA_ALL_DEV_UP_WAIT_CNT) {
if (uda_all_dev_is_up()) {
break;
}
ka_system_msleep(UDA_ALL_DEV_UP_WAIT_TIME);
wait_cnt++;
}
uda_info("Reorder wait end. (dev_add_num=%u; detected_phy_dev_num=%u)\n",
reorder_insts.dev_add_num, uda_get_detected_phy_dev_num());
ka_task_mutex_lock(&reorder_insts.work_mutex);
if (uda_udevid_reorder_flag) {
_uda_udevid_reorder();
_uda_master_id_reorder();
} else {
uda_allocate_logic_id();
}
for (i = 0; i < reorder_insts.dev_add_num; i++) {
ka_task_mutex_lock(&uda_dev_mutex);
ret = _uda_add_dev_ex(&reorder_insts.dev_type, &reorder_insts.dev_para[i], NULL, &udevid);
ka_task_mutex_unlock(&uda_dev_mutex);
if (ret == 0) {
(void)uda_notifier_call(udevid, &reorder_insts.dev_type, UDA_INIT);
}
}
uda_info("Device added. (reorder=%d; dev_add_num=%u)\n", uda_udevid_reorder_flag, reorder_insts.dev_add_num);
reorder_insts.wait_all_dev_work_state = UDA_ALL_DEV_UP_WORK_FINISH;
ka_task_mutex_unlock(&reorder_insts.work_mutex);
uda_info("Reorder task end.\n");
}
static int uda_dev_add_after_wait_work(struct uda_dev_para *para)
{
unsigned int udevid = 0;
int ret;
if (uda_udevid_reorder_flag) {
reorder_insts.dev_para[reorder_insts.dev_add_num].master_id = reorder_insts.udevid;
reorder_insts.dev_para[reorder_insts.dev_add_num].udevid = reorder_insts.udevid;
reorder_insts.udevid++;
} else {
reorder_insts.dev_para[reorder_insts.dev_add_num].master_id = para->udevid;
reorder_insts.dev_para[reorder_insts.dev_add_num].udevid = para->udevid;
}
reorder_insts.dev_para[reorder_insts.dev_add_num].logic_id = reorder_insts.logic_id;
reorder_insts.logic_id++;
ka_task_mutex_lock(&uda_dev_mutex);
ret = _uda_add_dev_ex(&reorder_insts.dev_type, &reorder_insts.dev_para[reorder_insts.dev_add_num], NULL, &udevid);
ka_task_mutex_unlock(&uda_dev_mutex);
if (ret == 0) {
(void)uda_notifier_call(udevid, &reorder_insts.dev_type, UDA_INIT);
}
return ret;
}
STATIC int uda_alloc_dev_para(unsigned int all_dev_num, struct uda_dev_type *type)
{
if (reorder_insts.dev_para == NULL) {
if (all_dev_num == 0) {
uda_err("The number of scanned devices is 0.\n");
return -EINVAL;
}
reorder_insts.dev_para = dbl_kzalloc(sizeof(struct uda_dev_para) * all_dev_num, KA_GFP_KERNEL | __KA_GFP_ACCOUNT);
if (reorder_insts.dev_para == NULL) {
uda_err("Out of memory.\n");
return -ENOMEM;
}
reorder_insts.dev_type = *type;
reorder_insts.udevid = 0;
reorder_insts.logic_id = 0;
reorder_insts.dev_add_num = 0;
reorder_insts.wait_all_dev_work_state = 0;
ka_task_mutex_init(&reorder_insts.work_mutex);
}
return 0;
}
STATIC int uda_wait_all_dev_up(struct uda_dev_type *type, struct uda_dev_para *para)
{
unsigned int all_dev_num = uda_get_detected_phy_dev_num();
unsigned int udevid = 0;
unsigned int set_add_id = para->udevid;
int ret;
unsigned int i;
ret = uda_alloc_dev_para(all_dev_num, type);
if (ret != 0) {
return ret;
}
for (i = 0; i < reorder_insts.dev_add_num; i++) {
if (reorder_insts.dev_para[i].add_id == set_add_id) {
reorder_insts.dev_para[i].dev = para->dev;
ka_task_mutex_lock(&uda_dev_mutex);
ret = _uda_add_dev_ex(&reorder_insts.dev_type, &reorder_insts.dev_para[i], NULL, &udevid);
ka_task_mutex_unlock(&uda_dev_mutex);
if (ret == 0) {
(void)uda_notifier_call(udevid, &reorder_insts.dev_type, UDA_INIT);
}
return ret;
}
}
ka_task_mutex_lock(&reorder_insts.work_mutex);
if (reorder_insts.dev_add_num >= all_dev_num) {
ka_task_mutex_unlock(&reorder_insts.work_mutex);
uda_err("Reorder insts is full. (dev_add_num=%u; all_dev_num=%u)\n", reorder_insts.dev_add_num, all_dev_num);
return -EINVAL;
}
reorder_insts.dev_para[reorder_insts.dev_add_num] = *para;
reorder_insts.dev_para[reorder_insts.dev_add_num].add_id = set_add_id;
reorder_insts.dev_para[reorder_insts.dev_add_num].udevid = UDA_INVALID_UDEVID;
reorder_insts.dev_para[reorder_insts.dev_add_num].logic_id = UDA_INVALID_UDEVID;
reorder_insts.dev_para[reorder_insts.dev_add_num].char_flag = UDA_ENABLE_CHAR_NUMBERING;
if (reorder_insts.wait_all_dev_work_state == UDA_ALL_DEV_UP_WORK_FINISH) {
ret = uda_dev_add_after_wait_work(para);
if (ret != 0) {
ka_task_mutex_unlock(&reorder_insts.work_mutex);
return ret;
}
}
reorder_insts.dev_add_num++;
ka_task_mutex_unlock(&reorder_insts.work_mutex);
if (reorder_insts.dev_add_num == 1) {
ka_task_schedule_work(&reorder_insts.wait_all_dev_work);
}
uda_info("Reorder add success. (dev_add_num=%u; add_id=%u)\n", reorder_insts.dev_add_num, para->udevid);
return 0;
}
static int uda_add_dev_ex(struct uda_dev_type *type, struct uda_dev_para *para,
struct uda_mia_dev_para *mia_para, u32 *udevid)
{
int ret;
if ((type == NULL) || (para == NULL) || (udevid == NULL)) {
uda_err("Null ptr.\n");
return -EINVAL;
}
ret = uda_dev_type_valid_check(type);
if (ret != 0) {
uda_err("Invalid type.\n");
return ret;
}
if (type->object == UDA_ENTITY) {
if (((para->udevid != UDA_INVALID_UDEVID) && !uda_is_phy_dev(para->udevid))) {
uda_err("Invalid para. (udevid=%u)\n", para->udevid);
return -EINVAL;
}
} else {
if (para->udevid >= UDA_UDEV_MAX_NUM) {
uda_err("Invalid para. (udevid=%u)\n", para->udevid);
return -EINVAL;
}
}
if (UDA_WAIT_ALL_DEV_UP_FLAG && para->pf_flag == 1) {
return uda_wait_all_dev_up(type, para);
} else if (para->pf_flag == 0 && mia_para != NULL) {
para->add_id = uda_make_udevid(mia_para);
} else {
para->add_id = para->udevid;
}
ka_task_mutex_lock(&uda_dev_mutex);
ret = _uda_add_dev_ex(type, para, mia_para, udevid);
ka_task_mutex_unlock(&uda_dev_mutex);
if (ret == 0) {
(void)uda_notifier_call(*udevid, type, UDA_INIT);
}
return ret;
}
int uda_add_dev(struct uda_dev_type *type, struct uda_dev_para *para, u32 *udevid)
{
return uda_add_dev_ex(type, para, NULL, udevid);
}
KA_EXPORT_SYMBOL(uda_add_dev);
static int uda_mia_dev_check(struct uda_mia_dev_para *mia_para)
{
if (!uda_is_phy_dev(mia_para->phy_devid) || (mia_para->sub_devid >= UDA_SUB_DEV_MAX_NUM)
|| (uda_make_udevid(mia_para) >= UDA_UDEV_MAX_NUM)) {
uda_err("Invalid para. (phy_devid=%u; sub_devid=%u)\n", mia_para->phy_devid, mia_para->sub_devid);
return -EINVAL;
}
return 0;
}
int uda_add_mia_dev(struct uda_dev_type *type, struct uda_dev_para *para,
struct uda_mia_dev_para *mia_para, u32 *udevid)
{
if ((para == NULL) || (mia_para == NULL)) {
uda_err("Null ptr.\n");
return -EINVAL;
}
if (para->udevid != UDA_INVALID_UDEVID) {
uda_err("Mia udevid cannot be specified. (udevid=%u)\n", para->udevid);
return -EINVAL;
}
if (uda_mia_dev_check(mia_para) != 0) {
return -EINVAL;
}
para->pf_flag = 0;
return uda_add_dev_ex(type, para, mia_para, udevid);
}
KA_EXPORT_SYMBOL(uda_add_mia_dev);
static int _uda_remove_dev(struct uda_dev_inst *dev_inst, struct uda_dev_type *type)
{
if (uda_dev_type_is_match(type, &dev_inst->type)) {
#ifdef CFG_FEATURE_DEVID_TRANS
int ret = uda_access_remove_dev(dev_inst->udevid, &dev_inst->access);
if (ret != 0) {
return ret;
}
#endif
ka_task_write_lock_bh(&uda_dev_lock);
dev_insts[dev_inst->udevid] = NULL;
ka_task_write_unlock_bh(&uda_dev_lock);
if (dev_inst->agent_dev != NULL) {
struct uda_dev_inst *agent_dev_inst = dev_inst->agent_dev;
uda_warn("Not remove agent dev. (udevid=%d)\n", dev_inst->udevid);
ka_base_kref_put(&agent_dev_inst->ref, uda_dev_inst_release);
}
ka_base_kref_put(&dev_inst->ref, uda_dev_inst_release);
} else {
struct uda_dev_inst *agent_dev_inst = dev_inst->agent_dev;
dev_inst->agent_dev = NULL;
ka_base_kref_put(&agent_dev_inst->ref, uda_dev_inst_release);
}
return 0;
}
int uda_remove_dev(struct uda_dev_type *type, u32 udevid)
{
struct uda_dev_inst *dev_inst = NULL;
int ret;
if ((type == NULL) || (udevid >= UDA_UDEV_MAX_NUM)) {
uda_err("Invalid para. (udevid=%u)\n", udevid);
return -EINVAL;
}
ret = uda_dev_type_valid_check(type);
if (ret != 0) {
uda_err("Invalid type.\n");
return ret;
}
dev_inst = uda_dev_inst_get(udevid);
if (dev_inst == NULL) {
uda_err("Invalid udevid. (udevid=%u)\n", udevid);
return -EINVAL;
}
if (!uda_dev_type_is_match(type, &dev_inst->type)) {
struct uda_dev_inst *agent_dev_inst = dev_inst->agent_dev;
if ((agent_dev_inst == NULL) || (!uda_dev_type_is_match(type, &agent_dev_inst->type))) {
uda_err("Remove type mismatch. (udevid=%d)\n", udevid);
uda_show_type("Remove type", type);
uda_show_type("Dev type", &dev_inst->type);
uda_dev_inst_put(dev_inst);
return -ENODEV;
}
}
(void)uda_notifier_call(udevid, type, UDA_UNINIT);
#ifndef EMU_ST
if (!uda_is_phy_dev(udevid)) {
#else
{
#endif
ka_task_mutex_lock(&uda_dev_mutex);
ret = _uda_remove_dev(dev_inst, type);
ka_task_mutex_unlock(&uda_dev_mutex);
}
dev_inst->para.dev = NULL;
uda_update_status_by_action(&dev_inst->status, UDA_REMOVE);
if (ret != 0) {
(void)uda_notifier_call(udevid, type, UDA_INIT);
}
uda_dev_inst_put(dev_inst);
return ret;
}
KA_EXPORT_SYMBOL(uda_remove_dev);
int uda_get_action_para(u32 udevid, enum uda_notified_action action, u32 *val)
{
struct uda_dev_inst *dev_inst = NULL;
if ((action < 0) || (action >= UDA_ACTION_MAX)) {
uda_err("Invalid action. (udevid=%u; action=%d)\n", udevid, action);
return -EINVAL;
}
if (val == NULL) {
uda_err("Null ptr. (udevid=%u; action=%d)\n", udevid, action);
return -EINVAL;
}
dev_inst = uda_dev_inst_get(udevid);
if (dev_inst == NULL) {
return -EINVAL;
}
*val = dev_inst->action_para[action];
uda_dev_inst_put(dev_inst);
return 0;
}
KA_EXPORT_SYMBOL(uda_get_action_para);
static void uda_dev_ctrl_restore(struct uda_dev_inst *dev_inst, enum uda_dev_ctrl_cmd cmd, u32 val)
{
static enum uda_notified_action ctrl_cmd_to_restore_action[UDA_CTRL_MAX] = {
[UDA_CTRL_SUSPEND] = UDA_RESUME,
[UDA_CTRL_RESUME] = UDA_SUSPEND,
[UDA_CTRL_TO_MIA] = UDA_TO_SIA,
[UDA_CTRL_TO_SIA] = UDA_TO_MIA,
[UDA_CTRL_MIA_CHANGE] = UDA_ACTION_MAX,
[UDA_CTRL_REMOVE] = UDA_ACTION_MAX,
[UDA_CTRL_HOTRESET] = UDA_HOTRESET_CANCEL,
[UDA_CTRL_HOTRESET_CANCEL] = UDA_ACTION_MAX,
[UDA_CTRL_SHUTDOWN] = UDA_ACTION_MAX,
[UDA_CTRL_PRE_HOTRESET] = UDA_PRE_HOTRESET_CANCEL,
[UDA_CTRL_PRE_HOTRESET_CANCEL] = UDA_ACTION_MAX,
[UDA_CTRL_ADD_GROUP] = UDA_DEL_GROUP,
[UDA_CTRL_DEL_GROUP] = UDA_ACTION_MAX,
[UDA_CTRL_UPDATE_P2P_ADDR] = UDA_ACTION_MAX,
[UDA_CTRL_COMMUNICATION_LOST] = UDA_ACTION_MAX,
[UDA_CTRL_AIC_ATU_CFG] = UDA_ACTION_MAX,
};
if (ctrl_cmd_to_restore_action[cmd] != UDA_ACTION_MAX) {
dev_inst->action_para[ctrl_cmd_to_restore_action[cmd]] = val;
(void)uda_notifier_call(dev_inst->udevid, &dev_inst->type, ctrl_cmd_to_restore_action[cmd]);
}
}
static int _uda_dev_ctrl(struct uda_dev_inst *dev_inst, enum uda_dev_ctrl_cmd cmd, u32 val)
{
int ret;
static enum uda_notified_action ctrl_cmd_to_action[UDA_CTRL_MAX] = {
[UDA_CTRL_SUSPEND] = UDA_SUSPEND,
[UDA_CTRL_RESUME] = UDA_RESUME,
[UDA_CTRL_TO_MIA] = UDA_TO_MIA,
[UDA_CTRL_TO_SIA] = UDA_TO_SIA,
[UDA_CTRL_MIA_CHANGE] = UDA_MIA_CHANGE,
[UDA_CTRL_REMOVE] = UDA_REMOVE,
[UDA_CTRL_HOTRESET] = UDA_HOTRESET,
[UDA_CTRL_HOTRESET_CANCEL] = UDA_HOTRESET_CANCEL,
[UDA_CTRL_SHUTDOWN] = UDA_SHUTDOWN,
[UDA_CTRL_PRE_HOTRESET] = UDA_PRE_HOTRESET,
[UDA_CTRL_PRE_HOTRESET_CANCEL] = UDA_PRE_HOTRESET_CANCEL,
[UDA_CTRL_ADD_GROUP] = UDA_ADD_GROUP,
[UDA_CTRL_DEL_GROUP] = UDA_DEL_GROUP,
[UDA_CTRL_UPDATE_P2P_ADDR] = UDA_UPDATE_P2P_ADDR,
[UDA_CTRL_COMMUNICATION_LOST] = UDA_COMMUNICATION_LOST,
[UDA_CTRL_AIC_ATU_CFG] = UDA_AIC_ATU_CFG,
};
if (uda_is_action_conflict(dev_inst->status, ctrl_cmd_to_action[cmd])) {
uda_err("Invalid cmd. (udevid=%u; cmd=%d; status=%x)\n", dev_inst->udevid, cmd, dev_inst->status);
return -EINVAL;
}
dev_inst->action_para[ctrl_cmd_to_action[cmd]] = val;
ret = uda_notifier_call(dev_inst->udevid, &dev_inst->type, ctrl_cmd_to_action[cmd]);
if (ret != 0) {
uda_dev_ctrl_restore(dev_inst, cmd, val);
uda_debug("Notifier call failed. (udevid=%d; cmd=%d; ret=%d)\n", dev_inst->udevid, cmd, ret);
return ret;
}
uda_update_status_by_action(&dev_inst->status, ctrl_cmd_to_action[cmd]);
uda_info("Dev ctrl success. (udevid=%d; cmd=%d)\n", dev_inst->udevid, cmd);
return 0;
}
int uda_dev_ctrl_ex(u32 udevid, enum uda_dev_ctrl_cmd cmd, u32 val)
{
struct uda_dev_inst *dev_inst = NULL;
int ret;
if ((cmd < 0) || (cmd >= UDA_CTRL_MAX)) {
uda_err("Invalid cmd. (udevid=%u; cmd=%d)\n", udevid, cmd);
return -EINVAL;
}
if (uda_is_phy_dev(udevid)) {
if ((cmd == UDA_CTRL_MIA_CHANGE) || (cmd == UDA_CTRL_REMOVE)) {
uda_err("Phy dev not support cmd. (udevid=%u; cmd=%d)\n", udevid, cmd);
return -EINVAL;
}
} else {
if ((cmd == UDA_CTRL_SUSPEND) || (cmd == UDA_CTRL_RESUME)
|| (cmd == UDA_CTRL_TO_MIA) || (cmd == UDA_CTRL_TO_SIA)
|| (cmd == UDA_CTRL_SHUTDOWN)) {
uda_err("Mia dev not support cmd. (udevid=%u; cmd=%d)\n", udevid, cmd);
return -EINVAL;
}
}
dev_inst = uda_dev_inst_get(udevid);
if (dev_inst == NULL) {
return -EINVAL;
}
ret = _uda_dev_ctrl(dev_inst, cmd, val);
uda_dev_inst_put(dev_inst);
return ret;
}
KA_EXPORT_SYMBOL(uda_dev_ctrl_ex);
int uda_dev_ctrl(u32 udevid, enum uda_dev_ctrl_cmd cmd)
{
return uda_dev_ctrl_ex(udevid, cmd, 0);
}
KA_EXPORT_SYMBOL(uda_dev_ctrl);
int uda_agent_dev_ctrl(u32 udevid, enum uda_dev_ctrl_cmd cmd)
{
struct uda_dev_inst *dev_inst = NULL;
int ret;
if ((cmd < 0) || (cmd >= UDA_CTRL_MAX)) {
uda_err("Invalid cmd. (udevid=%u; cmd=%d)\n", udevid, cmd);
return -EINVAL;
}
if (uda_is_phy_dev(udevid)) {
if ((cmd == UDA_CTRL_MIA_CHANGE) || (cmd == UDA_CTRL_REMOVE)) {
uda_err("Phy dev not support cmd. (udevid=%u; cmd=%d)\n", udevid, cmd);
return -EINVAL;
}
} else {
if ((cmd == UDA_CTRL_SUSPEND) || (cmd == UDA_CTRL_RESUME)
|| (cmd == UDA_CTRL_TO_MIA) || (cmd == UDA_CTRL_TO_SIA)) {
uda_err("Mia dev not support cmd. (udevid=%u; cmd=%d)\n", udevid, cmd);
return -EINVAL;
}
}
dev_inst = uda_dev_inst_get(udevid);
if (dev_inst == NULL) {
uda_err("uda_dev_inst_get fail. (udevid=%u; cmd=%d)\n", udevid, cmd);
return -EINVAL;
}
if (dev_inst->agent_dev == NULL) {
uda_err("agent dev does not exist. (udevid=%u; cmd=%d)\n", udevid, cmd);
uda_dev_inst_put(dev_inst);
return -EINVAL;
}
ret = _uda_dev_ctrl((struct uda_dev_inst *)dev_inst->agent_dev, cmd, 0);
uda_dev_inst_put(dev_inst);
return ret;
}
KA_EXPORT_SYMBOL(uda_agent_dev_ctrl);
int uda_dev_set_remote_udevid(u32 udevid, u32 remote_udevid)
{
struct uda_dev_inst *dev_inst = uda_dev_inst_get(udevid);
if (dev_inst == NULL) {
uda_err("Invalid udevid. (udevid=%u)\n", udevid);
return -EINVAL;
}
dev_inst->para.remote_udevid = remote_udevid;
uda_dev_inst_put(dev_inst);
return 0;
}
KA_EXPORT_SYMBOL(uda_dev_set_remote_udevid);
int uda_dev_get_remote_udevid(u32 udevid, u32 *remote_udevid)
{
return uda_udevid_to_remote_udevid(udevid, remote_udevid);
}
KA_EXPORT_SYMBOL(uda_dev_get_remote_udevid);
bool uda_is_support_udev_mng(void)
{
#ifdef CFG_FEATURE_SURPORT_UDEV_MNG
return true;
#else
return false;
#endif
}
KA_EXPORT_SYMBOL(uda_is_support_udev_mng);
static ka_device_t *_uda_get_device(u32 udevid, bool is_agent)
{
ka_device_t *dev = NULL;
struct uda_dev_inst *dev_inst = uda_dev_inst_get(udevid);
if (dev_inst == NULL) {
uda_err("Invalid udevid. (udevid=%u)\n", udevid);
return NULL;
}
if (is_agent) {
struct uda_dev_inst *agent_dev_inst = dev_inst->agent_dev;
if (agent_dev_inst != NULL) {
dev = agent_dev_inst->para.dev;
}
} else {
dev = dev_inst->para.dev;
}
uda_dev_inst_put(dev_inst);
return dev;
}
ka_device_t *hal_kernel_uda_get_device(u32 udevid)
{
return uda_get_device(udevid);
}
KA_EXPORT_SYMBOL(hal_kernel_uda_get_device);
ka_device_t *uda_get_device(u32 udevid)
{
return _uda_get_device(udevid, false);
}
KA_EXPORT_SYMBOL(uda_get_device);
ka_device_t *uda_get_agent_device(u32 udevid)
{
return _uda_get_device(udevid, true);
}
KA_EXPORT_SYMBOL(uda_get_agent_device);
u32 uda_get_chip_type(u32 udevid)
{
u32 chip_type = HISI_CHIP_UNKNOWN;
struct uda_dev_inst *dev_inst = uda_dev_inst_get(udevid);
if (dev_inst == NULL) {
uda_err("Invalid udevid. (udevid=%u)\n", udevid);
return HISI_CHIP_UNKNOWN;
}
chip_type = dev_inst->para.chip_type;
uda_dev_inst_put(dev_inst);
return chip_type;
}
KA_EXPORT_SYMBOL(uda_get_chip_type);
u32 uda_get_master_id(u32 udevid)
{
u32 master_id = UDA_INVALID_UDEVID;
struct uda_dev_inst *dev_inst = uda_dev_inst_get(udevid);
if (dev_inst == NULL) {
uda_err("Invalid udevid. (udevid=%u)\n", udevid);
return UDA_INVALID_UDEVID;
}
master_id = dev_inst->para.master_id;
uda_dev_inst_put(dev_inst);
return master_id;
}
KA_EXPORT_SYMBOL(uda_get_master_id);
int uda_udevid_to_mia_devid(u32 udevid, struct uda_mia_dev_para *mia_para)
{
struct uda_dev_inst *dev_inst = NULL;
if (mia_para == NULL) {
uda_err("Null ptr\n");
return -EINVAL;
}
if (udevid < UDA_MIA_UDEV_OFFSET) {
uda_err("Invalid udevid. (udevid=%u)\n", udevid);
return -EINVAL;
}
dev_inst = uda_dev_inst_get(udevid);
if (dev_inst == NULL) {
uda_err("Invalid udevid. (udevid=%u)\n", udevid);
return -EINVAL;
}
*mia_para = dev_inst->mia_para;
uda_dev_inst_put(dev_inst);
return 0;
}
KA_EXPORT_SYMBOL(uda_udevid_to_mia_devid);
int uda_mia_devid_to_udevid(struct uda_mia_dev_para *mia_para, u32 *udevid)
{
struct uda_dev_inst *dev_inst = NULL;
if ((mia_para == NULL) || (udevid == NULL)) {
uda_err("Null ptr\n");
return -EINVAL;
}
if (uda_mia_dev_check(mia_para) != 0) {
return -EINVAL;
}
*udevid = uda_make_udevid(mia_para);
dev_inst = uda_dev_inst_get(*udevid);
if (dev_inst == NULL) {
uda_err("Invalid para. (phy_devid=%u; sub_devid=%u)\n", mia_para->phy_devid, mia_para->sub_devid);
return -EINVAL;
}
uda_dev_inst_put(dev_inst);
return 0;
}
KA_EXPORT_SYMBOL(uda_mia_devid_to_udevid);
static int uda_agent_dev_status_check(u32 udevid, struct uda_dev_inst *dev_inst)
{
#if !defined(DRV_HOST) && defined(CFG_FEATURE_REMOTE_DEV_CHECK)
if ((dev_inst->agent_dev == NULL) && (dev_inst->para.remote_udevid == UDA_INVALID_UDEVID)) {
uda_debug("Remote udevid is invalid, agent dev is NULL. (udevid=%u)\n", udevid);
return -EFAULT;
}
#else
(void)udevid;
(void)dev_inst;
#endif
return 0;
}
int uda_udevid_to_remote_udevid(u32 udevid, u32 *remote_udevid)
{
int ret = 0;
struct uda_dev_inst *dev_inst = uda_dev_inst_get(udevid);
if (dev_inst == NULL) {
uda_err("Invalid udevid. (udevid=%u)\n", udevid);
return -EINVAL;
}
ret = uda_agent_dev_status_check(udevid, dev_inst);
if (ret != 0) {
return ret;
}
*remote_udevid = ((dev_inst->agent_dev != NULL) || (dev_inst->para.remote_udevid != UDA_INVALID_UDEVID)) ?
dev_inst->para.remote_udevid : udevid;
uda_dev_inst_put(dev_inst);
if (*remote_udevid == UDA_INVALID_UDEVID) {
uda_warn("Remote udevid not config. (udevid=%u)\n", udevid);
return -EFAULT;
}
return 0;
}
int uda_remote_udevid_to_udevid(u32 remote_udevid, u32 *udevid)
{
u32 i;
for (i = 0; i < UDA_UDEV_MAX_NUM; i++) {
struct uda_dev_inst *dev_inst = uda_dev_inst_get(i);
if (dev_inst == NULL) {
continue;
}
if (dev_inst->para.remote_udevid == remote_udevid) {
*udevid = i;
uda_dev_inst_put(dev_inst);
return 0;
}
uda_dev_inst_put(dev_inst);
}
return -EINVAL;
}
KA_EXPORT_SYMBOL(uda_remote_udevid_to_udevid);
u32 uda_get_dev_num_all(void)
{
u32 udevid, udev_num = 0;
for (udevid = 0; udevid < UDA_MAX_PHY_DEV_NUM; udevid++) {
if (dev_insts[udevid] != NULL) {
udev_num++;
}
}
return udev_num;
}
u32 uda_get_dev_num_local(void)
{
u32 udevid, udev_num = 0;
for (udevid = 0; udevid < UDA_MAX_PHY_DEV_NUM; udevid++) {
if (dev_insts[udevid] != NULL && dev_insts[udevid]->type.location == UDA_LOCAL) {
udev_num++;
}
}
return udev_num;
}
u32 uda_get_dev_num(void)
{
return uda_get_dev_num_adapt();
}
KA_EXPORT_SYMBOL(uda_get_dev_num);
u32 uda_get_mia_dev_num(void)
{
u32 udevid, udev_num = 0;
for (udevid = UDA_MIA_UDEV_OFFSET; udevid < UDA_UDEV_MAX_NUM; udevid++) {
if (dev_insts[udevid] != NULL) {
udev_num++;
}
}
return udev_num;
}
KA_EXPORT_SYMBOL(uda_get_mia_dev_num);
u32 uda_get_host_id(void)
{
return UDA_HOST_ID;
}
KA_EXPORT_SYMBOL(uda_get_host_id);
bool uda_is_udevid_exist(u32 udevid)
{
struct uda_dev_inst *dev_inst = uda_dev_inst_get(udevid);
if (dev_inst == NULL) {
return false;
}
uda_dev_inst_put(dev_inst);
return true;
}
KA_EXPORT_SYMBOL(uda_is_udevid_exist);
int uda_set_udevid_reorder_para(u32 add_id, struct udevid_reorder_para *para)
{
if (add_id >= UDA_UDEV_MAX_NUM || para == NULL) {
uda_err("Invalid add_id or reorder_para is NULL. (add_id=%u; para_is_NULL=%d)\n", add_id, (para == NULL));
return -EINVAL;
}
if (reorder_para == NULL) {
reorder_para = dbl_kzalloc(sizeof(struct udevid_reorder_para) * UDA_UDEV_MAX_NUM, KA_GFP_KERNEL | __KA_GFP_ACCOUNT);
if (reorder_para == NULL) {
uda_err("Out of memory.\n");
return -ENOMEM;
}
}
ka_mm_memcpy_fromio(&reorder_para[add_id], para, sizeof(struct udevid_reorder_para));
g_reorder_para_addr[add_id] = (void *)para;
return 0;
}
KA_EXPORT_SYMBOL(uda_set_udevid_reorder_para);
int uda_get_udevid_reorder_para(u32 udevid, struct udevid_reorder_para *para)
{
struct uda_dev_inst *dev_inst = NULL;
if (udevid >= UDA_UDEV_MAX_NUM || para == NULL) {
uda_err("Invalid udevid or reorder_para is NULL. (udevid=%u; info_is_NULL=%d)\n", udevid, (para == NULL));
return -EINVAL;
}
dev_inst = uda_dev_inst_get(udevid);
if (dev_inst == NULL) {
uda_err("Invalid udevid. (udevid=%u)\n", udevid);
return -EINVAL;
}
if (reorder_para == NULL) {
uda_dev_inst_put(dev_inst);
uda_err("Reorder_para is NULL.\n");
return -EINVAL;
}
*para = reorder_para[dev_inst->para.add_id];
uda_dev_inst_put(dev_inst);
return 0;
}
KA_EXPORT_SYMBOL(uda_get_udevid_reorder_para);
int uda_udevid_to_add_id(u32 udevid, u32 *add_id)
{
struct uda_dev_inst *dev_inst = NULL;
dev_inst = uda_dev_inst_get_ex(udevid);
if (dev_inst == NULL) {
*add_id = udevid;
uda_warn("Invalid udevid. (udevid=%u)\n", udevid);
return -EINVAL;
}
*add_id = dev_inst->para.add_id;
uda_dev_inst_put(dev_inst);
return 0;
}
KA_EXPORT_SYMBOL(uda_udevid_to_add_id);
int uda_add_id_to_udevid(u32 add_id, u32 *udevid)
{
struct uda_dev_inst *dev_inst = NULL;
int i;
if (udevid == NULL) {
uda_err("Null ptr\n");
return -EINVAL;
}
for (i = 0; i < UDA_UDEV_MAX_NUM; i++) {
dev_inst = uda_dev_inst_get_ex(i);
if (dev_inst == NULL) {
continue;
}
if (dev_inst->para.add_id == add_id) {
*udevid = i;
uda_dev_inst_put(dev_inst);
return 0;
}
uda_dev_inst_put(dev_inst);
}
*udevid = add_id;
uda_warn("Invalid add ID. (add_id=%u)\n", add_id);
return -EINVAL;
}
KA_EXPORT_SYMBOL(uda_add_id_to_udevid);
int uda_dev_init(void)
{
(void)memset_s(dev_insts, sizeof(dev_insts), 0, sizeof(dev_insts));
ka_task_mutex_init(&uda_dev_mutex);
ka_task_rwlock_init(&uda_dev_lock);
KA_TASK_INIT_WORK(&reorder_insts.wait_all_dev_work, uda_wait_all_dev_up_work);
return 0;
}
void uda_dev_uninit(void)
{
u32 udevid;
(void)ka_task_cancel_work_sync(&reorder_insts.wait_all_dev_work);
if (reorder_insts.dev_para != NULL) {
dbl_kfree(reorder_insts.dev_para);
reorder_insts.dev_para = NULL;
}
if (reorder_para != NULL) {
dbl_kfree(reorder_para);
reorder_para = NULL;
}
for (udevid = 0; udevid < UDA_UDEV_MAX_NUM; udevid++) {
if (dev_insts[udevid] != NULL) {
if (dev_insts[udevid]->agent_dev != NULL) {
uda_destroy_dev_inst(dev_insts[udevid]->agent_dev);
}
uda_destroy_dev_inst(dev_insts[udevid]);
}
}
}