Revert to Fedora kernel-2.6.17-1.2187_FC5 patched with vs2.0.2.1; there are too many...
[linux-2.6.git] / arch / ia64 / kernel / palinfo.c
index 27123bb..859fb37 100644 (file)
@@ -8,11 +8,14 @@
  *
  * Copyright (C) 2000-2001, 2003 Hewlett-Packard Co
  *     Stephane Eranian <eranian@hpl.hp.com>
+ * Copyright (C) 2004 Intel Corporation
+ *  Ashok Raj <ashok.raj@intel.com>
  *
  * 05/26/2000  S.Eranian       initial release
  * 08/21/2000  S.Eranian       updated to July 2000 PAL specs
  * 02/05/2001   S.Eranian      fixed module support
  * 10/23/2001  S.Eranian       updated pal_perf_mon_info bug fixes
+ * 03/24/2004  Ashok Raj       updated to work with CPU Hotplug
  */
 #include <linux/config.h>
 #include <linux/types.h>
@@ -22,6 +25,9 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/efi.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
+#include <linux/cpumask.h>
 
 #include <asm/pal.h>
 #include <asm/sal.h>
@@ -234,7 +240,7 @@ cache_info(char *page)
                        }
                        p += sprintf(p,
                                     "%s Cache level %lu:\n"
-                                    "\tSize           : %lu bytes\n"
+                                    "\tSize           : %u bytes\n"
                                     "\tAttributes     : ",
                                     cache_types[j+cci.pcci_unified], i+1,
                                     cci.pcci_cache_size);
@@ -301,11 +307,9 @@ vm_info(char *page)
 
        if ((status = ia64_pal_vm_summary(&vm_info_1, &vm_info_2)) !=0) {
                printk(KERN_ERR "ia64_pal_vm_summary=%ld\n", status);
-               return 0;
-       }
-
+       } else {
 
-       p += sprintf(p,
+               p += sprintf(p,
                     "Physical Address Space         : %d bits\n"
                     "Virtual Address Space          : %d bits\n"
                     "Protection Key Registers(PKR)  : %d\n"
@@ -313,92 +317,99 @@ vm_info(char *page)
                     "Hash Tag ID                    : 0x%x\n"
                     "Size of RR.rid                 : %d\n",
                     vm_info_1.pal_vm_info_1_s.phys_add_size,
-                    vm_info_2.pal_vm_info_2_s.impl_va_msb+1, vm_info_1.pal_vm_info_1_s.max_pkr+1,
-                    vm_info_1.pal_vm_info_1_s.key_size, vm_info_1.pal_vm_info_1_s.hash_tag_id,
+                    vm_info_2.pal_vm_info_2_s.impl_va_msb+1,
+                    vm_info_1.pal_vm_info_1_s.max_pkr+1,
+                    vm_info_1.pal_vm_info_1_s.key_size,
+                    vm_info_1.pal_vm_info_1_s.hash_tag_id,
                     vm_info_2.pal_vm_info_2_s.rid_size);
+       }
 
-       if (ia64_pal_mem_attrib(&attrib) != 0)
-               return 0;
-
-       p += sprintf(p, "Supported memory attributes    : ");
-       sep = "";
-       for (i = 0; i < 8; i++) {
-               if (attrib & (1 << i)) {
-                       p += sprintf(p, "%s%s", sep, mem_attrib[i]);
-                       sep = ", ";
+       if (ia64_pal_mem_attrib(&attrib) == 0) {
+               p += sprintf(p, "Supported memory attributes    : ");
+               sep = "";
+               for (i = 0; i < 8; i++) {
+                       if (attrib & (1 << i)) {
+                               p += sprintf(p, "%s%s", sep, mem_attrib[i]);
+                               sep = ", ";
+                       }
                }
+               p += sprintf(p, "\n");
        }
-       p += sprintf(p, "\n");
 
        if ((status = ia64_pal_vm_page_size(&tr_pages, &vw_pages)) !=0) {
                printk(KERN_ERR "ia64_pal_vm_page_size=%ld\n", status);
-               return 0;
-       }
-
-       p += sprintf(p,
-                    "\nTLB walker                     : %simplemented\n"
-                    "Number of DTR                  : %d\n"
-                    "Number of ITR                  : %d\n"
-                    "TLB insertable page sizes      : ",
-                    vm_info_1.pal_vm_info_1_s.vw ? "" : "not ",
-                    vm_info_1.pal_vm_info_1_s.max_dtr_entry+1,
-                    vm_info_1.pal_vm_info_1_s.max_itr_entry+1);
+       } else {
 
+               p += sprintf(p,
+                            "\nTLB walker                     : %simplemented\n"
+                            "Number of DTR                  : %d\n"
+                            "Number of ITR                  : %d\n"
+                            "TLB insertable page sizes      : ",
+                            vm_info_1.pal_vm_info_1_s.vw ? "" : "not ",
+                            vm_info_1.pal_vm_info_1_s.max_dtr_entry+1,
+                            vm_info_1.pal_vm_info_1_s.max_itr_entry+1);
 
-       p = bitvector_process(p, tr_pages);
 
-       p += sprintf(p, "\nTLB purgeable page sizes       : ");
+               p = bitvector_process(p, tr_pages);
 
-       p = bitvector_process(p, vw_pages);
+               p += sprintf(p, "\nTLB purgeable page sizes       : ");
 
+               p = bitvector_process(p, vw_pages);
+       }
        if ((status=ia64_get_ptce(&ptce)) != 0) {
                printk(KERN_ERR "ia64_get_ptce=%ld\n", status);
-               return 0;
-       }
-
-       p += sprintf(p,
+       } else {
+               p += sprintf(p,
                     "\nPurge base address             : 0x%016lx\n"
                     "Purge outer loop count         : %d\n"
                     "Purge inner loop count         : %d\n"
                     "Purge outer loop stride        : %d\n"
                     "Purge inner loop stride        : %d\n",
-                    ptce.base, ptce.count[0], ptce.count[1], ptce.stride[0], ptce.stride[1]);
+                    ptce.base, ptce.count[0], ptce.count[1],
+                    ptce.stride[0], ptce.stride[1]);
 
-       p += sprintf(p,
+               p += sprintf(p,
                     "TC Levels                      : %d\n"
                     "Unique TC(s)                   : %d\n",
                     vm_info_1.pal_vm_info_1_s.num_tc_levels,
                     vm_info_1.pal_vm_info_1_s.max_unique_tcs);
 
-       for(i=0; i < vm_info_1.pal_vm_info_1_s.num_tc_levels; i++) {
-               for (j=2; j>0 ; j--) {
-                       tc_pages = 0; /* just in case */
+               for(i=0; i < vm_info_1.pal_vm_info_1_s.num_tc_levels; i++) {
+                       for (j=2; j>0 ; j--) {
+                               tc_pages = 0; /* just in case */
 
 
-                       /* even without unification, some levels may not be present */
-                       if ((status=ia64_pal_vm_info(i,j, &tc_info, &tc_pages)) != 0) {
-                               continue;
-                       }
+                               /* even without unification, some levels may not be present */
+                               if ((status=ia64_pal_vm_info(i,j, &tc_info, &tc_pages)) != 0) {
+                                       continue;
+                               }
 
-                       p += sprintf(p,
+                               p += sprintf(p,
                                     "\n%s Translation Cache Level %d:\n"
                                     "\tHash sets           : %d\n"
                                     "\tAssociativity       : %d\n"
                                     "\tNumber of entries   : %d\n"
                                     "\tFlags               : ",
-                                    cache_types[j+tc_info.tc_unified], i+1, tc_info.tc_num_sets,
-                                    tc_info.tc_associativity, tc_info.tc_num_entries);
+                                    cache_types[j+tc_info.tc_unified], i+1,
+                                    tc_info.tc_num_sets,
+                                    tc_info.tc_associativity,
+                                    tc_info.tc_num_entries);
 
-                       if (tc_info.tc_pf) p += sprintf(p, "PreferredPageSizeOptimized ");
-                       if (tc_info.tc_unified) p += sprintf(p, "Unified ");
-                       if (tc_info.tc_reduce_tr) p += sprintf(p, "TCReduction");
+                               if (tc_info.tc_pf)
+                                       p += sprintf(p, "PreferredPageSizeOptimized ");
+                               if (tc_info.tc_unified)
+                                       p += sprintf(p, "Unified ");
+                               if (tc_info.tc_reduce_tr)
+                                       p += sprintf(p, "TCReduction");
 
-                       p += sprintf(p, "\n\tSupported page sizes: ");
+                               p += sprintf(p, "\n\tSupported page sizes: ");
 
-                       p = bitvector_process(p, tc_pages);
+                               p = bitvector_process(p, tc_pages);
 
-                       /* when unified date (j=2) is enough */
-                       if (tc_info.tc_unified) break;
+                               /* when unified date (j=2) is enough */
+                               if (tc_info.tc_unified)
+                                       break;
+                       }
                }
        }
        p += sprintf(p, "\n");
@@ -434,14 +445,14 @@ register_info(char *page)
                p += sprintf(p, "\n");
        }
 
-       if (ia64_pal_rse_info(&phys_stacked, &hints) != 0) return 0;
+       if (ia64_pal_rse_info(&phys_stacked, &hints) == 0) {
 
        p += sprintf(p,
                     "RSE stacked physical registers   : %ld\n"
                     "RSE load/store hints             : %ld (%s)\n",
                     phys_stacked, hints.ph_data,
-                    hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(\?\?)");
-
+                    hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(??)");
+       }
        if (ia64_pal_debug_info(&iregs, &dregs))
                return 0;
 
@@ -473,7 +484,7 @@ static const char *proc_features[]={
        "Enable CMCI promotion",
        "Enable MCA to BINIT promotion",
        "Enable MCA promotion",
-       "Enable BEER promotion"
+       "Enable BERR promotion"
 };
 
 
@@ -509,10 +520,10 @@ static const char *bus_features[]={
        NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
        NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
        NULL, NULL, NULL, NULL,
-       "Enable Cache Line Repl. Exclusive",
        "Enable Cache Line Repl. Shared",
+       "Enable Cache Line Repl. Exclusive",
        "Disable Transaction Queuing",
-       "Disable Reponse Error Checking",
+       "Disable Response Error Checking",
        "Disable Bus Error Checking",
        "Disable Bus Requester Internal Error Signalling",
        "Disable Bus Requester Error Signalling",
@@ -637,9 +648,9 @@ frequency_info(char *page)
        if (ia64_pal_freq_ratios(&proc, &bus, &itc) != 0) return 0;
 
        p += sprintf(p,
-                    "Processor/Clock ratio   : %ld/%ld\n"
-                    "Bus/Clock ratio         : %ld/%ld\n"
-                    "ITC/Clock ratio         : %ld/%ld\n",
+                    "Processor/Clock ratio   : %d/%d\n"
+                    "Bus/Clock ratio         : %d/%d\n"
+                    "ITC/Clock ratio         : %d/%d\n",
                     proc.num, proc.den, bus.num, bus.den, itc.num, itc.den);
 
        return p - page;
@@ -768,13 +779,12 @@ static palinfo_entry_t palinfo_entries[]={
  * does not do recursion of deletion
  *
  * Notes:
- *     - first +1 accounts for the cpuN entry
- *     - second +1 account for toplevel palinfo
- *
+ *     - +1 accounts for the cpuN directory entry in /proc/pal
  */
-#define NR_PALINFO_PROC_ENTRIES        (NR_CPUS*(NR_PALINFO_ENTRIES+1)+1)
+#define NR_PALINFO_PROC_ENTRIES        (NR_CPUS*(NR_PALINFO_ENTRIES+1))
 
 static struct proc_dir_entry *palinfo_proc_entries[NR_PALINFO_PROC_ENTRIES];
+static struct proc_dir_entry *palinfo_dir;
 
 /*
  * This data structure is used to pass which cpu,function is being requested
@@ -888,47 +898,107 @@ palinfo_read_entry(char *page, char **start, off_t off, int count, int *eof, voi
        return len;
 }
 
-static int __init
-palinfo_init(void)
+static void
+create_palinfo_proc_entries(unsigned int cpu)
 {
 #      define CPUSTR   "cpu%d"
 
        pal_func_cpu_u_t f;
-       struct proc_dir_entry **pdir = palinfo_proc_entries;
-       struct proc_dir_entry *palinfo_dir, *cpu_dir;
-       int i, j;
+       struct proc_dir_entry **pdir;
+       struct proc_dir_entry *cpu_dir;
+       int j;
        char cpustr[sizeof(CPUSTR)];
 
-       printk(KERN_INFO "PAL Information Facility v%s\n", PALINFO_VERSION);
-
-       palinfo_dir = proc_mkdir("pal", NULL);
 
        /*
         * we keep track of created entries in a depth-first order for
         * cleanup purposes. Each entry is stored into palinfo_proc_entries
         */
-       for (i=0; i < NR_CPUS; i++) {
-
-               if (!cpu_online(i)) continue;
+       sprintf(cpustr,CPUSTR, cpu);
 
-               sprintf(cpustr,CPUSTR, i);
+       cpu_dir = proc_mkdir(cpustr, palinfo_dir);
 
-               cpu_dir = proc_mkdir(cpustr, palinfo_dir);
+       f.req_cpu = cpu;
 
-               f.req_cpu = i;
+       /*
+        * Compute the location to store per cpu entries
+        * We dont store the top level entry in this list, but
+        * remove it finally after removing all cpu entries.
+        */
+       pdir = &palinfo_proc_entries[cpu*(NR_PALINFO_ENTRIES+1)];
+       *pdir++ = cpu_dir;
+       for (j=0; j < NR_PALINFO_ENTRIES; j++) {
+               f.func_id = j;
+               *pdir = create_proc_read_entry(
+                               palinfo_entries[j].name, 0, cpu_dir,
+                               palinfo_read_entry, (void *)f.value);
+               if (*pdir)
+                       (*pdir)->owner = THIS_MODULE;
+               pdir++;
+       }
+}
 
-               for (j=0; j < NR_PALINFO_ENTRIES; j++) {
-                       f.func_id = j;
-                       *pdir = create_proc_read_entry(
-                                       palinfo_entries[j].name, 0, cpu_dir,
-                                       palinfo_read_entry, (void *)f.value);
-                       if (*pdir)
-                               (*pdir)->owner = THIS_MODULE;
-                       pdir++;
+static void
+remove_palinfo_proc_entries(unsigned int hcpu)
+{
+       int j;
+       struct proc_dir_entry *cpu_dir, **pdir;
+
+       pdir = &palinfo_proc_entries[hcpu*(NR_PALINFO_ENTRIES+1)];
+       cpu_dir = *pdir;
+       *pdir++=NULL;
+       for (j=0; j < (NR_PALINFO_ENTRIES); j++) {
+               if ((*pdir)) {
+                       remove_proc_entry ((*pdir)->name, cpu_dir);
+                       *pdir ++= NULL;
                }
-               *pdir++ = cpu_dir;
        }
-       *pdir = palinfo_dir;
+
+       if (cpu_dir) {
+               remove_proc_entry(cpu_dir->name, palinfo_dir);
+       }
+}
+
+static int palinfo_cpu_callback(struct notifier_block *nfb,
+                                                               unsigned long action,
+                                                               void *hcpu)
+{
+       unsigned int hotcpu = (unsigned long)hcpu;
+
+       switch (action) {
+       case CPU_ONLINE:
+               create_palinfo_proc_entries(hotcpu);
+               break;
+#ifdef CONFIG_HOTPLUG_CPU
+       case CPU_DEAD:
+               remove_palinfo_proc_entries(hotcpu);
+               break;
+#endif
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block palinfo_cpu_notifier =
+{
+       .notifier_call = palinfo_cpu_callback,
+       .priority = 0,
+};
+
+static int __init
+palinfo_init(void)
+{
+       int i = 0;
+
+       printk(KERN_INFO "PAL Information Facility v%s\n", PALINFO_VERSION);
+       palinfo_dir = proc_mkdir("pal", NULL);
+
+       /* Create palinfo dirs in /proc for all online cpus */
+       for_each_online_cpu(i) {
+               create_palinfo_proc_entries(i);
+       }
+
+       /* Register for future delivery via notify registration */
+       register_cpu_notifier(&palinfo_cpu_notifier);
 
        return 0;
 }
@@ -939,10 +1009,19 @@ palinfo_exit(void)
        int i = 0;
 
        /* remove all nodes: depth first pass. Could optimize this  */
-       for (i=0; i< NR_PALINFO_PROC_ENTRIES ; i++) {
-               if (palinfo_proc_entries[i])
-                       remove_proc_entry (palinfo_proc_entries[i]->name, NULL);
+       for_each_online_cpu(i) {
+               remove_palinfo_proc_entries(i);
        }
+
+       /*
+        * Remove the top level entry finally
+        */
+       remove_proc_entry(palinfo_dir->name, NULL);
+
+       /*
+        * Unregister from cpu notifier callbacks
+        */
+       unregister_cpu_notifier(&palinfo_cpu_notifier);
 }
 
 module_init(palinfo_init);