c-r3k.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/page.h>
  16. #include <asm/pgtable.h>
  17. #include <asm/mmu_context.h>
  18. #include <asm/system.h>
  19. #include <asm/isadep.h>
  20. #include <asm/io.h>
  21. #include <asm/bootinfo.h>
  22. #include <asm/cpu.h>
  23. static unsigned long icache_size, dcache_size; /* Size in bytes */
  24. static unsigned long icache_lsize, dcache_lsize; /* Size in bytes */
  25. #undef DEBUG_CACHE
  26. unsigned long __init r3k_cache_size(unsigned long ca_flags)
  27. {
  28. unsigned long flags, status, dummy, size;
  29. volatile unsigned long *p;
  30. p = (volatile unsigned long *) KSEG0;
  31. flags = read_32bit_cp0_register(CP0_STATUS);
  32. /* isolate cache space */
  33. write_32bit_cp0_register(CP0_STATUS, (ca_flags|flags)&~ST0_IEC);
  34. *p = 0xa5a55a5a;
  35. dummy = *p;
  36. status = read_32bit_cp0_register(CP0_STATUS);
  37. if (dummy != 0xa5a55a5a || (status & ST0_CM)) {
  38. size = 0;
  39. } else {
  40. for (size = 128; size <= 0x40000; size <<= 1)
  41. *(p + size) = 0;
  42. *p = -1;
  43. for (size = 128;
  44.      (size <= 0x40000) && (*(p + size) == 0);
  45.      size <<= 1)
  46. ;
  47. if (size > 0x40000)
  48. size = 0;
  49. }
  50. write_32bit_cp0_register(CP0_STATUS, flags);
  51. return size * sizeof(*p);
  52. }
  53. unsigned long __init r3k_cache_lsize(unsigned long ca_flags)
  54. {
  55. unsigned long flags, status, lsize, i;
  56. volatile unsigned long *p;
  57. p = (volatile unsigned long *) KSEG0;
  58. flags = read_32bit_cp0_register(CP0_STATUS);
  59. /* isolate cache space */
  60. write_32bit_cp0_register(CP0_STATUS, (ca_flags|flags)&~ST0_IEC);
  61. for (i = 0; i < 128; i++)
  62. *(p + i) = 0;
  63. *(volatile unsigned char *)p = 0;
  64. for (lsize = 1; lsize < 128; lsize <<= 1) {
  65. *(p + lsize);
  66. status = read_32bit_cp0_register(CP0_STATUS);
  67. if (!(status & ST0_CM))
  68. break;
  69. }
  70. for (i = 0; i < 128; i += lsize)
  71. *(volatile unsigned char *)(p + i) = 0;
  72. write_32bit_cp0_register(CP0_STATUS, flags);
  73. return lsize * sizeof(*p);
  74. }
  75. static void __init r3k_probe_cache(void)
  76. {
  77. dcache_size = r3k_cache_size(ST0_ISC);
  78. if (dcache_size)
  79. dcache_lsize = r3k_cache_lsize(ST0_ISC);
  80. icache_size = r3k_cache_size(ST0_ISC|ST0_SWC);
  81. if (icache_size)
  82. icache_lsize = r3k_cache_lsize(ST0_ISC|ST0_SWC);
  83. }
  84. static void r3k_flush_icache_range(unsigned long start, unsigned long end)
  85. {
  86. unsigned long size, i, flags;
  87. volatile unsigned char *p;
  88. size = end - start;
  89. if (size > icache_size || KSEGX(start) != KSEG0) {
  90. start = KSEG0;
  91. size = icache_size;
  92. }
  93. p = (char *)start;
  94. flags = read_32bit_cp0_register(CP0_STATUS);
  95. /* isolate cache space */
  96. write_32bit_cp0_register(CP0_STATUS, (ST0_ISC|ST0_SWC|flags)&~ST0_IEC);
  97. for (i = 0; i < size; i += 0x080) {
  98. asm (  "sbt$0, 0x000(%0)nt"
  99. "sbt$0, 0x004(%0)nt"
  100. "sbt$0, 0x008(%0)nt"
  101. "sbt$0, 0x00c(%0)nt"
  102. "sbt$0, 0x010(%0)nt"
  103. "sbt$0, 0x014(%0)nt"
  104. "sbt$0, 0x018(%0)nt"
  105. "sbt$0, 0x01c(%0)nt"
  106.   "sbt$0, 0x020(%0)nt"
  107. "sbt$0, 0x024(%0)nt"
  108. "sbt$0, 0x028(%0)nt"
  109. "sbt$0, 0x02c(%0)nt"
  110. "sbt$0, 0x030(%0)nt"
  111. "sbt$0, 0x034(%0)nt"
  112. "sbt$0, 0x038(%0)nt"
  113. "sbt$0, 0x03c(%0)nt"
  114. "sbt$0, 0x040(%0)nt"
  115. "sbt$0, 0x044(%0)nt"
  116. "sbt$0, 0x048(%0)nt"
  117. "sbt$0, 0x04c(%0)nt"
  118. "sbt$0, 0x050(%0)nt"
  119. "sbt$0, 0x054(%0)nt"
  120. "sbt$0, 0x058(%0)nt"
  121. "sbt$0, 0x05c(%0)nt"
  122.   "sbt$0, 0x060(%0)nt"
  123. "sbt$0, 0x064(%0)nt"
  124. "sbt$0, 0x068(%0)nt"
  125. "sbt$0, 0x06c(%0)nt"
  126. "sbt$0, 0x070(%0)nt"
  127. "sbt$0, 0x074(%0)nt"
  128. "sbt$0, 0x078(%0)nt"
  129. "sbt$0, 0x07c(%0)nt"
  130. : : "r" (p) );
  131. p += 0x080;
  132. }
  133. write_32bit_cp0_register(CP0_STATUS, flags);
  134. }
  135. static void r3k_flush_dcache_range(unsigned long start, unsigned long end)
  136. {
  137. unsigned long size, i, flags;
  138. volatile unsigned char *p;
  139. size = end - start;
  140. if (size > dcache_size || KSEGX(start) != KSEG0) {
  141. start = KSEG0;
  142. size = dcache_size;
  143. }
  144. p = (char *)start;
  145. flags = read_32bit_cp0_register(CP0_STATUS);
  146. /* isolate cache space */
  147. write_32bit_cp0_register(CP0_STATUS, (ST0_ISC|flags)&~ST0_IEC);
  148. for (i = 0; i < size; i += 0x080) {
  149. asm (  "sbt$0, 0x000(%0)nt"
  150. "sbt$0, 0x004(%0)nt"
  151. "sbt$0, 0x008(%0)nt"
  152. "sbt$0, 0x00c(%0)nt"
  153.   "sbt$0, 0x010(%0)nt"
  154. "sbt$0, 0x014(%0)nt"
  155. "sbt$0, 0x018(%0)nt"
  156. "sbt$0, 0x01c(%0)nt"
  157.   "sbt$0, 0x020(%0)nt"
  158. "sbt$0, 0x024(%0)nt"
  159. "sbt$0, 0x028(%0)nt"
  160. "sbt$0, 0x02c(%0)nt"
  161.   "sbt$0, 0x030(%0)nt"
  162. "sbt$0, 0x034(%0)nt"
  163. "sbt$0, 0x038(%0)nt"
  164. "sbt$0, 0x03c(%0)nt"
  165.   "sbt$0, 0x040(%0)nt"
  166. "sbt$0, 0x044(%0)nt"
  167. "sbt$0, 0x048(%0)nt"
  168. "sbt$0, 0x04c(%0)nt"
  169.   "sbt$0, 0x050(%0)nt"
  170. "sbt$0, 0x054(%0)nt"
  171. "sbt$0, 0x058(%0)nt"
  172. "sbt$0, 0x05c(%0)nt"
  173.   "sbt$0, 0x060(%0)nt"
  174. "sbt$0, 0x064(%0)nt"
  175. "sbt$0, 0x068(%0)nt"
  176. "sbt$0, 0x06c(%0)nt"
  177.   "sbt$0, 0x070(%0)nt"
  178. "sbt$0, 0x074(%0)nt"
  179. "sbt$0, 0x078(%0)nt"
  180. "sbt$0, 0x07c(%0)nt"
  181. : : "r" (p) );
  182. p += 0x080;
  183. }
  184. write_32bit_cp0_register(CP0_STATUS,flags);
  185. }
  186. static inline unsigned long get_phys_page (unsigned long addr,
  187.    struct mm_struct *mm)
  188. {
  189. pgd_t *pgd;
  190. pmd_t *pmd;
  191. pte_t *pte;
  192. unsigned long physpage;
  193. pgd = pgd_offset(mm, addr);
  194. pmd = pmd_offset(pgd, addr);
  195. pte = pte_offset(pmd, addr);
  196. if ((physpage = pte_val(*pte)) & _PAGE_VALID)
  197. return KSEG0ADDR(physpage & PAGE_MASK);
  198. return 0;
  199. }
  200. static inline void r3k_flush_cache_all(void)
  201. {
  202. }
  203. static inline void r3k___flush_cache_all(void)
  204. {
  205. r3k_flush_icache_range(KSEG0, KSEG0 + icache_size);
  206. }
  207. static void r3k_flush_cache_mm(struct mm_struct *mm)
  208. {
  209. }
  210. static void r3k_flush_cache_range(struct mm_struct *mm, unsigned long start,
  211.   unsigned long end)
  212. {
  213. }
  214. static void r3k_flush_cache_page(struct vm_area_struct *vma,
  215.    unsigned long page)
  216. {
  217. }
  218. static void r3k_flush_page_to_ram(struct page * page)
  219. {
  220. /*
  221.  * Nothing to be done
  222.  */
  223. }
  224. static void r3k_flush_icache_page(struct vm_area_struct *vma, struct page *page)
  225. {
  226. struct mm_struct *mm = vma->vm_mm;
  227. unsigned long physpage;
  228. if (mm->context == 0)
  229. return;
  230. if (!(vma->vm_flags & VM_EXEC))
  231. return;
  232. #ifdef DEBUG_CACHE
  233. printk("cpage[%d,%08lx]", (int)mm->context, page);
  234. #endif
  235. physpage = (unsigned long) page_address(page);
  236. if (physpage)
  237. r3k_flush_icache_range(physpage, physpage + PAGE_SIZE);
  238. }
  239. static void r3k_flush_cache_sigtramp(unsigned long addr)
  240. {
  241. unsigned long flags;
  242. #ifdef DEBUG_CACHE
  243. printk("csigtramp[%08lx]", addr);
  244. #endif
  245. flags = read_32bit_cp0_register(CP0_STATUS);
  246. write_32bit_cp0_register(CP0_STATUS, flags&~ST0_IEC);
  247. /* Fill the TLB to avoid an exception with caches isolated. */
  248. asm (  "lwt$0, 0x000(%0)nt"
  249. "lwt$0, 0x004(%0)nt"
  250. : : "r" (addr) );
  251. write_32bit_cp0_register(CP0_STATUS, (ST0_ISC|ST0_SWC|flags)&~ST0_IEC);
  252. asm (  "sbt$0, 0x000(%0)nt"
  253. "sbt$0, 0x004(%0)nt"
  254. : : "r" (addr) );
  255. write_32bit_cp0_register(CP0_STATUS, flags);
  256. }
  257. static void r3k_dma_cache_wback_inv(unsigned long start, unsigned long size)
  258. {
  259. iob();
  260. r3k_flush_dcache_range(start, start + size);
  261. }
  262. void __init ld_mmu_r23000(void)
  263. {
  264. unsigned long config;
  265. _clear_page = r3k_clear_page;
  266. _copy_page = r3k_copy_page;
  267. r3k_probe_cache();
  268. _flush_cache_all = r3k_flush_cache_all;
  269. ___flush_cache_all = r3k___flush_cache_all;
  270. _flush_cache_mm = r3k_flush_cache_mm;
  271. _flush_cache_range = r3k_flush_cache_range;
  272. _flush_cache_page = r3k_flush_cache_page;
  273. _flush_cache_sigtramp = r3k_flush_cache_sigtramp;
  274. _flush_page_to_ram = r3k_flush_page_to_ram;
  275. _flush_icache_page = r3k_flush_icache_page;
  276. _flush_icache_range = r3k_flush_icache_range;
  277. _dma_cache_wback_inv = r3k_dma_cache_wback_inv;
  278. printk("Primary instruction cache %dkb, linesize %d bytesn",
  279. (int) (icache_size >> 10), (int) icache_lsize);
  280. printk("Primary data cache %dkb, linesize %d bytesn",
  281. (int) (dcache_size >> 10), (int) dcache_lsize);
  282. }