xref: /kernel/linux/linux-5.10/arch/mips/mm/ioremap.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
38c2ecf20Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
48c2ecf20Sopenharmony_ci * for more details.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * (C) Copyright 1995 1996 Linus Torvalds
78c2ecf20Sopenharmony_ci * (C) Copyright 2001, 2002 Ralf Baechle
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci#include <linux/export.h>
108c2ecf20Sopenharmony_ci#include <asm/addrspace.h>
118c2ecf20Sopenharmony_ci#include <asm/byteorder.h>
128c2ecf20Sopenharmony_ci#include <linux/ioport.h>
138c2ecf20Sopenharmony_ci#include <linux/sched.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <linux/vmalloc.h>
168c2ecf20Sopenharmony_ci#include <linux/mm_types.h>
178c2ecf20Sopenharmony_ci#include <linux/io.h>
188c2ecf20Sopenharmony_ci#include <asm/cacheflush.h>
198c2ecf20Sopenharmony_ci#include <asm/tlbflush.h>
208c2ecf20Sopenharmony_ci#include <ioremap.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define IS_LOW512(addr) (!((phys_addr_t)(addr) & (phys_addr_t) ~0x1fffffffULL))
238c2ecf20Sopenharmony_ci#define IS_KSEG1(addr) (((unsigned long)(addr) & ~0x1fffffffUL) == CKSEG1)
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistatic int __ioremap_check_ram(unsigned long start_pfn, unsigned long nr_pages,
268c2ecf20Sopenharmony_ci			       void *arg)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	unsigned long i;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	for (i = 0; i < nr_pages; i++) {
318c2ecf20Sopenharmony_ci		if (pfn_valid(start_pfn + i) &&
328c2ecf20Sopenharmony_ci		    !PageReserved(pfn_to_page(start_pfn + i)))
338c2ecf20Sopenharmony_ci			return 1;
348c2ecf20Sopenharmony_ci	}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	return 0;
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci/*
408c2ecf20Sopenharmony_ci * ioremap_prot     -   map bus memory into CPU space
418c2ecf20Sopenharmony_ci * @phys_addr:    bus address of the memory
428c2ecf20Sopenharmony_ci * @size:      size of the resource to map
438c2ecf20Sopenharmony_ci *
448c2ecf20Sopenharmony_ci * ioremap_prot gives the caller control over cache coherency attributes (CCA)
458c2ecf20Sopenharmony_ci */
468c2ecf20Sopenharmony_civoid __iomem *ioremap_prot(phys_addr_t phys_addr, unsigned long size,
478c2ecf20Sopenharmony_ci		unsigned long prot_val)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	unsigned long flags = prot_val & _CACHE_MASK;
508c2ecf20Sopenharmony_ci	unsigned long offset, pfn, last_pfn;
518c2ecf20Sopenharmony_ci	struct vm_struct *area;
528c2ecf20Sopenharmony_ci	phys_addr_t last_addr;
538c2ecf20Sopenharmony_ci	unsigned long vaddr;
548c2ecf20Sopenharmony_ci	void __iomem *cpu_addr;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	cpu_addr = plat_ioremap(phys_addr, size, flags);
578c2ecf20Sopenharmony_ci	if (cpu_addr)
588c2ecf20Sopenharmony_ci		return cpu_addr;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	phys_addr = fixup_bigphys_addr(phys_addr, size);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	/* Don't allow wraparound or zero size */
638c2ecf20Sopenharmony_ci	last_addr = phys_addr + size - 1;
648c2ecf20Sopenharmony_ci	if (!size || last_addr < phys_addr)
658c2ecf20Sopenharmony_ci		return NULL;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	/*
688c2ecf20Sopenharmony_ci	 * Map uncached objects in the low 512mb of address space using KSEG1,
698c2ecf20Sopenharmony_ci	 * otherwise map using page tables.
708c2ecf20Sopenharmony_ci	 */
718c2ecf20Sopenharmony_ci	if (IS_LOW512(phys_addr) && IS_LOW512(last_addr) &&
728c2ecf20Sopenharmony_ci	    flags == _CACHE_UNCACHED)
738c2ecf20Sopenharmony_ci		return (void __iomem *) CKSEG1ADDR(phys_addr);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	/*
768c2ecf20Sopenharmony_ci	 * Don't allow anybody to remap RAM that may be allocated by the page
778c2ecf20Sopenharmony_ci	 * allocator, since that could lead to races & data clobbering.
788c2ecf20Sopenharmony_ci	 */
798c2ecf20Sopenharmony_ci	pfn = PFN_DOWN(phys_addr);
808c2ecf20Sopenharmony_ci	last_pfn = PFN_DOWN(last_addr);
818c2ecf20Sopenharmony_ci	if (walk_system_ram_range(pfn, last_pfn - pfn + 1, NULL,
828c2ecf20Sopenharmony_ci				  __ioremap_check_ram) == 1) {
838c2ecf20Sopenharmony_ci		WARN_ONCE(1, "ioremap on RAM at %pa - %pa\n",
848c2ecf20Sopenharmony_ci			  &phys_addr, &last_addr);
858c2ecf20Sopenharmony_ci		return NULL;
868c2ecf20Sopenharmony_ci	}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	/*
898c2ecf20Sopenharmony_ci	 * Mappings have to be page-aligned
908c2ecf20Sopenharmony_ci	 */
918c2ecf20Sopenharmony_ci	offset = phys_addr & ~PAGE_MASK;
928c2ecf20Sopenharmony_ci	phys_addr &= PAGE_MASK;
938c2ecf20Sopenharmony_ci	size = PAGE_ALIGN(last_addr + 1) - phys_addr;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	/*
968c2ecf20Sopenharmony_ci	 * Ok, go for it..
978c2ecf20Sopenharmony_ci	 */
988c2ecf20Sopenharmony_ci	area = get_vm_area(size, VM_IOREMAP);
998c2ecf20Sopenharmony_ci	if (!area)
1008c2ecf20Sopenharmony_ci		return NULL;
1018c2ecf20Sopenharmony_ci	vaddr = (unsigned long)area->addr;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	flags |= _PAGE_GLOBAL | _PAGE_PRESENT | __READABLE | __WRITEABLE;
1048c2ecf20Sopenharmony_ci	if (ioremap_page_range(vaddr, vaddr + size, phys_addr,
1058c2ecf20Sopenharmony_ci			__pgprot(flags))) {
1068c2ecf20Sopenharmony_ci		free_vm_area(area);
1078c2ecf20Sopenharmony_ci		return NULL;
1088c2ecf20Sopenharmony_ci	}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	return (void __iomem *)(vaddr + offset);
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ioremap_prot);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_civoid iounmap(const volatile void __iomem *addr)
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	if (!plat_iounmap(addr) && !IS_KSEG1(addr))
1178c2ecf20Sopenharmony_ci		vunmap((void *)((unsigned long)addr & PAGE_MASK));
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ciEXPORT_SYMBOL(iounmap);
120