1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Re-map IO memory to kernel address space so that we can access it. 4 * This is needed for high PCI addresses that aren't mapped in the 5 * 640k-1MB IO memory area on PC's 6 * 7 * (C) Copyright 1995 1996 Linus Torvalds 8 */ 9 #include <linux/vmalloc.h> 10 #include <linux/mm.h> 11 #include <linux/io.h> 12 #include <linux/export.h> 13 14 void __iomem *generic_ioremap_prot(phys_addr_t phys_addr, size_t size, 15 pgprot_t prot) 16 { 17 unsigned long offset, vaddr; 18 phys_addr_t last_addr; 19 struct vm_struct *area; 20 21 /* Disallow wrap-around or zero size */ 22 last_addr = phys_addr + size - 1; 23 if (!size || last_addr < phys_addr) 24 return NULL; 25 26 /* Page-align mappings */ 27 offset = phys_addr & (~PAGE_MASK); 28 phys_addr -= offset; 29 size = PAGE_ALIGN(size + offset); 30 31 if (!ioremap_allowed(phys_addr, size, pgprot_val(prot))) 32 return NULL; 33 34 area = get_vm_area_caller(size, VM_IOREMAP, 35 __builtin_return_address(0)); 36 if (!area) 37 return NULL; 38 vaddr = (unsigned long)area->addr; 39 area->phys_addr = phys_addr; 40 41 if (ioremap_page_range(vaddr, vaddr + size, phys_addr, prot)) { 42 free_vm_area(area); 43 return NULL; 44 } 45 46 return (void __iomem *)(vaddr + offset); 47 } 48 49 #ifndef ioremap_prot 50 void __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size, 51 unsigned long prot) 52 { 53 return generic_ioremap_prot(phys_addr, size, __pgprot(prot)); 54 } 55 EXPORT_SYMBOL(ioremap_prot); 56 #endif 57 58 void generic_iounmap(volatile void __iomem *addr) 59 { 60 void *vaddr = (void *)((unsigned long)addr & PAGE_MASK); 61 62 if (!iounmap_allowed(vaddr)) 63 return; 64 65 if (is_vmalloc_addr(vaddr)) 66 vunmap(vaddr); 67 } 68 69 #ifndef iounmap 70 void iounmap(volatile void __iomem *addr) 71 { 72 generic_iounmap(addr); 73 } 74 EXPORT_SYMBOL(iounmap); 75 #endif 76