diff --git a/components/power/los_pm.c b/components/power/los_pm.c
index a9c1c1e7..46f5cd92 100644
--- a/components/power/los_pm.c
+++ b/components/power/los_pm.c
@@ -34,20 +34,23 @@
#include "los_sched.h"
#include "los_timer.h"
#include "los_memory.h"
+#include "los_swtmr.h"
#if (LOSCFG_KERNEL_PM == 1)
#define OS_PM_NODE_FREE 0x80000000U
#define OS_PM_LOCK_MAX 0xFFFFU
+#define OS_PM_SYS_EARLY 1
+#define OS_PM_SYS_DEVICE_EARLY 2
-typedef UINT32 (*Suspend)(VOID);
+typedef UINT32 (*SysSuspend)(VOID);
+typedef UINT32 (*Suspend)(UINT32 mode);
-#if (LOSCFG_KERNEL_PM_DEBUG == 1)
typedef struct {
CHAR *name;
UINT32 count;
+ UINT32 swtmrID;
LOS_DL_LIST list;
} OsPmLockCB;
-#endif
typedef struct {
LOS_SysSleepEnum pmMode;
@@ -60,11 +63,12 @@ typedef struct {
#if (LOSCFG_BASE_CORE_TICK_WTIMER == 0)
UINT64 enterSleepTime;
#endif
-#if (LOSCFG_KERNEL_PM_DEBUG == 1)
LOS_DL_LIST lockList;
-#endif
} LosPmCB;
+#define PM_EVENT_LOCK_MASK 0xF
+#define PM_EVENT_LOCK_RELEASE 0x1
+STATIC EVENT_CB_S g_pmEvent;
STATIC LosPmCB g_pmCB;
STATIC LosPmSysctrl *g_sysctrl = NULL;
STATIC UINT64 g_pmSleepTime;
@@ -99,7 +103,7 @@ STATIC VOID OsPmTickTimerStart(LosPmCB *pm)
return;
}
-STATIC VOID OsPmTickTimerStop(LosPmCB *pm)
+STATIC BOOL OsPmTickTimerStop(LosPmCB *pm)
{
#if (LOSCFG_BASE_CORE_TICK_WTIMER == 0)
UINT64 sleepCycle;
@@ -108,13 +112,13 @@ STATIC VOID OsPmTickTimerStop(LosPmCB *pm)
LosPmTickTimer *tickTimer = pm->tickTimer;
if ((tickTimer == NULL) || (tickTimer->tickLock == NULL)) {
- return;
+ return FALSE;
}
#if (LOSCFG_BASE_CORE_TICK_WTIMER == 0)
if (tickTimer->timerStart != NULL) {
if (realSleepTime == 0) {
- return;
+ return FALSE;
}
sleepCycle = OS_SYS_CYCLE_TO_NS(realSleepTime, OS_SYS_CLOCK);
@@ -124,12 +128,12 @@ STATIC VOID OsPmTickTimerStop(LosPmCB *pm)
pm->enterSleepTime = OsGetCurrSysTimeCycle();
tickTimer->tickLock();
tickTimer->timerStart(sleepCycle);
- return;
+ return TRUE;
}
#endif
tickTimer->tickLock();
- return;
+ return TRUE;
}
STATIC VOID OsPmCpuResume(LosPmCB *pm)
@@ -143,9 +147,9 @@ STATIC VOID OsPmCpuResume(LosPmCB *pm)
}
}
-STATIC Suspend OsPmCpuSuspend(LosPmCB *pm)
+STATIC SysSuspend OsPmCpuSuspend(LosPmCB *pm)
{
- Suspend sysSuspend = NULL;
+ SysSuspend sysSuspend = NULL;
/* cpu enter low power mode */
LOS_ASSERT(pm->sysctrl != NULL);
@@ -165,36 +169,94 @@ STATIC Suspend OsPmCpuSuspend(LosPmCB *pm)
return sysSuspend;
}
-STATIC UINT32 OsPmSuspendSleep(LosPmCB *pm)
+STATIC VOID OsPmResumePrepare(LosPmCB *pm, UINT32 mode, UINT32 prepare)
+{
+ if ((prepare == 0) && (pm->device->resume != NULL)) {
+ pm->device->resume(mode);
+ }
+
+ if (((prepare == 0) || (prepare == OS_PM_SYS_DEVICE_EARLY)) && (pm->sysctrl->late != NULL)) {
+ pm->sysctrl->late(mode);
+ }
+}
+
+STATIC UINT32 OsPmSuspendPrepare(Suspend sysSuspendEarly, Suspend deviceSuspend, UINT32 mode, UINT32 *prepare)
+{
+ UINT32 ret;
+
+ if (sysSuspendEarly != NULL) {
+ ret = sysSuspendEarly(mode);
+ if (ret != LOS_OK) {
+ *prepare = OS_PM_SYS_EARLY;
+ return ret;
+ }
+ }
+
+ if (deviceSuspend != NULL) {
+ ret = deviceSuspend(mode);
+ if (ret != LOS_OK) {
+ *prepare = OS_PM_SYS_DEVICE_EARLY;
+ return ret;
+ }
+ }
+
+ return LOS_OK;
+}
+
+STATIC UINT32 OsPmSuspendCheck(LosPmCB *pm, Suspend *sysSuspendEarly, Suspend *deviceSuspend, LOS_SysSleepEnum *mode)
{
- UINT32 ret = LOS_OK;
UINT32 intSave;
- LOS_SysSleepEnum mode;
- Suspend sysSuspend = NULL;
intSave = LOS_IntLock();
pm->sysMode = pm->pmMode;
- if ((pm->pmMode != LOS_SYS_NORMAL_SLEEP) && (pm->lock > 0)) {
+ if (pm->lock > 0) {
pm->sysMode = LOS_SYS_NORMAL_SLEEP;
- }
-
- if (pm->sysMode == LOS_SYS_NORMAL_SLEEP) {
LOS_IntRestore(intSave);
return LOS_NOK;
}
pm->isWake = FALSE;
- LOS_TaskLock();
+ *mode = pm->sysMode;
+ *sysSuspendEarly = pm->sysctrl->early;
+ *deviceSuspend = pm->device->suspend;
+ LOS_IntRestore(intSave);
+ return LOS_OK;
+}
- mode = pm->sysMode;
- if (pm->device->suspend != NULL) {
- ret = pm->device->suspend(mode);
- if (ret != LOS_OK) {
- goto DEVICE_EXIT;
- }
+STATIC UINT32 OsPmSuspendSleep(LosPmCB *pm)
+{
+ UINT32 ret, intSave;
+ Suspend sysSuspendEarly, deviceSuspend;
+ LOS_SysSleepEnum mode;
+ UINT32 prepare = 0;
+ BOOL tickTimerStop = FALSE;
+ SysSuspend sysSuspend;
+ UINT64 currTime;
+
+ ret = OsPmSuspendCheck(pm, &sysSuspendEarly, &deviceSuspend, &mode);
+ if (ret != LOS_OK) {
+ return ret;
}
- OsPmTickTimerStop(pm);
+ ret = OsPmSuspendPrepare(sysSuspendEarly, deviceSuspend, (UINT32)mode, &prepare);
+ if (ret != LOS_OK) {
+ intSave = LOS_IntLock();
+ LOS_TaskLock();
+ goto EXIT;
+ }
+
+ intSave = LOS_IntLock();
+ LOS_TaskLock();
+ if (pm->isWake || (pm->lock > 0)) {
+ goto EXIT;
+ }
+
+ tickTimerStop = OsPmTickTimerStop(pm);
+ if (!tickTimerStop) {
+ currTime = OsGetCurrSchedTimeCycle();
+ OsSchedResetSchedResponseTime(0);
+ OsSchedSetNextExpireTime(currTime, OS_INVALID, OS_SCHED_MAX_RESPONSE_TIME, TRUE);
+ }
sysSuspend = OsPmCpuSuspend(pm);
LOS_IntRestore(intSave);
@@ -209,22 +271,20 @@ STATIC UINT32 OsPmSuspendSleep(LosPmCB *pm)
OsPmTickTimerStart(pm);
- if (pm->device->resume != NULL) {
- pm->device->resume(mode);
- }
-
-DEVICE_EXIT:
+EXIT:
pm->sysMode = LOS_SYS_NORMAL_SLEEP;
+ OsPmResumePrepare(pm, (UINT32)mode, prepare);
LOS_IntRestore(intSave);
LOS_TaskUnlock();
return ret;
}
-STATIC VOID OsPmNormalSleep(LosPmCB *pm)
+STATIC VOID OsPmNormalSleep(VOID)
{
UINT32 intSave;
- Suspend sysSuspend = NULL;
+ LosPmCB *pm = &g_pmCB;
+ SysSuspend sysSuspend = NULL;
intSave = LOS_IntLock();
sysSuspend = OsPmCpuSuspend(pm);
@@ -237,24 +297,6 @@ STATIC VOID OsPmNormalSleep(LosPmCB *pm)
LOS_IntRestore(intSave);
}
-STATIC VOID OsPmEnter(VOID)
-{
- UINT32 ret;
- LosPmCB *pm = &g_pmCB;
-
- ret = OsPmSuspendSleep(pm);
- if (ret != LOS_OK) {
- OsPmNormalSleep(pm);
- }
-
- return;
-}
-
-STATIC VOID OsPmTask(VOID)
-{
- OsPmEnter();
-}
-
STATIC UINT32 OsPmDeviceRegister(LosPmCB *pm, LosPmDevice *device)
{
UINT32 intSave;
@@ -438,11 +480,8 @@ LOS_SysSleepEnum LOS_PmModeGet(VOID)
UINT32 LOS_PmModeSet(LOS_SysSleepEnum mode)
{
UINT32 intSave;
- UINT32 taskID;
- UINT32 ret;
LosPmCB *pm = &g_pmCB;
INT32 sleepMode = (INT32)mode;
- TSK_INIT_PARAM_S taskInitParam = { 0 };
if ((sleepMode < 0) || (sleepMode > LOS_SYS_SHUTDOWN)) {
return LOS_ERRNO_PM_INVALID_MODE;
@@ -472,17 +511,6 @@ UINT32 LOS_PmModeSet(LOS_SysSleepEnum mode)
pm->pmMode = mode;
LOS_IntRestore(intSave);
- if ((mode == LOS_SYS_DEEP_SLEEP) || (mode == LOS_SYS_SHUTDOWN)) {
- taskInitParam.pfnTaskEntry = (TSK_ENTRY_FUNC)OsPmTask;
- taskInitParam.uwStackSize = LOSCFG_KERNEL_PM_TASK_STACKSIZE;
- taskInitParam.pcName = "pm";
- taskInitParam.usTaskPrio = LOSCFG_KERNEL_PM_TASK_PTIORITY;
- ret = LOS_TaskCreate(&taskID, &taskInitParam);
- if (ret != LOS_OK) {
- return ret;
- }
- }
-
return LOS_OK;
}
@@ -509,24 +537,17 @@ VOID LOS_PmLockInfoShow(VOID)
}
#endif
-UINT32 LOS_PmLockRequest(const CHAR *name)
+UINT32 OsPmLockRequest(const CHAR *name, UINT32 swtmrID)
{
UINT32 intSave;
UINT32 ret = LOS_ERRNO_PM_NOT_LOCK;
LosPmCB *pm = &g_pmCB;
-#if (LOSCFG_KERNEL_PM_DEBUG == 1)
OsPmLockCB *listNode = NULL;
OsPmLockCB *lock = NULL;
LOS_DL_LIST *head = &pm->lockList;
LOS_DL_LIST *list = head->pstNext;
- if (name == NULL) {
- return LOS_ERRNO_PM_INVALID_PARAM;
- }
-#endif
-
intSave = LOS_IntLock();
-#if (LOSCFG_KERNEL_PM_DEBUG == 1)
while (list != head) {
listNode = LOS_DL_LIST_ENTRY(list, OsPmLockCB, list);
if (strcmp(name, listNode->name) == 0) {
@@ -545,11 +566,17 @@ UINT32 LOS_PmLockRequest(const CHAR *name)
}
lock->name = (CHAR *)name;
lock->count = 1;
+ lock->swtmrID = swtmrID;
LOS_ListTailInsert(head, &lock->list);
} else if (lock->count < OS_PM_LOCK_MAX) {
lock->count++;
}
-#endif
+
+ if ((lock->swtmrID != OS_INVALID) && (lock->count > 1)) {
+ lock->count--;
+ LOS_IntRestore(intSave);
+ return LOS_ERRNO_PM_ALREADY_LOCK;
+ }
if (pm->lock < OS_PM_LOCK_MAX) {
pm->lock++;
@@ -560,25 +587,34 @@ UINT32 LOS_PmLockRequest(const CHAR *name)
return ret;
}
+UINT32 LOS_PmLockRequest(const CHAR *name)
+{
+ if (name == NULL) {
+ return LOS_ERRNO_PM_INVALID_PARAM;
+ }
+
+ return OsPmLockRequest(name, OS_INVALID);
+}
+
UINT32 LOS_PmLockRelease(const CHAR *name)
{
UINT32 intSave;
UINT32 ret = LOS_ERRNO_PM_NOT_LOCK;
LosPmCB *pm = &g_pmCB;
-#if (LOSCFG_KERNEL_PM_DEBUG == 1)
OsPmLockCB *lock = NULL;
OsPmLockCB *listNode = NULL;
LOS_DL_LIST *head = &pm->lockList;
LOS_DL_LIST *list = head->pstNext;
- VOID *lockFree = NULL;
+ OsPmLockCB *lockFree = NULL;
+ BOOL isRelease = FALSE;
+ UINT32 mode;
if (name == NULL) {
return LOS_ERRNO_PM_INVALID_PARAM;
}
-#endif
intSave = LOS_IntLock();
-#if (LOSCFG_KERNEL_PM_DEBUG == 1)
+ mode = (UINT32)pm->pmMode;
while (list != head) {
listNode = LOS_DL_LIST_ENTRY(list, OsPmLockCB, list);
if (strcmp(name, listNode->name) == 0) {
@@ -599,25 +635,139 @@ UINT32 LOS_PmLockRelease(const CHAR *name)
lockFree = lock;
}
}
-#endif
if (pm->lock > 0) {
pm->lock--;
+ if (pm->lock == 0) {
+ isRelease = TRUE;
+ }
ret = LOS_OK;
}
-
LOS_IntRestore(intSave);
-#if (LOSCFG_KERNEL_PM_DEBUG == 1)
- (VOID)LOS_MemFree((VOID *)OS_SYS_MEM_ADDR, lockFree);
-#endif
+
+ if (lockFree != NULL) {
+ (VOID)LOS_SwtmrDelete(lockFree->swtmrID);
+ (VOID)LOS_MemFree((VOID *)OS_SYS_MEM_ADDR, lockFree);
+ }
+
+ if (isRelease && (mode > LOS_SYS_NORMAL_SLEEP)) {
+ (VOID)LOS_EventWrite(&g_pmEvent, PM_EVENT_LOCK_RELEASE);
+ }
+
return ret;
}
+VOID OsPmFreezeTaskUnsafe(UINT32 taskID)
+{
+ UINT64 responseTime;
+ LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID);
+
+ responseTime = GET_SORTLIST_VALUE(&taskCB->sortList);
+ OsDeleteSortLink(&taskCB->sortList, OS_SORT_LINK_TASK);
+ SET_SORTLIST_VALUE(&taskCB->sortList, responseTime);
+ taskCB->taskStatus |= OS_TASK_FALG_FREEZE;
+ return;
+}
+
+VOID OsPmUnfreezeTaskUnsafe(UINT32 taskID)
+{
+ LosTaskCB *taskCB = OS_TCB_FROM_TID(taskID);
+ UINT64 currTime, responseTime;
+ UINT32 remainTick;
+
+ taskCB->taskStatus &= ~OS_TASK_FALG_FREEZE;
+ currTime = OsGetCurrSchedTimeCycle();
+ responseTime = GET_SORTLIST_VALUE(&taskCB->sortList);
+ if (responseTime > currTime) {
+ remainTick = ((responseTime - currTime) + OS_CYCLE_PER_TICK - 1) / OS_CYCLE_PER_TICK;
+ OsAdd2SortLink(&taskCB->sortList, currTime, remainTick, OS_SORT_LINK_TASK);
+ return;
+ }
+
+ SET_SORTLIST_VALUE(&taskCB->sortList, OS_SORT_LINK_INVALID_TIME);
+ LOS_ListDelete(&taskCB->pendList);
+ taskCB->taskStatus &= ~(OS_TASK_STATUS_DELAY | OS_TASK_STATUS_PEND_TIME);
+ return;
+}
+
+STATIC VOID OsPmSwtmrHandler(UINT32 arg)
+{
+ const CHAR *name = (const CHAR *)arg;
+ UINT32 ret = LOS_PmLockRelease(name);
+ if (ret != LOS_OK) {
+ PRINT_ERR("Pm delay lock %s release faled! : 0x%x\n", name, ret);
+ }
+}
+
+UINT32 LOS_PmTimeLockRequest(const CHAR *name, UINT64 millisecond)
+{
+ UINT32 ticks;
+ UINT32 swtmrID;
+ UINT32 ret;
+
+ if ((name == NULL) || !millisecond) {
+ return LOS_ERRNO_PM_INVALID_PARAM;
+ }
+
+ ticks = (UINT32)((millisecond + OS_MS_PER_TICK - 1) / OS_MS_PER_TICK);
+#if (LOSCFG_BASE_CORE_SWTMR_ALIGN == 1)
+ ret = LOS_SwtmrCreate(ticks, LOS_SWTMR_MODE_ONCE, OsPmSwtmrHandler, &swtmrID, (UINT32)(UINTPTR)name,
+ OS_SWTMR_ROUSES_ALLOW, OS_SWTMR_ALIGN_INSENSITIVE);
+#else
+ ret = LOS_SwtmrCreate(ticks, LOS_SWTMR_MODE_ONCE, OsPmSwtmrHandler, &swtmrID, (UINT32)(UINTPTR)name);
+#endif
+ if (ret != LOS_OK) {
+ return ret;
+ }
+
+ ret = OsPmLockRequest(name, swtmrID);
+ if (ret != LOS_OK) {
+ (VOID)LOS_SwtmrDelete(swtmrID);
+ return ret;
+ }
+
+ ret = LOS_SwtmrStart(swtmrID);
+ if (ret != LOS_OK) {
+ (VOID)LOS_PmLockRelease(name);
+ }
+
+ return ret;
+}
+
+UINT32 LOS_PmReadLock(VOID)
+{
+ UINT32 ret = LOS_EventRead(&g_pmEvent, PM_EVENT_LOCK_MASK, LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);
+ if (ret > PM_EVENT_LOCK_MASK) {
+ PRINT_ERR("%s event read failed! ERROR: 0x%x\n", ret);
+ }
+
+ return LOS_OK;
+}
+
+UINT32 LOS_PmSuspend(UINT32 wakeCount)
+{
+ (VOID)wakeCount;
+ return OsPmSuspendSleep(&g_pmCB);
+}
+
STATIC VOID OsPmSleepTimeSet(UINT64 sleepTime)
{
g_pmSleepTime = sleepTime;
}
+BOOL OsIsPmMode(VOID)
+{
+ LosPmCB *pm = &g_pmCB;
+
+ UINT32 intSave = LOS_IntLock();
+ if ((pm->sysMode != LOS_SYS_NORMAL_SLEEP) && (pm->lock == 0)) {
+ LOS_IntRestore(intSave);
+ return TRUE;
+ }
+ LOS_IntRestore(intSave);
+ return FALSE;
+}
+
UINT32 OsPmInit(VOID)
{
UINT32 ret;
@@ -626,16 +776,15 @@ UINT32 OsPmInit(VOID)
(VOID)memset_s(pm, sizeof(LosPmCB), 0, sizeof(LosPmCB));
pm->pmMode = LOS_SYS_NORMAL_SLEEP;
-#if (LOSCFG_KERNEL_PM_DEBUG == 1)
LOS_ListInit(&pm->lockList);
-#endif
+ (VOID)LOS_EventInit(&g_pmEvent);
ret = OsSchedRealSleepTimeSet(OsPmSleepTimeSet);
if (ret != LOS_OK) {
return ret;
}
- ret = OsPmEnterHandlerSet(OsPmEnter);
+ ret = OsPmEnterHandlerSet(OsPmNormalSleep);
if (ret != LOS_OK) {
return ret;
}
diff --git a/components/power/los_pm.h b/components/power/los_pm.h
index 5564de6d..a3e7e3f9 100644
--- a/components/power/los_pm.h
+++ b/components/power/los_pm.h
@@ -118,6 +118,15 @@
*/
#define LOS_ERRNO_PM_DEVICE_NULL LOS_ERRNO_OS_ERROR(LOS_MOD_PM, 0x09)
+/**
+ * @ingroup los_pm
+ * Pm error code: The delay lock has already been activated.
+ *
+ * Value: 0x0200200a
+ *
+ */
+#define LOS_ERRNO_PM_ALREADY_LOCK LOS_ERRNO_OS_ERROR(LOS_MOD_PM, 0x0a)
+
typedef enum {
LOS_SYS_NORMAL_SLEEP = 0,
LOS_SYS_LIGHT_SLEEP,
@@ -132,8 +141,8 @@ typedef enum {
} LOS_PmNodeType;
typedef struct {
- UINT32 (*suspend)(UINT32 mode);
- VOID (*resume)(UINT32 mode);
+ UINT32 (*suspend)(UINT32 mode); /* The device enters low power consumption, Unlocked task scheduling. */
+ VOID (*resume)(UINT32 mode); /* The device exits from low power consumption, Unlocked task scheduling. */
} LosPmDevice;
typedef struct {
@@ -146,13 +155,47 @@ typedef struct {
} LosPmTickTimer;
typedef struct {
+ /* Preparations before the CPU enters low power consumption.
+ * All modes except normal mode are invoked.
+ * Unlocked task scheduling.
+ */
+ UINT32 (*early)(UINT32 mode);
+ /* The system performs low-power recovery.
+ * All modes except normal mode are invoked.
+ * Unlocked task scheduling.
+ */
+ VOID (*late)(UINT32 mode);
+ /* The system enters the Normal sleep mode.
+ * In normal mode, the value cannot be NULL.
+ */
UINT32 (*normalSuspend)(VOID);
+ /* The system recovers from normal sleep.
+ * The value can be NULL.
+ */
VOID (*normalResume)(VOID);
+ /* The system enters the light sleep mode.
+ * In light sleep mode, the value cannot be NULL.
+ */
UINT32 (*lightSuspend)(VOID);
+ /* The system recovers from light sleep.
+ * The value can be NULL.
+ */
VOID (*lightResume)(VOID);
+ /* The system enters the deep sleep mode.
+ * In deep sleep mode, the value cannot be NULL.
+ */
UINT32 (*deepSuspend)(VOID);
+ /* The system recovers from deep sleep.
+ * The value can be NULL.
+ */
VOID (*deepResume)(VOID);
+ /* The system enters the shutdown mode.
+ * In shutdown mode, the value cannot be NULL.
+ */
UINT32 (*shutdownSuspend)(VOID);
+ /* The system recovers from shutdown.
+ * In shutdown mode, the value cannot be NULL.
+ */
VOID (*shutdownResume)(VOID);
} LosPmSysctrl;
@@ -174,6 +217,60 @@ typedef struct {
*/
UINT32 OsPmInit(VOID);
+/**
+ * @ingroup los_pm
+ * @brief Whether the low power consumption condition is met.
+ *
+ * @par Description:
+ * This API is used to check whether low power consumption is met.
+ *
+ * @attention None.
+ *
+ * @param None.
+ *
+ * @retval TRUE or FALSE.
+ * @par Dependency:
+ *
- los_pm.h: the header file that contains the API declaration.
+ * @see
+ */
+BOOL OsIsPmMode(VOID);
+
+/**
+ * @ingroup los_pm
+ * @brief Freeze delay tasks, internal interfaces between modules.
+ *
+ * @par Description:
+ * This API is used to freeze delay tasks.
+ *
+ * @attention None.
+ *
+ * @param taskID [IN] task ID.
+ *
+ * @retval None.
+ * @par Dependency:
+ * - los_pm.h: the header file that contains the API declaration.
+ * @see OsPmUnfreezeTaskUnsafe
+ */
+VOID OsPmFreezeTaskUnsafe(UINT32 taskID);
+
+/**
+ * @ingroup los_pm
+ * @brief Unfreeze delayed tasks, internal interface between modules.
+ *
+ * @par Description:
+ * This API is used to unfreeze delayed tasks.
+ *
+ * @attention None.
+ *
+ * @param taskID [IN] task ID.
+ *
+ * @retval None.
+ * @par Dependency:
+ * - los_pm.h: the header file that contains the API declaration.
+ * @see OsPmFreezeTaskUnsafe
+ */
+VOID OsPmUnfreezeTaskUnsafe(UINT32 taskID);
+
/**
* @ingroup los_pm
* @brief Register a power management node.
@@ -285,6 +382,27 @@ UINT32 LOS_PmModeSet(LOS_SysSleepEnum mode);
*/
UINT32 LOS_PmLockRequest(const CHAR *name);
+/**
+ * @ingroup los_pm
+ * @brief Request to obtain the lock in current mode, so that the system will not enter
+ * this mode when it enters the idle task next time. After the specified interval, the
+ * lock is automatically released.
+ *
+ * @par Description:
+ * This API is used to obtain the delay lock in current mode.
+ *
+ * @attention None.
+ *
+ * @param name [IN] Who requests the lock.
+ * @param millisecond [IN] Specifies the time to automatically release the lock.
+ *
+ * @retval error code, LOS_OK means success.
+ * @par Dependency:
+ * - los_pm.h: the header file that contains the API declaration.
+ * @see LOS_PmLockRelease
+ */
+UINT32 LOS_PmTimeLockRequest(const CHAR *name, UINT64 millisecond);
+
/**
* @ingroup los_pm
* @brief Release the lock in current mode so that the next time the system enters
@@ -304,6 +422,42 @@ UINT32 LOS_PmLockRequest(const CHAR *name);
*/
UINT32 LOS_PmLockRelease(const CHAR *name);
+/**
+ * @ingroup los_pm
+ * @brief Gets the current PM lock status.
+ *
+ * @par Description:
+ * This API is used to Get the current PM lock status.
+ *
+ * @attention None.
+ *
+ * @param NA.
+ *
+ * @retval Number of awakening sources of the device.
+ * @par Dependency:
+ * - los_pm.h: the header file that contains the API declaration.
+ * @see
+ */
+UINT32 LOS_PmReadLock(VOID);
+
+/**
+ * @ingroup los_pm
+ * @brief The system enters the low-power flow.
+ *
+ * @par Description:
+ * This API is used to enter the system into a low-power process.
+ *
+ * @attention None.
+ *
+ * @param wakeCount [IN] Number of wake sources.
+ *
+ * @retval error code, LOS_OK means success.
+ * @par Dependency:
+ * - los_pm.h: the header file that contains the API declaration.
+ * @see
+ */
+UINT32 LOS_PmSuspend(UINT32 wakeCount);
+
#if (LOSCFG_KERNEL_PM_DEBUG == 1)
/**
* @ingroup los_pm
diff --git a/kernel/include/los_sched.h b/kernel/include/los_sched.h
index df26da61..87b8189b 100644
--- a/kernel/include/los_sched.h
+++ b/kernel/include/los_sched.h
@@ -61,6 +61,8 @@ VOID OsSchedSetIdleTaskSchedParam(LosTaskCB *idleTask);
UINT32 OsSchedSwtmrScanRegister(SchedScan func);
+VOID OsSchedSetNextExpireTime(UINT64 startTime, UINT32 responseID, UINT64 taskEndTime, BOOL timeUpdate);
+
VOID OsSchedUpdateExpireTime(UINT64 startTime, BOOL timeUpdate);
VOID OsSchedTaskDeQueue(LosTaskCB *taskCB);
diff --git a/kernel/include/los_task.h b/kernel/include/los_task.h
index 1df6c111..0e587535 100644
--- a/kernel/include/los_task.h
+++ b/kernel/include/los_task.h
@@ -1175,6 +1175,14 @@ extern VOID LOS_UDelay(UINT64 microseconds);
*/
#define OS_TASK_STATUS_PEND_TIME 0x0080
+/**
+ * @ingroup los_task
+ * Flag that indicates the task or task control block status.
+ *
+ * The delayed operation of this task is frozen.
+ */
+#define OS_TASK_FALG_FREEZE 0x4000
+
/**
* @ingroup los_task
* Flag that indicates the task is in userspace.
diff --git a/kernel/src/los_sched.c b/kernel/src/los_sched.c
index a0b2c221..b0d72d6d 100644
--- a/kernel/src/los_sched.c
+++ b/kernel/src/los_sched.c
@@ -179,7 +179,7 @@ STATIC INLINE VOID OsSchedTickReload(UINT64 nextResponseTime, UINT32 responseID,
HalSysTickReload(nextResponseTime);
}
-STATIC INLINE VOID OsSchedSetNextExpireTime(UINT64 startTime, UINT32 responseID, UINT64 taskEndTime, BOOL timeUpdate)
+VOID OsSchedSetNextExpireTime(UINT64 startTime, UINT32 responseID, UINT64 taskEndTime, BOOL timeUpdate)
{
UINT64 nextExpireTime;
UINT64 nextResponseTime = 0;
@@ -415,7 +415,7 @@ BOOL OsSchedModifyTaskSchedParam(LosTaskCB *taskCB, UINT16 priority)
}
taskCB->priority = priority;
- OsHookCall(LOS_HOOK_TYPE_TASK_PRIMODIFY, taskCB, taskCB->priority);
+ OsHookCall(LOS_HOOK_TYPE_TASK_PRIMODIFY, taskCB, taskCB->priority);
if (taskCB->taskStatus & OS_TASK_STATUS_RUNNING) {
return TRUE;
}
diff --git a/kernel/src/los_task.c b/kernel/src/los_task.c
index a4f5afbc..33437640 100644
--- a/kernel/src/los_task.c
+++ b/kernel/src/los_task.c
@@ -44,6 +44,9 @@
#if (LOSCFG_BASE_CORE_CPUP == 1)
#include "los_cpup.h"
#endif
+#if (LOSCFG_KERNEL_PM == 1)
+#include "los_pm.h"
+#endif
/**
* @ingroup los_task
@@ -403,7 +406,6 @@ LITE_OS_SEC_TEXT_INIT UINT32 OsIdleTaskCreate(VOID)
taskInitParam.pcName = "IdleCore000";
taskInitParam.usTaskPrio = OS_TASK_PRIORITY_LOWEST;
retVal = LOS_TaskCreateOnly(&g_idleTaskID, &taskInitParam);
-
if (retVal != LOS_OK) {
return retVal;
}
@@ -803,6 +805,12 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskResume(UINT32 taskID)
OS_GOTO_ERREND();
}
+#if (LOSCFG_KERNEL_PM == 1)
+ if (tempStatus & OS_TASK_FALG_FREEZE) {
+ OsPmUnfreezeTaskUnsafe(taskID);
+ }
+#endif
+
taskCB->taskStatus &= (~OS_TASK_STATUS_SUSPEND);
if (!(taskCB->taskStatus & OS_CHECK_TASK_BLOCK)) {
OsSchedTaskEnQueue(taskCB);
@@ -862,6 +870,12 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskSuspend(UINT32 taskID)
OsSchedTaskDeQueue(taskCB);
}
+#if (LOSCFG_KERNEL_PM == 1)
+ if ((tempStatus & (OS_TASK_STATUS_PEND_TIME | OS_TASK_STATUS_DELAY)) && OsIsPmMode()) {
+ OsPmFreezeTaskUnsafe(taskID);
+ }
+#endif
+
taskCB->taskStatus |= OS_TASK_STATUS_SUSPEND;
OsHookCall(LOS_HOOK_TYPE_MOVEDTASKTOSUSPENDEDLIST, taskCB);
if (taskID == g_losTask.runTask->taskID) {
diff --git a/testsuits/sample/kernel/power/BUILD.gn b/testsuits/sample/kernel/power/BUILD.gn
index 1f8177cd..9fefaa7d 100644
--- a/testsuits/sample/kernel/power/BUILD.gn
+++ b/testsuits/sample/kernel/power/BUILD.gn
@@ -31,6 +31,7 @@ static_library("test_pm") {
"It_los_pm.c",
"It_los_pm_001.c",
"It_los_pm_002.c",
+ "It_los_pm_003.c",
]
include_dirs = [ "//kernel/liteos_m/components/power" ]
diff --git a/testsuits/sample/kernel/power/It_los_pm.c b/testsuits/sample/kernel/power/It_los_pm.c
index fa61be39..dd731e72 100644
--- a/testsuits/sample/kernel/power/It_los_pm.c
+++ b/testsuits/sample/kernel/power/It_los_pm.c
@@ -31,9 +31,10 @@
#include "osTest.h"
#include "It_los_pm.h"
-VOID ItSuiteLosPm()
+VOID ItSuiteLosPm(VOID)
{
ItLosPm001();
ItLosPm002();
+ ItLosPm003();
}
diff --git a/testsuits/sample/kernel/power/It_los_pm.h b/testsuits/sample/kernel/power/It_los_pm.h
index 82809c35..6190979c 100644
--- a/testsuits/sample/kernel/power/It_los_pm.h
+++ b/testsuits/sample/kernel/power/It_los_pm.h
@@ -55,6 +55,7 @@ extern "C" {
extern VOID ItLosPm001(VOID);
extern VOID ItLosPm002(VOID);
+extern VOID ItLosPm003(VOID);
#ifdef __cplusplus
#if __cplusplus
diff --git a/testsuits/sample/kernel/power/It_los_pm_001.c b/testsuits/sample/kernel/power/It_los_pm_001.c
index ac3f8571..81ff4667 100644
--- a/testsuits/sample/kernel/power/It_los_pm_001.c
+++ b/testsuits/sample/kernel/power/It_los_pm_001.c
@@ -50,16 +50,21 @@ static VOID SysResume(VOID)
{
}
-static UINT32 SysSuspend(VOID)
-{
- return HalEnterSleep();
-}
-
static LosPmSysctrl g_sysctrl = {
.normalSuspend = NULL,
.normalResume = SysResume,
};
+static VOID TimerStart(UINT64 timer)
+{
+
+}
+
+static UINT64 GetTimerCycle(VOID)
+{
+ return 0;
+}
+
static VOID TickLock(VOID)
{
return;
@@ -128,7 +133,7 @@ static UINT32 TestCase(VOID)
g_tickTimer.tickLock = TickLock;
g_tickTimer.tickUnlock = TickUnlock;
- g_tickTimer.timerStart = TickLock;
+ g_tickTimer.timerStart = TimerStart;
ret = LOS_PmRegister(LOS_PM_TYPE_TICK_TIMER, &g_tickTimer);
ICUNIT_ASSERT_EQUAL(ret, LOS_ERRNO_PM_INVALID_PARAM, ret);
@@ -136,7 +141,7 @@ static UINT32 TestCase(VOID)
ret = LOS_PmRegister(LOS_PM_TYPE_TICK_TIMER, &g_tickTimer);
ICUNIT_ASSERT_EQUAL(ret, LOS_ERRNO_PM_INVALID_PARAM, ret);
- g_tickTimer.timerCycleGet = TickLock;
+ g_tickTimer.timerCycleGet = GetTimerCycle;
ret = LOS_PmRegister(LOS_PM_TYPE_TICK_TIMER, &g_tickTimer);
ICUNIT_ASSERT_EQUAL(ret, LOS_ERRNO_PM_INVALID_PARAM, ret);
@@ -159,4 +164,3 @@ VOID ItLosPm001(VOID) // IT_Layer_ModuleORFeature_No
{
TEST_ADD_CASE("ItLosPm001", TestCase, TEST_LOS, TEST_TASK, TEST_LEVEL0, TEST_FUNCTION);
}
-
diff --git a/testsuits/sample/kernel/power/It_los_pm_002.c b/testsuits/sample/kernel/power/It_los_pm_002.c
index 762e8edd..a64964f5 100644
--- a/testsuits/sample/kernel/power/It_los_pm_002.c
+++ b/testsuits/sample/kernel/power/It_los_pm_002.c
@@ -32,9 +32,14 @@
#include "It_los_pm.h"
#include "los_timer.h"
+#define myprintf // printf
+#define TEST_LOOP 5
+static EVENT_CB_S g_pmTestEvent;
+static UINT32 g_taskID1, g_taskID2;
static UINT32 g_deviceCount = 0;
static UINT32 g_sysCount = 0;
-static UINT32 g_sysTickTimerCount = 0;
+static volatile UINT32 g_pmTestCount = 0;
+
static UINT32 DeviceSuspend(UINT32 mode)
{
g_deviceCount++;
@@ -53,26 +58,6 @@ static LosPmDevice g_device = {
.resume = DeviceResume,
};
-static VOID TickLock(VOID)
-{
- g_testCount++;
- g_sysTickTimerCount++;
-}
-
-static VOID TickUnlock(VOID)
-{
- g_sysTickTimerCount--;
-}
-
-static LosPmTickTimer g_tickTimer = {
- .tickLock = TickLock,
- .tickUnlock = TickUnlock,
- .timerStart = NULL,
- .timerStop = NULL,
- .timerCycleGet = NULL,
- .freq = 0,
-};
-
static VOID SysResume(VOID)
{
if (g_sysCount != (UINT32)-1) {
@@ -85,29 +70,154 @@ static UINT32 SysSuspend(VOID)
g_testCount++;
g_sysCount++;
- if ((g_sysTickTimerCount != 1) || (g_deviceCount != 1) || (g_sysCount != 1)) {
+ if ((g_deviceCount != 1) || (g_sysCount != 1)) { /* 1: sys count */
g_sysCount = (UINT32)-1;
}
+ UINT64 timeout = LOS_SchedTickTimeoutNsGet();
+ printf("pm timeout : %u ns -> %u ticks\n", (UINT32)timeout, (UINT32)(timeout / OS_NS_PER_TICK));
return HalEnterSleep();
}
+static UINT32 SystemPmEarly(UINT32 mode)
+{
+ UINT32 ret;
+
+ ret = LOS_TaskSuspend(g_taskID2);
+ ICUNIT_ASSERT_EQUAL(ret, LOS_OK, ret);
+
+ ret = LOS_TaskSuspend(g_taskID1);
+ if (ret != LOS_OK) {
+ (VOID)LOS_TaskResume(g_taskID2);
+ }
+ ICUNIT_ASSERT_EQUAL(ret, LOS_OK, ret);
+
+ return LOS_OK;
+}
+
+static VOID SystemPmLate(UINT32 mode)
+{
+ UINT32 ret;
+ LosTaskCB *taskCB = NULL;
+
+ ICUNIT_ASSERT_EQUAL_VOID(mode, LOS_SYS_LIGHT_SLEEP, mode);
+
+ ret = LOS_TaskResume(g_taskID2);
+ ICUNIT_ASSERT_EQUAL_VOID(ret, LOS_OK, ret);
+
+ ret = LOS_TaskResume(g_taskID1);
+ ICUNIT_ASSERT_EQUAL_VOID(ret, LOS_OK, ret);
+}
+
static LosPmSysctrl g_sysctrl = {
+ .early = SystemPmEarly,
+ .late = SystemPmLate,
.normalSuspend = HalEnterSleep,
.normalResume = NULL,
.lightSuspend = SysSuspend,
.lightResume = SysResume,
};
+#define TEST_FLAGS 100
+static VOID PmTestTask(VOID)
+{
+ UINT32 ret;
+ UINT32 wakeCount;
+
+ while (1) {
+ wakeCount = LOS_PmReadLock();
+
+ ret = LOS_PmSuspend(wakeCount);
+ ICUNIT_GOTO_EQUAL(ret, LOS_OK, ret, EXIT);
+ ICUNIT_GOTO_NOT_EQUAL(g_testCount, 0, g_sysCount, EXIT);
+ ICUNIT_GOTO_EQUAL(g_sysCount, 0, g_sysCount, EXIT);
+
+ g_pmTestCount++;
+ if (g_pmTestCount > TEST_LOOP) {
+ break;
+ }
+ printf("PmTestTask loop: %u\n", g_pmTestCount);
+ }
+
+EXIT:
+ g_pmTestCount = TEST_FLAGS;
+ (VOID)LOS_EventWrite(&g_pmTestEvent, 0x1); /* 0x1: test exit evnet */
+ return;
+}
+
+#define TEST_TASK1_LOOP 10
+static volatile UINT32 g_testSample1Count, g_testSample2Count;
+static void TaskSampleEntry2(void)
+{
+ UINT32 g_testSample2Count = TEST_FLAGS;
+
+ while (1) {
+ if (g_testSample2Count == TEST_FLAGS) {
+ g_testSample2Count = 0;
+ LOS_PmLockRequest("TaskSampleEntry2");
+ myprintf("%s request pm lock\n", __FUNCTION__);
+ }
+
+ myprintf("TaskSampleEntry2 running...count: %u\n\r", g_testSample2Count);
+ LOS_TaskDelay(20); /* sleep 20 ticks */
+
+ if (g_testSample2Count <= TEST_TASK1_LOOP) { /* */
+ g_testSample2Count++;
+ }
+ if (g_testSample2Count == TEST_TASK1_LOOP) {
+ LOS_PmLockRelease("TaskSampleEntry2");
+ myprintf("%s release pm lock\n", __FUNCTION__);
+ }
+
+ if (g_pmTestCount > TEST_LOOP) {
+ break;
+ }
+ }
+
+ LOS_PmLockRelease("TaskSampleEntry2");
+ myprintf("TaskSampleEntry2 exit\n");
+}
+
+static void TaskSampleEntry1(void)
+{
+ UINT32 g_testSample1Count = 0;
+
+ while (1) {
+ if (g_testSample1Count == 0) {
+ LOS_PmLockRequest("TaskSampleEntry1");
+ myprintf("%s request pm lock\n", __FUNCTION__);
+ }
+
+ myprintf("TaskSampleEntry1 running...%u\n\r", g_testSample1Count);
+ LOS_TaskDelay(50); /* sleep 50 ticks */
+
+ g_testSample1Count++;
+ if (g_testSample1Count == TEST_TASK1_LOOP) {
+ LOS_PmLockRelease("TaskSampleEntry1");
+ myprintf("%s release pm lock\n", __FUNCTION__);
+ } else if (g_testSample1Count == (TEST_TASK1_LOOP + 1)) { /* 1: incremental */
+ g_testSample1Count = 0;
+ g_testSample2Count = TEST_FLAGS;
+ }
+
+ if (g_pmTestCount > TEST_LOOP) {
+ break;
+ }
+ }
+
+ LOS_PmLockRelease("TaskSampleEntry1");
+ myprintf("TaskSampleEntry1 exit\n");
+}
+
static UINT32 TestCase(VOID)
{
UINT32 ret;
+ TSK_INIT_PARAM_S task1 = { 0 };
g_sysCount = 0;
g_deviceCount = 0;
- g_sysTickTimerCount = 0;
g_testCount = 0;
- ret = LOS_PmRegister(LOS_PM_TYPE_TICK_TIMER, &g_tickTimer);
+ ret = LOS_EventInit(&g_pmTestEvent);
ICUNIT_ASSERT_EQUAL(ret, LOS_OK, ret);
ret = LOS_PmRegister(LOS_PM_TYPE_DEVICE, &g_device);
@@ -119,34 +229,42 @@ static UINT32 TestCase(VOID)
ret = LOS_PmModeSet(LOS_SYS_LIGHT_SLEEP);
ICUNIT_ASSERT_EQUAL(ret, LOS_OK, ret);
- LOS_PmLockRequest("testlock");
- LOS_TaskDelay(100); /* delay 100 ticks */
- LOS_PmLockRelease("testlock");
+ task1.pfnTaskEntry = (TSK_ENTRY_FUNC)PmTestTask;
+ task1.uwStackSize = 0x2000; /* 0x2000 pm task stack size */
+ task1.pcName = "pmTask";
+ task1.usTaskPrio = 5; /* 5: pm task prio */
+ ret = LOS_TaskCreate(&g_testTaskID01, &task1);
+ ICUNIT_ASSERT_EQUAL(ret, LOS_OK, ret);
- ICUNIT_GOTO_EQUAL(g_testCount, 0, g_testCount, EXIT);
+ task1.pfnTaskEntry = (TSK_ENTRY_FUNC)TaskSampleEntry1;
+ task1.uwStackSize = 0x1000; /* 0x1000 task stack size */
+ task1.pcName = "TaskSampleEntry1";
+ task1.usTaskPrio = 10; /* 10: task prio */
+ ret = LOS_TaskCreate(&g_taskID1, &task1);
+ ICUNIT_ASSERT_EQUAL(ret, LOS_OK, ret);
- LOS_TaskDelay(100); /* delay 100 ticks */
+ task1.pfnTaskEntry = (TSK_ENTRY_FUNC)TaskSampleEntry2;
+ task1.uwStackSize = 0x1000; /* 0x1000 task stack size */
+ task1.pcName = "TaskSampleEntry2";
+ task1.usTaskPrio = 12; /* 12: task prio */
+ ret = LOS_TaskCreate(&g_taskID2, &task1);
+ ICUNIT_ASSERT_EQUAL(ret, LOS_OK, ret);
- ICUNIT_GOTO_NOT_EQUAL(g_testCount, 0, g_sysCount, EXIT);
- ICUNIT_GOTO_EQUAL(g_sysCount, 0, g_sysCount, EXIT);
+ (VOID)LOS_EventRead(&g_pmTestEvent, 0xff, LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);
ret = LOS_PmUnregister(LOS_PM_TYPE_DEVICE, &g_device);
ICUNIT_ASSERT_EQUAL(ret, LOS_OK, ret);
- ret = LOS_PmUnregister(LOS_PM_TYPE_TICK_TIMER, &g_tickTimer);
+ ret = LOS_PmModeSet(LOS_SYS_NORMAL_SLEEP);
ICUNIT_ASSERT_EQUAL(ret, LOS_OK, ret);
+ (VOID)LOS_TaskDelete(g_taskID1);
+ (VOID)LOS_TaskDelete(g_taskID2);
+ (VOID)LOS_TaskDelete(g_testTaskID01);
return LOS_OK;
-
-EXIT:
- LOS_PmUnregister(LOS_PM_TYPE_DEVICE, &g_device);
-
- LOS_PmUnregister(LOS_PM_TYPE_TICK_TIMER, &g_tickTimer);
- return LOS_NOK;
}
VOID ItLosPm002(VOID) // IT_Layer_ModuleORFeature_No
{
TEST_ADD_CASE("ItLosPm002", TestCase, TEST_LOS, TEST_TASK, TEST_LEVEL0, TEST_FUNCTION);
}
-
diff --git a/testsuits/sample/kernel/power/It_los_pm_003.c b/testsuits/sample/kernel/power/It_los_pm_003.c
new file mode 100644
index 00000000..55092096
--- /dev/null
+++ b/testsuits/sample/kernel/power/It_los_pm_003.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved.
+ *
+ * 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.
+ */
+
+#include "osTest.h"
+#include "It_los_pm.h"
+#include "los_timer.h"
+
+#define TEST_LOOP 5
+static EVENT_CB_S g_pmTestEvent;
+static UINT32 g_taskID1, g_taskID2;
+static UINT32 g_deviceCount = 0;
+static UINT32 g_sysCount = 0;
+static volatile UINT32 g_pmTestCount = 0;
+static UINT32 g_pmTimeLock = 0;
+
+static UINT32 DeviceSuspend(UINT32 mode)
+{
+ g_deviceCount++;
+ g_testCount++;
+ return LOS_OK;
+}
+
+static VOID DeviceResume(UINT32 mode)
+{
+ g_deviceCount--;
+ return;
+}
+
+static LosPmDevice g_device = {
+ .suspend = DeviceSuspend,
+ .resume = DeviceResume,
+};
+
+static VOID SysResume(VOID)
+{
+ if (g_sysCount != (UINT32)-1) {
+ g_sysCount--;
+ }
+}
+
+static UINT32 SysSuspend(VOID)
+{
+ g_testCount++;
+ g_sysCount++;
+
+ if ((g_deviceCount != 1) || (g_sysCount != 1)) { /* 2: device count 1: sys count */
+ g_sysCount = (UINT32)-1;
+ }
+
+ UINT64 timeout = LOS_SchedTickTimeoutNsGet();
+ printf("pm timeout : %u ns -> %u ticks\n", (UINT32)timeout, (UINT32)(timeout / OS_NS_PER_TICK));
+ return HalEnterSleep();
+}
+
+static UINT32 SystemPmEarly(UINT32 mode)
+{
+ UINT32 ret;
+
+ ICUNIT_ASSERT_EQUAL(mode, LOS_SYS_LIGHT_SLEEP, mode);
+
+ ret = LOS_TaskSuspend(g_taskID2);
+ ICUNIT_ASSERT_EQUAL(ret, LOS_OK, ret);
+
+ ret = LOS_TaskSuspend(g_taskID1);
+ if (ret != LOS_OK) {
+ (VOID)LOS_TaskResume(g_taskID2);
+ }
+ ICUNIT_ASSERT_EQUAL(ret, LOS_OK, ret);
+
+ return LOS_OK;
+}
+
+static VOID SystemPmLate(UINT32 mode)
+{
+ UINT32 ret;
+
+ ICUNIT_ASSERT_EQUAL_VOID(mode, LOS_SYS_LIGHT_SLEEP, mode);
+
+ ret = LOS_TaskResume(g_taskID2);
+ ICUNIT_ASSERT_EQUAL_VOID(ret, LOS_OK, ret);
+
+ ret = LOS_TaskResume(g_taskID1);
+ ICUNIT_ASSERT_EQUAL_VOID(ret, LOS_OK, ret);
+}
+
+static LosPmSysctrl g_sysctrl = {
+ .early = SystemPmEarly,
+ .late = SystemPmLate,
+ .normalSuspend = HalEnterSleep,
+ .normalResume = NULL,
+ .lightSuspend = SysSuspend,
+ .lightResume = SysResume,
+};
+
+#define TEST_FLAGS 100
+static VOID PmTestTask(VOID)
+{
+ UINT32 ret;
+ UINT32 wakeCount;
+
+ while (1) {
+ wakeCount = LOS_PmReadLock();
+
+ ret = LOS_PmSuspend(wakeCount);
+ ICUNIT_GOTO_EQUAL(ret, LOS_OK, ret, EXIT);
+ ICUNIT_GOTO_NOT_EQUAL(g_testCount, 0, g_sysCount, EXIT);
+ ICUNIT_GOTO_EQUAL(g_sysCount, 0, g_sysCount, EXIT);
+
+ g_pmTimeLock = 0;
+ g_pmTestCount++;
+ if (g_pmTestCount > TEST_LOOP) {
+ break;
+ }
+ printf("PmTestTask loop: %u\n", g_pmTestCount);
+ }
+
+EXIT:
+ g_pmTestCount = TEST_FLAGS;
+ (VOID)LOS_EventWrite(&g_pmTestEvent, 0x1); /* 0x1: test exit evnet */
+ return;
+}
+
+static void TaskSampleEntry2(void)
+{
+ while (1) {
+ LOS_TaskDelay(20); /* sleep 20 ticks */
+ if (g_pmTestCount > TEST_LOOP) {
+ break;
+ }
+ }
+}
+
+static void TaskSampleEntry1(void)
+{
+ UINT32 ret;
+
+ while (1) {
+ if (g_pmTimeLock == 0) {
+ g_pmTimeLock = TEST_FLAGS;
+ ret = LOS_PmTimeLockRequest("TaskSampleEntry1", 1000); /* delay 1000 ms */
+ ICUNIT_ASSERT_EQUAL_VOID(ret, LOS_OK, ret);
+
+ ret = LOS_PmTimeLockRequest("TaskSampleEntry1", 1000); /* delay 1000 ms */
+ ICUNIT_ASSERT_EQUAL_VOID(ret, LOS_ERRNO_PM_ALREADY_LOCK, ret);
+ }
+
+ LOS_TaskDelay(50); /* sleep 50 ticks */
+
+ if (g_pmTestCount > TEST_LOOP) {
+ break;
+ }
+ }
+
+ return;
+}
+
+static UINT32 TestCase(VOID)
+{
+ UINT32 ret;
+ TSK_INIT_PARAM_S task1 = { 0 };
+ g_sysCount = 0;
+ g_deviceCount = 0;
+ g_testCount = 0;
+
+ ret = LOS_EventInit(&g_pmTestEvent);
+ ICUNIT_ASSERT_EQUAL(ret, LOS_OK, ret);
+
+ ret = LOS_PmRegister(LOS_PM_TYPE_DEVICE, &g_device);
+ ICUNIT_ASSERT_EQUAL(ret, LOS_OK, ret);
+
+ ret = LOS_PmRegister(LOS_PM_TYPE_SYSCTRL, &g_sysctrl);
+ ICUNIT_ASSERT_EQUAL(ret, LOS_OK, ret);
+
+ ret = LOS_PmModeSet(LOS_SYS_LIGHT_SLEEP);
+ ICUNIT_ASSERT_EQUAL(ret, LOS_OK, ret);
+
+ task1.pfnTaskEntry = (TSK_ENTRY_FUNC)PmTestTask;
+ task1.uwStackSize = 0x2000; /* 0x2000 pm task stack size */
+ task1.pcName = "pmTask";
+ task1.usTaskPrio = 5; /* 5: pm task prio */
+ ret = LOS_TaskCreate(&g_testTaskID01, &task1);
+ ICUNIT_ASSERT_EQUAL(ret, LOS_OK, ret);
+
+ task1.pfnTaskEntry = (TSK_ENTRY_FUNC)TaskSampleEntry1;
+ task1.uwStackSize = 0x1000; /* 0x1000 task stack size */
+ task1.pcName = "TaskSampleEntry1";
+ task1.usTaskPrio = 10; /* 10: task prio */
+ ret = LOS_TaskCreate(&g_taskID1, &task1);
+ ICUNIT_ASSERT_EQUAL(ret, LOS_OK, ret);
+
+ task1.pfnTaskEntry = (TSK_ENTRY_FUNC)TaskSampleEntry2;
+ task1.uwStackSize = 0x1000; /* 0x1000 task stack size */
+ task1.pcName = "TaskSampleEntry2";
+ task1.usTaskPrio = 12; /* 12: task prio */
+ ret = LOS_TaskCreate(&g_taskID2, &task1);
+ ICUNIT_ASSERT_EQUAL(ret, LOS_OK, ret);
+
+ (VOID)LOS_EventRead(&g_pmTestEvent, 0xff, LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);
+
+ ret = LOS_PmUnregister(LOS_PM_TYPE_DEVICE, &g_device);
+ ICUNIT_ASSERT_EQUAL(ret, LOS_OK, ret);
+
+ ret = LOS_PmModeSet(LOS_SYS_NORMAL_SLEEP);
+ ICUNIT_ASSERT_EQUAL(ret, LOS_OK, ret);
+
+ (VOID)LOS_TaskDelete(g_taskID1);
+ (VOID)LOS_TaskDelete(g_taskID2);
+ (VOID)LOS_TaskDelete(g_testTaskID01);
+ return LOS_OK;
+}
+
+VOID ItLosPm003(VOID) // IT_Layer_ModuleORFeature_No
+{
+ TEST_ADD_CASE("ItLosPm003", TestCase, TEST_LOS, TEST_TASK, TEST_LEVEL0, TEST_FUNCTION);
+}