Zephyr v3.7.0 · 커널과 서비스 소스 분석

Zephyr 전력 관리: CPU·시스템·장치

실행할 스레드가 없다고 해서 장치를 꺼도 되는 것은 아닙니다. idle, 절전 정책, 장치 사용 횟수의 결정 범위를 살펴봅니다.

본문 기준: Zephyr 3.7.0 LTS3 · 이후 유지보수 패치는 별도입니다.

기준은 Zephyr v3.7.0, commit 36940db938a8f4a1e919496793ed439850a221c2다. 아래 경로는 각 기능을 켜고 SoC·보드·드라이버가 해당 훅을 구현했을 때의 구조다. 도식의 장치 A·B·C와 시간은 설명용이며 실기 전력·지연 측정값이 아니다.

1. CPU, 시스템, 장치는 서로 다른 질문에 답한다

CPU가 당장 실행할 스레드를 찾지 못하면 idle thread가 돈다. CONFIG_PM=y이면 그 시점에 시스템 전력 정책이 CPU/SoC 상태를 제안할 수 있다. 장치 PM은 또 다른 층이다. 시스템 절전에 맞춰 한꺼번에 장치를 처리할 수도 있고, CPU가 계속 실행 중이어도 각 장치의 사용 횟수로 suspend할 수도 있다. idle 진입 = 장치 suspend로 읽으면 설정과 드라이버 조건을 놓친다.

표 1. 켜는 스위치와 실제 결정의 주체
구성판단·동작추가 전제
CONFIG_PMidle 중 시스템 전력 상태를 고르고 진입을 시도v3.7.0 Kconfig는 HAS_PM과 시스템 클록을 요구; 플랫폼 상태·훅 필요
CONFIG_PM_DEVICE드라이버 PM action 인터페이스 제공드라이버별 action callback이 있어야 실제 하드웨어 동작
CONFIG_PM_DEVICE_SYSTEM_MANAGED시스템 저전력 상태로 갈 때 대상 장치를 suspend/resumeCONFIG_PM_DEVICE 아래 선택, 실제 경로에는 시스템 PM 진입 필요
CONFIG_PM_DEVICE_RUNTIME장치별 사용 횟수의 0↔1 경계에서 suspend/resume개별 장치의 runtime PM 활성화와 드라이버 action 필요

근거: System PM, Device PM, Runtime PM, subsys/pm/Kconfig 5–17행과 83–153행.

2. idle thread의 기본 대기와 PM 상태 진입을 구분한다

v3.7.0의 kernel/idle.c는 idle 반복에서 다음 timeout을 보고 pm_system_suspend()를 시도한다. PM이 꺼져 있거나 상태 선택이 ACTIVE로 끝나면 일반 k_cpu_idle()로 이어진다. 상태를 골랐더라도 시스템 관리 장치 suspend가 실패하면 PM 진입을 취소하고 역시 일반 idle로 간다. PM 상태에 실제 진입하면 pm_state_set()이 SoC 상태 전환을 맡고, 복귀 훅과 통지 절차가 뒤따른다. 둘 다 CPU가 쉬는 경로지만 동일한 상태나 절전 깊이를 보장하지 않는다.

그림 1. 한 CPU의 idle 분기 — 정책이 상태를 고를 때만 PM 경로

↔ 좁은 화면에서는 흐름을 좌우로 이동해 읽으세요.

1 · idle thread다음 timeout을 확인. 로컬 IRQ 잠금 상태에서 진입.
2 · CONFIG_PM?off이면 일반 CPU idle로 곧장 이동.
3 · 정책/강제 상태플랫폼 상태·시간·제약을 평가.
4 · 선택됨pm_state_set()으로 SoC 저전력 상태 요청.
5 · 복귀장치/SoC post-op과 통지 뒤 실행 재개.
대안 A · PM 비활성k_cpu_idle() 사용. PM 정책·시스템 관리 장치 suspend를 뜻하지 않는다.
대안 B · PM 진입 실패상태가 없거나 장치 suspend가 실패하면 false → k_cpu_idle().
깨울 사건애플리케이션과 보드가 해당 상태에서 유효한 wake event를 준비.

이 그림은 함수 호출의 선택 관계를 요약한다. ISR에서 시작되는 복귀 처리와 SoC별 실제 대기 명령은 간략화했다.

따라서 CONFIG_PM=y만 보고 깊은 sleep을 기대해서는 안 된다. pm_state_force()로 지정한 상태는 해당 진입에서 기본 정책 선택을 건너뛴다. 아래 시간·lock 필터는 기본 정책을 통한 선택에 관한 설명이다. 보드가 상태를 제공해야 하고, 그 상태에서 살아 있는 wake source를 애플리케이션이 마련해야 한다. SMP에서는 CPU별 PM 상태를 다루며, 모든 CPU의 장치를 매 CPU마다 suspend하는 구조도 아니다.

근거: kernel/idle.c 28–75행, subsys/pm/pm.c 120–201행, 3.7.0 System PM 설명.

3. 정책은 ‘남은 시간’만 보지 않는다

기본 residency 정책은 CPU에 정의된 상태를 살펴보고 최소 체류 시간 + 복귀 지연이 다음 사건까지의 시간에 들어오는지 검사한다. 상태 lock과 최대 허용 latency도 걸러낸다. 그래서 타이머가 멀리 있어도 잠긴 상태에는 들어갈 수 없고, 상태가 하나도 적합하지 않으면 ACTIVE로 남는다. 애플리케이션 정의 정책은 pm_policy_next_state()를 구현하는 다른 선택이다.

표 2. 동일한 idle에도 결과를 바꾸는 조건
확인기본 정책의 판정실기에서 볼 자료
플랫폼 상태 목록정의되지 않은 절전 상태는 선택하지 못함보드/SoC devicetree의 power state
체류·복귀 시간남은 시간 ≥ 최소 체류 + exit latency다음 timeout, min-residency-us, exit-latency-us
상태 lock·latency잠금 중이거나 exit latency가 지정 한도 이상인 상태는 건너뜀pm_policy_state_lock_get() 사용처와 latency 요청
장치 busyCONFIG_PM_NEED_ALL_DEVICES_IDLE=y이면 기본 정책이 전체 busy를 먼저 검사. 단, v3.7.0에서는 PM_DEVICE && !SMP에 의존하여 SMP에서는 선택할 수 없음최종 .config·pm_device_busy_set/clear() 균형

근거: 3.7.0 정책 문서, subsys/pm/policy.c 216–281행, subsys/pm/Kconfig 47–52행.

4. 시스템 관리 장치 PM은 시스템 상태와 함께 움직인다

CONFIG_PM_DEVICE_SYSTEM_MANAGED=y인 경로는 선택된 CPU 저전력 상태가 장치 PM을 요구할 때 장치를 역초기화 순서로 suspend하고, 복귀하면서 반대 순서로 resume를 호출한다. 의존성이 초기화 순서에 맞아야 하는 이유다. v3.7.0은 runtime PM이 활성화된 장치, wakeup 활성 장치, busy 장치 등을 이 순회에서 건너뛴다. -ENOSYS·-ENOTSUP·-EALREADY는 건너뛰는 예외다. 그 밖의 음수 오류로 드라이버의 suspend action이 실패하면 이미 suspend된 장치에 역순 resume를 시도하고 CPU PM 진입을 취소한다. 이 복귀 함수는 각 resume 반환값을 검사하지 않으므로 실제 장치 재개 성공은 드라이버 상태·로그로 따로 확인해야 한다.

그림 2. 시스템 관리 대상 A→B→C가 있을 때의 왕복 순서

↔ 좁은 화면에서는 세 장치 열을 좌우로 이동해 읽으세요.

단계
장치 A · 먼저 초기화
장치 B
장치 C · 나중 초기화
부팅
① A 준비
② B 준비
③ C 준비
저전력 진입
③ A suspend
② B suspend
① C suspend
복귀 호출
① A resume
② B resume
③ C resume

A→B→C는 순서 설명용이다. 실제 순회는 준비 상태, busy, wakeup, runtime 활성 여부를 보고 일부 장치를 건너뛰며, 드라이버에서 오류가 나면 진입을 취소한다.

표 3. ‘모든 장치를 끈다’고 말할 수 없는 이유
조건v3.7.0 경로결과
선택 상태가 장치 PM 제외PM_STATE_RUNTIME_IDLE이면 항상 생략. 그 밖의 상태도 zephyr,pm-device-disabled가 있으면 생략시스템 상태는 들어가도 장치 순회는 없을 수 있음
runtime PM 활성 장치시스템 관리 순회에서 건너뜀장치 자신의 get/put 계약으로 상태 유지
busy·wakeup 활성 장치장치 순회에서 건너뜀전체 busy 검사 옵션은 PM_DEVICE && !SMP에서만 선택 가능; SMP는 그 옵션으로 진입을 막지 못함
건너뛰기 예외 외의 suspend 음수 오류이미 멈춘 대상에 역순 resume 호출 시도이번 시스템 상태 진입 취소. resume 반환값은 이 경로에서 무시되므로 실제 재개 여부 별도 확인
SMP의 동시 idle마지막 활성 CPU가 장치 suspend, 첫 복귀 CPU가 resumeCPU마다 같은 장치 action을 반복하지 않음

근거: 3.7.0 Device PM 문서, device_system_managed.c 27–75행, pm.c 82–98행과 150–162행.

5. runtime PM은 ‘지금 이 장치를 쓰는가’를 센다

CONFIG_PM_DEVICE_RUNTIME=y는 시스템 idle 여부와 별개로 장치의 사용 횟수를 센다. 개별 장치도 pm_device_runtime_enable() 또는 zephyr,pm-device-runtime-auto로 활성화되어야 한다. 첫 get()은 필요하면 resume하고, 중첩된 get은 장치를 계속 활성 상태로 두며, 마지막 put()은 suspend한다. 동기식 put은 완료를 기다린다. put_async()는 커널 시작 후 일반(non-ISR-safe) 장치에서는 suspend 작업을 예약하지만, ISR-safe 장치는 동기 경로를 쓰고 pre-kernel 문맥에서는 async 요청이 동기로 강제된다. 그러므로 API 성공·실제 상태·타이밍을 구별해 관찰한다.

그림 3. 한 장치의 사용 횟수와 물리 상태 — 동기식 예시

↔ 좁은 화면에서는 시간 단계를 좌우로 이동해 읽으세요.

시간
t0 · 사용 전
t1 · 첫 get
t2 · 추가 get/put
t3 · 마지막 put
usage
0
0 → 1
1 → 2 → 1
1 → 0
장치
SUSPENDED
RESUME → ACTIVE
ACTIVE 유지
SUSPEND → SUSPENDED

초기 suspended는 runtime PM이 성공적으로 활성화된 장치의 일반 모델이다. 커널 시작 후 non-ISR-safe 장치의 async put은 SUSPENDING을 지나며 작업 실행 시점이 달라진다. ISR-safe와 pre-kernel 경로는 동기 처리한다.

표 4. 사용 횟수·상태·호출 책임
사건코어가 하는 일주의
runtime enable장치별 runtime 제어 시작전역 Kconfig만으로 모든 장치가 자동 활성화되지는 않음
첫 get / 마지막 put사용 횟수 경계에서 드라이버 RESUME / SUSPEND action반환값 확인, get/put 짝 맞추기
put_async커널 시작 후 non-ISR-safe 장치는 usage 0에서 suspend 작업 예약ISR-safe 장치는 즉시 동기 처리, pre-kernel은 async=false로 강제. 예약 경로에서 즉시 완료 단정 금지
시스템 상태 전환runtime 활성 장치를 system-managed 순회에서 제외장치가 active인 채 플랫폼 깊은 절전으로 가도 안전한지 따로 설계

근거: 3.7.0 Runtime PM 문서, device_runtime.c 46–83행, 166–230행과 285–370행.

6. 전원 도메인과 일반 의존성을 같은 자동화로 보지 않는다

센서가 버스를 거쳐 동작한다면 센서와 버스의 수명도 맞춰야 한다. Zephyr 3.7.0 문서는 runtime PM이 일반 장치 간 의존성은 자동 관리하지 않는다고 명시한다. 필요하면 드라이버가 의존 장치를 직접 get/put한다. 예외적으로 CONFIG_PM_DEVICE_POWER_DOMAIN=y이고 devicetree의 power-domain 관계가 있으며 자식과 도메인 모두 runtime PM이 활성화된 경우, 자식의 runtime get/put이 도메인 get/put을 시도한다. 자식 runtime PM이 꺼져 있으면 get은 이 연쇄 이전에 반환한다. 도메인 드라이버의 action callback과 wakeup 경로도 별도로 갖춰야 한다.

표 5. 두 종류의 의존 관계
관계3.7.0에서의 책임검증할 것
센서 → 버스처럼 일반 의존성사용하는 드라이버가 상위/의존 장치의 get/put 순서를 직접 관리자식 사용 중 부모가 잠들지 않는지
자식 → power-domainCONFIG_PM_DEVICE_POWER_DOMAIN=y, DT 관계, 자식 runtime 활성화가 있을 때 도메인 get/put 시도도메인 runtime 활성화, action callback·wakeup 설계, 오류 반환
깊은 시스템 절전 → 장치 전원 손실필요하면 CONFIG_PM_POLICY_DEVICE_CONSTRAINTS와 상태 lock 사용작업 중 손실되는 상태를 정책이 제외하는지
Wake source도 별도 계약이다. devicetree의 wakeup-source 선언은 능력을 나타내며, v3.7.0은 초기화만으로 기능을 켜지 않는다. 필요할 때 pm_device_wakeup_enable()을 호출하고 드라이버·SoC가 해당 절전 상태에서 실제 깨움 신호를 유지하는지 확인한다. 자식 장치를 wake source로 쓴다면 그 전원 도메인도 wakeup 상태로 설정할 책임이 드라이버 또는 애플리케이션에 있다.

근거: Runtime PM 의존성 주의, Power Domain의 wakeup 주의, Device PM wakeup·제약, subsys/pm/Kconfig 101–108행, device_runtime.c 15–20행과 166–223행.

7. 보드에서 재현할 때 확인할 기록

  1. Zephyr commit, 보드·SoC, 최종 .config의 PM·PM_DEVICE·PM_DEVICE_SYSTEM_MANAGED·PM_DEVICE_RUNTIME를 같이 남긴다.
  2. devicetree의 CPU power state와 체류/exit latency, zephyr,pm-device-disabled, wakeup source를 상태별로 확인한다.
  3. 시스템 idle 경로에서 선택된 상태, 실제 pm_state_set() 진입, 복귀 통지와 유효한 wake event를 따로 기록한다.
  4. 장치별 runtime 활성화 여부, get/put 사용 횟수, action callback 성공/실패, system-managed 순회 대상 여부를 나눠 본다.
  5. 버스·전원 도메인·자식 장치의 의존 수명과 드라이버가 직접 관리하는 get/put 순서를 검사한다.

이 글은 구조를 설명한다. CONFIG_PM=y 또는 장치 callback 하나만으로 특정 보드의 전력 절감량, 복귀 시간, wakeup 성공을 보증하지 않는다.

8. 고정 버전 근거와 설명의 경계

공식 문서의 일반 계약과 같은 commit의 구현 분기를 함께 확인했다. 도식은 원본 설명용이며, SoC별 pm_state_set() 구현·하드웨어 측정·모든 드라이버 action을 실기 검증한 결과는 아니다.

연결해서 읽기