01 · QUESTION
무엇을 증명할 것인가
장치가 `lspci`에는 보이는데 driver의 MMIO, DMA 또는 interrupt만 실패할 때 어느 resource ownership 단계에서 멈춘 것인가?
DWC link-up 이후 DBI와 iATU가 CPU·PCIe 주소를 연결하고 Linux가 BDF와 BAR를 배치하며 bus mastering, DMA mapping과 MSI/MSI-X를 활성화하는 순서를 추적합니다. 이 글은 Linux 로그를 출발점으로 삼지 않습니다. 같은 사건이 보드, controller, firmware, kernel에서 어떤 이름과 번호로 바뀌는지 아래에서 위로 연결합니다.
02 · CONTRACT
입력과 완료 조건
| 구분 | 확인할 내용 |
|---|---|
| 입력 | L0 link, 정상 configuration access, firmware host windows와 interrupt/IOMMU description |
| 출력 | driver가 BAR를 매핑하고 DMA queue와 MSI vector를 사용해 transaction을 완료하는 상태 |
| 소유권 | PCI core는 bus/resource, driver는 device register와 queue, DMA/IOMMU core는 IOVA lifetime, IRQ core는 vector lifetime을 소유 |
| 완료 조건 | probe 성공뿐 아니라 MMIO readback, DMA completion, interrupt counter와 teardown까지 검증 |
03 · BOTTOM-UP
완전히 아래에서 시작하는 8단계
PCI core는 bus 0의 device/function을 읽고 Header Type과 class code로 endpoint와 bridge를 구분한다. bridge의 Primary/Secondary/Subordinate Bus Number가 뒤쪽 hierarchy를 연다. ARI가 켜진 경우 function numbering과 forwarding 규칙이 달라진다.
증거: `lspci -tv`, config header, bridge bus-number register
BAR에 all-ones를 쓰고 readback mask를 해석해 required size와 alignment를 얻는다. 64-bit BAR는 두 DWORD가 한 resource이며 prefetchable은 CPU cacheable이라는 뜻이 아니라 read side effect 없이 bridge가 prefetch할 수 있다는 PCI 속성이다.
증거: raw BAR, resource flags, size와 alignment, bridge window requirement
Linux는 firmware가 준 주소를 보존하거나 unassigned resource를 host `ranges/_CRS` 안에 배치한다. bridge I/O, non-prefetchable memory, prefetchable memory window가 child BAR 전체를 포함해야 한다. 32-bit endpoint 제약과 64-bit host aperture를 혼동하면 allocation이 실패한다.
증거: `/proc/iomem`, sysfs resource, boot log의 BAR assignment, bridge window
`pci_enable_device()`가 필요한 bridge/device state를 활성화하고 driver가 region을 request한 뒤 `pci_iomap()`으로 BAR를 kernel virtual address에 연결한다. Memory Space Enable과 Bus Master Enable은 다르며 DMA 전에 `pci_set_master()`가 필요하다.
증거: PCI_COMMAND, `/proc/iomem`, requested region owner, mapped BAR virtual/physical address
driver가 DMA mask를 합의한 뒤 coherent ring 또는 streaming buffer를 map한다. IOMMU가 켜지면 device가 보는 DMA address는 IOVA이고 physical address와 같지 않다. descriptor 내용과 ownership bit를 쓴 뒤 `dma_wmb()`를 거쳐 doorbell을 울려야 한다.
증거: DMA mask, IOVA/PA mapping, IOMMU group/domain, descriptor dump, fault log
MSI는 device가 특정 address/data로 Memory Write TLP를 보내 interrupt를 만든다. MSI-X는 vector별 table entry와 mask를 가진다. GIC ITS, x86 interrupt remapping, RISC-V IMSIC가 message를 target CPU interrupt로 변환할 수 있다.
증거: MSI capability/table, allocated vector, `/proc/interrupts`, irq affinity, remapper fault
probe는 enable, region request, DMA setup, IRQ allocation, hardware reset, queue start, net/block/core registration 순으로 진행한다. 중간 실패 시 역순으로 해제해야 한다. probe 성공 log만으로 runtime datapath가 검증된 것은 아니다.
증거: dynamic debug, probe 단계별 trace, devres 상태와 remove callback
CPU가 descriptor를 채우고 doorbell MMIO를 쓰면 endpoint가 PCIe Memory Read로 descriptor/data를 가져간다. 완료 후 endpoint가 host memory status를 쓰고 MSI를 보낸다. interrupt handler는 completion ring을 회수해 upper layer에 완료를 게시한다.
증거: MMIO write trace, PCIe TLP, DMA/IOMMU fault, interrupt timestamp, completion index
0. Discover · BDF와 multifunction/bridge 탐색
PCI core는 bus 0의 device/function을 읽고 Header Type과 class code로 endpoint와 bridge를 구분한다. bridge의 Primary/Secondary/Subordinate Bus Number가 뒤쪽 hierarchy를 연다. ARI가 켜진 경우 function numbering과 forwarding 규칙이 달라진다.
남길 증거: `lspci -tv`, config header, bridge bus-number register
bridge 아래 BDF가 안 보이면 endpoint driver보다 bus-number와 Type-1 routing을 먼저 본다.
1. Size · BAR sizing과 prefetchable 속성
BAR에 all-ones를 쓰고 readback mask를 해석해 required size와 alignment를 얻는다. 64-bit BAR는 두 DWORD가 한 resource이며 prefetchable은 CPU cacheable이라는 뜻이 아니라 read side effect 없이 bridge가 prefetch할 수 있다는 PCI 속성이다.
남길 증거: raw BAR, resource flags, size와 alignment, bridge window requirement
device decode를 끈 상태에서 sizing하고 원래 값을 복원해야 한다.
2. Assign · host aperture와 bridge window 배치
Linux는 firmware가 준 주소를 보존하거나 unassigned resource를 host `ranges/_CRS` 안에 배치한다. bridge I/O, non-prefetchable memory, prefetchable memory window가 child BAR 전체를 포함해야 한다. 32-bit endpoint 제약과 64-bit host aperture를 혼동하면 allocation이 실패한다.
남길 증거: `/proc/iomem`, sysfs resource, boot log의 BAR assignment, bridge window
resource collision이나 no space가 있으면 driver probe에서 BAR를 만지기 전에 해결한다.
3. Enable · Command register와 MMIO mapping
`pci_enable_device()`가 필요한 bridge/device state를 활성화하고 driver가 region을 request한 뒤 `pci_iomap()`으로 BAR를 kernel virtual address에 연결한다. Memory Space Enable과 Bus Master Enable은 다르며 DMA 전에 `pci_set_master()`가 필요하다.
남길 증거: PCI_COMMAND, `/proc/iomem`, requested region owner, mapped BAR virtual/physical address
MMIO read가 all-ones이면 power state, BAR decode, bridge window와 endpoint reset을 재확인한다.
4. DMA · DMA mask, IOVA와 descriptor publication
driver가 DMA mask를 합의한 뒤 coherent ring 또는 streaming buffer를 map한다. IOMMU가 켜지면 device가 보는 DMA address는 IOVA이고 physical address와 같지 않다. descriptor 내용과 ownership bit를 쓴 뒤 `dma_wmb()`를 거쳐 doorbell을 울려야 한다.
남길 증거: DMA mask, IOVA/PA mapping, IOMMU group/domain, descriptor dump, fault log
completion 전에 unmap/free하면 device가 재사용 memory를 덮을 수 있다.
5. MSI · MSI/MSI-X vector와 message routing
MSI는 device가 특정 address/data로 Memory Write TLP를 보내 interrupt를 만든다. MSI-X는 vector별 table entry와 mask를 가진다. GIC ITS, x86 interrupt remapping, RISC-V IMSIC가 message를 target CPU interrupt로 변환할 수 있다.
남길 증거: MSI capability/table, allocated vector, `/proc/interrupts`, irq affinity, remapper fault
interrupt vector를 해제하기 전에 device MSI generation과 DMA queue를 먼저 멈춘다.
6. Driver · probe, queue start와 error unwind
probe는 enable, region request, DMA setup, IRQ allocation, hardware reset, queue start, net/block/core registration 순으로 진행한다. 중간 실패 시 역순으로 해제해야 한다. probe 성공 log만으로 runtime datapath가 검증된 것은 아니다.
남길 증거: dynamic debug, probe 단계별 trace, devres 상태와 remove callback
각 resource의 획득과 실패 label을 표로 만들어 leak와 double-free를 확인한다.
7. Runtime · MMIO doorbell → DMA → MSI completion
CPU가 descriptor를 채우고 doorbell MMIO를 쓰면 endpoint가 PCIe Memory Read로 descriptor/data를 가져간다. 완료 후 endpoint가 host memory status를 쓰고 MSI를 보낸다. interrupt handler는 completion ring을 회수해 upper layer에 완료를 게시한다.
남길 증거: MMIO write trace, PCIe TLP, DMA/IOMMU fault, interrupt timestamp, completion index
한 transaction ID를 descriptor index, DMA address, interrupt vector와 끝까지 연결한다.
04 · DIAGRAMS
주소와 상태가 이동하는 모습
L0 link, 정상 configuration access, firmware host windows와 interrupt/IOMMU description
PCI core는 bus/resource, driver는 device register와 queue, DMA/IOMMU core는 IOVA lifetime, IRQ core는 vector lifetime을 소유
driver가 BAR를 매핑하고 DMA queue와 MSI vector를 사용해 transaction을 완료하는 상태
probe 성공뿐 아니라 MMIO readback, DMA completion, interrupt counter와 teardown까지 검증
05 · SYNOPSYS DESIGNWARE IP
Synopsys DWC Controller programming: DBI, iATU, AXI와 MSI
link가 L0에 들어온 뒤에는 PHY보다 DWC digital controller의 주소 변환과 Root Port programming이 중심이 됩니다. CPU가 보는 DBI/AXI 주소, PCIe bus address, endpoint BAR address, DMA IOVA를 서로 다른 번호 공간으로 두고 DWC iATU region이 어느 두 공간을 연결하는지 계산합니다.
DBI / DBI2
RC Type-1 configuration, Port Logic와 일부 EP shadow/BAR programming에 접근합니다.
- 관찰
- dbi_base와 dbi_base2, RO write enable 구간
- 대표 실패
- DBI와 application register base를 바꿔 읽어 전혀 다른 값을 정상으로 오판
Config aperture
PCI core의 BDF access를 DWC config-space window로 받습니다.
- 관찰
- child bus 여부에 따라 CFG0 또는 CFG1
- 대표 실패
- bus 1 endpoint에 CFG1을 쓰거나 bridge 뒤 장치에 CFG0을 써 Completion이 없음
Outbound iATU
CPU AXI base/limit를 PCIe target address와 TLP type으로 변환합니다.
- 관찰
- MEM/IO/CFG0/CFG1/MSG region
- 대표 실패
- base·limit inclusive 계산 또는 upper address 오류로 일부 BAR만 접근 실패
Inbound iATU
Endpoint가 보낸 Memory Read/Write를 SoC physical aperture로 변환합니다.
- 관찰
- BAR match 또는 address match, target base
- 대표 실패
- DMA address와 inbound target/IOMMU 구성이 맞지 않아 AXI abort
AXI master/slave
CPU MMIO/config 요청과 inbound DMA request를 outstanding transaction으로 운반합니다.
- 관찰
- AXI ID/width/burst/ordering와 error response
- 대표 실패
- PCIe Completion Timeout과 SoC interconnect timeout을 같은 오류로 취급
Root Port setup
class code, BAR, bus number, command, lane width와 speed capability를 RC configuration에 맞춥니다.
- 관찰
- dw_pcie_setup_rc()와 host_ops
- 대표 실패
- DBI RO-write override를 닫지 않아 runtime write protection이 깨짐
MSI controller
DWC 내부 MSI address, enable/mask/status를 irqdomain으로 연결하거나 platform 외부 MSI domain을 사용합니다.
- 관찰
- PCIE_MSI_ADDR/ENABLE/MASK/STATUS
- 대표 실패
- 내부 MSI와 GIC ITS 경로를 동시에 구성하거나 둘 다 구성하지 않음
Optional eDMA
일부 DWC configuration은 embedded DMA read/write channel과 linked-list engine을 포함합니다.
- 관찰
- channel control, doorbell, LLP, interrupt status
- 대표 실패
- 일반 endpoint bus-master DMA와 DWC eDMA를 같은 엔진으로 오해
PHY와 Controller가 만나는 PIPE 경계
한쪽 register만 보고 link 상태를 판정하지 않습니다. 동일 사건에 대해 PHY evidence와 controller evidence를 같은 행에 놓고 처음 불일치하는 구간을 찾습니다.
| 단계 | PHY 쪽에서 확인 | DWC Controller 쪽에서 확인 | 경계 판정 |
|---|---|---|---|
| Configuration read | PHY: L0와 DLL active를 유지 | Controller: CFG0/CFG1 iATU와 BDF target 생성 | 0xffff이면 LNKSTA와 iATU region을 같은 순간에 저장 |
| BAR MMIO | PHY: TLP 전송 품질과 replay를 보장 | Controller: outbound MEM base/limit/target 변환 | CPU physical, PCI bus address, BAR assigned base를 세 열로 계산 |
| Endpoint DMA read | PHY: Memory Read TLP와 Completion 전달 | Controller/SoC: inbound routing 또는 IOMMU requester context | IOMMU fault의 requester ID와 BDF를 연결 |
| Endpoint DMA write | PHY: posted Memory Write 전달 | Controller/SoC: inbound target와 cache coherency | posted이므로 CPU memory 관찰과 device completion을 따로 확인 |
| MSI | PHY: MSI Memory Write TLP 전달 | Controller: internal MSI status 또는 external MSI domain route | DMA completion write가 보인 뒤 MSI가 오는 순서를 timestamp로 검증 |
| Teardown | PHY: 새 TLP 차단 및 link/power transition | Controller: bus master off, IRQ mask, ATU/queue 해제 | device가 더 이상 DMA하지 않는 증거 뒤 mapping을 반환 |
DWC 공개 register와 읽는 목적
| Register/영역 | 역할 | 검증 시 주의점 |
|---|---|---|
| PCIE_MISC_CONTROL_1_OFF 0x8bc | DBI read-only write enable | RC setup 중에만 PCIE_DBI_RO_WR_EN을 set하고 반드시 clear |
| PCIE_ATU_VIEWPORT 0x900 | v4.80a 이전 region selector | direction과 index를 선택한 뒤 공용 register window programming |
| PCIE_ATU_UNROLL_BASE | v4.80a 이후 direct region base | outbound/inbound와 region index가 address에 포함됨 |
| REGION_CTRL1 | TLP type MEM/IO/CFG0/CFG1/MSG | 주소만 맞아도 type이 틀리면 상대편 routing이 다름 |
| REGION_CTRL2 | enable, BAR mode, config shift, function match | enable readback과 LINK_WAIT_IATU retry를 확인 |
| LOWER/UPPER_BASE + LIMIT | CPU 측 source aperture | limit가 inclusive이며 4GiB 경계를 넘는 region은 upper limit 지원 확인 |
| LOWER/UPPER_TARGET | PCIe 측 target address 또는 BDF | CFG region은 bus/device/function field encoding 확인 |
| MSI_ADDR/ENABLE/MASK/STATUS | DWC internal MSI block | irqdomain vector와 status bit group을 맞춤 |
CFG0와 CFG1의 차이
Root Port 바로 아래 bus의 endpoint에는 Type 0 Configuration Request가 필요하고, bridge 너머에는 Type 1 routing이 필요합니다. DWC host driver는 bus topology에 따라 iATU TLP type과 target BDF를 바꾸므로 bus number가 잘못되면 PHY가 완전히 정상이어도 enumeration이 끊깁니다.
Viewport와 unrolled iATU
DWC v4.80a 이전에는 PCIE_ATU_VIEWPORT로 region과 방향을 고른 뒤 하나의 register 창을 재사용합니다. 이후 IP는 region마다 직접 접근 가능한 unrolled 공간을 둘 수 있습니다. Linux는 version/capability로 방식을 결정하므로 bring-up dump도 같은 방식을 따라야 합니다.
DMA 주소는 iATU 하나로 끝나지 않는다
Endpoint가 보는 PCIe address가 SoC interconnect address로 변환된 뒤 IOMMU가 다시 IOVA를 physical page로 변환할 수 있습니다. DWC inbound iATU, SMMU stream ID, DMA API가 각각 한 번씩 주소 공간을 바꿀 수 있으므로 descriptor에 적힌 값만 보고 PA라고 부르면 안 됩니다.
DWC eDMA와 endpoint DMA 구분
DWC eDMA는 controller IP에 선택적으로 합성되는 별도 엔진입니다. NVMe나 Ethernet endpoint가 자체 DMA engine으로 bus master transaction을 만드는 것과 다릅니다. Linux config와 register presence를 확인한 뒤 eDMA channel register를 해석합니다.
06 · DETAILED MANUAL
DBI, ECAM, iATU, BAR, DMA와 MSI를 주소 단위로 추적하는 상세 매뉴얼
이 장은 link가 L0에 들어온 이후를 다룹니다. 같은 숫자를 CPU physical address, PCI bus address, endpoint BAR offset, DMA address와 IOVA로 번갈아 부르는 실수를 막기 위해 모든 transaction을 '누가 생성했고 어느 translation을 통과했는가'로 기록합니다. 예시 주소는 계산 방법을 보여 주기 위한 가상 값이며 실제 board의 DT ranges, iommu-map와 DWC region capability로 다시 계산해야 합니다.
공개적으로 다시 확인할 수 있는 자료
공개되지 않은 vendor register나 integration별 offset을 추측해서 채우지 않았습니다. 아래 제조사 자료, architecture 문서와 Linux v6.18.37 원본에서 다시 확인할 수 있는 범위만 사용했습니다.
Linux v6.18.37 DWC common source
iATU programming, version/capability와 eDMA detection
Linux v6.18.37 DWC host source
ECAM/CFG access, Root Port setup, MSI irqdomain와 host lifecycle
Linux v6.18.37 PCI probe
Vendor ID read, pci_dev 생성, BAR sizing와 bridge scan
Linux v6.18.37 PCI resource assignment
bridge window와 endpoint BAR resource 배치
Linux DWC Devicetree binding
reg/ranges, iATU window 수, lane/speed와 MSI/IOMMU 연결
07 · REGISTERS
읽어야 할 상태와 해석
값 하나만 떼어 보지 말고 동일 사건의 enable, status, ownership, completion register를 한 줄에 기록합니다. read-to-clear나 write-one-to-clear 속성은 반드시 datasheet에서 먼저 확인합니다.
| 레지스터/상태 | 소유 블록 | 검증할 의미 |
|---|---|---|
| BAR0..5 | endpoint aperture | size/type/prefetch와 assigned base |
| PCI_COMMAND | decode control | MEM/IO/BUS_MASTER bit를 단계별로 확인 |
| Bridge windows | Type-1 header | child BAR 전체를 포함하는지 확인 |
| MSI-X Table/PBA | BAR 내부 | vector control mask와 pending bit |
| IOMMU context | platform specific | requester ID가 올바른 domain에 연결됐는지 확인 |
| AER status | Root/Endpoint | Unsupported Request, Completion Timeout, Poisoned TLP |
08 · LINUX SOURCE
Linux v6.18.37 원본 코드와 줄별 해설
라인 번호를 고정해 외우는 대신 함수 선언을 기준으로 Linux v6.18.37 tree에서 다시 찾았습니다. 로컬 tree에 있는 파일은 실제 코드를 직접 싣고, 나머지는 원본 파일과 읽을 함수 좌표를 연결했습니다.
Linux v6.18.37 · 실제 원본 코드
DWC outbound iATU region programming과 enable 확인
drivers/pci/controller/dwc/pcie-designware.c:517-613
517 * "TLP Digest Rules", when an endpoint receives TLP
518 * Digest when its ECRC check functionality is disabled
519 * in AER registers, received TLP Digest is just ignored.
520 * Since there is no issue or error reported either side, best way to
521 * handle the scenario is to program TD bit by default.
522 */
523
524 return val | PCIE_ATU_TD;
525}
526
527int dw_pcie_prog_outbound_atu(struct dw_pcie *pci,
528 const struct dw_pcie_ob_atu_cfg *atu)
529{
530 u64 parent_bus_addr = atu->parent_bus_addr;
531 u32 retries, val;
532 u64 limit_addr;
533
534 limit_addr = parent_bus_addr + atu->size - 1;
535
536 if ((limit_addr & ~pci->region_limit) != (parent_bus_addr & ~pci->region_limit) ||
537 !IS_ALIGNED(parent_bus_addr, pci->region_align) ||
538 !IS_ALIGNED(atu->pci_addr, pci->region_align) || !atu->size) {
539 return -EINVAL;
540 }
541
542 dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_LOWER_BASE,
543 lower_32_bits(parent_bus_addr));
544 dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_UPPER_BASE,
545 upper_32_bits(parent_bus_addr));
546
547 dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_LIMIT,
548 lower_32_bits(limit_addr));
549 if (dw_pcie_ver_is_ge(pci, 460A))
550 dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_UPPER_LIMIT,
551 upper_32_bits(limit_addr));
552
553 dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_LOWER_TARGET,
554 lower_32_bits(atu->pci_addr));
555 dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_UPPER_TARGET,
556 upper_32_bits(atu->pci_addr));
557
558 val = atu->type | atu->routing | PCIE_ATU_FUNC_NUM(atu->func_no);
559 if (upper_32_bits(limit_addr) > upper_32_bits(parent_bus_addr) &&
560 dw_pcie_ver_is_ge(pci, 460A))
561 val |= PCIE_ATU_INCREASE_REGION_SIZE;
562 if (dw_pcie_ver_is(pci, 490A) || dw_pcie_ver_is(pci, 500A))
563 val = dw_pcie_enable_ecrc(val);
564 dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_REGION_CTRL1, val);
565
566 val = PCIE_ATU_ENABLE | atu->ctrl2;
567 if (atu->type == PCIE_ATU_TYPE_MSG) {
568 /* The data-less messages only for now */
569 val |= PCIE_ATU_INHIBIT_PAYLOAD | atu->code;
570 }
571 dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_REGION_CTRL2, val);
572
573 /*
574 * Make sure ATU enable takes effect before any subsequent config
575 * and I/O accesses.
576 */
577 for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
578 val = dw_pcie_readl_atu_ob(pci, atu->index, PCIE_ATU_REGION_CTRL2);
579 if (val & PCIE_ATU_ENABLE)
580 return 0;
581
582 mdelay(LINK_WAIT_IATU);
583 }
584
585 dev_err(pci->dev, "Outbound iATU is not being enabled\n");
586
587 return -ETIMEDOUT;
588}
589
590static inline u32 dw_pcie_readl_atu_ib(struct dw_pcie *pci, u32 index, u32 reg)
591{
592 return dw_pcie_readl_atu(pci, PCIE_ATU_REGION_DIR_IB, index, reg);
593}
594
595static inline void dw_pcie_writel_atu_ib(struct dw_pcie *pci, u32 index, u32 reg,
596 u32 val)
597{
598 dw_pcie_writel_atu(pci, PCIE_ATU_REGION_DIR_IB, index, reg, val);
599}
600
601int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int type,
602 u64 parent_bus_addr, u64 pci_addr, u64 size)
603{
604 u64 limit_addr = pci_addr + size - 1;
605 u32 retries, val;
606
607 if ((limit_addr & ~pci->region_limit) != (pci_addr & ~pci->region_limit) ||
608 !IS_ALIGNED(parent_bus_addr, pci->region_align) ||
609 !IS_ALIGNED(pci_addr, pci->region_align) || !size) {
610 return -EINVAL;
611 }
612
613 dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_BASE,* "TLP Digest Rules", when an endpoint receives TLP
원본 주석입니다. DWC outbound iATU region programming과 enable 확인에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Digest when its ECRC check functionality is disabled
원본 주석입니다. DWC outbound iATU region programming과 enable 확인에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* in AER registers, received TLP Digest is just ignored.
원본 주석입니다. DWC outbound iATU region programming과 enable 확인에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Since there is no issue or error reported either side, best way to
원본 주석입니다. DWC outbound iATU region programming과 enable 확인에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* handle the scenario is to program TD bit by default.
원본 주석입니다. DWC outbound iATU region programming과 enable 확인에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*/
원본 주석입니다. DWC outbound iATU region programming과 enable 확인에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
return val | PCIE_ATU_TD;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
int dw_pcie_prog_outbound_atu(struct dw_pcie *pci,
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 DWC outbound iATU region programming과 enable 확인의 입력 계약을 만족하는지 확인합니다.
const struct dw_pcie_ob_atu_cfg *atu)
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
u64 parent_bus_addr = atu->parent_bus_addr;
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
u32 retries, val;
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
u64 limit_addr;
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
limit_addr = parent_bus_addr + atu->size - 1;
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if ((limit_addr & ~pci->region_limit) != (parent_bus_addr & ~pci->region_limit) ||
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
!IS_ALIGNED(parent_bus_addr, pci->region_align) ||
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
!IS_ALIGNED(atu->pci_addr, pci->region_align) || !atu->size) {
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
return -EINVAL;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_LOWER_BASE,
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
lower_32_bits(parent_bus_addr));
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_UPPER_BASE,
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
upper_32_bits(parent_bus_addr));
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_LIMIT,
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
lower_32_bits(limit_addr));
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (dw_pcie_ver_is_ge(pci, 460A))
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_UPPER_LIMIT,
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
upper_32_bits(limit_addr));
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_LOWER_TARGET,
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
lower_32_bits(atu->pci_addr));
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_UPPER_TARGET,
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
upper_32_bits(atu->pci_addr));
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
val = atu->type | atu->routing | PCIE_ATU_FUNC_NUM(atu->func_no);
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (upper_32_bits(limit_addr) > upper_32_bits(parent_bus_addr) &&
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
dw_pcie_ver_is_ge(pci, 460A))
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
val |= PCIE_ATU_INCREASE_REGION_SIZE;
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (dw_pcie_ver_is(pci, 490A) || dw_pcie_ver_is(pci, 500A))
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
val = dw_pcie_enable_ecrc(val);
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_REGION_CTRL1, val);
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
val = PCIE_ATU_ENABLE | atu->ctrl2;
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (atu->type == PCIE_ATU_TYPE_MSG) {
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
/* The data-less messages only for now */
원본 주석입니다. DWC outbound iATU region programming과 enable 확인에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
val |= PCIE_ATU_INHIBIT_PAYLOAD | atu->code;
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
dw_pcie_writel_atu_ob(pci, atu->index, PCIE_ATU_REGION_CTRL2, val);
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/*
원본 주석입니다. DWC outbound iATU region programming과 enable 확인에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Make sure ATU enable takes effect before any subsequent config
원본 주석입니다. DWC outbound iATU region programming과 enable 확인에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* and I/O accesses.
원본 주석입니다. DWC outbound iATU region programming과 enable 확인에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*/
원본 주석입니다. DWC outbound iATU region programming과 enable 확인에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
여러 pending source 또는 resource를 순회하는 구간입니다. 한 번의 진입에서 처리 가능한 양과 종료 조건이 interrupt latency에 영향을 줍니다.
val = dw_pcie_readl_atu_ob(pci, atu->index, PCIE_ATU_REGION_CTRL2);
공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.
if (val & PCIE_ATU_ENABLE)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return 0;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
mdelay(LINK_WAIT_IATU);
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dev_err(pci->dev, "Outbound iATU is not being enabled\n");
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
return -ETIMEDOUT;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
static inline u32 dw_pcie_readl_atu_ib(struct dw_pcie *pci, u32 index, u32 reg)
공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
return dw_pcie_readl_atu(pci, PCIE_ATU_REGION_DIR_IB, index, reg);
공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
static inline void dw_pcie_writel_atu_ib(struct dw_pcie *pci, u32 index, u32 reg,
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
u32 val)
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
dw_pcie_writel_atu(pci, PCIE_ATU_REGION_DIR_IB, index, reg, val);
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int type,
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 DWC outbound iATU region programming과 enable 확인의 입력 계약을 만족하는지 확인합니다.
u64 parent_bus_addr, u64 pci_addr, u64 size)
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
u64 limit_addr = pci_addr + size - 1;
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
u32 retries, val;
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if ((limit_addr & ~pci->region_limit) != (pci_addr & ~pci->region_limit) ||
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
!IS_ALIGNED(parent_bus_addr, pci->region_align) ||
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
!IS_ALIGNED(pci_addr, pci->region_align) || !size) {
DWC outbound iATU region programming과 enable 확인의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
return -EINVAL;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_BASE,
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
Linux v6.18.37 · 실제 원본 코드
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming
drivers/pci/controller/dwc/pcie-designware.c:593-677
593}
594
595static inline void dw_pcie_writel_atu_ib(struct dw_pcie *pci, u32 index, u32 reg,
596 u32 val)
597{
598 dw_pcie_writel_atu(pci, PCIE_ATU_REGION_DIR_IB, index, reg, val);
599}
600
601int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int type,
602 u64 parent_bus_addr, u64 pci_addr, u64 size)
603{
604 u64 limit_addr = pci_addr + size - 1;
605 u32 retries, val;
606
607 if ((limit_addr & ~pci->region_limit) != (pci_addr & ~pci->region_limit) ||
608 !IS_ALIGNED(parent_bus_addr, pci->region_align) ||
609 !IS_ALIGNED(pci_addr, pci->region_align) || !size) {
610 return -EINVAL;
611 }
612
613 dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_BASE,
614 lower_32_bits(pci_addr));
615 dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_BASE,
616 upper_32_bits(pci_addr));
617
618 dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LIMIT,
619 lower_32_bits(limit_addr));
620 if (dw_pcie_ver_is_ge(pci, 460A))
621 dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_LIMIT,
622 upper_32_bits(limit_addr));
623
624 dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_TARGET,
625 lower_32_bits(parent_bus_addr));
626 dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_TARGET,
627 upper_32_bits(parent_bus_addr));
628
629 val = type;
630 if (upper_32_bits(limit_addr) > upper_32_bits(pci_addr) &&
631 dw_pcie_ver_is_ge(pci, 460A))
632 val |= PCIE_ATU_INCREASE_REGION_SIZE;
633 dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL1, val);
634 dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2, PCIE_ATU_ENABLE);
635
636 /*
637 * Make sure ATU enable takes effect before any subsequent config
638 * and I/O accesses.
639 */
640 for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
641 val = dw_pcie_readl_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2);
642 if (val & PCIE_ATU_ENABLE)
643 return 0;
644
645 mdelay(LINK_WAIT_IATU);
646 }
647
648 dev_err(pci->dev, "Inbound iATU is not being enabled\n");
649
650 return -ETIMEDOUT;
651}
652
653int dw_pcie_prog_ep_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
654 int type, u64 parent_bus_addr, u8 bar, size_t size)
655{
656 u32 retries, val;
657
658 if (!IS_ALIGNED(parent_bus_addr, pci->region_align) ||
659 !IS_ALIGNED(parent_bus_addr, size))
660 return -EINVAL;
661
662 dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_TARGET,
663 lower_32_bits(parent_bus_addr));
664 dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_TARGET,
665 upper_32_bits(parent_bus_addr));
666
667 dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL1, type |
668 PCIE_ATU_FUNC_NUM(func_no));
669 dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2,
670 PCIE_ATU_ENABLE | PCIE_ATU_FUNC_NUM_MATCH_EN |
671 PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
672
673 /*
674 * Make sure ATU enable takes effect before any subsequent config
675 * and I/O accesses.
676 */
677 for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
static inline void dw_pcie_writel_atu_ib(struct dw_pcie *pci, u32 index, u32 reg,
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
u32 val)
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
dw_pcie_writel_atu(pci, PCIE_ATU_REGION_DIR_IB, index, reg, val);
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
int dw_pcie_prog_inbound_atu(struct dw_pcie *pci, int index, int type,
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 입력 계약을 만족하는지 확인합니다.
u64 parent_bus_addr, u64 pci_addr, u64 size)
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
u64 limit_addr = pci_addr + size - 1;
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
u32 retries, val;
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if ((limit_addr & ~pci->region_limit) != (pci_addr & ~pci->region_limit) ||
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
!IS_ALIGNED(parent_bus_addr, pci->region_align) ||
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
!IS_ALIGNED(pci_addr, pci->region_align) || !size) {
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
return -EINVAL;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_BASE,
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
lower_32_bits(pci_addr));
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_BASE,
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
upper_32_bits(pci_addr));
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LIMIT,
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
lower_32_bits(limit_addr));
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (dw_pcie_ver_is_ge(pci, 460A))
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_LIMIT,
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
upper_32_bits(limit_addr));
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_TARGET,
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
lower_32_bits(parent_bus_addr));
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_TARGET,
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
upper_32_bits(parent_bus_addr));
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
val = type;
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (upper_32_bits(limit_addr) > upper_32_bits(pci_addr) &&
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
dw_pcie_ver_is_ge(pci, 460A))
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
val |= PCIE_ATU_INCREASE_REGION_SIZE;
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL1, val);
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2, PCIE_ATU_ENABLE);
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/*
원본 주석입니다. DWC inbound iATU의 PCI address, parent address와 inclusive limit programming에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Make sure ATU enable takes effect before any subsequent config
원본 주석입니다. DWC inbound iATU의 PCI address, parent address와 inclusive limit programming에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* and I/O accesses.
원본 주석입니다. DWC inbound iATU의 PCI address, parent address와 inclusive limit programming에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*/
원본 주석입니다. DWC inbound iATU의 PCI address, parent address와 inclusive limit programming에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
여러 pending source 또는 resource를 순회하는 구간입니다. 한 번의 진입에서 처리 가능한 양과 종료 조건이 interrupt latency에 영향을 줍니다.
val = dw_pcie_readl_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2);
공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.
if (val & PCIE_ATU_ENABLE)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return 0;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
mdelay(LINK_WAIT_IATU);
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dev_err(pci->dev, "Inbound iATU is not being enabled\n");
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
return -ETIMEDOUT;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
int dw_pcie_prog_ep_inbound_atu(struct dw_pcie *pci, u8 func_no, int index,
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 입력 계약을 만족하는지 확인합니다.
int type, u64 parent_bus_addr, u8 bar, size_t size)
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
u32 retries, val;
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if (!IS_ALIGNED(parent_bus_addr, pci->region_align) ||
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
!IS_ALIGNED(parent_bus_addr, size))
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
return -EINVAL;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_LOWER_TARGET,
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
lower_32_bits(parent_bus_addr));
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_UPPER_TARGET,
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
upper_32_bits(parent_bus_addr));
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL1, type |
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
PCIE_ATU_FUNC_NUM(func_no));
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dw_pcie_writel_atu_ib(pci, index, PCIE_ATU_REGION_CTRL2,
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
PCIE_ATU_ENABLE | PCIE_ATU_FUNC_NUM_MATCH_EN |
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
PCIE_ATU_BAR_MODE_ENABLE | (bar << 8));
DWC inbound iATU의 PCI address, parent address와 inclusive limit programming의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/*
원본 주석입니다. DWC inbound iATU의 PCI address, parent address와 inclusive limit programming에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Make sure ATU enable takes effect before any subsequent config
원본 주석입니다. DWC inbound iATU의 PCI address, parent address와 inclusive limit programming에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* and I/O accesses.
원본 주석입니다. DWC inbound iATU의 PCI address, parent address와 inclusive limit programming에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*/
원본 주석입니다. DWC inbound iATU의 PCI address, parent address와 inclusive limit programming에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
for (retries = 0; retries < LINK_WAIT_MAX_IATU_RETRIES; retries++) {
여러 pending source 또는 resource를 순회하는 구간입니다. 한 번의 진입에서 처리 가능한 양과 종료 조건이 interrupt latency에 영향을 줍니다.
Linux v6.18.37 · 실제 원본 코드
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드
drivers/pci/controller/dwc/pcie-designware-host.c:412-482
412 res->name = "msg";
413 res->flags = win->res->flags | IORESOURCE_BUSY;
414
415 if (!devm_request_resource(pci->dev, win->res, res))
416 pp->msg_res = res;
417 }
418}
419
420static int dw_pcie_config_ecam_iatu(struct dw_pcie_rp *pp)
421{
422 struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
423 struct dw_pcie_ob_atu_cfg atu = {0};
424 resource_size_t bus_range_max;
425 struct resource_entry *bus;
426 int ret;
427
428 bus = resource_list_first_type(&pp->bridge->windows, IORESOURCE_BUS);
429
430 /*
431 * Root bus under the host bridge doesn't require any iATU configuration
432 * as DBI region will be used to access root bus config space.
433 * Immediate bus under Root Bus, needs type 0 iATU configuration and
434 * remaining buses need type 1 iATU configuration.
435 */
436 atu.index = 0;
437 atu.type = PCIE_ATU_TYPE_CFG0;
438 atu.parent_bus_addr = pp->cfg0_base + SZ_1M;
439 /* 1MiB is to cover 1 (bus) * 32 (devices) * 8 (functions) */
440 atu.size = SZ_1M;
441 atu.ctrl2 = PCIE_ATU_CFG_SHIFT_MODE_ENABLE;
442 ret = dw_pcie_prog_outbound_atu(pci, &atu);
443 if (ret)
444 return ret;
445
446 bus_range_max = resource_size(bus->res);
447
448 if (bus_range_max < 2)
449 return 0;
450
451 /* Configure remaining buses in type 1 iATU configuration */
452 atu.index = 1;
453 atu.type = PCIE_ATU_TYPE_CFG1;
454 atu.parent_bus_addr = pp->cfg0_base + SZ_2M;
455 atu.size = (SZ_1M * bus_range_max) - SZ_2M;
456 atu.ctrl2 = PCIE_ATU_CFG_SHIFT_MODE_ENABLE;
457
458 return dw_pcie_prog_outbound_atu(pci, &atu);
459}
460
461static int dw_pcie_create_ecam_window(struct dw_pcie_rp *pp, struct resource *res)
462{
463 struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
464 struct device *dev = pci->dev;
465 struct resource_entry *bus;
466
467 bus = resource_list_first_type(&pp->bridge->windows, IORESOURCE_BUS);
468 if (!bus)
469 return -ENODEV;
470
471 pp->cfg = pci_ecam_create(dev, res, bus->res, &pci_generic_ecam_ops);
472 if (IS_ERR(pp->cfg))
473 return PTR_ERR(pp->cfg);
474
475 return 0;
476}
477
478static bool dw_pcie_ecam_enabled(struct dw_pcie_rp *pp, struct resource *config_res)
479{
480 struct resource *bus_range;
481 u64 nr_buses;
482 res->name = "msg";
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
res->flags = win->res->flags | IORESOURCE_BUSY;
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if (!devm_request_resource(pci->dev, win->res, res))
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
pp->msg_res = res;
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
static int dw_pcie_config_ecam_iatu(struct dw_pcie_rp *pp)
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 입력 계약을 만족하는지 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
struct dw_pcie_ob_atu_cfg atu = {0};
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
resource_size_t bus_range_max;
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
struct resource_entry *bus;
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
int ret;
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
bus = resource_list_first_type(&pp->bridge->windows, IORESOURCE_BUS);
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/*
원본 주석입니다. ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Root bus under the host bridge doesn't require any iATU configuration
원본 주석입니다. ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* as DBI region will be used to access root bus config space.
원본 주석입니다. ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Immediate bus under Root Bus, needs type 0 iATU configuration and
원본 주석입니다. ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* remaining buses need type 1 iATU configuration.
원본 주석입니다. ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*/
원본 주석입니다. ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
atu.index = 0;
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
atu.type = PCIE_ATU_TYPE_CFG0;
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
atu.parent_bus_addr = pp->cfg0_base + SZ_1M;
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
/* 1MiB is to cover 1 (bus) * 32 (devices) * 8 (functions) */
원본 주석입니다. ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
atu.size = SZ_1M;
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
atu.ctrl2 = PCIE_ATU_CFG_SHIFT_MODE_ENABLE;
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
ret = dw_pcie_prog_outbound_atu(pci, &atu);
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (ret)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return ret;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
bus_range_max = resource_size(bus->res);
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if (bus_range_max < 2)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return 0;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Configure remaining buses in type 1 iATU configuration */
원본 주석입니다. ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
atu.index = 1;
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
atu.type = PCIE_ATU_TYPE_CFG1;
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
atu.parent_bus_addr = pp->cfg0_base + SZ_2M;
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
atu.size = (SZ_1M * bus_range_max) - SZ_2M;
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
atu.ctrl2 = PCIE_ATU_CFG_SHIFT_MODE_ENABLE;
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
return dw_pcie_prog_outbound_atu(pci, &atu);
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
static int dw_pcie_create_ecam_window(struct dw_pcie_rp *pp, struct resource *res)
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 입력 계약을 만족하는지 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
struct device *dev = pci->dev;
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
struct resource_entry *bus;
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
bus = resource_list_first_type(&pp->bridge->windows, IORESOURCE_BUS);
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (!bus)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return -ENODEV;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
pp->cfg = pci_ecam_create(dev, res, bus->res, &pci_generic_ecam_ops);
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (IS_ERR(pp->cfg))
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return PTR_ERR(pp->cfg);
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
return 0;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
static bool dw_pcie_ecam_enabled(struct dw_pcie_rp *pp, struct resource *config_res)
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 입력 계약을 만족하는지 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
struct resource *bus_range;
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
u64 nr_buses;
ECAM mode에서 immediate bus CFG0와 나머지 bus CFG1 region을 나누는 코드의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
Linux v6.18.37 · 실제 원본 코드
DWC Root Port DBI와 outbound window 설정
drivers/pci/controller/dwc/pcie-designware-host.c:1037-1119
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
1065 /* Setup interrupt pins */
1066 val = dw_pcie_readl_dbi(pci, PCI_INTERRUPT_LINE);
1067 val &= 0xffff00ff;
1068 val |= 0x00000100;
1069 dw_pcie_writel_dbi(pci, PCI_INTERRUPT_LINE, val);
1070
1071 /* Setup bus numbers */
1072 val = dw_pcie_readl_dbi(pci, PCI_PRIMARY_BUS);
1073 val &= 0xff000000;
1074 val |= 0x00ff0100;
1075 dw_pcie_writel_dbi(pci, PCI_PRIMARY_BUS, val);
1076
1077 /* Setup command register */
1078 val = dw_pcie_readl_dbi(pci, PCI_COMMAND);
1079 val &= 0xffff0000;
1080 val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
1081 PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
1082 dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
1083
1084 dw_pcie_hide_unsupported_l1ss(pci);
1085
1086 dw_pcie_config_presets(pp);
1087 /*
1088 * If the platform provides its own child bus config accesses, it means
1089 * the platform uses its own address translation component rather than
1090 * ATU, so we should not program the ATU here.
1091 */
1092 if (pp->bridge->child_ops == &dw_child_pcie_ops) {
1093 ret = dw_pcie_iatu_setup(pp);
1094 if (ret)
1095 return ret;
1096 }
1097
1098 dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);
1099
1100 /* Program correct class for RC */
1101 dw_pcie_writew_dbi(pci, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
1102
1103 val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
1104 val |= PORT_LOGIC_SPEED_CHANGE;
1105 dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
1106
1107 dw_pcie_dbi_ro_wr_dis(pci);
1108
1109 return 0;
1110}
1111EXPORT_SYMBOL_GPL(dw_pcie_setup_rc);
1112
1113static int dw_pcie_pme_turn_off(struct dw_pcie *pci)
1114{
1115 struct dw_pcie_ob_atu_cfg atu = { 0 };
1116 void __iomem *mem;
1117 int ret;
1118
1119 if (pci->num_ob_windows <= pci->pp.msg_atu_index)(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if (speed >= PCIE_SPEED_32_0GT)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
dw_pcie_program_presets(pp, PCIE_SPEED_32_0GT);
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if (speed >= PCIE_SPEED_64_0GT)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
dw_pcie_program_presets(pp, PCIE_SPEED_64_0GT);
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
int dw_pcie_setup_rc(struct dw_pcie_rp *pp)
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 DWC Root Port DBI와 outbound window 설정의 입력 계약을 만족하는지 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
u32 val;
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
int ret;
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/*
원본 주석입니다. DWC Root Port DBI와 outbound window 설정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Enable DBI read-only registers for writing/updating configuration.
원본 주석입니다. DWC Root Port DBI와 outbound window 설정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Write permission gets disabled towards the end of this function.
원본 주석입니다. DWC Root Port DBI와 outbound window 설정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*/
원본 주석입니다. DWC Root Port DBI와 outbound window 설정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
dw_pcie_dbi_ro_wr_en(pci);
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dw_pcie_setup(pci);
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dw_pcie_msi_init(pp);
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Setup RC BARs */
원본 주석입니다. DWC Root Port DBI와 outbound window 설정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0x00000004);
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_1, 0x00000000);
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Setup interrupt pins */
원본 주석입니다. DWC Root Port DBI와 outbound window 설정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
val = dw_pcie_readl_dbi(pci, PCI_INTERRUPT_LINE);
공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.
val &= 0xffff00ff;
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
val |= 0x00000100;
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dw_pcie_writel_dbi(pci, PCI_INTERRUPT_LINE, val);
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Setup bus numbers */
원본 주석입니다. DWC Root Port DBI와 outbound window 설정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
val = dw_pcie_readl_dbi(pci, PCI_PRIMARY_BUS);
공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.
val &= 0xff000000;
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
val |= 0x00ff0100;
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dw_pcie_writel_dbi(pci, PCI_PRIMARY_BUS, val);
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Setup command register */
원본 주석입니다. DWC Root Port DBI와 outbound window 설정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
val = dw_pcie_readl_dbi(pci, PCI_COMMAND);
공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.
val &= 0xffff0000;
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
val |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
PCI_COMMAND_MASTER | PCI_COMMAND_SERR;
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dw_pcie_writel_dbi(pci, PCI_COMMAND, val);
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dw_pcie_hide_unsupported_l1ss(pci);
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dw_pcie_config_presets(pp);
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
/*
원본 주석입니다. DWC Root Port DBI와 outbound window 설정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* If the platform provides its own child bus config accesses, it means
원본 주석입니다. DWC Root Port DBI와 outbound window 설정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* the platform uses its own address translation component rather than
원본 주석입니다. DWC Root Port DBI와 outbound window 설정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* ATU, so we should not program the ATU here.
원본 주석입니다. DWC Root Port DBI와 outbound window 설정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*/
원본 주석입니다. DWC Root Port DBI와 outbound window 설정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
if (pp->bridge->child_ops == &dw_child_pcie_ops) {
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
ret = dw_pcie_iatu_setup(pp);
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (ret)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return ret;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dw_pcie_writel_dbi(pci, PCI_BASE_ADDRESS_0, 0);
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Program correct class for RC */
원본 주석입니다. DWC Root Port DBI와 outbound window 설정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
dw_pcie_writew_dbi(pci, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.
val |= PORT_LOGIC_SPEED_CHANGE;
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dw_pcie_dbi_ro_wr_dis(pci);
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
return 0;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
EXPORT_SYMBOL_GPL(dw_pcie_setup_rc);
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
static int dw_pcie_pme_turn_off(struct dw_pcie *pci)
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 DWC Root Port DBI와 outbound window 설정의 입력 계약을 만족하는지 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
struct dw_pcie_ob_atu_cfg atu = { 0 };
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
void __iomem *mem;
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
int ret;
DWC Root Port DBI와 outbound window 설정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if (pci->num_ob_windows <= pci->pp.msg_atu_index)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
Linux v6.18.37 · 실제 원본 코드
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler
drivers/pci/controller/dwc/pcie-designware-host.c:41-107
41 .supported_flags = DW_PCIE_MSI_FLAGS_SUPPORTED,
42 .bus_select_token = DOMAIN_BUS_PCI_MSI,
43 .chip_flags = MSI_CHIP_FLAG_SET_ACK,
44 .prefix = "DW-",
45 .init_dev_msi_info = msi_lib_init_dev_msi_info,
46};
47
48/* MSI int handler */
49irqreturn_t dw_handle_msi_irq(struct dw_pcie_rp *pp)
50{
51 int i, pos;
52 unsigned long val;
53 u32 status, num_ctrls;
54 irqreturn_t ret = IRQ_NONE;
55 struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
56
57 num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
58
59 for (i = 0; i < num_ctrls; i++) {
60 status = dw_pcie_readl_dbi(pci, PCIE_MSI_INTR0_STATUS +
61 (i * MSI_REG_CTRL_BLOCK_SIZE));
62 if (!status)
63 continue;
64
65 ret = IRQ_HANDLED;
66 val = status;
67 pos = 0;
68 while ((pos = find_next_bit(&val, MAX_MSI_IRQS_PER_CTRL,
69 pos)) != MAX_MSI_IRQS_PER_CTRL) {
70 generic_handle_domain_irq(pp->irq_domain,
71 (i * MAX_MSI_IRQS_PER_CTRL) +
72 pos);
73 pos++;
74 }
75 }
76
77 return ret;
78}
79
80/* Chained MSI interrupt service routine */
81static void dw_chained_msi_isr(struct irq_desc *desc)
82{
83 struct irq_chip *chip = irq_desc_get_chip(desc);
84 struct dw_pcie_rp *pp;
85
86 chained_irq_enter(chip, desc);
87
88 pp = irq_desc_get_handler_data(desc);
89 dw_handle_msi_irq(pp);
90
91 chained_irq_exit(chip, desc);
92}
93
94static void dw_pci_setup_msi_msg(struct irq_data *d, struct msi_msg *msg)
95{
96 struct dw_pcie_rp *pp = irq_data_get_irq_chip_data(d);
97 struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
98 u64 msi_target;
99
100 msi_target = (u64)pp->msi_data;
101
102 msg->address_lo = lower_32_bits(msi_target);
103 msg->address_hi = upper_32_bits(msi_target);
104
105 msg->data = d->hwirq;
106
107 dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n",.supported_flags = DW_PCIE_MSI_FLAGS_SUPPORTED,
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
.bus_select_token = DOMAIN_BUS_PCI_MSI,
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
.chip_flags = MSI_CHIP_FLAG_SET_ACK,
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
.prefix = "DW-",
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
.init_dev_msi_info = msi_lib_init_dev_msi_info,
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
};
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* MSI int handler */
원본 주석입니다. DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
irqreturn_t dw_handle_msi_irq(struct dw_pcie_rp *pp)
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 입력 계약을 만족하는지 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
int i, pos;
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
unsigned long val;
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
u32 status, num_ctrls;
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
irqreturn_t ret = IRQ_NONE;
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
for (i = 0; i < num_ctrls; i++) {
여러 pending source 또는 resource를 순회하는 구간입니다. 한 번의 진입에서 처리 가능한 양과 종료 조건이 interrupt latency에 영향을 줍니다.
status = dw_pcie_readl_dbi(pci, PCIE_MSI_INTR0_STATUS +
공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.
(i * MSI_REG_CTRL_BLOCK_SIZE));
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (!status)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
continue;
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
ret = IRQ_HANDLED;
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
val = status;
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
pos = 0;
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
while ((pos = find_next_bit(&val, MAX_MSI_IRQS_PER_CTRL,
여러 pending source 또는 resource를 순회하는 구간입니다. 한 번의 진입에서 처리 가능한 양과 종료 조건이 interrupt latency에 영향을 줍니다.
pos)) != MAX_MSI_IRQS_PER_CTRL) {
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
generic_handle_domain_irq(pp->irq_domain,
hardware ID를 Linux IRQ core로 넘기는 경계입니다. 여기부터 hwirq, virq, irq_desc, irqaction의 번호 공간을 구분해 추적합니다.
(i * MAX_MSI_IRQS_PER_CTRL) +
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
pos);
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
pos++;
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
return ret;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Chained MSI interrupt service routine */
원본 주석입니다. DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
static void dw_chained_msi_isr(struct irq_desc *desc)
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 입력 계약을 만족하는지 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
struct irq_chip *chip = irq_desc_get_chip(desc);
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
struct dw_pcie_rp *pp;
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
chained_irq_enter(chip, desc);
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
pp = irq_desc_get_handler_data(desc);
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dw_handle_msi_irq(pp);
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
chained_irq_exit(chip, desc);
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
static void dw_pci_setup_msi_msg(struct irq_data *d, struct msi_msg *msg)
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 입력 계약을 만족하는지 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
struct dw_pcie_rp *pp = irq_data_get_irq_chip_data(d);
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
u64 msi_target;
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
msi_target = (u64)pp->msi_data;
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
msg->address_lo = lower_32_bits(msi_target);
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
msg->address_hi = upper_32_bits(msi_target);
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
msg->data = d->hwirq;
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dev_dbg(pci->dev, "msi#%d address_hi %#x address_lo %#x\n",
DWC 내부 MSI status block을 읽고 irqdomain으로 전달하는 handler의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
Linux v6.18.37 · 실제 원본 코드
DWC MSI target address, enable과 mask register 초기화
drivers/pci/controller/dwc/pcie-designware-host.c:243-293
243 irq_set_chained_handler_and_data(pp->msi_irq[ctrl],
244 NULL, NULL);
245 }
246
247 irq_domain_remove(pp->irq_domain);
248}
249EXPORT_SYMBOL_GPL(dw_pcie_free_msi);
250
251void dw_pcie_msi_init(struct dw_pcie_rp *pp)
252{
253 struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
254 u64 msi_target = (u64)pp->msi_data;
255 u32 ctrl, num_ctrls;
256
257 if (!pci_msi_enabled() || !pp->has_msi_ctrl)
258 return;
259
260 num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
261
262 /* Initialize IRQ Status array */
263 for (ctrl = 0; ctrl < num_ctrls; ctrl++) {
264 dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK +
265 (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
266 pp->irq_mask[ctrl]);
267 dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_ENABLE +
268 (ctrl * MSI_REG_CTRL_BLOCK_SIZE),
269 ~0);
270 }
271
272 /* Program the msi_data */
273 dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_LO, lower_32_bits(msi_target));
274 dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_HI, upper_32_bits(msi_target));
275}
276EXPORT_SYMBOL_GPL(dw_pcie_msi_init);
277
278static int dw_pcie_parse_split_msi_irq(struct dw_pcie_rp *pp)
279{
280 struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
281 struct device *dev = pci->dev;
282 struct platform_device *pdev = to_platform_device(dev);
283 u32 ctrl, max_vectors;
284 int irq;
285
286 /* Parse any "msiX" IRQs described in the devicetree */
287 for (ctrl = 0; ctrl < MAX_MSI_CTRLS; ctrl++) {
288 char msi_name[] = "msiX";
289
290 msi_name[3] = '0' + ctrl;
291 irq = platform_get_irq_byname_optional(pdev, msi_name);
292 if (irq == -ENXIO)
293 break;irq_set_chained_handler_and_data(pp->msi_irq[ctrl],
DWC MSI target address, enable과 mask register 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
NULL, NULL);
DWC MSI target address, enable과 mask register 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
irq_domain_remove(pp->irq_domain);
DWC MSI target address, enable과 mask register 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
EXPORT_SYMBOL_GPL(dw_pcie_free_msi);
DWC MSI target address, enable과 mask register 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
void dw_pcie_msi_init(struct dw_pcie_rp *pp)
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 DWC MSI target address, enable과 mask register 초기화의 입력 계약을 만족하는지 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
DWC MSI target address, enable과 mask register 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
u64 msi_target = (u64)pp->msi_data;
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 DWC MSI target address, enable과 mask register 초기화의 입력 계약을 만족하는지 확인합니다.
u32 ctrl, num_ctrls;
DWC MSI target address, enable과 mask register 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if (!pci_msi_enabled() || !pp->has_msi_ctrl)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
num_ctrls = pp->num_vectors / MAX_MSI_IRQS_PER_CTRL;
DWC MSI target address, enable과 mask register 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Initialize IRQ Status array */
원본 주석입니다. DWC MSI target address, enable과 mask register 초기화에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
for (ctrl = 0; ctrl < num_ctrls; ctrl++) {
여러 pending source 또는 resource를 순회하는 구간입니다. 한 번의 진입에서 처리 가능한 양과 종료 조건이 interrupt latency에 영향을 줍니다.
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_MASK +
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
(ctrl * MSI_REG_CTRL_BLOCK_SIZE),
DWC MSI target address, enable과 mask register 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
pp->irq_mask[ctrl]);
DWC MSI target address, enable과 mask register 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dw_pcie_writel_dbi(pci, PCIE_MSI_INTR0_ENABLE +
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
(ctrl * MSI_REG_CTRL_BLOCK_SIZE),
DWC MSI target address, enable과 mask register 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
~0);
DWC MSI target address, enable과 mask register 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Program the msi_data */
원본 주석입니다. DWC MSI target address, enable과 mask register 초기화에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_LO, lower_32_bits(msi_target));
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
dw_pcie_writel_dbi(pci, PCIE_MSI_ADDR_HI, upper_32_bits(msi_target));
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
EXPORT_SYMBOL_GPL(dw_pcie_msi_init);
DWC MSI target address, enable과 mask register 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
static int dw_pcie_parse_split_msi_irq(struct dw_pcie_rp *pp)
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 DWC MSI target address, enable과 mask register 초기화의 입력 계약을 만족하는지 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
DWC MSI target address, enable과 mask register 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
struct device *dev = pci->dev;
DWC MSI target address, enable과 mask register 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
struct platform_device *pdev = to_platform_device(dev);
DWC MSI target address, enable과 mask register 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
u32 ctrl, max_vectors;
DWC MSI target address, enable과 mask register 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
int irq;
DWC MSI target address, enable과 mask register 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Parse any "msiX" IRQs described in the devicetree */
원본 주석입니다. DWC MSI target address, enable과 mask register 초기화에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
for (ctrl = 0; ctrl < MAX_MSI_CTRLS; ctrl++) {
여러 pending source 또는 resource를 순회하는 구간입니다. 한 번의 진입에서 처리 가능한 양과 종료 조건이 interrupt latency에 영향을 줍니다.
char msi_name[] = "msiX";
DWC MSI target address, enable과 mask register 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
msi_name[3] = '0' + ctrl;
DWC MSI target address, enable과 mask register 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
irq = platform_get_irq_byname_optional(pdev, msi_name);
DWC MSI target address, enable과 mask register 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (irq == -ENXIO)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
break;
DWC MSI target address, enable과 mask register 초기화의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
Linux v6.18.37 · 실제 원본 코드
DWC eDMA mode, channel, IRQ와 linked-list resource detection
drivers/pci/controller/dwc/pcie-designware.c:1088-1150
1088 &paddr, GFP_KERNEL);
1089 if (!ll->vaddr.mem)
1090 return -ENOMEM;
1091
1092 ll->paddr = paddr;
1093 }
1094
1095 return 0;
1096}
1097
1098int dw_pcie_edma_detect(struct dw_pcie *pci)
1099{
1100 int ret;
1101
1102 /* Don't fail if no eDMA was found (for the backward compatibility) */
1103 ret = dw_pcie_edma_find_chip(pci);
1104 if (ret)
1105 return 0;
1106
1107 /* Don't fail on the IRQs verification (for the backward compatibility) */
1108 ret = dw_pcie_edma_irq_verify(pci);
1109 if (ret) {
1110 dev_err(pci->dev, "Invalid eDMA IRQs found\n");
1111 return 0;
1112 }
1113
1114 ret = dw_pcie_edma_ll_alloc(pci);
1115 if (ret) {
1116 dev_err(pci->dev, "Couldn't allocate LLP memory\n");
1117 return ret;
1118 }
1119
1120 /* Don't fail if the DW eDMA driver can't find the device */
1121 ret = dw_edma_probe(&pci->edma);
1122 if (ret && ret != -ENODEV) {
1123 dev_err(pci->dev, "Couldn't register eDMA device\n");
1124 return ret;
1125 }
1126
1127 dev_info(pci->dev, "eDMA: unroll %s, %hu wr, %hu rd\n",
1128 pci->edma.mf == EDMA_MF_EDMA_UNROLL ? "T" : "F",
1129 pci->edma.ll_wr_cnt, pci->edma.ll_rd_cnt);
1130
1131 return 0;
1132}
1133
1134void dw_pcie_edma_remove(struct dw_pcie *pci)
1135{
1136 dw_edma_remove(&pci->edma);
1137}
1138
1139void dw_pcie_hide_unsupported_l1ss(struct dw_pcie *pci)
1140{
1141 u16 l1ss;
1142 u32 l1ss_cap;
1143
1144 if (pci->l1ss_support)
1145 return;
1146
1147 l1ss = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS);
1148 if (!l1ss)
1149 return;
1150 &paddr, GFP_KERNEL);
DWC eDMA mode, channel, IRQ와 linked-list resource detection의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (!ll->vaddr.mem)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return -ENOMEM;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
ll->paddr = paddr;
DWC eDMA mode, channel, IRQ와 linked-list resource detection의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
return 0;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
int dw_pcie_edma_detect(struct dw_pcie *pci)
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 DWC eDMA mode, channel, IRQ와 linked-list resource detection의 입력 계약을 만족하는지 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
int ret;
DWC eDMA mode, channel, IRQ와 linked-list resource detection의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Don't fail if no eDMA was found (for the backward compatibility) */
원본 주석입니다. DWC eDMA mode, channel, IRQ와 linked-list resource detection에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
ret = dw_pcie_edma_find_chip(pci);
DWC eDMA mode, channel, IRQ와 linked-list resource detection의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (ret)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return 0;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Don't fail on the IRQs verification (for the backward compatibility) */
원본 주석입니다. DWC eDMA mode, channel, IRQ와 linked-list resource detection에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
ret = dw_pcie_edma_irq_verify(pci);
DWC eDMA mode, channel, IRQ와 linked-list resource detection의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (ret) {
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
dev_err(pci->dev, "Invalid eDMA IRQs found\n");
DWC eDMA mode, channel, IRQ와 linked-list resource detection의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
return 0;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
ret = dw_pcie_edma_ll_alloc(pci);
DWC eDMA mode, channel, IRQ와 linked-list resource detection의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (ret) {
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
dev_err(pci->dev, "Couldn't allocate LLP memory\n");
DWC eDMA mode, channel, IRQ와 linked-list resource detection의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
return ret;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Don't fail if the DW eDMA driver can't find the device */
원본 주석입니다. DWC eDMA mode, channel, IRQ와 linked-list resource detection에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
ret = dw_edma_probe(&pci->edma);
DWC eDMA mode, channel, IRQ와 linked-list resource detection의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (ret && ret != -ENODEV) {
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
dev_err(pci->dev, "Couldn't register eDMA device\n");
DWC eDMA mode, channel, IRQ와 linked-list resource detection의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
return ret;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dev_info(pci->dev, "eDMA: unroll %s, %hu wr, %hu rd\n",
DWC eDMA mode, channel, IRQ와 linked-list resource detection의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
pci->edma.mf == EDMA_MF_EDMA_UNROLL ? "T" : "F",
DWC eDMA mode, channel, IRQ와 linked-list resource detection의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
pci->edma.ll_wr_cnt, pci->edma.ll_rd_cnt);
DWC eDMA mode, channel, IRQ와 linked-list resource detection의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
return 0;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
void dw_pcie_edma_remove(struct dw_pcie *pci)
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 DWC eDMA mode, channel, IRQ와 linked-list resource detection의 입력 계약을 만족하는지 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
dw_edma_remove(&pci->edma);
DWC eDMA mode, channel, IRQ와 linked-list resource detection의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
void dw_pcie_hide_unsupported_l1ss(struct dw_pcie *pci)
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 DWC eDMA mode, channel, IRQ와 linked-list resource detection의 입력 계약을 만족하는지 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
u16 l1ss;
DWC eDMA mode, channel, IRQ와 linked-list resource detection의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
u32 l1ss_cap;
DWC eDMA mode, channel, IRQ와 linked-list resource detection의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if (pci->l1ss_support)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
l1ss = dw_pcie_find_ext_capability(pci, PCI_EXT_CAP_ID_L1SS);
DWC eDMA mode, channel, IRQ와 linked-list resource detection의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (!l1ss)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
Linux v6.18.37 · 실제 원본 코드
Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계
2612 return NULL;
2613}
2614#endif
2615
2616/*
2617 * Read the config data for a PCI device, sanity-check it,
2618 * and fill in the dev structure.
2619 */
2620static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
2621{
2622 struct pci_dev *dev;
2623 u32 l;
2624
2625 /*
2626 * Create pwrctrl device (if required) for the PCI device to handle the
2627 * power state. If the pwrctrl device is created, then skip scanning
2628 * further as the pwrctrl core will rescan the bus after powering on
2629 * the device.
2630 */
2631 if (pci_pwrctrl_create_device(bus, devfn))
2632 return NULL;
2633
2634 if (!pci_bus_read_dev_vendor_id(bus, devfn, &l, 60*1000))
2635 return NULL;
2636
2637 dev = pci_alloc_dev(bus);
2638 if (!dev)
2639 return NULL;
2640
2641 dev->devfn = devfn;
2642 dev->vendor = l & 0xffff;
2643 dev->device = (l >> 16) & 0xffff;
2644
2645 if (pci_setup_device(dev)) {
2646 pci_bus_put(dev->bus);
2647 kfree(dev);
2648 return NULL;
2649 }
2650
2651 return dev;
2652}
2653
2654void pcie_report_downtraining(struct pci_dev *dev)
2655{
2656 if (!pci_is_pcie(dev))
2657 return;
2658
2659 /* Look from the device up to avoid downstream ports with no devices */
2660 if ((pci_pcie_type(dev) != PCI_EXP_TYPE_ENDPOINT) &&
2661 (pci_pcie_type(dev) != PCI_EXP_TYPE_LEG_END) &&
2662 (pci_pcie_type(dev) != PCI_EXP_TYPE_UPSTREAM))
2663 return;
2664
2665 /* Multi-function PCIe devices share the same link/status */
2666 if (PCI_FUNC(dev->devfn) != 0 || dev->is_virtfn)
2667 return;
2668 return NULL;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
#endif
빌드 설정에 따라 포함되는 경로입니다. 실행 중 분기가 아니므로 실제 커널의 .config와 전처리 결과를 함께 봐야 합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/*
원본 주석입니다. Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Read the config data for a PCI device, sanity-check it,
원본 주석입니다. Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* and fill in the dev structure.
원본 주석입니다. Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*/
원본 주석입니다. Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
static struct pci_dev *pci_scan_device(struct pci_bus *bus, int devfn)
Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
struct pci_dev *dev;
Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
u32 l;
Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/*
원본 주석입니다. Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Create pwrctrl device (if required) for the PCI device to handle the
원본 주석입니다. Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* power state. If the pwrctrl device is created, then skip scanning
원본 주석입니다. Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* further as the pwrctrl core will rescan the bus after powering on
원본 주석입니다. Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* the device.
원본 주석입니다. Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*/
원본 주석입니다. Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
if (pci_pwrctrl_create_device(bus, devfn))
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return NULL;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if (!pci_bus_read_dev_vendor_id(bus, devfn, &l, 60*1000))
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return NULL;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dev = pci_alloc_dev(bus);
Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (!dev)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return NULL;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dev->devfn = devfn;
Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dev->vendor = l & 0xffff;
Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dev->device = (l >> 16) & 0xffff;
Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if (pci_setup_device(dev)) {
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
pci_bus_put(dev->bus);
Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
kfree(dev);
Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
return NULL;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
return dev;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
void pcie_report_downtraining(struct pci_dev *dev)
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계의 입력 계약을 만족하는지 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
if (!pci_is_pcie(dev))
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Look from the device up to avoid downstream ports with no devices */
원본 주석입니다. Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
if ((pci_pcie_type(dev) != PCI_EXP_TYPE_ENDPOINT) &&
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
(pci_pcie_type(dev) != PCI_EXP_TYPE_LEG_END) &&
Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(pci_pcie_type(dev) != PCI_EXP_TYPE_UPSTREAM))
Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
return;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Multi-function PCIe devices share the same link/status */
원본 주석입니다. Vendor ID를 읽어 pci_dev를 만들고 중복 scan을 방지하는 경계에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
if (PCI_FUNC(dev->devfn) != 0 || dev->is_virtfn)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
Linux v6.18.37 · 실제 원본 코드
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정
1987/**
1988 * pci_setup_device - Fill in class and map information of a device
1989 * @dev: the device structure to fill
1990 *
1991 * Initialize the device structure with information about the device's
1992 * vendor,class,memory and IO-space addresses, IRQ lines etc.
1993 * Called at initialisation of the PCI subsystem and by CardBus services.
1994 * Returns 0 on success and negative if unknown type of device (not normal,
1995 * bridge or CardBus).
1996 */
1997int pci_setup_device(struct pci_dev *dev)
1998{
1999 u32 class;
2000 u16 cmd;
2001 u8 hdr_type;
2002 int err, pos = 0;
2003 struct pci_bus_region region;
2004 struct resource *res;
2005
2006 hdr_type = pci_hdr_type(dev);
2007
2008 dev->sysdata = dev->bus->sysdata;
2009 dev->dev.parent = dev->bus->bridge;
2010 dev->dev.bus = &pci_bus_type;
2011 dev->hdr_type = FIELD_GET(PCI_HEADER_TYPE_MASK, hdr_type);
2012 dev->multifunction = FIELD_GET(PCI_HEADER_TYPE_MFD, hdr_type);
2013 dev->error_state = pci_channel_io_normal;
2014 set_pcie_port_type(dev);
2015
2016 err = pci_set_of_node(dev);
2017 if (err)
2018 return err;
2019 pci_set_acpi_fwnode(dev);
2020
2021 pci_dev_assign_slot(dev);
2022
2023 /*
2024 * Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
2025 * set this higher, assuming the system even supports it.
2026 */
2027 dev->dma_mask = 0xffffffff;
2028
2029 dev_set_name(&dev->dev, "%04x:%02x:%02x.%d", pci_domain_nr(dev->bus),
2030 dev->bus->number, PCI_SLOT(dev->devfn),
2031 PCI_FUNC(dev->devfn));
2032
2033 class = pci_class(dev);
2034
2035 dev->revision = class & 0xff;
2036 dev->class = class >> 8; /* upper 3 bytes */
2037
2038 if (pci_early_dump)
2039 early_dump_pci_device(dev);
2040
2041 /* Need to have dev->class ready */
2042 dev->cfg_size = pci_cfg_space_size(dev);
2043
2044 /* Need to have dev->cfg_size ready */
2045 set_pcie_thunderbolt(dev);
2046
2047 set_pcie_untrusted(dev);
2048
2049 if (pci_is_pcie(dev))
2050 dev->supported_speeds = pcie_get_supported_speeds(dev);
2051
2052 /* "Unknown power state" */
2053 dev->current_state = PCI_UNKNOWN;
2054
2055 /* Early fixups, before probing the BARs */
2056 pci_fixup_device(pci_fixup_early, dev);
2057
2058 pci_set_removable(dev);
2059
2060 pci_info(dev, "[%04x:%04x] type %02x class %#08x %s\n",
2061 dev->vendor, dev->device, dev->hdr_type, dev->class,
2062 pci_type_str(dev));
2063
2064 /* Device class may be changed after fixup */
2065 class = dev->class >> 8;
2066
2067 if (dev->non_compliant_bars && !dev->mmio_always_on) {
2068 pci_read_config_word(dev, PCI_COMMAND, &cmd);
2069 if (cmd & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
2070 pci_info(dev, "device has non-compliant BARs; disabling IO/MEM decoding\n");
2071 cmd &= ~PCI_COMMAND_IO;
2072 cmd &= ~PCI_COMMAND_MEMORY;
2073 pci_write_config_word(dev, PCI_COMMAND, cmd);
2074 }
2075 }
2076
2077 dev->broken_intx_masking = pci_intx_mask_broken(dev);
2078
2079 switch (dev->hdr_type) { /* header type */
2080 case PCI_HEADER_TYPE_NORMAL: /* standard header */
2081 if (class == PCI_CLASS_BRIDGE_PCI)
2082 goto bad;
2083 pci_read_irq(dev);
2084 pci_read_bases(dev, PCI_STD_NUM_BARS, PCI_ROM_ADDRESS);
2085
2086 pci_subsystem_ids(dev, &dev->subsystem_vendor, &dev->subsystem_device);
2087
2088 /*
2089 * Do the ugly legacy mode stuff here rather than broken chip
2090 * quirk code. Legacy mode ATA controllers have fixed
2091 * addresses. These are not always echoed in BAR0-3, and/**
원본 주석입니다. Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* pci_setup_device - Fill in class and map information of a device
원본 주석입니다. Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* @dev: the device structure to fill
원본 주석입니다. Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*
원본 주석입니다. Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Initialize the device structure with information about the device's
원본 주석입니다. Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* vendor,class,memory and IO-space addresses, IRQ lines etc.
원본 주석입니다. Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Called at initialisation of the PCI subsystem and by CardBus services.
원본 주석입니다. Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Returns 0 on success and negative if unknown type of device (not normal,
원본 주석입니다. Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* bridge or CardBus).
원본 주석입니다. Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*/
원본 주석입니다. Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
int pci_setup_device(struct pci_dev *dev)
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 입력 계약을 만족하는지 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
u32 class;
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
u16 cmd;
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
u8 hdr_type;
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
int err, pos = 0;
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
struct pci_bus_region region;
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
struct resource *res;
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
hdr_type = pci_hdr_type(dev);
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dev->sysdata = dev->bus->sysdata;
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dev->dev.parent = dev->bus->bridge;
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dev->dev.bus = &pci_bus_type;
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dev->hdr_type = FIELD_GET(PCI_HEADER_TYPE_MASK, hdr_type);
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dev->multifunction = FIELD_GET(PCI_HEADER_TYPE_MFD, hdr_type);
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dev->error_state = pci_channel_io_normal;
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
set_pcie_port_type(dev);
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
err = pci_set_of_node(dev);
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (err)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return err;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
pci_set_acpi_fwnode(dev);
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
pci_dev_assign_slot(dev);
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/*
원본 주석입니다. Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
원본 주석입니다. Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* set this higher, assuming the system even supports it.
원본 주석입니다. Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*/
원본 주석입니다. Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
dev->dma_mask = 0xffffffff;
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dev_set_name(&dev->dev, "%04x:%02x:%02x.%d", pci_domain_nr(dev->bus),
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dev->bus->number, PCI_SLOT(dev->devfn),
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
PCI_FUNC(dev->devfn));
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
class = pci_class(dev);
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dev->revision = class & 0xff;
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dev->class = class >> 8; /* upper 3 bytes */
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if (pci_early_dump)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
early_dump_pci_device(dev);
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Need to have dev->class ready */
원본 주석입니다. Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
dev->cfg_size = pci_cfg_space_size(dev);
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Need to have dev->cfg_size ready */
원본 주석입니다. Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
set_pcie_thunderbolt(dev);
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
set_pcie_untrusted(dev);
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if (pci_is_pcie(dev))
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
dev->supported_speeds = pcie_get_supported_speeds(dev);
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* "Unknown power state" */
원본 주석입니다. Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
dev->current_state = PCI_UNKNOWN;
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Early fixups, before probing the BARs */
원본 주석입니다. Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
pci_fixup_device(pci_fixup_early, dev);
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
pci_set_removable(dev);
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
pci_info(dev, "[%04x:%04x] type %02x class %#08x %s\n",
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dev->vendor, dev->device, dev->hdr_type, dev->class,
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
pci_type_str(dev));
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Device class may be changed after fixup */
원본 주석입니다. Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
class = dev->class >> 8;
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if (dev->non_compliant_bars && !dev->mmio_always_on) {
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
pci_read_config_word(dev, PCI_COMMAND, &cmd);
공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.
if (cmd & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
pci_info(dev, "device has non-compliant BARs; disabling IO/MEM decoding\n");
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
cmd &= ~PCI_COMMAND_IO;
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
cmd &= ~PCI_COMMAND_MEMORY;
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
pci_write_config_word(dev, PCI_COMMAND, cmd);
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
dev->broken_intx_masking = pci_intx_mask_broken(dev);
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
switch (dev->hdr_type) { /* header type */
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
case PCI_HEADER_TYPE_NORMAL: /* standard header */
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (class == PCI_CLASS_BRIDGE_PCI)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
goto bad;
공통 정리 또는 오류 경로로 이동합니다. 이미 얻은 clock, mapping, IRQ, DMA 자원의 역순 해제가 맞는지 확인합니다.
pci_read_irq(dev);
공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.
pci_read_bases(dev, PCI_STD_NUM_BARS, PCI_ROM_ADDRESS);
공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
pci_subsystem_ids(dev, &dev->subsystem_vendor, &dev->subsystem_device);
Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/*
원본 주석입니다. Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Do the ugly legacy mode stuff here rather than broken chip
원본 주석입니다. Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* quirk code. Legacy mode ATA controllers have fixed
원본 주석입니다. Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* addresses. These are not always echoed in BAR0-3, and
원본 주석입니다. Config header, class, BAR와 subsystem 정보를 pci_dev에 채우는 과정에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
Linux v6.18.37 · 실제 원본 코드
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석
335 res->flags = 0;
336out:
337 if (res->flags)
338 pci_info(dev, "%s %pR\n", res_name, res);
339
340 return (res->flags & IORESOURCE_MEM_64) ? 1 : 0;
341}
342
343static __always_inline void pci_read_bases(struct pci_dev *dev,
344 unsigned int howmany, int rom)
345{
346 u32 rombar, stdbars[PCI_STD_NUM_BARS];
347 unsigned int pos, reg;
348 u16 orig_cmd;
349
350 BUILD_BUG_ON(statically_true(howmany > PCI_STD_NUM_BARS));
351
352 if (dev->non_compliant_bars)
353 return;
354
355 /* Per PCIe r4.0, sec 9.3.4.1.11, the VF BARs are all RO Zero */
356 if (dev->is_virtfn)
357 return;
358
359 /* No printks while decoding is disabled! */
360 if (!dev->mmio_always_on) {
361 pci_read_config_word(dev, PCI_COMMAND, &orig_cmd);
362 if (orig_cmd & PCI_COMMAND_DECODE_ENABLE) {
363 pci_write_config_word(dev, PCI_COMMAND,
364 orig_cmd & ~PCI_COMMAND_DECODE_ENABLE);
365 }
366 }
367
368 __pci_size_stdbars(dev, howmany, PCI_BASE_ADDRESS_0, stdbars);
369 if (rom)
370 __pci_size_rom(dev, rom, &rombar);
371
372 if (!dev->mmio_always_on &&
373 (orig_cmd & PCI_COMMAND_DECODE_ENABLE))
374 pci_write_config_word(dev, PCI_COMMAND, orig_cmd);
375
376 for (pos = 0; pos < howmany; pos++) {
377 struct resource *res = &dev->resource[pos];
378 reg = PCI_BASE_ADDRESS_0 + (pos << 2);
379 pos += __pci_read_base(dev, pci_bar_unknown,
380 res, reg, &stdbars[pos]);
381 }
382
383 if (rom) {
384 struct resource *res = &dev->resource[PCI_ROM_RESOURCE];
385 dev->rom_base_reg = rom;
386 res->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH |
387 IORESOURCE_READONLY | IORESOURCE_SIZEALIGN;
388 __pci_read_base(dev, pci_bar_mem32, res, rom, &rombar);
389 }
390}
391
392static void pci_read_bridge_io(struct pci_dev *dev, struct resource *res,
393 bool log)
394{
395 u8 io_base_lo, io_limit_lo;
396 unsigned long io_mask, io_granularity, base, limit;
397 struct pci_bus_region region;
398
399 io_mask = PCI_IO_RANGE_MASK;
400 io_granularity = 0x1000;
401 if (dev->io_window_1k) {
402 /* Support 1K I/O space granularity */
403 io_mask = PCI_IO_1K_RANGE_MASK;
404 io_granularity = 0x400;
405 }
406
407 pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
408 pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
409 base = (io_base_lo & io_mask) << 8;
410 limit = (io_limit_lo & io_mask) << 8;
411
412 if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
413 u16 io_base_hi, io_limit_hi;
414
415 pci_read_config_word(dev, PCI_IO_BASE_UPPER16, &io_base_hi);
416 pci_read_config_word(dev, PCI_IO_LIMIT_UPPER16, &io_limit_hi);
417 base |= ((unsigned long) io_base_hi << 16);
418 limit |= ((unsigned long) io_limit_hi << 16);
419 }
420
421 res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
422
423 if (base <= limit) {
424 region.start = base;
425 region.end = limit + io_granularity - 1;
426 pcibios_bus_to_resource(dev->bus, res, ®ion);
427 if (log)
428 pci_info(dev, " bridge window %pR\n", res);
429 } else {
430 resource_set_range(res, 0, 0);
431 res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED;
432 }
433}
434
435static void pci_read_bridge_mmio(struct pci_dev *dev, struct resource *res,
436 bool log)
437{
438 u16 mem_base_lo, mem_limit_lo;
439 unsigned long base, limit;res->flags = 0;
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
out:
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (res->flags)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
pci_info(dev, "%s %pR\n", res_name, res);
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
return (res->flags & IORESOURCE_MEM_64) ? 1 : 0;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
static __always_inline void pci_read_bases(struct pci_dev *dev,
공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.
unsigned int howmany, int rom)
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
u32 rombar, stdbars[PCI_STD_NUM_BARS];
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
unsigned int pos, reg;
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
u16 orig_cmd;
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
BUILD_BUG_ON(statically_true(howmany > PCI_STD_NUM_BARS));
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if (dev->non_compliant_bars)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Per PCIe r4.0, sec 9.3.4.1.11, the VF BARs are all RO Zero */
원본 주석입니다. BAR all-ones sizing, type, 64-bit pair와 resource flag 해석에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
if (dev->is_virtfn)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* No printks while decoding is disabled! */
원본 주석입니다. BAR all-ones sizing, type, 64-bit pair와 resource flag 해석에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
if (!dev->mmio_always_on) {
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
pci_read_config_word(dev, PCI_COMMAND, &orig_cmd);
공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.
if (orig_cmd & PCI_COMMAND_DECODE_ENABLE) {
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
pci_write_config_word(dev, PCI_COMMAND,
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
orig_cmd & ~PCI_COMMAND_DECODE_ENABLE);
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
__pci_size_stdbars(dev, howmany, PCI_BASE_ADDRESS_0, stdbars);
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (rom)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
__pci_size_rom(dev, rom, &rombar);
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if (!dev->mmio_always_on &&
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
(orig_cmd & PCI_COMMAND_DECODE_ENABLE))
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
pci_write_config_word(dev, PCI_COMMAND, orig_cmd);
hardware 또는 공유 메모리에 상태를 게시합니다. write가 완료되는 지점과 다음 read/doorbell 사이의 ordering 조건을 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
for (pos = 0; pos < howmany; pos++) {
여러 pending source 또는 resource를 순회하는 구간입니다. 한 번의 진입에서 처리 가능한 양과 종료 조건이 interrupt latency에 영향을 줍니다.
struct resource *res = &dev->resource[pos];
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
reg = PCI_BASE_ADDRESS_0 + (pos << 2);
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
pos += __pci_read_base(dev, pci_bar_unknown,
공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.
res, reg, &stdbars[pos]);
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if (rom) {
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
struct resource *res = &dev->resource[PCI_ROM_RESOURCE];
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dev->rom_base_reg = rom;
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
res->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH |
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
IORESOURCE_READONLY | IORESOURCE_SIZEALIGN;
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
__pci_read_base(dev, pci_bar_mem32, res, rom, &rombar);
공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
static void pci_read_bridge_io(struct pci_dev *dev, struct resource *res,
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 입력 계약을 만족하는지 확인합니다.
bool log)
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
u8 io_base_lo, io_limit_lo;
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
unsigned long io_mask, io_granularity, base, limit;
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
struct pci_bus_region region;
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
io_mask = PCI_IO_RANGE_MASK;
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
io_granularity = 0x1000;
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (dev->io_window_1k) {
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
/* Support 1K I/O space granularity */
원본 주석입니다. BAR all-ones sizing, type, 64-bit pair와 resource flag 해석에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
io_mask = PCI_IO_1K_RANGE_MASK;
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
io_granularity = 0x400;
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.
pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.
base = (io_base_lo & io_mask) << 8;
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
limit = (io_limit_lo & io_mask) << 8;
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
u16 io_base_hi, io_limit_hi;
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
pci_read_config_word(dev, PCI_IO_BASE_UPPER16, &io_base_hi);
공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.
pci_read_config_word(dev, PCI_IO_LIMIT_UPPER16, &io_limit_hi);
공유 상태나 MMIO를 읽습니다. 이 값은 단순 변수라기보다 hardware가 갱신한 시점과 read ordering을 포함해 해석해야 합니다.
base |= ((unsigned long) io_base_hi << 16);
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
limit |= ((unsigned long) io_limit_hi << 16);
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if (base <= limit) {
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
region.start = base;
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
region.end = limit + io_granularity - 1;
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
pcibios_bus_to_resource(dev->bus, res, ®ion);
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (log)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
pci_info(dev, " bridge window %pR\n", res);
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
} else {
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
resource_set_range(res, 0, 0);
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED;
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
static void pci_read_bridge_mmio(struct pci_dev *dev, struct resource *res,
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 입력 계약을 만족하는지 확인합니다.
bool log)
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
u16 mem_base_lo, mem_limit_lo;
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
unsigned long base, limit;
BAR all-ones sizing, type, 64-bit pair와 resource flag 해석의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
Linux v6.18.37 · 실제 원본 코드
Root bus resource assignment
drivers/pci/setup-bus.c:2237-2307
2237 free_list(fail_head);
2238}
2239
2240/*
2241 * First try will not touch PCI bridge res.
2242 * Second and later try will clear small leaf bridge res.
2243 * Will stop till to the max depth if can not find good one.
2244 */
2245void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus)
2246{
2247 LIST_HEAD(realloc_head);
2248 /* List of resources that want additional resources */
2249 struct list_head *add_list = NULL;
2250 int tried_times = 0;
2251 enum release_type rel_type = leaf_only;
2252 LIST_HEAD(fail_head);
2253 int pci_try_num = 1;
2254 enum enable_type enable_local;
2255
2256 /* Don't realloc if asked to do so */
2257 enable_local = pci_realloc_detect(bus, pci_realloc_enable);
2258 if (pci_realloc_enabled(enable_local)) {
2259 int max_depth = pci_bus_get_depth(bus);
2260
2261 pci_try_num = max_depth + 1;
2262 dev_info(&bus->dev, "max bus depth: %d pci_try_num: %d\n",
2263 max_depth, pci_try_num);
2264 }
2265
2266 while (1) {
2267 /*
2268 * Last try will use add_list, otherwise will try good to
2269 * have as must have, so can realloc parent bridge resource
2270 */
2271 if (tried_times + 1 == pci_try_num)
2272 add_list = &realloc_head;
2273 /*
2274 * Depth first, calculate sizes and alignments of all
2275 * subordinate buses.
2276 */
2277 __pci_bus_size_bridges(bus, add_list);
2278
2279 pci_root_bus_distribute_available_resources(bus, add_list);
2280
2281 /* Depth last, allocate resources and update the hardware. */
2282 __pci_bus_assign_resources(bus, add_list, &fail_head);
2283 if (WARN_ON_ONCE(add_list && !list_empty(add_list)))
2284 free_list(add_list);
2285 tried_times++;
2286
2287 /* Any device complain? */
2288 if (list_empty(&fail_head))
2289 break;
2290
2291 if (tried_times >= pci_try_num) {
2292 if (enable_local == undefined) {
2293 dev_info(&bus->dev,
2294 "Some PCI device resources are unassigned, try booting with pci=realloc\n");
2295 } else if (enable_local == auto_enabled) {
2296 dev_info(&bus->dev,
2297 "Automatically enabled pci realloc, if you have problem, try booting with pci=realloc=off\n");
2298 }
2299 free_list(&fail_head);
2300 break;
2301 }
2302
2303 /* Third times and later will not check if it is leaf */
2304 if (tried_times + 1 > 2)
2305 rel_type = whole_subtree;
2306
2307 pci_prepare_next_assign_round(&fail_head, tried_times, rel_type);free_list(fail_head);
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/*
원본 주석입니다. Root bus resource assignment에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* First try will not touch PCI bridge res.
원본 주석입니다. Root bus resource assignment에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Second and later try will clear small leaf bridge res.
원본 주석입니다. Root bus resource assignment에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Will stop till to the max depth if can not find good one.
원본 주석입니다. Root bus resource assignment에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*/
원본 주석입니다. Root bus resource assignment에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus)
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 Root bus resource assignment의 입력 계약을 만족하는지 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
LIST_HEAD(realloc_head);
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
/* List of resources that want additional resources */
원본 주석입니다. Root bus resource assignment에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
struct list_head *add_list = NULL;
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
int tried_times = 0;
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
enum release_type rel_type = leaf_only;
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
LIST_HEAD(fail_head);
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
int pci_try_num = 1;
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
enum enable_type enable_local;
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Don't realloc if asked to do so */
원본 주석입니다. Root bus resource assignment에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
enable_local = pci_realloc_detect(bus, pci_realloc_enable);
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (pci_realloc_enabled(enable_local)) {
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
int max_depth = pci_bus_get_depth(bus);
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 Root bus resource assignment의 입력 계약을 만족하는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
pci_try_num = max_depth + 1;
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dev_info(&bus->dev, "max bus depth: %d pci_try_num: %d\n",
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
max_depth, pci_try_num);
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
while (1) {
여러 pending source 또는 resource를 순회하는 구간입니다. 한 번의 진입에서 처리 가능한 양과 종료 조건이 interrupt latency에 영향을 줍니다.
/*
원본 주석입니다. Root bus resource assignment에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Last try will use add_list, otherwise will try good to
원본 주석입니다. Root bus resource assignment에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* have as must have, so can realloc parent bridge resource
원본 주석입니다. Root bus resource assignment에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*/
원본 주석입니다. Root bus resource assignment에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
if (tried_times + 1 == pci_try_num)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
add_list = &realloc_head;
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
/*
원본 주석입니다. Root bus resource assignment에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Depth first, calculate sizes and alignments of all
원본 주석입니다. Root bus resource assignment에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* subordinate buses.
원본 주석입니다. Root bus resource assignment에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*/
원본 주석입니다. Root bus resource assignment에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
__pci_bus_size_bridges(bus, add_list);
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
pci_root_bus_distribute_available_resources(bus, add_list);
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Depth last, allocate resources and update the hardware. */
원본 주석입니다. Root bus resource assignment에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
__pci_bus_assign_resources(bus, add_list, &fail_head);
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (WARN_ON_ONCE(add_list && !list_empty(add_list)))
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
free_list(add_list);
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
tried_times++;
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Any device complain? */
원본 주석입니다. Root bus resource assignment에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
if (list_empty(&fail_head))
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
break;
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if (tried_times >= pci_try_num) {
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
if (enable_local == undefined) {
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
dev_info(&bus->dev,
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
"Some PCI device resources are unassigned, try booting with pci=realloc\n");
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
} else if (enable_local == auto_enabled) {
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
dev_info(&bus->dev,
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
"Automatically enabled pci realloc, if you have problem, try booting with pci=realloc=off\n");
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
free_list(&fail_head);
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
break;
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/* Third times and later will not check if it is leaf */
원본 주석입니다. Root bus resource assignment에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
if (tried_times + 1 > 2)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
rel_type = whole_subtree;
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
pci_prepare_next_assign_round(&fail_head, tried_times, rel_type);
Root bus resource assignment의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
Linux v6.18.37 · 실제 원본 코드
PCI device enable
2143 * pci_enable_device - Initialize device before it's used by a driver.
2144 * @dev: PCI device to be initialized
2145 *
2146 * Initialize device before it's used by a driver. Ask low-level code
2147 * to enable I/O and memory. Wake up the device if it was suspended.
2148 * Beware, this function can fail.
2149 *
2150 * Note we don't actually enable the device many times if we call
2151 * this function repeatedly (we just increment the count).
2152 */
2153int pci_enable_device(struct pci_dev *dev)
2154{
2155 return pci_enable_device_flags(dev, IORESOURCE_MEM | IORESOURCE_IO);
2156}
2157EXPORT_SYMBOL(pci_enable_device);
2158
2159/*
2160 * pcibios_device_add - provide arch specific hooks when adding device dev
2161 * @dev: the PCI device being added
2162 *
2163 * Permits the platform to provide architecture specific functionality when
2164 * devices are added. This is the default implementation. Architecture
2165 * implementations can override this.
2166 */
2167int __weak pcibios_device_add(struct pci_dev *dev)
2168{
2169 return 0;
2170}
2171
2172/**
2173 * pcibios_release_device - provide arch specific hooks when releasing
2174 * device dev
2175 * @dev: the PCI device being released
2176 *
2177 * Permits the platform to provide architecture specific functionality when
2178 * devices are released. This is the default implementation. Architecture
2179 * implementations can override this.
2180 */
2181void __weak pcibios_release_device(struct pci_dev *dev) {}
2182
2183/*** pci_enable_device - Initialize device before it's used by a driver.
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* @dev: PCI device to be initialized
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Initialize device before it's used by a driver. Ask low-level code
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* to enable I/O and memory. Wake up the device if it was suspended.
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Beware, this function can fail.
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Note we don't actually enable the device many times if we call
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* this function repeatedly (we just increment the count).
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*/
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
int pci_enable_device(struct pci_dev *dev)
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 PCI device enable의 입력 계약을 만족하는지 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
return pci_enable_device_flags(dev, IORESOURCE_MEM | IORESOURCE_IO);
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
EXPORT_SYMBOL(pci_enable_device);
PCI device enable의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/*
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* pcibios_device_add - provide arch specific hooks when adding device dev
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* @dev: the PCI device being added
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Permits the platform to provide architecture specific functionality when
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* devices are added. This is the default implementation. Architecture
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* implementations can override this.
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*/
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
int __weak pcibios_device_add(struct pci_dev *dev)
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 PCI device enable의 입력 계약을 만족하는지 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
return 0;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/**
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* pcibios_release_device - provide arch specific hooks when releasing
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* device dev
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* @dev: the PCI device being released
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Permits the platform to provide architecture specific functionality when
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* devices are released. This is the default implementation. Architecture
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* implementations can override this.
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*/
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
void __weak pcibios_release_device(struct pci_dev *dev) {}
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 PCI device enable의 입력 계약을 만족하는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/**
원본 주석입니다. PCI device enable에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
Linux v6.18.37 · 실제 원본 코드
BAR mapping
23 * the details if this is a MMIO or PIO address space and will just do what
24 * you expect from them in the correct way.
25 *
26 * @maxlen specifies the maximum length to map. If you want to get access to
27 * the complete BAR from offset to the end, pass %0 here.
28 * */
29void __iomem *pci_iomap_range(struct pci_dev *dev,
30 int bar,
31 unsigned long offset,
32 unsigned long maxlen)
33{
34 resource_size_t start, len;
35 unsigned long flags;
36
37 if (!pci_bar_index_is_valid(bar))
38 return NULL;
39
40 start = pci_resource_start(dev, bar);
41 len = pci_resource_len(dev, bar);
42 flags = pci_resource_flags(dev, bar);
43
44 if (len <= offset || !start)
45 return NULL;
46
47 len -= offset;
48 start += offset;
49 if (maxlen && len > maxlen)
50 len = maxlen;
51 if (flags & IORESOURCE_IO)
52 return __pci_ioport_map(dev, start, len);
53 if (flags & IORESOURCE_MEM)
54 return ioremap(start, len);
55 /* What? */
56 return NULL;
57}
58EXPORT_SYMBOL(pci_iomap_range);
59
60/**
61 * pci_iomap_wc_range - create a virtual WC mapping cookie for a PCI BAR
62 * @dev: PCI device that owns the BAR
63 * @bar: BAR number
64 * @offset: map memory at the given offset in BAR
65 * @maxlen: max length of the memory to map
66 *
67 * Using this function you will get a __iomem address to your device BAR.
68 * You can access it using ioread*() and iowrite*(). These functions hide
69 * the details if this is a MMIO or PIO address space and will just do what
70 * you expect from them in the correct way. When possible write combining
71 * is used.* the details if this is a MMIO or PIO address space and will just do what
원본 주석입니다. BAR mapping에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* you expect from them in the correct way.
원본 주석입니다. BAR mapping에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*
원본 주석입니다. BAR mapping에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* @maxlen specifies the maximum length to map. If you want to get access to
원본 주석입니다. BAR mapping에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* the complete BAR from offset to the end, pass %0 here.
원본 주석입니다. BAR mapping에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* */
원본 주석입니다. BAR mapping에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
void __iomem *pci_iomap_range(struct pci_dev *dev,
함수 경계입니다. 호출자가 넘긴 번호 공간과 현재 CPU/controller context가 BAR mapping의 입력 계약을 만족하는지 확인합니다.
int bar,
BAR mapping의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
unsigned long offset,
BAR mapping의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
unsigned long maxlen)
BAR mapping의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
{
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
resource_size_t start, len;
BAR mapping의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
unsigned long flags;
BAR mapping의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if (!pci_bar_index_is_valid(bar))
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return NULL;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
start = pci_resource_start(dev, bar);
BAR mapping의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
len = pci_resource_len(dev, bar);
BAR mapping의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
flags = pci_resource_flags(dev, bar);
BAR mapping의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
if (len <= offset || !start)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return NULL;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
len -= offset;
BAR mapping의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
start += offset;
BAR mapping의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (maxlen && len > maxlen)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
len = maxlen;
BAR mapping의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
if (flags & IORESOURCE_IO)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return __pci_ioport_map(dev, start, len);
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
if (flags & IORESOURCE_MEM)
상태나 ID를 분류하는 분기입니다. 이 조건의 참·거짓은 장치 register, firmware 기술 또는 CPU mode 중 하나에서 결정됩니다.
return ioremap(start, len);
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
/* What? */
원본 주석입니다. BAR mapping에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
return NULL;
호출자에게 상태를 반환합니다. 반환값만 보지 말고 그 전에 controller ownership이나 active 상태가 정리되었는지 확인합니다.
}
제어 블록의 범위를 표시합니다. 이 괄호 안에서만 유효한 lock, CPU context, resource lifetime을 함께 표시해 둡니다.
EXPORT_SYMBOL(pci_iomap_range);
BAR mapping의 한 단계입니다. 이 줄이 바꾸는 software 상태를 대응하는 controller register나 trace checkpoint와 연결해 확인합니다.
(blank)
논리 구간을 나누는 빈 줄입니다. 바로 위에서 준비한 상태와 다음 제어 흐름을 분리해 읽습니다.
/**
원본 주석입니다. BAR mapping에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* pci_iomap_wc_range - create a virtual WC mapping cookie for a PCI BAR
원본 주석입니다. BAR mapping에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* @dev: PCI device that owns the BAR
원본 주석입니다. BAR mapping에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* @bar: BAR number
원본 주석입니다. BAR mapping에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* @offset: map memory at the given offset in BAR
원본 주석입니다. BAR mapping에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* @maxlen: max length of the memory to map
원본 주석입니다. BAR mapping에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
*
원본 주석입니다. BAR mapping에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* Using this function you will get a __iomem address to your device BAR.
원본 주석입니다. BAR mapping에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* You can access it using ioread*() and iowrite*(). These functions hide
원본 주석입니다. BAR mapping에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* the details if this is a MMIO or PIO address space and will just do what
원본 주석입니다. BAR mapping에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* you expect from them in the correct way. When possible write combining
원본 주석입니다. BAR mapping에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
* is used.
원본 주석입니다. BAR mapping에서 뒤따르는 코드가 전제하는 하드웨어 조건이나 예외를 먼저 확인합니다.
09 · VERIFICATION
실제 장비에서 확인하는 순서
- Hierarchy
실행 `lspci -tv`와 각 bridge의 bus number/window를 저장한다.
통과 기준 parent window가 child resource를 완전히 포함해야 한다.
- BAR
실행 `cat /sys/bus/pci/devices/<BDF>/resource`를 driver map과 대조한다.
통과 기준 BAR physical range와 ioremap 대상이 같은 resource여야 한다.
- DMA
실행 IOMMU fault logging과 driver descriptor dump를 동시에 켠다.
통과 기준 fault requester ID, IOVA, direction이 해당 queue entry와 일치해야 한다.
- MSI
실행 `grep <driver> /proc/interrupts`와 affinity를 확인한다.
통과 기준 queue activity와 vector count가 함께 증가해야 한다.
- Teardown
실행 unbind/bind와 suspend/resume를 반복한다.
통과 기준 resource, IOVA, vector가 누적되지 않고 동일 순서로 재획득돼야 한다.
10 · FAILURE MATRIX
처음 끊긴 경계로 원인을 좁히기
| 관측 결과 | 우선 의심할 경계 | 다음 증거 |
|---|---|---|
| BAR no space | bridge/host window가 작거나 alignment 불가 | resource tree와 firmware ranges |
| MMIO all-ones | decode/power/reset/window 문제 | PCI_COMMAND, D-state, BAR와 bridge window |
| IOMMU fault | 잘못된 IOVA, size, direction 또는 lifetime | requester ID와 descriptor DMA address |
| MSI count 0 | message routing/table mask/vector 문제 | MSI-X entry, remapper, irqdomain |
| interrupt는 오나 완료 없음 | DMA visibility 또는 device status 해석 문제 | descriptor ownership, dma barrier, completion index |
핵심은 마지막 오류 메시지가 아니라 처음 기대값과 달라진 checkpoint입니다. 그보다 아래의 통과 증거와 그 지점의 실패 증거를 한 묶음으로 남겨야 수정의 효과도 검증할 수 있습니다.