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(-)
댓글 없음:
댓글 쓰기