ioremap

来源:互联网 发布:江恩八线指标源码 编辑:程序博客网 时间:2024/05/19 16:21

1. ioremap

arch/arm/include/asm/io.h
#define ioremap(cookie,size)        __arch_ioremap((cookie), (size), MT_DEVICE)
#define __arch_ioremap            __arm_ioremap

arch/arm/mm/ioremap.c
void __iomem *
__arm_ioremap(unsigned long phys_addr, size_t size, unsigned int mtype)
{
    return __arm_ioremap_caller(phys_addr, size, mtype,
            __builtin_return_address(0));
}

void __iomem *__arm_ioremap_caller(unsigned long phys_addr, size_t size,
    unsigned int mtype, void *caller)
{
    unsigned long 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);
}

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;

    /*
     * High mappings must be supersection aligned
     */
    if (pfn >= 0x100000 && (__pfn_to_phys(pfn) & ~SUPERSECTION_MASK))
        return NULL;

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

    type = get_mem_type(mtype);
    if (!type)
        return NULL;

    /*1]得到 vm_area:
     * Page align the mapping size, taking account of any offset.
     */
    size = PAGE_ALIGN(offset + size);

    area = get_vm_area_caller(size, VM_IOREMAP, caller);
     if (!area)
         return NULL;
     addr = (unsigned long)area->addr;
    /*2] ioremap_page_range*/
    err = ioremap_page_range(addr, addr + size, __pfn_to_phys(pfn),
                     __pgprot(type->prot_pte));

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

    flush_cache_vmap(addr, addr + size);
    return (void __iomem *) (offset + addr);
}

/*建立了对应的页表*/
lib/ioremap.c
int ioremap_page_range(unsigned long addr,
               unsigned long end, phys_addr_t phys_addr, pgprot_t prot)
{
    pgd_t *pgd;
    unsigned long start;
    unsigned long next;
    int err;

    BUG_ON(addr >= end);

    start = addr;
    phys_addr -= addr;
    pgd = pgd_offset_k(addr);
    do {
        next = pgd_addr_end(addr, end);
        err = ioremap_pud_range(pgd, addr, next, phys_addr+addr, prot);
        if (err)
            break;
    } while (pgd++, addr = next, addr != end);

    flush_cache_vmap(start, end);

    return err;
}

2. iounmap 对应的函数


arch/arm/include/asm/io.h:

#define iounmap                __arch_iounmap

#define __arch_iounmap            __iounmap

arch/arm/mm/ioremap.c

void __iounmap(volatile void __iomem *io_addr)
{

}