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 | |