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/sched.h> 12 #include <linux/io.h> 13 #include <linux/export.h> 14 #include <asm/cacheflush.h> 15 16 #include "pgalloc-track.h" 17 18 #ifdef CONFIG_HAVE_ARCH_HUGE_VMAP 19 static bool __ro_after_init iomap_max_page_shift = PAGE_SHIFT; 20 21 static int __init set_nohugeiomap(char *str) 22 { 23 iomap_max_page_shift = P4D_SHIFT; 24 return 0; 25 } 26 early_param("nohugeiomap", set_nohugeiomap); 27 #else /* CONFIG_HAVE_ARCH_HUGE_VMAP */ 28 static const bool iomap_max_page_shift = PAGE_SHIFT; 29 #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */ 30 31 int ioremap_page_range(unsigned long addr, 32 unsigned long end, phys_addr_t phys_addr, pgprot_t prot) 33 { 34 return vmap_range(addr, end, phys_addr, prot, iomap_max_page_shift); 35 } 36 37 #ifdef CONFIG_GENERIC_IOREMAP 38 void __iomem *ioremap_prot(phys_addr_t addr, size_t size, unsigned long prot) 39 { 40 unsigned long offset, vaddr; 41 phys_addr_t last_addr; 42 struct vm_struct *area; 43 44 /* Disallow wrap-around or zero size */ 45 last_addr = addr + size - 1; 46 if (!size || last_addr < addr) 47 return NULL; 48 49 /* Page-align mappings */ 50 offset = addr & (~PAGE_MASK); 51 addr -= offset; 52 size = PAGE_ALIGN(size + offset); 53 54 area = get_vm_area_caller(size, VM_IOREMAP, 55 __builtin_return_address(0)); 56 if (!area) 57 return NULL; 58 vaddr = (unsigned long)area->addr; 59 60 if (ioremap_page_range(vaddr, vaddr + size, addr, __pgprot(prot))) { 61 free_vm_area(area); 62 return NULL; 63 } 64 65 return (void __iomem *)(vaddr + offset); 66 } 67 EXPORT_SYMBOL(ioremap_prot); 68 69 void iounmap(volatile void __iomem *addr) 70 { 71 vunmap((void *)((unsigned long)addr & PAGE_MASK)); 72 } 73 EXPORT_SYMBOL(iounmap); 74 #endif /* CONFIG_GENERIC_IOREMAP */ 75