본문으로 건너뛰기
PCIe Deep Dive · 10/19

Ch 10: Linux PCI Basics — Enumeration·Driver Model·sysfs

· Hawk · 6분 읽기

#한 줄 요약

“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·MCFGfirmware↔kernel 인터페이스.

Ch 3 Configuration Space·Ch 4 BAR에서 device가 자기를 광고하는 layout을 봤습니다. 이 장은 Linux가 그 layout을 읽어 driver model로 통합하는 흐름을 본격적으로 분해합니다.

#Boot Enumeration

단계주체
1UEFI/BIOS가 Configuration Space probe·BAR 할당·bridge bus numbering
2UEFI가 ACPI MCFG (ECAM 영역) 등록
3Linux pci-acpi.cMCFG 읽고 root bus 등록
4Linux *pci_scan_root_bus()*가 각 bus walk → struct pci_dev 생성
5sysfs에 entry 노출 (/sys/bus/pci/devices/)
6deferred: pci_bus_add_devices가 driver matching·probe 호출

Re-enumerationhot-plug·VFIO에서 일어남. echo 1 > /sys/bus/pci/rescan으로 manual trigger.

#struct pci_dev — 핵심 멤버

멤버의미
struct device devLinux device model 통합
u16 vendor·deviceVendor·Device ID
u16 subsystem_vendor·subsystem_device서브시스템 식별
u32 classClass Code
u8 hdr_typeType 0 또는 Type 1
u8 bus·devfnBDF
struct resource resource[6]BAR 0~5의 resource
struct pci_driver *driver매칭된 driver
void *driver_datadriver 전용 데이터
struct pci_bus *bus속한 bus
struct list_head bus_listbus의 device list

drivers/pci/probe.c에서 struct pci_dev 할당·초기화.

#struct pci_driver

멤버의미
const struct pci_device_id *id_tableVendor·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_handlerAER callback (Ch 7)
struct device_driver driverLinux 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·_CIDACPI 기반 (root port 등)

여러 driver가 같은 device 매칭하면 bind priority에 따라 결정. /sys/bus/pci/drivers/<drv>/bind수동 binding.

#probe·remove 생명 주기

단계함수의미
1pci_enable_device(pdev)Memory·I/O space 활성, IRQ 할당
2pci_request_regions(pdev, "mydrv")BAR 영역 exclusive ownership 요청
3pci_set_master(pdev)DMA bus master 활성
4pci_iomap(pdev, bar, max_size)BAR을 kernel virtual address로 매핑
5pci_alloc_irq_vectors()MSI/MSI-X 할당 (Ch 5)
6request_irq(irq, isr, ...)ISR 등록
7Driver 자체 init (queue·workqueue 등)
8remove역순 cleanup

각 단계 실패면 별도 errno. dmesg | grep <drv>각 단계 결과 추적.

#sysfs 구조

/sys/bus/pci/:

경로내용
devices/<BDF>/각 device
devices/<BDF>/configConfiguration Space 4 KB (binary)
devices/<BDF>/resourceBAR 정보
devices/<BDF>/resource<N>각 BAR (mmap 가능)
devices/<BDF>/driver매칭된 driver symlink
devices/<BDF>/vendor·device·classID 정보
devices/<BDF>/numa_nodeNUMA locality
devices/<BDF>/sriov_numvfsSR-IOV (PF에서만)
devices/<BDF>/resetFLR/secondary bus reset trigger
drivers/<drv>/각 driver
drivers/<drv>/bind·unbind수동 driver binding
slots/hot-plug slot 정보

lspci사실상 sysfs 읽기. lspci -ttopology tree, lspci -vv상세 capability dump.

#ACPI 통합

영역역할
MCFGECAM 영역 (Ch 3)
DSDTdevice 동작·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 같은 serviceportdrv가 통합:

Service모듈
AERaer service
Hot-plugpciehp
Power Managementpme
DPCdpc
BW Notificationbwctrl

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 setpcidriver 영향device hang 또는 OS crash 위험.

#”remove가 동기로 즉시 완료”

driver removeoutstanding I/O·workqueue 등 cleanup 필요. 비동기 cleanup 패턴 흔함. 완료 보장은 wait_for_completion 등 명시적.

#정리

  • Linux PCI subsystem은 firmware enumerationstruct pci_dev로 흡수.
  • pci_driver의 id_tabledevice ID 매칭probe/remove.
  • Probe 패턴: enable → request_regions → set_master → iomap → alloc_irq_vectors → request_irq.
  • /sys/bus/pci/모든 통합 viewlspci도 sysfs 읽기.
  • ACPI MCFG·PRTfirmware↔kernel 인터페이스.
  • pcie-portdriverAER·hot-plug·PM·DPC service 통합.
  • MODULE_DEVICE_TABLEudev autoload.

#다음 편

Ch 11: DMA·IOMMU — ATS·PRI·PASID·IOMMUFD에서 DMA buffer 관리·IOMMU mapping·SVM 기반을 본격적으로 분해합니다.

#관련 항목

#시리즈 자료 출처 안내

본 글의 1차 자료·정책은 Ch 1 footer 참고.