Arm Linux Kernel Hacks

rousalome.egloos.com

포토로그 Kernel Crash


통계 위젯 (화이트)

9365
557
421924


[Arm프로세서] GIC: GICD_ICFGR<n> 레지스터 Arm: GIC

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에 적용하는 동작입니다.


덧글

댓글 입력 영역