cache.S 5.5 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
	invalidate_icache_by_line x0, x1, x2, x3, 9f
64
	mov	x0, #0
65 66
1:
	uaccess_ttbr0_disable x1
67 68 69
	ret
9:
	mov	x0, #-EFAULT
70
	b	1b
71 72 73
ENDPROC(flush_icache_range)
ENDPROC(__flush_cache_user_range)

74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
/*
 *	invalidate_icache_range(start,end)
 *
 *	Ensure that the I cache is invalid within specified region.
 *
 *	- start   - virtual start address of region
 *	- end     - virtual end address of region
 */
ENTRY(invalidate_icache_range)
	uaccess_ttbr0_enable x2, x3

	invalidate_icache_by_line x0, x1, x2, x3, 2f
	mov	x0, xzr
1:
	uaccess_ttbr0_disable x1
	ret
2:
	mov	x0, #-EFAULT
	b	1b
ENDPROC(invalidate_icache_range)

95
/*
96
 *	__flush_dcache_area(kaddr, size)
97
 *
98 99
 *	Ensure that any D-cache lines for the interval [kaddr, kaddr+size)
 *	are cleaned and invalidated to the PoC.
100 101 102 103 104
 *
 *	- kaddr   - kernel address
 *	- size    - size in question
 */
ENTRY(__flush_dcache_area)
105
	dcache_by_line_op civac, sy, x0, x1, x2, x3
106
	ret
107
ENDPIPROC(__flush_dcache_area)
108

109 110 111 112 113 114 115 116 117 118 119 120 121 122
/*
 *	__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)

123
/*
124 125 126 127 128 129 130
 *	__inval_dcache_area(kaddr, size)
 *
 * 	Ensure that any D-cache lines for the interval [kaddr, kaddr+size)
 * 	are invalidated. Any partial lines at the ends of the interval are
 *	also cleaned to PoC to prevent data loss.
 *
 *	- kaddr   - kernel address
131
 *	- size    - size in question
132
 */
133
ENTRY(__inval_dcache_area)
134 135
	/* FALLTHROUGH */

136
/*
137 138 139
 *	__dma_inv_area(start, size)
 *	- start   - virtual start address of region
 *	- size    - size in question
140
 */
141 142
__dma_inv_area:
	add	x1, x1, x0
143 144
	dcache_line_size x2, x3
	sub	x3, x2, #1
145
	tst	x1, x3				// end cache line aligned?
146
	bic	x1, x1, x3
147 148 149 150 151 152 153 154 155
	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
156
	cmp	x0, x1
157
	b.lo	2b
158 159
	dsb	sy
	ret
160
ENDPIPROC(__inval_dcache_area)
161 162 163 164 165 166 167 168 169 170 171 172 173
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 */
174 175

/*
176
 *	__dma_clean_area(start, size)
177
 *	- start   - virtual start address of region
178
 *	- size    - size in question
179
 */
180 181
__dma_clean_area:
	dcache_by_line_op cvac, sy, x0, x1, x2, x3
182
	ret
183 184
ENDPIPROC(__clean_dcache_area_poc)
ENDPROC(__dma_clean_area)
185

R
Robin Murphy 已提交
186 187 188 189 190 191 192 193 194 195 196 197 198 199
/*
 *	__clean_dcache_area_pop(kaddr, size)
 *
 * 	Ensure that any D-cache lines for the interval [kaddr, kaddr+size)
 * 	are cleaned to the PoP.
 *
 *	- kaddr   - kernel address
 *	- size    - size in question
 */
ENTRY(__clean_dcache_area_pop)
	dcache_by_line_op cvap, sy, x0, x1, x2, x3
	ret
ENDPIPROC(__clean_dcache_area_pop)

200
/*
201 202 203 204
 *	__dma_flush_area(start, size)
 *
 *	clean & invalidate D / U line
 *
205
 *	- start   - virtual start address of region
206
 *	- size    - size in question
207
 */
208 209
ENTRY(__dma_flush_area)
	dcache_by_line_op civac, sy, x0, x1, x2, x3
210
	ret
211
ENDPIPROC(__dma_flush_area)
212 213 214 215 216 217 218 219 220

/*
 *	__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
221 222
	b.eq	__dma_inv_area
	b	__dma_clean_area
223
ENDPIPROC(__dma_map_area)
224 225 226 227 228 229 230 231 232

/*
 *	__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
233
	b.ne	__dma_inv_area
234
	ret
235
ENDPIPROC(__dma_unmap_area)