1/* $Id: module.c,v 1.1.1.1 2008/10/15 03:26:03 james26_jang Exp $ 2 * 3 * This file is subject to the terms and conditions of the GNU General Public 4 * License. See the file "COPYING" in the main directory of this archive 5 * for more details. 6 * 7 * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved. 8 */ 9 10#include <linux/types.h> 11#include <linux/slab.h> 12#include <asm/sn/sgi.h> 13#include <asm/sn/sn_sal.h> 14#include <asm/sn/io.h> 15#include <asm/sn/invent.h> 16#include <asm/sn/hcl.h> 17#include <asm/sn/labelcl.h> 18#include <asm/sn/xtalk/xbow.h> 19#include <asm/sn/pci/bridge.h> 20#include <asm/sn/klconfig.h> 21#include <asm/sn/sn1/hubdev.h> 22#include <asm/sn/module.h> 23#include <asm/sn/pci/pcibr.h> 24#include <asm/sn/xtalk/xswitch.h> 25#include <asm/sn/nodepda.h> 26#include <asm/sn/sn_cpuid.h> 27 28 29/* #define LDEBUG 1 */ 30 31#ifdef LDEBUG 32#define DPRINTF printk 33#define printf printk 34#else 35#define DPRINTF(x...) 36#endif 37 38module_t *modules[MODULE_MAX]; 39int nummodules; 40 41#define SN00_SERIAL_FUDGE 0x3b1af409d513c2 42#define SN0_SERIAL_FUDGE 0x6e 43 44void 45encode_int_serial(uint64_t src,uint64_t *dest) 46{ 47 uint64_t val; 48 int i; 49 50 val = src + SN00_SERIAL_FUDGE; 51 52 53 for (i = 0; i < sizeof(long long); i++) { 54 ((char*)dest)[i] = 55 ((char*)&val)[sizeof(long long)/2 + 56 ((i%2) ? ((i/2 * -1) - 1) : (i/2))]; 57 } 58} 59 60 61void 62decode_int_serial(uint64_t src, uint64_t *dest) 63{ 64 uint64_t val; 65 int i; 66 67 for (i = 0; i < sizeof(long long); i++) { 68 ((char*)&val)[sizeof(long long)/2 + 69 ((i%2) ? ((i/2 * -1) - 1) : (i/2))] = 70 ((char*)&src)[i]; 71 } 72 73 *dest = val - SN00_SERIAL_FUDGE; 74} 75 76 77void 78encode_str_serial(const char *src, char *dest) 79{ 80 int i; 81 82 for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) { 83 84 dest[i] = src[MAX_SERIAL_NUM_SIZE/2 + 85 ((i%2) ? ((i/2 * -1) - 1) : (i/2))] + 86 SN0_SERIAL_FUDGE; 87 } 88} 89 90void 91decode_str_serial(const char *src, char *dest) 92{ 93 int i; 94 95 for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) { 96 dest[MAX_SERIAL_NUM_SIZE/2 + 97 ((i%2) ? ((i/2 * -1) - 1) : (i/2))] = src[i] - 98 SN0_SERIAL_FUDGE; 99 } 100} 101 102 103module_t *module_lookup(moduleid_t id) 104{ 105 int i; 106 107 for (i = 0; i < nummodules; i++) 108 if (modules[i]->id == id) { 109 DPRINTF("module_lookup: found m=0x%p\n", modules[i]); 110 return modules[i]; 111 } 112 113 return NULL; 114} 115 116/* 117 * module_add_node 118 * 119 * The first time a new module number is seen, a module structure is 120 * inserted into the module list in order sorted by module number 121 * and the structure is initialized. 122 * 123 * The node number is added to the list of nodes in the module. 124 */ 125 126module_t *module_add_node(moduleid_t id, cnodeid_t n) 127{ 128 module_t *m; 129 int i; 130 char buffer[16]; 131 132#ifdef __ia64 133 memset(buffer, 0, 16); 134 format_module_id(buffer, id, MODULE_FORMAT_BRIEF); 135 DPRINTF("module_add_node: id=%s node=%d\n", buffer, n); 136#endif 137 138 if ((m = module_lookup(id)) == 0) { 139#ifdef LATER 140 m = kmem_zalloc_node(sizeof (module_t), KM_NOSLEEP, n); 141#else 142 m = kmalloc(sizeof (module_t), GFP_KERNEL); 143 memset(m, 0 , sizeof(module_t)); 144#endif 145 ASSERT_ALWAYS(m); 146 147 m->id = id; 148 spin_lock_init(&m->lock); 149 150 mutex_init_locked(&m->thdcnt); 151 152// set_elsc(&m->elsc); 153 elsc_init(&m->elsc, COMPACT_TO_NASID_NODEID(n)); 154 spin_lock_init(&m->elsclock); 155 156 /* Insert in sorted order by module number */ 157 158 for (i = nummodules; i > 0 && modules[i - 1]->id > id; i--) 159 modules[i] = modules[i - 1]; 160 161 modules[i] = m; 162 nummodules++; 163 } 164 165 m->nodes[m->nodecnt++] = n; 166 167 DPRINTF("module_add_node: module %s now has %d nodes\n", buffer, m->nodecnt); 168 169 return m; 170} 171 172int module_probe_snum(module_t *m, nasid_t nasid) 173{ 174 lboard_t *board; 175 klmod_serial_num_t *comp; 176 char * bcopy(const char * src, char * dest, int count); 177 char serial_number[16]; 178 179 /* 180 * record brick serial number 181 */ 182 board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA); 183 184 if (! board || KL_CONFIG_DUPLICATE_BOARD(board)) 185 { 186#if LDEBUG 187 printf ("module_probe_snum: no IP35 board found!\n"); 188#endif 189 return 0; 190 } 191 192 board_serial_number_get( board, serial_number ); 193 if( serial_number[0] != '\0' ) { 194 encode_str_serial( serial_number, m->snum.snum_str ); 195 m->snum_valid = 1; 196 } 197#if LDEBUG 198 else { 199 printf("module_probe_snum: brick serial number is null!\n"); 200 } 201 printf("module_probe_snum: brick serial number == %s\n", serial_number); 202#endif /* DEBUG */ 203 204 board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), 205 KLTYPE_IOBRICK_XBOW); 206 207 if (! board || KL_CONFIG_DUPLICATE_BOARD(board)) 208 return 0; 209 210 comp = GET_SNUM_COMP(board); 211 212 if (comp) { 213#if LDEBUG 214 int i; 215 216 printf("********found module with id %x and string", m->id); 217 218 for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) 219 printf(" %x ", comp->snum.snum_str[i]); 220 221 printf("\n"); /* Fudged string is not ASCII */ 222#endif 223 224 if (comp->snum.snum_str[0] != '\0') { 225 bcopy(comp->snum.snum_str, 226 m->sys_snum, 227 MAX_SERIAL_NUM_SIZE); 228 m->sys_snum_valid = 1; 229 } 230 } 231 232 if (m->sys_snum_valid) 233 return 1; 234 else { 235 DPRINTF("Invalid serial number for module %d, " 236 "possible missing or invalid NIC.", m->id); 237 return 0; 238 } 239} 240 241void 242io_module_init(void) 243{ 244 cnodeid_t node; 245 lboard_t *board; 246 nasid_t nasid; 247 int nserial; 248 module_t *m; 249 250 DPRINTF("*******module_init\n"); 251 252 nserial = 0; 253 254 for (node = 0; node < numnodes; node++) { 255 nasid = COMPACT_TO_NASID_NODEID(node); 256 257 board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA); 258 ASSERT(board); 259 260 m = module_add_node(board->brd_module, node); 261 262 if (! m->snum_valid && module_probe_snum(m, nasid)) 263 nserial++; 264 } 265 266 DPRINTF("********found total of %d serial numbers in the system\n", 267 nserial); 268 269 if (nserial == 0) 270 printk(KERN_WARNING "io_module_init: No serial number found.\n"); 271} 272 273elsc_t *get_elsc(void) 274{ 275 return &NODEPDA(cpuid_to_cnodeid(smp_processor_id()))->module->elsc; 276} 277 278int 279get_kmod_info(cmoduleid_t cmod, module_info_t *mod_info) 280{ 281 int i; 282 283 if (cmod < 0 || cmod >= nummodules) 284 return EINVAL; 285 286 if (! modules[cmod]->snum_valid) 287 return ENXIO; 288 289 mod_info->mod_num = modules[cmod]->id; 290 { 291 char temp[MAX_SERIAL_NUM_SIZE]; 292 293 decode_str_serial(modules[cmod]->snum.snum_str, temp); 294 295 /* if this is an invalid serial number return an error */ 296 if (temp[0] != 'K') 297 return ENXIO; 298 299 mod_info->serial_num = 0; 300 301 for (i = 0; i < MAX_SERIAL_NUM_SIZE && temp[i] != '\0'; i++) { 302 mod_info->serial_num <<= 4; 303 mod_info->serial_num |= (temp[i] & 0xf); 304 305 mod_info->serial_str[i] = temp[i]; 306 } 307 308 mod_info->serial_str[i] = '\0'; 309 } 310 311 return 0; 312} 313