linux內核是如何支持深度睡眠(deep sleep)方式的?


1. 硬件架構

  arm64

2. 內核版本

  4.19

3. 分析相關函數

  setup_arch()

    -> psci_dt_init()

      -> psci_0_2_init()

        -> get_set_conduit_method()

          -> of_property_read_string(np, "method", &method))

          -> set_conduit(PSCI_CONDUIT_HVC) 或set_conduit(PSCI_CONDUIT_SMC),根據設備樹中的method屬性來設定,

            設定invoke_psci_fn回調函數(__invoke_psci_fn_smc或者__invoke_psci_fn_hvc)

        -> psci_probe()

 

  __invoke_psci_fn_smc()

    -> arm_smccc_smc(),這是個宏定義,如下;

      #define arm_smccc_smc(...) __arm_smccc_smc(__VA_ARGS__, NULL)

      ->__arm_smccc_smc(),定義在arch/arm64/kernel/smccc-call.S中:

          .macro SMCCC instr
          .cfi_startproc
          \instr #0
          ldr x4, [sp]
          stp x0, x1, [x4, #ARM_SMCCC_RES_X0_OFFS]
          stp x2, x3, [x4, #ARM_SMCCC_RES_X2_OFFS]
          ldr x4, [sp, #8]
          cbz x4, 1f /* no quirk structure */
          ldr x9, [x4, #ARM_SMCCC_QUIRK_ID_OFFS]
          cmp x9, #ARM_SMCCC_QUIRK_QCOM_A6
          b.ne 1f
          str x6, [x4, ARM_SMCCC_QUIRK_STATE_OFFS]
          1: ret
          .cfi_endproc
          .endm

 
         

        /*
        * void arm_smccc_smc(unsigned long a0, unsigned long a1, unsigned long a2,
        * unsigned long a3, unsigned long a4, unsigned long a5,
        * unsigned long a6, unsigned long a7, struct arm_smccc_res *res,
        * struct arm_smccc_quirk *quirk)
        */

       
       ENTRY(__arm_smccc_smc)       SMCCC smc        ENDPROC(__arm_smccc_smc)

 4. 相關變量

  4.1 suspend_state_t mem_sleep_default = PM_SUSPEND_MAX; (kernel/power/suspend.c)

    PM_SUSPEND_MAX的定義:   

      #define PM_SUSPEND_MAX          ((__force suspend_state_t) 4)

    所以默認mem_sleep_default = 4;

  4.2 suspend_state_t mem_sleep_current = PM_SUSPEND_TO_IDLE;   

    PM_SUSPEND_TO_IDLE的定義:   

      #define PM_SUSPEND_TO_IDLE          ((__force suspend_state_t) 1)

    所以默認mem_sleep_current = 1;

  4.3 那么在哪里將mem_sleep_current的值改變了呢?

      在suspend_set_ops()中改變了此值,調用路徑如下:

      psci_init_system_suspend()

        -> psci_features()

        -> suspend_set_ops()

  4.4 psci的版本號是從哪里獲取的?

    是從TF-A獲取的

  4.5 TF-A中psci固件的版本獲取

    相關代碼在TF-A倉庫的lib/psci/psci_main.c文件中     

    unsigned int psci_version(void)
    {
          return PSCI_MAJOR_VER | PSCI_MINOR_VER;
    }

     調用路徑如下:

     psci_smc_handler()

      -> psci_version()

    

    

  

      


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM