patch-2.1.79 linux/arch/ppc/kernel/ppc_htab.c

Next file: linux/arch/ppc/kernel/ppc_ksyms.c
Previous file: linux/arch/ppc/kernel/ppc_asm.tmpl
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.78/linux/arch/ppc/kernel/ppc_htab.c linux/arch/ppc/kernel/ppc_htab.c
@@ -1,5 +1,5 @@
 /*
- * $Id: ppc_htab.c,v 1.7 1997/08/24 19:33:32 cort Exp $
+ * $Id: ppc_htab.c,v 1.16 1997/11/17 18:25:04 cort Exp $
  *
  * PowerPC hash table management proc entry.  Will show information
  * about the current hash table and will allow changes to it.
@@ -25,16 +25,19 @@
 #include <asm/io.h>
 #include <asm/pgtable.h>
 
-static long ppc_htab_read(struct inode * inode, struct file * file,
-			   char * buf, unsigned long nbytes);
-static long ppc_htab_write(struct inode * inode, struct file * file,
-			    const char * buffer, unsigned long count);
-static long long ppc_htab_lseek(struct inode * inode, struct file * file, 
-				 long long offset, int orig);
+static ssize_t ppc_htab_read(struct file * file, char * buf,
+			     size_t count, loff_t *ppos);
+static ssize_t ppc_htab_write(struct file * file, const char * buffer,
+			      size_t count, loff_t *ppos);
+static long long ppc_htab_lseek(struct file * file, loff_t offset, int orig);
 
 extern PTE *Hash, *Hash_end;
 extern unsigned long Hash_size, Hash_mask;
 extern unsigned long _SDR1;
+extern unsigned long htab_reloads;
+extern unsigned long htab_evicts;
+extern unsigned long pte_misses;
+extern unsigned long pte_errors;
 
 static struct file_operations ppc_htab_operations = {
     ppc_htab_lseek,	/* lseek   */
@@ -72,24 +75,107 @@
     NULL	    /* permission  */
 };
 
+/* these will go into processor.h when I'm done debugging -- Cort */
+#define MMCR0 952
+#define MMCR0_PMC1_CYCLES (0x1<<7)
+#define MMCR0_PMC1_ICACHEMISS (0x5<<7)
+#define MMCR0_PMC1_DTLB (0x6<<7)
+#define MMCR0_PMC2_DCACHEMISS (0x6)
+#define MMCR0_PMC2_CYCLES (0x1)
+#define MMCR0_PMC2_ITLB (0x7)
+#define MMCR0_PMC2_LOADMISSTIME (0x5)
+
+#define PMC1 953
+#define PMC2 954
+
+char *pmc1_lookup(unsigned long mmcr0)
+{
+	switch ( mmcr0 & (0x7f<<7) )
+	{
+	case 0x0:
+		return "none";
+	case MMCR0_PMC1_CYCLES:
+		return "cycles";
+	case MMCR0_PMC1_ICACHEMISS:
+		return "ic miss";
+	case MMCR0_PMC1_DTLB:
+		return "dtlb miss";
+	default:
+		return "unknown";
+	}
+}	
+
+char *pmc2_lookup(unsigned long mmcr0)
+{
+	switch ( mmcr0 & 0x3f )
+	{
+	case 0x0:
+		return "none";
+	case MMCR0_PMC2_CYCLES:
+		return "cycles";
+	case MMCR0_PMC2_DCACHEMISS:
+		return "dc miss";
+	case MMCR0_PMC2_ITLB:
+		return "itlb miss";
+	case MMCR0_PMC2_LOADMISSTIME:
+		return "load miss time";
+	default:
+		return "unknown";
+	}
+}	
+
 
 /*
  * print some useful info about the hash table.  This function
  * is _REALLY_ slow (see the nested for loops below) but nothing
  * in here should be really timing critical. -- Cort
  */
-static long ppc_htab_read(struct inode * inode, struct file * file,
-			   char * buf, unsigned long nbytes)
+static ssize_t ppc_htab_read(struct file * file, char * buf,
+			     size_t count, loff_t *ppos)
 {
+	unsigned long mmcr0 = 0, pmc1 = 0, pmc2 = 0;
 	int n = 0, valid;
-	unsigned int kptes = 0, overflow = 0, uptes = 0;
+	unsigned int kptes = 0, overflow = 0, uptes = 0, zombie_ptes = 0;
 	PTE *ptr;
 	struct task_struct *p;
-	char buffer[128];
-	
-	if (nbytes < 0)
+	char buffer[512];
+
+	if (count < 0)
 		return -EINVAL;
 
+	switch ( _get_PVR()>>16 )
+	{
+	case 4:  /* 604 */
+	case 9:  /* 604e */
+	case 10: /* 604ev5 */
+		asm volatile ("mfspr %0,952 \n\t"
+		    "mfspr %1,953 \n\t"
+		    "mfspr %2,954 \n\t"
+		    : "=r" (mmcr0), "=r" (pmc1), "=r" (pmc2) );
+		n += sprintf( buffer + n,
+			      "604 Performance Monitoring\n"
+			      "MMCR0\t\t: %08lx %s%s ",
+			      mmcr0,
+			      ( mmcr0>>28 & 0x2 ) ? "(user mode counted)" : "",
+			      ( mmcr0>>28 & 0x4 ) ? "(kernel mode counted)" : "");
+		n += sprintf( buffer + n,
+			      "\nPMC1\t\t: %08lx (%s)\n"
+			      "PMC2\t\t: %08lx (%s)\n",
+			      pmc1, pmc1_lookup(mmcr0),
+			      pmc2, pmc2_lookup(mmcr0));
+		break;
+	default:
+		break;
+	}
+
+	
+	/* if we don't have a htab */
+	if ( Hash_size == 0 )
+	{
+		n += sprintf( buffer + n, "No Hash Table used\n");
+		goto return_string;
+	}
+	
 	/*
 	 * compute user/kernel pte's table this info can be
 	 * misleading since there can be valid (v bit set) entries
@@ -97,11 +183,12 @@
 	 * due to the way tlb invalidation is handled on the ppc
 	 * -- Cort
 	 */
-	for ( ptr = Hash ; ptr < Hash_end ; ptr += sizeof(PTE))
+	for ( ptr = Hash ; ptr < Hash_end ; ptr++)
 	{
 		if (ptr->v)
 		{
 			/* make sure someone is using this context/vsid */
+			valid = 0;
 			for_each_task(p)
 			{
 				if ( (ptr->vsid >> 4) == p->mm->context )
@@ -111,7 +198,10 @@
 				}
 			}
 			if ( !valid )
+			{
+				zombie_ptes++;
 				continue;
+			}
 			/* user not allowed read or write */
 			if (ptr->pp == PP_RWXX)
 				kptes++;
@@ -122,7 +212,8 @@
 		}
 	}
 	
-	n += sprintf( buffer,
+	n += sprintf( buffer + n,
+		      "PTE Hash Table Information\n"
 		      "Size\t\t: %luKb\n"
 		      "Buckets\t\t: %lu\n"
  		      "Address\t\t: %08lx\n"
@@ -130,6 +221,7 @@
 		      "User ptes\t: %u\n"
 		      "Kernel ptes\t: %u\n"
 		      "Overflows\t: %u\n"
+		      "Zombies\t\t: %u\n"
 		      "Percent full\t: %%%lu\n",
                       (unsigned long)(Hash_size>>10),
 		      (Hash_size/(sizeof(PTE)*8)),
@@ -138,30 +230,233 @@
                       uptes,
 		      kptes,
 		      overflow,
+		      zombie_ptes,
 		      ((kptes+uptes)*100) / (Hash_size/sizeof(PTE))
 		);
 
-	if (file->f_pos >= strlen(buffer))
+	n += sprintf( buffer + n,
+		      "Reloads\t\t: %08lx\n"
+		      "Evicts\t\t: %08lx\n"
+		      "Non-error misses: %08lx\n"
+		      "Error misses\t: %08lx\n",
+		      htab_reloads, htab_evicts, pte_misses, pte_errors);
+	
+return_string:
+	if (*ppos >= strlen(buffer))
 		return 0;
-	if (n > strlen(buffer) - file->f_pos)
-		n = strlen(buffer) - file->f_pos;
-	copy_to_user(buf, buffer + file->f_pos, n);
-	file->f_pos += n;
+	if (n > strlen(buffer) - *ppos)
+		n = strlen(buffer) - *ppos;
+	copy_to_user(buf, buffer + *ppos, n);
+	*ppos += n;
 	return n;
 }
 
 /*
- * Can't _yet_ adjust the hash table size while running. -- Cort
+ * Allow user to define performance counters and resize the hash table
  */
-static long
-ppc_htab_write(struct inode * inode, struct file * file,
-		const char * buffer, unsigned long count)
+static ssize_t ppc_htab_write(struct file * file, const char * buffer,
+			      size_t count, loff_t *ppos)
 {
-	unsigned long size;
-	extern void reset_SDR1(void);
-	
+	unsigned long tmp;
 	if ( current->uid != 0 )
 		return -EACCES;
+	/* don't set the htab size for now */
+	if ( !strncmp( buffer, "size ", 5) )
+		return -EBUSY;
+
+	/* turn off performance monitoring */
+	if ( !strncmp( buffer, "off", 3) )
+	{
+		switch ( _get_PVR()>>16 )
+		{
+		case 4:  /* 604 */
+		case 9:  /* 604e */
+		case 10: /* 604ev5 */
+			asm volatile ("mtspr %0, %3 \n\t"
+			    "mtspr %1, %3 \n\t"
+			    "mtspr %2, %3 \n\t"			    
+			    :: "i" (MMCR0), "i" (PMC1), "i" (PMC2), "r" (0));
+			break;
+		default:
+			break;
+		}
+			
+	}
+
+	if ( !strncmp( buffer, "reset", 5) )
+	{
+		switch ( _get_PVR()>>16 )
+		{
+		case 4:  /* 604 */
+		case 9:  /* 604e */
+		case 10: /* 604ev5 */
+			/* reset PMC1 and PMC2 */
+			asm volatile (
+				"mtspr 953, %0 \n\t"
+				"mtspr 954, %0 \n\t"
+				:: "r" (0));
+			break;
+		default:
+			break;
+		}
+		htab_reloads = 0;
+		htab_evicts = 0;
+		pte_misses = 0;
+		pte_errors = 0;
+	}
+
+	if ( !strncmp( buffer, "user", 4) )
+	{
+		switch ( _get_PVR()>>16 )
+		{
+		case 4:  /* 604 */
+		case 9:  /* 604e */
+		case 10: /* 604ev5 */
+			/* setup mmcr0 and clear the correct pmc */
+			asm("mfspr %0,%1\n\t"  : "=r" (tmp) : "i" (MMCR0));
+			tmp &= ~(0x60000000);
+			tmp |= 0x20000000;
+			asm volatile (
+				"mtspr %1,%0 \n\t"    /* set new mccr0 */
+				"mtspr %3,%4 \n\t"    /* reset the pmc */
+				"mtspr %5,%4 \n\t"    /* reset the pmc2 */
+				:: "r" (tmp), "i" (MMCR0), "i" (0),
+				"i" (PMC1),  "r" (0), "i"(PMC2) );
+			break;
+		default:
+			break;
+		}
+	}
+
+	if ( !strncmp( buffer, "kernel", 6) )
+	{
+		switch ( _get_PVR()>>16 )
+		{
+		case 4:  /* 604 */
+		case 9:  /* 604e */
+		case 10: /* 604ev5 */
+			/* setup mmcr0 and clear the correct pmc */
+			asm("mfspr %0,%1\n\t"  : "=r" (tmp) : "i" (MMCR0));
+			tmp &= ~(0x60000000);
+			tmp |= 0x40000000;
+			asm volatile (
+				"mtspr %1,%0 \n\t"    /* set new mccr0 */
+				"mtspr %3,%4 \n\t"    /* reset the pmc */
+				"mtspr %5,%4 \n\t"    /* reset the pmc2 */
+				:: "r" (tmp), "i" (MMCR0), "i" (0),
+				"i" (PMC1),  "r" (0), "i"(PMC2) );
+			break;
+		default:
+			break;
+		}
+	}
+	
+	/* PMC1 values */
+	if ( !strncmp( buffer, "dtlb", 4) )
+	{
+		switch ( _get_PVR()>>16 )
+		{
+		case 4:  /* 604 */
+		case 9:  /* 604e */
+		case 10: /* 604ev5 */
+			/* setup mmcr0 and clear the correct pmc */
+			asm("mfspr %0,%1\n\t"  : "=r" (tmp) : "i" (MMCR0));
+			tmp &= ~(0x7f<<7);
+			tmp |= MMCR0_PMC1_DTLB;
+			asm volatile (
+				"mtspr %1,%0 \n\t"    /* set new mccr0 */
+				"mtspr %3,%4 \n\t"    /* reset the pmc */
+				:: "r" (tmp), "i" (MMCR0), "i" (MMCR0_PMC1_DTLB),
+				"i" (PMC1),  "r" (0) );
+		}
+	}	
+
+	if ( !strncmp( buffer, "ic miss", 7) )
+	{
+		switch ( _get_PVR()>>16 )
+		{
+		case 4:  /* 604 */
+		case 9:  /* 604e */
+		case 10: /* 604ev5 */
+			/* setup mmcr0 and clear the correct pmc */
+			asm("mfspr %0,%1\n\t"  : "=r" (tmp) : "i" (MMCR0));
+			tmp &= ~(0x7f<<7);
+			tmp |= MMCR0_PMC1_ICACHEMISS;
+			asm volatile (
+				"mtspr %1,%0 \n\t"    /* set new mccr0 */
+				"mtspr %3,%4 \n\t"    /* reset the pmc */
+				:: "r" (tmp), "i" (MMCR0),
+				"i" (MMCR0_PMC1_ICACHEMISS), "i" (PMC1),  "r" (0));
+		}
+	}	
+
+	/* PMC2 values */
+	if ( !strncmp( buffer, "load miss time", 14) )
+	{
+		switch ( _get_PVR()>>16 )
+		{
+		case 4:  /* 604 */
+		case 9:  /* 604e */
+		case 10: /* 604ev5 */
+			/* setup mmcr0 and clear the correct pmc */
+		       asm volatile(
+			       "mfspr %0,%1\n\t"     /* get current mccr0 */
+			       "rlwinm %0,%0,0,0,31-6\n\t"  /* clear bits [26-31] */
+			       "ori   %0,%0,%2 \n\t" /* or in mmcr0 settings */
+			       "mtspr %1,%0 \n\t"    /* set new mccr0 */
+			       "mtspr %3,%4 \n\t"    /* reset the pmc */
+			       : "=r" (tmp)
+			       : "i" (MMCR0), "i" (MMCR0_PMC2_LOADMISSTIME),
+			       "i" (PMC2),  "r" (0) );
+		}
+	}
+	
+	if ( !strncmp( buffer, "itlb", 4) )
+	{
+		switch ( _get_PVR()>>16 )
+		{
+		case 4:  /* 604 */
+		case 9:  /* 604e */
+		case 10: /* 604ev5 */
+			/* setup mmcr0 and clear the correct pmc */
+		       asm volatile(
+			       "mfspr %0,%1\n\t"     /* get current mccr0 */
+			       "rlwinm %0,%0,0,0,31-6\n\t"  /* clear bits [26-31] */
+			       "ori   %0,%0,%2 \n\t" /* or in mmcr0 settings */
+			       "mtspr %1,%0 \n\t"    /* set new mccr0 */
+			       "mtspr %3,%4 \n\t"    /* reset the pmc */
+			       : "=r" (tmp)
+			       : "i" (MMCR0), "i" (MMCR0_PMC2_ITLB),
+			       "i" (PMC2),  "r" (0) );
+		}
+	}
+
+	if ( !strncmp( buffer, "dc miss", 7) )
+	{
+		switch ( _get_PVR()>>16 )
+		{
+		case 4:  /* 604 */
+		case 9:  /* 604e */
+		case 10: /* 604ev5 */
+			/* setup mmcr0 and clear the correct pmc */
+		       asm volatile(
+			       "mfspr %0,%1\n\t"     /* get current mccr0 */
+			       "rlwinm %0,%0,0,0,31-6\n\t"  /* clear bits [26-31] */
+			       "ori   %0,%0,%2 \n\t" /* or in mmcr0 settings */
+			       "mtspr %1,%0 \n\t"    /* set new mccr0 */
+			       "mtspr %3,%4 \n\t"    /* reset the pmc */
+			       : "=r" (tmp)
+			       : "i" (MMCR0), "i" (MMCR0_PMC2_DCACHEMISS),
+			       "i" (PMC2),  "r" (0) );
+		}
+	}	
+	
+
+	return count;
+	
+#if 0 /* resizing htab is a bit difficult right now -- Cort */
+	unsigned long size;
+	extern void reset_SDR1(void);
 	
 	/* only know how to set size right now */
 	if ( strncmp( buffer, "size ", 5) )
@@ -196,14 +491,13 @@
 	flush_tlb_all();
 
 	reset_SDR1();
-	printk("done\n");
+#endif	
 	return count;
 }
 
 
 static long long
-ppc_htab_lseek(struct inode * inode, struct file * file, 
-				 long long offset, int orig)
+ppc_htab_lseek(struct file * file, loff_t offset, int orig)
 {
     switch (orig) {
     case 0:

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov