diff --git a/fs/proc/os_adapt/power_proc.c b/fs/proc/os_adapt/power_proc.c index f8a6f6ebf070afa7e3fdd74183f3b7cf4e2381ee..3d61eb9a267514ca716438046d652a8e19dfab47 100644 --- a/fs/proc/os_adapt/power_proc.c +++ b/fs/proc/os_adapt/power_proc.c @@ -76,22 +76,33 @@ static int PowerModeWrite(struct ProcFile *pf, const char *buf, size_t count, lo (void)count; (void)ppos; + LOS_SysSleepEnum mode; + if (buf == NULL) { return 0; } - if (strcmp(buf, "normal") != 0) { - return LOS_NOK; + if (strcmp(buf, "normal") == 0) { + mode = LOS_SYS_NORMAL_SLEEP; + } else if (strcmp(buf, "light") == 0) { + mode = LOS_SYS_LIGHT_SLEEP; + } else if (strcmp(buf, "deep") == 0) { + mode = LOS_SYS_DEEP_SLEEP; + } else if (strcmp(buf, "shutdown") == 0) { + mode = LOS_SYS_SHUTDOWN; + } else { + PRINT_ERR("Unsupported hibernation mode: %s\n", buf); + return -EINVAL; } - return 0; + return -LOS_PmModeSet(mode); } static int PowerModeRead(struct SeqBuf *m, void *v) { (void)v; - LosBufPrintf(m, "normal \n"); + LosBufPrintf(m, "normal light deep shutdown\n"); return 0; } @@ -103,14 +114,30 @@ static const struct ProcFileOperations PowerMode = { static int PowerCountRead(struct SeqBuf *m, void *v) { (void)v; - UINT32 count = LOS_PmLockCountGet(); + UINT32 count = LOS_PmReadLock(); LosBufPrintf(m, "%u\n", count); return 0; } +static int PowerCountWrite(struct ProcFile *pf, const char *buf, size_t count, loff_t *ppos) +{ + (void)pf; + (void)count; + (void)ppos; + + int weakCount; + + if (buf == NULL) { + return 0; + } + + weakCount = atoi(buf); + return -LOS_PmSuspend(weakCount); +} + static const struct ProcFileOperations PowerCount = { - .write = NULL, + .write = PowerCountWrite, .read = PowerCountRead, }; diff --git a/kernel/base/core/los_task.c b/kernel/base/core/los_task.c index 646c9cc3f75bed9722725aba515076b92e81ada4..26d9a8d078f9bcd46c01e3ac219ab386c739a06f 100644 --- a/kernel/base/core/los_task.c +++ b/kernel/base/core/los_task.c @@ -78,10 +78,6 @@ LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_taskSpin); STATIC VOID OsConsoleIDSetHook(UINT32 param1, UINT32 param2) __attribute__((weakref("OsSetConsoleID"))); -#define OS_CHECK_TASK_BLOCK (OS_TASK_STATUS_DELAY | \ - OS_TASK_STATUS_PENDING | \ - OS_TASK_STATUS_SUSPENDED) - /* temp task blocks for booting procedure */ LITE_OS_SEC_BSS STATIC LosTaskCB g_mainTask[LOSCFG_KERNEL_CORE_NUM]; @@ -736,7 +732,6 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskResume(UINT32 taskID) UINT32 intSave; UINT32 errRet; LosTaskCB *taskCB = NULL; - BOOL needSched = FALSE; if (OS_TID_CHECK_INVALID(taskID)) { return LOS_ERRNO_TSK_ID_INVALID; @@ -756,17 +751,11 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskResume(UINT32 taskID) OS_GOTO_ERREND(); } - taskCB->taskStatus &= ~OS_TASK_STATUS_SUSPENDED; - if (!(taskCB->taskStatus & OS_CHECK_TASK_BLOCK)) { - OsSchedTaskEnQueue(taskCB); - if (OS_SCHEDULER_ACTIVE) { - needSched = TRUE; - } - } + BOOL needSched = OsSchedResume(taskCB); SCHEDULER_UNLOCK(intSave); LOS_MpSchedule(OS_MP_CPU_ALL); - if (needSched) { + if (OS_SCHEDULER_ACTIVE && needSched) { LOS_Schedule(); } @@ -834,16 +823,7 @@ LITE_OS_SEC_TEXT STATIC UINT32 OsTaskSuspend(LosTaskCB *taskCB) return errRet; } - if (tempStatus & OS_TASK_STATUS_READY) { - OsSchedTaskDeQueue(taskCB); - } - - taskCB->taskStatus |= OS_TASK_STATUS_SUSPENDED; - OsHookCall(LOS_HOOK_TYPE_MOVEDTASKTOSUSPENDEDLIST, taskCB); - if (taskCB == OsCurrTaskGet()) { - OsSchedResched(); - } - + OsSchedSuspend(taskCB); return LOS_OK; } diff --git a/kernel/base/include/los_sched_pri.h b/kernel/base/include/los_sched_pri.h index 1cf06bd14e8719a6c07447fc6e8eb17d5723b229..9270aa78b443f99cca9f0abdf9728a483da129f0 100644 --- a/kernel/base/include/los_sched_pri.h +++ b/kernel/base/include/los_sched_pri.h @@ -162,6 +162,8 @@ extern VOID OsSchedSetIdleTaskSchedParam(LosTaskCB *idleTask); extern UINT32 OsSchedSwtmrScanRegister(SchedScan func); +extern VOID OsSchedResetSchedResponseTime(UINT64 responseTime); + extern VOID OsSchedUpdateExpireTime(UINT64 startTime); extern VOID OsSchedToUserReleaseLock(VOID); @@ -178,6 +180,10 @@ extern BOOL OsSchedModifyTaskSchedParam(LosTaskCB *taskCB, UINT16 policy, UINT16 extern BOOL OsSchedModifyProcessSchedParam(LosProcessCB *processCB, UINT16 policy, UINT16 priority); +extern VOID OsSchedSuspend(LosTaskCB *taskCB); + +extern BOOL OsSchedResume(LosTaskCB *taskCB); + extern VOID OsSchedDelay(LosTaskCB *runTask, UINT32 tick); extern VOID OsSchedYield(VOID); diff --git a/kernel/base/include/los_task_pri.h b/kernel/base/include/los_task_pri.h index 1085571b70e36e272f076c689b0052ffbf2bca84..04c5454f865030cfb31b117353b352099d9929f3 100644 --- a/kernel/base/include/los_task_pri.h +++ b/kernel/base/include/los_task_pri.h @@ -210,6 +210,14 @@ extern SPIN_LOCK_S g_taskSpin; */ #define OS_TASK_FLAG_EXIT_KILL 0x4000U +/** + * @ingroup los_task + * Flag that indicates the task or task control block status. + * + * The delayed operation of this task is frozen. + */ +#define OS_TASK_FLAG_FREEZE 0x8000U + /** * @ingroup los_task * Flag that indicates the task property. diff --git a/kernel/base/sched/sched_sq/los_sched.c b/kernel/base/sched/sched_sq/los_sched.c index 23845bdc2ea6324a92d99c88b2c0a29fcea60664..effca28bac6359f34b41bd590d912f6b0645c56c 100644 --- a/kernel/base/sched/sched_sq/los_sched.c +++ b/kernel/base/sched/sched_sq/los_sched.c @@ -47,6 +47,7 @@ #ifdef LOSCFG_SCHED_DEBUG #include "los_stat_pri.h" #endif +#include "los_pm_pri.h" #define OS_32BIT_MAX 0xFFFFFFFFUL #define OS_SCHED_FIFO_TIMEOUT 0x7FFFFFFF @@ -58,6 +59,8 @@ #define OS_SCHED_READY_MAX 30 #define OS_TIME_SLICE_MIN (INT32)((50 * OS_SYS_NS_PER_US) / OS_NS_PER_CYCLE) /* 50us */ +#define OS_CHECK_TASK_BLOCK (OS_TASK_STATUS_DELAY | OS_TASK_STATUS_PENDING | OS_TASK_STATUS_SUSPENDED) + typedef struct { LOS_DL_LIST priQueueList[OS_PRIORITY_QUEUE_NUM]; UINT32 readyTasks[OS_PRIORITY_QUEUE_NUM]; @@ -760,6 +763,81 @@ BOOL OsSchedModifyProcessSchedParam(LosProcessCB *processCB, UINT16 policy, UINT return needSched; } +STATIC VOID OsSchedFreezeTask(LosTaskCB *taskCB) +{ + UINT64 responseTime; + + if (!OsIsPmMode()) { + return; + } + + if (!(taskCB->taskStatus & (OS_TASK_STATUS_PEND_TIME | OS_TASK_STATUS_DELAY))) { + return; + } + + responseTime = GET_SORTLIST_VALUE(&taskCB->sortList); + OsDeleteSortLink(&taskCB->sortList, OS_SORT_LINK_TASK); + SET_SORTLIST_VALUE(&taskCB->sortList, responseTime); + taskCB->taskStatus |= OS_TASK_FLAG_FREEZE; + return; +} + +STATIC VOID OsSchedUnfreezeTask(LosTaskCB *taskCB) +{ + UINT64 currTime, responseTime; + UINT32 remainTick; + + if (!(taskCB->taskStatus & OS_TASK_FLAG_FREEZE)) { + return; + } + + taskCB->taskStatus &= ~OS_TASK_FLAG_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); + if (taskCB->taskStatus & OS_TASK_STATUS_PENDING) { + LOS_ListDelete(&taskCB->pendList); + } + taskCB->taskStatus &= ~(OS_TASK_STATUS_DELAY | OS_TASK_STATUS_PEND_TIME | OS_TASK_STATUS_PENDING); + return; +} + +VOID OsSchedSuspend(LosTaskCB *taskCB) +{ + if (taskCB->taskStatus & OS_TASK_STATUS_READY) { + OsSchedTaskDeQueue(taskCB); + } + + OsSchedFreezeTask(taskCB); + + taskCB->taskStatus |= OS_TASK_STATUS_SUSPENDED; + OsHookCall(LOS_HOOK_TYPE_MOVEDTASKTOSUSPENDEDLIST, taskCB); + if (taskCB == OsCurrTaskGet()) { + OsSchedResched(); + } +} + +BOOL OsSchedResume(LosTaskCB *taskCB) +{ + BOOL needSched = FALSE; + + OsSchedUnfreezeTask(taskCB); + + taskCB->taskStatus &= ~OS_TASK_STATUS_SUSPENDED; + if (!(taskCB->taskStatus & OS_CHECK_TASK_BLOCK)) { + OsSchedTaskEnQueue(taskCB); + needSched = TRUE; + } + + return needSched; +} + VOID OsSchedTick(VOID) { Sched *sched = g_sched; @@ -792,6 +870,12 @@ VOID OsSchedSetIdleTaskSchedParam(LosTaskCB *idleTask) OsSchedTaskEnQueue(idleTask); } +VOID OsSchedResetSchedResponseTime(UINT64 responseTime) +{ + Percpu *cpu = OsPercpuGet(); + cpu->responseTime = responseTime; +} + UINT32 OsSchedSwtmrScanRegister(SchedScan func) { if (func == NULL) { diff --git a/kernel/extended/BUILD.gn b/kernel/extended/BUILD.gn index e8b2f7a2a829d0c0e8bce0ea1ad1f57db6fff075..0ddf48048fa29651a258f340aae71ce8566d15a9 100644 --- a/kernel/extended/BUILD.gn +++ b/kernel/extended/BUILD.gn @@ -61,5 +61,6 @@ config("public") { "vdso:public", "perf:public", "lms:public", + "power:public", ] } diff --git a/kernel/extended/power/BUILD.gn b/kernel/extended/power/BUILD.gn index d21ffda6ec4413b2030c039661f0eae1ef9e4d61..4cdd59e86fdd92c7f189cc509fb6713900ab6c19 100644 --- a/kernel/extended/power/BUILD.gn +++ b/kernel/extended/power/BUILD.gn @@ -34,3 +34,7 @@ module_name = get_path_info(rebase_path("."), "name") kernel_module(module_name) { sources = [ "los_pm.c" ] } + +config("public") { + include_dirs = [ "." ] +} diff --git a/kernel/extended/power/los_pm.c b/kernel/extended/power/los_pm.c index 7c8bc9d20773b365503210b45a8b4e73074d5ce4..84eb2e5aa8e273fb92378221dd335a87324e3b3d 100644 --- a/kernel/extended/power/los_pm.c +++ b/kernel/extended/power/los_pm.c @@ -35,8 +35,11 @@ #include "los_init.h" #include "los_memory.h" #include "los_spinlock.h" +#include "los_swtmr.h" #include "los_mp.h" +#define OS_MS_PER_TICK (OS_SYS_MS_PER_SECOND / LOSCFG_BASE_CORE_TICK_PER_SECOND) + #ifdef LOSCFG_KERNEL_PM #define PM_INFO_SHOW(seqBuf, arg...) do { \ if (seqBuf != NULL) { \ @@ -46,38 +49,342 @@ } \ } while (0) -#define OS_PM_LOCK_MAX 0xFFFFU -#define OS_PM_LOCK_NAME_MAX 28 +#define OS_PM_LOCK_MAX 0xFFFFU +#define OS_PM_LOCK_NAME_MAX 28 +#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); typedef struct { CHAR name[OS_PM_LOCK_NAME_MAX]; UINT32 count; + UINT32 swtmrID; LOS_DL_LIST list; } OsPmLockCB; typedef struct { - LOS_SysSleepEnum mode; + LOS_SysSleepEnum pmMode; + LOS_SysSleepEnum sysMode; UINT16 lock; + BOOL isWake; + LosPmDevice *device; + LosPmSysctrl *sysctrl; + UINT64 enterSleepTime; LOS_DL_LIST lockList; } LosPmCB; +#define PM_EVENT_LOCK_MASK 0xF +#define PM_EVENT_LOCK_RELEASE 0x1 +STATIC EVENT_CB_S g_pmEvent; STATIC LosPmCB g_pmCB; STATIC SPIN_LOCK_INIT(g_pmSpin); +STATIC VOID OsPmTickTimerStart(LosPmCB *pm) +{ + (VOID)pm; + return; +} + +STATIC BOOL OsPmTickTimerStop(LosPmCB *pm) +{ + (VOID)pm; + return FALSE; +} + +STATIC VOID OsPmCpuResume(LosPmCB *pm) +{ + if ((pm->sysMode == LOS_SYS_NORMAL_SLEEP) && (pm->sysctrl->normalResume != NULL)) { + pm->sysctrl->normalResume(); + } else if ((pm->sysMode == LOS_SYS_LIGHT_SLEEP) && (pm->sysctrl->lightResume != NULL)) { + pm->sysctrl->lightResume(); + } else if ((pm->sysMode == LOS_SYS_DEEP_SLEEP) && (pm->sysctrl->deepResume != NULL)) { + pm->sysctrl->deepResume(); + } +} + +STATIC SysSuspend OsPmCpuSuspend(LosPmCB *pm) +{ + SysSuspend sysSuspend = NULL; + + /* cpu enter low power mode */ + LOS_ASSERT(pm->sysctrl != NULL); + + if (pm->sysMode == LOS_SYS_NORMAL_SLEEP) { + sysSuspend = pm->sysctrl->normalSuspend; + } else if (pm->sysMode == LOS_SYS_LIGHT_SLEEP) { + sysSuspend = pm->sysctrl->lightSuspend; + } else if (pm->sysMode == LOS_SYS_DEEP_SLEEP) { + sysSuspend = pm->sysctrl->deepSuspend; + } else { + sysSuspend = pm->sysctrl->shutdownSuspend; + } + + LOS_ASSERT(sysSuspend != NULL); + + return sysSuspend; +} + +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) +{ + LOS_SpinLock(&g_pmSpin); + pm->sysMode = pm->pmMode; + if (pm->lock > 0) { + pm->sysMode = LOS_SYS_NORMAL_SLEEP; + LOS_SpinUnlock(&g_pmSpin); + return LOS_NOK; + } + + pm->isWake = FALSE; + *mode = pm->sysMode; + *sysSuspendEarly = pm->sysctrl->early; + *deviceSuspend = pm->device->suspend; + LOS_SpinUnlock(&g_pmSpin); + return LOS_OK; +} + +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) { + PRINT_ERR("Pm suspend mode is normal sleep! lock count %d\n", pm->lock); + return ret; + } + + ret = OsPmSuspendPrepare(sysSuspendEarly, deviceSuspend, (UINT32)mode, &prepare); + if (ret != LOS_OK) { + LOS_SpinLockSave(&g_pmSpin, &intSave); + LOS_TaskLock(); + goto EXIT; + } + + LOS_SpinLockSave(&g_pmSpin, &intSave); + LOS_TaskLock(); + if (pm->isWake || (pm->lock > 0)) { + goto EXIT; + } + + tickTimerStop = OsPmTickTimerStop(pm); + if (!tickTimerStop) { + currTime = OsGetCurrSchedTimeCycle(); + OsSchedResetSchedResponseTime(0); + OsSchedUpdateExpireTime(currTime); + } + + sysSuspend = OsPmCpuSuspend(pm); + LOS_SpinUnlockRestore(&g_pmSpin, intSave); + + if (!pm->isWake) { + ret = sysSuspend(); + } + + LOS_SpinLockSave(&g_pmSpin, &intSave); + + OsPmCpuResume(pm); + + OsPmTickTimerStart(pm); + +EXIT: + pm->sysMode = LOS_SYS_NORMAL_SLEEP; + OsPmResumePrepare(pm, (UINT32)mode, prepare); + LOS_SpinUnlockRestore(&g_pmSpin, intSave); + + LOS_TaskUnlock(); + return ret; +} + +STATIC UINT32 OsPmDeviceRegister(LosPmCB *pm, LosPmDevice *device) +{ + if ((device->suspend == NULL) || (device->resume == NULL)) { + return LOS_EINVAL; + } + + LOS_SpinLock(&g_pmSpin); + pm->device = device; + LOS_SpinUnlock(&g_pmSpin); + + return LOS_OK; +} + +STATIC UINT32 OsPmSysctrlRegister(LosPmCB *pm, LosPmSysctrl *sysctrl) +{ + LOS_SpinLock(&g_pmSpin); + pm->sysctrl = sysctrl; + LOS_SpinUnlock(&g_pmSpin); + + return LOS_OK; +} + +UINT32 LOS_PmRegister(LOS_PmNodeType type, VOID *node) +{ + LosPmCB *pm = &g_pmCB; + + if (node == NULL) { + return LOS_EINVAL; + } + + switch (type) { + case LOS_PM_TYPE_DEVICE: + return OsPmDeviceRegister(pm, (LosPmDevice *)node); + case LOS_PM_TYPE_TICK_TIMER: + PRINT_ERR("Pm, %d is an unsupported type\n", type); + return LOS_EINVAL; + case LOS_PM_TYPE_SYSCTRL: + return OsPmSysctrlRegister(pm, (LosPmSysctrl *)node); + default: + break; + } + + return LOS_EINVAL; +} + +STATIC UINT32 OsPmDeviceUnregister(LosPmCB *pm, LosPmDevice *device) +{ + LOS_SpinLock(&g_pmSpin); + if (pm->device == device) { + pm->device = NULL; + pm->pmMode = LOS_SYS_NORMAL_SLEEP; + LOS_SpinUnlock(&g_pmSpin); + return LOS_OK; + } + + LOS_SpinUnlock(&g_pmSpin); + return LOS_EINVAL; +} + +STATIC UINT32 OsPmSysctrlUnregister(LosPmCB *pm, LosPmSysctrl *sysctrl) +{ + LOS_SpinLock(&g_pmSpin); + pm->sysctrl = NULL; + LOS_SpinUnlock(&g_pmSpin); + + return LOS_OK; +} + +UINT32 LOS_PmUnregister(LOS_PmNodeType type, VOID *node) +{ + LosPmCB *pm = &g_pmCB; + + if (node == NULL) { + return LOS_EINVAL; + } + + switch (type) { + case LOS_PM_TYPE_DEVICE: + return OsPmDeviceUnregister(pm, (LosPmDevice *)node); + case LOS_PM_TYPE_TICK_TIMER: + PRINT_ERR("Pm, %d is an unsupported type\n", type); + return LOS_EINVAL; + case LOS_PM_TYPE_SYSCTRL: + return OsPmSysctrlUnregister(pm, (LosPmSysctrl *)node); + default: + break; + } + + return LOS_EINVAL; +} + +VOID LOS_PmWakeSet(VOID) +{ + LosPmCB *pm = &g_pmCB; + + LOS_SpinLock(&g_pmSpin); + pm->isWake = TRUE; + LOS_SpinUnlock(&g_pmSpin); + return; +} + LOS_SysSleepEnum LOS_PmModeGet(VOID) { LOS_SysSleepEnum mode; LosPmCB *pm = &g_pmCB; LOS_SpinLock(&g_pmSpin); - mode = pm->mode; + mode = pm->pmMode; LOS_SpinUnlock(&g_pmSpin); return mode; } +UINT32 LOS_PmModeSet(LOS_SysSleepEnum mode) +{ + LosPmCB *pm = &g_pmCB; + INT32 sleepMode = (INT32)mode; + + if ((sleepMode < 0) || (sleepMode > LOS_SYS_SHUTDOWN)) { + return LOS_EINVAL; + } + + LOS_SpinLock(&g_pmSpin); + if ((mode != LOS_SYS_NORMAL_SLEEP) && (pm->device == NULL)) { + LOS_SpinUnlock(&g_pmSpin); + return LOS_EINVAL; + } + + if ((mode == LOS_SYS_LIGHT_SLEEP) && (pm->sysctrl->lightSuspend == NULL)) { + LOS_SpinUnlock(&g_pmSpin); + return LOS_EINVAL; + } + + if ((mode == LOS_SYS_DEEP_SLEEP) && (pm->sysctrl->deepSuspend == NULL)) { + LOS_SpinUnlock(&g_pmSpin); + return LOS_EINVAL; + } + + if ((mode == LOS_SYS_SHUTDOWN) && (pm->sysctrl->shutdownSuspend == NULL)) { + LOS_SpinUnlock(&g_pmSpin); + return LOS_EINVAL; + } + + pm->pmMode = mode; + LOS_SpinUnlock(&g_pmSpin); + + return LOS_OK; +} + UINT32 LOS_PmLockCountGet(VOID) { UINT16 count; @@ -92,43 +399,38 @@ UINT32 LOS_PmLockCountGet(VOID) VOID LOS_PmLockInfoShow(struct SeqBuf *m) { - UINT32 intSave; LosPmCB *pm = &g_pmCB; OsPmLockCB *lock = NULL; LOS_DL_LIST *head = &pm->lockList; LOS_DL_LIST *list = head->pstNext; - intSave = LOS_IntLock(); + LOS_SpinLock(&g_pmSpin); while (list != head) { lock = LOS_DL_LIST_ENTRY(list, OsPmLockCB, list); PM_INFO_SHOW(m, "%-30s%5u\n\r", lock->name, lock->count); list = list->pstNext; } - LOS_IntRestore(intSave); + LOS_SpinUnlock(&g_pmSpin); return; } -UINT32 LOS_PmLockRequest(const CHAR *name) +UINT32 OsPmLockRequest(const CHAR *name, UINT32 swtmrID) { INT32 len; errno_t err; + UINT32 ret = LOS_EINVAL; LosPmCB *pm = &g_pmCB; - OsPmLockCB *listNode = NULL; OsPmLockCB *lock = NULL; LOS_DL_LIST *head = &pm->lockList; LOS_DL_LIST *list = head->pstNext; - if (name == NULL) { - return LOS_EINVAL; - } - if (OS_INT_ACTIVE) { return LOS_EINTR; } len = strlen(name); - if (len == 0) { + if (len <= 0) { return LOS_EINVAL; } @@ -139,7 +441,7 @@ UINT32 LOS_PmLockRequest(const CHAR *name) } while (list != head) { - listNode = LOS_DL_LIST_ENTRY(list, OsPmLockCB, list); + OsPmLockCB *listNode = LOS_DL_LIST_ENTRY(list, OsPmLockCB, list); if (strcmp(name, listNode->name) == 0) { lock = listNode; break; @@ -154,33 +456,53 @@ UINT32 LOS_PmLockRequest(const CHAR *name) LOS_SpinUnlock(&g_pmSpin); return LOS_ENOMEM; } - err = memcpy_s(lock->name, OS_PM_LOCK_NAME_MAX, name, len + 1); if (err != EOK) { LOS_SpinUnlock(&g_pmSpin); (VOID)LOS_MemFree((VOID *)OS_SYS_MEM_ADDR, lock); return err; } - lock->count = 1; + lock->swtmrID = swtmrID; LOS_ListTailInsert(head, &lock->list); } else if (lock->count < OS_PM_LOCK_MAX) { lock->count++; } - pm->lock++; + if ((lock->swtmrID != OS_INVALID) && (lock->count > 1)) { + lock->count--; + LOS_SpinUnlock(&g_pmSpin); + return LOS_EINVAL; + } + + if (pm->lock < OS_PM_LOCK_MAX) { + pm->lock++; + ret = LOS_OK; + } + LOS_SpinUnlock(&g_pmSpin); - return LOS_OK; + return ret; +} + +UINT32 LOS_PmLockRequest(const CHAR *name) +{ + if (name == NULL) { + return LOS_EINVAL; + } + + return OsPmLockRequest(name, OS_INVALID); } UINT32 LOS_PmLockRelease(const CHAR *name) { + UINT32 ret = LOS_EINVAL; LosPmCB *pm = &g_pmCB; 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_EINVAL; @@ -196,8 +518,9 @@ UINT32 LOS_PmLockRelease(const CHAR *name) return LOS_EINVAL; } + mode = (UINT32)pm->pmMode; while (list != head) { - listNode = LOS_DL_LIST_ENTRY(list, OsPmLockCB, list); + OsPmLockCB *listNode = LOS_DL_LIST_ENTRY(list, OsPmLockCB, list); if (strcmp(name, listNode->name) == 0) { lock = listNode; break; @@ -208,7 +531,7 @@ UINT32 LOS_PmLockRelease(const CHAR *name) if (lock == NULL) { LOS_SpinUnlock(&g_pmSpin); - return LOS_EACCES; + return LOS_EINVAL; } else if (lock->count > 0) { lock->count--; if (lock->count == 0) { @@ -216,21 +539,111 @@ UINT32 LOS_PmLockRelease(const CHAR *name) lockFree = lock; } } - pm->lock--; + + if (pm->lock > 0) { + pm->lock--; + if (pm->lock == 0) { + isRelease = TRUE; + } + ret = LOS_OK; + } LOS_SpinUnlock(&g_pmSpin); - (VOID)LOS_MemFree((VOID *)OS_SYS_MEM_ADDR, lockFree); + 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; +} + +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; + UINT16 swtmrID; + UINT32 ret; + + if ((name == NULL) || !millisecond) { + return LOS_EINVAL; + } + + 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", __FUNCTION__, ret); + } + return LOS_OK; } +UINT32 LOS_PmSuspend(UINT32 wakeCount) +{ + (VOID)wakeCount; + return OsPmSuspendSleep(&g_pmCB); +} + +BOOL OsIsPmMode(VOID) +{ + LosPmCB *pm = &g_pmCB; + + LOS_SpinLock(&g_pmSpin); + if ((pm->sysMode != LOS_SYS_NORMAL_SLEEP) && (pm->lock == 0)) { + LOS_SpinUnlock(&g_pmSpin); + return TRUE; + } + LOS_SpinUnlock(&g_pmSpin); + return FALSE; +} + UINT32 OsPmInit(VOID) { LosPmCB *pm = &g_pmCB; (VOID)memset_s(pm, sizeof(LosPmCB), 0, sizeof(LosPmCB)); - pm->mode = LOS_SYS_NORMAL_SLEEP; + pm->pmMode = LOS_SYS_NORMAL_SLEEP; LOS_ListInit(&pm->lockList); + (VOID)LOS_EventInit(&g_pmEvent); + return LOS_OK; } diff --git a/kernel/extended/power/los_pm_pri.h b/kernel/extended/power/los_pm_pri.h new file mode 100644 index 0000000000000000000000000000000000000000..03cd7dcc1839fca7d3b20216de35cc69826726a8 --- /dev/null +++ b/kernel/extended/power/los_pm_pri.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020-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. + */ + +#ifndef _LOS_PM_PRI_H +#define _LOS_PM_PRI_H + +#include "los_config.h" +#include "los_typedef.h" + +#ifdef LOSCFG_KERNEL_PM + +BOOL OsIsPmMode(VOID); + +#else + +STATIC INLINE BOOL OsIsPmMode(VOID) +{ + return FALSE; +} + +#endif +#endif diff --git a/kernel/include/los_err.h b/kernel/include/los_err.h index eb64b7d95e65847ed4a89fda72ada5443de68cb8..f85e6ca4bd55d0d30dd7b98ef2e9ca95e2b28085 100644 --- a/kernel/include/los_err.h +++ b/kernel/include/los_err.h @@ -144,6 +144,7 @@ enum LOS_MOUDLE_ID { LOS_MOD_CPUP = 0x1e, LOS_MOD_HOOK = 0x1f, LOS_MOD_PERF = 0x20, + LOS_MOD_PM = 0x21, LOS_MOD_SHELL = 0x31, LOS_MOD_DRIVER = 0x41, LOS_MOD_BUTT diff --git a/kernel/include/los_pm.h b/kernel/include/los_pm.h index b26adf501df698962c355858405197a0538fa3ae..6bfdb3e55c4441ea0a8e727c76ba7dafd05952ac 100644 --- a/kernel/include/los_pm.h +++ b/kernel/include/los_pm.h @@ -45,6 +45,118 @@ typedef enum { LOS_SYS_SHUTDOWN, } LOS_SysSleepEnum; +typedef enum { + LOS_PM_TYPE_DEVICE = 0, + LOS_PM_TYPE_TICK_TIMER, /* reserved */ + LOS_PM_TYPE_SYSCTRL, +} LOS_PmNodeType; + +typedef struct { + 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 { + /* 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; + +/** + * @ingroup los_pm + * @brief Register a power management node. + * + * @par Description: + * This API is used to register a power management node. + * + * @attention None. + * + * @param type [IN] The types supported by the PM module. + * @param node [IN] power management node. + * + * @retval error code, LOS_OK means success. + * @par Dependency: + *