2014년 11월 30일 일요일

Install Golang on OSX

Install GoLang

  • Used Env: OSX 10.9.x or higher
  • used tool: brew or Tarball

install go

  • case i) brew
    # brew install go
    
  • case ii) tarball
cd $HOME
wget https://storage.googleapis.com/golang/go1.2.2.src.tar.gz
tar zxvf go1.2.2.src.tar.gz
cd go/src
./all.bash
Installed at "$HOME/go"

Enviroment Variable setting

if [ -x "`which go`" ]; then
  export _GOROOT=`go env GOROOT`
  export GOPATH=$HOME/.goproj
  PATH=$PATH:$GOPATH/bin:$_GOROOT/bin
fi
  • GOROOT is not needed
  • PATH setting for godoc

godoc

go get code.google.com/p/go.tools/cmd/godoc

vim setting

go get github.com/nsf/gocode
go get code.google.com/p/go.tools/cmd/goimports
if $_GOROOT != ''
  set rtp+=${_GOROOT}/misc/vim
    set rtp+=${GOPATH}/src/github.com/nsf/gocode/vim
    endif

"use goimports instead of gofmt
let g:gofmt_command = 'goimports'

"When save :Fmt
au BufWritePre *.go Fmt
au BufNewFile,BufRead *.go set sw=4 noexpandtab ts=4
au FileType go compiler go

2014년 11월 29일 토요일

[Linux Kernel] 80주차(2014.11.29)

ARM10C 80주차 후기

일시 : 2014.11.29 (80주차)
모임명 : NAVER개발자커뮤니티지원_IAMROOT.ORG_10차ARM-C
장소 : 토즈 타워점
장소지원 : NAVER 개발자 커뮤니티 지원 프로그램
참여인원 : 2명

진도

  • 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

main.c::start_kernel()

asmlinkage void __init start_kernel(void)
{
...
    setup_arch(&command_line);
...
    mm_init();
    // buddy와 slab 을 활성화 하고 기존 할당 받은 bootmem 은 buddy,
    // pcpu 메모리, vmlist 는 slab으로 이관
...
    rcu_init();
    // rcu 자료구조 bh, sched, preempt 를 각각 초기화 수행함
...
    /* init some links before init_ISA_irqs() */
    early_irq_init();
    // irq_desc 0 ~ 15 까지의 object을 할당 받고 초기화를 수행
    // allocated_irqs에 bit를 1로 세팅하고 radix tree에 각 irq_desc를 노트로 추가

    init_IRQ();
  • call: start_kernel()->init_IRQ()
    • 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()
    • // exynos-combiner.c 에 정의된 함수를 사용하여 초기화 수행
    • // __irqchip_begin: irqchip_of_match_exynos4210_combiner
    • of_irq_init(__irqchip_begin);

irqchip.h::irqchip_init()

  • called: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()
    • // exynos-combiner.c 에 정의된 함수를 사용하여 초기화 수행
    • // __irqchip_begin: irqchip_of_match_exynos4210_combiner
    • of_irq_init(__irqchip_begin);
void __init of_irq_init(const struct of_device_id *matches)
{
    struct device_node *np, *parent = NULL;
    // parent: NULL
    struct intc_desc *desc, *temp_desc;
    struct list_head intc_desc_list, intc_parent_list;

    INIT_LIST_HEAD(&intc_desc_list);
    // intc_desc_list 리스트 초기화 수행

    INIT_LIST_HEAD(&intc_parent_list);
    // intc_parent_list 리스트 초기화 수행

    // matches: irqchip_of_match_exynos4210_combiner
    for_each_matching_node(np, matches) {
    // for (np = of_find_matching_node(NULL, matches); np; np = of_find_matching_node(np, matches))

        // np: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
        // of_find_property(devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소, "interrupt-controller", NULL):
        // combiner node의 "interrupt-controller" property의 주소
        // np: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
        // of_find_property(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, "interrupt-controller", NULL):
        // gic node의 "interrupt-controller" property의 주소
        if (!of_find_property(np, "interrupt-controller", NULL))
            continue;
        /*
         * Here, we allocate and populate an intc_desc with the node
         * pointer, interrupt-parent device_node etc.
         */
        // sizeof(struct intc_desc): 16 bytes, GFP_KERNEL: 0xD0
        // kzalloc(16, GFP_KERNEL: 0xD0): kmem_cache#30-o10
        // sizeof(struct intc_desc): 16 bytes, GFP_KERNEL: 0xD0
        // kzalloc(16, GFP_KERNEL: 0xD0): kmem_cache#30-o11
        desc = kzalloc(sizeof(*desc), GFP_KERNEL);
        // desc: kmem_cache#30-o10
        // desc: kmem_cache#30-o11

        // desc: kmem_cache#30-o10
        // desc: kmem_cache#30-o11
        if (WARN_ON(!desc))
            goto err;

        // desc->dev: (kmem_cache#30-o10)->dev, np: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
        // desc->dev: (kmem_cache#30-o11)->dev, np: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
        desc->dev = np;
        // desc->dev: (kmem_cache#30-o10)->dev: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
        // desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소

        // desc->interrupt_parent: (kmem_cache#30-o10)->interrupt_parent, np: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
        // of_irq_find_parent(devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소): gic node 주소
        // desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent, np: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
        // of_irq_find_parent(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소): gic node 주소
        desc->interrupt_parent = of_irq_find_parent(np);
        // desc->interrupt_parent: (kmem_cache#30-o10)->interrupt_parent: gic node 주소
        // desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: gic node 주소

        // desc->interrupt_parent: (kmem_cache#30-o10)->interrupt_parent: gic node 주소
        // np: devtree에서 allnext로 순회 하면서 찾은 combiner node의 주소
        // desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: gic node 주소
        // np: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
        if (desc->interrupt_parent == np)
            // desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: gic node 주소
            desc->interrupt_parent = NULL;
            // desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL

        // &desc->list: &(kmem_cache#30-o10)->list
        // &desc->list: &(kmem_cache#30-o11)->list
        list_add_tail(&desc->list, &intc_desc_list);
        // intc_desc_list에 (kmem_cache#30-o10)->list를 tail에 추가
        // intc_desc_list에 (kmem_cache#30-o11)->list를 tail에 추가
    }

    // irqchip_of_match_exynos4210_combiner, irqchip_of_match_cortex_a15_gic 의
    // struct intc_desc 메모리 할당, intc_desc 맴버가 초기화 된 값이 intc_desc_list list의 tail로 추가됨

    // list_empty(&intc_desc_list): 0
    while (!list_empty(&intc_desc_list)) {
        list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
        // for (desc = list_first_entry(&intc_desc_list, typeof(*desc), list),
        //  temp_desc = list_next_entry(desc, list);
        //      &desc->list != (&intc_desc_list);
        //      desc = temp_desc, temp_desc = list_next_entry(temp_desc, list))

            // desc: kmem_cache#30-o10 (exynos4210_combiner), temp_desc: kmem_cache#30-o11 (cortex_a15_gic)
            // desc: kmem_cache#30-o11 (cortex_a15_gic), temp_desc: NULL

            const struct of_device_id *match;
            int ret;
            of_irq_init_cb_t irq_init_cb;

            // desc->interrupt_parent: (kmem_cache#30-o10)->interrupt_parent: gic node 주소, parent: NULL
            // desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL, parent: NULL
            if (desc->interrupt_parent != parent)
                continue;
                // continue 수행 (exynos4210_combiner)

            // &desc->list: (kmem_cache#30-o11)->list
            list_del(&desc->list);
            // intc_desc_list에서 (kmem_cache#30-o11)->list를 삭제

            // matches: irqchip_of_match_cortex_a15_gic,
            // desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
            // of_match_node(cortex_a15_gic, devtree에서 allnext로 순회 하면서 찾은 gic node의 주소):
            // irqchip_of_match_cortex_a15_gic
            match = of_match_node(matches, desc->dev);
            // match: irqchip_of_match_cortex_a15_gic

            // match->data; irqchip_of_match_cortex_a15_gic.data: gic_of_init
            if (WARN(!match->data,
                "of_irq_init: no init function for %s\n",
                match->compatible)) {
                kfree(desc);
                continue;
            }

            // match->compatible: irqchip_of_match_cortex_a15_gic.compatible: "arm,cortex-a15-gic",
            // desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
            // desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL
            pr_debug("of_irq_init: init %s @ %p, parent %p\n",
                 match->compatible,
                 desc->dev, desc->interrupt_parent);
            // "of_irq_init: init arm,cortex-a15-gic @ 0x(gic node의 주소), parent 0\n"

            // match->data; irqchip_of_match_cortex_a15_gic.data: gic_of_init
            irq_init_cb = (of_irq_init_cb_t)match->data;
            // irq_init_cb: gic_of_init

            // desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
            // desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL
            // gic_of_init(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, NULL):
            ret = irq_init_cb(desc->dev, desc->interrupt_parent);
  • call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()
    • // desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
    • // desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL
    • // gic_of_init(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, NULL):
    • // __irqchip_begin: irqchip_of_match_exynos4210_combiner
    • // irq_init_cb = (of_irq_init_cb_t)match->data;
    • 여기서 irq_init_cb: gic_of_init 로 되어 gic_of_init()를 실행한다.
    • ret = irq_init_cb(desc->dev, desc->interrupt_parent);

irq_gic.c::gic_of_init()

  • called: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()
    • // desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
    • // desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL
    • // gic_of_init(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, NULL):
    • // __irqchip_begin: irqchip_of_match_exynos4210_combiner
    • // irq_init_cb = (of_irq_init_cb_t)match->data;
    • 여기서 irq_init_cb: gic_of_init 로 되어 gic_of_init()를 실행한다.
    • ret = irq_init_cb(desc->dev, desc->interrupt_parent);
// ARM10C 20141018
// desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL
int __init gic_of_init(struct device_node *node, struct device_node *parent)
{
    void __iomem *cpu_base;
    void __iomem *dist_base;
    u32 percpu_offset;
    int irq;

    // node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
    if (WARN_ON(!node))
        return -ENODEV;

    // node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
    // of_iomap(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, 0): 0xf0000000
    dist_base = of_iomap(node, 0);
    // dist_base: 0xf0000000

    // of_iomap에서 한일:
    // device tree 있는  gic node에서 node의 resource 값을 가져옴
    // (&res)->start: 0x10481000
    // (&res)->end: 0x10481fff
    // (&res)->flags: IORESOURCE_MEM: 0x00000200
    // (&res)->name: "/interrupt-controller@10481000"
    /*
    // alloc area (GIC#0) 를 만들고 rb tree에 alloc area 를 추가
    // 가상주소 va_start 기준으로 GIC#0 를 RB Tree 추가한 결과
    //
    //                                  CHID-b
    //                               (0xF8000000)
    //                              /            \
    //                         TMR-r               PMU-r
    //                    (0xF6300000)             (0xF8180000)
    //                      /      \               /           \
    //                 SYSC-b      WDT-b         CMU-b         SRAM-b
    //            (0xF6100000)   (0xF6400000)  (0xF8100000)   (0xF8400000)
    //             /                                                 \
    //        GIC#0-r                                                 ROMC-r
    //   (0xF0000000)                                                 (0xF84C0000)
    //
    // vmap_area_list에 GIC#0 - SYSC -TMR - WDT - CHID - CMU - PMU - SRAM - ROMC
    // 순서로 리스트에 연결이 됨
    //
    // (kmem_cache#30-oX (vm_struct))->flags: GFP_KERNEL: 0xD0
    // (kmem_cache#30-oX (vm_struct))->addr: 0xf0000000
    // (kmem_cache#30-oX (vm_struct))->size: 0x2000
    // (kmem_cache#30-oX (vm_struct))->caller: __builtin_return_address(0)
    //
    // (kmem_cache#30-oX (vmap_area GIC#0))->vm: kmem_cache#30-oX (vm_struct)
    // (kmem_cache#30-oX (vmap_area GIC#0))->flags: 0x04
    */
    // device tree 있는  gic node에서 node의 resource 값을 pgtable에 매핑함
    // 0xc0004780이 가리키는 pte의 시작주소에 0x10481653 값을 갱신
    // (linux pgtable과 hardware pgtable의 값 같이 갱신)
    //
    //  pgd                   pte
    // |              |
    // +--------------+
    // |              |       +--------------+ +0
    // |              |       |  0xXXXXXXXX  | ---> 0x10481653 에 매칭되는 linux pgtable 값
    // +- - - - - - - +       |  Linux pt 0  |
    // |              |       +--------------+ +1024
    // |              |       |              |
    // +--------------+ +0    |  Linux pt 1  |
    // | *(c0004780)  |-----> +--------------+ +2048
    // |              |       |  0x10481653  | ---> 2052
    // +- - - - - - - + +4    |   h/w pt 0   |
    // | *(c0004784)  |-----> +--------------+ +3072
    // |              |       +              +
    // +--------------+ +8    |   h/w pt 1   |
    // |              |       +--------------+ +4096
    //
    // cache의 값을 전부 메모리에 반영

    // dist_base: 0xf000000
    WARN(!dist_base, "unable to map gic dist registers\n");

    // node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
    // of_iomap(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, 1): 0xf002000
    cpu_base = of_iomap(node, 1);
    // cpu_base: 0xf0002000

    // of_iomap에서 한일:
    // device tree 있는  gic node에서 node의 resource 값을 가져옴
    // (&res)->start: 0x10482000
    // (&res)->end: 0x10482fff
    // (&res)->flags: IORESOURCE_MEM: 0x00000200
    // (&res)->name: "/interrupt-controller@10481000"
    /*
    // alloc area (GIC#1) 를 만들고 rb tree에 alloc area 를 추가
    // 가상주소 va_start 기준으로 GIC#1 를 RB Tree 추가한 결과
    //
    //                                  CHID-b
    //                               (0xF8000000)
    //                              /            \
    //                         TMR-r               PMU-r
    //                    (0xF6300000)             (0xF8180000)
    //                      /      \               /           \
    //                GIC#1-b      WDT-b         CMU-b         SRAM-b
    //            (0xF0002000)   (0xF6400000)  (0xF8100000)   (0xF8400000)
    //             /       \                                          \
    //        GIC#0-r     SYSC-r                                       ROMC-r
    //    (0xF0000000)   (0xF6100000)                                 (0xF84C0000)
    //
    // vmap_area_list에 GIC#0 - GIC#1 - SYSC -TMR - WDT - CHID - CMU - PMU - SRAM - ROMC
    // 순서로 리스트에 연결이 됨
    //
    // (kmem_cache#30-oX (vm_struct))->flags: GFP_KERNEL: 0xD0
    // (kmem_cache#30-oX (vm_struct))->addr: 0xf0002000
    // (kmem_cache#30-oX (vm_struct))->size: 0x2000
    // (kmem_cache#30-oX (vm_struct))->caller: __builtin_return_address(0)
    //
    // (kmem_cache#30-oX (vmap_area GIC#1))->vm: kmem_cache#30-oX (vm_struct)
    // (kmem_cache#30-oX (vmap_area GIC#1))->flags: 0x04
    */
    // device tree 있는  gic node에서 node의 resource 값을 pgtable에 매핑함
    // 0xc0004780이 가리키는 pte의 시작주소에 0x10482653 값을 갱신
    // (linux pgtable과 hardware pgtable의 값 같이 갱신)
    //
    //  pgd                   pte
    // |              |
    // +--------------+
    // |              |       +--------------+ +0
    // |              |       |  0xXXXXXXXX  | ---> 0x10482653 에 매칭되는 linux pgtable 값
    // +- - - - - - - +       |  Linux pt 0  |
    // |              |       +--------------+ +1024
    // |              |       |              |
    // +--------------+ +0    |  Linux pt 1  |
    // | *(c0004780)  |-----> +--------------+ +2048
    // |              |       |  0x10482653  | ---> 2060
    // +- - - - - - - + +4    |   h/w pt 0   |
    // | *(c0004784)  |-----> +--------------+ +3072
    // |              |       +              +
    // +--------------+ +8    |   h/w pt 1   |
    // |              |       +--------------+ +4096
    //
    // cache의 값을 전부 메모리에 반영

    // cpu_base: 0xf0002000
    WARN(!cpu_base, "unable to map gic cpu registers\n");

    // node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
    // of_property_read_u32(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, "cpu-offset", &percpu_offset):
    // 0이 아닌 err 값
    if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
        percpu_offset = 0;
        // percpu_offset: 0

    // gic_cnt: 0, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset: 0,
    // node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
    gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);
  • call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()
    • // gic_cnt: 0, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset: 0,
    • // node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
    • gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);

irq-gic.c::gic_init_bases()

  • called: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()
    • // gic_cnt: 0, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset: 0,
    • // node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
    • gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);
// ARM10C 20141108
// gic_cnt: 0, -1, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset: 0,
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
void __init gic_init_bases(unsigned int gic_nr, int irq_start,
               void __iomem *dist_base, void __iomem *cpu_base,
               u32 percpu_offset, struct device_node *node)
{
    irq_hw_number_t hwirq_base;
    struct gic_chip_data *gic;
    int gic_irqs, irq_base, i;

    // gic_nr: 0, MAX_GIC_NR: 1
    BUG_ON(gic_nr >= MAX_GIC_NR);

    // gic_nr: 0
    gic = &gic_data[gic_nr];
    // gic: &gic_data[0]
#ifdef CONFIG_GIC_NON_BANKED // CONFIG_GIC_NON_BANKED=n
#endif
    {           /* Normal, sane GIC... */
        // percpu_offset: 0
        WARN(percpu_offset,
             "GIC_NON_BANKED not enabled, ignoring %08x offset!",
             percpu_offset);
        // gic->dist_base.common_base: (&gic_data[0])->dist_base.common_base, dist_base: 0xf0000000
        gic->dist_base.common_base = dist_base;
        // gic->dist_base.common_base: (&gic_data[0])->dist_base.common_base: 0xf0000000

        // gic->cpu_base.common_base: (&gic_data[0])->cpu_base.common_base, cpu_base: 0xf0002000
        gic->cpu_base.common_base = cpu_base;
        // gic->cpu_base.common_base: (&gic_data[0])->cpu_base.common_base: 0xf0002000

        // gic: &gic_data[0]
        gic_set_base_accessor(gic, gic_get_common_base); // null function
    }

    /*
     * Initialize the CPU interface map to all CPUs.
     * It will be refined as each CPU probes its ID.
     */
    // NR_GIC_CPU_IF: 8
    for (i = 0; i < NR_GIC_CPU_IF; i++)
        // i: 0
        gic_cpu_map[i] = 0xff;
        // gic_cpu_map[0]: 0xff
        // i: 1...7 까지 수행

    // gic_cpu_map[0...7]: 0xff

    /*
     * For primary GICs, skip over SGIs.
     * For secondary GICs, skip over PPIs, too.
     */
    // gic_nr: 0, irq_start: -1
    if (gic_nr == 0 && (irq_start & 31) > 0) {
        hwirq_base = 16;
        // hwirq_base: 16

        // irq_start: -1
        if (irq_start != -1)
            irq_start = (irq_start & ~31) + 16;
    } else {
        hwirq_base = 32;
    }

    /*
     * Find out how many interrupts are supported.
     * The GIC only supports up to 1020 interrupt sources.
     */
    // T.R.M: 8.3.2 Distributor register descriptions
    // Interrupt Controller Type Register:
    // b00100 Up to 160 interrupts, 128 external interrupt lines.
    //
    // gic: &gic_data[0], gic_data_dist_base(&gic_data[0]): 0xf0000000, GIC_DIST_CTR: 0x004
    // readl_relaxed(0xf0000000 + 0x004): 0x0000FC24
    gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f;
    // gic_irqs: 0x4

    // gic_irqs: 0x4
    gic_irqs = (gic_irqs + 1) * 32;
    // gic_irqs: 160

    // gic_irqs: 160
    if (gic_irqs > 1020)
        gic_irqs = 1020;

    // gic->gic_irqs: (&gic_data[0])->gic_irqs, gic_irqs: 160
    gic->gic_irqs = gic_irqs;
    // gic->gic_irqs: (&gic_data[0])->gic_irqs: 160

    // gic_irqs: 160, hwirq_base: 16
    gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
    // gic_irqs: 144

    // irq_start: -1, gic_irqs: 144, numa_node_id(): 0
    // irq_alloc_descs(-1, 16, 144, 0): 16
    irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id());
  • call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_alloc_descs()
    • // irq_start: -1, gic_irqs: 144, numa_node_id(): 0
    • // irq_alloc_descs(-1, 16, 144, 0): 16
    • irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id());

irq.h::irq_alloc_descs()

  • called: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_alloc_descs()
    • // irq_start: -1, gic_irqs: 144, numa_node_id(): 0
    • // irq_alloc_descs(-1, 16, 144, 0): 16
    • irq_base = irq_alloc_descs(irq_start, 16, gic_irqs, numa_node_id());
// ARM10C 20141115
// THIS_MODULE: ((struct module *)0)
// irq_start: -1, 16, gic_irqs: 144, numa_node_id(): 0
#define irq_alloc_descs(irq, from, cnt, node)   \
    __irq_alloc_descs(irq, from, cnt, node, THIS_MODULE)
  • call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_alloc_descs()->irq_alloc_descs()
    • // irq: irq_start: -1, from: 16, cnt: 144, THIS_MODULE: numa_node_id(): 0
    • __irq_alloc_descs(irq, from, cnt, node, THIS_MODULE)

irqdesc.c::__irq_alloc_descs()

  • call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_alloc_descs()->irq_alloc_descs()
    • // irq: irq_start: -1, from: 16, cnt: 144, THIS_MODULE: numa_node_id(): 0
    • __irq_alloc_descs(irq, from, cnt, node, THIS_MODULE)
// ARM10C 20141115
// irq_start: -1, 16, gic_irqs: 144, numa_node_id(): 0, THIS_MODULE: ((struct module *)0)
int __ref
__irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
          struct module *owner)
{
    int start, ret;

    // cnt: 144
    if (!cnt)
        return -EINVAL;

    // irq: -1
    if (irq >= 0) {
        if (from > irq)
            return -EINVAL;
        from = irq;
    }

    mutex_lock(&sparse_irq_lock);
    // sparse_irq_lock을 이용한 mutex lock 수행

    // IRQ_BITMAP_BITS: 8212, from: 16, cnt: 144
    // bitmap_find_next_zero_area(allocated_irqs, 8212, 16, 144, 0): 16
    start = bitmap_find_next_zero_area(allocated_irqs, IRQ_BITMAP_BITS,
                       from, cnt, 0);
    // start: 16

    // EEXIST: 17
    ret = -EEXIST;
    // ret: -17

    // irq: -1, start: 16
    if (irq >=0 && start != irq)
        goto err;

    // start: 16, cnt: 144, nr_irqs: 16
    if (start + cnt > nr_irqs) {
        // start: 16, cnt: 144
        // irq_expand_nr_irqs(160): 0
        ret = irq_expand_nr_irqs(start + cnt);
        // ret: 0
        // irq_expand_nr_irqs에서 한일:
        // 전역변수 nr_irqs 값을 160으로 갱신

        // ret: 0
        if (ret)
            goto err;
    }

    // start: 16, cnt: 144
    bitmap_set(allocated_irqs, start, cnt);
    // bitmap_set에서 한일:
    // allocated_irqs 의 16 bit 부터 144 bit를 1로 set

    mutex_unlock(&sparse_irq_lock);
    // sparse_irq_lock을 이용한 mutex unlock 수행

    // start: 16, cnt: 144, node: 0, owner: NULL
    // alloc_descs(16, 144, 0, NULL): 16
    return alloc_descs(start, cnt, node, owner);
    // return 16

    /*
     * alloc_descs에서 한일:
     * struct irq_desc의 자료 구조크기 만큼 160개의 메모리를 할당 받아
     * radix tree 구조로 구성
     *
     * radix tree의 root node: &irq_desc_tree 값을 변경
     * (&irq_desc_tree)->rnode: kmem_cache#20-o1 (RADIX_LSB: 1)
     * (&irq_desc_tree)->height: 2
     *
     * (kmem_cache#20-o1)->height: 2
     * (kmem_cache#20-o1)->count: 3
     * (kmem_cache#20-o1)->parent: NULL
     * (kmem_cache#20-o1)->slots[0]: kmem_cache#20-o0 (radix height 1 관리 주소)
     * (kmem_cache#20-o1)->slots[1]: kmem_cache#20-o2 (radix height 1 관리 주소)
     * (kmem_cache#20-o1)->slots[2]: kmem_cache#20-o3 (radix height 1 관리 주소)
     *
     * (kmem_cache#20-o0)->height: 1
     * (kmem_cache#20-o0)->count: 63
     * (kmem_cache#20-o0)->parent: kmem_cache#20-o1 (RADIX_LSB: 1)
     * (kmem_cache#20-o0)->slots[0...63]: kmem_cache#28-oX (irq 0...63)
     *
     * (kmem_cache#20-o2)->height: 1
     * (kmem_cache#20-o2)->count: 63
     * (kmem_cache#20-o2)->parent: kmem_cache#20-o1 (RADIX_LSB: 1)
     * (kmem_cache#20-o2)->slots[0...63]: kmem_cache#28-oX (irq 63...127)
     *
     * (kmem_cache#20-o3)->height: 1
     * (kmem_cache#20-o3)->count: 32
     * (kmem_cache#20-o3)->parent: kmem_cache#20-o1 (RADIX_LSB: 1)
     * (kmem_cache#20-o3)->slots[0...63]: kmem_cache#28-oX (irq 127...160)
     *
     * (&irq_desc_tree)->rnode -->  +-----------------------+
     *                              |    radix_tree_node    |
     *                              |   (kmem_cache#20-o1)  |
     *                              +-----------------------+
     *                              | height: 2 | count: 3  |
     *                              +-----------------------+
     *                              | radix_tree_node 0 ~ 2 |
     *                              +-----------------------+
     *                             /            |            \
     *     slot: 0                /   slot: 1   |              \ slot: 2
     *     +-----------------------+  +-----------------------+  +-----------------------+
     *     |    radix_tree_node    |  |    radix_tree_node    |  |    radix_tree_node    |
     *     |   (kmem_cache#20-o0)  |  |   (kmem_cache#20-o2)  |  |   (kmem_cache#20-o3)  |
     *     +-----------------------+  +-----------------------+  +-----------------------+
     *     | height: 1 | count: 64 |  | height: 1 | count: 64 |  | height: 1 | count: 32 |
     *     +-----------------------+  +-----------------------+  +-----------------------+
     *     |    irq  0 ~ 63        |  |    irq 64 ~ 127       |  |    irq 128 ~ 160      |
     *     +-----------------------+  +-----------------------+  +-----------------------+
     */
err:
    mutex_unlock(&sparse_irq_lock);
    return ret;
}
EXPORT_SYMBOL_GPL(__irq_alloc_descs);

irq_alloc_descs에서 한일:

  • struct irq_desc의 자료 구조크기 만큼 160개의 메모리를 할당 받아
  • radix tree 구조로 구성 *
  • radix tree의 root node: &irq_desc_tree 값을 변경
  • (&irq_desc_tree)->rnode: kmem_cache#20-o1 (RADIX_LSB: 1)
  • (&irq_desc_tree)->height: 2 *
  • (kmem_cache#20-o1)->height: 2
  • (kmem_cache#20-o1)->count: 3
  • (kmem_cache#20-o1)->parent: NULL
  • (kmem_cache#20-o1)->slots[0]: kmem_cache#20-o0 (radix height 1 관리 주소)
  • (kmem_cache#20-o1)->slots[1]: kmem_cache#20-o2 (radix height 1 관리 주소)
  • (kmem_cache#20-o1)->slots[2]: kmem_cache#20-o3 (radix height 1 관리 주소) *
  • (kmem_cache#20-o0)->height: 1
  • (kmem_cache#20-o0)->count: 63
  • (kmem_cache#20-o0)->parent: kmem_cache#20-o1 (RADIX_LSB: 1)
  • (kmem_cache#20-o0)->slots[0...63]: kmem_cache#28-oX (irq 0...63) *
  • (kmem_cache#20-o2)->height: 1
  • (kmem_cache#20-o2)->count: 63
  • (kmem_cache#20-o2)->parent: kmem_cache#20-o1 (RADIX_LSB: 1)
  • (kmem_cache#20-o2)->slots[0...63]: kmem_cache#28-oX (irq 63...127) *
  • (kmem_cache#20-o3)->height: 1
  • (kmem_cache#20-o3)->count: 32
  • (kmem_cache#20-o3)->parent: kmem_cache#20-o1 (RADIX_LSB: 1)
  • (kmem_cache#20-o3)->slots[0...63]: kmem_cache#28-oX (irq 127...160)
 (&irq_desc_tree)->rnode -->  +-----------------------+
                              |    radix_tree_node    |
                              |   (kmem_cache#20-o1)  |
                              +-----------------------+
                              | height: 2 | count: 3  |
                              +-----------------------+
                              | radix_tree_node 0 ~ 2 |
                              +-----------------------+
                             /            |            \
     slot: 0                /   slot: 1   |              \ slot: 2
     +-----------------------+  +-----------------------+  +-----------------------+
     |    radix_tree_node    |  |    radix_tree_node    |  |    radix_tree_node    |
     |   (kmem_cache#20-o0)  |  |   (kmem_cache#20-o2)  |  |   (kmem_cache#20-o3)  |
     +-----------------------+  +-----------------------+  +-----------------------+
     | height: 1 | count: 64 |  | height: 1 | count: 64 |  | height: 1 | count: 32 |
     +-----------------------+  +-----------------------+  +-----------------------+
     |    irq  0 ~ 63        |  |    irq 64 ~ 127       |  |    irq 128 ~ 160      |
     +-----------------------+  +-----------------------+  +-----------------------+
int __ref
__irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
          struct module *owner)
{

...

    // start: 16, cnt: 144, node: 0, owner: NULL
    return alloc_descs(start, cnt, node, owner);

err:
    mutex_unlock(&sparse_irq_lock);
    return ret;
}
EXPORT_SYMBOL_GPL(__irq_alloc_descs);
  • return: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_alloc_descs()->__irq_alloc_descs()
    • return alloc_descs(start, cnt, node, owner);
    • // return 16

irq-gic.c::gic_init_bases()

  • called: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()
    • gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);
    • gic_cnt: 0, -1, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset:0,
    • node: 
// ARM10C 20141108
// gic_cnt: 0, -1, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset: 0,
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
void __init gic_init_bases(unsigned int gic_nr, int irq_start,
               void __iomem *dist_base, void __iomem *cpu_base,
               u32 percpu_offset, struct device_node *node)
{
...

    // gic->domain: (&gic_data[0])->domain
    // node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
    // gic_irqs: 144, irq_base: 16, hwirq_base: 16, gic: &gic_data[0]
    gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
                    hwirq_base, &gic_irq_domain_ops, gic);
  • call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()

irqdomain.c::irq_domain_add_legacy()

  • called: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()
    • // gic->domain: (&gic_data[0])->domain
    • // node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
    • // gic_irqs: 144, irq_base: 16, hwirq_base: 16, gic: &gic_data[0]
// ARM10C 20141122
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
// gic_irqs: 144, irq_base: 16, hwirq_base: 16, &gic_irq_domain_ops, gic: &gic_data[0]
struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
                     unsigned int size,
                     unsigned int first_irq,
                     irq_hw_number_t first_hwirq,
                     const struct irq_domain_ops *ops,
                     void *host_data)
{
    struct irq_domain *domain;
...
    // domain: kmem_cache#25-o0, first_irq: 16, first_hwirq: 16, size: 144
    irq_domain_associate_many(domain, first_irq, first_hwirq, size);
  • call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()->irq_domain_associate_many()

irqdomain.c::irq_domain_associate_many()

  • called: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()->irq_domain_associate_many()
// ARM10C 20141122
// domain: kmem_cache#25-o0, first_irq: 16, first_hwirq: 16, size: 144
void irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base,
                   irq_hw_number_t hwirq_base, int count)
{
    int i;

    // domain->of_node: (kmem_cache#25-o0)->of_node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
    // of_node_full_name(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소): "/interrupt-controller@10481000"
    // irq_base: 16, hwirq_base: 16, count: 144
    pr_debug("%s(%s, irqbase=%i, hwbase=%i, count=%i)\n", __func__,
        of_node_full_name(domain->of_node), irq_base, (int)hwirq_base, count);
    // "irq_domain_associate_many(/interrupt-controller@10481000, irqbase=16, hwbase=16, count=144)\n"

    // count: 144
    for (i = 0; i < count; i++) {
        // domain: kmem_cache#25-o0, irq_base: 16, i: 0, hwirq_base: 16
        // irq_domain_associate(kmem_cache#25-o0, 16, 16): 0
        irq_domain_associate(domain, irq_base + i, hwirq_base + i);

    }
}
EXPORT_SYMBOL_GPL(irq_domain_associate_many);
  • call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()->irq_domain_associate_many()->irq_domain_assoicate()

irq_domain_assoicate() 에서 한일

  • i: 1...144번까지 (irq 16 ~ irq160) 까지 반복 실행한다.
  • return: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()->irq_domain_associate_many()->irq_domain_assoicate()

irqdomain.c::irq_domain_add_legacy()

  • return: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()->irq_domain_associate_many()
// ARM10C 20141122
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
// gic_irqs: 144, irq_base: 16, hwirq_base: 16, &gic_irq_domain_ops, gic: &gic_data[0]
struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
                     unsigned int size,
                     unsigned int first_irq,
                     irq_hw_number_t first_hwirq,
                     const struct irq_domain_ops *ops,
                     void *host_data)
{
...
    // domain: kmem_cache#25-o0, first_irq: 16, first_hwirq: 16, size: 144
    irq_domain_associate_many(domain, first_irq, first_hwirq, size);

    return domain;
}
EXPORT_SYMBOL_GPL(irq_domain_add_legacy);
  • return: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()

oirq_domain_add_legacy()가 한일

irq-gic.c::gic_init_bases()

  • return: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()
// ARM10C 20141108
// gic_cnt: 0, -1, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset: 0,
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
void __init gic_init_bases(unsigned int gic_nr, int irq_start,
               void __iomem *dist_base, void __iomem *cpu_base,
               u32 percpu_offset, struct device_node *node)
{
...

    // gic->domain: (&gic_data[0])->domain
    // node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
    // gic_irqs: 144, irq_base: 16, hwirq_base: 16, gic: &gic_data[0]
    gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
                    hwirq_base, &gic_irq_domain_ops, gic);

    // gic->domain: 
    if (WARN_ON(!gic->domain))
        return;

    if (gic_nr == 0) {
#ifdef CONFIG_SMP
        // gic_raise_softirq: 
        set_smp_cross_call(gic_raise_softirq);
  • call set_smp_cross_call()
    • start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()

smp.c::set_smp_cross_call()

void __init set_smp_cross_call(void (*fn)(const struct cpumask *, unsigned int))
{
    if (!smp_cross_call)
        smp_cross_call = fn;
}
  • IPI_CALL_FUNC
enum ipi_msg_type {
    IPI_WAKEUP,
    IPI_TIMER,
    IPI_RESCHEDULE,
    IPI_CALL_FUNC,
    IPI_CALL_FUNC_SINGLE,
    IPI_CPU_STOP,
    IPI_IRQ_WORK,
    IPI_COMPLETION,
};

irq-gic.c::gic_init_bases()

  • return: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()
// ARM10C 20141108
// gic_cnt: 0, -1, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset: 0,
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
void __init gic_init_bases(unsigned int gic_nr, int irq_start,
               void __iomem *dist_base, void __iomem *cpu_base,
               u32 percpu_offset, struct device_node *node)
{
...

    // gic->domain: (&gic_data[0])->domain
    // node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
    // gic_irqs: 144, irq_base: 16, hwirq_base: 16, gic: &gic_data[0]
    gic->domain = irq_domain_add_legacy(node, gic_irqs, irq_base,
                    hwirq_base, &gic_irq_domain_ops, gic);

    // gic->domain: 
    if (WARN_ON(!gic->domain))
        return;

    if (gic_nr == 0) {
#ifdef CONFIG_SMP
        // gic_raise_softirq: 
        set_smp_cross_call(gic_raise_softirq);
        // smp_cross_call: gic_raise_softirq 함수 등록.

        // fic_cpu_notifier:
        register_cpu_notifier(&gic_cpu_notifier);
        // registar_cpu_notifier() 한일 

        set_handle_irq(gic_handle_irq);
    }

    gic_chip.flags |= gic_arch_extn.flags;
    gic_dist_init(gic);
    gic_cpu_init(gic);
    gic_pm_init(gic);
}
// ARM10C 20141122
static struct irq_chip gic_chip = {
    .name           = "GIC",
    .irq_mask       = gic_mask_irq,
    .irq_unmask     = gic_unmask_irq,
    .irq_eoi        = gic_eoi_irq,
    .irq_set_type       = gic_set_type,
    .irq_retrigger      = gic_retrigger,
#ifdef CONFIG_SMP // CONFIG_SMP=y
    .irq_set_affinity   = gic_set_affinity,
#endif
    .irq_set_wake       = gic_set_wake,
};
struct irq_chip gic_arch_extn = {
    .irq_eoi    = NULL,
    .irq_mask   = NULL,
    .irq_unmask = NULL,
    .irq_retrigger  = NULL,
    .irq_set_type   = NULL,
    .irq_set_wake   = NULL,
};
  • call gic_dist_init(gic)

irq-gic.c::gic_disc_init()

static void __init gic_dist_init(struct gic_chip_data *gic)
{
    unsigned int i;
    u32 cpumask;

    // gic->gic_irqs: (&gic_data[0]->gis_irqs: 160
    unsigned int gic_irqs = gic->gic_irqs;
    // gic_irqs: 160

    // gic: &gic_data[0]
    void __iomem *base = gic_data_dist_base(gic);
  • call: void __iomem *base = gic_data_dist_base(gic);

gic_data_dist_base()

irq-gic.c::gic_disc_init()

static void __init gic_dist_init(struct gic_chip_data *gic)
{
    unsigned int i;
    u32 cpumask;

    // gic->gic_irqs: (&gic_data[0]->gis_irqs: 160
    unsigned int gic_irqs = gic->gic_irqs;
    // gic_irqs: 160

    // gic: &gic_data[0]
    void __iomem *base = gic_data_dist_base(gic);

    // GIC_DIST_CTRL: 0
    writel_relaxed(0, base + GIC_DIST_CTRL);

## irq-gic.c::gic_disc_init()

```c
static void __init gic_dist_init(struct gic_chip_data *gic)
{
    unsigned int i;
    u32 cpumask;

...

    // GIC_DIST_CTRL: 0
    writel_relaxed(0, base + GIC_DIST_CTRL);
  • GIC_DIST_CTRL: GIC distrubut control register
    • G.A.S.: Gic Archtectecture Specification
  • writel_relaxed(0, base + GIC_DIST_CTRL); 의미
    • GIC_DIST_CTRL: 0x0000 0000 (reset value)로 초기화함.
  • GIC-400
    • 1) GIC-390 is implemented using the GICv1 architecture
    • 2) GIC-400 is implemented using the GICv2 architecture,
    • and has been tested and silicon proven in big.LITTLE
    • combinations see: ARM Generic Interrupt Controller
    • For newer A class processors it is recommended that GIC-400 us used
    • as it is compatible with ARMv7 and ARMv8 architecture.
    • ARM are also encouraging some R class processor customers
    • to move from GIC-390 to GIC-400 for consistency
    • and for future-proofing,
    • there is a small delta in interrupt latency for GIC-400
    • and the latency is also deterministic.
  • GIC-400 과 GIC-390 비교:
    • Positives:
    • Virtualization support (only applicable to v7-A with Virtualization Extensions or v8)
    • Single AMBA AXI4 slave interface
    • (PL390 had 2 slave ports for no good reason – saves on interconnect)
    • Differences of note:
    • Cannot be configured with AHB slave port (unlike PL390) –
    • however NIC-400 can help here however by providing a bridge to AHB where required
    • Fewer PPIs (private peripheral interrupts) – 4 generic PPIs compared to up to 16
    • Fewer SPIs (shared peripheral interrupts) – up to 480 compared to up to 988

irq-gic.c::gic_disc_init()

static void __init gic_dist_init(struct gic_chip_data *gic)
{
    unsigned int i;
    u32 cpumask;

...

    // GIC_DIST_CTRL: 0
    writel_relaxed(0, base + GIC_DIST_CTRL);
    // GIC_DIST_CTRL: 0(reset value)로 초기화

    /*
     * Set all global interrupts to be level triggered, active low.
     */
    // gic_irqs: 160
    for (i = 32; i < gic_irqs; i += 16)
        // i:32, base: 0xf0000000, GIC_DIST_CONFIG: 0xc00
        // i: 32 * 4 / 16 
        writel_relaxed(0, base + GIC_DIST_CONFIG + i * 4 / 16);
        // 0xf00000c08: Iterrupt Contfiguation Register
        // 0xc08 ~ 0xc24 (32)까지 레지스터 설정
        // register GICD_ICFGR2의 값을 0으로 초기화
        // SGI: Softwared Generated Interrupts
        // PPI: Private Peripheral Interrupts
        // SPI: Shared Peripheral Interrupts
    // GICD_ICFGR2 ~ GICD_IRFGR9까지의 값을 0으로 초기화


    /*
     * Set all global interrupts to this CPU only.
     */
    cpumask = gic_get_cpumask(gic);

irq-gic.c::gic_get_cpumask()

static u8 gic_get_cpumask(struct gic_chip_data *gic)
{
    void __iomem *base = gic_data_dist_base(gic);
    // base: 0xf0000000

    u32 mask, i;

    // GIC_DIST_TARGET: 0x800
    for (i = mask = 0; i < 32; i += 4) {
        // base: 0xf0000000, GIC_DIST_TARGET: 0x800, i:0
        // readl_relaxed(0xf0000800) : 0x01010101 (reset값)
        mask = readl_relaxed(base + GIC_DIST_TARGET + i);

        // mask: 0x0101 0101
        mask |= mask >> 16;
        // mask: 0x0101 0101
        mask |= mask >> 8;
        // mask: 0x0101 0101
        if (mask)
            break;
    }

    if (!mask)
        pr_crit("GIC CPU mask not found - kernel will fail to boot.\n");

    return mask;
}
  • return mask: 0x01010101

irq-gic.c::gic_disc_init()

  • return mask: 0x01010101
static void __init gic_dist_init(struct gic_chip_data *gic)
{
    unsigned int i;
    u32 cpumask;

...
    cpumask = gic_get_cpumask(gic);
    // cpumask: 0x0101 0101

    cpumask |= cpumask << 8;
    cpumask |= cpumask << 16;
    // cpu0으로 모든 irq를 할당해 놓는다. 
    for (i = 32; i < gic_irqs; i += 4)
        // i: 0x820: Processor target register SPI[3:0] ... 8 ~ 39까지
        // 0x01010101 로 모두 cpu0으로 할당한다.

        writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
        // register: GIC_ITARGETSR8 값을 0x01010101 로 모두 cpu0으로 할당한다.
        // i:32... 156까지 수행
    /*
     * Set priority on all global interrupts.
     */
    for (i = 32; i < gic_irqs; i += 4)
        writel_relaxed(0xa0a0a0a0, base + GIC_DIST_PRI + i * 4 / 4);

    /*
     * Disable all interrupts.  Leave the PPI and SGIs alone
     * as these enables are banked registers.
     */
    for (i = 32; i < gic_irqs; i += 32)
        writel_relaxed(0xffffffff, base + GIC_DIST_ENABLE_CLEAR + i * 4 / 32);

    writel_relaxed(1, base + GIC_DIST_CTRL);
}

irq-gic.c::gic_disc_init()

  • return mask: 0x01010101
static void __init gic_dist_init(struct gic_chip_data *gic)
{
    unsigned int i;
    u32 cpumask;

...
    // gic_irqs: 160
    for (i = 32; i < gic_irqs; i += 4)
        // GIC_DIST_TARGET: 0x800, i: 32

        writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);

## irq-gic.c::gic_init_bases()
* return: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()

```c
// ARM10C 20141108
// gic_cnt: 0, -1, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset: 0,
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
void __init gic_init_bases(unsigned int gic_nr, int irq_start,
               void __iomem *dist_base, void __iomem *cpu_base,
               u32 percpu_offset, struct device_node *node)
{
...

    gic_chip.flags |= gic_arch_extn.flags;
    gic_dist_init(gic);
    gic_cpu_init(gic);

irq-gic.c::gic_init_bases()

  • return: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()
// ARM10C 20141108
// gic_cnt: 0, -1, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset: 0,
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
void __init gic_init_bases(unsigned int gic_nr, int irq_start,
               void __iomem *dist_base, void __iomem *cpu_base,
               u32 percpu_offset, struct device_node *node)
{
...

    gic_chip.flags |= gic_arch_extn.flags;
    gic_dist_init(gic);
    // gic: &gic_data[0]
    gic_cpu_init(gic);

irq-gic.c::gic_get_cpumask()

static void gic_cpu_init(struct gic_chip_data *gic)
{
    // gic: &gic_data[0]
    void __iomem *dist_base = gic_data_dist_base(gic);
    // *dist_base: 0xf0000000

    // gic: &gic_data[0]
    void __iomem *base = gic_data_cpu_base(gic);
    unsigned int cpu_mask, cpu = smp_processor_id();

    // NR_GIC_CPU_IF: 8
    BUG_ON(cpu >= NR_GIC_CPU_IF);

    // gic: &gic_data[0]
    cpu_mask = gic_get_cpumask(gic);
    // cpu_mask: 0x01010101
    gic_cpu_map[cpu] = cpu_mask;
    // gic_cpu_map[0]: 0x01

    // NR_GIC_CPU_IF: 8
    for (i = 0; i < NR_GIC_CPU_IF; i++)
        // cpu: 0
        if (i != cpu)
            gic_cpu_map[i] &= ~cpu_mask;
            // gic_cpu_map[1]: 0
            // ...
            // gic_cpu_map[7]: 0
    // GIC_DIST_ENABLE_CLEAR: 0x180         
    writel_relaxed(0xffff0000, dist_base + GIC_DIST_ENABLE_CLEAR);
    // register GICD_ICENABLER0: 0xffff0000
    // 0xffff0000 0~15bit는 SGI, 16~31: PPI를 en/disable함
    // PPI[16:31]: disable 0xffffxxxx, 


    // GIC_DIST_ENABLE_SET: 0x100
    writel_relaxed(0x0000ffff, dist_base + GIC_DIST_ENABLE_SET);
    // registar: GICD_ISENABLER0 값을 0x0000ffff로 설정
    // 0x0000ffff 0~15bit는 SGI, 16~31: PPI를 en/disable함
    // SPI[15:0] : enable  0xxxxxffff

    for (i = 0; i < 32; i += 4)
        // 
        writel_relaxed(0xa0a0a0a0, dist_base + GIC_DIST_PRI + i * 4 / 4);
        // i: 4...28까지 실행
        // register GICD_IPRIORITY1~8 값을 0xa0a0a0a0로 설정

    // base: 0xf0002000, GIC_CPU_PRIMASK: 0x4
    writel_relaxed(0xf0, base + GIC_CPU_PRIMASK);
    // register: GICC_PMR을 0xf0로 설정(240이상 priority만 허용)
    // Provides an interrupt priority filter.
    // Only interrupts with higher priority than the value in this register
    // are signaled to the processor.

    // base: 0xf0002000, GIC_CPU_CTRL: 0x0
    writel_relaxed(1, base + GIC_CPU_CTRL);
    // register: GICC_CTLR 값을 1로 설정
    // 1의 값의 의미: cpu에 전달되는 인터럽트를 enable함.
}   
static inline void __iomem *gic_data_cpu_base(struct gic_chip_data *data)
{
    return data->get_base(&data->cpu_base);
}
static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly;
// gic_cpu_map[8]

irq-gic.c::gic_init_bases()

  • return: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()->gic_of_init()->gic_init_bases()->irq_domain_add_legacy()
// ARM10C 20141108
// gic_cnt: 0, -1, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset: 0,
// node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
void __init gic_init_bases(unsigned int gic_nr, int irq_start,
               void __iomem *dist_base, void __iomem *cpu_base,
               u32 percpu_offset, struct device_node *node)
{
...

    gic_chip.flags |= gic_arch_extn.flags;
    gic_dist_init(gic);
    // gic: &gic_data[0]
    gic_cpu_init(gic);
    // gic: &gic_data[0]    
    gic_pm_init(gic);
}   

irq-gic.c::gic_pm_init

static void __init gic_pm_init(struct gic_chip_data *gic)
{
    // gic->saved_ppi_enable: (&gic_data[0])->saved_ppi_enable: 
    gic->saved_ppi_enable = __alloc_percpu(DIV_ROUND_UP(32, 32) * 4,
        sizeof(u32));
    // gic->saved_ppi_enable: (&gic_data[0])->saved_ppi_enable: 4
    // __alloc_percpu(4,4): 의미
    // kmem_cache#26-oX: 512할당받은 slut에서 4Bx 4개만 할당받은 주소

    BUG_ON(!gic->saved_ppi_enable);

    // gic->saved_ppi_conf: (&gic_data[0]->saved_ppi_conf
    // DIV_ROUND_UP (32,16): 2 
    gic->saved_ppi_conf = __alloc_percpu(DIV_ROUND_UP(32, 16) * 4,
        sizeof(u32));
    // gic->saved_ppi_conf  :
    // kmem_cache#26-oX: 512할당받은 slut에서 8B 할당받은 주소

    BUG_ON(!gic->saved_ppi_conf);

    if (gic == &gic_data[0])
        cpu_pm_register_notifier(&gic_notifier_block);
}
static struct notifier_block gic_notifier_block = {
    .notifier_call = gic_notifier,
};

cpu_pm.c::cpu_pm_register_notifier()

int cpu_pm_register_notifier(struct notifier_block *nb)
{
    unsigned long flags;
    int ret;

    // 
    write_lock_irqsave(&cpu_pm_notifier_lock, flags);
    // cpu_pm_notifier_lock을 이용한 lock설정후 cpsr 저장

    // nb: &gic_notifier_block
    ret = raw_notifier_chain_register(&cpu_pm_notifier_chain, nb);
    // raw_notifier_chain_register에서 한일
    // (&cpu_pm_notifier_chain)->head: &gic_notifier_block

    write_unlock_irqrestore(&cpu_pm_notifier_lock, flags);
    // cpu_pm_notifier_lock을 이용한 cpsr 복원
    return ret;
}
EXPORT_SYMBOL_GPL(cpu_pm_register_notifier);

irq_gic.c::gic_of_init()

  • call: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()->irq_init_cb()
    • ret = irq_init_cb(desc->dev, desc->interrupt_parent);
    • // __irqchip_begin: irqchip_of_match_exynos4210_combiner
    • // irq_init_cb = (of_irq_init_cb_t)match->data;
    • 여기서 irq_init_cb: gic_of_init 로 되어 gic_of_init()를 실행한다.
// ARM10C 20141018
// desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
// desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL
int __init gic_of_init(struct device_node *node, struct device_node *parent)
{
...
    // gic_cnt: 0, dist_base: 0xf0000000, cpu_base: 0xf0002000, percpu_offset: 0,
    // node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
    gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);

    // gic_cnt: 0
    if (!gic_cnt)
        // node: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
        gic_init_physaddr(node);
        // null function
    // parent 
    if (parent) {
        irq = irq_of_parse_and_map(node, 0);
        gic_cascade_irq(gic_cnt, irq);
    }
    gic_cnt++;
    // gic_cnt: 1
    return 0;
}

irq-gic.c::gic_init_physaddr()

void __init gic_init_physaddr(struct device_node *node)
{
    struct resource res;
    if (of_address_to_resource(node, 0, &res) == 0) {
        gic_dist_physaddr = res.start;
        pr_info("GIC physical location is %#lx\n", gic_dist_physaddr);
    }
}

irqchip.h::irqchip_init()

  • called: start_kernel()->init_IRQ()->irqchip_init()->of_irq_init()
    • of_irq_init(__irqchip_begin);
    • // __irqchip_begin: irqchip_of_match_exynos4210_combiner
void __init of_irq_init(const struct of_device_id *matches)
{
...
    // list_empty(&intc_desc_list): 0
    while (!list_empty(&intc_desc_list)) {
        list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
        // for (desc = list_first_entry(&intc_desc_list, typeof(*desc), list),
        //  temp_desc = list_next_entry(desc, list);
        //      &desc->list != (&intc_desc_list);
        //      desc = temp_desc, temp_desc = list_next_entry(temp_desc, list))

            // desc: kmem_cache#30-o10 (exynos4210_combiner), temp_desc: kmem_cache#30-o11 (cortex_a15_gic)
            // desc: kmem_cache#30-o11 (cortex_a15_gic), temp_desc: NULL

            const struct of_device_id *match;
            int ret;
            of_irq_init_cb_t irq_init_cb;

            // desc->interrupt_parent: (kmem_cache#30-o10)->interrupt_parent: gic node 주소, parent: NULL
            // desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL, parent: NULL
            if (desc->interrupt_parent != parent)
                continue;
                // continue 수행 (exynos4210_combiner)

            // &desc->list: (kmem_cache#30-o11)->list
            list_del(&desc->list);
            // intc_desc_list에서 (kmem_cache#30-o11)->list를 삭제

            // matches: irqchip_of_match_cortex_a15_gic,
            // desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
            // of_match_node(cortex_a15_gic, devtree에서 allnext로 순회 하면서 찾은 gic node의 주소):
            // irqchip_of_match_cortex_a15_gic
            match = of_match_node(matches, desc->dev);
            // match: irqchip_of_match_cortex_a15_gic

            // match->data; irqchip_of_match_cortex_a15_gic.data: gic_of_init
            if (WARN(!match->data,
                "of_irq_init: no init function for %s\n",
                match->compatible)) {
                kfree(desc);
                continue;
            }

            // match->compatible: irqchip_of_match_cortex_a15_gic.compatible: "arm,cortex-a15-gic",
            // desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소
            // desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL
            pr_debug("of_irq_init: init %s @ %p, parent %p\n",
                 match->compatible,
                 desc->dev, desc->interrupt_parent);
            // "of_irq_init: init arm,cortex-a15-gic @ 0x(gic node의 주소), parent 0\n"

            // match->data; irqchip_of_match_cortex_a15_gic.data: gic_of_init
            irq_init_cb = (of_irq_init_cb_t)match->data;
            // irq_init_cb: gic_of_init

            // desc->dev: (kmem_cache#30-o11)->dev: devtree에서 allnext로 순회 하면서 찾은 gic node의 주소,
            // desc->interrupt_parent: (kmem_cache#30-o11)->interrupt_parent: NULL
            // gic_of_init(devtree에서 allnext로 순회 하면서 찾은 gic node의 주소, NULL):
            ret = irq_init_cb(desc->dev, desc->interrupt_parent);
            // ret: 0
            if (ret) {
                kfree(desc);
                continue;
            }
            // &desc->list: (kmem_cache#30-o11)->list
            list_add_tail(&desc->list, &intc_parent_list);
            // &initc_parent_list에 (kmem_cache#30-o11)->list를 연결
        }
        // desc: NULL, intc_parrent_list: NULL로 loop 탈출

        // list_first_entry_or_null()
        // sizeof(struct desc): 16Byte
        // 
        desc = list_first_entry_or_null(&intc_parent_list,
                        typeof(*desc), list);
        // #define list_first_entry_or_null(ptr, type, member) \
        //  (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL)
        //
        // desc: kmem_cache#30_o11(cortex_a15_gic)

        if (!desc) {
            pr_err("of_irq_init: children remain, but no parents\n");
            break;
        }
        list_del(&desc->list);
        // &(kmem_cache#30-o11) (cortect_a15_gic)->list에 연결된 자료구조 삭제
        // desc->dev: &(kmem_cache#30-o11) (cortect_a15_gic)->dev

        parent = desc->dev;
        // parrent:  &(kmem_cache#30-o11) (cortect_a15_gic)->dev
        kfree(desc);
    }

slub.c::kfree()

void kfree(const void *x)
{
    struct page *page;

    void *object = (void *)x;
    // object: kmem_cache#30-o11

    trace_kfree(_RET_IP_, x);

    // x: kmem_cache#30-o11
    if (unlikely(ZERO_OR_NULL_PTR(x)))
        return;
    // unlikely(kmem_cache#30-o11): false

    // x: kmem_cache#30-o11
    // virt_to_head_page(kmem_cache#30-o11): kmem_cache#30-o11의 page주소
    page = virt_to_head_page(x);

    if (unlikely(!PageSlab(page))) {
        BUG_ON(!PageCompound(page));
        kfree_hook(x);
        __free_memcg_kmem_pages(page, compound_order(page));
        return;
    }
    slab_free(page->slab_cache, page, object, _RET_IP_);
}
EXPORT_SYMBOL(kfree);
static inline struct page *virt_to_head_page(const void *x)
{
    struct page *page = virt_to_page(x);
    return compound_head(page);
}
#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)

log

  • 1st log
   1cccb59..8041c56  master     -> origin/master
Updating 1cccb59..8041c56
Fast-forward
Reference/IHI0048B_b_gic_architecture_specification.pdf | Bin 0 -> 1245215 bytes
arch/arm/include/asm/exception.h                        |   3 +++
arch/arm/include/asm/io.h                               |   2 ++
arch/arm/include/asm/irq.h                              |   3 ++-
arch/arm/kernel/entry-armv.S                            |   1 +
arch/arm/kernel/irq.c                                   |   7 ++++-
arch/arm/kernel/smp.c                                   |   6 +++++
drivers/irqchip/irq-gic.c                               | 159 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
include/linux/cpu.h                                     |   1 +
include/linux/irq.h                                     |   1 +
include/linux/irqchip/arm-gic.h                         |  10 ++++++++
kernel/cpu.c                                            |   7 +++++
kernel/irq/irqdomain.c                                  |  38 ++++++++++++++++++++++++++++
kernel/notifier.c                                       |   6 +++++
14 files changed, 239 insertions(+), 5 deletions(-)
create mode 100644 Reference/IHI0048B_b_gic_architecture_specification.pdf
  • 2nd log
   8041c56..db8a459  master     -> origin/master
Updating 8041c56..db8a459
Fast-forward
arch/arm/include/asm/memory.h   |   2 +
drivers/irqchip/irq-gic.c       | 267 +++++++++++++++++++++++++++++++++++++++-
drivers/of/irq.c                | 257 +++++++++++++++++++++++++++++++++++++-
include/linux/cpu_pm.h          |   2 +-
include/linux/irqchip/arm-gic.h |   6 +
include/linux/kernel.h          |   2 +
include/linux/list.h            |   3 +
include/linux/mm.h              |  13 ++
include/linux/mm_types.h        |   1 +
include/linux/notifier.h        |   1 +
include/linux/page-flags.h      |   6 +
include/linux/slab.h            |   2 +
include/linux/smp.h             |   1 +
include/trace/events/kmem.h     |   2 +
kernel/cpu_pm.c                 |  12 ++
kernel/notifier.c               |   5 +
mm/percpu.c                     |   2 +
mm/slub.c                       |  16 +++
18 files changed, 594 insertions(+), 6 deletions(-)