2017-07-10 18:05:09 -07:00
/*
* ( C ) Copyright 1995 1996 Linus Torvalds
* ( C ) Copyright 2012 Regents of the University of California
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation , version 2.
*
* 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 .
*/
# include <linux/export.h>
# include <linux/mm.h>
# include <linux/vmalloc.h>
# include <linux/io.h>
# include <asm/pgtable.h>
/*
* Remap an arbitrary physical address space into the kernel virtual
* address space . Needed when the kernel wants to access high addresses
* directly .
*
* NOTE ! We need to allow non - page - aligned mappings too : we will obviously
* have to convert them into an offset in a page - aligned mapping , but the
* caller shouldn ' t need to know that small detail .
*/
static void __iomem * __ioremap_caller ( phys_addr_t addr , size_t size ,
pgprot_t prot , void * caller )
{
phys_addr_t last_addr ;
unsigned long offset , vaddr ;
struct vm_struct * area ;
/* Disallow wrap-around or zero size */
last_addr = addr + size - 1 ;
if ( ! size | | last_addr < addr )
return NULL ;
/* Page-align mappings */
offset = addr & ( ~ PAGE_MASK ) ;
2018-10-02 16:52:31 +08:00
addr - = offset ;
2017-07-10 18:05:09 -07:00
size = PAGE_ALIGN ( size + offset ) ;
area = get_vm_area_caller ( size , VM_IOREMAP , caller ) ;
if ( ! area )
return NULL ;
vaddr = ( unsigned long ) area - > addr ;
if ( ioremap_page_range ( vaddr , vaddr + size , addr , prot ) ) {
free_vm_area ( area ) ;
return NULL ;
}
return ( void __iomem * ) ( vaddr + offset ) ;
}
/*
* ioremap - map bus memory into CPU space
* @ offset : bus address of the memory
* @ size : size of the resource to map
*
* ioremap performs a platform specific sequence of operations to
* make bus memory CPU accessible via the readb / readw / readl / writeb /
* writew / writel functions and the other mmio helpers . The returned
* address is not guaranteed to be usable directly as a virtual
* address .
*
* Must be freed with iounmap .
*/
void __iomem * ioremap ( phys_addr_t offset , unsigned long size )
{
return __ioremap_caller ( offset , size , PAGE_KERNEL ,
__builtin_return_address ( 0 ) ) ;
}
EXPORT_SYMBOL ( ioremap ) ;
/**
* iounmap - Free a IO remapping
* @ addr : virtual address from ioremap_ *
*
* Caller must ensure there is only one unmapping for the same pointer .
*/
2017-11-29 17:55:14 -08:00
void iounmap ( volatile void __iomem * addr )
2017-07-10 18:05:09 -07:00
{
vunmap ( ( void * ) ( ( unsigned long ) addr & PAGE_MASK ) ) ;
}
EXPORT_SYMBOL ( iounmap ) ;