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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  *  include/asm-s390/pgalloc.h
  3.  *
  4.  *  S390 version
  5.  *    Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
  6.  *    Author(s): Hartmut Penner (hpenner@de.ibm.com)
  7.  *               Martin Schwidefsky (schwidefsky@de.ibm.com)
  8.  *
  9.  *  Derived from "include/asm-i386/pgalloc.h"
  10.  *    Copyright (C) 1994  Linus Torvalds
  11.  */
  12. #ifndef _S390_PGALLOC_H
  13. #define _S390_PGALLOC_H
  14. #include <linux/config.h>
  15. #include <asm/processor.h>
  16. #include <linux/threads.h>
  17. #define pgd_quicklist (S390_lowcore.cpu_data.pgd_quick)
  18. #define pmd_quicklist (S390_lowcore.cpu_data.pmd_quick)
  19. #define pte_quicklist (S390_lowcore.cpu_data.pte_quick)
  20. #define pgtable_cache_size (S390_lowcore.cpu_data.pgtable_cache_sz)
  21. /*
  22.  * Allocate and free page tables. The xxx_kernel() versions are
  23.  * used to allocate a kernel page table - this turns on ASN bits
  24.  * if any.
  25.  */
  26. /*
  27.  * page directory allocation/free routines.
  28.  */
  29. extern __inline__ pgd_t *get_pgd_slow (void)
  30. {
  31. pgd_t *ret;
  32.         int i;
  33. ret = (pgd_t *) __get_free_pages(GFP_KERNEL, 2);
  34. if (ret != NULL)
  35.         for (i = 0; i < PTRS_PER_PGD; i++) 
  36.                 pgd_clear(ret + i);
  37. return ret;
  38. }
  39. extern __inline__ pgd_t *get_pgd_fast (void)
  40. {
  41. unsigned long *ret = pgd_quicklist;
  42. if (ret != NULL) {
  43. pgd_quicklist = (unsigned long *)(*ret);
  44. ret[0] = ret[1];
  45. pgtable_cache_size -= 4;
  46. }
  47. return (pgd_t *) ret;
  48. }
  49. extern __inline__ pgd_t *pgd_alloc (struct mm_struct *mm)
  50. {
  51. pgd_t *pgd;
  52. pgd = get_pgd_fast();
  53. if (!pgd)
  54. pgd = get_pgd_slow();
  55. return pgd;
  56. }
  57. extern __inline__ void free_pgd_fast (pgd_t *pgd)
  58. {
  59. *(unsigned long *) pgd = (unsigned long) pgd_quicklist;
  60. pgd_quicklist = (unsigned long *) pgd;
  61. pgtable_cache_size += 4;
  62. }
  63. extern __inline__ void free_pgd_slow (pgd_t *pgd)
  64. {
  65.         free_pages((unsigned long) pgd, 2);
  66. }
  67. #define pgd_free(pgd) free_pgd_fast(pgd)
  68. extern inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
  69. {
  70. pgd_val(*pgd) = _PGD_ENTRY | __pa(pmd);
  71. }
  72. /*
  73.  * page middle directory allocation/free routines.
  74.  */
  75. extern inline pmd_t * pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
  76. {
  77. pmd_t *pmd;
  78.         int i;
  79. pmd = (pmd_t *) __get_free_pages(GFP_KERNEL, 2);
  80. if (pmd != NULL) {
  81. for (i=0; i < PTRS_PER_PMD; i++)
  82. pmd_clear(pmd+i);
  83. }
  84. return pmd;
  85. }
  86. extern __inline__ pmd_t *
  87. pmd_alloc_one_fast(struct mm_struct *mm, unsigned long address)
  88. {
  89. unsigned long *ret = (unsigned long *) pmd_quicklist;
  90. if (ret != NULL) {
  91. pmd_quicklist = (unsigned long *)(*ret);
  92. ret[0] = ret[1];
  93. pgtable_cache_size -= 4;
  94. }
  95. return (pmd_t *) ret;
  96. }
  97. extern __inline__ void pmd_free_fast (pmd_t *pmd)
  98. {
  99. *(unsigned long *) pmd = (unsigned long) pmd_quicklist;
  100. pmd_quicklist = (unsigned long *) pmd;
  101. pgtable_cache_size += 4;
  102. }
  103. extern __inline__ void pmd_free_slow (pmd_t *pmd)
  104. {
  105. free_pages((unsigned long) pmd, 2);
  106. }
  107. #define pmd_free(pmd) pmd_free_fast(pmd)
  108. extern inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
  109. {
  110. pmd_val(*pmd) = _PMD_ENTRY | __pa(pte);
  111. pmd_val1(*pmd) = _PMD_ENTRY | __pa(pte+256);
  112. }
  113. /*
  114.  * page table entry allocation/free routines.
  115.  */
  116. extern inline pte_t * pte_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
  117. {
  118. pte_t *pte;
  119.         int i;
  120. pte = (pte_t *) __get_free_page(GFP_KERNEL);
  121. if (pte != NULL) {
  122. for (i=0; i < PTRS_PER_PTE; i++)
  123. pte_clear(pte+i);
  124. }
  125. return pte;
  126. }
  127. extern __inline__ pte_t* pte_alloc_one_fast(struct mm_struct *mm, unsigned long address)
  128. {
  129.         unsigned long *ret = (unsigned long *) pte_quicklist;
  130.         if (ret != NULL) {
  131.                 pte_quicklist = (unsigned long *)(*ret);
  132.                 ret[0] = ret[1];
  133.                 pgtable_cache_size--;
  134.         }
  135.         return (pte_t *)ret;
  136. }
  137. extern __inline__ void pte_free_fast (pte_t *pte)
  138. {
  139. *(unsigned long *) pte = (unsigned long) pte_quicklist;
  140. pte_quicklist = (unsigned long *) pte;
  141. pgtable_cache_size++;
  142. }
  143. extern __inline__ void pte_free_slow (pte_t *pte)
  144. {
  145.         free_page((unsigned long) pte);
  146. }
  147. #define pte_free(pte) pte_free_fast(pte)
  148. extern int do_check_pgt_cache (int, int);
  149. /*
  150.  * This establishes kernel virtual mappings (e.g., as a result of a
  151.  * vmalloc call).  Since s390-esame uses a separate kernel page table,
  152.  * there is nothing to do here... :)
  153.  */
  154. #define set_pgdir(vmaddr, entry) do { } while(0)
  155. /*
  156.  * TLB flushing:
  157.  *
  158.  *  - flush_tlb() flushes the current mm struct TLBs
  159.  *  - flush_tlb_all() flushes all processes TLBs 
  160.  *    called only from vmalloc/vfree
  161.  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  162.  *  - flush_tlb_page(vma, vmaddr) flushes one page
  163.  *  - flush_tlb_range(mm, start, end) flushes a range of pages
  164.  *  - flush_tlb_pgtables(mm, start, end) flushes a range of page tables
  165.  */
  166. /*
  167.  * S/390 has three ways of flushing TLBs
  168.  * 'ptlb' does a flush of the local processor
  169.  * 'csp' flushes the TLBs on all PUs of a SMP
  170.  * 'ipte' invalidates a pte in a page table and flushes that out of
  171.  * the TLBs of all PUs of a SMP
  172.  */
  173. #define local_flush_tlb() 
  174. do {  __asm__ __volatile__("ptlb": : :"memory"); } while (0)
  175. #ifndef CONFIG_SMP
  176. /*
  177.  * We always need to flush, since s390 does not flush tlb
  178.  * on each context switch
  179.  */
  180. static inline void flush_tlb(void)
  181. {
  182. local_flush_tlb();
  183. }
  184. static inline void flush_tlb_all(void)
  185. {
  186. local_flush_tlb();
  187. }
  188. static inline void flush_tlb_mm(struct mm_struct *mm) 
  189. {
  190. local_flush_tlb();
  191. }
  192. static inline void flush_tlb_page(struct vm_area_struct *vma,
  193.   unsigned long addr)
  194. {
  195. local_flush_tlb();
  196. }
  197. static inline void flush_tlb_range(struct mm_struct *mm,
  198.    unsigned long start, unsigned long end)
  199. {
  200. local_flush_tlb();
  201. }
  202. #else
  203. #include <asm/smp.h>
  204. static inline void global_flush_tlb(void)
  205. {
  206. long dummy = 0;
  207. __asm__ __volatile__ (
  208.                 "    la   4,3(%0)n"
  209.                 "    nill 4,0xfffcn"
  210.                 "    la   4,1(4)n"
  211.                 "    slr  2,2n"
  212.                 "    slr  3,3n"
  213.                 "    csp  2,4"
  214.                 : : "a" (&dummy) : "cc", "2", "3", "4" );
  215. }
  216. /*
  217.  * We only have to do global flush of tlb if process run since last
  218.  * flush on any other pu than current. 
  219.  * If we have threads (mm->count > 1) we always do a global flush, 
  220.  * since the process runs on more than one processor at the same time.
  221.  */
  222. static inline void __flush_tlb_mm(struct mm_struct * mm)
  223. {
  224. if ((smp_num_cpus > 1) &&
  225.     ((atomic_read(&mm->mm_count) != 1) ||
  226.      (mm->cpu_vm_mask != (1UL << smp_processor_id())))) {
  227. mm->cpu_vm_mask = (1UL << smp_processor_id());
  228. global_flush_tlb();
  229. } else {                 
  230. local_flush_tlb();
  231. }
  232. }
  233. static inline void flush_tlb(void)
  234. {
  235. __flush_tlb_mm(current->mm);
  236. }
  237. static inline void flush_tlb_all(void)
  238. {
  239. global_flush_tlb();
  240. }
  241. static inline void flush_tlb_mm(struct mm_struct *mm) 
  242. {
  243. __flush_tlb_mm(mm); 
  244. }
  245. static inline void flush_tlb_page(struct vm_area_struct *vma,
  246.   unsigned long addr)
  247. {
  248. __flush_tlb_mm(vma->vm_mm);
  249. }
  250. static inline void flush_tlb_range(struct mm_struct *mm,
  251.    unsigned long start, unsigned long end)
  252. {
  253. __flush_tlb_mm(mm); 
  254. }
  255. #endif
  256. extern inline void flush_tlb_pgtables(struct mm_struct *mm,
  257.                                       unsigned long start, unsigned long end)
  258. {
  259.         /* S/390 does not keep any page table caches in TLB */
  260. }
  261. static inline int ptep_test_and_clear_and_flush_young(struct vm_area_struct *vma, 
  262.                                                       unsigned long address, pte_t *ptep)
  263. {
  264. /* No need to flush TLB; bits are in storage key */
  265. return ptep_test_and_clear_young(ptep);
  266. }
  267. static inline int ptep_test_and_clear_and_flush_dirty(struct vm_area_struct *vma, 
  268.                                                       unsigned long address, pte_t *ptep)
  269. {
  270. /* No need to flush TLB; bits are in storage key */
  271. return ptep_test_and_clear_dirty(ptep);
  272. }
  273. static inline pte_t ptep_invalidate(struct vm_area_struct *vma, 
  274.                                     unsigned long address, pte_t *ptep)
  275. {
  276. pte_t pte = *ptep;
  277. if (!(pte_val(pte) & _PAGE_INVALID)) 
  278. __asm__ __volatile__ ("ipte %0,%1" : : "a" (ptep), "a" (address));
  279. pte_clear(ptep);
  280. return pte;
  281. }
  282. static inline void ptep_establish(struct vm_area_struct *vma, 
  283.                                   unsigned long address, pte_t *ptep, pte_t entry)
  284. {
  285. ptep_invalidate(vma, address, ptep);
  286. set_pte(ptep, entry);
  287. }
  288. #endif /* _S390_PGALLOC_H */