Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[linux-2.6.git] / arch / ppc / kernel / ppc_htab.c
index ad7808f..bd129d3 100644 (file)
  * 2 of the License, or (at your option) any later version.
  */
 
-#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
 #include <linux/sysctl.h>
+#include <linux/capability.h>
 #include <linux/ctype.h>
 #include <linux/threads.h>
 #include <linux/smp_lock.h>
+#include <linux/seq_file.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
 
 #include <asm/uaccess.h>
-#include <asm/bitops.h>
 #include <asm/mmu.h>
 #include <asm/residual.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/reg.h>
 
-static ssize_t ppc_htab_read(struct file * file, char __user * buf,
-                            size_t count, loff_t *ppos);
+static int ppc_htab_show(struct seq_file *m, void *v);
 static ssize_t ppc_htab_write(struct file * file, const char __user * buffer,
                              size_t count, loff_t *ppos);
-static long long ppc_htab_lseek(struct file * file, loff_t offset, int orig);
-int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
-                 void __user *buffer, size_t *lenp);
-
 extern PTE *Hash, *Hash_end;
 extern unsigned long Hash_size, Hash_mask;
 extern unsigned long _SDR1;
@@ -49,10 +46,17 @@ extern unsigned long pte_errors;
 extern unsigned int primary_pteg_full;
 extern unsigned int htab_hash_searches;
 
-struct file_operations ppc_htab_operations = {
-        .llseek =       ppc_htab_lseek,
-        .read =         ppc_htab_read,
-        .write =        ppc_htab_write,
+static int ppc_htab_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ppc_htab_show, NULL);
+}
+
+const struct file_operations ppc_htab_operations = {
+       .open           = ppc_htab_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .write          = ppc_htab_write,
+       .release        = single_release,
 };
 
 static char *pmc1_lookup(unsigned long mmcr0)
@@ -96,31 +100,25 @@ static char *pmc2_lookup(unsigned long mmcr0)
  * is _REALLY_ slow (see the nested for loops below) but nothing
  * in here should be really timing critical. -- Cort
  */
-static ssize_t ppc_htab_read(struct file * file, char __user * buf,
-                            size_t count, loff_t *ppos)
+static int ppc_htab_show(struct seq_file *m, void *v)
 {
        unsigned long mmcr0 = 0, pmc1 = 0, pmc2 = 0;
-       int n = 0;
-#if defined(CONFIG_PPC_STD_MMU) && !defined(CONFIG_PPC64BRIDGE)
+#if defined(CONFIG_PPC_STD_MMU)
        unsigned int kptes = 0, uptes = 0;
        PTE *ptr;
 #endif /* CONFIG_PPC_STD_MMU */
-       char buffer[512];
-
-       if (count < 0)
-               return -EINVAL;
 
-       if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
+       if (cpu_has_feature(CPU_FTR_604_PERF_MON)) {
                mmcr0 = mfspr(SPRN_MMCR0);
                pmc1 = mfspr(SPRN_PMC1);
                pmc2 = mfspr(SPRN_PMC2);
-               n += sprintf( buffer + n,
+               seq_printf(m,
                              "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,
+               seq_printf(m,
                              "\nPMC1\t\t: %08lx (%s)\n"
                              "PMC2\t\t: %08lx (%s)\n",
                              pmc1, pmc1_lookup(mmcr0),
@@ -129,13 +127,11 @@ static ssize_t ppc_htab_read(struct file * file, char __user * buf,
 
 #ifdef CONFIG_PPC_STD_MMU
        /* if we don't have a htab */
-       if ( Hash_size == 0 )
-       {
-               n += sprintf( buffer + n, "No Hash Table used\n");
-               goto return_string;
+       if ( Hash_size == 0 ) {
+               seq_printf(m, "No Hash Table used\n");
+               return 0;
        }
 
-#ifndef CONFIG_PPC64BRIDGE
        for (ptr = Hash; ptr < Hash_end; ptr++) {
                unsigned int mctx, vsid;
 
@@ -149,31 +145,26 @@ static ssize_t ppc_htab_read(struct file * file, char __user * buf,
                else
                        uptes++;
        }
-#endif
 
-       n += sprintf( buffer + n,
+       seq_printf(m,
                      "PTE Hash Table Information\n"
                      "Size\t\t: %luKb\n"
                      "Buckets\t\t: %lu\n"
                      "Address\t\t: %08lx\n"
                      "Entries\t\t: %lu\n"
-#ifndef CONFIG_PPC64BRIDGE
                      "User ptes\t: %u\n"
                      "Kernel ptes\t: %u\n"
                      "Percent full\t: %lu%%\n"
-#endif
                       , (unsigned long)(Hash_size>>10),
                      (Hash_size/(sizeof(PTE)*8)),
                      (unsigned long)Hash,
                      Hash_size/sizeof(PTE)
-#ifndef CONFIG_PPC64BRIDGE
                       , uptes,
                      kptes,
                      ((kptes+uptes)*100) / (Hash_size/sizeof(PTE))
-#endif
                );
 
-       n += sprintf( buffer + n,
+       seq_printf(m,
                      "Reloads\t\t: %lu\n"
                      "Preloads\t: %lu\n"
                      "Searches\t: %u\n"
@@ -181,23 +172,13 @@ static ssize_t ppc_htab_read(struct file * file, char __user * buf,
                      "Evicts\t\t: %lu\n",
                      htab_reloads, htab_preloads, htab_hash_searches,
                      primary_pteg_full, htab_evicts);
-return_string:
 #endif /* CONFIG_PPC_STD_MMU */
 
-       n += sprintf( buffer + n,
+       seq_printf(m,
                      "Non-error misses: %lu\n"
                      "Error misses\t: %lu\n",
                      pte_misses, pte_errors);
-       if (*ppos >= strlen(buffer))
-               return 0;
-       if (n > strlen(buffer) - *ppos)
-               n = strlen(buffer) - *ppos;
-       if (n > count)
-               n = count;
-       if (copy_to_user(buf, buffer + *ppos, n))
-               return -EFAULT;
-       *ppos += n;
-       return n;
+       return 0;
 }
 
 /*
@@ -210,7 +191,7 @@ static ssize_t ppc_htab_write(struct file * file, const char __user * ubuffer,
        unsigned long tmp;
        char buffer[16];
 
-       if ( current->uid != 0 )
+       if (!capable(CAP_SYS_ADMIN))
                return -EACCES;
        if (strncpy_from_user(buffer, ubuffer, 15))
                return -EFAULT;
@@ -222,7 +203,7 @@ static ssize_t ppc_htab_write(struct file * file, const char __user * ubuffer,
 
        if ( !strncmp( buffer, "reset", 5) )
        {
-               if (cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON) {
+               if (cpu_has_feature(CPU_FTR_604_PERF_MON)) {
                        /* reset PMC1 and PMC2 */
                        mtspr(SPRN_PMC1, 0);
                        mtspr(SPRN_PMC2, 0);
@@ -234,7 +215,7 @@ static ssize_t ppc_htab_write(struct file * file, const char __user * ubuffer,
        }
 
        /* Everything below here requires the performance monitor feature. */
-       if ( !cur_cpu_spec[0]->cpu_features & CPU_FTR_604_PERF_MON )
+       if (!cpu_has_feature(CPU_FTR_604_PERF_MON))
                return count;
 
        /* turn off performance monitoring */
@@ -330,28 +311,8 @@ static ssize_t ppc_htab_write(struct file * file, const char __user * ubuffer,
 #endif /* CONFIG_PPC_STD_MMU */
 }
 
-
-static long long
-ppc_htab_lseek(struct file * file, loff_t offset, int orig)
-{
-    long long ret = -EINVAL;
-
-    lock_kernel();
-    switch (orig) {
-    case 0:
-       file->f_pos = offset;
-       ret = file->f_pos;
-       break;
-    case 1:
-       file->f_pos += offset;
-       ret = file->f_pos;
-    }
-    unlock_kernel();
-    return ret;
-}
-
 int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
-                 void __user *buffer_arg, size_t *lenp)
+                 void __user *buffer_arg, size_t *lenp, loff_t *ppos)
 {
        int vleft, first=1, len, left, val;
        char __user *buffer = (char __user *) buffer_arg;
@@ -372,10 +333,10 @@ int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
                "0.5", "1.0", "(reserved2)", "(reserved3)"
        };
 
-       if (!(cur_cpu_spec[0]->cpu_features & CPU_FTR_L2CR))
+       if (!cpu_has_feature(CPU_FTR_L2CR))
                return -EFAULT;
 
-       if ( /*!table->maxlen ||*/ (filp->f_pos && !write)) {
+       if ( /*!table->maxlen ||*/ (*ppos && !write)) {
                *lenp = 0;
                return 0;
        }
@@ -448,15 +409,15 @@ int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
        }
 
        if (!write && !first && left) {
-               if(put_user('\n', (char *) buffer))
+               if(put_user('\n', (char __user *) buffer))
                        return -EFAULT;
                left--, buffer++;
        }
        if (write) {
-               p = (char *) buffer;
+               char __user *s = (char __user *) buffer;
                while (left) {
                        char c;
-                       if(get_user(c, p++))
+                       if(get_user(c, s++))
                                return -EFAULT;
                        if (!isspace(c))
                                break;
@@ -466,6 +427,35 @@ int proc_dol2crvec(ctl_table *table, int write, struct file *filp,
        if (write && first)
                return -EINVAL;
        *lenp -= left;
-       filp->f_pos += *lenp;
+       *ppos += *lenp;
+       return 0;
+}
+
+#ifdef CONFIG_SYSCTL
+/*
+ * Register our sysctl.
+ */
+static ctl_table htab_ctl_table[]={
+       {
+               .ctl_name       = KERN_PPC_L2CR,
+               .procname       = "l2cr",
+               .mode           = 0644,
+               .proc_handler   = &proc_dol2crvec,
+       },
+       { 0, },
+};
+static ctl_table htab_sysctl_root[] = {
+       { 1, "kernel", NULL, 0, 0755, htab_ctl_table, },
+       { 0,},
+};
+
+static int __init
+register_ppc_htab_sysctl(void)
+{
+       register_sysctl_table(htab_sysctl_root, 0);
+
        return 0;
 }
+
+__initcall(register_ppc_htab_sysctl);
+#endif