Home | History | Annotate | Line # | Download | only in arm
      1 /*-
      2  * Copyright (c) 2010 Per Odlund <per.odlund (at) armagedon.se>
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     14  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     15  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     23  * POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 /* ARMv7 assembly functions for manipulating caches and other core functions.
     27  * Based on cpufuncs for v6 and xscale.
     28  */
     29 
     30 #include "assym.h"
     31 #include <machine/asm.h>
     32 #include <arm/locore.h>
     33 
     34 	.arch	armv7a
     35 
     36 ENTRY(armv7_cpu_sleep)
     37 	dsb
     38 	wfi				@ wait for an interrupt
     39 	b	irq_idle_entry		@ assume we got an interrupt
     40 END(armv7_cpu_sleep)
     41 
     42 ENTRY(armv7_wait)
     43 	mrc	p15, 0, r0, c2, c0, 0	@ arbitrary read of CP15
     44 	add	r0, r0, #0		@ a stall
     45 	bx	lr
     46 END(armv7_wait)
     47 
     48 ENTRY(armv7_context_switch)
     49 	dsb				@ data synchronization barrier
     50 	mrc	p15, 0, ip, c0, c0, 5	@ get MPIDR
     51 	cmp	ip, #0
     52 	orrlt	r0, r0, #TTBR_MPATTR	@ MP, cachable (Normal WB)
     53 	orrge	r0, r0, #TTBR_UPATTR	@ Non-MP, cacheable, normal WB
     54 	mcr	p15, 0, r0, c2, c0, 0 	@ set the new TTBR 0
     55 #ifdef ARM_MMU_EXTENDED
     56 	cmp	r1, #0
     57 	mcreq	p15, 0, r0, c2, c0, 1   @ set the new TTBR 1
     58 #else
     59 	mcr	p15, 0, r0, c8, c7, 0	@ flush the I+D
     60 #endif
     61 	dsb
     62 	isb
     63 	bx	lr
     64 END(armv7_context_switch)
     65 
     66 #ifdef ARM_MMU_EXTENDED_XXX
     67 ENTRY(armv7up_tlb_flushID_ASID)
     68 	mcr	p15, 0, r0, c8, c7, 2	@ flush I+D tlb all ASID
     69 	dsb				@ data synchronization barrier
     70 	isb
     71 	bx	lr
     72 END(armv7up_tlb_flushID_ASID)
     73 
     74 #ifdef MULTIPROCESSOR
     75 ENTRY(armv7mp_tlb_flushID_ASID)
     76 	mcr	p15, 0, r0, c8, c3, 2	@ flush I+D tlb all ASID
     77 	dsb				@ data synchronization barrier
     78 	isb
     79 	bx	lr
     80 END(armv7mp_tlb_flushID_ASID)
     81 #endif
     82 #endif
     83 
     84 STRONG_ALIAS(armv7up_tlb_flushD_SE, armv7up_tlb_flushID_SE)
     85 STRONG_ALIAS(armv7up_tlb_flushI_SE, armv7up_tlb_flushID_SE)
     86 ENTRY(armv7up_tlb_flushID_SE)
     87 	bfc	r0, #0, #12		@ Always KERNEL_PID, i.e. 0
     88 	mcr	p15, 0, r0, c8, c7, 1	@ flush I+D tlb single entry
     89 #if PAGE_SIZE == 2*L2_S_SIZE
     90 	add	r0, r0, #L2_S_SIZE
     91 	mcr	p15, 0, r0, c8, c7, 1	@ flush I+D tlb single entry
     92 #endif
     93 	dsb				@ data synchronization barrier
     94 	isb
     95 	bx	lr
     96 END(armv7up_tlb_flushID_SE)
     97 
     98 #ifdef MULTIPROCESSOR
     99 STRONG_ALIAS(armv7mp_tlb_flushD_SE, armv7mp_tlb_flushID_SE)
    100 STRONG_ALIAS(armv7mp_tlb_flushI_SE, armv7mp_tlb_flushID_SE)
    101 ENTRY(armv7mp_tlb_flushID_SE)
    102 	bfc	r0, #0, #12		@ Always KERNEL_PID, i.e. 0
    103 	mcr	p15, 0, r0, c8, c3, 1	@ flush I+D tlb single entry
    104 #if PAGE_SIZE == 2*L2_S_SIZE
    105 	add	r0, r0, #L2_S_SIZE
    106 	mcr	p15, 0, r0, c8, c3, 1	@ flush I+D tlb single entry
    107 #endif
    108 	dsb				@ data synchronization barrier
    109 	isb
    110 	bx	lr
    111 END(armv7mp_tlb_flushID_SE)
    112 #endif
    113 
    114 #ifdef MULTIPROCESSOR
    115 STRONG_ALIAS(armv7mp_tlb_flushD, armv7up_tlb_flushD)
    116 #endif
    117 ENTRY(armv7up_tlb_flushD)
    118 	mov	r0, #0
    119 	mcr	p15, 0, r0, c8, c6, 0	@ flush entire D tlb
    120 	dsb				@ data synchronization barrier
    121 	isb
    122 	bx      lr
    123 END(armv7up_tlb_flushD)
    124 
    125 STRONG_ALIAS(armv7up_tlb_flushI, armv7up_tlb_flushID)
    126 ENTRY(armv7up_tlb_flushID)
    127 	dsb
    128 	mov	r0, #0
    129 	mcr	p15, 0, r0, c8, c7, 0	@ flush entire I+D tlb
    130 	mcr	p15, 0, r0, c7, c5, 6	@ branch predictor invalidate
    131 	dsb				@ data synchronization barrier
    132 	isb
    133 	bx      lr
    134 END(armv7up_tlb_flushID)
    135 
    136 #ifdef MULTIPROCESSOR
    137 STRONG_ALIAS(armv7mp_tlb_flushI, armv7mp_tlb_flushID)
    138 ENTRY(armv7mp_tlb_flushID)
    139 	dsb
    140 	mov	r0, #0
    141 	mcr	p15, 0, r0, c8, c3, 0	@ flush entire I+D tlb, IS
    142 	mcr	p15, 0, r0, c7, c1, 6	@ branch predictor invalidate, IS
    143 	dsb				@ data synchronization barrier
    144 	isb
    145 	bx      lr
    146 END(armv7mp_tlb_flushID)
    147 #endif
    148 
    149 ENTRY_NP(armv7_setttb)
    150 	mrc	p15, 0, ip, c0, c0, 5	@ get MPIDR
    151 	cmp	ip, #0
    152 	orrlt	r0, r0, #TTBR_MPATTR	@ MP, cachable (Normal WB)
    153 	orrge	r0, r0, #TTBR_UPATTR	@ Non-MP, cacheable, normal WB
    154 	mcr	p15, 0, r0, c2, c0, 0   @ load new TTBR 0
    155 #ifdef ARM_MMU_EXTENDED
    156 	cmp	r1, #0
    157 	mcreq	p15, 0, r0, c2, c0, 1   @ load new TTBR 1
    158 #else
    159 	mcr	p15, 0, r0, c8, c7, 0   @ invalidate all I+D TLBs
    160 #endif
    161 	dsb				@ data synchronization barrier
    162 	isb
    163 	bx	lr
    164 END(armv7_setttb)
    165 
    166 /* Other functions. */
    167 
    168 ENTRY_NP(armv7_drain_writebuf)
    169 	dsb				@ data synchronization barrier
    170 	RET
    171 END(armv7_drain_writebuf)
    172 
    173 /* Cache operations. */
    174 
    175 /* LINTSTUB: void armv7_icache_sync_range(vaddr_t, vsize_t); */
    176 ENTRY_NP(armv7_icache_sync_range)
    177 	mov	ip, #CPU_CSSR_InD
    178 	mcr	p15, 2, ip, c0, c0, 0	@ set cache level to L1-I
    179 	mrc	p15, 1, r2, c0, c0, 0	@ read CCSIDR
    180 	mov	ip, #0
    181 	mcr	p15, 2, ip, c0, c0, 0	@ set cache level to L1-D
    182 	mrc	p15, 1, r3, c0, c0, 0	@ read CCSIDR
    183 	and	r2, r2, #7		@ get line size (log2(size)-4, 0=16)
    184 	and	r3, r3, #7		@ get line size (log2(size)-4, 0=16)
    185 	cmp	r2, r3			@ compare ilinesize to dlinesize
    186 	movgt	r2, r3			@ pick lesser of the two
    187 	mov	ip, #16			@ make a bit mask
    188 	lsl	r2, ip, r2		@ and shift into position
    189 	sub	ip, r2, #1		@ make into a mask
    190 	and	r3, r0, ip		@ get offset into cache line
    191 	add	r1, r1, r3		@ add to length
    192 	bic	r0, r0, ip		@ clear offset from start.
    193 1:
    194 	mcr	p15, 0, r0, c7, c10, 1	@ wb the D-Cache line
    195 	mcr	p15, 0, r0, c7, c5, 1	@ invalidate the I-Cache line
    196 	add	r0, r0, r2
    197 	subs	r1, r1, r2
    198 	bhi	1b
    199 
    200 	dsb				@ data synchronization barrier
    201 	isb
    202 	bx	lr
    203 END(armv7_icache_sync_range)
    204 
    205 /* LINTSTUB: void armv7_icache_sync_all(void); */
    206 ENTRY_NP(armv7_icache_sync_all)
    207 	/*
    208 	 * We assume that the code here can never be out of sync with the
    209 	 * dcache, so that we can safely flush the Icache and fall through
    210 	 * into the Dcache cleaning code.
    211 	 */
    212 	stmdb	sp!, {r0, lr}
    213 	bl	_C_LABEL(armv7_idcache_wbinv_all) @clean the D cache
    214 	ldmia	sp!, {r0, lr}
    215 	dsb				@ data synchronization barrier
    216 	isb
    217 	bx	lr
    218 END(armv7_icache_sync_all)
    219 
    220 ENTRY(armv7_dcache_wb_range)
    221 	mov	ip, #0
    222 	mcr	p15, 2, ip, c0, c0, 0	@ set cache level to L1
    223 	mrc	p15, 1, r2, c0, c0, 0	@ read CCSIDR
    224 	and	r2, r2, #7		@ get line size (log2(size)-4, 0=16)
    225 	mov	ip, #16			@ make a bit mask
    226 	lsl	r2, ip, r2		@ and shift into position
    227 	sub	ip, r2, #1		@ make into a mask
    228 	and	r3, r0, ip		@ get offset into cache line
    229 	add	r1, r1, r3		@ add to length
    230 	bic	r0, r0, ip		@ clear offset from start.
    231 	dsb
    232 1:
    233 	mcr	p15, 0, r0, c7, c10, 1	@ wb the D-Cache to PoC
    234 	add	r0, r0, r2
    235 	subs	r1, r1, r2
    236 	bhi	1b
    237 	dsb				@ data synchronization barrier
    238 	bx	lr
    239 END(armv7_dcache_wb_range)
    240 
    241 /* LINTSTUB: void armv7_dcache_wbinv_range(vaddr_t, vsize_t); */
    242 ENTRY(armv7_dcache_wbinv_range)
    243 	mov	ip, #0
    244 	mcr	p15, 2, ip, c0, c0, 0	@ set cache level to L1
    245 	mrc	p15, 1, r2, c0, c0, 0	@ read CCSIDR
    246 	and	r2, r2, #7		@ get line size (log2(size)-4, 0=16)
    247 	mov	ip, #16			@ make a bit mask
    248 	lsl	r2, ip, r2		@ and shift into position
    249 	sub	ip, r2, #1		@ make into a mask
    250 	and	r3, r0, ip		@ get offset into cache line
    251 	add	r1, r1, r3		@ add to length
    252 	bic	r0, r0, ip		@ clear offset from start.
    253 	dsb
    254 1:
    255 	mcr	p15, 0, r0, c7, c14, 1	@ wb and inv the D-Cache line to PoC
    256 	add	r0, r0, r2
    257 	subs	r1, r1, r2
    258 	bhi	1b
    259 	dsb				@ data synchronization barrier
    260 	bx	lr
    261 END(armv7_dcache_wbinv_range)
    262 
    263 /* * LINTSTUB: void armv7_dcache_inv_range(vaddr_t, vsize_t); */
    264 ENTRY(armv7_dcache_inv_range)
    265 	mov	ip, #0
    266 	mcr	p15, 2, ip, c0, c0, 0	@ set cache level to L1
    267 	mrc	p15, 1, r2, c0, c0, 0	@ read CCSIDR
    268 	and	r2, r2, #7		@ get line size (log2(size)-4, 0=16)
    269 	mov	ip, #16			@ make a bit mask
    270 	lsl	r2, ip, r2		@ and shift into position
    271 	sub	ip, r2, #1		@ make into a mask
    272 	and	r3, r0, ip		@ get offset into cache line
    273 	add	r1, r1, r3		@ add to length
    274 	bic	r0, r0, ip		@ clear offset from start.
    275 1:
    276 	mcr	p15, 0, r0, c7, c6, 1	@ invalidate the D-Cache line
    277 	add	r0, r0, r2
    278 	subs	r1, r1, r2
    279 	bhi	1b
    280 
    281 	dsb				@ data synchronization barrier
    282 	bx	lr
    283 END(armv7_dcache_inv_range)
    284 
    285 
    286 /* * LINTSTUB: void armv7_idcache_wbinv_range(vaddr_t, vsize_t); */
    287 ENTRY(armv7_idcache_wbinv_range)
    288 	mov	ip, #0
    289 	mcr	p15, 2, ip, c0, c0, 0	@ set cache level to L1
    290 	mrc	p15, 1, r2, c0, c0, 0	@ read CCSIDR
    291 	and	r2, r2, #7		@ get line size (log2(size)-4, 0=16)
    292 	mov	ip, #16			@ make a bit mask
    293 	lsl	r2, ip, r2		@ and shift into position
    294 	sub	ip, r2, #1		@ make into a mask
    295 	and	r3, r0, ip		@ get offset into cache line
    296 	add	r1, r1, r3		@ add to length
    297 	bic	r0, r0, ip		@ clear offset from start.
    298 	dsb
    299 1:
    300 	mcr	p15, 0, r0, c7, c5, 1	@ invalidate the I-Cache line
    301 	mcr	p15, 0, r0, c7, c14, 1 	@ wb and inv the D-Cache line
    302 	add	r0, r0, r2
    303 	subs	r1, r1, r2
    304 	bhi	1b
    305 
    306 	dsb				@ data synchronization barrier
    307 	isb
    308 	bx	lr
    309 END(armv7_idcache_wbinv_range)
    310 
    311 /* * LINTSTUB: void armv7_idcache_wbinv_all(void); */
    312 ENTRY_NP(armv7_idcache_wbinv_all)
    313 	/*
    314 	 * We assume that the code here can never be out of sync with the
    315 	 * dcache, so that we can safely flush the Icache and fall through
    316 	 * into the Dcache purging code.
    317 	 */
    318 	dmb
    319 	mcr	p15, 0, r0, c7, c5, 0
    320 	b	_C_LABEL(armv7_dcache_wbinv_all)
    321 END(armv7_idcache_wbinv_all)
    322 
    323 /*
    324  * These work very hard to not push registers onto the stack
    325  * and to limit themselves to use r0-r3 and ip.
    326  */
    327 /* * LINTSTUB: void armv7_icache_inv_all(void); */
    328 ENTRY_NP(armv7_icache_inv_all)
    329 	mov	r0, #0
    330 	mcr	p15, 2, r0, c0, c0, 0	@ set cache level to L1
    331 	mrc	p15, 1, r0, c0, c0, 0	@ read CCSIDR
    332 
    333 	ubfx	r2, r0, #13, #15	@ get num sets - 1 from CCSIDR
    334 	ubfx	r3, r0, #3, #10		@ get numways - 1 from CCSIDR
    335 	clz	r1, r3			@ number of bits to MSB of way
    336 	lsl	r3, r3, r1		@ shift into position
    337 	mov	ip, #1			@
    338 	lsl	ip, ip, r1		@ ip now contains the way decr
    339 
    340 	ubfx	r0, r0, #0, #3		@ get linesize from CCSIDR
    341 	add	r0, r0, #4		@ apply bias
    342 	lsl	r2, r2, r0		@ shift sets by log2(linesize)
    343 	add	r3, r3, r2		@ merge numsets - 1 with numways - 1
    344 	sub	ip, ip, r2		@ subtract numsets - 1 from way decr
    345 	mov	r1, #1
    346 	lsl	r1, r1, r0		@ r1 now contains the set decr
    347 	mov	r2, ip			@ r2 now contains set way decr
    348 
    349 	/* r3 = ways/sets, r2 = way decr, r1 = set decr, r0 and ip are free */
    350 1:	mcr	p15, 0, r3, c7, c6, 2	@ DCISW (data cache invalidate by set/way)
    351 	movs	r0, r3			@ get current way/set
    352 	beq	2f			@ at 0 means we are done.
    353 	lsls	r0, r0, #10		@ clear way bits leaving only set bits
    354 	subne	r3, r3, r1		@ non-zero?, decrement set #
    355 	subeq	r3, r3, r2		@ zero?, decrement way # and restore set count
    356 	b	1b
    357 
    358 2:	dsb				@ wait for stores to finish
    359 	mov	r0, #0			@ and ...
    360 	mcr	p15, 0, r0, c7, c5, 0	@ invalidate L1 cache
    361 	isb				@ instruction sync barrier
    362 	bx	lr			@ return
    363 END(armv7_icache_inv_all)
    364 
    365 /* * LINTSTUB: void armv7_dcache_l1inv_all(void); */
    366 ENTRY_NP(armv7_dcache_l1inv_all)
    367 	mrc	p15, 1, r0, c0, c0, 1	@ read CLIDR
    368 	and	r0, r0, #0x7		@ check L1
    369 	bxeq	lr			@ return if no L1 cache
    370 	mov	r3, #0			@ start with L1
    371 	mcr	p15, 2, r3, c0, c0, 0	@ select cache level
    372 	isb
    373 	mrc	p15, 1, r0, c0, c0, 0	@ read CCSIDR
    374 
    375 	ubfx	ip, r0, #0, #3		@ get linesize from CCSIDR
    376 	add	ip, ip, #4		@ apply bias
    377 	ubfx	r2, r0, #13, #15	@ get numsets - 1 from CCSIDR
    378 	lsl	r2, r2, ip		@ shift to set position
    379 	orr	r3, r3, r2		@ merge set into way/set/level
    380 	mov	r1, #1
    381 	lsl	r1, r1, ip		@ r1 = set decr
    382 
    383 	ubfx	ip, r0, #3, #10		@ get numways - 1 from [to be discarded] CCSIDR
    384 	clz	r2, ip			@ number of bits to MSB of way
    385 	lsl	ip, ip, r2		@ shift by that into way position
    386 	mov	r0, #1			@
    387 	lsl	r2, r0, r2		@ r2 now contains the way decr
    388 	mov	r0, r3 			@ get sets/level (no way yet)
    389 	orr	r3, r3, ip		@ merge way into way/set/level
    390 	bfc	r0, #0, #4		@ clear low 4 bits (level) to get numset - 1
    391 	sub	r2, r2, r0		@ subtract from way decr
    392 
    393 	/* r3 = ways/sets/level, r2 = way decr, r1 = set decr, r0 and ip are free */
    394 1:	mcr	p15, 0, r3, c7, c6, 2	@ DCISW (data cache invalidate by set/way)
    395 	cmp	r3, #15			@ are we done with this level (way/set == 0)
    396 	bls	.Ldone_l1inv		@ yes, we've finished
    397 	ubfx	r0, r3, #4, #18		@ extract set bits
    398 	cmp	r0, #0			@ compare
    399 	subne	r3, r3, r1		@ non-zero?, decrement set #
    400 	subeq	r3, r3, r2		@ zero?, decrement way # and restore set count
    401 	b	1b
    402 
    403 .Ldone_l1inv:
    404 	dsb
    405 	mov	r0, #0			@ default back to cache level 0
    406 	mcr	p15, 2, r0, c0, c0, 0	@ select cache level
    407 	dsb
    408 	isb
    409 	bx	lr
    410 END(armv7_dcache_l1inv_all)
    411 
    412 /* * LINTSTUB: void armv7_dcache_inv_all(void); */
    413 ENTRY_NP(armv7_dcache_inv_all)
    414 	mrc	p15, 1, r0, c0, c0, 1	@ read CLIDR
    415 	tst	r0, #0x07000000
    416 	beq	.Ldone_inv
    417 	mov	r3, #0			@ start with L1
    418 
    419 .Lstart_inv:
    420 	add	r2, r3, r3, lsr #1	@ r2 = level * 3 / 2
    421 	mov	r1, r0, lsr r2		@ r1 = cache type
    422 	tst	r1, #6			@ is it data or i&d?
    423 	beq	.Lnext_level_inv	@ nope, skip level
    424 
    425 	mcr	p15, 2, r3, c0, c0, 0	@ select cache level
    426 	isb
    427 	mrc	p15, 1, r0, c0, c0, 0	@ read CCSIDR
    428 
    429 	ubfx	ip, r0, #0, #3		@ get linesize from CCSIDR
    430 	add	ip, ip, #4		@ apply bias
    431 	ubfx	r2, r0, #13, #15	@ get numsets - 1 from CCSIDR
    432 	lsl	r2, r2, ip		@ shift to set position
    433 	orr	r3, r3, r2		@ merge set into way/set/level
    434 	mov	r1, #1
    435 	lsl	r1, r1, ip		@ r1 = set decr
    436 
    437 	ubfx	ip, r0, #3, #10		@ get numways - 1 from [to be discarded] CCSIDR
    438 	clz	r2, ip			@ number of bits to MSB of way
    439 	lsl	ip, ip, r2		@ shift by that into way position
    440 	mov	r0, #1			@
    441 	lsl	r2, r0, r2		@ r2 now contains the way decr
    442 	mov	r0, r3 			@ get sets/level (no way yet)
    443 	orr	r3, r3, ip		@ merge way into way/set/level
    444 	bfc	r0, #0, #4		@ clear low 4 bits (level) to get numset - 1
    445 	sub	r2, r2, r0		@ subtract from way decr
    446 
    447 	/* r3 = ways/sets/level, r2 = way decr, r1 = set decr, r0 and ip are free */
    448 1:	mcr	p15, 0, r3, c7, c6, 2	@ DCISW (data cache invalidate by set/way)
    449 	cmp	r3, #15			@ are we done with this level (way/set == 0)
    450 	bls	.Lnext_level_inv	@ yes, go to next level
    451 	ubfx	r0, r3, #4, #18		@ extract set bits
    452 	cmp	r0, #0			@ compare
    453 	subne	r3, r3, r1		@ non-zero?, decrement set #
    454 	subeq	r3, r3, r2		@ zero?, decrement way # and restore set count
    455 	b	1b
    456 
    457 .Lnext_level_inv:
    458 	dsb
    459 	mrc	p15, 1, r0, c0, c0, 1	@ read CLIDR
    460 	ubfx	ip, r0, #24, #3		@ narrow to LoC
    461 	add	r3, r3, #2		@ go to next level
    462 	cmp	r3, ip, lsl #1		@ compare
    463 	blt	.Lstart_inv		@ not done, next level (r0 == CLIDR)
    464 
    465 .Ldone_inv:
    466 	mov	r0, #0			@ default back to cache level 0
    467 	mcr	p15, 2, r0, c0, c0, 0	@ select cache level
    468 	dsb
    469 	isb
    470 	bx	lr
    471 END(armv7_dcache_inv_all)
    472 
    473 /* * LINTSTUB: void armv7_dcache_wbinv_all(void); */
    474 ENTRY_NP(armv7_dcache_wbinv_all)
    475 	mrc	p15, 1, r0, c0, c0, 1	@ read CLIDR
    476 	tst	r0, #0x07000000
    477 	bxeq	lr
    478 	mov	r3, #0			@ start with L1
    479 
    480 .Lstart_wbinv:
    481 	add	r2, r3, r3, lsr #1	@ r2 = level * 3 / 2
    482 	mov	r1, r0, lsr r2		@ r1 = cache type
    483 	tst	r1, #6			@ is it unified or data?
    484 	beq	.Lnext_level_wbinv	@ nope, skip level
    485 
    486 	mcr	p15, 2, r3, c0, c0, 0	@ select cache level
    487 	isb
    488 	mrc	p15, 1, r0, c0, c0, 0	@ read CCSIDR
    489 
    490 	ubfx	ip, r0, #0, #3		@ get linesize from CCSIDR
    491 	add	ip, ip, #4		@ apply bias
    492 	ubfx	r2, r0, #13, #15	@ get numsets - 1 from CCSIDR
    493 	lsl	r2, r2, ip		@ shift to set position
    494 	orr	r3, r3, r2		@ merge set into way/set/level
    495 	mov	r1, #1
    496 	lsl	r1, r1, ip		@ r1 = set decr
    497 
    498 	ubfx	ip, r0, #3, #10		@ get numways - 1 from [to be discarded] CCSIDR
    499 	clz	r2, ip			@ number of bits to MSB of way
    500 	lsl	ip, ip, r2		@ shift by that into way position
    501 	mov	r0, #1			@
    502 	lsl	r2, r0, r2		@ r2 now contains the way decr
    503 	mov	r0, r3 			@ get sets/level (no way yet)
    504 	orr	r3, r3, ip		@ merge way into way/set/level
    505 	bfc	r0, #0, #4		@ clear low 4 bits (level) to get numset - 1
    506 	sub	r2, r2, r0		@ subtract from way decr
    507 
    508 	/* r3 = ways/sets/level, r2 = way decr, r1 = set decr, r0 and ip are free */
    509 1:	mcr	p15, 0, r3, c7, c14, 2	@ DCCISW (data cache clean and invalidate by set/way)
    510 	cmp	r3, #15			@ are we done with this level (way/set == 0)
    511 	bls	.Lnext_level_wbinv	@ yes, go to next level
    512 	ubfx	r0, r3, #4, #18		@ extract set bits
    513 	cmp	r0, #0			@ compare
    514 	subne	r3, r3, r1		@ non-zero?, decrement set #
    515 	subeq	r3, r3, r2		@ zero?, decrement way # and restore set count
    516 	b	1b
    517 
    518 .Lnext_level_wbinv:
    519 	dsb
    520 	mrc	p15, 1, r0, c0, c0, 1	@ read CLIDR
    521 	ubfx	ip, r0, #24, #3		@ narrow to LoC
    522 	add	r3, r3, #2		@ go to next level
    523 	cmp	r3, ip, lsl #1		@ compare
    524 	blt	.Lstart_wbinv		@ not done, next level (r0 == CLIDR)
    525 
    526 .Ldone_wbinv:
    527 	mov	r0, #0			@ default back to cache level 0
    528 	mcr	p15, 2, r0, c0, c0, 0	@ select cache level
    529 	dsb
    530 	isb
    531 	bx	lr
    532 END(armv7_dcache_wbinv_all)
    533