이 코드는 어떤 문제를 푸나요?
인터럽트 컨트롤러를 설정하기 전에 Linux가 IRQ 번호별 상태를 보관할 자료구조가 필요합니다. irq_desc가 그 관리 객체입니다. 이 예제는 CONFIG_SPARSE_IRQ 쪽 정의를 읽으며, 모든 구성에서 같은 저장 방식이라고 가정하지 않습니다.
읽을 범위: v6.18.37 · kernel/irq/irqdesc.c · early_irq_init 549–575행입니다. 아래에 이 범위의 원문과 각 줄의 설명을 실었습니다. 주제 전체의 흐름과 다른 경로는 기존 분석에서 함께 읽으실 수 있습니다.
먼저 알아둘 개념
IRQ 번호
Linux 내부에서 인터럽트를 구별하는 번호입니다. 컨트롤러의 하드웨어 번호와 항상 같지는 않습니다.
irq_desc
IRQ의 상태·처리 정보·연결 관계를 보관하는 커널 객체입니다.
처음 읽을 때
코드를 읽을 때 초기 CPU affinity와 필요한 IRQ 수를 구합니다. 그다음 어느 상태가 바뀌는지 각 줄에서 확인하세요.
더 깊이 살펴볼 때
이 경로의 호출 문맥, 잠금·인터럽트 상태, 오류 시 남는 자원을 함께 추적해 보세요. 호출된 함수가 수행하는 작업과 현재 함수가 직접 보장하는 범위를 구분하는 것이 중요합니다.
그림으로 보는 변화

1. 기본 정책
초기 CPU affinity와 필요한 IRQ 수를 구합니다.
화살표는 소프트웨어 준비 순서입니다.
2. 범위 제한
설정 값이 지원 범위를 넘지 않도록 조정합니다.
검증과 조정이며 IRQ를 실제 발생시키지 않습니다.
3. 객체 등록
초기 번호에 irq_desc를 만들고 검색 구조에 넣습니다.
자료구조 준비와 IRQ 컨트롤러 초기화는 별도 단계입니다.
early_irq_init를 한 줄씩 읽기
줄 번호는 v6.18.37 원문 기준입니다. 주석·빈 줄을 포함한 함수 전체를 먼저 보고, 그 아래에서 각 줄을 설명합니다.
int __init early_irq_init(void)
{
int i, initcnt, node = first_online_node;
struct irq_desc *desc;
init_irq_default_affinity();
/* Let arch update nr_irqs and return the nr of preallocated irqs */
initcnt = arch_probe_nr_irqs();
printk(KERN_INFO "NR_IRQS: %d, nr_irqs: %d, preallocated irqs: %d\n",
NR_IRQS, nr_irqs, initcnt);
if (WARN_ON(nr_irqs > MAX_SPARSE_IRQS))
nr_irqs = MAX_SPARSE_IRQS;
if (WARN_ON(initcnt > MAX_SPARSE_IRQS))
initcnt = MAX_SPARSE_IRQS;
if (initcnt > nr_irqs)
nr_irqs = initcnt;
for (i = 0; i < initcnt; i++) {
desc = alloc_desc(i, node, 0, NULL, NULL);
irq_insert_desc(i, desc);
}
return arch_early_irq_init();
}int __init early_irq_init(void)IRQ 번호에 대응하는 irq_desc 소프트웨어 관리 객체와 기본 CPU 배치를 마련합니다. 하드웨어 컨트롤러 초기화 전에 준비하는 단계이며 마지막 아키텍처 초기화 결과를 반환합니다.
int i, initcnt, node = first_online_node;i는 초기 IRQ 번호 순회에, initcnt는 미리 만들 관리 객체 수에 사용합니다. node는 그 객체 메모리를 할당할 첫 온라인 NUMA 노드입니다.
struct irq_desc *desc;현재 번호에 대해 만든 IRQ 관리 객체를 담습니다. 이 객체는 핸들러·상태·잠금 등을 관리하며 인터럽트 컨트롤러의 하드웨어 레지스터 자체가 아닙니다. 포인터가 보관하는 것은 객체의 주소입니다. 이 선언만으로 대상 구조체나 문자열의 내용이 복사되지는 않습니다.
init_irq_default_affinity();별도 정책이 없을 때 IRQ가 실행될 CPU 집합의 기본값을 준비합니다.
initcnt = arch_probe_nr_irqs();아키텍처가 요구하는 초기 IRQ 개수를 얻습니다.
printk(KERN_INFO "NR_IRQS: %d, nr_irqs: %d, preallocated irqs: %d\n",IRQ 번호 공간의 빌드 기준값, 현재 관리 범위와 미리 만들 객체 수를 비교해 출력합니다. 이 셋이 항상 같은 값일 필요는 없습니다.
NR_IRQS, nr_irqs, initcnt);앞 로그에 각각 빌드 기준, 런타임 IRQ 범위와 사전 할당 개수를 넘깁니다. 뒤에서는 Sparse IRQ 상한과 비교해 지나치게 큰 값을 제한합니다. 앞줄에서 시작한 호출이나 식에 이어지는 부분이므로, 이 줄만으로 별도의 함수 호출이 생기지는 않습니다.
if (WARN_ON(nr_irqs > MAX_SPARSE_IRQS))필요한 IRQ 번호 범위가 Sparse IRQ 구현의 상한을 넘는지 검사합니다. 참이면 경고하고 아래에서 nr_irqs를 지원 가능한 상한으로 낮춥니다.
nr_irqs = MAX_SPARSE_IRQS;관리할 IRQ 수를 Sparse IRQ 구현이 지원하는 상한으로 제한합니다.
if (WARN_ON(initcnt > MAX_SPARSE_IRQS))미리 만들 irq_desc 수가 구현 상한을 넘는지 확인합니다. 경고만 내는 것이 아니라 아래 대입으로 실제 반복 범위도 제한합니다.
initcnt = MAX_SPARSE_IRQS;미리 만들 IRQ 객체 수도 구현의 상한을 넘지 않게 줄입니다.
if (initcnt > nr_irqs)미리 만들어야 할 IRQ 객체 수가 현재 IRQ 번호 범위보다 큰지 확인합니다.
nr_irqs = initcnt;초기 객체들을 모두 표현할 수 있게 관리할 IRQ 번호 수를 늘립니다.
for (i = 0; i < initcnt; i++) {초기에 사용할 0번부터 initcnt-1번까지 각 IRQ에 대해 관리 객체를 만들고 번호 조회 구조에 등록합니다. 실제 장치 IRQ를 발생시키는 반복이 아닙니다.
desc = alloc_desc(i, node, 0, NULL, NULL);IRQ 번호와 노드 정보에 맞춰 irq_desc 관리 객체를 만듭니다.
irq_insert_desc(i, desc);생성한 IRQ 객체를 번호로 찾을 수 있는 관리 구조에 넣습니다.
return arch_early_irq_init();범용 자료구조 준비 뒤 아키텍처의 이른 IRQ 초기화 결과를 돌려줍니다.
함께 생각해 볼 질문
desc 등록으로 장치 IRQ가 바로 동작하나요?
컨트롤러·도메인 매핑·핸들러 등록 등 후속 준비가 필요합니다.
Sparse IRQ란 모든 번호의 객체를 미리 만드는 뜻인가요?
필요한 IRQ 객체를 동적으로 관리하는 구성으로 이해해야 합니다.
왜 개수 상한을 검사하나요?
유효한 번호 범위와 구현이 처리할 수 있는 최대 범위를 벗어나지 않게 하기 위해서입니다.
출처와 읽은 범위
Linux stable v6.18.37 · kernel/irq/irqdesc.c
해당 버전 원본 파일 · 기존 코드 분석 · 설명 원고
