File: /usr/src/linux/arch/ia64/sn/io/klgraph.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     /*
12      * klgraph.c-
13      *      This file specifies the interface between the kernel and the PROM's
14      *      configuration data structures.
15      */
16     
17     #include <linux/types.h>
18     #include <linux/config.h>
19     #include <linux/slab.h>
20     #include <asm/sn/sgi.h>
21     #include <asm/sn/iograph.h>
22     #include <asm/sn/invent.h>
23     #include <asm/sn/hcl.h>
24     #include <asm/sn/labelcl.h>
25     
26     #include <asm/sn/agent.h>
27     #include <asm/sn/kldir.h>
28     #include <asm/sn/gda.h> 
29     #include <asm/sn/klconfig.h>
30     #include <asm/sn/router.h>
31     #include <asm/sn/xtalk/xbow.h>
32     #include <asm/sn/hcl_util.h>
33     
34     /* #define KLGRAPH_DEBUG 1 */
35     #ifdef KLGRAPH_DEBUG
36     #define GRPRINTF(x)	printk x
37     #define CE_GRPANIC	CE_PANIC
38     #else
39     #define GRPRINTF(x)
40     #define CE_GRPANIC	CE_PANIC
41     #endif
42     
43     #include <asm/sn/sn_private.h>
44     
45     extern char arg_maxnodes[];
46     extern int maxnodes;
47     
48     
49     /*
50      * Support for verbose inventory via hardware graph. 
51      * klhwg_invent_alloc allocates the necessary size of inventory information
52      * and fills in the generic information.
53      */
54     invent_generic_t *
55     klhwg_invent_alloc(cnodeid_t cnode, int class, int size)
56     {
57     	invent_generic_t *invent;
58     
59     	invent = kern_malloc(size);
60     	if (!invent) return NULL;
61     	
62     	invent->ig_module = NODE_MODULEID(cnode);
63     	invent->ig_slot = SLOTNUM_GETSLOT(NODE_SLOTID(cnode));
64     	invent->ig_invclass = class;
65     
66     	return invent;
67     }
68     
69     /* 
70      * Add information about the baseio prom version number
71      * as a part of detailed inventory info in the hwgraph.
72      */
73     void
74     klhwg_baseio_inventory_add(devfs_handle_t baseio_vhdl,cnodeid_t cnode)
75     {
76     	invent_miscinfo_t	*baseio_inventory;
77     	unsigned char		version = 0,revision = 0;
78     
79     	/* Allocate memory for the "detailed inventory" info
80     	 * for the baseio
81     	 */
82     	baseio_inventory = (invent_miscinfo_t *) 
83     		klhwg_invent_alloc(cnode, INV_PROM, sizeof(invent_miscinfo_t));
84     	baseio_inventory->im_type = INV_IO6PROM;
85     	/* Read the io6prom revision from the nvram */
86     #ifdef LATER
87     	nvram_prom_version_get(&version,&revision);
88     #endif
89     	/* Store the revision info  in the inventory */
90     	baseio_inventory->im_version = version;
91     	baseio_inventory->im_rev = revision;
92     	/* Put the inventory info in the hardware graph */
93     	hwgraph_info_add_LBL(baseio_vhdl, INFO_LBL_DETAIL_INVENT, 
94     			     (arbitrary_info_t) baseio_inventory);
95     	/* Make the information available to the user programs
96     	 * thru hwgfs.
97     	 */
98             hwgraph_info_export_LBL(baseio_vhdl, INFO_LBL_DETAIL_INVENT,
99     				sizeof(invent_miscinfo_t));
100     }
101     
102     char	*hub_rev[] = {
103     	"0.0",
104     	"1.0",
105     	"2.0",
106     	"2.1",
107     	"2.2",
108     	"2.3"
109     };
110     
111     /*
112      * Add detailed cpu inventory info to the hardware graph.
113      */
114     void
115     klhwg_hub_invent_info(devfs_handle_t hubv,
116     		      cnodeid_t cnode, 
117     		      klhub_t *hub)
118     {
119     	invent_miscinfo_t *hub_invent;
120     
121     	hub_invent = (invent_miscinfo_t *) 
122     	    klhwg_invent_alloc(cnode, INV_MISC, sizeof(invent_miscinfo_t));
123     	if (!hub_invent)
124     	    return;
125     
126     	if (KLCONFIG_INFO_ENABLED((klinfo_t *)hub))
127     	    hub_invent->im_gen.ig_flag = INVENT_ENABLED;
128     
129     	hub_invent->im_type = INV_HUB;
130     	hub_invent->im_rev = hub->hub_info.revision;
131     	hub_invent->im_speed = hub->hub_speed;
132     	hwgraph_info_add_LBL(hubv, INFO_LBL_DETAIL_INVENT, 
133     			     (arbitrary_info_t) hub_invent);
134             hwgraph_info_export_LBL(hubv, INFO_LBL_DETAIL_INVENT,
135     				sizeof(invent_miscinfo_t));
136     }
137     
138     /* ARGSUSED */
139     void
140     klhwg_add_hub(devfs_handle_t node_vertex, klhub_t *hub, cnodeid_t cnode)
141     {
142     	devfs_handle_t myhubv;
143     	int rc;
144     
145     	GRPRINTF(("klhwg_add_hub: adding %s\n", EDGE_LBL_HUB));
146     
147     	(void) hwgraph_path_add(node_vertex, EDGE_LBL_HUB, &myhubv);
148     	rc = device_master_set(myhubv, node_vertex);
149     
150     #ifdef	LATER
151     	/*
152     	 * Activate when we support hub stats.
153     	 */
154     	rc = hwgraph_info_add_LBL(myhubv, INFO_LBL_HUB_INFO,
155                             (arbitrary_info_t)(&NODEPDA(cnode)->hubstats));
156     #endif
157     
158     	if (rc != GRAPH_SUCCESS) {
159     		PRINT_WARNING("klhwg_add_hub: Can't add hub info label 0x%p, code %d",
160     			myhubv, rc);
161     	}
162     
163     	klhwg_hub_invent_info(myhubv, cnode, hub);
164     
165     #ifndef BRINGUP
166     	init_hub_stats(cnode, NODEPDA(cnode));
167     	sndrv_attach(myhubv);
168     #else
169     	/*
170     	 * Need to call our driver to do the attach?
171     	 */
172     	FIXME("klhwg_add_hub: Need to add code to do the attach.\n");
173     #endif
174     }
175     
176     #ifndef BRINGUP
177     
178     void
179     klhwg_add_rps(devfs_handle_t node_vertex, cnodeid_t cnode, int flag)
180     {
181     	devfs_handle_t myrpsv;
182     	invent_rpsinfo_t *rps_invent;
183     	int rc;
184     
185             if(cnode == CNODEID_NONE)
186                     return;                                                        
187     	
188     	GRPRINTF(("klhwg_add_rps: adding %s to vertex 0x%x\n", EDGE_LBL_RPS,
189     		node_vertex));
190     
191     	rc = hwgraph_path_add(node_vertex, EDGE_LBL_RPS, &myrpsv);
192     	if (rc != GRAPH_SUCCESS)
193     		return;
194     
195     	device_master_set(myrpsv, node_vertex);
196     
197             rps_invent = (invent_rpsinfo_t *)
198                 klhwg_invent_alloc(cnode, INV_RPS, sizeof(invent_rpsinfo_t));
199     
200             if (!rps_invent)
201                 return;
202     
203     	rps_invent->ir_xbox = 0;	/* not an xbox RPS */
204     
205             if (flag)
206                 rps_invent->ir_gen.ig_flag = INVENT_ENABLED;
207             else
208                 rps_invent->ir_gen.ig_flag = 0x0;                                  
209     
210             hwgraph_info_add_LBL(myrpsv, INFO_LBL_DETAIL_INVENT,
211                                  (arbitrary_info_t) rps_invent);
212             hwgraph_info_export_LBL(myrpsv, INFO_LBL_DETAIL_INVENT,
213                                     sizeof(invent_rpsinfo_t));                     
214     	
215     }
216     
217     /*
218      * klhwg_update_rps gets invoked when the system controller sends an 
219      * interrupt indicating the power supply has lost/regained the redundancy.
220      * It's responsible for updating the Hardware graph information.
221      *	rps_state = 0 -> if the rps lost the redundancy
222      *		  = 1 -> If it is redundant. 
223      */
224     void 
225     klhwg_update_rps(cnodeid_t cnode, int rps_state)
226     {
227             devfs_handle_t node_vertex;
228             devfs_handle_t rpsv;
229             invent_rpsinfo_t *rps_invent;                                          
230             int rc;
231             if(cnode == CNODEID_NONE)
232                     return;                                                        
233     
234             node_vertex = cnodeid_to_vertex(cnode);                                
235     	rc = hwgraph_edge_get(node_vertex, EDGE_LBL_RPS, &rpsv);
236             if (rc != GRAPH_SUCCESS)  {
237     		return;
238     	}
239     
240     	rc = hwgraph_info_get_LBL(rpsv, INFO_LBL_DETAIL_INVENT, 
241     				  (arbitrary_info_t *)&rps_invent);
242             if (rc != GRAPH_SUCCESS)  {
243                     return;
244             }                                                                      
245     
246     	if (rps_state == 0 ) 
247     		rps_invent->ir_gen.ig_flag = 0;
248     	else 
249     		rps_invent->ir_gen.ig_flag = INVENT_ENABLED;
250     }
251     
252     void
253     klhwg_add_xbox_rps(devfs_handle_t node_vertex, cnodeid_t cnode, int flag)
254     {
255     	devfs_handle_t myrpsv;
256     	invent_rpsinfo_t *rps_invent;
257     	int rc;
258     
259             if(cnode == CNODEID_NONE)
260                     return;                                                        
261     	
262     	GRPRINTF(("klhwg_add_rps: adding %s to vertex 0x%x\n", 
263     		  EDGE_LBL_XBOX_RPS, node_vertex));
264     
265     	rc = hwgraph_path_add(node_vertex, EDGE_LBL_XBOX_RPS, &myrpsv);
266     	if (rc != GRAPH_SUCCESS)
267     		return;
268     
269     	device_master_set(myrpsv, node_vertex);
270     
271             rps_invent = (invent_rpsinfo_t *)
272                 klhwg_invent_alloc(cnode, INV_RPS, sizeof(invent_rpsinfo_t));
273     
274             if (!rps_invent)
275                 return;
276     
277     	rps_invent->ir_xbox = 1;	/* xbox RPS */
278     
279             if (flag)
280                 rps_invent->ir_gen.ig_flag = INVENT_ENABLED;
281             else
282                 rps_invent->ir_gen.ig_flag = 0x0;                                  
283     
284             hwgraph_info_add_LBL(myrpsv, INFO_LBL_DETAIL_INVENT,
285                                  (arbitrary_info_t) rps_invent);
286             hwgraph_info_export_LBL(myrpsv, INFO_LBL_DETAIL_INVENT,
287                                     sizeof(invent_rpsinfo_t));                     
288     	
289     }
290     
291     /*
292      * klhwg_update_xbox_rps gets invoked when the xbox system controller
293      * polls the status register and discovers that the power supply has 
294      * lost/regained the redundancy.
295      * It's responsible for updating the Hardware graph information.
296      *	rps_state = 0 -> if the rps lost the redundancy
297      *		  = 1 -> If it is redundant. 
298      */
299     void 
300     klhwg_update_xbox_rps(cnodeid_t cnode, int rps_state)
301     {
302             devfs_handle_t node_vertex;
303             devfs_handle_t rpsv;
304             invent_rpsinfo_t *rps_invent;                                          
305             int rc;
306             if(cnode == CNODEID_NONE)
307                     return;                                                        
308     
309             node_vertex = cnodeid_to_vertex(cnode);                                
310     	rc = hwgraph_edge_get(node_vertex, EDGE_LBL_XBOX_RPS, &rpsv);
311             if (rc != GRAPH_SUCCESS)  {
312     		return;
313     	}
314     
315     	rc = hwgraph_info_get_LBL(rpsv, INFO_LBL_DETAIL_INVENT, 
316     				  (arbitrary_info_t *)&rps_invent);
317             if (rc != GRAPH_SUCCESS)  {
318                     return;
319             }                                                                      
320     
321     	if (rps_state == 0 ) 
322     		rps_invent->ir_gen.ig_flag = 0;
323     	else 
324     		rps_invent->ir_gen.ig_flag = INVENT_ENABLED;
325     }
326     
327     #endif /* BRINGUP */
328     
329     void
330     klhwg_add_xbow(cnodeid_t cnode, nasid_t nasid)
331     {
332     	lboard_t *brd;
333     	klxbow_t *xbow_p;
334     	nasid_t hub_nasid;
335     	cnodeid_t hub_cnode;
336     	int widgetnum;
337     	devfs_handle_t xbow_v, hubv;
338     	/*REFERENCED*/
339     	graph_error_t err;
340     
341     #if CONFIG_SGI_IP35 || CONFIG_IA64_SGI_SN1 || defined(CONFIG_IA64_GENERIC)
342     	if ((brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid),
343     				KLTYPE_IOBRICK_XBOW)) == NULL)
344     			return;
345     #endif
346     
347     	if (KL_CONFIG_DUPLICATE_BOARD(brd))
348     	    return;
349     
350     	GRPRINTF(("klhwg_add_xbow: adding cnode %d nasid %d xbow edges\n",
351     			cnode, nasid));
352     
353     	if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW))
354     	    == NULL)
355     	    return;
356     
357     #ifdef	LATER
358     	/*
359     	 * We cannot support this function in devfs .. see below where 
360     	 * we use hwgraph_path_add() to create this vertex with a known 
361     	 * name.
362     	 */
363     	err = hwgraph_vertex_create(&xbow_v);
364     	ASSERT(err == GRAPH_SUCCESS);
365     
366     	xswitch_vertex_init(xbow_v);
367     #endif /* LATER */
368     
369     	for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) {
370     		if (!XBOW_PORT_TYPE_HUB(xbow_p, widgetnum)) 
371     		    continue;
372     
373     		hub_nasid = XBOW_PORT_NASID(xbow_p, widgetnum);
374     		if (hub_nasid == INVALID_NASID) {
375     			PRINT_WARNING("hub widget %d, skipping xbow graph\n", widgetnum);
376     			continue;
377     		}
378     
379     		hub_cnode = NASID_TO_COMPACT_NODEID(hub_nasid);
380     
381     		if (is_specified(arg_maxnodes) && hub_cnode == INVALID_CNODEID) {
382     			continue;
383     		}
384     			
385     		hubv = cnodeid_to_vertex(hub_cnode);
386     
387     		err = hwgraph_path_add(hubv, EDGE_LBL_XTALK, &xbow_v);
388                     if (err != GRAPH_SUCCESS) {
389                             if (err == GRAPH_DUP)
390                                     PRINT_WARNING("klhwg_add_xbow: Check for "
391                                             "working routers and router links!");
392     
393                             PRINT_PANIC("klhwg_add_xbow: Failed to add "
394                                     "edge: vertex 0x%p (0x%p) to vertex 0x%p (0x%p),"
395                                     "error %d\n",
396                                     hubv, hubv, xbow_v, xbow_v, err);
397                     }
398     		xswitch_vertex_init(xbow_v); 
399     
400     		NODEPDA(hub_cnode)->xbow_vhdl = xbow_v;
401     
402     		/*
403     		 * XXX - This won't work is we ever hook up two hubs
404     		 * by crosstown through a crossbow.
405     		 */
406     		if (hub_nasid != nasid) {
407     			NODEPDA(hub_cnode)->xbow_peer = nasid;
408     			NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->xbow_peer =
409     				hub_nasid;
410     		}
411     
412     		GRPRINTF(("klhwg_add_xbow: adding port nasid %d %s to vertex 0x%p\n",
413     			hub_nasid, EDGE_LBL_XTALK, hubv));
414     
415     #ifdef	LATER
416     		err = hwgraph_edge_add(hubv, xbow_v, EDGE_LBL_XTALK);
417     		if (err != GRAPH_SUCCESS) {
418     			if (err == GRAPH_DUP)
419     				PRINT_WARNING("klhwg_add_xbow: Check for "
420     					"working routers and router links!");
421     
422     			PRINT_PANIC("klhwg_add_xbow: Failed to add "
423     				"edge: vertex 0x%p (0x%p) to vertex 0x%p (0x%p), "
424     				"error %d\n",
425     				hubv, hubv, xbow_v, xbow_v, err);
426     		}
427     #endif
428     	}
429     }
430     
431     
432     /* ARGSUSED */
433     void
434     klhwg_add_node(devfs_handle_t hwgraph_root, cnodeid_t cnode, gda_t *gdap)
435     {
436     	nasid_t nasid;
437     	lboard_t *brd;
438     	klhub_t *hub;
439     	devfs_handle_t node_vertex = NULL;
440     	char path_buffer[100];
441     	int rv;
442     	char *s;
443     	int board_disabled = 0;
444     
445     	nasid = COMPACT_TO_NASID_NODEID(cnode);
446     	brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27);
447     	GRPRINTF(("klhwg_add_node: Adding cnode %d, nasid %d, brd 0x%p\n",
448                     cnode, nasid, brd));
449     	ASSERT(brd);
450     
451     	do {
452     
453     		/* Generate a hardware graph path for this board. */
454     		board_to_path(brd, path_buffer);
455     
456     		GRPRINTF(("klhwg_add_node: adding %s to vertex 0x%p\n",
457     			path_buffer, hwgraph_root));
458     		rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex);
459     
460     		if (rv != GRAPH_SUCCESS)
461     			PRINT_PANIC("Node vertex creation failed.  "
462     					  "Path == %s",
463     				path_buffer);
464     
465     		hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
466     		ASSERT(hub);
467     		if(hub->hub_info.flags & KLINFO_ENABLE)
468     			board_disabled = 0;
469     		else
470     			board_disabled = 1;
471     		
472     		if(!board_disabled) {
473     			mark_nodevertex_as_node(node_vertex,
474     					    cnode + board_disabled * numnodes);
475     
476     			s = dev_to_name(node_vertex, path_buffer, sizeof(path_buffer));
477     			NODEPDA(cnode)->hwg_node_name =
478     						kmalloc(strlen(s) + 1,
479     						GFP_KERNEL);
480     			ASSERT_ALWAYS(NODEPDA(cnode)->hwg_node_name != NULL);
481     			strcpy(NODEPDA(cnode)->hwg_node_name, s);
482     
483     			hubinfo_set(node_vertex, NODEPDA(cnode)->pdinfo);
484     
485     			/* Set up node board's slot */
486     			NODEPDA(cnode)->slotdesc = brd->brd_slot;
487     
488     			/* Set up the module we're in */
489     			NODEPDA(cnode)->module_id = brd->brd_module;
490     			NODEPDA(cnode)->module = module_lookup(brd->brd_module);
491     		}
492     
493     		if(!board_disabled)
494     		klhwg_add_hub(node_vertex, hub, cnode);
495     		
496     		brd = KLCF_NEXT(brd);
497     		if (brd)
498     			brd = find_lboard(brd, KLTYPE_IP27);
499     		else
500     			break;
501     	} while(brd);
502     }
503     
504     
505     /* ARGSUSED */
506     void
507     klhwg_add_all_routers(devfs_handle_t hwgraph_root)
508     {
509     	nasid_t nasid;
510     	cnodeid_t cnode;
511     	lboard_t *brd;
512     	devfs_handle_t node_vertex;
513     	char path_buffer[100];
514     	int rv;
515     
516     	for (cnode = 0; cnode < maxnodes; cnode++) {
517     		nasid = COMPACT_TO_NASID_NODEID(cnode);
518     
519     		GRPRINTF(("klhwg_add_all_routers: adding router on cnode %d\n",
520     			cnode));
521     
522     		brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
523     				KLTYPE_ROUTER);
524     
525     		if (!brd)
526     			/* No routers stored in this node's memory */
527     			continue;
528     
529     		do {
530     			ASSERT(brd);
531     			GRPRINTF(("Router board struct is %p\n", brd));
532     
533     			/* Don't add duplicate boards. */
534     			if (brd->brd_flags & DUPLICATE_BOARD)
535     				continue;
536     
537     			GRPRINTF(("Router 0x%p module number is %d\n", brd, brd->brd_module));
538     			/* Generate a hardware graph path for this board. */
539     			board_to_path(brd, path_buffer);
540     
541     			GRPRINTF(("Router path is %s\n", path_buffer));
542     
543     			/* Add the router */
544     			GRPRINTF(("klhwg_add_all_routers: adding %s to vertex 0x%p\n",
545     				path_buffer, hwgraph_root));
546     			rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex);
547     
548     			if (rv != GRAPH_SUCCESS)
549     				PRINT_PANIC("Router vertex creation "
550     						  "failed.  Path == %s",
551     					path_buffer);
552     
553     			GRPRINTF(("klhwg_add_all_routers: get next board from 0x%p\n",
554     					brd));
555     		/* Find the rest of the routers stored on this node. */
556     		} while ( (brd = find_lboard_class(KLCF_NEXT(brd),
557     			 KLTYPE_ROUTER)) );
558     
559     		GRPRINTF(("klhwg_add_all_routers: Done.\n"));
560     	}
561     
562     }
563     
564     /* ARGSUSED */
565     void
566     klhwg_connect_one_router(devfs_handle_t hwgraph_root, lboard_t *brd,
567     			 cnodeid_t cnode, nasid_t nasid)
568     {
569     	klrou_t *router;
570     	char path_buffer[50];
571     	char dest_path[50];
572     	devfs_handle_t router_hndl;
573     	devfs_handle_t dest_hndl;
574     	int rc;
575     	int port;
576     	lboard_t *dest_brd;
577     
578     	GRPRINTF(("klhwg_connect_one_router: Connecting router on cnode %d\n",
579     			cnode));
580     
581     	/* Don't add duplicate boards. */
582     	if (brd->brd_flags & DUPLICATE_BOARD) {
583     		GRPRINTF(("klhwg_connect_one_router: Duplicate router 0x%p on cnode %d\n",
584     			brd, cnode));
585     		return;
586     	}
587     
588     	/* Generate a hardware graph path for this board. */
589     	board_to_path(brd, path_buffer);
590     
591     	rc = hwgraph_traverse(hwgraph_root, path_buffer, &router_hndl);
592     
593     	if (rc != GRAPH_SUCCESS && is_specified(arg_maxnodes))
594     			return;
595     
596     	if (rc != GRAPH_SUCCESS)
597     		PRINT_WARNING("Can't find router: %s", path_buffer);
598     
599     	/* We don't know what to do with multiple router components */
600     	if (brd->brd_numcompts != 1) {
601     		PRINT_PANIC("klhwg_connect_one_router: %d cmpts on router\n",
602     			brd->brd_numcompts);
603     		return;
604     	}
605     
606     
607     	/* Convert component 0 to klrou_t ptr */
608     	router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd),
609     					      brd->brd_compts[0]);
610     
611     	for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
612     		/* See if the port's active */
613     		if (router->rou_port[port].port_nasid == INVALID_NASID) {
614     			GRPRINTF(("klhwg_connect_one_router: port %d inactive.\n",
615     				 port));
616     			continue;
617     		}
618     		if (is_specified(arg_maxnodes) && NASID_TO_COMPACT_NODEID(router->rou_port[port].port_nasid) 
619     		    == INVALID_CNODEID) {
620     			continue;
621     		}
622     
623     		dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
624     				router->rou_port[port].port_nasid,
625     				router->rou_port[port].port_offset);
626     
627     		/* Generate a hardware graph path for this board. */
628     		board_to_path(dest_brd, dest_path);
629     
630     		rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl);
631     
632     		if (rc != GRAPH_SUCCESS) {
633     			if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd))
634     				continue;
635     			PRINT_PANIC("Can't find router: %s", dest_path);
636     		}
637     		GRPRINTF(("klhwg_connect_one_router: Link from %s/%d to %s\n",
638     			  path_buffer, port, dest_path));
639     
640     		sprintf(dest_path, "%d", port);
641     
642     		rc = hwgraph_edge_add(router_hndl, dest_hndl, dest_path);
643     
644     		if (rc == GRAPH_DUP) {
645     			GRPRINTF(("Skipping port %d. nasid %d %s/%s\n",
646     				  port, router->rou_port[port].port_nasid,
647     				  path_buffer, dest_path));
648     			continue;
649     		}
650     
651     		if (rc != GRAPH_SUCCESS && !is_specified(arg_maxnodes))
652     			PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p error 0x%x\n",
653     				path_buffer, dest_path, dest_hndl, rc);
654     		
655     	}
656     }
657     
658     
659     void
660     klhwg_connect_routers(devfs_handle_t hwgraph_root)
661     {
662     	nasid_t nasid;
663     	cnodeid_t cnode;
664     	lboard_t *brd;
665     
666     	for (cnode = 0; cnode < maxnodes; cnode++) {
667     		nasid = COMPACT_TO_NASID_NODEID(cnode);
668     
669     		GRPRINTF(("klhwg_connect_routers: Connecting routers on cnode %d\n",
670     			cnode));
671     
672     		brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
673     				KLTYPE_ROUTER);
674     
675     		if (!brd)
676     			continue;
677     
678     		do {
679     
680     			nasid = COMPACT_TO_NASID_NODEID(cnode);
681     
682     			klhwg_connect_one_router(hwgraph_root, brd,
683     						 cnode, nasid);
684     
685     		/* Find the rest of the routers stored on this node. */
686     		} while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) );
687     	}
688     }
689     
690     
691     
692     void
693     klhwg_connect_hubs(devfs_handle_t hwgraph_root)
694     {
695     	nasid_t nasid;
696     	cnodeid_t cnode;
697     	lboard_t *brd;
698     	klhub_t *hub;
699     	lboard_t *dest_brd;
700     	devfs_handle_t hub_hndl;
701     	devfs_handle_t dest_hndl;
702     	char path_buffer[50];
703     	char dest_path[50];
704     	graph_error_t rc;
705     
706     	for (cnode = 0; cnode < maxnodes; cnode++) {
707     		nasid = COMPACT_TO_NASID_NODEID(cnode);
708     
709     		GRPRINTF(("klhwg_connect_hubs: Connecting hubs on cnode %d\n",
710     			cnode));
711     
712     		brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid),
713     				KLTYPE_IP27);
714     		ASSERT(brd);
715     
716     		hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
717     		ASSERT(hub);
718     
719     		/* See if the port's active */
720     		if (hub->hub_port.port_nasid == INVALID_NASID) {
721     			GRPRINTF(("klhwg_connect_hubs: port inactive.\n"));
722     			continue;
723     		}
724     
725     		if (is_specified(arg_maxnodes) && NASID_TO_COMPACT_NODEID(hub->hub_port.port_nasid) == INVALID_CNODEID)
726     			continue;
727     
728     		/* Generate a hardware graph path for this board. */
729     		board_to_path(brd, path_buffer);
730     
731     		GRPRINTF(("klhwg_connect_hubs: Hub path is %s.\n", path_buffer));
732     		rc = hwgraph_traverse(hwgraph_root, path_buffer, &hub_hndl);
733     
734     		if (rc != GRAPH_SUCCESS)
735     			PRINT_WARNING("Can't find hub: %s", path_buffer);
736     
737     		dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
738     				hub->hub_port.port_nasid,
739     				hub->hub_port.port_offset);
740     
741     		/* Generate a hardware graph path for this board. */
742     		board_to_path(dest_brd, dest_path);
743     
744     		rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl);
745     
746     		if (rc != GRAPH_SUCCESS) {
747     			if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd))
748     				continue;
749     			PRINT_PANIC("Can't find board: %s", dest_path);
750     		} else {
751     		
752     
753     			GRPRINTF(("klhwg_connect_hubs: Link from %s to %s.\n",
754     			  path_buffer, dest_path));
755     
756     			rc = hwgraph_edge_add(hub_hndl, dest_hndl, EDGE_LBL_INTERCONNECT);
757     
758     			if (rc != GRAPH_SUCCESS)
759     				PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p, error 0x%x\n",
760     				path_buffer, dest_path, dest_hndl, rc);
761     
762     		}
763     	}
764     }
765     
766     /* Store the pci/vme disabled board information as extended administrative
767      * hints which can later be used by the drivers using the device/driver
768      * admin interface. 
769      */
770     void
771     klhwg_device_disable_hints_add(void)
772     {
773     	cnodeid_t	cnode; 		/* node we are looking at */
774     	nasid_t		nasid;		/* nasid of the node */
775     	lboard_t	*board;		/* board we are looking at */
776     	int		comp_index;	/* component index */
777     	klinfo_t	*component;	/* component in the board we are
778     					 * looking at 
779     					 */
780     	char		device_name[MAXDEVNAME];
781     	
782     #ifdef	LATER
783     	device_admin_table_init();
784     #endif
785     	for(cnode = 0; cnode < numnodes; cnode++) {
786     		nasid = COMPACT_TO_NASID_NODEID(cnode);
787     		board = (lboard_t *)KL_CONFIG_INFO(nasid);
788     		/* Check out all the board info stored  on a node */
789     		while(board) {
790     			/* No need to look at duplicate boards or non-io 
791     			 * boards
792     			 */
793     			if (KL_CONFIG_DUPLICATE_BOARD(board) ||
794     			    KLCLASS(board->brd_type) != KLCLASS_IO) {
795     				board = KLCF_NEXT(board);
796     				continue;
797     			}
798     			/* Check out all the components of a board */
799     			for (comp_index = 0; 
800     			     comp_index < KLCF_NUM_COMPS(board);
801     			     comp_index++) {
802     				component = KLCF_COMP(board,comp_index);
803     				/* If the component is enabled move on to
804     				 * the next component
805     				 */
806     				if (KLCONFIG_INFO_ENABLED(component))
807     					continue;
808     				/* NOTE : Since the prom only supports
809     				 * the disabling of pci devices the following
810     				 * piece of code makes sense. 
811     				 * Make sure that this assumption is valid
812     				 */
813     				/* This component is disabled. Store this
814     				 * hint in the extended device admin table
815     				 */
816     				/* Get the canonical name of the pci device */
817     				device_component_canonical_name_get(board,
818     							    component,
819     							    device_name);
820     #ifdef	LATER
821     				device_admin_table_update(device_name,
822     							  ADMIN_LBL_DISABLED,
823     							  "yes");
824     #endif
825     #ifdef DEBUG
826     				printf("%s DISABLED\n",device_name);
827     #endif				
828     			}
829     			/* go to the next board info stored on this 
830     			 * node 
831     			 */
832     			board = KLCF_NEXT(board);
833     		}
834     	}
835     }
836     
837     void
838     klhwg_add_all_modules(devfs_handle_t hwgraph_root)
839     {
840     	cmoduleid_t	cm;
841     	char		name[128];
842     	devfs_handle_t	vhdl;
843     	int		rc;
844     	char		buffer[16];
845     
846     	/* Add devices under each module */
847     
848     	for (cm = 0; cm < nummodules; cm++) {
849     		/* Use module as module vertex fastinfo */
850     
851     #ifdef __ia64
852     		memset(buffer, 0, 16);
853     		format_module_id(buffer, modules[cm]->id, MODULE_FORMAT_BRIEF);
854     		sprintf(name, EDGE_LBL_MODULE "/%s", buffer);
855     #else
856     		sprintf(name, EDGE_LBL_MODULE "/%x", modules[cm]->id);
857     #endif
858     
859     		rc = hwgraph_path_add(hwgraph_root, name, &vhdl);
860     		ASSERT(rc == GRAPH_SUCCESS);
861     		rc = rc;
862     
863     		hwgraph_fastinfo_set(vhdl, (arbitrary_info_t) modules[cm]);
864     
865     		/* Add system controller */
866     
867     #ifdef __ia64
868     		sprintf(name,
869     			EDGE_LBL_MODULE "/%s/" EDGE_LBL_L1,
870     			buffer);
871     #else
872     		sprintf(name,
873     			EDGE_LBL_MODULE "/%x/" EDGE_LBL_L1,
874     			modules[cm]->id);
875     #endif
876     
877     		rc = hwgraph_path_add(hwgraph_root, name, &vhdl);
878     		ASSERT_ALWAYS(rc == GRAPH_SUCCESS); 
879     		rc = rc;
880     
881     		hwgraph_info_add_LBL(vhdl,
882     				     INFO_LBL_ELSC,
883     				     (arbitrary_info_t) (__psint_t) 1);
884     
885     #ifdef	LATER
886     		sndrv_attach(vhdl);
887     #else
888     		/*
889     		 * We need to call the drivers attach routine ..
890     		 */
891     		FIXME("klhwg_add_all_modules: Need code to call driver attach.\n");
892     #endif
893     	}
894     }
895     
896     void
897     klhwg_add_all_nodes(devfs_handle_t hwgraph_root)
898     {
899     	//gda_t		*gdap = GDA;
900     	gda_t		*gdap;
901     	cnodeid_t	cnode;
902     
903     	gdap = (gda_t *)0xe000000000002400;
904     
905     	FIXME("klhwg_add_all_nodes: FIX GDA\n");
906     
907     	for (cnode = 0; cnode < numnodes; cnode++) {
908     		ASSERT(gdap->g_nasidtable[cnode] != INVALID_NASID);
909     		klhwg_add_node(hwgraph_root, cnode, gdap);
910     	}
911     
912     	for (cnode = 0; cnode < numnodes; cnode++) {
913     		ASSERT(gdap->g_nasidtable[cnode] != INVALID_NASID);
914     
915     		klhwg_add_xbow(cnode, gdap->g_nasidtable[cnode]);
916     	}
917     
918     	/*
919     	 * As for router hardware inventory information, we set this
920     	 * up in router.c. 
921     	 */
922     	
923     	klhwg_add_all_routers(hwgraph_root);
924     	klhwg_connect_routers(hwgraph_root);
925     	klhwg_connect_hubs(hwgraph_root);
926     
927     	/* Assign guardian nodes to each of the
928     	 * routers in the system.
929     	 */
930     
931     #ifdef	LATER
932     	router_guardians_set(hwgraph_root);
933     #endif
934     
935     	/* Go through the entire system's klconfig
936     	 * to figure out which pci components have been disabled
937     	 */
938     	klhwg_device_disable_hints_add();
939     
940     }
941