cache.S 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. /*
  2. * Cache maintenance
  3. *
  4. * Copyright (C) 2001 Deep Blue Solutions Ltd.
  5. * Copyright (C) 2012 ARM Ltd.
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <linux/linkage.h>
  20. #include <linux/init.h>
  21. #include <asm/assembler.h>
  22. #include <asm/cpufeature.h>
  23. #include <asm/alternative-asm.h>
  24. #include "proc-macros.S"
  25. /*
  26. * __flush_dcache_all()
  27. *
  28. * Flush the whole D-cache.
  29. *
  30. * Corrupted registers: x0-x7, x9-x11
  31. */
  32. __flush_dcache_all:
  33. dmb sy // ensure ordering with previous memory accesses
  34. mrs x0, clidr_el1 // read clidr
  35. and x3, x0, #0x7000000 // extract loc from clidr
  36. lsr x3, x3, #23 // left align loc bit field
  37. cbz x3, finished // if loc is 0, then no need to clean
  38. mov x10, #0 // start clean at cache level 0
  39. loop1:
  40. add x2, x10, x10, lsr #1 // work out 3x current cache level
  41. lsr x1, x0, x2 // extract cache type bits from clidr
  42. and x1, x1, #7 // mask of the bits for current cache only
  43. cmp x1, #2 // see what cache we have at this level
  44. b.lt skip // skip if no cache, or just i-cache
  45. save_and_disable_irqs x9 // make CSSELR and CCSIDR access atomic
  46. msr csselr_el1, x10 // select current cache level in csselr
  47. isb // isb to sych the new cssr&csidr
  48. mrs x1, ccsidr_el1 // read the new ccsidr
  49. restore_irqs x9
  50. and x2, x1, #7 // extract the length of the cache lines
  51. add x2, x2, #4 // add 4 (line length offset)
  52. mov x4, #0x3ff
  53. and x4, x4, x1, lsr #3 // find maximum number on the way size
  54. clz w5, w4 // find bit position of way size increment
  55. mov x7, #0x7fff
  56. and x7, x7, x1, lsr #13 // extract max number of the index size
  57. loop2:
  58. mov x9, x4 // create working copy of max way size
  59. loop3:
  60. lsl x6, x9, x5
  61. orr x11, x10, x6 // factor way and cache number into x11
  62. lsl x6, x7, x2
  63. orr x11, x11, x6 // factor index number into x11
  64. dc cisw, x11 // clean & invalidate by set/way
  65. subs x9, x9, #1 // decrement the way
  66. b.ge loop3
  67. subs x7, x7, #1 // decrement the index
  68. b.ge loop2
  69. skip:
  70. add x10, x10, #2 // increment cache number
  71. cmp x3, x10
  72. b.gt loop1
  73. finished:
  74. mov x10, #0 // swith back to cache level 0
  75. msr csselr_el1, x10 // select current cache level in csselr
  76. dsb sy
  77. isb
  78. ret
  79. ENDPROC(__flush_dcache_all)
  80. /*
  81. * flush_cache_all()
  82. *
  83. * Flush the entire cache system. The data cache flush is now achieved
  84. * using atomic clean / invalidates working outwards from L1 cache. This
  85. * is done using Set/Way based cache maintainance instructions. The
  86. * instruction cache can still be invalidated back to the point of
  87. * unification in a single instruction.
  88. */
  89. ENTRY(flush_cache_all)
  90. mov x12, lr
  91. bl __flush_dcache_all
  92. mov x0, #0
  93. ic ialluis // I+BTB cache invalidate
  94. ret x12
  95. ENDPROC(flush_cache_all)
  96. /*
  97. * flush_icache_range(start,end)
  98. *
  99. * Ensure that the I and D caches are coherent within specified region.
  100. * This is typically used when code has been written to a memory region,
  101. * and will be executed.
  102. *
  103. * - start - virtual start address of region
  104. * - end - virtual end address of region
  105. */
  106. ENTRY(flush_icache_range)
  107. /* FALLTHROUGH */
  108. /*
  109. * __flush_cache_user_range(start,end)
  110. *
  111. * Ensure that the I and D caches are coherent within specified region.
  112. * This is typically used when code has been written to a memory region,
  113. * and will be executed.
  114. *
  115. * - start - virtual start address of region
  116. * - end - virtual end address of region
  117. */
  118. ENTRY(__flush_cache_user_range)
  119. dcache_line_size x2, x3
  120. sub x3, x2, #1
  121. bic x4, x0, x3
  122. 1:
  123. user_alternative_insn 9f, "dc cvau, x4", "dc civac, x4", ARM64_WORKAROUND_CLEAN_CACHE
  124. add x4, x4, x2
  125. cmp x4, x1
  126. b.lo 1b
  127. dsb ish
  128. icache_line_size x2, x3
  129. sub x3, x2, #1
  130. bic x4, x0, x3
  131. 1:
  132. USER(9f, ic ivau, x4 ) // invalidate I line PoU
  133. add x4, x4, x2
  134. cmp x4, x1
  135. b.lo 1b
  136. 9: // ignore any faulting cache operation
  137. dsb ish
  138. isb
  139. ret
  140. ENDPROC(flush_icache_range)
  141. ENDPROC(__flush_cache_user_range)
  142. /*
  143. * __flush_dcache_area(kaddr, size)
  144. *
  145. * Ensure that the data held in the page kaddr is written back to the
  146. * page in question.
  147. *
  148. * - kaddr - kernel address
  149. * - size - size in question
  150. */
  151. ENTRY(__flush_dcache_area)
  152. dcache_line_size x2, x3
  153. add x1, x0, x1
  154. sub x3, x2, #1
  155. bic x0, x0, x3
  156. 1: dc civac, x0 // clean & invalidate D line / unified line
  157. add x0, x0, x2
  158. cmp x0, x1
  159. b.lo 1b
  160. dsb sy
  161. ret
  162. ENDPROC(__flush_dcache_area)
  163. /*
  164. * __inval_cache_range(start, end)
  165. * - start - start address of region
  166. * - end - end address of region
  167. */
  168. ENTRY(__inval_cache_range)
  169. /* FALLTHROUGH */
  170. /*
  171. * __dma_inv_range(start, end)
  172. * - start - virtual start address of region
  173. * - end - virtual end address of region
  174. */
  175. __dma_inv_range:
  176. dcache_line_size x2, x3
  177. sub x3, x2, #1
  178. tst x1, x3 // end cache line aligned?
  179. bic x1, x1, x3
  180. b.eq 1f
  181. dc civac, x1 // clean & invalidate D / U line
  182. 1: tst x0, x3 // start cache line aligned?
  183. bic x0, x0, x3
  184. b.eq 2f
  185. dc civac, x0 // clean & invalidate D / U line
  186. b 3f
  187. 2: dc ivac, x0 // invalidate D / U line
  188. 3: add x0, x0, x2
  189. cmp x0, x1
  190. b.lo 2b
  191. dsb sy
  192. ret
  193. ENDPROC(__inval_cache_range)
  194. ENDPROC(__dma_inv_range)
  195. /*
  196. * __dma_clean_range(start, end)
  197. * - start - virtual start address of region
  198. * - end - virtual end address of region
  199. */
  200. __dma_clean_range:
  201. dcache_line_size x2, x3
  202. sub x3, x2, #1
  203. bic x0, x0, x3
  204. 1: alternative_insn "dc cvac, x0", "dc civac, x0", ARM64_WORKAROUND_CLEAN_CACHE
  205. add x0, x0, x2
  206. cmp x0, x1
  207. b.lo 1b
  208. dsb sy
  209. ret
  210. ENDPROC(__dma_clean_range)
  211. /*
  212. * __dma_flush_range(start, end)
  213. * - start - virtual start address of region
  214. * - end - virtual end address of region
  215. */
  216. ENTRY(__dma_flush_range)
  217. dcache_line_size x2, x3
  218. sub x3, x2, #1
  219. bic x0, x0, x3
  220. 1: dc civac, x0 // clean & invalidate D / U line
  221. add x0, x0, x2
  222. cmp x0, x1
  223. b.lo 1b
  224. dsb sy
  225. ret
  226. ENDPROC(__dma_flush_range)
  227. /*
  228. * __dma_map_area(start, size, dir)
  229. * - start - kernel virtual start address
  230. * - size - size of region
  231. * - dir - DMA direction
  232. */
  233. ENTRY(__dma_map_area)
  234. add x1, x1, x0
  235. cmp w2, #DMA_FROM_DEVICE
  236. b.eq __dma_inv_range
  237. b __dma_clean_range
  238. ENDPROC(__dma_map_area)
  239. /*
  240. * __dma_unmap_area(start, size, dir)
  241. * - start - kernel virtual start address
  242. * - size - size of region
  243. * - dir - DMA direction
  244. */
  245. ENTRY(__dma_unmap_area)
  246. add x1, x1, x0
  247. cmp w2, #DMA_TO_DEVICE
  248. b.ne __dma_inv_range
  249. ret
  250. ENDPROC(__dma_unmap_area)