ARM10C 80주차 후기
일시 : 2014.11.29 (80주차)
모임명 : NAVER개발자커뮤니티지원_IAMROOT.ORG_10차ARM-C
장소 : 토즈 타워점
장소지원 : NAVER 개발자 커뮤니티 지원 프로그램
참여인원 : 2명
진도
main.c::start_kernel()
asmlinkage void __init start_kernel(void)
{
...
setup_arch(&command_line);
...
mm_init();
// buddy와 slab 을 활성화 하고 기존 할당 받은 bootmem 은 buddy,
// pcpu 메모리, vmlist 는 slab으로 이관
...
rcu_init();
// rcu 자료구조 bh, sched, preempt 를 각각 초기화 수행함
...
/* 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();
- call: start_kernel()->init_IRQ()
irq.c::init_IRQ()
- called: start_kernel()->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();
}
- call: start_kernel()->init_IRQ()->irqchip_init()
irqchip.h::irqchip_init()
- called: start_kernel()->init_IRQ()->irqchip_init()
// ARM10C 20141004
extern struct of_device_id __irqchip_begin[];
// ARM10C 20141004
void __init irqchip_init(void)
{
// exynos-combiner.c 에 정의된 함수를 사용하여 초기화 수행
// __irqchip_begin: irqchip_of_match_exynos4210_combiner
of_irq_init(__irqchip_begin);
}
- call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()
- // exynos-combiner.c 에 정의된 함수를 사용하여 초기화 수행
- // __irqchip_begin: irqchip_of_match_exynos4210_combiner
- of_irq_init(__irqchip_begin);
irqchip.h::irqchip_init()
- called: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()
- // exynos-combiner.c 에 정의된 함수를 사용하여 초기화 수행
- // __irqchip_begin: irqchip_of_match_exynos4210_combiner
- of_irq_init(__irqchip_begin);
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의 주소
// desc->interrupt_parent: (kmem_cache#30-o10)->interrupt_parent, np: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
// of_irq_find_parent(devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소): gic node 주소
// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent, np: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
// of_irq_find_parent(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소): gic node 주소
desc->interrupt_parent = of_irq_find_parent(np);
// desc->interrupt_parent: (kmem_cache#30-o10)->interrupt_parent: gic node 주소
// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: gic node 주소
// desc->interrupt_parent: (kmem_cache#30-o10)->interrupt_parent: gic node 주소
// np: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: gic node 주소
// np: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
if (desc->interrupt_parent == np)
// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: gic node 주소
desc->interrupt_parent = NULL;
// desc->interrupt_parent: (kmem_cache#30-o11)->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로 추가됨
// list_empty(&intc_desc_list): 0
while (!list_empty(&intc_desc_list)) {
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)
// desc: kmem_cache#30-o11 (cortex_a15_gic), temp_desc: NULL
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: gic node 주소, parent: NULL
// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL, parent: NULL
if (desc->interrupt_parent != parent)
continue;
// continue 수행 (exynos4210_combiner)
// &desc->list: (kmem_cache#30-o11)->list
list_del(&desc->list);
// intc_desc_list에서 (kmem_cache#30-o11)->list를 삭제
// matches: irqchip_of_match_cortex_a15_gic,
// desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
// of_match_node(cortex_a15_gic, devtree에서 allnext로 순회 하면서 찾은 gic node의 주소):
// irqchip_of_match_cortex_a15_gic
match = of_match_node(matches, desc->dev);
// match: irqchip_of_match_cortex_a15_gic
// match->data; irqchip_of_match_cortex_a15_gic.data: gic_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_cortex_a15_gic.compatible: "arm,cortex-a15-gic",
// desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
// desc->interrupt_parent: (kmem_cache#30-o11)->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 arm,cortex-a15-gic @ 0x(gic node의 주소), parent 0\n"
// match->data; irqchip_of_match_cortex_a15_gic.data: gic_of_init
irq_init_cb = (of_irq_init_cb_t)match->data;
// irq_init_cb: gic_of_init
// desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL
// gic_of_init(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, NULL):
ret = irq_init_cb(desc->dev, desc->interrupt_parent);
- call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()
- // desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
- // desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL
- // gic_of_init(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, NULL):
- // __irqchip_begin: irqchip_of_match_exynos4210_combiner
- // irq_init_cb = (of_irq_init_cb_t)match->data;
- 여기서 irq_init_cb: gic_of_init 로 되어 gic_of_init()를 실행한다.
- ret = irq_init_cb(desc->dev, desc->interrupt_parent);
irq_gic.c::gic_of_init()
- called: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()
- // desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
- // desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL
- // gic_of_init(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, NULL):
- // __irqchip_begin: irqchip_of_match_exynos4210_combiner
- // irq_init_cb = (of_irq_init_cb_t)match->data;
- 여기서 irq_init_cb: gic_of_init 로 되어 gic_of_init()를 실행한다.
- ret = irq_init_cb(desc->dev, desc->interrupt_parent);
// ARM10C 20141018
// desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL
int __init gic_of_init(struct device_node *node, struct device_node *parent)
{
void __iomem *cpu_base;
void __iomem *dist_base;
u32 percpu_offset;
int irq;
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
if (WARN_ON(!node))
return -ENODEV;
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
// of_iomap(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, 0): 0xf0000000
dist_base = of_iomap(node, 0);
// dist_base: 0xf0000000
// of_iomap에서 한일:
// device tree 있는 gic node에서 node의 resource 값을 가져옴
// (&res)->start: 0x10481000
// (&res)->end: 0x10481fff
// (&res)->flags: IORESOURCE_MEM: 0x00000200
// (&res)->name: "/interrupt-controller@10481000"
/*
// alloc area (GIC#0) 를 만들고 rb tree에 alloc area 를 추가
// 가상주소 va_start 기준으로 GIC#0 를 RB Tree 추가한 결과
//
// CHID-b
// (0xF8000000)
// / \
// TMR-r PMU-r
// (0xF6300000) (0xF8180000)
// / \ / \
// SYSC-b WDT-b CMU-b SRAM-b
// (0xF6100000) (0xF6400000) (0xF8100000) (0xF8400000)
// / \
// GIC#0-r ROMC-r
// (0xF0000000) (0xF84C0000)
//
// vmap_area_list에 GIC#0 - SYSC -TMR - WDT - CHID - CMU - PMU - SRAM - ROMC
// 순서로 리스트에 연결이 됨
//
// (kmem_cache#30-oX (vm_struct))->flags: GFP_KERNEL: 0xD0
// (kmem_cache#30-oX (vm_struct))->addr: 0xf0000000
// (kmem_cache#30-oX (vm_struct))->size: 0x2000
// (kmem_cache#30-oX (vm_struct))->caller: __builtin_return_address(0)
//
// (kmem_cache#30-oX (vmap_area GIC#0))->vm: kmem_cache#30-oX (vm_struct)
// (kmem_cache#30-oX (vmap_area GIC#0))->flags: 0x04
*/
// device tree 있는 gic node에서 node의 resource 값을 pgtable에 매핑함
// 0xc0004780이 가리키는 pte의 시작주소에 0x10481653 값을 갱신
// (linux pgtable과 hardware pgtable의 값 같이 갱신)
//
// pgd pte
// | |
// +--------------+
// | | +--------------+ +0
// | | | 0xXXXXXXXX | ---> 0x10481653 에 매칭되는 linux pgtable 값
// +- - - - - - - + | Linux pt 0 |
// | | +--------------+ +1024
// | | | |
// +--------------+ +0 | Linux pt 1 |
// | *(c0004780) |-----> +--------------+ +2048
// | | | 0x10481653 | ---> 2052
// +- - - - - - - + +4 | h/w pt 0 |
// | *(c0004784) |-----> +--------------+ +3072
// | | + +
// +--------------+ +8 | h/w pt 1 |
// | | +--------------+ +4096
//
// cache의 값을 전부 메모리에 반영
// dist_base: 0xf000000
WARN(!dist_base, "unable to map gic dist registers\n");
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
// of_iomap(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, 1): 0xf002000
cpu_base = of_iomap(node, 1);
// cpu_base: 0xf0002000
// of_iomap에서 한일:
// device tree 있는 gic node에서 node의 resource 값을 가져옴
// (&res)->start: 0x10482000
// (&res)->end: 0x10482fff
// (&res)->flags: IORESOURCE_MEM: 0x00000200
// (&res)->name: "/interrupt-controller@10481000"
/*
// alloc area (GIC#1) 를 만들고 rb tree에 alloc area 를 추가
// 가상주소 va_start 기준으로 GIC#1 를 RB Tree 추가한 결과
//
// CHID-b
// (0xF8000000)
// / \
// TMR-r PMU-r
// (0xF6300000) (0xF8180000)
// / \ / \
// GIC#1-b WDT-b CMU-b SRAM-b
// (0xF0002000) (0xF6400000) (0xF8100000) (0xF8400000)
// / \ \
// GIC#0-r SYSC-r ROMC-r
// (0xF0000000) (0xF6100000) (0xF84C0000)
//
// vmap_area_list에 GIC#0 - GIC#1 - SYSC -TMR - WDT - CHID - CMU - PMU - SRAM - ROMC
// 순서로 리스트에 연결이 됨
//
// (kmem_cache#30-oX (vm_struct))->flags: GFP_KERNEL: 0xD0
// (kmem_cache#30-oX (vm_struct))->addr: 0xf0002000
// (kmem_cache#30-oX (vm_struct))->size: 0x2000
// (kmem_cache#30-oX (vm_struct))->caller: __builtin_return_address(0)
//
// (kmem_cache#30-oX (vmap_area GIC#1))->vm: kmem_cache#30-oX (vm_struct)
// (kmem_cache#30-oX (vmap_area GIC#1))->flags: 0x04
*/
// device tree 있는 gic node에서 node의 resource 값을 pgtable에 매핑함
// 0xc0004780이 가리키는 pte의 시작주소에 0x10482653 값을 갱신
// (linux pgtable과 hardware pgtable의 값 같이 갱신)
//
// pgd pte
// | |
// +--------------+
// | | +--------------+ +0
// | | | 0xXXXXXXXX | ---> 0x10482653 에 매칭되는 linux pgtable 값
// +- - - - - - - + | Linux pt 0 |
// | | +--------------+ +1024
// | | | |
// +--------------+ +0 | Linux pt 1 |
// | *(c0004780) |-----> +--------------+ +2048
// | | | 0x10482653 | ---> 2060
// +- - - - - - - + +4 | h/w pt 0 |
// | *(c0004784) |-----> +--------------+ +3072
// | | + +
// +--------------+ +8 | h/w pt 1 |
// | | +--------------+ +4096
//
// cache의 값을 전부 메모리에 반영
// cpu_base: 0xf0002000
WARN(!cpu_base, "unable to map gic cpu registers\n");
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
// of_property_read_u32(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, "cpu-offset", &percpu_offset):
// 0이 아닌 err 값
if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
percpu_offset = 0;
// percpu_offset: 0
// gic_cnt: 0, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset: 0,
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);
- call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()
- // gic_cnt: 0, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset: 0,
- // node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
- gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);
irq-gic.c::gic_init_bases()
- called: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()
- // gic_cnt: 0, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset: 0,
- // node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
- gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);
// ARM10C 20141108
// gic_cnt: 0, -1, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset: 0,
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
void __init gic_init_bases(unsigned int gic_nr, int irq_start,
void __iomem *dist_base, void __iomem *cpu_base,
u32 percpu_offset, struct device_node *node)
{
irq_hw_number_t hwirq_base;
struct gic_chip_data *gic;
int gic_irqs, irq_base, i;
// gic_nr: 0, MAX_GIC_NR: 1
BUG_ON(gic_nr >= MAX_GIC_NR);
// gic_nr: 0
gic = &gic_data[gic_nr];
// gic: &gic_data[0]
#ifdef CONFIG_GIC_NON_BANKED // CONFIG_GIC_NON_BANKED=n
#endif
{ /* Normal, sane GIC... */
// percpu_offset: 0
WARN(percpu_offset,
"GIC_NON_BANKED not enabled, ignoring %08x offset!",
percpu_offset);
// gic->dist_base.common_base: (&gic_data[0])->dist_base.common_base, dist_base: 0xf0000000
gic->dist_base.common_base = dist_base;
// gic->dist_base.common_base: (&gic_data[0])->dist_base.common_base: 0xf0000000
// gic->cpu_base.common_base: (&gic_data[0])->cpu_base.common_base, cpu_base: 0xf0002000
gic->cpu_base.common_base = cpu_base;
// gic->cpu_base.common_base: (&gic_data[0])->cpu_base.common_base: 0xf0002000
// gic: &gic_data[0]
gic_set_base_accessor(gic, gic_get_common_base); // null function
}
/*
* Initialize the CPU interface map to all CPUs.
* It will be refined as each CPU probes its ID.
*/
// NR_GIC_CPU_IF: 8
for (i = 0; i < NR_GIC_CPU_IF; i++)
// i: 0
gic_cpu_map[i] = 0xff;
// gic_cpu_map[0]: 0xff
// i: 1...7 까지 수행
// gic_cpu_map[0...7]: 0xff
/*
* For primary GICs, skip over SGIs.
* For secondary GICs, skip over PPIs, too.
*/
// gic_nr: 0, irq_start: -1
if (gic_nr == 0 && (irq_start & 31) > 0) {
hwirq_base = 16;
// hwirq_base: 16
// irq_start: -1
if (irq_start != -1)
irq_start = (irq_start & ~31) + 16;
} else {
hwirq_base = 32;
}
/*
* Find out how many interrupts are supported.
* The GIC only supports up to 1020 interrupt sources.
*/
// T.R.M: 8.3.2 Distributor register descriptions
// Interrupt Controller Type Register:
// b00100 Up to 160 interrupts, 128 external interrupt lines.
//
// gic: &gic_data[0], gic_data_dist_base(&gic_data[0]): 0xf0000000, GIC_DIST_CTR: 0x004
// readl_relaxed(0xf0000000 + 0x004): 0x0000FC24
gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f;
// gic_irqs: 0x4
// gic_irqs: 0x4
gic_irqs = (gic_irqs + 1) * 32;
// gic_irqs: 160
// gic_irqs: 160
if (gic_irqs > 1020)
gic_irqs = 1020;
// gic->gic_irqs: (&gic_data[0])->gic_irqs, gic_irqs: 160
gic->gic_irqs = gic_irqs;
// gic->gic_irqs: (&gic_data[0])->gic_irqs: 160
// gic_irqs: 160, hwirq_base: 16
gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
// gic_irqs: 144
// irq_start: -1, gic_irqs: 144, numa_node_id(): 0
// irq_alloc_descs(-1, 16, 144, 0): 16
irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id());
- call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_alloc_descs()
- // irq_start: -1, gic_irqs: 144, numa_node_id(): 0
- // irq_alloc_descs(-1, 16, 144, 0): 16
- irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id());
irq.h::irq_alloc_descs()
- called: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_alloc_descs()
- // irq_start: -1, gic_irqs: 144, numa_node_id(): 0
- // irq_alloc_descs(-1, 16, 144, 0): 16
- irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id());
// ARM10C 20141115
// THIS_MODULE: ((struct module *)0)
// irq_start: -1, 16, gic_irqs: 144, numa_node_id(): 0
#define irq_alloc_descs(irq, from, cnt, node) \
__irq_alloc_descs(irq, from, cnt, node, THIS_MODULE)
- call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_alloc_descs()->irq_alloc_descs()
- // irq: irq_start: -1, from: 16, cnt: 144, THIS_MODULE: numa_node_id(): 0
- __irq_alloc_descs(irq, from, cnt, node, THIS_MODULE)
irqdesc.c::__irq_alloc_descs()
- call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_alloc_descs()->irq_alloc_descs()
- // irq: irq_start: -1, from: 16, cnt: 144, THIS_MODULE: numa_node_id(): 0
- __irq_alloc_descs(irq, from, cnt, node, THIS_MODULE)
// ARM10C 20141115
// irq_start: -1, 16, gic_irqs: 144, numa_node_id(): 0, THIS_MODULE: ((struct module *)0)
int __ref
__irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
struct module *owner)
{
int start, ret;
// cnt: 144
if (!cnt)
return -EINVAL;
// irq: -1
if (irq >= 0) {
if (from > irq)
return -EINVAL;
from = irq;
}
mutex_lock(&sparse_irq_lock);
// sparse_irq_lock을 이용한 mutex lock 수행
// IRQ_BITMAP_BITS: 8212, from: 16, cnt: 144
// bitmap_find_next_zero_area(allocated_irqs, 8212, 16, 144, 0): 16
start = bitmap_find_next_zero_area(allocated_irqs, IRQ_BITMAP_BITS,
from, cnt, 0);
// start: 16
// EEXIST: 17
ret = -EEXIST;
// ret: -17
// irq: -1, start: 16
if (irq >=0 && start != irq)
goto err;
// start: 16, cnt: 144, nr_irqs: 16
if (start + cnt > nr_irqs) {
// start: 16, cnt: 144
// irq_expand_nr_irqs(160): 0
ret = irq_expand_nr_irqs(start + cnt);
// ret: 0
// irq_expand_nr_irqs에서 한일:
// 전역변수 nr_irqs 값을 160으로 갱신
// ret: 0
if (ret)
goto err;
}
// start: 16, cnt: 144
bitmap_set(allocated_irqs, start, cnt);
// bitmap_set에서 한일:
// allocated_irqs 의 16 bit 부터 144 bit를 1로 set
mutex_unlock(&sparse_irq_lock);
// sparse_irq_lock을 이용한 mutex unlock 수행
// start: 16, cnt: 144, node: 0, owner: NULL
// alloc_descs(16, 144, 0, NULL): 16
return alloc_descs(start, cnt, node, owner);
// return 16
/*
* alloc_descs에서 한일:
* struct irq_desc의 자료 구조크기 만큼 160개의 메모리를 할당 받아
* radix tree 구조로 구성
*
* radix tree의 root node: &irq_desc_tree 값을 변경
* (&irq_desc_tree)->rnode: kmem_cache#20-o1 (RADIX_LSB: 1)
* (&irq_desc_tree)->height: 2
*
* (kmem_cache#20-o1)->height: 2
* (kmem_cache#20-o1)->count: 3
* (kmem_cache#20-o1)->parent: NULL
* (kmem_cache#20-o1)->slots[0]: kmem_cache#20-o0 (radix height 1 관리 주소)
* (kmem_cache#20-o1)->slots[1]: kmem_cache#20-o2 (radix height 1 관리 주소)
* (kmem_cache#20-o1)->slots[2]: kmem_cache#20-o3 (radix height 1 관리 주소)
*
* (kmem_cache#20-o0)->height: 1
* (kmem_cache#20-o0)->count: 63
* (kmem_cache#20-o0)->parent: kmem_cache#20-o1 (RADIX_LSB: 1)
* (kmem_cache#20-o0)->slots[0...63]: kmem_cache#28-oX (irq 0...63)
*
* (kmem_cache#20-o2)->height: 1
* (kmem_cache#20-o2)->count: 63
* (kmem_cache#20-o2)->parent: kmem_cache#20-o1 (RADIX_LSB: 1)
* (kmem_cache#20-o2)->slots[0...63]: kmem_cache#28-oX (irq 63...127)
*
* (kmem_cache#20-o3)->height: 1
* (kmem_cache#20-o3)->count: 32
* (kmem_cache#20-o3)->parent: kmem_cache#20-o1 (RADIX_LSB: 1)
* (kmem_cache#20-o3)->slots[0...63]: kmem_cache#28-oX (irq 127...160)
*
* (&irq_desc_tree)->rnode --> +-----------------------+
* | radix_tree_node |
* | (kmem_cache#20-o1) |
* +-----------------------+
* | height: 2 | count: 3 |
* +-----------------------+
* | radix_tree_node 0 ~ 2 |
* +-----------------------+
* / | \
* slot: 0 / slot: 1 | \ slot: 2
* +-----------------------+ +-----------------------+ +-----------------------+
* | radix_tree_node | | radix_tree_node | | radix_tree_node |
* | (kmem_cache#20-o0) | | (kmem_cache#20-o2) | | (kmem_cache#20-o3) |
* +-----------------------+ +-----------------------+ +-----------------------+
* | height: 1 | count: 64 | | height: 1 | count: 64 | | height: 1 | count: 32 |
* +-----------------------+ +-----------------------+ +-----------------------+
* | irq 0 ~ 63 | | irq 64 ~ 127 | | irq 128 ~ 160 |
* +-----------------------+ +-----------------------+ +-----------------------+
*/
err:
mutex_unlock(&sparse_irq_lock);
return ret;
}
EXPORT_SYMBOL_GPL(__irq_alloc_descs);
irq_alloc_descs에서 한일:
- struct irq_desc의 자료 구조크기 만큼 160개의 메모리를 할당 받아
- radix tree 구조로 구성 *
- radix tree의 root node: &irq_desc_tree 값을 변경
- (&irq_desc_tree)->rnode: kmem_cache#20-o1 (RADIX_LSB: 1)
- (&irq_desc_tree)->height: 2 *
- (kmem_cache#20-o1)->height: 2
- (kmem_cache#20-o1)->count: 3
- (kmem_cache#20-o1)->parent: NULL
- (kmem_cache#20-o1)->slots[0]: kmem_cache#20-o0 (radix height 1 관리 주소)
- (kmem_cache#20-o1)->slots[1]: kmem_cache#20-o2 (radix height 1 관리 주소)
- (kmem_cache#20-o1)->slots[2]: kmem_cache#20-o3 (radix height 1 관리 주소) *
- (kmem_cache#20-o0)->height: 1
- (kmem_cache#20-o0)->count: 63
- (kmem_cache#20-o0)->parent: kmem_cache#20-o1 (RADIX_LSB: 1)
- (kmem_cache#20-o0)->slots[0...63]: kmem_cache#28-oX (irq 0...63) *
- (kmem_cache#20-o2)->height: 1
- (kmem_cache#20-o2)->count: 63
- (kmem_cache#20-o2)->parent: kmem_cache#20-o1 (RADIX_LSB: 1)
- (kmem_cache#20-o2)->slots[0...63]: kmem_cache#28-oX (irq 63...127) *
- (kmem_cache#20-o3)->height: 1
- (kmem_cache#20-o3)->count: 32
- (kmem_cache#20-o3)->parent: kmem_cache#20-o1 (RADIX_LSB: 1)
- (kmem_cache#20-o3)->slots[0...63]: kmem_cache#28-oX (irq 127...160)
(&irq_desc_tree)->rnode --> +-----------------------+
| radix_tree_node |
| (kmem_cache#20-o1) |
+-----------------------+
| height: 2 | count: 3 |
+-----------------------+
| radix_tree_node 0 ~ 2 |
+-----------------------+
/ | \
slot: 0 / slot: 1 | \ slot: 2
+-----------------------+ +-----------------------+ +-----------------------+
| radix_tree_node | | radix_tree_node | | radix_tree_node |
| (kmem_cache#20-o0) | | (kmem_cache#20-o2) | | (kmem_cache#20-o3) |
+-----------------------+ +-----------------------+ +-----------------------+
| height: 1 | count: 64 | | height: 1 | count: 64 | | height: 1 | count: 32 |
+-----------------------+ +-----------------------+ +-----------------------+
| irq 0 ~ 63 | | irq 64 ~ 127 | | irq 128 ~ 160 |
+-----------------------+ +-----------------------+ +-----------------------+
int __ref
__irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
struct module *owner)
{
...
// start: 16, cnt: 144, node: 0, owner: NULL
return alloc_descs(start, cnt, node, owner);
err:
mutex_unlock(&sparse_irq_lock);
return ret;
}
EXPORT_SYMBOL_GPL(__irq_alloc_descs);
- return: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_alloc_descs()->__irq_alloc_descs()
- return alloc_descs(start, cnt, node, owner);
- // return 16
irq-gic.c::gic_init_bases()
- called: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()
- gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);
- gic_cnt: 0, -1, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset:0,
- node:
// ARM10C 20141108
// gic_cnt: 0, -1, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset: 0,
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
void __init gic_init_bases(unsigned int gic_nr, int irq_start,
void __iomem *dist_base, void __iomem *cpu_base,
u32 percpu_offset, struct device_node *node)
{
...
// gic->domain: (&gic_data[0])->domain
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
// gic_irqs: 144, irq_base: 16, hwirq_base: 16, gic: &gic_data[0]
gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
hwirq_base, &gic_irq_domain_ops, gic);
- call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()
irqdomain.c::irq_domain_add_legacy()
- called: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()
- // gic->domain: (&gic_data[0])->domain
- // node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
- // gic_irqs: 144, irq_base: 16, hwirq_base: 16, gic: &gic_data[0]
// ARM10C 20141122
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
// gic_irqs: 144, irq_base: 16, hwirq_base: 16, &gic_irq_domain_ops, gic: &gic_data[0]
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)
{
struct irq_domain *domain;
...
// domain: kmem_cache#25-o0, first_irq: 16, first_hwirq: 16, size: 144
irq_domain_associate_many(domain, first_irq, first_hwirq, size);
- call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()->irq_domain_associate_many()
irqdomain.c::irq_domain_associate_many()
- called: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()->irq_domain_associate_many()
// ARM10C 20141122
// domain: kmem_cache#25-o0, first_irq: 16, first_hwirq: 16, size: 144
void irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base,
irq_hw_number_t hwirq_base, int count)
{
int i;
// domain->of_node: (kmem_cache#25-o0)->of_node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
// of_node_full_name(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소): "/interrupt-controller@10481000"
// irq_base: 16, hwirq_base: 16, count: 144
pr_debug("%s(%s, irqbase=%i, hwbase=%i, count=%i)\n", __func__,
of_node_full_name(domain->of_node), irq_base, (int)hwirq_base, count);
// "irq_domain_associate_many(/interrupt-controller@10481000, irqbase=16, hwbase=16, count=144)\n"
// count: 144
for (i = 0; i < count; i++) {
// domain: kmem_cache#25-o0, irq_base: 16, i: 0, hwirq_base: 16
// irq_domain_associate(kmem_cache#25-o0, 16, 16): 0
irq_domain_associate(domain, irq_base + i, hwirq_base + i);
}
}
EXPORT_SYMBOL_GPL(irq_domain_associate_many);
- call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()->irq_domain_associate_many()->irq_domain_assoicate()
irq_domain_assoicate() 에서 한일
i: 1...144번까지 (irq 16 ~ irq160) 까지 반복 실행한다.
return: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()->irq_domain_associate_many()->irq_domain_assoicate()
irqdomain.c::irq_domain_add_legacy()
- return: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()->irq_domain_associate_many()
// ARM10C 20141122
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
// gic_irqs: 144, irq_base: 16, hwirq_base: 16, &gic_irq_domain_ops, gic: &gic_data[0]
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)
{
...
// domain: kmem_cache#25-o0, first_irq: 16, first_hwirq: 16, size: 144
irq_domain_associate_many(domain, first_irq, first_hwirq, size);
return domain;
}
EXPORT_SYMBOL_GPL(irq_domain_add_legacy);
- return: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()
oirq_domain_add_legacy()가 한일
irq-gic.c::gic_init_bases()
- return: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()
// ARM10C 20141108
// gic_cnt: 0, -1, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset: 0,
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
void __init gic_init_bases(unsigned int gic_nr, int irq_start,
void __iomem *dist_base, void __iomem *cpu_base,
u32 percpu_offset, struct device_node *node)
{
...
// gic->domain: (&gic_data[0])->domain
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
// gic_irqs: 144, irq_base: 16, hwirq_base: 16, gic: &gic_data[0]
gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
hwirq_base, &gic_irq_domain_ops, gic);
// gic->domain:
if (WARN_ON(!gic->domain))
return;
if (gic_nr == 0) {
#ifdef CONFIG_SMP
// gic_raise_softirq:
set_smp_cross_call(gic_raise_softirq);
- call set_smp_cross_call()
- start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()
smp.c::set_smp_cross_call()
void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int))
{
if (!smp_cross_call)
smp_cross_call = fn;
}
enum ipi_msg_type {
IPI_WAKEUP,
IPI_TIMER,
IPI_RESCHEDULE,
IPI_CALL_FUNC,
IPI_CALL_FUNC_SINGLE,
IPI_CPU_STOP,
IPI_IRQ_WORK,
IPI_COMPLETION,
};
irq-gic.c::gic_init_bases()
- return: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()
// ARM10C 20141108
// gic_cnt: 0, -1, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset: 0,
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
void __init gic_init_bases(unsigned int gic_nr, int irq_start,
void __iomem *dist_base, void __iomem *cpu_base,
u32 percpu_offset, struct device_node *node)
{
...
// gic->domain: (&gic_data[0])->domain
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
// gic_irqs: 144, irq_base: 16, hwirq_base: 16, gic: &gic_data[0]
gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
hwirq_base, &gic_irq_domain_ops, gic);
// gic->domain:
if (WARN_ON(!gic->domain))
return;
if (gic_nr == 0) {
#ifdef CONFIG_SMP
// gic_raise_softirq:
set_smp_cross_call(gic_raise_softirq);
// smp_cross_call: gic_raise_softirq 함수 등록.
// fic_cpu_notifier:
register_cpu_notifier(&gic_cpu_notifier);
// registar_cpu_notifier() 한일
set_handle_irq(gic_handle_irq);
}
gic_chip.flags |= gic_arch_extn.flags;
gic_dist_init(gic);
gic_cpu_init(gic);
gic_pm_init(gic);
}
// ARM10C 20141122
static struct irq_chip gic_chip = {
.name = "GIC",
.irq_mask = gic_mask_irq,
.irq_unmask = gic_unmask_irq,
.irq_eoi = gic_eoi_irq,
.irq_set_type = gic_set_type,
.irq_retrigger = gic_retrigger,
#ifdef CONFIG_SMP // CONFIG_SMP=y
.irq_set_affinity = gic_set_affinity,
#endif
.irq_set_wake = gic_set_wake,
};
struct irq_chip gic_arch_extn = {
.irq_eoi = NULL,
.irq_mask = NULL,
.irq_unmask = NULL,
.irq_retrigger = NULL,
.irq_set_type = NULL,
.irq_set_wake = NULL,
};
irq-gic.c::gic_disc_init()
static void __init gic_dist_init(struct gic_chip_data *gic)
{
unsigned int i;
u32 cpumask;
// gic->gic_irqs: (&gic_data[0]->gis_irqs: 160
unsigned int gic_irqs = gic->gic_irqs;
// gic_irqs: 160
// gic: &gic_data[0]
void __iomem *base = gic_data_dist_base(gic);
- call: void __iomem *base = gic_data_dist_base(gic);
gic_data_dist_base()
irq-gic.c::gic_disc_init()
static void __init gic_dist_init(struct gic_chip_data *gic)
{
unsigned int i;
u32 cpumask;
// gic->gic_irqs: (&gic_data[0]->gis_irqs: 160
unsigned int gic_irqs = gic->gic_irqs;
// gic_irqs: 160
// gic: &gic_data[0]
void __iomem *base = gic_data_dist_base(gic);
// GIC_DIST_CTRL: 0
writel_relaxed(0, base + GIC_DIST_CTRL);
## irq-gic.c::gic_disc_init()
```c
static void __init gic_dist_init(struct gic_chip_data *gic)
{
unsigned int i;
u32 cpumask;
...
// GIC_DIST_CTRL: 0
writel_relaxed(0, base + GIC_DIST_CTRL);
irq-gic.c::gic_disc_init()
static void __init gic_dist_init(struct gic_chip_data *gic)
{
unsigned int i;
u32 cpumask;
...
// GIC_DIST_CTRL: 0
writel_relaxed(0, base + GIC_DIST_CTRL);
// GIC_DIST_CTRL: 0(reset value)로 초기화
/*
* Set all global interrupts to be level triggered, active low.
*/
// gic_irqs: 160
for (i = 32; i < gic_irqs; i += 16)
// i:32, base: 0xf0000000, GIC_DIST_CONFIG: 0xc00
// i: 32 * 4 / 16
writel_relaxed(0, base + GIC_DIST_CONFIG + i * 4 / 16);
// 0xf00000c08: Iterrupt Contfiguation Register
// 0xc08 ~ 0xc24 (32)까지 레지스터 설정
// register GICD_ICFGR2의 값을 0으로 초기화
// SGI: Softwared Generated Interrupts
// PPI: Private Peripheral Interrupts
// SPI: Shared Peripheral Interrupts
// GICD_ICFGR2 ~ GICD_IRFGR9까지의 값을 0으로 초기화
/*
* Set all global interrupts to this CPU only.
*/
cpumask = gic_get_cpumask(gic);
irq-gic.c::gic_get_cpumask()
static u8 gic_get_cpumask(struct gic_chip_data *gic)
{
void __iomem *base = gic_data_dist_base(gic);
// base: 0xf0000000
u32 mask, i;
// GIC_DIST_TARGET: 0x800
for (i = mask = 0; i < 32; i += 4) {
// base: 0xf0000000, GIC_DIST_TARGET: 0x800, i:0
// readl_relaxed(0xf0000800) : 0x01010101 (reset값)
mask = readl_relaxed(base + GIC_DIST_TARGET + i);
// mask: 0x0101 0101
mask |= mask >> 16;
// mask: 0x0101 0101
mask |= mask >> 8;
// mask: 0x0101 0101
if (mask)
break;
}
if (!mask)
pr_crit("GIC CPU mask not found - kernel will fail to boot.\n");
return mask;
}
irq-gic.c::gic_disc_init()
static void __init gic_dist_init(struct gic_chip_data *gic)
{
unsigned int i;
u32 cpumask;
...
cpumask = gic_get_cpumask(gic);
// cpumask: 0x0101 0101
cpumask |= cpumask << 8;
cpumask |= cpumask << 16;
// cpu0으로 모든 irq를 할당해 놓는다.
for (i = 32; i < gic_irqs; i += 4)
// i: 0x820: Processor target register SPI[3:0] ... 8 ~ 39까지
// 0x01010101 로 모두 cpu0으로 할당한다.
writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
// register: GIC_ITARGETSR8 값을 0x01010101 로 모두 cpu0으로 할당한다.
// i:32... 156까지 수행
/*
* Set priority on all global interrupts.
*/
for (i = 32; i < gic_irqs; i += 4)
writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);
/*
* Disable all interrupts. Leave the PPI and SGIs alone
* as these enables are banked registers.
*/
for (i = 32; i < gic_irqs; i += 32)
writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);
writel_relaxed(1, base + GIC_DIST_CTRL);
}
irq-gic.c::gic_disc_init()
static void __init gic_dist_init(struct gic_chip_data *gic)
{
unsigned int i;
u32 cpumask;
...
// gic_irqs: 160
for (i = 32; i < gic_irqs; i += 4)
// GIC_DIST_TARGET: 0x800, i: 32
writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
## irq-gic.c::gic_init_bases()
* return: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()
```c
// ARM10C 20141108
// gic_cnt: 0, -1, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset: 0,
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
void __init gic_init_bases(unsigned int gic_nr, int irq_start,
void __iomem *dist_base, void __iomem *cpu_base,
u32 percpu_offset, struct device_node *node)
{
...
gic_chip.flags |= gic_arch_extn.flags;
gic_dist_init(gic);
gic_cpu_init(gic);
irq-gic.c::gic_init_bases()
- return: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()
// ARM10C 20141108
// gic_cnt: 0, -1, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset: 0,
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
void __init gic_init_bases(unsigned int gic_nr, int irq_start,
void __iomem *dist_base, void __iomem *cpu_base,
u32 percpu_offset, struct device_node *node)
{
...
gic_chip.flags |= gic_arch_extn.flags;
gic_dist_init(gic);
// gic: &gic_data[0]
gic_cpu_init(gic);
irq-gic.c::gic_get_cpumask()
static void gic_cpu_init(struct gic_chip_data *gic)
{
// gic: &gic_data[0]
void __iomem *dist_base = gic_data_dist_base(gic);
// *dist_base: 0xf0000000
// gic: &gic_data[0]
void __iomem *base = gic_data_cpu_base(gic);
unsigned int cpu_mask, cpu = smp_processor_id();
// NR_GIC_CPU_IF: 8
BUG_ON(cpu >= NR_GIC_CPU_IF);
// gic: &gic_data[0]
cpu_mask = gic_get_cpumask(gic);
// cpu_mask: 0x01010101
gic_cpu_map[cpu] = cpu_mask;
// gic_cpu_map[0]: 0x01
// NR_GIC_CPU_IF: 8
for (i = 0; i < NR_GIC_CPU_IF; i++)
// cpu: 0
if (i != cpu)
gic_cpu_map[i] &= ~cpu_mask;
// gic_cpu_map[1]: 0
// ...
// gic_cpu_map[7]: 0
// GIC_DIST_ENABLE_CLEAR: 0x180
writel_relaxed(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
// register GICD_ICENABLER0: 0xffff0000
// 0xffff0000 0~15bit는 SGI, 16~31: PPI를 en/disable함
// PPI[16:31]: disable 0xffffxxxx,
// GIC_DIST_ENABLE_SET: 0x100
writel_relaxed(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
// registar: GICD_ISENABLER0 값을 0x0000ffff로 설정
// 0x0000ffff 0~15bit는 SGI, 16~31: PPI를 en/disable함
// SPI[15:0] : enable 0xxxxxffff
for (i = 0; i < 32; i += 4)
//
writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
// i: 4...28까지 실행
// register GICD_IPRIORITY1~8 값을 0xa0a0a0a0로 설정
// base: 0xf0002000, GIC_CPU_PRIMASK: 0x4
writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
// register: GICC_PMR을 0xf0로 설정(240이상 priority만 허용)
// Provides an interrupt priority filter.
// Only interrupts with higher priority than the value in this register
// are signaled to the processor.
// base: 0xf0002000, GIC_CPU_CTRL: 0x0
writel_relaxed(1, base + GIC_CPU_CTRL);
// register: GICC_CTLR 값을 1로 설정
// 1의 값의 의미: cpu에 전달되는 인터럽트를 enable함.
}
static inline void __iomem *gic_data_cpu_base(struct gic_chip_data *data)
{
return data->get_base(&data->cpu_base);
}
static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly;
// gic_cpu_map[8]
irq-gic.c::gic_init_bases()
- return: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()
// ARM10C 20141108
// gic_cnt: 0, -1, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset: 0,
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
void __init gic_init_bases(unsigned int gic_nr, int irq_start,
void __iomem *dist_base, void __iomem *cpu_base,
u32 percpu_offset, struct device_node *node)
{
...
gic_chip.flags |= gic_arch_extn.flags;
gic_dist_init(gic);
// gic: &gic_data[0]
gic_cpu_init(gic);
// gic: &gic_data[0]
gic_pm_init(gic);
}
irq-gic.c::gic_pm_init
static void __init gic_pm_init(struct gic_chip_data *gic)
{
// gic->saved_ppi_enable: (&gic_data[0])->saved_ppi_enable:
gic->saved_ppi_enable = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4,
sizeof(u32));
// gic->saved_ppi_enable: (&gic_data[0])->saved_ppi_enable: 4
// __alloc_percpu(4,4): 의미
// kmem_cache#26-oX: 512할당받은 slut에서 4Bx 4개만 할당받은 주소
BUG_ON(!gic->saved_ppi_enable);
// gic->saved_ppi_conf: (&gic_data[0]->saved_ppi_conf
// DIV_ROUND_UP (32,16): 2
gic->saved_ppi_conf = __alloc_percpu(DIV_ROUND_UP(32, 16) * 4,
sizeof(u32));
// gic->saved_ppi_conf :
// kmem_cache#26-oX: 512할당받은 slut에서 8B 할당받은 주소
BUG_ON(!gic->saved_ppi_conf);
if (gic == &gic_data[0])
cpu_pm_register_notifier(&gic_notifier_block);
}
static struct notifier_block gic_notifier_block = {
.notifier_call = gic_notifier,
};
cpu_pm.c::cpu_pm_register_notifier()
int cpu_pm_register_notifier(struct notifier_block *nb)
{
unsigned long flags;
int ret;
//
write_lock_irqsave(&cpu_pm_notifier_lock, flags);
// cpu_pm_notifier_lock을 이용한 lock설정후 cpsr 저장
// nb: &gic_notifier_block
ret = raw_notifier_chain_register(&cpu_pm_notifier_chain, nb);
// raw_notifier_chain_register에서 한일
// (&cpu_pm_notifier_chain)->head: &gic_notifier_block
write_unlock_irqrestore(&cpu_pm_notifier_lock, flags);
// cpu_pm_notifier_lock을 이용한 cpsr 복원
return ret;
}
EXPORT_SYMBOL_GPL(cpu_pm_register_notifier);
irq_gic.c::gic_of_init()
- call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()
- ret = irq_init_cb(desc->dev, desc->interrupt_parent);
- // __irqchip_begin: irqchip_of_match_exynos4210_combiner
- // irq_init_cb = (of_irq_init_cb_t)match->data;
- 여기서 irq_init_cb: gic_of_init 로 되어 gic_of_init()를 실행한다.
// ARM10C 20141018
// desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL
int __init gic_of_init(struct device_node *node, struct device_node *parent)
{
...
// gic_cnt: 0, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset: 0,
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);
// gic_cnt: 0
if (!gic_cnt)
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
gic_init_physaddr(node);
// null function
// parent
if (parent) {
irq = irq_of_parse_and_map(node, 0);
gic_cascade_irq(gic_cnt, irq);
}
gic_cnt++;
// gic_cnt: 1
return 0;
}
irq-gic.c::gic_init_physaddr()
void __init gic_init_physaddr(struct device_node *node)
{
struct resource res;
if (of_address_to_resource(node, 0, &res) == 0) {
gic_dist_physaddr = res.start;
pr_info("GIC physical location is %#lx\n", gic_dist_physaddr);
}
}
irqchip.h::irqchip_init()
- called: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()
- of_irq_init(__irqchip_begin);
- // __irqchip_begin: irqchip_of_match_exynos4210_combiner
void __init of_irq_init(const struct of_device_id *matches)
{
...
// list_empty(&intc_desc_list): 0
while (!list_empty(&intc_desc_list)) {
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)
// desc: kmem_cache#30-o11 (cortex_a15_gic), temp_desc: NULL
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: gic node 주소, parent: NULL
// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL, parent: NULL
if (desc->interrupt_parent != parent)
continue;
// continue 수행 (exynos4210_combiner)
// &desc->list: (kmem_cache#30-o11)->list
list_del(&desc->list);
// intc_desc_list에서 (kmem_cache#30-o11)->list를 삭제
// matches: irqchip_of_match_cortex_a15_gic,
// desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
// of_match_node(cortex_a15_gic, devtree에서 allnext로 순회 하면서 찾은 gic node의 주소):
// irqchip_of_match_cortex_a15_gic
match = of_match_node(matches, desc->dev);
// match: irqchip_of_match_cortex_a15_gic
// match->data; irqchip_of_match_cortex_a15_gic.data: gic_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_cortex_a15_gic.compatible: "arm,cortex-a15-gic",
// desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
// desc->interrupt_parent: (kmem_cache#30-o11)->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 arm,cortex-a15-gic @ 0x(gic node의 주소), parent 0\n"
// match->data; irqchip_of_match_cortex_a15_gic.data: gic_of_init
irq_init_cb = (of_irq_init_cb_t)match->data;
// irq_init_cb: gic_of_init
// desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL
// gic_of_init(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, NULL):
ret = irq_init_cb(desc->dev, desc->interrupt_parent);
// ret: 0
if (ret) {
kfree(desc);
continue;
}
// &desc->list: (kmem_cache#30-o11)->list
list_add_tail(&desc->list, &intc_parent_list);
// &initc_parent_list에 (kmem_cache#30-o11)->list를 연결
}
// desc: NULL, intc_parrent_list: NULL로 loop 탈출
// list_first_entry_or_null()
// sizeof(struct desc): 16Byte
//
desc = list_first_entry_or_null(&intc_parent_list,
typeof(*desc), list);
// #define list_first_entry_or_null(ptr, type, member) \
// (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL)
//
// desc: kmem_cache#30_o11(cortex_a15_gic)
if (!desc) {
pr_err("of_irq_init: children remain, but no parents\n");
break;
}
list_del(&desc->list);
// &(kmem_cache#30-o11) (cortect_a15_gic)->list에 연결된 자료구조 삭제
// desc->dev: &(kmem_cache#30-o11) (cortect_a15_gic)->dev
parent = desc->dev;
// parrent: &(kmem_cache#30-o11) (cortect_a15_gic)->dev
kfree(desc);
}
slub.c::kfree()
void kfree(const void *x)
{
struct page *page;
void *object = (void *)x;
// object: kmem_cache#30-o11
trace_kfree(_RET_IP_, x);
// x: kmem_cache#30-o11
if (unlikely(ZERO_OR_NULL_PTR(x)))
return;
// unlikely(kmem_cache#30-o11): false
// x: kmem_cache#30-o11
// virt_to_head_page(kmem_cache#30-o11): kmem_cache#30-o11의 page주소
page = virt_to_head_page(x);
if (unlikely(!PageSlab(page))) {
BUG_ON(!PageCompound(page));
kfree_hook(x);
__free_memcg_kmem_pages(page, compound_order(page));
return;
}
slab_free(page->slab_cache, page, object, _RET_IP_);
}
EXPORT_SYMBOL(kfree);
static inline struct page *virt_to_head_page(const void *x)
{
struct page *page = virt_to_page(x);
return compound_head(page);
}
#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
log
1cccb59..8041c56 master -> origin/master
Updating 1cccb59..8041c56
Fast-forward
Reference/IHI0048B_b_gic_architecture_specification.pdf | Bin 0 -> 1245215 bytes
arch/arm/include/asm/exception.h | 3 +++
arch/arm/include/asm/io.h | 2 ++
arch/arm/include/asm/irq.h | 3 ++-
arch/arm/kernel/entry-armv.S | 1 +
arch/arm/kernel/irq.c | 7 ++++-
arch/arm/kernel/smp.c | 6 +++++
drivers/irqchip/irq-gic.c | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
include/linux/cpu.h | 1 +
include/linux/irq.h | 1 +
include/linux/irqchip/arm-gic.h | 10 ++++++++
kernel/cpu.c | 7 +++++
kernel/irq/irqdomain.c | 38 ++++++++++++++++++++++++++++
kernel/notifier.c | 6 +++++
14 files changed, 239 insertions(+), 5 deletions(-)
create mode 100644 Reference/IHI0048B_b_gic_architecture_specification.pdf
8041c56..db8a459 master -> origin/master
Updating 8041c56..db8a459
Fast-forward
arch/arm/include/asm/memory.h | 2 +
drivers/irqchip/irq-gic.c | 267 +++++++++++++++++++++++++++++++++++++++-
drivers/of/irq.c | 257 +++++++++++++++++++++++++++++++++++++-
include/linux/cpu_pm.h | 2 +-
include/linux/irqchip/arm-gic.h | 6 +
include/linux/kernel.h | 2 +
include/linux/list.h | 3 +
include/linux/mm.h | 13 ++
include/linux/mm_types.h | 1 +
include/linux/notifier.h | 1 +
include/linux/page-flags.h | 6 +
include/linux/slab.h | 2 +
include/linux/smp.h | 1 +
include/trace/events/kmem.h | 2 +
kernel/cpu_pm.c | 12 ++
kernel/notifier.c | 5 +
mm/percpu.c | 2 +
mm/slub.c | 16 +++
18 files changed, 594 insertions(+), 6 deletions(-)