* 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_base_pub.h"
#include "ka_list_pub.h"
#include "ka_memory_pub.h"
#include "ka_task_pub.h"
#include "soc_resmng_log.h"
#include "soc_subsys_ts.h"
int subsys_ts_set_rsv_mem(struct soc_resmng_ts *ts_resmng, const char *name, struct soc_rsv_mem_info *rsv_mem)
{
struct soc_rsv_mem *mem = NULL;
ka_task_mutex_lock(&ts_resmng->mutex);
mem = rsv_mem_node_find(name, &ts_resmng->rsv_mems_head);
if (mem != NULL) {
soc_res_name_copy(mem->name, name);
mem->info = *rsv_mem;
ka_task_mutex_unlock(&ts_resmng->mutex);
return 0;
}
mem = ka_mm_kzalloc(sizeof(*mem), KA_GFP_KERNEL);
if (mem == NULL) {
ka_task_mutex_unlock(&ts_resmng->mutex);
return -ENOSPC;
}
soc_res_name_copy(mem->name, name);
mem->info = *rsv_mem;
ka_list_add(&mem->list_node, &ts_resmng->rsv_mems_head);
ka_task_mutex_unlock(&ts_resmng->mutex);
return 0;
}
int subsys_ts_get_rsv_mem(struct soc_resmng_ts *ts_resmng, const char *name, struct soc_rsv_mem_info *rsv_mem)
{
struct soc_rsv_mem *mem = NULL;
ka_task_mutex_lock(&ts_resmng->mutex);
mem = rsv_mem_node_find(name, &ts_resmng->rsv_mems_head);
if (mem == NULL) {
ka_task_mutex_unlock(&ts_resmng->mutex);
return -ENOENT;
}
*rsv_mem = mem->info;
ka_task_mutex_unlock(&ts_resmng->mutex);
return 0;
}
int subsys_ts_set_reg_base(struct soc_resmng_ts *ts_resmng, const char *name,
struct soc_reg_base_info *io_base)
{
struct soc_reg_base *reg = NULL;
ka_task_mutex_lock(&ts_resmng->mutex);
reg = io_bases_node_find(name, &ts_resmng->io_bases_head);
if (reg != NULL) {
soc_res_name_copy(reg->name, name);
reg->info = *io_base;
ka_task_mutex_unlock(&ts_resmng->mutex);
return 0;
}
reg = ka_mm_kzalloc(sizeof(*reg), KA_GFP_KERNEL);
if (reg == NULL) {
ka_task_mutex_unlock(&ts_resmng->mutex);
return -ENOSPC;
}
soc_res_name_copy(reg->name, name);
reg->info = *io_base;
ka_list_add(®->list_node, &ts_resmng->io_bases_head);
ka_task_mutex_unlock(&ts_resmng->mutex);
return 0;
}
int subsys_ts_get_reg_base(struct soc_resmng_ts *ts_resmng, const char *name,
struct soc_reg_base_info *io_base)
{
struct soc_reg_base *reg = NULL;
ka_task_mutex_lock(&ts_resmng->mutex);
reg = io_bases_node_find(name, &ts_resmng->io_bases_head);
if (reg == NULL) {
ka_task_mutex_unlock(&ts_resmng->mutex);
return -ENOENT;
}
*io_base = reg->info;
ka_task_mutex_unlock(&ts_resmng->mutex);
return 0;
}
int subsys_ts_set_irq_num(struct soc_resmng_ts *ts_resmng, u32 irq_type, u32 irq_num)
{
struct soc_irq_info *info = NULL;
int ret;
if (irq_type >= TS_IRQ_TYPE_MAX) {
soc_err("Param is illegal. (type=%u)\n", irq_type);
return -EINVAL;
}
info = &ts_resmng->irq_infos[irq_type];
ka_task_mutex_lock(&ts_resmng->mutex);
if (info->irqs != NULL) {
resmng_irqs_destroy(info);
}
ret = resmng_irqs_create(info, irq_num);
if (ret != 0) {
ka_task_mutex_unlock(&ts_resmng->mutex);
soc_err("Irq_base create failed. (irq_num=%u)\n", irq_num);
return ret;
}
info->irq_num = irq_num;
ka_task_mutex_unlock(&ts_resmng->mutex);
return 0;
}
int subsys_ts_get_irq_num(struct soc_resmng_ts *ts_resmng, u32 irq_type, u32 *irq_num)
{
struct soc_irq_info *info = NULL;
if (irq_type >= TS_IRQ_TYPE_MAX) {
soc_err("Param is illegal. (type=%u)\n", irq_type);
return -EINVAL;
}
info = &ts_resmng->irq_infos[irq_type];
ka_task_mutex_lock(&ts_resmng->mutex);
if (info->irqs == NULL) {
ka_task_mutex_unlock(&ts_resmng->mutex);
return -ENOENT;
}
*irq_num = info->irq_num;
ka_task_mutex_unlock(&ts_resmng->mutex);
return 0;
}
int subsys_ts_set_irq_by_index(struct soc_resmng_ts *ts_resmng, u32 irq_type, u32 index, u32 irq)
{
struct soc_irq_info *info = NULL;
if (irq_type >= TS_IRQ_TYPE_MAX) {
soc_err("Param is illegal. (type=%u)\n", irq_type);
return -EINVAL;
}
info = &ts_resmng->irq_infos[irq_type];
ka_task_mutex_lock(&ts_resmng->mutex);
if (index >= info->irq_num) {
ka_task_mutex_unlock(&ts_resmng->mutex);
soc_err("Index is illegal. (index=%u; irq_num=%u; irq_type=%u)\n", index, info->irq_num, irq_type);
return -EINVAL;
}
info->irqs[index].irq = irq;
ka_task_mutex_unlock(&ts_resmng->mutex);
return 0;
}
int subsys_ts_get_irq_by_index(struct soc_resmng_ts *ts_resmng, u32 irq_type, u32 index, u32 *irq)
{
struct soc_irq_info *info = NULL;
if (irq_type >= TS_IRQ_TYPE_MAX) {
soc_err("Param is illegal. (type=%u)\n", irq_type);
return -EINVAL;
}
info = &ts_resmng->irq_infos[irq_type];
ka_task_mutex_lock(&ts_resmng->mutex);
if (index >= info->irq_num) {
ka_task_mutex_unlock(&ts_resmng->mutex);
soc_err("Index is illegal. (index=%u; irq_num=%u; irq_type=%u)\n", index, info->irq_num, irq_type);
return -EINVAL;
}
if (info->irqs[index].irq == SOC_IRQ_INVALID_VALUE) {
ka_task_mutex_unlock(&ts_resmng->mutex);
return -ENOENT;
}
*irq = info->irqs[index].irq;
ka_task_mutex_unlock(&ts_resmng->mutex);
return 0;
}
int subsys_ts_set_irq(struct soc_resmng_ts *ts_resmng, u32 irq_type, u32 irq)
{
struct soc_irq_info *info = NULL;
if (irq_type >= TS_IRQ_TYPE_MAX) {
return -EINVAL;
}
info = &ts_resmng->irq_infos[irq_type];
ka_task_mutex_lock(&ts_resmng->mutex);
info->irq = irq;
info->valid = true;
ka_task_mutex_unlock(&ts_resmng->mutex);
return 0;
}
int subsys_ts_get_irq(struct soc_resmng_ts *ts_resmng, u32 irq_type, u32 *irq)
{
struct soc_irq_info *info = NULL;
if (irq_type >= TS_IRQ_TYPE_MAX) {
soc_err("Param is illegal. (type=%u)\n", irq_type);
return -EINVAL;
}
info = &ts_resmng->irq_infos[irq_type];
ka_task_mutex_lock(&ts_resmng->mutex);
if (info->valid == false) {
ka_task_mutex_unlock(&ts_resmng->mutex);
return -ENOENT;
}
*irq = info->irq;
ka_task_mutex_unlock(&ts_resmng->mutex);
return 0;
}
int subsys_ts_set_hwirq(struct soc_resmng_ts *ts_resmng, u32 irq_type, u32 irq, u32 hwirq)
{
struct soc_irq_info *info = NULL;
int index;
if (irq_type >= TS_IRQ_TYPE_MAX) {
return -EINVAL;
}
info = &ts_resmng->irq_infos[irq_type];
ka_task_mutex_lock(&ts_resmng->mutex);
index = find_irq_index(info, irq);
if (index == info->irq_num) {
ka_task_mutex_unlock(&ts_resmng->mutex);
soc_err("No such irq. (type=%u; irq=%u)\n", irq_type, irq);
return -EINVAL;
}
if (info->irqs[index].hwirq != SOC_IRQ_INVALID_VALUE) {
ka_task_mutex_unlock(&ts_resmng->mutex);
soc_err("Repeated set. (type=%u; irq=%u)\n", irq_type, irq);
return -EEXIST;
}
info->irqs[index].hwirq = hwirq;
ka_task_mutex_unlock(&ts_resmng->mutex);
return 0;
}
int subsys_ts_get_hwirq(struct soc_resmng_ts *ts_resmng, u32 irq_type, u32 irq, u32 *hwirq)
{
struct soc_irq_info *info = NULL;
int index;
if (irq_type >= TS_IRQ_TYPE_MAX) {
soc_err("Param is illegal. (type=%u)\n", irq_type);
return -EINVAL;
}
info = &ts_resmng->irq_infos[irq_type];
ka_task_mutex_lock(&ts_resmng->mutex);
index = find_irq_index(info, irq);
if (index == info->irq_num) {
ka_task_mutex_unlock(&ts_resmng->mutex);
soc_warn("No such irq. (type=%u; irq=%u)\n", irq_type, irq);
return -EINVAL;
}
if (info->irqs[index].hwirq == SOC_IRQ_INVALID_VALUE) {
ka_task_mutex_unlock(&ts_resmng->mutex);
return -ENOENT;
}
*hwirq = info->irqs[index].hwirq;
ka_task_mutex_unlock(&ts_resmng->mutex);
return 0;
}
int subsys_ts_set_tscpu_to_taishan_irq(struct soc_resmng_ts *ts_resmng, u32 irq_type, u32 irq, u32 tscpu_to_taishan_irq)
{
struct soc_irq_info *info = NULL;
int index;
if (irq_type >= TS_IRQ_TYPE_MAX) {
return -EINVAL;
}
info = &ts_resmng->irq_infos[irq_type];
ka_task_mutex_lock(&ts_resmng->mutex);
index = find_irq_index(info, irq);
if (index == info->irq_num) {
ka_task_mutex_unlock(&ts_resmng->mutex);
soc_err("No such irq. (type=%u; irq=%u)\n", irq_type, irq);
return -EINVAL;
}
if (info->irqs[index].tscpu_to_taishan_irq != SOC_IRQ_INVALID_VALUE) {
ka_task_mutex_unlock(&ts_resmng->mutex);
soc_err("Repeated set. (type=%u; irq=%u)\n", irq_type, irq);
return -EEXIST;
}
info->irqs[index].tscpu_to_taishan_irq = tscpu_to_taishan_irq;
ka_task_mutex_unlock(&ts_resmng->mutex);
return 0;
}
int subsys_ts_get_tscpu_to_taishan_irq(struct soc_resmng_ts *ts_resmng, u32 irq_type, u32 irq,
u32 *tscpu_to_taishan_irq)
{
struct soc_irq_info *info = NULL;
int index;
if (irq_type >= TS_IRQ_TYPE_MAX) {
soc_err("Param is illegal. (type=%u)\n", irq_type);
return -EINVAL;
}
info = &ts_resmng->irq_infos[irq_type];
ka_task_mutex_lock(&ts_resmng->mutex);
index = find_irq_index(info, irq);
if (index == info->irq_num) {
ka_task_mutex_unlock(&ts_resmng->mutex);
soc_err("No such irq. (type=%u; irq=%u)\n", irq_type, irq);
return -EINVAL;
}
if (info->irqs[index].tscpu_to_taishan_irq == SOC_IRQ_INVALID_VALUE) {
ka_task_mutex_unlock(&ts_resmng->mutex);
return -ENOENT;
}
*tscpu_to_taishan_irq = info->irqs[index].tscpu_to_taishan_irq;
ka_task_mutex_unlock(&ts_resmng->mutex);
return 0;
}
int subsys_ts_set_key_value(struct soc_resmng_ts *ts_resmng, const char *name, u64 value)
{
int ret;
ka_task_mutex_lock(&ts_resmng->mutex);
ret = dev_set_key_value(&ts_resmng->key_value_head, name, value);
ka_task_mutex_unlock(&ts_resmng->mutex);
return ret;
}
int subsys_ts_get_key_value(struct soc_resmng_ts *ts_resmng, const char *name, u64 *value)
{
int ret;
ka_task_mutex_lock(&ts_resmng->mutex);
ret = dev_get_key_value(&ts_resmng->key_value_head, name, value);
ka_task_mutex_unlock(&ts_resmng->mutex);
return ret;
}
void subsys_ts_set_ts_status(struct soc_resmng_ts *ts_resmng, u32 status)
{
ka_base_atomic_set(&ts_resmng->ts_status, status);
}
void subsys_ts_get_ts_status(struct soc_resmng_ts *ts_resmng, u32 *status)
{
*status = (u32)ka_base_atomic_read(&ts_resmng->ts_status);
}
int subsys_ts_set_mia_res_ex(struct soc_resmng_ts *ts_resmng, u32 type, struct soc_mia_res_info_ex *info)
{
if (type >= MIA_MAX_RES_TYPE) {
soc_err("Invalid mia res type. (type=%u)\n", type);
return -EINVAL;
}
ka_task_mutex_lock(&ts_resmng->mutex);
ts_resmng->res_info_ex[type].start = info->start;
ts_resmng->res_info_ex[type].total_num = info->total_num;
ts_resmng->res_info_ex[type].bitmap = info->bitmap;
ts_resmng->res_info_ex[type].unit_per_bit = info->unit_per_bit;
ka_task_mutex_unlock(&ts_resmng->mutex);
return 0;
}
int subsys_ts_get_mia_res_ex(struct soc_resmng_ts *ts_resmng, u32 type, struct soc_mia_res_info_ex *info)
{
if (type >= MIA_MAX_RES_TYPE) {
return -EINVAL;
}
ka_task_mutex_lock(&ts_resmng->mutex);
info->start = ts_resmng->res_info_ex[type].start;
info->total_num = ts_resmng->res_info_ex[type].total_num;
info->bitmap = ts_resmng->res_info_ex[type].bitmap;
info->unit_per_bit = ts_resmng->res_info_ex[type].unit_per_bit;
ka_task_mutex_unlock(&ts_resmng->mutex);
return 0;
}