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