컨텐츠 바로가기

irq_domain 정리

http://furmuwon.egloos.com/10945891

irq_domain 정리

 irq_domain 은 size 를 가질 수 있는데
 이 size 는 linux irq number 를 가지고 싶은 개수 이다. 
 만약 sound codec 내에서 발생하는 interrupt 의 종류가 10개 라면 
 이 10개 모두에 대한 linux irq number 를 가지고 싶다면 size 를 10으로 지정 한다.
 irq_domain 은 size 에 해당하는 linux irq number 를 저장하고 있다.
 
 10개를 예를 들면
 
 irq_domain 은 10개의 linux irq number 를 가지고 있고
 irq_domain 은 0-9 까지의 domain 내의 irq (index) 를 가진다.
 
 irq_domain 을 이용하는 입장에서 
 irq_domain 을 가지고 0-9중 5번째에 해당하는 linux irq number 를 넘겨주거나 생성한다.
 
 종류는 몇가지 있는것 같지만 현재 까지 분석한 내용으로 2개의 종류가 있다. LEGACY 와 LINEAR 이다.
 
 LEGACY 는 irq_domain 을 생성하기 전에 미리 10개의 linux irq number 를 가지고 있는 상태이다.
 irq_alloc_descs(irq, from, cnt, node) 함수를 사용하여 cnt 만큼 linux irq number 를 할당 받는다.(irq 는 시작 번호, irq 가 -1 이라면 동적 생성?)
 리턴 값으로 cnt 만큼 할당한 이후 맨첫번째에 해당하는 linux irq number 받는다. cnt 만큼 할당한 linux irq number 는 단계적이어야 한다. 
 1->2->3->4 이런식으로 1->4->8->9 이런식으로 안된다. ( 100번 을 리턴 받았다면 100~109 가 linux irq number 이다.)
 그 이후 irq_domain_add_legacy() 함수를 호출 하여 irq_domain 을 생성한다.
 
 이와 같이 사용 된다.
 Q. 위에 생성한 irq_domain 을 이용하여 7번째에 해당하는 linux irq number 를 알려줘 = irq_create_mapping(any_irq_domain, 7)
 A. 100~109번호 중 7번째에 해당하는 106 을 알려준다.
 A. 106번호로 request irq 를 등록하고 핸들러도 등록 할 수 있다.
   
 LINEAR 는 irq_domain 을 안에 10개 번호를 저장할 공간을 생성해 놓고 linux irq number 의 생성은 요청이 있을 때 사용한다.
 irq_domain_add_linear() 함수를 호출 하여 irq_domain 을 생성해 놓고 10개 크기 만큼의 배열을 생성해 놓는다.
 그 이후 요청이 있을때 linux irq number 를 리턴하여 준다.
 
 이와 같이 사용 된다.
 Q. 위에 생성한 irq_domain 을 이용하여 7번째에 해당하는 linux irq number 를 알려줘  = irq_create_mapping(any_irq_domain, 7)
 A. irq_domain 내에 10개의 배열중 7번째에 해당하는 배열에 아무 값이 없어서 irq_alloc_desc_from 함수를 이용하여 
    linux irq number 1개를 할당 하고 7번째 배열에 linux irq number 를 저장하고 리턴한다.
   ( irq_domain 내의 0~6,8~9 배열의 값은 0이다. 즉 linux irq number 를 할당 받지 못한 상태로 계속 있고 향후 그 index 에 대한 요청이 있을 때 생성 된다.)
   
 A. 이후 리턴한 linux irq number 를 이용하여 request irq 를 등록하고 핸들러도 등록 할 수 있다. 
 
 하지만 106번 이나 리턴받은 linux irq number에  해당하는 interrupt_handler 는 누가 수행 할까?
 
 이렇게 역매핑으로 얻은 linux irq number interrupt handler 들은 스스로 혼자 수행 될 수 없다.
 ( 원론적으로 다른 linux irq number 도 마찬가지 이다. GIC 를 통하여 id 확인하여 그 id 에 해당하는 handler 를 수행하는 것일 테니까 )
 
 선으로 연결된 (wired line) interrupt handler 에서 handle_nested_irq() 함수를 사용하여 106번에 해당하는 interrupt handler 를 수행 한다.
 
 다음과 같이...
 handle_nested_irq(irq_find_mapping(any_irq_domain, 7));

----------------------------
아래는 리눅스 커널 도큐먼트 밑에 있는 걸 번역..... 한건데 부끄럽다..

리눅스 커널의 현재 디자인은 단하나의 큰 번호로 된 각각 독립적인 번호로 할당되어 있는 IRQ 소스 공간을 사용 하고 있다.
그것이 오직 하나의 인터럽트 컨트롤일때 간단하다.
그러나 다중의 인터럽트 컨트롤러가 있는 시스템은 각 컨트롤은 할당되어지고 겹치지 않는 리눅스 IRQ 번호를 얻는것을 을 보장 해야 한다.
irq_alloc_desc*() and irq_free_desc*() API들은 irq 번호를 제공한다.
그러나, 리눅스 IRQ 번호 공간 안으로 어떠한 컨트롤-로컬 IRQ(hwirq) 번호 역매핑 지원을 제공하지 않는다.
irq_domain 라이브러리는 irq_alloc_desc*() API 의 상위에서 hwirq 와 IRQ 번호 사이에 매핑을 추가 한다.
맵핑을 관리하는 irq_domain 은 인터럽트 컨트롤러 드라이버 열린 코딩 그들자신의 역매핑 계획이 선호 된다.
irq_domain 은 디바이트리 인터럽트 명시자들로 부터 hwirq 번호로 번형을 시행한다.
또 다른 IRQ 토폴로지 데이타 소스를 지원하기 위하여 쉽게 확장 가능하다.

=== irq_domain usage ===
인터럽트 컨트롤러 드라이버는 irq_domain_add_* 형태의 함수들중 하나를 호출 하여 irq_domain을 생성하고 등록한다.
( 각 맵핑 방법은 다른 할당자 함수다, 나중에 다시)
함수는 성공시 irq_domain 으로 포인터를 되돌려 줄 것이다.
호출자는 최소 .map 콜백이 덧붙여진 irq_domain_ops 구조체 와 함께 할당자 함수를 제공해야 한다.

대개의 경우, irq_domain 은 어떠한 hwirq 와 IRQ 번호 사이에 매핑없이 빈것으로 시작될 것이다.
매핑들은 irq_crete_mapping() 를 호출 함으로써 irq_domain로 추가 된다.
irq_create_mapping은 인수들로 irq_domain 과 hwirq 번호를 받아 들인다.

만약 hwirq를 위한 매핑이 이미 존재하지 않는다면, 새로운 리눅스 irq_desc를 할당하고,
hwirq 와 함께 그것을 결부 짓고, .map() 콜백 함수를 호출 한다.
그래서 드라이버는 어떤 요구된 하드웨어 셋업을 실시한다.

인터럽트를 받게 될때, irq_find_mapping() 함수는 hwirq 번호로 부터 Linux IRQ 번호를 찾는데 사용 해야 한다.

만약 드라이버가 리눅스 IRQ 번호 나 irq_data 포인터를 가진다면,
관련된 hwirq 번호를 알아내기 위해 필요하다.( 예를 들어 irq_chip 콜백들 )
그리고 그것은 irq_data->hwirq 부터 즉시 얻을 수 있다.

=== Types of irq_domain mappings ===

그것은 hwirq 부터 리눅스 irq 까지 역매핑을 위해 여러가지 메커니즘으로 이용가능하다.
그리고 각 메커니즘은 다른 할당 함수를 사용한다 역맵 종류는 사용 케이스에 의존 하여 사용된다.
각 역맵 종류는 아래에 설명 되어 있다.

==== Linear ====
irq_domain_add_linear()

1차 역맵은 hwirq 번호에 의해 정렬 된 고정 크기 테이블을 유지 한다.
hwirq 번호가 매핑 되었을 때, irq_desc는 hwirq를 위해 할당 된다.
그리고 IRQ 번호는 테이블에 저장 된다.
1차 맵은 hwirq들의 최대 번호 가 고정 되어 지거나 비교적 작은 번호 (~ < 256) 일때 좋은 선택이다.
이 맵의 장점은 IRQ 번호의 고정된 시간 검색 이다.
그리고 irq_descs는 사용하는 IRQ를 위해 할당된다.
단점은 가장 크게 가능한 hwirq 번호 만큼 큰 테이블이어야 한다.
드라이버의 대부분는 1차맵을 사용 해야 한다.

나중에 시간 되면 밑으로 번역......
==== Tree ==== 
irq_domain_add_tree()

The irq_domain maintains a radix tree map from hwirq numbers to Linux
IRQs.  When an hwirq is mapped, an irq_desc is allocated and the
hwirq is used as the lookup key for the radix tree.

The tree map is a good choice if the hwirq number can be very large
since it doesn't need to allocate a table as large as the largest
hwirq number.  The disadvantage is that hwirq to IRQ number lookup is
dependent on how many entries are in the table.

Very few drivers should need this mapping.  At the moment, powerpc
iseries is the only user.

==== No Map ===-
irq_domain_add_nomap()

The No Map mapping is to be used when the hwirq number is
programmable in the hardware.  In this case it is best to program the
Linux IRQ number into the hardware itself so that no mapping is
required.  Calling irq_create_direct_mapping() will allocate a Linux
IRQ number and call the .map() callback so that driver can program the
Linux IRQ number into the hardware.

Most drivers cannot use this mapping.

==== Legacy ====
irq_domain_add_simple()
irq_domain_add_legacy()
irq_domain_add_legacy_isa()

The Legacy mapping is a special case for drivers that already have a
range of irq_descs allocated for the hwirqs.  It is used when the
driver cannot be immediately converted to use the linear mapping.  For
example, many embedded system board support files use a set of #defines
for IRQ numbers that are passed to struct device registrations.  In that
case the Linux IRQ numbers cannot be dynamically assigned and the legacy
mapping should be used.

The legacy map assumes a contiguous range of IRQ numbers has already
been allocated for the controller and that the IRQ number can be
calculated by adding a fixed offset to the hwirq number, and
visa-versa.  The disadvantage is that it requires the interrupt
controller to manage IRQ allocations and it requires an irq_desc to be
allocated for every hwirq, even if it is unused.

The legacy map should only be used if fixed IRQ mappings must be
supported.  For example, ISA controllers would use the legacy map for
mapping Linux IRQs 0-15 so that existing ISA drivers get the correct IRQ
numbers.

Most users of legacy mappings should use irq_domain_add_simple() which
will use a legacy domain only if an IRQ range is supplied by the
system and will otherwise use a linear domain mapping.



---------------- 2013-03-26 추가 --------------------------------------
struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
unsigned int size,
unsigned int first_irq,
irq_hw_number_t first_hwirq,
const struct irq_domain_ops *ops,
void *host_data)
 
first_irq 번호는 linux irq number ( irq_desc.irq_data.irq ) 중 중심이 되는 1개 이다.
만약 size 가 10 이고 first_irq 가 88 이라고 한다면
irq_desc.irq_dat.irq 번호 88 ~ 97번까지 10개가 비어 있어야 한다.
이 상황에서 first_hwirq 번호가 20 이라고 가정해 보자.

irq_desc.irq_data.irq   88
irq_desc.irq_data.hwirq 20

irq_desc.irq_data.irq   89
irq_desc.irq_data.hwirq 21

irq_desc.irq_data.irq   90
irq_desc.irq_data.hwirq 22

.......................

이렇게 된다.

domain->revmap_data.legacy.first_hwirq 에는 20 (first_hwirq)
domain->revmap_data.legacy.first_irq 에는 88 (first_irq) 
를 기록해 놓는다.


진짜로 haware irq 22번이 발생 했다면
static unsigned int irq_domain_legacy_revmap(struct irq_domain *domain, irq_hw_number_t hwirq)
에서 hwirq 매개변수에 22를 넣어 주면

return hwirq - first_hwirq + domain->revmap_data.legacy.first_irq;
          22 - 20          + 88
          
가 되어 90번이 return 된다. 이 90번은 irq_desc.irq_data.irq 90 이다.

덧글|신고