요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.
1. 요약·해설
원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.
2. 영어 원문 전체
번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.
원문 전체 펼치기
==========
Interrupts
==========
2.5.2-rmk5:
This is the first kernel that contains a major shake up of some of the
major architecture-specific subsystems.
Firstly, it contains some pretty major changes to the way we handle the
MMU TLB. Each MMU TLB variant is now handled completely separately -
we have TLB v3, TLB v4 (without write buffer), TLB v4 (with write buffer),
and finally TLB v4 (with write buffer, with I TLB invalidate entry).
There is more assembly code inside each of these functions, mainly to
allow more flexible TLB handling for the future.
Secondly, the IRQ subsystem.
The 2.5 kernels will be having major changes to the way IRQs are handled.
Unfortunately, this means that machine types that touch the irq_desc[]
array (basically all machine types) will break, and this means every
machine type that we currently have.
Lets take an example. On the Assabet with Neponset, we have::
GPIO25 IRR:2
SA1100 ------------> Neponset -----------> SA1111
IIR:1
-----------> USAR
IIR:0
-----------> SMC9196
The way stuff currently works, all SA1111 interrupts are mutually
exclusive of each other - if you're processing one interrupt from the
SA1111 and another comes in, you have to wait for that interrupt to
finish processing before you can service the new interrupt. Eg, an
IDE PIO-based interrupt on the SA1111 excludes all other SA1111 and
SMC9196 interrupts until it has finished transferring its multi-sector
data, which can be a long time. Note also that since we loop in the
SA1111 IRQ handler, SA1111 IRQs can hold off SMC9196 IRQs indefinitely.
The new approach brings several new ideas...
We introduce the concept of a "parent" and a "child". For example,
to the Neponset handler, the "parent" is GPIO25, and the "children"d
are SA1111, SMC9196 and USAR.
We also bring the idea of an IRQ "chip" (mainly to reduce the size of
the irqdesc array). This doesn't have to be a real "IC"; indeed the
SA11x0 IRQs are handled by two separate "chip" structures, one for
GPIO0-10, and another for all the rest. It is just a container for
the various operations (maybe this'll change to a better name).
This structure has the following operations::
struct irqchip {
/*
* Acknowledge the IRQ.
* If this is a level-based IRQ, then it is expected to mask the IRQ
* as well.
*/
void (*ack)(unsigned int irq);
/*
* Mask the IRQ in hardware.
*/
void (*mask)(unsigned int irq);
/*
* Unmask the IRQ in hardware.
*/
void (*unmask)(unsigned int irq);
/*
* Re-run the IRQ
*/
void (*rerun)(unsigned int irq);
/*
* Set the type of the IRQ.
*/
int (*type)(unsigned int irq, unsigned int, type);
};
ack
- required. May be the same function as mask for IRQs
handled by do_level_IRQ.
mask
- required.
unmask
- required.
rerun
- optional. Not required if you're using do_level_IRQ for all
IRQs that use this 'irqchip'. Generally expected to re-trigger
the hardware IRQ if possible. If not, may call the handler
directly.
type
- optional. If you don't support changing the type of an IRQ,
it should be null so people can detect if they are unable to
set the IRQ type.
For each IRQ, we keep the following information:
- "disable" depth (number of disable_irq()s without enable_irq()s)
- flags indicating what we can do with this IRQ (valid, probe,
noautounmask) as before
- status of the IRQ (probing, enable, etc)
- chip
- per-IRQ handler
- irqaction structure list
The handler can be one of the 3 standard handlers - "level", "edge" and
"simple", or your own specific handler if you need to do something special.
The "level" handler is what we currently have - its pretty simple.
"edge" knows about the brokenness of such IRQ implementations - that you
need to leave the hardware IRQ enabled while processing it, and queueing
further IRQ events should the IRQ happen again while processing. The
"simple" handler is very basic, and does not perform any hardware
manipulation, nor state tracking. This is useful for things like the
SMC9196 and USAR above.
So, what's changed?
===================
1. Machine implementations must not write to the irqdesc array.
2. New functions to manipulate the irqdesc array. The first 4 are expected
to be useful only to machine specific code. The last is recommended to
only be used by machine specific code, but may be used in drivers if
absolutely necessary.
set_irq_chip(irq,chip)
Set the mask/unmask methods for handling this IRQ
set_irq_handler(irq,handler)
Set the handler for this IRQ (level, edge, simple)
set_irq_chained_handler(irq,handler)
Set a "chained" handler for this IRQ - automatically
enables this IRQ (eg, Neponset and SA1111 handlers).
set_irq_flags(irq,flags)
Set the valid/probe/noautoenable flags.
set_irq_type(irq,type)
Set active the IRQ edge(s)/level. This replaces the
SA1111 INTPOL manipulation, and the set_GPIO_IRQ_edge()
function. Type should be one of IRQ_TYPE_xxx defined in
<linux/irq.h>
3. set_GPIO_IRQ_edge() is obsolete, and should be replaced by set_irq_type.
4. Direct access to SA1111 INTPOL is deprecated. Use set_irq_type instead.
5. A handler is expected to perform any necessary acknowledgement of the
parent IRQ via the correct chip specific function. For instance, if
the SA1111 is directly connected to a SA1110 GPIO, then you should
acknowledge the SA1110 IRQ each time you re-read the SA1111 IRQ status.
6. For any child which doesn't have its own IRQ enable/disable controls
(eg, SMC9196), the handler must mask or acknowledge the parent IRQ
while the child handler is called, and the child handler should be the
"simple" handler (not "edge" nor "level"). After the handler completes,
the parent IRQ should be unmasked, and the status of all children must
be re-checked for pending events. (see the Neponset IRQ handler for
details).
7. fixup_irq() is gone, as is `arch/arm/mach-*/include/mach/irq.h`
Please note that this will not solve all problems - some of them are
hardware based. Mixing level-based and edge-based IRQs on the same
parent signal (eg neponset) is one such area where a software based
solution can't provide the full answer to low IRQ latency.
3. 한국어 전문 번역
영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.
Interrupts
1-412.5.2-rmk5는 주요 architecture-specific subsystem을 크게 재구성한 첫 kernel입니다.
첫째, MMU TLB 처리 방식이 크게 바뀌었습니다. TLB v3, write buffer 없는 TLB v4, write buffer가 있는 TLB v4, write buffer와 I-TLB invalidate entry가 모두 있는 TLB v4를 각각 완전히 분리해 처리합니다. 향후 더 유연한 TLB 처리를 위해 각 함수 안의 assembly code가 늘었습니다.
둘째는 IRQ subsystem입니다. 2.5 kernel의 IRQ 처리 변화 때문에 `irq_desc[]` array를 직접 건드리던 거의 모든 machine type 구현이 깨지게 되었습니다.
Assabet과 Neponset의 interrupt 연결 예는 다음과 같습니다.
GPIO25 IRR:2
SA1100 ------------> Neponset -----------> SA1111
IIR:1
-----------> USAR
IIR:0
-----------> SMC9196
GPIO25 parent가 Neponset에서 SA1111, USAR, SMC9196 child interrupt로 분기합니다.
기존 방식에서는 SA1111 interrupt끼리 상호 배타적으로 처리됩니다. SA1111 interrupt 하나를 처리하는 동안 다른 interrupt가 오면 앞 처리가 끝날 때까지 기다려야 합니다. 예를 들어 SA1111의 IDE PIO interrupt가 multi-sector data를 전송하는 긴 시간 동안 다른 SA1111과 SMC9196 interrupt가 모두 막힙니다. SA1111 IRQ handler 안에서 loop하므로 SMC9196 IRQ가 무기한 지연될 수도 있습니다.
Parent, child and IRQ chip
42-96새 접근은 parent와 child 개념을 도입합니다. Neponset handler 관점에서 parent는 `GPIO25`, child는 `SA1111`, `SMC9196`, `USAR`입니다.
`irqdesc` array 크기를 줄이기 위해 IRQ `chip` 개념도 도입합니다. 실제 IC일 필요는 없으며 여러 operation을 담는 container입니다. SA11x0 IRQ도 GPIO0-10용과 나머지용 두 `chip` structure로 처리합니다.
struct irqchip {
/*
* Acknowledge the IRQ.
* If this is a level-based IRQ, then it is expected to mask the IRQ
* as well.
*/
void (*ack)(unsigned int irq);
/*
* Mask the IRQ in hardware.
*/
void (*mask)(unsigned int irq);
/*
* Unmask the IRQ in hardware.
*/
void (*unmask)(unsigned int irq);
/*
* Re-run the IRQ
*/
void (*rerun)(unsigned int irq);
/*
* Set the type of the IRQ.
*/
int (*type)(unsigned int irq, unsigned int, type);
};
| operation | 필수 여부와 의미 |
|---|---|
| `ack` | 필수. IRQ를 acknowledge하며 level IRQ에서는 mask도 해야 합니다. `do_level_IRQ`가 처리하면 `mask`와 같은 함수일 수 있습니다. |
| `mask` | 필수. hardware에서 IRQ를 mask합니다. |
| `unmask` | 필수. hardware에서 IRQ mask를 해제합니다. |
| `rerun` | 선택. 이 irqchip의 모든 IRQ에 `do_level_IRQ`를 쓰면 필요 없습니다. 가능하면 hardware IRQ를 다시 trigger하고, 불가능하면 handler를 직접 호출할 수 있습니다. |
| `type` | 선택. IRQ type 변경을 지원하지 않으면 caller가 이를 감지할 수 있도록 NULL이어야 합니다. |
Per-IRQ state and handlers
97-117각 IRQ에는 다음 정보를 보관합니다.
- `enable_irq()` 없이 호출한 `disable_irq()` 수를 나타내는 disable depth
- valid, probe, noautounmask 같은 capability flag
- probing, enabled 같은 IRQ status
- chip
- per-IRQ handler
- `irqaction` structure list
| handler | 동작 |
|---|---|
| level | 기존의 단순한 level-triggered 처리 방식 |
| edge | 처리 중에도 hardware IRQ를 켜 두고 다시 발생한 event를 queue해야 하는 edge IRQ 구현 특성을 처리 |
| simple | hardware 조작과 state tracking을 하지 않는 최소 handler로 SMC9196·USAR 같은 child에 적합 |
| custom | 특별한 처리가 필요할 때 machine이 제공 |
So, what's changed?
118-169machine implementation은 더 이상 `irqdesc` array에 직접 쓰면 안 됩니다.
| 함수 | 역할 |
|---|---|
| `set_irq_chip(irq,chip)` | IRQ 처리에 사용할 mask/unmask method 설정 |
| `set_irq_handler(irq,handler)` | level, edge, simple handler 설정 |
| `set_irq_chained_handler(irq,handler)` | Neponset·SA1111처럼 IRQ를 자동 enable하는 chained handler 설정 |
| `set_irq_flags(irq,flags)` | valid, probe, noautoenable flag 설정 |
| `set_irq_type(irq,type)` | active edge 또는 level 설정. `<linux/irq.h>`의 `IRQ_TYPE_xxx`를 사용 |
앞 네 함수는 machine-specific code에서만 쓸 것으로 예상합니다. 마지막 `set_irq_type()`도 machine-specific code 사용을 권장하지만 꼭 필요하면 driver가 쓸 수 있습니다.
`set_GPIO_IRQ_edge()`는 obsolete이며 `set_irq_type()`으로 바꿔야 합니다. SA1111 `INTPOL` 직접 접근도 deprecated이며 같은 대체 함수를 사용합니다.
handler는 올바른 chip-specific 함수로 parent IRQ를 acknowledge해야 합니다. SA1111이 SA1110 GPIO에 직접 연결되었다면 SA1111 IRQ status를 다시 읽을 때마다 SA1110 IRQ를 acknowledge합니다.
SMC9196처럼 자체 IRQ enable/disable control이 없는 child는 child handler를 호출하는 동안 parent IRQ를 mask 또는 acknowledge해야 하며 child에는 edge나 level이 아닌 `simple` handler를 씁니다. 완료 후 parent를 unmask하고 모든 child의 pending event를 다시 검사합니다. 자세한 예는 Neponset IRQ handler를 참고합니다.
`fixup_irq()`와 `arch/arm/mach-*/include/mach/irq.h`는 제거되었습니다.
이 변경으로 모든 문제를 풀 수는 없습니다. 같은 parent signal에 level IRQ와 edge IRQ를 섞는 Neponset 같은 hardware 구조는 software만으로 낮은 IRQ latency를 완전히 보장할 수 없습니다.
요약과 해설
interrupts.rst:1-169핵심 변화는 machine code의 `irq_desc[]` 직접 조작을 API 기반 chip·handler 설정으로 바꾼 것입니다. chained parent는 child dispatch와 acknowledge를 책임지고, 자체 mask control이 없는 child에는 `simple` handler를 사용합니다.