GICD_ICFGR(Interrupt Configuration Registers) 는 'Interrupt Configuration Registers' 약자로 GICD_ICFGR<n> 레지스터를 통해 SPI 인터럽트를 에지 트리거(edge-triggered) 혹은 레벨 센시티브(level-sensitive)으로 설정할 수 있습니다.
GICD_ICFGR은 GICD_ICFGR<n>으로 표기되며 n의 범위는 0~63입니다.
GICD_ICFGR<n> 레지스터는 2개의 비트로 SPI 인터럽트 속성을 설정하므로, 하나의 레지스터로 16개의 인터럽트의 속성을 설정할 수 있습니다. <n>의 범위가 0~63이므로 1024개 인터럽트(1024 = 16 x 64)의 속성을 설정할 수 있습니다.
GICD_ICFGR 레지스터의 비트 맵
이어서 다음 그림을 보면서 GICD_ICFGR 레지스터의 비트 맵을 알아봅시다.

그림 16.9 CICD_ICFGR 레지스터의 비트 맵
GICD_ICFGR<n> 레지스터는 2개의 비트로 Int_config<x>를 설정합니다. 각 비트에 따라 인터럽트는 다음과 같이 설정됩니다.
0b00: 레벨 센시티브(level-sensitive)
0b10: 에지 트리거(edge-triggered)
[정보] 하드웨어 관점으로 인터럽트란
인터럽트는 하드웨어 관점으로 다음과 같은 전기 신호로 볼 수 있습니다.
인터럽트 신호는 레벨 센시티브(level-sensitive)와 에지 트리거, 2가지 타입으로 분류됩니다. 레벨 센시티브(level-sensitive)는 특정 신호가 하이(High)나 로우(Low)로 유지돼야 인터럽트로 식별합니다. 에지 트리거(edge-trigger)는 신호가 하이서 로우, 로우에서 하이로 바뀌면 인터럽트가 유발됐다고 식별합니다.
GICD_ICFGR 레지스터에 접근하는 예제 코드
이번에는 XEN 하이퍼바이저에서 GICD_ICFGR에 접근해 인터럽트를 레벨 센시티브 혹은 에지 트리거로 설정하는 예제 코드를 소개합니다.
https://github.com/xen-project/xen/blob/stable-4.15/xen/arch/arm/gic-v3.c
01 static void gicv3_set_irq_type(struct irq_desc *desc, unsigned int type)
02 {
03 uint32_t cfg, actual, edgebit;
04 void __iomem *base;
05 unsigned int irq = desc->irq;
...
06 if ( irq >= NR_GIC_LOCAL_IRQS)
07 base = GICD + GICD_ICFGR + (irq / 16) * 4;
08 else
09 base = GICD_RDIST_SGI_BASE + GICR_ICFGR1;
10
11 cfg = readl_relaxed(base);
12
13 edgebit = 2u << (2 * (irq % 16));
14 if ( type & IRQ_TYPE_LEVEL_MASK )
15 cfg &= ~edgebit;
16 else if ( type & IRQ_TYPE_EDGE_BOTH )
17 cfg |= edgebit;
18
19 writel_relaxed(cfg, base);
먼저 06~07번째 줄을 봅시다.
06 if ( irq >= NR_GIC_LOCAL_IRQS)
07 base = GICD + GICD_ICFGR + (irq / 16) * 4;
07번째 줄을 보면 디스리뷰터의 베이스 주소인 GICD가 확인됩니다. 이 주소에 GICD_ICFGR 레지스터의 오프셋 주소와 함수의 인자(인터럽트 번호)를 더해 base에 저장합니다. 인터럽트 아이디를 바탕으로, 메모리 맵드 방식으로 접근하는 인터럽트 아이디에 해당되는 주소를 계산하는 루틴입니다.
이어서 11번째 줄을 분석하겠습니다.
11 cfg = readl_relaxed(base);
GICD_ICFGR<n> 레지스터의 값을 cfg에 저장하는 동작입니다.
이어서 13~17번째 줄을 봅시다.
13 edgebit = 2u << (2 * (irq % 16));
14 if ( type & IRQ_TYPE_LEVEL_MASK )
15 cfg &= ~edgebit;
16 else if ( type & IRQ_TYPE_EDGE_BOTH )
17 cfg |= edgebit;
인터럽트 속성을 에지 트리거 혹은 레벨 센시티브로 설정하는 루틴입니다. 14번째 줄은 type과 IRQ_TYPE_LEVEL_MASK 간 AND 비트 연산을 수행한 후 그 결과가 true이면 cfg 변수에 에지 트리거를 나타내는 값을 클리어하는 동작입니다. 간단히 설명하면 인터럽트를 레벨 센시티브로 설정하는 구문입니다.
16번째 줄은 인터럽트를 레벨 센시티브로 설정하는 구문입니다. type과 IRQ_TYPE_EDGE_BOTH 간 AND 비트 연산을 수행한 결과가 true이면 cfg 변수에 에지 트리거를 나타내는 값을 설정합니다.
마지막으로 19번째 줄을 봅시다.
19 writel_relaxed(cfg, base);
에지 트리거 혹은 레벨 센시티브 속성 정보가 담긴 cfg를 base에 적용하는 동작입니다.
최근 덧글