1. 概述
电源管理是操作系统中重要的一部分。要实现电源管理功能,首先需要设备本身支持电源管理操作,其次是操作系统支持电源管理操作。
SylixOS支持电源管理功能,电源管理分为两大部分:CPU功耗管理和外设功耗管理。
1.1 CPU功耗管理
SylixOS中,CPU功耗管理分为三个能级:
1.正常运行(Running):CPU正常执行指令。
2.省电模式(PowerSaving):所有具有电源管理功能的设备进入 PowerSaving 模式,同时CPU主频降低,多核CPU仅保留一个CPU运行。
3.休眠模式(Sleep):系统休眠所有具有电源管理功能的设备进入 Suspend 模式,系统需要通过指定事件唤醒休眠模式系统,会从复位向量处恢复,需要 bootloader/BIOS 程序配合。
需要的注意的是,在SMP多核中,可以动态调整CPU运行的核心数。
1.2 外设功耗管理
SylixOS中,外设功耗管理分为四个状态:
1.正常运行状态:设备被打开,驱动程序请求电源管理适配器连通设备电源与时钟,开始工作。
2.设备关闭状态:设备被关闭,驱动程序请求电源管理适配器断开设备电源与时钟,停止工作。
3.省电模式状态:系统进入省电模式,请求高能耗设备进入省电模式。
4.设备空闲状态:设备功耗管理单元具有看门狗功能,一旦空闲时间超过设置,系统会将设备变为空闲状态。
1.3 系统框架
SylixOS下电源管理结构如图1 -1所示。
图1 1电源管理系统框架
每个电源管理适配器(PM Adapter)可以管理多个设备(由相应的通道号区分),电源管理适配器管理的通道号总数决定这个适配器可以管理多少个设备。应用层可以对支持电源管理的设备进行进入休眠模式、进入省电模式、恢复正常模式等电源管理操作。
2. 系统接口及实现
2.1 系统接口概述
SylixOS中,电源管理部分提供了下面6个函数接口供应用层使用,如表2-1所示。
2.1.1 系统休眠
控制所有支持休眠功能的外设进入休眠状态,同时内核进入休眠状态。
VOID Lw_PowerM_Suspend(VOID);
2.1.2 系统唤醒
控制所有支持休眠功能的外设从休眠状态恢复正常状态,同时内核恢复正常状态。
VOID Lw_PowerM_Resume(VOID);
2.1.3 设置CPU节能参数
设置多核系统中运行的CPU核数目以及CPU能耗级别,系统根据参数关闭或打开CPU核,同时设置CPU能耗级别,设置CPU以不同的主频运行,进入节能模式时降低主频,反之则升高主频。本函数还会将CPU参数的改变通知到所有支持电源管理的外设。
VOID Lw_PowerM_CpuSet(ULONG ulNCpus, UINT uiPowerLevel);
其中参数:参数 ulNCpus是运行态的CPU核个数;
参数 uiPowerLevel是CPU能耗级别。
2.1.4 获取CPU节能参数
该函数获得当前运行的CPU个数和CPU能耗级别。
VOID Lw_PowerM_CpuGet(ULONG *pulNCpus, UINT *puiPowerLevel);
其中参数: 参数 pulNCpus返回运行态的CPU核个数;
参数 puiPowerLevel返回CPU能耗级别。
2.1.5 系统进入省电模式
使系统进入省电模式。控制所有支持电源管理的设备进入省电模式,同时设置运行的CPU核数目以及能耗级别。
VOID Lw_PowerM_SavingEnter(ULONG ulNCpus, UINT uiPowerLevel);
其中参数: 参数 ulNCpus是运行态的CPU核个数;
参数 uiPowerLevel是CPU能耗级别。
2.1.6 系统退出省电模式
控制系统退出省电模式,控制所有支持电源管理的设备退出省电模式,同时设置运行的CPU核数目以及能耗级别。
VOID Lw_PowerM_SavingExit(ULONG ulNCpus, UINT uiPowerLevel);
其中参数: 参数 ulNCpus是运行态的CPU核个数;
参数 uiPowerLevel是CPU能耗级别。
2.2 系统接口实现
2.2.1 系统休眠和唤醒
系统在进行休眠或者唤醒操作时,首先遍历电源设备管理链表,对链表中支持电源管理的设备进行休眠或者唤醒操作,然后对系统内核进行休眠或唤醒操作。系统接口实现流程如图2- 1所示。
图2- 1 系统休眠或唤醒流程
1. 系统休眠
对系统进行休眠操作,需调用API_PowerMSuspend系统接口,实现外设和系统内核进入休眠状态。函数原型如程序清单 2- 1所示。
程序清单2- 1 系统休眠
VOID API_PowerMSuspend (VOID) { PLW_LIST_LINE plineTemp; PLW_PM_DEV pmdev; __POWERM_LOCK(); /* * 遍历电源管理链表,对链表中设备进行休眠处理 */ for (plineTemp = _G_plinePMDev; plineTemp != LW_NULL; plineTemp = _list_line_get_next(plineTemp)) { pmdev = _LIST_ENTRY(plineTemp, LW_PM_DEV, PMD_lineManage); if (pmdev->PMD_pmdfunc && pmdev->PMD_pmdfunc->PMDF_pfuncSuspend) { pmdev->PMD_pmdfunc->PMDF_pfuncSuspend(pmdev); } } __POWERM_UNLOCK(); API_KernelSuspend(); /* 内核休眠处理 */ }
该函数实现以下功能:
-
遍历电源设备管理链表中支持电源管理的设备;
-
调用PMDF_pfuncSuspend函数,对加入电源管理链表中的外设依次进行休眠处理;
-
调用API_KernelSuspend函数,使内核进入休眠状态。
2. 系统唤醒
系统从休眠状态唤醒,需调用API_PowerMResume系统接口,实现外设和内核从休眠状态唤醒,函数原型如程序清单2- 2所示。
程序清单2- 2 系统休眠
VOID API_PowerMResume (VOID) { PLW_LIST_LINE plineTemp; PLW_PM_DEV pmdev; __POWERM_LOCK(); /* * 遍历电源管理链表,对链表中设备进行唤醒处理 */ for (plineTemp = _G_plinePMDev; plineTemp != LW_NULL; plineTemp = _list_line_get_next(plineTemp)) { pmdev = _LIST_ENTRY(plineTemp, LW_PM_DEV, PMD_lineManage); if (pmdev->PMD_pmdfunc && pmdev->PMD_pmdfunc->PMDF_pfuncResume) { pmdev->PMD_pmdfunc->PMDF_pfuncResume(pmdev); } } __POWERM_UNLOCK(); API_KernelResume(); /* 内核唤醒处理 */ }
该函数实现以下功能:
1.遍历电源设备管理链表中支持电源管理的设备;
2.调用PMDF_pfuncResume函数,对加入电源管理链表中的外设进行唤醒处理;
3.调用API_KernelResume函数,使内核从休眠中唤醒。
2.2.2 CPU节电参数设置和获取
CPU节电参数的设置,根据传入参数对CPU核进行关闭和打开,然后设置CPU能耗等级。获取CPU节电参数,首先获取当前系统运行CPU核个数,然后获取CPU能耗等级。系统接口实现流程如图2-2所示:
图2- 2 CPU节电参数设置、获取流程
1. 设置CPU节电参数
设置CPU节电参数,需调用API_PowerMCpuSet系统接口,函数原型如程序清单2 - 3所示。
程序清单2 - 3 设置CPU节电参数
VOID API_PowerMCpuSet (ULONG ulNCpus, UINT uiPowerLevel) { PLW_LIST_LINE plineTemp; PLW_PM_DEV pmdev; UINT uiOldPowerLevel; #if LW_CFG_SMP_EN > 0 ULONG i; ULONG ulActCnt = 0; #endif /* LW_CFG_SMP_EN > 0 */ if (ulNCpus == 0) { _ErrorHandle(EINVAL); return; } if (ulNCpus > LW_NCPUS) { ulNCpus = LW_NCPUS; } #if LW_CFG_SMP_EN > 0 for (i = 0; i < LW_NCPUS; i++) { /* 获取当前系统运行CPU数 */ if (API_CpuIsUp(i)) { ulActCnt++; } } if (ulActCnt > ulNCpus) { /* 需要关闭一些 CPU */ #if LW_CFG_SMP_CPU_DOWN_EN > 0 ULONG ulDownCnt = ulActCnt - ulNCpus; for (i = 1; i < LW_NCPUS; i++) { if (API_CpuIsUp(i)) { API_CpuDown(i); ulDownCnt--; } if (ulDownCnt == 0) { break; } } #endif /* LW_CFG_SMP_CPU_DOWN_EN > 0 */ } else if (ulActCnt < ulNCpus) { /* 需要打开一些 CPU */ ULONG ulUpCnt = ulNCpus - ulActCnt; for (i = 1; i < LW_NCPUS; i++) { if (!API_CpuIsUp(i)) { API_CpuUp(i); ulUpCnt--; } if (ulUpCnt == 0) { break; } } } #endif /* LW_CFG_SMP_EN > 0 */ API_CpuPowerGet(&uiOldPowerLevel); /* 获得CPU运行能级 */ if (uiOldPowerLevel != uiPowerLevel) { API_CpuPowerSet(uiPowerLevel); /* 设置CPU运行能级 */ __POWERM_LOCK(); /* * 遍历电源管理链表,将节电参数通知支持电源管理的外设 */ for (plineTemp = _G_plinePMDev; plineTemp != LW_NULL; plineTemp = _list_line_get_next(plineTemp)) { pmdev = _LIST_ENTRY(plineTemp, LW_PM_DEV, PMD_lineManage); if (pmdev->PMD_pmdfunc && pmdev->PMD_pmdfunc->PMDF_pfuncCpuPower) { pmdev->PMD_pmdfunc->PMDF_pfuncCpuPower(pmdev); } } __POWERM_UNLOCK(); }
该函数实现以下功能:
-
获取当前系统运行的CPU核数;
-
若传入参数小于当前系统运行CPU核数,则关闭一些CPU核;
-
若传入参数大于当前系统运行CPU核数,则打开一些CPU核;
-
获取当前CPU能耗等级,根据传入参数设置CPU能耗等级;
-
遍历电源管理设备链表,将CPU节电参数通知所有支持电源管理的外设。
2. 获取CPU节电参数
获取CPU节电参数,需调用API_PowerMCpuGet系统接口,函数原型如程序清单2-4所示。
程序清单2-4 获取CPU节电参数
VOID API_PowerMCpuGet (ULONG *pulNCpus, UINT *puiPowerLevel) { #if LW_CFG_SMP_EN > 0 ULONG i; ULONG ulActCnt = 0; /* * 获取CPU运行核数 */ if (pulNCpus) { for (i = 0; i < LW_NCPUS; i++) { if (API_CpuIsUp(i)) { ulActCnt++; } } *pulNCpus = ulActCnt; } #else if (pulNCpus) { *pulNCpus = 1ul; } #endif /* LW_CFG_SMP_EN > 0 */ if (puiPowerLevel) { API_CpuPowerGet(puiPowerLevel); /* 获取CPU运行能级 */ } }
该函数实现以下功能:
-
获取当前系统CPU核数;
-
获取当前系统CPU运行能级。
2.2.3 系统省电模式进入和退出
系统进入或退出省电模式,首先通知所有支持电源管理的外设进入或者退出省电模式,然后根据传入参数设置CPU节电参数。系统接口实现流程如图2- 3所示。
图2 -3 进入、退出省电模式流程
1. 进入省电模式
系统进入省电模式,需调用API_PowerMSavingEnter系统接口,函数原型如程序清单2-5所示。
程序清单2-5 进入省电模式
VOID API_PowerMSavingEnter (ULONG ulNCpus, UINT uiPowerLevel) { PLW_LIST_LINE plineTemp; PLW_PM_DEV pmdev; if (ulNCpus == 0) { _ErrorHandle(EINVAL); return; } __POWERM_LOCK(); /* * 遍历电源管理链表,使外设进入省电模式 */ for (plineTemp = _G_plinePMDev; plineTemp != LW_NULL; plineTemp = _list_line_get_next(plineTemp)) { pmdev = _LIST_ENTRY(plineTemp, LW_PM_DEV, PMD_lineManage); if (pmdev->PMD_pmdfunc && pmdev->PMD_pmdfunc->PMDF_pfuncPowerSavingEnter) { pmdev->PMD_pmdfunc->PMDF_pfuncPowerSavingEnter(pmdev); } } _G_bPowerSavingMode = LW_TRUE; __POWERM_UNLOCK(); API_PowerMCpuSet(ulNCpus, uiPowerLevel); /* CPU节电参数设置 */ }
该函数实现以下功能:
-
遍历电源管理链表,把电源管理链表中所有支持电源管理的设备设置为省电模式;
-
设置CPU节电参数,根据传入参数,对CPU节电参数进行设置,调用2.2.2节中API_PowerMCpuSet接口函数。
2. 退出省电模式
系统退出省电模式,需调用API_PowerMSavingExit系统接口,函数原型如程序清单2-6所示。
程序清单2-6 退出省电模式
VOID API_PowerMSavingExit (ULONG ulNCpus,UINT uiPowerLevel)
{
PLW_LIST_LINE plineTemp;
PLW_PM_DEV pmdev;
if (ulNCpus == 0) {
_ErrorHandle(EINVAL);
return;
}
__POWERM_LOCK();
/*
* 遍历电源管理链表,使外设外设省电模式
*/
for (plineTemp =_G_plinePMDev;
plineTemp != LW_NULL;
plineTemp =_list_line_get_next(plineTemp)) {
pmdev =_LIST_ENTRY(plineTemp,LW_PM_DEV,PMD_lineManage);
if (pmdev->PMD_pmdfunc &&
pmdev->PMD_pmdfunc->PMDF_pfuncPowerSavingExit) {
pmdev->PMD_pmdfunc->PMDF_pfuncPowerSavingExit(pmdev);
}
}
_G_bPowerSavingMode =LW_FALSE;
__POWERM_UNLOCK();
API_PowerMCpuSet(ulNCpus,uiPowerLevel); /* CPU节电参数设置 */
}
该函数实现以下功能:
-
遍历电源管理链表,把电源管理链表中所有支持电源管理的设备退出省电模式;
-
设置CPU节电参数,根据传入参数,对CPU节电参数进行设置,调用2.2.2节中API_PowerMCpuSet接口函数。
3. 小结
本文档介绍了SylixOS向应用层提供的电源管理系统接口,以及接口的实现流程。应用层可以调用这些系统接口,实现系统的电源管理工作。