1 /*
2 * PowerPC hash table management proc entry. Will show information
3 * about the current hash table and will allow changes to it.
4 *
5 * Written by Cort Dougan (cort@cs.nmt.edu)
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
13 #include <linux/config.h>
14 #include <linux/errno.h>
15 #include <linux/sched.h>
16 #include <linux/proc_fs.h>
17 #include <linux/stat.h>
18 #include <linux/sysctl.h>
19 #include <linux/ctype.h>
20 #include <linux/threads.h>
21
22 #include <asm/uaccess.h>
23 #include <asm/bitops.h>
24 #include <asm/mmu.h>
25 #include <asm/processor.h>
26 #include <asm/residual.h>
27 #include <asm/io.h>
28 #include <asm/pgtable.h>
29 #include <asm/cputable.h>
30 #include <asm/system.h>
31
32 static ssize_t ppc_htab_read(struct file * file, char * buf,
33 size_t count, loff_t *ppos);
34 static ssize_t ppc_htab_write(struct file * file, const char * buffer,
35 size_t count, loff_t *ppos);
36 static long long ppc_htab_lseek(struct file * file, loff_t offset, int orig);
37 int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
38 void *buffer, size_t *lenp);
39
40 extern PTE *Hash, *Hash_end;
41 extern unsigned long Hash_size, Hash_mask;
42 extern unsigned long _SDR1;
43 extern unsigned long htab_reloads;
44 extern unsigned long htab_preloads;
45 extern unsigned long htab_evicts;
46 extern unsigned long pte_misses;
47 extern unsigned long pte_errors;
48 extern unsigned int primary_pteg_full;
49 extern unsigned int htab_hash_searches;
50
51 /* these will go into processor.h when I'm done debugging -- Cort */
52 #define MMCR0 952
53 #define MMCR0_PMC1_CYCLES (0x1<<7)
54 #define MMCR0_PMC1_ICACHEMISS (0x5<<7)
55 #define MMCR0_PMC1_DTLB (0x6<<7)
56 #define MMCR0_PMC2_DCACHEMISS (0x6)
57 #define MMCR0_PMC2_CYCLES (0x1)
58 #define MMCR0_PMC2_ITLB (0x7)
59 #define MMCR0_PMC2_LOADMISSTIME (0x5)
60
61 #define PMC1 953
62 #define PMC2 954
63
64 struct file_operations ppc_htab_operations = {
65 llseek: ppc_htab_lseek,
66 read: ppc_htab_read,
67 write: ppc_htab_write,
68 };
69
pmc1_lookup(unsigned long mmcr0)70 static char *pmc1_lookup(unsigned long mmcr0)
71 {
72 switch ( mmcr0 & (0x7f<<7) )
73 {
74 case 0x0:
75 return "none";
76 case MMCR0_PMC1_CYCLES:
77 return "cycles";
78 case MMCR0_PMC1_ICACHEMISS:
79 return "ic miss";
80 case MMCR0_PMC1_DTLB:
81 return "dtlb miss";
82 default:
83 return "unknown";
84 }
85 }
86
pmc2_lookup(unsigned long mmcr0)87 static char *pmc2_lookup(unsigned long mmcr0)
88 {
89 switch ( mmcr0 & 0x3f )
90 {
91 case 0x0:
92 return "none";
93 case MMCR0_PMC2_CYCLES:
94 return "cycles";
95 case MMCR0_PMC2_DCACHEMISS:
96 return "dc miss";
97 case MMCR0_PMC2_ITLB:
98 return "itlb miss";
99 case MMCR0_PMC2_LOADMISSTIME:
100 return "load miss time";
101 default:
102 return "unknown";
103 }
104 }
105
106 /*
107 * print some useful info about the hash table. This function
108 * is _REALLY_ slow (see the nested for loops below) but nothing
109 * in here should be really timing critical. -- Cort
110 */
ppc_htab_read(struct file * file,char * buf,size_t count,loff_t * ppos)111 static ssize_t ppc_htab_read(struct file * file, char * buf,
112 size_t count, loff_t *ppos)
113 {
114 unsigned long mmcr0 = 0, pmc1 = 0, pmc2 = 0;
115 loff_t pos = *ppos;
116 int n = 0;
117 #if defined(CONFIG_PPC_STD_MMU) && !defined(CONFIG_PPC64BRIDGE)
118 int valid;
119 unsigned int kptes = 0, uptes = 0, zombie_ptes = 0;
120 PTE *ptr;
121 struct task_struct *p;
122 #endif /* CONFIG_PPC_STD_MMU */
123 char buffer[512];
124
125 if (count < 0)
126 return -EINVAL;
127
128 if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
129 asm volatile ("mfspr %0,952 \n\t"
130 "mfspr %1,953 \n\t"
131 "mfspr %2,954 \n\t"
132 : "=r" (mmcr0), "=r" (pmc1), "=r" (pmc2) );
133 n += sprintf( buffer + n,
134 "604 Performance Monitoring\n"
135 "MMCR0\t\t: %08lx %s%s ",
136 mmcr0,
137 ( mmcr0>>28 & 0x2 ) ? "(user mode counted)" : "",
138 ( mmcr0>>28 & 0x4 ) ? "(kernel mode counted)" : "");
139 n += sprintf( buffer + n,
140 "\nPMC1\t\t: %08lx (%s)\n"
141 "PMC2\t\t: %08lx (%s)\n",
142 pmc1, pmc1_lookup(mmcr0),
143 pmc2, pmc2_lookup(mmcr0));
144 }
145
146 #ifdef CONFIG_PPC_STD_MMU
147 /* if we don't have a htab */
148 if ( Hash_size == 0 )
149 {
150 n += sprintf( buffer + n, "No Hash Table used\n");
151 goto return_string;
152 }
153
154 #ifndef CONFIG_PPC64BRIDGE
155 for ( ptr = Hash ; ptr < Hash_end ; ptr++)
156 {
157 unsigned int ctx, mctx, vsid;
158
159 if (!ptr->v)
160 continue;
161 /* make sure someone is using this context/vsid */
162 /* first undo the esid skew */
163 vsid = ptr->vsid;
164 mctx = ((vsid - (vsid & 0xf) * 0x111) >> 4) & 0xfffff;
165 if (mctx == 0) {
166 kptes++;
167 continue;
168 }
169 /* now undo the context skew; 801921 * 897 == 1 mod 2^20 */
170 ctx = (mctx * 801921) & 0xfffff;
171 valid = 0;
172 for_each_task(p) {
173 if (p->mm != NULL && ctx == p->mm->context) {
174 valid = 1;
175 uptes++;
176 break;
177 }
178 }
179 if (!valid)
180 zombie_ptes++;
181 }
182 #endif
183
184 n += sprintf( buffer + n,
185 "PTE Hash Table Information\n"
186 "Size\t\t: %luKb\n"
187 "Buckets\t\t: %lu\n"
188 "Address\t\t: %08lx\n"
189 "Entries\t\t: %lu\n"
190 #ifndef CONFIG_PPC64BRIDGE
191 "User ptes\t: %u\n"
192 "Kernel ptes\t: %u\n"
193 "Zombies\t\t: %u\n"
194 "Percent full\t: %lu%%\n"
195 #endif
196 , (unsigned long)(Hash_size>>10),
197 (Hash_size/(sizeof(PTE)*8)),
198 (unsigned long)Hash,
199 Hash_size/sizeof(PTE)
200 #ifndef CONFIG_PPC64BRIDGE
201 , uptes,
202 kptes,
203 zombie_ptes,
204 ((kptes+uptes)*100) / (Hash_size/sizeof(PTE))
205 #endif
206 );
207
208 n += sprintf( buffer + n,
209 "Reloads\t\t: %lu\n"
210 "Preloads\t: %lu\n"
211 "Searches\t: %u\n"
212 "Overflows\t: %u\n"
213 "Evicts\t\t: %lu\n",
214 htab_reloads, htab_preloads, htab_hash_searches,
215 primary_pteg_full, htab_evicts);
216 return_string:
217 #endif /* CONFIG_PPC_STD_MMU */
218
219 n += sprintf( buffer + n,
220 "Non-error misses: %lu\n"
221 "Error misses\t: %lu\n",
222 pte_misses, pte_errors);
223 if (pos != (unsigned)pos || pos >= strlen(buffer))
224 return 0;
225 if (n > strlen(buffer) - pos)
226 n = strlen(buffer) - pos;
227 if (n > count)
228 n = count;
229 copy_to_user(buf, buffer + pos, n);
230 *ppos = pos + n;
231 return n;
232 }
233
234 /*
235 * Allow user to define performance counters and resize the hash table
236 */
ppc_htab_write(struct file * file,const char * buffer,size_t count,loff_t * ppos)237 static ssize_t ppc_htab_write(struct file * file, const char * buffer,
238 size_t count, loff_t *ppos)
239 {
240 #ifdef CONFIG_PPC_STD_MMU
241 unsigned long tmp;
242 if ( current->uid != 0 )
243 return -EACCES;
244 /* don't set the htab size for now */
245 if ( !strncmp( buffer, "size ", 5) )
246 return -EBUSY;
247
248 /* turn off performance monitoring */
249 if ( !strncmp( buffer, "off", 3) )
250 {
251 if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
252 asm volatile ("mtspr %0, %3 \n\t"
253 "mtspr %1, %3 \n\t"
254 "mtspr %2, %3 \n\t"
255 :: "i" (MMCR0), "i" (PMC1), "i" (PMC2), "r" (0));
256 }
257 }
258
259 if ( !strncmp( buffer, "reset", 5) )
260 {
261 if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
262 /* reset PMC1 and PMC2 */
263 asm volatile (
264 "mtspr 953, %0 \n\t"
265 "mtspr 954, %0 \n\t"
266 :: "r" (0));
267 }
268 htab_reloads = 0;
269 htab_evicts = 0;
270 pte_misses = 0;
271 pte_errors = 0;
272 }
273
274 if ( !strncmp( buffer, "user", 4) )
275 {
276 if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
277 /* setup mmcr0 and clear the correct pmc */
278 asm("mfspr %0,%1\n\t" : "=r" (tmp) : "i" (MMCR0));
279 tmp &= ~(0x60000000);
280 tmp |= 0x20000000;
281 asm volatile (
282 "mtspr %1,%0 \n\t" /* set new mccr0 */
283 "mtspr %3,%4 \n\t" /* reset the pmc */
284 "mtspr %5,%4 \n\t" /* reset the pmc2 */
285 :: "r" (tmp), "i" (MMCR0), "i" (0),
286 "i" (PMC1), "r" (0), "i"(PMC2) );
287 }
288 }
289
290 if ( !strncmp( buffer, "kernel", 6) )
291 {
292 if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
293 /* setup mmcr0 and clear the correct pmc */
294 asm("mfspr %0,%1\n\t" : "=r" (tmp) : "i" (MMCR0));
295 tmp &= ~(0x60000000);
296 tmp |= 0x40000000;
297 asm volatile (
298 "mtspr %1,%0 \n\t" /* set new mccr0 */
299 "mtspr %3,%4 \n\t" /* reset the pmc */
300 "mtspr %5,%4 \n\t" /* reset the pmc2 */
301 :: "r" (tmp), "i" (MMCR0), "i" (0),
302 "i" (PMC1), "r" (0), "i"(PMC2) );
303 }
304 }
305
306 /* PMC1 values */
307 if ( !strncmp( buffer, "dtlb", 4) )
308 {
309 if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
310 /* setup mmcr0 and clear the correct pmc */
311 asm("mfspr %0,%1\n\t" : "=r" (tmp) : "i" (MMCR0));
312 tmp &= ~(0x7f<<7);
313 tmp |= MMCR0_PMC1_DTLB;
314 asm volatile (
315 "mtspr %1,%0 \n\t" /* set new mccr0 */
316 "mtspr %3,%4 \n\t" /* reset the pmc */
317 :: "r" (tmp), "i" (MMCR0), "i" (MMCR0_PMC1_DTLB),
318 "i" (PMC1), "r" (0) );
319 }
320 }
321
322 if ( !strncmp( buffer, "ic miss", 7) )
323 {
324 if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
325 /* setup mmcr0 and clear the correct pmc */
326 asm("mfspr %0,%1\n\t" : "=r" (tmp) : "i" (MMCR0));
327 tmp &= ~(0x7f<<7);
328 tmp |= MMCR0_PMC1_ICACHEMISS;
329 asm volatile (
330 "mtspr %1,%0 \n\t" /* set new mccr0 */
331 "mtspr %3,%4 \n\t" /* reset the pmc */
332 :: "r" (tmp), "i" (MMCR0),
333 "i" (MMCR0_PMC1_ICACHEMISS), "i" (PMC1), "r" (0));
334 }
335 }
336
337 /* PMC2 values */
338 if ( !strncmp( buffer, "load miss time", 14) )
339 {
340 if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
341 /* setup mmcr0 and clear the correct pmc */
342 asm volatile(
343 "mfspr %0,%1\n\t" /* get current mccr0 */
344 "rlwinm %0,%0,0,0,31-6\n\t" /* clear bits [26-31] */
345 "ori %0,%0,%2 \n\t" /* or in mmcr0 settings */
346 "mtspr %1,%0 \n\t" /* set new mccr0 */
347 "mtspr %3,%4 \n\t" /* reset the pmc */
348 : "=r" (tmp)
349 : "i" (MMCR0), "i" (MMCR0_PMC2_LOADMISSTIME),
350 "i" (PMC2), "r" (0) );
351 }
352 }
353
354 if ( !strncmp( buffer, "itlb", 4) )
355 {
356 if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
357 /* setup mmcr0 and clear the correct pmc */
358 asm volatile(
359 "mfspr %0,%1\n\t" /* get current mccr0 */
360 "rlwinm %0,%0,0,0,31-6\n\t" /* clear bits [26-31] */
361 "ori %0,%0,%2 \n\t" /* or in mmcr0 settings */
362 "mtspr %1,%0 \n\t" /* set new mccr0 */
363 "mtspr %3,%4 \n\t" /* reset the pmc */
364 : "=r" (tmp)
365 : "i" (MMCR0), "i" (MMCR0_PMC2_ITLB),
366 "i" (PMC2), "r" (0) );
367 }
368 }
369
370 if ( !strncmp( buffer, "dc miss", 7) )
371 {
372 if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
373 /* setup mmcr0 and clear the correct pmc */
374 asm volatile(
375 "mfspr %0,%1\n\t" /* get current mccr0 */
376 "rlwinm %0,%0,0,0,31-6\n\t" /* clear bits [26-31] */
377 "ori %0,%0,%2 \n\t" /* or in mmcr0 settings */
378 "mtspr %1,%0 \n\t" /* set new mccr0 */
379 "mtspr %3,%4 \n\t" /* reset the pmc */
380 : "=r" (tmp)
381 : "i" (MMCR0), "i" (MMCR0_PMC2_DCACHEMISS),
382 "i" (PMC2), "r" (0) );
383 }
384 }
385
386
387 return count;
388
389 #if 0 /* resizing htab is a bit difficult right now -- Cort */
390 unsigned long size;
391 extern void reset_SDR1(void);
392
393 /* only know how to set size right now */
394 if ( strncmp( buffer, "size ", 5) )
395 return -EINVAL;
396
397 size = simple_strtoul( &buffer[5], NULL, 10 );
398
399 /* only allow to shrink */
400 if ( size >= Hash_size>>10 )
401 return -EINVAL;
402
403 /* minimum size of htab */
404 if ( size < 64 )
405 return -EINVAL;
406
407 /* make sure it's a multiple of 64k */
408 if ( size % 64 )
409 return -EINVAL;
410
411 printk("Hash table resize to %luk\n", size);
412 /*
413 * We need to rehash all kernel entries for the new htab size.
414 * Kernel only since we do a flush_tlb_all(). Since it's kernel
415 * we only need to bother with vsids 0-15. To avoid problems of
416 * clobbering un-rehashed values we put the htab at a new spot
417 * and put everything there.
418 * -- Cort
419 */
420 Hash_size = size<<10;
421 Hash_mask = (Hash_size >> 6) - 1;
422 _SDR1 = __pa(Hash) | (Hash_mask >> 10);
423 flush_tlb_all();
424
425 reset_SDR1();
426 #endif
427 return count;
428 #else /* CONFIG_PPC_STD_MMU */
429 return 0;
430 #endif /* CONFIG_PPC_STD_MMU */
431 }
432
433
434 static long long
ppc_htab_lseek(struct file * file,loff_t offset,int orig)435 ppc_htab_lseek(struct file * file, loff_t offset, int orig)
436 {
437 switch (orig) {
438 case 0:
439 file->f_pos = offset;
440 return(file->f_pos);
441 case 1:
442 file->f_pos += offset;
443 return(file->f_pos);
444 case 2:
445 return(-EINVAL);
446 default:
447 return(-EINVAL);
448 }
449 }
450
451 #define TMPBUFLEN 512
proc_dol2crvec(ctl_table * table,int write,struct file * filp,void * buffer,size_t * lenp)452 int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
453 void *buffer, size_t *lenp)
454 {
455 int vleft, first=1, len, left, val;
456 char buf[TMPBUFLEN], *p;
457 static const char *sizestrings[4] = {
458 "2MB", "256KB", "512KB", "1MB"
459 };
460 static const char *clockstrings[8] = {
461 "clock disabled", "+1 clock", "+1.5 clock", "+3.5 clock",
462 "+2 clock", "+2.5 clock", "+3 clock", "+4 clock"
463 };
464 static const char *typestrings[4] = {
465 "flow-through burst SRAM", "reserved SRAM",
466 "pipelined burst SRAM", "pipelined late-write SRAM"
467 };
468 static const char *holdstrings[4] = {
469 "0.5", "1.0", "(reserved2)", "(reserved3)"
470 };
471
472 if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR))
473 return -EFAULT;
474
475 if ( /*!table->maxlen ||*/ (filp->f_pos && !write)) {
476 *lenp = 0;
477 return 0;
478 }
479
480 vleft = table->maxlen / sizeof(int);
481 left = *lenp;
482
483 for (; left /*&& vleft--*/; first=0) {
484 if (write) {
485 while (left) {
486 char c;
487 if(get_user(c,(char *) buffer))
488 return -EFAULT;
489 if (!isspace(c))
490 break;
491 left--;
492 buffer++;
493 }
494 if (!left)
495 break;
496 len = left;
497 if (len > TMPBUFLEN-1)
498 len = TMPBUFLEN-1;
499 if(copy_from_user(buf, buffer, len))
500 return -EFAULT;
501 buf[len] = 0;
502 p = buf;
503 if (*p < '0' || *p > '9')
504 break;
505 val = simple_strtoul(p, &p, 0);
506 len = p-buf;
507 if ((len < left) && *p && !isspace(*p))
508 break;
509 buffer += len;
510 left -= len;
511 _set_L2CR(val);
512 } else {
513 int is750fx = cur_cpu_spec[0]->cpu_features & CPU_FTR_750FX;
514 p = buf;
515 if (!first)
516 *p++ = '\t';
517 val = _get_L2CR();
518 p += sprintf(p, "0x%08x: ", val);
519 p += sprintf(p, " L2 %s, ", (val >> 31) & 1 ? "enabled" :
520 "disabled");
521 if (!(val>>30&1))
522 p += sprintf(p, "no ");
523 if (is750fx)
524 p += sprintf(p, "ECC checkstop");
525 else
526 p += sprintf(p, "parity");
527
528 /* 75x & 74x0 have different L2CR than 745x */
529 if (!(cur_cpu_spec[0]->cpu_features &
530 CPU_FTR_SPEC7450)) {
531 if (!is750fx) {
532 p += sprintf(p, ", %s",
533 sizestrings[(val >> 28) & 3]);
534 p += sprintf(p, ", %s",
535 clockstrings[(val >> 25) & 7]);
536 p += sprintf(p, ", %s",
537 typestrings[(val >> 23) & 3]);
538 }
539 p += sprintf(p, "%s", (val>>22)&1 ?
540 ", data only" : "");
541 if (!is750fx) {
542 p += sprintf(p, "%s", (val>>20)&1 ?
543 ", ZZ enabled": "");
544 }
545 p += sprintf(p, ", %s", (val>>19)&1 ?
546 "write-through" : "copy-back");
547 p += sprintf(p, "%s", (val>>18)&1 ?
548 ", testing" : "");
549 if (!is750fx) {
550 p += sprintf(p, ", %sns hold",
551 holdstrings[(val>>16)&3]);
552 p += sprintf(p, "%s", (val>>15)&1 ?
553 ", DLL slow" : "");
554 p += sprintf(p, "%s", (val>>14)&1 ?
555 ", diff clock" :"");
556 p += sprintf(p, "%s", (val>>13)&1 ?
557 ", DLL bypass" :"");
558 } else {
559 if ((val>>11)&1)
560 p += sprintf(p, ", lock way 0");
561 if ((val>>10)&1)
562 p += sprintf(p, ", lock way 1");
563 if ((val>>9)&1)
564 p += sprintf(p, ", Snoop Hit in Locked Line Error Enabled");
565 }
566 } else { /* 745x */
567 p += sprintf(p, ", %sinstn only", (val>>20)&1 ?
568 "" : "no ");
569 p += sprintf(p, ", %sdata only", (val>>16)&1 ?
570 "" : "no ");
571 p += sprintf(p, ", %s replacement",
572 (val>>12)&1 ? "secondary" : "default");
573 }
574
575 p += sprintf(p,"\n");
576
577 len = strlen(buf);
578 if (len > left)
579 len = left;
580 if(copy_to_user(buffer, buf, len))
581 return -EFAULT;
582 left -= len;
583 buffer += len;
584 break;
585 }
586 }
587
588 if (!write && !first && left) {
589 if(put_user('\n', (char *) buffer))
590 return -EFAULT;
591 left--, buffer++;
592 }
593 if (write) {
594 p = (char *) buffer;
595 while (left) {
596 char c;
597 if(get_user(c, p++))
598 return -EFAULT;
599 if (!isspace(c))
600 break;
601 left--;
602 }
603 }
604 if (write && first)
605 return -EINVAL;
606 *lenp -= left;
607 filp->f_pos += *lenp;
608 return 0;
609 }
610
proc_dol3crvec(ctl_table * table,int write,struct file * filp,void * buffer,size_t * lenp)611 int proc_dol3crvec(ctl_table *table, int write, struct file *filp,
612 void *buffer, size_t *lenp)
613 {
614 int vleft, first=1, len, left, val;
615 char buf[TMPBUFLEN], *p;
616 static const char *clockstrings[8] = {
617 "+6 clock", "reserved(1)", "+2 clock", "+2.5 clock",
618 "+3 clock", "+3.5 clock", "+4 clock", "+5 clock"
619 };
620 static const char *clocksampstrings[4] = {
621 "2 clock", "3 clock", "4 clock", "5 clock"
622 };
623 static const char *pclocksampstrings[8] = {
624 "0 P-clock", "1 P-clock", "2 P-clock", "3 P-clock",
625 "4 P-clock", "5 P-clock", "reserved(6)", "reserved(7)"
626 };
627 static const char *typestrings[4] = {
628 "MSUG2 DDR SRAM",
629 "Pipelined synchronous late-write SRAM",
630 "Reserved", "PB2 SRAM"
631 };
632
633 if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L3CR))
634 return -EFAULT;
635 if (write)
636 return -EFAULT;
637
638 if (filp->f_pos && !write) {
639 *lenp = 0;
640 return 0;
641 }
642
643 vleft = table->maxlen / sizeof(int);
644 left = *lenp;
645
646 for (; left; first=0) {
647 p = buf;
648 if (!first)
649 *p++ = '\t';
650 val = _get_L3CR();
651 p += sprintf(p, "0x%08x: ", val);
652 p += sprintf(p, " L3 %s", (val >> 31) & 1 ? "enabled" :
653 "disabled");
654 p += sprintf(p, ", %sdata parity", (val>>30)&1 ? "" :
655 "no ");
656 p += sprintf(p, ", %saddr parity", (val>>29)&1 ? "" :
657 "no ");
658 p += sprintf(p, ", %s", (val>>28)&1 ? "2MB" : "1MB");
659 p += sprintf(p, ", clocks %s", (val>>27)&1 ? "enabled" :
660 "disabled");
661 p += sprintf(p, ", %s", clockstrings[(val >> 23) & 7]);
662 p += sprintf(p, ", %sinstn only", (val>>22)&1 ? "" :
663 "no ");
664 p += sprintf(p, ", %ssample point override",
665 (val>>18)&1 ? "" : "no ");
666 p += sprintf(p, ", %s sample point",
667 clocksampstrings[(val>>16)&3]);
668 p += sprintf(p, ", %s sample point",
669 pclocksampstrings[(val>>13)&7]);
670 p += sprintf(p, ", %s replacement", (val>>12)&1 ?
671 "secondary" : "default");
672 p += sprintf(p, ", %s", typestrings[(val >> 8) & 3]);
673 p += sprintf(p, ", %sclock cntl", (val>>7)&1 ? "" :
674 "no ");
675 p += sprintf(p, ", %sdata only", (val>>6)&1 ? "" :
676 "no ");
677 p += sprintf(p, ", private mem %s", (val>>2)&1 ?
678 "enabled" : "disabled");
679 p += sprintf(p, ", %sprivate mem", val&1 ? "2MB " :
680 "1MB ");
681 p += sprintf(p,"\n");
682
683 len = strlen(buf);
684 if (len > left)
685 len = left;
686 if(copy_to_user(buffer, buf, len))
687 return -EFAULT;
688 left -= len;
689 buffer += len;
690 break;
691 }
692
693 if (!write && !first && left) {
694 if(put_user('\n', (char *) buffer))
695 return -EFAULT;
696 left--, buffer++;
697 }
698 *lenp -= left;
699 filp->f_pos += *lenp;
700 return 0;
701 }
702