1 /* $Id$
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-2003 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/module.h>
22 #include <asm/sn/pci/pcibr.h>
23 #include <asm/sn/xtalk/xswitch.h>
24 #include <asm/sn/nodepda.h>
25 #include <asm/sn/sn_cpuid.h>
26 
27 
28 /* #define LDEBUG	1  */
29 
30 #ifdef LDEBUG
31 #define DPRINTF		printk
32 #define printf		printk
33 #else
34 #define DPRINTF(x...)
35 #endif
36 
37 module_t	       *modules[MODULE_MAX];
38 int			nummodules;
39 
40 #define SN00_SERIAL_FUDGE	0x3b1af409d513c2
41 #define SN0_SERIAL_FUDGE	0x6e
42 
43 void
encode_int_serial(uint64_t src,uint64_t * dest)44 encode_int_serial(uint64_t src,uint64_t *dest)
45 {
46     uint64_t val;
47     int i;
48 
49     val = src + SN00_SERIAL_FUDGE;
50 
51 
52     for (i = 0; i < sizeof(long long); i++) {
53 	((char*)dest)[i] =
54 	    ((char*)&val)[sizeof(long long)/2 +
55 			 ((i%2) ? ((i/2 * -1) - 1) : (i/2))];
56     }
57 }
58 
59 
60 void
decode_int_serial(uint64_t src,uint64_t * dest)61 decode_int_serial(uint64_t src, uint64_t *dest)
62 {
63     uint64_t val;
64     int i;
65 
66     for (i = 0; i < sizeof(long long); i++) {
67 	((char*)&val)[sizeof(long long)/2 +
68 		     ((i%2) ? ((i/2 * -1) - 1) : (i/2))] =
69 	    ((char*)&src)[i];
70     }
71 
72     *dest = val - SN00_SERIAL_FUDGE;
73 }
74 
75 
76 void
encode_str_serial(const char * src,char * dest)77 encode_str_serial(const char *src, char *dest)
78 {
79     int i;
80 
81     for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) {
82 
83 	dest[i] = src[MAX_SERIAL_NUM_SIZE/2 +
84 		     ((i%2) ? ((i/2 * -1) - 1) : (i/2))] +
85 	    SN0_SERIAL_FUDGE;
86     }
87 }
88 
89 void
decode_str_serial(const char * src,char * dest)90 decode_str_serial(const char *src, char *dest)
91 {
92     int i;
93 
94     for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++) {
95 	dest[MAX_SERIAL_NUM_SIZE/2 +
96 	    ((i%2) ? ((i/2 * -1) - 1) : (i/2))] = src[i] -
97 	    SN0_SERIAL_FUDGE;
98     }
99 }
100 
101 
module_lookup(moduleid_t id)102 module_t *module_lookup(moduleid_t id)
103 {
104     int			i;
105 
106     for (i = 0; i < nummodules; i++)
107 	if (modules[i]->id == id) {
108 	    DPRINTF("module_lookup: found m=0x%p\n", modules[i]);
109 	    return modules[i];
110 	}
111 
112     return NULL;
113 }
114 
115 /*
116  * module_add_node
117  *
118  *   The first time a new module number is seen, a module structure is
119  *   inserted into the module list in order sorted by module number
120  *   and the structure is initialized.
121  *
122  *   The node number is added to the list of nodes in the module.
123  */
124 
module_add_node(geoid_t geoid,cnodeid_t cnodeid)125 module_t *module_add_node(geoid_t geoid, cnodeid_t cnodeid)
126 {
127     module_t	       *m;
128     int			i;
129     char		buffer[16];
130     moduleid_t		moduleid;
131     slabid_t		slab_number;
132 
133     memset(buffer, 0, 16);
134     moduleid = geo_module(geoid);
135     format_module_id(buffer, moduleid, MODULE_FORMAT_BRIEF);
136     DPRINTF("module_add_node: moduleid=%s node=%d ", buffer, cnodeid);
137 
138     if ((m = module_lookup(moduleid)) == 0) {
139 	m = kmalloc(sizeof (module_t), GFP_KERNEL);
140 	ASSERT_ALWAYS(m);
141 	memset(m, 0 , sizeof(module_t));
142 
143 	for (slab_number = 0; slab_number <= MAX_SLABS; slab_number++) {
144 		m->nodes[slab_number] = -1;
145 	}
146 
147 	m->id = moduleid;
148 	spin_lock_init(&m->lock);
149 
150 	init_MUTEX_LOCKED(&m->thdcnt);
151 
152 	/* Insert in sorted order by module number */
153 
154 	for (i = nummodules; i > 0 && modules[i - 1]->id > moduleid; i--)
155 	    modules[i] = modules[i - 1];
156 
157 	modules[i] = m;
158 	nummodules++;
159     }
160 
161     /*
162      * Save this information in the correct slab number of the node in the
163      * module.
164      */
165     slab_number = geo_slab(geoid);
166     DPRINTF("slab number added 0x%x\n", slab_number);
167 
168     if (m->nodes[slab_number] != -1)
169 	panic("module_add_node .. slab previously found\n");
170 
171     m->nodes[slab_number] = cnodeid;
172     m->geoid[slab_number] = geoid;
173 
174     return m;
175 }
176 
module_probe_snum(module_t * m,nasid_t host_nasid,nasid_t nasid)177 int module_probe_snum(module_t *m, nasid_t host_nasid, nasid_t nasid)
178 {
179     lboard_t	       *board;
180     klmod_serial_num_t *comp;
181     char * bcopy(const char * src, char * dest, int count);
182     char serial_number[16];
183 
184     /*
185      * record brick serial number
186      */
187     board = find_lboard((lboard_t *) KL_CONFIG_INFO(host_nasid), KLTYPE_SNIA);
188 
189     if (! board || KL_CONFIG_DUPLICATE_BOARD(board))
190     {
191 #if	LDEBUG
192 	printf ("module_probe_snum: no IP35 board found!\n");
193 #endif
194 	return 0;
195     }
196 
197     board_serial_number_get( board, serial_number );
198     if( serial_number[0] != '\0' ) {
199 	encode_str_serial( serial_number, m->snum.snum_str );
200 	m->snum_valid = 1;
201     }
202 #if	LDEBUG
203     else {
204 	printf("module_probe_snum: brick serial number is null!\n");
205     }
206     printf("module_probe_snum: brick serial number == %s\n", serial_number);
207 #endif /* DEBUG */
208 
209     board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid),
210 			KLTYPE_IOBRICK_XBOW);
211 
212     if (! board || KL_CONFIG_DUPLICATE_BOARD(board))
213 	return 0;
214 
215     comp = GET_SNUM_COMP(board);
216 
217     if (comp) {
218 #if LDEBUG
219 	    int i;
220 
221 	    printf("********found module with id %x and string", m->id);
222 
223 	    for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++)
224 		printf(" %x ", comp->snum.snum_str[i]);
225 
226 	    printf("\n");	/* Fudged string is not ASCII */
227 #endif
228 
229 	    if (comp->snum.snum_str[0] != '\0') {
230 		bcopy(comp->snum.snum_str,
231 		      m->sys_snum,
232 		      MAX_SERIAL_NUM_SIZE);
233 		m->sys_snum_valid = 1;
234 	    }
235     }
236 
237     if (m->sys_snum_valid)
238 	return 1;
239     else {
240 	DPRINTF("Invalid serial number for module %d, "
241 		"possible missing or invalid NIC.", m->id);
242 	return 0;
243     }
244 }
245 
246 void
io_module_init(void)247 io_module_init(void)
248 {
249     cnodeid_t		node;
250     lboard_t	       *board;
251     nasid_t		nasid;
252     int			nserial;
253     module_t	       *m;
254 
255     DPRINTF("*******module_init\n");
256 
257     nserial = 0;
258 
259     /*
260      * First pass just scan for compute node boards KLTYPE_SNIA.
261      * We do not support memoryless compute nodes.
262      */
263     for (node = 0; node < numnodes; node++) {
264 	nasid = COMPACT_TO_NASID_NODEID(node);
265 	board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
266 	ASSERT(board);
267 
268 	HWGRAPH_DEBUG((__FILE__, __FUNCTION__, __LINE__, NULL, NULL, "Found Shub lboard 0x%lx nasid 0x%x cnode 0x%x \n", (unsigned long)board, (int)nasid, (int)node));
269 
270 	m = module_add_node(board->brd_geoid, node);
271 	if (! m->snum_valid && module_probe_snum(m, nasid, nasid))
272 	    nserial++;
273     }
274 
275     /*
276      * Second scan, look for TIO's board hosted by compute nodes.
277      */
278     for (node = numnodes; node < numionodes; node++) {
279 	nasid_t		tio_nasid;
280 	cnodeid_t	tio_node;
281 	char		serial_number[16];
282 
283         tio_nasid = COMPACT_TO_NASID_NODEID(node);
284         board = find_lboard((lboard_t *) KL_CONFIG_INFO(tio_nasid), KLTYPE_TIO);
285 	ASSERT(board);
286 	tio_node = NASID_TO_COMPACT_NODEID(tio_nasid);
287 
288 	HWGRAPH_DEBUG((__FILE__, __FUNCTION__, __LINE__, NULL, NULL, "Found TIO lboard 0x%lx tio nasid %d tio cnode %d\n", (unsigned long)board, (int)tio_nasid, (int)tio_node));
289 
290         m = module_add_node(board->brd_geoid, tio_node);
291 
292 	/*
293 	 * Get and initialize the serial number of TIO.
294 	 */
295 	board_serial_number_get( board, serial_number );
296     	if( serial_number[0] != '\0' ) {
297         	encode_str_serial( serial_number, m->snum.snum_str );
298         	m->snum_valid = 1;
299 		nserial++;
300 	}
301     }
302 }
303