ARM10C 79주차 후기
일시 : 2014.11.22 (79주차)
모임명 : NAVER개발자커뮤니티지원_IAMROOT.ORG_10차ARM-C
장소 : 토즈 타워점
장소지원 : NAVER 개발자 커뮤니티 지원 프로그램
참여인원 : 3명
진도
- init_IRQ()->...->gic_of_init()->gic_init_bases()을 계속 분석합니다.
- init_IRQ()->...->gic_of_init()->gic_init_bases()->irq_alloc_descs();
- irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id());
- // irq_base: 16
- spinlock 과 mutex 차이
- link
- In theory, when a thread tries to lock a mutex and it does not succeed,
- because the mutex is already locked,
- it will go to sleep, immediately allowing another thread to run.
- It will continue to sleep until being woken up,
- which will be the case once the mutex is being unlocked
- by whatever thread was holding the lock before.
- When a thread tries to lock a spinlock and it does not succeed,
- it will continuously re-try locking it,
- until it finally succeeds;
- thus it will not allow another thread to take its place
- (however, the operating system will forcefully switch to another thread,
- once the CPU runtime quantum of the current thread has been exceeded, of course).
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으로 이관
...
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()
- 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_init();
irqchip.h::irqchip_init()
- called: start_kernel()->init_IRQ()->irqchip_init()
- 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()
- of_irq_init(__irqchip_begin);
- //__irqchip_begin: irqchip_of_match_exynos4210_combiner
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)
{
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()
- 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()를 실행한다.
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)
{
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
// 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
// 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: * call: 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);
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)
{
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
if (percpu_offset) { /* Frankein-GIC without banked registers... */
unsigned int cpu;
gic->dist_base.percpu_base = alloc_percpu(void __iomem *);
gic->cpu_base.percpu_base = alloc_percpu(void __iomem *);
if (WARN_ON(!gic->dist_base.percpu_base ||
!gic->cpu_base.percpu_base)) {
free_percpu(gic->dist_base.percpu_base);
free_percpu(gic->cpu_base.percpu_base);
return;
}
for_each_possible_cpu(cpu) {
unsigned long offset = percpu_offset * cpu_logical_map(cpu);
*per_cpu_ptr(gic->dist_base.percpu_base, cpu) = dist_base + offset;
*per_cpu_ptr(gic->cpu_base.percpu_base, cpu) = cpu_base + offset;
}
gic_set_base_accessor(gic, gic_get_percpu_base);
} else
#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
// 2014/11/08 종료
// 2014/11/15 시작
// 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());
// irq_base: 16
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->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());
// irq_base: 16
// irq_base: 16, IS_ERR_VALUE(16): 0
if (IS_ERR_VALUE(irq_base)) {
WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
irq_start);
irq_base = irq_start;
}
// 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;
// of_node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
// first_hwirq: 16, size: 144, ops: &gic_irq_domain_ops, host_data: &gic_data[0]
// __irq_domain_add(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, 160, 160, 0,
// &gic_irq_domain_ops, &gic_data[0]): kmem_cache#25-o0
domain = __irq_domain_add(of_node, first_hwirq + size,
first_hwirq + size, 0, ops, host_data);
- 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_add()
- domain = __irq_domain_add(of_node, first_hwirq + size, first_hwirq + size, 0, ops, host_data);
irqdomain.c::__irq_domain_add()
- 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_add()
- domain = __irq_domain_add(of_node, first_hwirq + size, first_hwirq + size, 0, ops, host_data);
// ARM10C 20141122
// of_node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
// 160, 160, 0, ops: &gic_irq_domain_ops, host_data: &gic_data[0]
struct irq_domain *__irq_domain_add(struct device_node *of_node, int size,
irq_hw_number_t hwirq_max, int direct_max,
const struct irq_domain_ops *ops,
void *host_data)
{
struct irq_domain *domain;
// sizeof(struct irq_domain): 52, sizeof(unsigned int): 4, size: 160, GFP_KERNEL: 0xD0
// of_node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
// of_node_to_nid(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소): 0
// kzalloc_node(692, GFP_KERNEL: 0xD0, 0): kmem_cache#25-o0
domain = kzalloc_node(sizeof(*domain) + (sizeof(unsigned int) * size),
GFP_KERNEL, of_node_to_nid(of_node));
// domain: kmem_cache#25-o0
// domain: kmem_cache#25-o0
if (WARN_ON(!domain))
return NULL;
/* Fill structure */
// &domain->revmap_tree: &(kmem_cache#25-o0)->revmap_tree, GFP_KERNEL: 0xD0
INIT_RADIX_TREE(&domain->revmap_tree, GFP_KERNEL);
// INIT_RADIX_TREE(&(kmem_cache#25-o0)->revmap_tree, GFP_KERNEL: 0xD0):
// do {
// (&(kmem_cache#25-o0)->revmap_tree)->height = 0;
// (&(kmem_cache#25-o0)->revmap_tree)->gfp_mask = (GFP_KERNEL: 0xD0);
// (&(kmem_cache#25-o0)->revmap_tree)->rnode = NULL;
// } while (0)
// domain->ops: (kmem_cache#25-o0)->ops, ops: &gic_irq_domain_ops
domain->ops = ops;
// domain->ops: (kmem_cache#25-o0)->ops: &gic_irq_domain_ops
// domain->host_data: (kmem_cache#25-o0)->host_data, host_data: &gic_data[0]
domain->host_data = host_data;
// domain->host_data: (kmem_cache#25-o0)->host_data: &gic_data[0]
// domain->of_node: (kmem_cache#25-o0)->of_node,
// of_node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
// of_node_get(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소):
// devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
domain->of_node = of_node_get(of_node);
// domain->of_node: (kmem_cache#25-o0)->of_node:
// devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
// domain->hwirq_max: (kmem_cache#25-o0)->hwirq_max, hwirq_max: 160
domain->hwirq_max = hwirq_max;
// domain->hwirq_max: (kmem_cache#25-o0)->hwirq_max: 160
// domain->revmap_size: (kmem_cache#25-o0)->revmap_size, size: 160
domain->revmap_size = size;
// domain->revmap_size: (kmem_cache#25-o0)->revmap_size: 160
// domain->revmap_direct_max_irq: (kmem_cache#25-o0)->revmap_direct_max_irq, direct_max: 0
domain->revmap_direct_max_irq = direct_max;
// domain->revmap_direct_max_irq: (kmem_cache#25-o0)->revmap_direct_max_irq: 0
mutex_lock(&irq_domain_mutex);
// irq_domain_mutex을 사용한 mutex lock 설정
// domain->link: (kmem_cache#25-o0)->link
list_add(&domain->link, &irq_domain_list);
// irq_domain_list에 (kmem_cache#25-o0)->link를 추가
mutex_unlock(&irq_domain_mutex);
// irq_domain_mutex을 사용한 mutex lock 해재
// domain->name: (kmem_cache#25-o0)->name: NULL
pr_debug("Added domain %s\n", domain->name);
// domain: kmem_cache#25-o0
return domain;
// return kmem_cache#25-o0
}
EXPORT_SYMBOL_GPL(__irq_domain_add);
- 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_add()
- domain = __irq_domain_add(of_node, first_hwirq + size, first_hwirq + size, 0, ops, host_data);
- return domain: (kmem_cache#25-o0)
__irq_domain_add()에서 한일:
// (&(kmem_cache#25-o0)->revmap_tree)->height = 0; // (&(kmem_cache#25-o0)->revmap_tree)->gfp_mask = (GFP_KERNEL: 0xD0); // (&(kmem_cache#25-o0)->revmap_tree)->rnode = NULL; // (kmem_cache#25-o0)->ops: &gic_irq_domain_ops // (kmem_cache#25-o0)->host_data: &gic_data[0] // (kmem_cache#25-o0)->of_node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소 // (kmem_cache#25-o0)->hwirq_max: 160 // (kmem_cache#25-o0)->revmap_size: 160 // (kmem_cache#25-o0)->revmap_direct_max_irq: 0 // // irq_domain_list에 (kmem_cache#25-o0)->link를 추가
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()->__irq_domain_add()
- domain = __irq_domain_add(of_node, first_hwirq + size, first_hwirq + size, 0, ops, host_data);
- return domain: (kmem_cache#25-o0)
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;
// of_node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
// first_hwirq: 16, size: 144, ops: &gic_irq_domain_ops, host_data: &gic_data[0]
// __irq_domain_add(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, 160, 160, 0,
// &gic_irq_domain_ops, &gic_data[0]): kmem_cache#25-o0
domain = __irq_domain_add(of_node, first_hwirq + size,
first_hwirq + size, 0, ops, host_data);
// domain: kmem_cache#25-o0
// domain: kmem_cache#25-o0
if (WARN_ON(!domain))
return NULL;
// 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_associcate_many()
- // domain: kmem_cache#25-o0, first_irq: 16, first_hwirq: 16, size: 144
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_associcate_many()
- // domain: kmem_cache#25-o0, first_irq: 16, first_hwirq: 16, size: 144
// 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(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_associcate_many()->irq_domain_associate()
- // domain: kmem_cache#25-o0, irq_base: 16, i: 0, hwirq_base: 16
- for loop (i: 0~ 144)
- irq_domain_associate(domain, irq_base + i, hwirq_base + i);
irqdomain.c::irq_domain_associate()
- 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_associcate_many()->irq_domain_associate()
- // domain: kmem_cache#25-o0, irq_base: 16, i: 0, hwirq_base: 16
- for loop (i: 0~ 144)
- irq_domain_associate(domain, irq_base + i, hwirq_base + i);
// ARM10C 20141122
// domain: kmem_cache#25-o0, irq_base: 16, hwirq_base: 16
int irq_domain_associate(struct irq_domain *domain, unsigned int virq,
irq_hw_number_t hwirq)
{
// virq: 16, irq_get_irq_data(16): &(kmem_cache#28-oX (irq 16))->irq_data
struct irq_data *irq_data = irq_get_irq_data(virq);
// irq_data: &(kmem_cache#28-oX (irq 16))->irq_data
- 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_associcate_many()->irq_domain_associate()->irq_get_irq_data()
- // domain: kmem_cache#25-o0, irq_base: 16, i: 0, hwirq_base: 16
- for loop (i: 0~ 144)
- irq_domain_associate(domain, irq_base + i, hwirq_base + i);
- struct irq_data *irq_data = irq_get_irq_data(virq);
- // virq: 16~160까지
chip.c::irq_get_irq_data()
- 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_associcate_many()->irq_domain_associate()->irq_get_irq_data()
- // domain: kmem_cache#25-o0, irq_base: 16, i: 0, hwirq_base: 16
- for loop (i: 0~ 144)
- irq_domain_associate(domain, irq_base + i, hwirq_base + i);
- struct irq_data *irq_data = irq_get_irq_data(virq);
- // virq: 16~160까지
// ARM10C 20141122
// virq: 16
struct irq_data *irq_get_irq_data(unsigned int irq)
{
// irq: 16, irq_to_desc(16): kmem_cache#28-oX (irq 16)
struct irq_desc *desc = irq_to_desc(irq);
// desc: kmem_cache#28-oX (irq 16)
// desc: kmem_cache#28-oX (irq 16)
// &desc->irq_data: &(kmem_cache#28-oX (irq 16))->irq_data
return desc ? &desc->irq_data : NULL;
// return &(kmem_cache#28-oX (irq 16))->irq_data
}
EXPORT_SYMBOL_GPL(irq_get_irq_data);
- 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_associcate_many()->irq_domain_associate()->irq_get_irq_data()->irq_to_desc()
- // domain: kmem_cache#25-o0, irq_base: 16, i: 0, hwirq_base: 16
- for loop (i: 0~ 144)
- irq_domain_associate(domain, irq_base + i, hwirq_base + i);
- struct irq_data *irq_data = irq_get_irq_data(virq);
- // virq: 16~160까지
irqdesc.c::irq_to_desc()
- 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_associcate_many()->irq_domain_associate()->irq_get_irq_data()->irq_to_desc()
- // domain: kmem_cache#25-o0, irq_base: 16, i: 0, hwirq_base: 16
- for loop (i: 0~ 144)
- irq_domain_associate(domain, irq_base + i, hwirq_base + i);
- struct irq_data *irq_data = irq_get_irq_data(virq);
- // virq: 16~160까지
- struct irq_desc *desc = irq_to_desc(irq);
- // irq: virq: 16~160까지
// ARM10C 20141122
// irq: 16
struct irq_desc *irq_to_desc(unsigned int irq)
{
// irq: 16, radix_tree_lookup(&irq_desc_tree, 16): kmem_cache#28-oX (irq 16)
return radix_tree_lookup(&irq_desc_tree, irq);
// return kmem_cache#28-oX (irq 16)
}
EXPORT_SYMBOL(irq_to_desc);
- 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_associcate_many()->irq_domain_associate()->irq_get_irq_data()->irq_to_desc()
- // domain: kmem_cache#25-o0, irq_base: 16, i: 0, hwirq_base: 16
- for loop (i: 0~ 144)
- irq_domain_associate(domain, irq_base + i, hwirq_base + i);
- struct irq_data *irq_data = irq_get_irq_data(virq);
- // virq: 16~160까지
- struct irq_desc *desc = irq_to_desc(irq);
- // irq: virq: 16~160까지
- // irq: 16, radix_tree_lookup(&irq_desc_tree, 16): kmem_cache#28-oX (irq 16)
- return radix_tree_lookup(&irq_desc_tree, irq);
radix-tree.c::radix_tree_lookup()
- 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_associcate_many()->irq_domain_associate()->irq_get_irq_data()->irq_to_desc()
- // domain: kmem_cache#25-o0, irq_base: 16, i: 0, hwirq_base: 16
- for loop (i: 0~ 144)
- irq_domain_associate(domain, irq_base + i, hwirq_base + i);
- struct irq_data *irq_data = irq_get_irq_data(virq);
- // virq: 16~160까지
- struct irq_desc *desc = irq_to_desc(irq);
- // irq: virq: 16~160까지
- // irq: 16, radix_tree_lookup(&irq_desc_tree, 16): kmem_cache#28-oX (irq 16)
- return radix_tree_lookup(&irq_desc_tree, irq);
// ARM10C 20141122
// &irq_desc_tree, irq: 16
void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index)
{
// root: &irq_desc_tree, index: 16
// radix_tree_lookup_element(&irq_desc_tree, 16, 0): kmem_cache#28-oX (irq 16)
return radix_tree_lookup_element(root, index, 0);
// return kmem_cache#28-oX (irq 16)
}
EXPORT_SYMBOL(radix_tree_lookup);
- 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_associcate_many()->irq_domain_associate()->irq_get_irq_data()->irq_to_desc()
- // domain: kmem_cache#25-o0, irq_base: 16, i: 0, hwirq_base: 16
- for loop (i: 0~ 144)
- irq_domain_associate(domain, irq_base + i, hwirq_base + i);
- struct irq_data *irq_data = irq_get_irq_data(virq);
- // virq: 16~160까지
- struct irq_desc *desc = irq_to_desc(irq);
- // irq: virq: 16~160까지
- // irq: 16, radix_tree_lookup(&irq_desc_tree, 16): kmem_cache#28-oX (irq 16)
- return radix_tree_lookup(&irq_desc_tree, irq);
- // root: &irq_desc_tree, index: 16
- // radix_tree_lookup_element(&irq_desc_tree, 16, 0): kmem_cache#28-oX (irq 16)
- return radix_tree_lookup_element(root, index, 0);
radix-tree.c::radix_tree_lookup_element()
- 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_associcate_many()->irq_domain_associate()->irq_get_irq_data()->irq_to_desc()
- // domain: kmem_cache#25-o0, irq_base: 16, i: 0, hwirq_base: 16
- for loop (i: 0~ 144)
- irq_domain_associate(domain, irq_base + i, hwirq_base + i);
- struct irq_data *irq_data = irq_get_irq_data(virq);
- // virq: 16~160까지
- struct irq_desc *desc = irq_to_desc(irq);
- // irq: virq: 16~160까지
- // irq: 16, radix_tree_lookup(&irq_desc_tree, 16): kmem_cache#28-oX (irq 16)
- return radix_tree_lookup(&irq_desc_tree, irq);
- // root: &irq_desc_tree, index: 16
- // radix_tree_lookup_element(&irq_desc_tree, 16, 0): kmem_cache#28-oX (irq 16)
- return radix_tree_lookup_element(root, index, 0);
// ARM10C 20141122
// root: &irq_desc_tree, index: 16, 0
static void *radix_tree_lookup_element(struct radix_tree_root *root,
unsigned long index, int is_slot)
{
unsigned int height, shift;
struct radix_tree_node *node, **slot;
// root->rnode: (&irq_desc_tree)->rnode: kmem_cache#20-o1 (RADIX_LSB: 1)
// rcu_dereference_raw((&irq_desc_tree)->rnode): kmem_cache#20-o1 (RADIX_LSB: 1)
node = rcu_dereference_raw(root->rnode);
- call: radic_tree_lookup_element()->rcu_dereference_raw()
rcpudata.h::rcu_dereference_raw()
- called: radic_tree_lookup_element()->rcu_dereference_raw()
// ARM10C 20141122
// root->rnode: (&irq_desc_tree)->rnode: kmem_cache#20-o1 (RADIX_LSB: 1)
#define rcu_dereference_raw(p) rcu_dereference_check(p, 1) /*@@@ needed? @@@*/
- call: radic_tree_lookup_element()->rcu_dereference_raw()->rcu_dereference_check()
rcupdate.h::rcu_dereference_check()
- called: radic_tree_lookup_element()->rcu_dereference_raw()->rcu_dereference_check()
#define rcu_dereference_check(p, c) \
__rcu_dereference_check((p), rcu_read_lock_held() || (c), __rcu)
- call: radic_tree_lookup_element()->rcu_dereference_raw()->rcu_dereference_check()->__rcu_dereference_check()
rcupdate.h::__rcu_dereference_check()
- called: radic_tree_lookup_element()->rcu_dereference_raw()->rcu_dereference_check()->__rcu_dereference_check()
#define __rcu_dereference_check(p, c, space) \
({ \
typeof(*p) *_________p1 = (typeof(*p)*__force )ACCESS_ONCE(p); \
rcu_lockdep_assert(c, "suspicious rcu_dereference_check()" \
" usage"); \
rcu_dereference_sparse(p, space); \
smp_read_barrier_depends(); \
((typeof(*p) __force __kernel *)(_________p1)); \
})
- 정리하면
// #define __rcu_dereference_check((&irq_desc_tree)->rnode, c, __rcu):
// ({
// typeof(*(&irq_desc_tree)->rnode) *_________p1 = (typeof(*(&irq_desc_tree)->rnode)*__force )ACCESS_ONCE((&irq_desc_tree)->rnode);
// rcu_lockdep_assert(1, "suspicious rcu_dereference_check()" " usage"); // null function
// rcu_dereference_sparse((&irq_desc_tree)->rnode, __rcu); // null function
// smp_read_barrier_depends(); // null function
// ((typeof(*(&irq_desc_tree)->rnode) __force __kernel *)(_________p1));
// })
- call: radic_tree_lookup_element()->rcu_dereference_raw()->rcu_dereference_check()->__rcu_dereference_check()->rcu_lockdep_assert()
rcupdate.h::rcu_lockdep_asset()
- called: radic_tree_lookup_element()->rcu_dereference_raw()->rcu_dereference_check()->__rcu_dereference_check()->rcu_lockdep_assert()
// ARM10C 20141122
#define rcu_lockdep_assert(c, s) do { } while (0)
- return: radic_tree_lookup_element()->rcu_dereference_raw()->rcu_dereference_check()->__rcu_dereference_check()
rcupdate.h::__rcu_dereference_check()
- return: radic_tree_lookup_element()->rcu_dereference_raw()->rcu_dereference_check()->__rcu_dereference_check()
#define __rcu_dereference_check(p, c, space) \
({ \
typeof(*p) *_________p1 = (typeof(*p)*__force )ACCESS_ONCE(p); \
rcu_lockdep_assert(c, "suspicious rcu_dereference_check()" \
" usage"); \
rcu_dereference_sparse(p, space); \
smp_read_barrier_depends(); \
((typeof(*p) __force __kernel *)(_________p1)); \
})
- call: radic_tree_lookup_element()->rcu_dereference_raw()->rcu_dereference_check()->__rcu_dereference_check()->rcu_dereference_sparse()
rcupdate.h::rcu_dereference_sparse()
- called: radic_tree_lookup_element()->rcu_dereference_raw()->rcu_dereference_check()->__rcu_dereference_check()->rcu_dereference_sparse()
// ARM10C 20141122
#define rcu_dereference_sparse(p, space)
#endif /* #else #ifdef __CHECKER__ */
- null function
- return: radic_tree_lookup_element()->rcu_dereference_raw()->rcu_dereference_check()->__rcu_dereference_check()->rcu_dereference_sparse()
rcupdate.h::__rcu_dereference_check()
- return: radic_tree_lookup_element()->rcu_dereference_raw()->rcu_dereference_check()->__rcu_dereference_check()->rcu_dereference_sparse()
#define __rcu_dereference_check(p, c, space) \
({ \
typeof(*p) *_________p1 = (typeof(*p)*__force )ACCESS_ONCE(p); \
rcu_lockdep_assert(c, "suspicious rcu_dereference_check()" \
" usage"); \
rcu_dereference_sparse(p, space); \
smp_read_barrier_depends(); \
((typeof(*p) __force __kernel *)(_________p1)); \
})
- call: radic_tree_lookup_element()->rcu_dereference_raw()->rcu_dereference_check()->__rcu_dereference_check()->smp_read_barrier_depends()
barrier.h::smp_read_barrier_depends()
- call: radic_tree_lookup_element()->rcu_dereference_raw()->rcu_dereference_check()->__rcu_dereference_check()->smp_read_barrier_depends()
// ARM10C 20141122
#define smp_read_barrier_depends() do { } while(0)
- null funtion
- return: radic_tree_lookup_element()->rcu_dereference_raw()->rcu_dereference_check()->__rcu_dereference_check()->smp_read_barrier_depends()
radix-tree.c::radix_tree_lookup_element()
- 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_associcate_many()->irq_domain_associate()->irq_get_irq_data()->irq_to_desc()
- // domain: kmem_cache#25-o0, irq_base: 16, i: 0, hwirq_base: 16
- for loop (i: 0~ 144)
- irq_domain_associate(domain, irq_base + i, hwirq_base + i);
- struct irq_data *irq_data = irq_get_irq_data(virq);
- // virq: 16~160까지
- struct irq_desc *desc = irq_to_desc(irq);
- // irq: virq: 16~160까지
- // irq: 16, radix_tree_lookup(&irq_desc_tree, 16): kmem_cache#28-oX (irq 16)
- return radix_tree_lookup(&irq_desc_tree, irq);
- // root: &irq_desc_tree, index: 16
- // radix_tree_lookup_element(&irq_desc_tree, 16, 0): kmem_cache#28-oX (irq 16)
- return radix_tree_lookup_element(root, index, 0);
// ARM10C 20141122
// root: &irq_desc_tree, index: 16, 0
static void *radix_tree_lookup_element(struct radix_tree_root *root,
unsigned long index, int is_slot)
{
unsigned int height, shift;
struct radix_tree_node *node, **slot;
// root->rnode: (&irq_desc_tree)->rnode: kmem_cache#20-o1 (RADIX_LSB: 1)
// rcu_dereference_raw((&irq_desc_tree)->rnode): kmem_cache#20-o1 (RADIX_LSB: 1)
node = rcu_dereference_raw(root->rnode);
// node: kmem_cache#20-o1 (RADIX_LSB: 1)
// node: kmem_cache#20-o1 (RADIX_LSB: 1)
if (node == NULL)
return NULL;
// node: kmem_cache#20-o1 (RADIX_LSB: 1)
// radix_tree_is_indirect_ptr(kmem_cache#20-o1 (RADIX_LSB: 1)): 1
if (!radix_tree_is_indirect_ptr(node)) {
if (index > 0)
return NULL;
return is_slot ? (void *)&root->rnode : node;
}
// node: kmem_cache#20-o1 (RADIX_LSB: 1)
// indirect_to_ptr(kmem_cache#20-o1 (RADIX_LSB: 1)): kmem_cache#20-o1 (RADIX_LSB: 0)
node = indirect_to_ptr(node);
// node: kmem_cache#20-o1 (RADIX_LSB: 0)
// node->height: (kmem_cache#20-o1)->height: 2
height = node->height;
// height: 2
// index: 16, height: 2, radix_tree_maxindex(2): 4095
if (index > radix_tree_maxindex(height))
return NULL;
// height: 2, RADIX_TREE_MAP_SHIFT: 6
shift = (height-1) * RADIX_TREE_MAP_SHIFT;
// shift: 6
rcupdate.h::rcu_dereference_raw()
#define rcu_dereference_raw(p) rcu_dereference_check(p, 1) /*@@@ needed? @@@*/
- 풀어쓰면
// ARM10C 20141122
// *slot: (kmem_cache#20-o1)->slots[0], 1, __rcu
//
// #define __rcu_dereference_check((kmem_cache#20-o1)->slots[0], 1, __rcu):
// ({
// typeof(*(kmem_cache#20-o1)->slots[0]) *_________p1 = (typeof(*(kmem_cache#20-o1)->slots[0])*__force )ACCESS_ONCE((kmem_cache#20-o1)->slots[0]);
// rcu_lockdep_assert(1, "suspicious rcu_dereference_check()" " usage");
// rcu_dereference_sparse((kmem_cache#20-o1)->slots[0], __rcu);
// smp_read_barrier_depends();
// ((typeof(*(kmem_cache#20-o1)->slots[0]) __force __kernel *)(_________p1));
// })
- return radix_tree_lookup_element()
- // kmem_cahe#20-o0
radix-tree.c::radix_tree_lookup_element()
- return: radix_tree_lookup_element()->rcu_dereference_raw()
static void *radix_tree_lookup_element(struct radix_tree_root *root,
unsigned long index, int is_slot)
{
...
do {
// node->slots: (kmem_cache#20-o1)->slots, index: 16, shift: 6, RADIX_TREE_MAP_MASK: 0x3f
slot = (struct radix_tree_node **)
(node->slots + ((index>>shift) & RADIX_TREE_MAP_MASK));
// slot: &(kmem_cache#20-o1)->slots[0]
// *slot: (kmem_cache#20-o1)->slots[0]
// rcu_dereference_raw((kmem_cache#20-o1)->slots[0]): kmem_cache#20-o0
node = rcu_dereference_raw(*slot);
// node: kmem_cache#20-o0
// node: kmem_cache#20-o0
if (node == NULL)
return NULL;
// shift: 6, RADIX_TREE_MAP_SHIFT: 6
shift -= RADIX_TREE_MAP_SHIFT;
// shift: 0
// height: 2
height--;
// height: 1
// height: 1
} while (height > 0);
- 2nd loop
static void *radix_tree_lookup_element(struct radix_tree_root *root,
unsigned long index, int is_slot)
{
...
do {
// node->slots: (kmem_cache#20-o1)->slots, index: 16, shift: 6, RADIX_TREE_MAP_MASK: 0x3f
// node->slots: (kmem_cache#20-o0)->slots, index: 16, shift: 0, RADIX_TREE_MAP_MASK: 0x3f
slot = (struct radix_tree_node **)
(node->slots + ((index>>shift) & RADIX_TREE_MAP_MASK));
// slot: &(kmem_cache#20-o1)->slots[0]
// slot: &(kmem_cache#20-o0)->slots[16]
// *slot: (kmem_cache#20-o1)->slots[0]
// rcu_dereference_raw((kmem_cache#20-o1)->slots[0]): kmem_cache#20-o0
// *slot: (kmem_cache#20-o0)->slots[16]
// rcu_dereference_raw((kmem_cache#20-o0)->slots[16]): kmem_cache#28-oX (irq 16)
node = rcu_dereference_raw(*slot);
// node: kmem_cache#20-o0
// node: kmem_cache#28-oX (irq 16)
// node: kmem_cache#20-o0
// node: kmem_cache#28-oX (irq 16)
if (node == NULL)
return NULL;
// shift: 6, RADIX_TREE_MAP_SHIFT: 6
// shift: 0, RADIX_TREE_MAP_SHIFT: 6
shift -= RADIX_TREE_MAP_SHIFT;
// shift: 0
// shift: 0xfffffffa
// height: 2
// height: 1
height--;
// height: 1
// height: 0
// height: 1
// height: 0
} while (height > 0);
// is_slot: 0
// node: kmem_cache#28-oX (irq: 16)
return is_slot ? (void *)slot : indirect_to_ptr(node);
// return indirect_to_ptr(node: kmem_cache#28-oX (irq: 16))
// return kmem_cache#28-oX (irq: 16)
}
- 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_associcate_many()->irq_domain_associate()->irq_get_irq_data()->irq_to_desc()
- // domain: kmem_cache#25-o0, irq_base: 16, i: 0, hwirq_base: 16
- for loop (i: 0~ 144)
- irq_domain_associate(domain, irq_base + i, hwirq_base + i);
- struct irq_data *irq_data = irq_get_irq_data(virq);
- // virq: 16~160까지
- struct irq_desc *desc = irq_to_desc(irq);
- // irq: virq: 16~160까지
- // irq: 16, radix_tree_lookup(&irq_desc_tree, 16): kmem_cache#28-oX (irq 16)
- return radix_tree_lookup(&irq_desc_tree, irq);
- // root: &irq_desc_tree, index: 16
- // radix_tree_lookup_element(&irq_desc_tree, 16, 0): kmem_cache#28-oX (irq 16)
- return radix_tree_lookup_element(root, index, 0);
chip.c::irq_get_irq_data()
- 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_associcate_many()->irq_domain_associate()->irq_get_irq_data()->irq_to_desc()
- // domain: kmem_cache#25-o0, irq_base: 16, i: 0, hwirq_base: 16
- for loop (i: 0~ 144)
- irq_domain_associate(domain, irq_base + i, hwirq_base + i);
- struct irq_data *irq_data = irq_get_irq_data(virq);
- // virq: 16~160까지
// ARM10C 20141122
// virq: 16
struct irq_data *irq_get_irq_data(unsigned int irq)
{
// irq: 16, irq_to_desc(16): kmem_cache#28-oX (irq 16)
struct irq_desc *desc = irq_to_desc(irq);
// desc: kmem_cache#28-oX (irq 16)
// desc: kmem_cache#28-oX (irq 16)
// &desc->irq_data: &(kmem_cache#28-oX (irq 16))->irq_data
return desc ? &desc->irq_data : NULL;
// return &(kmem_cache#28-oX (irq 16))->irq_data
}
EXPORT_SYMBOL_GPL(irq_get_irq_data);
- 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_associcate_many()->irq_domain_associate()->irq_get_irq_data()->irq_to_desc()
- // domain: kmem_cache#25-o0, irq_base: 16, i: 0, hwirq_base: 16
- for loop (i: 0~ 144)
- irq_domain_associate(domain, irq_base + i, hwirq_base + i);
- struct irq_data *irq_data = irq_get_irq_data(virq);
- // virq: 16~160까지
irqdomain.c::irq_domain_assoiciate()
- 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_associcate_many()->irq_domain_associate()->irq_get_irq_data()->irq_to_desc()
- // domain: kmem_cache#25-o0, irq_base: 16, i: 0, hwirq_base: 16
- for loop (i: 0~ 144)
- irq_domain_associate(domain, irq_base + i, hwirq_base + i);
// ARM10C 20141122
// domain: kmem_cache#25-o0, irq_base: 16, hwirq_base: 16
int irq_domain_associate(struct irq_domain *domain, unsigned int virq,
irq_hw_number_t hwirq)
{
// virq: 16, irq_get_irq_data(16): &(kmem_cache#28-oX (irq 16))->irq_data
struct irq_data *irq_data = irq_get_irq_data(virq);
// irq_data: &(kmem_cache#28-oX (irq 16))->irq_data
// irq_desc_alloc()에 연결되어 있던 radix-tree를 참조하여
// irq 16 (kmem_cache#28-oX)를 받아옴.
int ret;
// hwirq: 16, domain->hwirq_max: (kmem_cache#25-o0)->hwirq_max: 160
if (WARN(hwirq >= domain->hwirq_max,
"error: hwirq 0x%x is too large for %s\n", (int)hwirq, domain->name))
return -EINVAL;
// irq_data: &(kmem_cache#28-oX (irq 16))->irq_data, virq: 16
if (WARN(!irq_data, "error: virq%i is not allocated", virq))
return -EINVAL;
// irq_data->domain: (&(kmem_cache#28-oX (irq 16))->irq_data)->domain: NULL
if (WARN(irq_data->domain, "error: virq%i is already associated", virq))
return -EINVAL;
mutex_lock(&irq_domain_mutex);
// irq_domain_mutex을 사용한 mutex lock 설정
// irq_data->hwirq: (&(kmem_cache#28-oX (irq 16))->hwirq, hwirq: 16
irq_data->hwirq = hwirq;
// irq_data->hwirq: (&(kmem_cache#28-oX (irq 16))->hwirq: 16
// irq_data->domain: (&(kmem_cache#28-oX (irq 16))->domain , domain: NULL
irq_data->domain = domain;
// irq_data->domain: (&(kmem_cache#28-oX (irq 16))->domain: NULL
// domain->ops->map: (&(kmem_cache#25-o0->ops->map: gic_irq_domain_map
if (domain->ops->map) {
// domain->ops->map: (&(kmem_cache#25-o0->ops->map: gic_irq_domain_map
// domain: kmem_cache#25_o0, 16, 16
ret = domain->ops->map(domain, virq, hwirq);
- 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_associcate_many()->irq_domain_associate()
- // domain: kmem_cache#25-o0, irq_base: 16, i: 0, hwirq_base: 16
- for loop (i: 0~ 144)
- irq_domain_associate(domain, irq_base + i, hwirq_base + i);
- ret = domain->ops->map(domain, virq, hwirq);
- // domain->ops->map: (&(kmem_cache#25-o0->ops->map: gic_irq_domain_map
- // domain: kmem_cache#25_o0, 16, 16
irq-gic.c::gic_irq_domain_map()
- 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_associcate_many()->irq_domain_associate()
- // domain: kmem_cache#25-o0, irq_base: 16, i: 0, hwirq_base: 16
- for loop (i: 0~ 144)
- irq_domain_associate(domain, irq_base + i, hwirq_base + i);
- ret = domain->ops->map(domain, virq, hwirq);
- // domain->ops->map: (&(kmem_cache#25-o0->ops->map: gic_irq_domain_map
- // domain: kmem_cache#25_o0, 16~160, 16~160
// ARM10C 20141122
// kmem_cache#25-o0, 16, 16
static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw)
{
// hw: 16
if (hw < 32) {
irq_set_percpu_devid(irq);
irq_set_chip_and_handler(irq, &gic_chip,
handle_percpu_devid_irq);
set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
} else {
irq_set_chip_and_handler(irq, &gic_chip,
handle_fasteoi_irq);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
}
irq_set_chip_data(irq, d->host_data);
return 0;
}
- hw < 32이므로 두종류로 구분된다.
- 32이하는 handle_percpu_devid_irq
- 32이상은 handle_fasteoi_irq
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq);
- // kmem_cache#25-o0, 16~160, 16~160
irq-gic.c::irq_set_percpu_devid()
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq);
- // kmem_cache#25-o0, 16~31, 16~31
int irq_set_percpu_devid(unsigned int irq)
{
// irq: 16~31, irq_to_desc(): kmem_cache@28-oX (irq xx)
struct irq_desc *desc = irq_to_desc(irq);
// desc: kmem_cache#28-oX
// desc: kmem_cache#28-oX
if (!desc)
return -EINVAL;
// desc: (kmem_cache#28-oX)->percpu_enabled
if (desc->percpu_enabled)
return -EINVAL;
// desc: (kmem_cache#28-oX)->percpu_enabled, sizeof(*desc-percpu_enabled): 4
desc->percpu_enabled = kzalloc(sizeof(*desc->percpu_enabled), GFP_KERNEL);
// desc->percpu_enabled: (kmem_cache#30-oX)
if (!desc->percpu_enabled)
return -ENOMEM;
irq_set_percpu_devid_flags(irq);
return 0;
}
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()
- // irq: 16~31
irq.h::irq_set_percpu_devid_flags()
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()
- // irq: 16~31
static inline void irq_set_percpu_devid_flags(unsigned int irq)
{
irq_set_status_flags(irq,
IRQ_NOAUTOEN | IRQ_PER_CPU | IRQ_NOTHREAD |
IRQ_NOPROBE | IRQ_PER_CPU_DEVID);
}
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()
- // irq: 16~31
irq.h::irq_set_status_flags()
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()
- // irq: 16~31
static inline void irq_set_status_flags(unsigned int irq, unsigned long set)
{
irq_modify_status(irq, 0, set);
}
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()
- // irq: 16~31
chip.c::irq_modify_status()
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()
- // irq: 16~31
void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set)
{
unsigned long flags;
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()
- // irq: 16~31
internals.h::irq_get_desc_lock()
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irq_get_desc_lock()
- // irq: 16~31
static inline struct irq_desc *
irq_get_desc_lock(unsigned int irq, unsigned long *flags, unsigned int check)
{
return __irq_get_desc_lock(irq, flags, false, check);
}
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irq_get_desc_lock()->__irq_get_desc_lock()->__irq_get_desc_lock()
- // irq: 16~31
irqdesc.c::__irq_get_desc_lock()
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irq_get_desc_lock()->__irq_get_desc_lock()->__irq_get_desc_lock()
- // irq: 16~31
struct irq_desc *
__irq_get_desc_lock(unsigned int irq, unsigned long *flags, bool bus,
unsigned int check)
{
struct irq_desc *desc = irq_to_desc(irq);
// desc: ...
if (desc) {
// check: false
if (check & _IRQ_DESC_CHECK) {
if ((check & _IRQ_DESC_PERCPU) &&
!irq_settings_is_per_cpu_devid(desc))
return NULL;
if (!(check & _IRQ_DESC_PERCPU) &&
irq_settings_is_per_cpu_devid(desc))
return NULL;
}
// bus: false
if (bus)
chip_bus_lock(desc);
// &desc->lock: &(kmem_cahce#28-oX->lock, *flags: flags
raw_spin_lock_irqsave(&desc->lock, *flags);
// &(kmem_cache#28-oX)->lock를 사용하여 splin lock
}
return desc;
// desc:
}
- return: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irq_get_desc_lock()->__irq_get_desc_lock()->__irq_get_desc_lock()
- // irq: 16~31
chip.c::irq_modify_status()
- return: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irq_get_desc_lock()->__irq_get_desc_lock()->__irq_get_desc_lock()
- // irq: 16~31
void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set)
{
unsigned long flags;
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
if (!desc)
return;
irq_settings_clr_and_set(desc, clr, set);
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irq_settings_clr_and_set()
settings.h::irq_settings_clr_and_set()
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irq_settings_clr_and_set()
// ARM10C 20141004
// desc: kmem_cache#28-o0, 0xFFFFFFFF, _IRQ_DEFAULT_INIT_FLAGS: 0xc00
static inline void
irq_settings_clr_and_set(struct irq_desc *desc, u32 clr, u32 set)
{
// desc->status_use_accessors: (kmem_cache#28-o0)->status_use_accessors: 0
// clr: 0xFFFFFFFF, _IRQF_MODIFY_MASK: 0x3ff0f
desc->status_use_accessors &= ~(clr & _IRQF_MODIFY_MASK);
// desc->status_use_accessors: (kmem_cache#28-o0)->status_use_accessors: 0
// set: 0xc00, _IRQF_MODIFY_MASK: 0x3ff0f
desc->status_use_accessors |= (set & _IRQF_MODIFY_MASK);
// desc->status_use_accessors: (kmem_cache#28-o0)->status_use_accessors: 0xc00
}
- return: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irq_settings_clr_and_set()
chip.c::irq_modify_status()
- return: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irq_settings_clr_and_set()
- // irq: 16~31
void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set)
{
unsigned long flags;
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
if (!desc)
return;
irq_settings_clr_and_set(desc, clr, set);
// (kmem_cache#28-oX) (irq:xx)->status_use_acceassors: 0x31600
// IRQD_NO_BALANCING: 0x400, IRQD_PER_CPU: 0x800,
// IRQD_TRIGGER_MASK: 0xf, IRQD_LEVEL: 0x2000, IRQD_MOVE_PCNTXT: 0x8000
irqd_clear(&desc->irq_data, IRQD_NO_BALANCING | IRQD_PER_CPU |
IRQD_TRIGGER_MASK | IRQD_LEVEL | IRQD_MOVE_PCNTXT);
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irqd_clear()
internals.h::irqd_clear()
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irqd_clear()
static inline void irqd_clear(struct irq_data *d, unsigned int mask)
{
// (&kmem_cache#28-oX)->state_use_accessors): 0x10000
// mask: 0xac0f
d->state_use_accessors &= ~mask;
// (&kmem_cache#28-oX)->state_use_accessors): 0x10000
}
- return: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irqd_clear()
- return // (&kmem_cache#28-oX)->state_use_accessors): 0x10000
chip.c::irq_modify_status()
- return: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irqd_clear()
- return // (&kmem_cache#28-oX)->state_use_accessors): 0x10000
- // irq: 16~31
void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set)
{
unsigned long flags;
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
if (!desc)
return;
irq_settings_clr_and_set(desc, clr, set);
// (kmem_cache#28-oX) (irq:xx)->status_use_acceassors: 0x31600
//
irqd_clear(&desc->irq_data, IRQD_NO_BALANCING | IRQD_PER_CPU |
IRQD_TRIGGER_MASK | IRQD_LEVEL | IRQD_MOVE_PCNTXT);
static inline bool irq_settings_has_no_balance_set(struct irq_desc *desc)
{
return desc->status_use_accessors & _IRQ_NO_BALANCING;
}
static inline bool irq_settings_is_per_cpu(struct irq_desc *desc)
{
return desc->status_use_accessors & _IRQ_PER_CPU;
}
static inline bool irq_settings_can_move_pcntxt(struct irq_desc *desc)
{
return desc->status_use_accessors & _IRQ_MOVE_PCNTXT;
}
static inline bool irq_settings_is_level(struct irq_desc *desc)
{
return desc->status_use_accessors & _IRQ_LEVEL;
}
static inline void irqd_set(struct irq_data *d, unsigned int mask)
{
// d->state_use_accessors: (&(kmem_cache#28-o0)->irq_data)->state_use_accessors: 0, mask: 0x10000
d->state_use_accessors |= mask;
// d->state_use_accessors: (&(kmem_cache#28-o0)->irq_data)->state_use_accessors: 0x10000
}
//
if (irq_settings_has_no_balance_set(desc))
//
irqd_set(&desc->irq_data, IRQD_NO_BALANCING);
//
if (irq_settings_is_per_cpu(desc))
irqd_set(&desc->irq_data, IRQD_PER_CPU);
if (irq_settings_can_move_pcntxt(desc))
irqd_set(&desc->irq_data, IRQD_MOVE_PCNTXT);
if (irq_settings_is_level(desc))
irqd_set(&desc->irq_data, IRQD_LEVEL);
irqd_set(&desc->irq_data, irq_settings_get_trigger_mask(desc));
irq_put_desc_unlock(desc, flags);
}
EXPORT_SYMBOL_GPL(irq_modify_status);
- return: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irq_put_desc_unlock()
internal.h::irq_put_desc_unlock()
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irq_put_desc_unlock()
static inline void
irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags)
{
__irq_put_desc_unlock(desc, flags, false);
}
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irq_put_desc_unlock()->__irq_put_desc_unlock()
irqdesc.c::__irq_put_desc_unlock()
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irq_put_desc_unlock()->__irq_put_desc_unlock()
void __irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags, bool bus)
{
raw_spin_unlock_irqrestore(&desc->lock, flags);
if (bus)
chip_bus_sync_unlock(desc);
}
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irq_put_desc_unlock()->raw_spin_unlock_irqrestore()
spinlock.h::raw_spin_unloc_irqrestore()
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irq_put_desc_unlock()->raw_spin_unlock_irqrestore()
#define raw_spin_unlock_irqrestore(lock, flags) \
do { \
typecheck(unsigned long, flags); \
_raw_spin_unlock_irqrestore(lock, flags); \
} while (0)
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irq_put_desc_unlock()->raw_spin_unlock_irqrestore()->_raw_spin_unlock_irqrestore()->__raw_spin_unlock_irqrestore()
spinlock_api_smp.h::_raw_spin_unlock_irqrestore()
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irq_put_desc_unlock()->raw_spin_unlock_irqrestore()->_raw_spin_unlock_irqrestore()->__raw_spin_unlock_irqrestore()
#define _raw_spin_unlock_irqrestore(lock, flags) __raw_spin_unlock_irqrestore(lock, flags)
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irq_put_desc_unlock()->raw_spin_unlock_irqrestore()->_raw_spin_unlock_irqrestore()->__raw_spin_unlock_irqrestore()
spinlock_api_smp.h::__raw_spin_unlock_irqrestore()
- call: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irq_put_desc_unlock()->raw_spin_unlock_irqrestore()->_raw_spin_unlock_irqrestore()->__raw_spin_unlock_irqrestore()
// spin_unlock 하고, cpsr_c(제어 필드 마스크 바이트) 원복
static inline void __raw_spin_unlock_irqrestore(raw_spinlock_t *lock,
unsigned long flags)
{
spin_release(&lock->dep_map, 1, _RET_IP_);
do_raw_spin_unlock(lock);
local_irq_restore(flags);
preempt_enable();
}
- return: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irq_put_desc_unlock()
irqdesc.c::__irq_put_desc_unlock()
- return: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)->irq_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()->irq_put_desc_unlock()
void __irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags, bool bus)
{
raw_spin_unlock_irqrestore(&desc->lock, flags);
// bus: false
if (bus)
chip_bus_sync_unlock(desc);
}
- return: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)
irq-gic.c::irq_set_percpu_devid()
- called: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq);
- // kmem_cache#25-o0, 16~31, 16~31
- return: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq)
int irq_set_percpu_devid(unsigned int irq)
{
// irq: 16~31, irq_to_desc(): kmem_cache@28-oX (irq xx)
struct irq_desc *desc = irq_to_desc(irq);
// desc: kmem_cache#28-oX
// desc: kmem_cache#28-oX
if (!desc)
return -EINVAL;
// desc: (kmem_cache#28-oX)->percpu_enabled
if (desc->percpu_enabled)
return -EINVAL;
// desc: (kmem_cache#28-oX)->percpu_enabled, sizeof(*desc-percpu_enabled): 4
desc->percpu_enabled = kzalloc(sizeof(*desc->percpu_enabled), GFP_KERNEL);
// desc->percpu_enabled: (kmem_cache#30-oX)
if (!desc->percpu_enabled)
return -ENOMEM;
irq_set_percpu_devid_flags(irq);
return 0;
}
- return: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq): 0
irq-gic.c::gic_irq_domain_map()
- return: ...->gic_irq_domain_map-> irq_set_percpu_devid(irq): 0
// ARM10C 20141122
// kmem_cache#25-o0, 16, 16
static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw)
{
if (hw < 32) {
irq_set_percpu_devid(irq);
irq_set_chip_and_handler(irq, &gic_chip,
handle_percpu_devid_irq);
- call: ...->gic_irq_domain_map-> irq_set_chip_and_handler()
irq-gic.c::
- call: ...->gic_irq_domain_map-> irq_set_chip_and_handler()
static inline void irq_set_chip_and_handler(unsigned int irq, struct irq_chip *chip,
irq_flow_handler_t handle)
{
irq_set_chip_and_handler_name(irq, chip, handle, NULL);
}
- call: ...->gic_irq_domain_map-> irq_set_chip_and_handler()->irq_set_chip_and_handler_name()
chip.c::irq_set_chip_and_handler_name()
- call: ...->gic_irq_domain_map-> irq_set_chip_and_handler()->irq_set_chip_and_handler_name()
irq_set_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
irq_flow_handler_t handle, const char *name)
{
// irq: 16, chip: gic_chip
irq_set_chip(irq, chip);
__irq_set_handler(irq, handle, 0, name);
}
EXPORT_SYMBOL_GPL(irq_set_chip_and_handler_name);
- call: ...->gic_irq_domain_map-> irq_set_chip_and_handler()->irq_set_chip_and_handler_name()->irq_set_chip()
chip.c:: irq_set_chip()
- call: ...->gic_irq_domain_map-> irq_set_chip_and_handler()->irq_set_chip_and_handler_name()->irq_set_chip()
int irq_set_chip(unsigned int irq, struct irq_chip *chip)
{
unsigned long flags;
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
// *desc: irq_get_desc_lock():
if (!desc)
return -EINVAL;
// chip:
if (!chip)
chip = &no_irq_chip;
// chip:
desc->irq_data.chip = chip;
// desc->irq_data.chip: ...
// desc:
// flags:
irq_put_desc_unlock(desc, flags);
/*
* For !CONFIG_SPARSE_IRQ make the irq show up in
* allocated_irqs. For the CONFIG_SPARSE_IRQ case, it is
* already marked, and this call is harmless.
*/
irq_reserve_irq(irq);
return 0;
}
EXPORT_SYMBOL(irq_set_chip);
- call: ...->gic_irq_domain_map-> irq_set_chip_and_handler()->irq_set_chip_and_handler_name()->irq_set_chip()->irq_put_desc_unlock()
internals.h::irq_put_desc_unlock()
- called: ...->gic_irq_domain_map-> irq_set_chip_and_handler()->irq_set_chip_and_handler_name()->irq_set_chip()->irq_put_desc_unlock()
static inline void
irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags)
{
__irq_put_desc_unlock(desc, flags, false);
}
- call: ...->gic_irq_domain_map-> irq_set_chip_and_handler()->irq_set_chip_and_handler_name()->irq_set_chip()->irq_put_desc_unlock()->__irq_put_desc_unlock()
irqdesc.c::__irq_put_desc_unlock()
- called: ...->gic_irq_domain_map-> irq_set_chip_and_handler()->irq_set_chip_and_handler_name()->irq_set_chip()->irq_put_desc_unlock()->__irq_put_desc_unlock()
void __irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags, bool bus)
{
raw_spin_unlock_irqrestore(&desc->lock, flags);
if (bus)
chip_bus_sync_unlock(desc);
}
- return: ...->gic_irq_domain_map-> irq_set_chip_and_handler()->irq_set_chip_and_handler_name()->irq_set_chip()->irq_put_desc_unlock()
chip.c::irq_set_chip()
- return: ...->gic_irq_domain_map-> irq_set_chip_and_handler()->irq_set_chip_and_handler_name()->irq_set_chip()->irq_put_desc_unlock()
int irq_set_chip(unsigned int irq, struct irq_chip *chip)
{
unsigned long flags;
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
if (!desc)
return -EINVAL;
if (!chip)
chip = &no_irq_chip;
desc->irq_data.chip = chip;
irq_put_desc_unlock(desc, flags);
/*
* For !CONFIG_SPARSE_IRQ make the irq show up in
* allocated_irqs. For the CONFIG_SPARSE_IRQ case, it is
* already marked, and this call is harmless.
*/
irq_reserve_irq(irq);
- call: ...->gic_irq_domain_map-> irq_set_chip_and_handler()->irq_set_chip_and_handler_name()->irq_set_chip()->irq_reserve_irq()
irq.h::irq_reserve_irq()
- called: ...->gic_irq_domain_map-> irq_set_chip_and_handler()->irq_set_chip_and_handler_name()->irq_set_chip()->irq_reserve_irq()
static inline int irq_reserve_irq(unsigned int irq)
{
return irq_reserve_irqs(irq, 1);
}
- call: ...->gic_irq_domain_map-> irq_set_chip_and_handler()->irq_set_chip_and_handler_name()->irq_set_chip()->irq_reserve_irq()->irq_reserve_irqs()
irqdesc.c::irq_reserve_irqs()
- called: ...->gic_irq_domain_map-> irq_set_chip_and_handler()->irq_set_chip_and_handler_name()->irq_set_chip()->irq_reserve_irq()->irq_reserve_irqs()
int irq_reserve_irqs(unsigned int from, unsigned int cnt)
{
unsigned int start;
int ret = 0;
// nr_irqs: 160
if (!cnt || (from + cnt) > nr_irqs)
return -EINVAL;
mutex_lock(&sparse_irq_lock);
// sparse_irq_lock 실행
// nr_irqs: 160, from: 16, cnt: 1, 0
start = bitmap_find_next_zero_area(allocated_irqs, nr_irqs, from, cnt, 0);
// from: 16, start:
if (start == from)
bitmap_set(allocated_irqs, start, cnt);
else
ret = -EEXIST;
mutex_unlock(&sparse_irq_lock);
return ret;
}
- return: ...->gic_irq_domain_map-> irq_set_chip_and_handler()->irq_set_chip_and_handler_name()->irq_set_chip()
chip.c::irq_set_chip()
- return: ...->gic_irq_domain_map-> irq_set_chip_and_handler()->irq_set_chip_and_handler_name()->irq_set_chip()
int irq_set_chip(unsigned int irq, struct irq_chip *chip)
{
unsigned long flags;
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
if (!desc)
return -EINVAL;
if (!chip)
chip = &no_irq_chip;
desc->irq_data.chip = chip;
irq_put_desc_unlock(desc, flags);
/*
* For !CONFIG_SPARSE_IRQ make the irq show up in
* allocated_irqs. For the CONFIG_SPARSE_IRQ case, it is
* already marked, and this call is harmless.
*/
irq_reserve_irq(irq);
return 0;
}
EXPORT_SYMBOL(irq_set_chip);
- return: ...->gic_irq_domain_map-> irq_set_chip_and_handler()->irq_set_chip_and_handler_name()->irq_set_chip()
- return 0;
chip.c::irq_set_chip_and_handler_name()
void
irq_set_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
irq_flow_handler_t handle, const char *name)
{
irq_set_chip(irq, chip);
__irq_set_handler(irq, handle, 0, name);
}
EXPORT_SYMBOL_GPL(irq_set_chip_and_handler_name);
- call: ...->gic_irq_domain_map-> irq_set_chip_and_handler()->irq_set_chip_and_handler_name()
chip.c::__irq_set_handler()
- call: ...->gic_irq_domain_map-> irq_set_chip_and_handler()->irq_set_chip_and_handler_name()
void
__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
const char *name)
{
unsigned long flags;
struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0);
- call: ...->gic_irq_domain_map-> irq_set_chip_and_handler()->irq_set_chip_and_handler_name()->irq_get_desc_buslock()
internals.h::__irq_get_desc_lock()
- call: ...->gic_irq_domain_map-> irq_set_chip_and_handler()->irq_set_chip_and_handler_name()->irq_get_desc_buslock()->__irq_get_desc_lock()
static inline struct irq_desc *
irq_get_desc_buslock(unsigned int irq, unsigned long *flags, unsigned int check)
{
return __irq_get_desc_lock(irq, flags, true, check);
}
irqdesc.c::__irq_get_desc_lock()
struct irq_desc *
__irq_get_desc_lock(unsigned int irq, unsigned long *flags, bool bus,
unsigned int check)
{
struct irq_desc *desc = irq_to_desc(irq);
if (desc) {
if (check & _IRQ_DESC_CHECK) {
if ((check & _IRQ_DESC_PERCPU) &&
!irq_settings_is_per_cpu_devid(desc))
return NULL;
if (!(check & _IRQ_DESC_PERCPU) &&
irq_settings_is_per_cpu_devid(desc))
return NULL;
}
if (bus)
chip_bus_lock(desc);
raw_spin_lock_irqsave(&desc->lock, *flags);
}
return desc;
}
internals.h::chip_bus_lock()
static inline void chip_bus_lock(struct irq_desc *desc)
{
// desc->irq_data.chip->irq_bus_lock: NULL
if (unlikely(desc->irq_data.chip->irq_bus_lock))
desc->irq_data.chip->irq_bus_lock(&desc->irq_data);
}
- return:
- call: ...->gic_irq_domain_map-> irq_set_chip_and_handler()->irq_set_chip_and_handler_name()
chip.c::
void
__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
const char *name)
{
unsigned long flags;
struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0);
if (!desc)
return;
if (!handle) {
handle = handle_bad_irq;
} else {
if (WARN_ON(desc->irq_data.chip == &no_irq_chip))
goto out;
}
/* Uninstall? */
if (handle == handle_bad_irq) {
if (desc->irq_data.chip != &no_irq_chip)
mask_ack_irq(desc);
irq_state_set_disabled(desc);
desc->depth = 1;
}
// desc->handle_irq: kmem_cahce#28-oX (irq: xx): handle: handle_percpu_devid_irq
desc->handle_irq = handle;
// desc->handle_irq: kmem_cahce#28-oX (irq: xx): handle: handle_percpu_devid_irq
// desc->name: kmem_cahce#28-oX (irq: xx): name: NULL
desc->name = name;
// desc->name: kmem_cahce#28-oX (irq: xx): NULL
// is_chained: 0
if (handle != handle_bad_irq && is_chained) {
irq_settings_set_noprobe(desc);
irq_settings_set_norequest(desc);
irq_settings_set_nothread(desc);
irq_startup(desc, true);
}
out:
irq_put_desc_busunlock(desc, flags);
}
EXPORT_SYMBOL_GPL(__irq_set_handler);
- call
- irq_put_desc_busunlock(desc, flags);
internals.h::
static inline void
irq_put_desc_busunlock(struct irq_desc *desc, unsigned long flags)
{
__irq_put_desc_unlock(desc, flags, true);
}
irqdesc.c::__irq_pu_desc_unlock()
void __irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags, bool bus)
{
raw_spin_unlock_irqrestore(&desc->lock, flags);
if (bus)
chip_bus_sync_unlock(desc);
}
- return ...->gic_irq_domain_map()
irq-gic.c::gic_irq_domain_map()
- return ...->gic_irq_domain_map()
// ARM10C 20141122
// kmem_cache#25-o0, 16, 16
static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw)
{
if (hw < 32) {
irq_set_percpu_devid(irq);
irq_set_chip_and_handler(irq, &gic_chip,
handle_percpu_devid_irq);
// ...
set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
- call set_irq_flags()
irq.c::set_irq_flags()
- called:
void set_irq_flags(unsigned int irq, unsigned int iflags)
{
unsigned long clr = 0, set = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
if (irq >= nr_irqs) {
printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq);
return;
}
if (iflags & IRQF_VALID)
clr |= IRQ_NOREQUEST;
if (iflags & IRQF_PROBE)
clr |= IRQ_NOPROBE;
if (!(iflags & IRQF_NOAUTOEN))
clr |= IRQ_NOAUTOEN;
/* Order is clear bits in "clr" then set bits in "set" */
irq_modify_status(irq, clr, set & ~clr);
}
EXPORT_SYMBOL_GPL(set_irq_flags);
- call: irq_modify_status()
chip.c::irq_modify_status()
void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set)
{
unsigned long flags;
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
if (!desc)
return;
irq_settings_clr_and_set(desc, clr, set);
irqd_clear(&desc->irq_data, IRQD_NO_BALANCING | IRQD_PER_CPU |
IRQD_TRIGGER_MASK | IRQD_LEVEL | IRQD_MOVE_PCNTXT);
if (irq_settings_has_no_balance_set(desc))
irqd_set(&desc->irq_data, IRQD_NO_BALANCING);
if (irq_settings_is_per_cpu(desc))
irqd_set(&desc->irq_data, IRQD_PER_CPU);
if (irq_settings_can_move_pcntxt(desc))
irqd_set(&desc->irq_data, IRQD_MOVE_PCNTXT);
if (irq_settings_is_level(desc))
irqd_set(&desc->irq_data, IRQD_LEVEL);
irqd_set(&desc->irq_data, irq_settings_get_trigger_mask(desc));
irq_put_desc_unlock(desc, flags);
}
EXPORT_SYMBOL_GPL(irq_modify_status);
irq-gic.c::gic_irq_domain_map()
// ARM10C 20141122
// kmem_cache#25-o0, 16, 16
static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw)
{
if (hw < 32) {
irq_set_percpu_devid(irq);
irq_set_chip_and_handler(irq, &gic_chip,
handle_percpu_devid_irq);
set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
} else {
irq_set_chip_and_handler(irq, &gic_chip,
handle_fasteoi_irq);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
}
irq_set_chip_data(irq, d->host_data);
return 0;
}
- call: irq_set_chip_data()
int irq_set_chip_data(unsigned int irq, void *data)
{
unsigned long flags;
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
if (!desc)
return -EINVAL;
desc->irq_data.chip_data = data;
irq_put_desc_unlock(desc, flags);
return 0;
}
EXPORT_SYMBOL(irq_set_chip_data);
internals.h::irq_get_desc_lock()
static inline struct irq_desc *
irq_get_desc_lock(unsigned int irq, unsigned long *flags, unsigned int check)
{
return __irq_get_desc_lock(irq, flags, false, check);
}
chip.c::irq_set_chip_data()
int irq_set_chip_data(unsigned int irq, void *data)
{
unsigned long flags;
struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0);
if (!desc)
return -EINVAL;
desc->irq_data.chip_data = data;
irq_put_desc_unlock(desc, flags);
return 0;
}
EXPORT_SYMBOL(irq_set_chip_data);
- return 0;
irq-gic.c::gic_irq_domain_map()
// ARM10C 20141122
// kmem_cache#25-o0, 16, 16
static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hw)
{
if (hw < 32) {
irq_set_percpu_devid(irq);
irq_set_chip_and_handler(irq, &gic_chip,
handle_percpu_devid_irq);
set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN);
} else {
irq_set_chip_and_handler(irq, &gic_chip,
handle_fasteoi_irq);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
}
irq_set_chip_data(irq, d->host_data);
return 0;
}
- return irq_domain_assoicate()
irqdomain.c::irq_domain_aasoicate()
// ARM10C 20141122
// domain: kmem_cache#25-o0, irq_base: 16, hwirq_base: 16
int irq_domain_associate(struct irq_domain *domain, unsigned int virq,
irq_hw_number_t hwirq)
{
...
if (domain->ops->map) {
// domain->ops->map: (kmem_cache#25-o0)->ops->map: gic_irq_domain_map
// domain: domain: kmem_cache#25-o0, virq: 16, hwirq: 16
// gic_irq_domain_map(kmem_cache#25-o0, 16, 16):
ret = domain->ops->map(domain, virq, hwirq);
if (ret != -EPERM) {
pr_info("%s didn't like hwirq-0x%lx to VIRQ%i mapping (rc=%d)\n",
domain->name, hwirq, virq, ret);
}
irq_data->domain = NULL;
irq_data->hwirq = 0;
mutex_unlock(&irq_domain_mutex);
return ret;
}
/* If not already assigned, give the domain the chip's name */
// domain->name: NULL, irq_data->chip: &gic-chip
if (!domain->name && irq_data->chip)
domain->name = irq_data->chip->name;
// domain-name: chip: &gic-chip->name: "GIC"
}
// hwirq: 16~160, domain->revmap_size: 160
if (hwirq < domain->revmap_size) {
domain->linear_revmap[hwirq] = virq;
// domain->linear_revmap[16~160] = 16~160;
} else {
mutex_lock(&revmap_trees_mutex);
radix_tree_insert(&domain->revmap_tree, hwirq, irq_data);
mutex_unlock(&revmap_trees_mutex);
}
mutex_unlock(&irq_domain_mutex);
irq_clear_status_flags(virq, IRQ_NOREQUEST);
irq.h::irq_clear_status_flags()
static inline void irq_clear_status_flags(unsigned int irq, unsigned long clr)
{
irq_modify_status(irq, clr, 0);
}
irqdomain.c::irq_domain_aasoicate()
// ARM10C 20141122
// domain: kmem_cache#25-o0, irq_base: 16, hwirq_base: 16
int irq_domain_associate(struct irq_domain *domain, unsigned int virq,
irq_hw_number_t hwirq)
{
...
irq_clear_status_flags(virq, IRQ_NOREQUEST);
return 0;
}
EXPORT_SYMBOL_GPL(irq_domain_associate);
- return: gic_init_bases()
irq-gic.c::gic_init_bases()
// 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);
log
- 1st log
a82b8aa..371ff1b master -> origin/master
Updating a82b8aa..371ff1b
Fast-forward
arch/arm/include/asm/barrier.h | 1 +
drivers/irqchip/irq-gic.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/compiler.h | 2 ++
include/linux/err.h | 1 +
include/linux/gfp.h | 1 +
include/linux/irq.h | 1 +
include/linux/irqdesc.h | 1 +
include/linux/irqdomain.h | 3 +++
include/linux/of.h | 6 +++++-
include/linux/radix-tree.h | 13 +++++++++++++
include/linux/rcupdate.h | 36 ++++++++++++++++++++++++++++++++++++
include/linux/slab.h | 5 +++++
kernel/irq/chip.c | 7 +++++++
kernel/irq/irqdesc.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
kernel/irq/irqdomain.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/radix-tree.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
16 files changed, 417 insertions(+), 2 deletions(-)
댓글 없음:
댓글 쓰기