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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * pmc.c
  3.  * Copyright (C) 2001 Dave Engebretsen & Mike Corrigan IBM Corporation
  4.  * 
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  * 
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  * 
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  18.  */
  19. /* Change Activity:
  20.  * 2001/06/05 : engebret : Created.
  21.  * 2002/04/11 : engebret : Add btmalloc code.
  22.  * End Change Activity 
  23.  */
  24. #include <asm/proc_fs.h>
  25. #include <asm/paca.h>
  26. #include <asm/iSeries/ItLpPaca.h>
  27. #include <asm/iSeries/ItLpQueue.h>
  28. #include <asm/processor.h>
  29. #include <linux/proc_fs.h>
  30. #include <linux/spinlock.h>
  31. #include <linux/slab.h>
  32. #include <linux/vmalloc.h>
  33. #include <asm/pmc.h>
  34. #include <asm/uaccess.h>
  35. #include <asm/naca.h>
  36. #include <asm/pgalloc.h>
  37. #include <asm/pgtable.h>
  38. #include <asm/mmu_context.h>
  39. #include <asm/page.h>
  40. #include <asm/machdep.h>
  41. #include <asm/lmb.h>
  42. #include <asm/abs_addr.h>
  43. #include <asm/ppcdebug.h>
  44. struct _pmc_sw pmc_sw_system = {
  45. 0  
  46. };
  47. struct _pmc_sw pmc_sw_cpu[NR_CPUS] = {
  48. {0 }, 
  49. };
  50. /*
  51.  * Provide enough storage for either system level counters or
  52.  * one cpu's counters.
  53.  */
  54. struct _pmc_sw_text pmc_sw_text;
  55. struct _pmc_hw_text pmc_hw_text;
  56. extern pte_t *find_linux_pte( pgd_t * pgdir, unsigned long ea );
  57. extern pgd_t *bolted_pgd;
  58. static struct vm_struct *get_btm_area(unsigned long size, unsigned long flags);
  59. static int local_free_bolted_pages(unsigned long ea, unsigned long num);
  60. extern pgd_t bolted_dir[];
  61. pgd_t *bolted_pgd  = (pgd_t *)&bolted_dir;
  62. struct vm_struct *btmlist = NULL;
  63. struct mm_struct btmalloc_mm = {pgd             : bolted_dir,
  64.                                 page_table_lock : SPIN_LOCK_UNLOCKED};
  65. extern spinlock_t hash_table_lock;
  66. char *
  67. ppc64_pmc_stab(int file)
  68. {
  69. int  n;
  70. unsigned long stab_faults, stab_capacity_castouts, stab_invalidations; 
  71. unsigned long i;
  72. stab_faults = stab_capacity_castouts = stab_invalidations = n = 0;
  73. if (file == -1) {
  74. for (i = 0;  i < smp_num_cpus; i++) {
  75. stab_faults += pmc_sw_cpu[i].stab_faults;
  76. stab_capacity_castouts += pmc_sw_cpu[i].stab_capacity_castouts;
  77. stab_invalidations += pmc_sw_cpu[i].stab_invalidations;
  78. }
  79. n += sprintf(pmc_sw_text.buffer + n,    
  80.      "Faults         0x%lxn", stab_faults); 
  81. n += sprintf(pmc_sw_text.buffer + n, 
  82.      "Castouts       0x%lxn", stab_capacity_castouts); 
  83. n += sprintf(pmc_sw_text.buffer + n, 
  84.      "Invalidations  0x%lxn", stab_invalidations); 
  85. } else {
  86. n += sprintf(pmc_sw_text.buffer + n,
  87.      "Faults         0x%lxn", 
  88.      pmc_sw_cpu[file].stab_faults);
  89. n += sprintf(pmc_sw_text.buffer + n,   
  90.      "Castouts       0x%lxn", 
  91.      pmc_sw_cpu[file].stab_capacity_castouts);
  92. n += sprintf(pmc_sw_text.buffer + n,   
  93.      "Invalidations  0x%lxn", 
  94.      pmc_sw_cpu[file].stab_invalidations);
  95. for (i = 0; i < STAB_ENTRY_MAX; i++) {
  96. if (pmc_sw_cpu[file].stab_entry_use[i]) {
  97. n += sprintf(pmc_sw_text.buffer + n,   
  98.      "Entry %02ld       0x%lxn", i, 
  99.      pmc_sw_cpu[file].stab_entry_use[i]);
  100. }
  101. }
  102. }
  103. return(pmc_sw_text.buffer); 
  104. }
  105. char *
  106. ppc64_pmc_htab(int file)
  107. {
  108. int  n;
  109. unsigned long htab_primary_overflows, htab_capacity_castouts;
  110. unsigned long htab_read_to_write_faults; 
  111. htab_primary_overflows = htab_capacity_castouts = 0;
  112. htab_read_to_write_faults = n = 0;
  113. if (file == -1) {
  114. n += sprintf(pmc_sw_text.buffer + n,    
  115.      "Primary Overflows  0x%lxn", 
  116.      pmc_sw_system.htab_primary_overflows); 
  117. n += sprintf(pmc_sw_text.buffer + n, 
  118.      "Castouts           0x%lxn", 
  119.      pmc_sw_system.htab_capacity_castouts); 
  120. } else {
  121. n += sprintf(pmc_sw_text.buffer + n,
  122.      "Primary Overflows  N/An");
  123. n += sprintf(pmc_sw_text.buffer + n,   
  124.      "Castouts           N/Ann");
  125. }
  126. return(pmc_sw_text.buffer); 
  127. }
  128. char *
  129. ppc64_pmc_hw(int file)
  130. {
  131. int  n;
  132. n = 0;
  133. if (file == -1) {
  134. n += sprintf(pmc_hw_text.buffer + n, "Not Implementedn");
  135. } else {
  136. n += sprintf(pmc_hw_text.buffer + n,    
  137.      "MMCR0  0x%lxn", mfspr(MMCR0)); 
  138. n += sprintf(pmc_hw_text.buffer + n, 
  139.      "MMCR1  0x%lxn", mfspr(MMCR1)); 
  140. #if 0
  141. n += sprintf(pmc_hw_text.buffer + n,    
  142.      "MMCRA  0x%lxn", mfspr(MMCRA)); 
  143. #endif
  144. n += sprintf(pmc_hw_text.buffer + n,    
  145.      "PMC1   0x%lxn", mfspr(PMC1)); 
  146. n += sprintf(pmc_hw_text.buffer + n,    
  147.      "PMC2   0x%lxn", mfspr(PMC2)); 
  148. n += sprintf(pmc_hw_text.buffer + n,    
  149.      "PMC3   0x%lxn", mfspr(PMC3)); 
  150. n += sprintf(pmc_hw_text.buffer + n,    
  151.      "PMC4   0x%lxn", mfspr(PMC4)); 
  152. n += sprintf(pmc_hw_text.buffer + n,    
  153.      "PMC5   0x%lxn", mfspr(PMC5)); 
  154. n += sprintf(pmc_hw_text.buffer + n,    
  155.      "PMC6   0x%lxn", mfspr(PMC6)); 
  156. n += sprintf(pmc_hw_text.buffer + n,    
  157.      "PMC7   0x%lxn", mfspr(PMC7)); 
  158. n += sprintf(pmc_hw_text.buffer + n,    
  159.      "PMC8   0x%lxn", mfspr(PMC8)); 
  160. }
  161. return(pmc_hw_text.buffer); 
  162. }
  163. /*
  164.  * Manage allocations of storage which is bolted in the HPT and low fault
  165.  * overhead in the segment tables. Intended to be used for buffers used 
  166.  * to collect performance data.  
  167.  *
  168.  * Remaining Issues:
  169.  *   - Power4 is not tested at all, 0xB regions will always be castout of slb
  170.  *   - On Power3, 0xB00000000 esid is left in the stab for all time,
  171.  *     other 0xB segments are castout, but not explicitly removed.
  172.  *   - Error path checking is weak at best, wrong at worst.
  173.  *
  174.  * btmalloc - Allocate a buffer which is bolted in the HPT and (eventually)
  175.  *            the segment table.
  176.  *
  177.  * Input : unsigned long size: bytes of storage to allocate.
  178.  * Return: void * : pointer to the kernal address of the buffer.
  179.  */
  180. void* btmalloc (unsigned long size) {
  181. pgd_t *pgdp;
  182. pmd_t *pmdp;
  183. pte_t *ptep, pte;
  184. unsigned long ea_base, ea, hpteflags;
  185. struct vm_struct *area;
  186. unsigned long pa, pg_count, page, vsid, slot, va, arpn, vpn;
  187.   
  188. size = PAGE_ALIGN(size);
  189. if (!size || (size >> PAGE_SHIFT) > num_physpages) return NULL;
  190. spin_lock(&btmalloc_mm.page_table_lock);
  191. spin_lock(&hash_table_lock);
  192. /* Get a virtual address region in the bolted space */
  193. area = get_btm_area(size, 0);
  194. if (!area) {
  195. spin_unlock(&btmalloc_mm.page_table_lock);
  196. return NULL;
  197. }
  198. ea_base = (unsigned long) area->addr;
  199. pg_count = (size >> PAGE_SHIFT);
  200. /* Create a Linux page table entry and an HPTE for each page */
  201. for(page = 0; page < pg_count; page++) {
  202. pa = get_free_page(GFP_KERNEL) - PAGE_OFFSET; 
  203. ea = ea_base + (page * PAGE_SIZE);
  204. vsid = get_kernel_vsid(ea);
  205. va = ( vsid << 28 ) | ( pa & 0xfffffff );
  206. vpn = va >> PAGE_SHIFT;
  207. arpn = ((unsigned long)__v2a(ea)) >> PAGE_SHIFT;
  208. /* Get a pointer to the linux page table entry for this page
  209.  * allocating pmd or pte pages along the way as needed.  Note
  210.  * that the pmd & pte pages are not themselfs bolted.
  211.  */
  212. pgdp = pgd_offset_b(ea);
  213. pmdp = pmd_alloc(&btmalloc_mm, pgdp, ea);
  214. ptep = pte_alloc(&btmalloc_mm, pmdp, ea);
  215. pte = *ptep;
  216. /* Clear any old hpte and set the new linux pte */
  217. set_pte(ptep, mk_pte_phys(pa & PAGE_MASK, PAGE_KERNEL));
  218. hpteflags = _PAGE_ACCESSED|_PAGE_COHERENT|PP_RWXX;
  219. pte_val(pte) &= ~_PAGE_HPTEFLAGS;
  220. pte_val(pte) |= _PAGE_HASHPTE;
  221. slot = ppc_md.hpte_insert(vpn, arpn, hpteflags, 1, 0);  
  222. pte_val(pte) |= ((slot<<12) & 
  223.  (_PAGE_GROUP_IX | _PAGE_SECONDARY));
  224. }
  225. spin_unlock(&hash_table_lock);
  226. spin_unlock(&btmalloc_mm.page_table_lock);
  227. return (void*)ea_base;
  228. }
  229. /*
  230.  * Free a range of bolted pages that were allocated with btmalloc
  231.  */
  232. void btfree(void *ea) {
  233. struct vm_struct **p, *tmp;
  234. unsigned long size = 0;
  235. if ((!ea) || ((PAGE_SIZE-1) & (unsigned long)ea)) {
  236. printk(KERN_ERR "Trying to btfree() bad address (%p)n", ea);
  237. return;
  238. }
  239. spin_lock(&btmalloc_mm.page_table_lock);
  240. /* Scan the bolted memory list for an entry matching
  241.  * the address to be freed, get the size (in bytes)
  242.  * and free the entry.  The list lock is not dropped
  243.  * until the page table entries are removed.
  244.  */
  245. for(p = &btmlist; (tmp = *p); p = &tmp->next ) {
  246. if ( tmp->addr == ea ) {
  247. size = tmp->size;
  248. break;
  249. }
  250. }
  251. /* If no entry found, it is an error */
  252. if ( !size ) {
  253. printk(KERN_ERR "Trying to btfree() bad address (%p)n", ea);
  254. spin_unlock(&btmalloc_mm.page_table_lock);
  255. return;
  256. }
  257. /* Free up the bolted pages and remove the page table entries */
  258. if(local_free_bolted_pages((unsigned long)ea, size >> PAGE_SHIFT)) {
  259. *p = tmp->next;
  260. kfree(tmp);
  261. }
  262. spin_unlock(&btmalloc_mm.page_table_lock);
  263. }
  264. static int local_free_bolted_pages(unsigned long ea, unsigned long num) {
  265. int i;
  266. pte_t pte;
  267. for(i=0; i<num; i++) {
  268. pte_t *ptep = find_linux_pte(bolted_pgd, ea);
  269. if(!ptep) {
  270. panic("free_bolted_pages - page being freed "
  271.       "(0x%lx) is not bolted", ea );
  272. }
  273. pte = *ptep;
  274. pte_clear(ptep);
  275. __free_pages(pte_page(pte), 0);
  276. flush_hash_page(0, ea, ptep); 
  277. ea += PAGE_SIZE;
  278. }
  279. return 1;
  280. }
  281. /*
  282.  * get_btm_area
  283.  *
  284.  * Get a virtual region in the bolted space
  285.  */
  286. static struct vm_struct *get_btm_area(unsigned long size, 
  287.       unsigned long flags) {
  288. unsigned long addr;
  289. struct vm_struct **p, *tmp, *area;
  290.   
  291. area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
  292. if (!area) return NULL;
  293. addr = BTMALLOC_START;
  294. for (p = &btmlist; (tmp = *p) ; p = &tmp->next) {
  295. if (size + addr < (unsigned long) tmp->addr)
  296. break;
  297. addr = tmp->size + (unsigned long) tmp->addr;
  298. if (addr + size > BTMALLOC_END) {
  299. kfree(area);
  300. return NULL;
  301. }
  302. }
  303. if (addr + size > BTMALLOC_END) {
  304. kfree(area);
  305. return NULL;
  306. }
  307. area->flags = flags;
  308. area->addr = (void *)addr;
  309. area->size = size;
  310. area->next = *p;
  311. *p = area;
  312. return area;
  313. }