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