linux/arch/ia64/sn/kernel/sn2/prominfo_proc.c
<<
>>
Prefs
   1/*
   2 * This file is subject to the terms and conditions of the GNU General Public
   3 * License.  See the file "COPYING" in the main directory of this archive
   4 * for more details.
   5 *
   6 * Copyright (C) 1999,2001-2004, 2006 Silicon Graphics, Inc.  All Rights Reserved.
   7 *
   8 * Module to export the system's Firmware Interface Tables, including
   9 * PROM revision numbers and banners, in /proc
  10 */
  11#include <linux/module.h>
  12#include <linux/slab.h>
  13#include <linux/proc_fs.h>
  14#include <linux/nodemask.h>
  15#include <asm/system.h>
  16#include <asm/io.h>
  17#include <asm/sn/sn_sal.h>
  18#include <asm/sn/sn_cpuid.h>
  19#include <asm/sn/addrs.h>
  20
  21MODULE_DESCRIPTION("PROM version reporting for /proc");
  22MODULE_AUTHOR("Chad Talbott");
  23MODULE_LICENSE("GPL");
  24
  25/* Standard Intel FIT entry types */
  26#define FIT_ENTRY_FIT_HEADER    0x00    /* FIT header entry */
  27#define FIT_ENTRY_PAL_B         0x01    /* PAL_B entry */
  28/* Entries 0x02 through 0x0D reserved by Intel */
  29#define FIT_ENTRY_PAL_A_PROC    0x0E    /* Processor-specific PAL_A entry */
  30#define FIT_ENTRY_PAL_A         0x0F    /* PAL_A entry, same as... */
  31#define FIT_ENTRY_PAL_A_GEN     0x0F    /* ...Generic PAL_A entry */
  32#define FIT_ENTRY_UNUSED        0x7F    /* Unused (reserved by Intel?) */
  33/* OEM-defined entries range from 0x10 to 0x7E. */
  34#define FIT_ENTRY_SAL_A         0x10    /* SAL_A entry */
  35#define FIT_ENTRY_SAL_B         0x11    /* SAL_B entry */
  36#define FIT_ENTRY_SALRUNTIME    0x12    /* SAL runtime entry */
  37#define FIT_ENTRY_EFI           0x1F    /* EFI entry */
  38#define FIT_ENTRY_FPSWA         0x20    /* embedded fpswa entry */
  39#define FIT_ENTRY_VMLINUX       0x21    /* embedded vmlinux entry */
  40
  41#define FIT_MAJOR_SHIFT (32 + 8)
  42#define FIT_MAJOR_MASK  ((1 << 8) - 1)
  43#define FIT_MINOR_SHIFT 32
  44#define FIT_MINOR_MASK  ((1 << 8) - 1)
  45
  46#define FIT_MAJOR(q)    \
  47        ((unsigned) ((q) >> FIT_MAJOR_SHIFT) & FIT_MAJOR_MASK)
  48#define FIT_MINOR(q)    \
  49        ((unsigned) ((q) >> FIT_MINOR_SHIFT) & FIT_MINOR_MASK)
  50
  51#define FIT_TYPE_SHIFT  (32 + 16)
  52#define FIT_TYPE_MASK   ((1 << 7) - 1)
  53
  54#define FIT_TYPE(q)     \
  55        ((unsigned) ((q) >> FIT_TYPE_SHIFT) & FIT_TYPE_MASK)
  56
  57struct fit_type_map_t {
  58        unsigned char type;
  59        const char *name;
  60};
  61
  62static const struct fit_type_map_t fit_entry_types[] = {
  63        {FIT_ENTRY_FIT_HEADER, "FIT Header"},
  64        {FIT_ENTRY_PAL_A_GEN, "Generic PAL_A"},
  65        {FIT_ENTRY_PAL_A_PROC, "Processor-specific PAL_A"},
  66        {FIT_ENTRY_PAL_A, "PAL_A"},
  67        {FIT_ENTRY_PAL_B, "PAL_B"},
  68        {FIT_ENTRY_SAL_A, "SAL_A"},
  69        {FIT_ENTRY_SAL_B, "SAL_B"},
  70        {FIT_ENTRY_SALRUNTIME, "SAL runtime"},
  71        {FIT_ENTRY_EFI, "EFI"},
  72        {FIT_ENTRY_VMLINUX, "Embedded Linux"},
  73        {FIT_ENTRY_FPSWA, "Embedded FPSWA"},
  74        {FIT_ENTRY_UNUSED, "Unused"},
  75        {0xff, "Error"},
  76};
  77
  78static const char *fit_type_name(unsigned char type)
  79{
  80        struct fit_type_map_t const *mapp;
  81
  82        for (mapp = fit_entry_types; mapp->type != 0xff; mapp++)
  83                if (type == mapp->type)
  84                        return mapp->name;
  85
  86        if ((type > FIT_ENTRY_PAL_A) && (type < FIT_ENTRY_UNUSED))
  87                return "OEM type";
  88        if ((type > FIT_ENTRY_PAL_B) && (type < FIT_ENTRY_PAL_A))
  89                return "Reserved";
  90
  91        return "Unknown type";
  92}
  93
  94static int
  95get_fit_entry(unsigned long nasid, int index, unsigned long *fentry,
  96              char *banner, int banlen)
  97{
  98        return ia64_sn_get_fit_compt(nasid, index, fentry, banner, banlen);
  99}
 100
 101
 102/*
 103 * These two routines display the FIT table for each node.
 104 */
 105static int dump_fit_entry(char *page, unsigned long *fentry)
 106{
 107        unsigned type;
 108
 109        type = FIT_TYPE(fentry[1]);
 110        return sprintf(page, "%02x %-25s %x.%02x %016lx %u\n",
 111                       type,
 112                       fit_type_name(type),
 113                       FIT_MAJOR(fentry[1]), FIT_MINOR(fentry[1]),
 114                       fentry[0],
 115                       /* mult by sixteen to get size in bytes */
 116                       (unsigned)(fentry[1] & 0xffffff) * 16);
 117}
 118
 119
 120/*
 121 * We assume that the fit table will be small enough that we can print
 122 * the whole thing into one page.  (This is true for our default 16kB
 123 * pages -- each entry is about 60 chars wide when printed.)  I read
 124 * somewhere that the maximum size of the FIT is 128 entries, so we're
 125 * OK except for 4kB pages (and no one is going to do that on SN
 126 * anyway).
 127 */
 128static int
 129dump_fit(char *page, unsigned long nasid)
 130{
 131        unsigned long fentry[2];
 132        int index;
 133        char *p;
 134
 135        p = page;
 136        for (index=0;;index++) {
 137                BUG_ON(index * 60 > PAGE_SIZE);
 138                if (get_fit_entry(nasid, index, fentry, NULL, 0))
 139                        break;
 140                p += dump_fit_entry(p, fentry);
 141        }
 142
 143        return p - page;
 144}
 145
 146static int
 147dump_version(char *page, unsigned long nasid)
 148{
 149        unsigned long fentry[2];
 150        char banner[128];
 151        int index;
 152        int len;
 153
 154        for (index = 0; ; index++) {
 155                if (get_fit_entry(nasid, index, fentry, banner,
 156                                  sizeof(banner)))
 157                        return 0;
 158                if (FIT_TYPE(fentry[1]) == FIT_ENTRY_SAL_A)
 159                        break;
 160        }
 161
 162        len = sprintf(page, "%x.%02x\n", FIT_MAJOR(fentry[1]),
 163                      FIT_MINOR(fentry[1]));
 164        page += len;
 165
 166        if (banner[0])
 167                len += snprintf(page, PAGE_SIZE-len, "%s\n", banner);
 168
 169        return len;
 170}
 171
 172/* same as in proc_misc.c */
 173static int
 174proc_calc_metrics(char *page, char **start, off_t off, int count, int *eof,
 175                  int len)
 176{
 177        if (len <= off + count)
 178                *eof = 1;
 179        *start = page + off;
 180        len -= off;
 181        if (len > count)
 182                len = count;
 183        if (len < 0)
 184                len = 0;
 185        return len;
 186}
 187
 188static int
 189read_version_entry(char *page, char **start, off_t off, int count, int *eof,
 190                   void *data)
 191{
 192        int len;
 193
 194        /* data holds the NASID of the node */
 195        len = dump_version(page, (unsigned long)data);
 196        len = proc_calc_metrics(page, start, off, count, eof, len);
 197        return len;
 198}
 199
 200static int
 201read_fit_entry(char *page, char **start, off_t off, int count, int *eof,
 202               void *data)
 203{
 204        int len;
 205
 206        /* data holds the NASID of the node */
 207        len = dump_fit(page, (unsigned long)data);
 208        len = proc_calc_metrics(page, start, off, count, eof, len);
 209
 210        return len;
 211}
 212
 213/* module entry points */
 214int __init prominfo_init(void);
 215void __exit prominfo_exit(void);
 216
 217module_init(prominfo_init);
 218module_exit(prominfo_exit);
 219
 220static struct proc_dir_entry **proc_entries;
 221static struct proc_dir_entry *sgi_prominfo_entry;
 222
 223#define NODE_NAME_LEN 11
 224
 225int __init prominfo_init(void)
 226{
 227        struct proc_dir_entry **entp;
 228        struct proc_dir_entry *p;
 229        cnodeid_t cnodeid;
 230        unsigned long nasid;
 231        int size;
 232        char name[NODE_NAME_LEN];
 233
 234        if (!ia64_platform_is("sn2"))
 235                return 0;
 236
 237        size = num_online_nodes() * sizeof(struct proc_dir_entry *);
 238        proc_entries = kzalloc(size, GFP_KERNEL);
 239        if (!proc_entries)
 240                return -ENOMEM;
 241
 242        sgi_prominfo_entry = proc_mkdir("sgi_prominfo", NULL);
 243
 244        entp = proc_entries;
 245        for_each_online_node(cnodeid) {
 246                sprintf(name, "node%d", cnodeid);
 247                *entp = proc_mkdir(name, sgi_prominfo_entry);
 248                nasid = cnodeid_to_nasid(cnodeid);
 249                p = create_proc_read_entry("fit", 0, *entp, read_fit_entry,
 250                                           (void *)nasid);
 251                if (p)
 252                        p->owner = THIS_MODULE;
 253                p = create_proc_read_entry("version", 0, *entp,
 254                                           read_version_entry, (void *)nasid);
 255                if (p)
 256                        p->owner = THIS_MODULE;
 257                entp++;
 258        }
 259
 260        return 0;
 261}
 262
 263void __exit prominfo_exit(void)
 264{
 265        struct proc_dir_entry **entp;
 266        unsigned int cnodeid;
 267        char name[NODE_NAME_LEN];
 268
 269        entp = proc_entries;
 270        for_each_online_node(cnodeid) {
 271                remove_proc_entry("fit", *entp);
 272                remove_proc_entry("version", *entp);
 273                sprintf(name, "node%d", cnodeid);
 274                remove_proc_entry(name, sgi_prominfo_entry);
 275                entp++;
 276        }
 277        remove_proc_entry("sgi_prominfo", NULL);
 278        kfree(proc_entries);
 279}
 280
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.