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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * BK Id: SCCS/s.4xx_tlb.c 1.5 05/17/01 18:14:23 cort
  3.  */
  4. /*
  5.  *
  6.  *    Copyright (c) 1998-1999 TiVo, Inc.
  7.  *      Original implementation.
  8.  *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
  9.  *      Minor rework.
  10.  *
  11.  *    Module name: 4xx_tlb.c
  12.  *
  13.  *    Description:
  14.  *      Routines for manipulating the TLB on PowerPC 400-class processors.
  15.  *
  16.  */
  17. #include <linux/mm.h>
  18. #include <asm/processor.h>
  19. #include <asm/io.h>
  20. #include <asm/mmu.h>
  21. #include <asm/pgtable.h>
  22. #include <asm/system.h>
  23. /* Preprocessor Defines */
  24. #if !defined(TRUE) || TRUE != 1
  25. #define TRUE    1
  26. #endif
  27. #if !defined(FALSE) || FALSE != 0
  28. #define FALSE   0
  29. #endif
  30. /* Global Variables */
  31. static int pinned = 0;
  32. /* Function Prototypes */
  33. static int PPC4xx_tlb_miss(struct pt_regs *, unsigned long, int);
  34. extern void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
  35. /*
  36.  * ()
  37.  *
  38.  * Description:
  39.  *   This routine...
  40.  *
  41.  * Input(s):
  42.  *
  43.  *
  44.  * Output(s):
  45.  *
  46.  *
  47.  * Returns:
  48.  *
  49.  *
  50.  */
  51. static inline void
  52. PPC4xx_tlb_write(unsigned long tag, unsigned long data, unsigned int index)
  53. {
  54. asm("tlbwe %0,%1,1" : : "r" (data), "r" (index));
  55. asm("tlbwe %0,%1,0" : : "r" (tag), "r" (index));
  56. }
  57. /*
  58.  * ()
  59.  *
  60.  * Description:
  61.  *   This routine...
  62.  *
  63.  * Input(s):
  64.  *
  65.  *
  66.  * Output(s):
  67.  *
  68.  *
  69.  * Returns:
  70.  *
  71.  *
  72.  */
  73. void
  74. PPC4xx_flush_tlb_all(void)
  75. {
  76. int i;
  77. unsigned long flags, pid;
  78. save_flags(flags);
  79. cli();
  80. pid = mfspr(SPRN_PID);
  81. mtspr(SPRN_PID, 0);
  82. for (i = pinned; i < PPC4XX_TLB_SIZE; i++) {
  83. PPC4xx_tlb_write(0, 0, i);
  84. }
  85. asm("sync;isync");
  86. mtspr(SPRN_PID, pid);
  87. restore_flags(flags);
  88. }
  89. /*
  90.  * ()
  91.  *
  92.  * Description:
  93.  *   This routine...
  94.  *
  95.  * Input(s):
  96.  *
  97.  *
  98.  * Output(s):
  99.  *
  100.  *
  101.  * Returns:
  102.  *
  103.  *
  104.  */
  105. void
  106. PPC4xx_dtlb_miss(struct pt_regs *regs)
  107. {
  108. unsigned long addr = mfspr(SPRN_DEAR);
  109. int write = mfspr(SPRN_ESR) & ESR_DST;
  110. if (PPC4xx_tlb_miss(regs, addr, write) < 0) {
  111. sti();
  112. do_page_fault(regs, addr, write);
  113. cli();
  114. }
  115. }
  116. /*
  117.  * ()
  118.  *
  119.  * Description:
  120.  *   This routine...
  121.  *
  122.  * Input(s):
  123.  *
  124.  *
  125.  * Output(s):
  126.  *
  127.  *
  128.  * Returns:
  129.  *
  130.  *
  131.  */
  132. void
  133. PPC4xx_itlb_miss(struct pt_regs *regs)
  134. {
  135. unsigned long addr = regs->nip;
  136. if (PPC4xx_tlb_miss(regs, addr, 0) < 0) {
  137. sti();
  138. do_page_fault(regs, addr, 0);
  139. cli();
  140. }
  141. }
  142. /*
  143.  * ()
  144.  *
  145.  * Description:
  146.  *   This routine...
  147.  *
  148.  * Input(s):
  149.  *
  150.  *
  151.  * Output(s):
  152.  *
  153.  *
  154.  * Returns:
  155.  *
  156.  *
  157.  */
  158. void
  159. PPC4xx_tlb_pin(unsigned long va, unsigned long pa, int pagesz, int cache)
  160. {
  161. unsigned long tag, data;
  162. unsigned long opid;
  163. if (pinned >= PPC4XX_TLB_SIZE)
  164. return;
  165. opid = mfspr(SPRN_PID);
  166. mtspr(SPRN_PID, 0);
  167. data = (pa & TLB_RPN_MASK) | TLB_WR;
  168. if (cache)
  169. data |= (TLB_EX);
  170. else
  171. data |= (TLB_G | TLB_I);
  172. tag = (va & TLB_EPN_MASK) | TLB_VALID | pagesz;
  173. PPC4xx_tlb_write(tag, data, pinned++);
  174. mtspr(SPRN_PID, opid);
  175. return;
  176. }
  177. /*
  178.  * ()
  179.  *
  180.  * Description:
  181.  *   This routine...
  182.  *
  183.  * Input(s):
  184.  *
  185.  *
  186.  * Output(s):
  187.  *
  188.  *
  189.  * Returns:
  190.  *
  191.  *
  192.  */
  193. void
  194. PPC4xx_tlb_unpin(unsigned long va, unsigned long pa, int size)
  195. {
  196. /* XXX - To be implemented. */
  197. }
  198. /*
  199.  * ()
  200.  *
  201.  * Description:
  202.  *   This routine...
  203.  *
  204.  * Input(s):
  205.  *
  206.  *
  207.  * Output(s):
  208.  *
  209.  *
  210.  * Returns:
  211.  *
  212.  *
  213.  */
  214. static inline void
  215. PPC4xx_tlb_update(unsigned long addr, pte_t *pte)
  216. {
  217.         unsigned long data, tag, rand;
  218.         int i, found = 1;
  219.         /* Construct the hardware TLB entry from the Linux-style PTE */
  220.         tag = tag = (addr & PAGE_MASK) | TLB_VALID | TLB_PAGESZ(PAGESZ_4K);
  221.         data = data = (pte_val(*pte) & PAGE_MASK) | TLB_EX | TLB_WR;
  222. #if 0
  223.         if (pte_val(*pte) & _PAGE_HWWRITE)
  224.                 data |= TLB_WR;
  225. #endif
  226.         if (pte_val(*pte) & _PAGE_NO_CACHE)
  227.                 data |= TLB_I;
  228.         if (pte_val(*pte) & _PAGE_GUARDED)
  229.                 data |= TLB_G;
  230.         if (addr < KERNELBASE)
  231.                 data |= TLB_ZSEL(1);
  232.         /* Attempt to match the new tag to an existing entry in the TLB. */
  233.         asm("tlbsx. %0,0,%2;"
  234.     "beq 1f;"
  235.     "li %1,0;1:" : "=r" (i), "=r" (found) : "r" (tag));
  236. /*
  237.  * If we found a match for the tag, reuse the entry index and update
  238.  * the tag and data portions. Otherwise, we did not find a match. Use
  239.  * the lower 5 bits of the lower time base register as a pseudo-random
  240.  * index into the TLB and replace the entry at that index.
  241.  */
  242.         if (found) {
  243. PPC4xx_tlb_write(tag, data, i);
  244.         } else {
  245. rand = mfspr(SPRN_TBLO) & (PPC4XX_TLB_SIZE - 1);
  246. rand += pinned;
  247. if (rand >= PPC4XX_TLB_SIZE)
  248. rand -= pinned;
  249. PPC4xx_tlb_write(tag, data, rand);
  250. asm("isync;sync");
  251.         }
  252. }
  253. /*
  254.  * ()
  255.  *
  256.  * Description:
  257.  *   This routine...
  258.  *
  259.  * Input(s):
  260.  *
  261.  *
  262.  * Output(s):
  263.  *
  264.  *
  265.  * Returns:
  266.  *
  267.  *
  268.  */
  269. static int
  270. PPC4xx_tlb_miss(struct pt_regs *regs, unsigned long addr, int write)
  271. {
  272.         unsigned long spid, ospid;
  273.         struct mm_struct *mm;
  274.         pgd_t *pgd;
  275.         pmd_t *pmd;
  276.         pte_t *pte;
  277.         if (!user_mode(regs) && (addr >= KERNELBASE)) {
  278.                 mm = &init_mm;
  279.                 spid = 0;
  280.         } else {
  281.                 mm = current->mm;
  282.                 spid = mfspr(SPRN_PID);
  283.         }
  284.         pgd = pgd_offset(mm, addr);
  285.         if (pgd_none(*pgd))
  286.                 goto bad;
  287.         pmd = pmd_offset(pgd, addr);
  288.         if (pmd_none(*pmd))
  289.                 goto bad;
  290.         pte = pte_offset(pmd, addr);
  291.         if (pte_none(*pte) || !pte_present(*pte))
  292.                 goto bad;
  293.         if (write) {
  294.                 if (!pte_write(*pte))
  295.                         goto bad;
  296.                 set_pte(pte, pte_mkdirty(*pte));
  297.         }
  298.         set_pte(pte, pte_mkyoung(*pte));
  299.         ospid = mfspr(SPRN_PID);
  300.         mtspr(SPRN_PID, spid);
  301.         PPC4xx_tlb_update(addr, pte);
  302.         mtspr(SPRN_PID, ospid);
  303. return (0);
  304. bad:
  305. return (-1);
  306. }