ARM10C 73주차 후기
일시 : 2014.10.11 (73주차)
모임명 : NAVER개발자커뮤니티지원_IAMROOT.ORG_10차ARM-C
장소 : 토즈 타워점
장소지원 : NAVER 개발자 커뮤니티 지원 프로그램
참여인원 : 4명
스터디에 도움될 만한 정보 공유
스터디 진도 :
- init_IRQ();
- exynos-combiner.c 에 정의된 함수를 사용하여 초기화 수행
- __irqchip_begin: irqchip_of_match_exynos4210_combiner
main.c::start_kernel()
asmlinkage void __init start_kernel(void)
{
...
boot_cpu_init();
// 현재 cpu(core id)를 얻어서 cpu_XXX_bits[] 의 cpu를 셋한다.
...
setup_arch(&command_line);
...
mm_init();
// buddy와 slab 을 활성화 하고 기존 할당 받은 bootmem 은 buddy,
// pcpu 메모리, vmlist 는 slab으로 이관
sched_init();
// scheduler가 사용하는 자료 구조 초기화, idle_threads를 init_task로 세팅
preempt_disable();
// preempt count를 증가시켜 preemption 못하도록 막음
...
rcu_init();
// rcu 자료구조 bh, sched, preempt 를 각각 초기화 수행함
...
radix_tree_init();
// radix tree로 사용하는 radix_tree_node_cachep에 kmem_cache#20을 생성 및 초기화 후 할당하고
// height_to_maxindex을 초기화 수행
/* init some links before init_ISA_irqs() */
early_irq_init();
// irq_desc 0 ~ 15 까지의 object을 할당 받고 초기화를 수행
// allocated_irqs에 bit를 1로 세팅하고 radix tree에 각 irq_desc를 노트로 추가
init_IRQ();
지난시간에 이어 init_IRQ() 분석 진행 중
irq.c::init_IRQ()
// ARM10C 20141004
void __init init_IRQ(void)
{
// CONFIG_OF=y, machine_desc->init_irq: __mach_desc_EXYNOS5_DT.init_irq: 0
if (IS_ENABLED(CONFIG_OF) && !machine_desc->init_irq)
irqchip_init();
else
machine_desc->init_irq();
}
irqchip.c::of_irq_init()
- irqchip_init()은 다시 of_irq_init()을 __irqchip_begin을 매개변수로 해서 호출한다.
// ARM10C 20141004
void __init irqchip_init(void)
{
// exynos-combiner.c 에 정의된 함수를 사용하여 초기화 수행
// __irqchip_begin: irqchip_of_match_exynos4210_combiner
of_irq_init(__irqchip_begin);
}
- 여기서 __irqchip_begin은 외부 구조체로 정의한다.
// ARM10C 20141004
extern struct of_device_id __irqchip_begin[];
- 외부 구조체는 vmlinux.lds.h에서 링크된다.
o#ifdef CONFIG_IRQCHIP // CONFIG_IRQCHIP=y
/*
// ARM10C 20141004
*/
#define IRQCHIP_OF_MATCH_TABLE() \
. = ALIGN(8); \
VMLINUX_SYMBOL(__irqchip_begin) = .; \
*(__irqchip_of_table) \
*(__irqchip_of_end)
#else
#define IRQCHIP_OF_MATCH_TABLE()
#endif
irq.c::of_irq_init()
// ARM10C 20141004
// __irqchip_begin: irqchip_of_match_exynos4210_combiner
void __init of_irq_init(const struct of_device_id *matches)
{
struct device_node *np, *parent = NULL;
// parent: NULL
struct intc_desc *desc, *temp_desc;
struct list_head intc_desc_list, intc_parent_list;
INIT_LIST_HEAD(&intc_desc_list);
// intc_desc_list 리스트 초기화 수행
INIT_LIST_HEAD(&intc_parent_list);
// intc_parent_list 리스트 초기화 수행
// matches: irqchip_of_match_exynos4210_combiner
for_each_matching_node(np, matches) {
// for (np = of_find_matching_node(NULL, matches); np; np = of_find_matching_node(np, matches))
// np: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
// of_find_property(devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소, "interrupt-controller", NULL):
// combiner node의 "interrupt-controller" property의 주소
// np: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
// of_find_property(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, "interrupt-controller", NULL):
// gic node의 "interrupt-controller" property의 주소
if (!of_find_property(np, "interrupt-controller", NULL))
continue;
/*
* Here, we allocate and populate an intc_desc with the node
* pointer, interrupt-parent device_node etc.
*/
// sizeof(struct intc_desc): 16 bytes, GFP_KERNEL: 0xD0
// kzalloc(16, GFP_KERNEL: 0xD0): kmem_cache#30-o10
// sizeof(struct intc_desc): 16 bytes, GFP_KERNEL: 0xD0
// kzalloc(16, GFP_KERNEL: 0xD0): kmem_cache#30-o11
desc = kzalloc(sizeof(*desc), GFP_KERNEL);
// desc: kmem_cache#30-o10
// desc: kmem_cache#30-o11
// desc: kmem_cache#30-o10
// desc: kmem_cache#30-o11
if (WARN_ON(!desc))
goto err;
// desc->dev: (kmem_cache#30-o10)->dev, np: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
// desc->dev: (kmem_cache#30-o11)->dev, np: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
desc->dev = np;
// desc->dev: (kmem_cache#30-o10)->dev: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
// desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
// 2014/10/04 종료
// 2014/10/11 시작
// desc->interrupt_parent: (kmem_cache#30-o10)->interrupt_parent, np: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
// of_irq_find_parent(devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소): NULL
// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent, np: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
// of_irq_find_parent(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소): exynos5.dtsi 에 있는 gic node
desc->interrupt_parent = of_irq_find_parent(np);
// desc->interrupt_parent: (kmem_cache#30-o10)->interrupt_parent: NULL
// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL
// desc->interrupt_parent: (kmem_cache#30-o10)->interrupt_parent: NULL
// np: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL
// np: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
if (desc->interrupt_parent == np)
desc->interrupt_parent = NULL;
// &desc->list: &(kmem_cache#30-o10)->list
// &desc->list: &(kmem_cache#30-o11)->list
list_add_tail(&desc->list, &intc_desc_list);
// intc_desc_list에 (kmem_cache#30-o10)->list를 tail에 추가
// intc_desc_list에 (kmem_cache#30-o11)->list를 tail에 추가
}
// irqchip_of_match_exynos4210_combiner, irqchip_of_match_cortex_a15_gic 의
// struct intc_desc 메모리 할당, intc_desc 맴버가 초기화 된 값이 intc_desc_list list의 tail로 추가됨
/*
* The root irq controller is the one without an interrupt-parent.
* That one goes first, followed by the controllers that reference it,
* followed by the ones that reference the 2nd level controllers, etc.
*/
// list_empty(&intc_desc_list): 0
while (!list_empty(&intc_desc_list)) {
/*
* Process all controllers with the current 'parent'.
* First pass will be looking for NULL as the parent.
* The assumption is that NULL parent means a root controller.
*/
list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
// for (desc = list_first_entry(&intc_desc_list, typeof(*desc), list),
// temp_desc = list_next_entry(desc, list);
// &desc->list != (&intc_desc_list);
// desc = temp_desc, temp_desc = list_next_entry(temp_desc, list))
// desc: kmem_cache#30-o10 (exynos4210_combiner), temp_desc: kmem_cache#30-o11 (cortex_a15_gic)
const struct of_device_id *match;
int ret;
of_irq_init_cb_t irq_init_cb;
// desc->interrupt_parent: (kmem_cache#30-o10)->interrupt_parent: NULL, parent: NULL
if (desc->interrupt_parent != parent)
continue;
// &desc->list: (kmem_cache#30-o10)->list
list_del(&desc->list);
// intc_desc_list에서 (kmem_cache#30-o10)->list를 삭제
// matches: irqchip_of_match_exynos4210_combiner,
// desc->dev: (kmem_cache#30-o10)->dev: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
// of_match_node(irqchip_of_match_exynos4210_combiner, devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소):
// irqchip_of_match_exynos4210_combiner
match = of_match_node(matches, desc->dev);
// match: irqchip_of_match_exynos4210_combiner
// match->data; irqchip_of_match_exynos4210_combiner.data: combiner_of_init
if (WARN(!match->data,
"of_irq_init: no init function for %s\n",
match->compatible)) {
kfree(desc);
continue;
}
// match->compatible; irqchip_of_match_exynos4210_combiner.compatible: "samsung,exynos4210-combiner",
// desc->dev: (kmem_cache#30-o10)->dev: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
// desc->interrupt_parent: (kmem_cache#30-o10)->interrupt_parent: NULL
pr_debug("of_irq_init: init %s @ %p, parent %p\n",
match->compatible,
desc->dev, desc->interrupt_parent);
// "of_irq_init: init samsung,exynos4210-combiner @ 0x(combiner node의 주소), parent 0\n"
// 2014/10/11 종료
irq.c::of_irq_init() 요약.
- INIT_LIST_HEAD(&intc_desc_list);
- INIT_LIST_HEAD(&intc_parent_list);
- for_each_matching_node(np, matches) {
- desc = kzalloc(sizeof(*desc), GFP_KERNEL);
- desc: kmem_cache#30-o11
- desc->dev = np;
- desc->dev: (kmem_cache#30-o10)->dev: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
- desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
- desc->interrupt_parent = of_irq_find_parent(np);
- desc->interrupt_parent: (kmem_cache#30-o10)->interrupt_parent: NULL
- desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL
- list_add_tail(&desc->list, &intc_desc_list);
- intc_desc_list에 (kmem_cache#30-o10)->list를 tail에 추가
- intc_desc_list에 (kmem_cache#30-o11)->list를 tail에 추가
- while (!list_empty(&intc_desc_list)) {
- list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
- list_del(&desc->list);
- intc_desc_list에서 (kmem_cache#30-o10)->list를 삭제
- match = of_match_node(matches, desc->dev);
- match: irqchip_of_match_exynos4210_combiner
- pr_debug("of_irq_init: init %s @ %p, parent %p\n", match->compatible, desc->dev, desc->interrupt_parent);
- "of_irq_init: init samsung,exynos4210-combiner @ 0x(combiner node의 주소), parent 0\n"
- 다음주에 init_IRQ()를 계속 분석합니다.
string.c::strlen()
size_t strlen(const char *s)
{
const char *sc = s;
while (*sc != '\0')
sc++;
return sc - s;
}
irq.c::of_irq_find_parent()
// ARM10C 20141011
// np: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
struct device_node *of_irq_find_parent(struct device_node *child)
{
struct device_node *p;
const __be32 *parp;
// child: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
// of_node_get(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소):
// devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
if (!of_node_get(child))
return NULL;
do {
// child: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
// of_get_property(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, "interrupt-parent", NULL): gic 의 주소
parp = of_get_property(child, "interrupt-parent", NULL);
// parp: gic 의 주소
// parp: gic 의 주소
if (parp == NULL)
p = of_get_parent(child);
else {
// of_irq_workarounds: 0, OF_IMAP_NO_PHANDLE: 0x00000002
if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
p = of_node_get(of_irq_dflt_pic);
else
// parp: gic 의 주소, of_find_node_by_phandle(gic 의 주소): NULL
p = of_find_node_by_phandle(be32_to_cpup(parp));
// p: NULL
}
// child: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
of_node_put(child); // null function
// child: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, p: NULL
child = p;
// child: NULL
// p: NULL, of_get_property(NULL, "#interrupt-cells", NULL): NULL
} while (p && of_get_property(p, "#interrupt-cells", NULL) == NULL);
// p: NULL
return p;
// return NULL
}
base.c::of_get_property()
// ARM10C 20141011
const void *of_get_property(const struct device_node *np, const char *name,
int *lenp)
{
struct property *pp = of_find_property(np, name, lenp);
return pp ? pp->value : NULL;
}
EXPORT_SYMBOL(of_get_property);
base.c::of_find_property()
// ARM10C 20141011
// np: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소 (cortex_a15_gic), "interrupt-controller", NULL
struct property *of_find_property(const struct device_node *np,
const char *name,
int *lenp)
{
struct property *pp;
unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags);
// devtree_lock을 사용한 spin lock 수행하고 cpsr을 flags에 저장
// np: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소, name: "interrupt-controller", lenp: NULL
// __of_find_property(devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소, "interrupt-controller", NULL):
// combiner node의 "interrupt-controller" property의 주소
pp = __of_find_property(np, name, lenp);
// pp: combiner node의 "interrupt-controller" property의 주소
raw_spin_unlock_irqrestore(&devtree_lock, flags);
// devtree_lock을 사용한 spin lock 해재하고 flags에 저장된 cpsr을 복원
// pp: combiner node의 "interrupt-controller" property의 주소
return pp;
// return: combiner node의 "interrupt-controller" property의 주소
}
EXPORT_SYMBOL(of_find_property);
base.c::__of_find_property()
// ARM10C 20141004
// np: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소, name: "interrupt-controller", lenp: NULL
static struct property *__of_find_property(const struct device_node *np,
const char *name, int *lenp)
{
struct property *pp;
// np: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
if (!np)
return NULL;
// np: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
for (pp = np->properties; pp; pp = pp->next) {
// pp: pp->name이 "interrupt-controller" 일때의 주소 (exynos5.dtsi)
// pp->name: "interrupt-controller", name: "interrupt-controller"
// of_prop_cmp("interrupt-controller", "interrupt-controller"): 0
if (of_prop_cmp(pp->name, name) == 0) {
// lenp: NULL
if (lenp)
*lenp = pp->length;
break;
}
}
// pp: combiner node의 "interrupt-controller" property의 주소
return pp;
// return combiner node의 "interrupt-controller" property의 주소
}
base.c::of_find_node_by_phandle()
- np->phandle에 값이 존재하기 위해선 exynos5420 용 dts 파일들의 node 들 중에
- "phandle", "linux,phandle" property를 가지는 node가 존재해야 값을 가짐 (fdt.c의 360 line 참고)
- exynos5420 용 dts 파일들의 node를 찾아 본 결과 "phandle", "linux,phandle" property를
- 가지는 node는 존재하지 않음
- for loop 수행 결과 np값은 NULL을 가지게 됨
// ARM10C 20141011
// parp: gic 의 주소
struct device_node *of_find_node_by_phandle(phandle handle)
{
struct device_node *np;
unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags);
// devtree_lock을 사용한 spin lock 수행하고 cpsr을 flags에 저장
for (np = of_allnodes; np; np = np->allnext)
// np->phandle: NULL, handle: gic 의 주소
if (np->phandle == handle)
break;
// np: NULL
of_node_get(np);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
// devtree_lock을 사용한 spin lock 해재하고 flags에 저장된 cpsr을 복원
// np: NULL
return np;
// return NULL
}
EXPORT_SYMBOL(of_find_node_by_phandle);
of.h::of_node_get()
// ARM10C 20141011
static inline struct device_node *of_node_get(struct device_node *node)
{
return node;
}
of.h::of_node_put()
// ARM10C 20141004
static inline void of_node_put(struct device_node *node) { }
base.c::of_get_property()
// ARM10C 20141011
const void *of_get_property(const struct device_node *np, const char *name,
int *lenp)
{
struct property *pp = of_find_property(np, name, lenp);
return pp ? pp->value : NULL;
}
EXPORT_SYMBOL(of_get_property);
base.c::of_match_node()
// ARM10C 20141011
// matches: irqchip_of_match_exynos4210_combiner,
// desc->dev: (kmem_cache#30-o10)->dev: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
const struct of_device_id *of_match_node(const struct of_device_id *matches,
const struct device_node *node)
{
const struct of_device_id *match;
unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags);
// devtree_lock을 사용한 spin lock 수행하고 cpsr을 flags에 저장
// matches: irqchip_of_match_exynos4210_combiner, node: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
// __of_match_node(irqchip_of_match_exynos4210_combiner, devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소):
// irqchip_of_match_exynos4210_combiner
match = __of_match_node(matches, node);
// match: irqchip_of_match_exynos4210_combiner
raw_spin_unlock_irqrestore(&devtree_lock, flags);
// devtree_lock을 사용한 spin lock 해재하고 flags에 저장된 cpsr을 복원
// match: irqchip_of_match_exynos4210_combiner
return match;
// return irqchip_of_match_exynos4210_combiner
}
EXPORT_SYMBOL(of_match_node);
base.c::__of_match_node()
// ARM10C 20141011
// matches: irqchip_of_match_exynos4210_combiner, node: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
static
const struct of_device_id *__of_match_node(const struct of_device_id *matches,
const struct device_node *node)
{
// matches: irqchip_of_match_exynos4210_combiner
// matches: irqchip_of_match_cortex_a15_gic
if (!matches)
return NULL;
// matches->name[0]: irqchip_of_match_cortex_a15_gic->name[0]: NULL,
// matches->type[0]: irqchip_of_match_cortex_a15_gic->type[0]: NULL,
// matches->compatible[0]: irqchip_of_match_cortex_a15_gic->compatible[0]: 'a'
while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
int match = 1;
// match: 1
// matches->name[0]: irqchip_of_match_cortex_a15_gic->name[0]: NULL
if (matches->name[0])
match &= node->name
&& !strcmp(matches->name, node->name);
// matches->type[0]: irqchip_of_match_cortex_a15_gic->type[0]: NULL
if (matches->type[0])
match &= node->type
&& !strcmp(matches->type, node->type);
// matches->compatible[0]: irqchip_of_match_cortex_a15_gic->compatible[0]: 'a'
if (matches->compatible[0])
// match: 1, node: gic node의 주소,
// matches->compatible: irqchip_of_match_cortex_a15_gic->compatible: "arm,cortex-a15-gic"
// __of_device_is_compatible(gic node의 주소, "arm,cortex-a15-gic"): 1
match &= __of_device_is_compatible(node,
matches->compatible);
// match: 1
// match: 1
if (match)
// matches: irqchip_of_match_cortex_a15_gic
return matches;
// return irqchip_of_match_cortex_a15_gic
matches++;
}
return NULL;
}
댓글 없음:
댓글 쓰기