* 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 "securec.h"
#include "ka_list_pub.h"
#include "ka_memory_pub.h"
#include "ka_task_pub.h"
#include "ka_driver_pub.h"
#include "ka_base_pub.h"
#include "ka_kernel_def_pub.h"
#include "fms/fms_dtm.h"
#include "fms_define.h"
#include "pbl_mem_alloc_interface.h"
#include "dms_dtm_init.h"
#define HOST_LOCAL 1000
struct state_item_list {
struct state_item item;
ka_list_head_t list;
};
static struct dms_system_ctrl_block *g_dms_system_ccb = NULL;
#ifdef CFG_FEATURE_DEVICE_STATE_TABLE
static struct dms_state_table g_dms_state_table = {};
static void dms_state_table_list_node_init(struct state_item_list *item_node, uint32_t node_type, uint32_t node_id)
{
KA_INIT_LIST_HEAD(&item_node->list);
item_node->item.node_type = node_type;
item_node->item.node_id = node_id;
}
static void dms_state_table_parse_node(ka_list_head_t *dms_node_list, ka_device_node_t *node, uint32_t *cnt)
{
struct state_item_list *item_node = NULL;
uint32_t *id = NULL;
uint32_t type, num, i, real_num;
int ret;
ret = of_property_read_u32(node, "node_type", &type);
if (ret != 0) {
dms_warn("state table node type unrecognizable, (ret=%d)\n", ret);
return;
}
ret = of_property_read_u32(node, "node_num", &num);
if (ret != 0) {
dms_warn("state table node num unrecognizable, (type=%u; ret=%d)\n", type, ret);
return;
}
if (num == 0) {
dms_warn("state table node num warn, (num=0)\n");
return;
}
id = ka_mm_kmalloc(sizeof(uint32_t) * num, KA_GFP_KERNEL | __KA_GFP_ACCOUNT);
if (id == NULL) {
dms_warn("state table node id alloc warn, (type=%u; num=%u)\n", type, num);
return;
}
ret = of_property_read_variable_u32_array(node, "node_id", id, 0, num);
if (ret < 0) {
dms_warn("state table node id read warn, (type=%u; num=%u; ret=%d)\n", type, num, ret);
ka_mm_kfree(id);
return;
}
real_num = (uint32_t)ret;
if (real_num != num) {
dms_warn("state table node num not equal, (type=%u; num=%u; real=%u)\n", type, num, real_num);
}
for (i = 0; i < real_num; i++) {
item_node = ka_mm_kzalloc(sizeof(struct state_item_list), KA_GFP_KERNEL | __KA_GFP_ACCOUNT);
if (item_node == NULL) {
dms_warn("state table item node alloc warn, (type=%u; i=%u)\n", type, i);
break;
}
dms_state_table_list_node_init(item_node, type, id[i]);
ka_list_add(&item_node->list, dms_node_list);
*cnt = *cnt + 1;
}
ka_mm_kfree(id);
}
static void dms_state_table_entry_init(struct state_item *item, struct state_item_list *item_node)
{
item->node_type = item_node->item.node_type;
item->node_id = item_node->item.node_id;
item->node = NULL;
}
int state_item_cmp(const void *a, const void *b)
{
const struct state_item *ia = (const struct state_item *)a;
const struct state_item *ib = (const struct state_item *)b;
if (ia->node_type != ib->node_type) {
return ia->node_type - ib->node_type;
} else {
return ia->node_id - ib->node_id;
}
}
static void dms_init_device_state_table(void)
{
ka_list_head_t dms_node_list = {};
ka_device_node_t *np = NULL;
ka_device_node_t *child = NULL;
struct state_item_list *item_node = NULL;
struct state_item_list *temp_node = NULL;
uint32_t cnt = 0, i = 0;
KA_INIT_LIST_HEAD(&dms_node_list);
np = ka_driver_of_find_compatible_node(NULL, NULL, "hisi,dms_device_table");
if (np == NULL) {
dms_info("dms state table no valid node\n");
return;
}
ka_driver_for_each_child_of_node(np, child) {
dms_state_table_parse_node(&dms_node_list, child, &cnt);
}
ka_driver_of_node_put(np);
if (cnt == 0) {
dms_info("dms state table cnt is 0\n");
return;
}
g_dms_state_table.item = ka_mm_vzalloc(sizeof(struct state_item) * cnt);
if (g_dms_state_table.item == NULL) {
dms_warn("device state table alloc no mem, (size=%zu)\n", sizeof(struct state_item) * cnt);
ka_list_for_each_entry_safe(item_node, temp_node, &dms_node_list, list) {
ka_list_del(&item_node->list);
ka_mm_kfree(item_node);
}
return;
}
g_dms_state_table.num = cnt;
ka_list_for_each_entry_safe(item_node, temp_node, &dms_node_list, list) {
dms_state_table_entry_init(&g_dms_state_table.item[i], item_node);
ka_list_del(&item_node->list);
ka_mm_kfree(item_node);
i++;
}
ka_base_sort(g_dms_state_table.item, cnt, sizeof(struct state_item), state_item_cmp, NULL);
dms_info("dms state table init success, (cnt=%u).\n", cnt);
}
static void dms_uninit_device_state_table(void)
{
if (g_dms_state_table.item != NULL) {
ka_mm_vfree(g_dms_state_table.item);
g_dms_state_table.item = NULL;
}
g_dms_state_table.num = 0;
}
struct dms_state_table *dms_get_state_table(void)
{
return &g_dms_state_table;
}
KA_EXPORT_SYMBOL(dms_get_state_table);
#endif
struct dms_system_ctrl_block* dms_get_sys_ctrl_cb(void)
{
return g_dms_system_ccb;
}
KA_EXPORT_SYMBOL(dms_get_sys_ctrl_cb);
static void dms_free_sys_ctrl_cb(void)
{
if (g_dms_system_ccb != NULL) {
dbl_kfree(g_dms_system_ccb);
g_dms_system_ccb = NULL;
}
}
int dms_check_device_id(int dev_id)
{
if ((dev_id < 0) || (dev_id >= ASCEND_DEV_MAX_NUM)) {
return -1;
}
return 0;
}
KA_EXPORT_SYMBOL(dms_check_device_id);
DMS_MODE_T dms_get_rc_ep_mode(void)
{
#ifdef CFG_FEATURE_EP_MODE
return DMS_EP_MODE;
#else
return DMS_RC_MODE;
#endif
}
KA_EXPORT_SYMBOL(dms_get_rc_ep_mode);
struct dms_dev_ctrl_block* dms_get_dev_cb(int dev_id)
{
struct dms_system_ctrl_block* cb = dms_get_sys_ctrl_cb();
int ret;
if (cb == NULL) {
dms_err("g_dms_system_ccb is NULL. \n");
return NULL;
}
ret = dms_check_device_id(dev_id);
if (ret != 0) {
dms_err("dev_id out of range. (ret=%d; dev_id=%d)\n", ret, dev_id);
return NULL;
}
return &cb->dev_cb_table[dev_id];
}
KA_EXPORT_SYMBOL(dms_get_dev_cb);
bool dms_is_devid_valid(int dev_id)
{
struct dms_dev_ctrl_block *dev_cb = NULL;
dev_cb = dms_get_dev_cb(dev_id);
if (dev_cb == NULL) {
dms_err("Get dev_ctrl block failed. (dev_id=%d)\n", dev_id);
return false ;
}
if (dev_cb->state != DMS_IN_USED) {
dms_err("Device state not in used. (dev_id=%d; state=%u)\n", dev_id, dev_cb->state);
return false ;
}
return true;
}
KA_EXPORT_SYMBOL(dms_is_devid_valid);
STATIC int dms_init_dev_cb(void)
{
int i;
struct dms_dev_ctrl_block* cb;
g_dms_system_ccb = dbl_kzalloc(sizeof(struct dms_system_ctrl_block), KA_GFP_KERNEL | __KA_GFP_ACCOUNT);
if (g_dms_system_ccb == NULL) {
dms_err("Memory alloc for g_dms_system_ccb failed.\n");
return -ENOMEM;
}
cb = &g_dms_system_ccb->base_cb;
ka_task_mutex_init(&cb->node_lock);
KA_INIT_LIST_HEAD(&cb->dev_node_list);
for (i = 0; i < ASCEND_DEV_MAX_NUM; i++) {
cb = &g_dms_system_ccb->dev_cb_table[i];
ka_task_mutex_init(&cb->node_lock);
KA_INIT_LIST_HEAD(&cb->dev_node_list);
}
return 0;
}
STATIC void dms_uninit_dev_cb(void)
{
int i;
struct dms_dev_ctrl_block* cb;
cb = &g_dms_system_ccb->base_cb;
ka_task_mutex_lock(&cb->node_lock);
ka_task_mutex_unlock(&cb->node_lock);
ka_task_mutex_destroy(&cb->node_lock);
KA_INIT_LIST_HEAD(&cb->dev_node_list);
for (i = 0; i < ASCEND_DEV_MAX_NUM; i++) {
cb = &g_dms_system_ccb->dev_cb_table[i];
ka_task_mutex_lock(&cb->node_lock);
ka_task_mutex_unlock(&cb->node_lock);
ka_task_mutex_destroy(&cb->node_lock);
KA_INIT_LIST_HEAD(&cb->dev_node_list);
}
dms_free_sys_ctrl_cb();
}
int dms_dtm_init(void)
{
int ret;
dms_info("dms_dtm_init start.\n");
ret = dms_init_dev_cb();
if (ret != 0) {
dms_err("dms init dev cb failed.(ret=%d)\n", ret);
return ret;
}
#ifdef CFG_FEATURE_DEVICE_STATE_TABLE
dms_init_device_state_table();
#endif
dms_info("Dms driver init success.\n");
return ret;
}
void dms_dtm_exit(void)
{
dms_info("dms_dtm_exit start.\n");
#ifdef CFG_FEATURE_DEVICE_STATE_TABLE
dms_uninit_device_state_table();
#endif
dms_uninit_dev_cb();
dms_info("Dms dtm driver exit success.\n");
}