[PCIe] Data Link Layer 완전 정리 | DLLP, ACK/NAK, Retry Buffer, 시퀀스 번호

2026. 6. 17. 22:03기초지식

반응형

Data Link Layer란?

PCIe 3계층 구조의 중간 레이어이다. Transaction Layer에서 내려온 TLP에 Sequence Number와 LCRC를 붙여 DLLP(Data Link Layer Packet)와 함께 Physical Layer로 전달한다. 수신 측에서는 LCRC 검사와 Sequence Number로 오류를 감지하고 ACK/NAK으로 재전송을 제어한다.

Data Link Layer의 핵심 기능은 세 가지이다. TLP 신뢰성 보장 (ACK/NAK + Retry), Flow Control UpdateFC 전송, 링크 관리 (DL_Up/Down 상태)이다.


TLP 전송 시 Data Link Layer가 추가하는 필드

// TLP가 Data Link Layer를 통과할 때의 구조
// [Sequence Number (2B)] [TLP Header + Payload] [LCRC (4B)]
//
// Sequence Number - 12-bit. TLP 식별 및 순서 보장. 0~4095 순환
// LCRC (Link CRC) - 32-bit CRC. Link 구간 오류 검출 전용
//                   End-to-End 보호는 TLP의 ECRC가 담당
//                   LCRC는 수신 후 스트립되어 상위 레이어로 올라가지 않음

Replay Buffer (Retry Buffer)

송신 측은 전송한 TLP의 사본을 Replay Buffer에 보관한다. ACK 수신 전까지 삭제하지 않는다. NAK 또는 Replay Timer 만료 시 Replay Buffer에서 해당 TLP를 재전송한다.

Replay Buffer 크기는 유한하다. 버퍼가 가득 차면 새로운 TLP 전송이 차단된다. 버퍼 크기는 링크 지연(Round-Trip Latency)과 링크 대역폭을 고려하여 설계한다.

// Replay Buffer 동작 흐름
// 1. TX: TLP + SeqNum 전송, Replay Buffer에 복사본 보관
// 2. RX: LCRC 검사
//    - 정상: ACK(AckNakSeqNum = 수신한 SeqNum) 전송
//    - 오류: NAK(AckNakSeqNum = 오류 SeqNum) 전송
// 3. TX: ACK 수신 시 해당 SeqNum까지 Replay Buffer에서 삭제
//         NAK 수신 시 해당 SeqNum부터 Replay Buffer에서 재전송
// 4. TX: Replay Timer 만료 시 ACK 없이도 재전송 (최대 4회)
//         4회 초과 시 링크 재초기화 (Recovery 상태 진입)

DLLP (Data Link Layer Packet)

DLLP는 TLP와 달리 Data Link Layer 자체에서 생성하고 소비한다. Transaction Layer로 올라가지 않는다. Physical Layer를 통해 점대점(Point-to-Point)으로 전달된다.

DLLP 구조는 4B 고정이다. [Type(1B)] [Type-specific(2B)] [CRC(1B)]이다.

DLLP 타입은 다음과 같다.

ACK - TLP 정상 수신 확인. AckNakSeqNum 포함
NAK - TLP 수신 오류. AckNakSeqNum 포함. 재전송 요청
UpdateFC_P - Posted FC Credit 업데이트 (PH, PD)
UpdateFC_NP - Non-Posted FC Credit 업데이트 (NPH, NPD)
UpdateFC_Cpl - Completion FC Credit 업데이트 (CplH, CplD)
PM_Enter_L1 - L1 전력 상태 진입 요청
PM_Enter_L23 - L2/L3 전력 상태 진입 요청
PM_Request_Ack - 전력 관리 요청 응답
Vendor-defined - 벤더 정의 타입


ACK/NAK 메커니즘 상세

// ACK DLLP 구조
// [7:0]  Type = 0x00 (ACK)
// [23:8] AckNakSeqNum - 성공적으로 수신한 마지막 TLP SeqNum
//                        이 SeqNum까지의 모든 TLP를 수신했다는 의미
//                        Cumulative ACK (누적 승인)
// [31:24] CRC

// NAK DLLP 구조
// [7:0]  Type = 0x10 (NAK)
// [23:8] AckNakSeqNum - 오류가 발생한 TLP SeqNum
//                        이 SeqNum부터 재전송 요청
// [31:24] CRC

ACK는 Cumulative 방식이다. SeqNum=10의 ACK는 0~10까지 모두 정상 수신했음을 의미한다. ACK Latency Timer가 만료되기 전에 ACK를 전송해야 한다. ACK를 늦게 보내면 Replay Timer가 만료되어 불필요한 재전송이 발생한다.


Replay Timer와 Replay Number

Replay Timer - 송신 측에서 ACK를 기다리는 타임아웃. 링크 속도와 길이에 따라 결정. 만료 시 Replay Buffer에서 재전송 시작

Replay Number - 연속 재전송 횟수 카운터. 0~3까지 증가. ACK 수신 시 0으로 리셋. 4(0b100)에 도달하면 링크 오류로 판단하고 Recovery 상태 진입 후 링크 재초기화

// Replay Timer 값 계산 (링크 속도별)
// Gen1 (2.5GT/s): Replay Timer = 4096 Symbol Time
// Gen2 (5GT/s):   Replay Timer = 4096 Symbol Time
// Gen3 (8GT/s):   Replay Timer = 4096 * (128b/130b ratio) 보정
// 실제 값은 링크 너비(x1~x16)와 Round-Trip Latency에 따라 달라짐

Flow Control UpdateFC

Transaction Layer가 TLP를 소비(처리)하면 Data Link Layer는 해당 Credit을 반환하는 UpdateFC DLLP를 상대방에게 전송한다. 이를 통해 송신 측은 수신 측 버퍼 가용량을 업데이트한다.

// UpdateFC DLLP 구조 (UpdateFC_P, UpdateFC_NP, UpdateFC_Cpl 공통)
// [7:0]   Type
// [9:8]   VC ID (Virtual Channel 식별)
// [19:10] HdrFC  - Header Credit 반환량
// [23:20] DataFC - Data Credit 반환량 (상위 4bit)
// [31:24] CRC
// (전체 32bit, DataFC는 8bit = [23:20]상위 + 별도 필드)

// FC Credit 단위
// Header Credit: 1 Credit = 1 TLP Header
// Data Credit:   1 Credit = 4 Bytes of payload

DL_Up / DL_Down 상태

Data Link Layer는 링크 상태를 DL_Up과 DL_Down으로 관리한다.

DL_Down - 링크 초기 상태 또는 오류 상태. TLP 전송 불가. Physical Layer의 LTSSM이 L0 상태에 도달하기 전이거나 링크 재초기화 중인 상태

DL_Up - 링크 정상 동작 상태. FC 초기화(InitFC) 완료 후 진입. TLP 전송 가능

// DL_Up 진입 조건
// 1. Physical Layer: LTSSM이 L0 상태 도달
// 2. Data Link Layer: InitFC 교환 완료
//    - 양방향으로 InitFC1, InitFC2 DLLP 교환
//    - 모든 VC의 Posted/Non-Posted/Completion FC 초기값 설정
// 3. Data Link Layer: DL_Up 상태로 전환
// 4. Transaction Layer에 DL_Up 통보 -> TLP 전송 가능

InitFC (Flow Control 초기화)

링크 트레이닝 완료 직후 Data Link Layer에서 수행한다. InitFC1, InitFC2 두 단계로 구성된다.

InitFC1 - 각 측이 초기 FC Credit 값을 담은 InitFC1 DLLP를 전송한다. 수신 측 버퍼 크기를 상대방에게 광고한다
InitFC2 - 동일한 FC Credit 값을 한 번 더 전송한다. 신뢰성 확보 목적

InitFC 완료 후 DL_Up 상태가 되고 실제 TLP 전송이 시작된다. UpdateFC는 이후 지속적으로 전송되어 버퍼 가용량을 동적으로 업데이트한다.


📚 다음 글

기초지식 카테고리 글 더보기