Ch 10: Linux PCI Basics — Enumeration·Driver Model·sysfs
#한 줄 요약
“Linux PCI subsystem은 firmware·UEFI가 끝낸 enumeration을 받아 struct pci_dev로 표현하고, pci_driver의 id_table과 매칭해 probe → resource → IRQ → I/O의 생명주기를 관리합니다.” —
/sys/bus/pci/가 모든 device·driver 통합 view.lspci도 결국 sysfs read. ACPI PRT·MCFG가 firmware↔kernel 인터페이스.
Ch 3 Configuration Space·Ch 4 BAR에서 device가 자기를 광고하는 layout을 봤습니다. 이 장은 Linux가 그 layout을 읽어 driver model로 통합하는 흐름을 본격적으로 분해합니다.
#Boot Enumeration
| 단계 | 주체 |
|---|---|
| 1 | UEFI/BIOS가 Configuration Space probe·BAR 할당·bridge bus numbering |
| 2 | UEFI가 ACPI MCFG (ECAM 영역) 등록 |
| 3 | Linux pci-acpi.c가 MCFG 읽고 root bus 등록 |
| 4 | Linux *pci_scan_root_bus()*가 각 bus walk → struct pci_dev 생성 |
| 5 | sysfs에 entry 노출 (/sys/bus/pci/devices/) |
| 6 | deferred: pci_bus_add_devices가 driver matching·probe 호출 |
Re-enumeration은 hot-plug·VFIO에서 일어남. echo 1 > /sys/bus/pci/rescan으로 manual trigger.
#struct pci_dev — 핵심 멤버
| 멤버 | 의미 |
|---|---|
struct device dev | Linux device model 통합 |
u16 vendor·device | Vendor·Device ID |
u16 subsystem_vendor·subsystem_device | 서브시스템 식별 |
u32 class | Class Code |
u8 hdr_type | Type 0 또는 Type 1 |
u8 bus·devfn | BDF |
struct resource resource[6] | BAR 0~5의 resource |
struct pci_driver *driver | 매칭된 driver |
void *driver_data | driver 전용 데이터 |
struct pci_bus *bus | 속한 bus |
struct list_head bus_list | bus의 device list |
drivers/pci/probe.c에서 struct pci_dev 할당·초기화.
#struct pci_driver
| 멤버 | 의미 |
|---|---|
const struct pci_device_id *id_table | Vendor·Device·Class 매칭 패턴 |
int (*probe)(struct pci_dev *, const struct pci_device_id *) | device 발견 시 |
void (*remove)(struct pci_dev *) | device 해제 시 |
int (*suspend·resume)(struct pci_dev *) | PM callback |
const struct pci_error_handlers *err_handler | AER callback (Ch 7) |
struct device_driver driver | Linux driver model |
static const struct pci_device_id my_pci_table[] = { { PCI_DEVICE(0x8086, 0x1234) }, { PCI_DEVICE_CLASS(PCI_CLASS_NETWORK_ETHERNET << 8, ~0) }, { 0 }};MODULE_DEVICE_TABLE(pci, my_pci_table);
static struct pci_driver my_driver = { .name = "mydrv", .id_table = my_pci_table, .probe = my_probe, .remove = my_remove,};module_pci_driver(my_driver);#Driver Matching
Vendor·Device ID 매칭이 기본. 추가 매칭:
| 패턴 | 사용 |
|---|---|
PCI_DEVICE(v, d) | 특정 V/D |
PCI_DEVICE_SUB(v,d,sv,sd) | Sub-system도 매칭 |
PCI_DEVICE_CLASS(class, mask) | Class 기반 (모든 NIC 등) |
ACPI _HID·_CID | ACPI 기반 (root port 등) |
여러 driver가 같은 device 매칭하면 bind priority에 따라 결정. /sys/bus/pci/drivers/<drv>/bind로 수동 binding.
#probe·remove 생명 주기
| 단계 | 함수 | 의미 |
|---|---|---|
| 1 | pci_enable_device(pdev) | Memory·I/O space 활성, IRQ 할당 |
| 2 | pci_request_regions(pdev, "mydrv") | BAR 영역 exclusive ownership 요청 |
| 3 | pci_set_master(pdev) | DMA bus master 활성 |
| 4 | pci_iomap(pdev, bar, max_size) | BAR을 kernel virtual address로 매핑 |
| 5 | pci_alloc_irq_vectors() | MSI/MSI-X 할당 (Ch 5) |
| 6 | request_irq(irq, isr, ...) | ISR 등록 |
| 7 | Driver 자체 init (queue·workqueue 등) | |
| 8 | remove 시 역순 cleanup |
각 단계 실패면 별도 errno. dmesg | grep <drv>로 각 단계 결과 추적.
#sysfs 구조
/sys/bus/pci/:
| 경로 | 내용 |
|---|---|
devices/<BDF>/ | 각 device |
devices/<BDF>/config | Configuration Space 4 KB (binary) |
devices/<BDF>/resource | BAR 정보 |
devices/<BDF>/resource<N> | 각 BAR (mmap 가능) |
devices/<BDF>/driver | 매칭된 driver symlink |
devices/<BDF>/vendor·device·class | ID 정보 |
devices/<BDF>/numa_node | NUMA locality |
devices/<BDF>/sriov_numvfs | SR-IOV (PF에서만) |
devices/<BDF>/reset | FLR/secondary bus reset trigger |
drivers/<drv>/ | 각 driver |
drivers/<drv>/bind·unbind | 수동 driver binding |
slots/ | hot-plug slot 정보 |
lspci는 사실상 sysfs 읽기. lspci -t로 topology tree, lspci -vv로 상세 capability dump.
#ACPI 통합
| 영역 | 역할 |
|---|---|
| MCFG | ECAM 영역 (Ch 3) |
| DSDT | device 동작·resource·PRT |
| PRT (PCI Routing Table) | INTx → APIC vector 매핑 |
| HOTPLUG (HPET·_OST) | hot-plug event 통보 |
x86은 ACPI 의존도 큼. ARM·POWER는 DT (Device Tree) 또는 ACPI + DT 혼용.
#pcie-portdriver
Root Port·Switch Port 같은 service를 portdrv가 통합:
| Service | 모듈 |
|---|---|
| AER | aer service |
| Hot-plug | pciehp |
| Power Management | pme |
| DPC | dpc |
| BW Notification | bwctrl |
drivers/pci/pcie/portdrv.c가 각 service 모듈에 dispatch. portbus driver model.
#자주 하는 실수
#”pci_enable_device 안 해도 BAR 읽기 됨”
sysfs config는 enable 무관. BAR I/O·DMA는 반드시 enable 후. pci_request_regions까지 안 하면 다른 driver와 충돌 가능.
#”MODULE_DEVICE_TABLE 없으면 작동 안 함”
작동은 함 — 다만 udev autoload 안 됨. manual modprobe 필요. 항상 MODULE_DEVICE_TABLE(pci, …) 등록 권장.
#”ID 매칭만 되면 probe 호출”
Class·subsystem ID도 매칭. *generic driver (예: nouveau)*가 priority 낮은 매칭. vendor-specific driver가 우선 binding.
#”sysfs config write로 BAR 변경”
BAR write는 driver가 owner일 때만 안전. manual setpci는 driver 영향 — device hang 또는 OS crash 위험.
#”remove가 동기로 즉시 완료”
driver remove는 outstanding I/O·workqueue 등 cleanup 필요. 비동기 cleanup 패턴 흔함. 완료 보장은 wait_for_completion 등 명시적.
#정리
- Linux PCI subsystem은 firmware enumeration을 struct pci_dev로 흡수.
- pci_driver의 id_table과 device ID 매칭해 probe/remove.
- Probe 패턴: enable → request_regions → set_master → iomap → alloc_irq_vectors → request_irq.
/sys/bus/pci/가 모든 통합 view —lspci도 sysfs 읽기.- ACPI MCFG·PRT가 firmware↔kernel 인터페이스.
- pcie-portdriver가 AER·hot-plug·PM·DPC service 통합.
- MODULE_DEVICE_TABLE로 udev autoload.
#다음 편
Ch 11: DMA·IOMMU — ATS·PRI·PASID·IOMMUFD에서 DMA buffer 관리·IOMMU mapping·SVM 기반을 본격적으로 분해합니다.
#관련 항목
- Ch 3: Configuration Space
- Ch 4: BAR & MMIO — pci_iomap
- Ch 5: Interrupts — pci_alloc_irq_vectors
- Ch 7: Error Handling — pci_error_handlers
#시리즈 자료 출처 안내
본 글의 1차 자료·정책은 Ch 1 footer 참고.
PCIe Deep Dive · 10 of 19
- 1Ch 1: PCIe Fundamentals — 계층 구조와 토폴로지
- 2Ch 2: TLP — Transaction Layer Packet
- 3Ch 3: Configuration Space — 4 KB ECAM·Capability Linked List
- 4Ch 4: BAR & MMIO — Device 자원의 호스트 주소 매핑
- 5Ch 5: Interrupts — INTx·MSI·MSI-X·Interrupt Remapping
- 6Ch 6: Power Management — D-state·L-state·ASPM
- 7Ch 7: Error Handling — Correctable·Uncorrectable·AER·DPC
- 8Ch 8: Data Link Layer — DLLP·ACK/NAK·Flow Control·FLIT Mode
- 9Ch 9: Physical Layer — LTSSM·Equalization·SerDes
- 10Ch 10: Linux PCI Basics — Enumeration·Driver Model·sysfs
- 11Ch 11: DMA·IOMMU — Coherent·Streaming·ATS·PRI·PASID·IOMMUFD
- 12Ch 12: Virtualization I — Pass-through·SR-IOV·VFIO·DPDK·SPDK
- 13Ch 13: Virtualization II — vIOMMU·Scalable IOV·VirtIO·IDE·TDISP
- 14Ch 14: Linux Operations — Hot-plug·AER Recovery·DPC·ARI
- 15Ch 15: Tools — lspci·setpci·pcimem·protocol analyzer
- 16Ch 16: Troubleshooting — 실무 시나리오북
- 17Ch 17: Performance — Bandwidth·Latency·Tuning
- 18Ch 18: Register Maps — Config Space·Capability 비트 reference
- 19Ch 19: 고급 기능 — Lane Margining·10-bit Tag·TPH·ACS·L0p
관련 글
Ch 19: 고급 기능 — Lane Margining·10-bit Tag·TPH·ACS·L0p
코어 동작 너머의 PCIe spec 기능들 — Lane Margining(신호 마진 측정)·10-bit Tag(outstanding 확장)·TPH(캐시 주입 힌트)·ACS(격리)·L0p(부분폭 저전력)을 실무 관점에서 정리합니다.
Ch 18: Register Maps — Config Space·Capability 비트 reference
PCIe register reference — Type 0/1 header·PCIe Cap·AER·MSI·MSI-X·SR-IOV·ACS·LTR의 주요 비트 layout.
Ch 17: Performance — Bandwidth·Latency·Tuning
PCIe 성능 — theoretical vs effective BW·MaxPayload·MaxReadReq·latency breakdown·NUMA·P2P·ASPM 영향·tuning.