ARM10C 74주차 후기
일시 : 2014.10.18 (74주차)
모임명 : NAVER개발자커뮤니티지원_IAMROOT.ORG_10차ARM-C
장소 : 토즈 타워점
장소지원 : NAVER 개발자 커뮤니티 지원 프로그램
참여인원 : 4명
도움될 만한 정보 공유
진도 :
- init_IRQ();
- exynos-combiner.c 에 정의된 함수를 사용하여 초기화 수행
- __irqchip_begin: irqchip_of_match_exynos4210_combiner
main.c::start_kernel()
asmlinkage void __init start_kernel(void)
{
...
boot_cpu_init();
// 현재 cpu(core id)를 얻어서 cpu_XXX_bits[] 의 cpu를 셋한다.
...
setup_arch(&command_line);
...
mm_init();
// buddy와 slab 을 활성화 하고 기존 할당 받은 bootmem 은 buddy,
// pcpu 메모리, vmlist 는 slab으로 이관
sched_init();
// scheduler가 사용하는 자료 구조 초기화, idle_threads를 init_task로 세팅
preempt_disable();
// preempt count를 증가시켜 preemption 못하도록 막음
...
rcu_init();
// rcu 자료구조 bh, sched, preempt 를 각각 초기화 수행함
...
radix_tree_init();
// radix tree로 사용하는 radix_tree_node_cachep에 kmem_cache#20을 생성 및 초기화 후 할당하고
// height_to_maxindex을 초기화 수행
/* 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();
지난시간에 이어 init_IRQ() 분석 진행 중
irq-gic.c::gic_of_init()
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;
if (WARN_ON(!node))
return -ENODEV;
dist_base = of_iomap(node, 0);
WARN(!dist_base, "unable to map gic dist registers\n");
cpu_base = of_iomap(node, 1);
WARN(!cpu_base, "unable to map gic cpu registers\n");
if (of_property_read_u32(node, "cpu-offset", &percpu_offset))
percpu_offset = 0;
gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node);
if (!gic_cnt)
gic_init_physaddr(node);
if (parent) {
irq = irq_of_parse_and_map(node, 0);
gic_cascade_irq(gic_cnt, irq);
}
gic_cnt++;
return 0;
}
address.c::of_iomap()
- dist_base = of_iomap(node, 0);
void __iomem *of_iomap(struct device_node *np, int index)
{
struct resource res;
if (of_address_to_resource(np, index, &res))
return NULL;
return ioremap(res.start, resource_size(&res));
}
EXPORT_SYMBOL(of_iomap);
resource
address.c::of_address_to_resource()
- if (of_address_to_resource(np, index, &res))
int of_address_to_resource(struct device_node *dev, int index,
struct resource *r)
{
const __be32 *addrp;
u64 size;
unsigned int flags;
const char *name = NULL;
addrp = of_get_address(dev, index, &size, &flags);
if (addrp == NULL)
return -EINVAL;
/* Get optional "reg-names" property to add a name to a resource */
of_property_read_string_index(dev, "reg-names", index, &name);
return __of_address_to_resource(dev, addrp, size, flags, name, r);
}
EXPORT_SYMBOL_GPL(of_address_to_resource);
address.c::of_get_address()
struct device_node {
const char *name;
const char *type;
phandle phandle;
const char *full_name;
struct property *properties;
struct property *deadprops; /* removed properties */
struct device_node *parent;
struct device_node *child;
struct device_node *sibling;
struct device_node *next; /* next device of same type */
struct device_node *allnext; /* next in list of all nodes */
struct proc_dir_entry *pde; /* this node's proc directory */
struct kref kref;
unsigned long _flags;
void *data;
#if defined(CONFIG_SPARC) // CONFIG_SPARC=n
const char *path_component_name;
unsigned int unique_id;
struct of_irq_controller *irq_trans;
#endif
};
- address.c::of_match_bus()
- address.c::of_bus of_busses[] = {
/* ISA */
{
.name = "isa",
.addresses = "reg",
.match = of_bus_isa_match,
.count_cells = of_bus_isa_count_cells,
.map = of_bus_isa_map,
.translate = of_bus_isa_translate,
.get_flags = of_bus_isa_get_flags,
},
/* Default */
{
.name = "default",
.addresses = "reg",
.match = NULL,
.count_cells = of_bus_default_count_cells,
.map = of_bus_default_map,
.translate = of_bus_default_translate,
.get_flags = of_bus_default_get_flags,
},
- address.c::of_bus_isa_match()
static int of_bus_isa_match(struct device_node *np)
{
return !strcmp(np->name, "isa");
}
static struct of_bus *of_match_bus(struct device_node *np)
{
int i;
for (i = 0; i < ARRAY_SIZE(of_busses); i++)
if (!of_busses[i].match || of_busses[i].match(np))
// i: 1
return &of_busses[i];
// return &of_busses[1]
BUG();
return NULL;
}
여기서 i: 1이 되어 ISA가 아닌 Default가 반환된다.
address.c::of_get_address()에서
- bus = of_match_bus(parent);
// bus: &of_busses[1]
address.c::of_bus_default_count_cells()
static void of_bus_default_count_cells(struct device_node *dev,
int *addrc, int *sizec)
{
if (addrc)
*addrc = of_n_addr_cells(dev);
if (sizec)
*sizec = of_n_size_cells(dev);
}
- base.c::of_n_addr_cells()
int of_n_addr_cells(struct device_node *np)
{
const __be32 *ip;
do {
if (np->parent)
np = np->parent;
ip = of_get_property(np, "#address-cells", NULL);
if (ip)
return be32_to_cpup(ip);
} while (np->parent);
/* No #address-cells property for the root node */
return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
}
EXPORT_SYMBOL(of_n_addr_cells);
- base.c::of_n_size_cells()
int of_n_size_cells(struct device_node *np)
{
const __be32 *ip;
do {
if (np->parent)
np = np->parent;
ip = of_get_property(np, "#size-cells", NULL);
if (ip)
return be32_to_cpup(ip);
} while (np->parent);
/* No #size-cells property for the root node */
return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
}
EXPORT_SYMBOL(of_n_size_cells);
static inline u64 of_read_number(const __be32 *cell, int size)
{
u64 r = 0;
while (size--)
r = (r << 32) | be32_to_cpu(*(cell++));
return r;
}
size 값 (0x1000)을 반환한다.
ioport.h::
#define IORESOURCE_MEM 0x00000200
- address.h::of_bus_default_get_flags()
static unsigned int of_bus_default_get_flags(const __be32 *addr)
{
return IORESOURCE_MEM;
}
const __be32 *of_get_address(struct device_node *dev, int index, u64 *size,
unsigned int *flags)
{
const __be32 *prop;
unsigned int psize;
struct device_node *parent;
struct of_bus *bus;
int onesize, i, na, ns;
/* Get parent & match bus type */
parent = of_get_parent(dev);
if (parent == NULL)
return NULL;
bus = of_match_bus(parent);
bus->count_cells(dev, &na, &ns);
of_node_put(parent);
if (!OF_CHECK_ADDR_COUNT(na))
return NULL;
/* Get "reg" or "assigned-addresses" property */
prop = of_get_property(dev, bus->addresses, &psize);
if (prop == NULL)
return NULL;
psize /= 4;
onesize = na + ns;
for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
if (i == index) {
if (size)
*size = of_read_number(prop + na, ns);
if (flags)
*flags = bus->get_flags(prop);
return prop;
}
return NULL;
}
EXPORT_SYMBOL(of_get_address);
- return gic node의 reg property 값은 시작 주소.
address.c::of_address_to_resource()
int of_address_to_resource(struct device_node *dev, int index,
struct resource *r)
{
const __be32 *addrp;
u64 size;
unsigned int flags;
const char *name = NULL;
addrp = of_get_address(dev, index, &size, &flags);
// addrp: gic node 값의 시작 주소.
if (addrp == NULL)
return -EINVAL;
/* Get optional "reg-names" property to add a name to a resource */
of_property_read_string_index(dev, "reg-names", index, &name);
return __of_address_to_resource(dev, addrp, size, flags, name, r);
}
EXPORT_SYMBOL_GPL(of_address_to_resource);
base.c::of_property_read_string_index()
int of_property_read_string_index(struct device_node *np, const char *propname,
int index, const char **output)
{
struct property *prop = of_find_property(np, propname, NULL);
int i = 0;
size_t l = 0, total = 0;
const char *p;
if (!prop)
return -EINVAL;
if (!prop->value)
return -ENODATA;
if (strnlen(prop->value, prop->length) >= prop->length)
return -EILSEQ;
p = prop->value;
for (i = 0; total < prop->length; total += l, p += l) {
l = strlen(p) + 1;
if (i++ == index) {
*output = p;
return 0;
}
}
return -ENODATA;
}
EXPORT_SYMBOL_GPL(of_property_read_string_index);
address.c::__of_address_to_resource()
return __of_address_to_resource(dev, addrp, size, flags, name, r);
dev:
- addrp:
- size:
- flags:
- name:
- r:
static int __of_address_to_resource(struct device_node *dev,
const __be32 *addrp, u64 size, unsigned int flags,
const char *name, struct resource *r)
{
u64 taddr;
if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
return -EINVAL;
taddr = of_translate_address(dev, addrp);
if (taddr == OF_BAD_ADDR)
return -EINVAL;
memset(r, 0, sizeof(struct resource));
if (flags & IORESOURCE_IO) {
unsigned long port;
port = pci_address_to_pio(taddr);
if (port == (unsigned long)-1)
return -EINVAL;
r->start = port;
r->end = port + size - 1;
} else {
r->start = taddr;
r->end = taddr + size - 1;
}
r->flags = flags;
r->name = name ? name : dev->full_name;
return 0;
}
address.c::of_translate_address()
- taddr = of_translate_address(dev, addrp);
u64 of_translate_address(struct device_node *dev, const __be32 *in_addr)
{
return __of_translate_address(dev, in_addr, "ranges");
}
EXPORT_SYMBOL(of_translate_address);
address.c::__of_translate_address()
static u64 __of_translate_address(struct device_node *dev,
const __be32 *in_addr, const char *rprop)
{
struct device_node *parent = NULL;
struct of_bus *bus, *pbus;
__be32 addr[OF_MAX_ADDR_CELLS];
int na, ns, pna, pns;
u64 result = OF_BAD_ADDR;
pr_debug("OF: ** translation for device %s **\n", of_node_full_name(dev));
/* Increase refcount at current level */
of_node_get(dev);
/* Get parent & match bus type */
parent = of_get_parent(dev);
if (parent == NULL)
goto bail;
bus = of_match_bus(parent);
/* Count address cells & copy address locally */
bus->count_cells(dev, &na, &ns);
if (!OF_CHECK_COUNTS(na, ns)) {
printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
of_node_full_name(dev));
goto bail;
}
memcpy(addr, in_addr, na * 4);
pr_debug("OF: bus is %s (na=%d, ns=%d) on %s\n",
bus->name, na, ns, of_node_full_name(parent));
of_dump_addr("OF: translating address:", addr, na);
/* Translate */
for (;;) {
/* Switch to parent bus */
of_node_put(dev);
dev = parent;
parent = of_get_parent(dev);
/* If root, we have finished */
if (parent == NULL) {
pr_debug("OF: reached root node\n");
result = of_read_number(addr, na);
break;
}
/* Get new parent bus and counts */
pbus = of_match_bus(parent);
pbus->count_cells(dev, &pna, &pns);
if (!OF_CHECK_COUNTS(pna, pns)) {
printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
of_node_full_name(dev));
break;
}
pr_debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
pbus->name, pna, pns, of_node_full_name(parent));
/* Apply bus translation */
if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop))
break;
/* Complete the move up one level */
na = pna;
ns = pns;
bus = pbus;
of_dump_addr("OF: one level translation:", addr, na);
}
bail:
of_node_put(parent);
of_node_put(dev);
return result;
}
- pr_debug("OF: ** translation for device %s **\n", of_node_full_name(dev));
- of.h::of_node_full_name()
- fullname: @를 포함한 string: /interrupt-controller@10481000
- name: @뒤를 뺀 node string: interrupt-controller
static inline const char *of_node_full_name(const struct device_node *np)
{
return np ? np->full_name : "<no-node>";
}
static inline struct device_node *of_node_get(struct device_node *node)
{
return node;
}
parent = of_get_parent(dev);
bus = of_match_bus(parent);
bus->count_cells(dev, &na, &ns);
- &of_busses[1]
- of_bus_default_count_cells()
- na: 1, ns:1
if (!OF_CHECK_COUNTS(na, ns)) {
- address::OF_CHECK_COUNT()
#define OF_CHECK_COUNTS(na, ns) (OF_CHECK_ADDR_COUNT(na) && (ns) > 0)
pr_debug("OF: bus is %s (na=%d, ns=%d) on %s\n", bus->name, na, ns, of_node_full_name(parent));
- bus->name: "default"
- na: 1, ns:1
- of_node_fullname: "/"
of_dump_addr("OF: translating address:", addr, na);
- address.c::of_dump_addr()
static void of_dump_addr(const char *s, const __be32 *addr, int na) { }
ioremap.c::__arm_ioremap_caller()
void __iomem *__arm_ioremap_caller(phys_addr_t phys_addr, size_t size,
unsigned int mtype, void *caller)
{
phys_addr_t last_addr;
unsigned long offset = phys_addr & ~PAGE_MASK;
unsigned long pfn = __phys_to_pfn(phys_addr);
/*
* Don't allow wraparound or zero size
*/
last_addr = phys_addr + size - 1;
if (!size || last_addr < phys_addr)
return NULL;
return __arm_ioremap_pfn_caller(pfn, offset, size, mtype,
caller);
}
ioremap.c::__arm_ioremap_pfn_caller()
- type = get_mem_type(mtype);
- mtype: DT_DEVICE: 0
const struct mem_type *get_mem_type(unsigned int type)
{
return type < ARRAY_SIZE(mem_types) ? &mem_types[type] : NULL;
}
EXPORT_SYMBOL(get_mem_type);
size = PAGE_ALIGN(offset + size);
if (size && !(sizeof(phys_addr_t) == 4 && pfn >= 0x100000)) {
- (size && !(sizeof(phys_addr_t) == 4 && pfn >= 0x100000)): 1
- svm = find_static_vm_paddr(paddr, size, mtype);
ioremap.c::find_static_vm_paddr()
- list_for_each_entry(svm, &static_vmlist, list)
- #define VM_ARM_STATIC_MAPPING 0x40000000
- #define VM_ARM_MTYPE_MASK (0x1f << 20)
static struct static_vm *find_static_vm_paddr(phys_addr_t paddr,
size_t size, unsigned int mtype)
{
struct static_vm *svm;
struct vm_struct *vm;
list_for_each_entry(svm, &static_vmlist, list) {
vm = &svm->vm;
if (!(vm->flags & VM_ARM_STATIC_MAPPING))
continue;
if ((vm->flags & VM_ARM_MTYPE_MASK) != VM_ARM_MTYPE(mtype))
continue;
if (vm->phys_addr > paddr ||
paddr + size - 1 > vm->phys_addr + vm->size - 1)
continue;
return svm;
}
return NULL;
}
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;
phys_addr_t paddr = __pfn_to_phys(pfn);
#ifndef CONFIG_ARM_LPAE
/*
* High mappings must be supersection aligned
*/
if (pfn >= 0x100000 && (paddr & ~SUPERSECTION_MASK))
return NULL;
#endif
type = get_mem_type(mtype);
if (!type)
return NULL;
/*
* Page align the mapping size, taking account of any offset.
*/
size = PAGE_ALIGN(offset + size);
/*
* Try to reuse one of the static mapping whenever possible.
*/
if (size && !(sizeof(phys_addr_t) == 4 && pfn >= 0x100000)) {
struct static_vm *svm;
svm = find_static_vm_paddr(paddr, size, mtype);
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+
*/
if (WARN_ON(pfn_valid(pfn)))
return NULL;
area = get_vm_area_caller(size, VM_IOREMAP, caller);
if (!area)
return NULL;
addr = (unsigned long)area->addr;
area->phys_addr = paddr;
#if !defined(CONFIG_SMP) && !defined(CONFIG_ARM_LPAE)
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
err = ioremap_page_range(addr, addr + size, paddr,
__pgprot(type->prot_pte));
if (err) {
vunmap((void *)addr);
return NULL;
}
flush_cache_vmap(addr, addr + size);
return (void __iomem *) (offset + addr);
}
git log
From github.com:arm10c/linux-stable
44dc97e..9f21bbb master -> origin/master
Merge made by the 'recursive' strategy.
arch/arm/include/asm/io.h | 5 +
arch/arm/include/asm/memory.h | 2 +
arch/arm/include/asm/pgtable-2level.h | 8 ++
arch/arm/mm/ioremap.c | 54 ++++++++-
arch/arm/mm/mm.h | 5 +
arch/arm/mm/mmu.c | 5 +
drivers/irqchip/irq-gic.c | 5 +
drivers/of/address.c | 212 +++++++++++++++++++++++++++++++++-
drivers/of/base.c | 73 +++++++++---
drivers/of/irq.c | 82 +++++++------
include/asm-generic/io.h | 2 +-
include/linux/ioport.h | 6 +
include/linux/list.h | 5 +
include/linux/of.h | 12 ++
include/linux/of_address.h | 2 +-
15 files changed, 420 insertions(+), 58 deletions(-)
댓글 없음:
댓글 쓰기