Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xtensa: support ioremap for memory outside KIO region

Map physical memory outside KIO region into the vmalloc area.
Unmap it with vunmap.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>

+82 -4
+13 -3
arch/xtensa/include/asm/io.h
··· 25 25 26 26 #ifdef CONFIG_MMU 27 27 28 + void __iomem *xtensa_ioremap_nocache(unsigned long addr, unsigned long size); 29 + void __iomem *xtensa_ioremap_cache(unsigned long addr, unsigned long size); 30 + void xtensa_iounmap(volatile void __iomem *addr); 31 + 28 32 /* 29 33 * Return the virtual address for the specified bus memory. 30 - * Note that we currently don't support any address outside the KIO segment. 31 34 */ 32 35 static inline void __iomem *ioremap_nocache(unsigned long offset, 33 36 unsigned long size) ··· 39 36 && offset - XCHAL_KIO_PADDR < XCHAL_KIO_SIZE) 40 37 return (void*)(offset-XCHAL_KIO_PADDR+XCHAL_KIO_BYPASS_VADDR); 41 38 else 42 - BUG(); 39 + return xtensa_ioremap_nocache(offset, size); 43 40 } 44 41 45 42 static inline void __iomem *ioremap_cache(unsigned long offset, ··· 49 46 && offset - XCHAL_KIO_PADDR < XCHAL_KIO_SIZE) 50 47 return (void*)(offset-XCHAL_KIO_PADDR+XCHAL_KIO_CACHED_VADDR); 51 48 else 52 - BUG(); 49 + return xtensa_ioremap_cache(offset, size); 53 50 } 54 51 #define ioremap_cache ioremap_cache 55 52 ··· 63 60 64 61 static inline void iounmap(volatile void __iomem *addr) 65 62 { 63 + unsigned long va = (unsigned long) addr; 64 + 65 + if (!(va >= XCHAL_KIO_CACHED_VADDR && 66 + va - XCHAL_KIO_CACHED_VADDR < XCHAL_KIO_SIZE) && 67 + !(va >= XCHAL_KIO_BYPASS_VADDR && 68 + va - XCHAL_KIO_BYPASS_VADDR < XCHAL_KIO_SIZE)) 69 + xtensa_iounmap(addr); 66 70 } 67 71 68 72 #define virt_to_bus virt_to_phys
+1 -1
arch/xtensa/mm/Makefile
··· 3 3 # 4 4 5 5 obj-y := init.o misc.o 6 - obj-$(CONFIG_MMU) += cache.o fault.o mmu.o tlb.o 6 + obj-$(CONFIG_MMU) += cache.o fault.o ioremap.o mmu.o tlb.o 7 7 obj-$(CONFIG_HIGHMEM) += highmem.o
+68
arch/xtensa/mm/ioremap.c
··· 1 + /* 2 + * ioremap implementation. 3 + * 4 + * Copyright (C) 2015 Cadence Design Systems Inc. 5 + * 6 + * This program is free software; you can redistribute it and/or modify 7 + * it under the terms of the GNU General Public License version 2 as 8 + * published by the Free Software Foundation. 9 + */ 10 + 11 + #include <linux/io.h> 12 + #include <linux/vmalloc.h> 13 + #include <asm/cacheflush.h> 14 + #include <asm/io.h> 15 + #include <asm/pgtable.h> 16 + 17 + static void __iomem *xtensa_ioremap(unsigned long paddr, unsigned long size, 18 + pgprot_t prot) 19 + { 20 + unsigned long offset = paddr & ~PAGE_MASK; 21 + unsigned long pfn = __phys_to_pfn(paddr); 22 + struct vm_struct *area; 23 + unsigned long vaddr; 24 + int err; 25 + 26 + paddr &= PAGE_MASK; 27 + 28 + WARN_ON(pfn_valid(pfn)); 29 + 30 + size = PAGE_ALIGN(offset + size); 31 + 32 + area = get_vm_area(size, VM_IOREMAP); 33 + if (!area) 34 + return NULL; 35 + 36 + vaddr = (unsigned long)area->addr; 37 + area->phys_addr = paddr; 38 + 39 + err = ioremap_page_range(vaddr, vaddr + size, paddr, prot); 40 + 41 + if (err) { 42 + vunmap((void *)vaddr); 43 + return NULL; 44 + } 45 + 46 + flush_cache_vmap(vaddr, vaddr + size); 47 + return (void __iomem *)(offset + vaddr); 48 + } 49 + 50 + void __iomem *xtensa_ioremap_nocache(unsigned long addr, unsigned long size) 51 + { 52 + return xtensa_ioremap(addr, size, pgprot_noncached(PAGE_KERNEL)); 53 + } 54 + EXPORT_SYMBOL(xtensa_ioremap_nocache); 55 + 56 + void __iomem *xtensa_ioremap_cache(unsigned long addr, unsigned long size) 57 + { 58 + return xtensa_ioremap(addr, size, PAGE_KERNEL); 59 + } 60 + EXPORT_SYMBOL(xtensa_ioremap_cache); 61 + 62 + void xtensa_iounmap(volatile void __iomem *io_addr) 63 + { 64 + void *addr = (void *)(PAGE_MASK & (unsigned long)io_addr); 65 + 66 + vunmap(addr); 67 + } 68 + EXPORT_SYMBOL(xtensa_iounmap);