mirror of
https://github.com/torvalds/linux.git
synced 2024-12-14 15:13:52 +00:00
caab277b1d
Based on 1 normalized pattern(s): this program is free software you can redistribute it and or modify it under the terms of the gnu general public license version 2 as published by the free software foundation this program is distributed in the hope that it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details you should have received a copy of the gnu general public license along with this program if not see http www gnu org licenses extracted by the scancode license scanner the SPDX license identifier GPL-2.0-only has been chosen to replace the boilerplate/reference in 503 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Alexios Zavras <alexios.zavras@intel.com> Reviewed-by: Allison Randal <allison@lohutok.net> Reviewed-by: Enrico Weigelt <info@metux.net> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190602204653.811534538@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
103 lines
2.4 KiB
C
103 lines
2.4 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Based on arch/arm/mm/ioremap.c
|
|
*
|
|
* (C) Copyright 1995 1996 Linus Torvalds
|
|
* Hacked for ARM by Phil Blundell <philb@gnu.org>
|
|
* Hacked to allow all architectures to build, and various cleanups
|
|
* by Russell King
|
|
* Copyright (C) 2012 ARM Ltd.
|
|
*/
|
|
|
|
#include <linux/export.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/vmalloc.h>
|
|
#include <linux/io.h>
|
|
|
|
#include <asm/fixmap.h>
|
|
#include <asm/tlbflush.h>
|
|
#include <asm/pgalloc.h>
|
|
|
|
static void __iomem *__ioremap_caller(phys_addr_t phys_addr, size_t size,
|
|
pgprot_t prot, void *caller)
|
|
{
|
|
unsigned long last_addr;
|
|
unsigned long offset = phys_addr & ~PAGE_MASK;
|
|
int err;
|
|
unsigned long addr;
|
|
struct vm_struct *area;
|
|
|
|
/*
|
|
* Page align the mapping address and size, taking account of any
|
|
* offset.
|
|
*/
|
|
phys_addr &= PAGE_MASK;
|
|
size = PAGE_ALIGN(size + offset);
|
|
|
|
/*
|
|
* Don't allow wraparound, zero size or outside PHYS_MASK.
|
|
*/
|
|
last_addr = phys_addr + size - 1;
|
|
if (!size || last_addr < phys_addr || (last_addr & ~PHYS_MASK))
|
|
return NULL;
|
|
|
|
/*
|
|
* Don't allow RAM to be mapped.
|
|
*/
|
|
if (WARN_ON(pfn_valid(__phys_to_pfn(phys_addr))))
|
|
return NULL;
|
|
|
|
area = get_vm_area_caller(size, VM_IOREMAP, caller);
|
|
if (!area)
|
|
return NULL;
|
|
addr = (unsigned long)area->addr;
|
|
area->phys_addr = phys_addr;
|
|
|
|
err = ioremap_page_range(addr, addr + size, phys_addr, prot);
|
|
if (err) {
|
|
vunmap((void *)addr);
|
|
return NULL;
|
|
}
|
|
|
|
return (void __iomem *)(offset + addr);
|
|
}
|
|
|
|
void __iomem *__ioremap(phys_addr_t phys_addr, size_t size, pgprot_t prot)
|
|
{
|
|
return __ioremap_caller(phys_addr, size, prot,
|
|
__builtin_return_address(0));
|
|
}
|
|
EXPORT_SYMBOL(__ioremap);
|
|
|
|
void __iounmap(volatile void __iomem *io_addr)
|
|
{
|
|
unsigned long addr = (unsigned long)io_addr & PAGE_MASK;
|
|
|
|
/*
|
|
* We could get an address outside vmalloc range in case
|
|
* of ioremap_cache() reusing a RAM mapping.
|
|
*/
|
|
if (is_vmalloc_addr((void *)addr))
|
|
vunmap((void *)addr);
|
|
}
|
|
EXPORT_SYMBOL(__iounmap);
|
|
|
|
void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size)
|
|
{
|
|
/* For normal memory we already have a cacheable mapping. */
|
|
if (pfn_valid(__phys_to_pfn(phys_addr)))
|
|
return (void __iomem *)__phys_to_virt(phys_addr);
|
|
|
|
return __ioremap_caller(phys_addr, size, __pgprot(PROT_NORMAL),
|
|
__builtin_return_address(0));
|
|
}
|
|
EXPORT_SYMBOL(ioremap_cache);
|
|
|
|
/*
|
|
* Must be called after early_fixmap_init
|
|
*/
|
|
void __init early_ioremap_init(void)
|
|
{
|
|
early_ioremap_setup();
|
|
}
|