2015년 1월 10일 토요일

[Linux Kernel] 86주차(2015.1.10)

ARM10C 86주차 후기

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

86주차 진도

  • start_kernel()->time_init(); 진행중

main.c::start_kernel()

asmlinkage void __init start_kernel(void)
{
...
    setup_arch(&command_line);
...
    mm_init();
    // buddy와 slab 을 활성화 하고 기존 할당 받은 bootmem 은 buddy,
    // pcpu 메모리, vmlist 는 slab으로 이관
    sched_init();
    // scheduler가 사용하는 자료 구조 초기화, idle_threads를 init_task로 세팅
...
    init_IRQ();
    // gic, combiner이 사용할 메모리 할당과 자료 구조 설정,
    // gic irq (0~15), combiner irq (32~63) interrupt 를 enable 시킴
    tick_init();
    // tick 관련 mask 변수를 0으로 초기화 수행

    init_timers();
    // boot_tvec_bases의 맴버 값을 초기화하고 timers_nb를 cpu_notifier 에 등록,
    // softirq_vec[1] 에 run_timer_softirq 등록하여 초기화 수행

    hrtimers_init();
    // hrtimer_bases의 맴버 값을 초기화하고 hrtimers_nb를 cpu_notifier 에 등록,
    // softirq_vec[8] 에 run_hrtimer_softirq 등록하여 초기화 수행

    softirq_init();
    // tasklet_vec, tasklet_hi_vec 맴버 값을 초기화하고,
    // softirq_vec[6]에 tasklet_action, softirq_vec[0]에 tasklet_hi_action 등록하여 초기화 수행

    timekeeping_init();
    // ntp 관련 전역변수 초기화, timekeeper, shadow_timekeeper의 맴버값 초기화 수행

    time_init();
  • start_kernel()->time_init()

time.c::time_init()

  • start_kernel()->time_init()
// ARM10C 20150103
void __init time_init(void)
{
    // machine_desc->init_time: __mach_desc_EXYNOS5_DT.init_time: NULL
    if (machine_desc->init_time) {
        machine_desc->init_time();
    } else {
#ifdef CONFIG_COMMON_CLK // CONFIG_COMMON_CLK=y
        of_clk_init(NULL);
#endif
        clocksource_of_init();
    }
}
  • start_kernel()->time_init()->of_clk_init(NULL);

clk.c::of_clk_init()

  • start_kernel()->time_init()->of_clk_init(NULL)->of_clk_init()
// ARM10C 20150103
// NULL
void __init of_clk_init(const struct of_device_id *matches)
{
    const struct of_device_id *match;
    struct device_node *np;

    // matches: NULL
    if (!matches)
        // __clk_of_table:
        // __clk_of_table_fixed_factor_clk
        // __clk_of_table_fixed_clk
        // __clk_of_table_exynos4210_audss_clk
        // __clk_of_table_exynos5250_audss_clk
        // __clk_of_table_exynos5420_clk
        matches = __clk_of_table;
        // matches:
        // __clk_of_table_fixed_factor_clk
        // __clk_of_table_fixed_clk
        // __clk_of_table_exynos4210_audss_clk
        // __clk_of_table_exynos5250_audss_clk
        // __clk_of_table_exynos5420_clk

    for_each_matching_node_and_match(np, matches, &match) {
    // for (np = of_find_matching_node_and_match(NULL, matches, &match);
    //      np; np = of_find_matching_node_and_match(np, matches, &match))

        // np: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소, match: __clk_of_table_exynos5420_clk

        // match->data: __clk_of_table_exynos5420_clk.data: exynos5420_clk_init
        of_clk_init_cb_t clk_init_cb = match->data;
        // clk_init_cb: exynos5420_clk_init

        // clk_init_cb: exynos5420_clk_init,
        // np: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소
        // exynos5420_clk_init(devtree에서 allnext로 순회 하면서 찾은 clock node의 주소)
        clk_init_cb(np);
    }
}
#endif
  • start_kernel()->time_init()->of_clk_init(NULL)->of_clk_init()->exynos5420_clk_init()

clk-exynos5420.c:clk_init_cb()

  • start_kernel()->time_init()->of_clk_init(NULL)->of_clk_init()->exynos5420_clk_init()
/* register exynos5420 clocks */
// ARM10C 20150103
// devtree에서 allnext로 순회 하면서 찾은 clock node의 주소
static void __init exynos5420_clk_init(struct device_node *np)
{
    void __iomem *reg_base;

// 2015/01/03 종료
// 2015/01/10 시작

    // np: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소
    if (np) {
        // np: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소
        // of_iomap(devtree에서 allnext로 순회 하면서 찾은 clock node의 주소, 0): 0xf0040000
        reg_base = of_iomap(np, 0);
        // reg_base: 0xf0040000
  • start_kernel()->time_init()->of_clk_init(NULL)->of_clk_init()->exynos5420_clk_init()->of_iomap();
    • // np: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소
    • reg_base = of_iomap(np, 0);

address.c::of_iomap()

  • start_kernel()->time_init()->of_clk_init(NULL)->of_clk_init()->exynos5420_clk_init()->of_iomap();
// ARM10C 20150110
// np: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소, 0
void __iomem *of_iomap(struct device_node *np, int index)
{
    struct resource res;

    // np: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소, index: 0
    // of_address_to_resource(devtree에서 allnext로 순회 하면서 찾은 clock node의 주소, 0, &res): 0
    if (of_address_to_resource(np, index, &res))
        return NULL;

    // np: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소
    // of_address_to_resource에서 한일(index: 0):
    // (&res)->start: 0x10010000
    // (&res)->end: 0x1003ffff
    // (&res)->flags: IORESOURCE_MEM: 0x00000200
    // (&res)->name: "/clock-controller@10010000"

    // res.start: 0x10010000, resource_size(&res): 0x30000
    // ioremap(0x10010000, 0x30000): 0xf0040000
    return ioremap(res.start, resource_size(&res));
    // return 0xf0040000
}
EXPORT_SYMBOL(of_iomap);

io.h::ioremap()

// ARM10C 20150110
// res.start: 0x10010000, resource_size(&res): 0x30000
#define ioremap(cookie,size)        __arm_ioremap((cookie), (size), MT_DEVICE)

ioremap.c::__arm_ioremap()

*
// ARM10C 20150110
// res.start: 0x10010000, resource_size(&res): 0x30000, MT_DEVICE: 0
void __iomem *
__arm_ioremap(phys_addr_t phys_addr, size_t size, unsigned int mtype)
{
    // phys_addr: 0x10010000, size: 0x30000, mtype: MT_DEVICE: 0
    // arch_ioremap_caller(0x10010000, 0x30000, MT_DEVICE: 0, __builtin_return_address(0)): 0xf0040000
    return arch_ioremap_caller(phys_addr, size, mtype,
        __builtin_return_address(0));
    // return 0xf0040000
}
EXPORT_SYMBOL(__arm_ioremap);

ioremap.c::__arm_ioremap_caller()

// ARM10C 20150110
// phys_addr: 0x10010000, size: 0x30000, mtype: MT_DEVICE: 0, __builtin_return_address(0)
void __iomem *__arm_ioremap_caller(phys_addr_t phys_addr, size_t size,
    unsigned int mtype, void *caller)
{
    phys_addr_t last_addr;
    // phys_addr: 0x10010000, PAGE_MASK: 0xFFFFF000
    unsigned long offset = phys_addr & ~PAGE_MASK;
    // offset: 0

    // phys_addr: 0x10010000, __phys_to_pfn(0x10010000): 0x10010
    unsigned long pfn = __phys_to_pfn(phys_addr);
    // pfn: 0x10010

    /*
     * Don't allow wraparound or zero size
     */
    // phys_addr: 0x10010000, size: 0x30000
    last_addr = phys_addr + size - 1;
    // last_addr: 0x1003ffff

    // size: 0x30000, last_addr: 0x1003ffff, phys_addr: 0x10010000
    if (!size || last_addr < phys_addr)
        return NULL;

    // pfn: 0x10010, offset: 0, size: 0x30000, mtype: MT_DEVICE: 0, caller: __builtin_return_address(0)
    // __arm_ioremap_pfn_caller(0x10010, 0, 0x30000, MT_DEVICE: 0, __builtin_return_address(0)): 0xf0040000
    return __arm_ioremap_pfn_caller(pfn, offset, size, mtype,
            caller);
    // return 0xf0040000
}

ioremap.c::__arm_ioremap_pfn_caller()

// ARM10C 20150110
// pfn: 0x10010, offset: 0, size: 0x30000, mtype: MT_DEVICE: 0, caller: __builtin_return_address(0)
void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
    unsigned long offset, size_t size, unsigned int mtype, void *caller)
{
    const struct mem_type *type;
    int err;
    unsigned long addr;
    struct vm_struct *area;
    // pfn: 0x10010, __pfn_to_phys(0x10010): 0x10010000
    phys_addr_t paddr = __pfn_to_phys(pfn);
    // paddr: 0x10010000

#ifndef CONFIG_ARM_LPAE // CONFIG_ARM_LPAE=n
    /*
     * High mappings must be supersection aligned
     */
    // pfn: 0x10010, paddr: 0x10010000, SUPERSECTION_MASK: 0xff000000
    if (pfn >= 0x100000 && (paddr & ~SUPERSECTION_MASK))
        return NULL;
#endif

    // mtype: MT_DEVICE: 0
    // get_mem_type(MT_DEVICE: 0): &mem_types[0]
    type = get_mem_type(mtype);
    // type: &mem_types[0]

    // type: &mem_types[0]
    if (!type)
        return NULL;

    /*
     * Page align the mapping size, taking account of any offset.
     */

    // offset: 0, size: 0x30000, PAGE_ALIGN(0x30000): 0x30000
    size = PAGE_ALIGN(offset + size);
    // size: 0x30000

    /*
     * Try to reuse one of the static mapping whenever possible.
     */

    // size: 0x30000, sizeof(phys_addr_t): 4, pfn: 0x10010
    if (size && !(sizeof(phys_addr_t) == 4 && pfn >= 0x100000)) {
        struct static_vm *svm;

        // paddr: 0x10010000 size: 0x30000, mtype: MT_DEVICE: 0
        // find_static_vm_paddr(0x10010000, 0x30000, MT_DEVICE: 0): NULL
        svm = find_static_vm_paddr(paddr, size, mtype);
        // svm: NULL

        // svm: NULL
        if (svm) {
            addr = (unsigned long)svm->vm.addr;
            addr += paddr - svm->vm.phys_addr;
            return (void __iomem *) (offset + addr);
        }
    }

    /*
     * Don't allow RAM to be mapped - this causes problems with ARMv6+
     */
    // pfn: 0x10010, pfn_valid(0x10010): 0
    if (WARN_ON(pfn_valid(pfn)))
        return NULL;

    // size: 0x30000, VM_IOREMAP: 0x00000001, caller: __builtin_return_address(0)
    // get_vm_area_caller(0x30000, 0x00000001, __builtin_return_address(0)): kmem_cache#30-oX (vm_struct)
    area = get_vm_area_caller(size, VM_IOREMAP, caller);
    // area: kmem_cache#30-oX (vm_struct)

    /*
    // get_vm_area_caller이 한일:
    // alloc area (CLK) 를 만들고 rb tree에 alloc area 를 추가
    // 가상주소 va_start 기준으로 CLK 를 RB Tree 추가한 결과
    //
    //                                  CHID-b
    //                               (0xF8000000)
    //                              /            \
    //                         TMR-b               PMU-b
    //                    (0xF6300000)             (0xF8180000)
    //                      /      \               /           \
    //                GIC#1-r      WDT-b         CMU-b         SRAM-b
    //            (0xF0002000)   (0xF6400000)  (0xF8100000)   (0xF8400000)
    //             /       \                                          \
    //        GIC#0-b     CLK-b                                        ROMC-r
    //    (0xF0000000)   (0xF0040000)                                 (0xF84C0000)
    //                   /      \
    //               COMB-r     SYSC-r
    //          (0xF0004000)   (0xF6100000)
    //
    // vmap_area_list에 GIC#0 - GIC#1 - COMB - CLK - 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: 0xf0040000
    // (kmem_cache#30-oX (vm_struct))->size: 0x31000
    // (kmem_cache#30-oX (vm_struct))->caller: __builtin_return_address(0)
    //
    // (kmem_cache#30-oX (vmap_area CLK))->vm: kmem_cache#30-oX (vm_struct)
    // (kmem_cache#30-oX (vmap_area CLK))->flags: 0x04
    */

    // area: kmem_cache#30-oX (vm_struct)
    if (!area)
        return NULL;

    // area->addr: (kmem_cache#30-oX (vm_struct))->addr: 0xf0040000
    addr = (unsigned long)area->addr;
    // addr: 0xf0040000

    // area->phys_addr: (kmem_cache#30-oX (vm_struct))->phys_addr, paddr: 0x10010000
    area->phys_addr = paddr;
    // area->phys_addr: (kmem_cache#30-oX (vm_struct))->phys_addr: 0x10010000

#if !defined(CONFIG_SMP) && !defined(CONFIG_ARM_LPAE) // CONFIG_SMP=y, CONFIG_ARM_LPAE=n
    if (DOMAIN_IO == 0 &&
        (((cpu_architecture() >= CPU_ARCH_ARMv6) && (get_cr() & CR_XP)) ||
           cpu_is_xsc3()) && pfn >= 0x100000 &&
           !((paddr | size | addr) & ~SUPERSECTION_MASK)) {
        area->flags |= VM_ARM_SECTION_MAPPING;
        err = remap_area_supersections(addr, pfn, size, type);
    } else if (!((paddr | size | addr) & ~PMD_MASK)) {
        area->flags |= VM_ARM_SECTION_MAPPING;
        err = remap_area_sections(addr, pfn, size, type);
    } else
#endif
        // addr: 0xf0040000, size: 0x31000, paddr: 0x10010000,
        // type->prot_pte: (&mem_types[0])->prot_pte: PROT_PTE_DEVICE | L_PTE_MT_DEV_SHARED | L_PTE_SHARED (0x653)
        // ioremap_page_range(0xf0040000, 0xf0071000, 0x10010000, PROT_PTE_DEVICE | L_PTE_MT_DEV_SHARED | L_PTE_SHARED (0x653)): 0
        err = ioremap_page_range(addr, addr + size, paddr,
                     __pgprot(type->prot_pte));
        // err: 0


        // ioremap_page_range에서 한일:
        // 0xc0004780이 가리키는 pte의 시작주소에 0x10010653 값을 갱신
        // (linux pgtable과 hardware pgtable의 값 같이 갱신)
        //
        //  pgd                   pte
        // |              |
        // +--------------+
        // |              |       +--------------+ +0
        // |              |       |  0xXXXXXXXX  | ---> 0x10010653 에 매칭되는 linux pgtable 값
        // +- - - - - - - +       |  Linux pt 0  |
        // |              |       +--------------+ +1024
        // |              |       |              |
        // +--------------+ +0    |  Linux pt 1  |
        // | *(c0004780)  |-----> +--------------+ +2048
        // |              |       |  0x10010653  | ---> 2308
        // +- - - - - - - + +4    |   h/w pt 0   |
        // | *(c0004784)  |-----> +--------------+ +3072
        // |              |       +              +
        // +--------------+ +8    |   h/w pt 1   |
        // |              |       +--------------+ +4096

    // err: 0
    if (err) {
        vunmap((void *)addr);
        return NULL;
    }

    // addr: 0xf0040000, size: 0x30000
    flush_cache_vmap(addr, addr + size);
    // cache의 값을 전부 메모리에 반영

    // offset: 0, addr: 0xf0040000
    return (void __iomem *) (offset + addr);
    // return 0xf0040000
}

clk-exynos5420.c:clk_init_cb()

  • start_kernel()->time_init()->of_clk_init(NULL)->of_clk_init()->exynos5420_clk_init()
/* register exynos5420 clocks */
// ARM10C 20150103
// devtree에서 allnext로 순회 하면서 찾은 clock node의 주소
static void __init exynos5420_clk_init(struct device_node *np)
{
    void __iomem *reg_base;

// 2015/01/03 종료
// 2015/01/10 시작

    // np: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소
    if (np) {
        // np: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소
        // of_iomap(devtree에서 allnext로 순회 하면서 찾은 clock node의 주소, 0): 0xf0040000
        reg_base = of_iomap(np, 0);
        // reg_base: 0xf0040000
  • of_iomap에서 한일: // device tree 있는 clock node에서 node의 resource 값을 가져옴 // of_address_to_resource에서 한일(index: 0): // (&res)->start: 0x10010000 // (&res)->end: 0x1003ffff // (&res)->flags: IORESOURCE_MEM: 0x00000200 // (&res)->name: "/clock-controller@10010000" // // alloc area (CLK) 를 만들고 rb tree에 alloc area 를 추가 // 가상주소 va_start 기준으로 CLK 를 RB Tree 추가한 결과 // // CHID-b // (0xF8000000) // / \ // TMR-b PMU-b // (0xF6300000) (0xF8180000) // / \ / \ // GIC#1-r WDT-b CMU-b SRAM-b // (0xF0002000) (0xF6400000) (0xF8100000) (0xF8400000) // / \ \ // GIC#0-b CLK-b ROMC-r // (0xF0000000) (0xF0040000) (0xF84C0000) // / \ // COMB-r SYSC-r // (0xF0004000) (0xF6100000) // // vmap_area_list에 GIC#0 - GIC#1 - COMB - CLK - 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: 0xf0040000 // (kmem_cache#30-oX (vm_struct))->size: 0x31000 // (kmem_cache#30-oX (vm_struct))->caller: __builtin_return_address(0) // // (kmem_cache#30-oX (vmap_area CLK))->vm: kmem_cache#30-oX (vm_struct) // (kmem_cache#30-oX (vmap_area CLK))->flags: 0x04 // // device tree 있는 clock node에서 node의 resource 값을 pgtable에 매핑함 // 0xc0004780이 가리키는 pte의 시작주소에 0x10010653 값을 갱신 // (linux pgtable과 hardware pgtable의 값 같이 갱신) // // pgd pte // | | // +--------------+ // | | +--------------+ +0 // | | | 0xXXXXXXXX | ---> 0x10010653 에 매칭되는 linux pgtable 값 // +- - - - - - - + | Linux pt 0 | // | | +--------------+ +1024 // | | | | // +--------------+ +0 | Linux pt 1 | // | *(c0004780) |-----> +--------------+ +2048 // | | | 0x10010653 | ---> 2308 // +- - - - - - - + +4 | h/w pt 0 | // | *(c0004784) |-----> +--------------+ +3072 // | | + + // +--------------+ +8 | h/w pt 1 | // | | +--------------+ +4096 // // cache의 값을 전부 메모리에 반영
/* register exynos5420 clocks */
// ARM10C 20150103
// devtree에서 allnext로 순회 하면서 찾은 clock node의 주소
static void __init exynos5420_clk_init(struct device_node *np)
{
    void __iomem *reg_base;

// 2015/01/03 종료
// 2015/01/10 시작

    // np: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소
    if (np) {
        // np: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소
        // of_iomap(devtree에서 allnext로 순회 하면서 찾은 clock node의 주소, 0): 0xf0040000
        reg_base = of_iomap(np, 0);
        // reg_base: 0xf0040000
        // reg_base: 0xf0040000
        if (!reg_base)
            panic("%s: failed to map registers\n", __func__);
    } else {
        panic("%s: unable to determine soc\n", __func__);
    }

    // np: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소, reg_base: 0xf0040000, nr_clks: 769
    // ARRAY_SIZE(exynos5420_clk_regs): 59
    samsung_clk_init(np, reg_base, nr_clks,
            exynos5420_clk_regs, ARRAY_SIZE(exynos5420_clk_regs),
            NULL, 0);

clk.c::samsung_clk_init()

/* setup the essentials required to support clock lookup using ccf */
// ARM10C 20150110
// np: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소, reg_base: 0xf0040000, nr_clks: 769
// exynos5420_clk_regs, ARRAY_SIZE(exynos5420_clk_regs): 59, NULL, 0
void __init samsung_clk_init(struct device_node *np, void __iomem *base,
        unsigned long nr_clks, unsigned long *rdump,
        unsigned long nr_rdump, unsigned long *soc_rdump,
        unsigned long nr_soc_rdump)
{
    // base: 0xf0040000
    reg_base = base;
    // reg_base: 0xf0040000

#ifdef CONFIG_PM_SLEEP // CONFIG_PM_SLEEP=y
    // rdump: exynos5420_clk_regs, nr_rdump: 59
    if (rdump && nr_rdump) {
        unsigned int idx;

        // sizeof(struct samsung_clk_reg_dump): 8 bytes, nr_rdump: 59, nr_soc_rdump: 0
        // kzalloc(472, GFP_KERNEL: 0xD0): kmem_cache#26-oX
        reg_dump = kzalloc(sizeof(struct samsung_clk_reg_dump)
                * (nr_rdump + nr_soc_rdump), GFP_KERNEL);
        // reg_dump: kmem_cache#26-oX

        // reg_dump: kmem_cache#26-oX
        if (!reg_dump) {
            pr_err("%s: memory alloc for register dump failed\n",
                    __func__);
            return;
        }

        // nr_rdump: 59
        for (idx = 0; idx < nr_rdump; idx++)
            // idx: 0, reg_dump[0].offset: (kmem_cache#26-oX)[0].offset, rdump[0]: exynos5420_clk_regs[0]
            reg_dump[idx].offset = rdump[idx];
            // reg_dump[0].offset: (kmem_cache#26-oX)[0].offset: exynos5420_clk_regs[0]
            //
            // idx: 1...58 까지 루프 수행

        // nr_soc_rdump: 0
        for (idx = 0; idx < nr_soc_rdump; idx++)
            reg_dump[nr_rdump + idx].offset = soc_rdump[idx];

        // nr_rdump: 59, nr_soc_rdump: 0
        nr_reg_dump = nr_rdump + nr_soc_rdump;
        // nr_reg_dump: 59

        register_syscore_ops(&samsung_clk_syscore_ops);

        // register_syscore_ops에서 한일:
        // syscore_ops_list의 tail에 (&samsung_clk_syscore_ops)->node 를 추가
    }
#endif

    // sizeof(struct clk *): 4, nr_clks: 769
    // kzalloc(3076, GFP_KERNEL: 0xD0): kmem_cache#23-o0
    clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
    // clk_table: kmem_cache#23-o0

    // clk_table: kmem_cache#23-o0
    if (!clk_table)
        panic("could not allocate clock lookup table\n");

    // np: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소
    if (!np)
        return;

#ifdef CONFIG_OF // CONFIG_OF=y
    // clk_table: kmem_cache#23-o0
    clk_data.clks = clk_table;
    // clk_data.clks: kmem_cache#23-o0 (clk_table)

    // nr_clks: 769
    clk_data.clk_num = nr_clks;
    // clk_data.clk_num: 769

    // np: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소
    of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);

    // of_clk_add_provider에서 한일:
    // struct of_clk_provider 의 메모리(kmem_cache#30-oX)를 할당 받고 맴버값 초기화 수행
    //
    // (kmem_cache#30-oX)->node: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소
    // (kmem_cache#30-oX)->data: &clk_data
    // (kmem_cache#30-oX)->get: of_clk_src_onecell_get
    //
    // list인 of_clk_providers의 head에 (kmem_cache#30-oX)->link를 추가
#endif
}

clk-exynos5420.c::exynos5420_clk_init()

/* register exynos5420 clocks */
// ARM10C 20150103
// devtree에서 allnext로 순회 하면서 찾은 clock node의 주소
static void __init exynos5420_clk_init(struct device_node *np)
{
    void __iomem *reg_base;

// 2015/01/03 종료
// 2015/01/10 시작

    // np: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소
    if (np) {
        // np: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소
        // of_iomap(devtree에서 allnext로 순회 하면서 찾은 clock node의 주소, 0): 0xf0040000
        reg_base = of_iomap(np, 0);
        // reg_base: 0xf0040000
        // reg_base: 0xf0040000
        if (!reg_base)
            panic("%s: failed to map registers\n", __func__);
    } else {
        panic("%s: unable to determine soc\n", __func__);
    }

    // np: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소, reg_base: 0xf0040000, nr_clks: 769
    // ARRAY_SIZE(exynos5420_clk_regs): 59
    samsung_clk_init(np, reg_base, nr_clks,
            exynos5420_clk_regs, ARRAY_SIZE(exynos5420_clk_regs),
            NULL, 0);
  • samsung_clk_init 에서 한일: // struct samsung_clk_reg_dump를 59개 만큼 메모리를 할당 받아 // exynos5420_clk_regs의 값으로 맴버값 세팅 // (kmem_cache#26-oX)[0...58].offset: exynos5420_clk_regs[0...58] // // syscore_ops_list의 tail에 (&samsung_clk_syscore_ops)->node 를 추가 // // struct clk * 를 769개 만큼 메모리를 clk_table에 할당 받음 // clk_table: kmem_cache#23-o0 // // clk_data.clks: kmem_cache#23-o0 (clk_table) // clk_data.clk_num: 769 // // struct of_clk_provider 의 메모리(kmem_cache#30-oX)를 할당 받고 맴버값 초기화 수행 // // (kmem_cache#30-oX)->node: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소 // (kmem_cache#30-oX)->data: &clk_data // (kmem_cache#30-oX)->get: of_clk_src_onecell_get // // list인 of_clk_providers의 head에 (kmem_cache#30-oX)->link를 추가
/* register exynos5420 clocks */
// ARM10C 20150103
// devtree에서 allnext로 순회 하면서 찾은 clock node의 주소
static void __init exynos5420_clk_init(struct device_node *np)
{
    void __iomem *reg_base;

// 2015/01/03 종료
// 2015/01/10 시작

    // np: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소
    if (np) {
        // np: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소
        // of_iomap(devtree에서 allnext로 순회 하면서 찾은 clock node의 주소, 0): 0xf0040000
        reg_base = of_iomap(np, 0);
        // reg_base: 0xf0040000
        // reg_base: 0xf0040000
        if (!reg_base)
            panic("%s: failed to map registers\n", __func__);
    } else {
        panic("%s: unable to determine soc\n", __func__);
    }

    // np: devtree에서 allnext로 순회 하면서 찾은 clock node의 주소, reg_base: 0xf0040000, nr_clks: 769
    // ARRAY_SIZE(exynos5420_clk_regs): 59
    samsung_clk_init(np, reg_base, nr_clks,
            exynos5420_clk_regs, ARRAY_SIZE(exynos5420_clk_regs),
            NULL, 0);

    // ARRAY_SIZE(exynos5420_fixed_rate_ext_clks): 1
    samsung_clk_of_register_fixed_ext(exynos5420_fixed_rate_ext_clks,
            ARRAY_SIZE(exynos5420_fixed_rate_ext_clks),
            ext_clk_match);

clk.c::samsung_clk_init()

/* setup the essentials required to support clock lookup using ccf */
void __init samsung_clk_init(struct device_node *np, void __iomem *base,
        unsigned long nr_clks, unsigned long *rdump,
        unsigned long nr_rdump, unsigned long *soc_rdump,
        unsigned long nr_soc_rdump)
{
        // base: 0xf0040000
    reg_base = base;
        // reg_base: 0xf0040000

#ifdef CONFIG_PM_SLEEP // CONFIG_PM_SLEEP=y
    if (rdump && nr_rdump) {
        unsigned int idx;
        reg_dump = kzalloc(sizeof(struct samsung_clk_reg_dump)
                * (nr_rdump + nr_soc_rdump), GFP_KERNEL);
        // reg_dump: 472 이므로 
        if (!reg_dump) {
            pr_err("%s: memory alloc for register dump failed\n",
                    __func__);
            return;
        }

clk.c:: samsung_clk_syscore_ops

static struct syscore_ops samsung_clk_syscore_ops = {
    .suspend    = samsung_clk_suspend,
    .resume     = samsung_clk_resume,
};

syscore.c::register_syscore_ops()

void register_syscore_ops(struct syscore_ops *ops)
{
    mutex_lock(&syscore_ops_lock);
        // syscore_ops_lock으로 mutex lock실행

    list_add_tail(&ops->node, &syscore_ops_list);
        // &ops->node: (&samsung_clk_syscore_ops)->node를 추가. 
    mutex_unlock(&syscore_ops_lock);
        // syscore_ops_lock으로 mutex unlock실행
}
EXPORT_SYMBOL_GPL(register_syscore_ops);

clk.c::clk_table

static struct clk **clk_table;

clk.c::samsung_clk_init()

/* setup the essentials required to support clock lookup using ccf */
void __init samsung_clk_init(struct device_node *np, void __iomem *base,
        unsigned long nr_clks, unsigned long *rdump,
        unsigned long nr_rdump, unsigned long *soc_rdump,
        unsigned long nr_soc_rdump)
{
        // base: 0xf0040000
    reg_base = base;
        // reg_base: 0xf0040000

#ifdef CONFIG_PM_SLEEP // CONFIG_PM_SLEEP=y
    if (rdump && nr_rdump) {
        unsigned int idx;
        reg_dump = kzalloc(sizeof(struct samsung_clk_reg_dump)
                * (nr_rdump + nr_soc_rdump), GFP_KERNEL);
        // reg_dump: 472 이므로 
        if (!reg_dump) {
            pr_err("%s: memory alloc for register dump failed\n",
                    __func__);
            return;
        }
        // nr_rdump: 59
        for (idx = 0; idx < nr_rdump; idx++)
                // idx:0 reg_dump[0].offset: (kmem_cach#26-oX)[0].offset, 
                // rdump[0]: exynos5420_clk_regs[0] 
            reg_dump[idx].offset = rdump[idx];
        // idx: 1...58까지 반복 실행
        for (idx = 0; idx < nr_soc_rdump; idx++)
                // nr_rdump:59, idx: nr_soc_rdump: 0 
            reg_dump[nr_rdump + idx].offset = soc_rdump[idx];
        nr_reg_dump = nr_rdump + nr_soc_rdump;
        register_syscore_ops(&samsung_clk_syscore_ops);
    }
#endif

    // sizeof(struct clk *): 4, nr_clks: 59,
    // sizeof(struct clk *) * nr_clks: 3076
    clk_table = kzalloc(sizeof(struct clk *) * nr_clks, GFP_KERNEL);
    // kmem_cache#23-oX(4096B)

    if (!clk_table)
        panic("could not allocate clock lookup table\n");

    if (!np)
        return;

#ifdef CONFIG_OF // CONFIG_OF=y
    clk_data.clks = clk_table;
    // clk_data.clks: kmem_cache#23-o0 (clk_table)

    clk_data.clk_num = nr_clks;
    // clk_data.clk_num: 769

    of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
#endif
}

clk.c::of_clk_add_provider()

struct of_clk_provider {
    struct list_head link;

    struct device_node *node;
    struct clk *(*get)(struct of_phandle_args *clkspec, void *data);
    void *data;
};
int of_clk_add_provider(struct device_node *np,
            struct clk *(*clk_src_get)(struct of_phandle_args *clkspec,
                           void *data),
            void *data)
{
    struct of_clk_provider *cp;

    cp = kzalloc(sizeof(struct of_clk_provider), GFP_KERNEL);
    if (!cp)
        return -ENOMEM;

    cp->node = of_node_get(np);
    cp->data = data;
    cp->get = clk_src_get;

    mutex_lock(&of_clk_lock);
    list_add(&cp->link, &of_clk_providers);
    mutex_unlock(&of_clk_lock);
    pr_debug("Added clock from %s\n", np->full_name);

    return 0;
}
EXPORT_SYMBOL_GPL(of_clk_add_provider);

clk.c::samsung_clk_of_register_fixed_ext()

void __init samsung_clk_of_register_fixed_ext(
            struct samsung_fixed_rate_clock *fixed_rate_clk,
            unsigned int nr_fixed_rate_clk,
            struct of_device_id *clk_matches)
{
    const struct of_device_id *match;
    struct device_node *np;
    u32 freq;

// #define for_each_matching_node_and_match(dn, matches, match) \
//  for (dn = of_find_matching_node_and_match(NULL, matches, match); \
//       dn; dn = of_find_matching_node_and_match(dn, matches, match))

    for_each_matching_node_and_match(np, clk_matches, &match) {
        if (of_property_read_u32(np, "clock-frequency", &freq))
            continue;
        fixed_rate_clk[(u32)match->data].fixed_rate = freq;
    }
    samsung_clk_register_fixed_rate(fixed_rate_clk, nr_fixed_rate_clk);
}

clk.c::samsung_clk_register_fixed_rate()

void __init samsung_clk_register_fixed_rate(
        struct samsung_fixed_rate_clock *list, unsigned int nr_clk)
{
    struct clk *clk;
    unsigned int idx, ret;

    for (idx = 0; idx < nr_clk; idx++, list++) {
        clk = clk_register_fixed_rate(NULL, list->name,
            list->parent_name, list->flags, list->fixed_rate);
        if (IS_ERR(clk)) {
            pr_err("%s: failed to register clock %s\n", __func__,
                list->name);
            continue;
        }

        samsung_clk_add_lookup(clk, list->id);

        /*
         * Unconditionally add a clock lookup for the fixed rate clocks.
         * There are not many of these on any of Samsung platforms.
         */
        ret = clk_register_clkdev(clk, list->name, NULL);
        if (ret)
            pr_err("%s: failed to register clock lookup for %s",
                __func__, list->name);
    }
}

clk-fixed-rate.c::clk_register_fixed_rate()

struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
        const char *parent_name, unsigned long flags,
        unsigned long fixed_rate)
{
    struct clk_fixed_rate *fixed;
    struct clk *clk;
    struct clk_init_data init;

    /* allocate fixed-rate clock */
    fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL);
    if (!fixed) {
        pr_err("%s: could not allocate fixed clk\n", __func__);
        return ERR_PTR(-ENOMEM);
    }

    init.name = name;
    init.ops = &clk_fixed_rate_ops;
    init.flags = flags | CLK_IS_BASIC;
    init.parent_names = (parent_name ? &parent_name: NULL);
    init.num_parents = (parent_name ? 1 : 0);

    /* struct clk_fixed_rate assignments */
    fixed->fixed_rate = fixed_rate;
    fixed->hw.init = &init;

    /* register the clock */
    clk = clk_register(dev, &fixed->hw);

    if (IS_ERR(clk))
        kfree(fixed);

    return clk;
}
EXPORT_SYMBOL_GPL(clk_register_fixed_rate);

clk.c::clk_register()

struct clk *clk_register(struct device *dev, struct clk_hw *hw)
{
    int ret;
    struct clk *clk;

    clk = kzalloc(sizeof(*clk), GFP_KERNEL);
    if (!clk) {
        pr_err("%s: could not allocate clk\n", __func__);
        ret = -ENOMEM;
        goto fail_out;
    }

    ret = _clk_register(dev, hw, clk);
    if (!ret)
        return clk;

    kfree(clk);
fail_out:
    return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(clk_register);

log

  • 1st log
   5ad5c32..e5f8cd1  master     -> origin/master
Updating 5ad5c32..e5f8cd1
Fast-forward
arch/arm/include/asm/bitops.h        |   2 ++
arch/arm/include/asm/io.h            |   2 ++
arch/arm/mm/ioremap.c                |  37 +++++++++++++++++++++++
drivers/clk/samsung/clk-exynos5420.c |   1 +
drivers/of/address.c                 |  15 ++++++++++
include/linux/kernel.h               |   1 +
include/linux/list.h                 |   5 ++++
include/linux/rbtree.h               |   2 ++
include/uapi/linux/kernel.h          |   2 ++
lib/rbtree.c                         |   2 ++
mm/vmalloc.c                         | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
11 files changed, 192 insertions(+)
  • 2nd log
   e5f8cd1..7a65241  master     -> origin/master
Updating e5f8cd1..7a65241
Fast-forward
arch/arm/mm/ioremap.c                      |  77 ++++++++++++++++++-
arch/arm/plat-samsung/include/plat/clock.h |   3 +-
drivers/base/syscore.c                     |  12 +++
drivers/clk/clk-fixed-rate.c               |  33 ++++++++
drivers/clk/clk.c                          |  33 ++++++++
drivers/clk/samsung/clk-exynos5420.c       | 103 +++++++++++++++++++++++++
drivers/clk/samsung/clk.c                  |  92 +++++++++++++++++++++--
drivers/clk/samsung/clk.h                  |   4 +
drivers/of/address.c                       |   3 +-
include/linux/bitops.h                     |   1 +
include/linux/clk-provider.h               |  12 ++-
include/linux/gfp.h                        |   1 +
include/linux/mod_devicetable.h            |   1 +
include/linux/of.h                         |   8 ++
include/linux/slab.h                       |  29 +++++++
include/linux/syscore_ops.h                |   1 +
lib/ioremap.c                              |   3 +
mm/vmalloc.c                               | 117 +++++++++++++++++++++++++----
18 files changed, 509 insertions(+), 24 deletions(-)

댓글 없음:

댓글 쓰기