2014년 11월 22일 토요일

[Linux Kernel] 79주차(2014.11.22)

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_set_percpu_devid_flags()->irq_set_status_flags()->irq_modify_status()

  • 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(-)

댓글 없음:

댓글 쓰기