이 글은 제가 PCIe를 공부하면서 겪은 시행착오를 바탕으로 정리한 글입니다. PCIe를 처음 접하는 분들에게 좋은 길라잡이가 되었으면 합니다.
이전 글)
Quality of Service
QoS는 네트워크에서 데이터 전송의 질을 관리하고 보장하기 위한 기술과 정책의 집합을 의미합니다. QoS는 데이터 트래픽을 우선순위에 따라 처리하여, 네트워크의 성능을 최적화하고, 특정 응용 프로그램이나 서비스에 필요한 대역폭과 지연 시간을 보장하는 데 중요합니다.
PCIe에서 역시 QoS를 지원하는데, traffic class, virtual channel, port arbitration, vc arbitration을 통해 QoS를 지원합니다.
Traffic Class & Virtual Channel
Traffic Class
Packet header의 일부로서, src에서 dst까지 변하지 않고 유지됩니다. TC값은 해당 packet이 사용해야 할 VC를 지시합니다.
Virtual Channel
Link를 통해 traffic flow를 처리하는 buffer와 추가 로직을 포함합니다. VC0은 필수적이며, 나머지 7개의 VC는 선택적입니다. packet의 TC에 따라 특정 VC에 배치하며, 이는 traffic의 우선순위로 종류에 따라 적절한 리소스를 할당 및 관리에 도움을 줍니다. TC와 VC의 매핑 정보는 PCIe Extended Capability Space의 Virtual Channel Capability Structure에 명시되어 있습니다. 다음 그림은 virtual channel의 개념에 대한 예시입니다.
Transaction Ordering Rule
같은 TC내의 packet들에게 적용되는 규칙이며, 이는 동일한 TC내에서 data packet이 예측 가능하고 일관된 순서로 처리되도록 보장합니다. 그러나 다른 TC로 mapping 된 packet 간에는 정해진 순서가 없으므로, software는 다른 TC 값을 가지는 packet 간에 의존성이 있다면 주의 깊게 관리해야 합니다.
Port Arbitration
여러 디바이스 또는 포트가 공유하는 리소스에 대한 접근을 관리하고 조정하는 메커니즘입니다. 동일한 VC 중 어느 input port로 들어온 트래픽을 처리할 지에 대한 arbitration입니다.
VC Arbitration
쉽게 생각하여, 여러 VC가 있을 때, 어떤 방식으로 VC를 arbitration 할지에 대한 것입니다. 예를 들어서 2개의 VC가 있으며, 총 10번의 데이터 전송을 한다고 가정했을 때, 우선순위가 높은 VC1을 8번 보낼 때마다 우선순위가 낮은 VC0를 2번 보내는 방식으로 VC 간 전송 중재를 할 수 있습니다. 일반적으로 weighted round-robin방식을 사용합니다.
Flow Control
PCIe에서 flow control의 주요 목적은 수신 측에서 처리할 수 있는 것보다 더 많은 데이터가 전송되지 않도록 하여 수신 측의 버퍼 오버플로우를 방지하는 데 있습니다. 구현 메커니즘은 credit-based 방식으로 구현되면 각 연결에 대해 두 가지 중요한 credit 유형이 있는데:
- Data Credits: 이 credit은 실제 데이터를 전송하는 데 사용되며, 수신 측이 처리할 수 있는 데이터 양을 기준으로 합니다.
- Header Credits: header credit은 데이터 패킷의 헤더를 전송하는 데 사용되며, 각 트랜잭션 헤더에 대한 수신 가능한 버퍼 크기를 나타냅니다.
각 연결의 시작 시, 수신 측은 전송 측에 초기 credit 할당을 알립니다. data나 header가 수신되면, 수신측은 사용된 credit 만큼 감소시키고, 처리가 완료되면 사용된 credit을 회복시켜 다시 전송측에 credit을 반환합니다. 이 credit 교환 과정은 지속적으로 이루어지며, 데이터의 흐름을 동적으로 조절합니다.
위 그림은 flow control의 동작을 묘사하고 있습니다. 처음 접할 때 혼란스러운 것이 flow control은 transaction layer의 작업이지만 DLLP(Data Link Layer Packet)을 사용하여 수행됩니다. 비록 flow control 자체가 data link layer에서 수행되지만, transaction layer에서 발생하는 데이터 전송 요구에 의해 이러한 flow control을 필요하게 됩니다. 즉, transaction layer에서 생성된 데이터 요구가 data link layer를 통해 안정적으로 효율적으로 처리될 수 있도록 DLLP를 사용하는 것입니다.
또 다른 이유는 오버헤드 최소화입니다. flow control도 결국 링크 관리를 위한 추가적인 작업입니다. DLLP와 같은 작은 packet을 사용하여 이 오버헤드를 최소화하는 것입니다. 여담으로 CXL(Compute Express Link)에서는 link layer라는 개념이 존재하지만 flit packing/unpacking과 retry를 지원할 뿐 DLLP와 같은 추가적인 packet을 만들지는 않습니다. 추후 CXL에 관련된 내용도 정리하도록 하겠습니다. 다시 돌아와서, 수신 측의 data link layer는 사용 가능한 공간의 양을 기록하고 DLLP를 통해 Tx로 보냅니다. Tx가 DLLP를 받으면 FC counter값을 업데이트합니다.
The FC Initialization Sequence
Flow control 초기화 과정은 link layer의 DLCMSM(Data Link Control and Management State Machine)에 의해 관여됩니다. 다음 그림에서 보이는 것처럼, reset은 state machine을 DL_Inactive 상태로 만드며, DL_Inactive 상태에서는 link 및 transaction layer에 DL_Down 신호가 전송됩니다. 한편, physical layer로부터 LinkUp 신호를 기다립니다. 이는 LTSSM이 작업을 완료하고 physcial layer가 준비되었음을 나타냅니다. 이는 FC 초기화를 처리하는 두 단계를 포함하는 DL_Init 하위 상태로의 전환을 유발합니다.
FC_Init1
FC_INIT1 상태 동안 장치는 연속적으로 3개의 InitFC1 flow control DLLP를 전송하여 수신 버퍼 크기를 알립니다. 스펙에 따르면, packet은 Post, Non-posteed, Completion 순으로 전송되어야 합니다. 이 패킷들은 상대방 장치에 자신이 받을 수 있는 데이터의 양을 알려줍니다.
FC_Init2
이 단계에서는 앞서 보낸 credit 정보가 올바르게 전달되고 인식되었는지 확인하는 과정을 거칩니다. 각 장치는 다시 한번 credit 정보를 포함한 packet을 보내어 초기화가 성공적으로 이루어졌음을 확인합니다.
Flow Control Elements
Flow Control을 어떤 방식으로 구현하는지에 대해 좀 더 깊이 알아봅시다. 다음 그림은 flow control을 위한 송신 측과 수신 측에 있는 구성 요소들을 나타낸 것입니다.
송신측 요소
- Transactions Pending Buffer: 같은 virtual channel에서 보낼 transaction을 보관.
- Credits Consumed counter: 이 buffer에서 보낸 모든 transaction의 credit합을 포함. CC로 표현.
- Credit Limit counter: 수신자에 의해 해당 flow control buffer로 초기화. 초기화 후, flow control update packet이 주기적으로 전송되어 수신자에서 사용 가능해진 flow control credit을 업데이트. CL로 표현
- Flow Control Gating Logic: 수신자가 보류 중인 TLP를 수락할 수 있는 충분한 flow control credit을 가지고 있는지 여부를 결정하는 계산을 수행. 다음 TLP에 필요한 credit과 CC가 CL을 초과하지 않는지 확인.
수신측 요소
Flow Control Buffer: 들어오는 header나 data를 저장
Credit Allocated: 할당된(사용 가능한) 총 flow control credit을 추적.
Flow Control Example
예시를 같이 알아봅시다. 이 예시는 non-posted header에 관련된 flow control에 초점을 맞추고 있습니다.
1. 초기화 이후의 flow control
flow control 초기화가 완료된 후, 장치들은 정상 작동을 위해 준비됩니다. 이 예시에서는 flow control buffer는 2KB 크기이며, 각 credit은 5DW(20byte)이며 이는 총 102d(66h)의 flow control credit unit이 사용 가능함을 의미합니다. 왼쪽 그림은 초기화 후 각 카운터와 레지스터에 있는 값들을 포함한 관련 요소들을 보여줍니다.
송신자가 TLP를 보내기 위해 준비되면, 먼저 flow control credit을 확인해야 합니다. credit 검사는 2의 보수를 사용하여 수행되며, 다음 공식을 만족해야 합니다. DLLP의 header FC 필드의 크기가 8bit 이므로 계산하면 왼쪽과 같이 방정식을 만족하는 것을 볼 수 있습니다. 즉, 이 패킷은 전송될 수 있습니다.
Credit Check: (CR은 CC + PTLP에 필요한 credit)
CL 01100110b (66h) - CR 00000001b (01h) = n
CR is converted to 2's complement:
00000001 (CR)
11111110 (CR inverted)
11111110 + 1
11111111 (2's complement)
2's complement added to CL:
01100110 (CL)
11111111 (2's complement of CR)
01100101 = 65h (carry bit is dropped)
2. Flow Control Buffer Fills Up
이제 수신자가 어떤 이유로 잠시 동안 flow control buffer에서 transaction을 제거하지 못하는 상황을 가정해 보겠습니다. 시간이 흘러 결국 flow control buffer가 완전히 차게 될 것입니다. 이 상황에서 송신자가 다른 TLP를 보내려고 하고 flow control credit을 확인한다면,: CL은 66h이며, CR은 67h가 될 것이기에 위 방정식을 만족하지 못할 것입니다. 이제 CL값이 67h 이상으로 업데이트된 flow control DLLP를 받을 때까지 채널은 차단됩니다. 새로운 값이 CL register에 로드되면, 다시 한번 송신자의 크레딧 검사를 통해 TLP를 보낼 수 있습니다.
3. Counters Roll Over
CL 값이 rollover 되어서 CL - CR 값이 음수가 나올 수 있어 문제가 될 것 같지만, 2의 보수 계산법에서는 문제가 되지 않습니다. 그렇기에 CL값이 roll over 되어도 크레딧 검사는 올바르게 진행됩니다.
Flow Control Updates
수신자는 buffer에서 transaction이 제거될 때마다 이웃 장치에 사용 가능한 flow control credit을 정기적으로 업데이트해야 합니다. 다음 그림은 송신자가 버퍼가 가득 차 헤더 트랜잭션을 보낼 수 없었던 예를 보여줍니다. 이 그림에서 수신자는 flow control buffer에서 세 개의 헤더를 제거했습니다. 이제 더 많은 공간이 생겼지만, 인접 장치는 이 사실을 모를 것입니다. 헤더가 버퍼에서 제거됨에 따라 CREDITS_ALLOCATED 카운트는 66h에서 69h로 증가합니다. 이 새로운 카운트는 flow control DLLP를 사용하여 인접 장치의 CREDIT_LIMIT register에 보고됩니다. CL이 업데이트되면 추가 TLP가 이제 전송될 수 있습니다.
참고) DLLP 전송 실패 가능성
flow control DLLP가 어떠한 문제로 인해 전송에 실패한다면 어떻게 될까요? TLP 같은 경우 retry buffer에 복사본이 있어 재전송하면 되지만 DLLP에는 재생 메커니즘이 없으며, 오류가 발생하면 패킷이 단순히 드롭됩니다. 하지만 잘 생각해 보면 DLLP가 실패하더라도, 성공하는 다음 DLLP는 카운터를 다시 동기화할 것입니다. 이 경우 송신자가 다음 TLP를 보낼 수 있기 전에 FC credit을 기다리는 동안 일부 시간이 낭비될 수 있지만, 정보는 손실되지 않습니다.
Next Topic)
- 이번 글을 통해 transaction layer에서의 역할 중 하나인 Qos와 flow control에 대해 알아보았습니다. 다음 글은 transaction layer에서 하는 또 다른 역할인 transaction ordering에 대해 알아보도록 합시다.
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 |
[2] PCIe - Transaction Layer (TLPs) (0) | 2024.05.12 |
[1] PCIe - Introduction 2 (0) | 2024.05.11 |
[0] PCIe - Introduction 1 (0) | 2024.05.11 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!