X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;ds=sidebyside;f=arch%2Fia64%2Fsn%2Fkernel%2Fsn2%2Fprominfo_proc.c;h=32db72ae751c3f33f2e79f95ebe53963a6fd605c;hb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;hp=bcc938b2883842602a11fae5b03e46ca48dbb1fd;hpb=a2c21200f1c81b08cb55e417b68150bba439b646;p=linux-2.6.git diff --git a/arch/ia64/sn/kernel/sn2/prominfo_proc.c b/arch/ia64/sn/kernel/sn2/prominfo_proc.c index bcc938b28..32db72ae7 100644 --- a/arch/ia64/sn/kernel/sn2/prominfo_proc.c +++ b/arch/ia64/sn/kernel/sn2/prominfo_proc.c @@ -3,10 +3,10 @@ * 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 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 #include @@ -14,41 +14,14 @@ #include #include #include -#include -#include - -/* to lookup nasids */ +#include #include +#include 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 */ @@ -81,12 +54,6 @@ MODULE_LICENSE("GPL"); #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; @@ -125,32 +92,148 @@ fit_type_name(unsigned char 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. + +/* ============ BEGIN temp til old PROMs are no longer supported ============= + * + * The OS should not make direct access to the PROM flash memory. Access to + * this region must be serialized with a PROM lock. If SAL on one cpu is + * updating the FLASH error log at the same time another cpu is accessing the + * PROM, data corruption will occur. + * + * To solve the problem, all flash PROM access has been moved to SAL. Because + * not all systems will have instant PROM updates, we need to support a new OS + * running on a system with old PROMs. + * + * This code should be deleted after 1 OS/PROM release has occurred & the OS + * no longer supports downrev PROMs. (PROM support should be in the 3.50 + * PROMs). + */ +#define SUPPORT_OLD_PROMS +#ifdef SUPPORT_OLD_PROMS + + +#define FIT_SIGNATURE 0x2020205f5449465ful + +/* Sub-regions determined by bits in Node Offset */ +#define LB_PROM_SPACE 0x0000000700000000ul /* Local LB PROM */ + +/* Offset of PROM banner pointers in SAL A and SAL B */ +#define SAL_A_BANNER_OFFSET (1 * 16) +#define SAL_B_BANNER_OFFSET (3 * 16) + +/* Architected IA64 firmware space */ +#define FW_BASE 0x00000000FF000000 +#define FW_TOP 0x0000000100000000 + +static unsigned long +convert_fw_addr(nasid_t nasid, unsigned long addr) +{ + /* snag just the node-relative offset */ + addr &= ~0ul >> (63-35); + /* the pointer to SAL A is relative to IA-64 compatibility + * space. However, the PROM is mapped at a different offset + * in MMR space (both local and global) + */ + addr += 0x700000000; + return GLOBAL_MMR_ADDR(nasid, addr); +} + +static int +valid_fw_addr(unsigned long addr) +{ + addr &= ~(1ul << 63); /* Clear cached/uncached bit */ + return (addr >= FW_BASE && addr < FW_TOP); +} + +static unsigned long * +lookup_fit(int nasid) +{ + unsigned long *fitp; + unsigned long fit_paddr; + unsigned long *fit_vaddr; + + fitp = (void *)GLOBAL_MMR_ADDR(nasid, LB_PROM_SPACE - 32); + fit_paddr = readq(fitp); + fit_vaddr = (unsigned long *) convert_fw_addr(nasid, fit_paddr); + return fit_vaddr; +} +#endif /* SUPPORT_OLD_PROMS */ +/* ============ END temp til old PROMs are no longer supported ============= */ + +static int +get_fit_entry(unsigned long nasid, int index, unsigned long *fentry, + char *banner, int banlen) +{ + int ret; + + ret = ia64_sn_get_fit_compt(nasid, index, fentry, banner, banlen); + +#ifdef SUPPORT_OLD_PROMS + /* The following is hack is temporary until PROMs are updated */ + if (ret == SALRET_NOT_IMPLEMENTED) { + unsigned long *fitadr = lookup_fit(nasid); + int nentries; + + if (readq(fitadr) != FIT_SIGNATURE) { + printk(KERN_WARNING "Unrecognized FIT signature"); + return -2; + } + + nentries = (unsigned int) (readq(fitadr + 1) & 0xffffff); + if (index >= nentries) + return -2; + + fentry[0] = readq(fitadr + 2 * index); + fentry[1] = readq(fitadr + 2 * index + 1); + ret = 0; + + if (banner && FIT_TYPE(fentry[1]) == FIT_ENTRY_SAL_A) { + unsigned long i, qw, *bwp, *qwp; + + banner[0] = '\0'; + qw = fentry[0]; /* Address of SAL A */ + if (!valid_fw_addr(qw)) + return 0; + + qw += SAL_A_BANNER_OFFSET; + qw = convert_fw_addr(nasid, qw); + + qw = readq(qw); /* Address of banner */ + if (!valid_fw_addr(qw)) + return 0; + qw = convert_fw_addr(nasid, qw); + qwp = (unsigned long *) qw; + bwp = (unsigned long *) banner; + for (i=0; i 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 */ @@ -228,8 +303,8 @@ read_version_entry(char *page, char **start, off_t off, int count, int *eof, { int len = 0; - /* 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; } @@ -240,56 +315,13 @@ read_fit_entry(char *page, char **start, off_t off, int count, int *eof, { int len = 0; - /* 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); @@ -308,17 +340,12 @@ prominfo_init(void) struct proc_dir_entry **entp; struct proc_dir_entry *p; cnodeid_t cnodeid; - nasid_t nasid; + unsigned long nasid; 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); @@ -332,12 +359,12 @@ prominfo_init(void) nasid = cnodeid_to_nasid(cnodeid); p = create_proc_read_entry( "fit", 0, *entp, read_fit_entry, - lookup_fit(nasid)); + (void *)nasid); if (p) p->owner = THIS_MODULE; p = create_proc_read_entry( "version", 0, *entp, read_version_entry, - lookup_fit(nasid)); + (void *)nasid); if (p) p->owner = THIS_MODULE; } @@ -352,8 +379,6 @@ prominfo_exit(void) unsigned cnodeid; char name[NODE_NAME_LEN]; - TRACE(); - for (cnodeid = 0, entp = proc_entries; cnodeid < numnodes; cnodeid++, entp++) {