← HardwareDUJINLABS.COM

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에서 어떤 이름과 번호로 바뀌는지 아래에서 위로 연결합니다.

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단계

그림 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처럼 공개 자료만으로 확정할 수 없는 값은 임의로 채우지 않고, 어느 문서와 어느 측정값에서 확인해야 하는지를 적습니다.

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

공개되지 않은 vendor register나 integration별 offset을 추측해서 채우지 않았습니다. 아래 제조사 자료, architecture 문서와 Linux v6.18.37 원본에서 다시 확인할 수 있는 범위만 사용했습니다.

Synopsys PCIe 5.0 PHY

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

07 · REGISTERS

읽어야 할 상태와 해석

값 하나만 떼어 보지 말고 동일 사건의 enable, status, ownership, completion register를 한 줄에 기록합니다. read-to-clear나 write-one-to-clear 속성은 반드시 datasheet에서 먼저 확인합니다.

레지스터/상태소유 블록검증할 의미
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
L70 #define LINK_WAIT_IATU 9

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L71 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L72 /* Synopsys-specific PCIe configuration registers */

원본 주석입니다. Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L73 #define PCIE_PORT_FORCE 0x708

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L74 #define PORT_FORCE_DO_DESKEW_FOR_SRIS BIT(23)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L75 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L76 #define PCIE_PORT_AFR 0x70C

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L77 #define PORT_AFR_N_FTS_MASK GENMASK(15, 8)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L78 #define PORT_AFR_N_FTS(n) FIELD_PREP(PORT_AFR_N_FTS_MASK, n)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L79 #define PORT_AFR_CC_N_FTS_MASK GENMASK(23, 16)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L80 #define PORT_AFR_CC_N_FTS(n) FIELD_PREP(PORT_AFR_CC_N_FTS_MASK, n)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L81 #define PORT_AFR_ENTER_ASPM BIT(30)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L82 #define PORT_AFR_L0S_ENTRANCE_LAT_SHIFT 24

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L83 #define PORT_AFR_L0S_ENTRANCE_LAT_MASK GENMASK(26, 24)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L84 #define PORT_AFR_L1_ENTRANCE_LAT_SHIFT 27

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L85 #define PORT_AFR_L1_ENTRANCE_LAT_MASK GENMASK(29, 27)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L86 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L87 #define PCIE_PORT_LINK_CONTROL 0x710

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L88 #define PORT_LINK_DLL_LINK_EN BIT(5)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L89 #define PORT_LINK_FAST_LINK_MODE BIT(7)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L90 #define PORT_LINK_MODE_MASK GENMASK(21, 16)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L91 #define PORT_LINK_MODE(n) FIELD_PREP(PORT_LINK_MODE_MASK, n)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L92 #define PORT_LINK_MODE_1_LANES PORT_LINK_MODE(0x1)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L93 #define PORT_LINK_MODE_2_LANES PORT_LINK_MODE(0x3)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L94 #define PORT_LINK_MODE_4_LANES PORT_LINK_MODE(0x7)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L95 #define PORT_LINK_MODE_8_LANES PORT_LINK_MODE(0xf)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L96 #define PORT_LINK_MODE_16_LANES PORT_LINK_MODE(0x1f)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L97 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L98 #define PCIE_PORT_LANE_SKEW 0x714

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L99 #define PORT_LANE_SKEW_INSERT_MASK GENMASK(23, 0)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L100 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L101 #define PCIE_PORT_DEBUG0 0x728

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L102 #define PORT_LOGIC_LTSSM_STATE_MASK 0x3f

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L103 #define PORT_LOGIC_LTSSM_STATE_L0 0x11

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L104 #define PCIE_PORT_DEBUG1 0x72C

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L105 #define PCIE_PORT_DEBUG1_LINK_UP BIT(4)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L106 #define PCIE_PORT_DEBUG1_LINK_IN_TRAINING BIT(29)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L107 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L108 #define PCIE_LINK_WIDTH_SPEED_CONTROL 0x80C

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L109 #define PORT_LOGIC_N_FTS_MASK GENMASK(7, 0)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L110 #define PORT_LOGIC_SPEED_CHANGE BIT(17)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L111 #define PORT_LOGIC_LINK_WIDTH_MASK GENMASK(12, 8)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L112 #define PORT_LOGIC_LINK_WIDTH(n) FIELD_PREP(PORT_LOGIC_LINK_WIDTH_MASK, n)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L113 #define PORT_LOGIC_LINK_WIDTH_1_LANES PORT_LOGIC_LINK_WIDTH(0x1)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L114 #define PORT_LOGIC_LINK_WIDTH_2_LANES PORT_LOGIC_LINK_WIDTH(0x2)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L115 #define PORT_LOGIC_LINK_WIDTH_4_LANES PORT_LOGIC_LINK_WIDTH(0x4)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L116 #define PORT_LOGIC_LINK_WIDTH_8_LANES PORT_LOGIC_LINK_WIDTH(0x8)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L117 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L118 #define PCIE_MSI_ADDR_LO 0x820

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L119 #define PCIE_MSI_ADDR_HI 0x824

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L120 #define PCIE_MSI_INTR0_ENABLE 0x828

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L121 #define PCIE_MSI_INTR0_MASK 0x82C

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L122 #define PCIE_MSI_INTR0_STATUS 0x830

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L123 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L124 #define GEN3_RELATED_OFF 0x890

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L125 #define GEN3_RELATED_OFF_GEN3_ZRXDC_NONCOMPL BIT(0)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L126 #define GEN3_RELATED_OFF_RXEQ_RGRDLESS_RXTS BIT(13)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L127 #define GEN3_RELATED_OFF_GEN3_EQ_DISABLE BIT(16)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L128 #define GEN3_RELATED_OFF_RATE_SHADOW_SEL_SHIFT 24

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L129 #define GEN3_RELATED_OFF_RATE_SHADOW_SEL_MASK GENMASK(25, 24)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L130 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L131 #define GEN3_EQ_CONTROL_OFF 0x8A8

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L132 #define GEN3_EQ_CONTROL_OFF_FB_MODE GENMASK(3, 0)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L133 #define GEN3_EQ_CONTROL_OFF_PHASE23_EXIT_MODE BIT(4)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L134 #define GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC GENMASK(23, 8)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L135 #define GEN3_EQ_CONTROL_OFF_FOM_INC_INITIAL_EVAL BIT(24)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L136 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L137 #define GEN3_EQ_FB_MODE_DIR_CHANGE_OFF 0x8AC

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L138 #define GEN3_EQ_FMDC_T_MIN_PHASE23 GENMASK(4, 0)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L139 #define GEN3_EQ_FMDC_N_EVALS GENMASK(9, 5)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L140 #define GEN3_EQ_FMDC_MAX_PRE_CURSOR_DELTA GENMASK(13, 10)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L141 #define GEN3_EQ_FMDC_MAX_POST_CURSOR_DELTA GENMASK(17, 14)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L142 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L143 #define PCIE_PORT_MULTI_LANE_CTRL 0x8C0

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L144 #define PORT_MLTI_UPCFG_SUPPORT BIT(7)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L145 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L146 #define PCIE_VERSION_NUMBER 0x8F8

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L147 #define PCIE_VERSION_TYPE 0x8FC

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L148 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L149 /*

원본 주석입니다. Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L150 * iATU inbound and outbound windows CSRs. Before the IP-core v4.80a each

원본 주석입니다. Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L151 * iATU region CSRs had been indirectly accessible by means of the dedicated

원본 주석입니다. Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L152 * viewport selector. The iATU/eDMA CSRs space was re-designed in DWC PCIe

원본 주석입니다. Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L153 * v4.80a in a way so the viewport was unrolled into the directly accessible

원본 주석입니다. Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L154 * iATU/eDMA CSRs space.

원본 주석입니다. Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L155 */

원본 주석입니다. Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L156 #define PCIE_ATU_VIEWPORT 0x900

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L157 #define PCIE_ATU_REGION_DIR_IB BIT(31)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L158 #define PCIE_ATU_REGION_DIR_OB 0

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L159 #define PCIE_ATU_VIEWPORT_BASE 0x904

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L160 #define PCIE_ATU_UNROLL_BASE(dir, index) \

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L161 (((index) << 9) | ((dir == PCIE_ATU_REGION_DIR_IB) ? BIT(8) : 0))

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L162 #define PCIE_ATU_VIEWPORT_SIZE 0x2C

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L163 #define PCIE_ATU_REGION_CTRL1 0x000

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L164 #define PCIE_ATU_INCREASE_REGION_SIZE BIT(13)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L165 #define PCIE_ATU_TYPE_MEM 0x0

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L166 #define PCIE_ATU_TYPE_IO 0x2

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L167 #define PCIE_ATU_TYPE_CFG0 0x4

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L168 #define PCIE_ATU_TYPE_CFG1 0x5

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L169 #define PCIE_ATU_TYPE_MSG 0x10

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L170 #define PCIE_ATU_TD BIT(8)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L171 #define PCIE_ATU_FUNC_NUM(pf) ((pf) << 20)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L172 #define PCIE_ATU_REGION_CTRL2 0x004

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L173 #define PCIE_ATU_ENABLE BIT(31)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L174 #define PCIE_ATU_BAR_MODE_ENABLE BIT(30)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L175 #define PCIE_ATU_CFG_SHIFT_MODE_ENABLE BIT(28)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L176 #define PCIE_ATU_INHIBIT_PAYLOAD BIT(22)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L177 #define PCIE_ATU_FUNC_NUM_MATCH_EN BIT(19)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L178 #define PCIE_ATU_LOWER_BASE 0x008

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L179 #define PCIE_ATU_UPPER_BASE 0x00C

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L180 #define PCIE_ATU_LIMIT 0x010

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L181 #define PCIE_ATU_LOWER_TARGET 0x014

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L182 #define PCIE_ATU_BUS(x) FIELD_PREP(GENMASK(31, 24), x)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L183 #define PCIE_ATU_DEV(x) FIELD_PREP(GENMASK(23, 19), x)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L184 #define PCIE_ATU_FUNC(x) FIELD_PREP(GENMASK(18, 16), x)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L185 #define PCIE_ATU_UPPER_TARGET 0x018

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L186 #define PCIE_ATU_UPPER_LIMIT 0x020

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L187 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L188 #define PCIE_MISC_CONTROL_1_OFF 0x8BC

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L189 #define PCIE_DBI_RO_WR_EN BIT(0)

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L190 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L191 #define PCIE_MSIX_DOORBELL 0x948

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L192 #define PCIE_MSIX_DOORBELL_PF_SHIFT 24

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L193 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L194 /*

원본 주석입니다. Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L195 * eDMA CSRs. DW PCIe IP-core v4.70a and older had the eDMA registers accessible

원본 주석입니다. Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L196 * over the Port Logic registers space. Afterwards the unrolled mapping was

원본 주석입니다. Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L197 * introduced so eDMA and iATU could be accessed via a dedicated registers

원본 주석입니다. Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L198 * space.

원본 주석입니다. Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L199 */

원본 주석입니다. Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L200 #define PCIE_DMA_VIEWPORT_BASE 0x970

Synopsys DWC Port Logic, link debug와 iATU 공개 register 정의의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

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 
L194 of_property_read_u32(np, "num-lanes", &pci->num_lanes);

공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.

L195 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L196 if (of_property_read_bool(np, "snps,enable-cdm-check"))

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L197 dw_pcie_cap_set(pci, CDM_CHECK);

DWC component version과 type을 실제 register에서 판별하는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L198 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L199 return 0;

호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.

L200 }

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L201 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L202 void dw_pcie_version_detect(struct dw_pcie *pci)

함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 DWC component version과 type을 실제 register에서 판별하는 과정의 입력 계약을 만족하는지 확인합니다.

L203 {

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L204 u32 ver;

DWC component version과 type을 실제 register에서 판별하는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L205 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L206 /* The content of the CSR is zero on DWC PCIe older than v4.70a */

원본 주석입니다. DWC component version과 type을 실제 register에서 판별하는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L207 ver = dw_pcie_readl_dbi(pci, PCIE_VERSION_NUMBER);

공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.

L208 if (!ver)

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L209 return;

호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.

L210 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L211 if (pci->version && pci->version != ver)

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L212 dev_warn(pci->dev, "Versions don't match (%08x != %08x)\n",

DWC component version과 type을 실제 register에서 판별하는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L213 pci->version, ver);

DWC component version과 type을 실제 register에서 판별하는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L214 else

DWC component version과 type을 실제 register에서 판별하는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L215 pci->version = ver;

DWC component version과 type을 실제 register에서 판별하는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L216 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L217 ver = dw_pcie_readl_dbi(pci, PCIE_VERSION_TYPE);

공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.

L218 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L219 if (pci->type && pci->type != ver)

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L220 dev_warn(pci->dev, "Types don't match (%08x != %08x)\n",

DWC component version과 type을 실제 register에서 판별하는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L221 pci->type, ver);

DWC component version과 type을 실제 register에서 판별하는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L222 else

DWC component version과 type을 실제 register에서 판별하는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L223 pci->type = ver;

DWC component version과 type을 실제 register에서 판별하는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L224 }

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L225 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L226 u8 dw_pcie_find_capability(struct dw_pcie *pci, u8 cap)

DWC component version과 type을 실제 register에서 판별하는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L227 {

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L228 return PCI_FIND_NEXT_CAP(dw_pcie_read_cfg, PCI_CAPABILITY_LIST, cap,

공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.

L229 NULL, pci);

DWC component version과 type을 실제 register에서 판별하는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L230 }

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L231 EXPORT_SYMBOL_GPL(dw_pcie_find_capability);

DWC component version과 type을 실제 register에서 판별하는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L232 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L233 u16 dw_pcie_find_ext_capability(struct dw_pcie *pci, u8 cap)

DWC component version과 type을 실제 register에서 판별하는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L234 {

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L235 return PCI_FIND_NEXT_EXT_CAP(dw_pcie_read_cfg, 0, cap, NULL, pci);

공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.

L236 }

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L237 EXPORT_SYMBOL_GPL(dw_pcie_find_ext_capability);

DWC component version과 type을 실제 register에서 판별하는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L238 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L239 void dw_pcie_remove_capability(struct dw_pcie *pci, u8 cap)

함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 DWC component version과 type을 실제 register에서 판별하는 과정의 입력 계약을 만족하는지 확인합니다.

L240 {

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L241 u8 cap_pos, pre_pos, next_pos;

DWC component version과 type을 실제 register에서 판별하는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L242 u16 reg;

DWC component version과 type을 실제 register에서 판별하는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L243 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L244 cap_pos = PCI_FIND_NEXT_CAP(dw_pcie_read_cfg, PCI_CAPABILITY_LIST, cap,

공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.

L245 &pre_pos, pci);

DWC component version과 type을 실제 register에서 판별하는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L246 if (!cap_pos)

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L247 return;

호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.

L248 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L249 reg = dw_pcie_readw_dbi(pci, cap_pos);

공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.

L250 next_pos = (reg & 0xff00) >> 8;

DWC component version과 type을 실제 register에서 판별하는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L251 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L252 dw_pcie_dbi_ro_wr_en(pci);

DWC component version과 type을 실제 register에서 판별하는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L253 if (pre_pos == PCI_CAPABILITY_LIST)

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L254 dw_pcie_writeb_dbi(pci, PCI_CAPABILITY_LIST, next_pos);

hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.

L255 else

DWC component version과 type을 실제 register에서 판별하는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L256 dw_pcie_writeb_dbi(pci, pre_pos + 1, next_pos);

hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.

L257 dw_pcie_dbi_ro_wr_dis(pci);

DWC component version과 type을 실제 register에서 판별하는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L258 }

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L259 EXPORT_SYMBOL_GPL(dw_pcie_remove_capability);

DWC component version과 type을 실제 register에서 판별하는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L260 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

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);
L1155 */

원본 주석입니다. Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L1156 l1ss_cap = dw_pcie_readl_dbi(pci, l1ss + PCI_L1SS_CAP);

공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.

L1157 l1ss_cap &= ~(PCI_L1SS_CAP_PCIPM_L1_1 | PCI_L1SS_CAP_ASPM_L1_1 |

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1158 PCI_L1SS_CAP_PCIPM_L1_2 | PCI_L1SS_CAP_ASPM_L1_2 |

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1159 PCI_L1SS_CAP_L1_PM_SS);

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1160 dw_pcie_writel_dbi(pci, l1ss + PCI_L1SS_CAP, l1ss_cap);

hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.

L1161 }

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L1162 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L1163 void dw_pcie_setup(struct dw_pcie *pci)

함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 입력 계약을 만족하는지 확인합니다.

L1164 {

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L1165 u32 val;

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1166 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L1167 dw_pcie_link_set_max_speed(pci);

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1168 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L1169 /* Configure Gen1 N_FTS */

원본 주석입니다. Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L1170 if (pci->n_fts[0]) {

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L1171 val = dw_pcie_readl_dbi(pci, PCIE_PORT_AFR);

공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.

L1172 val &= ~(PORT_AFR_N_FTS_MASK | PORT_AFR_CC_N_FTS_MASK);

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1173 val |= PORT_AFR_N_FTS(pci->n_fts[0]);

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1174 val |= PORT_AFR_CC_N_FTS(pci->n_fts[0]);

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1175 dw_pcie_writel_dbi(pci, PCIE_PORT_AFR, val);

hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.

L1176 }

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L1177 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L1178 /* Configure Gen2+ N_FTS */

원본 주석입니다. Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L1179 if (pci->n_fts[1]) {

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L1180 val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);

공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.

L1181 val &= ~PORT_LOGIC_N_FTS_MASK;

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1182 val |= pci->n_fts[1];

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1183 dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);

hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.

L1184 }

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L1185 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L1186 if (dw_pcie_cap_is(pci, CDM_CHECK)) {

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L1187 val = dw_pcie_readl_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS);

공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.

L1188 val |= PCIE_PL_CHK_REG_CHK_REG_CONTINUOUS |

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1189 PCIE_PL_CHK_REG_CHK_REG_START;

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1190 dw_pcie_writel_dbi(pci, PCIE_PL_CHK_REG_CONTROL_STATUS, val);

hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.

L1191 }

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L1192 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L1193 val = dw_pcie_readl_dbi(pci, PCIE_PORT_LINK_CONTROL);

공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.

L1194 val &= ~PORT_LINK_FAST_LINK_MODE;

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1195 val |= PORT_LINK_DLL_LINK_EN;

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1196 dw_pcie_writel_dbi(pci, PCIE_PORT_LINK_CONTROL, val);

hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.

L1197 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L1198 dw_pcie_link_set_max_link_width(pci, pci->num_lanes);

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1199 }

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L1200 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L1201 resource_size_t dw_pcie_parent_bus_offset(struct dw_pcie *pci,

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1202 const char *reg_name,

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1203 resource_size_t cpu_phys_addr)

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1204 {

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L1205 struct device *dev = pci->dev;

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1206 struct device_node *np = dev->of_node;

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1207 int index;

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1208 u64 reg_addr, fixup_addr;

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1209 u64 (*fixup)(struct dw_pcie *pcie, u64 cpu_addr);

함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 입력 계약을 만족하는지 확인합니다.

L1210 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L1211 /* Look up reg_name address on parent bus */

원본 주석입니다. Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L1212 index = of_property_match_string(np, "reg-names", reg_name);

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1213 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L1214 if (index < 0) {

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L1215 dev_err(dev, "No %s in devicetree \"reg\" property\n", reg_name);

Link speed, lane width와 N_FTS를 programming하는 DWC 공통 setup의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

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 
L1014 /*

원본 주석입니다. Gen3 이상 각 data rate와 lane의 equalization preset programming에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L1015 * Write preset values to the registers byte-by-byte for the given

원본 주석입니다. Gen3 이상 각 data rate와 lane의 equalization preset programming에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L1016 * number of lanes and register size.

원본 주석입니다. Gen3 이상 각 data rate와 lane의 equalization preset programming에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L1017 */

원본 주석입니다. Gen3 이상 각 data rate와 lane의 equalization preset programming에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L1018 for (i = 0; i < pci->num_lanes * lane_reg_size; i++)

여러 pending source 또는 resource를 순회하는 구간입니다. 한 번의 진입에서 처리 가능한 양과 종료 조건이 interrupt latency에 영향을 줍니다.

L1019 dw_pcie_writeb_dbi(pci, cap + lane_eq_offset + i, presets[i]);

hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.

L1020 }

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L1021 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L1022 static void dw_pcie_config_presets(struct dw_pcie_rp *pp)

함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 Gen3 이상 각 data rate와 lane의 equalization preset programming의 입력 계약을 만족하는지 확인합니다.

L1023 {

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L1024 struct dw_pcie *pci = to_dw_pcie_from_pp(pp);

Gen3 이상 각 data rate와 lane의 equalization preset programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1025 enum pci_bus_speed speed = pcie_link_speed[pci->max_link_speed];

Gen3 이상 각 data rate와 lane의 equalization preset programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1026 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L1027 /*

원본 주석입니다. Gen3 이상 각 data rate와 lane의 equalization preset programming에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L1028 * Lane equalization settings need to be applied for all data rates the

원본 주석입니다. Gen3 이상 각 data rate와 lane의 equalization preset programming에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L1029 * controller supports and for all supported lanes.

원본 주석입니다. Gen3 이상 각 data rate와 lane의 equalization preset programming에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L1030 */

원본 주석입니다. Gen3 이상 각 data rate와 lane의 equalization preset programming에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L1031 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L1032 if (speed >= PCIE_SPEED_8_0GT)

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L1033 dw_pcie_program_presets(pp, PCIE_SPEED_8_0GT);

Gen3 이상 각 data rate와 lane의 equalization preset programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1034 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L1035 if (speed >= PCIE_SPEED_16_0GT)

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L1036 dw_pcie_program_presets(pp, PCIE_SPEED_16_0GT);

Gen3 이상 각 data rate와 lane의 equalization preset programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1037 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L1038 if (speed >= PCIE_SPEED_32_0GT)

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L1039 dw_pcie_program_presets(pp, PCIE_SPEED_32_0GT);

Gen3 이상 각 data rate와 lane의 equalization preset programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1040 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L1041 if (speed >= PCIE_SPEED_64_0GT)

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L1042 dw_pcie_program_presets(pp, PCIE_SPEED_64_0GT);

Gen3 이상 각 data rate와 lane의 equalization preset programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1043 }

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L1044 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L1045 int dw_pcie_setup_rc(struct dw_pcie_rp *pp)

함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 Gen3 이상 각 data rate와 lane의 equalization preset programming의 입력 계약을 만족하는지 확인합니다.

L1046 {

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L1047 struct dw_pcie *pci = to_dw_pcie_from_pp(pp);

Gen3 이상 각 data rate와 lane의 equalization preset programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1048 u32 val;

Gen3 이상 각 data rate와 lane의 equalization preset programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1049 int ret;

Gen3 이상 각 data rate와 lane의 equalization preset programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1050 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L1051 /*

원본 주석입니다. Gen3 이상 각 data rate와 lane의 equalization preset programming에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L1052 * Enable DBI read-only registers for writing/updating configuration.

원본 주석입니다. Gen3 이상 각 data rate와 lane의 equalization preset programming에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L1053 * Write permission gets disabled towards the end of this function.

원본 주석입니다. Gen3 이상 각 data rate와 lane의 equalization preset programming에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L1054 */

원본 주석입니다. Gen3 이상 각 data rate와 lane의 equalization preset programming에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L1055 dw_pcie_dbi_ro_wr_en(pci);

Gen3 이상 각 data rate와 lane의 equalization preset programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1056 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L1057 dw_pcie_setup(pci);

Gen3 이상 각 data rate와 lane의 equalization preset programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1058 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L1059 dw_pcie_msi_init(pp);

Gen3 이상 각 data rate와 lane의 equalization preset programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L1060 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L1061 /* Setup RC BARs */

원본 주석입니다. Gen3 이상 각 data rate와 lane의 equalization preset programming에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L1062 dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0x00000004);

hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.

L1063 dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_1, 0x00000000);

hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.

L1064 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

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		}
L560 * visconti_pcie_cpu_addr_fixup() uses pp->io_base, so we have to

원본 주석입니다. DesignWare Root Port 초기화에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L561 * call dw_pcie_parent_bus_offset() after setting pp->io_base.

원본 주석입니다. DesignWare Root Port 초기화에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L562 */

원본 주석입니다. DesignWare Root Port 초기화에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L563 pci->parent_bus_offset = dw_pcie_parent_bus_offset(pci, "config",

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L564 pp->cfg0_base);

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L565 return 0;

호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.

L566 }

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L567 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L568 int dw_pcie_host_init(struct dw_pcie_rp *pp)

함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 DesignWare Root Port 초기화의 입력 계약을 만족하는지 확인합니다.

L569 {

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L570 struct dw_pcie *pci = to_dw_pcie_from_pp(pp);

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L571 struct device *dev = pci->dev;

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L572 struct device_node *np = dev->of_node;

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L573 struct pci_host_bridge *bridge;

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L574 int ret;

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L575 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L576 raw_spin_lock_init(&pp->lock);

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L577 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L578 bridge = devm_pci_alloc_host_bridge(dev, 0);

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L579 if (!bridge)

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L580 return -ENOMEM;

호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.

L581 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L582 pp->bridge = bridge;

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L583 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L584 ret = dw_pcie_host_get_resources(pp);

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L585 if (ret)

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L586 return ret;

호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.

L587 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L588 if (pp->ops->init) {

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L589 ret = pp->ops->init(pp);

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L590 if (ret)

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L591 goto err_free_ecam;

공통 정리 또는 오류 경로로 이동합니다. 이미 얻은 clock, mapping, IRQ, DMA 자원의 역순 해제가 맞는지 확인합니다.

L592 }

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L593 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L594 if (pci_msi_enabled()) {

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L595 pp->has_msi_ctrl = !(pp->ops->msi_init ||

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L596 of_property_present(np, "msi-parent") ||

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L597 of_property_present(np, "msi-map"));

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L598 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L599 /*

원본 주석입니다. DesignWare Root Port 초기화에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L600 * For the has_msi_ctrl case the default assignment is handled

원본 주석입니다. DesignWare Root Port 초기화에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L601 * in the dw_pcie_msi_host_init().

원본 주석입니다. DesignWare Root Port 초기화에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L602 */

원본 주석입니다. DesignWare Root Port 초기화에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L603 if (!pp->has_msi_ctrl && !pp->num_vectors) {

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L604 pp->num_vectors = MSI_DEF_NUM_VECTORS;

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L605 } else if (pp->num_vectors > MAX_MSI_IRQS) {

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L606 dev_err(dev, "Invalid number of vectors\n");

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L607 ret = -EINVAL;

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L608 goto err_deinit_host;

공통 정리 또는 오류 경로로 이동합니다. 이미 얻은 clock, mapping, IRQ, DMA 자원의 역순 해제가 맞는지 확인합니다.

L609 }

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L610 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L611 if (pp->ops->msi_init) {

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L612 ret = pp->ops->msi_init(pp);

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L613 if (ret < 0)

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L614 goto err_deinit_host;

공통 정리 또는 오류 경로로 이동합니다. 이미 얻은 clock, mapping, IRQ, DMA 자원의 역순 해제가 맞는지 확인합니다.

L615 } else if (pp->has_msi_ctrl) {

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L616 ret = dw_pcie_msi_host_init(pp);

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L617 if (ret < 0)

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L618 goto err_deinit_host;

공통 정리 또는 오류 경로로 이동합니다. 이미 얻은 clock, mapping, IRQ, DMA 자원의 역순 해제가 맞는지 확인합니다.

L619 }

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L620 }

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L621 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L622 dw_pcie_version_detect(pci);

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L623 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L624 dw_pcie_iatu_detect(pci);

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L625 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L626 if (pci->num_lanes < 1)

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L627 pci->num_lanes = dw_pcie_link_get_max_link_width(pci);

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L628 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L629 ret = of_pci_get_equalization_presets(dev, &pp->presets, pci->num_lanes);

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L630 if (ret)

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L631 goto err_free_msi;

공통 정리 또는 오류 경로로 이동합니다. 이미 얻은 clock, mapping, IRQ, DMA 자원의 역순 해제가 맞는지 확인합니다.

L632 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L633 if (pp->ecam_enabled) {

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L634 ret = dw_pcie_config_ecam_iatu(pp);

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L635 if (ret) {

상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.

L636 dev_err(dev, "Failed to configure iATU in ECAM mode\n");

DesignWare Root Port 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L637 goto err_free_msi;

공통 정리 또는 오류 경로로 이동합니다. 이미 얻은 clock, mapping, IRQ, DMA 자원의 역순 해제가 맞는지 확인합니다.

L638 }

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

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{
L3221 *

원본 주석입니다. PCI bus scan 진입에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L3222 * Return how far we've got finding sub-buses.

원본 주석입니다. PCI bus scan 진입에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L3223 */

원본 주석입니다. PCI bus scan 진입에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L3224 dev_dbg(&bus->dev, "bus scan returning with max=%02x\n", max);

PCI bus scan 진입의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L3225 return max;

호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.

L3226 }

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L3227 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L3228 /**

원본 주석입니다. PCI bus scan 진입에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L3229 * pci_scan_child_bus() - Scan devices below a bus

원본 주석입니다. PCI bus scan 진입에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L3230 * @bus: Bus to scan for devices

원본 주석입니다. PCI bus scan 진입에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L3231 *

원본 주석입니다. PCI bus scan 진입에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L3232 * Scans devices below @bus including subordinate buses. Returns new

원본 주석입니다. PCI bus scan 진입에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L3233 * subordinate number including all the found devices.

원본 주석입니다. PCI bus scan 진입에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L3234 */

원본 주석입니다. PCI bus scan 진입에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L3235 unsigned int pci_scan_child_bus(struct pci_bus *bus)

함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 PCI bus scan 진입의 입력 계약을 만족하는지 확인합니다.

L3236 {

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L3237 return pci_scan_child_bus_extend(bus, 0);

호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.

L3238 }

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L3239 EXPORT_SYMBOL_GPL(pci_scan_child_bus);

PCI bus scan 진입의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L3240 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L3241 /**

원본 주석입니다. PCI bus scan 진입에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L3242 * pcibios_root_bridge_prepare - Platform-specific host bridge setup

원본 주석입니다. PCI bus scan 진입에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L3243 * @bridge: Host bridge to set up

원본 주석입니다. PCI bus scan 진입에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L3244 *

원본 주석입니다. PCI bus scan 진입에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L3245 * Default empty implementation. Replace with an architecture-specific setup

원본 주석입니다. PCI bus scan 진입에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L3246 * routine, if necessary.

원본 주석입니다. PCI bus scan 진입에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L3247 */

원본 주석입니다. PCI bus scan 진입에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.

L3248 int __weak pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)

함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 PCI bus scan 진입의 입력 계약을 만족하는지 확인합니다.

L3249 {

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L3250 return 0;

호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.

L3251 }

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L3252 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L3253 void __weak pcibios_add_bus(struct pci_bus *bus)

함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 PCI bus scan 진입의 입력 계약을 만족하는지 확인합니다.

L3254 {

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L3255 }

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L3256 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L3257 void __weak pcibios_remove_bus(struct pci_bus *bus)

함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 PCI bus scan 진입의 입력 계약을 만족하는지 확인합니다.

L3258 {

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L3259 }

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

L3260 (blank)

논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.

L3261 struct pci_bus *pci_create_root_bus(struct device *parent, int bus,

PCI bus scan 진입의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L3262 struct pci_ops *ops, void *sysdata, struct list_head *resources)

PCI bus scan 진입의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.

L3263 {

제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.

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입니다. 그보다 아래의 통과 증거와 그 지점의 실패 증거를 한 묶음으로 남겨야 수정의 효과도 검증할 수 있습니다.