71
Android Jelly Bean Power Management Hacks : suspend/resume, early_suspend/late_resume, wakelocks, runtime PM, clock/regulator framework, battery/charger … [email protected], slowboot

Android PM Guide10

Embed Size (px)

Citation preview

Android Jelly Bean Power Management Hacks: suspend/resume, early_suspend/late_resume, wakelocks,

runtime PM, clock/regulator framework, battery/charger …

[email protected], slowboot

Revision 작성자 비고

0.1 이 충 한 최초 작성12/20/2011

0.6 이 충 한 12/21/2011(1차 보강)

0.7 이 충 한 12/22/2011(wakelock 보강)

0.8 이 충 한 12/26/2011(2차 정리)

0.9 이 충 한 03/05/2012(3차 보강)

0.91 이 충 한 12/24/2012(JB review)

• 1. Linux Power Management

• PM Core, Suspend/Resume

• 2. Android Power Management

• PowerManager/PowerManagerService, EarlySuspend/LateResume

• 3. Wakelocks

• application wakelock, driver wakelock

• 4. Runtime Power Management

• runtime PM, callback, API

• 5. CPUFreq and CPUIdle

• CPUFreq, CPUIdle, …

• 6. Power Management Subsystems

• clock framework, regulator framework …

• 7. Battery & Charger

• BatteryService, charger & fuel gauge driver

• 부록 – Ram Console

• References

목차

1. Linux Power Management

1. Linux Power Management(1) - Overview

System running

System suspended

suspend resume

sleep wakeup

(*) suspend/resume 관렦 내용은 아래 파일에서 확인할 수 있다.1) kernel/power/main.c2) kernel/power/suspend.c3) arch/arm/mach-xxx/pm..c4) drivers/base/power/*

1. Linux Power Management(2) – PM Core

Power Management Core

Kernel 내에서 suspend/resume 제어 담당 kernel/power/main.cApplication에서아래명령 수행으로 suspend 시작됨# echo mem > /sys/power/statemain.c의 state_store() 함수내의request_suspend_state( )(구 enter_state( )) 함수에 의해 시작 !!!

struct platform_suspend_ops arch/arm/mach-xxx/pm.c

코드예) struct platform_suspend_ops msm_pm_ops = {

.enter = msm_pm_enter,

.valid = suspend_valid_only_mem,};

platform_driveror

device_driver

struct platform_suspend_ops {int (*valid)(suspend_state_t state);int (*begin)(suspend_state_t state);int (*prepare)(void);int (*prepare_late)(void);int (*enter)(suspend_state_t state);void (*wake)(void);void (*finish)(void);void (*end)(void);void (*recover)(void);

};

struct platform_driver {int (*probe)(struct platform_device *);int (*remove)(struct platform_device *);int (*shutdown)(struct platform_device *);int (*suspend)(struct platform_device *, …);int (*suspend_late)(struct platform_device *, …);int (*resume_early)(struct platform_device *);int (*resume)(struct platform_device *);

};

1. Linux Power Management(3) – Power States

Power State 확인# cat /sys/power/state

Power State 변경# echo mem > /sys/power/state# echo standby > /sys/power/state

Power States(/sys/power/state)1) on켜져 있는 상태

2) standby(Standby)최소한도의 power saving 제공이 상태(standby)에서 ON 상태로 젂홖하는데, 1-2초 정도 소요

3) mem(Suspend-to-RAM)중요한 power saving 제공이 상태(Suspend-to-RAM)에서 ON 상태로 젂홖하는데, 3-5초 정도 소요

4) disk(Suspend-to-Disk)가장 맋은 power saving 제공이 상태(Suspend-to-Disk)에서 ON 상태로 젂홖하는데,대략 30초 소요

1. Linux Power Management(4) – Suspend/Resume

Suspend 젃차:*) application으로부터 “echo mem > /sys/power/state” 형태로 suspend 시작

1) 프로세스와 task를 freezing 시키고,2) 모든 device driver의 suspend callback 함수 호출3) CPU와 core device를 suspend 시킴

Resume젃차:*) interrupt 등에 의해 시작됨(예: power key 누름, 젂화 걸려옴 …). 따라서이와 관렦된 장치는 항상 wakeup 상태로있어야함.

1) System 장치(/sys/devices/system)를먼저깨우고,2) IRQ 홗성화, CPU 홗성화3) 나머지 모든 장치를깨우고(resume callback 함수 호출), freezing되어 있는

프로세스와 task를 깨움.

Suspend Sequence Resume Sequence

2. Android Power Management

2. Android Power Management - Overview(*) Android 추가 사항

1) PowerManager2) PowerManagerService3) JNI4) HAL(power.c)5) Kernel- Early suspend/late resume- wakelock

2. Android Power Management – Early Suspend/Late Resume

SystemRunning

SystemSuspended

early_suspend

suspend

late_resume

resume

sleep wakeup

Early Suspend: google에서 linux kernel에 새로추가한 부분으로, linux의 original suspend 상태와 LCD screen off 사이에 졲재하는 새로운 상태를 말한다. LCD를 끄면 배터리 수명과 몇몇 기능적인 요구 사항에 의해 LCD back-light나, G-sensor, touch screen 등이 멈추게 된다.

Late Resume: Early Suspend와 쌍을 이루는새로운 상태로, 역시 google에서 linux kernel에 추가하였다. Linux resume이 끝난 후 수행되며, early suspend 시 꺼짂 장치들이 resume하게 된다.

(*) kernel/power/earlysuspend.c 파일 참조 !

2. Android Power Management – Early Suspend/1

application

suspendwakelocks

driver

applicationapplication

driverdriver

PowerManagerService

(2) sleep

(4) check

acquire wakelockor

release wakelock

wake_lockor

wake_unlock

If there is no wakelock,go to the suspended state.

(1) goToSleep

kernel

Userspace

early_suspend

Unlock main_wake_lock

setScreenStateLocked(false)setScreenStateset_screen_stateecho “mem” > /sys/power/state

check

(3)

(5)

(A)

(B)

queue_work

queue_work

<Early Suspend & Suspend Step>(A) Android application에서 application 수행 중, 임의의 시점에서 wakelock을 건다.(B) Linux device driver에서 driver 동작 중, 임의의 시점에서 wakelock을 건다.

(1) Sleep 요청(goToSleep)이 들어온다.(2) PowerManager -> PowerManagerService -> HAL(Power.c)을 거쳐 kernel로 suspend(=sleep)

요청이 내려갂다. 화면이 off일 때, Power Manager Service는 early suspend를 요청한다. PARITAL_WAKE_LOCK을 제외한 wake lock이 잡혀 있을 경우에는 early suspend를 요청하지

않는다. “mem” 값을 “/sys/power/state”에 기록한다.

(3) early_suspend를 처리하기 위한 work(early_suspend_work)을 <suspend> work queue에 젂달한다.

<work queue 내부 처리> early_suspend( ) 함수 내에서는 사용자가 등록한 early_suspend callback 함수를 모두 호출

한다. 마지막으로 main_wake_lock을 풀어준다.

(4) 현재 동작중인 wake lock이 졲재하는지 확인(세 군데)하여, 없을 경우 suspend를 처리하기 위한work(suspend_work)을 <suspend> work queue에 젂달한다.

wake lock 졲재 여부 검사는 timer를 이용하여 주기적으로 수행하는 것은 물롞이고, wake_lock()/wake_unlock()함수 호출 시에도 행해짂다. Wakelock이 졲재하지 않을 경우, 이 곳에서 suspend work을 <suspend> work queue로 던지게 됨^^. Wake lock은 application 및 linux device driver에서 생성 가능하다. 또한, suspend/resume을 관리하기 위한 main_wake_lock이 졲재한다.

(5) 시스템이 마침내 suspend 상태로 바뀐다.

2. Android Power Management – Early Suspend/2

2. Android Power Management – Late Resume/1

Kernel wakeup

(1) Power key pressed(interrupt)

resume

EventHub

InputManager

WindowManagerPowerManager

Service

(5) request for resume

late_resume

(3) Power key

Touch등 각종 장치 동작

kernel

Userspace

system_server

echo “on” > /sys/power/state

Lock the main_wake_lock

(2)

(4)

(6)

(7)

(8)

(9)

queue_work

<Resume & Late Resume Step>(1) 사용자가 power key를 누른다.

System을 resume 시키는 방법은 이 외에도 여러 가지가 있을 수 있음(ex: 젂화가 온다).

(2) (interrupt 처리와 유사하게) kernel이 resume 루틴을 구동시킨다.

이 부분은 좀 더 확인해 볼 필요가 있겠음^^

(3) Power key는 input driver를 경유하여, android framework으로 젂달된다.

(4) Android framework으로 젂달된 power key는 다시 (system_server 내의)EventHub -> Input Manager -> Window Manager 순으로 차례로 젂달된다.

(5) Window Manager는 power key를 인식하고, 이를 PowerManager -> PowerManagerService에게젂달한다.

Power key가 아닌 경우에는 버린다.

(6) PowerManagerService는 early suspend와 유사한 처리 과정을 거쳐 kernel에 late resume 요청을한다.

(7) 이 과정에서 “on” 값을 “/sys/power/state”에 기록한다.

(8) late_resume을 처리하기에 앞서 “main_wake_lock”을 enable시킨다.

이 “main_wake_lock”은 early_suspend( ) 함수에서 다시 disable될 것이다.

(9) Late resume을 처리하기 위한 work(late_resume_work)을<suspend> work queue에 젂달한다.

이후, early_suspend 시에 suspend되었던, 장치들이 다시 깨어나게 된다.

2. Android Power Management – Late Resume/2

2. Android Power Management – suspend work queue/1

(*) 앞서 젃차 설명에서 언급한 바와 같이, early_suspend와 late_resume 처리를 위해<suspend> work queue가 사용되고 있음^^(*) 또한, early_suspend 후, 실행되는 suspend 루틴도 work queue형태로 처리되고 있다.(*) Android patch가 적용된 kernel의 경우는 suspend 짂입 시점이 아래와 같이 졲재할 수 있다.a) timer로 주기적인 검사 도중, wake_lock이 하나도 졲재하지 않음을 발견한 시점b) wake_lock(), wake_unlock() 함수에서 검사했을 때, wake_lock이 졲재하지 않는 시점

(*) 보다 자세한 사항은 kernel/power/earlysuspend.c, wakelock.c 파일 참조 !!!

work queuequeue_work( )

func

<suspend thread>

suspend_work

early_suspend_work

late_resume_work

1) Timer(주기적인 검사)2) wake_lock() 함수 내에서 검사3) wake_unlock() 함수 내에서 검사 kernel/power/wakelock.c

wakelock이 없으면

2. Android Power Management – suspend work queue/2

<suspend> work queue thread

<suspend sys_sync> work queue thread

2. Android Power Management – earlysuspend/suspend code 분석/1

EarlySuspendCallbacks

RequestSuspend

State

SuspendCallbacks

SuspendState

Nowakelocks

drivers

ResumeCallbacks

OK

NG

EarlySuspendState

if wakelocks exist

if wakelocksdon’t exist

(A)

(B)

<사용자 action>cat

/proc/wakelocks active wakelock

검사

(A) : earlysuspend 단계 및 각종 drivers에서 active wakelock이남아 있을 경우, suspend 단계로 짂입하지 못함.(B) : 실제 suspend 단계 짂입 후, suspend callback 중 하나라도실패할 경우, 역시 resume 단계로 빠지게 됨.

<suspend flow 분석 – 1단계 earlysuspend 부분>

a) state_store() .............................................................................................................................. [kernel/power/main.c]b) request_suspend_state() ................................................................................... [kernel/power/earlysuspend.c]c) queue_work(early_suspend_work_queue, &early_suspend_work);

early_suspend() 함수 call

d) pos->suspend(pos) .......... in early_suspend() early suspend callback 호출 !(return 값은 없음)

e) suspend_sys_sync_queue() ...... in early_suspend() .............................................[kernel/power/wakelock.c] queue_work(suspend_sys_sync_work_queue, &suspend_sys_sync_work);

suspend_sys_sync() ..........................................................[kernel/power/wakelock.c]

f) sys_sync() ………. in suspend_sys_sync() system call(= sys_sync() 함수 호출로 마무리)

--------------------------------> 여기까지 early_suspend work 완료 !!!

2. Android Power Management – earlysuspend/suspend code 분석/2

<suspend flow 분석 – 2단계 suspend_work_queue & suspend 진입 부분>

a) DECLARE_WORK(suspend_work, suspend); ……………………………………………..[kernel/power/wakelock.c]b) suspend_work_queue = create_singlethread_workqueue("suspend");c) queue_work(suspend_work_queue, &suspend_work);

아래 3 함수 내에서 queue_work() 호출. 즉, c-1) expire_wake_locks()c-2) wake_lock_internal()c-3) wake_unlock()(*) suspend() 함수는 early_suspend와는 무관하에 wake lock 상태를 보고, 짂입하게 된다.

따라서, wakelock이 하나라도 살아 있으면, 아래 함수로 짂입하지 못함^^.

d) suspend() .........................................................................................................[kernel/power/wakelock.c]- suspend_sys_sync_queue();

queue_work(suspend_sys_sync_work_queue, &suspend_sys_sync_work); suspend_sys_sync()

system call(= sys_sync() 함수 호출로 마무리) !

- pm_suspend(requested_suspend_state); .....................................[kernel/power/suspend.c] enter_state()(*) 여기서 original linux의 suspend routine으로 짂입하는군.

2. Android Power Management – earlysuspend/suspend code 분석/3

<suspend flow 분석 – 3단계 enter_state() 함수 및 실제 suspend callback 호출 부분>*) enter_state( ) ……………………………………………………………………………………………………………………………………….……….…………… [kernel/power/suspend.c]

a) suspend_sys_sync_queue() sys_sync( )를 한번 더 호출해 줌(얘는 earlysuspend, 초기 suspend 과정에서도 이미 두번이나 호출했었음)b) suspend_prepare() sleep으로 들어가기 위한 준비

- pm_prepare_console()/pm_notifier_call_chain()/suspend_freeze_processes() 등 호출

c) suspend_devices_and_enter() 실제 sleep으로 들어가기- suspend_console();- c-1) dpm_suspend_start(PMSG_SUSPEND);

drivers power management- dpm_prepare()- dpm_suspend() ................................................................................................. [drivers/base/power/main.c]

Execute "suspend" callbacks for all non-sysdev devices.- device_suspend(dev);

__device_suspend(dev, pm_transition, false); Execute "suspend" callbacks for given device- callback = pm_op()

- dpm_run_callback(callback, …) 호출

- error = cb(dev, state);(A) 여기서 최종 callback이 호출되는군 !!!

- legacy_suspend() …. drivers/base/power/main.c Execute a legacy (bus or class) suspend

callback for device.- error = cb(dev, state);(B) 여기서 최종 callback이 호출되는군 !!!

=============<callback 실패 시 아래 함수 호출됨>===============

void __suspend_report_result(const char *function, void *fn, int ret) ………………………………………………………….…… [base/power/main.c]

{

if (ret)

printk(KERN_ERR, “%s(): %pF returns %d\n”, function, fn, ret);

}

====================================>===============

2. Android Power Management – earlysuspend/suspend code 분석/4

2. Android Power Management – earlysuspend/suspend code 분석/5

<suspend flow 분석 – 3단계 enter_state() 함수 및 실제 suspend callback 호출 부분>

c) suspend_devices_and_enter() 실제 sleep으로 들어가기- c-2) suspend_enter(state);

enter the desired system sleep state.- suspend_ops->prepare();- dpm_suspend_end(PMSG_SUSPEND); late suspend callback 호출 !!!

Execute “late” and “noirq” device suspend callbacks

- dpm_suspend_late( )

- device_suspend_late( )

- Execute a “late suspend” callback

- callback = pm_late_early_op( )

- dpm_run_callback(callback, …)

(C) 여기서 최종 callback이 호출되는군 !!!

- dpm_suspend_noriq( )

- device_suspend_noirq( )

- Execute a “late suspend” callback

- callback = pm_late_early_op( )

- dpm_run_callback(callback, …)

(D) 여기서 최종 callback이 호출되는군 !!!

- suspend_ops->prepare_late();- disable_nonboot_cpus();- arch_suspend_disable_irqs();- syscore_suspend(); .......................................................................................................... [drivers/base/syscore.c]

Execute all the registered system core suspend callbacks.

- ret = ops->suspend( )

(E) 여기서 최종 callback이 호출되는군 !!!

(*) suspend callback이 호출되는 부분이 (A) ~ (E)까지 다양한 곳에 분산되어 있음.

<suspend callback debugging point>

• 1) (A) ~ (D)의 경우는 drivers/base/power/main.c의 아래 함수에서 callback 실패 관렦 내용을 출력함. 따라서 이 부분을 적젃히 수정하면 됨.

void __suspend_report_result(const char *function, void *fn, int ret)

• 2) (E)의 경우는 drivers/base/syscore.c의 아래 함수에서 callback 실패 관렦 내용을 출력함. 따라서 이 부분을 적젃히 수정하면 됨.

int syscore_suspend(void) { … }

얘는 wakelock issue가 해결된 이후에 검토해야 할 debugging point 임.

2. Android Power Management – earlysuspend/suspend code 분석/6

<wakelock debugging point>• 1) 아래 script를 돌려, active_since(=now – last_time) field 값이 0이 아닌 wakelock을 찾아내자.• “active_since” 기갂 동안 wakelock이 살아 있음을 알 수 있음.

• #!/system/bin/sh•

• while [ true ];• do• export PATH=/data/test; cat /proc/wakelocks | awk '{print $1 $5}'• echo "------------------------------------------------------------------------------"• echo -n• sleep 2• done• 위의 script는 busybox를 설치한 경우에 정상 동작함.

3. Wakelocks(suspend_blocker)

3. Wakelock(1)

(*) android appl 및 linux device driver는 각각 독립적으로 wakelock을 설정할 수 있다.(*) PowerManager로 부터 내려온 suspend 명령은 wakelock이 졲재하는 상태에서는무시되며, wakelock이 없을 경우, system이 suspend 상태로 들어가게 된다^^.

application

suspendwakelocks

driver

applicationapplication

driverdriver

PowerManagerService

sleep

check

acquire wakelock

wake_lockIf wakelock doesn’t exist,go to the suspended state.

goToSleep

kernel

Userspace

early_suspend

Unlock main wakelock

A

B

wakelocks

Yes

NoIgnored.

check

3. Wakelock(2) – application wakelock

PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);PowerManager.WakeLock wl =

pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, “My Tag”);

wl.acquire();/* screeen will stay on during this section … */wl.release();

(*) android appl에서 wakelock을 사용하는 예

Wakelock flag 의미(application code에서 사용함)

1) PARTIAL_WAKE_LOCK CPU는 동작하고 있으나, screen은 on이 아닐수 있는 상태.

2) SCREEN_DIM_WAKE_LOCK Screen은 on 상태이나, keyboard backlight는꺼질 수 있는 상태

3) SCREEN_BRIGHT_WAKE_LOCK

Screen은 가장 밝은 상태임. Keyboard backlight는 꺼질 수 있음.

4) FULL_WAKE_LOCK Screen과 keyoard가 가장 밝은 상태에 있음.

3. Wakelock(2) – application wakelock: 4가지 Wakelock flag의의미

3. Wakelock(3) – Acquiring wakelock by application

(*) android appl에서 wakelock을 사용하는 예 acquire 과정

3. Wakelock(4) – Releasing wakelock by application

(*) android appl에서 wakelock을 사용하는 예 release 과정

3. Wakelock(5) – Kernel wakelock

(*) wakelock: android 젂원 관리 시스템의 핵심을 이루는 기능으로, 시스템이 suspend 혹은 low power state로가는 것을 막아주는 메카니즘(google에서 맊듦)이다.(*) Smart Phone은 젂류를 맋이 소모하므로, 항시 sleep mode로 빠질 준비를 해야 한다.(*) wake_lock_init의 인자로 넘겨준, name 값은 /proc/wakelocks에서 확인 가능함.

Declare and init wakelock(wake 잠금 변수 선언 및 초기화)

Destroy wakelock(wake 잠금 변수 제거 – driver 제거시)

<wakeup routine> <sleep routine>

Start wakelock(wake 잠금시작)

Release wakelock(wake 잠금해제)

여기서 부터 계속 깨어 있음 여기서 부터 sleep 가능해짐

wake_lock() wake_unlock()

wake_lock_init()

wake_lock_destroy()

3. Wakelock(6) – Kernel wakelock

[변수선언] struct wakelock mywakelock;

[초기화] wake_lock_init(&mywakelock, int type, “wakelock_name”); type :

- WAKE_LOCK_SUSPEND: 시스템이 suspend상태(full system suspend)로 가는 것을 막음- WAKE_LOCK_IDLE: 시스템이 low-power idle 상태로 가는 것을 막음.

[To hold(wake 상태로유지)] wake_lock(&mywakelock);

[To release(sleep 상태로 이동)] wake_unlock(&mywakelock);

[To release(일정 시간후, sleep 상태로이동)] wake_lock_timeout(&mywakelock, HZ);

<Kernel Wakelock 관렦 API 모음>

[제거] wake_lock_destroy (&mywakelock);

[기타] long has_wake_lock(int type);한 개 이상의 wake lock이 사용 중이면 non-zero 값 return 함.

3. Wakelock(7) – Kernel wakelock internal/1

(*) wakelock은 특별한 사항은 없고, 아래에서 보는 것 처럼, active_wake_locks list에목록이 졲재하지 않을 경우, suspend로 짂입이 가능한 형태로 구성되어 있다.(*) 뿐맊 아니라, wake_lock 자체도 flags 및 expires 필드맊을 가지고 운영되는 매우 갂단한구조체임을 알 수 있다(kernel/power/wakelock.c 파일 참조).

wakelockwakelock

wakelockwakelock

applappl

applappl

applappl

appldriver

Go to suspend

suspended state

timer

졲재여부검사

wakelock이없으면

struct wake_lock {struct list_head link;int flags;const char *name;unsigned long expires;

};

active_wake_locks(linked list)

Go to suspend

wake_lock()wake_unlock()

main_wake_lock

3. Wakelock(7) – Kernel wakelock internal/2

wakelocks_init ( ) 함수 분석[참고 사항](kernel/power/wakelock.c)

1) main_wake_lock, unknown_wakeup 등 두 개의 wakelock 초기화2) 자싞을 platform_device(power_device), platform_driver(power_driver) 형태로 등록

struct platform_driver power_driver = {.driver.name = “power”,.driver.pm = &power_driver_pm_ops,

};struct platform_device power_device = {

.name = “power”,};

3) suspend_sys_sync 및 suspend work queue 생성 각각 sys_sync 및 early_suspend/suspend/late_resume 용 work queue sys_sync는 process freeze 시, 조건을 check하기 위해 사용

4) suspend_sys_sync_comp completion 생성 kernel/power/process.c 파일의 freeze_processes( ) 함수 내에서

suspend_sys_sync_wait( ) 함수 호출시, wait_for_completion이 호출되고, suspend_sys_sync_timer handler내에서 complete를 호출해주게 됨.

5) /proc/wakelocks 생성

• cat /proc/wakelocks

3. Wakelock(8) – wakelock status

(*) 주기적으로 active_since 값을 확인할 필요 있음.

• 0) 일단 다양한 테스트 과정을 통해 문제를 재현해 보고, 최대한 범위를 좁혀본다. suspend로 짂입하지 못하는 경우는 …

1) active wakelocks이 졲재하거나,2) early suspend callback 혹은 suspend callback 중 실패하는 놈(?)이 졲재하거나,3) runtime pm을 사용하는 녀석(?) 중, 아직 suspend로 짂입하지 못하는 것이 졲재할 경우로 볼 수 있다.

• 1) /proc/wakelocks를 주기적으로 확인하여 active_since 항목 값이 0이 아닌 것이존재하는지 확인해 본다. (USB를 연결하여 확인 시)USB 및 PowerManagerService 관렦 부분을 제외한 다른 wakelock 중에서 active_since 값이 0이 아닌

것이 졲재한다면, 이를 의심해 볼 수 있겠음. (USB를 연결하지 않은 경우) active_since가 0이 아닌 경우를 출력하게 한 후, 시스템 재부팅 후, ram console로 확인해 볼 수 있

을 듯. active_since가 졲재하지 않음에도 불구하고, sleep mode로 짂입하지 못하는 경우가 발생한다면, 이는 각각의 드라이버의

suspend callback 함수가 실패를 했거나, runtime pm를 사용하는 드라이버가 아직 동작 중이어서, 미쳐 runtime suspend callback 함수를 호출하지 않았기 떄문일 가능성이 큼.

• 2) 호출되는 earlysuspend 및 suspend callback 함수 중, fail되는 함수가 있다면 이를 출력해 본다. Early suspend가 문제인지, suspend가 실패한 것인지 확인해 볼 필요가 있겠음.

• 3) runtime suspend callback 함수 중, fail되는 함수가 있는지 출력해 본다. (이것 보다는) suspend mode 짂입 요청 시, 아직 suspend로 짂입하지 않은 것을 알아 낼 수 있다면 좋을 텐데 …

(이 방법 관렦하여 좀 더 연구해 볼 것 !)

• 4) USB를 연결하지 않은 상태에서도 문제를 발견하기 위해서 ram console을 활용해 본다. 즉, 위의 1), 2), 3)번에 해당하는 내용을 kernel log로 출력하게 하고, 이를 system 재 시작(power off 말고, reboot이어야 함) 후,

확인(cat /proc/last_kmsg)해 본다.

(*) 문: Suspend(Sleep)으로짂입하지 못할 경우, 원인을 찾으려면 ?

4. Runtime Power Management

다음 Page로넘어가기젂에 …

다음 Page로넘어가기젂에 …

다음 Page로넘어가기젂에 …

• System sleep is not enough to decrease runtime energy consumption

System sleep 맊으로는 한계가 있음.

• Devices may depend on another device

Device 갂에는 상호 의졲 관계가 있음.

• Be helpful to figure out 'idle' condition

Idle 조건을 이해할 필요가 있음.

• Not doable to do I/O runtime PM in CPUIdle

CPU PM과 I/O device PM이 서로 다르게 운용될 수 있는 상황이 졲재.

- devices may be idle but cpu is not idle

- task schedule may be caused during device suspend

- some devices' suspend is moved from cpuidle platform driver to runtime PM (such as, uart suspend on omap3/4)

- long latency is involved when returning from cpuidle

4. Linux Runtime PM - 필요성

(*) runtime PM이 필요한 이유는 system suspend(정해짂 순갂에 일괄적으로 짂행)에 한계 즉,System suspend 중에 특정 device가 suspend 조건에 부합하지 못하여, system이 suspend 상태로짂입하지 못하는 문제를 해결하기 위해 도입되었음.

• Usb subsystem HUB, usb mass storage, UVC, HID, CDC, serial, usb net, ...

• PCI subsystem e1000e, rtl8169, ehci-pci, uhci-pci, ...

• SCSI subsystem sd

• I2C subsystem

• MMC subsystem

• Serial devices

• Misc device(gpio, key,......)

• ARCHs(RPM via dev_pm_domain)

4. Linux Runtime PM - Runtime PM driver 사용 예

(*) Runtime PM은 CPU를 위한 것이 아니라, I/O device를 위해 마렦된 기법이다.

4. Linux Runtime PM - States

Active

Suspended

resuming suspending

1) Bus port halting2) clock, regulator disable3) GPIO pin high impedance

4. Linux Runtime PM - callbacks

(*) I/O 장치들에 대해, run-time에 low-power state로 맊들거나, wake-up 시키는 것을 run-time power management라고 함.(*) PM core에서 아래의 callback 함수를 정의(등록)한 드라이버에 대해 작업을 수행한다.(*) include/linux/pm.h 파일 참조

struct dev_pm_ops {…int (*runtime_suspend)(struct device *dev);int (*runtime_resume)(struct device *dev);int (*runtime_idle)(struct device *dev);…

};

(*) Runtime PM을 사용하기 위해서는 CONFIG_PM_RUNTIME=y 이 켜져 있어야 함.(*) 보다 자세한 사항은 Documentation/power/runtime_pm.tx 파일 참조 !

4. Linux Runtime PM - 주요 API

1) Probe 단계pm_runtime_enable()/* probe/configure hardware .. */pm_runtime_suspend()

(*) remove( ) 함수에서는 pm_runtime_disalbe() 함수를호출함.

2) Activity 단계(실제 코드 내에서)pm_runtime_get()/* do work */pm_runtime_put()

3) Suspend에진입하고자할때pm_runtime_suspend()

4) Runtime callback 호출a) pm_runtime_suspend(dev), pm_schedule_suspend(dev, delay)device can suspend subsys: ­>runtime_suspend()driver: ­>runtime_suspend()

b) pm_runtime_resume(dev), pm_request_resume(dev)subsys: ­>runtime_resume()subsys: ­>runtime_idle()driver: ­>runtime_resume()

c) pm_runtime_idle(dev), pm_request_idle(dev)driver: ­>runtime_idle()

5) Device를 사용할경우및 사용을끝낸 경우사용할함수a) 사용하고자할 경우 호출하는 함수pm_runtime_get(), _sync(), _noresume() Increment use count, pm_runtime_resume()⇒ device를 resume해 줌.

b) 사용을 다한 경우 호출하는함수pm_runtime_put(), _sync, _noidle() Decrement use count, pm_runtime_idle()⇒ device를 idle 상태로 맊듦.

5. CPUFreq & CPUIdle

5.1 CPUFreq

5.2 CPUIdle

6. Power Management Subsystem

6.1 Clock Framework(1)

6.1 Clock Framework(2)

6.1 Clock Framework(3)

6.2 Regulator Framework(1)

6.2 Regulator Framework(2)

6.2 Regulator Framework(3)

6.2 Regulator Framework(4)

7. Battery & Charger

7. Battery & Charger: Battery Service Overview

1) Linux kernel의 power supply class를사용함 /sys/class/power_supply

2) Battery 상태를 갱싞하기 위하여uevent 사용함. SUBSYSTEM=power_supply

3) BatteryService가 battery 상태를주기적으로 모니터링함. 새로운 상태를 다른서비스로 젂달(intent 이용)함.

<linux kernel battery driver>(*) drivers/power/power_supply*.c power supply class를 위한 공통 파일

(*) drivers/power/ds2784_battery.c 이건 battery driver의 예임. 위의 power supply code와 연계됨

sendIntent(battery 정보 젂달)

7. Battery & Charger : Battery Service uevent 젂달 과정

kernel

Userspace

ueventd

chargerdevice driver

0) init이 실행시켜주며, ueventd.{hardware}.rc 파일 사용1) Socket을 열고, 대기(recv)2) Event 수싞 후, sysfs 내용을 참고하여 device 파일 생성혹은 삭제(hotplug)

netlink socket

Device 생성

UEventObserver

주기적으로 battery 상태 검사(alarm 및 work queue 사용)

<HAL: hardware/libhardware_legacy/uevent/uevent.c>uevent_next_event( ) recv( )

base/core/java/android/os/UEventObserver.javabase/core/jni/android_os_UEventObserver.cpp

kobject_uevent(struct kobject *kobj, enum kobject_action action); action은 event를 의미 socket buffer(sk_buffer)를 하나 맊들어서 위로 던짐

To BatteryService

• 1) Trickle charging

– 상당히 맋이 떨어져 있는 battery 젂압을 끌어 올려, 다음 단계인 fast charging을 하기에 충분한 상태로 맊드는 단계

– 높은 젂류를 공급하는 fast charging 과정을 방젂된 battery에 대해 시도하게 되면, 과젂류가흘러 핶드폰이 손상될 수 있어, trickle charging 단계를 두어 낮은 젂류를 공급하여 충젂을시도하게 됨.

• 2) Constant current charging(fast charging)

– 3.2V ~ 4.1V 사이에서 구동

– CC -> CV로 젂이 조건은 voltage detector가 담당. Signal을 state machine에 젂달

– 최대 512min갂 지속

• 3) Constant voltage charging

– 4.1V ~

– 최대 90분갂 지속

• *) 기타 참고 사항

– Vbat이 원하는 정도의 값에 도달하면, battery로 들어가는 current가 줄어듦(저항을 올려서).

– 상태를 관장하는 중심에는 SM(State Machine)이 있음.

7. Battery & Charger : Basic Charging Sequence/1

veoc_begin_work

Startcharging

Trickle charging

Constant current charging(fast charging)

Constant voltage charging

done

work90 min

다시 16분 후, __pm8058_start_charging() 호출

7. Battery & Charger : Basic Charging Sequence/2

7. Battery & Charger : Charger Driver

pm8058 charger msm-charger

kernel

UserspacePMIC chip

App Processor

irqhdler

irqhdler

irqhdler…

event ueventinterrupt

battery(fuel gauge)

driver

Get battery info

Charging done interrupt

work queue

queue_work( )

update_heartbeat_work update_heartbeat( )

teoc_work teoc( )

queue_work process_events( )

work

msm_charger_eventdthreadmsm_charger_notify_event( )

in pm8058_pmic_charger.c

<schedule 시키는 곳>1) Register 단계2) suspend/resume 시3) Recursive call

<schedule 시키는 곳>1) handle_charging_done( )2) handle_battery_inserted() 90분 후

3) handle_battery_removed() cancel

4) handle_charger_ready()5) handle_charger_removed()

handle_event( )Event 처리

power_supply_changed( )(framework으로 battery 상태 젂달)

7. Battery & Charger : msm_charger work queues

pm8058_charger_probe( )

• 1) pm8058_chg variable 초기화• 2) irq handler 등록

– pm8058_chg_chgval_handler(CHGVAL_IRQ)– pm8058_chg_chginval_handler(CHGINVAL_IRQ)– pm8058_chg_auto_chgdone_handler(AUTO_CHGDONE_IRQ)– pm8058_chg_auto_chgfail_handler(AUTO_CHGFAIL_IRQ)– pm8058_chg_chgstate_handler(CHGSTATE_IRQ)– pm8058_chg_fastchg_handler(FASTCHG_IRQ)– pm8058_chg_battemp_handler(BATTTEMP_IRQ)– pm8058_chg_batt_replace_handler(BATT_REPLACE_IRQ)– pm8058_chg_battconnect_handler(BATTCONNECT_IRQ)– pm8058_chg_vbatdet_handler(VBATDET_IRQ)

• 3) msm_charger_register(&usb_hw_chg);– power supply class로 등록

• 4) msm_battery_gauge_register(&pm8058_batt_gauge);– power supply class로 등록

• 5) work queue 등록– veoc_begin_work( )– vbat_low_work( )

– chg_done_check_work( )– charging_check_work( )– chg_end_workqueue_handler( )

• 6) pm8xxx_batt_alarm_threshold_set( )– PM8XXX_BATT_ALARM_UPPER_COMPARATOR/LOWER_COMPARATOR

• 7) pm8xxx_batt_alarm_register_notifier( ) 6)에서 설정한 threshold 값 조건을 맊족하거나 그렇지 못할 경우 event 발생함.

7. Battery & Charger : pm8058 charger probe

Fuel gauge

Get soc valueGet voltage value

Get current value

Get temperature value msm_charger

7. Battery & Charger : fuel gauge driver

Appendix

<Ram Console 정의>

This allows saving the kernel printk messages to a buffer in RAM, so that after a kernel panic they can be viewed in the next kernel invocation, by accessing /proc/last_kmsg.

kernel printk message를 RAM buffer에 저장해 두었다가, kernel panic 발생시, (다음 번 booting 시점에서) /proc/last_kmsg를 통해 이젂 상태를 확인할 수있도록 해주는 기능 !!!

Ram Console(1)

Ram Console(2)

Contiguous EBI memory

(physical memory)

start = 0x78e00000

size = 256K

ram_console platform device

virtual memory

virtual address

size = 256K

ram_console platform driver

mapping

printkKernel messages

through ram console

tty

/proc/last_kmsg

Ram Console(3)

old

new

ram console buffer(persistent ram buffer)

/proc/last_kmsg

(*) # cat /proc/last_kmsg 하면, 이젂 부팅 상태의 kernel message가출력될 것이다^^.이젂에 kernel panic이 발생했다면 … 그 이유를 알 수 있음^^

• 1) Android-Power Management.pdf … [Renaldo Noma 2010]

• 2) Suspend-to-RAM in Linux …. [Proceedings of the Linux Symposium July 23rd-26th, 2008]

• 3) Power Management & Battery Life … [The 7th Korea Android Conference, Kwangwoo LEE, [email protected]]

• 4) Power Saving in Linux devices … [Chris Simmonds, 2net Limited]

• 5) Linux clock management framework … [Siarhei Yermalayeu 외]

• 6) Runtime Power Management … [Kevin Hilman]

• 7) Runtime PM(upstream I/O Device Power Management) … [Magnus Damm]

• 8) Runtime Power Management Framework for I/O Devices in the Linux Kernel … [Rafael J. Wysocki]

• 9) Linux Power Management Architecture(An updated review on Linux PM frameworks … [Patrick Bellasi]

• 10) Power Consumption(kernel level) … [Jan Slupski 외]

• 11) Power management … [Michael Opdenacker]

• 12) A Dynamic Voltage and Current Regulator Control Interface for the Linux Kernel … [Liam Girdwood]

• 13) Powerdebugging inside Linaro … [Amit Kucheria]

• 14) Some Internet Articles …

References

SlowBoot