ppc_htab.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:15k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * BK Id: SCCS/s.ppc_htab.c 1.19 10/16/01 15:58:42 trini
  3.  */
  4. /*
  5.  * PowerPC hash table management proc entry.  Will show information
  6.  * about the current hash table and will allow changes to it.
  7.  *
  8.  * Written by Cort Dougan (cort@cs.nmt.edu)
  9.  *
  10.  * This program is free software; you can redistribute it and/or
  11.  * modify it under the terms of the GNU General Public License
  12.  * as published by the Free Software Foundation; either version
  13.  * 2 of the License, or (at your option) any later version.
  14.  */
  15. #include <linux/config.h>
  16. #include <linux/errno.h>
  17. #include <linux/sched.h>
  18. #include <linux/proc_fs.h>
  19. #include <linux/stat.h>
  20. #include <linux/sysctl.h>
  21. #include <linux/ctype.h>
  22. #include <linux/threads.h>
  23. #include <asm/uaccess.h>
  24. #include <asm/bitops.h>
  25. #include <asm/mmu.h>
  26. #include <asm/processor.h>
  27. #include <asm/residual.h>
  28. #include <asm/io.h>
  29. #include <asm/pgtable.h>
  30. #include <asm/cputable.h>
  31. #include <asm/system.h>
  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. extern PTE *Hash, *Hash_end;
  40. extern unsigned long Hash_size, Hash_mask;
  41. extern unsigned long _SDR1;
  42. extern unsigned long htab_reloads;
  43. extern unsigned long htab_preloads;
  44. extern unsigned long htab_evicts;
  45. extern unsigned long pte_misses;
  46. extern unsigned long pte_errors;
  47. extern unsigned int primary_pteg_full;
  48. extern unsigned int htab_hash_searches;
  49. /* these will go into processor.h when I'm done debugging -- Cort */
  50. #define MMCR0 952
  51. #define MMCR0_PMC1_CYCLES (0x1<<7)
  52. #define MMCR0_PMC1_ICACHEMISS (0x5<<7)
  53. #define MMCR0_PMC1_DTLB (0x6<<7)
  54. #define MMCR0_PMC2_DCACHEMISS (0x6)
  55. #define MMCR0_PMC2_CYCLES (0x1)
  56. #define MMCR0_PMC2_ITLB (0x7)
  57. #define MMCR0_PMC2_LOADMISSTIME (0x5)
  58. #define PMC1 953
  59. #define PMC2 954
  60. struct file_operations ppc_htab_operations = {
  61.         llseek:         ppc_htab_lseek,
  62.         read:           ppc_htab_read,
  63.         write:          ppc_htab_write,
  64. };
  65. static char *pmc1_lookup(unsigned long mmcr0)
  66. {
  67. switch ( mmcr0 & (0x7f<<7) )
  68. {
  69. case 0x0:
  70. return "none";
  71. case MMCR0_PMC1_CYCLES:
  72. return "cycles";
  73. case MMCR0_PMC1_ICACHEMISS:
  74. return "ic miss";
  75. case MMCR0_PMC1_DTLB:
  76. return "dtlb miss";
  77. default:
  78. return "unknown";
  79. }
  80. }
  81. static char *pmc2_lookup(unsigned long mmcr0)
  82. {
  83. switch ( mmcr0 & 0x3f )
  84. {
  85. case 0x0:
  86. return "none";
  87. case MMCR0_PMC2_CYCLES:
  88. return "cycles";
  89. case MMCR0_PMC2_DCACHEMISS:
  90. return "dc miss";
  91. case MMCR0_PMC2_ITLB:
  92. return "itlb miss";
  93. case MMCR0_PMC2_LOADMISSTIME:
  94. return "load miss time";
  95. default:
  96. return "unknown";
  97. }
  98. }
  99. /*
  100.  * print some useful info about the hash table.  This function
  101.  * is _REALLY_ slow (see the nested for loops below) but nothing
  102.  * in here should be really timing critical. -- Cort
  103.  */
  104. static ssize_t ppc_htab_read(struct file * file, char * buf,
  105.      size_t count, loff_t *ppos)
  106. {
  107. unsigned long mmcr0 = 0, pmc1 = 0, pmc2 = 0;
  108. int n = 0;
  109. #ifdef CONFIG_PPC_STD_MMU
  110. int valid;
  111. unsigned int kptes = 0, uptes = 0, zombie_ptes = 0;
  112. PTE *ptr;
  113. struct task_struct *p;
  114. #endif /* CONFIG_PPC_STD_MMU */
  115. char buffer[512];
  116. if (count < 0)
  117. return -EINVAL;
  118. if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
  119. asm volatile ("mfspr %0,952 nt"
  120.     "mfspr %1,953 nt"
  121.     "mfspr %2,954 nt"
  122.     : "=r" (mmcr0), "=r" (pmc1), "=r" (pmc2) );
  123. n += sprintf( buffer + n,
  124.       "604 Performance Monitoringn"
  125.       "MMCR0tt: %08lx %s%s ",
  126.       mmcr0,
  127.       ( mmcr0>>28 & 0x2 ) ? "(user mode counted)" : "",
  128.       ( mmcr0>>28 & 0x4 ) ? "(kernel mode counted)" : "");
  129. n += sprintf( buffer + n,
  130.       "nPMC1tt: %08lx (%s)n"
  131.       "PMC2tt: %08lx (%s)n",
  132.       pmc1, pmc1_lookup(mmcr0),
  133.       pmc2, pmc2_lookup(mmcr0));
  134. }
  135. #ifdef CONFIG_PPC_STD_MMU
  136. /* if we don't have a htab */
  137. if ( Hash_size == 0 )
  138. {
  139. n += sprintf( buffer + n, "No Hash Table usedn");
  140. goto return_string;
  141. }
  142. for ( ptr = Hash ; ptr < Hash_end ; ptr++)
  143. {
  144. unsigned int ctx, mctx, vsid;
  145. if (!ptr->v)
  146. continue;
  147. /* make sure someone is using this context/vsid */
  148. /* first undo the esid skew */
  149. vsid = ptr->vsid;
  150. mctx = ((vsid - (vsid & 0xf) * 0x111) >> 4) & 0xfffff;
  151. if (mctx == 0) {
  152. kptes++;
  153. continue;
  154. }
  155. /* now undo the context skew; 801921 * 897 == 1 mod 2^20 */
  156. ctx = (mctx * 801921) & 0xfffff;
  157. valid = 0;
  158. for_each_task(p) {
  159. if (p->mm != NULL && ctx == p->mm->context) {
  160. valid = 1;
  161. uptes++;
  162. break;
  163. }
  164. }
  165. if (!valid)
  166. zombie_ptes++;
  167. }
  168. n += sprintf( buffer + n,
  169.       "PTE Hash Table Informationn"
  170.       "Sizett: %luKbn"
  171.       "Bucketstt: %lun"
  172.         "Addresstt: %08lxn"
  173.       "Entriestt: %lun"
  174.       "User ptest: %un"
  175.       "Kernel ptest: %un"
  176.       "Zombiestt: %un"
  177.       "Percent fullt: %lu%%n",
  178.                       (unsigned long)(Hash_size>>10),
  179.       (Hash_size/(sizeof(PTE)*8)),
  180.       (unsigned long)Hash,
  181.       Hash_size/sizeof(PTE),
  182.                       uptes,
  183.       kptes,
  184.       zombie_ptes,
  185.       ((kptes+uptes)*100) / (Hash_size/sizeof(PTE))
  186. );
  187. n += sprintf( buffer + n,
  188.       "Reloadstt: %lun"
  189.       "Preloadst: %lun"
  190.       "Searchest: %un"
  191.       "Overflowst: %un"
  192.       "Evictstt: %lun",
  193.       htab_reloads, htab_preloads, htab_hash_searches,
  194.       primary_pteg_full, htab_evicts);
  195. return_string:
  196. #endif /* CONFIG_PPC_STD_MMU */
  197. n += sprintf( buffer + n,
  198.       "Non-error misses: %lun"
  199.       "Error missest: %lun",
  200.       pte_misses, pte_errors);
  201. if (*ppos >= strlen(buffer))
  202. return 0;
  203. if (n > strlen(buffer) - *ppos)
  204. n = strlen(buffer) - *ppos;
  205. if (n > count)
  206. n = count;
  207. copy_to_user(buf, buffer + *ppos, n);
  208. *ppos += n;
  209. return n;
  210. }
  211. /*
  212.  * Allow user to define performance counters and resize the hash table
  213.  */
  214. static ssize_t ppc_htab_write(struct file * file, const char * buffer,
  215.       size_t count, loff_t *ppos)
  216. {
  217. #ifdef CONFIG_PPC_STD_MMU
  218. unsigned long tmp;
  219. if ( current->uid != 0 )
  220. return -EACCES;
  221. /* don't set the htab size for now */
  222. if ( !strncmp( buffer, "size ", 5) )
  223. return -EBUSY;
  224. /* turn off performance monitoring */
  225. if ( !strncmp( buffer, "off", 3) )
  226. {
  227. if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
  228. asm volatile ("mtspr %0, %3 nt"
  229.     "mtspr %1, %3 nt"
  230.     "mtspr %2, %3 nt"     
  231.     :: "i" (MMCR0), "i" (PMC1), "i" (PMC2), "r" (0));
  232. }
  233. }
  234. if ( !strncmp( buffer, "reset", 5) )
  235. {
  236. if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
  237. /* reset PMC1 and PMC2 */
  238. asm volatile (
  239. "mtspr 953, %0 nt"
  240. "mtspr 954, %0 nt"
  241. :: "r" (0));
  242. }
  243. htab_reloads = 0;
  244. htab_evicts = 0;
  245. pte_misses = 0;
  246. pte_errors = 0;
  247. }
  248. if ( !strncmp( buffer, "user", 4) )
  249. {
  250. if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
  251. /* setup mmcr0 and clear the correct pmc */
  252. asm("mfspr %0,%1nt"  : "=r" (tmp) : "i" (MMCR0));
  253. tmp &= ~(0x60000000);
  254. tmp |= 0x20000000;
  255. asm volatile (
  256. "mtspr %1,%0 nt"    /* set new mccr0 */
  257. "mtspr %3,%4 nt"    /* reset the pmc */
  258. "mtspr %5,%4 nt"    /* reset the pmc2 */
  259. :: "r" (tmp), "i" (MMCR0), "i" (0),
  260. "i" (PMC1),  "r" (0), "i"(PMC2) );
  261. }
  262. }
  263. if ( !strncmp( buffer, "kernel", 6) )
  264. {
  265. if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
  266. /* setup mmcr0 and clear the correct pmc */
  267. asm("mfspr %0,%1nt"  : "=r" (tmp) : "i" (MMCR0));
  268. tmp &= ~(0x60000000);
  269. tmp |= 0x40000000;
  270. asm volatile (
  271. "mtspr %1,%0 nt"    /* set new mccr0 */
  272. "mtspr %3,%4 nt"    /* reset the pmc */
  273. "mtspr %5,%4 nt"    /* reset the pmc2 */
  274. :: "r" (tmp), "i" (MMCR0), "i" (0),
  275. "i" (PMC1),  "r" (0), "i"(PMC2) );
  276. }
  277. }
  278. /* PMC1 values */
  279. if ( !strncmp( buffer, "dtlb", 4) )
  280. {
  281. if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
  282. /* setup mmcr0 and clear the correct pmc */
  283. asm("mfspr %0,%1nt"  : "=r" (tmp) : "i" (MMCR0));
  284. tmp &= ~(0x7f<<7);
  285. tmp |= MMCR0_PMC1_DTLB;
  286. asm volatile (
  287. "mtspr %1,%0 nt"    /* set new mccr0 */
  288. "mtspr %3,%4 nt"    /* reset the pmc */
  289. :: "r" (tmp), "i" (MMCR0), "i" (MMCR0_PMC1_DTLB),
  290. "i" (PMC1),  "r" (0) );
  291. }
  292. }
  293. if ( !strncmp( buffer, "ic miss", 7) )
  294. {
  295. if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
  296. /* setup mmcr0 and clear the correct pmc */
  297. asm("mfspr %0,%1nt"  : "=r" (tmp) : "i" (MMCR0));
  298. tmp &= ~(0x7f<<7);
  299. tmp |= MMCR0_PMC1_ICACHEMISS;
  300. asm volatile (
  301. "mtspr %1,%0 nt"    /* set new mccr0 */
  302. "mtspr %3,%4 nt"    /* reset the pmc */
  303. :: "r" (tmp), "i" (MMCR0),
  304. "i" (MMCR0_PMC1_ICACHEMISS), "i" (PMC1),  "r" (0));
  305. }
  306. }
  307. /* PMC2 values */
  308. if ( !strncmp( buffer, "load miss time", 14) )
  309. {
  310. if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
  311. /* setup mmcr0 and clear the correct pmc */
  312.        asm volatile(
  313.        "mfspr %0,%1nt"     /* get current mccr0 */
  314.        "rlwinm %0,%0,0,0,31-6nt"  /* clear bits [26-31] */
  315.        "ori   %0,%0,%2 nt" /* or in mmcr0 settings */
  316.        "mtspr %1,%0 nt"    /* set new mccr0 */
  317.        "mtspr %3,%4 nt"    /* reset the pmc */
  318.        : "=r" (tmp)
  319.        : "i" (MMCR0), "i" (MMCR0_PMC2_LOADMISSTIME),
  320.        "i" (PMC2),  "r" (0) );
  321. }
  322. }
  323. if ( !strncmp( buffer, "itlb", 4) )
  324. {
  325. if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
  326. /* setup mmcr0 and clear the correct pmc */
  327.        asm volatile(
  328.        "mfspr %0,%1nt"     /* get current mccr0 */
  329.        "rlwinm %0,%0,0,0,31-6nt"  /* clear bits [26-31] */
  330.        "ori   %0,%0,%2 nt" /* or in mmcr0 settings */
  331.        "mtspr %1,%0 nt"    /* set new mccr0 */
  332.        "mtspr %3,%4 nt"    /* reset the pmc */
  333.        : "=r" (tmp)
  334.        : "i" (MMCR0), "i" (MMCR0_PMC2_ITLB),
  335.        "i" (PMC2),  "r" (0) );
  336. }
  337. }
  338. if ( !strncmp( buffer, "dc miss", 7) )
  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,%1nt"     /* get current mccr0 */
  344.        "rlwinm %0,%0,0,0,31-6nt"  /* clear bits [26-31] */
  345.        "ori   %0,%0,%2 nt" /* or in mmcr0 settings */
  346.        "mtspr %1,%0 nt"    /* set new mccr0 */
  347.        "mtspr %3,%4 nt"    /* reset the pmc */
  348.        : "=r" (tmp)
  349.        : "i" (MMCR0), "i" (MMCR0_PMC2_DCACHEMISS),
  350.        "i" (PMC2),  "r" (0) );
  351. }
  352. }
  353. return count;
  354. #if 0 /* resizing htab is a bit difficult right now -- Cort */
  355. unsigned long size;
  356. extern void reset_SDR1(void);
  357. /* only know how to set size right now */
  358. if ( strncmp( buffer, "size ", 5) )
  359. return -EINVAL;
  360. size = simple_strtoul( &buffer[5], NULL, 10 );
  361. /* only allow to shrink */
  362. if ( size >= Hash_size>>10 )
  363. return -EINVAL;
  364. /* minimum size of htab */
  365. if ( size < 64 )
  366. return -EINVAL;
  367. /* make sure it's a multiple of 64k */
  368. if ( size % 64 )
  369. return -EINVAL;
  370. printk("Hash table resize to %lukn", size);
  371. /*
  372.  * We need to rehash all kernel entries for the new htab size.
  373.  * Kernel only since we do a flush_tlb_all().  Since it's kernel
  374.  * we only need to bother with vsids 0-15.  To avoid problems of
  375.  * clobbering un-rehashed values we put the htab at a new spot
  376.  * and put everything there.
  377.  * -- Cort
  378.  */
  379. Hash_size = size<<10;
  380. Hash_mask = (Hash_size >> 6) - 1;
  381.         _SDR1 = __pa(Hash) | (Hash_mask >> 10);
  382. flush_tlb_all();
  383. reset_SDR1();
  384. #endif
  385. return count;
  386. #else /* CONFIG_PPC_STD_MMU */
  387. return 0;
  388. #endif /* CONFIG_PPC_STD_MMU */
  389. }
  390. static long long
  391. ppc_htab_lseek(struct file * file, loff_t offset, int orig)
  392. {
  393.     switch (orig) {
  394.     case 0:
  395. file->f_pos = offset;
  396. return(file->f_pos);
  397.     case 1:
  398. file->f_pos += offset;
  399. return(file->f_pos);
  400.     case 2:
  401. return(-EINVAL);
  402.     default:
  403. return(-EINVAL);
  404.     }
  405. }
  406. int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
  407.   void *buffer, size_t *lenp)
  408. {
  409. int vleft, first=1, len, left, val;
  410. #define TMPBUFLEN 256
  411. char buf[TMPBUFLEN], *p;
  412. static const char *sizestrings[4] = {
  413. "2MB", "256KB", "512KB", "1MB"
  414. };
  415. static const char *clockstrings[8] = {
  416. "clock disabled", "+1 clock", "+1.5 clock", "reserved(3)",
  417. "+2 clock", "+2.5 clock", "+3 clock", "reserved(7)"
  418. };
  419. static const char *typestrings[4] = {
  420. "flow-through burst SRAM", "reserved SRAM",
  421. "pipelined burst SRAM", "pipelined late-write SRAM"
  422. };
  423. static const char *holdstrings[4] = {
  424. "0.5", "1.0", "(reserved2)", "(reserved3)"
  425. };
  426. if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR))
  427. return -EFAULT;
  428. if ( /*!table->maxlen ||*/ (filp->f_pos && !write)) {
  429. *lenp = 0;
  430. return 0;
  431. }
  432. vleft = table->maxlen / sizeof(int);
  433. left = *lenp;
  434. for (; left /*&& vleft--*/; first=0) {
  435. if (write) {
  436. while (left) {
  437. char c;
  438. if(get_user(c,(char *) buffer))
  439. return -EFAULT;
  440. if (!isspace(c))
  441. break;
  442. left--;
  443. ((char *) buffer)++;
  444. }
  445. if (!left)
  446. break;
  447. len = left;
  448. if (len > TMPBUFLEN-1)
  449. len = TMPBUFLEN-1;
  450. if(copy_from_user(buf, buffer, len))
  451. return -EFAULT;
  452. buf[len] = 0;
  453. p = buf;
  454. if (*p < '0' || *p > '9')
  455. break;
  456. val = simple_strtoul(p, &p, 0);
  457. len = p-buf;
  458. if ((len < left) && *p && !isspace(*p))
  459. break;
  460. buffer += len;
  461. left -= len;
  462. _set_L2CR(val);
  463. } else {
  464. p = buf;
  465. if (!first)
  466. *p++ = 't';
  467. val = _get_L2CR();
  468. p += sprintf(p, "0x%08x: ", val);
  469. p += sprintf(p, " %s", (val >> 31) & 1 ? "enabled" :
  470.       "disabled");
  471. p += sprintf(p, ", %sparity", (val>>30)&1 ? "" : "no ");
  472. p += sprintf(p, ", %s", sizestrings[(val >> 28) & 3]);
  473. p += sprintf(p, ", %s", clockstrings[(val >> 25) & 7]);
  474. p += sprintf(p, ", %s", typestrings[(val >> 23) & 2]);
  475. p += sprintf(p, "%s", (val>>22)&1 ? ", data only" : "");
  476. p += sprintf(p, "%s", (val>>20)&1 ? ", ZZ enabled": "");
  477. p += sprintf(p, ", %s", (val>>19)&1 ? "write-through" :
  478. "copy-back");
  479. p += sprintf(p, "%s", (val>>18)&1 ? ", testing" : "");
  480. p += sprintf(p, ", %sns hold",holdstrings[(val>>16)&3]);
  481. p += sprintf(p, "%s", (val>>15)&1 ? ", DLL slow" : "");
  482. p += sprintf(p, "%s", (val>>14)&1 ? ", diff clock" :"");
  483. p += sprintf(p, "%s", (val>>13)&1 ? ", DLL bypass" :"");
  484. p += sprintf(p,"n");
  485. len = strlen(buf);
  486. if (len > left)
  487. len = left;
  488. if(copy_to_user(buffer, buf, len))
  489. return -EFAULT;
  490. left -= len;
  491. buffer += len;
  492. break;
  493. }
  494. }
  495. if (!write && !first && left) {
  496. if(put_user('n', (char *) buffer))
  497. return -EFAULT;
  498. left--, buffer++;
  499. }
  500. if (write) {
  501. p = (char *) buffer;
  502. while (left) {
  503. char c;
  504. if(get_user(c, p++))
  505. return -EFAULT;
  506. if (!isspace(c))
  507. break;
  508. left--;
  509. }
  510. }
  511. if (write && first)
  512. return -EINVAL;
  513. *lenp -= left;
  514. filp->f_pos += *lenp;
  515. return 0;
  516. }