* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1999,2001-2003 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (C) 1999,2001-2004, 2006 Silicon Graphics, Inc. All Rights Reserved.
*
* Module to export the system's Firmware Interface Tables, including
- * PROM revision numbers, in /proc
+ * PROM revision numbers and banners, in /proc
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
+#include <linux/nodemask.h>
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/sn/sn2/addrs.h>
-#include <asm/sn/simulator.h>
-
-/* to lookup nasids */
+#include <asm/sn/sn_sal.h>
#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/addrs.h>
MODULE_DESCRIPTION("PROM version reporting for /proc");
MODULE_AUTHOR("Chad Talbott");
MODULE_LICENSE("GPL");
-#undef DEBUG_PROMINFO
-
-#define TRACE_PROMINFO
-
-#if defined(DEBUG_PROMINFO)
-# define DPRINTK(x...) printk(KERN_DEBUG x)
-#else
-# define DPRINTK(x...)
-#endif
-
-#if defined(TRACE_PROMINFO) && defined(DEBUG_PROMINFO)
-# if defined(__GNUC__)
-# define TRACE() printk(KERN_DEBUG "%s:%d:%s\n", \
- __FILE__, __LINE__, __FUNCTION__)
-# else
-# define TRACE() printk(KERN_DEBUG "%s:%d\n", __LINE__, __FILE__)
-# endif
-#else
-# define TRACE()
-#endif
-
-/* Sub-regions determined by bits in Node Offset */
-#define LB_PROM_SPACE 0x0000000700000000ul /* Local LB PROM */
-
-#define FIT_SIGNATURE 0x2020205f5449465ful
/* Standard Intel FIT entry types */
#define FIT_ENTRY_FIT_HEADER 0x00 /* FIT header entry */
#define FIT_ENTRY_PAL_B 0x01 /* PAL_B entry */
#define FIT_TYPE(q) \
((unsigned) ((q) >> FIT_TYPE_SHIFT) & FIT_TYPE_MASK)
-#define FIT_ENTRY(type, maj, min, size) \
- ((((unsigned long)(maj) & FIT_MAJOR_MASK) << FIT_MAJOR_SHIFT) | \
- (((unsigned long)(min) & FIT_MINOR_MASK) << FIT_MINOR_SHIFT) | \
- (((unsigned long)(type) & FIT_TYPE_MASK) << FIT_TYPE_SHIFT) | \
- (size))
-
struct fit_type_map_t {
- unsigned char type;
- const char *name;
+ unsigned char type;
+ const char *name;
};
static const struct fit_type_map_t fit_entry_types[] = {
- { FIT_ENTRY_FIT_HEADER, "FIT Header" },
- { FIT_ENTRY_PAL_A_GEN, "Generic PAL_A" },
- { FIT_ENTRY_PAL_A_PROC, "Processor-specific PAL_A" },
- { FIT_ENTRY_PAL_A, "PAL_A" },
- { FIT_ENTRY_PAL_B, "PAL_B" },
- { FIT_ENTRY_SAL_A, "SAL_A" },
- { FIT_ENTRY_SAL_B, "SAL_B" },
- { FIT_ENTRY_SALRUNTIME, "SAL runtime" },
- { FIT_ENTRY_EFI, "EFI" },
- { FIT_ENTRY_VMLINUX, "Embedded Linux" },
- { FIT_ENTRY_FPSWA, "Embedded FPSWA" },
- { FIT_ENTRY_UNUSED, "Unused" },
- { 0xff, "Error" },
+ {FIT_ENTRY_FIT_HEADER, "FIT Header"},
+ {FIT_ENTRY_PAL_A_GEN, "Generic PAL_A"},
+ {FIT_ENTRY_PAL_A_PROC, "Processor-specific PAL_A"},
+ {FIT_ENTRY_PAL_A, "PAL_A"},
+ {FIT_ENTRY_PAL_B, "PAL_B"},
+ {FIT_ENTRY_SAL_A, "SAL_A"},
+ {FIT_ENTRY_SAL_B, "SAL_B"},
+ {FIT_ENTRY_SALRUNTIME, "SAL runtime"},
+ {FIT_ENTRY_EFI, "EFI"},
+ {FIT_ENTRY_VMLINUX, "Embedded Linux"},
+ {FIT_ENTRY_FPSWA, "Embedded FPSWA"},
+ {FIT_ENTRY_UNUSED, "Unused"},
+ {0xff, "Error"},
};
-static const char *
-fit_type_name(unsigned char type)
+static const char *fit_type_name(unsigned char type)
{
- struct fit_type_map_t const*mapp;
+ struct fit_type_map_t const *mapp;
for (mapp = fit_entry_types; mapp->type != 0xff; mapp++)
if (type == mapp->type)
return "Unknown type";
}
-/* These two routines read the FIT table directly from the FLASH PROM
- * on a specific node. The PROM can only be accessed using aligned 64
- * bit reads, so we do that and then shift and mask the result to get
- * at each field.
- */
static int
-dump_fit_entry(char *page, unsigned long *fentry)
+get_fit_entry(unsigned long nasid, int index, unsigned long *fentry,
+ char *banner, int banlen)
{
- unsigned long q1, q2;
- unsigned type;
+ return ia64_sn_get_fit_compt(nasid, index, fentry, banner, banlen);
+}
+
- TRACE();
+/*
+ * These two routines display the FIT table for each node.
+ */
+static int dump_fit_entry(char *page, unsigned long *fentry)
+{
+ unsigned type;
- q1 = readq(fentry);
- q2 = readq(fentry + 1);
- type = FIT_TYPE(q2);
+ type = FIT_TYPE(fentry[1]);
return sprintf(page, "%02x %-25s %x.%02x %016lx %u\n",
type,
fit_type_name(type),
- FIT_MAJOR(q2), FIT_MINOR(q2),
- q1,
+ FIT_MAJOR(fentry[1]), FIT_MINOR(fentry[1]),
+ fentry[0],
/* mult by sixteen to get size in bytes */
- (unsigned)q2 * 16);
+ (unsigned)(fentry[1] & 0xffffff) * 16);
}
-/* We assume that the fit table will be small enough that we can print
+
+/*
+ * We assume that the fit table will be small enough that we can print
* the whole thing into one page. (This is true for our default 16kB
* pages -- each entry is about 60 chars wide when printed.) I read
* somewhere that the maximum size of the FIT is 128 entries, so we're
* anyway).
*/
static int
-dump_fit(char *page, unsigned long *fit)
+dump_fit(char *page, unsigned long nasid)
{
- unsigned long qw;
- int nentries;
- int fentry;
+ unsigned long fentry[2];
+ int index;
char *p;
- TRACE();
-
- DPRINTK("dumping fit from %p\n", (void *)fit);
-
- qw = readq(fit);
- DPRINTK("FIT signature: %016lx (%.8s)\n", qw, (char *)&qw);
- if (qw != FIT_SIGNATURE)
- printk(KERN_WARNING "Unrecognized FIT signature");
-
- qw = readq(fit + 1);
- nentries = (unsigned)qw;
- DPRINTK("number of fit entries: %u\n", nentries);
- /* check that we won't overflow the page -- see comment above */
- BUG_ON(nentries * 60 > PAGE_SIZE);
-
p = page;
- for (fentry = 0; fentry < nentries; fentry++)
- /* each FIT entry is two 64 bit words */
- p += dump_fit_entry(p, fit + 2 * fentry);
+ for (index=0;;index++) {
+ BUG_ON(index * 60 > PAGE_SIZE);
+ if (get_fit_entry(nasid, index, fentry, NULL, 0))
+ break;
+ p += dump_fit_entry(p, fentry);
+ }
return p - page;
}
static int
-dump_version(char *page, unsigned long *fit)
+dump_version(char *page, unsigned long nasid)
{
- int nentries;
- int fentry;
- unsigned long qw;
+ unsigned long fentry[2];
+ char banner[128];
+ int index;
+ int len;
+
+ for (index = 0; ; index++) {
+ if (get_fit_entry(nasid, index, fentry, banner,
+ sizeof(banner)))
+ return 0;
+ if (FIT_TYPE(fentry[1]) == FIT_ENTRY_SAL_A)
+ break;
+ }
- TRACE();
+ len = sprintf(page, "%x.%02x\n", FIT_MAJOR(fentry[1]),
+ FIT_MINOR(fentry[1]));
+ page += len;
- nentries = (unsigned)readq(fit + 1);
- BUG_ON(nentries * 60 > PAGE_SIZE);
+ if (banner[0])
+ len += snprintf(page, PAGE_SIZE-len, "%s\n", banner);
- for (fentry = 0; fentry < nentries; fentry++) {
- qw = readq(fit + 2 * fentry + 1);
- if (FIT_TYPE(qw) == FIT_ENTRY_SAL_A)
- return sprintf(page, "%x.%02x\n",
- FIT_MAJOR(qw), FIT_MINOR(qw));
- }
- return 0;
+ return len;
}
/* same as in proc_misc.c */
proc_calc_metrics(char *page, char **start, off_t off, int count, int *eof,
int len)
{
- if (len <= off+count) *eof = 1;
+ if (len <= off + count)
+ *eof = 1;
*start = page + off;
len -= off;
- if (len>count) len = count;
- if (len<0) len = 0;
+ if (len > count)
+ len = count;
+ if (len < 0)
+ len = 0;
return len;
}
read_version_entry(char *page, char **start, off_t off, int count, int *eof,
void *data)
{
- int len = 0;
+ int len;
- /* data holds the pointer to this node's FIT */
- len = dump_version(page, (unsigned long *)data);
+ /* data holds the NASID of the node */
+ len = dump_version(page, (unsigned long)data);
len = proc_calc_metrics(page, start, off, count, eof, len);
return len;
}
read_fit_entry(char *page, char **start, off_t off, int count, int *eof,
void *data)
{
- int len = 0;
+ int len;
- /* data holds the pointer to this node's FIT */
- len = dump_fit(page, (unsigned long *)data);
+ /* data holds the NASID of the node */
+ len = dump_fit(page, (unsigned long)data);
len = proc_calc_metrics(page, start, off, count, eof, len);
return len;
}
-/* this is a fake FIT that's used on the medusa simulator which
- * doesn't usually run a complete PROM.
- */
-#ifdef CONFIG_IA64_SGI_SN_SIM
-static unsigned long fakefit[] = {
- /* this is all we need to satisfy the code below */
- FIT_SIGNATURE,
- FIT_ENTRY(FIT_ENTRY_FIT_HEADER, 0x02, 0x60, 2),
- /* dump something arbitrary for
- * /proc/sgi_prominfo/nodeX/version */
- 0xbadbeef00fa3ef17ul,
- FIT_ENTRY(FIT_ENTRY_SAL_A, 0, 0x99, 0x100)
-};
-#endif
-
-static unsigned long *
-lookup_fit(int nasid)
-{
- unsigned long *fitp;
- unsigned long fit_paddr;
- unsigned long *fit_vaddr;
-
-#ifdef CONFIG_IA64_SGI_SN_SIM
- if (IS_RUNNING_ON_SIMULATOR())
- return fakefit;
-#endif
-
- fitp = (void *)GLOBAL_MMR_ADDR(nasid, LB_PROM_SPACE - 32);
- DPRINTK("pointer to fit at %p\n", (void *)fitp);
- fit_paddr = readq(fitp);
- DPRINTK("fit pointer contains %lx\n", fit_paddr);
- /* snag just the node-relative offset */
- fit_paddr &= ~0ul >> (63-35);
- /* the pointer to the FIT is relative to IA-64 compatibility
- * space. However, the PROM is mapped at a different offset
- * in MMR space (both local and global)
- */
- fit_paddr += 0x700000000;
- fit_vaddr = (void *)GLOBAL_MMR_ADDR(nasid, fit_paddr);
- DPRINTK("fit at %p\n", (void *)fit_vaddr);
- return fit_vaddr;
-}
-
/* module entry points */
int __init prominfo_init(void);
void __exit prominfo_exit(void);
#define NODE_NAME_LEN 11
-int __init
-prominfo_init(void)
+int __init prominfo_init(void)
{
struct proc_dir_entry **entp;
struct proc_dir_entry *p;
cnodeid_t cnodeid;
- nasid_t nasid;
+ unsigned long nasid;
+ int size;
char name[NODE_NAME_LEN];
if (!ia64_platform_is("sn2"))
return 0;
- TRACE();
-
- DPRINTK("running on cpu %d\n", smp_processor_id());
- DPRINTK("numnodes %d\n", numnodes);
-
- proc_entries = kmalloc(numnodes * sizeof(struct proc_dir_entry *),
- GFP_KERNEL);
+ size = num_online_nodes() * sizeof(struct proc_dir_entry *);
+ proc_entries = kzalloc(size, GFP_KERNEL);
+ if (!proc_entries)
+ return -ENOMEM;
sgi_prominfo_entry = proc_mkdir("sgi_prominfo", NULL);
- for (cnodeid = 0, entp = proc_entries;
- cnodeid < numnodes;
- cnodeid++, entp++) {
+ entp = proc_entries;
+ for_each_online_node(cnodeid) {
sprintf(name, "node%d", cnodeid);
*entp = proc_mkdir(name, sgi_prominfo_entry);
nasid = cnodeid_to_nasid(cnodeid);
- p = create_proc_read_entry(
- "fit", 0, *entp, read_fit_entry,
- lookup_fit(nasid));
+ p = create_proc_read_entry("fit", 0, *entp, read_fit_entry,
+ (void *)nasid);
if (p)
p->owner = THIS_MODULE;
- p = create_proc_read_entry(
- "version", 0, *entp, read_version_entry,
- lookup_fit(nasid));
+ p = create_proc_read_entry("version", 0, *entp,
+ read_version_entry, (void *)nasid);
if (p)
p->owner = THIS_MODULE;
+ entp++;
}
return 0;
}
-void __exit
-prominfo_exit(void)
+void __exit prominfo_exit(void)
{
struct proc_dir_entry **entp;
- unsigned cnodeid;
+ unsigned int cnodeid;
char name[NODE_NAME_LEN];
- TRACE();
-
- for (cnodeid = 0, entp = proc_entries;
- cnodeid < numnodes;
- cnodeid++, entp++) {
+ entp = proc_entries;
+ for_each_online_node(cnodeid) {
remove_proc_entry("fit", *entp);
remove_proc_entry("version", *entp);
sprintf(name, "node%d", cnodeid);
remove_proc_entry(name, sgi_prominfo_entry);
+ entp++;
}
remove_proc_entry("sgi_prominfo", NULL);
kfree(proc_entries);