본문으로 건너뛰기
Kernel Debugging · 8/9

CXL 커널 드라이버 디버깅 — ftrace·bpftrace·drgn 활용

· Hawk · 3분 읽기

#drivers/cxl/ 모듈 의존성

CXL은 여러 모듈로 분할되어 있어 한 모듈만 추적해서는 안 됩니다. 의존성 체인:

cxl_acpi ← ACPI CEDT 파싱, root port 생성
cxl_pci ← PCI subsystem 통합, MMIO 매핑
cxl_core ← 공통 베이스 — port, decoder, region, memdev
↑ ↑
cxl_mem cxl_pmem ← memory device·persistent memory
↑ ↑
cxl_port cxl_acpi ← switch·root port

문제가 어느 모듈에서 발생했는지에 따라 추적 도구가 다릅니다.

#ftrace로 probe 흐름

CXL 디바이스가 등록될 때 probe 함수 호출 순서를 보고 싶다면:

Terminal window
# 1. function_graph tracer 활성화
$ echo function_graph > /sys/kernel/debug/tracing/current_tracer
# 2. CXL 관련 함수만 필터
$ echo 'cxl_*' > /sys/kernel/debug/tracing/set_ftrace_filter
$ echo 'cxl_acpi_probe cxl_pci_probe cxl_mem_probe' >> /sys/kernel/debug/tracing/set_ftrace_filter
# 3. tracing 시작
$ echo 1 > /sys/kernel/debug/tracing/tracing_on
# 4. 디바이스 rescan
$ echo 1 > /sys/bus/pci/rescan
# 5. trace 확인
$ cat /sys/kernel/debug/tracing/trace
0) 3.241 us | cxl_acpi_probe();
0) + 12.45 us | cxl_pci_probe() {
0) 1.832 us | cxl_setup_regs();
0) 8.123 us | cxl_dvsec_init();
0) + 12.45 us | }
0) 5.234 us | cxl_mem_probe();

probe가 어디서 멈췄는지 또는 예상과 다른 순서로 호출되는지 한눈에 보입니다.

#bpftrace로 Mailbox 명령 캡처

CXL 디바이스와 호스트는 mailbox로 명령·응답을 주고받습니다. mailbox 명령이 실패하면 디바이스 상태가 의심되는데, 어떤 명령이 언제 실패했는지 알아야 합니다.

Terminal window
# Mailbox 호출 추적
$ bpftrace -e '
kprobe:cxl_mbox_send_cmd {
printf("[%llu] opcode=0x%x size=%d\n", nsecs, arg1, arg2);
}
kretprobe:cxl_mbox_send_cmd {
if (retval != 0) {
printf(" ERROR: ret=%d\n", retval);
}
}
'
# 출력 예
[1234567890] opcode=0x4400 size=64 # Get Health Info
[1234567892] opcode=0x4300 size=8 # Get LSA
ERROR: ret=-110 # ETIMEDOUT

Timeout이 나는 opcode를 식별하면 디바이스 firmware 문제인지 호스트 mailbox 드라이버 문제인지 좁힐 수 있습니다.

#drgn으로 커널 상태 검사

drgn은 살아 있는 커널의 데이터 구조를 Python으로 검사하는 도구입니다. CXL의 port·decoder·region 객체를 직접 볼 수 있습니다 (helper 함수가 drgn 표준 패키지에 아직 없으면 자체 walker로 작성):

# drgn 세션 — helper 자체 작성 또는 직접 struct walk
>>> from drgn import Object
>>>
>>> # 모든 CXL port 나열 (개념적 — 실제는 kernel struct walk)
>>> for port in walk_cxl_ports(prog):
... print(f"port {port.name}, decoder_count={port.nr_dport}")
port port0, decoder_count=2
port port1, decoder_count=4
>>>
>>> # 특정 region 상태
>>> region = prog["cxl_region_lookup"]("region0")
>>> print(f"size={region.size} interleave={region.interleave_ways}")
size=137438953472 interleave=2
>>>
>>> # HDM Decoder 매핑
>>> for d in port.decoders:
... print(f" decoder {d.id}: base={hex(d.hpa_range.start)} size={d.hpa_range.end - d.hpa_range.start}")

drgn은 kdump core살아 있는 커널 둘 다에서 동작합니다. CXL 전용 helper module은 drgn mainline 추가 진행 중. 현 시점에서는 struct walker를 직접 구현하는 게 일반적입니다.

#자주 만나는 함정

증상원인
cxl_pci_probe가 호출 안 됨cxl_core 모듈 미로딩 또는 PCI driver match 실패
cxl_acpi만 로딩, cxl_mem 없음CEDT 항목은 있지만 디바이스 DVSEC 인식 실패
Mailbox timeout 빈번디바이스 busy 또는 firmware bug. mbox_ready_timeout 늘림
Region 생성 후 access 시 OOPSHDM Decoder 미프로그래밍. cxl create-region 다시
ftrace에 함수가 안 보임inline됨. noinline 패치 또는 fprobe 시도
/sys/bus/cxl 비어 있음modprobe cxl_acpi 안 함 또는 ACPI table 결함
drgn for_each_cxl_port 빈 리스트port가 정말 없음 (드라이버 미로딩)
AER 이벤트가 dmesg에 떠도 disconnectcxl_pci_err_handler 활성. driver model 정상
cxl list -RT 항목이 lspci보다 적음CEDT 부족. kernel parameter cxl_acpi.debug=1로 추적

#정리

  • CXL 드라이버는 cxl_acpi·cxl_pci·cxl_core·cxl_mem·cxl_port 여러 모듈로 분할되어 추적이 까다롭습니다.
  • ftrace function_graphprobe 호출 순서를 시각화합니다.
  • bpftracemailbox 명령 호출과 실패를 캡처합니다.
  • drgn으로 살아 있는 커널의 port·decoder·region 객체를 Python으로 검사합니다.
  • 모듈 의존성을 항상 먼저 확인cxl_core 미로딩이 가장 흔한 침묵 실패입니다.

#다음 장 예고

Ch 9 — drivers/cxl 코드 분석. 드라이버 진입점부터 sysfs까지 코드 경로를 본격적으로 분해.

#관련 항목