1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Cache management functions for Hexagon 4 * 5 * Copyright (c) 2010-2011, The Linux Foundation. All rights reserved. 6 */ 7 8 #include <linux/mm.h> 9 #include <asm/cacheflush.h> 10 #include <asm/hexagon_vm.h> 11 12 #define spanlines(start, end) \ 13 (((end - (start & ~(LINESIZE - 1))) >> LINEBITS) + 1) 14 15 void flush_dcache_range(unsigned long start, unsigned long end) 16 { 17 unsigned long lines = spanlines(start, end-1); 18 unsigned long i, flags; 19 20 start &= ~(LINESIZE - 1); 21 22 local_irq_save(flags); 23 24 for (i = 0; i < lines; i++) { 25 __asm__ __volatile__ ( 26 " dccleaninva(%0); " 27 : 28 : "r" (start) 29 ); 30 start += LINESIZE; 31 } 32 local_irq_restore(flags); 33 } 34 35 void flush_icache_range(unsigned long start, unsigned long end) 36 { 37 unsigned long lines = spanlines(start, end-1); 38 unsigned long i, flags; 39 40 start &= ~(LINESIZE - 1); 41 42 local_irq_save(flags); 43 44 for (i = 0; i < lines; i++) { 45 __asm__ __volatile__ ( 46 " dccleana(%0); " 47 " icinva(%0); " 48 : 49 : "r" (start) 50 ); 51 start += LINESIZE; 52 } 53 __asm__ __volatile__ ( 54 "isync" 55 ); 56 local_irq_restore(flags); 57 } 58 EXPORT_SYMBOL(flush_icache_range); 59 60 void hexagon_clean_dcache_range(unsigned long start, unsigned long end) 61 { 62 unsigned long lines = spanlines(start, end-1); 63 unsigned long i, flags; 64 65 start &= ~(LINESIZE - 1); 66 67 local_irq_save(flags); 68 69 for (i = 0; i < lines; i++) { 70 __asm__ __volatile__ ( 71 " dccleana(%0); " 72 : 73 : "r" (start) 74 ); 75 start += LINESIZE; 76 } 77 local_irq_restore(flags); 78 } 79 80 void hexagon_inv_dcache_range(unsigned long start, unsigned long end) 81 { 82 unsigned long lines = spanlines(start, end-1); 83 unsigned long i, flags; 84 85 start &= ~(LINESIZE - 1); 86 87 local_irq_save(flags); 88 89 for (i = 0; i < lines; i++) { 90 __asm__ __volatile__ ( 91 " dcinva(%0); " 92 : 93 : "r" (start) 94 ); 95 start += LINESIZE; 96 } 97 local_irq_restore(flags); 98 } 99 100 101 102 103 /* 104 * This is just really brutal and shouldn't be used anyways, 105 * especially on V2. Left here just in case. 106 */ 107 void flush_cache_all_hexagon(void) 108 { 109 unsigned long flags; 110 local_irq_save(flags); 111 __vmcache_ickill(); 112 __vmcache_dckill(); 113 __vmcache_l2kill(); 114 local_irq_restore(flags); 115 mb(); 116 } 117 118 void copy_to_user_page(struct vm_area_struct *vma, struct page *page, 119 unsigned long vaddr, void *dst, void *src, int len) 120 { 121 memcpy(dst, src, len); 122 if (vma->vm_flags & VM_EXEC) { 123 flush_icache_range((unsigned long) dst, 124 (unsigned long) dst + len); 125 } 126 } 127