SylixOS电源管理概述以及接口介绍


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 电源管理系统接口

系统接口功能
API_PowerMSuspend系统休眠
API_PowerMResume系统唤醒
API_PowerMCpuSet设置CPU节电参数
API_PowerMCpuGet获取CPU节电参数
API_PowerMSavingEnter系统进入省电模式
API_PowerMSavingExit系统退出省电模式

2.1.1 系统休眠

控制所有支持休眠功能的外设进入休眠状态同时内核进入休眠状态。

VOIDLw_PowerM_Suspend(VOID);

2.1.2 系统唤醒

控制所有支持休眠功能的外设从休眠状态恢复正常状态同时内核恢复正常状态。

VOIDLw_PowerM_Resume(VOID);

2.1.3 设置CPU节能参数

设置多核系统中运行的CPU核数目以及CPU能耗级别系统根据参数关闭或打开CPU核同时设置CPU能耗级别设置CPU以不同的主频运行进入节能模式时降低主频反之则升高主频。本函数还会将CPU参数的改变通知到所有支持电源管理的外设。

VOIDLw_PowerM_CpuSet(ULONG ulNCpus, UINT uiPowerLevel);

其中参数:    参数 ulNCpus是运行态的CPU核个数

            参数 uiPowerLevel是CPU能耗级别。

2.1.4 获取CPU节能参数

该函数获得当前运行的CPU个数和CPU能耗级别。

VOIDLw_PowerM_CpuGet(ULONG *pulNCpus, UINT *puiPowerLevel);

其中参数: 参数 pulNCpus返回运行态的CPU核个数

参数 puiPowerLevel返回CPU能耗级别。

2.1.5 系统进入省电模式

使系统进入省电模式。控制所有支持电源管理的设备进入省电模式同时设置运行的CPU核数目以及能耗级别。

VOIDLw_PowerM_SavingEnter(ULONG ulNCpus,UINT uiPowerLevel);

其中参数: 参数 ulNCpus是运行态的CPU核个数

参数 uiPowerLevel是CPU能耗级别。

2.1.6 系统退出省电模式

控制系统退出省电模式控制所有支持电源管理的设备退出省电模式同时设置运行的CPU核数目以及能耗级别。

VOIDLw_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();                                          /*  内核休眠处理              */
}

该函数实现以下功能

  1.  遍历电源设备管理链表中支持电源管理的设备

  2.  调用PMDF_pfuncSuspend函数对加入电源管理链表中的外设依次进行休眠处理

  3.  调用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++) {
        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();
    }
}

    该函数实现以下功能:

1. 获取当前系统运行的CPU核数;

2.若传入参数小于当前系统运行CPU核数,则关闭一些CPU核;

3.若传入参数大于当前系统运行CPU核数,则打开一些CPU核;

4.获取当前CPU能耗等级,根据传入参数设置CPU能耗等级;

5.遍历电源管理设备链表,将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;

    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);
    }
}

该函数实现以下功能

  1.  获取当前系统CPU核数

  2.  获取当前系统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);
}

该函数实现以下功能

  1.  遍历电源管理链表把电源管理链表中所有支持电源管理的设备设置为省电模式

  2.  设置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);
}

该函数实现以下功能

  1.  遍历电源管理链表把电源管理链表中所有支持电源管理的设备退出省电模式

  2.  设置CPU节电参数根据传入参数对CPU节电参数进行设置调用2.2.2节中API_PowerMCpuSet接口函数。

3. 小结

本文档介绍了SylixOS向应用层提供的电源管理系统接口以及接口的实现流程。应用层可以调用这些系统接口实现系统的电源管理工作。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章