/* ----------------------------------------------------------------------------
 * Copyright (c) Huawei Technologies Co., Ltd. 2013-2021. All rights reserved.
 * Description: Interrupt Abstraction Layer And API Implementation
 * Author: Huawei LiteOS Team
 * Create: 2013-01-01
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 * conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 * of conditions and the following disclaimer in the documentation and/or other materials
 * provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 * to endorse or promote products derived from this software without specific prior written
 * permission.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * --------------------------------------------------------------------------- */
/*
关于LiteOS中硬件中断处理的部分，涉及了中断的注册、删除、触发、使能、禁止等操作
*/
#include "los_hwi_pri.h"
#include "los_hwi.h"
#include "los_memory.h"
#include "los_spinlock.h"
#include "los_trace.h"
#ifdef LOSCFG_KERNEL_CPUP
#include "los_cpup_pri.h"
#endif
#ifdef LOSCFG_DEBUG_SCHED_STATISTICS
#include "los_sched_debug_pri.h"
#endif
#include "los_err_pri.h"

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */

/* spinlock for hwi module, only available on SMP mode */
LITE_OS_SEC_BSS  SPIN_LOCK_INIT(g_hwiSpin);

#define HWI_LOCK(state)       LOS_SpinLockSave(&g_hwiSpin, &(state))
#define HWI_UNLOCK(state)     LOS_SpinUnlockRestore(&g_hwiSpin, (state))

size_t g_intCount[LOSCFG_KERNEL_CORE_NUM] = {0};

#ifdef LOSCFG_KERNEL_LOWPOWER
STATIC WAKEUPFROMINTHOOK g_intWakeupHook = NULL;
#endif

const HwiControllerOps *g_hwiOps = NULL;

typedef VOID (*HWI_PROC_FUNC0)(VOID);
typedef VOID (*HWI_PROC_FUNC2)(INT32, VOID *);
//OsIrqNestingActive：用于在处理中断期间激活中断嵌套计数器，避免在处理时钟中断时进行抢占
STATIC INLINE VOID OsIrqNestingActive(UINT32 hwiNum)
{
#ifdef LOSCFG_ARCH_INTERRUPT_PREEMPTION
    /* preemption not allowed when handling tick interrupt */
    if (hwiNum != OS_TICK_INT_NUM) {
        (VOID)LOS_IntUnLock();
    }
#endif
}
//OsIrqNestingInactive：用于在处理中断结束后禁用中断嵌套计数器
STATIC INLINE VOID OsIrqNestingInactive(UINT32 hwiNum)
{
#ifdef LOSCFG_ARCH_INTERRUPT_PREEMPTION
    if (hwiNum != OS_TICK_INT_NUM) {
        (VOID)LOS_IntLock();
    }
#endif
}
//OsIrqNestingCntGet：获取当前CPU的中断嵌套计数值
size_t OsIrqNestingCntGet(VOID)
{
    return g_intCount[ArchCurrCpuid()];
}
//OsIrqNestingCntSet：设置当前CPU的中断嵌套计数值
VOID OsIrqNestingCntSet(size_t val)
{
    g_intCount[ArchCurrCpuid()] = val;
}
//InterruptHandle：处理中断的实际函数，根据中断号调用对应的中断处理函数
STATIC INLINE VOID InterruptHandle(HwiHandleInfo *hwiForm)
{
    hwiForm->respCount++;
#ifdef LOSCFG_SHARED_IRQ
    while (hwiForm->next != NULL) {
        hwiForm = hwiForm->next;
#endif
        if (hwiForm->registerInfo) {
            HWI_PROC_FUNC2 func = (HWI_PROC_FUNC2)hwiForm->hook;
            if (func != NULL) {
                UINTPTR *param = (UINTPTR *)(hwiForm->registerInfo);
                func((INT32)(*param), (VOID *)(*(param + 1)));
            }
        } else {
            HWI_PROC_FUNC0 func = (HWI_PROC_FUNC0)hwiForm->hook;
            if (func != NULL) {
                func();
            }
        }
#ifdef LOSCFG_SHARED_IRQ
    }
#endif
}
//OsIntHandle：中断处理入口函数，负责处理中断前的一些准备工作，如调用中断处理前的钩子函数等
VOID OsIntHandle(UINT32 hwiNum, HwiHandleInfo *hwiForm)
{
    size_t *intCnt = NULL;

#ifdef LOSCFG_CPUP_INCLUDE_IRQ
    OsCpupIrqStart();
#endif
    intCnt = &g_intCount[ArchCurrCpuid()];
    *intCnt = *intCnt + 1;

#ifdef LOSCFG_DEBUG_SCHED_STATISTICS
    OsHwiStatistics(hwiNum);
#endif

#ifdef LOSCFG_KERNEL_LOWPOWER
    if (g_intWakeupHook != NULL) {
        g_intWakeupHook(hwiNum);
    }
#endif
    LOS_TRACE(HWI_RESPONSE_IN, hwiNum);

    OsIrqNestingActive(hwiNum);
    InterruptHandle(hwiForm);
    OsIrqNestingInactive(hwiNum);

    LOS_TRACE(HWI_RESPONSE_OUT, hwiNum);

    *intCnt = *intCnt - 1;

#ifdef LOSCFG_CPUP_INCLUDE_IRQ
    OsCpupIrqEnd(hwiNum);
#endif
}
//OsIntEntry：中断向量入口函数，根据中断号调用对应的中断处理函数
VOID OsIntEntry(VOID)
{
    if ((g_hwiOps != NULL) && (g_hwiOps->handleIrq != NULL)) {
        g_hwiOps->handleIrq();
    }
    return;
}
//OsHwiCpIrqParam：根据传入的中断参数结构体分配内存，并将参数信息拷贝到新分配的内存中
STATIC HWI_ARG_T OsHwiCpIrqParam(const HWI_IRQ_PARAM_S *irqParam)
{
    HWI_IRQ_PARAM_S *paramByAlloc = NULL;

    paramByAlloc = (HWI_IRQ_PARAM_S *)LOS_MemAlloc(m_aucSysMem0, sizeof(HWI_IRQ_PARAM_S));
    if (paramByAlloc != NULL) {
        (VOID)memcpy_s(paramByAlloc, sizeof(HWI_IRQ_PARAM_S), irqParam, sizeof(HWI_IRQ_PARAM_S));
    }

    return (HWI_ARG_T)paramByAlloc;
}
#ifndef LOSCFG_SHARED_IRQ
//OsHwiDel：删除指定的中断处理函数
STATIC UINT32 OsHwiDel(HwiHandleInfo *hwiForm, const HWI_IRQ_PARAM_S *irqParam, UINT32 irqId)
{
    UINT32 intSave;

    (VOID)irqParam;
    HWI_LOCK(intSave);
    hwiForm->hook = NULL;
    if (hwiForm->registerInfo) {
        (VOID)LOS_MemFree(m_aucSysMem0, (VOID *)hwiForm->registerInfo);
    }
    hwiForm->registerInfo = 0;
    hwiForm->respCount = 0;
    if (g_hwiOps->disableIrq == NULL) {
        HWI_UNLOCK(intSave);
        return LOS_ERRNO_HWI_PROC_FUNC_NULL;
    }
    g_hwiOps->disableIrq(irqId);

    HWI_UNLOCK(intSave);
    return LOS_OK;
}
//OsHwiCreate：创建中断处理函数，并将其添加到中断处理链表中
STATIC UINT32 OsHwiCreate(HwiHandleInfo *hwiForm, HWI_MODE_T hwiMode, HWI_PROC_FUNC hwiHandler,
                          const HWI_IRQ_PARAM_S *irqParam)
{
    UINT32 intSave;

    if (hwiMode & IRQF_SHARED) {
        return LOS_ERRNO_HWI_SHARED_ERROR;
    }
    HWI_LOCK(intSave);
    if (hwiForm->hook == NULL) {
        hwiForm->hook = hwiHandler;

        if (irqParam != NULL) {
            hwiForm->registerInfo = OsHwiCpIrqParam(irqParam);
            if (hwiForm->registerInfo == (HWI_ARG_T)NULL) {
                HWI_UNLOCK(intSave);
                return LOS_ERRNO_HWI_NO_MEMORY;
            }
        }
    } else {
        HWI_UNLOCK(intSave);
        return LOS_ERRNO_HWI_ALREADY_CREATED;
    }
    HWI_UNLOCK(intSave);
    return LOS_OK;
}
#else /* LOSCFG_SHARED_IRQ */
//函数OsFreeHwiNode:用于释放中断处理函数节点，并在需要时禁止该中断
STATIC INLINE UINT32 OsFreeHwiNode(HwiHandleInfo *head, HwiHandleInfo *hwiForm, UINT32 irqId)
{
    UINT32 ret = LOS_OK;

    if (hwiForm->registerInfo != (HWI_ARG_T)NULL) {
        (VOID)LOS_MemFree(m_aucSysMem0, (VOID *)hwiForm->registerInfo);
    }

    (VOID)LOS_MemFree(m_aucSysMem0, hwiForm);

    if (head->next == NULL) {
        head->shareMode = 0;
        head->respCount = 0;
        if (g_hwiOps->disableIrq == NULL) {
            ret = LOS_ERRNO_HWI_PROC_FUNC_NULL;
            return ret;
        }
        g_hwiOps->disableIrq(irqId);
    }

    return ret;
}
//OsHwiDel:用于删除硬件中断处理函数，它首先判断中断是否是共享中断
//如果不是，则直接释放该中断的处理函数节点;如果是共享中断，则遍历链表找到对应的设备ID，然后释放该中断的处理函数节点
STATIC UINT32 OsHwiDel(HwiHandleInfo *head, const HWI_IRQ_PARAM_S *irqParam, UINT32 irqId)
{
    HwiHandleInfo *hwiFormPrev = NULL;
    HwiHandleInfo *hwiForm = NULL;
    UINT32 intSave;
    UINT32 ret;

    HWI_LOCK(intSave);

    if ((head->shareMode & IRQF_SHARED) && ((irqParam == NULL) || (irqParam->pDevId == NULL))) {
        HWI_UNLOCK(intSave);
        return LOS_ERRNO_HWI_SHARED_ERROR;
    }

    /* Non-shared interrupt. */
    if (!(head->shareMode & IRQF_SHARED)) {
        if (head->next == NULL) {
            HWI_UNLOCK(intSave);
            return LOS_ERRNO_HWI_HWINUM_UNCREATE;
        }

        hwiForm = head->next;
        head->next = NULL;
        ret = OsFreeHwiNode(head, hwiForm, irqId);
        HWI_UNLOCK(intSave);
        return ret;
    }

    /* Shared interrupt. */
    hwiFormPrev = head;
    hwiForm = head->next;
    while (hwiForm != NULL) {
        if (((HWI_IRQ_PARAM_S *)(hwiForm->registerInfo))->pDevId == irqParam->pDevId) {
            break;
        }
        hwiFormPrev = hwiForm;
        hwiForm = hwiForm->next;
    }

    if (hwiForm == NULL) {
        HWI_UNLOCK(intSave);
        return LOS_ERRNO_HWI_HWINUM_UNCREATE;
    }

    hwiFormPrev->next = hwiForm->next;
    ret = OsFreeHwiNode(head, hwiForm, irqId);
    HWI_UNLOCK(intSave);
    return ret;
}
//OsHwiCreate:用于创建硬件中断处理函数，它首先判断中断是否是共享中断，并检查是否已经存在具有相同设备ID的中断处理函数节点，如果存在则返回错误
//然后申请内存并初始化新的中断处理函数节点，将其添加到链表中
STATIC UINT32 OsHwiCreate(HwiHandleInfo *head, HWI_MODE_T hwiMode, HWI_PROC_FUNC hwiHandler,
                          const HWI_IRQ_PARAM_S *irqParam)
{
    UINT32 intSave;
    HwiHandleInfo *hwiFormNode = NULL;
    HWI_IRQ_PARAM_S *hwiParam = NULL;
    HWI_MODE_T modeResult = hwiMode & IRQF_SHARED;
    HwiHandleInfo *hwiForm = NULL;

    if (modeResult && ((irqParam == NULL) || (irqParam->pDevId == NULL))) {
        return LOS_ERRNO_HWI_SHARED_ERROR;
    }

    HWI_LOCK(intSave);

    if ((head->next != NULL) && ((modeResult == 0) || (!(head->shareMode & IRQF_SHARED)))) {
        HWI_UNLOCK(intSave);
        return LOS_ERRNO_HWI_SHARED_ERROR;
    }

    hwiForm = head;
    while (hwiForm->next != NULL) {
        hwiForm = hwiForm->next;
        hwiParam = (HWI_IRQ_PARAM_S *)(hwiForm->registerInfo);
        if (hwiParam->pDevId == irqParam->pDevId) {
            HWI_UNLOCK(intSave);
            return LOS_ERRNO_HWI_ALREADY_CREATED;
        }
    }

    hwiFormNode = (HwiHandleInfo *)LOS_MemAlloc(m_aucSysMem0, sizeof(HwiHandleInfo));
    if (hwiFormNode == NULL) {
        HWI_UNLOCK(intSave);
        return LOS_ERRNO_HWI_NO_MEMORY;
    }
    hwiForm->respCount = 0;

    if (irqParam != NULL) {
        hwiFormNode->registerInfo = OsHwiCpIrqParam(irqParam);
        if (hwiFormNode->registerInfo == (HWI_ARG_T)NULL) {
            HWI_UNLOCK(intSave);
            (VOID) LOS_MemFree(m_aucSysMem0, hwiFormNode);
            return LOS_ERRNO_HWI_NO_MEMORY;
        }
    } else {
        hwiFormNode->registerInfo = 0;
    }

    hwiFormNode->hook = hwiHandler;
    hwiFormNode->next = (struct tagHwiHandleForm *)NULL;
    hwiForm->next = hwiFormNode;

    head->shareMode = modeResult;

    HWI_UNLOCK(intSave);
    return LOS_OK;
}
#endif

size_t IntActive()
{
    size_t intCount;
    UINT32 intSave = LOS_IntLock();

    intCount = g_intCount[ArchCurrCpuid()];
    LOS_IntRestore(intSave);
    return intCount;
}
//LOS_HwiCreate 函数：用于创建硬件中断处理函数
//它会注册一个中断处理函数，并将其与指定的硬件中断号相关联
//可以设置中断的优先级、硬件中断模式和处理函数
LITE_OS_SEC_TEXT UINT32 LOS_HwiCreate(HWI_HANDLE_T hwiNum,
                                           HWI_PRIOR_T hwiPrio,
                                           HWI_MODE_T hwiMode,
                                           HWI_PROC_FUNC hwiHandler,
                                           HWI_IRQ_PARAM_S *irqParam)
{
    UINT32 ret;
    HwiHandleInfo *hwiForm = NULL;

    if (hwiHandler == NULL) {
        return LOS_ERRNO_HWI_PROC_FUNC_NULL;
    }

    if ((g_hwiOps == NULL) || (g_hwiOps->getHandleForm == NULL)) {
        return LOS_ERRNO_HWI_PROC_FUNC_NULL;
    }

    hwiForm = g_hwiOps->getHandleForm(hwiNum);
    if (hwiForm == NULL) {
        return LOS_ERRNO_HWI_NUM_INVALID;
    }
    LOS_TRACE(HWI_CREATE, hwiNum, hwiPrio, hwiMode, (UINTPTR)hwiHandler);

    ret = OsHwiCreate(hwiForm, hwiMode, hwiHandler, irqParam);
    LOS_TRACE(HWI_CREATE_SHARE, hwiNum, (UINTPTR)(irqParam != NULL ? irqParam->pDevId : NULL), ret);

    /* priority will be changed if setIrqPriority implemented,
     * but interrupt preemption only allowed when LOSCFG_ARCH_INTERRUPT_PREEMPTION enable */
    if ((ret == LOS_OK) && (g_hwiOps->setIrqPriority != NULL)) {
        ret = g_hwiOps->setIrqPriority(hwiNum, hwiPrio);
        if (ret != LOS_OK) {
            (VOID)OsHwiDel(hwiForm, irqParam, hwiNum);
        }
    }
    return ret;
}
//LOS_HwiDelete 函数：用于删除已经创建的硬件中断处理函数
//通过指定硬件中断号，可以将之前注册的中断处理函数从系统中删除
LITE_OS_SEC_TEXT UINT32 LOS_HwiDelete(HWI_HANDLE_T hwiNum, HWI_IRQ_PARAM_S *irqParam)
{
    UINT32 ret;
    HwiHandleInfo *hwiForm = NULL;

    if ((g_hwiOps == NULL) || (g_hwiOps->getHandleForm == NULL)) {
        return LOS_ERRNO_HWI_PROC_FUNC_NULL;
    }

    hwiForm = g_hwiOps->getHandleForm(hwiNum);
    if (hwiForm == NULL) {
        return LOS_ERRNO_HWI_NUM_INVALID;
    }
    LOS_TRACE(HWI_DELETE, hwiNum);

    ret = OsHwiDel(hwiForm, irqParam, hwiNum);
    LOS_TRACE(HWI_DELETE_SHARE, hwiNum, (UINTPTR)(irqParam != NULL ? irqParam->pDevId : NULL), ret);

    return ret;
}
//LOS_HwiTrigger 函数：用于手动触发指定的硬件中断
//调用该函数后，会立即触发对应的硬件中断，使得系统执行相应的中断处理函数
LITE_OS_SEC_TEXT UINT32 LOS_HwiTrigger(HWI_HANDLE_T hwiNum)
{
    if ((g_hwiOps == NULL) || (g_hwiOps->triggerIrq == NULL)) {
        return LOS_ERRNO_HWI_PROC_FUNC_NULL;
    }
    LOS_TRACE(HWI_TRIGGER, hwiNum);

    return g_hwiOps->triggerIrq(hwiNum);
}
//LOS_HwiEnable 函数：用于使能指定的硬件中断
//调用该函数后，系统将允许对应的硬件中断产生，并执行相应的中断处理函数
LITE_OS_SEC_TEXT UINT32 LOS_HwiEnable(HWI_HANDLE_T hwiNum)
{
    if ((g_hwiOps == NULL) || (g_hwiOps->enableIrq == NULL)) {
        return LOS_ERRNO_HWI_PROC_FUNC_NULL;
    }
    LOS_TRACE(HWI_ENABLE, hwiNum);

    return g_hwiOps->enableIrq(hwiNum);
}
//LOS_HwiDisable 函数：用于禁止指定的硬件中断
//调用该函数后，系统将阻止对应的硬件中断产生，屏蔽其影响
LITE_OS_SEC_TEXT UINT32 LOS_HwiDisable(HWI_HANDLE_T hwiNum)
{
    if ((g_hwiOps == NULL) || (g_hwiOps->disableIrq == NULL)) {
        return LOS_ERRNO_HWI_PROC_FUNC_NULL;
    }
    LOS_TRACE(HWI_DISABLE, hwiNum);

    return g_hwiOps->disableIrq(hwiNum);
}
//LOS_HwiClear 函数：用于清除指定的硬件中断
//在某些平台上，硬件中断发生后可能需要手动清除中断标志位，以便正确处理后续的中断
LITE_OS_SEC_TEXT UINT32 LOS_HwiClear(HWI_HANDLE_T hwiNum)
{
    if ((g_hwiOps == NULL) || (g_hwiOps->clearIrq == NULL)) {
        return LOS_ERRNO_HWI_PROC_FUNC_NULL;
    }
    LOS_TRACE(HWI_CLEAR, hwiNum);

    return g_hwiOps->clearIrq(hwiNum);
}
//LOS_HwiSetPriority 函数：用于设置硬件中断的优先级
//通过指定硬件中断号和优先级，可以调整硬件中断的触发顺序
LITE_OS_SEC_TEXT UINT32 LOS_HwiSetPriority(HWI_HANDLE_T hwiNum, HWI_PRIOR_T priority)
{
    if ((g_hwiOps == NULL) || (g_hwiOps->setIrqPriority == NULL)) {
        return LOS_ERRNO_HWI_PROC_FUNC_NULL;
    }
    LOS_TRACE(HWI_SETPRI, hwiNum, priority);

    return g_hwiOps->setIrqPriority(hwiNum, priority);
}
#ifdef LOSCFG_KERNEL_SMP
//LOS_HwiSetAffinity函数：用于设置硬件中断的处理CPU亲和性
//它首先检查硬件中断操作函数指针是否为空，然后调用具体的操作函数来设置中断的处理CPU亲和性
LITE_OS_SEC_TEXT UINT32 LOS_HwiSetAffinity(HWI_HANDLE_T hwiNum, UINT32 cpuMask)
{
    if ((g_hwiOps == NULL) || (g_hwiOps->setIrqCpuAffinity == NULL)) {
        return LOS_ERRNO_HWI_PROC_FUNC_NULL;
    }
    LOS_TRACE(HWI_SETAFFINITY, hwiNum, cpuMask);

    return g_hwiOps->setIrqCpuAffinity(hwiNum, cpuMask);
}
//LOS_HwiSendIpi函数：用于发送硬件中断处理请求给指定的CPU
//它首先检查硬件中断操作函数指针是否为空，然后调用具体的操作函数来发送中断处理请求
LITE_OS_SEC_TEXT UINT32 LOS_HwiSendIpi(HWI_HANDLE_T hwiNum, UINT32 cpuMask)
{
    if ((g_hwiOps == NULL) || (g_hwiOps->sendIpi == NULL)) {
        return LOS_ERRNO_HWI_PROC_FUNC_NULL;
    }
    LOS_TRACE(HWI_SENDIPI, hwiNum, cpuMask);

    return g_hwiOps->sendIpi(cpuMask, hwiNum);
}
#endif

#ifdef LOSCFG_KERNEL_LOWPOWER
//LOS_IntWakeupHookReg函数：用于注册中断唤醒回调函数
//它将传入的回调函数赋值给全局变量g_intWakeupHook，以便在中断唤醒时调用该回调函数
LITE_OS_SEC_TEXT_MINOR VOID LOS_IntWakeupHookReg(WAKEUPFROMINTHOOK hook)
{
    g_intWakeupHook = hook;
}
#endif

/* Initialization of the hardware interrupt */
//OsHwiInit函数：用于初始化硬件中断
//它会调用具体的平台相关函数来进行硬件中断的初始化操作
LITE_OS_SEC_TEXT_INIT VOID OsHwiInit(VOID)
{
    ArchIrqInit();
    return;
}

#ifdef __cplusplus
#if __cplusplus
}
#endif /* __cplusplus */
#endif /* __cplusplus */
