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

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/init.h>
  12. #include <linux/kernel.h>
  13. #include <linux/sched.h>
  14. #include <linux/mm.h>
  15. #include <asm/cacheops.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. /* For R3000 cores with R4000 style caches */
  25. static unsigned long icache_size, dcache_size; /* Size in bytes */
  26. extern long scache_size;
  27. #define icache_lsize mips_cpu.icache.linesz
  28. #define dcache_lsize mips_cpu.dcache.linesz
  29. #include <asm/r4kcache.h>
  30. extern int r3k_have_wired_reg; /* in r3k-tlb.c */
  31. static void tx39h_flush_page_to_ram(struct page * page)
  32. {
  33. }
  34. /* TX39H-style cache flush routines. */
  35. static void tx39h_flush_icache_all(void)
  36. {
  37. unsigned long start = KSEG0;
  38. unsigned long end = (start + icache_size);
  39. unsigned long flags, config;
  40. /* disable icache (set ICE#) */
  41. __save_and_cli(flags);
  42. config = read_32bit_cp0_register(CP0_CONF);
  43. /* invalidate icache */
  44. while (start < end) {
  45. cache16_unroll32(start, Index_Invalidate_I);
  46. start += 0x200;
  47. }
  48. write_32bit_cp0_register(CP0_CONF, config);
  49. __restore_flags(flags);
  50. }
  51. static void tx39h_dma_cache_wback_inv(unsigned long addr, unsigned long size)
  52. {
  53. unsigned long end, a;
  54. iob();
  55. a = addr & ~(dcache_lsize - 1);
  56. end = (addr + size) & ~(dcache_lsize - 1);
  57. while (1) {
  58. invalidate_dcache_line(a); /* Hit_Invalidate_D */
  59. if (a == end) break;
  60. a += dcache_lsize;
  61. }
  62. }
  63. /* TX39H2,TX39H3 */
  64. static inline void tx39_flush_cache_all(void)
  65. {
  66. unsigned long flags, config;
  67. __save_and_cli(flags);
  68. blast_dcache16_wayLSB();
  69. /* disable icache (set ICE#) */
  70. config = read_32bit_cp0_register(CP0_CONF);
  71. write_32bit_cp0_register(CP0_CONF, config&~TX39_CONF_ICE);
  72. blast_icache16_wayLSB();
  73. write_32bit_cp0_register(CP0_CONF, config);
  74. __restore_flags(flags);
  75. }
  76. static void tx39_flush_cache_mm(struct mm_struct *mm)
  77. {
  78. if(mm->context != 0) {
  79. #ifdef DEBUG_CACHE
  80. printk("cmm[%d]", (int)mm->context);
  81. #endif
  82. tx39_flush_cache_all();
  83. }
  84. }
  85. static void tx39_flush_cache_range(struct mm_struct *mm,
  86.     unsigned long start,
  87.     unsigned long end)
  88. {
  89. if(mm->context != 0) {
  90. unsigned long flags, config;
  91. #ifdef DEBUG_CACHE
  92. printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end);
  93. #endif
  94. __save_and_cli(flags);
  95. blast_dcache16_wayLSB();
  96. /* disable icache (set ICE#) */
  97. config = read_32bit_cp0_register(CP0_CONF);
  98. write_32bit_cp0_register(CP0_CONF, config&~TX39_CONF_ICE);
  99. blast_icache16_wayLSB();
  100. write_32bit_cp0_register(CP0_CONF, config);
  101. __restore_flags(flags);
  102. }
  103. }
  104. static void tx39_flush_cache_page(struct vm_area_struct *vma,
  105.    unsigned long page)
  106. {
  107. struct mm_struct *mm = vma->vm_mm;
  108. unsigned long flags;
  109. pgd_t *pgdp;
  110. pmd_t *pmdp;
  111. pte_t *ptep;
  112. /*
  113.  * If ownes no valid ASID yet, cannot possibly have gotten
  114.  * this page into the cache.
  115.  */
  116. if(mm->context == 0)
  117. return;
  118. #ifdef DEBUG_CACHE
  119. printk("cpage[%d,%08lx]", (int)mm->context, page);
  120. #endif
  121. __save_and_cli(flags);
  122. page &= PAGE_MASK;
  123. pgdp = pgd_offset(mm, page);
  124. pmdp = pmd_offset(pgdp, page);
  125. ptep = pte_offset(pmdp, page);
  126. /*
  127.  * If the page isn't marked valid, the page cannot possibly be
  128.  * in the cache.
  129.  */
  130. if(!(pte_val(*ptep) & _PAGE_PRESENT))
  131. goto out;
  132. /*
  133.  * Doing flushes for another ASID than the current one is
  134.  * too difficult since stupid R4k caches do a TLB translation
  135.  * for every cache flush operation.  So we do indexed flushes
  136.  * in that case, which doesn't overly flush the cache too much.
  137.  */
  138. if((mm == current->active_mm) && (pte_val(*ptep) & _PAGE_VALID)) {
  139. blast_dcache16_page(page);
  140. } else {
  141. /*
  142.  * Do indexed flush, too much work to get the (possible)
  143.  * tlb refills to work correctly.
  144.  */
  145. page = (KSEG0 + (page & (dcache_size - 1)));
  146. blast_dcache16_page_indexed_wayLSB(page);
  147. }
  148. out:
  149. __restore_flags(flags);
  150. }
  151. static void tx39_flush_page_to_ram(struct page * page)
  152. {
  153. blast_dcache16_page((unsigned long)page_address(page));
  154. }
  155. static void tx39_flush_icache_range(unsigned long start, unsigned long end)
  156. {
  157. flush_cache_all();
  158. }
  159. static void tx39_flush_icache_page(struct vm_area_struct *vma, struct page *page)
  160. {
  161. if (!(vma->vm_flags & VM_EXEC))
  162. return;
  163. flush_cache_all();
  164. }
  165. static void tx39_dma_cache_wback_inv(unsigned long addr, unsigned long size)
  166. {
  167. unsigned long end, a;
  168. if (size >= dcache_size) {
  169. flush_cache_all();
  170. } else {
  171. a = addr & ~(dcache_lsize - 1);
  172. end = (addr + size) & ~(dcache_lsize - 1);
  173. while (1) {
  174. flush_dcache_line(a); /* Hit_Writeback_Inv_D */
  175. if (a == end) break;
  176. a += dcache_lsize;
  177. }
  178. }
  179. }
  180. static void tx39_dma_cache_inv(unsigned long addr, unsigned long size)
  181. {
  182. unsigned long end, a;
  183. if (size >= dcache_size) {
  184. flush_cache_all();
  185. } else {
  186. a = addr & ~(dcache_lsize - 1);
  187. end = (addr + size) & ~(dcache_lsize - 1);
  188. while (1) {
  189. invalidate_dcache_line(a); /* Hit_Invalidate_D */
  190. if (a == end) break;
  191. a += dcache_lsize;
  192. }
  193. }
  194. }
  195. static void tx39_dma_cache_wback(unsigned long addr, unsigned long size)
  196. {
  197. panic("tx39_dma_cache called - should not happen.");
  198. }
  199. static void tx39_flush_cache_sigtramp(unsigned long addr)
  200. {
  201. unsigned long config;
  202. unsigned int flags;
  203. __save_and_cli(flags);
  204. protected_writeback_dcache_line(addr & ~(dcache_lsize - 1));
  205. /* disable icache (set ICE#) */
  206. config = read_32bit_cp0_register(CP0_CONF);
  207. write_32bit_cp0_register(CP0_CONF, config&~TX39_CONF_ICE);
  208. protected_flush_icache_line(addr & ~(icache_lsize - 1));
  209. write_32bit_cp0_register(CP0_CONF, config);
  210. __restore_flags(flags);
  211. }
  212. static __init void tx39_probe_cache(void)
  213. {
  214. unsigned long config;
  215. config = read_32bit_cp0_register(CP0_CONF);
  216. icache_size = 1 << (10 + ((config >> 19) & 3));
  217. dcache_size = 1 << (10 + ((config >> 16) & 3));
  218. icache_lsize = 16;
  219. switch (mips_cpu.cputype) {
  220. case CPU_TX3912:
  221. dcache_lsize = 4;
  222. break;
  223. case CPU_TX3922:
  224. case CPU_TX3927:
  225. case CPU_TX39XX:
  226. default:
  227. dcache_lsize = 16;
  228. break;
  229. }
  230. }
  231. void __init ld_mmu_tx39(void)
  232. {
  233. unsigned long config;
  234. _clear_page = r3k_clear_page;
  235. _copy_page = r3k_copy_page;
  236. config = read_32bit_cp0_register(CP0_CONF);
  237. config &= ~TX39_CONF_WBON;
  238. write_32bit_cp0_register(CP0_CONF, config);
  239. tx39_probe_cache();
  240. switch (mips_cpu.cputype) {
  241. case CPU_TX3912:
  242. /* TX39/H core (writethru direct-map cache) */
  243. _flush_cache_all = tx39h_flush_icache_all;
  244. ___flush_cache_all = tx39h_flush_icache_all;
  245. _flush_cache_mm = (void *) tx39h_flush_icache_all;
  246. _flush_cache_range = (void *) tx39h_flush_icache_all;
  247. _flush_cache_page = (void *) tx39h_flush_icache_all;
  248. _flush_cache_sigtramp = (void *) tx39h_flush_icache_all;
  249. _flush_page_to_ram = tx39h_flush_page_to_ram;
  250. _flush_icache_page = (void *) tx39h_flush_icache_all;
  251. _flush_icache_range = (void *) tx39h_flush_icache_all;
  252. _dma_cache_wback_inv = tx39h_dma_cache_wback_inv;
  253. break;
  254. case CPU_TX3922:
  255. case CPU_TX3927:
  256. default:
  257. /* TX39/H2,H3 core (writeback 2way-set-associative cache) */
  258. r3k_have_wired_reg = 1;
  259. set_wired (0); /* set 8 on reset... */
  260. /* board-dependent init code may set WBON */
  261. _flush_cache_all = tx39_flush_cache_all;
  262. ___flush_cache_all = tx39_flush_cache_all;
  263. _flush_cache_mm = tx39_flush_cache_mm;
  264. _flush_cache_range = tx39_flush_cache_range;
  265. _flush_cache_page = tx39_flush_cache_page;
  266. _flush_cache_sigtramp = tx39_flush_cache_sigtramp;
  267. _flush_page_to_ram = tx39_flush_page_to_ram;
  268. _flush_icache_page = tx39_flush_icache_page;
  269. _flush_icache_range = tx39_flush_icache_range;
  270. _dma_cache_wback_inv = tx39_dma_cache_wback_inv;
  271. _dma_cache_wback = tx39_dma_cache_wback;
  272. _dma_cache_inv = tx39_dma_cache_inv;
  273. break;
  274. }
  275. if (mips_cpu.icache.ways == 0)
  276. mips_cpu.icache.ways = 1;
  277. if (mips_cpu.dcache.ways == 0)
  278. mips_cpu.dcache.ways = 1;
  279. mips_cpu.icache.sets =
  280. icache_size / mips_cpu.icache.ways / mips_cpu.icache.linesz;
  281. mips_cpu.dcache.sets =
  282. dcache_size / mips_cpu.dcache.ways / mips_cpu.dcache.linesz;
  283. printk("Primary instruction cache %dkb, linesize %d bytesn",
  284. (int) (icache_size >> 10), (int) icache_lsize);
  285. printk("Primary data cache %dkb, linesize %d bytesn",
  286. (int) (dcache_size >> 10), (int) dcache_lsize);
  287. }