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