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

Linux/Unix编程

开发平台:

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