-- 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 c_network_port = require 'device.class.network_port'

local card_resource_mpu = {}

local MPU_IDLE<const> = 0 -- 0 表示MPU空闲

local function update_link_ability_by_ncsi(resource_obj)
    local s = resource_obj.ncsi_config_obj:LinkAbility({package_id = resource_obj.package_id}):value()
    if not s then
        return
    end
    resource_obj.LinkWidthCapability = s.link_width
    resource_obj.LinkSpeedCapability = s.link_speed
    log:info('get the link capability, LinkWidthCapability:%s, LinkSpeedCapability:%s',
        resource_obj.LinkWidthCapability, resource_obj.LinkSpeedCapability)
end

local function update_link_status_by_ncsi(resource_obj)
    local s = resource_obj.ncsi_config_obj:LinkInfo({package_id = resource_obj.package_id}):value()
    if not s then
        return
    end
    resource_obj.LinkWidth = s.link_width
    resource_obj.LinkSpeed = s.link_speed
    log:info('get the link status, link_width_status:%s, link_speed_status:%s', resource_obj.LinkWidth,
        resource_obj.LinkSpeed)
end

--MPU恢复空闲则发送一次性信息获取指令
local function resume_fetch_properties(resource_obj)
    resource_obj:next_tick(update_link_ability_by_ncsi, resource_obj)
    resource_obj:next_tick(update_link_status_by_ncsi, resource_obj)
end

local function pause_ncsi_schedulers(resource_obj)
    log:notice("pause ncsi schedulers ,size of ncsi schedulers is %s", #resource_obj.ncsi_schedulers)
    for _, s in ipairs(resource_obj.ncsi_schedulers) do
        s:pause()
    end
end

local function resume_ncsi_schedulers(resource_obj)
    log:notice("resume ncsi schedulers ,size of ncsi schedulers is %s", #resource_obj.ncsi_schedulers)
    for _, s in ipairs(resource_obj.ncsi_schedulers) do
        s:resume()
    end
end

-- MPU繁忙时暂定所有的轮询操作
local function pause(resource_obj)
    pause_ncsi_schedulers(resource_obj)
    -- 暂停对应网口的轮询操作
    local ports = c_network_port.collection:fetch_by_position(resource_obj:get_position())
    for _, port in pairs(ports) do
        port:pause()
    end
end

-- MPU空闲时恢复所有的轮询操作
local function resume(resource_obj)
    resume_ncsi_schedulers(resource_obj)
    local ports = c_network_port.collection:fetch_by_position(resource_obj:get_position())
    resume_fetch_properties(resource_obj)
    -- 恢复对应网口的轮询操作
    for _, port in pairs(ports) do
        port:resume()
    end
end

function card_resource_mpu.wait_mpu_idle(resource_obj)
    if resource_obj.MPUBusyStatus == MPU_IDLE then
        return true
    end
    local retry_times = 0
    while true do
        skynet.sleep(600)
        if resource_obj.MPUBusyStatus == MPU_IDLE then
            return true
        end
        if retry_times > 199 then
            -- 等待20min，MPU始终繁忙则返回超时
            log:notice("waiting for MPU idle timed out")
            return false
        end
        retry_times = retry_times + 1
    end
end

function card_resource_mpu.check_mpu_status(resource_obj)
    resource_obj:listen('MPUBusyStatus', function(_, value)
        if value ~= MPU_IDLE then
            log:notice('MPU become busy')
            pause(resource_obj)
            return true
        end
        log:notice('MPU become idle')
        resume(resource_obj)
        return true
    end)
    if resource_obj.MPUBusyStatus ~= MPU_IDLE then
        log:notice('MPU is busy')
        pause(resource_obj)
    end
end

return card_resource_mpu