리눅스 커널 - NVMe PCI Driver BAR 설정
NVMe PCI Driver Basic - https://ildelusion.blogspot.com/2025/12/nvme-pci-driver.html
https://elixir.bootlin.com/linux/v4.18.20/source/drivers/nvme/host/pci.c 참고하여 NVMe 디바이스에 대한 BAR 설정을 따라가보자.
Calling Path
nvme_probe() --> nvme_dev_map() --> nvme_remap_bar()
nvme_remap_bar()에서 아래 라인이 실행됨
dev->bar = ioremap(pci_resource_start(pdev, 0), size);
pdev->resource[0].start --> 이 NVMe PCI 디바이스의 0번 BAR가 맵핑된 시스템 메모리 공간 상 물리 주소
ioremap()으로 해당 물리주소를 커널 가상 주소에 매핑한다.
nvme_dev_map()은 사실 nvme_remap_bar()를 부르기전에 pci_request_mem_regions() 함수를 먼저 부른다.
pci_request_mem_regions(pdev, "nvme")는 해당 PCI 디바이스가 가진 모든 MMIO(BAR) 메모리 영역을 “nvme” 드라이버 명의로 한꺼번에 예약하는 함수다.
이 예약이 성공하면 /proc/iomem에 해당 구간이 "nvme" 이름으로 표시되고,
다른 드라이버가 동일 범위를 다시 request_mem_region / pci_request_mem_regions로 잡는 것을 막는다. MMIO 레지스터를 ioremap() 해서 쓰기 전에, “이 주소 범위는 이 드라이버가 사용 중이다”라고 커널 리소스 관리 계층에 선언하는 단계다. 아래 함수가 결국 불리는 함수이다.
static int __pci_request_selected_regions(struct pci_dev *pdev, int bars,
const char *res_name, int excl) { int i; for (i = 0; i < 6; i++) if (bars & (1 << i)) if (__pci_request_region(pdev, i, res_name, excl)) goto err_out; return 0; err_out: while (--i >= 0) if (bars & (1 << i)) pci_release_region(pdev, i); return -EBUSY;
PCI 표준에서 정의된 최대 6개의 BAR(Base Address Register)를 모두 검사해서 사용 중인 것만 reserve 한다.
PCI 디바이스는 최대 6개의 BAR을 가질 수 있다.
BAR 번호 | 용도 예시---------|----------BAR 0 | NVMe 컨트롤러 레지스터 (MMIO)BAR 1 | NVMe Submission Queue DMA 메모리BAR 2 | NVMe Completion Queue DMA 메모리BAR 3 | 64-bit BAR의 상위 32비트BAR 4 | 추가 DMA 버퍼 또는 확장 레지스터BAR 5 | ROM 또는 추가 기능
댓글
댓글 쓰기