tlb-score.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /*
  2. * arch/score/mm/tlb-score.c
  3. *
  4. * Score Processor version.
  5. *
  6. * Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
  7. * Lennox Wu <lennox.wu@sunplusct.com>
  8. * Chen Liqin <liqin.chen@sunplusct.com>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, see the file COPYING, or write
  22. * to the Free Software Foundation, Inc.,
  23. * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  24. */
  25. #include <linux/highmem.h>
  26. #include <linux/module.h>
  27. #include <asm/irq.h>
  28. #include <asm/mmu_context.h>
  29. #include <asm/tlb.h>
  30. #define TLBSIZE 32
  31. unsigned long asid_cache = ASID_FIRST_VERSION;
  32. EXPORT_SYMBOL(asid_cache);
  33. void local_flush_tlb_all(void)
  34. {
  35. unsigned long flags;
  36. unsigned long old_ASID;
  37. int entry;
  38. local_irq_save(flags);
  39. old_ASID = pevn_get() & ASID_MASK;
  40. pectx_set(0); /* invalid */
  41. entry = tlblock_get(); /* skip locked entries*/
  42. for (; entry < TLBSIZE; entry++) {
  43. tlbpt_set(entry);
  44. pevn_set(KSEG1);
  45. barrier();
  46. tlb_write_indexed();
  47. }
  48. pevn_set(old_ASID);
  49. local_irq_restore(flags);
  50. }
  51. /*
  52. * If mm is currently active_mm, we can't really drop it. Instead,
  53. * we will get a new one for it.
  54. */
  55. static inline void
  56. drop_mmu_context(struct mm_struct *mm)
  57. {
  58. unsigned long flags;
  59. local_irq_save(flags);
  60. get_new_mmu_context(mm);
  61. pevn_set(mm->context & ASID_MASK);
  62. local_irq_restore(flags);
  63. }
  64. void local_flush_tlb_mm(struct mm_struct *mm)
  65. {
  66. if (mm->context != 0)
  67. drop_mmu_context(mm);
  68. }
  69. void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
  70. unsigned long end)
  71. {
  72. struct mm_struct *mm = vma->vm_mm;
  73. unsigned long vma_mm_context = mm->context;
  74. if (mm->context != 0) {
  75. unsigned long flags;
  76. int size;
  77. local_irq_save(flags);
  78. size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
  79. if (size <= TLBSIZE) {
  80. int oldpid = pevn_get() & ASID_MASK;
  81. int newpid = vma_mm_context & ASID_MASK;
  82. start &= PAGE_MASK;
  83. end += (PAGE_SIZE - 1);
  84. end &= PAGE_MASK;
  85. while (start < end) {
  86. int idx;
  87. pevn_set(start | newpid);
  88. start += PAGE_SIZE;
  89. barrier();
  90. tlb_probe();
  91. idx = tlbpt_get();
  92. pectx_set(0);
  93. pevn_set(KSEG1);
  94. if (idx < 0)
  95. continue;
  96. tlb_write_indexed();
  97. }
  98. pevn_set(oldpid);
  99. } else {
  100. /* Bigger than TLBSIZE, get new ASID directly */
  101. get_new_mmu_context(mm);
  102. if (mm == current->active_mm)
  103. pevn_set(vma_mm_context & ASID_MASK);
  104. }
  105. local_irq_restore(flags);
  106. }
  107. }
  108. void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
  109. {
  110. unsigned long flags;
  111. int size;
  112. local_irq_save(flags);
  113. size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
  114. if (size <= TLBSIZE) {
  115. int pid = pevn_get();
  116. start &= PAGE_MASK;
  117. end += PAGE_SIZE - 1;
  118. end &= PAGE_MASK;
  119. while (start < end) {
  120. long idx;
  121. pevn_set(start);
  122. start += PAGE_SIZE;
  123. tlb_probe();
  124. idx = tlbpt_get();
  125. if (idx < 0)
  126. continue;
  127. pectx_set(0);
  128. pevn_set(KSEG1);
  129. barrier();
  130. tlb_write_indexed();
  131. }
  132. pevn_set(pid);
  133. } else {
  134. local_flush_tlb_all();
  135. }
  136. local_irq_restore(flags);
  137. }
  138. void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
  139. {
  140. if (vma && vma->vm_mm->context != 0) {
  141. unsigned long flags;
  142. int oldpid, newpid, idx;
  143. unsigned long vma_ASID = vma->vm_mm->context;
  144. newpid = vma_ASID & ASID_MASK;
  145. page &= PAGE_MASK;
  146. local_irq_save(flags);
  147. oldpid = pevn_get() & ASID_MASK;
  148. pevn_set(page | newpid);
  149. barrier();
  150. tlb_probe();
  151. idx = tlbpt_get();
  152. pectx_set(0);
  153. pevn_set(KSEG1);
  154. if (idx < 0) /* p_bit(31) - 1: miss, 0: hit*/
  155. goto finish;
  156. barrier();
  157. tlb_write_indexed();
  158. finish:
  159. pevn_set(oldpid);
  160. local_irq_restore(flags);
  161. }
  162. }
  163. /*
  164. * This one is only used for pages with the global bit set so we don't care
  165. * much about the ASID.
  166. */
  167. void local_flush_tlb_one(unsigned long page)
  168. {
  169. unsigned long flags;
  170. int oldpid, idx;
  171. local_irq_save(flags);
  172. oldpid = pevn_get();
  173. page &= (PAGE_MASK << 1);
  174. pevn_set(page);
  175. barrier();
  176. tlb_probe();
  177. idx = tlbpt_get();
  178. pectx_set(0);
  179. if (idx >= 0) {
  180. /* Make sure all entries differ. */
  181. pevn_set(KSEG1);
  182. barrier();
  183. tlb_write_indexed();
  184. }
  185. pevn_set(oldpid);
  186. local_irq_restore(flags);
  187. }
  188. void __update_tlb(struct vm_area_struct *vma, unsigned long address, pte_t pte)
  189. {
  190. unsigned long flags;
  191. int idx, pid;
  192. /*
  193. * Handle debugger faulting in for debugee.
  194. */
  195. if (current->active_mm != vma->vm_mm)
  196. return;
  197. pid = pevn_get() & ASID_MASK;
  198. local_irq_save(flags);
  199. address &= PAGE_MASK;
  200. pevn_set(address | pid);
  201. barrier();
  202. tlb_probe();
  203. idx = tlbpt_get();
  204. pectx_set(pte_val(pte));
  205. pevn_set(address | pid);
  206. if (idx < 0)
  207. tlb_write_random();
  208. else
  209. tlb_write_indexed();
  210. pevn_set(pid);
  211. local_irq_restore(flags);
  212. }
  213. void tlb_init(void)
  214. {
  215. tlblock_set(0);
  216. local_flush_tlb_all();
  217. memcpy((void *)(EXCEPTION_VECTOR_BASE_ADDR + 0x100),
  218. &score7_FTLB_refill_Handler, 0xFC);
  219. flush_icache_range(EXCEPTION_VECTOR_BASE_ADDR + 0x100,
  220. EXCEPTION_VECTOR_BASE_ADDR + 0x1FC);
  221. }