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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * PowerPC64 Segment Translation Support.
  3.  *
  4.  * Dave Engebretsen and Mike Corrigan {engebret|mikejc}@us.ibm.com
  5.  *    Copyright (c) 2001 Dave Engebretsen
  6.  * 
  7.  *      This program is free software; you can redistribute it and/or
  8.  *      modify it under the terms of the GNU General Public License
  9.  *      as published by the Free Software Foundation; either version
  10.  *      2 of the License, or (at your option) any later version.
  11.  */
  12. #include <linux/config.h>
  13. #include <asm/pgtable.h>
  14. #include <asm/mmu.h>
  15. #include <asm/mmu_context.h>
  16. #include <asm/paca.h>
  17. #include <asm/naca.h>
  18. #include <asm/pmc.h>
  19. inline int make_ste(unsigned long stab, 
  20.     unsigned long esid, unsigned long vsid);
  21. inline void make_slbe(unsigned long esid, unsigned long vsid,
  22.       int large);
  23. /*
  24.  * Build an entry for the base kernel segment and put it into
  25.  * the segment table or SLB.  All other segment table or SLB
  26.  * entries are faulted in.
  27.  */
  28. void stab_initialize(unsigned long stab)
  29. {
  30. unsigned long esid, vsid; 
  31. esid = GET_ESID(KERNELBASE);
  32. vsid = get_kernel_vsid(esid << SID_SHIFT); 
  33. if (!__is_processor(PV_POWER4) && !__is_processor(PV_POWER4p)) {
  34.                 __asm__ __volatile__("isync; slbia; isync":::"memory");
  35. make_ste(stab, esid, vsid);
  36. } else {
  37.                 /* Invalidate the entire SLB & all the ERATS */
  38.                 __asm__ __volatile__("isync" : : : "memory");
  39. #ifndef CONFIG_PPC_ISERIES
  40.                 __asm__ __volatile__("slbmte  %0,%0"
  41.                                       : : "r" (0) : "memory");
  42.                 __asm__ __volatile__("isync; slbia; isync":::"memory");
  43. make_slbe(esid, vsid, 0);
  44. #else
  45.                 __asm__ __volatile__("isync; slbia; isync":::"memory");
  46. #endif
  47.         }
  48. }
  49. /*
  50.  * Create a segment table entry for the given esid/vsid pair.
  51.  */ 
  52. inline int
  53. make_ste(unsigned long stab, unsigned long esid, unsigned long vsid)
  54. {
  55. unsigned long entry, group, old_esid, castout_entry, i;
  56. unsigned int global_entry;
  57. STE *ste, *castout_ste;
  58. /* Search the primary group first. */
  59. global_entry = (esid & 0x1f) << 3;
  60. ste = (STE *)(stab | ((esid & 0x1f) << 7)); 
  61. /*
  62.  * Find an empty entry, if one exists.
  63.  */
  64. for(group = 0; group < 2; group++) {
  65. for(entry = 0; entry < 8; entry++, ste++) {
  66. if(!(ste->dw0.dw0.v)) {
  67. ste->dw1.dw1.vsid = vsid;
  68. /* Order VSID updte */
  69. __asm__ __volatile__ ("eieio" : : : "memory");
  70. ste->dw0.dw0.esid = esid;
  71. ste->dw0.dw0.v  = 1;
  72. ste->dw0.dw0.kp = 1;
  73. /* Order update     */
  74. __asm__ __volatile__ ("sync" : : : "memory"); 
  75. return(global_entry | entry);
  76. }
  77. }
  78. /* Now search the secondary group. */
  79. global_entry = ((~esid) & 0x1f) << 3;
  80. ste = (STE *)(stab | (((~esid) & 0x1f) << 7)); 
  81. }
  82. /*
  83.  * Could not find empty entry, pick one with a round robin selection.
  84.  * Search all entries in the two groups.  Note that the first time
  85.  * we get here, we start with entry 1 so the initializer
  86.  * can be common with the SLB castout code.
  87.  */
  88. /* This assumes we never castout when initializing the stab. */
  89. PMC_SW_PROCESSOR(stab_capacity_castouts); 
  90. castout_entry = get_paca()->xStab_data.next_round_robin;
  91. for(i = 0; i < 16; i++) {
  92. if(castout_entry < 8) {
  93. global_entry = (esid & 0x1f) << 3;
  94. ste = (STE *)(stab | ((esid & 0x1f) << 7)); 
  95. castout_ste = ste + castout_entry;
  96. } else {
  97. global_entry = ((~esid) & 0x1f) << 3;
  98. ste = (STE *)(stab | (((~esid) & 0x1f) << 7)); 
  99. castout_ste = ste + (castout_entry - 8);
  100. }
  101. if((((castout_ste->dw0.dw0.esid) >> 32) == 0) ||
  102.    (((castout_ste->dw0.dw0.esid) & 0xffffffff) > 0)) {
  103. /* Found an entry to castout.  It is either a user */
  104. /* region, or a secondary kernel segment.          */
  105. break;
  106. }
  107. castout_entry = (castout_entry + 1) & 0xf;
  108. }
  109. get_paca()->xStab_data.next_round_robin = (castout_entry + 1) & 0xf;
  110. /* Modify the old entry to the new value. */
  111. /* Force previous translations to complete. DRENG */
  112. __asm__ __volatile__ ("isync" : : : "memory" );
  113. castout_ste->dw0.dw0.v = 0;
  114. __asm__ __volatile__ ("sync" : : : "memory" );    /* Order update */
  115. castout_ste->dw1.dw1.vsid = vsid;
  116. __asm__ __volatile__ ("eieio" : : : "memory" );   /* Order update */
  117. old_esid = castout_ste->dw0.dw0.esid;
  118. castout_ste->dw0.dw0.esid = esid;
  119. castout_ste->dw0.dw0.v  = 1;
  120. castout_ste->dw0.dw0.kp = 1;
  121. __asm__ __volatile__ ("slbie  %0" : : "r" (old_esid << SID_SHIFT)); 
  122. /* Ensure completion of slbie */
  123. __asm__ __volatile__ ("sync" : : : "memory" );  
  124. return(global_entry | (castout_entry & 0x7));
  125. }
  126. /*
  127.  * Create a segment buffer entry for the given esid/vsid pair.
  128.  */ 
  129. inline void make_slbe(unsigned long esid, unsigned long vsid, int large)
  130. {
  131. unsigned long entry, castout_entry;
  132. slb_dword0 castout_esid_data;
  133. union {
  134. unsigned long word0;
  135. slb_dword0    data;
  136. } esid_data;
  137. union {
  138. unsigned long word0;
  139. slb_dword1    data;
  140. } vsid_data;
  141. /*
  142.  * Find an empty entry, if one exists.
  143.  */
  144. for(entry = 0; entry < naca->slb_size; entry++) {
  145. __asm__ __volatile__("slbmfee  %0,%1" 
  146.      : "=r" (esid_data) : "r" (entry)); 
  147. if(!esid_data.data.v) {
  148. /* 
  149.  * Write the new SLB entry.
  150.  */
  151. vsid_data.word0 = 0;
  152. vsid_data.data.vsid = vsid;
  153. vsid_data.data.kp = 1;
  154. if (large)
  155. vsid_data.data.l = 1;
  156. esid_data.word0 = 0;
  157. esid_data.data.esid = esid;
  158. esid_data.data.v = 1;
  159. esid_data.data.index = entry;
  160. /* slbie not needed as no previous mapping existed. */
  161. /* Order update  */
  162. __asm__ __volatile__ ("isync" : : : "memory");
  163. __asm__ __volatile__ ("slbmte  %0,%1" 
  164.       : : "r" (vsid_data), 
  165.       "r" (esid_data)); 
  166. /* Order update  */
  167. __asm__ __volatile__ ("isync" : : : "memory");
  168. return;
  169. }
  170. }
  171. /*
  172.  * Could not find empty entry, pick one with a round robin selection.
  173.  */
  174. PMC_SW_PROCESSOR(stab_capacity_castouts); 
  175. castout_entry = get_paca()->xStab_data.next_round_robin;
  176. __asm__ __volatile__("slbmfee  %0,%1" 
  177.      : "=r" (castout_esid_data) 
  178.      : "r" (castout_entry)); 
  179. entry = castout_entry; 
  180. castout_entry++; 
  181. if(castout_entry >= naca->slb_size) {
  182. castout_entry = 1; 
  183. }
  184. get_paca()->xStab_data.next_round_robin = castout_entry;
  185. /* Invalidate the old entry. */
  186. castout_esid_data.v = 0; /* Set the class to 0 */
  187. /* slbie not needed as the previous mapping is still valid. */
  188. __asm__ __volatile__("slbie  %0" : : "r" (castout_esid_data)); 
  189. /* 
  190.  * Write the new SLB entry.
  191.  */
  192. vsid_data.word0 = 0;
  193. vsid_data.data.vsid = vsid;
  194. vsid_data.data.kp = 1;
  195. if (large)
  196. vsid_data.data.l = 1;
  197. esid_data.word0 = 0;
  198. esid_data.data.esid = esid;
  199. esid_data.data.v = 1;
  200. esid_data.data.index = entry;
  201. __asm__ __volatile__ ("isync" : : : "memory");   /* Order update */
  202. __asm__ __volatile__ ("slbmte  %0,%1" 
  203.       : : "r" (vsid_data), "r" (esid_data)); 
  204. __asm__ __volatile__ ("isync" : : : "memory" );   /* Order update */
  205. }
  206. /*
  207.  * Allocate a segment table entry for the given ea.
  208.  */
  209. int ste_allocate ( unsigned long ea, 
  210.    unsigned long trap) 
  211. {
  212. unsigned long vsid, esid;
  213. int kernel_segment = 0;
  214. PMC_SW_PROCESSOR(stab_faults); 
  215. /* Check for invalid effective addresses. */
  216. if (!IS_VALID_EA(ea)) {
  217. return 1;
  218. }
  219. /* Kernel or user address? */
  220. if (REGION_ID(ea)) {
  221. kernel_segment = 1;
  222. vsid = get_kernel_vsid( ea );
  223. } else {
  224. struct mm_struct *mm = current->mm;
  225. if ( mm ) {
  226. vsid = get_vsid(mm->context, ea );
  227. } else {
  228. return 1;
  229. }
  230. }
  231. esid = GET_ESID(ea);
  232. if (trap == 0x380 || trap == 0x480) {
  233. #ifndef CONFIG_PPC_ISERIES
  234. if (REGION_ID(ea) == KERNEL_REGION_ID)
  235. make_slbe(esid, vsid, 1); 
  236. else
  237. #endif
  238. make_slbe(esid, vsid, 0); 
  239. } else {
  240. unsigned char top_entry, stab_entry, *segments; 
  241. stab_entry = make_ste(get_paca()->xStab_data.virt, esid, vsid);
  242. PMC_SW_PROCESSOR_A(stab_entry_use, stab_entry & 0xf); 
  243. segments = get_paca()->xSegments;
  244. top_entry = segments[0];
  245. if(!kernel_segment && top_entry < (STAB_CACHE_SIZE - 1)) {
  246. top_entry++;
  247. segments[top_entry] = stab_entry;
  248. if(top_entry == STAB_CACHE_SIZE - 1) top_entry = 0xff;
  249. segments[0] = top_entry;
  250. }
  251. }
  252. return(0); 
  253. }
  254.  
  255. /* 
  256.  * Flush all entries from the segment table of the current processor.
  257.  * Kernel and Bolted entries are not removed as we cannot tolerate 
  258.  * faults on those addresses.
  259.  */
  260. #define STAB_PRESSURE 0
  261. void flush_stab(void)
  262. {
  263. STE *stab = (STE *) get_paca()->xStab_data.virt;
  264. unsigned char *segments = get_paca()->xSegments;
  265. unsigned long flags, i;
  266. if (!__is_processor(PV_POWER4) && !__is_processor(PV_POWER4p)) {
  267. unsigned long entry;
  268. STE *ste;
  269. /* Force previous translations to complete. DRENG */
  270. __asm__ __volatile__ ("isync" : : : "memory");
  271. __save_and_cli(flags);
  272. if(segments[0] != 0xff && !STAB_PRESSURE) {
  273. for(i = 1; i <= segments[0]; i++) {
  274. ste = stab + segments[i]; 
  275. ste->dw0.dw0.v = 0;
  276. PMC_SW_PROCESSOR(stab_invalidations); 
  277. }
  278. } else {
  279. /* Invalidate all entries. */
  280.                         ste = stab;
  281.         /* Never flush the first entry. */ 
  282.         ste += 1;
  283. for(entry = 1;
  284.     entry < (PAGE_SIZE / sizeof(STE)); 
  285.     entry++, ste++) {
  286. unsigned long ea;
  287. ea = ste->dw0.dw0.esid << SID_SHIFT;
  288. if (STAB_PRESSURE || (!REGION_ID(ea))) {
  289. ste->dw0.dw0.v = 0;
  290. PMC_SW_PROCESSOR(stab_invalidations); 
  291. }
  292. }
  293. }
  294. *((unsigned long *)segments) = 0;
  295. __restore_flags(flags);
  296. /* Invalidate the SLB. */
  297. /* Force invals to complete. */
  298. __asm__ __volatile__ ("sync" : : : "memory");  
  299. /* Flush the SLB.            */
  300. __asm__ __volatile__ ("slbia" : : : "memory"); 
  301. /* Force flush to complete.  */
  302. __asm__ __volatile__ ("sync" : : : "memory");  
  303. } else {
  304. unsigned long flags;
  305. PMC_SW_PROCESSOR(stab_invalidations); 
  306. __save_and_cli(flags);
  307. __asm__ __volatile__("isync; slbia; isync":::"memory");
  308. __restore_flags(flags);
  309. }
  310. }