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

嵌入式Linux

开发平台:

Unix_Linux

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