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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* $Id: cache-sh4.c,v 1.16 2001/09/10 11:06:35 dwmw2 Exp $
  2.  *
  3.  *  linux/arch/sh/mm/cache.c
  4.  *
  5.  * Copyright (C) 1999, 2000  Niibe Yutaka
  6.  *
  7.  */
  8. #include <linux/config.h>
  9. #include <linux/init.h>
  10. #include <linux/mman.h>
  11. #include <linux/mm.h>
  12. #include <linux/threads.h>
  13. #include <asm/addrspace.h>
  14. #include <asm/page.h>
  15. #include <asm/pgtable.h>
  16. #include <asm/processor.h>
  17. #include <asm/cache.h>
  18. #include <asm/io.h>
  19. #include <asm/uaccess.h>
  20. #include <asm/pgalloc.h>
  21. #include <asm/mmu_context.h>
  22. #define CCR  0xff00001c /* Address of Cache Control Register */
  23. #define CCR_CACHE_OCE 0x0001 /* Operand Cache Enable */
  24. #define CCR_CACHE_WT 0x0002 /* Write-Through (for P0,U0,P3) (else writeback)*/
  25. #define CCR_CACHE_CB 0x0004 /* Copy-Back (for P1) (else writethrough) */
  26. #define CCR_CACHE_OCI 0x0008 /* OC Invalidate */
  27. #define CCR_CACHE_ORA 0x0020 /* OC RAM Mode */
  28. #define CCR_CACHE_OIX 0x0080 /* OC Index Enable */
  29. #define CCR_CACHE_ICE 0x0100 /* Instruction Cache Enable */
  30. #define CCR_CACHE_ICI 0x0800 /* IC Invalidate */
  31. #define CCR_CACHE_IIX 0x8000 /* IC Index Enable */
  32. /* Default CCR setup: 8k+16k-byte cache,P1-wb,enable */
  33. #define CCR_CACHE_VAL (CCR_CACHE_ICE|CCR_CACHE_CB|CCR_CACHE_OCE)
  34. #define CCR_CACHE_INIT (CCR_CACHE_VAL|CCR_CACHE_OCI|CCR_CACHE_ICI)
  35. #define CCR_CACHE_ENABLE (CCR_CACHE_OCE|CCR_CACHE_ICE)
  36. #define CACHE_IC_ADDRESS_ARRAY 0xf0000000
  37. #define CACHE_OC_ADDRESS_ARRAY 0xf4000000
  38. #define CACHE_VALID   1
  39. #define CACHE_UPDATED   2
  40. #define CACHE_OC_WAY_SHIFT       13
  41. #define CACHE_IC_WAY_SHIFT       13
  42. #define CACHE_OC_ENTRY_SHIFT      5
  43. #define CACHE_IC_ENTRY_SHIFT      5
  44. #define CACHE_OC_ENTRY_MASK 0x3fe0
  45. #define CACHE_OC_ENTRY_PHYS_MASK 0x0fe0
  46. #define CACHE_IC_ENTRY_MASK 0x1fe0
  47. #define CACHE_IC_NUM_ENTRIES 256
  48. #define CACHE_OC_NUM_ENTRIES 512
  49. static void __init
  50. detect_cpu_and_cache_system(void)
  51. {
  52. #ifdef CONFIG_CPU_SUBTYPE_ST40STB1
  53. cpu_data->type = CPU_ST40STB1;
  54. #elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751)
  55. cpu_data->type = CPU_SH7750;
  56. #else
  57. #error Unknown SH4 CPU type
  58. #endif
  59. }
  60. void __init cache_init(void)
  61. {
  62. unsigned long ccr;
  63. detect_cpu_and_cache_system();
  64. jump_to_P2();
  65. ccr = ctrl_inl(CCR);
  66. if (ccr & CCR_CACHE_ENABLE) {
  67. /*
  68.  * XXX: Should check RA here. 
  69.  * If RA was 1, we only need to flush the half of the caches.
  70.  */
  71. unsigned long addr, data;
  72. for (addr = CACHE_OC_ADDRESS_ARRAY;
  73.      addr < (CACHE_OC_ADDRESS_ARRAY+
  74.      (CACHE_OC_NUM_ENTRIES << CACHE_OC_ENTRY_SHIFT));
  75.      addr += (1 << CACHE_OC_ENTRY_SHIFT)) {
  76. data = ctrl_inl(addr);
  77. if ((data & (CACHE_UPDATED|CACHE_VALID))
  78.     == (CACHE_UPDATED|CACHE_VALID))
  79. ctrl_outl(data & ~CACHE_UPDATED, addr);
  80. }
  81. }
  82. ctrl_outl(CCR_CACHE_INIT, CCR);
  83. back_to_P1();
  84. }
  85. /*
  86.  * SH-4 has virtually indexed and physically tagged cache.
  87.  */
  88. static struct semaphore p3map_sem[4];
  89. void __init p3_cache_init(void)
  90. {
  91. /* In ioremap.c */
  92. extern int remap_area_pages(unsigned long address,
  93.     unsigned long phys_addr,
  94.     unsigned long size, unsigned long flags);
  95. if (remap_area_pages(P3SEG, 0, PAGE_SIZE*4, _PAGE_CACHABLE))
  96. panic("p3_cachie_init failed.");
  97. sema_init (&p3map_sem[0], 1);
  98. sema_init (&p3map_sem[1], 1);
  99. sema_init (&p3map_sem[2], 1);
  100. sema_init (&p3map_sem[3], 1);
  101. }
  102. /*
  103.  * Write back the dirty D-caches, but not invalidate them.
  104.  *
  105.  * START: Virtual Address (U0, P1, or P3)
  106.  * SIZE: Size of the region.
  107.  */
  108. void __flush_wback_region(void *start, int size)
  109. {
  110. unsigned long v;
  111. unsigned long begin, end;
  112. begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
  113. end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
  114. & ~(L1_CACHE_BYTES-1);
  115. for (v = begin; v < end; v+=L1_CACHE_BYTES) {
  116. asm volatile("ocbwb %0"
  117.      : /* no output */
  118.      : "m" (__m(v)));
  119. }
  120. }
  121. /*
  122.  * Write back the dirty D-caches and invalidate them.
  123.  *
  124.  * START: Virtual Address (U0, P1, or P3)
  125.  * SIZE: Size of the region.
  126.  */
  127. void __flush_purge_region(void *start, int size)
  128. {
  129. unsigned long v;
  130. unsigned long begin, end;
  131. begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
  132. end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
  133. & ~(L1_CACHE_BYTES-1);
  134. for (v = begin; v < end; v+=L1_CACHE_BYTES) {
  135. asm volatile("ocbp %0"
  136.      : /* no output */
  137.      : "m" (__m(v)));
  138. }
  139. }
  140. /*
  141.  * No write back please
  142.  */
  143. void __flush_invalidate_region(void *start, int size)
  144. {
  145. unsigned long v;
  146. unsigned long begin, end;
  147. begin = (unsigned long)start & ~(L1_CACHE_BYTES-1);
  148. end = ((unsigned long)start + size + L1_CACHE_BYTES-1)
  149. & ~(L1_CACHE_BYTES-1);
  150. for (v = begin; v < end; v+=L1_CACHE_BYTES) {
  151. asm volatile("ocbi %0"
  152.      : /* no output */
  153.      : "m" (__m(v)));
  154. }
  155. }
  156. /*
  157.  * Write back the range of D-cache, and purge the I-cache.
  158.  *
  159.  * Called from kernel/module.c:sys_init_module and routine for a.out format.
  160.  */
  161. void flush_icache_range(unsigned long start, unsigned long end)
  162. {
  163. flush_cache_all();
  164. }
  165. /*
  166.  * Write back the D-cache and purge the I-cache for signal trampoline. 
  167.  */
  168. void flush_cache_sigtramp(unsigned long addr)
  169. {
  170. unsigned long v, index;
  171. unsigned long flags; 
  172. v = addr & ~(L1_CACHE_BYTES-1);
  173. asm volatile("ocbwb %0"
  174.      : /* no output */
  175.      : "m" (__m(v)));
  176. index = CACHE_IC_ADDRESS_ARRAY| (v&CACHE_IC_ENTRY_MASK);
  177. save_and_cli(flags);
  178. jump_to_P2();
  179. ctrl_outl(0, index); /* Clear out Valid-bit */
  180. back_to_P1();
  181. restore_flags(flags);
  182. }
  183. /*
  184.  * Writeback&Invalidate the D-cache of the page
  185.  */
  186. static void __flush_dcache_page(unsigned long phys)
  187. {
  188. unsigned long addr, data;
  189. unsigned long flags;
  190. phys |= CACHE_VALID;
  191. save_and_cli(flags);
  192. jump_to_P2();
  193. /* Loop all the D-cache */
  194. for (addr = CACHE_OC_ADDRESS_ARRAY;
  195.      addr < (CACHE_OC_ADDRESS_ARRAY
  196.      +(CACHE_OC_NUM_ENTRIES<< CACHE_OC_ENTRY_SHIFT));
  197.      addr += (1<<CACHE_OC_ENTRY_SHIFT)) {
  198. data = ctrl_inl(addr)&(0x1ffff000|CACHE_VALID);
  199. if (data == phys)
  200. ctrl_outl(0, addr);
  201. }
  202. #if 0 /* DEBUG DEBUG */
  203. /* Loop all the I-cache */
  204. for (addr = CACHE_IC_ADDRESS_ARRAY;
  205.      addr < (CACHE_IC_ADDRESS_ARRAY
  206.      +(CACHE_IC_NUM_ENTRIES<< CACHE_IC_ENTRY_SHIFT));
  207.      addr += (1<<CACHE_IC_ENTRY_SHIFT)) {
  208. data = ctrl_inl(addr)&(0x1ffff000|CACHE_VALID);
  209. if (data == phys) {
  210. printk(KERN_INFO "__flush_cache_page: I-cache entry foundn");
  211. ctrl_outl(0, addr);
  212. }
  213. }
  214. #endif
  215. back_to_P1();
  216. restore_flags(flags);
  217. }
  218. /*
  219.  * Write back & invalidate the D-cache of the page.
  220.  * (To avoid "alias" issues)
  221.  */
  222. void flush_dcache_page(struct page *page)
  223. {
  224. if (test_bit(PG_mapped, &page->flags))
  225. __flush_dcache_page(PHYSADDR(page_address(page)));
  226. }
  227. void flush_cache_all(void)
  228. {
  229. extern unsigned long empty_zero_page[1024];
  230. unsigned long flags;
  231. unsigned long addr;
  232. save_and_cli(flags);
  233. /* Prefetch the data to write back D-cache */
  234. for (addr = (unsigned long)empty_zero_page;
  235.      addr < (unsigned long)empty_zero_page + 1024*16;
  236.      addr += L1_CACHE_BYTES)
  237. asm volatile("pref @%0"::"r" (addr));
  238. jump_to_P2();
  239. /* Flush D-cache/I-cache */
  240. ctrl_outl(CCR_CACHE_INIT, CCR);
  241. back_to_P1();
  242. restore_flags(flags);
  243. }
  244. void flush_cache_mm(struct mm_struct *mm)
  245. {
  246. /* Is there any good way? */
  247. /* XXX: possibly call flush_cache_range for each vm area */
  248. flush_cache_all();
  249. }
  250. /*
  251.  * Write back and invalidate D-caches.
  252.  *
  253.  * START, END: Virtual Address (U0 address)
  254.  *
  255.  * NOTE: We need to flush the _physical_ page entry.
  256.  * Flushing the cache lines for U0 only isn't enough.
  257.  * We need to flush for P1 too, which may contain aliases.
  258.  */
  259. void flush_cache_range(struct mm_struct *mm, unsigned long start,
  260.        unsigned long end)
  261. {
  262. /*
  263.  * We could call flush_cache_page for the pages of these range,
  264.  * but it's not efficient (scan the caches all the time...).
  265.  *
  266.  * We can't use A-bit magic, as there's the case we don't have
  267.  * valid entry on TLB.
  268.  */
  269. flush_cache_all();
  270. }
  271. /*
  272.  * Write back and invalidate I/D-caches for the page.
  273.  *
  274.  * ADDR: Virtual Address (U0 address)
  275.  */
  276. void flush_cache_page(struct vm_area_struct *vma, unsigned long address)
  277. {
  278. pgd_t *dir;
  279. pmd_t *pmd;
  280. pte_t *pte;
  281. pte_t entry;
  282. unsigned long phys, addr, data;
  283. unsigned long flags;
  284. dir = pgd_offset(vma->vm_mm, address);
  285. pmd = pmd_offset(dir, address);
  286. if (pmd_none(*pmd) || pmd_bad(*pmd))
  287. return;
  288. pte = pte_offset(pmd, address);
  289. entry = *pte;
  290. if (pte_none(entry) || !pte_present(entry))
  291. return;
  292. phys = pte_val(entry)&PTE_PHYS_MASK;
  293. phys |= CACHE_VALID;
  294. save_and_cli(flags);
  295. jump_to_P2();
  296. /* We only need to flush D-cache when we have alias */
  297. if ((address^phys) & CACHE_ALIAS) {
  298. /* Loop 4K of the D-cache */
  299. for (addr = CACHE_OC_ADDRESS_ARRAY | (address & CACHE_ALIAS);
  300.      addr < (CACHE_OC_ADDRESS_ARRAY + (address & CACHE_ALIAS) 
  301.      +(CACHE_OC_NUM_ENTRIES/4<<CACHE_OC_ENTRY_SHIFT));
  302.      addr += (1<<CACHE_OC_ENTRY_SHIFT)) {
  303. data = ctrl_inl(addr)&(0x1ffff000|CACHE_VALID);
  304. if (data == phys)
  305. ctrl_outl(0, addr);
  306. }
  307. /* Loop another 4K of the D-cache */
  308. for (addr = CACHE_OC_ADDRESS_ARRAY | (phys & CACHE_ALIAS);
  309.      addr < (CACHE_OC_ADDRESS_ARRAY + (phys & CACHE_ALIAS) 
  310.      +(CACHE_OC_NUM_ENTRIES/4<<CACHE_OC_ENTRY_SHIFT));
  311.      addr += (1<<CACHE_OC_ENTRY_SHIFT)) {
  312. data = ctrl_inl(addr)&(0x1ffff000|CACHE_VALID);
  313. if (data == phys)
  314. ctrl_outl(0, addr);
  315. }
  316. }
  317. if (vma->vm_flags & VM_EXEC)
  318. /* Loop 4K of the I-cache */
  319. for (addr = CACHE_IC_ADDRESS_ARRAY|(address&0x1000);
  320.      addr < ((CACHE_IC_ADDRESS_ARRAY|(address&0x1000))
  321.      +(CACHE_IC_NUM_ENTRIES/2<<CACHE_IC_ENTRY_SHIFT));
  322.      addr += (1<<CACHE_IC_ENTRY_SHIFT)) {
  323. data = ctrl_inl(addr)&(0x1ffff000|CACHE_VALID);
  324. if (data == phys)
  325. ctrl_outl(0, addr);
  326. }
  327. back_to_P1();
  328. restore_flags(flags);
  329. }
  330. /*
  331.  * clear_user_page
  332.  * @to: P1 address
  333.  * @address: U0 address to be mapped
  334.  */
  335. void clear_user_page(void *to, unsigned long address)
  336. {
  337. struct page *page = virt_to_page(to);
  338. __set_bit(PG_mapped, &page->flags);
  339. if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0)
  340. clear_page(to);
  341. else {
  342. pgprot_t pgprot = __pgprot(_PAGE_PRESENT | 
  343.    _PAGE_RW | _PAGE_CACHABLE |
  344.    _PAGE_DIRTY | _PAGE_ACCESSED | 
  345.    _PAGE_HW_SHARED | _PAGE_FLAGS_HARD);
  346. unsigned long phys_addr = PHYSADDR(to);
  347. unsigned long p3_addr = P3SEG + (address & CACHE_ALIAS);
  348. pgd_t *dir = pgd_offset_k(p3_addr);
  349. pmd_t *pmd = pmd_offset(dir, p3_addr);
  350. pte_t *pte = pte_offset(pmd, p3_addr);
  351. pte_t entry;
  352. unsigned long flags;
  353. entry = mk_pte_phys(phys_addr, pgprot);
  354. down(&p3map_sem[(address & CACHE_ALIAS)>>12]);
  355. set_pte(pte, entry);
  356. save_and_cli(flags);
  357. __flush_tlb_page(get_asid(), p3_addr);
  358. restore_flags(flags);
  359. update_mmu_cache(NULL, p3_addr, entry);
  360. __clear_user_page((void *)p3_addr, to);
  361. pte_clear(pte);
  362. up(&p3map_sem[(address & CACHE_ALIAS)>>12]);
  363. }
  364. }
  365. /*
  366.  * copy_user_page
  367.  * @to: P1 address
  368.  * @from: P1 address
  369.  * @address: U0 address to be mapped
  370.  */
  371. void copy_user_page(void *to, void *from, unsigned long address)
  372. {
  373. struct page *page = virt_to_page(to);
  374. __set_bit(PG_mapped, &page->flags);
  375. if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0)
  376. copy_page(to, from);
  377. else {
  378. pgprot_t pgprot = __pgprot(_PAGE_PRESENT | 
  379.    _PAGE_RW | _PAGE_CACHABLE |
  380.    _PAGE_DIRTY | _PAGE_ACCESSED | 
  381.    _PAGE_HW_SHARED | _PAGE_FLAGS_HARD);
  382. unsigned long phys_addr = PHYSADDR(to);
  383. unsigned long p3_addr = P3SEG + (address & CACHE_ALIAS);
  384. pgd_t *dir = pgd_offset_k(p3_addr);
  385. pmd_t *pmd = pmd_offset(dir, p3_addr);
  386. pte_t *pte = pte_offset(pmd, p3_addr);
  387. pte_t entry;
  388. unsigned long flags;
  389. entry = mk_pte_phys(phys_addr, pgprot);
  390. down(&p3map_sem[(address & CACHE_ALIAS)>>12]);
  391. set_pte(pte, entry);
  392. save_and_cli(flags);
  393. __flush_tlb_page(get_asid(), p3_addr);
  394. restore_flags(flags);
  395. update_mmu_cache(NULL, p3_addr, entry);
  396. __copy_user_page((void *)p3_addr, from, to);
  397. pte_clear(pte);
  398. up(&p3map_sem[(address & CACHE_ALIAS)>>12]);
  399. }
  400. }