cache.S 6.7 KB

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