andes.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:10k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * This file is subject to the terms and conditions of the GNU General Public
  3.  * License.  See the file "COPYING" in the main directory of this archive
  4.  * for more details.
  5.  *
  6.  * Copyright (C) 1997, 1998, 1999 Ralf Baechle (ralf@gnu.org)
  7.  * Copyright (C) 1999 Silicon Graphics, Inc.
  8.  * Copyright (C) 2000 Kanoj Sarcar (kanoj@sgi.com)
  9.  */
  10. #include <linux/init.h>
  11. #include <linux/kernel.h>
  12. #include <linux/sched.h>
  13. #include <linux/mm.h>
  14. #include <asm/page.h>
  15. #include <asm/pgtable.h>
  16. #include <asm/r10kcache.h>
  17. #include <asm/system.h>
  18. #include <asm/sgialib.h>
  19. #include <asm/mmu_context.h>
  20. static int scache_lsz64;
  21. /*
  22.  * This version has been tuned on an Origin.  For other machines the arguments
  23.  * of the pref instructin may have to be tuned differently.
  24.  */
  25. static void andes_clear_page(void * page)
  26. {
  27. __asm__ __volatile__(
  28. ".settnoreordernt"
  29. ".settnoatnt"
  30. "daddiut$1,%0,%2n"
  31. "1:tpref 7,512(%0)nt"
  32. "sdt$0,(%0)nt"
  33. "sdt$0,8(%0)nt"
  34. "sdt$0,16(%0)nt"
  35. "sdt$0,24(%0)nt"
  36. "daddiut%0,64nt"
  37. "sdt$0,-32(%0)nt"
  38. "sdt$0,-24(%0)nt"
  39. "sdt$0,-16(%0)nt"
  40. "bnet$1,%0,1bnt"
  41. "sdt$0,-8(%0)nt"
  42. ".settatnt"
  43. ".settreorder"
  44. :"=r" (page)
  45. :"0" (page), "I" (PAGE_SIZE)
  46. :"$1", "memory");
  47. }
  48. /* R10000 has no Create_Dirty type cacheops.  */
  49. static void andes_copy_page(void * to, void * from)
  50. {
  51. unsigned long dummy1, dummy2, reg1, reg2, reg3, reg4;
  52. __asm__ __volatile__(
  53. ".settnoreordernt"
  54. ".settnoatnt"
  55. "daddiut$1,%0,%8n"
  56. "1:tpreft0,2*128(%1)nt"
  57. "preft1,2*128(%0)nt"
  58. "ldt%2,(%1)nt"
  59. "ldt%3,8(%1)nt"
  60. "ldt%4,16(%1)nt"
  61. "ldt%5,24(%1)nt"
  62. "sdt%2,(%0)nt"
  63. "sdt%3,8(%0)nt"
  64. "sdt%4,16(%0)nt"
  65. "sdt%5,24(%0)nt"
  66. "daddiut%0,64nt"
  67. "daddiut%1,64nt"
  68. "ldt%2,-32(%1)nt"
  69. "ldt%3,-24(%1)nt"
  70. "ldt%4,-16(%1)nt"
  71. "ldt%5,-8(%1)nt"
  72. "sdt%2,-32(%0)nt"
  73. "sdt%3,-24(%0)nt"
  74. "sdt%4,-16(%0)nt"
  75. "bnet$1,%0,1bnt"
  76. " sdt%5,-8(%0)nt"
  77. ".settatnt"
  78. ".settreorder"
  79. :"=r" (dummy1), "=r" (dummy2), "=&r" (reg1), "=&r" (reg2),
  80.  "=&r" (reg3), "=&r" (reg4)
  81. :"0" (to), "1" (from), "I" (PAGE_SIZE));
  82. }
  83. /* Cache operations.  These are only used with the virtual memory system,
  84.    not for non-coherent I/O so it's ok to ignore the secondary caches.  */
  85. static void
  86. andes_flush_cache_l1(void)
  87. {
  88. blast_dcache32(); blast_icache64();
  89. }
  90. /*
  91.  * This is only used during initialization time. vmalloc() also calls
  92.  * this, but that will be changed pretty soon.
  93.  */
  94. static void
  95. andes_flush_cache_l2(void)
  96. {
  97. switch (sc_lsize()) {
  98. case 64:
  99. blast_scache64();
  100. break;
  101. case 128:
  102. blast_scache128();
  103. break;
  104. default:
  105. printk("Unknown L2 line sizen");
  106. while(1);
  107. }
  108. }
  109. void
  110. andes_flush_icache_page(unsigned long page)
  111. {
  112. if (scache_lsz64)
  113. blast_scache64_page(page);
  114. else
  115. blast_scache128_page(page);
  116. }
  117. static void
  118. andes_flush_cache_sigtramp(unsigned long addr)
  119. {
  120. protected_writeback_dcache_line(addr & ~(dc_lsize - 1));
  121. protected_flush_icache_line(addr & ~(ic_lsize - 1));
  122. }
  123. #define NTLB_ENTRIES       64
  124. #define NTLB_ENTRIES_HALF  32
  125. static inline void
  126. andes_flush_tlb_all(void)
  127. {
  128. unsigned long flags;
  129. unsigned long old_ctx;
  130. unsigned long entry;
  131. #ifdef DEBUG_TLB
  132. printk("[tlball]");
  133. #endif
  134. __save_and_cli(flags);
  135. /* Save old context and create impossible VPN2 value */
  136. old_ctx = get_entryhi() & 0xff;
  137. set_entryhi(CKSEG0);
  138. set_entrylo0(0);
  139. set_entrylo1(0);
  140. entry = get_wired();
  141. /* Blast 'em all away. */
  142. while(entry < NTLB_ENTRIES) {
  143. set_index(entry);
  144. tlb_write_indexed();
  145. entry++;
  146. }
  147. set_entryhi(old_ctx);
  148. __restore_flags(flags);
  149. }
  150. static void andes_flush_tlb_mm(struct mm_struct *mm)
  151. {
  152. if (CPU_CONTEXT(smp_processor_id(), mm) != 0) {
  153. unsigned long flags;
  154. #ifdef DEBUG_TLB
  155. printk("[tlbmm<%d>]", mm->context);
  156. #endif
  157. __save_and_cli(flags);
  158. get_new_cpu_mmu_context(mm, smp_processor_id());
  159. if(mm == current->mm)
  160. set_entryhi(CPU_CONTEXT(smp_processor_id(), mm) & 0xff);
  161. __restore_flags(flags);
  162. }
  163. }
  164. static void
  165. andes_flush_tlb_range(struct mm_struct *mm, unsigned long start,
  166.                       unsigned long end)
  167. {
  168. if (CPU_CONTEXT(smp_processor_id(), mm) != 0) {
  169. unsigned long flags;
  170. int size;
  171. #ifdef DEBUG_TLB
  172. printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xff),
  173.        start, end);
  174. #endif
  175. __save_and_cli(flags);
  176. size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
  177. size = (size + 1) >> 1;
  178. if(size <= NTLB_ENTRIES_HALF) {
  179. int oldpid = (get_entryhi() & 0xff);
  180. int newpid = (CPU_CONTEXT(smp_processor_id(), mm) & 0xff);
  181. start &= (PAGE_MASK << 1);
  182. end += ((PAGE_SIZE << 1) - 1);
  183. end &= (PAGE_MASK << 1);
  184. while(start < end) {
  185. int idx;
  186. set_entryhi(start | newpid);
  187. start += (PAGE_SIZE << 1);
  188. tlb_probe();
  189. idx = get_index();
  190. set_entrylo0(0);
  191. set_entrylo1(0);
  192. set_entryhi(KSEG0);
  193. if(idx < 0)
  194. continue;
  195. tlb_write_indexed();
  196. }
  197. set_entryhi(oldpid);
  198. } else {
  199. get_new_cpu_mmu_context(mm, smp_processor_id());
  200. if(mm == current->mm)
  201. set_entryhi(CPU_CONTEXT(smp_processor_id(), mm) & 
  202. 0xff);
  203. }
  204. __restore_flags(flags);
  205. }
  206. }
  207. static void
  208. andes_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
  209. {
  210. if (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) != 0) {
  211. unsigned long flags;
  212. int oldpid, newpid, idx;
  213. #ifdef DEBUG_TLB
  214. printk("[tlbpage<%d,%08lx>]", vma->vm_mm->context, page);
  215. #endif
  216. newpid = (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) & 0xff);
  217. page &= (PAGE_MASK << 1);
  218. __save_and_cli(flags);
  219. oldpid = (get_entryhi() & 0xff);
  220. set_entryhi(page | newpid);
  221. tlb_probe();
  222. idx = get_index();
  223. set_entrylo0(0);
  224. set_entrylo1(0);
  225. set_entryhi(KSEG0);
  226. if(idx < 0)
  227. goto finish;
  228. tlb_write_indexed();
  229. finish:
  230. set_entryhi(oldpid);
  231. __restore_flags(flags);
  232. }
  233. }
  234. /* XXX Simplify this.  On the R10000 writing a TLB entry for an virtual
  235.    address that already exists will overwrite the old entry and not result
  236.    in TLB malfunction or TLB shutdown.  */
  237. static void andes_update_mmu_cache(struct vm_area_struct * vma,
  238.                                    unsigned long address, pte_t pte)
  239. {
  240. unsigned long flags;
  241. pgd_t *pgdp;
  242. pmd_t *pmdp;
  243. pte_t *ptep;
  244. int idx, pid;
  245. /*
  246.  * Handle debugger faulting in for debugee.
  247.  */
  248. if (current->active_mm != vma->vm_mm)
  249. return;
  250. __save_and_cli(flags);
  251. pid = get_entryhi() & 0xff;
  252. if((pid != (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) & 0xff)) ||
  253.    (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) == 0)) {
  254. printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d "
  255. "tlbpid=%dn", (int) (CPU_CONTEXT(smp_processor_id(),
  256. vma->vm_mm) & 0xff), pid);
  257. }
  258. address &= (PAGE_MASK << 1);
  259. set_entryhi(address | (pid));
  260. pgdp = pgd_offset(vma->vm_mm, address);
  261. tlb_probe();
  262. pmdp = pmd_offset(pgdp, address);
  263. idx = get_index();
  264. ptep = pte_offset(pmdp, address);
  265. set_entrylo0(pte_val(*ptep++) >> 6);
  266. set_entrylo1(pte_val(*ptep) >> 6);
  267. set_entryhi(address | (pid));
  268. if(idx < 0) {
  269. tlb_write_random();
  270. } else {
  271. tlb_write_indexed();
  272. }
  273. set_entryhi(pid);
  274. __restore_flags(flags);
  275. }
  276. static void andes_show_regs(struct pt_regs *regs)
  277. {
  278. printk("Cpu %dn", smp_processor_id());
  279. /* Saved main processor registers. */
  280. printk("$0      : %016lx %016lx %016lx %016lxn",
  281.        0UL, regs->regs[1], regs->regs[2], regs->regs[3]);
  282. printk("$4      : %016lx %016lx %016lx %016lxn",
  283.                regs->regs[4], regs->regs[5], regs->regs[6], regs->regs[7]);
  284. printk("$8      : %016lx %016lx %016lx %016lxn",
  285.        regs->regs[8], regs->regs[9], regs->regs[10], regs->regs[11]);
  286. printk("$12     : %016lx %016lx %016lx %016lxn",
  287.                regs->regs[12], regs->regs[13], regs->regs[14], regs->regs[15]);
  288. printk("$16     : %016lx %016lx %016lx %016lxn",
  289.        regs->regs[16], regs->regs[17], regs->regs[18], regs->regs[19]);
  290. printk("$20     : %016lx %016lx %016lx %016lxn",
  291.                regs->regs[20], regs->regs[21], regs->regs[22], regs->regs[23]);
  292. printk("$24     : %016lx %016lxn",
  293.        regs->regs[24], regs->regs[25]);
  294. printk("$28     : %016lx %016lx %016lx %016lxn",
  295.        regs->regs[28], regs->regs[29], regs->regs[30], regs->regs[31]);
  296. printk("Hi      : %016lxn", regs->hi);
  297. printk("Lo      : %016lxn", regs->lo);
  298. /* Saved cp0 registers. */
  299. printk("epc     : %016lx    %snbadvaddr: %016lxn",
  300.        regs->cp0_epc, print_tainted(), regs->cp0_badvaddr);
  301. printk("Status  : %08xnCause   : %08xn",
  302.        (unsigned int) regs->cp0_status, (unsigned int) regs->cp0_cause);
  303. }
  304. void __init ld_mmu_andes(void)
  305. {
  306. printk("CPU revision is: %08xn", read_32bit_cp0_register(CP0_PRID));
  307. printk("Primary instruction cache %dkb, linesize %d bytesn",
  308.        icache_size >> 10, ic_lsize);
  309. printk("Primary data cache %dkb, linesize %d bytesn",
  310.        dcache_size >> 10, dc_lsize);
  311. printk("Secondary cache sized at %ldK, linesize %ldn",
  312.        scache_size() >> 10, sc_lsize());
  313. _clear_page = andes_clear_page;
  314. _copy_page = andes_copy_page;
  315. _flush_cache_l1 = andes_flush_cache_l1;
  316. _flush_cache_l2 = andes_flush_cache_l2;
  317. _flush_cache_sigtramp = andes_flush_cache_sigtramp;
  318. _flush_tlb_all = andes_flush_tlb_all;
  319. _flush_tlb_mm = andes_flush_tlb_mm;
  320. _flush_tlb_range = andes_flush_tlb_range;
  321. _flush_tlb_page = andes_flush_tlb_page;
  322. switch (sc_lsize()) {
  323. case 64:
  324. scache_lsz64 = 1;
  325. break;
  326. case 128:
  327. scache_lsz64 = 0;
  328. break;
  329. default:
  330. printk("Unknown L2 line sizen");
  331. while(1);
  332. }
  333.     
  334. update_mmu_cache = andes_update_mmu_cache;
  335. _show_regs = andes_show_regs;
  336.         flush_cache_l1();
  337. /*
  338.  * You should never change this register:
  339.  *   - On R4600 1.7 the tlbp never hits for pages smaller than
  340.  *     the value in the c0_pagemask register.
  341.  *   - The entire mm handling assumes the c0_pagemask register to
  342.  *     be set for 4kb pages.
  343.  */
  344. write_32bit_cp0_register(CP0_PAGEMASK, PM_4K);
  345.         /* From this point on the ARC firmware is dead.  */
  346. _flush_tlb_all();
  347.         /* Did I tell you that ARC SUCKS?  */
  348. }