tlb-r3k.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:6k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * r2300.c: R2000 and R3000 specific mmu/cache code.
  3.  *
  4.  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  5.  *
  6.  * with a lot of changes to make this thing work for R3000s
  7.  * Tx39XX R4k style caches added. HK
  8.  * Copyright (C) 1998, 1999, 2000 Harald Koerfgen
  9.  * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
  10.  */
  11. #include <linux/config.h>
  12. #include <linux/init.h>
  13. #include <linux/kernel.h>
  14. #include <linux/sched.h>
  15. #include <linux/mm.h>
  16. #include <asm/page.h>
  17. #include <asm/pgtable.h>
  18. #include <asm/mmu_context.h>
  19. #include <asm/system.h>
  20. #include <asm/isadep.h>
  21. #include <asm/io.h>
  22. #include <asm/bootinfo.h>
  23. #include <asm/cpu.h>
  24. extern char except_vec0_r2300;
  25. #undef DEBUG_TLB
  26. int r3k_have_wired_reg = 0; /* should be in mips_cpu? */
  27. /* TLB operations. */
  28. void local_flush_tlb_all(void)
  29. {
  30. unsigned long flags;
  31. unsigned long old_ctx;
  32. int entry;
  33. #ifdef DEBUG_TLB
  34. printk("[tlball]");
  35. #endif
  36. save_and_cli(flags);
  37. old_ctx = (get_entryhi() & 0xfc0);
  38. write_32bit_cp0_register(CP0_ENTRYLO0, 0);
  39. #ifdef CONFIG_CPU_TX39XX
  40. entry = r3k_have_wired_reg ? get_wired() : 8;
  41. #else
  42. entry = 8;
  43. #endif
  44. for (; entry < mips_cpu.tlbsize; entry++) {
  45. write_32bit_cp0_register(CP0_INDEX, entry << 8);
  46. write_32bit_cp0_register(CP0_ENTRYHI, ((entry | 0x80000) << 12));
  47. __asm__ __volatile__("tlbwi");
  48. }
  49. set_entryhi(old_ctx);
  50. restore_flags(flags);
  51. }
  52. void local_flush_tlb_mm(struct mm_struct *mm)
  53. {
  54. if (mm->context != 0) {
  55. unsigned long flags;
  56. #ifdef DEBUG_TLB
  57. printk("[tlbmm<%lu>]", (unsigned long) mm->context);
  58. #endif
  59. save_and_cli(flags);
  60. get_new_mmu_context(mm, smp_processor_id());
  61. if (mm == current->active_mm)
  62. set_entryhi(mm->context & 0xfc0);
  63. restore_flags(flags);
  64. }
  65. }
  66. void local_flush_tlb_range(struct mm_struct *mm, unsigned long start,
  67.                      unsigned long end)
  68. {
  69. if (mm->context != 0) {
  70. unsigned long flags;
  71. int size;
  72. #ifdef DEBUG_TLB
  73. printk("[tlbrange<%lu,0x%08lx,0x%08lx>]",
  74. (mm->context & 0xfc0), start, end);
  75. #endif
  76. save_and_cli(flags);
  77. size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
  78. if (size <= mips_cpu.tlbsize) {
  79. int oldpid = (get_entryhi() & 0xfc0);
  80. int newpid = (mm->context & 0xfc0);
  81. start &= PAGE_MASK;
  82. end += (PAGE_SIZE - 1);
  83. end &= PAGE_MASK;
  84. while (start < end) {
  85. int idx;
  86. set_entryhi(start | newpid);
  87. start += PAGE_SIZE;
  88. tlb_probe();
  89. idx = get_index();
  90. set_entrylo0(0);
  91. set_entryhi(KSEG0);
  92. if (idx < 0)
  93. continue;
  94. tlb_write_indexed();
  95. }
  96. set_entryhi(oldpid);
  97. } else {
  98. get_new_mmu_context(mm, smp_processor_id());
  99. if (mm == current->active_mm)
  100. set_entryhi(mm->context & 0xfc0);
  101. }
  102. restore_flags(flags);
  103. }
  104. }
  105. void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
  106. {
  107. if (!vma || vma->vm_mm->context != 0) {
  108. unsigned long flags;
  109. int oldpid, newpid, idx;
  110. #ifdef DEBUG_TLB
  111. printk("[tlbpage<%lu,0x%08lx>]", vma->vm_mm->context, page);
  112. #endif
  113. newpid = (vma->vm_mm->context & 0xfc0);
  114. page &= PAGE_MASK;
  115. save_and_cli(flags);
  116. oldpid = (get_entryhi() & 0xfc0);
  117. set_entryhi(page | newpid);
  118. tlb_probe();
  119. idx = get_index();
  120. set_entrylo0(0);
  121. set_entryhi(KSEG0);
  122. if (idx < 0)
  123. goto finish;
  124. tlb_write_indexed();
  125. finish:
  126. set_entryhi(oldpid);
  127. restore_flags(flags);
  128. }
  129. }
  130. void update_mmu_cache(struct vm_area_struct * vma, unsigned long address,
  131.                       pte_t pte)
  132. {
  133. unsigned long flags;
  134. pgd_t *pgdp;
  135. pmd_t *pmdp;
  136. pte_t *ptep;
  137. int idx, pid;
  138. /*
  139.  * Handle debugger faulting in for debugee.
  140.  */
  141. if (current->active_mm != vma->vm_mm)
  142. return;
  143. pid = get_entryhi() & 0xfc0;
  144. #ifdef DEBUG_TLB
  145. if ((pid != (vma->vm_mm->context & 0xfc0)) || (vma->vm_mm->context == 0)) {
  146. printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%lu tlbpid=%dn",
  147.        (vma->vm_mm->context & 0xfc0), pid);
  148. }
  149. #endif
  150. save_and_cli(flags);
  151. address &= PAGE_MASK;
  152. set_entryhi(address | (pid));
  153. pgdp = pgd_offset(vma->vm_mm, address);
  154. tlb_probe();
  155. pmdp = pmd_offset(pgdp, address);
  156. idx = get_index();
  157. ptep = pte_offset(pmdp, address);
  158. set_entrylo0(pte_val(*ptep));
  159. set_entryhi(address | (pid));
  160. if (idx < 0) {
  161. tlb_write_random();
  162. #if 0
  163. printk("[MISS]");
  164. #endif
  165. } else {
  166. tlb_write_indexed();
  167. #if 0
  168. printk("[HIT]");
  169. #endif
  170. }
  171. set_entryhi(pid);
  172. restore_flags(flags);
  173. }
  174. void __init add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
  175.                      unsigned long entryhi, unsigned long pagemask)
  176. {
  177. unsigned long flags;
  178. unsigned long old_ctx;
  179. static unsigned long wired = 0;
  180. #ifdef CONFIG_CPU_TX39XX
  181. if (r3k_have_wired_reg) {
  182. unsigned long old_pagemask;
  183. unsigned long w;
  184. #ifdef DEBUG_TLB
  185. printk("[tlbwired]");
  186. printk("ently lo0 %8x, hi %8xn, pagemask %8xn",
  187.        entrylo0, entryhi, pagemask);
  188. #endif
  189. save_and_cli(flags);
  190. /* Save old context and create impossible VPN2 value */
  191. old_ctx = (get_entryhi() & 0xff);
  192. old_pagemask = get_pagemask();
  193. w = get_wired();
  194. set_wired (w + 1);
  195. if (get_wired() != w + 1) {
  196. printk("[tlbwired] No WIRED reg?n");
  197. return;
  198. }
  199. set_index (w << 8);
  200. set_pagemask (pagemask);
  201. set_entryhi(entryhi);
  202. set_entrylo0(entrylo0);
  203. tlb_write_indexed();
  204. set_entryhi(old_ctx);
  205. set_pagemask (old_pagemask);
  206. local_flush_tlb_all();
  207. restore_flags(flags);
  208. return;
  209. }
  210. #endif
  211. if (wired < 8) {
  212. __save_and_cli(flags);
  213. old_ctx = get_entryhi() & 0xfc0;
  214. set_entrylo0(entrylo0);
  215. set_entryhi(entryhi);
  216. set_index(wired);
  217. wired++;
  218. tlb_write_indexed();
  219. set_entryhi(old_ctx);
  220.         local_flush_tlb_all();
  221. __restore_flags(flags);
  222. }
  223. }
  224. void __init r3k_tlb_init(void)
  225. {
  226. local_flush_tlb_all();
  227. memcpy((void *)KSEG0, &except_vec0_r2300, 0x80);
  228. flush_icache_range(KSEG0, KSEG0 + 0x80);
  229. }