이 글은 제가 PCIe를 공부하면서 겪은 시행착오를 바탕으로 정리한 글입니다. PCIe를 처음 접하는 분들에게 좋은 길라잡이가 되었으면 합니다.
이전 글)
Configuration Address Space
PCIe에서는 device의 configuration을 관리하기 위해 "Configuration Space"라는 특정 메모리 영역에 접근해야 합니다. 이 공간은 장치의 기능과 제어 옵션을 설정하는 데 사용되는 다양한 register를 포함하고 있습니다. PCIe에서는 주로 두 가지 방식으로 이 configuration space에 접근할 수 있습니다.
1. Legacy PCI Mechanism
이 방식은 원래 PCI bus에서 사용되던 방식을 기반으로 하며, 주로 I/O 포트를 사용해 configuration space에 접근합니다. 이 방식은 CPU가 특정 I/O 포트 주소에 있는 명령(IN/OUT instruction)을 사용하여 PCIe 장치의 구성 공간을 읽거나 쓸 수 있게 합니다.
- I/O 포트 접근: 0xCF8과 0xCFC 주소가 사용됩니다.
- 0xCF8: configuration space의 주소를 설정하는 데 사용되며,
- 0xCFC: 실제 데이터 전송을 수행.
이 방식은 호환성을 제공하지만, I/O 포트를 통한 접근은 시스템 리소스를 비효율적으로 사용할 수 있고 모든 현대 PCIe 시스템에서 최적의 성능을 제공하지는 않습니다.
2. Enhanced Configuration Access Mechanism
ECAM은 MMIO를 사용하여 configuration space에 접근합니다. 이 방식은 시스템의 메모리 주소 공간 내의 특정 영역을 할당하여 PCIe configuration space에 대한 직접적인 메모리 접근을 허용합니다. 이 접근 방식은 더 빠르고 효율적이며, 현대의 고성능 시스템에서 권장됩니다.
PCIe Configuration Header
PCIe configuration header는 PCIe device의 configuration space의 일부로서, device의 기능과 특성을 정의하는 중요한 정보를 포함하고 있습니다. 이 header는 device를 올바르게 식별, 구성 및 관리하는데 필요한 필수 데이터를 제공합니다. PCIe configuration header는 두 가지 주요 유형이 있습니다. Type0과 Type1. Type 0 헤더는 일반 endpoint device에 사용되며, Type 1 헤더는 bridge와 같은 포트를 포함하는 device에 사용됩니다.
Enumeration
PCIe의 enumeration 프로세스는 시스템이 부팅할 때 발생하며, 이 과정을 통해 시스템은 모든 PCIe device를 탐색하고, 구성하고, 관리할 수 있는 정보를 수집합니다. 이 과정은 호스트 시스템과 연결된 모든 PCIe 디바이스와 브리지의 구조를 파악하고 각 디바이스에 고유한 주소를 할당하는 단계를 포함합니다. enumeration 과정은 다음과 같은 단계로 구성됩니다.
1. Device 탐색
시스템이 부팅할 때 BIOS 또는 운영 체제의 초기화 코드가 root complex를 시작점으로 하여 PCIe bus를 스캔합니다. 이 과정에서 모든 연결된 디바이스와 브리지를 식별합니다. 이는 root complex에서 시작하여 깊이 우선(depth-frist) 알고리즘을 통해 모든 PCIe link를 따라 하위 디바이스와 브리지를 탐색함으로써 수행됩니다.
2. Bus 번호 할당
시스템은 각 브리지에 primary, secondary, subordinate 버스 번호를 할당합니다. 이 번호들을 브리지가 연결하는 PCIe 버스의 구조를 정의하는 데 사용됩니다. primary는 브리지 자신이 연결된 버스의 번호이며, secondary는 브리지가 직접 연결하는 첫 번째 버스, subordinate는 브리지 아래에 있는 가장 낮은 숫자의 버스를 나타낸다.
3. Resource 할당
디바이스 및 브리지의 Base Address Registers(BARs)가 조사되어 각 디바이스가 필요로 하는 메모리와 I/O 리소스의 양을 파악합니다. 그 후, 시스템은 사용 가능한 주소 공간에서 이 리소스를 할당합니다. 이 단계는 디바이스가 시스템 내에서 데이터를 주고받을 수 있도록 필요한 주소 공간을 확보하는 데 중요합니다.
Hot-Plug
위 예시를 보면 오른쪽 Root Complex의 Bus 번호가 10이 아닌 64부터 시작되는 것을 알 수 있습니다. 이는 PCIe가 hot plug를 지원하기 때문인데요, hot plug란 사용자가 시스템의 전원을 끄지 않고도 하드웨어 구성 요소를 추가하거나 제거할 수 있게 해 주는 기능입니다. 만약 Bus가 64부터 시작되지 않고 10부터 시작된다고 가정했을 때, 사용자가 Bus 9 다음 부분에 새로운 PCIe deivce를 추가한다면 Bus 10부터 enumeration 과정을 전부 다시 시작해야 되는 불상사가 발생하게 됩니다. 이를 방지하기 위해 intel 및 AMD에서는 일정 숫자 간격을 띄우는 방식을 채택합니다.
Address Space & Transaction Routing
PCIe에서 MMIO를 사용할 때, 메모리 공간은 prefetchable space와 non-prefetchable space로 나눌 수 있습니다. 이 구분은 메모리 접근 방식과 데이터의 사용 방식에 따른 것으로, 하드웨어와 소프트웨어 간의 효율적인 데이터 처리를 위해 중요합니다.
1. Non-prefetchable Space
이 공간은 데이터가 예측할 수 없거나, 실시간으로 변경되는 특성을 가진 메모리 영역을 지칭합니다. 이 공산의 데이터는 CPU 또는 다른 디바이스에 의해 prefetch 할 수 없습니다. 예를 들어, I/O 디바이스의 상태 레지스터나 제어 레지스터 같은 것이 이에 해당합니다. 이 영역의 데이터는 변경될 수 있고, 접근하는 시점에서의 정확한 데이터를 읽어야 하기 때문에 prefetching이 불가능합니다.
2. Prefetchable Space
이 공간은 데이터가 비교적 안정적이거나 변하지 않는 특성을 가지고 있어, CPU가 미리 데이터를 가져와 캐시 할 수 있는 메모리 영역을 말합니다. 이 영역에서는 대량의 데이터를 미리 읽어 들여 처리 속도를 향상할 수 있습니다. PCIe device의 configuration space에서는 configuration header 통해 해당 device의 메모리 공간이 prefetchable인지 non-prefetchable인지를 나타내는 플래그가 설정됩니다.
Base Address Register(BAR)
디바이스의 메모리와 I/O 자원에 대한 주소 매핑을 구성하는 중요한 구성 요소입니다. 이 register는 시스템이 각 PCIe 디바이스의 주소공간을 어떻게 참조하고 사용할 것인지를 정의합니다. PCIe device(Type0)의 configuration space에는 여러 개의 BAR이 있으며, 이들은 디바이스가 시스템 메모리 내에서 사용할 메모리 또는 I/O 주소 공간의 base address를 정의합니다. BAR은 device의 MMIO나 PMIO에 사용됩니다.
BAR Example
다음 BAR를 통해 시스템 소프트웨어가 장치의 메모리 주소 공간 크기를 결정하고 할당하는 과정을 세 단계로 나눈 것입니다.
1. 초기 상태 및 설정
Device의 BAR의 초기 상태는 하위 bit가 고정되어 메모리 크기 및 유형을 나타내고(그림 참조), 상위 bit은 알 수 없는 값(X)으로 초기화되어 있습니다. 시스템 소프트웨어는 모든 BAR에 "모두 1 쓰기" 작업을 수행하여 쓰기 가능한 비트들을 설정합니다. 이렇게 하면 고정된 하위 비트를 제외한 나머지 쓰기 가능한 상위 비트들이(여기서는 12번째 bit부터) 모두 1로 설정됩니다. 이 과정을 통해 어떤 bit가 가장 낮은 쓰기 가능 bit인지 확인할 수 있으며, 이 bit의 위치는 요청된 주소 공간의 크기를 나타냅니다. 예를 들어, 가장 낮은 쓰기 가능 bit가 12번째 bit라면, 요청된 주소 공간은 4KB입니다.
2. 주소 공간의 크기 및 유형 확인
모든 1쓴 후에, 소프트웨어는 각 BAR을 읽어서 그 장치가 요청하는 주소 공간의 크기와 유형을 결정합니다. 첫 번째 BAR인 BAR0부터 시작하여 값을 읽습니다.
BAR Bits | 의미 |
0 | 0은 memory request를 나타냅니다. |
2:1 | 32bit memory address임을 나타냅니다. |
3 | 해당 요청이 non-prefetchable memory에 대한 request임을 나타냅니다. |
11:4 | 0으로 하드코딩되어 있는 상태. 이를 통해 주소 공간의 크기가 4KB임을 알 수 있습니다. |
31:12 | 할당된 시작 주소. 여기서는 F900_0000h로 설정. 이 주소는 BAR에 작성되어 해당 주소부터 4KB 메모리가 할당됨을 의미합다. |
3. 주소 범위 할당
주소 공간의 크기와 유형을 알게 된 후, 시스템 소프트웨어는 BAR0에 주소 범위를 할당합니다. 할당된 시작 주소는 BAR에 작성되어 해당 주소부터 메모리가 할당됨을 나타냅니다.
Base/Limit Registers
Baes/limit register 역시 BAR와 비슷하게 bridge(Type1)가 관리하는 버스의 메모리 및 IO 주소 범위를 정의합니다. Base register는 주어진 주소 범위의 시작 주소를 저장하며, Limit register는 주어진 주소 범위의 끝 주소를 저장합니다. 예를 들어, bridge는 두 개의 버스를 연결할 수 있으며 각 bus의 device는 다른 메모리 및 I/O 주소 범위를 사용할 수 있습니다. base/limit register는 이러한 각 범위를 제어하여, 브리지를 통한 데이터 트래픽이 올바른 목적지로 라우팅 되도록 합니다.
Base/Limit Example
다음 예제에서 endpoint는 4KB NP-MMIO(F900_0000h - F900_0FFFh)를 요청하고 이를 부여받았습니다.
Final Example Address Routing Setup
다음 예제는 Type0 device는 BAR를 통해, Type1 device는 base/limit register를 통해 routing을 위한 setup을 완료한 모습입니다. 이를 통해 적절한 주소 공간을 통해 packet이 올바르게 routing 할 수 있습니다.
Transaction 유형에 따른 Routing 방식
PCIe는 데이터 패킷을 전송할 때 여러 routing 방식을 사용하여 특정 목적지까지 data를 정확히 전달합니다. PCIe는 주로 세 가지 routing 방식을 사용하는데, 이는 address routing, ID routing(Bus/Device/Function, BDF), 및 Implicit Routing입니다. 가 방식은 특정 상황과 요구사항에 따라 선택됩니다. 쉽게 말하자면, 특정 transaction 유형마다 세 가지 유형 중 하나가 이미 정해져 있습니다. 예를 들어 memory read 및 write transaction은 address routing방식을 사용합니다.
TLP Type | Routing 방식 |
Memory Read, Memory Write, AtomicOp | Address Routing |
IO Read and Write | Address Routing |
Configuration Read and Write | ID Routing |
Message, Message with Data | Address Routing, ID Routing, or Implicit Routing |
Completion, completion With Data | ID Routing |
1. Address Routing
Address Routing 방식은 메모리 주소를 기반으로 패킷을 라우팅 합니다. 이 방식은 메모리 읽기 및 쓰기 요청에 주로 사용됩니다. 각 PCIe packet에는 목적지 디바이스의 메모리 주소가 포함되어 있으며, 이 주소 정보를 사용하여 라우터나 스위치는 패킷을 적절한 출력 포트로 전달합니다. address routing은 메모리 공간이 매핑된 디방시를 목표로 하며, 해당 디바이스가 패킷을 받아 처리하게 됩니다.
2. ID Routing (BDF Routing)
ID routing 혹은 BDF(Bus/Device/Function) Routing 방식은 디바이스의 고유 식별자를 사용하여 패킷을 라우팅합니다. PCIe에서 각 디바이스는 고유한 bus 번호, device 번호, 그리고 function 번호를 가집니다. 이 세 가지 숫자의 조합은 네트워크 내의 모든 디바이스를 유일하게 식별하는 데 사용됩니다. ID routing은 주로 configuration space 접근에 주로 사용되며, 패킷은 이 식별자를 기반으로 정확한 디바이스로 전송됩니다.
3. Implicit Routing
이 방식은 패킷의 종류에 따라 자동으로 결정되는 라우팅 방식입니다. 주로 MSI와 같은 메시지 인터럽트와 관련된 유형에 에서 사용됩니다. 예를 들어 무조건 위로 올려서 Root Complex에 도달하게 하는 방식이 이 방식에 해당합니다.
Next Topic
이번 글을 끝으로 PCIe introduction은 마무리합니다. 다음 글부터는 PCIe layer를 보다 자세하게 알아볼 예정이며, 그중에서 transaction layer를 이해해 봅시다.
Reference)
- PCI Express® Base Specification Revision 5.0 Version 1.0
- PCI Express Technology 3.0 (minshare)
'Interface Standards > PCIe' 카테고리의 다른 글
[5] PCIe - Data Link Layer (DLLP & Ack/Nak protocol) (0) | 2024.05.13 |
---|---|
[4] PCIe - Transaction Layer (Ordering) (0) | 2024.05.12 |
[3] PCIe - Transaction Layer (Quality of Service & Flow Control) (0) | 2024.05.12 |
[2] PCIe - Transaction Layer (TLPs) (0) | 2024.05.12 |
[0] PCIe - Introduction 1 (0) | 2024.05.11 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!