/****************************************************************************** *(C) Copyright 2018 EIGENCOMM International Ltd. * All Rights Reserved ****************************************************************************** * Filename: * * Description: * * History: initiated by xuwang * * Notes: * ******************************************************************************/ /*----------------------------------------------------------------------------* * INCLUDES * *----------------------------------------------------------------------------*/ #include #include #include "cmsis_os2.h" #include "osaulfcmem.h" #include "exception_process.h" #if defined CHIP_EC718 || defined CHIP_EC716 #include "system_ec7xx.h" #elif defined CHIP_EC618 #include "system_ec618.h" #endif #include "sctdef.h" #include DEBUG_LOG_HEADER_FILE /*----------------------------------------------------------------------------* * MACROS * *----------------------------------------------------------------------------*/ #define OSA_ULFC_MEM_UNSET_TIMER_PERIOD (2 * 1000) /* 2sec, unit: ms */ /* lan max chanNo is 16(4bits) */ #define OSA_ULFC_MEM_NODE_MAXNUM 16 /* max task cnt is supported! */ #define OSA_ULFC_MEM_MSGQ_MAXNUM 4 #define OSA_ULFC_MEM_ALLOC_MAGIC 0xBFCA #define OSA_ULFC_MEM_FREED_MAGIC 0xBFCF #define OSA_ULFC_BLOCKING_EVT_FLAGS 0xF /* MCB: memory control block */ #define OSA_ULFC_MCB_TOTAL_SIZE(hasPbuf, hasUlpdu) (sizeof(OsaUlfcMemHdr_t) + \ ((hasPbuf) ? LWIP_PBUF_STRUCT_LEN : 0) + \ ((hasUlpdu) ? sizeof(UlPduBlock) : 0)) #define OSA_ULFC_ALIGN_UP(x,sz) (((x) + ((sz) - 1)) & (~((sz) - 1))) #define OSA_ULFC_ALIGN_DOWN(x,sz) ((x) & (~((sz) - 1))) #define OSA_ULFC_MEM_TFCM_SET(tfcm, fid) ((tfcm) |= (1 << (fid))) #define OSA_ULFC_MEM_TFCM_CLR(tfcm, fid) ((tfcm) &= ~(1 << (fid))) #define OSA_ULFC_MEM_BUILD_HDR(hdr, len, xtras) \ do\ {\ ((OsaUlfcMemHdr_t*)(hdr))->magicNum = OSA_ULFC_MEM_ALLOC_MAGIC;\ ((OsaUlfcMemHdr_t*)(hdr))->extras = (xtras);\ ((OsaUlfcMemHdr_t*)(hdr))->memSize = (len);\ }while(0) #define OSA_ULFC_MEM_BUILD_ULPDU(ulpdu, chno, buf, len, bpbuf) UL_PDU_BLOCK_SET_BASICS(ulpdu, chno, UL_AFC_MEM, 1, buf, len, bpbuf, 0, NULL) /*----------------------------------------------------------------------------* * DATA TYPE DEFINITION * *----------------------------------------------------------------------------*/ typedef uint32_t OsaUlfcMemFactorId_bm; typedef struct { uint8_t isInit :1; uint8_t hasAlert :1; /* 0/1: has reached/been above alert line or not? */ uint8_t hasNotif :1; /* 0/1: has notified the memory event(low water)? */ uint8_t isUnset :1; /* 0/1: ulfc conf will be unset? */ uint8_t rsvdBits :4; uint8_t refNum; uint8_t rsvd[2]; /* memory state machine: * ___________________ * | | * V | * FREE --> FROZEN --> USED */ uint32_t memFrozen; uint32_t memUsed; uint32_t memUsedPeak; uint32_t memThres; uint32_t memThresAlert; uint32_t memThresAlertPct; uint32_t memAllocCnt; uint32_t memFreeCnt; osTimerId_t ustTimer; osEventFlagsId_t handle; OsaUlfcSrcTaskId_bm bmTaskId; OsaUlfcMemFactorId_bm memTfcm; /* TFCM: Trigggerd-Factor-Control-Map */ }OsaUlfcMemNode_t; typedef struct { uint8_t taskId; /* OsaUlfcSrcTaskId_e */ uint8_t chanNo; uint8_t rsvd[2]; OsaUlfcMemNode_t *memNode; }OsaUlfcTimerCtx_t; typedef struct { OsaUlfcMemNode_t memNode[OSA_ULFC_MEM_NODE_MAXNUM]; OsaUlfcTimerCtx_t timerCtx[OSA_ULFC_MEM_NODE_MAXNUM]; }OsaUlfcMemMan_t; /*----------------------------------------------------------------------------* * PRIVATE FUNCTION DECLEARATION * *----------------------------------------------------------------------------*/ extern void ccioReportUlfcMemEvent(OsaUlfcMemEvtFlags_e flags, OsaUlfcMemEvtArgs_t *args); /*----------------------------------------------------------------------------* * GLOBAL VARIABLES * *----------------------------------------------------------------------------*/ /* ULFC memory is supported or not? */ AP_PLAT_COMMON_DATA static uint16_t gOsaUlfcMemSuppFlag = 1; AP_PLAT_COMMON_BSS static OsaUlfcMemMan_t gOsaUlfcMemMan; /*----------------------------------------------------------------------------* * PRIVATE FUNCTIONS * *----------------------------------------------------------------------------*/ static void OsaUlfcUnsetTimerExpr(OsaUlfcTimerCtx_t *timerCtx) { uint8_t isUnset = 0; if(timerCtx->chanNo >= OSA_ULFC_MEM_NODE_MAXNUM) { ECPLAT_PRINTF(UNILOG_OSA, ULFC_TIMER_EXPR_1, P_WARNING, "invalid chanNo(%d) err!", timerCtx->chanNo); return; } ECPLAT_PRINTF(UNILOG_OSA, ULFC_TIMER_EXPR_2, P_SIG, "UlfcMem(%d): task(%d/0x%x) unset(%d) timer event!", timerCtx->chanNo, timerCtx->taskId, timerCtx->memNode->bmTaskId, timerCtx->memNode->isUnset); uint32_t mask = SaveAndSetIRQMask(); EC_ASSERT(timerCtx->memNode->isInit, timerCtx->memNode, timerCtx->chanNo, timerCtx->taskId); isUnset = timerCtx->memNode->isUnset; RestoreIRQMask(mask); if(isUnset) { OsaUlfcDisable(timerCtx->chanNo, timerCtx->taskId); } } /*----------------------------------------------------------------------------* * GLOBAL FUNCTIONS * *----------------------------------------------------------------------------*/ /****************************************************************************** * @brief : OsaUlfcSetMemSuppFlag * @author: Xu.Wang * @note : support Ulfc Policy or Not? ******************************************************************************/ void OsaUlfcSetMemSuppFlag(uint16_t isSupp) { gOsaUlfcMemSuppFlag = isSupp; } /****************************************************************************** * @brief : OsaUlfcGetMemUsedThresAlertPct * @author: Xu.Wang * @note : ******************************************************************************/ uint32_t OsaUlfcGetMemUsedThresAlertPct(uint8_t chanNo) { OsaUlfcMemNode_t *memNode = NULL; if(chanNo >= OSA_ULFC_MEM_NODE_MAXNUM) { ECPLAT_PRINTF(UNILOG_OSA, ULFC_GET_USED_THRES_ALERT_PCT, P_WARNING, "invalid chanNo(%d) err!", chanNo); return 0; } memNode = &gOsaUlfcMemMan.memNode[chanNo]; if(!memNode->isInit) return OSA_ULFC_MEM_USED_THRES_ALERT_PCT_ANY; return memNode->memThresAlertPct; } /****************************************************************************** * @brief : OsaUlfcSetMemUsedThresAlertPct * @author: Xu.Wang * @note : ******************************************************************************/ void OsaUlfcSetMemUsedThresAlertPct(uint8_t chanNo, uint8_t alertPct) { OsaUlfcMemNode_t *memNode = NULL; if(chanNo >= OSA_ULFC_MEM_NODE_MAXNUM || alertPct > 100) { ECPLAT_PRINTF(UNILOG_OSA, ULFC_SET_USED_THRES_ALERT_PCT, P_WARNING, "invalid chanNo(%d) or alertPct(%d) err!", chanNo, alertPct); return; } memNode = &gOsaUlfcMemMan.memNode[chanNo]; if(!memNode->isInit) return; memNode->memThresAlert = ((memNode->memThres * alertPct) / 100); memNode->memThresAlertPct = alertPct; } /****************************************************************************** * @brief : OsaUlfcGetMemUsedSizeThres * @author: Xu.Wang * @note : ******************************************************************************/ uint32_t OsaUlfcGetMemUsedSizeThres(uint8_t chanNo) { OsaUlfcMemNode_t *memNode = NULL; if(chanNo >= OSA_ULFC_MEM_NODE_MAXNUM) { ECPLAT_PRINTF(UNILOG_OSA, ULFC_GET_USED_THRES, P_WARNING, "invalid chanNo(%d) err!", chanNo); return 0; } memNode = &gOsaUlfcMemMan.memNode[chanNo]; if(!memNode->isInit) return OSA_ULFC_MEM_USED_THRES_ANY; return memNode->memThres; } /****************************************************************************** * @brief : OsaUlfcSetMemUsedSizeThres * @author: Xu.Wang * @note : ******************************************************************************/ void OsaUlfcSetMemUsedSizeThres(uint8_t chanNo, uint32_t usedSize) { OsaUlfcMemNode_t *memNode = NULL; if(chanNo >= OSA_ULFC_MEM_NODE_MAXNUM) { ECPLAT_PRINTF(UNILOG_OSA, ULFC_SET_USED_THRES, P_WARNING, "invalid chanNo(%d) err!", chanNo); return; } memNode = &gOsaUlfcMemMan.memNode[chanNo]; if(!memNode->isInit) return; memNode->memThres = OSA_ULFC_ALIGN_UP(usedSize, 4); memNode->memThresAlert = ((memNode->memThres * memNode->memThresAlertPct) / 100); } /****************************************************************************** * @brief : OsaUlfcQueryEnableState * @author: Xu.Wang * @note : ******************************************************************************/ PPP_FM_RAMCODE uint8_t OsaUlfcQueryEnableState(uint8_t chanNo) { uint8_t isEnabled = 0; if(chanNo >= OSA_ULFC_MEM_NODE_MAXNUM) { ECPLAT_PRINTF(UNILOG_OSA, ULFC_QUERY_ENABLE_STATE, P_WARNING, "invalid chanNo(%d) err!", chanNo); return 0; } uint32_t mask = SaveAndSetIRQMask(); isEnabled = gOsaUlfcMemMan.memNode[chanNo].isInit; RestoreIRQMask(mask); return isEnabled; } /****************************************************************************** * @brief : OsaUlfcQueryMemAvlbSize * @author: Xu.Wang * @note : ******************************************************************************/ PPP_FM_RAMCODE uint32_t OsaUlfcQueryMemAvlbSize(uint8_t chanNo) { uint32_t avlbSize = 0; uint32_t totalSize = 0; OsaUlfcMemNode_t *memNode = NULL; if(chanNo >= OSA_ULFC_MEM_NODE_MAXNUM) { ECPLAT_PRINTF(UNILOG_OSA, ULFC_QUERY_AVLB_SIZE, P_WARNING, "invalid chanNo(%d) err!", chanNo); return 0; } memNode = &gOsaUlfcMemMan.memNode[chanNo]; if(!memNode->isInit) return 0; uint32_t mask = SaveAndSetIRQMask(); /* MCB size will be double if the imcoming data is stored in the tail and the head of the rbuf! */ totalSize = memNode->memFrozen + memNode->memUsed + (OSA_ULFC_MCB_TOTAL_SIZE(1, 1) << 1); avlbSize = memNode->memThres > totalSize ? (memNode->memThres - totalSize) : 0; RestoreIRQMask(mask); return avlbSize; } /****************************************************************************** * @brief : OsaUlfcGetMemStat * @author: Xu.Wang * @note : ******************************************************************************/ void OsaUlfcGetMemStat(uint8_t *buf, uint16_t bufLen) { uint8_t *ptr = buf; uint16_t tempSize = 0; uint16_t remnSize = bufLen; OsaUlfcMemNode_t *memNode = &gOsaUlfcMemMan.memNode[0]; if(!gOsaUlfcMemSuppFlag) return; if(!buf) return; for(uint16_t loop = 0; loop < OSA_ULFC_MEM_NODE_MAXNUM; loop++) { if(!memNode[loop].isInit) continue; tempSize = snprintf((char*)ptr, tempSize, "UlfcMem(%d/%d): tfcm(0x%x), frozen(%d), usedPeak(%d), used(%d), usedThres(%d/%d%%), alertThres(%d)\r\n", loop, gOsaUlfcMemSuppFlag, memNode[loop].memTfcm, memNode[loop].memFrozen, memNode[loop].memUsedPeak, memNode[loop].memUsed, memNode[loop].memThres, memNode[loop].memThresAlertPct, memNode[loop].memThresAlert); ptr += tempSize; remnSize -= tempSize; } } /****************************************************************************** * @brief : OsaUlfcFreezeMem * @author: Xu.Wang * @note : ******************************************************************************/ PPP_FM_RAMCODE void OsaUlfcFreezeMem(uint8_t chanNo, uint32_t wantedSize) { #if 0 uint32_t mask = 0; uint32_t frozenSize = OSA_ULFC_ALIGN_UP(wantedSize, 4) + OSA_ULFC_MCB_TOTAL_SIZE(1, 1); OsaUlfcMemNode_t *memNode = NULL; EC_ASSERT(chanNo < OSA_ULFC_MEM_NODE_MAXNUM && gOsaUlfcMemMan.memNode[chanNo].isInit, chanNo, gOsaUlfcMemMan.memNode[chanNo].isInit, wantedSize); memNode = &gOsaUlfcMemMan.memNode[chanNo]; if(gOsaUlfcMemSuppFlag) { mask = SaveAndSetIRQMask(); memNode->memFrozen += frozenSize; RestoreIRQMask(mask); } #endif return; } /****************************************************************************** * @brief : OsaUlfcAllocMem * @author: Xu.Wang * @note : ******************************************************************************/ PPP_FM_RAMCODE void* OsaUlfcAllocMem(uint32_t wantedSize, uint8_t hasPbuf, uint8_t hasUlpdu, uint8_t isBlocking, uint16_t extras) { uint8_t *buffer = NULL; uint8_t *ptr = NULL; uint32_t mask = 0; uint32_t memUsed = 0; //uint32_t allocSize = OSA_ULFC_ALIGN_UP(wantedSize, 4) + OSA_ULFC_MCB_TOTAL_SIZE(hasPbuf, hasUlpdu); uint32_t allocSize = OSA_ULFC_ALIGN_UP(wantedSize, 4) + OSA_ULFC_MCB_TOTAL_SIZE(1, 1); osEventFlagsId_t handle = NULL; OsaUlfcMemNode_t *memNode = NULL; OsaUlfcMemFactorId_bm memTfcm = 0; OsaUlfcMemEvtArgs_t evtArgs; EC_ASSERT(wantedSize || __get_IPSR() == 0, wantedSize, __get_IPSR(), extras); EC_ASSERT(extras < OSA_ULFC_MEM_NODE_MAXNUM && gOsaUlfcMemMan.memNode[extras].isInit, extras, gOsaUlfcMemMan.memNode[extras].isInit, wantedSize); memNode = &gOsaUlfcMemMan.memNode[extras]; while(gOsaUlfcMemSuppFlag) { mask = SaveAndSetIRQMask(); if(memNode->memUsed /*+ allocSize*/ >= memNode->memThres) { OSA_ULFC_MEM_TFCM_SET(memNode->memTfcm, OSA_ULFC_MFI_MEM_THRES); } else { OSA_ULFC_MEM_TFCM_CLR(memNode->memTfcm, OSA_ULFC_MFI_MEM_THRES); } memTfcm = memNode->memTfcm; memUsed = memNode->memUsed; handle = memNode->handle; RestoreIRQMask(mask); if(isBlocking && !handle) { handle = osEventFlagsNew(NULL); EC_ASSERT(handle, wantedSize, 0, 0); mask = SaveAndSetIRQMask(); memNode->handle = handle; RestoreIRQMask(mask); } if(!memTfcm) break; /* callback by user! */ evtArgs.extras = extras; evtArgs.memUsed = memUsed; OsaUlfcNotifyMemEvent(OSA_ULFC_MEF_HIGH_WATER, &evtArgs); if(!isBlocking) return NULL; osEventFlagsWait(memNode->handle, OSA_ULFC_BLOCKING_EVT_FLAGS, osFlagsWaitAny, osWaitForever); } buffer = (uint8_t*)mallocEc(allocSize); if(buffer == NULL) { return NULL; } mask = SaveAndSetIRQMask(); memNode->memAllocCnt ++; memNode->memFrozen -= (memNode->memFrozen <= allocSize ? memNode->memFrozen : allocSize); memNode->memUsed += allocSize; if(memNode->memUsed > memNode->memUsedPeak) { memNode->memUsedPeak = memNode->memUsed; } /* reach or above the alert line */ if(!memNode->hasAlert && memNode->memUsed >= memNode->memThresAlert) { memNode->hasAlert = 1; ECPLAT_PRINTF(UNILOG_OSA, OSA_ULFC_ALLOC_1, P_SIG, "UlfcMem(%d): alerting water! usedSize(%d), alertThres(%d/%d%%)", extras, memNode->memUsed, memNode->memThresAlert, memNode->memThresAlertPct); } RestoreIRQMask(mask); OSA_ULFC_MEM_BUILD_HDR(buffer, allocSize - sizeof(OsaUlfcMemHdr_t), extras); /* skip the ulfc hdr */ buffer += sizeof(OsaUlfcMemHdr_t); if(hasPbuf) { ptr = buffer + LWIP_PBUF_STRUCT_LEN; } else { ptr = buffer; } if(hasUlpdu) { memset(ptr, 0, sizeof(UlPduBlock)); OSA_ULFC_MEM_BUILD_ULPDU(ptr, extras, ptr + sizeof(UlPduBlock), wantedSize, hasPbuf); } //ECPLAT_PRINTF(UNILOG_OSA, OSA_ULFC_ALLOC_2, P_INFO, "UlfcMem(%d): alloc addr(0x%x), size(%d)", extras, buffer, allocSize); return (void*)buffer; } /****************************************************************************** * @brief : OsaUlfcFreeMem * @author: Xu.Wang * @note : ******************************************************************************/ PPP_FM_RAMCODE void OsaUlfcFreeMem(void *ptr) { uint8_t hasAlert = 0; uint8_t hasNotif = 0; uint16_t extras = 0; uint32_t freeSize = 0; uint32_t memUsed = 0; OsaUlfcMemNode_t *memNode = NULL; OsaUlfcMemHdr_t *ulfcHdr = NULL; OsaUlfcMemEvtArgs_t evtArgs; EC_ASSERT(ptr || __get_IPSR() == 0, __get_IPSR(), ptr, 0); ulfcHdr = (OsaUlfcMemHdr_t*)((uint8_t*)ptr - sizeof(OsaUlfcMemHdr_t)); EC_ASSERT(ulfcHdr->magicNum == OSA_ULFC_MEM_ALLOC_MAGIC, ulfcHdr->magicNum, OSA_ULFC_MEM_ALLOC_MAGIC, ulfcHdr); extras = ulfcHdr->extras; /* set it freed magic */ ulfcHdr->magicNum = OSA_ULFC_MEM_FREED_MAGIC; freeSize = OSA_ULFC_ALIGN_UP(ulfcHdr->memSize, 4) + sizeof(OsaUlfcMemHdr_t); freeEc(ulfcHdr); EC_ASSERT(extras < OSA_ULFC_MEM_NODE_MAXNUM && gOsaUlfcMemMan.memNode[extras].isInit, extras, OSA_ULFC_MEM_NODE_MAXNUM, gOsaUlfcMemMan.memNode[extras].isInit); memNode = &gOsaUlfcMemMan.memNode[extras]; uint32_t mask = SaveAndSetIRQMask(); EC_ASSERT(memNode->memUsed >= freeSize, memNode->memUsed, freeSize, extras); memNode->memFreeCnt ++; memNode->memUsed -= freeSize; hasAlert = memNode->hasAlert; hasNotif = memNode->hasNotif; memUsed = memNode->memUsed; RestoreIRQMask(mask); /* always trigger it! */ if(gOsaUlfcMemSuppFlag) { /* set it 85% of alerting water level to reduce the event of low water! */ if(hasAlert && (memUsed < (memNode->memThresAlert * 70) / 100)) { /* no matter to notify twice or more... */ if(!hasNotif) { uint32_t mask = SaveAndSetIRQMask(); memNode->hasNotif = 1; memNode->hasAlert = 0; RestoreIRQMask(mask); /* callback by user! */ evtArgs.extras = extras; evtArgs.memUsed = memUsed; OsaUlfcNotifyMemEvent(OSA_ULFC_MEF_LOW_WATER, &evtArgs); } } if(memNode->handle) { osEventFlagsSet(memNode->handle, OSA_ULFC_BLOCKING_EVT_FLAGS); } } //ECPLAT_PRINTF(UNILOG_OSA, OSA_ULFC_FREE_2, P_INFO, "UlfcMem(%d): free addr(0x%x), size(%d)", extras, ptr, freeSize); return; } /****************************************************************************** * @brief : OsaUlfcReallocMem * @author: Xu.Wang * @note : ******************************************************************************/ void OsaUlfcReallocMem(void *ptr, uint32_t wantedSize) { /* TBD */ } /****************************************************************************** * @brief : OsaUlfcEnable * @author: Xu.Wang * @note : ******************************************************************************/ void OsaUlfcEnable(uint8_t chanNo, uint8_t isBlocking, OsaUlfcSrcTaskId_e taskId) { osEventFlagsId_t handle = NULL; OsaUlfcMemNode_t *memNode = NULL; if(!gOsaUlfcMemSuppFlag) return; if(chanNo >= OSA_ULFC_MEM_NODE_MAXNUM) { ECPLAT_PRINTF(UNILOG_OSA, OSA_ULFC_ENABLE_1, P_WARNING, "invalid chanNo(%d) err!", chanNo); return; } memNode = &gOsaUlfcMemMan.memNode[chanNo]; uint32_t mask = SaveAndSetIRQMask(); if(!memNode->isInit) { memset(memNode, 0, sizeof(OsaUlfcMemNode_t)); memNode->isInit = 1; memNode->refNum = 1; memNode->memThres = OSA_ULFC_ALIGN_UP(OSA_ULFC_MEM_USED_THRES_DFT, 4); memNode->memThresAlert = ((memNode->memThres * OSA_ULFC_MEM_USED_THRES_ALERT_PCT_DFT) / 100); memNode->memThresAlertPct = OSA_ULFC_MEM_USED_THRES_ALERT_PCT_DFT; memNode->bmTaskId = (1 << taskId); } else { if(!(memNode->bmTaskId & (1 << taskId))) { memNode->refNum ++; memNode->isUnset = 0; /* clr */ memNode->bmTaskId |= (1 << taskId); } } handle = memNode->handle; RestoreIRQMask(mask); if(isBlocking && !handle) { handle = osEventFlagsNew(NULL); EC_ASSERT(handle, chanNo, memNode->handle, memNode->bmTaskId); mask = SaveAndSetIRQMask(); memNode->handle = handle; RestoreIRQMask(mask); } ECPLAT_PRINTF(UNILOG_OSA, OSA_ULFC_ENABLE_2, P_SIG, "UlfcMem(%d): set task(%d/0x%x) to %s mode(%d), latest ref(%d)!", chanNo, taskId, memNode->bmTaskId, isBlocking ? "blocking" : "nonblocking", isBlocking, memNode->refNum); return; } /****************************************************************************** * @brief : OsaUlfcDisable * @author: Xu.Wang * @note : ******************************************************************************/ void OsaUlfcDisable(uint8_t chanNo, OsaUlfcSrcTaskId_e taskId) { uint32_t opFlags = 0; osTimerId_t ustTimer = NULL; osEventFlagsId_t handle = NULL; OsaUlfcMemNode_t *memNode = NULL; OsaUlfcTimerCtx_t *timerCtx = NULL; if(!gOsaUlfcMemSuppFlag) return; if(chanNo >= OSA_ULFC_MEM_NODE_MAXNUM) { ECPLAT_PRINTF(UNILOG_OSA, OSA_ULFC_DISABLE_1, P_WARNING, "invalid chanNo(%d) err!", chanNo); return; } memNode = &gOsaUlfcMemMan.memNode[chanNo]; timerCtx = &gOsaUlfcMemMan.timerCtx[chanNo]; EC_ASSERT(memNode->isInit, memNode, chanNo, taskId); ECPLAT_PRINTF(UNILOG_OSA, OSA_ULFC_DISABLE_2, P_SIG, "UlfcMem(%d): unset task(%d/0x%x), latest ref(%d)!", chanNo, taskId, memNode->bmTaskId, memNode->refNum); uint32_t mask = SaveAndSetIRQMask(); if(memNode->bmTaskId & (1 << taskId)) { memNode->refNum --; memNode->bmTaskId &= ~(1 << taskId); } if(!memNode->refNum) { EC_ASSERT(!memNode->bmTaskId, memNode->bmTaskId, chanNo, memNode); if(memNode->memUsed) { /* unsetting is delayed! */ ustTimer = memNode->ustTimer; if(!ustTimer) { opFlags |= 0x1; memNode->isUnset = 1; } else { opFlags |= 0x2; } } else { opFlags |= 0x4; handle = memNode->handle; ustTimer = memNode->ustTimer; memset(memNode, 0, sizeof(OsaUlfcMemNode_t)); } } RestoreIRQMask(mask); if(opFlags & 0x1) { ECPLAT_PRINTF(UNILOG_OSA, OSA_ULFC_DISABLE_3, P_SIG, "UlfcMem(%d): create unset timer!", chanNo); timerCtx->taskId = taskId; timerCtx->chanNo = chanNo; timerCtx->memNode = memNode; ustTimer = osTimerNew((osTimerFunc_t)OsaUlfcUnsetTimerExpr, osTimerOnce, (void*)timerCtx, NULL); EC_ASSERT(ustTimer && osOK == osTimerStart(ustTimer, OSA_ULFC_MEM_UNSET_TIMER_PERIOD), ustTimer, memNode, chanNo); mask = SaveAndSetIRQMask(); memNode->ustTimer = ustTimer; RestoreIRQMask(mask); } else if(opFlags & 0x2) { /* reset timer period! */ EC_ASSERT(osOK == osTimerStart(ustTimer, OSA_ULFC_MEM_UNSET_TIMER_PERIOD), memNode, taskId, chanNo); } else if(opFlags & 0x4) { if(handle) { osEventFlagsDelete(handle); } if(ustTimer) { if(osTimerIsRunning(ustTimer)) { osTimerStop(ustTimer); } osTimerDelete(ustTimer); } } } /****************************************************************************** * @brief : OsaUlfcNotifyMemEvent * @author: Xu.Wang * @note : ******************************************************************************/ PPP_FM_RAMCODE void OsaUlfcNotifyMemEvent(OsaUlfcMemEvtFlags_e flags, OsaUlfcMemEvtArgs_t *args) { OsaUlfcMemNode_t *memNode = NULL; if(args->extras >= OSA_ULFC_MEM_NODE_MAXNUM) { ECPLAT_PRINTF(UNILOG_OSA, ULFC_NOTIFY_MEM_EVT, P_WARNING, "invalid chanNo(%d) err!", args->extras); return; } memNode = &gOsaUlfcMemMan.memNode[args->extras]; if(memNode->isInit) { ECPLAT_PRINTF(UNILOG_OSA, OSA_ULFC_EVT_NOTIF, P_SIG, "UlfcMem(%d): %s water(%d), usedSize(%d), @bmTaskId(0x%x)!", args->extras, flags ? "high" : "low", flags, args->memUsed, memNode->bmTaskId); #ifdef FEATURE_CCIO_ENABLE if(memNode->bmTaskId & (1 << OSA_ULFC_STI_CCIO_RX)) { /* for now, only low water event is the interest of ccio rx task! */ if(flags == OSA_ULFC_MEF_LOW_WATER) ccioReportUlfcMemEvent(flags, args); } #endif } } /****************************************************************************** * @brief : OsaUlfcConfmMemEvent * @author: Xu.Wang * @note : ******************************************************************************/ PPP_FM_RAMCODE void OsaUlfcConfmMemEvent(uint8_t chanNo) { OsaUlfcMemNode_t *memNode = NULL; if(chanNo >= OSA_ULFC_MEM_NODE_MAXNUM) { ECPLAT_PRINTF(UNILOG_OSA, ULFC_CONFM_MEM_EVT, P_WARNING, "invalid chanNo(%d) err!", chanNo); return; } memNode = &gOsaUlfcMemMan.memNode[chanNo]; uint32_t mask = SaveAndSetIRQMask(); if(memNode->isInit) { memNode->hasNotif = 0; } RestoreIRQMask(mask); }