patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / arch / ia64 / sn / io / sn2 / klgraph.c
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved.
7  */
8
9 /*
10  * klgraph.c-
11  *      This file specifies the interface between the kernel and the PROM's
12  *      configuration data structures.
13  */
14
15 #include <linux/types.h>
16 #include <linux/slab.h>
17 #include <linux/init.h>
18 #include <asm/sn/sgi.h>
19 #include <asm/sn/sn_sal.h>
20 #include <asm/sn/iograph.h>
21 #include <asm/sn/hcl.h>
22 #include <asm/sn/hcl_util.h>
23 #include <asm/sn/sn_private.h>
24
25 /* #define KLGRAPH_DEBUG 1 */
26 #ifdef KLGRAPH_DEBUG
27 #define GRPRINTF(x)     printk x
28 #else
29 #define GRPRINTF(x)
30 #endif
31
32 void mark_cpuvertex_as_cpu(vertex_hdl_t vhdl, cpuid_t cpuid);
33
34
35 /* ARGSUSED */
36 static void __init
37 klhwg_add_hub(vertex_hdl_t node_vertex, klhub_t *hub, cnodeid_t cnode)
38 {
39         vertex_hdl_t myhubv;
40         vertex_hdl_t hub_mon;
41         int rc;
42         extern struct file_operations shub_mon_fops;
43
44         hwgraph_path_add(node_vertex, EDGE_LBL_HUB, &myhubv);
45
46         HWGRAPH_DEBUG(__FILE__, __FUNCTION__,__LINE__, myhubv, NULL, "Created path for hub vertex for Shub node.\n");
47
48         rc = device_master_set(myhubv, node_vertex);
49         if (rc) {
50                 printk("klhwg_add_hub: Unable to create hub vertex.\n");
51                 return;
52         }
53         hub_mon = hwgraph_register(myhubv, EDGE_LBL_PERFMON,
54                 0, 0, 0, 0,
55                 S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
56                 &shub_mon_fops, (void *)(long)cnode);
57 }
58
59 /* ARGSUSED */
60 static void __init
61 klhwg_add_disabled_cpu(vertex_hdl_t node_vertex, cnodeid_t cnode, klcpu_t *cpu, slotid_t slot)
62 {
63         vertex_hdl_t my_cpu;
64         char name[120];
65         cpuid_t cpu_id;
66         nasid_t nasid;
67
68         nasid = cnodeid_to_nasid(cnode);
69         cpu_id = nasid_slice_to_cpuid(nasid, cpu->cpu_info.physid);
70         if(cpu_id != -1){
71                 snprintf(name, 120, "%s/%s/%c", EDGE_LBL_DISABLED, EDGE_LBL_CPU, 'a' + cpu->cpu_info.physid);
72                 (void) hwgraph_path_add(node_vertex, name, &my_cpu);
73
74                 HWGRAPH_DEBUG(__FILE__, __FUNCTION__,__LINE__, my_cpu, NULL, "Created path for disabled cpu slice.\n");
75
76                 mark_cpuvertex_as_cpu(my_cpu, cpu_id);
77                 device_master_set(my_cpu, node_vertex);
78                 return;
79         }
80 }
81
82 /* ARGSUSED */
83 static void __init
84 klhwg_add_cpu(vertex_hdl_t node_vertex, cnodeid_t cnode, klcpu_t *cpu)
85 {
86         vertex_hdl_t my_cpu, cpu_dir;
87         char name[120];
88         cpuid_t cpu_id;
89         nasid_t nasid;
90
91         nasid = cnodeid_to_nasid(cnode);
92         cpu_id = nasid_slice_to_cpuid(nasid, cpu->cpu_info.physid);
93
94         snprintf(name, 120, "%s/%d/%c",
95                 EDGE_LBL_CPUBUS,
96                 0,
97                 'a' + cpu->cpu_info.physid);
98
99         (void) hwgraph_path_add(node_vertex, name, &my_cpu);
100
101         HWGRAPH_DEBUG(__FILE__, __FUNCTION__,__LINE__, my_cpu, NULL, "Created path for active cpu slice.\n");
102
103         mark_cpuvertex_as_cpu(my_cpu, cpu_id);
104         device_master_set(my_cpu, node_vertex);
105
106         /* Add an alias under the node's CPU directory */
107         if (hwgraph_edge_get(node_vertex, EDGE_LBL_CPU, &cpu_dir) == GRAPH_SUCCESS) {
108                 snprintf(name, 120, "%c", 'a' + cpu->cpu_info.physid);
109                 (void) hwgraph_edge_add(cpu_dir, my_cpu, name);
110                 HWGRAPH_DEBUG(__FILE__, __FUNCTION__,__LINE__, cpu_dir, my_cpu, "Created % from vhdl1 to vhdl2.\n", name);
111         }
112 }
113
114
115 static void __init
116 klhwg_add_xbow(cnodeid_t cnode, nasid_t nasid)
117 {
118         lboard_t *brd;
119         klxbow_t *xbow_p;
120         nasid_t hub_nasid;
121         cnodeid_t hub_cnode;
122         int widgetnum;
123         vertex_hdl_t xbow_v, hubv;
124         /*REFERENCED*/
125         graph_error_t err;
126
127         if (!(brd = find_lboard_nasid((lboard_t *)KL_CONFIG_INFO(nasid), 
128                         nasid, KLTYPE_IOBRICK_XBOW)))
129                 return;
130
131         if (KL_CONFIG_DUPLICATE_BOARD(brd))
132             return;
133
134         if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW))
135             == NULL)
136             return;
137
138         for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) {
139                 if (!XBOW_PORT_TYPE_HUB(xbow_p, widgetnum)) 
140                     continue;
141
142                 hub_nasid = XBOW_PORT_NASID(xbow_p, widgetnum);
143                 if (hub_nasid == INVALID_NASID) {
144                         printk(KERN_WARNING  "hub widget %d, skipping xbow graph\n", widgetnum);
145                         continue;
146                 }
147
148                 hub_cnode = nasid_to_cnodeid(hub_nasid);
149
150                 if (hub_cnode == INVALID_CNODEID) {
151                         continue;
152                 }
153                         
154                 hubv = cnodeid_to_vertex(hub_cnode);
155
156                 err = hwgraph_path_add(hubv, EDGE_LBL_XTALK, &xbow_v);
157                 if (err != GRAPH_SUCCESS) {
158                         if (err == GRAPH_DUP)
159                                 printk(KERN_WARNING  "klhwg_add_xbow: Check for "
160                                         "working routers and router links!");
161
162                         printk("klhwg_add_xbow: Failed to add "
163                                 "edge: vertex 0x%p to vertex 0x%p,"
164                                 "error %d\n",
165                                 (void *)hubv, (void *)xbow_v, err);
166                         return;
167                 }
168
169                 HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, xbow_v, NULL, "Created path for xtalk.\n");
170
171                 xswitch_vertex_init(xbow_v); 
172
173                 NODEPDA(hub_cnode)->xbow_vhdl = xbow_v;
174
175                 /*
176                  * XXX - This won't work is we ever hook up two hubs
177                  * by crosstown through a crossbow.
178                  */
179                 if (hub_nasid != nasid) {
180                         NODEPDA(hub_cnode)->xbow_peer = nasid;
181                         NODEPDA(nasid_to_cnodeid(nasid))->xbow_peer =
182                                 hub_nasid;
183                 }
184         }
185 }
186
187
188 /* ARGSUSED */
189 static void __init
190 klhwg_add_node(vertex_hdl_t hwgraph_root, cnodeid_t cnode)
191 {
192         nasid_t nasid;
193         lboard_t *brd;
194         klhub_t *hub;
195         vertex_hdl_t node_vertex = NULL;
196         char path_buffer[100];
197         int rv;
198         char *s;
199         int board_disabled = 0;
200         klcpu_t *cpu;
201         vertex_hdl_t cpu_dir;
202
203         nasid = cnodeid_to_nasid(cnode);
204         brd = find_lboard_any((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
205         ASSERT(brd);
206
207         /* Generate a hardware graph path for this board. */
208         board_to_path(brd, path_buffer);
209         rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex);
210         if (rv != GRAPH_SUCCESS) {
211                 printk("Node vertex creation failed.  Path == %s", path_buffer);
212                 return;
213         }
214
215         HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, node_vertex, NULL, "Created path for SHUB node.\n");
216         hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
217         ASSERT(hub);
218         if(hub->hub_info.flags & KLINFO_ENABLE)
219                 board_disabled = 0;
220         else
221                 board_disabled = 1;
222                 
223         if(!board_disabled) {
224                 mark_nodevertex_as_node(node_vertex, cnode);
225                 s = dev_to_name(node_vertex, path_buffer, sizeof(path_buffer));
226                 NODEPDA(cnode)->hwg_node_name =
227                                         kmalloc(strlen(s) + 1, GFP_KERNEL);
228                 if (NODEPDA(cnode)->hwg_node_name <= 0) {
229                         printk("%s: no memory\n", __FUNCTION__);
230                         return;
231                 }
232                 strcpy(NODEPDA(cnode)->hwg_node_name, s);
233                 hubinfo_set(node_vertex, NODEPDA(cnode)->pdinfo);
234                 NODEPDA(cnode)->slotdesc = brd->brd_slot;
235                 NODEPDA(cnode)->geoid = brd->brd_geoid;
236                 NODEPDA(cnode)->module = module_lookup(geo_module(brd->brd_geoid));
237                 klhwg_add_hub(node_vertex, hub, cnode);
238         }
239
240         /*
241          * If there's at least 1 CPU, add a "cpu" directory to represent
242          * the collection of all CPUs attached to this node.
243          */
244         cpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU);
245         if (cpu) {
246                 graph_error_t rv;
247
248                 rv = hwgraph_path_add(node_vertex, EDGE_LBL_CPU, &cpu_dir);
249                 if (rv != GRAPH_SUCCESS) {
250                         printk("klhwg_add_node: Cannot create CPU directory\n");
251                         return;
252                 }
253                 HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, cpu_dir, NULL, "Created cpu directiry on SHUB node.\n");
254
255         }
256
257         while (cpu) {
258                 cpuid_t cpu_id;
259                 cpu_id = nasid_slice_to_cpuid(nasid,cpu->cpu_info.physid);
260                 if (cpu_online(cpu_id))
261                         klhwg_add_cpu(node_vertex, cnode, cpu);
262                 else
263                         klhwg_add_disabled_cpu(node_vertex, cnode, cpu, brd->brd_slot);
264
265                 cpu = (klcpu_t *)
266                         find_component(brd, (klinfo_t *)cpu, KLSTRUCT_CPU);
267         }
268 }
269
270
271 /* ARGSUSED */
272 static void __init
273 klhwg_add_all_routers(vertex_hdl_t hwgraph_root)
274 {
275         nasid_t nasid;
276         cnodeid_t cnode;
277         lboard_t *brd;
278         vertex_hdl_t node_vertex;
279         char path_buffer[100];
280         int rv;
281
282         for (cnode = 0; cnode < numnodes; cnode++) {
283                 nasid = cnodeid_to_nasid(cnode);
284                 brd = find_lboard_class_any((lboard_t *)KL_CONFIG_INFO(nasid),
285                                 KLTYPE_ROUTER);
286
287                 if (!brd)
288                         /* No routers stored in this node's memory */
289                         continue;
290
291                 do {
292                         ASSERT(brd);
293
294                         /* Don't add duplicate boards. */
295                         if (brd->brd_flags & DUPLICATE_BOARD)
296                                 continue;
297
298                         /* Generate a hardware graph path for this board. */
299                         board_to_path(brd, path_buffer);
300
301                         /* Add the router */
302                         rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex);
303                         if (rv != GRAPH_SUCCESS) {
304                                 printk("Router vertex creation "
305                                                   "failed.  Path == %s", path_buffer);
306                                 return;
307                         }
308                         HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, node_vertex, NULL, "Created router path.\n");
309
310                 /* Find the rest of the routers stored on this node. */
311                 } while ( (brd = find_lboard_class_any(KLCF_NEXT_ANY(brd),
312                          KLTYPE_ROUTER)) );
313         }
314
315 }
316
317 /* ARGSUSED */
318 static void __init
319 klhwg_connect_one_router(vertex_hdl_t hwgraph_root, lboard_t *brd,
320                          cnodeid_t cnode, nasid_t nasid)
321 {
322         klrou_t *router;
323         char path_buffer[50];
324         char dest_path[50];
325         vertex_hdl_t router_hndl;
326         vertex_hdl_t dest_hndl;
327         int rc;
328         int port;
329         lboard_t *dest_brd;
330
331         /* Don't add duplicate boards. */
332         if (brd->brd_flags & DUPLICATE_BOARD) {
333                 return;
334         }
335
336         /* Generate a hardware graph path for this board. */
337         board_to_path(brd, path_buffer);
338
339         rc = hwgraph_traverse(hwgraph_root, path_buffer, &router_hndl);
340
341         if (rc != GRAPH_SUCCESS)
342                         return;
343
344         if (rc != GRAPH_SUCCESS)
345                 printk(KERN_WARNING  "Can't find router: %s", path_buffer);
346
347         /* We don't know what to do with multiple router components */
348         if (brd->brd_numcompts != 1) {
349                 printk("klhwg_connect_one_router: %d cmpts on router\n",
350                         brd->brd_numcompts);
351                 return;
352         }
353
354
355         /* Convert component 0 to klrou_t ptr */
356         router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd),
357                                               brd->brd_compts[0]);
358
359         for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
360                 /* See if the port's active */
361                 if (router->rou_port[port].port_nasid == INVALID_NASID) {
362                         GRPRINTF(("klhwg_connect_one_router: port %d inactive.\n",
363                                  port));
364                         continue;
365                 }
366                 if (nasid_to_cnodeid(router->rou_port[port].port_nasid) 
367                     == INVALID_CNODEID) {
368                         continue;
369                 }
370
371                 dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
372                                 router->rou_port[port].port_nasid,
373                                 router->rou_port[port].port_offset);
374
375                 /* Generate a hardware graph path for this board. */
376                 board_to_path(dest_brd, dest_path);
377
378                 rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl);
379
380                 if (rc != GRAPH_SUCCESS) {
381                         if (KL_CONFIG_DUPLICATE_BOARD(dest_brd))
382                                 continue;
383                         printk("Can't find router: %s", dest_path);
384                         return;
385                 }
386
387                 sprintf(dest_path, "%d", port);
388
389                 rc = hwgraph_edge_add(router_hndl, dest_hndl, dest_path);
390
391                 if (rc == GRAPH_DUP) {
392                         GRPRINTF(("Skipping port %d. nasid %d %s/%s\n",
393                                   port, router->rou_port[port].port_nasid,
394                                   path_buffer, dest_path));
395                         continue;
396                 }
397
398                 if (rc != GRAPH_SUCCESS) {
399                         printk("Can't create edge: %s/%s to vertex 0x%p error 0x%x\n",
400                                 path_buffer, dest_path, (void *)dest_hndl, rc);
401                         return;
402                 }
403                 HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, router_hndl, dest_hndl, "Created edge %s from vhdl1 to vhdl2.\n", dest_path);
404                 
405         }
406 }
407
408
409 static void __init
410 klhwg_connect_routers(vertex_hdl_t hwgraph_root)
411 {
412         nasid_t nasid;
413         cnodeid_t cnode;
414         lboard_t *brd;
415
416         for (cnode = 0; cnode < numnodes; cnode++) {
417                 nasid = cnodeid_to_nasid(cnode);
418                 brd = find_lboard_class_any((lboard_t *)KL_CONFIG_INFO(nasid),
419                                 KLTYPE_ROUTER);
420
421                 if (!brd)
422                         continue;
423
424                 do {
425
426                         nasid = cnodeid_to_nasid(cnode);
427
428                         klhwg_connect_one_router(hwgraph_root, brd,
429                                                  cnode, nasid);
430
431                 /* Find the rest of the routers stored on this node. */
432                 } while ( (brd = find_lboard_class_any(KLCF_NEXT_ANY(brd), KLTYPE_ROUTER)) );
433         }
434 }
435
436
437
438 static void __init
439 klhwg_connect_hubs(vertex_hdl_t hwgraph_root)
440 {
441         nasid_t nasid;
442         cnodeid_t cnode;
443         lboard_t *brd;
444         klhub_t *hub;
445         lboard_t *dest_brd;
446         vertex_hdl_t hub_hndl;
447         vertex_hdl_t dest_hndl;
448         char path_buffer[50];
449         char dest_path[50];
450         graph_error_t rc;
451         int port;
452
453         for (cnode = 0; cnode < numionodes; cnode++) {
454                 nasid = cnodeid_to_nasid(cnode);
455
456                 brd = find_lboard_any((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
457
458                 hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
459                 ASSERT(hub);
460
461                 for (port = 1; port <= MAX_NI_PORTS; port++) {
462                         if (hub->hub_port[port].port_nasid == INVALID_NASID) {
463                                 continue; /* Port not active */
464                         }
465
466                         if (nasid_to_cnodeid(hub->hub_port[port].port_nasid) == INVALID_CNODEID)
467                                 continue;
468
469                         /* Generate a hardware graph path for this board. */
470                         board_to_path(brd, path_buffer);
471                         rc = hwgraph_traverse(hwgraph_root, path_buffer, &hub_hndl);
472
473                         if (rc != GRAPH_SUCCESS)
474                                 printk(KERN_WARNING  "Can't find hub: %s", path_buffer);
475
476                         dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
477                                         hub->hub_port[port].port_nasid,
478                                         hub->hub_port[port].port_offset);
479
480                         /* Generate a hardware graph path for this board. */
481                         board_to_path(dest_brd, dest_path);
482
483                         rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl);
484
485                         if (rc != GRAPH_SUCCESS) {
486                                 if (KL_CONFIG_DUPLICATE_BOARD(dest_brd))
487                                         continue;
488                                 printk("Can't find board: %s", dest_path);
489                                 return;
490                         } else {
491                                 char buf[1024];
492
493                                 rc = hwgraph_path_add(hub_hndl, EDGE_LBL_INTERCONNECT, &hub_hndl);
494
495                                 HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, hub_hndl, NULL, "Created link path.\n");
496
497                                 sprintf(buf,"%s/%s",path_buffer,EDGE_LBL_INTERCONNECT);
498                                 rc = hwgraph_traverse(hwgraph_root, buf, &hub_hndl);
499                                 sprintf(buf,"%d",port);
500                                 rc = hwgraph_edge_add(hub_hndl, dest_hndl, buf);
501
502                                 HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, hub_hndl, dest_hndl, "Created edge %s from vhdl1 to vhdl2.\n", buf);
503
504                                 if (rc != GRAPH_SUCCESS) {
505                                         printk("Can't create edge: %s/%s to vertex 0x%p, error 0x%x\n",
506                                                         path_buffer, dest_path, (void *)dest_hndl, rc);
507                                         return;
508                                 }
509                         }
510                 }
511         }
512 }
513
514 void __init
515 klhwg_add_all_modules(vertex_hdl_t hwgraph_root)
516 {
517         cmoduleid_t     cm;
518         char            name[128];
519         vertex_hdl_t    vhdl;
520         vertex_hdl_t  module_vhdl;
521         int             rc;
522         char            buffer[16];
523
524         /* Add devices under each module */
525
526         for (cm = 0; cm < nummodules; cm++) {
527                 /* Use module as module vertex fastinfo */
528
529                 memset(buffer, 0, 16);
530                 format_module_id(buffer, modules[cm]->id, MODULE_FORMAT_BRIEF);
531                 sprintf(name, EDGE_LBL_MODULE "/%s", buffer);
532
533                 rc = hwgraph_path_add(hwgraph_root, name, &module_vhdl);
534                 ASSERT(rc == GRAPH_SUCCESS);
535                 rc = rc;
536                 HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, module_vhdl, NULL, "Created module path.\n");
537
538                 hwgraph_fastinfo_set(module_vhdl, (arbitrary_info_t) modules[cm]);
539
540                 /* Add system controller */
541                 sprintf(name,
542                         EDGE_LBL_MODULE "/%s/" EDGE_LBL_L1,
543                         buffer);
544
545                 rc = hwgraph_path_add(hwgraph_root, name, &vhdl);
546                 ASSERT_ALWAYS(rc == GRAPH_SUCCESS); 
547                 rc = rc;
548                 HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, vhdl, NULL, "Created L1 path.\n");
549
550                 hwgraph_info_add_LBL(vhdl, INFO_LBL_ELSC,
551                                      (arbitrary_info_t)1);
552
553         }
554 }
555
556 void __init
557 klhwg_add_all_nodes(vertex_hdl_t hwgraph_root)
558 {
559         cnodeid_t       cnode;
560
561         for (cnode = 0; cnode < numionodes; cnode++) {
562                 klhwg_add_node(hwgraph_root, cnode);
563         }
564
565         for (cnode = 0; cnode < numionodes; cnode++) {
566                 klhwg_add_xbow(cnode, cnodeid_to_nasid(cnode));
567         }
568
569         /*
570          * As for router hardware inventory information, we set this
571          * up in router.c. 
572          */
573         
574         klhwg_add_all_routers(hwgraph_root);
575         klhwg_connect_routers(hwgraph_root);
576         klhwg_connect_hubs(hwgraph_root);
577 }