← Hardware

Hardware 01 · PCIe · Linux v6.18.37

Synopsys DesignWare PCIe: PHY부터 Configuration Space까지

Synopsys DesignWare PCIe Controller와 별도 PHY hard macro가 PIPE로 연결된 구성을 기준으로 전원, REFCLK, PERST#, SerDes/PCS, LTSSM, DBI, iATU와 Configuration Read까지 확인합니다.

검증 깊이
board → Linux 8 layers
그림
7 boundary diagrams
원본 코드
6 excerpts · 432 lines
기준
Linux v6.18.37

01 · QUESTION

무엇을 증명할 것인가

Linux가 장치를 찾지 못했을 때, 정말 PCI core 문제인지 아니면 그 전에 link 자체가 L0에 들어오지 못한 것인지 어떤 증거로 구분하는가?

Synopsys DesignWare PCIe Controller와 별도 PHY hard macro가 PIPE로 연결된 구성을 기준으로 전원, REFCLK, PERST#, SerDes/PCS, LTSSM, DBI, iATU와 Configuration Read까지 확인합니다. 이 글은 Linux 로그를 출발점으로 삼지 않습니다. 같은 사건이 보드, controller, firmware, kernel에서 어떤 이름과 번호로 바뀌는지 아래에서 위로 연결합니다.

PCIe의 점대점 연결은 인접한 두 포트 사이의 링크를 뜻하며, 장치에서 호스트까지 전용 대역폭을 보장한다는 뜻은 아닙니다. 스위치 뒤 endpoint마다 하행 링크가 따로 있어도 호스트 방향 트래픽은 같은 상행 링크를 공유할 수 있습니다. 또한 Linux의 P2P DMA 설명처럼 경로와 ACS(Access Control Services) 설정에 따라 장치 간 거래가 스위치 아래에서 전달되어 Root Port에 닿지 않을 수도 있습니다. 다른 계층으로 건너가는 P2P는 플랫폼 지원과 소프트웨어 정책을 별도로 확인해야 하므로, 모든 거래가 Root Complex를 거친다거나 모든 구성에서 직접 거래가 된다고 일반화하지 않습니다. 장치 탐색과 BAR·DMA·MSI 설정은 Linux 열거·자원·DMA·인터럽트 경로에서 이어서 확인합니다.

별도 플랫폼 사례: Zynq UltraScale+의 PS-GTR 공유

아래의 DesignWare 분석과는 별개로, Zynq UltraScale+ MPSoC에서는 여러 제어기가 네 개의 PS-GTR 송수신기를 공유합니다. AMD UG1137의 SIOU 설명은 PCIe, USB 3.0, DisplayPort, SATA, Ethernet 계열 인터페이스와 내부 연결 행렬(ICM)을 구분합니다. 제어기가 존재한다는 사실만으로 원하는 모든 인터페이스를 동시에 쓸 수 있는 것은 아닙니다. 해당 소자의 TRM에서 허용한 레인·제어기 조합과 클록 조건을 먼저 대조해야 합니다.

칩 내부 ICM 설정, 패키지 핀, 보드 배선, 외부 멀티플렉서는 서로 다른 확인 대상입니다. 외부 스위치로 커넥터의 연결 대상을 바꾸어도 PS-GTR 레인 수가 늘지는 않습니다. 보드 회로도와 초기화 설정에서 실제 연결과 선택 상태를 확인하고, 다른 보드의 멀티플렉서 설정이나 핀 배정을 그대로 재사용하지 않습니다. 이 사례를 DesignWare DBI·iATU 레지스터 설정으로 해석하지도 않습니다.

02 · CONTRACT

입력과 완료 조건

구분확인할 내용
입력안정된 전원 rail, 100MHz REFCLK, 해제 가능한 PERST#, 연결된 lane과 endpoint
출력L0 상태의 link와 Bus/Device/Function 0번 configuration header 응답
소유권PHY와 LTSSM은 controller hardware, bus number와 resource window는 firmware 및 Linux host bridge가 소유
완료 조건Link Status의 negotiated speed/width가 유효하고 Vendor ID read가 0xffff가 아님

03 · BOTTOM-UP

가장 아래 계층부터 확인하는 8단계

PCIe의 Transaction·Data Link·Physical 계층은 요청과 전송의 규칙을 정하지만 장치별 명령 의미까지 같게 만들지는 않습니다. NVMe는 별도 명령 체계와 NVMe over PCIe 전송 규격을 사용합니다. PCIe Ethernet NIC에서는 네트워크 패킷 데이터가 descriptor가 가리키는 호스트 메모리와 장치 사이를 DMA로 이동합니다. Ethernet과 NVMe를 동일한 PCIe 상위 프로토콜로 보거나, Application을 네 번째 PCIe 링크 계층으로 더하지 않습니다.

아래의 sequence number·LCRC·ACK/NAK 설명은 전통적인 non-Flit 전송을 읽는 기준입니다. Flit Mode의 오류 검사·재전송 형식을 같은 것으로 일반화하지 않습니다. 또한 링크의 ACK와 장치 명령의 완료는 다릅니다.

NVM Express의 PCIe 전송 규격 설명과 Intel PCIe GbE 개발자 매뉴얼, 3장 송수신 버퍼·descriptor을 구분해 읽습니다.

그림 1. 아래에서 Linux까지 올라오는 8개 검증 경계위 계층의 로그보다 아래 계층의 물리 증거를 먼저 확정합니다.
01
0. Board · 전원, reset, reference clock

Endpoint 전원 rail과 analog rail이 규격 범위에 들어온 뒤 REFCLK가 안정되고 PERST#가 최소 요구 시간 뒤 해제되어야 한다. common-clock 설계인지 SRNS/SRIS인지에 따라 양쪽 clock tolerance와 SSC 조건이 달라진다. CLKREQ#와 WAKE#는 link training의 필수 신호는 아니지만 ASPM, clock power management와 wake 동작을 검증할 때 반드시 분리해 본다.

증거: 전원 시퀀스 파형, REFCLK 주파수/SSC, PERST# 해제 시점, endpoint reset pin level

START
02
1. Electrical · Receiver detect와 lane electrical

Root Complex transmitter가 receiver termination을 검출하면서 Detect에서 Polling으로 이동한다. lane polarity inversion은 허용될 수 있지만 lane reversal 지원은 controller 구성에 달려 있다. insertion loss, AC coupling capacitor 위치, differential impedance와 lane mapping이 틀리면 Polling.Active 또는 Recovery에서 반복한다.

증거: 고속 scope/BER 장비, controller receiver-detect bitmap, lane별 training 상태

CHECKPOINT
03
2. LTSSM · TS1/TS2와 Detect → Polling → Configuration → L0

Ordered Set 교환으로 lane number, link number, speed와 training control을 맞춘다. Gen1에서 먼저 link를 만든 뒤 directed speed change로 상위 generation에 올라가는 controller도 많다. Recovery가 반복되면 equalization, clock, signal integrity 또는 상대편 capability를 구분해야 한다.

증거: LTSSM state history, Link Training bit, negotiated width/speed, equalization status

CHECKPOINT
04
3. Data Link · Sequence number, LCRC, ACK/NAK와 flow-control credit

Data Link Layer는 TLP에 sequence number와 LCRC를 붙이고 replay buffer로 손실을 복구한다. Posted, Non-Posted, Completion은 header/data credit가 따로 관리된다. credit가 0이면 물리 link가 L0여도 transaction이 진행하지 않는 것처럼 보일 수 있다.

증거: Bad DLLP/LCRC, Replay Number Rollover, replay timer, flow-control credit counter

CHECKPOINT
05
4. Transaction · Memory, Configuration, Completion TLP

Configuration Read는 requester ID, tag, first byte enable을 담아 전송되고 endpoint는 같은 tag를 가진 Completion with Data로 응답한다. Unsupported Request, Completer Abort, Completion Timeout은 서로 다른 failure다. Memory Write는 posted이므로 protocol completion이 없고 device register readback이나 별도 status로 완료를 확인해야 한다.

증거: protocol analyzer TLP, AER Uncorrectable Status, Completion Timeout, requester/completer ID

CHECKPOINT
06
5. Config · 4KiB Configuration Space와 capability list

첫 64 bytes에는 Vendor/Device ID, Command/Status, Class Code, Header Type과 BAR가 있다. PCIe Capability에는 Device/Link/Slot control과 status가 있고 0x100 이후 Extended Capability에는 AER, ACS, ATS, SR-IOV 등이 연결된다. ECAM은 bus/device/function/register를 physical address bit field로 바꾼다.

증거: ECAM base와 bus-range, `lspci -xxxx`, capability pointer loop, BAR size probe 결과

CHECKPOINT
07
6. Firmware · DT/ACPI host bridge description

Device Tree의 `reg`, `ranges`, `bus-range`, `num-lanes`, `max-link-speed`, reset/clock/PHY와 interrupt-map이 host controller를 설명한다. ACPI 시스템은 MCFG로 ECAM segment와 bus range를 제공하고 _CRS로 I/O와 MMIO aperture를 제공한다. firmware range와 실제 outbound ATU window가 일치해야 한다.

증거: live DT, ACPI MCFG/_CRS dump, controller DBI/ATU register와 host bridge resource log

CHECKPOINT
08
7. Linux · host probe와 첫 configuration read

host controller driver가 clock/reset/PHY를 켜고 root bus resource와 config-space accessor를 등록한다. PCI core가 device 0 function 0부터 Vendor ID를 읽어 function 존재 여부를 판단한다. 이때 실패하면 Linux log만 보지 말고 같은 시점의 LTSSM, AER, ATU와 ECAM physical address를 묶어서 본다.

증거: `dmesg`, dynamic debug, `lspci -vv`, `/sys/bus/pci/devices`, host controller trace

LINUX / RESULT
01

0. Board · 전원, reset, reference clock

Endpoint 전원 rail과 analog rail이 규격 범위에 들어온 뒤 REFCLK가 안정되고 PERST#가 최소 요구 시간 뒤 해제되어야 한다. common-clock 설계인지 SRNS/SRIS인지에 따라 양쪽 clock tolerance와 SSC 조건이 달라진다. CLKREQ#와 WAKE#는 link training의 필수 신호는 아니지만 ASPM, clock power management와 wake 동작을 검증할 때 반드시 분리해 본다.

남길 증거: 전원 시퀀스 파형, REFCLK 주파수/SSC, PERST# 해제 시점, endpoint reset pin level

이 단계가 실패하면 configuration read나 LTSSM register를 해석할 이유가 없다.

02

1. Electrical · Receiver detect와 lane electrical

Root Complex transmitter가 receiver termination을 검출하면서 Detect에서 Polling으로 이동한다. lane polarity inversion은 허용될 수 있지만 lane reversal 지원은 controller 구성에 달려 있다. insertion loss, AC coupling capacitor 위치, differential impedance와 lane mapping이 틀리면 Polling.Active 또는 Recovery에서 반복한다.

남길 증거: 고속 scope/BER 장비, controller receiver-detect bitmap, lane별 training 상태

모든 예상 lane이 detect되지 않으면 x4 설계가 x1로 축소되거나 link가 성립하지 않는다.

03

2. LTSSM · TS1/TS2와 Detect → Polling → Configuration → L0

Ordered Set 교환으로 lane number, link number, speed와 training control을 맞춘다. Gen1에서 먼저 link를 만든 뒤 directed speed change로 상위 generation에 올라가는 controller도 많다. Recovery가 반복되면 equalization, clock, signal integrity 또는 상대편 capability를 구분해야 한다.

남길 증거: LTSSM state history, Link Training bit, negotiated width/speed, equalization status

L0에 들어오기 전에는 정상 Memory/Configuration TLP 교환을 기대하지 않는다.

04

3. Data Link · Sequence number, LCRC, ACK/NAK와 flow-control credit

Data Link Layer는 TLP에 sequence number와 LCRC를 붙이고 replay buffer로 손실을 복구한다. Posted, Non-Posted, Completion은 header/data credit가 따로 관리된다. credit가 0이면 물리 link가 L0여도 transaction이 진행하지 않는 것처럼 보일 수 있다.

남길 증거: Bad DLLP/LCRC, Replay Number Rollover, replay timer, flow-control credit counter

link up과 transaction forward progress를 같은 의미로 보지 않는다.

05

4. Transaction · Memory, Configuration, Completion TLP

Configuration Read는 requester ID, tag, first byte enable을 담아 전송되고 endpoint는 같은 tag를 가진 Completion with Data로 응답한다. Unsupported Request, Completer Abort, Completion Timeout은 서로 다른 failure다. Memory Write는 posted이므로 protocol completion이 없고 device register readback이나 별도 status로 완료를 확인해야 한다.

남길 증거: protocol analyzer TLP, AER Uncorrectable Status, Completion Timeout, requester/completer ID

0xffff read가 no-device인지 poisoned/completion timeout인지 AER과 root-port status로 나눈다.

06

5. Config · 4KiB Configuration Space와 capability list

첫 64 bytes에는 Vendor/Device ID, Command/Status, Class Code, Header Type과 BAR가 있다. PCIe Capability에는 Device/Link/Slot control과 status가 있고 0x100 이후 Extended Capability에는 AER, ACS, ATS, SR-IOV 등이 연결된다. ECAM은 bus/device/function/register를 physical address bit field로 바꾼다.

남길 증거: ECAM base와 bus-range, `lspci -xxxx`, capability pointer loop, BAR size probe 결과

ECAM window와 bus-range가 틀리면 link가 정상이어도 Linux는 0xffff만 읽는다.

07

6. Firmware · DT/ACPI host bridge description

Device Tree의 `reg`, `ranges`, `bus-range`, `num-lanes`, `max-link-speed`, reset/clock/PHY와 interrupt-map이 host controller를 설명한다. ACPI 시스템은 MCFG로 ECAM segment와 bus range를 제공하고 _CRS로 I/O와 MMIO aperture를 제공한다. firmware range와 실제 outbound ATU window가 일치해야 한다.

남길 증거: live DT, ACPI MCFG/_CRS dump, controller DBI/ATU register와 host bridge resource log

주소 변환 창이 겹치거나 크기가 다르면 enumeration 뒤 BAR access에서 abort가 난다.

08

7. Linux · host probe와 첫 configuration read

host controller driver가 clock/reset/PHY를 켜고 root bus resource와 config-space accessor를 등록한다. PCI core가 device 0 function 0부터 Vendor ID를 읽어 function 존재 여부를 판단한다. 이때 실패하면 Linux log만 보지 말고 같은 시점의 LTSSM, AER, ATU와 ECAM physical address를 묶어서 본다.

남길 증거: `dmesg`, dynamic debug, `lspci -vv`, `/sys/bus/pci/devices`, host controller trace

Vendor ID와 class code가 안정적으로 읽혀야 resource sizing 단계로 넘어간다.

04 · DIAGRAMS

주소와 상태가 이동하는 모습

그림 2. PCIe 실행 경로왼쪽부터 신호나 데이터를 처리하는 순서를 나타냅니다. 각 단계에서 확인할 항목을 함께 표시했습니다.
01 Power stable
02 REFCLK valid
03 PERST# high
04 Receiver Detect
05 TS1/TS2
06 L0
그림 3. firmware와 Linux 번호 공간의 연결왼쪽부터 신호나 데이터를 처리하는 순서를 나타냅니다. 각 단계에서 확인할 항목을 함께 표시했습니다.
01 CfgRd0 TLP
02 Root Port routing
03 Endpoint config
04 CplD TLP
05 Vendor ID
06 pci_dev 생성
그림 4. 입력, 소유권, 완료 조건의 경계완료 조건을 충족하기 전에는 다음 계층이 해당 자원을 재사용하면 안 됩니다.
INPUT

안정된 전원 rail, 100MHz REFCLK, 해제 가능한 PERST#, 연결된 lane과 endpoint

OWNER

PHY와 LTSSM은 controller hardware, bus number와 resource window는 firmware 및 Linux host bridge가 소유

OUTPUT

L0 상태의 link와 Bus/Device/Function 0번 configuration header 응답

DONE

Link Status의 negotiated speed/width가 유효하고 Vendor ID read가 0xffff가 아님

05 · SYNOPSYS DESIGNWARE IP

Synopsys DesignWare PCIe Controller와 PHY 경계

여기서는 SoC에 가장 널리 통합되는 Synopsys DesignWare PCIe digital controller를 Root Complex로 사용하고, 별도의 PCIe PHY hard macro가 PIPE로 연결된 구성을 기준으로 읽습니다. 실제 PHY register와 SoC application register는 공정·SoC 업체마다 달라지지만, DWC DBI/Port Logic/iATU와 Linux dw_pcie 공통 계층의 경계는 반복해서 나타납니다.

그림 5. Synopsys DWC PCIe subsystem의 실제 분할SoC glue, digital controller, PIPE, PHY를 서로 다른 register bank로 봅니다.
01

SoC application logic

전원 domain, APB/AXI clock, core/PHY reset, PERST#, device type(RC/EP), LTSSM enable을 제어합니다.

관찰
vendor glue driver와 application register
대표 실패
PERST#와 LTSSM enable 순서가 바뀌면 Detect 이전 또는 Polling에서 정지
02

DBI configuration

Root Port의 Type-1 Configuration Space와 PCIe Capability를 CPU가 programming하는 내부 register 창입니다.

관찰
dbi_base, DBI read/write, PCI_COMMAND/LINK_CAP
대표 실패
DBI clock/reset이 없으면 값이 0 또는 bus fault이며 link 문제와 구분해야 함
03

Port Logic / LTSSM

lane mode, N_FTS, speed change, equalization과 Detect→Polling→Configuration→L0 상태를 관리합니다.

관찰
0x710, 0x728, 0x72c, 0x80c, 0x890 계열
대표 실패
controller 상태는 Polling인데 PHY PLL만 lock된 것을 link-up으로 오판
04

Transaction / Data Link

TLP 생성·routing, ACK/NAK, replay, flow-control credit, Root Port bridge 동작을 수행합니다.

관찰
AER, replay/credit counter, protocol analyzer
대표 실패
L0인데 Completion Timeout이면 electrical보다 routing/iATU/config path를 먼저 확인
05

AXI bridge

CPU의 AXI transaction을 PCIe TLP로, inbound PCIe request를 SoC AXI transaction으로 바꿉니다.

관찰
AXI decode, outstanding ID, ordering, slave/master error
대표 실패
AXI DECERR/SLVERR를 endpoint completion 오류와 구분
06

iATU

CPU address와 PCIe address/BDF를 outbound·inbound region으로 변환합니다. 구형 viewport 방식과 v4.80a 이후 unrolled register 방식이 있습니다.

관찰
region type, base, limit, target, enable
대표 실패
L0인데 config read가 0xffff이면 CFG0/CFG1 region과 BDF target을 우선 검사
07

MSI / eDMA option

DWC 내부 MSI controller와 선택적 eDMA가 포함될 수 있지만 SoC가 외부 MSI domain이나 별도 DMA를 사용할 수도 있습니다.

관찰
MSI address/mask/status, eDMA channel/LLP
대표 실패
IP configuration과 Linux driver가 기대하는 interrupt/DMA 구현 불일치
08

PIPE / PCIe PHY

Controller와 PHY 사이에서 power state, rate, electrical idle, receiver detect, Tx/Rx data와 status를 교환합니다.

관찰
PIPE state와 vendor PHY status를 같은 timestamp로 수집
대표 실패
PHY ready와 controller LTSSM 진행 사이에서 처음 끊긴 handshake를 찾음

PHY와 Controller가 만나는 PIPE 경계

한쪽 register만 보고 link 상태를 판정하지 않습니다. 동일 사건에 대해 PHY evidence와 controller evidence를 같은 행에 놓고 처음 불일치하는 구간을 찾습니다.

단계PHY 쪽에서 확인DWC Controller 쪽에서 확인경계 판정
Power/resetanalog/digital rail, PLL/SerDes reset, calibration 완료DBI/APB/AXI clock과 core reset, LTSSM disable 유지PHY calibration 전에 LTSSM을 시작하지 않음
Reference clockREFCLK 수신, PLL lock, SRNS/SRIS/common-clock modeLink Capability와 SRIS deskew/N_FTS 정책PLL lock은 receiver detect나 link-up을 의미하지 않음
Receiver Detecttermination detect 결과와 lane별 Rx readinessDetect state에서 PIPE 요청을 발행하고 결과를 소비예상 lane별 detect bitmap과 LTSSM state를 함께 기록
Polling / TS1·TS2직렬화·복구 clock·CDR, Tx/Rx electrical pathordered set 생성/해석, lane/link number와 polarity·lane reversal 정책PIPE RxStatus만 보지 말고 controller training state와 lane map을 대조
Gen3+ EqualizationCTLE/DFE, Tx preset/coeff 적용, eye/BER와 PVT marginRecovery.Equalization phase, preset request·평가와 directed speed changePHY FOM/eye가 좋아도 controller phase가 timeout이면 PIPE control 교환 검사
L0 / power stateelectrical idle exit, L0s/L1/L1SS 진입·복귀, clock/power gatingDLL active, credit/replay와 ASPM 정책ASPM off 비교로 PHY wake 지연과 protocol 오류를 분리

DWC 공개 register와 읽는 목적

Register/영역역할검증 시 주의점
DBI baseRoot Port Type-1 config와 capabilityDBI read-only write enable은 제한된 초기화 구간에서만 사용
PCIE_PORT_LINK_CONTROL 0x710DLL enable과 x1/x2/x4/x8/x16 link modesynthesis lane 수, DT num-lanes, PHY lane 수가 모두 일치해야 함
PCIE_PORT_DEBUG0 0x728하위 6bit LTSSM state0x11은 L0이며 단발 read보다 histogram이 유용
PCIE_PORT_DEBUG1 0x72clink-up과 link-in-training bit두 bit와 표준 PCI_EXP_LNKSTA를 함께 비교
PCIE_LINK_WIDTH_SPEED_CONTROL 0x80cnegotiated width가 아니라 target width와 speed-change 요청PORT_LOGIC_SPEED_CHANGE가 장시간 남으면 Recovery/equalization 확인
GEN3_RELATED_OFF 0x890Gen3 equalization·rate shadow 관련 DWC port logicIP version과 PHY PIPE 세대에 맞는 programming만 적용
PCIE_VERSION_NUMBER/TYPE 0x8f8/0x8fcDWC component version과 typequirk를 SoC 이름만으로 선택하지 말고 IP version도 기록
iATU viewport/unrollCFG0/CFG1/MEM/IO outbound와 inbound regionv4.80a 전후 접근 방식을 혼동하면 잘못된 register에 기록
그림 6. DWC와 PHY 초기화 순서왼쪽부터 신호나 데이터를 처리하는 순서를 나타냅니다. 각 단계에서 확인할 항목을 함께 표시했습니다.
01 Rails stable
02 PHY reset release
03 PHY calibration/PLL lock
04 DWC DBI clock/reset release
05 RC mode programming
06 PERST# release
07 LTSSM enable
08 L0
그림 7. 주소 또는 상태가 DWC를 통과하는 경로왼쪽부터 신호나 데이터를 처리하는 순서를 나타냅니다. 각 단계에서 확인할 항목을 함께 표시했습니다.
01 CPU config address
02 DWC AXI slave
03 outbound iATU CFG0/CFG1
04 Configuration TLP
05 Endpoint CplD
06 DWC completion
07 CPU Vendor ID

PHY를 controller register로 판단하지 않는다

DWC Port Debug의 LTSSM state는 controller가 보는 protocol state다. PLL lock, CDR lock, receiver detect, lane calibration, equalizer adaptation은 PHY 또는 SoC application register에서 따로 읽어야 한다. 두 register bank의 timestamp를 맞춰야 PIPE 경계의 deadlock을 찾을 수 있다.

PIPE 세대에 따라 책임이 이동한다

전통적인 PIPE에서는 PHY PCS가 encoding/decoding과 elastic buffer의 더 많은 부분을 담당할 수 있다. PIPE 5 SerDes architecture는 8b/10b·128b/130b encoding과 일부 protocol-specific 동작을 controller 쪽으로 옮긴다. 따라서 같은 ‘PHY 문제’라는 말을 쓰더라도 사용한 PIPE architecture를 먼저 확정해야 한다.

Synopsys common core와 SoC glue를 분리한다

Linux의 pcie-designware*.c는 DBI, iATU, Root Port와 공통 link 설정을 제공한다. Exynos, i.MX, Tegra 같은 glue driver는 clock/reset/PHY/application register와 LTSSM start_link를 구현한다. probe call graph에서 두 계층을 섞으면 누가 PHY를 켜야 하는지 놓치기 쉽다.

공개 register와 vendor PHY register의 범위

DWC Port Logic과 iATU offset은 Linux 소스에서 확인할 수 있지만, 실제 Synopsys PHY hard macro의 세부 tuning register는 라이선스 databook 및 SoC vendor TRM에 의존한다. 홈페이지에서는 공개적으로 검증 가능한 상태 이름과 경계를 사용하고 임의의 PHY offset을 만들어 쓰지 않습니다.

06 · DETAILED MANUAL

DWC Controller와 PHY를 실제로 구분해서 읽는 상세 매뉴얼

Synopsys 전체 databook은 IP 설정과 라이선스 옵션에 따라 내용이 달라집니다. 아래 내용은 공개된 Synopsys 제품 정보, PIPE 구조 설명, Linux v6.18.37 DWC 공통 드라이버와 공개 register 정의에서 다시 확인할 수 있는 범위만 사용합니다. PHY tuning 값이나 SoC application register offset처럼 공개 자료만으로 확정할 수 없는 값은 임의로 채우지 않고, 어느 문서와 어느 측정값에서 확인해야 하는지를 적습니다.

공개적으로 다시 확인할 수 있는 자료

공개되지 않은 제조사 레지스터나 제품별 오프셋은 추측하지 않았습니다. 아래의 제조사 자료, 아키텍처 문서, Linux v6.18.37 원본으로 확인할 수 있는 내용만 다뤘습니다.

Synopsys PCIe 5.0 PHY

PHY가 담당하는 SerDes, equalization, lane margining과 진단 기능의 공개 범위

07 · REGISTERS

읽어야 할 상태와 해석

같은 동작에 대한 활성화 상태, 처리 상태, 자원 소유권, 완료 레지스터 값을 함께 기록합니다. 읽으면 지워지는 비트나 1을 써야 지워지는 비트가 있는지는 먼저 데이터시트에서 확인합니다.

레지스터/상태소유 블록검증할 의미
PERST# / REFCLKboard signalreset deassert 전에 clock과 power가 안정됐는지 확인
LTSSM statecontroller-specificDetect/Polling/Recovery/L0 중 어디서 반복하는지 기록
PCI_EXP_LNKSTAPCIe Capability + 0x12현재 speed, negotiated width, training 상태
PCI_COMMANDConfig 0x04Memory/IO/Bus Master enable은 enumeration 이후 별도 단계
PCI_BAR0..5Config 0x10..0x24size probe와 assigned address를 구분
AER UE/CE StatusExtended CapabilityCompletion timeout, malformed TLP, bad DLLP/LCRC 분리

08 · LINUX SOURCE

Linux v6.18.37 원본 코드와 줄별 해설

라인 번호를 고정해 외우는 대신 함수 선언을 기준으로 Linux v6.18.37 tree에서 다시 찾았습니다. 로컬 tree에 있는 파일은 실제 코드를 직접 싣고, 나머지는 원본 파일과 읽을 함수 좌표를 연결했습니다.

Linux v6.18.37 · 실제 원본 코드

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의

drivers/pci/controller/dwc/pcie-designware.h:70-200

70#define LINK_WAIT_IATU			9
71 
72/* Synopsys-specific PCIe configuration registers */
73#define PCIE_PORT_FORCE			0x708
74#define PORT_FORCE_DO_DESKEW_FOR_SRIS	BIT(23)
75 
76#define PCIE_PORT_AFR			0x70C
77#define PORT_AFR_N_FTS_MASK		GENMASK(15, 8)
78#define PORT_AFR_N_FTS(n)		FIELD_PREP(PORT_AFR_N_FTS_MASK, n)
79#define PORT_AFR_CC_N_FTS_MASK		GENMASK(23, 16)
80#define PORT_AFR_CC_N_FTS(n)		FIELD_PREP(PORT_AFR_CC_N_FTS_MASK, n)
81#define PORT_AFR_ENTER_ASPM		BIT(30)
82#define PORT_AFR_L0S_ENTRANCE_LAT_SHIFT	24
83#define PORT_AFR_L0S_ENTRANCE_LAT_MASK	GENMASK(26, 24)
84#define PORT_AFR_L1_ENTRANCE_LAT_SHIFT	27
85#define PORT_AFR_L1_ENTRANCE_LAT_MASK	GENMASK(29, 27)
86 
87#define PCIE_PORT_LINK_CONTROL		0x710
88#define PORT_LINK_DLL_LINK_EN		BIT(5)
89#define PORT_LINK_FAST_LINK_MODE	BIT(7)
90#define PORT_LINK_MODE_MASK		GENMASK(21, 16)
91#define PORT_LINK_MODE(n)		FIELD_PREP(PORT_LINK_MODE_MASK, n)
92#define PORT_LINK_MODE_1_LANES		PORT_LINK_MODE(0x1)
93#define PORT_LINK_MODE_2_LANES		PORT_LINK_MODE(0x3)
94#define PORT_LINK_MODE_4_LANES		PORT_LINK_MODE(0x7)
95#define PORT_LINK_MODE_8_LANES		PORT_LINK_MODE(0xf)
96#define PORT_LINK_MODE_16_LANES		PORT_LINK_MODE(0x1f)
97 
98#define PCIE_PORT_LANE_SKEW		0x714
99#define PORT_LANE_SKEW_INSERT_MASK	GENMASK(23, 0)
100 
101#define PCIE_PORT_DEBUG0		0x728
102#define PORT_LOGIC_LTSSM_STATE_MASK	0x3f
103#define PORT_LOGIC_LTSSM_STATE_L0	0x11
104#define PCIE_PORT_DEBUG1		0x72C
105#define PCIE_PORT_DEBUG1_LINK_UP		BIT(4)
106#define PCIE_PORT_DEBUG1_LINK_IN_TRAINING	BIT(29)
107 
108#define PCIE_LINK_WIDTH_SPEED_CONTROL	0x80C
109#define PORT_LOGIC_N_FTS_MASK		GENMASK(7, 0)
110#define PORT_LOGIC_SPEED_CHANGE		BIT(17)
111#define PORT_LOGIC_LINK_WIDTH_MASK	GENMASK(12, 8)
112#define PORT_LOGIC_LINK_WIDTH(n)	FIELD_PREP(PORT_LOGIC_LINK_WIDTH_MASK, n)
113#define PORT_LOGIC_LINK_WIDTH_1_LANES	PORT_LOGIC_LINK_WIDTH(0x1)
114#define PORT_LOGIC_LINK_WIDTH_2_LANES	PORT_LOGIC_LINK_WIDTH(0x2)
115#define PORT_LOGIC_LINK_WIDTH_4_LANES	PORT_LOGIC_LINK_WIDTH(0x4)
116#define PORT_LOGIC_LINK_WIDTH_8_LANES	PORT_LOGIC_LINK_WIDTH(0x8)
117 
118#define PCIE_MSI_ADDR_LO		0x820
119#define PCIE_MSI_ADDR_HI		0x824
120#define PCIE_MSI_INTR0_ENABLE		0x828
121#define PCIE_MSI_INTR0_MASK		0x82C
122#define PCIE_MSI_INTR0_STATUS		0x830
123 
124#define GEN3_RELATED_OFF			0x890
125#define GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL	BIT(0)
126#define GEN3_RELATED_OFF_RXEQ_RGRDLESS_RXTS	BIT(13)
127#define GEN3_RELATED_OFF_GEN3_EQ_DISABLE	BIT(16)
128#define GEN3_RELATED_OFF_RATE_SHADOW_SEL_SHIFT	24
129#define GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK	GENMASK(25, 24)
130 
131#define GEN3_EQ_CONTROL_OFF			0x8A8
132#define GEN3_EQ_CONTROL_OFF_FB_MODE		GENMASK(3, 0)
133#define GEN3_EQ_CONTROL_OFF_PHASE23_EXIT_MODE	BIT(4)
134#define GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC	GENMASK(23, 8)
135#define GEN3_EQ_CONTROL_OFF_FOM_INC_INITIAL_EVAL	BIT(24)
136 
137#define GEN3_EQ_FB_MODE_DIR_CHANGE_OFF		0x8AC
138#define GEN3_EQ_FMDC_T_MIN_PHASE23		GENMASK(4, 0)
139#define GEN3_EQ_FMDC_N_EVALS			GENMASK(9, 5)
140#define GEN3_EQ_FMDC_MAX_PRE_CURSOR_DELTA	GENMASK(13, 10)
141#define GEN3_EQ_FMDC_MAX_POST_CURSOR_DELTA	GENMASK(17, 14)
142 
143#define PCIE_PORT_MULTI_LANE_CTRL	0x8C0
144#define PORT_MLTI_UPCFG_SUPPORT		BIT(7)
145 
146#define PCIE_VERSION_NUMBER		0x8F8
147#define PCIE_VERSION_TYPE		0x8FC
148 
149/*
150 * iATU inbound and outbound windows CSRs. Before the IP-core v4.80a each
151 * iATU region CSRs had been indirectly accessible by means of the dedicated
152 * viewport selector. The iATU/eDMA CSRs space was re-designed in DWC PCIe
153 * v4.80a in a way so the viewport was unrolled into the directly accessible
154 * iATU/eDMA CSRs space.
155 */
156#define PCIE_ATU_VIEWPORT		0x900
157#define PCIE_ATU_REGION_DIR_IB		BIT(31)
158#define PCIE_ATU_REGION_DIR_OB		0
159#define PCIE_ATU_VIEWPORT_BASE		0x904
160#define PCIE_ATU_UNROLL_BASE(dir, index) \
161	(((index) << 9) | ((dir == PCIE_ATU_REGION_DIR_IB) ? BIT(8) : 0))
162#define PCIE_ATU_VIEWPORT_SIZE		0x2C
163#define PCIE_ATU_REGION_CTRL1		0x000
164#define PCIE_ATU_INCREASE_REGION_SIZE	BIT(13)
165#define PCIE_ATU_TYPE_MEM		0x0
166#define PCIE_ATU_TYPE_IO		0x2
167#define PCIE_ATU_TYPE_CFG0		0x4
168#define PCIE_ATU_TYPE_CFG1		0x5
169#define PCIE_ATU_TYPE_MSG		0x10
170#define PCIE_ATU_TD			BIT(8)
171#define PCIE_ATU_FUNC_NUM(pf)           ((pf) << 20)
172#define PCIE_ATU_REGION_CTRL2		0x004
173#define PCIE_ATU_ENABLE			BIT(31)
174#define PCIE_ATU_BAR_MODE_ENABLE	BIT(30)
175#define PCIE_ATU_CFG_SHIFT_MODE_ENABLE	BIT(28)
176#define PCIE_ATU_INHIBIT_PAYLOAD	BIT(22)
177#define PCIE_ATU_FUNC_NUM_MATCH_EN      BIT(19)
178#define PCIE_ATU_LOWER_BASE		0x008
179#define PCIE_ATU_UPPER_BASE		0x00C
180#define PCIE_ATU_LIMIT			0x010
181#define PCIE_ATU_LOWER_TARGET		0x014
182#define PCIE_ATU_BUS(x)			FIELD_PREP(GENMASK(31, 24), x)
183#define PCIE_ATU_DEV(x)			FIELD_PREP(GENMASK(23, 19), x)
184#define PCIE_ATU_FUNC(x)		FIELD_PREP(GENMASK(18, 16), x)
185#define PCIE_ATU_UPPER_TARGET		0x018
186#define PCIE_ATU_UPPER_LIMIT		0x020
187 
188#define PCIE_MISC_CONTROL_1_OFF		0x8BC
189#define PCIE_DBI_RO_WR_EN		BIT(0)
190 
191#define PCIE_MSIX_DOORBELL		0x948
192#define PCIE_MSIX_DOORBELL_PF_SHIFT	24
193 
194/*
195 * eDMA CSRs. DW PCIe IP-core v4.70a and older had the eDMA registers accessible
196 * over the Port Logic registers space. Afterwards the unrolled mapping was
197 * introduced so eDMA and iATU could be accessed via a dedicated registers
198 * space.
199 */
200#define PCIE_DMA_VIEWPORT_BASE		0x970

Linux v6.18.37 · 실제 원본 코드

DWC component version과 type을 실제 register에서 판별하는 과정

drivers/pci/controller/dwc/pcie-designware.c:194-260

194	of_property_read_u32(np, "num-lanes", &pci->num_lanes);
195 
196	if (of_property_read_bool(np, "snps,enable-cdm-check"))
197		dw_pcie_cap_set(pci, CDM_CHECK);
198 
199	return 0;
200}
201 
202void dw_pcie_version_detect(struct dw_pcie *pci)
203{
204	u32 ver;
205 
206	/* The content of the CSR is zero on DWC PCIe older than v4.70a */
207	ver = dw_pcie_readl_dbi(pci, PCIE_VERSION_NUMBER);
208	if (!ver)
209		return;
210 
211	if (pci->version && pci->version != ver)
212		dev_warn(pci->dev, "Versions don't match (%08x != %08x)\n",
213			 pci->version, ver);
214	else
215		pci->version = ver;
216 
217	ver = dw_pcie_readl_dbi(pci, PCIE_VERSION_TYPE);
218 
219	if (pci->type && pci->type != ver)
220		dev_warn(pci->dev, "Types don't match (%08x != %08x)\n",
221			 pci->type, ver);
222	else
223		pci->type = ver;
224}
225 
226u8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap)
227{
228	return PCI_FIND_NEXT_CAP(dw_pcie_read_cfg, PCI_CAPABILITY_LIST, cap,
229				 NULL, pci);
230}
231EXPORT_SYMBOL_GPL(dw_pcie_find_capability);
232 
233u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap)
234{
235	return PCI_FIND_NEXT_EXT_CAP(dw_pcie_read_cfg, 0, cap, NULL, pci);
236}
237EXPORT_SYMBOL_GPL(dw_pcie_find_ext_capability);
238 
239void dw_pcie_remove_capability(struct dw_pcie *pci, u8 cap)
240{
241	u8 cap_pos, pre_pos, next_pos;
242	u16 reg;
243 
244	cap_pos = PCI_FIND_NEXT_CAP(dw_pcie_read_cfg, PCI_CAPABILITY_LIST, cap,
245				 &pre_pos, pci);
246	if (!cap_pos)
247		return;
248 
249	reg = dw_pcie_readw_dbi(pci, cap_pos);
250	next_pos = (reg & 0xff00) >> 8;
251 
252	dw_pcie_dbi_ro_wr_en(pci);
253	if (pre_pos == PCI_CAPABILITY_LIST)
254		dw_pcie_writeb_dbi(pci, PCI_CAPABILITY_LIST, next_pos);
255	else
256		dw_pcie_writeb_dbi(pci, pre_pos + 1, next_pos);
257	dw_pcie_dbi_ro_wr_dis(pci);
258}
259EXPORT_SYMBOL_GPL(dw_pcie_remove_capability);
260 

Linux v6.18.37 · 실제 원본 코드

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup

drivers/pci/controller/dwc/pcie-designware.c:1155-1215

1155	 */
1156	l1ss_cap = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);
1157	l1ss_cap &= ~(PCI_L1SS_CAP_PCIPM_L1_1 | PCI_L1SS_CAP_ASPM_L1_1 |
1158		      PCI_L1SS_CAP_PCIPM_L1_2 | PCI_L1SS_CAP_ASPM_L1_2 |
1159		      PCI_L1SS_CAP_L1_PM_SS);
1160	dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, l1ss_cap);
1161}
1162 
1163void dw_pcie_setup(struct dw_pcie *pci)
1164{
1165	u32 val;
1166 
1167	dw_pcie_link_set_max_speed(pci);
1168 
1169	/* Configure Gen1 N_FTS */
1170	if (pci->n_fts[0]) {
1171		val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR);
1172		val &= ~(PORT_AFR_N_FTS_MASK | PORT_AFR_CC_N_FTS_MASK);
1173		val |= PORT_AFR_N_FTS(pci->n_fts[0]);
1174		val |= PORT_AFR_CC_N_FTS(pci->n_fts[0]);
1175		dw_pcie_writel_dbi(pci, PCIE_PORT_AFR, val);
1176	}
1177 
1178	/* Configure Gen2+ N_FTS */
1179	if (pci->n_fts[1]) {
1180		val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
1181		val &= ~PORT_LOGIC_N_FTS_MASK;
1182		val |= pci->n_fts[1];
1183		dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
1184	}
1185 
1186	if (dw_pcie_cap_is(pci, CDM_CHECK)) {
1187		val = dw_pcie_readl_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS);
1188		val |= PCIE_PL_CHK_REG_CHK_REG_CONTINUOUS |
1189		       PCIE_PL_CHK_REG_CHK_REG_START;
1190		dw_pcie_writel_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS, val);
1191	}
1192 
1193	val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);
1194	val &= ~PORT_LINK_FAST_LINK_MODE;
1195	val |= PORT_LINK_DLL_LINK_EN;
1196	dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val);
1197 
1198	dw_pcie_link_set_max_link_width(pci, pci->num_lanes);
1199}
1200 
1201resource_size_t dw_pcie_parent_bus_offset(struct dw_pcie *pci,
1202					  const char *reg_name,
1203					  resource_size_t cpu_phys_addr)
1204{
1205	struct device *dev = pci->dev;
1206	struct device_node *np = dev->of_node;
1207	int index;
1208	u64 reg_addr, fixup_addr;
1209	u64 (*fixup)(struct dw_pcie *pcie, u64 cpu_addr);
1210 
1211	/* Look up reg_name address on parent bus */
1212	index = of_property_match_string(np, "reg-names", reg_name);
1213 
1214	if (index < 0) {
1215		dev_err(dev, "No %s in devicetree \"reg\" property\n", reg_name);

Linux v6.18.37 · 실제 원본 코드

Gen3 이상 각 data rate와 lane의 equalization preset programming

drivers/pci/controller/dwc/pcie-designware-host.c:1014-1064

1014	/*
1015	 * Write preset values to the registers byte-by-byte for the given
1016	 * number of lanes and register size.
1017	 */
1018	for (i = 0; i < pci->num_lanes * lane_reg_size; i++)
1019		dw_pcie_writeb_dbi(pci, cap + lane_eq_offset + i, presets[i]);
1020}
1021 
1022static void dw_pcie_config_presets(struct dw_pcie_rp *pp)
1023{
1024	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
1025	enum pci_bus_speed speed = pcie_link_speed[pci->max_link_speed];
1026 
1027	/*
1028	 * Lane equalization settings need to be applied for all data rates the
1029	 * controller supports and for all supported lanes.
1030	 */
1031 
1032	if (speed >= PCIE_SPEED_8_0GT)
1033		dw_pcie_program_presets(pp, PCIE_SPEED_8_0GT);
1034 
1035	if (speed >= PCIE_SPEED_16_0GT)
1036		dw_pcie_program_presets(pp, PCIE_SPEED_16_0GT);
1037 
1038	if (speed >= PCIE_SPEED_32_0GT)
1039		dw_pcie_program_presets(pp, PCIE_SPEED_32_0GT);
1040 
1041	if (speed >= PCIE_SPEED_64_0GT)
1042		dw_pcie_program_presets(pp, PCIE_SPEED_64_0GT);
1043}
1044 
1045int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
1046{
1047	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
1048	u32 val;
1049	int ret;
1050 
1051	/*
1052	 * Enable DBI read-only registers for writing/updating configuration.
1053	 * Write permission gets disabled towards the end of this function.
1054	 */
1055	dw_pcie_dbi_ro_wr_en(pci);
1056 
1057	dw_pcie_setup(pci);
1058 
1059	dw_pcie_msi_init(pp);
1060 
1061	/* Setup RC BARs */
1062	dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0x00000004);
1063	dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_1, 0x00000000);
1064 

Linux v6.18.37 · 실제 원본 코드

DesignWare Root Port 초기화

drivers/pci/controller/dwc/pcie-designware-host.c:560-638

560	 * visconti_pcie_cpu_addr_fixup() uses pp->io_base, so we have to
561	 * call dw_pcie_parent_bus_offset() after setting pp->io_base.
562	 */
563	pci->parent_bus_offset = dw_pcie_parent_bus_offset(pci, "config",
564							   pp->cfg0_base);
565	return 0;
566}
567 
568int dw_pcie_host_init(struct dw_pcie_rp *pp)
569{
570	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
571	struct device *dev = pci->dev;
572	struct device_node *np = dev->of_node;
573	struct pci_host_bridge *bridge;
574	int ret;
575 
576	raw_spin_lock_init(&pp->lock);
577 
578	bridge = devm_pci_alloc_host_bridge(dev, 0);
579	if (!bridge)
580		return -ENOMEM;
581 
582	pp->bridge = bridge;
583 
584	ret = dw_pcie_host_get_resources(pp);
585	if (ret)
586		return ret;
587 
588	if (pp->ops->init) {
589		ret = pp->ops->init(pp);
590		if (ret)
591			goto err_free_ecam;
592	}
593 
594	if (pci_msi_enabled()) {
595		pp->has_msi_ctrl = !(pp->ops->msi_init ||
596				     of_property_present(np, "msi-parent") ||
597				     of_property_present(np, "msi-map"));
598 
599		/*
600		 * For the has_msi_ctrl case the default assignment is handled
601		 * in the dw_pcie_msi_host_init().
602		 */
603		if (!pp->has_msi_ctrl && !pp->num_vectors) {
604			pp->num_vectors = MSI_DEF_NUM_VECTORS;
605		} else if (pp->num_vectors > MAX_MSI_IRQS) {
606			dev_err(dev, "Invalid number of vectors\n");
607			ret = -EINVAL;
608			goto err_deinit_host;
609		}
610 
611		if (pp->ops->msi_init) {
612			ret = pp->ops->msi_init(pp);
613			if (ret < 0)
614				goto err_deinit_host;
615		} else if (pp->has_msi_ctrl) {
616			ret = dw_pcie_msi_host_init(pp);
617			if (ret < 0)
618				goto err_deinit_host;
619		}
620	}
621 
622	dw_pcie_version_detect(pci);
623 
624	dw_pcie_iatu_detect(pci);
625 
626	if (pci->num_lanes < 1)
627		pci->num_lanes = dw_pcie_link_get_max_link_width(pci);
628 
629	ret = of_pci_get_equalization_presets(dev, &pp->presets, pci->num_lanes);
630	if (ret)
631		goto err_free_msi;
632 
633	if (pp->ecam_enabled) {
634		ret = dw_pcie_config_ecam_iatu(pp);
635		if (ret) {
636			dev_err(dev, "Failed to configure iATU in ECAM mode\n");
637			goto err_free_msi;
638		}

Linux v6.18.37 · 실제 원본 코드

PCI bus scan 진입

drivers/pci/probe.c:3221-3263

3221	 *
3222	 * Return how far we've got finding sub-buses.
3223	 */
3224	dev_dbg(&bus->dev, "bus scan returning with max=%02x\n", max);
3225	return max;
3226}
3227 
3228/**
3229 * pci_scan_child_bus() - Scan devices below a bus
3230 * @bus: Bus to scan for devices
3231 *
3232 * Scans devices below @bus including subordinate buses. Returns new
3233 * subordinate number including all the found devices.
3234 */
3235unsigned int pci_scan_child_bus(struct pci_bus *bus)
3236{
3237	return pci_scan_child_bus_extend(bus, 0);
3238}
3239EXPORT_SYMBOL_GPL(pci_scan_child_bus);
3240 
3241/**
3242 * pcibios_root_bridge_prepare - Platform-specific host bridge setup
3243 * @bridge: Host bridge to set up
3244 *
3245 * Default empty implementation.  Replace with an architecture-specific setup
3246 * routine, if necessary.
3247 */
3248int __weak pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
3249{
3250	return 0;
3251}
3252 
3253void __weak pcibios_add_bus(struct pci_bus *bus)
3254{
3255}
3256 
3257void __weak pcibios_remove_bus(struct pci_bus *bus)
3258{
3259}
3260 
3261struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
3262		struct pci_ops *ops, void *sysdata, struct list_head *resources)
3263{

09 · VERIFICATION

실제 장비에서 확인하는 순서

  1. Board

    실행 scope로 power-good, REFCLK와 PERST#를 같은 trigger에 잡는다.

    통과 기준 reset이 clock보다 먼저 풀리거나 rail ramp 중 toggling이 없어야 한다.

  2. LTSSM

    실행 controller debug register를 1ms 간격으로 수집한다.

    통과 기준 L0 고정인지 Recovery 반복인지 state histogram으로 확인한다.

  3. Config

    실행 `lspci -s <BDF> -vvxxxx`와 root-port AER를 저장한다.

    통과 기준 Vendor/Device ID, Link Status, AER status가 같은 BDF를 가리켜야 한다.

  4. Address

    실행 ECAM 식으로 BDF register physical address를 계산한다.

    통과 기준 firmware MCFG/DT window와 controller outbound range 안에 있어야 한다.

  5. Stress

    실행 link retrain과 warm reset을 반복하며 width/speed를 기록한다.

    통과 기준 항상 같은 width/speed로 올라오고 correctable error 증가율이 안정적이어야 한다.

10 · FAILURE MATRIX

처음 끊긴 경계로 원인을 좁히기

관측 결과우선 의심할 경계다음 증거
Detect에 머묾receiver 미검출전원, AC coupling, lane 연결, endpoint reset
Polling/Recovery 반복TS 교환 또는 equalization 실패REFCLK/SSC, SI, polarity/lane map, preset
L0인데 0xffffECAM/ATU/bus-range 또는 endpoint config 응답 문제LTSSM과 config TLP/AER 동시 확인
x4가 x1로 협상일부 lane training 실패lane별 receiver detect와 equalization status
간헐 Completion Timeoutsignal integrity, power management, credit/replay 문제AER, replay counter, ASPM off 비교

핵심은 마지막 오류 메시지가 아니라 처음 기대값과 달라진 checkpoint입니다. 그보다 아래의 통과 증거와 그 지점의 실패 증거를 한 묶음으로 남겨야 수정의 효과도 검증할 수 있습니다.