cache-sh4.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /*
  2. * arch/sh/mm/cache-sh4.c
  3. *
  4. * Copyright (C) 1999, 2000, 2002 Niibe Yutaka
  5. * Copyright (C) 2001, 2002, 2003, 2004 Paul Mundt
  6. * Copyright (C) 2003 Richard Curnow
  7. *
  8. * This file is subject to the terms and conditions of the GNU General Public
  9. * License. See the file "COPYING" in the main directory of this archive
  10. * for more details.
  11. */
  12. #include <linux/init.h>
  13. #include <linux/mman.h>
  14. #include <linux/mm.h>
  15. #include <linux/threads.h>
  16. #include <asm/addrspace.h>
  17. #include <asm/page.h>
  18. #include <asm/pgtable.h>
  19. #include <asm/processor.h>
  20. #include <asm/cache.h>
  21. #include <asm/io.h>
  22. #include <asm/uaccess.h>
  23. #include <asm/pgalloc.h>
  24. #include <asm/mmu_context.h>
  25. #include <asm/cacheflush.h>
  26. extern void __flush_cache_4096_all(unsigned long start);
  27. static void __flush_cache_4096_all_ex(unsigned long start);
  28. extern void __flush_dcache_all(void);
  29. static void __flush_dcache_all_ex(void);
  30. /*
  31. * SH-4 has virtually indexed and physically tagged cache.
  32. */
  33. struct semaphore p3map_sem[4];
  34. void __init p3_cache_init(void)
  35. {
  36. if (remap_area_pages(P3SEG, 0, PAGE_SIZE*4, _PAGE_CACHABLE))
  37. panic("%s failed.", __FUNCTION__);
  38. sema_init (&p3map_sem[0], 1);
  39. sema_init (&p3map_sem[1], 1);
  40. sema_init (&p3map_sem[2], 1);
  41. sema_init (&p3map_sem[3], 1);
  42. }
  43. /*
  44. * Write back the dirty D-caches, but not invalidate them.
  45. *
  46. * START: Virtual Address (U0, P1, or P3)
  47. * SIZE: Size of the region.
  48. */
  49. void __flush_wback_region(void *start, int size)
  50. {
  51. unsigned long v;
  52. unsigned long begin, end;
  53. begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
  54. end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
  55. & ~(L1_CACHE_BYTES-1);
  56. for (v = begin; v < end; v+=L1_CACHE_BYTES) {
  57. asm volatile("ocbwb %0"
  58. : /* no output */
  59. : "m" (__m(v)));
  60. }
  61. }
  62. /*
  63. * Write back the dirty D-caches and invalidate them.
  64. *
  65. * START: Virtual Address (U0, P1, or P3)
  66. * SIZE: Size of the region.
  67. */
  68. void __flush_purge_region(void *start, int size)
  69. {
  70. unsigned long v;
  71. unsigned long begin, end;
  72. begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
  73. end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
  74. & ~(L1_CACHE_BYTES-1);
  75. for (v = begin; v < end; v+=L1_CACHE_BYTES) {
  76. asm volatile("ocbp %0"
  77. : /* no output */
  78. : "m" (__m(v)));
  79. }
  80. }
  81. /*
  82. * No write back please
  83. */
  84. void __flush_invalidate_region(void *start, int size)
  85. {
  86. unsigned long v;
  87. unsigned long begin, end;
  88. begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
  89. end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
  90. & ~(L1_CACHE_BYTES-1);
  91. for (v = begin; v < end; v+=L1_CACHE_BYTES) {
  92. asm volatile("ocbi %0"
  93. : /* no output */
  94. : "m" (__m(v)));
  95. }
  96. }
  97. static void __flush_dcache_all_ex(void)
  98. {
  99. unsigned long addr, end_addr, entry_offset;
  100. end_addr = CACHE_OC_ADDRESS_ARRAY + (cpu_data->dcache.sets << cpu_data->dcache.entry_shift) * cpu_data->dcache.ways;
  101. entry_offset = 1 << cpu_data->dcache.entry_shift;
  102. for (addr = CACHE_OC_ADDRESS_ARRAY; addr < end_addr; addr += entry_offset) {
  103. ctrl_outl(0, addr);
  104. }
  105. }
  106. static void __flush_cache_4096_all_ex(unsigned long start)
  107. {
  108. unsigned long addr, entry_offset;
  109. int i;
  110. entry_offset = 1 << cpu_data->dcache.entry_shift;
  111. for (i = 0; i < cpu_data->dcache.ways; i++, start += cpu_data->dcache.way_incr) {
  112. for (addr = CACHE_OC_ADDRESS_ARRAY + start;
  113. addr < CACHE_OC_ADDRESS_ARRAY + 4096 + start;
  114. addr += entry_offset) {
  115. ctrl_outl(0, addr);
  116. }
  117. }
  118. }
  119. void flush_cache_4096_all(unsigned long start)
  120. {
  121. if (cpu_data->dcache.ways == 1)
  122. __flush_cache_4096_all(start);
  123. else
  124. __flush_cache_4096_all_ex(start);
  125. }
  126. /*
  127. * Write back the range of D-cache, and purge the I-cache.
  128. *
  129. * Called from kernel/module.c:sys_init_module and routine for a.out format.
  130. */
  131. void flush_icache_range(unsigned long start, unsigned long end)
  132. {
  133. flush_cache_all();
  134. }
  135. /*
  136. * Write back the D-cache and purge the I-cache for signal trampoline.
  137. * .. which happens to be the same behavior as flush_icache_range().
  138. * So, we simply flush out a line.
  139. */
  140. void flush_cache_sigtramp(unsigned long addr)
  141. {
  142. unsigned long v, index;
  143. unsigned long flags;
  144. int i;
  145. v = addr & ~(L1_CACHE_BYTES-1);
  146. asm volatile("ocbwb %0"
  147. : /* no output */
  148. : "m" (__m(v)));
  149. index = CACHE_IC_ADDRESS_ARRAY | (v & cpu_data->icache.entry_mask);
  150. local_irq_save(flags);
  151. jump_to_P2();
  152. for(i = 0; i < cpu_data->icache.ways; i++, index += cpu_data->icache.way_incr)
  153. ctrl_outl(0, index); /* Clear out Valid-bit */
  154. back_to_P1();
  155. local_irq_restore(flags);
  156. }
  157. static inline void flush_cache_4096(unsigned long start,
  158. unsigned long phys)
  159. {
  160. unsigned long flags;
  161. extern void __flush_cache_4096(unsigned long addr, unsigned long phys, unsigned long exec_offset);
  162. /*
  163. * SH7751, SH7751R, and ST40 have no restriction to handle cache.
  164. * (While SH7750 must do that at P2 area.)
  165. */
  166. if ((cpu_data->flags & CPU_HAS_P2_FLUSH_BUG)
  167. || start < CACHE_OC_ADDRESS_ARRAY) {
  168. local_irq_save(flags);
  169. __flush_cache_4096(start | SH_CACHE_ASSOC, P1SEGADDR(phys), 0x20000000);
  170. local_irq_restore(flags);
  171. } else {
  172. __flush_cache_4096(start | SH_CACHE_ASSOC, P1SEGADDR(phys), 0);
  173. }
  174. }
  175. /*
  176. * Write back & invalidate the D-cache of the page.
  177. * (To avoid "alias" issues)
  178. */
  179. void flush_dcache_page(struct page *page)
  180. {
  181. if (test_bit(PG_mapped, &page->flags)) {
  182. unsigned long phys = PHYSADDR(page_address(page));
  183. /* Loop all the D-cache */
  184. flush_cache_4096(CACHE_OC_ADDRESS_ARRAY, phys);
  185. flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x1000, phys);
  186. flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x2000, phys);
  187. flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x3000, phys);
  188. }
  189. }
  190. static inline void flush_icache_all(void)
  191. {
  192. unsigned long flags, ccr;
  193. local_irq_save(flags);
  194. jump_to_P2();
  195. /* Flush I-cache */
  196. ccr = ctrl_inl(CCR);
  197. ccr |= CCR_CACHE_ICI;
  198. ctrl_outl(ccr, CCR);
  199. back_to_P1();
  200. local_irq_restore(flags);
  201. }
  202. void flush_cache_all(void)
  203. {
  204. if (cpu_data->dcache.ways == 1)
  205. __flush_dcache_all();
  206. else
  207. __flush_dcache_all_ex();
  208. flush_icache_all();
  209. }
  210. void flush_cache_mm(struct mm_struct *mm)
  211. {
  212. /* Is there any good way? */
  213. /* XXX: possibly call flush_cache_range for each vm area */
  214. /*
  215. * FIXME: Really, the optimal solution here would be able to flush out
  216. * individual lines created by the specified context, but this isn't
  217. * feasible for a number of architectures (such as MIPS, and some
  218. * SPARC) .. is this possible for SuperH?
  219. *
  220. * In the meantime, we'll just flush all of the caches.. this
  221. * seems to be the simplest way to avoid at least a few wasted
  222. * cache flushes. -Lethal
  223. */
  224. flush_cache_all();
  225. }
  226. /*
  227. * Write back and invalidate I/D-caches for the page.
  228. *
  229. * ADDR: Virtual Address (U0 address)
  230. * PFN: Physical page number
  231. */
  232. void flush_cache_page(struct vm_area_struct *vma, unsigned long address, unsigned long pfn)
  233. {
  234. unsigned long phys = pfn << PAGE_SHIFT;
  235. /* We only need to flush D-cache when we have alias */
  236. if ((address^phys) & CACHE_ALIAS) {
  237. /* Loop 4K of the D-cache */
  238. flush_cache_4096(
  239. CACHE_OC_ADDRESS_ARRAY | (address & CACHE_ALIAS),
  240. phys);
  241. /* Loop another 4K of the D-cache */
  242. flush_cache_4096(
  243. CACHE_OC_ADDRESS_ARRAY | (phys & CACHE_ALIAS),
  244. phys);
  245. }
  246. if (vma->vm_flags & VM_EXEC)
  247. /* Loop 4K (half) of the I-cache */
  248. flush_cache_4096(
  249. CACHE_IC_ADDRESS_ARRAY | (address & 0x1000),
  250. phys);
  251. }
  252. /*
  253. * Write back and invalidate D-caches.
  254. *
  255. * START, END: Virtual Address (U0 address)
  256. *
  257. * NOTE: We need to flush the _physical_ page entry.
  258. * Flushing the cache lines for U0 only isn't enough.
  259. * We need to flush for P1 too, which may contain aliases.
  260. */
  261. void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
  262. unsigned long end)
  263. {
  264. unsigned long p = start & PAGE_MASK;
  265. pgd_t *dir;
  266. pmd_t *pmd;
  267. pte_t *pte;
  268. pte_t entry;
  269. unsigned long phys;
  270. unsigned long d = 0;
  271. dir = pgd_offset(vma->vm_mm, p);
  272. pmd = pmd_offset(dir, p);
  273. do {
  274. if (pmd_none(*pmd) || pmd_bad(*pmd)) {
  275. p &= ~((1 << PMD_SHIFT) -1);
  276. p += (1 << PMD_SHIFT);
  277. pmd++;
  278. continue;
  279. }
  280. pte = pte_offset_kernel(pmd, p);
  281. do {
  282. entry = *pte;
  283. if ((pte_val(entry) & _PAGE_PRESENT)) {
  284. phys = pte_val(entry)&PTE_PHYS_MASK;
  285. if ((p^phys) & CACHE_ALIAS) {
  286. d |= 1 << ((p & CACHE_ALIAS)>>12);
  287. d |= 1 << ((phys & CACHE_ALIAS)>>12);
  288. if (d == 0x0f)
  289. goto loop_exit;
  290. }
  291. }
  292. pte++;
  293. p += PAGE_SIZE;
  294. } while (p < end && ((unsigned long)pte & ~PAGE_MASK));
  295. pmd++;
  296. } while (p < end);
  297. loop_exit:
  298. if (d & 1)
  299. flush_cache_4096_all(0);
  300. if (d & 2)
  301. flush_cache_4096_all(0x1000);
  302. if (d & 4)
  303. flush_cache_4096_all(0x2000);
  304. if (d & 8)
  305. flush_cache_4096_all(0x3000);
  306. if (vma->vm_flags & VM_EXEC)
  307. flush_icache_all();
  308. }
  309. /*
  310. * flush_icache_user_range
  311. * @vma: VMA of the process
  312. * @page: page
  313. * @addr: U0 address
  314. * @len: length of the range (< page size)
  315. */
  316. void flush_icache_user_range(struct vm_area_struct *vma,
  317. struct page *page, unsigned long addr, int len)
  318. {
  319. flush_cache_page(vma, addr, page_to_pfn(page));
  320. }