* 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 "uda_pub_def.h"
#include "pbl_spod_info.h"
#include "ka_barrier_pub.h"
#include "ka_kernel_def_pub.h"
#include "ka_base_pub.h"
#include "ka_task_pub.h"
#include "ka_memory_pub.h"
#include "pbl/pbl_uda.h"
#include "pbl_mem_alloc_interface.h"
#include "spod_info.h"
struct spod_info g_spod_info[UDA_MAX_PHY_DEV_NUM];
bool g_spod_info_been_set[UDA_MAX_PHY_DEV_NUM];
struct spod_node_status {
u8 status[DBL_SPOD_MAX_NUM];
};
#ifdef DRV_HOST
static struct spod_node_status *g_spod_node_status[UDA_MAX_PHY_DEV_NUM] = {NULL};
static ka_rw_semaphore_t g_spod_node_status_lock[UDA_MAX_PHY_DEV_NUM];
#endif
int dbl_get_spod_info(unsigned int udevid, struct spod_info *s)
{
if (udevid >= UDA_MAX_PHY_DEV_NUM || s == NULL) {
return -EINVAL;
}
if (!g_spod_info_been_set[udevid]) {
return -EAGAIN;
}
*s = g_spod_info[udevid];
return 0;
}
KA_EXPORT_SYMBOL(dbl_get_spod_info);
int dbl_set_spod_info(unsigned int udevid, struct spod_info *s)
{
if (udevid >= UDA_MAX_PHY_DEV_NUM || s == NULL) {
return -EINVAL;
}
g_spod_info[udevid] = *s;
ka_mb();
g_spod_info_been_set[udevid] = true;
return 0;
}
KA_EXPORT_SYMBOL(dbl_set_spod_info);
#define UDEVID_BIT_LEN 16
#define DIE_ID_BIT_LEN 2
#define CHIP_ID_BIT_LEN 4
#define SERVER_ID_BIT_LEN 10
static inline void parse_bit_shift(unsigned int *rcv, unsigned int *src, int bit_width)
{
*rcv = (*src) & KA_GENMASK(bit_width - 1, 0);
(*src) >>= bit_width;
}
int dbl_parse_sdid (unsigned int sdid, struct sdid_parse_info *s)
{
if (s == NULL) {
return -EINVAL;
}
parse_bit_shift(&s->udevid, &sdid, UDEVID_BIT_LEN);
parse_bit_shift(&s->die_id, &sdid, DIE_ID_BIT_LEN);
parse_bit_shift(&s->chip_id, &sdid, CHIP_ID_BIT_LEN);
parse_bit_shift(&s->server_id, &sdid, SERVER_ID_BIT_LEN);
return 0;
}
KA_EXPORT_SYMBOL(dbl_parse_sdid);
int dbl_make_sdid (struct sdid_parse_info *s, unsigned int *sdid)
{
unsigned int tmp_sdid;
if (s == NULL || sdid == NULL) {
return -EINVAL;
}
tmp_sdid = s->server_id;
tmp_sdid <<= CHIP_ID_BIT_LEN;
tmp_sdid |= s->chip_id;
tmp_sdid <<= DIE_ID_BIT_LEN;
tmp_sdid |= s->die_id;
tmp_sdid <<= UDEVID_BIT_LEN;
tmp_sdid |= s->udevid;
*sdid = tmp_sdid;
return 0;
}
KA_EXPORT_SYMBOL(dbl_make_sdid);
#ifdef DRV_HOST
static int dbl_get_spod_node_status(unsigned int local_udevid, unsigned int index, unsigned int *status)
{
struct spod_node_status *nodes_status = NULL;
ka_task_down_read(&g_spod_node_status_lock[local_udevid]);
nodes_status = g_spod_node_status[local_udevid];
if (nodes_status == NULL) {
ka_task_up_read(&g_spod_node_status_lock[local_udevid]);
return -ENODATA;
}
*status = nodes_status->status[index];
ka_task_up_read(&g_spod_node_status_lock[local_udevid]);
return 0;
}
int dbl_set_spod_node_status(unsigned int local_udevid, unsigned int index, unsigned int status)
{
struct spod_node_status *nodes_status = NULL;
if (local_udevid >= UDA_MAX_PHY_DEV_NUM) {
uda_err("Invalid udevid. (udevid=%u)\n", local_udevid);
return -EINVAL;
}
if (index >= DBL_SPOD_MAX_NUM) {
uda_err("Invalid index. (index=%u)\n", index);
return -EINVAL;
}
ka_task_down_write(&g_spod_node_status_lock[local_udevid]);
nodes_status = g_spod_node_status[local_udevid];
if (nodes_status == NULL) {
ka_task_up_write(&g_spod_node_status_lock[local_udevid]);
uda_err("Spod node status has not been inited. (local_udevid=%u)\n", local_udevid);
return -ENODATA;
}
nodes_status->status[index] = status;
ka_task_up_write(&g_spod_node_status_lock[local_udevid]);
return 0;
}
KA_EXPORT_SYMBOL_GPL(dbl_set_spod_node_status);
int dbl_spod_node_status_init(unsigned int udevid)
{
struct spod_node_status *nodes_status = NULL;
if (udevid >= UDA_MAX_PHY_DEV_NUM) {
uda_err("Invalid udevid. (udevid=%u)\n", udevid);
return -EINVAL;
}
ka_task_down_write(&g_spod_node_status_lock[udevid]);
if (g_spod_node_status[udevid] != NULL) {
ka_task_up_write(&g_spod_node_status_lock[udevid]);
uda_info("Spod node status has been inited. (udevid=%u)", udevid);
return 0;
}
nodes_status = (struct spod_node_status *)dbl_kzalloc(sizeof(struct spod_node_status), KA_GFP_KERNEL | __KA_GFP_ACCOUNT);
if (nodes_status == NULL) {
ka_task_up_write(&g_spod_node_status_lock[udevid]);
uda_err("malloc spod node status failed. (udevid=%u)", udevid);
return -ENOMEM;
}
g_spod_node_status[udevid] = nodes_status;
ka_task_up_write(&g_spod_node_status_lock[udevid]);
return 0;
}
KA_EXPORT_SYMBOL_GPL(dbl_spod_node_status_init);
void dbl_spod_node_status_uninit(unsigned int udevid)
{
if (udevid >= UDA_MAX_PHY_DEV_NUM) {
uda_err("Invalid udevid. (udevid=%u)\n", udevid);
return;
}
ka_task_down_write(&g_spod_node_status_lock[udevid]);
if (g_spod_node_status[udevid] == NULL) {
ka_task_up_write(&g_spod_node_status_lock[udevid]);
return;
}
dbl_kfree(g_spod_node_status[udevid]);
g_spod_node_status[udevid] = NULL;
ka_task_up_write(&g_spod_node_status_lock[udevid]);
}
KA_EXPORT_SYMBOL_GPL(dbl_spod_node_status_uninit);
void spod_info_init(void)
{
int i;
for (i = 0; i < UDA_MAX_PHY_DEV_NUM; ++i) {
ka_task_init_rwsem(&g_spod_node_status_lock[i]);
}
}
#endif
int hal_kernel_get_spod_node_status(unsigned int local_udevid, unsigned int remote_sdid, unsigned int *status)
{
#ifdef DRV_HOST
int ret = 0;
struct sdid_parse_info sdid_info = {0};
int index = 0;
unsigned int soc_type = SOC_TYPE_MAX;
if (!uda_is_phy_dev(local_udevid)) {
return -EOPNOTSUPP;
}
if (local_udevid >= UDA_MAX_PHY_DEV_NUM) {
return -EINVAL;
}
if (status == NULL) {
return -EFAULT;
}
ret = dbl_parse_sdid(remote_sdid, &sdid_info);
if (ret != 0) {
return ret;
}
DBL_SPOD_CHECK_SDID(sdid_info, ret);
if (ret != 0) {
return -ERANGE;
}
ret = hal_kernel_get_soc_type(local_udevid, &soc_type);
if (ret != 0) {
return (ret == -EOPNOTSUPP ? ret : -ENODEV);
}
if (soc_type != SOC_TYPE_CLOUD_V3) {
return -EOPNOTSUPP;
}
index = sdid_info.server_id * DBL_SPOD_MAX_UDEVID_NUM + sdid_info.udevid;
return dbl_get_spod_node_status(local_udevid, index, status);
#else
(void) local_udevid;
(void) remote_sdid;
(void) status;
return -EOPNOTSUPP;
#endif
}