18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * arch/parisc/mm/ioremap.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * (C) Copyright 1995 1996 Linus Torvalds 68c2ecf20Sopenharmony_ci * (C) Copyright 2001-2019 Helge Deller <deller@gmx.de> 78c2ecf20Sopenharmony_ci * (C) Copyright 2005 Kyle McMartin <kyle@parisc-linux.org> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 118c2ecf20Sopenharmony_ci#include <linux/errno.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/io.h> 148c2ecf20Sopenharmony_ci#include <linux/mm.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/* 178c2ecf20Sopenharmony_ci * Generic mapping function (not visible outside): 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* 218c2ecf20Sopenharmony_ci * Remap an arbitrary physical address space into the kernel virtual 228c2ecf20Sopenharmony_ci * address space. 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * NOTE! We need to allow non-page-aligned mappings too: we will obviously 258c2ecf20Sopenharmony_ci * have to convert them into an offset in a page-aligned mapping, but the 268c2ecf20Sopenharmony_ci * caller shouldn't need to know that small detail. 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_civoid __iomem *ioremap(unsigned long phys_addr, unsigned long size) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci void __iomem *addr; 318c2ecf20Sopenharmony_ci struct vm_struct *area; 328c2ecf20Sopenharmony_ci unsigned long offset, last_addr; 338c2ecf20Sopenharmony_ci pgprot_t pgprot; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#ifdef CONFIG_EISA 368c2ecf20Sopenharmony_ci unsigned long end = phys_addr + size - 1; 378c2ecf20Sopenharmony_ci /* Support EISA addresses */ 388c2ecf20Sopenharmony_ci if ((phys_addr >= 0x00080000 && end < 0x000fffff) || 398c2ecf20Sopenharmony_ci (phys_addr >= 0x00500000 && end < 0x03bfffff)) 408c2ecf20Sopenharmony_ci phys_addr |= F_EXTEND(0xfc000000); 418c2ecf20Sopenharmony_ci#endif 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci /* Don't allow wraparound or zero size */ 448c2ecf20Sopenharmony_ci last_addr = phys_addr + size - 1; 458c2ecf20Sopenharmony_ci if (!size || last_addr < phys_addr) 468c2ecf20Sopenharmony_ci return NULL; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci /* 498c2ecf20Sopenharmony_ci * Don't allow anybody to remap normal RAM that we're using.. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci if (phys_addr < virt_to_phys(high_memory)) { 528c2ecf20Sopenharmony_ci char *t_addr, *t_end; 538c2ecf20Sopenharmony_ci struct page *page; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci t_addr = __va(phys_addr); 568c2ecf20Sopenharmony_ci t_end = t_addr + (size - 1); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci for (page = virt_to_page(t_addr); 598c2ecf20Sopenharmony_ci page <= virt_to_page(t_end); page++) { 608c2ecf20Sopenharmony_ci if(!PageReserved(page)) 618c2ecf20Sopenharmony_ci return NULL; 628c2ecf20Sopenharmony_ci } 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci pgprot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | 668c2ecf20Sopenharmony_ci _PAGE_ACCESSED | _PAGE_NO_CACHE); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci /* 698c2ecf20Sopenharmony_ci * Mappings have to be page-aligned 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_ci offset = phys_addr & ~PAGE_MASK; 728c2ecf20Sopenharmony_ci phys_addr &= PAGE_MASK; 738c2ecf20Sopenharmony_ci size = PAGE_ALIGN(last_addr + 1) - phys_addr; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* 768c2ecf20Sopenharmony_ci * Ok, go for it.. 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_ci area = get_vm_area(size, VM_IOREMAP); 798c2ecf20Sopenharmony_ci if (!area) 808c2ecf20Sopenharmony_ci return NULL; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci addr = (void __iomem *) area->addr; 838c2ecf20Sopenharmony_ci if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size, 848c2ecf20Sopenharmony_ci phys_addr, pgprot)) { 858c2ecf20Sopenharmony_ci vunmap(addr); 868c2ecf20Sopenharmony_ci return NULL; 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci return (void __iomem *) (offset + (char __iomem *)addr); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ioremap); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_civoid iounmap(const volatile void __iomem *io_addr) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci unsigned long addr = (unsigned long)io_addr & PAGE_MASK; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci if (is_vmalloc_addr((void *)addr)) 988c2ecf20Sopenharmony_ci vunmap((void *)addr); 998c2ecf20Sopenharmony_ci} 1008c2ecf20Sopenharmony_ciEXPORT_SYMBOL(iounmap); 101