ASPM (Active State Power Management)
PCIe 링크가 유휴 상태(Idle State)일 때 자동으로 저전력 링크 상태로 전환하는 전원 관리(Power Management) 메커니즘입니다. L0s/L1과 L1 PM Substates(L1.1/L1.2), CLKREQ# 핀과 클럭 게이팅, LTR(Latency Tolerance Reporting), Linux 커널 aspm.c 구현과 정책 설정, 드라이버 관점의 ASPM 제어·상태 확인·주의사항, 그리고 실전 진단·튜닝·트러블슈팅을 end-to-end로 다룹니다.
핵심 요약
- ASPM — PCIe 링크가 유휴 상태일 때 하드웨어가 자동으로 저전력 링크 상태로 전환하는 표준 전원 관리 기능입니다.
- L0s — 레인(Lane) 단위로 진입하는 저전력 상태로, 진입·복귀가 빠릅니다.
- L1 — 링크 전체가 저전력 상태로 들어가는 것으로 전력 절감은 크지만 복귀 지연이 상대적으로 큽니다.
- L1 PM Substates (L1.1/L1.2) — L1에서 더 깊은 절전을 제공하는 하위 상태로, CLKREQ# 핀과 LTR(Latency Tolerance Reporting) 조건이 필요합니다.
- 정책 제어 — 커널에서
pcie_aspm=파라미터와 sysfs 정책으로 ASPM 동작을 켜거나 끌 수 있습니다.
단계별 이해
- 링크 상태 구분
L0(활성), L0s(레인 절전), L1(링크 절전)의 차이와 각 상태의 전력·지연 특성을 이해합니다. - L1 하위 상태 진입 조건
CLKREQ# 참조 클럭 제어와 LTR 메커니즘이 L1.1/L1.2 진입을 결정하는 방식을 파악합니다. - 커널 정책 적용
CONFIG_PCIEASPM,pcie_aspm=부팅 파라미터, sysfs 정책 파일을 통해 ASPM 동작을 설정합니다. - 지연 트레이드오프 검증
NVMe·네트워크 카드처럼 지연에 민감한 장비는lspci -vv와 카운터로 진입·복귀 지연을 확인하고 비활성화 여부를 결정합니다.
개요
ASPM(Active State Power Management)은 PCIe 링크가 트래픽이 없어 유휴(Idle) 상태일 때 하드웨어가 자동으로 링크를 저전력 상태로 전환하는 PCIe 표준 전원 관리 기능입니다. CPU가 데이터를 보내거나 받지 않는 동안 링크의 전송 레인(Lane) 단위 혹은 링크 전체를 저전력 상태로 만들어 대기 전력을 줄이는 것이 목적입니다.
ASPM은 소프트웨어(드라이버)의 개입 없이 링크 양쪽 디바이스가 협상하여 자동으로 동작합니다. 때문에 애플리케이션 코어 로직을 변경하지 않아도 노트북, 서버, 임베디드 시스템에서 유휴 전력을 상당히 줄일 수 있습니다. 다만 저전력 상태로 들어가거나 빠져나올 때 지연(Latency)이 발생하므로, 지연에 민감한 NVMe나 네트워크 카드에서는 상황에 따라 비활성화를 고려해야 합니다.
ASPM vs 디바이스 전원 관리 (PCI-PM)
혼동하기 쉬운 두 메커니즘을 정리하면 다음과 같습니다.
| 구분 | ASPM (링크 레벨) | PCI-PM (디바이스 레벨) |
|---|---|---|
| 제어 대상 | 링크의 물리적 전송 상태 (L0/L0s/L1) | 디바이스 펑션의 전원 상태 (D0~D3) |
| 진입 트리거 | 하드웨어가 유휴 감지 → 자동 | 소프트웨어(Power Management) 콜백(Callback)이 pci_set_power_state() 호출 |
| 표준 | PCIe Base Spec (링크 상태) | PCI PM Spec (D-states) |
| L1 하위 상태 | L1.1 (ASPM), L1.2 (ASPM) | L1.1 (PCI-PM), L1.2 (PCI-PM) |
| 전력 절감 | 상대적으로 작음 (링크만) | 큼 (디바이스 로직 자체 차단) |
| 복원 지연 | 수 μs ~ 수십 μs | 수 ms (D3) 이상 |
실제로 이 둘은 상호 보완적으로 동작합니다. 예를 들어 디바이스가 D3hot 상태로 들어가면 링크도 L1(PCI-PM 변형) 상태로 전환될 수 있으며, 반대로 ASPM의 L1 상태는 별도의 소프트웨어 절전 없이도 링크 전력만 줄입니다. 이 문서는 ASPM(링크 레벨)에 집중합니다.
링크 전원 상태와 전이
PCIe 링크는 아래와 같은 전원 상태를 가집니다. 각 상태의 전력/지연 특성과 진입 방식이 다릅니다.
| 상태 | 설명 | 진입/탈출 지연 |
|---|---|---|
| L0 | 완전 동작 (정상 전송) | — |
| L0s | 빠른 저전력, 단방향 (레인별 독립) | 64ns~4 μs 초과 (LNKCAP L0SEL 인코딩) |
| L1 | 깊은 저전력, 양방향 링크 비활성 | 1~64 μs (LNKCAP L1EL 인코딩, 64 μs 초과도 가능) |
| L1.1 | L1 Substate, PLL 꺼짐 | 수십 μs (별도 광고 없음, T_POWER_ON·칩 구현 의존) |
| L1.2 | L1 Substate, 공통 모드 전압 제거 | 수십~수백 μs (T_POWER_ON/T_COMMON_MODE 복원 추가) |
| L2/L3 | 보조 전원 / 전원 차단 | ms 단위 |
T_POWER_ON·T_COMMON_MODE와 칩 구현에 따라 달라집니다. 정확한 환경·출처 없이 특정 수치를 절대값으로 단정하지 마십시오.L0s — 단방향 빠른 절전
L0s는 레인(Lane) 단위로, 전송 방향(Tx/Rx) 중 한쪽이 유휴하면 그 방향만 저전력 상태로 전환합니다. 모든 레인이 양방향으로 유휴해야만 다른 상태로 갈 수 있는 것과 달리, L0s는 방향 독립이라 짧은 유휴 구간에서도 자주 활용됩니다. 전력 절감은 크지 않지만 전이 지연(수 μs 이하)이 작아 고빈도 짧은 유휴에서 유리합니다.
performance 정책은 policy_to_aspm_state()에서 0을 반환하므로 L0s와 L1을 모두 비활성화하고 Clock PM까지 끕니다.L1 — 양방향 깊은 절전
L1은 링크 전체가 유휴할 때 양방향 링크를 비활성화하는 상태입니다. 전력 절감이 L0s보다 크고 지연(수 μs~수십 μs)도 실무적으로 허용 가능한 수준이라, ASPM의 핵심 절전 상태로 널리 사용됩니다. L1 진입은 두 디바이스가 모두 L1을 지원하고 ASPM 링크 제어(Link Control) 레지스터(Register)에서 활성화되어 있을 때 가능합니다.
L1 PM Substates (L1.1 / L1.2)
PCIe 3.1에서 도입된 L1 PM Substates (Extended Capability ID 001Eh)는 L1 상태 안에서 미세하게 절전할 수 있는 하위 상태를 정의합니다. 두 가지가 있습니다.
- L1.1: L1에서 PLL(위상 고정 루프)을 끄고, CLKREQ# 핀을 이용해 레퍼런스 클럭을 게이팅합니다. 전기 신호와 Common mode voltage는 유지됩니다.
- L1.2: PLL과 레퍼런스 클럭을 모두 끄고, Common mode voltage까지 제거합니다. 가장 깊은 절전으로, 와이어(레인)의 전력까지 차단되어 전력 절감 효과가 큽니다. 대신 복원 지연이 가장 깁니다.
L1 Substate에 진입하려면 CLKREQ# 핀이 물리적으로 연결되어 있어야 합니다. 서버 메인보드에서는 CLKREQ#가 연결되지 않는 경우가 많아 L1.2를 사용할 수 없는 경우가 흔합니다. 또한 양쪽 디바이스가 각 상태를 지원(광고)해야 하며, 커널이 LnkCtl2/L1SubCtl 레지스터를 통해 해당 비트를 활성화해야 합니다.
LTR (Latency Tolerance Reporting)
LTR(Latency Tolerance Reporting)은 디바이스가 자신이 허용할 수 있는 최대 서비스 지연(snoop/non-snoop 각각)을 루트 컴플렉스(Root Complex)에 보고하는 메커니즘입니다. 플랫폼은 이 값을 바탕으로 링크를 얼마나 깊은 저전력 상태(L1.1/L1.2)로 보낼지, 그리고 CPU C-state 깊이를 얼마나 허용할지 결정합니다.
커널은 pci_configure_ltr()로 DevCtl2의 LTR_EN을 설정하고 엔드포인트까지의 ltr_path를 기록합니다. LTR은 PCIe r4.0 sec 6.18에 따라 루트 컴플렉스와 중간 스위치가 모두 LTR을 지원할 때만 활성화하며, _OSC로 LTR 제어권(OSC_PCI_EXPRESS_LTR_CONTROL)을 받지 못하면 네이티브 LTR을 쓰지 않습니다.
LTR_L1.2_THRESHOLD 임계값 기반으로 진입하기 때문에, 루트 컴플렉스까지 LTR 경로가 없으면 커널이 L1.2를 아예 활성화하지 않습니다(aspm_l1ss_init()의 ltr_path 검사, PCIe r4.0 sec 5.5.4/6.18). lspci -vvv에서 L1SubCtl1:에 ASPM_L1.2+가 보이지 않는다면 L1SS 캡 미광고, LTR 경로 부재, 또는 정책 제약을 순서대로 의심하십시오.예를 들어 NVMe SSD가 "읽기 요청 후 최대 50 μs까지 지연 허용"을 LTR로 보고하면, 링크 복원 시간이 LTR_L1.2_THRESHOLD 이하라면 플랫폼은 L1.2 진입을 허용합니다. 반대로 매우 낮은 LTR 값을 보고하는 저지연 디바이스는 L1 진입 자체가 제한됩니다.
하드웨어 프로토콜 상세
ASPM 관련 레지스터와 핀을 커널 개발 관점에서 정리합니다.
관련 레지스터
| 레지스터 | 위치 | 주요 비트 | 역할 |
|---|---|---|---|
| Link Capabilities (LnkCap) | PCIe Cap 0x0C | ASPM Support (bits 11:10) | 디바이스가 지원하는 ASPM 수준(L0s/L1) 광고 |
| Link Control (LnkCtl) | PCIe Cap 0x10 | ASPM Control (bits 1:0), Clock PM Enable (bit 8) | 현재 ASPM 상태 설정 + CLKREQ# 기반 클럭 전원 관리 활성화 |
| Link Capabilities 2 (LnkCap2) | PCIe Cap 0x2C | LTR Support | LTR 메커니즘 지원 여부 |
| Device Control 2 (DevCtl2) | PCIe Cap 0x28 | LTR Enable | LTR 보고 활성화 |
| L1 PM Substates Cap (L1SubCap) | Ext Cap 001Eh | PCI-PM_L1.1/1.2, ASPM_L1.1/1.2, PortCommonModeRestoreTime, PortTPowerOnTime | 각 L1 Substates 지원 여부와 복원 시간 광고 |
| L1 PM Substates Ctrl 1 (L1SubCtl1) | Ext Cap 001Eh | ASPM/PCI-PM L1.1/1.2 Enable, LTR1.2_Threshold | 각 L1 Substate 활성화 + LTR 기준값 |
| L1 PM Substates Ctrl 2 (L1SubCtl2) | Ext Cap 001Eh | T_POWER_ON, T_CommonMode | 복원 시간 파라미터 설정 |
CLKREQ# 핀과 클럭 게이팅
L1 Substates의 핵심은 레퍼런스 클럭 제어입니다. 오픈 드레인 방식의 CLKREQ# 핀은 다음 규칙으로 동작합니다.
- 링크가 L0(완전 동작)이거나 PCIe 링크가 클럭을 항상 공급해야 할 때
CLKREQ#는 낮은(Low) 상태를 유지합니다. - L1.1 진입 시 디바이스가
CLKREQ#를 해제(High)하여 호스트 브리지(Bridge)의 클럭 게이팅을 허용합니다. - L1.2에서는 클럭이 완전히 꺼지고, 복원 시 디바이스가
CLKREQ#를 다시 당겨 클럭을 재개한 뒤 링크를 재훈련합니다.
주의할 점은 커널이 CLKREQ# 배선 여부를 직접 검사하지 않는다는 것입니다. 커널은 L1SubCap 광고와 ltr_path만으로 L1.2 활성화를 결정하므로, 보드에서 CLKREQ#가 연결되지 않은 플랫폼에서는 하드웨어가 실제로 클럭을 게이팅할 수 없어 L1.2 진입이 불안정하거나 진입하지 못합니다(서버 메인보드에서 흔한 사례이므로 BIOS/보드 스펙 확인 필요). lspci -vvv의 LnkCtl:에 ClockPM-로 표시되면 클럭 전원 관리가 비활성화된 상태입니다.
Clock PM (클럭 전원 관리)
Clock PM(Clock Power Management)은 링크가 L1/L1.1/L1.2 상태일 때 CLKREQ#를 이용해 레퍼런스 클럭(Reference Clock) 자체를 게이팅(일시 정지)하는 기능입니다. 지원 여부는 LnkCap의 ClockPM 비트(bit 18)로 광고되고, LnkCtl의 Clock PM Enable(bit 8, CLKREQ_EN)으로 활성화됩니다.
커널은 pcie_clkpm_cap_init()으로 슬롯의 모든 펑션에서 지원 여부를 확인한 뒤 pcie_set_clkpm()으로 켭니다 (clkpm_capable/clkpm_enabled/clkpm_default/clkpm_disable 상태 추적). 정책과의 관계는 policy_to_clkpm_state()에 정리되어 있습니다 — performance는 끄고, powersave/powersupersave는 켜며, default는 BIOS 상태를 유지합니다.
ASPM 협상과 활성화 절차
ASPM이 실제로 동작하기까지는 다음과 같은 협상 단계를 거칩니다.
- 지원 광고: 각 디바이스가 LnkCap 레지스터로 자신이 지원하는 ASPM 수준을 광고합니다.
- 제어권 협상: 부팅 시 루트 컴플렉스와 OS가 ACPI
_OSC로 ASPM 제어권을 협상합니다. OS가 가져오면 커널이 정책을 적용하고, 펌웨어(Firmware)가 유지하면 펌웨어의 설정을 따릅니다. - 정책 결정: 커널이 부트 파라미터/모듈 파라미터로 결정된 ASPM 정책에 따라 각 링크의 LnkCtl ASPM Control 비트를 설정합니다.
- L1 Substate 활성화: L1SubCtl1의 각 Enable 비트를 설정하고, LTR 기준값(LTR1.2_Threshold)과 복원 시간(T_POWER_ON 등)을 구성합니다.
- 하드웨어 자동 전환: 이후 유휴를 감지한 하드웨어가 협상된 상태로 자동 전이합니다.
_OSC 협상이 실패하거나 펌웨어가 제어권을 유지하면, 커널의 ASPM 정책 설정이 실제 레지스터에 반영되지 않을 수 있습니다. 이런 경우 펌웨어 설정(대개 BIOS에서 ASPM 항목)을 확인해야 합니다. ACPI 문서의 _OSC 섹션을 참조하십시오.커널 구현
ASPM의 커널 구현은 주로 drivers/pci/pcie/aspm.c에 집중되어 있습니다. 핵심 개념부터 코드 경로까지 살펴봅니다.
커널 구성 옵션
| Kconfig | 설명 | 비고 |
|---|---|---|
CONFIG_PCIEASPM | ASPM 지원 여부 (bool) | 대부분의 배포판에서 기본 활성화 |
CONFIG_PCIEASPM_DEFAULT | 기본 정책: default | 플랫폼/펌웨어 기본값을 따름 |
CONFIG_PCIEASPM_POWERSAVE | 기본 정책: powersave | 절전 우선 |
CONFIG_PCIEASPM_POWERSUPERSAVE | 기본 정책: powersupersave | 최대 절전 (L1/L1.1/L1.2 모두 허용) |
CONFIG_PCIEASPM_PERFORMANCE | 기본 정책: performance | 성능 우선 (L0s/L1 비활성화) |
이 중 하나의 정책을 컴파일 시 기본값으로 내장할 수 있고, 부팅 시 pcie_aspm.policy=로 덮어씁니다.
ASPM 정책 (Policy)
커널은 4가지 정책을 지원하며, 이는 /sys/module/pcie_aspm/parameters/policy로 확인하고 런타임에 바꿀 수 있습니다.
| 정책 | L0s | L1 | L1.1/L1.2 | 용도 |
|---|---|---|---|---|
| default | BIOS 상태 유지 | BIOS 상태 유지 | BIOS 상태 유지 | BIOS/펌웨어가 켠 상태 그대로. 일반 소비자 시스템 |
| performance | 비활성화 | 비활성화 | 비활성화 | 저지연/고성능 필요 시 (Clock PM도 off) |
| powersave | 허용 | 허용 | 비활성화 | L0s+L1까지만. 노트북/모바일 기본 절전 |
| powersupersave | 허용 | 허용 | 허용(L1.1/L1.2, PCI-PM 변형 포함) | L1 서브스테이트까지 최대 절전 |
performance는 L0s와 L1을 모두 비활성화합니다. L0s는 양방향 트래픽 시 링크를 절반으로 만들어 처리량을 떨어뜨릴 수 있고, L1은 지연(수 μs~수십 μs)을 추가하기 때문입니다. powersave는 L0s+L1까지만 켜며 L1 서브스테이트는 켜지 않고, powersupersave만 L1.1/L1.2(PCI-PM 변형 포함)까지 허용합니다(커널 v4.2에서 추가된 정책). NVMe SSD나 고성능 NIC 같이 지연/처리량이 중요한 디바이스에는 performance가 권장됩니다.pci_enable_device()가 호출되는 시점에 pcie_aspm_powersave_config_link()로 정책을 반영합니다 (aspm.c 주석 참조).aspm.c 핵심 코드 경로
실제 커널 소스의 핵심 함수 시그니처와 동작을 정리합니다.
/* drivers/pci/pcie/aspm.c (v6.x 기준) — 핵심 구조와 함수 */
/* 링크별 ASPM 상태 구조체: 각 상태를 7비트 비트필드로 추적 */
struct pcie_link_state {
struct pci_dev *pdev; /* 링크의 업스트림 컴포넌트(포트) */
struct pci_dev *downstream; /* 다운스트림 컴포넌트 = 펑션 0 */
struct pcie_link_state *root; /* 루트 포트 링크 */
struct pcie_link_state *parent; /* 상위 링크 (스위치 체인) */
u32 aspm_support:7; /* 지원 가능한 ASPM 상태 */
u32 aspm_enabled:7; /* 현재 활성화된 상태 */
u32 aspm_capable:7; /* 지연 검사 통과 후 켤 수 있는 상태 */
u32 aspm_default:7; /* BIOS/override 기본값 */
u32 aspm_disable:7; /* 드라이버/사용자가 끈 상태 */
u32 clkpm_capable:1; /* Clock PM 지원 여부 (LNKCAP.CLKPM) */
u32 clkpm_enabled:1; /* 현재 Clock PM 상태 */
};
/* 정책을 상태 비트마스크로 변환 — powersave는 L0s+L1만, */
/* powersupersave만 L1 서브스테이트(PCIE_LINK_STATE_ASPM_ALL) 포함 */
static int policy_to_aspm_state(struct pcie_link_state *link)
{
switch (aspm_policy) {
case POLICY_PERFORMANCE: return 0;
case POLICY_POWERSAVE: return PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1;
case POLICY_POWER_SUPERSAVE: return PCIE_LINK_STATE_ASPM_ALL;
case POLICY_DEFAULT: return link->aspm_default;
}
return 0;
}
/* 루트 포트/스위치 다운스트림 포트에 대해 호출 (열거 직후) */
void pcie_aspm_init_link_state(struct pci_dev *pdev)
{
/* 1. pcie_aspm_sanity_check(): pre-1.1(RBER 없음)/비-PCIe면 slot 전체 비활성 */
/* 2. pcie_aspm_cap_init(): L0s/L1 지원 판정 + 공통 클럭 구성 */
/* 3. aspm_l1ss_init(): L1.1/L1.2 지원 판정 (LTR 경로 검사 포함) */
/* 4. pcie_aspm_check_latency(): 엔드포인트 허용 지연 검사 */
/* 5. pcie_clkpm_cap_init() 후 pcie_config_aspm_path()로 정책 적용 */
}
/* L1.2 사용 조건: 양쪽 L1SS 캡 + child->ltr_path(루트까지 LTR 경로) */
static void aspm_l1ss_init(struct pcie_link_state *link)
{
/* L1SubCap의 각 지원 비트를 양쪽 AND로 aspm_support에 반영 */
/* LTR 경로가 없으면 ASPM_L1_2 지원 비트를 제거 (PCIe r4.0) */
/* L1.2 지원 시 aspm_calc_l12_info()로 타이밍 파라미터 계산 */
}
/* 레지스터 반영 순서 (PCIe r6.2 sec 5.5.4/7.5.3.7): */
/* L1 먼저 비활성 → 자식부터 clear, 부모부터 set → L1SS 프로그래밍 */
static void pcie_config_aspm_link(struct pcie_link_state *link,
u32 state);
/* 드라이버 API: OS가 ASPM 제어권을 못 받았으면 -EPERM (경고 로그) */
int pci_disable_link_state(struct pci_dev *pdev, int state);
int pci_enable_link_state(struct pci_dev *pdev, int state);
/* 커널 파라미터: pcie_aspm=off / force, 모듈 파라미터 pcie_aspm.policy= */
static bool aspm_disabled; /* off 또는 pcie_no_aspm() 호출 후 */
static bool aspm_force; /* pcie_aspm=force */
드라이버는 링크 전원 관리를 원하지 않는 경우 pci_disable_link_state()를 호출해 특정 링크의 ASPM을 끌 수 있습니다. 대표적인 예가 리얼텍 r8169 드라이버입니다 — 프로브(Probe) 시 PCIE_LINK_STATE_L1을 비활성화하고(벤더가 안전하다고 플래그한 시스템 제외), Tx 타임아웃 발생 시 PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_L0S를 비활성화하며 "ASPM disabled on Tx timeout" 경고를 남깁니다.
드라이버 API와 aspm_disable/aspm_default
pci_disable_link_state()는 link->aspm_disable 마스크에 상태를 추가하고 정책을 재적용합니다. L1을 끄면 L1 서브스테이트도 함께 꺼집니다(pci_calc_aspm_disable_mask()가 L1SS 비트를 포함). pci_enable_link_state()는 aspm_disable을 건드리지 않고 aspm_default만 바꾸므로, 한 번 끈 상태는 정책 변경 외에는 되살릴 수 없습니다. OS가 ACPI _OSC로 ASPM 제어권을 얻지 못한 경우(aspm_disabled) 두 API 모두 -EPERM을 반환하고 can't disable ASPM; OS doesn't have ASPM control 경고를 출력합니다.
구현 세부: 펑션 0 제약 · 공통 클럭 · 지연 검사
펑션 0 제약: L1 PM Substates 캐퍼빌리티는 다중 펑션(Multi-function) 디바이스에서 펑션 0에만 구현된다는 규약이 있습니다. 커널의 pci_function_0()은 링크의 다운스트림 컴포넌트를 펑션 0으로 고정하며(link->downstream), 링크 상태 구조체(Struct)도 펑션 0이 제거될 때 해제됩니다(pcie_aspm_exit_link_state()). 같은 슬롯의 모든 펑션에는 동일한 ASPM 값을 프로그래밍합니다.
공통 클럭(Common Clock): pcie_aspm_configure_common_clock()은 양쪽 링크의 Slot Clock Configuration(LnkSta)을 확인해 동일하다면 LnkCtl의 Common Clock Configuration(CCC) 비트를 설정해 ASPM 탈출 지연을 줄입니다. 공통 클럭 구성은 LnkCap의 탈출 지연 값까지 바꿀 수 있으므로(PCIe r5.0 sec 7.5.3.6) 설정 후 지연을 다시 읽으며, 링크 재훈련(Retrain) 실패 시 이전 설정으로 복원합니다.
지연 예산 검사: pcie_aspm_check_latency()는 엔드포인트가 광고하는 허용 지연(LnkCap DEVCAP의 L0s/L1 필드)과 각 링크의 탈출 지연을 비교해 요구를 충족하지 못하는 방향의 상태를 aspm_capable에서 제거합니다. 스위치(Switch)를 지날 때마다 L1 탈출 지연에 1 μs가 더해지며, D0가 아닌 디바이스는 검사에서 제외됩니다.
L1.2 타이밍 파라미터와 Devicetree 속성
aspm_calc_l12_info()는 두 포트가 광고한 T_POWER_ON과 PortCommonModeRestoreTime 중 큰 값을 선택해 L1SubCtl2/L1SubCtl1에 프로그래밍하고, LTR_L1.2_THRESHOLD를 "T_POWER_ON + T_CommonMode + 2 μs(최대 T_POWER_OFF) + 4 μs(최소 T_L1.2)"로 계산합니다(PCIe r3.1 sec 5.5.3.3.1, Fig 5-16/5-17). 임계값 인코딩은 올림(round up)하여 L1.2에 과하게 자주 진입하지 않게 하며, 파라미터 갱신 시 L1.2 Enable 비트를 먼저 지웠다가 다시 설정하는 순서(r6.2 sec 5.5.4)를 지킵니다.
Devicetree 플랫폼에서는 aspm-no-l0s, aspm-no-l1, aspm-no-l1ss 프로퍼티(링크 포트 노드)로 펌웨어가 활성화한 기본 상태를 끌 수 있습니다. pcie_aspm_override_default_link_state()가 이를 처리하며, 하드웨어에 이미 켜져 있던 L1SS 상태를 지우고 "ASPM: default states" 로그를 남깁니다.
PCI 코어와의 상호작용
ASPM은 링크 계층 기능이므로 PCIe 포트 하위 시스템(drivers/pci/pcie/)에서 초기화됩니다. pcie_aspm_init_link_state()는 루트 포트/스위치 다운스트림 포트(링크의 업스트림 컴포넌트) 기준으로 호출되고, 디바이스 제거 시 pcie_aspm_exit_link_state()가 링크 상태를 해제하며, D-state 전환 시 pcie_aspm_pm_state_change()가 지연 검사를 다시 수행합니다. 예를 들어 디바이스가 D3hot으로 가면 링크가 L1(PCI-PM)로 전환될 수 있고, D0 복귀 시 L0로 돌아옵니다. suspend/resume 시에는 pci_save_aspm_l1ss_state()/pci_restore_aspm_l1ss_state()가 L1SS 설정을 저장·복원하며, 복원 시 L1.2를 자식부터 먼저 끄고 파라미터를 쓴 뒤 Enable 비트를 되살리는 순서를 따릅니다.
ASPM을 고려한 드라이버 구현
대부분의 디바이스 드라이버는 ASPM을 직접 다룰 필요가 없습니다. 커널이 정책과 펌웨어 협상 결과를 기반으로 처리하기 때문입니다. 다만 아래 세 가지 상황에서는 드라이버가 명시적으로 개입해야 합니다.
- 링크 안정성: 특정 하드웨어는 L0s/L1 전이 시 Replay Timer Timeout, Tx 타임아웃, 데이터 손상이 발생합니다. 드라이버는 probe 단계에서 해당 상태를 꺼야 합니다.
- 지연/처리량 보장: 저지연·고처리량이 결정적인 디바이스(NVMe SSD, 고성능 NIC, 실시간 경로)는 유휴 링크가 절전 상태에 있으면 첫 I/O에서 링크 복귀 지연이 추가됩니다.
- 전력 목표: 모바일/노트북용 디바이스는 정책이 허용하는 범위에서 더 적극적인 절전(L1.1/L1.2)을 유지하도록 설계할 수 있습니다.
pci_disable_link_state() 등)를 사용해야 합니다. 커널은 링크별 상태를 aspm_enabled/aspm_disable 마스크로 추적하고 정책 재적용 시 이 값을 레지스터에 다시 쓰므로, 레지스터를 직접 바꾸면 커널의 상태 추적과 불일치해 다음 정책 적용 때 덮어써지거나 되살아납니다.드라이버용 API와 링크 상태 상수
드라이버가 사용할 수 있는 API는 drivers/pci/pcie/aspm.c에 구현되어 있고 include/linux/pci.h에 선언되어 있습니다.
| API | 동작 | 비고 |
|---|---|---|
pci_disable_link_state(pdev, state) | aspm_disable 마스크에 상태를 추가하고 해당 링크에 즉시 반영 | L1 포함 시 L1SS 자동 포함. 제어권 없으면 -EPERM, 링크가 없으면 -EINVAL |
pci_enable_link_state(pdev, state) | aspm_default를 바꿔 상태를 키는 방향으로 재적용 | aspm_disable에 들어간 비트는 되살리지 못함 |
pci_set_link_state(pdev, state) | 요청한 상태를 링크의 기본 ASPM 상태로 설정하고 즉시 재적용 | 런타임 성능/절전 전환용 |
pcie_aspm_support_enabled() | 커널이 ASPM을 지원하는 환경인지 전역 판정 (bool) | 제어 시도 전 사전 확인용 |
pci_no_aspm() | 전역으로 ASPM이 비활성화된 상태인지 판정 (bool) | aspm_disabled && !aspm_force |
링크 상태 비트는 다음과 같습니다.
/* include/linux/pci.h — 드라이버가 사용하는 링크 상태 비트 */
#define PCIE_LINK_STATE_L0S BIT(0) /* L0s: 유휴 방향 링크 절반을 끔 */
#define PCIE_LINK_STATE_L1 BIT(1) /* L1: 링크를 끄고 복귀 지연 발생 */
#define PCIE_LINK_STATE_CLKPM BIT(2) /* Clock PM: CLKREQ# 게이팅 */
#define PCIE_LINK_STATE_L1_1 BIT(3) /* L1.1: 서브스테이트 */
#define PCIE_LINK_STATE_L1_2 BIT(4) /* L1.2: 추가 절전 (LTR 임계값으로 진입 제어) */
#define PCIE_LINK_STATE_L1SS \
(PCIE_LINK_STATE_L1_1 | PCIE_LINK_STATE_L1_2)
#define PCIE_LINK_STATE_ASPM_ALL \
(PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_L1SS)
pci_disable_link_state(pdev, PCIE_LINK_STATE_L1)만 호출해도 L1.1/L1.2가 함께 꺼집니다. pci_calc_aspm_disable_mask()가 L1SS 비트를 마스크에 포함하기 때문입니다. 반대로 "L1만 끄고 L1.2만 유지"하는 구성은 불가능합니다.구현 패턴과 코드 예시
패턴 1 — probe에서 링크 안정성/지연 요구에 따라 해제 (r8169 스타일): 링크 전이 시 오류가 보고된 컨트롤러는 초기화 단계에서 L1을 끕니다. 리얼텔 r8169이 대표적이며, 벤더가 안전함을 인증한 시스템에서만 ASPM을 유지합니다.
/* probe: 지연/안정성 요구에 따라 ASPM 해제 */
static int mynic_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
int ret;
ret = pci_enable_device(pdev); /* 여기서 커널 정책(default)이 먼저 반영됨 */
if (ret)
return ret;
/* L1 전이 시 Tx 타임아웃이 보고된 하드웨어: */
/* 벤더 안전 플래그가 없으면 L1을 끈다 (L1SS도 함께 꺼짐) */
if (!mynic_aspm_is_safe(pdev)) {
ret = pci_disable_link_state(pdev, PCIE_LINK_STATE_L1);
if (ret)
dev_warn(&pdev->dev,
"ASPM L1 disable failed: %d (제어권 없음 또는 링크 없음)\n",
ret);
}
/* ... 초기화 계속 ... */
return 0;
}
패턴 2 — 런타임 링크 불안정 감지 시 추가 해제: Tx 타임아웃 같은 증상이 나타나면 L0s까지 끕니다. r8169은 이 경우 "ASPM disabled on Tx timeout" 경고를 남깁니다.
/* Tx 타임아웃 발생 → 링크 불안정 의심 → L0s/L1 모두 해제 */
static void mynic_tx_timeout(struct net_device *ndev,
unsigned int txqueue)
{
struct mynic_priv *priv = netdev_priv(ndev);
if (!priv->aspm_disabled) {
int ret = pci_disable_link_state(priv->pdev,
PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1);
if (!ret) {
priv->aspm_disabled = true;
netdev_warn(ndev, "ASPM disabled on Tx timeout\n");
}
}
/* ... 재전송/링크 재설정 처리 ... */
}
패턴 3 — suspend/resume: 표준 PCI 전원 관리 경로에서는 PCI 코어가 L1SS 설정을 저장·복원합니다(pci_save_aspm_l1ss_state()/pci_restore_aspm_l1ss_state()). 자체 pm_ops를 구현하는 드라이버는 resume 콜백에서 링크가 기대한 상태인지 아래 "상태 확인" 섹션의 헬퍼로 재확인하는 것을 권장합니다.
패턴 4 — 전역 결함 하드웨어는 quirk로: 특정 드라이버에 한정되지 않고 칩 전반에 문제가 있는 경우 drivers/pci/quirks.c의 quirk_disable_aspm_l0s/quirk_disable_aspm_l0s_l1이 pcie_aspm_remove_cap() 경로로 ASPM 캡 자체를 제거합니다(인텔 82575/82598, ASMedia ASM1083/1085 등 — 트러블슈팅 섹션 참조).
드라이버 관점의 제어 흐름
probe에서의 초기 판단과 런타임에서의 재평가를 하나의 그림으로 정리하면 다음과 같습니다.
pci_enable_device() 시점에 정책을 반영합니다. 드라이버가 ASPM을 끄려면 pci_enable_device() 이후에 호출해야 커널 정책 반영과 순서 충돌이 없습니다.드라이버에서 ASPM 상태 확인
드라이버가 "지금 이 링크의 ASPM이 켜져 있는가"를 확인하는 방법은 커널 API, 레지스터 직접 읽기, 사용자 공간 도구로 나뉩니다. 각각 확인하는 대상이 다르므로 목적에 맞게 선택해야 합니다.
확인 방법 비교
| 방법 | 확인 대상 | 특징 | 권장 용도 |
|---|---|---|---|
pcie_aspm_enabled(pdev) | 커널 추적 값 link->aspm_enabled | bool 반환, EXPORT_SYMBOL_GPL | 드라이버 코드에서 빠른 판정 |
pcie_aspm_support_enabled() | 커널 전역 지원 여부 | bool 반환 | 링크 제어 시도 전 사전 확인 |
pci_no_aspm() | 전역 비활성 판정 | aspm_disabled && !aspm_force | 대체 경로 결정 (quirk 등) |
| LnkCtl 직접 읽기 | 하드웨어 레지스터 (L0s/L1/CLKREQ/CCC 비트) | pci_read_config_word() 사용 | 커널 북키핑과 펌웨어 개입 비교 |
| L1SubCtl1 직접 읽기 | L1SS 확장 캡 (L1.1/L1.2/PM 비트) | L1SS 캡 오프셋(Offset) 필요 (pdev->l1ss) | L1 PM Substates 세부 확인 |
/sys/bus/pci/devices/<BDF>/link/* | 링크별 enabled/disabled 문자열 | 사용자 공간, 드라이버 불필요 | 관리·스크립트·원격 진단 |
lspci -vv / setpci | LnkCap/LnkCtl/L1SubCtl1 원시 값 | 권한 없이 대부분 읽기 가능 | 휴먼 진단, 레지스터 덤프(Dump) |
| dmesg | 커널 로그 (비활성 사유 포함) | 초기화 시점에만 기록 | 원인 분석의 첫 단계 |
북키핑과 실측의 차이: pcie_aspm_enabled()는 커널이 링크별로 추적하는 aspm_enabled 값을 반환하고, LnkCtl 직접 읽기는 하드웨어 레지스터의 현재 값을 반환합니다. 두 값이 다르면 펌웨어(SMI/BIOS가 _OSC 제어권을 유지한 경우)나 다른 에이전트가 레지스터를 바꾼 것입니다. 이때 링크 제어 API는 -EPERM으로 실패합니다.
구현 상세 예시
아래는 드라이버에 넣을 수 있는 ASPM 상태 덤프 헬퍼입니다. pdev->exp_cap과 pdev->l1ss는 PCI 코어가 열거 시점에 캐시(Cache)한 캐퍼빌리티 오프셋입니다.
#include <linux/pci.h>
#include <linux/pci_regs.h>
/* 링크의 ASPM 상태를 로그에 남기는 드라이버 유틸리티 */
static void mydev_log_aspm_state(struct pci_dev *pdev)
{
u16 lnkctl, lnkcap, devctl2;
u32 l1ss_ctl1 = 0;
int l1ss_off;
if (!pci_is_pcie(pdev))
return;
/* 1) 커널 북키핑 값 */
dev_info(&pdev->dev,
"ASPM: kernel support=%d, this link enabled=%d\n",
pcie_aspm_support_enabled(), pcie_aspm_enabled(pdev));
/* 2) LnkCtl/LnkCap 직접 읽기 (하드웨어 실측) */
pci_read_config_word(pdev, pdev->exp_cap + PCI_EXP_LNKCTL, &lnkctl);
pci_read_config_word(pdev, pdev->exp_cap + PCI_EXP_LNKCAP, &lnkcap);
dev_info(&pdev->dev,
"LnkCtl=0x%04x LnkCap=0x%04x: L0s=%d L1=%d CLKREQ_EN=%d CCC=%d\n",
lnkctl, lnkcap,
(lnkctl & PCI_EXP_LNKCTL_ASPM_L0S) ? 1 : 0,
(lnkctl & PCI_EXP_LNKCTL_ASPM_L1) ? 1 : 0,
(lnkctl & PCI_EXP_LNKCTL_CLKREQ_EN) ? 1 : 0,
(lnkctl & PCI_EXP_LNKCTL_CCC) ? 1 : 0);
/* 3) L1 PM Substates 제어 레지스터 (L1SS 확장 캡) */
l1ss_off = pdev->l1ss;
if (l1ss_off) {
pci_read_config_dword(pdev, l1ss_off + PCI_L1SS_CTL1, &l1ss_ctl1);
dev_info(&pdev->dev,
"L1SS ctl1=0x%08x: ASPM_L1.1=%d ASPM_L1.2=%d"
" PM_L1.1=%d PM_L1.2=%d\n",
l1ss_ctl1,
(l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_1) ? 1 : 0,
(l1ss_ctl1 & PCI_L1SS_CTL1_ASPM_L1_2) ? 1 : 0,
(l1ss_ctl1 & PCI_L1SS_CTL1_PM_L1_1) ? 1 : 0,
(l1ss_ctl1 & PCI_L1SS_CTL1_PM_L1_2) ? 1 : 0);
}
/* 4) LTR 활성 여부 — L1.2 진입 조건 중 하나 */
pci_read_config_word(pdev, pdev->exp_cap + PCI_EXP_DEVCTL2, &devctl2);
dev_info(&pdev->dev, "LTR_EN=%d\n",
(devctl2 & PCI_EXP_DEVCTL2_LTR_EN) ? 1 : 0);
}
상태를 읽은 뒤 조건부로 동작하는 예시입니다. 비활성화 성공 후 레지스터를 다시 읽어 하드웨어 반영을 확인합니다.
/* probe: 지연 예산이 부족한 워크로드면 L1을 끄고 레지스터로 재확인 */
if (mydev_requires_low_latency(pdev)) {
int ret = pci_disable_link_state(pdev, PCIE_LINK_STATE_L1);
u16 lnkctl;
if (ret) {
dev_warn(&pdev->dev, "L1 disable failed: %d\n", ret);
} else {
pci_read_config_word(pdev, pdev->exp_cap + PCI_EXP_LNKCTL,
&lnkctl);
if (lnkctl & PCI_EXP_LNKCTL_ASPM_L1)
dev_warn(&pdev->dev,
"L1 is still enabled — 펌웨어 개입 가능성!\n");
}
}
sysfs와 사용자 공간 도구
드라이버 코드가 아닌 관리자 관점에서는 다음 방법을 사용합니다.
# 링크별 ASPM 상태 (드라이버 수정 없이)
for f in l0s_aspm l1_aspm l1_1_aspm l1_2_aspm clkpm; do
printf "%s=%s\n" "$f" "$(cat /sys/bus/pci/devices/0000:03:00.0/link/$f)"
done
# LnkCtl의 ASPM/CLKREQ 비트와 L1SS 상태 확인
lspci -vv -s 03:00.0 | grep -E "LnkCap:|LnkCtl:|L1Sub"
# setpci로 원시 레지스터 확인 (CAP_EXP+0x10 = LnkCtl, bit0=L0s bit1=L1)
setpci -s 03:00.0 CAP_EXP+10.w
# L1SubCtl1은 lspci -vvv로 확인한 L1SS 확장 캡 오프셋 + 0x08
상태 비트 지도
드라이버가 읽는 두 레지스터의 비트 배치는 다음과 같습니다.
ASPM 주의할 점
커널 API 사용 시 주의
- OS 제어권(
_OSC)이 없으면 API가 실패: 펌웨어가 ASPM 제어권을 유지하거나 FADT NO_ASPM,pcie_aspm=off상태면pci_disable_link_state()/pci_enable_link_state()는-EPERM을 반환합니다. dmesg로 사유를 확인한 뒤 BIOS 설정 또는pcie_aspm=force(FADT NO_ASPM만 무시)를 검토해야 합니다. - L1을 끄면 L1SS까지 함께 꺼짐:
pci_calc_aspm_disable_mask()가 L1SS 비트를 포함하므로 L1 비활성화는 L1.1/L1.2까지 전파됩니다. - 한 번 끈 상태는 되살릴 수 없음:
pci_enable_link_state()는aspm_disable을 건드리지 않고aspm_default만 바꾸므로, 드라이버가 끈 상태는 전역 정책 변경이나 재부팅 전에는 복구되지 않습니다. - 프로세스(Process) 컨텍스트(Context)에서 호출: 이 API들은 config 공간 I/O와 지연 검사를 수반하므로 인터럽트(Interrupt) 처리 루틴이나 원자적(Atomic) 문맥에서 호출하면 안 됩니다.
- 호출 시점: 커널은 초기화 중에는 정책을 즉시 적용하지 않으므로,
pci_enable_device()이후에 호출해야 커널 정책 반영과 충돌하지 않습니다. - 레지스터 직접 쓰기 금지: LnkCtl/L1SubCtl1을 드라이버가 직접 쓰면
aspm.c의 상태 추적과 불일치합니다. 읽기는 자유롭게 허용됩니다(상태 확인 섹션 참조).
플랫폼·하드웨어 주의
- 펑션 0 제약: L1 PM Substates 캐퍼빌리티는 다중 펑션(Multi-function) 디바이스에서 펑션 0에만 구현되며, 커널도 링크의 다운스트림 컴포넌트를 펑션 0으로 고정합니다. 자식 펑션에서 상태를 확인하면 같은 링크 값을 공유합니다.
- CLKREQ# 배선과 LTR 경로는 커널이 검사할 수 없는 요소: 미배선 보드에서는 L1.2가 켜지지 않아도 소프트웨어 문제가 아닙니다. 보드 스펙과
lspci의LnkCtl: ClockPM+를 함께 확인해야 합니다. - quirk로 ASPM 캡이 제거된 링크:
pcie_aspm_remove_cap()이 적용된 디바이스는 ASPM 지원 자체가 없으므로pcie_aspm_enabled()는 false, 제어 API는-EINVAL을 반환합니다. dmesg의 "Link Capabilities ... treated as unsupported" 로그로 확인할 수 있습니다. - L0s는 양방향 트래픽에서 불리: L0s는 유휴 방향 링크만 끄므로 양방향 전송이 잦은 NIC에서는 전이 오버헤드(Overhead)가 커집니다. 양방향 트래픽이 많은 장치는 L1보다 L0s를 먼저 꺼야 하는 경우도 있습니다.
- ASPM 비트는 "허용"을 의미할 뿐: LnkCtl의 ASPM 비트가 켜져 있어도 실제 진입은 링크 유휴 상태와 타이머(Timer)에 따라 달라집니다. 절전 효과 검증은 전력 측정/전이 관측이 필요합니다.
런타임·전원 관리 상호작용
- D-state 전환과의 이중 제어: 디바이스가 D3hot으로 가면 링크는 L1(PCI-PM 변형)로 전환되고 D0 복귀 시 L0로 돌아옵니다. runtime PM을 함께 쓰면 링크 절전과 D-state 절전이 중첩되므로, 전력 측정은 두 계층을 합산해 평가해야 합니다.
- suspend/resume의 L1SS 복원 순서: 복원 시 L1.2 Enable을 먼저 지우고 파라미터를 쓴 뒤 다시 켜는 순서(자식부터)를 PCI 코어가 처리합니다. 자체 PM을 구현하는 드라이버는
pci_save_aspm_l1ss_state()/pci_restore_aspm_l1ss_state()를 사용해야 하며, resume 직후에는 링크가 아직 안정화 전이므로 곧바로 큰 I/O를 보내지 않는 것이 좋습니다. - 스위치 체인: 드라이버가 제어하는 링크는 자신의 링크뿐입니다. 스위치 업링크(상위 링크)의 절전은 루트 포트 정책에 따르므로, 체인 전체의 절전을 원하면 상위 링크 정책을 함께 확인해야 합니다.
- 성능 수치의 환경 의존성: ASPM이 IOPS/지연에 미치는 영향은 워크로드와 하드웨어에 따라 크게 달라집니다. 측정 없이 정확한 수치를 단정하지 말고, 벤치마크 전후 비교로 판단해야 합니다(성능 수치 표기 규칙 참조).
설정과 진단
현재 정책 확인
# 현재 ASPM 정책 확인 ([]가 현재 값)
cat /sys/module/pcie_aspm/parameters/policy
# [default] performance powersave powersupersave
# 런타임에 정책 변경 (변경 즉시 모든 링크에 반영)
echo powersave > /sys/module/pcie_aspm/parameters/policy
정책 변경은 pcie_aspm_set_policy()가 전역 aspm_lock을 잡고 link_list의 모든 링크에 pcie_config_aspm_link()/pcie_set_clkpm()을 적용합니다. 단, pcie_aspm=off 또는 FADT NO_ASPM으로 aspm_disabled가 설정된 상태라면 -EPERM으로 거부됩니다(aspm_disabled 검사). "정책을 바꿔도 안 바뀐다"면 먼저 dmesg에서 비활성 사유를 확인하십시오.
링크 단위 sysfs 제어
전역 정책과 별개로 각 링크의 하위 컴포넌트 디바이스에는 link/ 속성 그룹이 노출됩니다(aspm_ctrl_attr_group, 그룹명 link). 해당 링크가 특정 상태를 지원(aspm_capable)할 때만 파일이 보이며, 값 1/0으로 링크 단위 aspm_disable 마스크를 조정합니다.
ls /sys/bus/pci/devices/0000:03:00.0/link/
# clkpm l0s_aspm l1_aspm l1_1_aspm l1_2_aspm l1_1_pcipm l1_2_pcipm
# 이 링크에서 L1만 끄기 (L1SS도 함께 꺼짐)
echo 0 > /sys/bus/pci/devices/0000:03:00.0/link/l1_aspm
# 다시 켜기 (정책이 허용하는 범위 내에서)
echo 1 > /sys/bus/pci/devices/0000:03:00.0/link/l1_aspm
| 속성 | 의미 |
|---|---|
clkpm | Clock PM 활성 여부 |
l0s_aspm | L0s |
l1_aspm | L1 |
l1_1_aspm / l1_2_aspm | ASPM 기반 L1.1 / L1.2 |
l1_1_pcipm / l1_2_pcipm | PCI-PM 기반 L1.1 / L1.2 (디바이스 D-state와 연계) |
aspm_attr_store_common()은 L1을 끄면 L1SS(l1_1_aspm 등)도 함께 끄고, L1SS를 켜면 L1도 함께 켭니다. pci_calc_aspm_enable_mask()/pci_calc_aspm_disable_mask()의 "L1 PM substates require L1" 규칙 때문입니다.부트 파라미터
# ASPM 완전 비활성화 (저지연 요구 시)
pcie_aspm=off
# ASPM 정책 지정
pcie_aspm.policy=performance
pcie_aspm.policy=powersave
pcie_aspm.policy=powersupersave
pcie_aspm.policy=default
# pre-1.1 디바이스나 FADT 비지원 환경에서도 ASPM 강제 적용
# (aspm_force가 설정되면 pcie_no_aspm()이 비활성화하지 않음)
pcie_aspm=force
# 커널 cmdline 예제 (GRUB)
# GRUB_CMDLINE_LINUX="pcie_aspm=off"
pcie_aspm=force 사용 주의: force는 펌웨어가 ASPM을 지원하지 않는 플랫폼에서도 강제로 활성화합니다. 링크가 불안정해질 수 있으며, 일부 하드웨어에서는 데이터 오류나 디바이스 무응답을 유발할 수 있습니다. 신중하게 사용하십시오.lspci로 상태 읽기
lspci -vv는 각 링크의 ASPM 지원과 현재 상태를 보여줍니다.
# 특정 디바이스의 ASPM 관련 상태
lspci -vv -s 03:00.0 | grep -i -A 3 "LnkCap\|LnkCtl"
# 예시 출력 해석
# LnkCap: Port #0, Speed 16GT/s, Width x4, ASPM L0s L1, ...
# → 이 디바이스는 L0s와 L1을 모두 지원
# LnkCtl: ASPM L1 Enabled; RCB 64 bytes, Disabled-CommClk+
# → 현재 L1이 활성화되어 있음
# L1 PM Substates 상태
lspci -vvv -s 03:00.0 | grep -A 10 "L1 PM Substates"
# L1SubCap: PCI-PM_L1.2+ PCI-PM_L1.1+ ASPM_L1.2+ ASPM_L1.1+ L1_PM_Substates+
# PortCommonModeRestoreTime=60us PortTPowerOnTime=10us
# L1SubCtl1: PCI-PM_L1.2+ PCI-PM_L1.1+ ASPM_L1.2+ ASPM_L1.1+
# T_CommonMode=0us LTR1.2_Threshold=163840ns
# LTR 지원/활성 여부 (ASPM L1.2의 전제 조건)
lspci -vvv -s 03:00.0 | grep -E "LTR|LnkCtl2"
# DevCap2: Completion Timeout: Range AB, TimeoutDis+ LTR+ OBFF Via message/WAKE#
# DevCtl2: Completion Timeout: 50ms to 50ms, TimeoutDis- LTR+ OBFF Disabled
# Capabilities: [220 v1] Latency Tolerance Reporting
# Max snoop latency: 3145728ns
# Max no snoop latency: 3145728ns
LnkCtl의 ASPM 필드는 현재 활성 상태를 표시합니다: ASPM Disabled(비활성), ASPM L0s Enabled, ASPM L1 Enabled, ASPM L0s L1 Enabled(둘 다 활성). LnkCap의 ASPM L0s L1은 하드웨어가 광고한 지원 범위이므로, "지원(LnkCap) vs 활성(LnkCtl)"을 구분해서 읽어야 합니다. 함께 보면 유용한 항목: ClockPM+/ClockPM-(LnkCtl bit 8), CommClk+/Disabled-CommClk+(Common Clock 여부). L1SubCtl1의 T_CommonMode/LTR1.2_Threshold는 커널 aspm_calc_l12_info()가 양단의 L1SubCap 값을 조합해 프로그래밍한 결과입니다.
커널 로그에서 ASPM 확인
# 부팅 시 ASPM 관련 메시지
dmesg | grep -i aspm
# 출력 예시 (문구는 커널 버전에 따라 다를 수 있음)
# PCIe ASPM is disabled ← pcie_aspm=off 적용
# PCIe ASPM is forcibly enabled ← pcie_aspm=force 적용
# pci 0000:00:1c.4: ASPM: Link Capabilities L0s L1 treated as
# unsupported to avoid device defect ← quirks.c 헤더 픽스업 적용
# acpi PNP0A08:00: _OSC: OS supports [ExtendedConfig ASPM ClockPM Segments MSI HPX-Type3]
# → OS가 _OSC에서 ASPM/ClockPM 지원을 선언
# acpi PNP0A08:00: FADT indicates ASPM is unsupported, using BIOS configuration
# → FADT(NO_ASPM)가 비지원 선언, 커널은 BIOS 설정을 유지하고 제어 포기
# acpi PNP0A08:00: _OSC: platform retains control of PCIe features (AE_...) ← 플랫폼 제어
커널이 ASPM을 비활성화하는 경로는 셋입니다: ① 부트 파라미터 pcie_aspm=off, ② ACPI FADT NO_ASPM 비트, ③ _OSC 협상 실패(플랫폼이 제어권 유지). ②③은 pcie_no_aspm()을 호출하며, 이 함수는 pcie_aspm=force(aspm_force)가 설정된 경우 비활성화를 건너뜁니다. 또한 pcie_no_aspm()은 정책을 default로 되돌리고 사용자 공간(User Space)의 정책 변경도 막습니다.
튜닝과 성능
ASPM 설정은 전력 절감과 레이턴시/처리량 사이의 절충입니다. 워크로드에 따라 적절한 정책을 선택해야 합니다.
저지연 워크로드 (NVMe / 고성능 NIC)
NVMe SSD, RDMA, 고성능 이더넷 카드처럼 요청-응답 왕복 시간이 중요한 디바이스에서는 L1 진입 시 추가되는 지연이 성능에 영향을 줄 수 있습니다. L1 Exit Latency는 링크가 LnkCap(L1EL)으로 광고하며 디바이스에 따라 1 μs부터 64 μs(초과 인코딩 포함)까지 크게 다릅니다. 커널 pcie_aspm_check_latency()는 경로상 스위치마다 1 μs를 추가해 엔드포인트의 허용값(DevCap L1)과 비교합니다. L1.2는 별도의 Exit Latency 광고가 없어 여기에 T_POWER_ON·T_COMMON_MODE 복원 시간(수십 μs)이 더해지므로, 유휴-활성 전환이 잦은 워크로드에서는 수십~수백 μs의 추가 왕복 지연이 발생할 수 있습니다. 다음과 같이 해당 경로의 ASPM을 끄는 것이 일반적입니다.
# 방법 1: 전역 정책을 performance로 (모든 링크)
pcie_aspm.policy=performance # 부트 파라미터
echo performance > /sys/module/pcie_aspm/parameters/policy # 런타임
# 방법 2: 드라이버가 pci_disable_link_state() 호출 (예: r8169는 probe 시 L1 비활성화)
# 방법 3: 링크 단위 sysfs로 해제 (드라이버 수정 없이, 재부팅 시 초기화됨)
echo 0 > /sys/bus/pci/devices/0000:03:00.0/link/l1_aspm
# 확인: 해당 링크의 LnkCtl이 ASPM Disabled가 되었는지
lspci -vv -s 03:00.0 | grep "LnkCtl:"
fio나 벤치마크 도구로 직접 검증하는 것을 권장합니다.절전 우선 워크로드 (노트북 / 모바일)
유휴 시간이 긴 모바일/노트북 워크로드는 절전이 우선입니다. powersupersave 정책으로 L1.1/L1.2까지 허용해 대기 전력을 최소화합니다(powersave는 L0s/L1까지만 활성화 — policy_to_aspm_state() 참조).
# 절전 최대화 (배터리 극대화)
echo powersupersave > /sys/module/pcie_aspm/parameters/policy
# L1.2 실제 동작 조건: 양단 L1SS 지원 + LTR 경로(ltr_path) + CLKREQ# 배선 + powersupersave
# L1.2 활성 여부는 lspci -vvv의 L1SubCtl1 (ASPM_L1.2+ 등)에서 확인
레이턴시 영향 측정
ASPM이 실제로 성능에 미치는 영향을 측정하려면 아래 도구를 활용할 수 있습니다.
turbostat/powertop: 전력 소비와 함께 디바이스 상태를 관찰합니다.iostat/fio: NVMe의 IOPS/지연을 정책 변경 전후로 비교합니다.perf: 네트워크 처리량/지연을 측정합니다.rtla timerlat/osnoise: 실시간(Real-time) 지연(레지던시)을 계측합니다. RTLA / timerlat / osnoise 문서를 참조하십시오.
lspci -vv, policy) → ② 정책 변경 → ③ 벤치마크 측정 → ④ 결과 비교로 최적 정책을 결정합니다. 전역 변경보다는 영향받는 워크로드에 맞춰 신중하게 적용하십시오.트러블슈팅
ASPM이 활성화되지 않음
| 증상 | 원인 | 조치 |
|---|---|---|
lspci에서 ASPM 항목 없음 | 펌웨어/CPU가 ASPM 미지원, 또는 정책이 performance | dmesg 확인 후 pcie_aspm=force/정책 변경 검토 |
| L1.2가 활성화 안 됨 | 양단 L1SS 미지원(캡 미광고), LTR 경로 부재(ltr_path), 정책이 powersupersave가 아님, 펌웨어 제어 유지, CLKREQ# 미배선(배선은 커널이 검사 불가) | lspci -vvv의 L1SubCap/DevCtl2(LTR)/L1SubCtl1 확인, 정책 변경, 보드 CLKREQ 배선 확인 |
| dmesg에 "FADT indicates ASPM is unsupported, using BIOS configuration" | ACPI FADT(NO_ASPM)가 ASPM 비지원 선언 | BIOS 설정 확인 또는 pcie_aspm=force (force면 pcie_no_aspm()이 비활성화하지 않음) |
정책 쓰기가 -EPERM으로 거부됨 | aspm_disabled 상태 (pcie_aspm=off 또는 FADT NO_ASPM) | dmesg로 비활성 사유 확인, force 옵션 또는 BIOS 설정 검토 |
ASPM으로 인한 링크 불안정
일부 하드웨어는 ASPM 진입 시 링크가 불안정해져 Uncorrectable Error나 디바이스 무응답이 발생할 수 있습니다. 커널 소스에서 확인된 실제 사례:
- 리얼텍 RTS525A 카드 리더 (
quirks.c): L0s를 켜면 Replay Timer Timeout 폭풍이 발생해quirk_disable_aspm_l0s가 적용됩니다. - 리얼텍 r8169 NIC: probe 시 "random device stop working problems as well as full system hangs"을 피하기 위해 기본적으로
pci_disable_link_state(pdev, PCIE_LINK_STATE_L1)를 호출합니다(시스템 벤더가 안전함을 표시한 경우 제외). RTL8168GU(VER_42)·VER_43 계열은 칩 자체 ASPM을 사용하지 않습니다("ASPM can even harm bus communication of other PCI devices"). - ASMedia ASM1083/1085 브리지 (
quirks.c):quirk_disable_aspm_l0s_l1로 L0s·L1을 모두 해제합니다.
이때는 해당 링크의 ASPM을 끕니다.
# 전역으로 ASPM 완전 비활성화
pcie_aspm=off
# 또는 특정 디바이스 기준으로 정책 조정
pcie_aspm.policy=performance
# AER 오류가 난다면 함께 확인
dmesg | grep -i "aer\|aspm"
커널에는 이런 하드웨어를 위해 drivers/pci/quirks.c에 헤더 픽스업이 준비되어 있습니다. quirk_disable_aspm_l0s는 인텔 82575/82598 이더넷 컨트롤러(L0s 전이 시 데이터 손상)와 리얼텍 RTS525A에, quirk_disable_aspm_l0s_l1은 ASMedia 0x1080(ASM1083/1085), Freescale 0x0451, PASEMI 0xa002, Huawei 0x1105에 적용됩니다(L1 단독용 quirk는 존재하지 않습니다). 또한 인텔 DG2(Arc, 0x4f8x·0x569x·0x56ax)는 aspm_l1_acceptable_latency quirk로 L1 허용 지연을 unlimited(0x7)로 올려 L1 ASPM을 허용합니다. 이들은 pcie_aspm_remove_cap()을 통해 동작하며 dmesg에 "ASPM: Link Capabilities ... treated as unsupported to avoid device defect" 로그를 남깁니다. 자세한 예는 네트워크 디바이스 드라이버 문서의 ASPM 섹션을 참조하십시오.
NVMe 성능 저하
NVMe 디바이스에서 ASPM(특히 L1.2) 활성 시 대기 전력은 줄지만, 요청 간 유휴 구간에서 L1 진입/복귀 지연이 추가되어 IOPS/지연이 저하될 수 있습니다. 고성능 NVMe 배열에서는 performance 정책이나 드라이버의 ASPM 제어를 사용하십시오.
전력이 줄지 않음
정책을 powersave로 바꿔도 전력이 줄지 않는 경우가 있습니다.
- 펌웨어가
_OSC로 제어권을 유지하고 있어 커널 설정이 무시될 수 있습니다. BIOS에서 ASPM 항목을 확인하십시오. - 디바이스가 D0 상태를 유지하면 링크 절전만으로 전체 전력 감소가 미미합니다. 디바이스 D-state(PCI / PCIe 참조)와 함께 고려해야 합니다.
- CLKREQ#이 배선되지 않아 L1.2로 진입하지 못하면 L1까지만 절전됩니다. 커널은 배선을 검사하지 못하므로 LnkCtl의
ClockPM+와 보드 스펙을 함께 확인해야 합니다.
참고자료
- Linux Kernel Documentation — PCI Power Management
- 커널 소스:
drivers/pci/pcie/aspm.c,drivers/pci/quirks.c - PCI Express Base Specification (L1 PM Substates, ASPM 챕터)
- PCI / PCIe 서브시스템 — Config Space, AER, D-States 등
- PCI / PCIe — ASPM과 함께 다룬 D-States, AER, 리셋 메커니즘
- 전원 관리 개요 — 시스템 레벨 전원 관리
- CPUIdle — CPU C-state와의 관계
- 네트워크 디바이스 드라이버 — ASPM quirk 사례