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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  3.  * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org)
  4.  * Copyright (C) 2000, 2001 Broadcom Corporation
  5.  *
  6.  * This program is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU General Public License
  8.  * as published by the Free Software Foundation; either version 2
  9.  * of the License, or (at your option) any later version.
  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, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  */
  20. #include <linux/config.h>
  21. #include <asm/mmu_context.h>
  22. #include <asm/bootinfo.h>
  23. #include <asm/cpu.h>
  24. /* Dump the current entry* and pagemask registers */
  25. static inline void dump_cur_tlb_regs(void)
  26. {
  27. unsigned int entryhihi, entryhilo, entrylo0hi, entrylo0lo, entrylo1hi;
  28. unsigned int entrylo1lo, pagemask;
  29. __asm__ __volatile__ (
  30. ".set push             n"
  31. ".set noreorder        n"
  32. "#.set mips64           n"
  33. ".set mips4            n"
  34. ".set noat             n"
  35. "     tlbr             n"
  36. "     dmfc0  $1, $10   n"
  37. "     dsrl32 %0, $1, 0 n"
  38. "     sll    %1, $1, 0 n"
  39. "     dmfc0  $1, $2    n"
  40. "     dsrl32 %2, $1, 0 n"
  41. "     sll    %3, $1, 0 n"
  42. "     dmfc0  $1, $3    n"
  43. "     dsrl32 %4, $1, 0 n"
  44. "     sll    %5, $1, 0 n"
  45. "     mfc0   %6, $5    n"
  46. ".set pop              n"
  47. : "=r" (entryhihi),
  48. "=r" (entryhilo),
  49. "=r" (entrylo0hi),
  50. "=r" (entrylo0lo),
  51. "=r" (entrylo1hi),
  52. "=r" (entrylo1lo),
  53. "=r" (pagemask));
  54. printk("%08X%08X %08X%08X %08X%08X %08X",
  55.        entryhihi, entryhilo,
  56.        entrylo0hi, entrylo0lo,
  57.        entrylo1hi, entrylo1lo,
  58.        pagemask);
  59. }
  60. void sb1_dump_tlb(void)
  61. {
  62. unsigned long old_ctx;
  63. unsigned long flags;
  64. int entry;
  65. __save_and_cli(flags);
  66. old_ctx = get_entryhi();
  67. printk("Current TLB registers state:n"
  68.        "      EntryHi       EntryLo0          EntryLo1     PageMask  Indexn"
  69.        "--------------------------------------------------------------------n");
  70. dump_cur_tlb_regs();
  71. printk(" %08Xn", read_32bit_cp0_register(CP0_INDEX));
  72. printk("nnFull TLB Dump:n"
  73.        "Idx      EntryHi       EntryLo0          EntryLo1     PageMaskn"
  74.        "--------------------------------------------------------------n");
  75. for (entry = 0; entry < mips_cpu.tlbsize; entry++) {
  76. set_index(entry);
  77. printk("n%02i ", entry);
  78. __asm__ __volatile__ (
  79. ".set push             n"
  80. "#.set mips64           n"
  81. ".set mips4           n"
  82. "     tlbr             n"
  83. ".set pop              n");
  84. dump_cur_tlb_regs();
  85. }
  86. printk("n");
  87. set_entryhi(old_ctx);
  88. __restore_flags(flags);
  89. }
  90. void local_flush_tlb_all(void)
  91. {
  92. unsigned long flags;
  93. unsigned long old_ctx;
  94. int entry;
  95. __save_and_cli(flags);
  96. /* Save old context and create impossible VPN2 value */
  97. old_ctx = (get_entryhi() & 0xff);
  98. set_entrylo0(0);
  99. set_entrylo1(0);
  100. for (entry = 0; entry < mips_cpu.tlbsize; entry++) {
  101. set_entryhi(KSEG0 + (PAGE_SIZE << 1) * entry);
  102. set_index(entry);
  103. tlb_write_indexed();
  104. }
  105. set_entryhi(old_ctx);
  106. __restore_flags(flags);
  107. }
  108. /*
  109.  * Use a bogus region of memory (starting at 0) to sanitize the TLB's.
  110.  * Use increments of the maximum page size (16MB), and check for duplicate
  111.  * entries before doing a given write.  Then, when we're safe from collisions
  112.  * with the firmware, go back and give all the entries invalid addresses with
  113.  * the normal flush routine.
  114.  */
  115. void sb1_sanitize_tlb(void)
  116. {
  117. int entry;
  118. long addr = 0;
  119. long inc = 1<<24;  /* 16MB */
  120. /* Save old context and create impossible VPN2 value */
  121. set_entrylo0(0);
  122. set_entrylo1(0);
  123. for (entry = 0; entry < mips_cpu.tlbsize; entry++) {
  124. do {
  125. addr += inc;
  126. set_entryhi(addr);
  127. tlb_probe();
  128. } while ((int)(get_index()) >= 0);
  129. set_index(entry);
  130. tlb_write_indexed();
  131. }
  132. /* Now that we know we're safe from collisions, we can safely flush
  133.    the TLB with the "normal" routine. */
  134. local_flush_tlb_all();
  135. }
  136. void local_flush_tlb_range(struct mm_struct *mm, unsigned long start,
  137.                       unsigned long end)
  138. {
  139. unsigned long flags;
  140. int cpu;
  141. __save_and_cli(flags);
  142. cpu = smp_processor_id();
  143. if(CPU_CONTEXT(cpu, mm) != 0) {
  144. int size;
  145. size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
  146. size = (size + 1) >> 1;
  147. if(size <= (mips_cpu.tlbsize/2)) {
  148. int oldpid = (get_entryhi() & 0xff);
  149. int newpid = (CPU_CONTEXT(cpu, mm) & 0xff);
  150. start &= (PAGE_MASK << 1);
  151. end += ((PAGE_SIZE << 1) - 1);
  152. end &= (PAGE_MASK << 1);
  153. while(start < end) {
  154. int idx;
  155. set_entryhi(start | newpid);
  156. start += (PAGE_SIZE << 1);
  157. tlb_probe();
  158. idx = get_index();
  159. set_entrylo0(0);
  160. set_entrylo1(0);
  161. set_entryhi(KSEG0 + (idx << (PAGE_SHIFT+1)));
  162. if(idx < 0)
  163. continue;
  164. tlb_write_indexed();
  165. }
  166. set_entryhi(oldpid);
  167. } else {
  168. get_new_mmu_context(mm, cpu);
  169. if (mm == current->active_mm)
  170. set_entryhi(CPU_CONTEXT(cpu, mm) & 0xff);
  171. }
  172. }
  173. __restore_flags(flags);
  174. }
  175. void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
  176. {
  177. unsigned long flags;
  178. #ifdef CONFIG_SMP
  179. /*
  180.  * This variable is eliminated from CPU_CONTEXT() if SMP isn't defined,
  181.  * so conditional it to get rid of silly "unused variable" compiler
  182.  * complaints
  183.  */
  184. int cpu = smp_processor_id();
  185. #endif
  186. __save_and_cli(flags);
  187. if (CPU_CONTEXT(cpu, vma->vm_mm) != 0) {
  188. int oldpid, newpid, idx;
  189. #ifdef DEBUG_TLB
  190. printk("[tlbpage<%d,%08lx>]", CPU_CONTEXT(cpu, vma->vm_mm), page);
  191. #endif
  192. newpid = (CPU_CONTEXT(cpu, vma->vm_mm) & 0xff);
  193. page &= (PAGE_MASK << 1);
  194. oldpid = (get_entryhi() & 0xff);
  195. set_entryhi (page | newpid);
  196. tlb_probe();
  197. idx = get_index();
  198. set_entrylo0(0);
  199. set_entrylo1(0);
  200. if(idx < 0)
  201. goto finish;
  202. /* Make sure all entries differ. */
  203. set_entryhi(KSEG0+(idx<<(PAGE_SHIFT+1)));
  204. tlb_write_indexed();
  205. finish:
  206. set_entryhi(oldpid);
  207. }
  208. __restore_flags(flags);
  209. }
  210. /* All entries common to a mm share an asid.  To effectively flush
  211.    these entries, we just bump the asid. */
  212. void local_flush_tlb_mm(struct mm_struct *mm)
  213. {
  214. unsigned long flags;
  215. int cpu;
  216. __save_and_cli(flags);
  217. cpu = smp_processor_id();
  218. if (CPU_CONTEXT(cpu, mm) != 0) {
  219. get_new_mmu_context(mm, smp_processor_id());
  220. if (mm == current->active_mm) {
  221. set_entryhi(CPU_CONTEXT(cpu, mm) & 0xff);
  222. }
  223. }
  224. __restore_flags(flags);
  225. }
  226. /* Stolen from mips32 routines */
  227. void sb1_update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
  228.                       pte_t pte)
  229. {
  230. unsigned long flags;
  231. pgd_t *pgdp;
  232. pmd_t *pmdp;
  233. pte_t *ptep;
  234. int idx, pid;
  235. /*
  236.  * Handle debugger faulting in for debugee.
  237.  */
  238. if (current->active_mm != vma->vm_mm)
  239. return;
  240. __save_and_cli(flags);
  241. pid = get_entryhi() & 0xff;
  242. #ifdef DEBUG_TLB
  243. if((pid != (CPU_CONTEXT(cpu, vma->vm_mm) & 0xff)) || (CPU_CONTEXT(cpu, vma->vm_mm) == 0)) {
  244. printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d tlbpid=%dn",
  245.        (int) (CPU_CONTEXT(cpu, vma->vm_mm) & 0xff), pid);
  246. }
  247. #endif
  248. address &= (PAGE_MASK << 1);
  249. set_entryhi(address | (pid));
  250. pgdp = pgd_offset(vma->vm_mm, address);
  251. tlb_probe();
  252. pmdp = pmd_offset(pgdp, address);
  253. idx = get_index();
  254. ptep = pte_offset(pmdp, address);
  255. set_entrylo0(pte_val(*ptep++) >> 6);
  256. set_entrylo1(pte_val(*ptep) >> 6);
  257. set_entryhi(address | (pid));
  258. if (idx < 0) {
  259. tlb_write_random();
  260. } else {
  261. tlb_write_indexed();
  262. }
  263. set_entryhi(pid);
  264. __restore_flags(flags);
  265. }
  266. /*
  267.  * This is called from loadmmu.c.  We have to set up all the
  268.  * memory management function pointers, as well as initialize
  269.  * the caches and tlbs
  270.  */
  271. void sb1_tlb_init(void)
  272. {
  273. u32 config1;
  274. config1 = read_mips32_cp0_config1();
  275. mips_cpu.tlbsize = ((config1 >> 25) & 0x3f) + 1;
  276. /*
  277.  * We don't know what state the firmware left the TLB's in, so this is
  278.  * the ultra-conservative way to flush the TLB's and avoid machine
  279.  * check exceptions due to duplicate TLB entries
  280.  */
  281. sb1_sanitize_tlb();
  282. _update_mmu_cache = sb1_update_mmu_cache;
  283. }