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