← Documents Documentation/PCI/pciebus-howto.rst GitHub 원문 ↗

Linux 6.18.37 · PCI

PCI Express Port Bus 드라이버 안내서 HOWTO

하나의 PCIe Port에서 HP·PME·AER·VC service driver를 동시에 실행하도록 Port Bus가 device ownership과 interrupt·config resource를 중재하는 방식을 설명합니다.

Source pathDocumentation/PCI/pciebus-howto.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

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

1. 요약·해설

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

요약·해설

pciebus-howto.rst:1-228

PCIe Port는 하나의 PCI-PCI Bridge device이면서 HP·PME·AER·VC라는 여러 service를 제공합니다. Port Bus driver는 물리 device를 소유하고 각 기능을 별도 service driver에 분배해 동시에 실행할 수 있게 합니다.

Service driver는 `pcie_port_service_driver`를 초기화한 뒤 전용 register·unregister API를 사용하며, device enable과 bus mastering, MSI/MSI-X mode 선택은 Port Bus에 맡깁니다.

여러 driver가 공유하는 PCI Express Capability Register는 concurrent update로 bit를 잃지 않도록 `pcie_capability_*_word()` RMW accessor로만 변경해야 합니다.

2. 영어 원문 전체

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

원문 전체 펼치기
1 .. SPDX-License-Identifier: GPL-2.0
2 .. include:: <isonum.txt>
3
4 ===========================================
5 The PCI Express Port Bus Driver Guide HOWTO
6 ===========================================
7
8 :Author: Tom L Nguyen tom.l.nguyen@intel.com 11/03/2004
9 :Copyright: |copy| 2004 Intel Corporation
10
11 About this guide
12 ================
13
14 This guide describes the basics of the PCI Express Port Bus driver
15 and provides information on how to enable the service drivers to
16 register/unregister with the PCI Express Port Bus Driver.
17
18
19 What is the PCI Express Port Bus Driver
20 =======================================
21
22 A PCI Express Port is a logical PCI-PCI Bridge structure. There
23 are two types of PCI Express Port: the Root Port and the Switch
24 Port. The Root Port originates a PCI Express link from a PCI Express
25 Root Complex and the Switch Port connects PCI Express links to
26 internal logical PCI buses. The Switch Port, which has its secondary
27 bus representing the switch's internal routing logic, is called the
28 switch's Upstream Port. The switch's Downstream Port is bridging from
29 switch's internal routing bus to a bus representing the downstream
30 PCI Express link from the PCI Express Switch.
31
32 A PCI Express Port can provide up to four distinct functions,
33 referred to in this document as services, depending on its port type.
34 PCI Express Port's services include native hotplug support (HP),
35 power management event support (PME), advanced error reporting
36 support (AER), and virtual channel support (VC). These services may
37 be handled by a single complex driver or be individually distributed
38 and handled by corresponding service drivers.
39
40 Why use the PCI Express Port Bus Driver?
41 ========================================
42
43 In existing Linux kernels, the Linux Device Driver Model allows a
44 physical device to be handled by only a single driver. The PCI
45 Express Port is a PCI-PCI Bridge device with multiple distinct
46 services. To maintain a clean and simple solution each service
47 may have its own software service driver. In this case several
48 service drivers will compete for a single PCI-PCI Bridge device.
49 For example, if the PCI Express Root Port native hotplug service
50 driver is loaded first, it claims a PCI-PCI Bridge Root Port. The
51 kernel therefore does not load other service drivers for that Root
52 Port. In other words, it is impossible to have multiple service
53 drivers load and run on a PCI-PCI Bridge device simultaneously
54 using the current driver model.
55
56 To enable multiple service drivers running simultaneously requires
57 having a PCI Express Port Bus driver, which manages all populated
58 PCI Express Ports and distributes all provided service requests
59 to the corresponding service drivers as required. Some key
60 advantages of using the PCI Express Port Bus driver are listed below:
61
62 - Allow multiple service drivers to run simultaneously on
63 a PCI-PCI Bridge Port device.
64
65 - Allow service drivers implemented in an independent
66 staged approach.
67
68 - Allow one service driver to run on multiple PCI-PCI Bridge
69 Port devices.
70
71 - Manage and distribute resources of a PCI-PCI Bridge Port
72 device to requested service drivers.
73
74 Configuring the PCI Express Port Bus Driver vs. Service Drivers
75 ===============================================================
76
77 Including the PCI Express Port Bus Driver Support into the Kernel
78 -----------------------------------------------------------------
79
80 Including the PCI Express Port Bus driver depends on whether the PCI
81 Express support is included in the kernel config. The kernel will
82 automatically include the PCI Express Port Bus driver as a kernel
83 driver when the PCI Express support is enabled in the kernel.
84
85 Enabling Service Driver Support
86 -------------------------------
87
88 PCI device drivers are implemented based on Linux Device Driver Model.
89 All service drivers are PCI device drivers. As discussed above, it is
90 impossible to load any service driver once the kernel has loaded the
91 PCI Express Port Bus Driver. To meet the PCI Express Port Bus Driver
92 Model requires some minimal changes on existing service drivers that
93 imposes no impact on the functionality of existing service drivers.
94
95 A service driver is required to use the two APIs shown below to
96 register its service with the PCI Express Port Bus driver (see
97 section 5.2.1 & 5.2.2). It is important that a service driver
98 initializes the pcie_port_service_driver data structure, included in
99 header file /include/linux/pcieport_if.h, before calling these APIs.
100 Failure to do so will result an identity mismatch, which prevents
101 the PCI Express Port Bus driver from loading a service driver.
102
103 pcie_port_service_register
104 ~~~~~~~~~~~~~~~~~~~~~~~~~~
105 ::
106
107 int pcie_port_service_register(struct pcie_port_service_driver *new)
108
109 This API replaces the Linux Driver Model's pci_register_driver API. A
110 service driver should always calls pcie_port_service_register at
111 module init. Note that after service driver being loaded, calls
112 such as pci_enable_device(dev) and pci_set_master(dev) are no longer
113 necessary since these calls are executed by the PCI Port Bus driver.
114
115 pcie_port_service_unregister
116 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
117 ::
118
119 void pcie_port_service_unregister(struct pcie_port_service_driver *new)
120
121 pcie_port_service_unregister replaces the Linux Driver Model's
122 pci_unregister_driver. It's always called by service driver when a
123 module exits.
124
125 Sample Code
126 ~~~~~~~~~~~
127
128 Below is sample service driver code to initialize the port service
129 driver data structure.
130 ::
131
132 static struct pcie_port_service_id service_id[] = { {
133 .vendor = PCI_ANY_ID,
134 .device = PCI_ANY_ID,
135 .port_type = PCIE_RC_PORT,
136 .service_type = PCIE_PORT_SERVICE_AER,
137 }, { /* end: all zeroes */ }
138 };
139
140 static struct pcie_port_service_driver root_aerdrv = {
141 .name = (char *)device_name,
142 .id_table = service_id,
143
144 .probe = aerdrv_load,
145 .remove = aerdrv_unload,
146
147 .suspend = aerdrv_suspend,
148 .resume = aerdrv_resume,
149 };
150
151 Below is a sample code for registering/unregistering a service
152 driver.
153 ::
154
155 static int __init aerdrv_service_init(void)
156 {
157 int retval = 0;
158
159 retval = pcie_port_service_register(&root_aerdrv);
160 if (!retval) {
161 /*
162 * FIX ME
163 */
164 }
165 return retval;
166 }
167
168 static void __exit aerdrv_service_exit(void)
169 {
170 pcie_port_service_unregister(&root_aerdrv);
171 }
172
173 module_init(aerdrv_service_init);
174 module_exit(aerdrv_service_exit);
175
176 Possible Resource Conflicts
177 ===========================
178
179 Since all service drivers of a PCI-PCI Bridge Port device are
180 allowed to run simultaneously, below lists a few of possible resource
181 conflicts with proposed solutions.
182
183 MSI and MSI-X Vector Resource
184 -----------------------------
185
186 Once MSI or MSI-X interrupts are enabled on a device, it stays in this
187 mode until they are disabled again. Since service drivers of the same
188 PCI-PCI Bridge port share the same physical device, if an individual
189 service driver enables or disables MSI/MSI-X mode it may result
190 unpredictable behavior.
191
192 To avoid this situation all service drivers are not permitted to
193 switch interrupt mode on its device. The PCI Express Port Bus driver
194 is responsible for determining the interrupt mode and this should be
195 transparent to service drivers. Service drivers need to know only
196 the vector IRQ assigned to the field irq of struct pcie_device, which
197 is passed in when the PCI Express Port Bus driver probes each service
198 driver. Service drivers should use (struct pcie_device*)dev->irq to
199 call request_irq/free_irq. In addition, the interrupt mode is stored
200 in the field interrupt_mode of struct pcie_device.
201
202 PCI Memory/IO Mapped Regions
203 ----------------------------
204
205 Service drivers for PCI Express Power Management (PME), Advanced
206 Error Reporting (AER), Hot-Plug (HP) and Virtual Channel (VC) access
207 PCI configuration space on the PCI Express port. In all cases the
208 registers accessed are independent of each other. This patch assumes
209 that all service drivers will be well behaved and not overwrite
210 other service driver's configuration settings.
211
212 PCI Config Registers
213 --------------------
214
215 Each service driver runs its PCI config operations on its own
216 capability structure except the PCI Express capability structure,
217 that is shared between many drivers including the service drivers.
218 RMW Capability accessors (pcie_capability_clear_and_set_word(),
219 pcie_capability_set_word(), and pcie_capability_clear_word()) protect
220 a selected set of PCI Express Capability Registers:
221
222 * Link Control Register
223 * Root Control Register
224 * Link Control 2 Register
225
226 Any change to those registers should be performed using RMW accessors to
227 avoid problems due to concurrent updates. For the up-to-date list of
228 protected registers, see pcie_capability_clear_and_set_word().
229

3. 한국어 전문 번역

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

안내서 소개

1-18

이 문서는 GPL-2.0으로 배포되며 저자는 Tom L Nguyen, 저작권자는 2004년 Intel Corporation입니다.

이 안내서는 PCI Express Port Bus 드라이버의 기본 원리를 설명하고, service driver가 PCI Express Port Bus Driver에 등록하거나 등록을 해제하도록 구현하는 방법을 제공합니다.

안내서의 범위
영역내용
Port Bus 기본PCIe Port와 service의 구조
Service 연동등록·해제 API와 driver data 구조
공유 resourceInterrupt, config space, RMW 동시성

Port Bus와 개별 service driver 사이의 contract를 중심으로 다룹니다.

.. SPDX-License-Identifier: GPL-2.0
.. include:: <isonum.txt>

===========================================
The PCI Express Port Bus Driver Guide HOWTO
===========================================

:Author: Tom L Nguyen tom.l.nguyen@intel.com 11/03/2004
:Copyright: |copy| 2004 Intel Corporation

About this guide
================

This guide describes the basics of the PCI Express Port Bus driver
and provides information on how to enable the service drivers to
register/unregister with the PCI Express Port Bus Driver.

PCI Express Port와 service

19-38

PCI Express Port는 논리적인 PCI-PCI Bridge 구조입니다. PCI Express Port에는 Root Port와 Switch Port 두 종류가 있습니다.

Root Port는 PCI Express Root Complex에서 PCI Express link를 시작합니다. Switch Port는 PCI Express link를 switch 내부의 논리 PCI bus에 연결합니다.

Secondary bus가 switch 내부 routing logic을 나타내는 Switch Port를 switch의 Upstream Port라고 합니다. Downstream Port는 switch 내부 routing bus에서 PCI Express Switch의 downstream PCI Express link를 나타내는 bus로 bridge합니다.

PCIe Port 연결 구조
PCIe Root ComplexRoot PortPCIe linkSwitch Upstream PortSwitch internal routing busSwitch Downstream PortDownstream PCIe link

Root Complex에서 switch 내부 bus를 거쳐 downstream link로 이어지는 논리 bridge 관계입니다.

PCI Express Port는 port type에 따라 서로 구별되는 기능을 최대 네 개까지 제공할 수 있으며 이 문서에서는 이를 service라고 부릅니다.

Service에는 native hotplug(HP), power management event(PME), Advanced Error Reporting(AER), Virtual Channel(VC)이 있습니다. 하나의 복합 driver가 모두 처리할 수도 있고 각각을 대응하는 service driver에 분배할 수도 있습니다.

PCIe Port service
약어Service
HPNative hotplug support
PMEPower Management Event support
AERAdvanced Error Reporting support
VCVirtual Channel support

하나의 물리적 PCI-PCI Bridge Port가 제공할 수 있는 독립 기능입니다.

What is the PCI Express Port Bus Driver
=======================================

A PCI Express Port is a logical PCI-PCI Bridge structure. There
are two types of PCI Express Port: the Root Port and the Switch
Port. The Root Port originates a PCI Express link from a PCI Express
Root Complex and the Switch Port connects PCI Express links to
internal logical PCI buses. The Switch Port, which has its secondary
bus representing the switch's internal routing logic, is called the
switch's Upstream Port. The switch's Downstream Port is bridging from
switch's internal routing bus to a bus representing the downstream
PCI Express link from the PCI Express Switch.

A PCI Express Port can provide up to four distinct functions,
referred to in this document as services, depending on its port type.
PCI Express Port's services include native hotplug support (HP),
power management event support (PME), advanced error reporting
support (AER), and virtual channel support (VC). These services may
be handled by a single complex driver or be individually distributed
and handled by corresponding service drivers.

Port Bus 드라이버가 필요한 이유

39-73

기존 Linux Device Driver Model에서는 하나의 물리 device를 driver 하나만 처리할 수 있습니다. 그러나 PCI Express Port는 여러 독립 service를 가진 하나의 PCI-PCI Bridge device입니다.

각 service를 단순하고 명확하게 유지하려면 별도 software service driver가 필요하지만, 그러면 여러 service driver가 같은 PCI-PCI Bridge device를 두고 경쟁하게 됩니다.

예를 들어 Root Port native hotplug service driver가 먼저 load되면 PCI-PCI Bridge Root Port를 claim합니다. Kernel은 그 Root Port에 다른 service driver를 load하지 않으므로 현재 driver model만으로는 여러 service driver를 동시에 실행할 수 없습니다.

PCI Express Port Bus driver는 존재하는 모든 PCI Express Port를 관리하고 각 service 요청을 대응하는 service driver에 분배하여 이 제약을 해결합니다.

Service driver 다중화
PCI-PCI Bridge PortPCI Express Port Bus driverHP service driver
PCI-PCI Bridge PortPCI Express Port Bus driverPME service driver
PCI-PCI Bridge PortPCI Express Port Bus driverAER service driver
PCI-PCI Bridge PortPCI Express Port Bus driverVC service driver

Port Bus가 하나의 물리 Port를 논리 service device들로 중재합니다.

이 구조를 사용하면 여러 service driver를 한 Port에서 동시에 실행하고, 각 service를 독립적인 단계로 구현하며, 하나의 service driver를 여러 PCI-PCI Bridge Port에서 실행할 수 있습니다. 또한 Port device의 resource를 요청한 service driver에 관리·분배할 수 있습니다.

Port Bus의 이점
이점효과
동시 실행한 Port에서 여러 service driver 실행
독립 구현Service별 staged development
재사용하나의 service driver가 여러 Port를 지원
Resource 중재Port resource를 service driver에 분배

Driver model의 단일 소유권을 service 단위 분배로 확장합니다.


Why use the PCI Express Port Bus Driver?
========================================

In existing Linux kernels, the Linux Device Driver Model allows a
physical device to be handled by only a single driver. The PCI
Express Port is a PCI-PCI Bridge device with multiple distinct
services. To maintain a clean and simple solution each service
may have its own software service driver. In this case several
service drivers will compete for a single PCI-PCI Bridge device.
For example, if the PCI Express Root Port native hotplug service
driver is loaded first, it claims a PCI-PCI Bridge Root Port. The
kernel therefore does not load other service drivers for that Root
Port. In other words, it is impossible to have multiple service
drivers load and run on a PCI-PCI Bridge device simultaneously
using the current driver model.

To enable multiple service drivers running simultaneously requires
having a PCI Express Port Bus driver, which manages all populated
PCI Express Ports and distributes all provided service requests
to the corresponding service drivers as required. Some key
advantages of using the PCI Express Port Bus driver are listed below:

  - Allow multiple service drivers to run simultaneously on
    a PCI-PCI Bridge Port device.

  - Allow service drivers implemented in an independent
    staged approach.

  - Allow one service driver to run on multiple PCI-PCI Bridge
    Port devices.

  - Manage and distribute resources of a PCI-PCI Bridge Port
    device to requested service drivers.

Kernel에 Port Bus 지원 포함하기

74-84

PCI Express Port Bus 드라이버 포함 여부는 kernel configuration에서 PCI Express 지원을 포함했는지에 따라 결정됩니다.

Kernel에서 PCI Express 지원을 활성화하면 PCI Express Port Bus driver가 kernel driver로 자동 포함됩니다.

Port Bus build 설정
Kernel config에서 PCI Express 지원 활성화PCI Express Port Bus driver 자동 포함

별도의 사용자 등록보다 PCI Express 지원 여부에 의해 자동 포함됩니다.

Configuring the PCI Express Port Bus Driver vs. Service Drivers
===============================================================

Including the PCI Express Port Bus Driver Support into the Kernel
-----------------------------------------------------------------

Including the PCI Express Port Bus driver depends on whether the PCI
Express support is included in the kernel config. The kernel will
automatically include the PCI Express Port Bus driver as a kernel
driver when the PCI Express support is enabled in the kernel.

Service driver 지원 활성화

85-102

모든 service driver는 Linux Device Driver Model을 기반으로 한 PCI device driver입니다. 그러나 Port Bus driver가 물리 Port를 이미 소유하므로 기존 방식 그대로는 service driver를 load할 수 없습니다.

기존 service driver에는 기능에 영향을 주지 않는 최소한의 변경만 적용하여 PCI Express Port Bus Driver Model에 맞출 수 있습니다.

Service driver는 아래의 두 API로 Port Bus driver에 service를 등록하고 해제해야 합니다. API를 호출하기 전에 `/include/linux/pcieport_if.h`에 정의된 `pcie_port_service_driver` data structure를 반드시 초기화해야 합니다.

초기화하지 않으면 identity mismatch가 발생해 PCI Express Port Bus driver가 해당 service driver를 load하지 못합니다.

Service driver 등록 전제
pcie_port_service_driver 초기화Service identity match등록 API 호출Port Bus가 service driver load

Identity 정보가 준비된 뒤에만 Port Bus가 service를 올바르게 match할 수 있습니다.

Enabling Service Driver Support
-------------------------------

PCI device drivers are implemented based on Linux Device Driver Model.
All service drivers are PCI device drivers. As discussed above, it is
impossible to load any service driver once the kernel has loaded the
PCI Express Port Bus Driver. To meet the PCI Express Port Bus Driver
Model requires some minimal changes on existing service drivers that
imposes no impact on the functionality of existing service drivers.

A service driver is required to use the two APIs shown below to
register its service with the PCI Express Port Bus driver (see
section 5.2.1 & 5.2.2). It is important that a service driver
initializes the pcie_port_service_driver data structure, included in
header file /include/linux/pcieport_if.h, before calling these APIs.
Failure to do so will result an identity mismatch, which prevents
the PCI Express Port Bus driver from loading a service driver.

Service 등록·해제 API

103-124

`pcie_port_service_register()`는 Linux Driver Model의 `pci_register_driver()`를 대신합니다. Service driver는 module 초기화 때 항상 이 함수를 호출해야 합니다.

int pcie_port_service_register(struct pcie_port_service_driver *new)

Service driver가 load된 뒤에는 `pci_enable_device(dev)`와 `pci_set_master(dev)`를 호출할 필요가 없습니다. PCI Port Bus driver가 이 작업을 이미 수행하기 때문입니다.

`pcie_port_service_unregister()`는 `pci_unregister_driver()`를 대신하며 service driver module이 종료될 때 항상 호출합니다.

void pcie_port_service_unregister(struct pcie_port_service_driver *new)
Port service API 대체 관계
기존 PCI APIPort service API호출 시점
pci_register_driver()pcie_port_service_register()Module init
pci_unregister_driver()pcie_port_service_unregister()Module exit
pci_enable_device()Port Bus가 수행Service driver에서 불필요
pci_set_master()Port Bus가 수행Service driver에서 불필요

물리 PCI device 소유권은 Port Bus에 두고 service만 등록합니다.

pcie_port_service_register
~~~~~~~~~~~~~~~~~~~~~~~~~~
::

  int pcie_port_service_register(struct pcie_port_service_driver *new)

This API replaces the Linux Driver Model's pci_register_driver API. A
service driver should always calls pcie_port_service_register at
module init. Note that after service driver being loaded, calls
such as pci_enable_device(dev) and pci_set_master(dev) are no longer
necessary since these calls are executed by the PCI Port Bus driver.

pcie_port_service_unregister
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::

  void pcie_port_service_unregister(struct pcie_port_service_driver *new)

pcie_port_service_unregister replaces the Linux Driver Model's
pci_unregister_driver. It's always called by service driver when a
module exits.

AER service driver 예제

125-175

첫 예제는 AER Root Port service driver가 사용할 ID table과 `struct pcie_port_service_driver`를 초기화합니다.

ID table은 vendor와 device를 `PCI_ANY_ID`로 두고 port type을 `PCIE_RC_PORT`, service type을 `PCIE_PORT_SERVICE_AER`로 제한한 뒤 all-zero entry로 끝냅니다.

static struct pcie_port_service_id service_id[] = { {
  .vendor = PCI_ANY_ID,
  .device = PCI_ANY_ID,
  .port_type = PCIE_RC_PORT,
  .service_type = PCIE_PORT_SERVICE_AER,
  }, { /* end: all zeroes */ }
};

`root_aerdrv`는 이름과 ID table, `aerdrv_load`·`aerdrv_unload` probe/remove callback, `aerdrv_suspend`·`aerdrv_resume` power-management callback을 연결합니다.

static struct pcie_port_service_driver root_aerdrv = {
  .name      = (char *)device_name,
  .id_table  = service_id,
  .probe     = aerdrv_load,
  .remove    = aerdrv_unload,
  .suspend   = aerdrv_suspend,
  .resume    = aerdrv_resume,
};

Module init 함수 `aerdrv_service_init()`는 `pcie_port_service_register(&root_aerdrv)`를 호출하고 반환값을 전달합니다. Module exit 함수 `aerdrv_service_exit()`는 같은 구조체를 `pcie_port_service_unregister()`에 넘깁니다.

static int __init aerdrv_service_init(void)
{
  int retval = 0;

  retval = pcie_port_service_register(&root_aerdrv);
  if (!retval) {
    /*
    * FIX ME
    */
  }
  return retval;
}

static void __exit aerdrv_service_exit(void)
{
  pcie_port_service_unregister(&root_aerdrv);
}

module_init(aerdrv_service_init);
module_exit(aerdrv_service_exit);
예제 service driver 생명주기
service_id + root_aerdrv 초기화module_initpcie_port_service_register()probe/suspend/resume/remove
module_exitpcie_port_service_unregister()

동일한 root_aerdrv 구조체를 module init과 exit에서 등록·해제합니다.

Sample Code
~~~~~~~~~~~

Below is sample service driver code to initialize the port service
driver data structure.
::

  static struct pcie_port_service_id service_id[] = { {
    .vendor = PCI_ANY_ID,
    .device = PCI_ANY_ID,
    .port_type = PCIE_RC_PORT,
    .service_type = PCIE_PORT_SERVICE_AER,
    }, { /* end: all zeroes */ }
  };

  static struct pcie_port_service_driver root_aerdrv = {
    .name                = (char *)device_name,
    .id_table        = service_id,

    .probe                = aerdrv_load,
    .remove                = aerdrv_unload,

    .suspend        = aerdrv_suspend,
    .resume                = aerdrv_resume,
  };

Below is a sample code for registering/unregistering a service
driver.
::

  static int __init aerdrv_service_init(void)
  {
    int retval = 0;

    retval = pcie_port_service_register(&root_aerdrv);
    if (!retval) {
      /*
      * FIX ME
      */
    }
    return retval;
  }

  static void __exit aerdrv_service_exit(void)
  {
    pcie_port_service_unregister(&root_aerdrv);
  }

  module_init(aerdrv_service_init);
  module_exit(aerdrv_service_exit);

MSI와 MSI-X vector 충돌 방지

176-201

한 PCI-PCI Bridge Port의 모든 service driver가 동시에 실행되므로 공유 resource 충돌을 조정해야 합니다.

Device에서 MSI 또는 MSI-X interrupt를 enable하면 다시 disable할 때까지 그 mode가 유지됩니다. 같은 Port의 service driver들은 하나의 물리 device를 공유하므로 개별 service driver가 MSI/MSI-X mode를 바꾸면 예측할 수 없는 동작이 생길 수 있습니다.

따라서 service driver는 device의 interrupt mode를 전환할 수 없습니다. PCI Express Port Bus driver가 mode를 결정하며 이 과정은 service driver에 투명해야 합니다.

Service driver가 알아야 하는 것은 probe 때 전달된 `struct pcie_device`의 `irq` field에 할당된 vector IRQ뿐입니다. `request_irq()`와 `free_irq()`에는 `(struct pcie_device *)dev->irq`를 사용합니다.

선택된 interrupt mode는 `struct pcie_device`의 `interrupt_mode` field에도 저장됩니다.

Interrupt resource 소유권
작업담당
MSI/MSI-X mode 선택·전환PCI Express Port Bus driver
Vector IRQ 확인struct pcie_device.irq
IRQ handler 등록·해제Service driver의 request_irq()/free_irq()
Mode 상태 확인struct pcie_device.interrupt_mode

Mode 선택은 Port Bus가 맡고 service driver는 배정된 IRQ만 사용합니다.

Service IRQ 전달
Physical PCI-PCI Bridge PortPort Bus가 interrupt mode 결정struct pcie_device.irqService driver request_irq()/free_irq()

Port Bus가 물리 device의 interrupt mode를 한 번 조정한 뒤 각 service에 vector를 넘깁니다.

Possible Resource Conflicts
===========================

Since all service drivers of a PCI-PCI Bridge Port device are
allowed to run simultaneously, below lists a few of possible resource
conflicts with proposed solutions.

MSI and MSI-X Vector Resource
-----------------------------

Once MSI or MSI-X interrupts are enabled on a device, it stays in this
mode until they are disabled again.  Since service drivers of the same
PCI-PCI Bridge port share the same physical device, if an individual
service driver enables or disables MSI/MSI-X mode it may result
unpredictable behavior.

To avoid this situation all service drivers are not permitted to
switch interrupt mode on its device. The PCI Express Port Bus driver
is responsible for determining the interrupt mode and this should be
transparent to service drivers. Service drivers need to know only
the vector IRQ assigned to the field irq of struct pcie_device, which
is passed in when the PCI Express Port Bus driver probes each service
driver. Service drivers should use (struct pcie_device*)dev->irq to
call request_irq/free_irq. In addition, the interrupt mode is stored
in the field interrupt_mode of struct pcie_device.

PCI Memory·I/O mapped region

202-211

PCI Express PME, AER, HP, VC service driver는 모두 PCI Express Port의 PCI configuration space에 접근합니다.

각 service가 접근하는 register는 서로 독립적입니다. 이 설계는 모든 service driver가 올바르게 동작하여 다른 service driver의 configuration setting을 덮어쓰지 않는다고 가정합니다.

Service별 config 접근
Service접근 원칙
PME자기 service register만 변경
AER자기 service register만 변경
HP자기 service register만 변경
VC자기 service register만 변경

같은 Port config space를 사용하지만 독립 register 영역을 지켜야 합니다.

PCI Memory/IO Mapped Regions
----------------------------

Service drivers for PCI Express Power Management (PME), Advanced
Error Reporting (AER), Hot-Plug (HP) and Virtual Channel (VC) access
PCI configuration space on the PCI Express port. In all cases the
registers accessed are independent of each other. This patch assumes
that all service drivers will be well behaved and not overwrite
other service driver's configuration settings.

공유 PCI Express Capability register

212-228

각 service driver는 자기 capability structure에서 PCI config operation을 수행합니다. 예외는 service driver를 포함한 여러 driver가 공유하는 PCI Express capability structure입니다.

Read-modify-write(RMW) capability accessor인 `pcie_capability_clear_and_set_word()`, `pcie_capability_set_word()`, `pcie_capability_clear_word()`는 선택된 PCI Express Capability Register를 동시 갱신으로부터 보호합니다.

보호 대상에는 Link Control Register, Root Control Register, Link Control 2 Register가 포함됩니다.

RMW로 보호되는 register
Register변경 방법
Link Control RegisterRMW capability accessor
Root Control RegisterRMW capability accessor
Link Control 2 RegisterRMW capability accessor

여러 driver가 공유하는 bit를 잃지 않도록 전용 accessor를 사용합니다.

이 register를 변경할 때는 concurrent update 문제를 피하도록 반드시 RMW accessor를 사용해야 합니다. 최신 보호 register 목록은 `pcie_capability_clear_and_set_word()` 구현을 참조하십시오.

공유 register 갱신
Service driver 변경 요청pcie_capability_*_word()Read + mask + update공유 PCIe Capability register

직접 write 대신 lock과 mask를 적용하는 RMW helper로 다른 driver의 bit를 보존합니다.

PCI Config Registers
--------------------

Each service driver runs its PCI config operations on its own
capability structure except the PCI Express capability structure,
that is shared between many drivers including the service drivers.
RMW Capability accessors (pcie_capability_clear_and_set_word(),
pcie_capability_set_word(), and pcie_capability_clear_word()) protect
a selected set of PCI Express Capability Registers:

* Link Control Register
* Root Control Register
* Link Control 2 Register

Any change to those registers should be performed using RMW accessors to
avoid problems due to concurrent updates. For the up-to-date list of
protected registers, see pcie_capability_clear_and_set_word().