/*

 * 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.

 */

#ifndef EVENT_SCHED_UT



#include "tsdrv_interface.h"

#include "comm_kernel_interface.h"

#include "pbl/pbl_uda.h"

#include "pbl/pbl_soc_res.h"



#include "ascend_hal_define.h"

#include "esched_kernel_interface.h"



#include "esched_fault_report.h"

#include "esched.h"

#include "esched_host_msg.h"

#include "esched_drv_adapt.h"

#include "topic_sched_common.h"

#include "topic_sched_v1.h"

#include "topic_sched_v2.h"

#include "esched_drv_adapt.h"



/* host intr reg */

#define STARS_TOPIC_HCPU_INT_REG_NUM                                2



#define STARS_TOPIC_HOST_AICPU_INT_MASK_NUM                         2



#define SCHED_HOST_CONF_INTR_FREQ         3

#define SCHED_HOST_MB_COUNT              (sizeof(u32) * KA_BITS_PER_BYTE)

#define SOFT_FAULT_REPORT_THR         60



struct esched_drv_dev_attr {

    u32 valid;

    u32 chip_id;

    u32 vf_id;

    int irq;

};



STATIC struct esched_drv_dev_attr *esched_drv_get_host_dev_attr(u32 dev_id)

{

    struct sched_hard_res *res = NULL;

    struct esched_drv_dev_attr *attr = NULL;



    res = esched_get_hard_res(dev_id);

    if (res == NULL) {

        sched_err("Failed to get hard res. (dev_id=%u)\n", dev_id);

        return NULL;

    }



    attr = (struct esched_drv_dev_attr *)res->priv;



    return (attr->valid == 1) ? attr : NULL;

}



STATIC int esched_drv_host_init_priv(struct sched_hard_res *res)

{

    int ret;

    struct esched_drv_dev_attr *attr = NULL;

    struct res_inst_info inst;



    if (res->priv == NULL) {

        res->priv = sched_vzalloc(sizeof(struct esched_drv_dev_attr) * SCHED_MAX_CHIP_NUM);

        if (res->priv == NULL) {

            return DRV_ERROR_INNER_ERR;

        }

    }



    attr = (struct esched_drv_dev_attr *)res->priv;



    ret = devdrv_get_pfvf_id_by_devid(res->dev_id, &attr->chip_id, &attr->vf_id);

    if (ret != 0) {

        sched_err("Failed to get pfvf id. (dev_id=%u)\n", res->dev_id);

        sched_vfree(res->priv);

        res->priv = NULL;

        return DRV_ERROR_INNER_ERR;

    }



    soc_resmng_inst_pack(&inst, res->dev_id, TS_SUBSYS, 0);



    ret = soc_resmng_get_irq_by_index(&inst, TS_STARS_TOPIC_IRQ, 0, &attr->irq);

    if (ret != 0) {

        sched_err("Get irq vector failed. (dev_id=%u; ret=%d)\n", res->dev_id, ret);

        sched_vfree(res->priv);

        res->priv = NULL;

        return ret;

    }



    ret = soc_resmng_get_hwirq(&inst, TS_STARS_TOPIC_IRQ, attr->irq, &res->irq[0]);

    if (ret != 0) {

        sched_err("Get hw irq failed. (irq=%u; dev_id=%u; ret=%d)\n", attr->irq, res->dev_id, ret);

        sched_vfree(res->priv);

        res->priv = NULL;

        return ret;

    }



    attr->valid = 1;



    sched_info("Host init hw res priv success. (devid=%d; vfid=%u; irq=%d)\n", res->dev_id, attr->vf_id, attr->irq);

    return DRV_ERROR_NONE;

}



STATIC void esched_drv_host_uninit_priv(struct sched_hard_res *res)

{

    if (res->priv == NULL) {

        return;

    }



    sched_vfree(res->priv);

    res->priv = NULL;

}



STATIC void topic_sched_host_aicpu_intr_mask_set(u32 dev_id, void __ka_mm_iomem *io_base,

    u32 mask_index, u32 vf_id, u32 val)

{

    if (esched_drv_get_topic_sched_version(dev_id) == (u32)TOPIC_SCHED_VERSION_V2) {

#ifndef EMU_ST

        topic_sched_host_aicpu_intr_mask_set_v2(io_base, mask_index, vf_id, val);

#endif

    } else {

        topic_sched_host_aicpu_intr_mask_set_v1(io_base, mask_index, vf_id, val);

    }

}



STATIC void topic_sched_host_ctrlcpu_intr_mask_set(u32 dev_id, void __ka_mm_iomem *io_base, u32 vf_id, u32 val)

{

    if (esched_drv_get_topic_sched_version(dev_id) == (u32)TOPIC_SCHED_VERSION_V1) {

        topic_sched_host_ctrlcpu_intr_mask_set_v1(io_base, vf_id, val);

    }

}



STATIC bool topic_sched_host_ccpu_is_mb_valid(u32 dev_id, const void __ka_mm_iomem *io_base, u32 mb_id, u32 vf_id)

{

    if (esched_drv_get_topic_sched_version(dev_id) == (u32)TOPIC_SCHED_VERSION_V1) {

        return topic_sched_host_ccpu_is_mb_valid_v1(io_base, mb_id, vf_id);

    }



    return false;

}



STATIC bool topic_sched_host_aicpu_is_mb_valid(u32 dev_id, const void __ka_mm_iomem *io_base, u32 mb_id, u32 vf_id)

{

    if (esched_drv_get_topic_sched_version(dev_id) == (u32)TOPIC_SCHED_VERSION_V2) {

#ifndef EMU_ST

        return topic_sched_host_aicpu_is_mb_valid_v2(io_base, mb_id, vf_id);

#endif

    } else {

        return topic_sched_host_aicpu_is_mb_valid_v1(io_base, mb_id, vf_id);

    }

}



STATIC void topic_sched_host_aicpu_intr_clr(u32 dev_id, void __ka_mm_iomem *io_base, u32 intr_index, u32 vf_id, u32 val)

{

    if (esched_drv_get_topic_sched_version(dev_id) == (u32)TOPIC_SCHED_VERSION_V2) {

#ifndef EMU_ST

        topic_sched_host_aicpu_intr_clr_v2(io_base, intr_index, vf_id, val);

#endif

    } else {

        topic_sched_host_aicpu_intr_clr_v1(io_base, intr_index, vf_id, val);

    }

}



STATIC void topic_sched_host_ccpu_intr_clr(u32 dev_id, void __ka_mm_iomem *io_base, u32 vf_id, u32 val)

{

    if (esched_drv_get_topic_sched_version(dev_id) == (u32)TOPIC_SCHED_VERSION_V1) {

        topic_sched_host_ccpu_intr_clr_v1(io_base, vf_id, val);

    }

}



STATIC void topic_sched_host_aicpu_intr_enable(u32 dev_id, void __ka_mm_iomem *io_base, u32 cpu_index, u32 vf_id)

{

    if (esched_drv_get_topic_sched_version(dev_id) == (u32)TOPIC_SCHED_VERSION_V2) {

#ifndef EMU_ST

        topic_sched_host_aicpu_intr_enable_v2(io_base, cpu_index, vf_id);

#endif

    } else {

        topic_sched_host_aicpu_intr_enable_v1(io_base, cpu_index, vf_id);

    }

}



STATIC void topic_sched_host_ctrlcpu_intr_enable(u32 dev_id, void __ka_mm_iomem *io_base, u32 cpu_index, u32 vf_id)

{

    if (esched_drv_get_topic_sched_version(dev_id) == (u32)TOPIC_SCHED_VERSION_V1) {

        topic_sched_host_ctrlcpu_intr_enable_v1(io_base, cpu_index, vf_id);

    }

}



STATIC void topic_sched_host_aicpu_int_all_status(u32 dev_id, const void __ka_mm_iomem *io_base, u32 *val, u32 vf_id)

{

    if (esched_drv_get_topic_sched_version(dev_id) == (u32)TOPIC_SCHED_VERSION_V2) {

#ifndef EMU_ST

        topic_sched_host_aicpu_int_all_status_v2(io_base, val, vf_id);

#endif

    } else {

        topic_sched_host_aicpu_int_all_status_v1(io_base, val, vf_id);

    }

}



STATIC void topic_sched_host_aicpu_intr_all_clr(u32 dev_id, void __ka_mm_iomem *io_base, u32 val, u32 vf_id)

{

    if (esched_drv_get_topic_sched_version(dev_id) == (u32)TOPIC_SCHED_VERSION_V2) {

#ifndef EMU_ST

        topic_sched_host_aicpu_intr_all_clr_v2(io_base, val, vf_id);

#endif

    } else {

        topic_sched_host_aicpu_intr_all_clr_v1(io_base, val, vf_id);

    }

}



STATIC void topic_sched_host_aicpu_int_status(u32 dev_id, const void __ka_mm_iomem *io_base,

    u32 intr_index, u32 *val, u32 vf_id)

{

    if (esched_drv_get_topic_sched_version(dev_id) == (u32)TOPIC_SCHED_VERSION_V2) {

#ifndef EMU_ST

        topic_sched_host_aicpu_int_status_v2(io_base, intr_index, val, vf_id);

#endif

    } else {

        topic_sched_host_aicpu_int_status_v1(io_base, intr_index, val, vf_id);

    }

}



STATIC void topic_sched_host_ccpu_int_status(u32 dev_id, const void __ka_mm_iomem *io_base, u32 *val, u32 vf_id)

{

    if (esched_drv_get_topic_sched_version(dev_id) != (u32)TOPIC_SCHED_VERSION_V2) {

        topic_sched_host_ccpu_int_status_v1(io_base, val, vf_id);

    } else {

        *val = 0;

    }

}



u32 esched_get_devid_from_hw_vfid(u32 chip_id, u32 hw_vfid, u32 sub_dev_num, u32 topic_id)

{

    return chip_id;

}



u32 esched_get_hw_vfid_from_devid(u32 dev_id)

{

    struct esched_drv_dev_attr *dev_attr = esched_drv_get_host_dev_attr(dev_id);



    return ESCHED_DRV_REASSIGN_VFID(dev_attr->vf_id);

}



bool esched_is_phy_dev(u32 dev_id)

{

    struct esched_drv_dev_attr *dev_attr = esched_drv_get_host_dev_attr(dev_id);



    return (dev_attr->vf_id > 0) ? false : true;

}



int esched_drv_config_pid(struct sched_proc_ctx *proc_ctx, u32 identity, devdrv_host_pids_info_t *pids_info)

{

    if (esched_drv_get_topic_sched_version(proc_ctx->node->node_id) != (u32)TOPIC_SCHED_VERSION_V1) {

#ifndef EMU_ST

        return 0;

#endif

    }



    if (pids_info->cp_type[0] == (unsigned int)DEVDRV_PROCESS_USER) {

        return 0;

    }



    return esched_drv_remote_add_pid(proc_ctx->node->node_id, proc_ctx->host_pid,

        pids_info->cp_type[0], proc_ctx->pid);

}



void esched_drv_del_pid(struct sched_proc_ctx *proc_ctx, u32 identity)

{

    if (esched_drv_get_topic_sched_version(proc_ctx->node->node_id) != (u32)TOPIC_SCHED_VERSION_V1) {

#ifndef EMU_ST

        return;

#endif

    }



    (void)esched_drv_remote_del_pid(proc_ctx->node->node_id, proc_ctx->host_pid, proc_ctx->pid);

}



void esched_drv_cpu_report(struct topic_data_chan *topic_chan, u32 error_code, u32 status)

{

    struct esched_drv_dev_attr *dev_attr = esched_drv_get_host_dev_attr(topic_chan->hard_res->dev_id);



    if (dev_attr == NULL) {

#ifndef EMU_ST

        sched_err("Invalid dev attr. (dev_id=%u)\n", topic_chan->hard_res->dev_id);

        return;

#endif

    }



    if (esched_drv_get_topic_sched_version(topic_chan->hard_res->dev_id) == (u32)TOPIC_SCHED_VERSION_V2) {

#ifndef EMU_ST

        esched_drv_cpu_report_v2(topic_chan, dev_attr->vf_id, error_code, status);

#endif

    } else {

        esched_drv_cpu_report_v1(topic_chan, dev_attr->vf_id, error_code, status);

    }

}



void esched_drv_get_status_report(struct topic_data_chan *topic_chan, u32 status)

{

}



bool esched_drv_is_mb_valid(struct topic_data_chan *topic_chan)

{

    struct esched_drv_dev_attr *dev_attr = esched_drv_get_host_dev_attr(topic_chan->hard_res->dev_id);



    if (dev_attr == NULL) {

        sched_err("Invalid dev attr. (dev_id=%u)\n", topic_chan->hard_res->dev_id);

        return 0;

    }



    if (topic_chan->mb_type == ACPU_HOST) {

        return topic_sched_host_aicpu_is_mb_valid(topic_chan->hard_res->dev_id, topic_chan->hard_res->io_base,

            topic_chan->mb_id, dev_attr->vf_id);

    } else {

        return topic_sched_host_ccpu_is_mb_valid(topic_chan->hard_res->dev_id, topic_chan->hard_res->io_base,

            topic_chan->mb_id, dev_attr->vf_id);

    }

}



bool esched_drv_is_get_mb_valid(struct topic_data_chan *topic_chan)

{

    return false;

}



int esched_cpu_port_submit_task(struct topic_data_chan *topic_chan, void *split_task, u32 timeout)

{

    return -EFAULT;

}



void esched_cpu_port_reset(struct topic_data_chan *topic_chan, struct sched_cpu_port_clear_info *clr_info)

{

}



STATIC void esched_drv_host_mb_intr_clr(struct topic_data_chan *topic_chan, u32 intr_index, u32 val, u32 vf_id)

{

    if (topic_chan->mb_type == ACPU_HOST) {

        topic_sched_host_aicpu_intr_clr(topic_chan->hard_res->dev_id, topic_chan->hard_res->io_base,

            intr_index, vf_id, val);

    }



    if (topic_chan->mb_type == CCPU_HOST) {

        topic_sched_host_ccpu_intr_clr(topic_chan->hard_res->dev_id, topic_chan->hard_res->io_base, vf_id, val);

    }

}



static void esched_drv_host_init_node_aicpu_chan(struct sched_numa_node *node)

{

    u32 chip_type = uda_get_chip_type(node->node_id);

    if ((chip_type == HISI_CLOUD_V2) || (chip_type == HISI_CLOUD_V4) || (chip_type == HISI_CLOUD_V5)) {

        node->hard_res.aicpu_chan_num = TOPIC_SCHED_HOST_AICPU_CHAN_NUM;

    } else {

        node->hard_res.aicpu_chan_num = 0;

    }



    node->hard_res.aicpu_chan_start_id = 0;



    node->hard_res.thread_spec.get_chan_func = NULL;

}



STATIC struct esched_drv_dev_attr *esched_drv_interrupt_get_host_dev_attr(u32 dev_id)

{

    struct sched_hard_res *res = NULL;

    struct esched_drv_dev_attr *attr = NULL;

    struct sched_numa_node *node = sched_get_numa_node(dev_id);

    if (node == NULL) {

        return NULL;

    }



    res = &node->hard_res;

    attr = (struct esched_drv_dev_attr *)res->priv;



    return (attr->valid == 1) ? attr : NULL;

}



STATIC struct topic_data_chan *esched_drv_interrupt_get_topic_chan(u32 dev_id, u32 chan_id)

{

    struct sched_numa_node *node = sched_get_numa_node(dev_id);



    if (chan_id >= TOPIC_SCHED_MAX_CHAN_NUM) {

        return NULL;

    }



    return node->hard_res.topic_chan[chan_id];

}





STATIC ka_irqreturn_t esched_drv_host_task_interrupt(int irq, void *data)

{

    struct sched_hard_res *res = (struct sched_hard_res *)data;

    struct topic_data_chan *topic_chan = NULL;

    struct sched_cpu_ctx *cpu_ctx = NULL;

    u32 offset, mb_id, i, val = 0;

    struct esched_drv_dev_attr *dev_attr = esched_drv_interrupt_get_host_dev_attr(res->dev_id);



    if (dev_attr == NULL) {

        return KA_IRQ_HANDLED;

    }



    for (i = 0; i < STARS_TOPIC_HCPU_INT_REG_NUM; i++) {

        topic_sched_host_aicpu_int_status(res->dev_id, res->io_base, i, &val, dev_attr->vf_id);



        if (val == 0) {

            continue;

        }



        for (offset = 0; offset < SCHED_HOST_MB_COUNT; offset++) {

            if ((val >> offset) & 0x1) {

                mb_id = SCHED_HOST_MB_COUNT * i + offset;

                topic_chan = esched_drv_interrupt_get_topic_chan(res->dev_id, mb_id);

                if (topic_chan == NULL) {

                    continue;

                }

                esched_drv_host_mb_intr_clr(topic_chan, i, val, dev_attr->vf_id);

                ka_system_tasklet_schedule(&topic_chan->sched_task);

            }

        }

    }



    /* Clear merge interrupt status */

    topic_sched_host_aicpu_int_all_status(res->dev_id, res->io_base, &val, dev_attr->vf_id);

    topic_sched_host_aicpu_intr_all_clr(res->dev_id, res->io_base, val, dev_attr->vf_id);



    topic_sched_host_ccpu_int_status(res->dev_id, res->io_base, &val, dev_attr->vf_id);

    if (val == 0) {

        return KA_IRQ_HANDLED;

    }



    cpu_ctx = sched_get_cpu_ctx(sched_get_numa_node(res->dev_id), NON_SCHED_DEFAULT_CPUID);

    esched_drv_host_mb_intr_clr(cpu_ctx->topic_chan, 0, val, dev_attr->vf_id);

    ka_system_tasklet_schedule(&cpu_ctx->topic_chan->sched_task);



    return KA_IRQ_HANDLED;

}



void esched_drv_mb_intr_enable(struct topic_data_chan *topic_chan)

{

    struct esched_drv_dev_attr *dev_attr = esched_drv_get_host_dev_attr(topic_chan->hard_res->dev_id);



    if (dev_attr == NULL) {

        sched_err("Invalid dev attr. (dev_id=%u)\n", topic_chan->hard_res->dev_id);

        return;

    }



    sched_debug("(uda_get_chip_type=%u; topic_chan->mb_type=%u)\n",

        uda_get_chip_type(topic_chan->hard_res->dev_id), topic_chan->mb_type);



    if (topic_chan->mb_type == ACPU_HOST) {

        topic_sched_host_aicpu_intr_enable(topic_chan->hard_res->dev_id, topic_chan->hard_res->io_base,

            topic_chan->mb_id, dev_attr->vf_id);

    } else {

        topic_sched_host_ctrlcpu_intr_enable(topic_chan->hard_res->dev_id, topic_chan->hard_res->io_base,

            topic_chan->mb_id, dev_attr->vf_id);

    }



    sched_debug("Show details. (mb_id=%u; mb_type=%u; irq=%d)\n",

        topic_chan->mb_id, topic_chan->mb_type, topic_chan->irq);

}



STATIC void esched_drv_host_init_cpu_mb(u32 chip_id, u32 mb_index, u32 wait_mb_id)

{

    struct topic_data_chan *topic_chan = esched_drv_get_topic_chan(chip_id, wait_mb_id);

    u32 offset = TOPIC_SCHED_MB_SIZE * wait_mb_id;



    topic_chan->mb_id = mb_index;

    topic_chan->chan_id = mb_index;



    /* host rsv_mem_va only use for mailbox */

    topic_chan->wait_mb = (struct topic_sched_mailbox *)(topic_chan->hard_res->rsv_mem_va + offset);



    sched_debug("Show details. (chip_id=%u; mb_type=%u; mb_index=%u; wait_mb_id=%u; offset=0x%x)\n",

        chip_id, topic_chan->mb_type, mb_index, wait_mb_id, offset);



    return;

}



STATIC int esched_drv_host_config_intr(struct sched_hard_res *res)

{

    int ret;



    /* hard sched just need to handle one irq in host */

    ret = esched_drv_remote_config_intr(res->dev_id, res->irq[0]);

    if (ret != 0) {

        sched_debug("Remote config irq_base not success. (dev_id=%u; irq_base=%d; ret=%d)\n",

            res->dev_id, res->irq[0], ret);

        return ret;

    }



    return 0;

}



STATIC int esched_drv_init_aicpu_chan(struct sched_numa_node *node)

{

    u32 chip_id = node->node_id;

    struct esched_drv_dev_attr *dev_attr = esched_drv_get_host_dev_attr(chip_id);

    struct sched_hard_res *res = esched_get_hard_res(chip_id);

    struct topic_data_chan *topic_chan = NULL;

    u32 i, chan_id;



    if (dev_attr == NULL) {

        sched_err("Invalid dev attr. (chip_id=%u)\n", chip_id);

        return DRV_ERROR_INVALID_DEVICE;

    }



    esched_drv_remote_add_mb(chip_id, dev_attr->vf_id);



    for (i = 0; i < res->aicpu_chan_num; i++) {

        chan_id = res->aicpu_chan_start_id + i;

        topic_chan = esched_drv_get_topic_chan(chip_id, chan_id);

        if (topic_chan == NULL) {

            return DRV_ERROR_INNER_ERR;

        }



        topic_chan->irq = res->irq[0];

        topic_chan->mb_type = ACPU_HOST;

        topic_chan->hard_res = res;

        topic_chan->cpu_ctx = NULL;

        esched_drv_host_init_cpu_mb(chip_id, chan_id, chan_id);

        ka_system_tasklet_init(&topic_chan->sched_task, esched_aicpu_sched_task, (uintptr_t)topic_chan);

        topic_chan->valid = SCHED_VALID;

    }



    return 0;

}



STATIC void esched_drv_uninit_aicpu_chan(struct sched_numa_node *node)

{

    struct topic_data_chan *topic_chan = NULL;

    struct sched_hard_res *res = &node->hard_res;

    u32 i, chan_id;



    for (i = 0; i < res->aicpu_chan_num; i++) {

#ifndef EMU_ST

        chan_id = res->aicpu_chan_start_id + i;

        topic_chan = esched_drv_get_topic_chan(node->node_id, chan_id);

        if (topic_chan == NULL) {

            continue;

        }

        if (topic_chan->valid == SCHED_VALID) {

            ka_system_tasklet_kill(&topic_chan->sched_task);

            topic_chan->valid = SCHED_INVALID;

        }

#endif

    }

}



STATIC int esched_drv_init_aicpu_topic_chan(struct sched_numa_node *node)

{

    int ret;



    ret = esched_drv_create_topic_chans(node->node_id, 0, node->hard_res.aicpu_chan_num, 0);

    if (ret != 0) {

        return ret;

    }



    ret = esched_drv_init_aicpu_chan(node);

    if (ret != 0) {

        esched_drv_destroy_topic_chans(node->node_id, 0, node->hard_res.aicpu_chan_num);

        return ret;

    }



    return 0;

}



STATIC void esched_drv_uninit_aicpu_topic_chan(struct sched_numa_node *node)

{

    esched_drv_uninit_aicpu_chan(node);

    esched_drv_destroy_topic_chans(node->node_id, 0, node->hard_res.aicpu_chan_num);

}



STATIC int esched_drv_init_ccpu_chan(struct sched_numa_node *node, u32 mb_id)

{

    u32 dev_id = node->node_id;

    struct topic_data_chan *topic_chan = NULL;

    struct sched_hard_res *res = esched_get_hard_res(dev_id);

    struct esched_drv_dev_attr *dev_attr = esched_drv_get_host_dev_attr(dev_id);

    u32 chan_id = res->ccpu_chan_id;



    if (dev_attr == NULL) {

        sched_err("Invalid dev attr. (dev_id=%u)\n", dev_id);

        return DRV_ERROR_INVALID_DEVICE;

    }



    topic_chan = esched_drv_get_topic_chan(dev_id, chan_id);

    if (topic_chan == NULL) {

        return DRV_ERROR_INNER_ERR;

    }



    topic_chan->irq = res->irq[0];   /* Not used in host side */

    topic_chan->mb_type = CCPU_HOST;

    topic_chan->hard_res = res;

    topic_chan->serial_no = 0;

    topic_chan->cpu_ctx = sched_get_cpu_ctx(node, NON_SCHED_DEFAULT_CPUID);

    topic_chan->cpu_ctx->topic_chan = topic_chan;



    esched_drv_host_init_cpu_mb(dev_id, mb_id, chan_id);

    ka_system_tasklet_init(&topic_chan->sched_task, esched_ccpu_sched_task, (uintptr_t)topic_chan);

    topic_chan->valid = SCHED_VALID;



    esched_drv_remote_add_mb(dev_id, dev_attr->vf_id);



    return 0;

}



STATIC void esched_drv_uninit_ccpu_chan(struct sched_numa_node *node)

{

    struct topic_data_chan *topic_chan = esched_drv_get_topic_chan(node->node_id, node->hard_res.ccpu_chan_id);



    if (topic_chan == NULL) {

        return;

    }



    if (topic_chan->valid == SCHED_VALID) {

        ka_system_tasklet_kill(&topic_chan->sched_task);

        topic_chan->valid = SCHED_INVALID;

    }

}



STATIC void esched_drv_uninit_ccpu_topic_chan(struct sched_numa_node *node)

{

    esched_drv_uninit_ccpu_chan(node);

    esched_drv_destroy_one_topic_chan(node->node_id, node->hard_res.ccpu_chan_id);

}



STATIC int esched_drv_init_ccpu_topic_chan(struct sched_numa_node *node)

{

    struct topic_data_chan *topic_chan = NULL;

    int ret;

    u32 mb_id, chan_id;



    ret = esched_drv_remote_get_cpu_mbid(node->node_id, CCPU_HOST, &mb_id, &chan_id);

    if (ret != 0) {

        return ret;

    }



    node->hard_res.ccpu_chan_id = chan_id;



    topic_chan = esched_drv_create_one_topic_chan(node->node_id, chan_id);

    if (topic_chan == NULL) {

        return DRV_ERROR_INNER_ERR;

    }



    ret = esched_drv_init_ccpu_chan(node, mb_id);

    if (ret != 0) {

        esched_drv_destroy_one_topic_chan(node->node_id, chan_id);

        return ret;

    }



    return 0;

}



STATIC int esched_drv_host_init_irq(struct sched_hard_res *res)

{

    u32 dev_id = res->dev_id;

    int ret;

    struct esched_drv_dev_attr *attr = (struct esched_drv_dev_attr *)res->priv;



    if (attr == NULL) {

        sched_err("Invalid attr. (dev_id=%u\n", dev_id);

        return DRV_ERROR_PARA_ERROR;

    }



    ret = devdrv_register_irq_by_vector_index(dev_id, (int)res->irq[0], esched_drv_host_task_interrupt,

        (void *)res, "topic_sched_aicpu");

    if (ret != 0) {

        sched_err("Request irq failed. (dev_id=%u; irq=%u; ret=%d)\n", dev_id, attr->irq, ret);

        return ret;

    }



    /* all cpu in host can handle the same irq */

    (void)ka_base_irq_set_affinity_hint(attr->irq, NULL);

    res->irq_reg_flag = 1;



    sched_info("Request irq success. (dev_id=%u; irq=%u)\n", dev_id, attr->irq);



    return 0;

}



STATIC void esched_drv_host_uninit_irq(struct sched_hard_res *res)

{

    struct esched_drv_dev_attr *attr = (struct esched_drv_dev_attr *)res->priv;



    if (attr == NULL) {

        sched_err("Invalid attr. (dev_id=%u\n", res->dev_id);

        return;

    }



    if (res->irq_reg_flag == 1) {

        (void)ka_base_irq_set_affinity_hint((u32)attr->irq, NULL);

        (void)devdrv_unregister_irq_by_vector_index(res->dev_id, res->irq[0], (void *)res);

        res->irq_reg_flag = 0;

    }

}



STATIC int esched_drv_host_init_aicpu_pool(struct sched_numa_node *node)

{

    int ret;



    ret = esched_drv_remote_add_pool(node->node_id, ACPU_HOST);

    if (ret != 0) {

        sched_err("Add aicpu pool failed. (devid=%u)\n", node->node_id);

        return ret;

    }



    sched_info("Add aicpu pool success. (devid=%u)\n", node->node_id);



    return 0;

}



STATIC int esched_drv_init_ccpu_pool(struct sched_numa_node *node)

{

    int ret;



    ret = esched_drv_remote_add_pool(node->node_id, CCPU_HOST);

    if (ret != 0) {

        sched_err("Add ccpu pool failed. (devid=%u)\n", node->node_id);

        return ret;

    }



    sched_info("Add ccpu pool success. (devid=%u)\n", node->node_id);

    return 0;

}



STATIC int esched_drv_host_ccpu_chan_init(struct sched_numa_node *node)

{

    int ret;



    if (esched_drv_get_topic_sched_version(node->node_id) == (u32)TOPIC_SCHED_VERSION_V2) {

#ifndef EMU_ST

        return 0;

#endif

    }



    ret = esched_drv_init_ccpu_pool(node);

    if (ret != 0) {

        return ret;

    }



    ret = esched_drv_init_ccpu_topic_chan(node);

    if (ret != 0) {

        return ret;

    }



    return 0;

}



STATIC void esched_drv_host_ccpu_chan_uninit(struct sched_numa_node *node)

{

    if (esched_drv_get_topic_sched_version(node->node_id) == (u32)TOPIC_SCHED_VERSION_V2) {

#ifndef EMU_ST

        return;

#endif

    }



    esched_drv_uninit_ccpu_topic_chan(node);

}



STATIC int esched_drv_host_aicpu_chan_init(struct sched_numa_node *node)

{

    int ret;



    esched_drv_host_init_node_aicpu_chan(node);



    ret = esched_drv_host_init_aicpu_pool(node);

    if (ret != 0) {

        return ret;

    }



    ret = esched_drv_init_aicpu_topic_chan(node);

    if (ret != 0) {

        return ret;

    }



    return 0;

}



STATIC void esched_drv_host_aicpu_chan_uninit(struct sched_numa_node *node)

{

    esched_drv_uninit_aicpu_topic_chan(node);

}



STATIC int esched_drv_host_map_addr(u32 dev_id, struct sched_hard_res *res)

{

    if (esched_drv_get_topic_sched_version(dev_id) == (u32)TOPIC_SCHED_VERSION_V2) {

#ifndef EMU_ST

        return esched_drv_host_map_addr_v2(dev_id, res);

#endif

    } else {

        return esched_drv_host_map_addr_v1(dev_id, res);

    }

}



STATIC void esched_host_iounmap(struct sched_hard_res *res)

{

    if (esched_drv_get_topic_sched_version(res->dev_id) == (u32)TOPIC_SCHED_VERSION_V2) {

#ifndef EMU_ST

        esched_host_iounmap_v2(res);

#endif

    } else {

        esched_host_iounmap_v1(res);

    }

}



STATIC void esched_drv_init_host_cpu_intr_mask(struct sched_hard_res *res)

{

    int i;

    struct esched_drv_dev_attr *dev_attr = esched_drv_get_host_dev_attr(res->dev_id);



    if (dev_attr == NULL) {

        sched_err("Invalid dev attr. (dev_id=%u)\n", res->dev_id);

        return;

    }



    /* init host aicpu intr mask */

    for (i = 0; i < STARS_TOPIC_HOST_AICPU_INT_MASK_NUM; i++) {

        topic_sched_host_aicpu_intr_mask_set(res->dev_id, res->io_base, i, dev_attr->vf_id, 0);

    }



    /* init host ctrlcpu intr mask */

    topic_sched_host_ctrlcpu_intr_mask_set(res->dev_id, res->io_base, dev_attr->vf_id, 0);

}



STATIC void esched_drv_host_mb_intr_all_reset(struct sched_hard_res *res)

{

    struct topic_data_chan *topic_chan = NULL;

    struct sched_cpu_ctx *cpu_ctx = NULL;

    u32 offset, mb_id, i, val = 0;

    u32 vf_id = ((struct esched_drv_dev_attr *)res->priv)->vf_id;

    u32 chip_type;



    for (i = 0; i < STARS_TOPIC_HCPU_INT_REG_NUM; i++) {

        topic_sched_host_aicpu_int_status(res->dev_id, res->io_base, i, &val, vf_id);

        for (offset = 0; offset < SCHED_HOST_MB_COUNT; offset++) {

            mb_id = SCHED_HOST_MB_COUNT * i + offset;

            topic_chan = esched_drv_get_topic_chan(res->dev_id, mb_id);

            if ((topic_chan == NULL) || (topic_chan->valid != SCHED_VALID)) {

                continue;

            }

            if ((val >> offset) & 0x1) {

                esched_drv_host_mb_intr_clr(topic_chan, i, val, vf_id);

            }

            esched_drv_mb_intr_enable(topic_chan);

        }

    }



    topic_sched_host_aicpu_int_all_status(res->dev_id, res->io_base, &val, vf_id);

    topic_sched_host_aicpu_intr_all_clr(res->dev_id, res->io_base, val, vf_id);



    chip_type = uda_get_chip_type(res->dev_id);

    /* topic v2 only support aicpu. */

    if ((chip_type != HISI_CLOUD_V4) && (chip_type != HISI_CLOUD_V5)) {

        cpu_ctx = sched_get_cpu_ctx(sched_get_numa_node(res->dev_id), NON_SCHED_DEFAULT_CPUID);

        topic_sched_host_ccpu_int_status(res->dev_id, res->io_base, &val, vf_id);

        if (val != 0) {

            esched_drv_host_mb_intr_clr(cpu_ctx->topic_chan, 0, val, vf_id);

        }

        esched_drv_mb_intr_enable(cpu_ctx->topic_chan);

    }

}



STATIC int esched_drv_host_init_non_sched_task_submit_chan(u32 chip_id, u32 pool_id)

{

#ifndef EMU_ST

    if (esched_drv_get_topic_sched_version(chip_id) == (u32)TOPIC_SCHED_VERSION_V2) {

        return 0;

    }

#endif

    return esched_drv_init_non_sched_task_submit_chan(chip_id, pool_id);

}



STATIC void esched_drv_host_uninit_non_sched_task_submit_chan(u32 chip_id)

{

#ifndef EMU_ST

    if (esched_drv_get_topic_sched_version(chip_id) == (u32)TOPIC_SCHED_VERSION_V2) {

        return;

    }

#endif

    return esched_drv_uninit_non_sched_task_submit_chan(chip_id);

}



static int esched_drv_host_get_udev_pool_id(u32 dev_id, u32 *pool_id)

{

    if (esched_drv_get_topic_sched_version(dev_id) == (u32)TOPIC_SCHED_VERSION_V1) {

        *pool_id = TOPIC_SCHED_HOST_POOL_ID;

        return 0;

    }



#ifndef EMU_ST

    return esched_drv_remote_get_pool_id(dev_id, pool_id);

#else

    return 0;

#endif

}



STATIC int esched_drv_init_msg_chan_main_proc(struct sched_hard_res *res)

{

    struct sched_numa_node *node = sched_get_numa_node(res->dev_id);

    u32 pool_id;

    int ret;



    ret = esched_drv_host_get_udev_pool_id(res->dev_id, &pool_id);

    if (ret != 0) {

#ifndef EMU_ST

        sched_err("Get udev pool id failed. (udev_id=%u)\n", res->dev_id);

        return DRV_ERROR_INNER_ERR;

#endif

    }



    ret = esched_drv_host_init_non_sched_task_submit_chan(res->dev_id, pool_id);

    if (ret != 0) {

        return DRV_ERROR_INNER_ERR;

    }



    ret = esched_drv_init_sched_task_submit_chan(res->dev_id, pool_id, 1, 1);

    if (ret != 0) {

#ifndef EMU_ST

        sched_err("Sched task chan init failed. (dev_id=%u)\n", res->dev_id);

        esched_drv_host_uninit_non_sched_task_submit_chan(res->dev_id);

        return 0;

#endif

    }



    ret = esched_drv_host_ccpu_chan_init(node);

    if (ret != 0) {

#ifndef EMU_ST

        sched_err("Host ccpu init failed. (dev_id=%u)\n", res->dev_id);

        esched_drv_uninit_sched_task_submit_chan(res->dev_id);

        esched_drv_host_uninit_non_sched_task_submit_chan(res->dev_id);

        return 0;

#endif

    }



    ret = esched_drv_host_aicpu_chan_init(node);

    if (ret != 0) {

#ifndef EMU_ST

        sched_err("Host aicpu init failed. (dev_id=%u)\n", res->dev_id);

        esched_drv_host_ccpu_chan_uninit(node);

        esched_drv_uninit_sched_task_submit_chan(res->dev_id);

        esched_drv_host_uninit_non_sched_task_submit_chan(res->dev_id);

        return 0;

#endif

    }



    ret = esched_drv_host_init_irq(res);

    if (ret != 0) {

        sched_err("Host irq init failed. (dev_id=%u)\n", res->dev_id);

        esched_drv_host_aicpu_chan_uninit(node);

        esched_drv_host_ccpu_chan_uninit(node);

        esched_drv_uninit_sched_task_submit_chan(res->dev_id);

        esched_drv_host_uninit_non_sched_task_submit_chan(res->dev_id);

        return 0;

    }



    esched_drv_host_mb_intr_all_reset(res);



    res->init_flag = SCHED_VALID;

    sched_info("Hw dev init success. (dev_id=%u)\n", res->dev_id);

    return 0;

}



STATIC void esched_drv_init_msg_chan_work(ka_work_struct_t *p_work)

{

    struct sched_hard_res *res = ka_container_of(p_work, struct sched_hard_res, init.work);

    int ret;



    if (res->intr_config_flag == SCHED_INVALID) {

        ret = esched_drv_host_config_intr(res);

        if (ret != 0) {

            res->retry_times++;

            sched_debug("Retry. (dev_id=%u; retry_times=%u; ret=%d)\n", res->dev_id, res->retry_times, ret);

            (void)ka_task_schedule_delayed_work(&res->init, SCHED_HOST_CONF_INTR_FREQ * KA_HZ);

            return;

        }

        res->intr_config_flag = SCHED_VALID;

    }



    ret = esched_drv_init_msg_chan_main_proc(res);

    if (ret != 0) {

        res->retry_times++;

        if ((res->retry_times > SOFT_FAULT_REPORT_THR) && (res->report_fault_flag == 0)) {

            res->report_fault_flag = 1;

            esched_kernel_soft_fault_report(res->dev_id);

        }

        sched_debug("Retry. (dev_id=%u; retry_times=%u; ret=%d)\n", res->dev_id, res->retry_times, ret);

        (void)ka_task_schedule_delayed_work(&res->init, 1 * KA_HZ);

        return;

    }



    return;

}



STATIC int esched_drv_init_msg_chan(struct sched_hard_res *res)

{

    int ret;



    if (res->intr_config_flag == SCHED_INVALID) {

        ret = esched_drv_host_config_intr(res);

        if (ret != 0) {

            res->retry_times++;

            return DRV_ERROR_INNER_ERR;

        }

        res->intr_config_flag = SCHED_VALID;

    }



    ret = esched_drv_init_msg_chan_main_proc(res);

    if (ret != 0) {

        res->retry_times++;

        sched_debug("Retry. (dev_id=%u; retry_times=%u; ret=%d)\n", res->dev_id, res->retry_times, ret);

        return DRV_ERROR_INNER_ERR;

    }

    res->delay_work_enable = 0;



    return 0;

}



int esched_drv_reset_phy_dev(u32 devid)

{

#ifndef EMU_ST

    int connect_type = devdrv_get_connect_protocol(devid);

    if ((connect_type != CONNECT_PROTOCOL_PCIE) && (connect_type != CONNECT_PROTOCOL_HCCS)) {

        return 0;

    }

#endif

    esched_drv_uninit_sched_task_submit_chan(devid);

    esched_drv_host_uninit_non_sched_task_submit_chan(devid);

    return 0;

}



void esched_drv_restore_phy_dev(u32 devid)

{

#ifndef EMU_ST

    int connect_type = devdrv_get_connect_protocol(devid);

    if ((connect_type != CONNECT_PROTOCOL_PCIE) && (connect_type != CONNECT_PROTOCOL_HCCS)) {

        return;

    }

#endif

    (void)esched_drv_host_config_intr(esched_get_hard_res(devid));

    (void)esched_drv_host_init_non_sched_task_submit_chan(devid, 0);

    (void)esched_drv_init_sched_task_submit_chan(devid, TOPIC_SCHED_HOST_POOL_ID, 1, 1);

    (void)esched_drv_host_init_priv(esched_get_hard_res(devid));

    esched_drv_host_mb_intr_all_reset(esched_get_hard_res(devid));

}



int esched_hw_dev_init(struct sched_numa_node *node)

{

    struct res_inst_info inst;

    struct sched_hard_res *res = &node->hard_res;

    u32 chip_id = node->node_id;

    u32 index = 0;

    int ret;

    u32 chip_type;

    u32 pool_id;

    int connect_type = devdrv_get_connect_protocol(chip_id);

    if ((connect_type != CONNECT_PROTOCOL_PCIE) && (connect_type != CONNECT_PROTOCOL_HCCS)) {

        return 0;

    }



    esched_drv_init_topic_types(chip_id);

    esched_drv_init_topic_sched_version(chip_id);



    res->dev_id = chip_id;



    soc_resmng_inst_pack(&inst, chip_id, TS_SUBSYS, 0);

    ret = soc_resmng_get_irq_num(&inst, TS_STARS_TOPIC_IRQ, &res->irq_num);

    if (ret != 0) {

#ifndef EMU_ST

        sched_err("Get irq num failed. (index=%u; chip_id=%u; ret=%d)\n", index, chip_id, ret);

        return ret;

#endif

    }



    res->irq = (int *)sched_vzalloc(sizeof(int) * res->irq_num);

    if (res->irq == NULL) {

        sched_err("Failed to vzalloc memory for res irq array. (size=0x%lx)\n", sizeof(int) * res->irq_num);

        return DRV_ERROR_OUT_OF_MEMORY;

    }



    ret = esched_drv_host_init_priv(res);

    if (ret != 0) {

        sched_vfree(res->irq);

        res->irq = NULL;

        sched_err("Host init priv failed. (chip_id=%u; ret=%d)\n", chip_id, ret);

        return ret;

    }



    ret = esched_drv_host_map_addr(chip_id, res);

    if (ret != 0) {

        esched_drv_host_uninit_priv(res);

        sched_vfree(res->irq);

        res->irq = NULL;

        sched_err("Failed to map addr. (chip_id=%u; ret=%d)\n", chip_id, ret);

        return ret;

    }



    chip_type = uda_get_chip_type(chip_id);

    if (!uda_is_phy_dev(chip_id) && ((chip_type == HISI_CLOUD_V4) || (chip_type == HISI_CLOUD_V5))) {

        ret = esched_drv_host_get_udev_pool_id(chip_id, &pool_id);

        if (ret != 0) {

    #ifndef EMU_ST

            esched_host_iounmap(res);

            esched_drv_host_uninit_priv(res);

            sched_vfree(res->irq);

            res->irq = NULL;

            sched_err("Get udev pool id failed. (udev_id=%u; ret=%d)\n", res->dev_id, ret);

            return ret;

    #endif

        }



        ret = esched_drv_init_sched_task_submit_chan(chip_id, pool_id, 1, 1);

        if (ret != 0) {

    #ifndef EMU_ST

            esched_host_iounmap(res);

            esched_drv_host_uninit_priv(res);

            sched_vfree(res->irq);

            res->irq = NULL;

            esched_kernel_soft_fault_report(chip_id);

            sched_err("Sched task chan init failed. (dev_id=%u; ret=%d)\n", res->dev_id, ret);

            return ret;

    #endif

        }

        res->init_flag = SCHED_VALID;

        sched_info("Host VF init success. (chip_id=%u, topic_sched_version=%u)\n", chip_id, res->topic_sched_version);

        return 0;

    }



    esched_drv_init_host_cpu_intr_mask(res);

    ret = esched_drv_init_msg_chan(res);

    if (ret != 0) {

        sched_warn("device not ready, need start delay work to retry. (chip_id=%u)\n", chip_id);

        KA_TASK_INIT_DELAYED_WORK(&res->init,  esched_drv_init_msg_chan_work);

        (void)ka_task_schedule_delayed_work(&res->init, 0);

        res->delay_work_enable = 1;

    }



    sched_info("Show details. (chip_id=%u, topic_sched_version=%u)\n", chip_id, res->topic_sched_version);



    return 0;

}



void esched_hw_dev_uninit(struct sched_numa_node *node)

{

    struct sched_hard_res *res = &node->hard_res;

    u32 chip_id = node->node_id;

    u32 chip_type;

    int connect_type = devdrv_get_connect_protocol(chip_id);

    if ((connect_type != CONNECT_PROTOCOL_PCIE) && (connect_type != CONNECT_PROTOCOL_HCCS)) {

        return;

    }



    res->init_flag = SCHED_INVALID;

    if (res->delay_work_enable != 0) {

        (void)ka_task_cancel_delayed_work_sync(&res->init);

    }

    res->delay_work_enable = 0;



    chip_type = uda_get_chip_type(chip_id);

    if (!uda_is_phy_dev(chip_id) && ((chip_type == HISI_CLOUD_V4) || (chip_type == HISI_CLOUD_V5))) {

        esched_drv_uninit_sched_task_submit_chan(chip_id);

        esched_host_iounmap(res);

        esched_drv_host_uninit_priv(res);

        sched_vfree(res->irq);

        res->irq = NULL;

        sched_info("Host vf uninit success. (chip_id=%u)\n", chip_id);

        return;

    }



    esched_drv_host_uninit_non_sched_task_submit_chan(chip_id);

    esched_drv_uninit_sched_task_submit_chan(chip_id);

    esched_drv_host_uninit_irq(res);

    esched_drv_host_ccpu_chan_uninit(node);

    esched_drv_host_aicpu_chan_uninit(node);

    esched_host_iounmap(res);



    sched_info("Show details. (chip_id=%u)\n", chip_id);



    esched_drv_host_uninit_priv(res);

    sched_vfree(res->irq);

    res->irq = NULL;

}

#else

void esched_drv_adapt_ut(void)

{

}

#endif