root/arch/arm/mm/cache-v7.S

/* [<][>][^][v][top][bottom][index][help] */
   1 /* SPDX-License-Identifier: GPL-2.0-only */
   2 /*
   3  *  linux/arch/arm/mm/cache-v7.S
   4  *
   5  *  Copyright (C) 2001 Deep Blue Solutions Ltd.
   6  *  Copyright (C) 2005 ARM Ltd.
   7  *
   8  *  This is the "shell" of the ARMv7 processor support.
   9  */
  10 #include <linux/linkage.h>
  11 #include <linux/init.h>
  12 #include <asm/assembler.h>
  13 #include <asm/errno.h>
  14 #include <asm/unwind.h>
  15 #include <asm/hardware/cache-b15-rac.h>
  16 
  17 #include "proc-macros.S"
  18 
  19 #ifdef CONFIG_CPU_ICACHE_MISMATCH_WORKAROUND
  20 .globl icache_size
  21         .data
  22         .align  2
  23 icache_size:
  24         .long   64
  25         .text
  26 #endif
  27 /*
  28  * The secondary kernel init calls v7_flush_dcache_all before it enables
  29  * the L1; however, the L1 comes out of reset in an undefined state, so
  30  * the clean + invalidate performed by v7_flush_dcache_all causes a bunch
  31  * of cache lines with uninitialized data and uninitialized tags to get
  32  * written out to memory, which does really unpleasant things to the main
  33  * processor.  We fix this by performing an invalidate, rather than a
  34  * clean + invalidate, before jumping into the kernel.
  35  *
  36  * This function is cloned from arch/arm/mach-tegra/headsmp.S, and needs
  37  * to be called for both secondary cores startup and primary core resume
  38  * procedures.
  39  */
  40 ENTRY(v7_invalidate_l1)
  41        mov     r0, #0
  42        mcr     p15, 2, r0, c0, c0, 0
  43        mrc     p15, 1, r0, c0, c0, 0
  44 
  45        movw    r1, #0x7fff
  46        and     r2, r1, r0, lsr #13
  47 
  48        movw    r1, #0x3ff
  49 
  50        and     r3, r1, r0, lsr #3      @ NumWays - 1
  51        add     r2, r2, #1              @ NumSets
  52 
  53        and     r0, r0, #0x7
  54        add     r0, r0, #4      @ SetShift
  55 
  56        clz     r1, r3          @ WayShift
  57        add     r4, r3, #1      @ NumWays
  58 1:     sub     r2, r2, #1      @ NumSets--
  59        mov     r3, r4          @ Temp = NumWays
  60 2:     subs    r3, r3, #1      @ Temp--
  61        mov     r5, r3, lsl r1
  62        mov     r6, r2, lsl r0
  63        orr     r5, r5, r6      @ Reg = (Temp<<WayShift)|(NumSets<<SetShift)
  64        mcr     p15, 0, r5, c7, c6, 2
  65        bgt     2b
  66        cmp     r2, #0
  67        bgt     1b
  68        dsb     st
  69        isb
  70        ret     lr
  71 ENDPROC(v7_invalidate_l1)
  72 
  73 /*
  74  *      v7_flush_icache_all()
  75  *
  76  *      Flush the whole I-cache.
  77  *
  78  *      Registers:
  79  *      r0 - set to 0
  80  */
  81 ENTRY(v7_flush_icache_all)
  82         mov     r0, #0
  83         ALT_SMP(mcr     p15, 0, r0, c7, c1, 0)          @ invalidate I-cache inner shareable
  84         ALT_UP(mcr      p15, 0, r0, c7, c5, 0)          @ I+BTB cache invalidate
  85         ret     lr
  86 ENDPROC(v7_flush_icache_all)
  87 
  88  /*
  89  *     v7_flush_dcache_louis()
  90  *
  91  *     Flush the D-cache up to the Level of Unification Inner Shareable
  92  *
  93  *     Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode)
  94  */
  95 
  96 ENTRY(v7_flush_dcache_louis)
  97         dmb                                     @ ensure ordering with previous memory accesses
  98         mrc     p15, 1, r0, c0, c0, 1           @ read clidr, r0 = clidr
  99 ALT_SMP(mov     r3, r0, lsr #20)                @ move LoUIS into position
 100 ALT_UP( mov     r3, r0, lsr #26)                @ move LoUU into position
 101         ands    r3, r3, #7 << 1                 @ extract LoU*2 field from clidr
 102         bne     start_flush_levels              @ LoU != 0, start flushing
 103 #ifdef CONFIG_ARM_ERRATA_643719
 104 ALT_SMP(mrc     p15, 0, r2, c0, c0, 0)          @ read main ID register
 105 ALT_UP( ret     lr)                             @ LoUU is zero, so nothing to do
 106         movw    r1, #:lower16:(0x410fc090 >> 4) @ ID of ARM Cortex A9 r0p?
 107         movt    r1, #:upper16:(0x410fc090 >> 4)
 108         teq     r1, r2, lsr #4                  @ test for errata affected core and if so...
 109         moveq   r3, #1 << 1                     @   fix LoUIS value
 110         beq     start_flush_levels              @   start flushing cache levels
 111 #endif
 112         ret     lr
 113 ENDPROC(v7_flush_dcache_louis)
 114 
 115 /*
 116  *      v7_flush_dcache_all()
 117  *
 118  *      Flush the whole D-cache.
 119  *
 120  *      Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode)
 121  *
 122  *      - mm    - mm_struct describing address space
 123  */
 124 ENTRY(v7_flush_dcache_all)
 125         dmb                                     @ ensure ordering with previous memory accesses
 126         mrc     p15, 1, r0, c0, c0, 1           @ read clidr
 127         mov     r3, r0, lsr #23                 @ move LoC into position
 128         ands    r3, r3, #7 << 1                 @ extract LoC*2 from clidr
 129         beq     finished                        @ if loc is 0, then no need to clean
 130 start_flush_levels:
 131         mov     r10, #0                         @ start clean at cache level 0
 132 flush_levels:
 133         add     r2, r10, r10, lsr #1            @ work out 3x current cache level
 134         mov     r1, r0, lsr r2                  @ extract cache type bits from clidr
 135         and     r1, r1, #7                      @ mask of the bits for current cache only
 136         cmp     r1, #2                          @ see what cache we have at this level
 137         blt     skip                            @ skip if no cache, or just i-cache
 138 #ifdef CONFIG_PREEMPT
 139         save_and_disable_irqs_notrace r9        @ make cssr&csidr read atomic
 140 #endif
 141         mcr     p15, 2, r10, c0, c0, 0          @ select current cache level in cssr
 142         isb                                     @ isb to sych the new cssr&csidr
 143         mrc     p15, 1, r1, c0, c0, 0           @ read the new csidr
 144 #ifdef CONFIG_PREEMPT
 145         restore_irqs_notrace r9
 146 #endif
 147         and     r2, r1, #7                      @ extract the length of the cache lines
 148         add     r2, r2, #4                      @ add 4 (line length offset)
 149         movw    r4, #0x3ff
 150         ands    r4, r4, r1, lsr #3              @ find maximum number on the way size
 151         clz     r5, r4                          @ find bit position of way size increment
 152         movw    r7, #0x7fff
 153         ands    r7, r7, r1, lsr #13             @ extract max number of the index size
 154 loop1:
 155         mov     r9, r7                          @ create working copy of max index
 156 loop2:
 157  ARM(   orr     r11, r10, r4, lsl r5    )       @ factor way and cache number into r11
 158  THUMB( lsl     r6, r4, r5              )
 159  THUMB( orr     r11, r10, r6            )       @ factor way and cache number into r11
 160  ARM(   orr     r11, r11, r9, lsl r2    )       @ factor index number into r11
 161  THUMB( lsl     r6, r9, r2              )
 162  THUMB( orr     r11, r11, r6            )       @ factor index number into r11
 163         mcr     p15, 0, r11, c7, c14, 2         @ clean & invalidate by set/way
 164         subs    r9, r9, #1                      @ decrement the index
 165         bge     loop2
 166         subs    r4, r4, #1                      @ decrement the way
 167         bge     loop1
 168 skip:
 169         add     r10, r10, #2                    @ increment cache number
 170         cmp     r3, r10
 171 #ifdef CONFIG_ARM_ERRATA_814220
 172         dsb
 173 #endif
 174         bgt     flush_levels
 175 finished:
 176         mov     r10, #0                         @ switch back to cache level 0
 177         mcr     p15, 2, r10, c0, c0, 0          @ select current cache level in cssr
 178         dsb     st
 179         isb
 180         ret     lr
 181 ENDPROC(v7_flush_dcache_all)
 182 
 183 /*
 184  *      v7_flush_cache_all()
 185  *
 186  *      Flush the entire cache system.
 187  *  The data cache flush is now achieved using atomic clean / invalidates
 188  *  working outwards from L1 cache. This is done using Set/Way based cache
 189  *  maintenance instructions.
 190  *  The instruction cache can still be invalidated back to the point of
 191  *  unification in a single instruction.
 192  *
 193  */
 194 ENTRY(v7_flush_kern_cache_all)
 195  ARM(   stmfd   sp!, {r4-r5, r7, r9-r11, lr}    )
 196  THUMB( stmfd   sp!, {r4-r7, r9-r11, lr}        )
 197         bl      v7_flush_dcache_all
 198         mov     r0, #0
 199         ALT_SMP(mcr     p15, 0, r0, c7, c1, 0)  @ invalidate I-cache inner shareable
 200         ALT_UP(mcr      p15, 0, r0, c7, c5, 0)  @ I+BTB cache invalidate
 201  ARM(   ldmfd   sp!, {r4-r5, r7, r9-r11, lr}    )
 202  THUMB( ldmfd   sp!, {r4-r7, r9-r11, lr}        )
 203         ret     lr
 204 ENDPROC(v7_flush_kern_cache_all)
 205 
 206  /*
 207  *     v7_flush_kern_cache_louis(void)
 208  *
 209  *     Flush the data cache up to Level of Unification Inner Shareable.
 210  *     Invalidate the I-cache to the point of unification.
 211  */
 212 ENTRY(v7_flush_kern_cache_louis)
 213  ARM(   stmfd   sp!, {r4-r5, r7, r9-r11, lr}    )
 214  THUMB( stmfd   sp!, {r4-r7, r9-r11, lr}        )
 215         bl      v7_flush_dcache_louis
 216         mov     r0, #0
 217         ALT_SMP(mcr     p15, 0, r0, c7, c1, 0)  @ invalidate I-cache inner shareable
 218         ALT_UP(mcr      p15, 0, r0, c7, c5, 0)  @ I+BTB cache invalidate
 219  ARM(   ldmfd   sp!, {r4-r5, r7, r9-r11, lr}    )
 220  THUMB( ldmfd   sp!, {r4-r7, r9-r11, lr}        )
 221         ret     lr
 222 ENDPROC(v7_flush_kern_cache_louis)
 223 
 224 /*
 225  *      v7_flush_cache_all()
 226  *
 227  *      Flush all TLB entries in a particular address space
 228  *
 229  *      - mm    - mm_struct describing address space
 230  */
 231 ENTRY(v7_flush_user_cache_all)
 232         /*FALLTHROUGH*/
 233 
 234 /*
 235  *      v7_flush_cache_range(start, end, flags)
 236  *
 237  *      Flush a range of TLB entries in the specified address space.
 238  *
 239  *      - start - start address (may not be aligned)
 240  *      - end   - end address (exclusive, may not be aligned)
 241  *      - flags - vm_area_struct flags describing address space
 242  *
 243  *      It is assumed that:
 244  *      - we have a VIPT cache.
 245  */
 246 ENTRY(v7_flush_user_cache_range)
 247         ret     lr
 248 ENDPROC(v7_flush_user_cache_all)
 249 ENDPROC(v7_flush_user_cache_range)
 250 
 251 /*
 252  *      v7_coherent_kern_range(start,end)
 253  *
 254  *      Ensure that the I and D caches are coherent within specified
 255  *      region.  This is typically used when code has been written to
 256  *      a memory region, and will be executed.
 257  *
 258  *      - start   - virtual start address of region
 259  *      - end     - virtual end address of region
 260  *
 261  *      It is assumed that:
 262  *      - the Icache does not read data from the write buffer
 263  */
 264 ENTRY(v7_coherent_kern_range)
 265         /* FALLTHROUGH */
 266 
 267 /*
 268  *      v7_coherent_user_range(start,end)
 269  *
 270  *      Ensure that the I and D caches are coherent within specified
 271  *      region.  This is typically used when code has been written to
 272  *      a memory region, and will be executed.
 273  *
 274  *      - start   - virtual start address of region
 275  *      - end     - virtual end address of region
 276  *
 277  *      It is assumed that:
 278  *      - the Icache does not read data from the write buffer
 279  */
 280 ENTRY(v7_coherent_user_range)
 281  UNWIND(.fnstart                )
 282         dcache_line_size r2, r3
 283         sub     r3, r2, #1
 284         bic     r12, r0, r3
 285 #ifdef CONFIG_ARM_ERRATA_764369
 286         ALT_SMP(W(dsb))
 287         ALT_UP(W(nop))
 288 #endif
 289 1:
 290  USER(  mcr     p15, 0, r12, c7, c11, 1 )       @ clean D line to the point of unification
 291         add     r12, r12, r2
 292         cmp     r12, r1
 293         blo     1b
 294         dsb     ishst
 295 #ifdef CONFIG_CPU_ICACHE_MISMATCH_WORKAROUND
 296         ldr     r3, =icache_size
 297         ldr     r2, [r3, #0]
 298 #else
 299         icache_line_size r2, r3
 300 #endif
 301         sub     r3, r2, #1
 302         bic     r12, r0, r3
 303 2:
 304  USER(  mcr     p15, 0, r12, c7, c5, 1  )       @ invalidate I line
 305         add     r12, r12, r2
 306         cmp     r12, r1
 307         blo     2b
 308         mov     r0, #0
 309         ALT_SMP(mcr     p15, 0, r0, c7, c1, 6)  @ invalidate BTB Inner Shareable
 310         ALT_UP(mcr      p15, 0, r0, c7, c5, 6)  @ invalidate BTB
 311         dsb     ishst
 312         isb
 313         ret     lr
 314 
 315 /*
 316  * Fault handling for the cache operation above. If the virtual address in r0
 317  * isn't mapped, fail with -EFAULT.
 318  */
 319 9001:
 320 #ifdef CONFIG_ARM_ERRATA_775420
 321         dsb
 322 #endif
 323         mov     r0, #-EFAULT
 324         ret     lr
 325  UNWIND(.fnend          )
 326 ENDPROC(v7_coherent_kern_range)
 327 ENDPROC(v7_coherent_user_range)
 328 
 329 /*
 330  *      v7_flush_kern_dcache_area(void *addr, size_t size)
 331  *
 332  *      Ensure that the data held in the page kaddr is written back
 333  *      to the page in question.
 334  *
 335  *      - addr  - kernel address
 336  *      - size  - region size
 337  */
 338 ENTRY(v7_flush_kern_dcache_area)
 339         dcache_line_size r2, r3
 340         add     r1, r0, r1
 341         sub     r3, r2, #1
 342         bic     r0, r0, r3
 343 #ifdef CONFIG_ARM_ERRATA_764369
 344         ALT_SMP(W(dsb))
 345         ALT_UP(W(nop))
 346 #endif
 347 1:
 348         mcr     p15, 0, r0, c7, c14, 1          @ clean & invalidate D line / unified line
 349         add     r0, r0, r2
 350         cmp     r0, r1
 351         blo     1b
 352         dsb     st
 353         ret     lr
 354 ENDPROC(v7_flush_kern_dcache_area)
 355 
 356 /*
 357  *      v7_dma_inv_range(start,end)
 358  *
 359  *      Invalidate the data cache within the specified region; we will
 360  *      be performing a DMA operation in this region and we want to
 361  *      purge old data in the cache.
 362  *
 363  *      - start   - virtual start address of region
 364  *      - end     - virtual end address of region
 365  */
 366 v7_dma_inv_range:
 367         dcache_line_size r2, r3
 368         sub     r3, r2, #1
 369         tst     r0, r3
 370         bic     r0, r0, r3
 371 #ifdef CONFIG_ARM_ERRATA_764369
 372         ALT_SMP(W(dsb))
 373         ALT_UP(W(nop))
 374 #endif
 375         mcrne   p15, 0, r0, c7, c14, 1          @ clean & invalidate D / U line
 376         addne   r0, r0, r2
 377 
 378         tst     r1, r3
 379         bic     r1, r1, r3
 380         mcrne   p15, 0, r1, c7, c14, 1          @ clean & invalidate D / U line
 381         cmp     r0, r1
 382 1:
 383         mcrlo   p15, 0, r0, c7, c6, 1           @ invalidate D / U line
 384         addlo   r0, r0, r2
 385         cmplo   r0, r1
 386         blo     1b
 387         dsb     st
 388         ret     lr
 389 ENDPROC(v7_dma_inv_range)
 390 
 391 /*
 392  *      v7_dma_clean_range(start,end)
 393  *      - start   - virtual start address of region
 394  *      - end     - virtual end address of region
 395  */
 396 v7_dma_clean_range:
 397         dcache_line_size r2, r3
 398         sub     r3, r2, #1
 399         bic     r0, r0, r3
 400 #ifdef CONFIG_ARM_ERRATA_764369
 401         ALT_SMP(W(dsb))
 402         ALT_UP(W(nop))
 403 #endif
 404 1:
 405         mcr     p15, 0, r0, c7, c10, 1          @ clean D / U line
 406         add     r0, r0, r2
 407         cmp     r0, r1
 408         blo     1b
 409         dsb     st
 410         ret     lr
 411 ENDPROC(v7_dma_clean_range)
 412 
 413 /*
 414  *      v7_dma_flush_range(start,end)
 415  *      - start   - virtual start address of region
 416  *      - end     - virtual end address of region
 417  */
 418 ENTRY(v7_dma_flush_range)
 419         dcache_line_size r2, r3
 420         sub     r3, r2, #1
 421         bic     r0, r0, r3
 422 #ifdef CONFIG_ARM_ERRATA_764369
 423         ALT_SMP(W(dsb))
 424         ALT_UP(W(nop))
 425 #endif
 426 1:
 427         mcr     p15, 0, r0, c7, c14, 1          @ clean & invalidate D / U line
 428         add     r0, r0, r2
 429         cmp     r0, r1
 430         blo     1b
 431         dsb     st
 432         ret     lr
 433 ENDPROC(v7_dma_flush_range)
 434 
 435 /*
 436  *      dma_map_area(start, size, dir)
 437  *      - start - kernel virtual start address
 438  *      - size  - size of region
 439  *      - dir   - DMA direction
 440  */
 441 ENTRY(v7_dma_map_area)
 442         add     r1, r1, r0
 443         teq     r2, #DMA_FROM_DEVICE
 444         beq     v7_dma_inv_range
 445         b       v7_dma_clean_range
 446 ENDPROC(v7_dma_map_area)
 447 
 448 /*
 449  *      dma_unmap_area(start, size, dir)
 450  *      - start - kernel virtual start address
 451  *      - size  - size of region
 452  *      - dir   - DMA direction
 453  */
 454 ENTRY(v7_dma_unmap_area)
 455         add     r1, r1, r0
 456         teq     r2, #DMA_TO_DEVICE
 457         bne     v7_dma_inv_range
 458         ret     lr
 459 ENDPROC(v7_dma_unmap_area)
 460 
 461         __INITDATA
 462 
 463         @ define struct cpu_cache_fns (see <asm/cacheflush.h> and proc-macros.S)
 464         define_cache_functions v7
 465 
 466         /* The Broadcom Brahma-B15 read-ahead cache requires some modifications
 467          * to the v7_cache_fns, we only override the ones we need
 468          */
 469 #ifndef CONFIG_CACHE_B15_RAC
 470         globl_equ       b15_flush_kern_cache_all,       v7_flush_kern_cache_all
 471 #endif
 472         globl_equ       b15_flush_icache_all,           v7_flush_icache_all
 473         globl_equ       b15_flush_kern_cache_louis,     v7_flush_kern_cache_louis
 474         globl_equ       b15_flush_user_cache_all,       v7_flush_user_cache_all
 475         globl_equ       b15_flush_user_cache_range,     v7_flush_user_cache_range
 476         globl_equ       b15_coherent_kern_range,        v7_coherent_kern_range
 477         globl_equ       b15_coherent_user_range,        v7_coherent_user_range
 478         globl_equ       b15_flush_kern_dcache_area,     v7_flush_kern_dcache_area
 479 
 480         globl_equ       b15_dma_map_area,               v7_dma_map_area
 481         globl_equ       b15_dma_unmap_area,             v7_dma_unmap_area
 482         globl_equ       b15_dma_flush_range,            v7_dma_flush_range
 483 
 484         define_cache_functions b15

/* [<][>][^][v][top][bottom][index][help] */