-- Copyright (c) 2024 Huawei Technologies Co., Ltd.
-- openUBMC is licensed under Mulan PSL v2.
-- You can use this software according to the terms and conditions of the Mulan PSL v2.
-- You may obtain a copy of Mulan PSL v2 at: http://license.coscl.org.cn/MulanPSL2
-- THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
-- EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
-- MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
-- See the Mulan PSL v2 for more details.

local log = require 'mc.logging'
local ncsi_channel = require 'ncsi.ncsi_protocol.ncsi_channel'
local ncsi_def = require 'ncsi.ncsi_protocol.ncsi_def'
local ncsi_package = require 'ncsi.ncsi_protocol.ncsi_package'
local ncsi_clear_state = require 'ncsi.ncsi_protocol.ncsi_clear_state'
local ncsi_version = require 'ncsi.ncsi_protocol.ncsi_version'
local ncsi_capabilities = require 'ncsi.ncsi_protocol.ncsi_capabilities'
local ncsi_aen = require 'ncsi.ncsi_protocol.ncsi_aen'
local ncsi_channel_init = require 'ncsi.ncsi_protocol.ncsi_channel_init'
local ncsi_parameter = require 'ncsi.ncsi_protocol.ncsi_parameter'

local ncsi_init = {}

local NCSI_ENABLED = 1
local NCSI_PACKAGE_MAX_ID = 8
local PACKAGE_SUPPORT = 1
local CHANNEL_SUPPORT = 1
local INTEL_MANUFACTURE_ID = 0x57010000

-- 初始化标志，确保iid只设置一次
local g_ncsi_paramter_init_flag = 0

-- 配置单个包的NCSI设置，包括包选择、状态清除、版本获取等
local function ncsi_configuration_setting_one(channel_id, eth_name)
    local ncsi_para = ncsi_parameter.get_instance():get_ncsi_parameter()
    for i = 0, NCSI_PACKAGE_MAX_ID - 1 do
        -- 选择包
        local ret = ncsi_package.ncsi_select_package(i, eth_name)
        if ret ~= ncsi_def.NCSI_SUCCESS then
            goto continue
        end

        -- 设置包存在标志
        ncsi_para.package_exist[i] = PACKAGE_SUPPORT
        -- 清除初始状态
        if ncsi_clear_state.ncsi_clear_initial_state(i, channel_id, eth_name) == ncsi_def.NCSI_SUCCESS then
            -- 设置通道存在标志
            ncsi_para.channel_exist[i][channel_id] = CHANNEL_SUPPORT

            -- 获取版本ID和ncsi能力
            if ncsi_version.ncsi_get_version_id(i, channel_id, eth_name) ~= ncsi_def.NCSI_SUCCESS or
                ncsi_capabilities.ncsi_get_capabilities(i, channel_id, eth_name) ~= ncsi_def.NCSI_SUCCESS then
                return NCSI_PACKAGE_MAX_ID
            end

            -- 初始化通道
            ncsi_channel_init.initial_channel(i, channel_id, eth_name)
        end
        -- Intel网卡特殊处理
        if ncsi_para.manufacture_id == INTEL_MANUFACTURE_ID then
            if ncsi_package.ncsi_deselect_package(i, eth_name) ~= ncsi_def.NCSI_SUCCESS then
                log:error('ncsi deselect package failed, eth_name is %s', eth_name)
                return NCSI_PACKAGE_MAX_ID
            end
        end

        if ret == ncsi_def.NCSI_SUCCESS then
            return i
        end
        ::continue::
    end
    return NCSI_PACKAGE_MAX_ID
end

-- 配置NCSI设置，包括包配置和通道启用
local function ncsi_configuration_setting(channel_id, eth_name, ncsi_enable_state)
    local ncsi_para = ncsi_parameter.get_instance():get_ncsi_parameter()

    -- 获取包ID
    local package_id = ncsi_configuration_setting_one(channel_id, eth_name)

    -- 检查NCSI状态
    if ncsi_enable_state ~= NCSI_ENABLED then
        log:debug('Ncsi port not enable %s port = %u', eth_name, channel_id)
        return package_id
    end

    -- 遍历所有包
    for i = 0, NCSI_PACKAGE_MAX_ID - 1 do
        -- 检查包和通道是否存在
        if ncsi_para.package_exist[i] ~= PACKAGE_SUPPORT or
            ncsi_para.channel_exist[i][channel_id] ~= CHANNEL_SUPPORT then
            goto continue
        end

        -- 启用通道
        local ret = ncsi_channel.ncsi_enable_channel(i, channel_id, eth_name)
        if ret == ncsi_def.NCSI_SUCCESS then
            log:debug('ncsi cmd ctrl enable channel success, package_id = %s, channel_id = %s, eth_name = %s',
                i, channel_id, eth_name)
            break
        end
        log:error('ncsi cmd ctrl enable channel failed, package_id = %s, channel_id = %s, eth_name = %s',
                i, channel_id, eth_name)
        ::continue::
    end

    return package_id
end

-- NCSI参数初始化入口函数，设置iid并调用配置设置
function ncsi_init.ncsi_paramter_init(channel_id, eth_name, state)
    -- 初始化ncsi参数
    if g_ncsi_paramter_init_flag == 0 then
        ncsi_parameter.get_instance():init_ncsi_parameter()
        g_ncsi_paramter_init_flag = 1
    end

    -- 初始化模块间依赖关系
    ncsi_init.init_dependencies()

    -- 配置NCSI设置
    local package_id = ncsi_configuration_setting(channel_id, eth_name, state)
    return ncsi_def.NCSI_SUCCESS, package_id
end

-- 重置初始化标志，用于测试
function ncsi_init.reset_init_flag()
    g_ncsi_paramter_init_flag = 0
end

-- 初始化模块间的依赖关系，解决循环依赖问题
function ncsi_init.init_dependencies()
    -- 注册AEN处理中需要的通道初始化回调函数
    ncsi_aen.register_channel_init_callback(ncsi_channel_init.initial_channel)
    log:debug('NCSI dependencies initialized successfully')
end

return ncsi_init