Documentation/driver-api/pci/p2pdma.rst GitHub 원문 ↗

Linux 6.18.37 · Driver API

PCI Peer-to-Peer DMA Support

PCI P2P DMA의 토폴로지 제약, provider·client·orchestrator 역할과 page 안전 규칙의 전문 번역입니다.

Source pathDocumentation/driver-api/pci/p2pdma.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약과 해설

p2pdma.rst:1-131

PCI P2P DMA는 현재 동일 bridge 뒤의 endpoint만 안전하게 지원합니다. Provider가 side-effect 없는 BAR memory를 page-backed resource로 공개하고, client는 표준 DMA mapping을 사용하며, orchestrator가 모든 client와 호환되는 가까운 provider를 선택해 reference와 allocation 수명을 관리합니다.

문서 구성
원문 줄내용
1-27Hierarchy routing과 `struct page` 제약
28-64세 driver 역할과 NVMe Target 예제
65-90Provider 등록·publish와 client mapping
91-113Orchestrator 호환성·할당·reference
114-126특수 page와 userspace 금지
127-131`drivers/pci/p2pdma.c` kernel-doc

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2
3 ============================
4 PCI Peer-to-Peer DMA Support
5 ============================
6
7 The PCI bus has pretty decent support for performing DMA transfers
8 between two devices on the bus. This type of transaction is henceforth
9 called Peer-to-Peer (or P2P). However, there are a number of issues that
10 make P2P transactions tricky to do in a perfectly safe way.
11
12 One of the biggest issues is that PCI doesn't require forwarding
13 transactions between hierarchy domains, and in PCIe, each Root Port
14 defines a separate hierarchy domain. To make things worse, there is no
15 simple way to determine if a given Root Complex supports this or not.
16 (See PCIe r4.0, sec 1.3.1). Therefore, as of this writing, the kernel
17 only supports doing P2P when the endpoints involved are all behind the
18 same PCI bridge, as such devices are all in the same PCI hierarchy
19 domain, and the spec guarantees that all transactions within the
20 hierarchy will be routable, but it does not require routing
21 between hierarchies.
22
23 The second issue is that to make use of existing interfaces in Linux,
24 memory that is used for P2P transactions needs to be backed by struct
25 pages. However, PCI BARs are not typically cache coherent so there are
26 a few corner case gotchas with these pages so developers need to
27 be careful about what they do with them.
28
29
30 Driver Writer's Guide
31 =====================
32
33 In a given P2P implementation there may be three or more different
34 types of kernel drivers in play:
35
36 * Provider - A driver which provides or publishes P2P resources like
37 memory or doorbell registers to other drivers.
38 * Client - A driver which makes use of a resource by setting up a
39 DMA transaction to or from it.
40 * Orchestrator - A driver which orchestrates the flow of data between
41 clients and providers.
42
43 In many cases there could be overlap between these three types (i.e.,
44 it may be typical for a driver to be both a provider and a client).
45
46 For example, in the NVMe Target Copy Offload implementation:
47
48 * The NVMe PCI driver is both a client, provider and orchestrator
49 in that it exposes any CMB (Controller Memory Buffer) as a P2P memory
50 resource (provider), it accepts P2P memory pages as buffers in requests
51 to be used directly (client) and it can also make use of the CMB as
52 submission queue entries (orchestrator).
53 * The RDMA driver is a client in this arrangement so that an RNIC
54 can DMA directly to the memory exposed by the NVMe device.
55 * The NVMe Target driver (nvmet) can orchestrate the data from the RNIC
56 to the P2P memory (CMB) and then to the NVMe device (and vice versa).
57
58 This is currently the only arrangement supported by the kernel but
59 one could imagine slight tweaks to this that would allow for the same
60 functionality. For example, if a specific RNIC added a BAR with some
61 memory behind it, its driver could add support as a P2P provider and
62 then the NVMe Target could use the RNIC's memory instead of the CMB
63 in cases where the NVMe cards in use do not have CMB support.
64
65
66 Provider Drivers
67 ----------------
68
69 A provider simply needs to register a BAR (or a portion of a BAR)
70 as a P2P DMA resource using :c:func:`pci_p2pdma_add_resource()`.
71 This will register struct pages for all the specified memory.
72
73 After that it may optionally publish all of its resources as
74 P2P memory using :c:func:`pci_p2pmem_publish()`. This will allow
75 any orchestrator drivers to find and use the memory. When marked in
76 this way, the resource must be regular memory with no side effects.
77
78 For the time being this is fairly rudimentary in that all resources
79 are typically going to be P2P memory. Future work will likely expand
80 this to include other types of resources like doorbells.
81
82
83 Client Drivers
84 --------------
85
86 A client driver only has to use the mapping API :c:func:`dma_map_sg()`
87 and :c:func:`dma_unmap_sg()` functions as usual, and the implementation
88 will do the right thing for the P2P capable memory.
89
90
91 Orchestrator Drivers
92 --------------------
93
94 The first task an orchestrator driver must do is compile a list of
95 all client devices that will be involved in a given transaction. For
96 example, the NVMe Target driver creates a list including the namespace
97 block device and the RNIC in use. If the orchestrator has access to
98 a specific P2P provider to use it may check compatibility using
99 :c:func:`pci_p2pdma_distance()` otherwise it may find a memory provider
100 that's compatible with all clients using :c:func:`pci_p2pmem_find()`.
101 If more than one provider is supported, the one nearest to all the clients will
102 be chosen first. If more than one provider is an equal distance away, the
103 one returned will be chosen at random (it is not an arbitrary but
104 truly random). This function returns the PCI device to use for the provider
105 with a reference taken and therefore when it's no longer needed it should be
106 returned with pci_dev_put().
107
108 Once a provider is selected, the orchestrator can then use
109 :c:func:`pci_alloc_p2pmem()` and :c:func:`pci_free_p2pmem()` to
110 allocate P2P memory from the provider. :c:func:`pci_p2pmem_alloc_sgl()`
111 and :c:func:`pci_p2pmem_free_sgl()` are convenience functions for
112 allocating scatter-gather lists with P2P memory.
113
114 Struct Page Caveats
115 -------------------
116
117 Driver writers should be very careful about not passing these special
118 struct pages to code that isn't prepared for it. At this time, the kernel
119 interfaces do not have any checks for ensuring this. This obviously
120 precludes passing these pages to userspace.
121
122 P2P memory is also technically IO memory but should never have any side
123 effects behind it. Thus, the order of loads and stores should not be important
124 and ioreadX(), iowriteX() and friends should not be necessary.
125
126
127 P2P DMA Support Library
128 =======================
129
130 .. kernel-doc:: drivers/pci/p2pdma.c
131 :export:
132

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

PCI P2P DMA의 범위와 안전 제약

1-27

PCI 버스는 버스에 연결된 두 장치 사이의 DMA 전송을 상당히 잘 지원하며, 이 문서는 이를 Peer-to-Peer 또는 P2P transaction이라고 부릅니다. 다만 모든 토폴로지에서 안전하게 사용할 수 있는 것은 아닙니다.

가장 큰 문제는 PCI가 서로 다른 hierarchy domain 사이의 transaction forwarding을 요구하지 않는다는 점입니다. PCIe에서는 각 Root Port가 별도 hierarchy domain을 정의하고, 특정 Root Complex가 domain 간 forwarding을 지원하는지 간단히 판별할 방법도 없습니다. 이 제약은 PCIe r4.0 section 1.3.1과 관련됩니다.

따라서 이 문서 시점의 커널은 모든 endpoint가 동일 PCI bridge 뒤에 있는 경우만 P2P로 지원합니다. 같은 hierarchy 안의 transaction은 specification이 routable임을 보장하지만, 서로 다른 hierarchy 사이의 routing은 보장하지 않습니다.

두 번째 문제는 기존 Linux 인터페이스를 사용하려면 P2P memory가 `struct page`로 뒷받침돼야 한다는 점입니다. PCI BAR는 일반적으로 cache coherent하지 않으므로 이 특수 page를 일반 RAM page처럼 전달하거나 접근할 때 corner case가 생깁니다.

지원되는 P2P routing 범위
PCI endpoint AShared PCI bridgePCI endpoint B
Endpoint behind Root Port 1Root ComplexEndpoint behind Root Port 2Routing not guaranteed

동일 bridge 아래의 endpoint는 같은 hierarchy domain에 있으므로 routing이 보장됩니다.

.. SPDX-License-Identifier: GPL-2.0

============================
PCI Peer-to-Peer DMA Support
============================

The PCI bus has pretty decent support for performing DMA transfers
between two devices on the bus. This type of transaction is henceforth
called Peer-to-Peer (or P2P). However, there are a number of issues that
make P2P transactions tricky to do in a perfectly safe way.

One of the biggest issues is that PCI doesn't require forwarding
transactions between hierarchy domains, and in PCIe, each Root Port
defines a separate hierarchy domain. To make things worse, there is no
simple way to determine if a given Root Complex supports this or not.
(See PCIe r4.0, sec 1.3.1). Therefore, as of this writing, the kernel
only supports doing P2P when the endpoints involved are all behind the
same PCI bridge, as such devices are all in the same PCI hierarchy
domain, and the spec guarantees that all transactions within the
hierarchy will be routable, but it does not require routing
between hierarchies.

The second issue is that to make use of existing interfaces in Linux,
memory that is used for P2P transactions needs to be backed by struct
pages. However, PCI BARs are not typically cache coherent so there are
a few corner case gotchas with these pages so developers need to
be careful about what they do with them.

Provider, client와 orchestrator

28-64

P2P 구현에는 세 종류 이상의 커널 드라이버 역할이 참여할 수 있습니다. provider는 memory나 doorbell register 같은 P2P resource를 제공하거나 publish합니다. client는 해당 resource를 출발지 또는 목적지로 삼아 DMA transaction을 설정합니다. orchestrator는 client와 provider 사이의 data flow를 조정합니다.

역할은 상호 배타적이지 않습니다. 하나의 드라이버가 provider이면서 client일 수 있고, 전체 전송을 조정하는 orchestrator까지 맡을 수 있습니다.

NVMe Target Copy Offload에서 NVMe PCI driver는 CMB, 즉 Controller Memory Buffer를 P2P memory resource로 공개하므로 provider입니다. 요청 buffer로 P2P memory page를 직접 받아들이므로 client이며, CMB를 submission queue entry에 사용할 수 있으므로 orchestrator 역할도 수행합니다.

같은 구성에서 RDMA driver는 RNIC가 NVMe device의 공개 memory로 직접 DMA하도록 하는 client입니다. NVMe Target driver `nvmet`은 RNIC에서 CMB로, 이어서 NVMe device로 흐르는 data와 반대 방향의 data를 orchestrate합니다.

현재 커널이 지원하는 구성은 이 배열뿐이지만, RNIC가 자체 BAR 뒤에 memory를 제공한다면 RNIC driver를 provider로 확장할 수 있습니다. 그러면 CMB가 없는 NVMe card에서도 NVMe Target이 RNIC memory를 대신 사용할 가능성이 있습니다.

NVMe Target P2P 역할
구성 요소역할기능
NVMe PCI driverProviderCMB를 P2P memory로 공개
NVMe PCI driverClientP2P page를 요청 buffer로 직접 수용
NVMe PCI driverOrchestratorCMB를 submission queue entry로 사용
RDMA driver / RNICClient공개된 memory로 직접 DMA
NVMe Target `nvmet`OrchestratorRNIC, CMB, NVMe 사이 data flow 조정



Driver Writer's Guide
=====================

In a given P2P implementation there may be three or more different
types of kernel drivers in play:

* Provider - A driver which provides or publishes P2P resources like
  memory or doorbell registers to other drivers.
* Client - A driver which makes use of a resource by setting up a
  DMA transaction to or from it.
* Orchestrator - A driver which orchestrates the flow of data between
  clients and providers.

In many cases there could be overlap between these three types (i.e.,
it may be typical for a driver to be both a provider and a client).

For example, in the NVMe Target Copy Offload implementation:

* The NVMe PCI driver is both a client, provider and orchestrator
  in that it exposes any CMB (Controller Memory Buffer) as a P2P memory
  resource (provider), it accepts P2P memory pages as buffers in requests
  to be used directly (client) and it can also make use of the CMB as
  submission queue entries (orchestrator).
* The RDMA driver is a client in this arrangement so that an RNIC
  can DMA directly to the memory exposed by the NVMe device.
* The NVMe Target driver (nvmet) can orchestrate the data from the RNIC
  to the P2P memory (CMB) and then to the NVMe device (and vice versa).

This is currently the only arrangement supported by the kernel but
one could imagine slight tweaks to this that would allow for the same
functionality. For example, if a specific RNIC added a BAR with some
memory behind it, its driver could add support as a P2P provider and
then the NVMe Target could use the RNIC's memory instead of the CMB
in cases where the NVMe cards in use do not have CMB support.

Provider driver의 resource 등록과 publish

65-82

Provider driver는 `pci_p2pdma_add_resource()`로 BAR 전체 또는 일부를 P2P DMA resource로 등록합니다. 이 호출은 지정한 memory 전체에 대응하는 `struct page`들을 등록합니다.

그 뒤 `pci_p2pmem_publish()`로 모든 resource를 P2P memory로 선택적으로 publish할 수 있습니다. Publish된 resource는 orchestrator driver가 탐색하고 사용할 수 있습니다. 이 방식으로 표시하는 resource는 side effect가 없는 regular memory여야 합니다.

현재 resource 분류는 비교적 단순하여 보통 모든 resource가 P2P memory입니다. 향후 doorbell 같은 다른 resource type으로 확장될 가능성이 있습니다.

Provider resource 수명
PCI BAR or BAR range`pci_p2pdma_add_resource()`Register `struct page` backing`pci_p2pmem_publish()`Discoverable P2P memory

BAR 범위를 page-backed P2P resource로 등록한 뒤 필요하면 전역 탐색 대상으로 공개합니다.


Provider Drivers
----------------

A provider simply needs to register a BAR (or a portion of a BAR)
as a P2P DMA resource using :c:func:`pci_p2pdma_add_resource()`.
This will register struct pages for all the specified memory.

After that it may optionally publish all of its resources as
P2P memory using :c:func:`pci_p2pmem_publish()`. This will allow
any orchestrator drivers to find and use the memory. When marked in
this way, the resource must be regular memory with no side effects.

For the time being this is fairly rudimentary in that all resources
are typically going to be P2P memory. Future work will likely expand
this to include other types of resources like doorbells.

Client driver의 DMA mapping

83-90

Client driver는 일반 scatter-gather DMA와 마찬가지로 `dma_map_sg()`와 `dma_unmap_sg()`를 사용하면 됩니다. DMA mapping 구현이 P2P 가능 memory를 인식하여 알맞게 처리합니다.

Client mapping 규칙
단계APIP2P 차이
Map`dma_map_sg()`기존 API 그대로 사용
Transfer장치 DMAP2P resource가 source 또는 destination
Unmap`dma_unmap_sg()`기존 API 그대로 정리

Client Drivers
--------------

A client driver only has to use the mapping API :c:func:`dma_map_sg()`
and :c:func:`dma_unmap_sg()` functions as usual, and the implementation
will do the right thing for the P2P capable memory.

Orchestrator의 호환성 검사와 memory 할당

91-113

Orchestrator가 먼저 할 일은 한 transaction에 참여할 모든 client device의 목록을 만드는 것입니다. NVMe Target은 namespace block device와 사용 중인 RNIC를 이 목록에 넣습니다.

사용할 특정 P2P provider를 알고 있으면 `pci_p2pdma_distance()`로 client들과의 호환성을 검사합니다. Provider가 정해지지 않았다면 `pci_p2pmem_find()`로 모든 client와 호환되는 memory provider를 찾습니다.

지원 가능한 provider가 여러 개면 모든 client에 가장 가까운 provider가 우선 선택됩니다. 같은 거리의 provider가 여럿이면 임의적 선택이 아니라 실제 random 선택을 수행합니다.

`pci_p2pmem_find()`는 reference를 획득한 provider의 PCI device를 반환합니다. 더 이상 필요하지 않을 때 반드시 `pci_dev_put()`으로 reference를 돌려줘야 합니다.

Provider를 선택한 뒤 `pci_alloc_p2pmem()`과 `pci_free_p2pmem()`으로 P2P memory를 할당·해제합니다. `pci_p2pmem_alloc_sgl()`과 `pci_p2pmem_free_sgl()`은 P2P memory로 scatter-gather list를 만들고 해제하는 편의 함수입니다.

Orchestrator 선택과 할당
Collect all client devices`pci_p2pdma_distance()` or `pci_p2pmem_find()`Nearest compatible providerProvider reference acquired`pci_dev_put()`
Selected provider`pci_alloc_p2pmem()`P2P memory`pci_free_p2pmem()`
Selected provider`pci_p2pmem_alloc_sgl()`P2P scatter-gather list`pci_p2pmem_free_sgl()`

모든 client와 호환되는 가까운 provider를 고르고 reference와 P2P allocation의 수명을 각각 정리합니다.

Orchestrator Drivers
--------------------

The first task an orchestrator driver must do is compile a list of
all client devices that will be involved in a given transaction. For
example, the NVMe Target driver creates a list including the namespace
block device and the RNIC in use. If the orchestrator has access to
a specific P2P provider to use it may check compatibility using
:c:func:`pci_p2pdma_distance()` otherwise it may find a memory provider
that's compatible with all clients using  :c:func:`pci_p2pmem_find()`.
If more than one provider is supported, the one nearest to all the clients will
be chosen first. If more than one provider is an equal distance away, the
one returned will be chosen at random (it is not an arbitrary but
truly random). This function returns the PCI device to use for the provider
with a reference taken and therefore when it's no longer needed it should be
returned with pci_dev_put().

Once a provider is selected, the orchestrator can then use
:c:func:`pci_alloc_p2pmem()` and :c:func:`pci_free_p2pmem()` to
allocate P2P memory from the provider. :c:func:`pci_p2pmem_alloc_sgl()`
and :c:func:`pci_p2pmem_free_sgl()` are convenience functions for
allocating scatter-gather lists with P2P memory.

특수 `struct page`의 사용 제한

114-126

P2P memory를 뒷받침하는 특수 `struct page`는 이를 처리할 준비가 되지 않은 코드에 전달하면 안 됩니다. 현재 커널 인터페이스는 이 오용을 자동 검사하지 않으므로 책임은 driver 작성자에게 있습니다. 특히 이 page를 userspace로 전달하는 것은 금지됩니다.

P2P memory는 기술적으로 IO memory이지만 그 뒤에 side effect가 있어서는 안 됩니다. 따라서 load와 store의 순서는 중요하지 않아야 하고 `ioreadX()`, `iowriteX()` 계열 접근자를 사용할 필요가 없어야 합니다.

P2P `struct page` 안전 규칙
규칙허용 여부이유
P2P-aware kernel code에 전달조건부 허용특수 page semantics를 이해해야 함
일반 page를 가정하는 코드에 전달금지커널 자동 검사 없음
Userspace에 전달금지특수 IO-backed page
Resource의 side effect금지regular memory처럼 사용
`ioreadX()` / `iowriteX()`불필요load/store 순서가 중요하지 않아야 함

Struct Page Caveats
-------------------

Driver writers should be very careful about not passing these special
struct pages to code that isn't prepared for it. At this time, the kernel
interfaces do not have any checks for ensuring this. This obviously
precludes passing these pages to userspace.

P2P memory is also technically IO memory but should never have any side
effects behind it. Thus, the order of loads and stores should not be important
and ioreadX(), iowriteX() and friends should not be necessary.

P2P DMA 지원 라이브러리 kernel-doc

127-131

이 절은 `drivers/pci/p2pdma.c`에 있는 export된 kernel-doc 항목을 P2P DMA Support Library API로 포함합니다. 앞에서 설명한 resource 등록, 호환성 탐색, allocation과 수명 관리 함수의 기준 구현 문서가 이 source path에서 생성됩니다.

Kernel-doc 연결
Source pathDirective노출 범위
`drivers/pci/p2pdma.c``.. kernel-doc::`P2P DMA library
`drivers/pci/p2pdma.c``:export:`export된 API

P2P DMA Support Library
=======================

.. kernel-doc:: drivers/pci/p2pdma.c
   :export: