cache.S 4.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * Cache maintenance
 *
 * Copyright (C) 2001 Deep Blue Solutions Ltd.
 * Copyright (C) 2012 ARM Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

20
#include <linux/errno.h>
21 22 23
#include <linux/linkage.h>
#include <linux/init.h>
#include <asm/assembler.h>
24
#include <asm/cpufeature.h>
25
#include <asm/alternative.h>
A
Al Viro 已提交
26
#include <asm/asm-uaccess.h>
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51

/*
 *	flush_icache_range(start,end)
 *
 *	Ensure that the I and D caches are coherent within specified region.
 *	This is typically used when code has been written to a memory region,
 *	and will be executed.
 *
 *	- start   - virtual start address of region
 *	- end     - virtual end address of region
 */
ENTRY(flush_icache_range)
	/* FALLTHROUGH */

/*
 *	__flush_cache_user_range(start,end)
 *
 *	Ensure that the I and D caches are coherent within specified region.
 *	This is typically used when code has been written to a memory region,
 *	and will be executed.
 *
 *	- start   - virtual start address of region
 *	- end     - virtual end address of region
 */
ENTRY(__flush_cache_user_range)
52
	uaccess_ttbr0_enable x2, x3
53 54 55 56
	dcache_line_size x2, x3
	sub	x3, x2, #1
	bic	x4, x0, x3
1:
57
user_alt 9f, "dc cvau, x4",  "dc civac, x4",  ARM64_WORKAROUND_CLEAN_CACHE
58 59 60
	add	x4, x4, x2
	cmp	x4, x1
	b.lo	1b
61
	dsb	ish
62 63 64 65 66 67 68 69 70

	icache_line_size x2, x3
	sub	x3, x2, #1
	bic	x4, x0, x3
1:
USER(9f, ic	ivau, x4	)		// invalidate I line PoU
	add	x4, x4, x2
	cmp	x4, x1
	b.lo	1b
71
	dsb	ish
72
	isb
73
	mov	x0, #0
74 75
1:
	uaccess_ttbr0_disable x1
76 77 78
	ret
9:
	mov	x0, #-EFAULT
79
	b	1b
80 81 82 83
ENDPROC(flush_icache_range)
ENDPROC(__flush_cache_user_range)

/*
84
 *	__flush_dcache_area(kaddr, size)
85
 *
86 87
 *	Ensure that any D-cache lines for the interval [kaddr, kaddr+size)
 *	are cleaned and invalidated to the PoC.
88 89 90 91 92
 *
 *	- kaddr   - kernel address
 *	- size    - size in question
 */
ENTRY(__flush_dcache_area)
93
	dcache_by_line_op civac, sy, x0, x1, x2, x3
94
	ret
95
ENDPIPROC(__flush_dcache_area)
96

97 98 99 100 101 102 103 104 105 106 107 108 109 110
/*
 *	__clean_dcache_area_pou(kaddr, size)
 *
 * 	Ensure that any D-cache lines for the interval [kaddr, kaddr+size)
 * 	are cleaned to the PoU.
 *
 *	- kaddr   - kernel address
 *	- size    - size in question
 */
ENTRY(__clean_dcache_area_pou)
	dcache_by_line_op cvau, ish, x0, x1, x2, x3
	ret
ENDPROC(__clean_dcache_area_pou)

111
/*
112 113 114
 *	__dma_inv_area(start, size)
 *	- start   - virtual start address of region
 *	- size    - size in question
115
 */
116 117
__dma_inv_area:
	add	x1, x1, x0
118 119
	/* FALLTHROUGH */

120
/*
121 122 123
 *	__inval_cache_range(start, end)
 *	- start   - start address of region
 *	- end     - end address of region
124
 */
125
ENTRY(__inval_cache_range)
126 127
	dcache_line_size x2, x3
	sub	x3, x2, #1
128
	tst	x1, x3				// end cache line aligned?
129
	bic	x1, x1, x3
130 131 132 133 134 135 136 137 138
	b.eq	1f
	dc	civac, x1			// clean & invalidate D / U line
1:	tst	x0, x3				// start cache line aligned?
	bic	x0, x0, x3
	b.eq	2f
	dc	civac, x0			// clean & invalidate D / U line
	b	3f
2:	dc	ivac, x0			// invalidate D / U line
3:	add	x0, x0, x2
139
	cmp	x0, x1
140
	b.lo	2b
141 142
	dsb	sy
	ret
143
ENDPIPROC(__inval_cache_range)
144 145 146 147 148 149 150 151 152 153 154 155 156
ENDPROC(__dma_inv_area)

/*
 *	__clean_dcache_area_poc(kaddr, size)
 *
 * 	Ensure that any D-cache lines for the interval [kaddr, kaddr+size)
 * 	are cleaned to the PoC.
 *
 *	- kaddr   - kernel address
 *	- size    - size in question
 */
ENTRY(__clean_dcache_area_poc)
	/* FALLTHROUGH */
157 158

/*
159
 *	__dma_clean_area(start, size)
160
 *	- start   - virtual start address of region
161
 *	- size    - size in question
162
 */
163 164
__dma_clean_area:
	dcache_by_line_op cvac, sy, x0, x1, x2, x3
165
	ret
166 167
ENDPIPROC(__clean_dcache_area_poc)
ENDPROC(__dma_clean_area)
168 169

/*
170 171 172 173
 *	__dma_flush_area(start, size)
 *
 *	clean & invalidate D / U line
 *
174
 *	- start   - virtual start address of region
175
 *	- size    - size in question
176
 */
177 178
ENTRY(__dma_flush_area)
	dcache_by_line_op civac, sy, x0, x1, x2, x3
179
	ret
180
ENDPIPROC(__dma_flush_area)
181 182 183 184 185 186 187 188 189

/*
 *	__dma_map_area(start, size, dir)
 *	- start	- kernel virtual start address
 *	- size	- size of region
 *	- dir	- DMA direction
 */
ENTRY(__dma_map_area)
	cmp	w2, #DMA_FROM_DEVICE
190 191
	b.eq	__dma_inv_area
	b	__dma_clean_area
192
ENDPIPROC(__dma_map_area)
193 194 195 196 197 198 199 200 201

/*
 *	__dma_unmap_area(start, size, dir)
 *	- start	- kernel virtual start address
 *	- size	- size of region
 *	- dir	- DMA direction
 */
ENTRY(__dma_unmap_area)
	cmp	w2, #DMA_TO_DEVICE
202
	b.ne	__dma_inv_area
203
	ret
204
ENDPIPROC(__dma_unmap_area)