808 lines
26 KiB
C
808 lines
26 KiB
C
/******************************************************************************
|
|
|
|
*(C) Copyright 2018 EIGENCOMM International Ltd.
|
|
|
|
* All Rights Reserved
|
|
|
|
******************************************************************************
|
|
* Filename:
|
|
*
|
|
* Description:
|
|
*
|
|
* History: initiated by xuwang
|
|
*
|
|
* Notes:
|
|
*
|
|
******************************************************************************/
|
|
|
|
/*----------------------------------------------------------------------------*
|
|
* INCLUDES *
|
|
*----------------------------------------------------------------------------*/
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#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);
|
|
}
|
|
|
|
|