1 .. include:: ../disclaimer-zh_CN.rst 2 3 :Original: Documentation/core-api/genericirq.rst 4 5 :翻译: 6 7 司延腾 Yanteng Si <siyanteng@loongson.cn> 8 9 :校译: 10 11 吴想成 Wu XiangCheng <bobwxc@email.cn> 12 13 .. include:: <isonum.txt> 14 15 .. _cn_core-api_genericirq: 16 17 ================ 18 Linux通用IRQ处理 19 ================ 20 21 :版权: |copy| 2005-2010: Thomas Gleixner 22 :版权: |copy| 2005-2006: Ingo Molnar 23 24 简介 25 ==== 26 27 通用中断处理层是为了给设备驱动程序提供一个完整的中断处理抽象(层)。它能够处 28 理所有不同类型的中断控制器硬件。设备驱动程序使用通用API函数来请求、启用、禁 29 用和释放中断。驱动程序不需要知道任何关于硬件处理中断的细节,所以它们可以在不同的 30 平台上使用而不需要修改代码。 31 32 本文档提供给那些希望在通用IRQ处理层的帮助下实现基于其架构的中断子系统的开发 33 者。 34 35 理论依据 36 ======== 37 38 Linux中中断处理的原始实现使用__do_IRQ()超级处理程序,它能够处理每种类型的 39 中断逻辑。 40 41 最初,Russell King确定了不同类型的处理程序,以便为Linux 2.5/2.6中的ARM中 42 断处理程序实现建立一个相当通用的集合。他区分了以下几种类型: 43 44 - 电平触发型 45 46 - 边沿触发型 47 48 - 简单型 49 50 在实现过程中,我们发现了另一种类型: 51 52 - 响应EOI(end of interrupt)型 53 54 在SMP的__do_IRQ()超级处理程序中,还需定义一种类型: 55 56 - 每cpu型(针对CPU SMP) 57 58 这种高层IRQ处理程序的拆分实现使我们能够为每个特定的中断类型优化中断处理的流 59 程。这减少了该特定代码路径的复杂性,并允许对特定类型进行优化处理。 60 61 最初的通用IRQ实现使用hw_interrupt_type结构体及其 ``->ack`` ``->end`` 等回 62 调来区分超级处理程序中的流控制。这导致了流逻辑和低级硬件逻辑的混合,也导致了 63 不必要的代码重复:例如i386中的 ``ioapic_level_irq`` 和 ``ioapic_edge_irq`` , 64 这两个IRQ类型共享许多低级的细节,但有不同的流处理。 65 66 一个更自然的抽象是“irq流”和“芯片细节”的干净分离。 67 68 分析一些架构的IRQ子系统的实现可以发现,他们中的大多数可以使用一套通用的“irq 69 流”方法,只需要添加芯片级的特定代码。这种分离对于那些需要IRQ流本身而不需要芯 70 片细节的特定(子)架构也很有价值——以提供了一个更透明的IRQ子系统设计。 71 72 每个中断描述符都被分配给它自己的高层流程处理程序,这通常是一个通用的实现。(这 73 种高层次的流程处理程序的实现也使得提供解复用处理程序变得简单,这可以在各种架 74 构的嵌入式平台上找到。) 75 76 这种分离使得通用中断处理层更加灵活和可扩展。例如,一个(子)架构可以使用通用 77 的IRQ流实现“电平触发型”中断,并添加一个(子)架构特定的“边沿型”实现。 78 79 为了使向新模型的过渡更容易,并防止破坏现有实现,__do_IRQ()超级处理程序仍然 80 可用。这导致了一种暂时的双重性。随着时间的推移,新的模型应该在越来越多的架构中 81 被使用,因为它能使IRQ子系统更小更干净。它已经被废弃三年了,即将被删除。 82 83 已知的缺陷和假设 84 ================ 85 86 没有(但愿如此)。 87 88 抽象层 89 ====== 90 91 中断代码中主要有三个抽象层次: 92 93 1. 高级别的驱动API 94 95 2. 高级别的IRQ流处理器 96 97 3. 芯片级的硬件封装 98 99 中断控制流 100 ---------- 101 102 每个中断都由一个中断描述符结构体irq_desc来描述。中断是由一个“无符号整型”的数值来 103 引用的,它在描述符结构体数组中选择相应的中断描述符结构体。描述符结构体包含状态 104 信息和指向中断流方法和中断芯片结构的指针,这些都是分配给这个中断的。 105 106 每当中断触发时,低级架构代码通过调用desc->handle_irq()调用到通用中断代码中。 107 这个高层IRQ处理函数只使用由分配的芯片描述符结构体引用的desc->irq_data.chip 108 基元。 109 110 高级驱动程序API 111 --------------- 112 113 高层驱动API由以下函数组成: 114 115 - request_irq() 116 117 - request_threaded_irq() 118 119 - free_irq() 120 121 - disable_irq() 122 123 - enable_irq() 124 125 - disable_irq_nosync() (SMP only) 126 127 - synchronize_irq() (SMP only) 128 129 - irq_set_irq_type() 130 131 - irq_set_irq_wake() 132 133 - irq_set_handler_data() 134 135 - irq_set_chip() 136 137 - irq_set_chip_data() 138 139 详见自动生成的函数文档。 140 141 .. note:: 142 143 由于文档构建流程所限,中文文档中并没有引入自动生成的函数文档,所以请读者直接 144 阅读源码注释。 145 146 电平触发型IRQ流处理程序 147 ----------------------- 148 149 通用层提供了一套预定义的irq-flow方法: 150 151 - handle_level_irq() 152 153 - handle_edge_irq() 154 155 - handle_fasteoi_irq() 156 157 - handle_simple_irq() 158 159 - handle_percpu_irq() 160 161 - handle_edge_eoi_irq() 162 163 - handle_bad_irq() 164 165 中断流处理程序(无论是预定义的还是架构特定的)由架构在启动期间或设备初始化期间分配给 166 特定中断。 167 168 默认流实现 169 ~~~~~~~~~~ 170 171 辅助函数 172 ^^^^^^^^ 173 174 辅助函数调用芯片基元,并被默认流实现所使用。以下是实现的辅助函数(简化摘录):: 175 176 default_enable(struct irq_data *data) 177 { 178 desc->irq_data.chip->irq_unmask(data); 179 } 180 181 default_disable(struct irq_data *data) 182 { 183 if (!delay_disable(data)) 184 desc->irq_data.chip->irq_mask(data); 185 } 186 187 default_ack(struct irq_data *data) 188 { 189 chip->irq_ack(data); 190 } 191 192 default_mask_ack(struct irq_data *data) 193 { 194 if (chip->irq_mask_ack) { 195 chip->irq_mask_ack(data); 196 } else { 197 chip->irq_mask(data); 198 chip->irq_ack(data); 199 } 200 } 201 202 noop(struct irq_data *data)) 203 { 204 } 205 206 207 208 默认流处理程序的实现 209 ~~~~~~~~~~~~~~~~~~~~ 210 211 电平触发型IRQ流处理器 212 ^^^^^^^^^^^^^^^^^^^^^ 213 214 handle_level_irq为电平触发型的中断提供了一个通用实现。 215 216 实现的控制流如下(简化摘录):: 217 218 desc->irq_data.chip->irq_mask_ack(); 219 handle_irq_event(desc->action); 220 desc->irq_data.chip->irq_unmask(); 221 222 223 默认的需回应IRQ流处理器 224 ^^^^^^^^^^^^^^^^^^^^^^^ 225 226 handle_fasteoi_irq为中断提供了一个通用的实现,它只需要在处理程序的末端有一个EOI。 227 228 实现的控制流如下(简化摘录):: 229 230 handle_irq_event(desc->action); 231 desc->irq_data.chip->irq_eoi(); 232 233 234 默认的边沿触发型IRQ流处理器 235 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ 236 237 handle_edge_irq为边沿触发型的中断提供了一个通用的实现。 238 239 实现的控制流如下(简化摘录):: 240 241 if (desc->status & running) { 242 desc->irq_data.chip->irq_mask_ack(); 243 desc->status |= pending | masked; 244 return; 245 } 246 desc->irq_data.chip->irq_ack(); 247 desc->status |= running; 248 do { 249 if (desc->status & masked) 250 desc->irq_data.chip->irq_unmask(); 251 desc->status &= ~pending; 252 handle_irq_event(desc->action); 253 } while (status & pending); 254 desc->status &= ~running; 255 256 257 默认的简单型IRQ流处理器 258 ^^^^^^^^^^^^^^^^^^^^^^^ 259 260 handle_simple_irq提供了一个简单型中断的通用实现。 261 262 .. note:: 263 264 简单型的流处理程序不调用任何处理程序/芯片基元。 265 266 实现的控制流程如下(简化摘录):: 267 268 handle_irq_event(desc->action); 269 270 271 默认的每CPU型流处理程序 272 ^^^^^^^^^^^^^^^^^^^^^^^ 273 274 handle_percpu_irq为每CPU型中断提供一个通用的实现。 275 276 每个CPU中断只在SMP上可用,该处理程序提供了一个没有锁的简化版本。 277 278 以下是控制流的实现(简化摘录):: 279 280 if (desc->irq_data.chip->irq_ack) 281 desc->irq_data.chip->irq_ack(); 282 handle_irq_event(desc->action); 283 if (desc->irq_data.chip->irq_eoi) 284 desc->irq_data.chip->irq_eoi(); 285 286 287 EOI边沿型IRQ流处理器 288 ^^^^^^^^^^^^^^^^^^^^ 289 290 handle_edge_eoi_irq提供了一个异常的边沿触发型处理程序,它只用于拯救powerpc/cell 291 上的一个严重失控的irq控制器。 292 293 坏的IRQ流处理器 294 ^^^^^^^^^^^^^^^ 295 296 handle_bad_irq用于处理没有真正分配处理程序的假中断。 297 298 特殊性和优化 299 ~~~~~~~~~~~~ 300 301 通用函数是为“干净”的架构和芯片设计的,它们没有平台特定的IRQ处理特殊性。如果一 302 个架构需要在“流”的层面上实现特殊性,那么它可以通过覆盖高层的IRQ-流处理程序来实 303 现。 304 305 延迟中断禁用 306 ~~~~~~~~~~~~ 307 308 每个中断可选择的功能是由Russell King在ARM中断实现中引入的,当调用disable_irq() 309 时,不会在硬件层面上屏蔽中断。中断保持启用状态,而在中断事件发生时在流处理器中被 310 屏蔽。这可以防止在硬件上丢失边沿中断,因为硬件上不存储边沿中断事件,而中断在硬件 311 级被禁用。当一个中断在IRQ_DISABLED标志被设置时到达,那么该中断在硬件层面被屏蔽, 312 IRQ_PENDING位被设置。当中断被enable_irq()重新启用时,将检查挂起位,如果它被设置, 313 中断将通过硬件或软件重发机制重新发送。(当你想使用延迟中断禁用功能,而你的硬件又不 314 能重新触发中断时,有必要启用CONFIG_HARDIRQS_SW_RESEND。) 延迟中断禁止功能是不可 315 配置的。 316 317 芯片级硬件封装 318 -------------- 319 320 芯片级硬件描述符结构体 :c:type:`irq_chip` 包含了所有与芯片直接相关的功能,这些功 321 能可以被irq流实现所利用。 322 323 - ``irq_ack`` 324 325 - ``irq_mask_ack`` - 可选的,建议使用的性能 326 327 - ``irq_mask`` 328 329 - ``irq_unmask`` 330 331 - ``irq_eoi`` - 可选的,EOI流处理程序需要 332 333 - ``irq_retrigger`` - 可选的 334 335 - ``irq_set_type`` - 可选的 336 337 - ``irq_set_wake`` - 可选的 338 339 这些基元的意思是严格意义上的:ack是指ACK,masking是指对IRQ线的屏蔽,等等。这取决 340 于流处理器如何使用这些基本的低级功能单元。 341 342 __do_IRQ入口点 343 ============== 344 345 最初的实现__do_IRQ()是所有类型中断的替代入口点。它已经不存在了。 346 347 这个处理程序被证明不适合所有的中断硬件,因此被重新实现了边沿/级别/简单/超高速中断 348 的拆分功能。这不仅是一个功能优化。它也缩短了中断的代码路径。 349 350 在SMP上的锁 351 =========== 352 353 芯片寄存器的锁定是由定义芯片基元的架构决定的。每个寄存器的结构通过desc->lock,由 354 通用层保护。 355 356 通用中断芯片 357 ============ 358 359 为了避免复制相同的IRQ芯片实现,核心提供了一个可配置的通用中断芯片实现。开发者在自 360 己实现相同的功能之前,应该仔细检查通用芯片是否符合他们的需求,并以稍微不同的方式实 361 现相同的功能。 362 363 该API在以下内核代码中: 364 365 kernel/irq/generic-chip.c 366 367 结构体 368 ====== 369 370 本章包含自动生成的结构体文档,这些结构体在通用IRQ层中使用。 371 372 该API在以下内核代码中: 373 374 include/linux/irq.h 375 376 include/linux/interrupt.h 377 378 提供的通用函数 379 ============== 380 381 这一章包含了自动生成的内核API函数的文档,这些函数被导出。 382 383 该API在以下内核代码中: 384 385 kernel/irq/manage.c 386 387 kernel/irq/chip.c 388 389 提供的内部函数 390 ============== 391 392 本章包含自动生成的内部函数的文档。 393 394 该API在以下内核代码中: 395 396 kernel/irq/irqdesc.c 397 398 kernel/irq/handle.c 399 400 kernel/irq/chip.c 401 402 鸣谢 403 ==== 404 405 感谢以下人士对本文档作出的贡献: 406 407 1. Thomas Gleixner tglx@linutronix.de 408 409 2. Ingo Molnar mingo@elte.hu
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.