参照元

説明

引数

返り値

参考

実装

static 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);
}

コメント


トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2016-02-24 (水) 12:01:25