File: /usr/src/linux/arch/ia64/sn/io/module.c
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 Silicon Graphics, Inc.
8 * Copyright (C) 2000 by Colin Ngam
9 */
10
11 #include <linux/types.h>
12 #include <linux/slab.h>
13 #include <asm/sn/sgi.h>
14 #include <asm/sn/invent.h>
15 #include <asm/sn/hcl.h>
16 #include <asm/sn/labelcl.h>
17 #include <asm/sn/xtalk/xbow.h>
18 #include <asm/sn/pci/bridge.h>
19 #include <asm/sn/klconfig.h>
20 #include <asm/sn/sn1/hubdev.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
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
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
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
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
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
125 module_t *module_add_node(moduleid_t id, cnodeid_t n)
126 {
127 module_t *m;
128 int i;
129 char buffer[16];
130
131 #ifdef __ia64
132 memset(buffer, 0, 16);
133 format_module_id(buffer, id, MODULE_FORMAT_BRIEF);
134 DPRINTF("module_add_node: id=%s node=%d\n", buffer, n);
135 #endif
136
137 if ((m = module_lookup(id)) == 0) {
138 #ifdef LATER
139 m = kmem_zalloc_node(sizeof (module_t), KM_NOSLEEP, n);
140 #else
141 m = kmalloc(sizeof (module_t), GFP_KERNEL);
142 memset(m, 0 , sizeof(module_t));
143 #endif
144 ASSERT_ALWAYS(m);
145
146 m->id = id;
147 spin_lock_init(&m->lock);
148
149 mutex_init_locked(&m->thdcnt);
150
151 // set_elsc(&m->elsc);
152 elsc_init(&m->elsc, COMPACT_TO_NASID_NODEID(n));
153 spin_lock_init(&m->elsclock);
154
155 /* Insert in sorted order by module number */
156
157 for (i = nummodules; i > 0 && modules[i - 1]->id > id; i--)
158 modules[i] = modules[i - 1];
159
160 modules[i] = m;
161 nummodules++;
162 }
163
164 m->nodes[m->nodecnt++] = n;
165
166 DPRINTF("module_add_node: module %s now has %d nodes\n", buffer, m->nodecnt);
167
168 return m;
169 }
170
171 int module_probe_snum(module_t *m, nasid_t nasid)
172 {
173 lboard_t *board;
174 klmod_serial_num_t *comp;
175 char * bcopy(const char * src, char * dest, int count);
176
177 board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid),
178 KLTYPE_MIDPLANE8);
179
180 if (! board || KL_CONFIG_DUPLICATE_BOARD(board))
181 return 0;
182
183 comp = GET_SNUM_COMP(board);
184
185 if (comp) {
186 #if LDEBUG
187 int i;
188
189 printf("********found module with id %x and string", m->id);
190
191 for (i = 0; i < MAX_SERIAL_NUM_SIZE; i++)
192 printf(" %x ", comp->snum.snum_str[i]);
193
194 printf("\n"); /* Fudged string is not ASCII */
195 #endif
196
197 if (comp->snum.snum_str[0] != '\0') {
198 bcopy(comp->snum.snum_str,
199 m->snum.snum_str,
200 MAX_SERIAL_NUM_SIZE);
201 m->snum_valid = 1;
202 }
203 }
204
205 if (m->snum_valid)
206 return 1;
207 else {
208 DPRINTF("Invalid serial number for module %d, "
209 "possible missing or invalid NIC.", m->id);
210 return 0;
211 }
212 }
213
214 void
215 io_module_init(void)
216 {
217 cnodeid_t node;
218 lboard_t *board;
219 nasid_t nasid;
220 int nserial;
221 module_t *m;
222
223 DPRINTF("*******module_init\n");
224
225 nserial = 0;
226
227 for (node = 0; node < numnodes; node++) {
228 nasid = COMPACT_TO_NASID_NODEID(node);
229
230 board = find_lboard((lboard_t *) KL_CONFIG_INFO(nasid),
231 KLTYPE_IP27);
232 ASSERT(board);
233
234 m = module_add_node(board->brd_module, node);
235
236 if (! m->snum_valid && module_probe_snum(m, nasid))
237 nserial++;
238 }
239
240 DPRINTF("********found total of %d serial numbers in the system\n",
241 nserial);
242
243 if (nserial == 0)
244 PRINT_WARNING("io_module_init: No serial number found.\n");
245 }
246
247 elsc_t *get_elsc(void)
248 {
249 return &NODEPDA(cpuid_to_cnodeid(smp_processor_id()))->module->elsc;
250 }
251
252 int
253 get_kmod_info(cmoduleid_t cmod, module_info_t *mod_info)
254 {
255 int i;
256
257 if (cmod < 0 || cmod >= nummodules)
258 return EINVAL;
259
260 if (! modules[cmod]->snum_valid)
261 return ENXIO;
262
263 mod_info->mod_num = modules[cmod]->id;
264 {
265 char temp[MAX_SERIAL_NUM_SIZE];
266
267 decode_str_serial(modules[cmod]->snum.snum_str, temp);
268
269 /* if this is an invalid serial number return an error */
270 if (temp[0] != 'K')
271 return ENXIO;
272
273 mod_info->serial_num = 0;
274
275 for (i = 0; i < MAX_SERIAL_NUM_SIZE && temp[i] != '\0'; i++) {
276 mod_info->serial_num <<= 4;
277 mod_info->serial_num |= (temp[i] & 0xf);
278
279 mod_info->serial_str[i] = temp[i];
280 }
281
282 mod_info->serial_str[i] = '\0';
283 }
284
285 return 0;
286 }
287