18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci#include <linux/io.h> 48c2ecf20Sopenharmony_ci#include <linux/slab.h> 58c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_civoid __iomem *__ioremap_caller(phys_addr_t addr, unsigned long size, 88c2ecf20Sopenharmony_ci pgprot_t prot, void *caller) 98c2ecf20Sopenharmony_ci{ 108c2ecf20Sopenharmony_ci phys_addr_t paligned, offset; 118c2ecf20Sopenharmony_ci void __iomem *ret; 128c2ecf20Sopenharmony_ci int err; 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci /* We don't support the 4K PFN hack with ioremap */ 158c2ecf20Sopenharmony_ci if (pgprot_val(prot) & H_PAGE_4K_PFN) 168c2ecf20Sopenharmony_ci return NULL; 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci /* 198c2ecf20Sopenharmony_ci * Choose an address to map it to. Once the vmalloc system is running, 208c2ecf20Sopenharmony_ci * we use it. Before that, we map using addresses going up from 218c2ecf20Sopenharmony_ci * ioremap_bot. vmalloc will use the addresses from IOREMAP_BASE 228c2ecf20Sopenharmony_ci * through ioremap_bot. 238c2ecf20Sopenharmony_ci */ 248c2ecf20Sopenharmony_ci paligned = addr & PAGE_MASK; 258c2ecf20Sopenharmony_ci offset = addr & ~PAGE_MASK; 268c2ecf20Sopenharmony_ci size = PAGE_ALIGN(addr + size) - paligned; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci if (size == 0 || paligned == 0) 298c2ecf20Sopenharmony_ci return NULL; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci if (slab_is_available()) 328c2ecf20Sopenharmony_ci return do_ioremap(paligned, offset, size, prot, caller); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci pr_warn("ioremap() called early from %pS. Use early_ioremap() instead\n", caller); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci err = early_ioremap_range(ioremap_bot, paligned, size, prot); 378c2ecf20Sopenharmony_ci if (err) 388c2ecf20Sopenharmony_ci return NULL; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci ret = (void __iomem *)ioremap_bot + offset; 418c2ecf20Sopenharmony_ci ioremap_bot += size; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci return ret; 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* 478c2ecf20Sopenharmony_ci * Unmap an IO region and remove it from vmalloc'd list. 488c2ecf20Sopenharmony_ci * Access to IO memory should be serialized by driver. 498c2ecf20Sopenharmony_ci */ 508c2ecf20Sopenharmony_civoid iounmap(volatile void __iomem *token) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci void *addr; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci if (!slab_is_available()) 558c2ecf20Sopenharmony_ci return; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci addr = (void *)((unsigned long __force)PCI_FIX_ADDR(token) & PAGE_MASK); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci if ((unsigned long)addr < ioremap_bot) { 608c2ecf20Sopenharmony_ci pr_warn("Attempt to iounmap early bolted mapping at 0x%p\n", addr); 618c2ecf20Sopenharmony_ci return; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci vunmap(addr); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(iounmap); 66