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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * TLB support routines.
  3.  *
  4.  * Copyright (C) 1998-2001 Hewlett-Packard Co
  5.  * David Mosberger-Tang <davidm@hpl.hp.com>
  6.  *
  7.  * 08/02/00 A. Mallick <asit.k.mallick@intel.com>
  8.  * Modified RID allocation for SMP
  9.  *          Goutham Rao <goutham.rao@intel.com>
  10.  *              IPI based ptc implementation and A-step IPI implementation.
  11.  */
  12. #include <linux/config.h>
  13. #include <linux/init.h>
  14. #include <linux/kernel.h>
  15. #include <linux/sched.h>
  16. #include <linux/smp.h>
  17. #include <linux/mm.h>
  18. #include <asm/mmu_context.h>
  19. #include <asm/pgalloc.h>
  20. #include <asm/pal.h>
  21. #include <asm/delay.h>
  22. #define SUPPORTED_PGBITS (
  23. 1 << _PAGE_SIZE_256M |
  24. 1 << _PAGE_SIZE_64M  |
  25. 1 << _PAGE_SIZE_16M  |
  26. 1 << _PAGE_SIZE_4M   |
  27. 1 << _PAGE_SIZE_1M   |
  28. 1 << _PAGE_SIZE_256K |
  29. 1 << _PAGE_SIZE_64K  |
  30. 1 << _PAGE_SIZE_16K  |
  31. 1 << _PAGE_SIZE_8K   |
  32. 1 << _PAGE_SIZE_4K )
  33. struct ia64_ctx ia64_ctx = {
  34. lock: SPIN_LOCK_UNLOCKED,
  35. next: 1,
  36. limit: (1 << 15) - 1, /* start out with the safe (architected) limit */
  37. max_ctx: ~0U
  38. };
  39. /*
  40.  * Acquire the ia64_ctx.lock before calling this function!
  41.  */
  42. void
  43. wrap_mmu_context (struct mm_struct *mm)
  44. {
  45. unsigned long tsk_context, max_ctx = ia64_ctx.max_ctx;
  46. struct task_struct *tsk;
  47. if (ia64_ctx.next > max_ctx)
  48. ia64_ctx.next = 300; /* skip daemons */
  49. ia64_ctx.limit = max_ctx + 1;
  50. /*
  51.  * Scan all the task's mm->context and set proper safe range
  52.  */
  53. read_lock(&tasklist_lock);
  54.   repeat:
  55. for_each_task(tsk) {
  56. if (!tsk->mm)
  57. continue;
  58. tsk_context = tsk->mm->context;
  59. if (tsk_context == ia64_ctx.next) {
  60. if (++ia64_ctx.next >= ia64_ctx.limit) {
  61. /* empty range: reset the range limit and start over */
  62. if (ia64_ctx.next > max_ctx)
  63. ia64_ctx.next = 300;
  64. ia64_ctx.limit = max_ctx + 1;
  65. goto repeat;
  66. }
  67. }
  68. if ((tsk_context > ia64_ctx.next) && (tsk_context < ia64_ctx.limit))
  69. ia64_ctx.limit = tsk_context;
  70. }
  71. read_unlock(&tasklist_lock);
  72. flush_tlb_all();
  73. }
  74. static inline void
  75. ia64_global_tlb_purge (unsigned long start, unsigned long end, unsigned long nbits)
  76. {
  77. static spinlock_t ptcg_lock = SPIN_LOCK_UNLOCKED;
  78. /* HW requires global serialization of ptc.ga.  */
  79. spin_lock(&ptcg_lock);
  80. {
  81. do {
  82. /*
  83.  * Flush ALAT entries also.
  84.  */
  85. asm volatile ("ptc.ga %0,%1;;srlz.i;;" :: "r"(start), "r"(nbits<<2)
  86.       : "memory");
  87. start += (1UL << nbits);
  88. } while (start < end);
  89. }
  90. spin_unlock(&ptcg_lock);
  91. }
  92. void
  93. __flush_tlb_all (void)
  94. {
  95. unsigned long i, j, flags, count0, count1, stride0, stride1, addr;
  96. addr    = local_cpu_data->ptce_base;
  97. count0  = local_cpu_data->ptce_count[0];
  98. count1  = local_cpu_data->ptce_count[1];
  99. stride0 = local_cpu_data->ptce_stride[0];
  100. stride1 = local_cpu_data->ptce_stride[1];
  101. local_irq_save(flags);
  102. for (i = 0; i < count0; ++i) {
  103. for (j = 0; j < count1; ++j) {
  104. asm volatile ("ptc.e %0" :: "r"(addr));
  105. addr += stride1;
  106. }
  107. addr += stride0;
  108. }
  109. local_irq_restore(flags);
  110. ia64_insn_group_barrier();
  111. ia64_srlz_i(); /* srlz.i implies srlz.d */
  112. ia64_insn_group_barrier();
  113. }
  114. void
  115. flush_tlb_range (struct mm_struct *mm, unsigned long start, unsigned long end)
  116. {
  117. unsigned long size = end - start;
  118. unsigned long nbits;
  119. if (mm != current->active_mm) {
  120. /* this does happen, but perhaps it's not worth optimizing for? */
  121. #ifdef CONFIG_SMP
  122. flush_tlb_all();
  123. #else
  124. mm->context = 0;
  125. #endif
  126. return;
  127. }
  128. nbits = ia64_fls(size + 0xfff);
  129. if (((1UL << nbits) & SUPPORTED_PGBITS) == 0) {
  130. if (nbits > _PAGE_SIZE_256M)
  131. nbits = _PAGE_SIZE_256M;
  132. else
  133. /*
  134.  * Some page sizes are not implemented in the
  135.  * IA-64 arch, so if we get asked to clear an
  136.  * unsupported page size, round up to the
  137.  * nearest page size.  Note that we depend on
  138.  * the fact that if page size N is not
  139.  * implemented, 2*N _is_ implemented.
  140.  */
  141. ++nbits;
  142. if (((1UL << nbits) & SUPPORTED_PGBITS) == 0)
  143. panic("flush_tlb_range: BUG: nbits=%lun", nbits);
  144. }
  145. start &= ~((1UL << nbits) - 1);
  146. # ifdef CONFIG_SMP
  147. platform_global_tlb_purge(start, end, nbits);
  148. # else
  149. do {
  150. asm volatile ("ptc.l %0,%1" :: "r"(start), "r"(nbits<<2) : "memory");
  151. start += (1UL << nbits);
  152. } while (start < end);
  153. # endif
  154. ia64_insn_group_barrier();
  155. ia64_srlz_i(); /* srlz.i implies srlz.d */
  156. ia64_insn_group_barrier();
  157. }
  158. void __init
  159. ia64_tlb_init (void)
  160. {
  161. ia64_ptce_info_t ptce_info;
  162. ia64_get_ptce(&ptce_info);
  163. local_cpu_data->ptce_base = ptce_info.base;
  164. local_cpu_data->ptce_count[0] = ptce_info.count[0];
  165. local_cpu_data->ptce_count[1] = ptce_info.count[1];
  166. local_cpu_data->ptce_stride[0] = ptce_info.stride[0];
  167. local_cpu_data->ptce_stride[1] = ptce_info.stride[1];
  168. __flush_tlb_all(); /* nuke left overs from bootstrapping... */
  169. }