전원 관리 프레임워크 (Power Management)

Linux 커널 PM 서브시스템 아키텍처, 시스템 절전(s2idle/S3/hibernate), cpuidle, 런타임 PM, dev_pm_ops, PM 도메인, PM QoS, Energy Model, powercap/RAPL, Regulator 종합 가이드.

관련 표준: ACPI 6.5 (전원 상태 G/S/D/C/P-states), Intel SDM (전력 관리 MSR) — 커널 PM 서브시스템이 구현하는 전원 관리 규격입니다. 종합 목록은 참고자료 — 표준 & 규격 섹션을 참고하세요.
교차 참조: ACPI G/S/D-state 및 열 관리는 ACPI 심화, cpufreq/governors/P-State은 ktime / Clock 심화, 전력 MSR/HWP는 MSR 레지스터, PCI D-state/ASPM은 PCI / PCIe 페이지를 참조하십시오.
전제 조건: 커널 아키텍처(하드웨어 추상화)와 인터럽트(wakeup 이벤트)를 먼저 읽으세요.
일상 비유: 전원 관리는 건물의 에너지 관리 시스템과 같습니다. 시스템 절전(Suspend)은 퇴근 후 건물 전체 조명을 끄는 것, 런타임 PM은 비어 있는 사무실만 개별적으로 조명을 끄는 것, cpuidle은 사용하지 않는 기계를 대기 모드로 전환하는 것, Hibernate는 모든 상태를 기록한 뒤 완전히 전원을 차단하는 것입니다.

핵심 요약

  • Suspend(S3) — RAM에 상태를 유지한 채 CPU/디바이스 전원을 끄는 절전 모드입니다.
  • Hibernate(S4) — RAM 내용을 디스크에 저장하고 완전 전원 차단. 복원 시 디스크에서 복구합니다.
  • 런타임 PM — 개별 디바이스를 사용하지 않을 때 자동으로 저전력 상태로 전환합니다.
  • cpuidle — idle CPU를 C-state(C0→C1→C3...)로 전환하여 전력을 절약합니다.
  • dev_pm_ops — 드라이버가 구현하는 PM 콜백 구조체. suspend/resume 등의 동작을 정의합니다.

단계별 이해

  1. 시스템 절전 체험systemctl suspend로 시스템을 S3 절전에 진입시킵니다.

    전원 버튼이나 키보드로 깨우면 모든 상태가 복원됩니다.

  2. 절전 상태 확인cat /sys/power/state로 지원되는 절전 상태를 확인합니다.

    freeze(s2idle), mem(S3), disk(hibernate) 등이 표시됩니다.

  3. 런타임 PM 확인/sys/bus/pci/devices/*/power/runtime_status로 각 PCI 디바이스의 PM 상태를 볼 수 있습니다.

    active, suspended, unsupported 중 하나입니다.

  4. 드라이버 관점 — 드라이버는 dev_pm_ops.suspend/.resume 콜백을 구현하여 절전/복원 동작을 정의합니다.

    하드웨어 레지스터 저장/복원, DMA 중단, 인터럽트 비활성화 등을 수행합니다.

PM 서브시스템 아키텍처 개요

Linux 커널의 전원 관리(PM) 코드는 여러 디렉토리에 분산되어 있으며, 시스템 레벨과 디바이스 레벨의 두 축으로 구성됩니다.

소스 트리 구조

경로역할
kernel/power/시스템 절전(suspend/hibernate), PM 코어, wakeup
drivers/base/power/디바이스 PM 인프라: dev_pm_ops, 런타임 PM, 클럭 PM
drivers/cpuidle/cpuidle 프레임워크, 거버너, 드라이버
drivers/opp/Operating Performance Points(OPP) 프레임워크
drivers/powercap/powercap 프레임워크, Intel/AMD RAPL
drivers/regulator/Regulator(전압/전류) 프레임워크
drivers/cpufreq/CPU 주파수 스케일링 (→ ktime/Clock)
drivers/thermal/열 관리 (→ ACPI)

핵심 구조체

/* include/linux/pm.h */
struct dev_pm_ops {
    int (*prepare)(struct device *dev);
    void (*complete)(struct device *dev);
    int (*suspend)(struct device *dev);
    int (*resume)(struct device *dev);
    int (*freeze)(struct device *dev);
    int (*thaw)(struct device *dev);
    int (*poweroff)(struct device *dev);
    int (*restore)(struct device *dev);
    int (*suspend_late)(struct device *dev);
    int (*resume_early)(struct device *dev);
    int (*freeze_late)(struct device *dev);
    int (*thaw_early)(struct device *dev);
    int (*poweroff_late)(struct device *dev);
    int (*restore_early)(struct device *dev);
    int (*suspend_noirq)(struct device *dev);
    int (*resume_noirq)(struct device *dev);
    int (*freeze_noirq)(struct device *dev);
    int (*thaw_noirq)(struct device *dev);
    int (*poweroff_noirq)(struct device *dev);
    int (*restore_noirq)(struct device *dev);
    int (*runtime_suspend)(struct device *dev);
    int (*runtime_resume)(struct device *dev);
    int (*runtime_idle)(struct device *dev);
};

/* include/linux/suspend.h */
struct platform_suspend_ops {
    int (*valid)(suspend_state_t state);
    int (*begin)(suspend_state_t state);
    int (*prepare)(void);
    int (*enter)(suspend_state_t state);
    void (*wake)(void);
    void (*finish)(void);
    void (*end)(void);
};

PM 서브시스템 계층 다이어그램

Userspace: /sys/power/ · powertop · turbostat · systemctl suspend System Sleep cpuidle PM QoS Energy Model powercap PM Core (kernel/power/ + drivers/base/power/) dev_pm_ops Runtime PM genpd OPP Regulator Wakeup Sources DPM List Clock PM cpufreq Thermal Platform / Hardware ACPI S-states C-states (MWAIT) P-states (HWP) PMIC / Regulators

시스템 절전 상태 (System Sleep)

Linux 커널은 세 가지 시스템 절전 상태를 지원하며, /sys/power/state를 통해 진입합니다.

절전 상태 매핑

/sys/power/state내부 상태ACPI 매핑설명
freezePM_SUSPEND_TO_IDLE (s2idle)S0 (S0ix)프로세스 동결 + 디바이스 저전력 + CPU idle. 가장 빠른 진입/복귀
memPM_SUSPEND_MEM (S2RAM)S3RAM 자체 리프레시 유지, 나머지 전원 차단. mem_sleep_default로 s2idle 대체 가능
diskPM_SUSPEND_DISK (hibernate)S4메모리 이미지를 swap에 기록 후 전원 차단. resume= 파라미터로 복원
mem_sleep_default: 최신 플랫폼(Intel Tiger Lake+, AMD Zen 3+)은 S3를 지원하지 않고 s2idle(S0ix)만 지원하는 경우가 많습니다. /sys/power/mem_sleep에서 현재 설정을 확인할 수 있습니다.

Suspend 진입 흐름

echo mem > /sys/power/state pm_suspend(state) suspend_prepare() 프로세스 동결 (freeze_processes) suspend_devices_and_enter() dpm_suspend_start() prepare → suspend 콜백 dpm_suspend_late() suspend_late 콜백 dpm_suspend_noirq() IRQ 비활성 후 suspend_noirq suspend_enter() platform→enter() / CPU offline ← 하드웨어 절전 → 웨이크업 이벤트 →

Resume 경로는 역순으로 진행됩니다: resume_noirq → resume_early → resume → complete. 각 단계에서 에러 발생 시 해당 지점부터 rollback이 이루어집니다.

Hibernate 흐름

/* Hibernate 진입 */
echo disk > /sys/power/state
  → hibernate()
    → freeze_processes()
    → dpm_suspend_start(PMSG_FREEZE)       /* 디바이스 freeze */create_image()                        /* 메모리 스냅샷 생성 */dpm_resume_end(PMSG_THAW)             /* 디바이스 복원 (이미지 쓰기용) */swsusp_write()                        /* swap 파티션에 이미지 기록 */dpm_suspend_start(PMSG_POWEROFF)      /* 디바이스 poweroff */hibernation_platform_enter()          /* ACPI S4 진입 */

/* Hibernate 복원 (부팅 시) */
커널 부팅 → resume=/dev/sdaX 파라미터 감지
  → swsusp_read()                          /* swap에서 이미지 로드 */restore_image()                        /* 메모리 복원 + 점프 */

주요 /sys/power/ 인터페이스

파일설명
/sys/power/state절전 상태 진입 (freeze, mem, disk)
/sys/power/mem_sleepmem 상태의 실제 모드 (s2idle, [deep])
/sys/power/diskhibernate 모드 (platform, shutdown, reboot, suspend, test_resume)
/sys/power/image_sizehibernate 이미지 목표 크기 (기본 RAM의 2/5)
/sys/power/wakeup_countwakeup 이벤트 카운터 (spurious wakeup 방지)
/sys/power/pm_testsuspend 테스트 모드 (none, core, processors, platform, devices, freezer)
/sys/power/suspend_statssuspend 성공/실패 통계

cpuidle 프레임워크

CPU가 실행할 작업이 없을 때, 커널은 cpuidle 프레임워크를 통해 적절한 저전력 상태(C-state)로 진입합니다. 깊은 C-state일수록 전력 절감이 크지만 복귀 지연(exit latency)도 증가합니다.

핵심 구조체

/* include/linux/cpuidle.h */
struct cpuidle_state {
    char  name[16];           /* C-state 이름 (예: "C1", "C6S") */
    char  desc[32];           /* 설명 */
    s64   exit_latency_ns;      /* 복귀 지연 (나노초) */
    s64   target_residency_ns;  /* 최소 체류 시간 */
    unsigned int flags;        /* CPUIDLE_FLAG_* */
    int (*enter)(struct cpuidle_device *dev,
               struct cpuidle_driver *drv, int index);
};

struct cpuidle_driver {
    const char *name;
    struct cpuidle_state states[CPUIDLE_STATE_MAX];
    int state_count;
    int safe_state_index;      /* BM-safe fallback state */
};

거버너 비교

거버너알고리즘적합 환경
menu예상 idle 시간 + 보정 계수 + PM QoS 제약범용 (기본값)
TEO (Timer Events Oriented)최근 타이머 이벤트 패턴 분석, 깊은 상태 적극 선택서버, 주기적 워크로드
ladderC-state를 단계적으로 승격/강등틱 기반(주로 레거시)
haltpoll짧은 busy-poll 후 halt, VM 게스트 최적화KVM 게스트

cpuidle 드라이버

드라이버플랫폼C-state 소스
intel_idleIntel 프로세서하드코딩된 MWAIT 힌트 테이블 (CPUID 기반)
acpi_idleACPI 지원 시스템ACPI _CST 메서드 (FADT C-state 정보)
psci_idle (ARM)ARM64 플랫폼PSCI cpu_suspend + DT idle-states

cpuidle 아키텍처 다이어그램

스케줄러 idle thread cpuidle_enter() Governor (menu/TEO) → 최적 C-state 선택 PM QoS 제약 확인 Driver (intel_idle) → HW 진입 (MWAIT) CPU Hardware C-state (C0 → C1 → C6 → C10)

sysfs 인터페이스

# CPU별 cpuidle 정보
/sys/devices/system/cpu/cpu0/cpuidle/state0/
    ├── name          # C-state 이름
    ├── desc          # 설명
    ├── latency       # 복귀 지연 (μs)
    ├── residency     # 최소 체류 시간 (μs)
    ├── usage         # 진입 횟수
    ├── time          # 총 체류 시간 (μs)
    ├── disable       # 0/1 (비활성화)
    └── above/below   # 이 상태보다 깊은/얕은 선택 횟수

# 현재 거버너
/sys/devices/system/cpu/cpuidle/current_governor

런타임 PM

런타임 PM은 시스템이 동작 중일 때 개별 디바이스의 전원을 동적으로 관리합니다. 사용하지 않는 디바이스를 자동으로 suspend하여 전력을 절감합니다.

상태 전환 다이어그램

RPM_ACTIVE RPM_SUSPENDING RPM_SUSPENDED RPM_RESUMING runtime_suspend() 콜백 성공 runtime_resume() 콜백 성공 abort

pm_runtime_* API

함수동작
pm_runtime_enable(dev)런타임 PM 활성화 (초기 usage_count=1이므로 필수)
pm_runtime_get_sync(dev)usage_count++ 후 동기 resume (에러 시 put 필요)
pm_runtime_put_sync(dev)usage_count-- 후 즉시 idle 검사 → suspend
pm_runtime_put_autosuspend(dev)usage_count-- 후 autosuspend 타이머 시작
pm_runtime_set_autosuspend_delay(dev, ms)autosuspend 지연 시간 설정
pm_runtime_use_autosuspend(dev)autosuspend 모드 활성화
pm_runtime_mark_last_busy(dev)마지막 사용 시각 갱신 (autosuspend 타이머 리셋)
pm_runtime_get_noresume(dev)usage_count++만 (resume 안 함)
pm_runtime_put_noidle(dev)usage_count--만 (idle 검사 안 함)
pm_runtime_forbid(dev)런타임 suspend 금지
pm_runtime_allow(dev)런타임 suspend 허용

Autosuspend 패턴

/* 디바이스 사용 시 (예: I/O 요청) */
pm_runtime_get_sync(dev);        /* resume + refcount++ */
/* ... 실제 작업 ... */
pm_runtime_mark_last_busy(dev);  /* 타이머 리셋 */
pm_runtime_put_autosuspend(dev); /* refcount--, delay 후 suspend */

드라이버 구현 예제

static int my_runtime_suspend(struct device *dev)
{
    struct my_device *priv = dev_get_drvdata(dev);
    clk_disable_unprepare(priv->clk);
    return 0;
}

static int my_runtime_resume(struct device *dev)
{
    struct my_device *priv = dev_get_drvdata(dev);
    return clk_prepare_enable(priv->clk);
}

static int my_probe(struct platform_device *pdev)
{
    struct device *dev = &pdev->dev;
    /* ... 초기화 ... */
    pm_runtime_set_autosuspend_delay(dev, 200);  /* 200ms */
    pm_runtime_use_autosuspend(dev);
    pm_runtime_set_active(dev);
    pm_runtime_enable(dev);
    return 0;
}

static void my_remove(struct platform_device *pdev)
{
    pm_runtime_disable(&pdev->dev);
    pm_runtime_set_suspended(&pdev->dev);
}

static const struct dev_pm_ops my_pm_ops = {
    RUNTIME_PM_OPS(my_runtime_suspend, my_runtime_resume, NULL)
};

런타임 PM sysfs

/sys/devices/.../power/
    ├── runtime_status     # active / suspended / suspending / resuming
    ├── runtime_usage      # usage_count
    ├── runtime_active_time
    ├── runtime_suspended_time
    ├── autosuspend_delay_ms
    └── control            # auto / on (on = 런타임 PM 강제 활성)

디바이스 PM (dev_pm_ops)

struct dev_pm_ops는 디바이스가 시스템 절전과 런타임 PM 이벤트에 응답하기 위한 22개 콜백을 정의합니다. 실제 드라이버에서는 매크로를 사용하여 간결하게 작성합니다.

콜백 전체 매핑

단계SuspendHibernate (freeze)Hibernate (restore)
prepareprepareprepareprepare
메인suspendfreezerestore
latesuspend_latefreeze_laterestore_early
noirqsuspend_noirqfreeze_noirqrestore_noirq
← 하드웨어 절전/복원 →
noirqresume_noirqthaw_noirq
earlyresume_earlythaw_early
메인resumethaw
completecompletecompletecomplete

편의 매크로

/* 시스템 PM 전용 (suspend = resume 콜백 재사용) */
DEFINE_SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn)

/* 런타임 PM + 시스템 PM (시스템 PM이 런타임 PM 콜백 재사용) */
DEFINE_RUNTIME_DEV_PM_OPS(name, suspend_fn, resume_fn, idle_fn)

/* pm_sleep_ptr() — CONFIG_PM_SLEEP 미설정 시 NULL로 최적화 */
static const struct dev_pm_ops my_pm_ops = {
    SYSTEM_SLEEP_PM_OPS(my_suspend, my_resume)
    RUNTIME_PM_OPS(my_rt_suspend, my_rt_resume, my_rt_idle)
};

static struct platform_driver my_drv = {
    .driver = {
        .name = "my-device",
        .pm   = pm_sleep_ptr(&my_pm_ops),
    },
};

DPM 리스트 순서

디바이스 PM(DPM)은 디바이스 등록 순서를 기반으로 리스트를 관리합니다. Suspend 시에는 역순(자식 → 부모), Resume 시에는 정순(부모 → 자식)으로 콜백을 호출하여 의존성을 보장합니다.

주의: noirq 콜백은 모든 IRQ가 비활성화된 상태에서 실행됩니다. 이 단계에서는 인터럽트를 사용하는 I/O(예: DMA 완료 대기)를 수행할 수 없습니다. PCI 디바이스의 경우 pci_save_state()/pci_restore_state()를 이 단계에서 호출합니다.

PM 도메인 (genpd)

Generic PM Domain(genpd)은 하나의 전력 도메인(power domain)에 속한 디바이스 그룹을 관리합니다. SoC에서 특정 하드웨어 블록의 전원을 독립적으로 켜고 끌 수 있으며, 도메인 간 계층 관계를 지원합니다.

핵심 구조체

/* include/linux/pm_domain.h */
struct generic_pm_domain {
    struct device dev;
    const char *name;
    unsigned int flags;         /* GENPD_FLAG_* */
    int (*power_on)(struct generic_pm_domain *domain);
    int (*power_off)(struct generic_pm_domain *domain);
    struct list_head parent_links;  /* 부모 도메인 링크 */
    struct list_head child_links;   /* 자식 도메인 링크 */
    struct list_head dev_list;      /* 소속 디바이스 리스트 */
};

PM 도메인 계층 다이어그램 (SoC 예시)

SoC Always-On CPU Power Domain GPU Power Domain Peripheral Domain CPU0/1 CPU2/3 GPU Core + Shader USB Domain UART Domain usb0, usb1 uart0..3 gpu0 cpu0, cpu1 cpu2, cpu3 규칙: 자식 도메인 중 하나라도 ON이면 부모도 ON 유지

genpd API

/* Provider 등록 */
pm_genpd_init(genpd, gov, is_off);       /* 도메인 초기화 */
pm_genpd_add_subdomain(parent, child);  /* 계층 관계 설정 */
of_genpd_add_provider_onecell(np, data); /* DT provider 등록 */

/* Consumer 연결 (DT 기반 자동) */
dev_pm_domain_attach(dev, true);        /* 디바이스를 도메인에 연결 */
dev_pm_domain_detach(dev, true);        /* 디바이스를 도메인에서 분리 */

Device Tree 바인딩

/* Provider (SoC DTSI) */
power_domains: power-controller@10000 {
    compatible = "vendor,soc-power-domains";
    #power-domain-cells = <1>;
};

/* Consumer (디바이스 노드) */
usb@20000 {
    compatible = "vendor,usb-controller";
    power-domains = <&power_domains 3>; /* domain index 3 */
};

PM QoS (Quality of Service)

PM QoS는 전원 관리 결정에 성능 제약 조건을 부과하는 프레임워크입니다. 디바이스나 서브시스템이 최소 응답 시간을 요구하면, cpuidle 거버너가 이 제약을 존중하여 깊은 C-state 진입을 제한합니다.

QoS 유형

유형인터페이스영향
CPU latency QoS/dev/cpu_dma_latency시스템 전체 최대 허용 C-state exit latency 제한
디바이스 PM QoS (latency)per-device sysfs개별 디바이스의 resume latency 제한
디바이스 PM QoS (flags)per-device sysfsNO_POWER_OFF 등 디바이스별 PM 정책
Frequency QoScpufreq 내부최소/최대 CPU 주파수 제한

API

/* CPU latency QoS (글로벌) */
struct pm_qos_request req;
cpu_latency_qos_add_request(&req, 50);  /* 최대 50μs latency 요구 */
cpu_latency_qos_update_request(&req, 100);
cpu_latency_qos_remove_request(&req);

/* 디바이스 PM QoS */
dev_pm_qos_add_request(dev, &req, DEV_PM_QOS_RESUME_LATENCY, 100);
dev_pm_qos_update_request(&req, 200);
dev_pm_qos_remove_request(&req);

cpuidle 연동

cpuidle 거버너(menu/TEO)는 매 idle 진입 시 cpuidle_governor_latency_req()를 호출하여 현재 유효한 최소 latency 제약을 확인합니다. exit_latency가 이 제약을 초과하는 C-state는 선택 후보에서 제외됩니다.

# 사용자 공간에서 latency 제약 설정
# /dev/cpu_dma_latency에 4바이트 LE 값 쓰기
# fd를 열고 있는 동안만 제약 유효
exec 3> /dev/cpu_dma_latency
printf '\x32\x00\x00\x00' >&3  # 50μs 제약
# ... 작업 수행 ...
exec 3>&-  # fd 닫기 → 제약 해제

Wakeup Sources

Wakeup source는 시스템을 절전 상태에서 깨울 수 있는 이벤트 소스를 추적합니다. 진행 중인 wakeup 이벤트가 있으면 suspend 진입을 중단(abort)합니다.

wakeup_source API

/* 디바이스에 wakeup capability 설정 */
device_init_wakeup(dev, true);    /* wakeup source 등록 + capable 설정 */
device_set_wakeup_enable(dev, true);

/* Wakeup 이벤트 보고 */
pm_wakeup_event(dev, msec);       /* msec 동안 suspend 방지 */
pm_stay_awake(dev);               /* suspend 방지 시작 */
pm_relax(dev);                    /* suspend 방지 해제 */
__pm_wakeup_event(ws, msec);      /* wakeup_source 직접 사용 */

wakeup_count 메커니즘

Suspend 진입 시 wakeup_count를 사용하면 race condition을 방지할 수 있습니다:

# 1. 현재 wakeup count 읽기
count=$(cat /sys/power/wakeup_count)

# 2. 같은 값을 다시 쓰기 (이 사이에 wakeup이 발생했으면 실패)
echo $count > /sys/power/wakeup_count || exit 1

# 3. suspend 진입 (wakeup 발생 시 즉시 abort)
echo mem > /sys/power/state

sysfs 인터페이스

# 디바이스별 wakeup 정보
/sys/devices/.../power/
    ├── wakeup            # enabled / disabled
    └── wakeup_count      # 디바이스의 wakeup 이벤트 횟수

# 전역 wakeup source 목록
/sys/class/wakeup/wakeup*/
    ├── name              # wakeup source 이름
    ├── active_count      # 활성화 횟수
    ├── event_count       # 총 이벤트 수
    ├── wakeup_count      # 실제 시스템 wakeup 횟수
    ├── expire_count      # 타임아웃 만료 횟수
    ├── active_time_ms    # 총 활성 시간
    ├── total_time_ms     # 총 시간
    ├── max_time_ms       # 최대 단일 활성 시간
    ├── last_change_ms    # 마지막 상태 변경
    └── prevent_suspend_time_ms
autosleep: /sys/power/autosleepmem을 쓰면 시스템은 wakeup 이벤트가 없을 때 자동으로 suspend에 진입합니다. Android에서 널리 사용됩니다.

Android 전원 관리

Android의 전원 관리는 커널의 wakeup source/autosleep 메커니즘을 핵심으로 사용한다. 초기 Android의 wakelocks는 out-of-tree 패치였으나, 커널 3.5에서 PM wakeup sources로 통합되었다.

Android 용어커널 메커니즘역사
WakeLock (Java API)wakeup_source + autosleepwakelocks → PM wakeup sources (3.5+)
Doze 모드alarm_timer + suspendAndroid 6.0+, 유휴 시 앱 활동 제한
App Standby Bucketscgroup freezer + cpusetAndroid 9+, 앱 사용 빈도별 차등 제한
/* Android WakeLock → 커널 wakeup_source 매핑 */
# /sys/power/wake_lock에 쓰기 → 유저스페이스 wakeup_source 생성
# PowerManager.WakeLock.acquire() → 최종적으로 여기에 도달
echo my_wakelock > /sys/power/wake_lock   # suspend 방지
echo my_wakelock > /sys/power/wake_unlock  # suspend 허용

/* UCLAMP: Android의 Power HAL이 태스크별 util 힌트를 설정 */
# foreground 앱: 높은 uclamp.min으로 성능 보장
# background 앱: 낮은 uclamp.max로 전력 절약
# EAS(Energy Aware Scheduling)가 util 힌트를 기반으로 에너지 효율적 코어 선택

Android의 Power HAL, UCLAMP, cgroup 기반 에너지 관리 등 심화 내용은 Android 커널 — 프로세스 모델을 참고하라.

Energy Model & EAS

Energy Model(EM)은 CPU의 주파수-전력 관계를 모델링하고, EAS(Energy Aware Scheduling)는 이 정보를 활용하여 태스크를 에너지 효율적인 CPU에 배치합니다.

핵심 구조체

/* include/linux/energy_model.h */
struct em_perf_state {
    unsigned long frequency;  /* kHz */
    unsigned long power;      /* mW (또는 추상 단위) */
    unsigned long cost;       /* 에너지 비용 (내부 계산) */
    unsigned long flags;
};

struct em_perf_domain {
    struct em_perf_state *table;
    int nr_perf_states;
    unsigned long cpus[];      /* cpumask */
};

EAS 활성화 조건

EAS 태스크 배치 흐름

find_energy_efficient_cpu(p, prev_cpu, sd_flag)
  → 각 performance domain에 대해:
    → 각 CPU에 태스크를 가상 배치
    → em_cpu_energy()로 에너지 소비 계산
    → compute_energy(): Σ(OPP_power × utilization / capacity)
  → 에너지가 최소인 CPU 선택
  → 이전 CPU 대비 6% 이상 절감 시에만 마이그레이션

EM + EAS 연동 다이어그램

cpufreq driver Energy Model freq → power 테이블 OPP Framework CFS Scheduler EAS (find_eec) schedutil 등록 em_cpu_energy() 주파수 결정

OPP 프레임워크

OPP(Operating Performance Points)는 디바이스가 동작할 수 있는 전압-주파수 조합을 관리합니다. cpufreq, devfreq, Energy Model 등이 OPP 테이블을 참조하여 동적 전압/주파수 스케일링(DVFS)을 수행합니다.

dev_pm_opp API

함수설명
dev_pm_opp_add(dev, freq, u_volt)동적 OPP 추가
dev_pm_opp_remove(dev, freq)OPP 제거
dev_pm_opp_find_freq_ceil(dev, &freq)freq 이상인 최소 OPP
dev_pm_opp_find_freq_floor(dev, &freq)freq 이하인 최대 OPP
dev_pm_opp_get_voltage(opp)OPP의 전압 반환
dev_pm_opp_get_freq(opp)OPP의 주파수 반환
dev_pm_opp_set_rate(dev, freq)주파수 설정 (전압 자동 조정)
dev_pm_opp_of_add_table(dev)DT에서 OPP 테이블 로드

Device Tree OPP 테이블

cpu_opp_table: opp-table {
    compatible = "operating-points-v2";
    opp-shared;

    opp-600000000 {
        opp-hz = /bits/ 64 <600000000>;
        opp-microvolt = <900000>;
        opp-supported-hw = <0x3>;
    };
    opp-1200000000 {
        opp-hz = /bits/ 64 <1200000000>;
        opp-microvolt = <1100000 1050000 1150000>; /* target min max */
    };
    opp-1800000000 {
        opp-hz = /bits/ 64 <1800000000>;
        opp-microvolt = <1250000>;
        turbo-mode;  /* 부스트 전용 */
    };
};

Thermal Throttling 연동

열 관리 서브시스템이 dev_pm_opp_put_clkname()과 cooling device를 통해 최대 OPP를 동적으로 제한합니다. 과열 시 상위 OPP가 비활성화되어 주파수가 자동으로 하향됩니다.

powercap & RAPL

powercap 프레임워크는 전력 상한(power capping)을 설정하는 통합 인터페이스를 제공합니다. 가장 대표적인 백엔드는 Intel/AMD의 RAPL(Running Average Power Limit)로, 프로세서 패키지·코어·메모리 등 전력 도메인별 에너지 소비를 모니터링하고 제한할 수 있습니다.

powercap/RAPL 아키텍처

RAPL은 하드웨어 MSR(또는 TPMI)에서 에너지 카운터와 전력 제한을 읽고 쓰는 커널 드라이버를 통해 powercap 프레임워크에 등록됩니다. 사용자 공간은 sysfs 또는 perf 이벤트를 통해 접근합니다.

Userspace perf stat power/ turbostat powertop /sys/class/powercap/ powercap sysfs write powercap Framework (drivers/powercap/powercap_sys.c) intel_rapl_common.c (RAPL 코어 로직) perf_event_intel_rapl.c (PMU 드라이버) powercap_zone ops perf PMU intel_rapl_msr.c intel_rapl_tpmi.c amd_energy.c Hardware MSR (606h, 610h, 619h …) TPMI (Intel Meteor Lake+) MSR (C001_0299h, Family 17h+)

RAPL 도메인

RAPL은 프로세서 내부를 여러 전력 도메인(power domain)으로 분리하여 도메인별 에너지 측정과 전력 제한을 제공합니다. 지원 도메인은 프로세서 세대에 따라 다릅니다.

도메인설명IntelAMD
package소켓 전체 (CPU + 언코어 + iGPU)Sandy Bridge+ (2세대+)Zen (Family 17h+)
core (PP0)CPU 코어만Sandy Bridge+Zen+
uncore (PP1)iGPU / 언코어클라이언트 전용 (Sandy Bridge+)
dram메모리 컨트롤러/DRAM서버 (Sandy Bridge-EP+), 클라이언트 (Haswell+)
psys플랫폼 전체 (SoC + PCH)Skylake+ (모바일/NUC)
참고: psys 도메인은 CPU뿐 아니라 PCH, 온보드 디바이스를 포함한 플랫폼 전체 전력을 측정합니다. 노트북/NUC 등 배터리 기반 시스템에서 전체 시스템 전력 예산(power budget) 관리에 유용합니다.

PL1/PL2/PL3/PL4 전력 제한 계층

RAPL은 최대 4단계의 전력 제한(Power Limit)을 제공합니다. 각 단계는 허용 전력과 시간 윈도우가 다르며, 하드웨어가 자율적으로 스로틀링을 적용합니다.

레벨명칭시간 윈도우동작 방식MSR
PL1Long-Term (장기)1~128초 (설정 가능)지속 가능한 TDP. 윈도우 내 평균 전력이 PL1 이하 유지MSR_PKG_POWER_LIMIT [14:0]
PL2Short-Term (단기)1~10ms 수준Turbo Boost 시 허용하는 순간 최대 전력. PL1의 1.2~1.5배MSR_PKG_POWER_LIMIT [46:32]
PL3Peak Power (피크)~10ms배터리 기반 시스템의 순간 피크 제한 (Kaby Lake+)MSR_PL3_CONTROL
PL4Max Power (최대)즉시하드웨어 즉시 차단 — 전류/전력 한계 초과 시 주파수 급강하MSR_VR_CURRENT_CONFIG
/* powercap sysfs에서 PL1/PL2 확인 및 설정 */

# PL1 (constraint_0) 확인
cat /sys/class/powercap/intel-rapl:0/constraint_0_name          # "long_term"
cat /sys/class/powercap/intel-rapl:0/constraint_0_power_limit_uw  # 현재 PL1 (μW)
cat /sys/class/powercap/intel-rapl:0/constraint_0_time_window_us  # 시간 윈도우 (μs)

# PL2 (constraint_1) 확인
cat /sys/class/powercap/intel-rapl:0/constraint_1_name          # "short_term"
cat /sys/class/powercap/intel-rapl:0/constraint_1_power_limit_uw

# PL1을 15W로 설정 (root 권한 필요)
echo 15000000 > /sys/class/powercap/intel-rapl:0/constraint_0_power_limit_uw
주의: PL1/PL2 값을 무리하게 높이면 과열 및 thermal throttling이 발생합니다. 반대로 PL1을 지나치게 낮추면 성능이 심각하게 저하됩니다. PL3/PL4는 대부분 BIOS/펌웨어가 설정하며 커널에서 직접 제어하지 않습니다.

powercap sysfs 인터페이스

/sys/class/powercap/intel-rapl:0/              # package-0
    ├── name                                     # "package-0"
    ├── energy_uj                                # 누적 에너지 (μJ, 읽기 전용)
    ├── max_energy_range_uj                      # 오버플로 범위
    ├── enabled                                  # 도메인 활성화 여부
    ├── constraint_0_power_limit_uw              # PL1 (장기 전력 제한, μW)
    ├── constraint_0_time_window_us              # PL1 시간 윈도우
    ├── constraint_0_name                        # "long_term"
    ├── constraint_0_max_power_uw                # PL1 최대 허용값
    ├── constraint_1_power_limit_uw              # PL2 (단기 전력 제한)
    ├── constraint_1_time_window_us
    ├── constraint_1_name                        # "short_term"
    └── constraint_1_max_power_uw
    intel-rapl:0:0/                              # core 서브도메인 (PP0)
        ├── name                                 # "core"
        └── energy_uj                            # 코어 에너지 (읽기 전용)
    intel-rapl:0:1/                              # uncore 서브도메인 (PP1)
    intel-rapl:0:2/                              # dram 서브도메인 (있는 경우)

RAPL 커널 드라이버 구조

커널의 RAPL 지원은 공통 로직과 하드웨어 백엔드로 분리된 모듈러 구조입니다.

모듈경로역할
intel_rapl_commondrivers/powercap/intel_rapl_common.cRAPL 도메인 관리, powercap zone 등록, 에너지 단위 변환, PL 읽기/쓰기 공통 로직
intel_rapl_msrdrivers/powercap/intel_rapl_msr.cMSR 기반 백엔드 — 대부분의 Intel/AMD CPU. rdmsr/wrmsr로 RAPL MSR 접근
intel_rapl_tpmidrivers/powercap/intel_rapl_tpmi.cTPMI(Topology Aware Register and PM Capsule Interface) 백엔드 — Meteor Lake+ MMIO 기반
amd_energydrivers/hwmon/amd_energy.cAMD Zen hwmon 드라이버 (powercap 미사용, hwmon으로 에너지 노출)
/* intel_rapl_common.c — 핵심 구조체 */
struct rapl_domain {
    const char          *name;
    enum rapl_domain_type id;        /* RAPL_DOMAIN_PACKAGE, PP0, PP1, DRAM, PLATFORM */
    u64                  energy_unit;  /* 에너지 단위 (MSR_RAPL_POWER_UNIT에서 파생) */
    u64                  power_unit;   /* 전력 단위 */
    struct powercap_zone power_zone;  /* powercap 프레임워크 zone */
    struct rapl_package  *rp;         /* 소속 패키지 */
};

struct rapl_package {
    unsigned int          id;          /* 패키지(소켓) ID */
    unsigned int          nr_domains;  /* 이 패키지의 도메인 수 */
    struct rapl_domain    *domains;    /* 도메인 배열 */
    struct rapl_if_priv  *priv;       /* 백엔드별 private 데이터 */
};
# RAPL 모듈 로드 확인
lsmod | grep rapl
# intel_rapl_msr         20480  0
# intel_rapl_common      36864  1 intel_rapl_msr
# powercap               16384  1 intel_rapl_common

# 에너지 단위 확인 (MSR_RAPL_POWER_UNIT, 606h)
rdmsr 0x606
# 결과 해석: bits[12:8]=에너지 단위, bits[3:0]=전력 단위, bits[19:16]=시간 단위

TPMI (Topology Aware Register and PM Capsule Interface)

TPMI는 Intel Meteor Lake(클라이언트, 2023) 및 Sapphire Rapids(서버, 4세대 Xeon) 이후 도입된 MMIO 기반 PM 레지스터 인터페이스입니다. PCIe 표준 기반의 아키텍처 모델로 설계되어, 기존 MSR의 모델별 코드 유지보수 부담을 줄이고 멀티 다이/칩렛 아키텍처에서 다이별(per-die) 세밀한 전력 관리를 지원합니다. Granite Rapids(Xeon 6 P-core), Sierra Forest(Xeon 6 E-core), Clearwater Forest 등 후속 세대에서 전면 채택되었습니다.

핵심 차이: MSR은 CPU별(rdmsr/wrmsr) 직렬 접근이지만, TPMI는 PCI MMIO BAR를 통해 토폴로지 인식(topology-aware) 병렬 접근이 가능합니다. RAPL뿐 아니라 SST, Uncore 주파수 제어, 성능 제한 사유(PLR) 등 다양한 PM 기능이 TPMI를 통해 통합 제공됩니다.

TPMI vs MSR 비교

항목MSR 방식TPMI 방식
접근 방식rdmsr/wrmsr (CPU 명령어)MMIO (readq/writeq, PCI BAR 매핑)
토폴로지CPU별 (per-CPU), IPI로 원격 CPU 접근다이별 (per-die), 직접 MMIO 매핑
확장성다이 수 증가 시 MSR 주소 충돌 우려PCI VSEC + PFS로 동적 열거, 다이별 독립 주소 공간
병렬 접근MSR 접근은 직렬화 (serialize)서로 다른 다이의 MMIO에 동시 접근 가능
기능 발견CPUID + MSR 존재 여부 수동 확인PFS(PM Feature Structure)로 자동 열거
디바이스 모델직접 MSR 접근, 플랫폼 디바이스 없음PCI auxiliary 디바이스로 등록, 표준 드라이버 모델
유지보수CPU 모델별 MSR 테이블 유지 필요아키텍처 인터페이스 — 세대 간 호환 유지
토폴로지 계층소켓 → CPU (flat)소켓 → 다이 → 전력 도메인 → 패브릭 클러스터
지원 범위Sandy Bridge (2011) 이후 전 세대Meteor Lake/Sapphire Rapids (2023) 이후

TPMI 아키텍처

TPMI는 PCI VSEC(Vendor Specific Extended Capability, ID=66)를 통해 발견됩니다. Intel VSEC 드라이버(intel_vsec.c)가 OOB(Out-of-Band) PCI 디바이스의 VSEC/DVSEC 구조를 스캔하여 TPMI를 감지하면, auxiliary 버스에 TPMI 코어 디바이스를 생성합니다. TPMI 코어는 VSEC 헤더의 tBIR(BAR Indicator Register) 필드로 대상 PCI BAR를 식별하고, Address 필드로 BAR 내 PFS 시작 오프셋을 계산합니다.

PCI 열거 단계 PCI VSEC (Vendor Specific) intel_vsec.c (VSEC 드라이버) PCI BAR → MMIO 매핑 TPMI 코어 (drivers/platform/x86/intel/tpmi.c) PFS 파싱 → 기능별 auxiliary 디바이스 생성 PFS (PM Feature Structure) 테이블 Feature ID | MMIO 오프셋 | 크기 | 잠금 상태 — 다이별 독립 엔트리 TPMI Feature 드라이버 (auxiliary_device) intel_rapl_tpmi ID=0 (RAPL) isst_tpmi ID=5 (SST) uncore-freq-tpmi ID=2 (UFS) tpmi_plr ID=8 (PLR) tpmi_power_domains ID=12 (PWR DMN) 사용자 공간 인터페이스 powercap sysfs (RAPL) isst_if sysfs (SST) uncore-freq sysfs debugfs (PLR) Hardware (Meteor Lake+ SoC) Compute Die 0: TPMI MMIO Region (BAR) Compute Die 1: TPMI MMIO Region (BAR) RAPL regs SST regs RAPL regs SST regs

PCI VSEC 발견 및 PFS 파싱

TPMI는 PCIe 설정 공간의 VSEC(Vendor Specific Extended Capability)를 통해 발견됩니다. Intel VSEC 드라이버(intel_vsec.c)가 TPMI 타입의 VSEC를 감지하면 TPMI 코어 드라이버를 로드하고, TPMI 코어는 MMIO에 매핑된 PFS(PM Feature Structure) 테이블을 파싱합니다.

/* PFS (PM Feature Structure) 엔트리 — 하드웨어 비트필드 레이아웃 */
/* drivers/platform/x86/intel/vsec_tpmi.c (커널 6.13+, 이전: tpmi.c) */
struct intel_tpmi_pfs_entry {
    u64 tpmi_id:8;       /* PM 기능 식별자 (0=RAPL, 2=UFS, 5=SST ...) */
    u64 num_entries:8;  /* 인스턴스 수 (전력 도메인/다이 수와 대응) */
    u64 entry_size:16;  /* 인스턴스 MMIO 블록 크기 (32비트 워드 단위) */
    u64 cap_offset:16;  /* PM_Features 베이스로부터 오프셋 (KB 단위) */
    u64 attribute:2;    /* 속성 플래그 (읽기 전용, 잠금 등) */
    u64 reserved:14;
} __packed;

/* TPMI 코어의 PFS 파싱 흐름 */
tpmi_pfs_init(tpmi_info):
    /* 1. PCI BAR0에서 PFS 헤더 읽기 */
    pfs_start = devm_ioremap_resource(dev, &pci_resource);

    /* 2. PFS 엔트리 순회하며 기능 열거 */
    for (i = 0; i < pfs_count; i++) {
        read_pfs_entry(&pfs[i]);
        /* 3. 기능별 MMIO 영역 매핑 */
        feature_mem = pfs_start + pfs[i].cap_offset;
        /* 4. auxiliary 디바이스 생성 (intel_rapl_tpmi, isst_tpmi 등) */
        intel_vsec_add_aux(dev, NULL, &feature_info, name);
    }

TPMI Feature ID 매핑

각 PM 기능은 고유한 TPMI ID를 가지며, PFS 테이블에서 이 ID를 통해 발견됩니다. 커널은 ID에 따라 해당 feature 드라이버의 auxiliary 디바이스를 생성합니다.

ID이름커널 드라이버설명
0RAPLintel_rapl_tpmiMMIO 기반 RAPL 도메인 — 에너지 측정 및 전력 제한
1PEM(커널 내부)Performance and Energy Monitoring — 성능/에너지 모니터링
2UFSuncore-freq-tpmiUncore Frequency Scaling — 다이별 언코어 주파수 제어
5SSTisst_tpmiIntel Speed Select Technology — PP/BF/TF/CP 프로파일
8PLRtpmi_plrPerformance Limit Reasons — 스로틀링 원인 보고 (debugfs)
10UMSuncore-freq-tpmiUncore Mesh/SoC 주파수 제어
12PWR_DMNtpmi_power_domains전력 도메인 파티셔닝
0x81INFO(TPMI 코어 내부)CPU↔PCI 토폴로지 매핑 (패키지 ID, PCI BDF). 실제 PM 기능이 아닌 메타 정보
참고: TPMI_INFO_ID(0x81)는 CPU 소켓과 PCI 디바이스 간의 매핑 정보를 제공하는 특수 pseudo-feature입니다. TPMI 코어가 이 정보를 읽어 intel_tpmi_plat_infopackage_id와 PCI BDF를 채웁니다.

TPMI 코어 구조체

/* include/linux/intel_tpmi.h — TPMI API 핵심 구조체 */

/* Feature 드라이버가 TPMI 코어에서 받는 플랫폼 정보 */
struct intel_tpmi_plat_info {
    u8  package_id;        /* CPU 소켓(패키지) ID */
    u8  bus_number;        /* PCI 버스 번호 */
    u8  device_number;     /* PCI 디바이스 번호 */
    u8  function_number;   /* PCI 펑션 번호 */
    u8  segment;           /* PCI 세그먼트 ID */
    u8  partition;          /* 패키지 파티션 ID */
    u16 cdie_mask;          /* 현재 파티션의 컴퓨트 다이 비트맵 */
};

/* TPMI 코어 내부 — 디바이스별 기능 관리 */
struct intel_tpmi_info {
    struct auxiliary_device *vsec_dev;    /* 부모 VSEC auxiliary 디바이스 */
    int                   feature_count;  /* 발견된 PM 기능 수 */
    struct intel_tpmi_pm_feature *tpmi_features; /* PM 기능 배열 */
};

/* PM 기능 인스턴스 정보 */
struct intel_tpmi_pm_feature {
    struct intel_tpmi_pfs_entry pfs_header;  /* 하드웨어 PFS 헤더 */
    unsigned int                vsec_offset; /* MMIO 시작 주소 (바이트) */
    /* vsec_offset = VSEC Address + cap_offset(KB) * 1024 */
};

/* CPU↔PCI 토폴로지 매핑 헤더 (TPMI_INFO_ID=0x81에서 읽음) */
struct tpmi_info_header {
    u64 fn:3;         /* PCI Function 번호 */
    u64 dev:5;        /* PCI Device 번호 */
    u64 bus:8;        /* PCI Bus 번호 */
    u64 pkg:8;        /* CPU Package ID */
    u64 reserved:40;
} __packed;

/* Feature 드라이버가 사용하는 TPMI API (include/linux/intel_tpmi.h) */
struct intel_tpmi_plat_info *tpmi_get_platform_data(
    struct auxiliary_device *adev);     /* 플랫폼 정보 반환 */
int tpmi_get_resource_count(
    struct auxiliary_device *adev);     /* MMIO 인스턴스 수 반환 */
struct resource *tpmi_get_resource_at_index(
    struct auxiliary_device *adev,
    int index);                          /* 인덱스별 MMIO resource 반환 */
int tpmi_get_feature_status(
    struct auxiliary_device *adev,
    int feature_id,
    bool *read_blocked,
    bool *write_blocked);               /* 기능 잠금/비활성 상태 확인 */

RAPL over TPMI (intel_rapl_tpmi.c)

Meteor Lake+에서 RAPL 레지스터는 MSR 대신 TPMI MMIO를 통해 접근합니다. intel_rapl_tpmi 드라이버는 TPMI 코어에서 RAPL 기능(ID=0)의 MMIO 영역을 받아, 기존 intel_rapl_common의 powercap 프레임워크에 MMIO 백엔드로 등록합니다. 각 RAPL 도메인의 MMIO 블록 크기는 128바이트(TPMI_RAPL_DOMAIN_SIZE)이며, 각 Power Limit이 개별 레지스터를 가집니다(기존 MSR은 PL1+PL2가 하나의 64비트 MSR에 패킹).

등록 흐름: ① TPMI 코어가 PFS에서 TPMI_ID_RAPL=0 발견 → ② auxiliary 디바이스 intel_vsec.tpmi-rapl.N 생성 → ③ intel_rapl_tpmi probe → ④ tpmi_get_resource_at_index()로 MMIO 매핑 → ⑤ rapl_add_package()로 powercap zone 등록 → ⑥ /sys/class/powercap/intel-rapl:* 노출

/* intel_rapl_tpmi.c — MMIO 기반 RAPL 백엔드 */

/* TPMI RAPL MMIO 레지스터 오프셋 (MSR 주소 대신 MMIO 오프셋 사용) */
#define TPMI_RAPL_REG_HEADER          0x00
#define TPMI_RAPL_REG_UNIT            0x08   /* 에너지/전력/시간 단위 */
#define TPMI_RAPL_REG_PL1             0x10   /* Package Power Limit 1 */
#define TPMI_RAPL_REG_PL2             0x18   /* Package Power Limit 2 */
#define TPMI_RAPL_REG_PL4             0x20   /* Package Power Limit 4 */
#define TPMI_RAPL_REG_ENERGY_STATUS   0x28   /* 에너지 카운터 */
#define TPMI_RAPL_REG_PERF_STATUS    0x30   /* 성능 스로틀 상태 */
#define TPMI_RAPL_REG_POWER_INFO     0x38   /* TDP, min/max 전력 */

/* 디바이스별 RAPL TPMI 패키지 구조체 */
struct tpmi_rapl_package {
    struct rapl_if_priv          priv;       /* RAPL 인터페이스 private */
    struct intel_tpmi_plat_info *tpmi_info; /* TPMI 플랫폼 정보 */
    struct rapl_package         *rp;        /* RAPL 패키지 포인터 */
    void __iomem               *base;      /* MMIO 베이스 주소 */
};

/* MMIO 기반 읽기 — IPI 없이 직접 접근 */
static int tpmi_rapl_read_raw(int id, struct reg_action *ra)
{
    ra->value = readq(base + ra->reg.mmio_offset);
    ra->value &= ra->mask;   /* 마스크 적용 */
    return 0;
}

/* MMIO 기반 쓰기 — read-modify-write 패턴 */
static int tpmi_rapl_write_raw(int id, struct reg_action *ra)
{
    u64 val;
    val = readq(base + ra->reg.mmio_offset);
    val &= ~ra->mask;                 /* 대상 비트 클리어 */
    val |= ra->value & ra->mask;      /* 새 값 삽입 */
    writeq(val, base + ra->reg.mmio_offset);
    return 0;
}

/* rapl_if_priv — intel_rapl_common에 TPMI 백엔드 등록 */
static struct rapl_if_priv tpmi_rapl_priv = {
    .type           = RAPL_IF_TPMI,
    .read_raw       = tpmi_rapl_read_raw,
    .write_raw      = tpmi_rapl_write_raw,
    .control_type   = NULL,    /* powercap에서 설정 */
    .reg_unit       = { .mmio_offset = TPMI_RAPL_REG_UNIT },
    .regs           = {       /* 도메인별 레지스터 매핑 */
        [RAPL_DOMAIN_PACKAGE] = {
            .pl1    = { .mmio_offset = TPMI_RAPL_REG_PL1 },
            .pl2    = { .mmio_offset = TPMI_RAPL_REG_PL2 },
            .pl4    = { .mmio_offset = TPMI_RAPL_REG_PL4 },
            .energy = { .mmio_offset = TPMI_RAPL_REG_ENERGY_STATUS },
            .info   = { .mmio_offset = TPMI_RAPL_REG_POWER_INFO },
        },
    },
};
투명한 전환: TPMI 기반 RAPL은 동일한 intel_rapl_common 프레임워크를 사용하므로, 사용자 공간에서는 기존과 동일한 /sys/class/powercap/intel-rapl:* 경로로 접근합니다. MSR→TPMI 전환은 커널 내부에서 투명하게 처리됩니다.

SST (Speed Select Technology) over TPMI

Intel Speed Select Technology(SST)는 동일 CPU 내에서 코어별 차등 성능 프로파일을 제공합니다. Meteor Lake+에서 SST는 TPMI(Feature ID=5)를 통해 접근합니다.

SST 기능설명사용 사례
SST-PPPerformance Profile — 미리 정의된 주파수/TDP 프로파일 전환워크로드에 따라 코어 수 vs 주파수 트레이드오프
SST-BFBase Frequency — 특정 코어의 기본 주파수를 상향지연시간에 민감한 코어에 높은 보장 주파수 할당
SST-TFTurbo Frequency — 특정 코어에 터보 주파수 우선 배분고성능 요구 스레드에 터보 주파수 집중
SST-CPCore Power — 코어별 전력 우선순위 설정중요 코어에 전력 예산 우선 배정
# intel-speed-select CLI 도구로 SST 상태 확인
intel-speed-select --info
intel-speed-select perf-profile info        # SST-PP 프로파일 정보
intel-speed-select base-freq info           # SST-BF 지원 코어 확인
intel-speed-select turbo-freq info          # SST-TF 상태
intel-speed-select core-power info          # SST-CP 우선순위

# SST-CP로 특정 코어에 높은 우선순위 부여
intel-speed-select core-power assoc --clos 0 --core 0,1,2,3   # 고성능 그룹
intel-speed-select core-power assoc --clos 3 --core 4,5,6,7   # 저전력 그룹

Uncore 주파수 제어 over TPMI

TPMI 이전에는 Uncore 주파수가 패키지/다이 단위로만 제어 가능했습니다. TPMI(Feature ID=2)는 패브릭 클러스터(fabric cluster) 단위의 세밀한 Uncore 주파수 제어를 지원합니다.

# Uncore 주파수 토폴로지 계층 (TPMI 기반)
# Package → Die → Power Domain → Fabric Cluster

# 기존 per-die 인터페이스 (TPMI 이전에도 동일)
/sys/devices/system/cpu/intel_uncore_frequency/
    package_00_die_00/
        ├── initial_max_freq_khz    # 초기 최대 주파수
        ├── initial_min_freq_khz    # 초기 최소 주파수
        ├── max_freq_khz            # 현재 최대 주파수 (쓰기 가능)
        └── min_freq_khz            # 현재 최소 주파수 (쓰기 가능)

# TPMI 추가: 클러스터 레벨 제어
    uncore00/
        ├── package_id              # 소켓 ID
        ├── domain_id               # 전력 도메인 ID
        ├── fabric_cluster_id       # 패브릭 클러스터 ID
        ├── current_freq_khz        # 현재 실제 주파수 (읽기 전용)
        ├── max_freq_khz
        └── min_freq_khz
활용 예시: 멀티 다이 Xeon 6 서버에서 메모리 집약적 워크로드가 특정 다이에 집중된 경우, 해당 다이의 패브릭 클러스터 Uncore 주파수를 높이고 나머지를 낮추어 전력 효율을 최적화할 수 있습니다.

PLR (Performance Limit Reasons) over TPMI

PLR(Feature ID=8)은 CPU 성능이 제한(스로틀링)되는 원인을 실시간으로 보고합니다. TPMI를 통해 debugfs에 노출되며, 성능 문제 진단에 활용됩니다.

# PLR 상태 확인 (debugfs)
ls /sys/kernel/debug/tpmi-plr/
# die0/  die1/  ...

cat /sys/kernel/debug/tpmi-plr/die0/status
# 각 비트가 스로틀링 원인을 나타냄:
# - thermal: 열 제한
# - power_limit_pl1: PL1(장기 전력) 초과
# - power_limit_pl2: PL2(단기 전력) 초과
# - electrical_design_point: 전류 한계 도달
# - turbo_transition_attenuation: 터보 전환 감쇠
# - prochot: 외부 PROCHOT# 신호

# PLR 스티키 비트 클리어 (해당 파일에 0 쓰기)
echo 0 > /sys/kernel/debug/tpmi-plr/die0/status
주의: PLR은 진단 전용 인터페이스입니다. 스티키 비트는 마지막 클리어 이후 발생한 모든 스로틀링 원인을 누적하므로, 주기적으로 클리어하면서 모니터링해야 정확한 시점을 파악할 수 있습니다.

TPMI 커널 설정

# TPMI 관련 Kconfig 옵션
CONFIG_INTEL_VSEC=m            # Intel Vendor Specific Extended Capabilities (필수)
CONFIG_INTEL_TPMI=m            # TPMI 코어 드라이버
CONFIG_INTEL_RAPL_TPMI=m       # RAPL over TPMI 백엔드
CONFIG_INTEL_UNCORE_FREQ_TPMI=m  # Uncore 주파수 제어 over TPMI
CONFIG_INTEL_SPEED_SELECT_INTERFACE=m  # SST over TPMI

# 로드된 TPMI 모듈 확인
lsmod | grep tpmi
# intel_rapl_tpmi        16384  0
# intel_uncore_freq_tpmi 16384  0
# isst_tpmi              20480  0
# intel_tpmi             24576  3 intel_rapl_tpmi,intel_uncore_freq_tpmi,isst_tpmi
# intel_vsec             16384  1 intel_tpmi

# TPMI 디바이스 확인 (PCI VSEC)
lspci -d 8086: -vvv | grep -A5 "Vendor Specific"

TPMI 소스 트리 구조

파일역할
include/linux/intel_tpmi.hTPMI API 헤더 — Feature ID 상수, 플랫폼 정보 구조체, 헬퍼 함수
drivers/platform/x86/intel/vsec.cPCI VSEC 드라이버 — TPMI 타입 감지 및 코어 디바이스 생성
drivers/platform/x86/intel/tpmi.cTPMI 코어 — PFS 파싱, MMIO 매핑, auxiliary 디바이스 생성, debugfs (커널 6.13+에서 vsec_tpmi.c로 개명)
drivers/powercap/intel_rapl_tpmi.cRAPL TPMI 백엔드 — MMIO 기반 에너지/전력 레지스터 접근
drivers/platform/x86/intel/uncore-frequency/Uncore 주파수 제어 (TPMI + MSR 백엔드)
drivers/platform/x86/intel/speed_select_if/SST 인터페이스 (TPMI + MMIO + MSR 백엔드)

TPMI debugfs 인터페이스

TPMI 코어 드라이버는 debugfs를 통해 PFS 테이블 덤프와 Feature별 MMIO 원시 읽기/쓰기를 제공합니다. 주로 디버깅과 펌웨어 설정 확인에 사용됩니다.

# TPMI debugfs 구조
/sys/kernel/debug/tpmi-<N>/
    ├── pfs_dump                     # PFS 테이블 전체 엔트리 출력
    ├── tpmi-id-<feature_id>/
    │   ├── mem_dump                 # Feature MMIO 영역 원시 덤프 (읽기 전용)
    │   └── mem_write                # 특정 오프셋에 MMIO 쓰기 (디버그용)
    └── ...

# PFS 엔트리 확인 (어떤 PM 기능이 지원되는지)
cat /sys/kernel/debug/tpmi-0/pfs_dump

# RAPL MMIO 레지스터 원시 값 확인
cat /sys/kernel/debug/tpmi-0/tpmi-id-0/mem_dump

TPMI 커널 머지 타임라인

커널 버전TPMI 마일스톤
6.3TPMI 기본 열거 드라이버 병합 (tpmi.c)
6.4RAPL TPMI 드라이버 (intel_rapl_tpmi.c) 병합
6.5Uncore 주파수 TPMI 지원, SST via TPMI
6.5~6.6TPMI debugfs, 기능 잠금 상태 인터페이스
6.6+CPU 토폴로지/도메인 매핑, 클러스터 레벨 제어
6.13드라이버 tpmi.cvsec_tpmi.c 개명, Clearwater Forest ID 추가

AMD RAPL 지원

AMD는 Zen 아키텍처(Family 17h, Ryzen 1000/EPYC 7001) 이후로 RAPL 호환 MSR을 제공합니다. 커널 intel_rapl_msr 드라이버가 AMD CPU도 지원하여 동일한 powercap sysfs 인터페이스로 접근 가능합니다.

항목Intel RAPLAMD RAPL
지원 시작Sandy Bridge (2세대, 2011)Zen (Family 17h, 2017)
도메인package, core, uncore, dram, psyspackage, core (Zen 2+에서 확장)
MSR 주소606h, 610h, 611h, 619h, 641h 등C001_0299h (core), C001_029Ah (pkg) 등
전력 제한 쓰기PL1/PL2 쓰기 가능읽기 전용 (에너지 측정만, 전력 제한 설정 불가)
커널 드라이버intel_rapl_msr / intel_rapl_tpmiintel_rapl_msr (AMD 지원 포함)
perf 이벤트power/energy-pkg,cores,ram/power/energy-pkg,cores/
참고: AMD의 RAPL MSR은 에너지 측정(energy counter)만 지원하며, Intel처럼 전력 상한(power limit)을 설정할 수 없습니다. AMD 시스템에서 전력 제한은 BIOS/UEFI의 PPT(Package Power Tracking) 설정이나 amd_pstate 드라이버의 EPP(Energy Performance Preference)를 통해 관리합니다.

perf 전력 이벤트 및 모니터링 도구

# RAPL 전력 측정 (perf) — 5초간 에너지 소비 측정
perf stat -e power/energy-pkg/,power/energy-cores/,power/energy-ram/ sleep 5

# 특정 프로세스의 전력 소비 프로파일링
perf stat -e power/energy-pkg/,power/energy-cores/ -- make -j$(nproc)

# turbostat — 실시간 전력/주파수/온도 모니터링
turbostat --show Package,Core,CPU,Avg_MHz,Busy%,PkgWatt,CorWatt,RAMWatt --interval 1

# powertop — 전력 소비 분석 + 절전 추천
powertop --auto-tune    # 자동 절전 최적화 적용
powertop --csv=report.csv --time=30   # 30초 측정 후 CSV 리포트

# powercap 에너지 직접 읽기 (커스텀 스크립트용)
E1=$(cat /sys/class/powercap/intel-rapl:0/energy_uj)
sleep 5
E2=$(cat /sys/class/powercap/intel-rapl:0/energy_uj)
echo "5초간 소비: $(( (E2 - E1) / 1000000 )) J, 평균: $(( (E2 - E1) / 5000000 )) W"

RAPL 정확도·보안·제한사항

보안 경고 — PLATYPUS 공격 (CVE-2020-8694, CVE-2020-8695): RAPL 에너지 카운터의 높은 해상도를 악용하여 비특권 프로세스가 AES 키 등 민감한 데이터를 추출할 수 있는 사이드 채널 공격이 2020년에 공개되었습니다. 이에 따라 Linux 커널 5.10+에서는 energy_uj 및 perf power 이벤트 접근에 CAP_SYS_RAWIO 또는 root 권한이 필요하도록 변경되었습니다.
항목설명
에너지 해상도약 15.3μJ (2-16 J × 에너지 단위). 실제 정확도는 ±5~10% 수준으로 절대 전력 측정보다는 상대 비교에 적합
카운터 오버플로32비트 에너지 카운터는 max_energy_range_uj 도달 시 0으로 랩어라운드. 고부하 서버에서 ~60초마다 발생 가능 — 폴링 간격 주의
접근 권한 (5.10+)/sys/class/powercap/*/energy_uj: root 또는 CAP_SYS_RAWIO. perf power 이벤트: perf_event_paranoid ≤ 0 또는 CAP_PERFMON
가상화 환경VM에서는 RAPL MSR 접근이 차단됨 (hypervisor가 trap). KVM -cpu host로 패스스루 가능하나 보안상 비권장
컨테이너cgroup v2의 perf 이벤트 네임스페이스와 결합하여 컨테이너별 에너지 측정 가능 (Kepler 프로젝트 등 활용)
# 현재 perf 접근 권한 확인
cat /proc/sys/kernel/perf_event_paranoid
# 4: 모든 perf 이벤트 제한 (기본값, 일부 배포판)
# 2: 커널 이벤트 제한 (기본값)
# 1: CPU 이벤트 제한
# 0: 제한 없음
# -1: 모든 접근 허용

# RAPL 에너지 읽기가 Permission denied인 경우
sudo sysctl kernel.perf_event_paranoid=0  # 임시 해제 (재부팅 시 초기화)

# 오버플로 범위 확인
cat /sys/class/powercap/intel-rapl:0/max_energy_range_uj
# 예: 262143328850 (≈262 kJ, 150W 시 ~29분마다 오버플로)

Regulator 프레임워크

참고: Regulator 프레임워크는 주로 ARM/SoC 임베디드 플랫폼에서 PMIC(Power Management IC)를 제어하는 데 사용됩니다. x86 데스크톱/서버에서는 ACPI 또는 EC(Embedded Controller)가 전압 관리를 대신합니다.

Consumer / Provider 모델

/* Consumer API — 디바이스 드라이버에서 전원 요청 */
struct regulator *reg = devm_regulator_get(dev, "vdd");
regulator_enable(reg);
regulator_set_voltage(reg, 1800000, 1800000);  /* 1.8V */
regulator_disable(reg);

/* Provider — PMIC 드라이버에서 regulator 등록 */
static const struct regulator_ops my_ops = {
    .enable          = my_enable,
    .disable         = my_disable,
    .set_voltage_sel = my_set_voltage,
    .get_voltage_sel = my_get_voltage,
    .list_voltage    = regulator_list_voltage_linear,
};

static const struct regulator_desc my_desc = {
    .name       = "LDO1",
    .ops        = &my_ops,
    .type       = REGULATOR_VOLTAGE,
    .min_uV     = 800000,
    .uV_step    = 50000,
    .n_voltages = 32,
};

Device Tree 바인딩

pmic@48 {
    compatible = "vendor,pmic";
    regulators {
        ldo1: LDO1 {
            regulator-name = "vdd_1v8";
            regulator-min-microvolt = <1800000>;
            regulator-max-microvolt = <1800000>;
            regulator-always-on;
        };
        buck1: BUCK1 {
            regulator-name = "vdd_cpu";
            regulator-min-microvolt = <800000>;
            regulator-max-microvolt = <1400000>;
            regulator-ramp-delay = <12500>; /* μV/μs */
        };
    };
};

/* Consumer 참조 */
cpu@0 {
    cpu-supply = <&buck1>;
};

PM 디버깅

pm_test 모드

Suspend를 단계별로 테스트하여 문제 구간을 좁힐 수 있습니다:

# 테스트 모드 설정 (해당 단계까지만 진행 후 resume)
echo freezer > /sys/power/pm_test    # 프로세스 동결만 테스트
echo devices > /sys/power/pm_test    # 디바이스 suspend까지
echo platform > /sys/power/pm_test   # 플랫폼 콜백까지
echo processors > /sys/power/pm_test # CPU 비활성화까지
echo core > /sys/power/pm_test       # 코어까지 (실제 진입 직전)

# 테스트 실행
echo mem > /sys/power/state

# 테스트 후 복원
echo none > /sys/power/pm_test

suspend_stats

# Suspend 통계 확인
cat /sys/power/suspend_stats/success     # 성공 횟수
cat /sys/power/suspend_stats/fail        # 실패 횟수
cat /sys/power/suspend_stats/last_failed_dev   # 마지막 실패 디바이스
cat /sys/power/suspend_stats/last_failed_step  # 마지막 실패 단계

pm_trace & PM 디버그 메시지

# pm_trace 활성화 (RTC에 해시 저장, 실패 디바이스 추적)
echo 1 > /sys/power/pm_trace
echo mem > /sys/power/state
# resume 후 dmesg에서 "hash matches" 메시지 확인

# 상세 PM 로그 활성화
echo 1 > /sys/power/pm_debug_messages

# initcall 디버깅 (부팅 시 느린 PM 콜백 찾기)
# 커널 cmdline: initcall_debug pm_debug_messages

ftrace PM 이벤트

# PM 관련 tracepoint
echo 1 > /sys/kernel/debug/tracing/events/power/suspend_resume/enable
echo 1 > /sys/kernel/debug/tracing/events/power/cpu_idle/enable
echo 1 > /sys/kernel/debug/tracing/events/power/device_pm_callback_start/enable
echo 1 > /sys/kernel/debug/tracing/events/power/device_pm_callback_end/enable

# suspend/resume 시간 프로파일링
echo mem > /sys/power/state
cat /sys/kernel/debug/tracing/trace

흔한 문제 & 해결

증상원인진단/해결
Suspend 시 시스템 정지디바이스 드라이버 콜백 무한 대기pm_test=devices로 범위 좁히기, pm_debug_messages=1
즉시 Wake-upSpurious wakeup source/proc/acpi/wakeup에서 소스 비활성화, wakeup_count 사용
Resume 후 디바이스 동작 안 함resume 콜백에서 레지스터 복원 누락드라이버의 resume/restore 콜백 확인
s2idle에서 전력 소비 높음디바이스가 D0 상태 유지turbostat/powertop으로 C-state 확인, PCI ASPM 점검
Hibernate 복원 실패resume= 파라미터 오류, swap 부족resume=/dev/sdX 확인, image_size 조정
런타임 PM 동작 안 함pm_runtime_enable() 미호출runtime_status sysfs 확인, control=auto 설정

PM 도구 요약

도구용도패키지
powertop전력 소비 분석, 튜닝 제안powertop
turbostatC-state/P-state/전력 실시간 모니터링linux-tools
cpupowercpufreq/cpuidle 설정 조회/변경linux-tools
sleepgraphsuspend/resume 타임라인 HTML 보고서sleepgraph (pm-graph)
intel_gpu_topIntel GPU 전력/활동 모니터링intel-gpu-tools
rapl-readRAPL 에너지 카운터 직접 읽기커스텀/perf

커널 설정 종합

Kconfig 옵션설명기본값
CONFIG_PMPM 프레임워크 전체Y
CONFIG_PM_SLEEP시스템 절전 (suspend/hibernate) 지원Y
CONFIG_SUSPENDsuspend-to-RAM (S3) / s2idleY
CONFIG_HIBERNATIONHibernate (S4, swap 이미지)Y (데스크톱)
CONFIG_PM_AUTOSLEEPautosleep (/sys/power/autosleep)N
CONFIG_PM_WAKELOCKS사용자 공간 wakelock (Android)N
CONFIG_PM_DEBUGPM 디버그 기능 (pm_test, suspend_stats)N
CONFIG_PM_TRACEpm_trace (RTC 기반 디바이스 추적)N
CONFIG_CPU_IDLEcpuidle 프레임워크Y
CONFIG_CPU_IDLE_GOV_MENUmenu 거버너Y
CONFIG_CPU_IDLE_GOV_TEOTEO 거버너Y
CONFIG_CPU_IDLE_GOV_HALTPOLLhaltpoll 거버너 (KVM)M
CONFIG_INTEL_IDLEintel_idle 드라이버Y (x86)
CONFIG_PM_GENERIC_DOMAINSgenpd (PM 도메인)Y
CONFIG_PM_OPPOPP 프레임워크Y (ARM)
CONFIG_POWERCAPpowercap 프레임워크Y
CONFIG_INTEL_RAPLIntel RAPL powercap 드라이버M
CONFIG_REGULATORRegulator 프레임워크Y (ARM)
CONFIG_ENERGY_MODELEnergy ModelY (ARM)
CONFIG_ENERGY_EFFICIENT_SCHEDEAS 활성화 (sched 내부)Y (ARM)