← Documents Documentation/core-api/irq/irq-domain.rst GitHub 원문 ↗

Linux 6.18.37 · Core API

The irq_domain Interrupt Number Mapping Library

컨트롤러 로컬 hwirq와 Linux IRQ 번호를 연결하는 irq_domain의 생성·조회 API, 매핑 유형, 계층형 domain과 stacked irq_chip을 설명합니다.

Source pathDocumentation/core-api/irq/irq-domain.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

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

1. 요약·해설

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

요약과 해설

irq-domain.rst:1-320

`irq_domain`은 인터럽트 컨트롤러 내부 번호인 `hwirq`와 전역 Linux IRQ 번호 사이의 매핑을 관리합니다. 여러 irqchip이 있는 시스템에서 드라이버마다 역매핑을 직접 구현하지 않도록 공통 계층을 제공합니다.

대부분의 드라이버는 작은 고정 번호 공간에 적합한 Linear 매핑을 사용합니다. 큰 희소 번호에는 Tree, 하드웨어에 Linux IRQ 번호를 직접 기록할 수 있는 특수 경우에는 No Map을 쓰며, Legacy 방식은 고정 번호 호환이 꼭 필요한 오래된 플랫폼에만 남겨야 합니다.

여러 인터럽트 컨트롤러를 거치는 시스템은 child에서 parent로 이어지는 계층형 `irq_domain`과 `irq_data`를 구성합니다. 각 계층에 stacked `irq_chip`을 연결하면 드라이버가 자신이 담당하는 하드웨어에 집중하면서 parent의 서비스를 재사용할 수 있습니다.

2. 영어 원문 전체

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

원문 전체 펼치기
1 ===============================================
2 The irq_domain Interrupt Number Mapping Library
3 ===============================================
4
5 The current design of the Linux kernel uses a single large number
6 space where each separate IRQ source is assigned a unique number.
7 This is simple when there is only one interrupt controller. But in
8 systems with multiple interrupt controllers, the kernel must ensure
9 that each one gets assigned non-overlapping allocations of Linux
10 IRQ numbers.
11
12 The number of interrupt controllers registered as unique irqchips
13 shows a rising tendency. For example, subdrivers of different kinds
14 such as GPIO controllers avoid reimplementing identical callback
15 mechanisms as the IRQ core system by modelling their interrupt
16 handlers as irqchips. I.e. in effect cascading interrupt controllers.
17
18 So in the past, IRQ numbers could be chosen so that they match the
19 hardware IRQ line into the root interrupt controller (i.e. the
20 component actually firing the interrupt line to the CPU). Nowadays,
21 this number is just a number and the number has no
22 relationship to hardware interrupt numbers.
23
24 For this reason, we need a mechanism to separate controller-local
25 interrupt numbers, called hardware IRQs, from Linux IRQ numbers.
26
27 The irq_alloc_desc*() and irq_free_desc*() APIs provide allocation of
28 IRQ numbers, but they don't provide any support for reverse mapping of
29 the controller-local IRQ (hwirq) number into the Linux IRQ number
30 space.
31
32 The irq_domain library adds a mapping between hwirq and IRQ numbers on
33 top of the irq_alloc_desc*() API. An irq_domain to manage the mapping
34 is preferred over interrupt controller drivers open coding their own
35 reverse mapping scheme.
36
37 irq_domain also implements a translation from an abstract struct
38 irq_fwspec to hwirq numbers (Device Tree, non-DT firmware node, ACPI
39 GSI, and software node so far), and can be easily extended to support
40 other IRQ topology data sources. The implementation is performed
41 without any extra platform support code.
42
43 irq_domain Usage
44 ================
45 struct irq_domain could be defined as an irq domain controller. That
46 is, it handles the mapping between hardware and virtual interrupt
47 numbers for a given interrupt domain. The domain structure is
48 generally created by the PIC code for a given PIC instance (though a
49 domain can cover more than one PIC if they have a flat number model).
50 It is the domain callbacks that are responsible for setting the
51 irq_chip on a given irq_desc after it has been mapped.
52
53 The host code and data structures use a fwnode_handle pointer to
54 identify the domain. In some cases, and in order to preserve source
55 code compatibility, this fwnode pointer is "upgraded" to a DT
56 device_node. For those firmware infrastructures that do not provide a
57 unique identifier for an interrupt controller, the irq_domain code
58 offers a fwnode allocator.
59
60 An interrupt controller driver creates and registers a struct irq_domain
61 by calling one of the irq_domain_create_*() functions (each mapping
62 method has a different allocator function, more on that later). The
63 function will return a pointer to the struct irq_domain on success. The
64 caller must provide the allocator function with a struct irq_domain_ops
65 pointer.
66
67 In most cases, the irq_domain will begin empty without any mappings
68 between hwirq and IRQ numbers. Mappings are added to the irq_domain
69 by calling irq_create_mapping() which accepts the irq_domain and a
70 hwirq number as arguments. If a mapping for the hwirq doesn't already
71 exist, irq_create_mapping() allocates a new Linux irq_desc, associates
72 it with the hwirq, and calls the :c:member:`irq_domain_ops.map()`
73 callback. In there, the driver can perform any required hardware
74 setup.
75
76 Once a mapping has been established, it can be retrieved or used via a
77 variety of methods:
78
79 - irq_resolve_mapping() returns a pointer to the irq_desc structure
80 for a given domain and hwirq number, or NULL if there was no
81 mapping.
82 - irq_find_mapping() returns a Linux IRQ number for a given domain and
83 hwirq number, or 0 if there was no mapping
84 - generic_handle_domain_irq() handles an interrupt described by a
85 domain and a hwirq number
86
87 Note that irq_domain lookups must happen in contexts that are
88 compatible with an RCU read-side critical section.
89
90 The irq_create_mapping() function must be called *at least once*
91 before any call to irq_find_mapping(), lest the descriptor will not
92 be allocated.
93
94 If the driver has the Linux IRQ number or the irq_data pointer, and
95 needs to know the associated hwirq number (such as in the irq_chip
96 callbacks) then it can be directly obtained from
97 :c:member:`irq_data.hwirq`.
98
99 Types of irq_domain Mappings
100 ============================
101
102 There are several mechanisms available for reverse mapping from hwirq
103 to Linux IRQ, and each mechanism uses a different allocation function.
104 Which reverse map type should be used depends on the use case. Each
105 of the reverse map types are described below:
106
107 Linear
108 ------
109
110 ::
111
112 irq_domain_create_linear()
113
114 The linear reverse map maintains a fixed-size table indexed by the
115 hwirq number. When a hwirq is mapped, an irq_desc is allocated for
116 the hwirq, and the IRQ number is stored in the table.
117
118 The Linear map is a good choice when the maximum number of hwirqs is
119 fixed and a relatively small number (~ < 256). The advantages of this
120 map are fixed-time lookup for IRQ numbers, and irq_descs are only
121 allocated for in-use IRQs. The disadvantage is that the table must be
122 as large as the largest possible hwirq number.
123
124 The majority of drivers should use the Linear map.
125
126 Tree
127 ----
128
129 ::
130
131 irq_domain_create_tree()
132
133 The irq_domain maintains a radix tree map from hwirq numbers to Linux
134 IRQs. When an hwirq is mapped, an irq_desc is allocated and the
135 hwirq is used as the lookup key for the radix tree.
136
137 The Tree map is a good choice if the hwirq number can be very large
138 since it doesn't need to allocate a table as large as the largest
139 hwirq number. The disadvantage is that hwirq to IRQ number lookup is
140 dependent on how many entries are in the table.
141
142 Very few drivers should need this mapping.
143
144 No Map
145 ------
146
147 ::
148
149 irq_domain_create_nomap()
150
151 The No Map mapping is to be used when the hwirq number is
152 programmable in the hardware. In this case it is best to program the
153 Linux IRQ number into the hardware itself so that no mapping is
154 required. Calling irq_create_direct_mapping() will allocate a Linux
155 IRQ number and call the .map() callback so that driver can program the
156 Linux IRQ number into the hardware.
157
158 Most drivers cannot use this mapping, and it is now gated on the
159 CONFIG_IRQ_DOMAIN_NOMAP option. Please refrain from introducing new
160 users of this API.
161
162 Legacy
163 ------
164
165 ::
166
167 irq_domain_create_simple()
168 irq_domain_create_legacy()
169
170 The Legacy mapping is a special case for drivers that already have a
171 range of irq_descs allocated for the hwirqs. It is used when the
172 driver cannot be immediately converted to use the Linear mapping. For
173 example, many embedded system board support files use a set of #defines
174 for IRQ numbers that are passed to struct device registrations. In that
175 case the Linux IRQ numbers cannot be dynamically assigned and the Legacy
176 mapping should be used.
177
178 As the name implies, the \*_legacy() functions are deprecated and only
179 exist to ease the support of ancient platforms. No new users should be
180 added. Same goes for the \*_simple() functions when their use results
181 in the legacy behaviour.
182
183 The Legacy map assumes a contiguous range of IRQ numbers has already
184 been allocated for the controller and that the IRQ number can be
185 calculated by adding a fixed offset to the hwirq number, and
186 visa-versa. The disadvantage is that it requires the interrupt
187 controller to manage IRQ allocations and it requires an irq_desc to be
188 allocated for every hwirq, even if it is unused.
189
190 The Legacy map should only be used if fixed IRQ mappings must be
191 supported. For example, ISA controllers would use the Legacy map for
192 mapping Linux IRQs 0-15 so that existing ISA drivers get the correct IRQ
193 numbers.
194
195 Most users of legacy mappings should use irq_domain_create_simple()
196 which will use a legacy domain only if an IRQ range is supplied by the
197 system and will otherwise use a linear domain mapping. The semantics of
198 this call are such that if an IRQ range is specified then descriptors
199 will be allocated on-the-fly for it, and if no range is specified it
200 will fall through to irq_domain_create_linear() which means *no* IRQ
201 descriptors will be allocated.
202
203 A typical use case for simple domains is where an irqchip provider
204 is supporting both dynamic and static IRQ assignments.
205
206 In order to avoid ending up in a situation where a linear domain is
207 used and no descriptor gets allocated it is very important to make sure
208 that the driver using the simple domain call irq_create_mapping()
209 before any irq_find_mapping() since the latter will actually work
210 for the static IRQ assignment case.
211
212 Hierarchy IRQ Domain
213 --------------------
214
215 On some architectures, there may be multiple interrupt controllers
216 involved in delivering an interrupt from the device to the target CPU.
217 Let's look at a typical interrupt delivery path on x86 platforms::
218
219 Device --> IOAPIC -> Interrupt remapping Controller -> Local APIC -> CPU
220
221 There are three interrupt controllers involved:
222
223 1) IOAPIC controller
224 2) Interrupt remapping controller
225 3) Local APIC controller
226
227 To support such a hardware topology and make software architecture match
228 hardware architecture, an irq_domain data structure is built for each
229 interrupt controller and those irq_domains are organized into hierarchy.
230 When building irq_domain hierarchy, the irq_domain nearest the device is
231 child and the irq_domain nearest the CPU is parent. So a hierarchy structure
232 as below will be built for the example above::
233
234 CPU Vector irq_domain (root irq_domain to manage CPU vectors)
235 ^
236 |
237 Interrupt Remapping irq_domain (manage irq_remapping entries)
238 ^
239 |
240 IOAPIC irq_domain (manage IOAPIC delivery entries/pins)
241
242 There are four major interfaces to use hierarchy irq_domain:
243
244 1) irq_domain_alloc_irqs(): allocate IRQ descriptors and interrupt
245 controller related resources to deliver these interrupts.
246 2) irq_domain_free_irqs(): free IRQ descriptors and interrupt controller
247 related resources associated with these interrupts.
248 3) irq_domain_activate_irq(): activate interrupt controller hardware to
249 deliver the interrupt.
250 4) irq_domain_deactivate_irq(): deactivate interrupt controller hardware
251 to stop delivering the interrupt.
252
253 The following is needed to support hierarchy irq_domain:
254
255 1) The :c:member:`parent` field in struct irq_domain is used to
256 maintain irq_domain hierarchy information.
257 2) The :c:member:`parent_data` field in struct irq_data is used to
258 build hierarchy irq_data to match hierarchy irq_domains. The
259 irq_data is used to store irq_domain pointer and hardware irq
260 number.
261 3) The :c:member:`alloc()`, :c:member:`free()`, and other callbacks in
262 struct irq_domain_ops to support hierarchy irq_domain operations.
263
264 With the support of hierarchy irq_domain and hierarchy irq_data ready,
265 an irq_domain structure is built for each interrupt controller, and an
266 irq_data structure is allocated for each irq_domain associated with an
267 IRQ.
268
269 For an interrupt controller driver to support hierarchy irq_domain, it
270 needs to:
271
272 1) Implement irq_domain_ops.alloc() and irq_domain_ops.free()
273 2) Optionally, implement irq_domain_ops.activate() and
274 irq_domain_ops.deactivate().
275 3) Optionally, implement an irq_chip to manage the interrupt controller
276 hardware.
277 4) There is no need to implement irq_domain_ops.map() and
278 irq_domain_ops.unmap(). They are unused with hierarchy irq_domain.
279
280 Note the hierarchy irq_domain is in no way x86-specific, and is
281 heavily used to support other architectures, such as ARM, ARM64 etc.
282
283 Stacked irq_chip
284 ~~~~~~~~~~~~~~~~
285
286 Now, we could go one step further to support stacked (hierarchy)
287 irq_chip. That is, an irq_chip is associated with each irq_data along
288 the hierarchy. A child irq_chip may implement a required action by
289 itself or by cooperating with its parent irq_chip.
290
291 With stacked irq_chip, interrupt controller driver only needs to deal
292 with the hardware managed by itself and may ask for services from its
293 parent irq_chip when needed. So we could achieve a much cleaner
294 software architecture.
295
296 Debugging
297 =========
298
299 Most of the internals of the IRQ subsystem are exposed in debugfs by
300 turning CONFIG_GENERIC_IRQ_DEBUGFS on.
301
302 Structures and Public Functions Provided
303 ========================================
304
305 This chapter contains the autogenerated documentation of the structures
306 and exported kernel API functions which are used for IRQ domains.
307
308 .. kernel-doc:: include/linux/irqdomain.h
309
310 .. kernel-doc:: kernel/irq/irqdomain.c
311 :export:
312
313 Internal Functions Provided
314 ===========================
315
316 This chapter contains the autogenerated documentation of the internal
317 functions.
318
319 .. kernel-doc:: kernel/irq/irqdomain.c
320 :internal:
321

3. 한국어 전문 번역

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

irq_domain 인터럽트 번호 매핑 라이브러리

1-4

irq_domain 인터럽트 번호 매핑 라이브러리 (The irq_domain Interrupt Number Mapping Library)

Linux IRQ 번호와 hwirq를 분리하는 이유

5-42

현재 Linux 커널은 하나의 큰 번호 공간을 사용하며 서로 다른 각 IRQ 소스에 고유 번호를 할당합니다. 인터럽트 컨트롤러가 하나뿐이면 간단하지만, 여러 컨트롤러가 있는 시스템에서는 각 컨트롤러가 서로 겹치지 않는 Linux IRQ 번호 범위를 받도록 커널이 보장해야 합니다.

고유한 `irqchip`으로 등록되는 인터럽트 컨트롤러 수는 계속 늘고 있습니다. 예를 들어 GPIO 컨트롤러 같은 여러 종류의 하위 드라이버는 IRQ core와 동일한 콜백 메커니즘을 다시 구현하는 대신 인터럽트 핸들러를 `irqchip`으로 모델링합니다. 결과적으로 계단식 인터럽트 컨트롤러가 됩니다.

과거에는 IRQ 번호가 CPU에 실제 인터럽트 선을 발생시키는 root interrupt controller의 하드웨어 IRQ 선과 일치하도록 선택할 수 있었습니다. 오늘날 Linux IRQ 번호는 단순한 번호일 뿐이며 하드웨어 인터럽트 번호와 직접적인 관계가 없습니다.

따라서 hardware IRQ 또는 `hwirq`라고 부르는 컨트롤러 로컬 인터럽트 번호를 Linux IRQ 번호와 분리하는 메커니즘이 필요합니다.

`irq_alloc_desc*()`와 `irq_free_desc*()` API는 IRQ 번호를 할당하고 해제하지만 컨트롤러 로컬 `hwirq`를 Linux IRQ 번호 공간으로 역매핑하는 기능은 제공하지 않습니다.

`irq_domain` 라이브러리는 `irq_alloc_desc*()` API 위에 `hwirq`와 IRQ 번호 사이의 매핑을 추가합니다. 인터럽트 컨트롤러 드라이버가 자체 역매핑 방식을 직접 구현하는 것보다 `irq_domain`으로 매핑을 관리하는 것이 권장됩니다.

`irq_domain`은 추상적인 `struct irq_fwspec`도 `hwirq` 번호로 변환합니다. 현재 Device Tree, non-DT firmware node, ACPI GSI, software node를 지원하며 다른 IRQ topology 데이터 소스도 쉽게 추가할 수 있습니다. 구현에는 별도의 플랫폼 지원 코드가 필요하지 않습니다.

irq_domain 사용법

43-98

`struct irq_domain`은 IRQ domain controller로 볼 수 있습니다. 즉 특정 interrupt domain의 hardware interrupt 번호와 virtual interrupt 번호 사이의 매핑을 처리합니다. 일반적으로 특정 PIC 인스턴스의 PIC 코드가 domain 구조체를 생성하지만, 여러 PIC가 평면 번호 모델을 사용하면 하나의 domain이 둘 이상을 포함할 수도 있습니다. 매핑 뒤 해당 `irq_desc`에 `irq_chip`을 설정하는 일은 domain callback이 담당합니다.

호스트 코드와 자료구조는 `fwnode_handle` 포인터로 domain을 식별합니다. 경우에 따라 소스 호환성을 유지하려고 이 `fwnode` 포인터를 DT `device_node`로 승격합니다. 인터럽트 컨트롤러의 고유 식별자를 제공하지 않는 firmware infrastructure를 위해 `irq_domain` 코드는 fwnode allocator도 제공합니다.

인터럽트 컨트롤러 드라이버는 매핑 방법별 `irq_domain_create_*()` 함수 중 하나를 호출하여 `struct irq_domain`을 생성하고 등록합니다. 성공하면 함수는 `struct irq_domain` 포인터를 반환합니다. 호출자는 allocator 함수에 `struct irq_domain_ops` 포인터를 제공해야 합니다.

대부분의 `irq_domain`은 처음에는 `hwirq`와 IRQ 번호 사이의 매핑이 없는 빈 상태입니다. `irq_create_mapping()`에 `irq_domain`과 `hwirq` 번호를 전달해 매핑을 추가합니다. 해당 `hwirq`의 매핑이 아직 없으면 이 함수는 새 Linux `irq_desc`를 할당하고 `hwirq`와 연결한 다음 `irq_domain_ops.map()` 콜백을 호출합니다. 드라이버는 이 콜백에서 필요한 하드웨어 설정을 수행할 수 있습니다.

매핑을 만든 뒤에는 다음 방법으로 조회하거나 사용할 수 있습니다.

  • `irq_resolve_mapping()`은 domain과 `hwirq`에 대응하는 `irq_desc` 포인터를 반환하고, 매핑이 없으면 `NULL`을 반환합니다.
  • `irq_find_mapping()`은 domain과 `hwirq`에 대응하는 Linux IRQ 번호를 반환하고, 매핑이 없으면 0을 반환합니다.
  • `generic_handle_domain_irq()`는 domain과 `hwirq`로 설명되는 인터럽트를 처리합니다.

`irq_domain` 조회는 RCU read-side critical section과 호환되는 context에서 수행해야 합니다.

descriptor가 할당되도록 `irq_find_mapping()`을 처음 호출하기 전에 `irq_create_mapping()`을 적어도 한 번은 호출해야 합니다.

드라이버가 Linux IRQ 번호 또는 `irq_data` 포인터를 알고 있고 연결된 `hwirq` 번호가 필요하다면, 예를 들어 `irq_chip` 콜백 안에서는 `irq_data.hwirq`에서 직접 얻을 수 있습니다.

irq_domain 매핑 유형

99-106

`hwirq`를 Linux IRQ로 역매핑하는 메커니즘은 여러 가지이며 각각 다른 할당 함수를 사용합니다. 사용할 역매핑 유형은 용도에 따라 선택합니다.

Linear 매핑

107-125
::

        irq_domain_create_linear()

Linear 역매핑은 `hwirq` 번호를 인덱스로 사용하는 고정 크기 테이블을 유지합니다. `hwirq`를 매핑할 때 해당 `hwirq`용 `irq_desc`를 할당하고 IRQ 번호를 테이블에 저장합니다.

최대 `hwirq` 수가 고정되어 있고 비교적 작을 때, 대략 256 미만일 때 적합합니다. IRQ 번호 조회 시간이 일정하고 사용 중인 IRQ에만 `irq_desc`를 할당하는 것이 장점입니다. 단점은 가능한 가장 큰 `hwirq` 번호만큼 테이블이 커야 한다는 점입니다.

대부분의 드라이버는 Linear 매핑을 사용해야 합니다.

Tree 매핑

126-143
::

        irq_domain_create_tree()

`irq_domain`은 `hwirq` 번호에서 Linux IRQ로 가는 radix tree 매핑을 유지합니다. `hwirq`를 매핑하면 `irq_desc`를 할당하고 `hwirq`를 radix tree 조회 키로 사용합니다.

Tree 매핑은 가능한 최대 `hwirq` 번호만큼 큰 테이블을 만들 필요가 없으므로 `hwirq` 번호가 매우 클 수 있을 때 적합합니다. 단점은 `hwirq`에서 IRQ 번호를 조회하는 비용이 트리의 항목 수에 영향을 받는다는 점입니다.

이 매핑이 필요한 드라이버는 매우 적습니다.

No Map 매핑

144-161
::

        irq_domain_create_nomap()

No Map은 하드웨어에서 `hwirq` 번호를 프로그래밍할 수 있을 때 사용합니다. 이 경우 Linux IRQ 번호 자체를 하드웨어에 기록하면 별도 매핑이 필요 없습니다. `irq_create_direct_mapping()`은 Linux IRQ 번호를 할당하고 `.map()` 콜백을 호출하여 드라이버가 그 번호를 하드웨어에 기록하게 합니다.

대부분의 드라이버는 이 매핑을 사용할 수 없으며 현재 `CONFIG_IRQ_DOMAIN_NOMAP` 옵션으로 제한됩니다. 이 API의 새 사용자를 추가하지 마십시오.

Legacy 매핑

162-211
::

        irq_domain_create_simple()
        irq_domain_create_legacy()

Legacy 매핑은 `hwirq`용 `irq_desc` 범위를 이미 할당한 드라이버를 위한 특수 방식입니다. 드라이버를 즉시 Linear 매핑으로 전환할 수 없을 때 사용합니다. 예를 들어 많은 임베디드 시스템 board support file은 `struct device` 등록에 전달할 IRQ 번호를 `#define` 집합으로 정의합니다. 이런 경우 Linux IRQ 번호를 동적으로 할당할 수 없어 Legacy 매핑이 필요합니다.

이름 그대로 `*_legacy()` 함수는 폐기 예정이며 오래된 플랫폼 지원을 쉽게 하려고 존재할 뿐입니다. 새 사용자를 추가해서는 안 됩니다. `*_simple()` 함수가 legacy 동작을 일으키는 경우도 마찬가지입니다.

Legacy 매핑은 컨트롤러에 연속된 IRQ 번호 범위가 이미 할당되어 있고, `hwirq` 번호에 고정 offset을 더하여 IRQ 번호를 계산하거나 반대로 계산할 수 있다고 가정합니다. 단점은 인터럽트 컨트롤러가 IRQ 할당을 직접 관리해야 하고 사용하지 않는 `hwirq`까지 모두 `irq_desc`를 할당해야 한다는 점입니다.

고정 IRQ 매핑을 반드시 지원해야 할 때만 Legacy 매핑을 사용해야 합니다. 예를 들어 ISA 컨트롤러는 기존 ISA 드라이버가 올바른 IRQ 번호를 얻도록 Linux IRQ 0-15를 Legacy 방식으로 매핑합니다.

대부분의 legacy 매핑 사용자는 `irq_domain_create_simple()`을 사용해야 합니다. 시스템이 IRQ 범위를 제공하면 legacy domain을 사용하고 그렇지 않으면 linear domain 매핑을 사용합니다. IRQ 범위를 지정하면 descriptor를 필요할 때 할당하며, 범위가 없으면 `irq_domain_create_linear()`로 넘어가므로 IRQ descriptor를 미리 할당하지 않습니다.

simple domain의 일반적인 용도는 하나의 irqchip provider가 동적 IRQ 할당과 정적 IRQ 할당을 모두 지원하는 경우입니다.

linear domain을 사용하면서 descriptor가 할당되지 않는 상황을 피하려면 simple domain을 쓰는 드라이버가 `irq_find_mapping()`보다 먼저 `irq_create_mapping()`을 호출해야 합니다. 정적 IRQ 할당에서는 `irq_find_mapping()`만으로도 동작할 수 있어 이 누락이 가려질 수 있습니다.

계층형 IRQ domain 토폴로지

212-241

일부 아키텍처에서는 장치의 인터럽트를 대상 CPU까지 전달하는 데 여러 인터럽트 컨트롤러가 관여합니다. x86 플랫폼의 일반적인 전달 경로는 다음과 같습니다.

x86 인터럽트 전달 경로
DeviceIOAPICInterrupt remapping ControllerLocal APICCPU

장치 인터럽트가 세 컨트롤러를 차례로 통과해 CPU에 도달합니다.

이 경로에는 IOAPIC controller, Interrupt remapping controller, Local APIC controller의 세 컨트롤러가 관여합니다.

하드웨어 토폴로지와 소프트웨어 구조를 맞추기 위해 각 인터럽트 컨트롤러마다 `irq_domain` 자료구조를 만들고 계층으로 구성합니다. 장치에 가장 가까운 `irq_domain`이 child이고 CPU에 가장 가까운 `irq_domain`이 parent입니다.

irq_domain 계층
IOAPIC irq_domainInterrupt Remapping irq_domainCPU Vector irq_domain (root)

IOAPIC domain이 child, CPU Vector domain이 root parent인 상향 계층입니다.

계층형 irq_domain 주요 인터페이스

242-252
  • `irq_domain_alloc_irqs()`는 IRQ descriptor와 인터럽트 전달에 필요한 컨트롤러 자원을 할당합니다.
  • `irq_domain_free_irqs()`는 해당 IRQ의 descriptor와 컨트롤러 자원을 해제합니다.
  • `irq_domain_activate_irq()`는 인터럽트를 전달하도록 컨트롤러 하드웨어를 활성화합니다.
  • `irq_domain_deactivate_irq()`는 인터럽트 전달을 멈추도록 컨트롤러 하드웨어를 비활성화합니다.

계층형 irq_domain 자료구조

253-263
  • `struct irq_domain`의 `parent` 필드는 `irq_domain` 계층 정보를 유지합니다.
  • `struct irq_data`의 `parent_data` 필드는 domain 계층과 일치하는 `irq_data` 계층을 구성합니다. `irq_data`는 `irq_domain` 포인터와 hardware IRQ 번호를 저장합니다.
  • `struct irq_domain_ops`의 `alloc()`, `free()` 및 다른 콜백은 계층형 `irq_domain` 연산을 지원합니다.

계층형 domain을 지원하는 드라이버

264-282

계층형 `irq_domain`과 `irq_data`가 준비되면 각 인터럽트 컨트롤러마다 `irq_domain` 구조체를 만들고, 하나의 IRQ와 연결된 각 `irq_domain`마다 `irq_data` 구조체를 할당합니다.

  • `irq_domain_ops.alloc()`과 `irq_domain_ops.free()`를 구현합니다.
  • 필요하면 `irq_domain_ops.activate()`와 `irq_domain_ops.deactivate()`를 구현합니다.
  • 필요하면 인터럽트 컨트롤러 하드웨어를 관리하는 `irq_chip`을 구현합니다.
  • 계층형 domain에서는 사용하지 않는 `irq_domain_ops.map()`과 `irq_domain_ops.unmap()`을 구현할 필요가 없습니다.

계층형 `irq_domain`은 x86 전용이 아니며 ARM과 ARM64를 비롯한 다른 아키텍처에서도 널리 사용됩니다.

Stacked irq_chip

283-295

계층형 `irq_domain`을 한 단계 확장하면 stacked, 즉 계층형 `irq_chip`을 지원할 수 있습니다. 계층의 각 `irq_data`에 `irq_chip` 하나를 연결하며 child `irq_chip`은 필요한 동작을 자체 구현하거나 parent `irq_chip`과 협력하여 수행할 수 있습니다.

stacked `irq_chip`을 사용하면 인터럽트 컨트롤러 드라이버는 자신이 관리하는 하드웨어만 처리하고 필요할 때 parent `irq_chip`에 서비스를 요청할 수 있으므로 소프트웨어 구조가 더 명확해집니다.

디버깅

296-301

`CONFIG_GENERIC_IRQ_DEBUGFS`를 켜면 IRQ subsystem 내부 정보 대부분을 debugfs에서 볼 수 있습니다.

제공되는 구조체와 공개 함수

302-312

이 절에는 IRQ domain에서 사용하는 구조체와 export된 kernel API 함수의 자동 생성 문서가 들어 있습니다.

.. kernel-doc:: include/linux/irqdomain.h
.. kernel-doc:: kernel/irq/irqdomain.c
   :export:

제공되는 내부 함수

313-320

이 절에는 내부 함수의 자동 생성 문서가 들어 있습니다.

.. kernel-doc:: kernel/irq/irqdomain.c
   :internal: