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
7 * Copyright (C) 1992 - 1997, 2000-2002 Silicon Graphics, Inc. All rights reserved.
12 * This file specifies the interface between the kernel and the PROM's
13 * configuration data structures.
16 #include <linux/types.h>
17 #include <linux/config.h>
18 #include <linux/slab.h>
19 #include <asm/sn/sgi.h>
20 #include <asm/sn/sn_sal.h>
21 #include <asm/sn/io.h>
22 #include <asm/sn/iograph.h>
23 #include <asm/sn/invent.h>
24 #include <asm/sn/hcl.h>
25 #include <asm/sn/labelcl.h>
26 #include <asm/sn/kldir.h>
27 #include <asm/sn/gda.h>
28 #include <asm/sn/klconfig.h>
29 #include <asm/sn/router.h>
30 #include <asm/sn/xtalk/xbow.h>
31 #include <asm/sn/hcl_util.h>
33 /* #define KLGRAPH_DEBUG 1 */
35 #define GRPRINTF(x) printk x
36 #define CE_GRPANIC CE_PANIC
39 #define CE_GRPANIC CE_PANIC
42 #include <asm/sn/sn_private.h>
44 extern char arg_maxnodes[];
45 extern u64 klgraph_addr[];
48 * Support for verbose inventory via hardware graph.
49 * klhwg_invent_alloc allocates the necessary size of inventory information
50 * and fills in the generic information.
53 klhwg_invent_alloc(cnodeid_t cnode, int class, int size)
55 invent_generic_t *invent;
57 invent = kern_malloc(size);
58 if (!invent) return NULL;
60 invent->ig_module = NODE_MODULEID(cnode);
61 invent->ig_slot = SLOTNUM_GETSLOT(NODE_SLOTID(cnode));
62 invent->ig_invclass = class;
68 * Add information about the baseio prom version number
69 * as a part of detailed inventory info in the hwgraph.
72 klhwg_baseio_inventory_add(devfs_handle_t baseio_vhdl,cnodeid_t cnode)
74 invent_miscinfo_t *baseio_inventory;
75 unsigned char version = 0,revision = 0;
77 /* Allocate memory for the "detailed inventory" info
80 baseio_inventory = (invent_miscinfo_t *)
81 klhwg_invent_alloc(cnode, INV_PROM, sizeof(invent_miscinfo_t));
82 baseio_inventory->im_type = INV_IO6PROM;
83 /* Read the io6prom revision from the nvram */
85 nvram_prom_version_get(&version,&revision);
87 /* Store the revision info in the inventory */
88 baseio_inventory->im_version = version;
89 baseio_inventory->im_rev = revision;
90 /* Put the inventory info in the hardware graph */
91 hwgraph_info_add_LBL(baseio_vhdl, INFO_LBL_DETAIL_INVENT,
92 (arbitrary_info_t) baseio_inventory);
93 /* Make the information available to the user programs
96 hwgraph_info_export_LBL(baseio_vhdl, INFO_LBL_DETAIL_INVENT,
97 sizeof(invent_miscinfo_t));
110 * Add detailed cpu inventory info to the hardware graph.
113 klhwg_hub_invent_info(devfs_handle_t hubv,
117 invent_miscinfo_t *hub_invent;
119 hub_invent = (invent_miscinfo_t *)
120 klhwg_invent_alloc(cnode, INV_MISC, sizeof(invent_miscinfo_t));
124 if (KLCONFIG_INFO_ENABLED((klinfo_t *)hub))
125 hub_invent->im_gen.ig_flag = INVENT_ENABLED;
127 hub_invent->im_type = INV_HUB;
128 hub_invent->im_rev = hub->hub_info.revision;
129 hub_invent->im_speed = hub->hub_speed;
130 hwgraph_info_add_LBL(hubv, INFO_LBL_DETAIL_INVENT,
131 (arbitrary_info_t) hub_invent);
132 hwgraph_info_export_LBL(hubv, INFO_LBL_DETAIL_INVENT,
133 sizeof(invent_miscinfo_t));
138 klhwg_add_hub(devfs_handle_t node_vertex, klhub_t *hub, cnodeid_t cnode)
140 #if defined(CONFIG_IA64_SGI_SN1)
141 devfs_handle_t myhubv;
142 devfs_handle_t hub_mon;
143 devfs_handle_t synergy;
147 extern struct file_operations hub_mon_fops;
149 GRPRINTF(("klhwg_add_hub: adding %s\n", EDGE_LBL_HUB));
151 (void) hwgraph_path_add(node_vertex, EDGE_LBL_HUB, &myhubv);
152 rc = device_master_set(myhubv, node_vertex);
157 rc = hwgraph_info_add_LBL(myhubv, INFO_LBL_HUB_INFO,
158 (arbitrary_info_t)(&NODEPDA(cnode)->hubstats));
160 if (rc != GRAPH_SUCCESS) {
161 printk(KERN_WARNING "klhwg_add_hub: Can't add hub info label 0x%p, code %d",
165 klhwg_hub_invent_info(myhubv, cnode, hub);
167 hub_mon = hwgraph_register(myhubv, EDGE_LBL_PERFMON,
168 0, DEVFS_FL_AUTO_DEVNUM,
170 S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
172 (void *)(long)cnode);
174 init_hub_stats(cnode, NODEPDA(cnode));
179 (void) hwgraph_path_add(myhubv, EDGE_LBL_SYNERGY, &synergy);
180 (void) hwgraph_path_add(synergy, "0", &fsb0);
181 (void) hwgraph_path_add(synergy, "1", &fsb1);
183 fsb0 = hwgraph_register(fsb0, EDGE_LBL_PERFMON,
184 0, DEVFS_FL_AUTO_DEVNUM,
186 S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
187 &synergy_mon_fops, (void *)SYNERGY_PERF_INFO(cnode, 0));
189 fsb1 = hwgraph_register(fsb1, EDGE_LBL_PERFMON,
190 0, DEVFS_FL_AUTO_DEVNUM,
192 S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
193 &synergy_mon_fops, (void *)SYNERGY_PERF_INFO(cnode, 1));
194 #endif /* CONFIG_IA64_SGI_SN1 */
198 klhwg_add_xbow(cnodeid_t cnode, nasid_t nasid)
205 devfs_handle_t xbow_v, hubv;
209 if ((brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IOBRICK_XBOW)) == NULL)
212 if (KL_CONFIG_DUPLICATE_BOARD(brd))
215 GRPRINTF(("klhwg_add_xbow: adding cnode %d nasid %d xbow edges\n",
218 if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW))
224 * We cannot support this function in devfs .. see below where
225 * we use hwgraph_path_add() to create this vertex with a known
228 err = hwgraph_vertex_create(&xbow_v);
229 ASSERT(err == GRAPH_SUCCESS);
231 xswitch_vertex_init(xbow_v);
234 for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) {
235 if (!XBOW_PORT_TYPE_HUB(xbow_p, widgetnum))
238 hub_nasid = XBOW_PORT_NASID(xbow_p, widgetnum);
239 if (hub_nasid == INVALID_NASID) {
240 printk(KERN_WARNING "hub widget %d, skipping xbow graph\n", widgetnum);
244 hub_cnode = NASID_TO_COMPACT_NODEID(hub_nasid);
246 if (is_specified(arg_maxnodes) && hub_cnode == INVALID_CNODEID) {
250 hubv = cnodeid_to_vertex(hub_cnode);
252 err = hwgraph_path_add(hubv, EDGE_LBL_XTALK, &xbow_v);
253 if (err != GRAPH_SUCCESS) {
254 if (err == GRAPH_DUP)
255 printk(KERN_WARNING "klhwg_add_xbow: Check for "
256 "working routers and router links!");
258 PRINT_PANIC("klhwg_add_xbow: Failed to add "
259 "edge: vertex 0x%p to vertex 0x%p,"
261 (void *)hubv, (void *)xbow_v, err);
263 xswitch_vertex_init(xbow_v);
265 NODEPDA(hub_cnode)->xbow_vhdl = xbow_v;
268 * XXX - This won't work is we ever hook up two hubs
269 * by crosstown through a crossbow.
271 if (hub_nasid != nasid) {
272 NODEPDA(hub_cnode)->xbow_peer = nasid;
273 NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->xbow_peer =
277 GRPRINTF(("klhwg_add_xbow: adding port nasid %d %s to vertex 0x%p\n",
278 hub_nasid, EDGE_LBL_XTALK, hubv));
281 err = hwgraph_edge_add(hubv, xbow_v, EDGE_LBL_XTALK);
282 if (err != GRAPH_SUCCESS) {
283 if (err == GRAPH_DUP)
284 printk(KERN_WARNING "klhwg_add_xbow: Check for "
285 "working routers and router links!");
287 PRINT_PANIC("klhwg_add_xbow: Failed to add "
288 "edge: vertex 0x%p (0x%p) to vertex 0x%p (0x%p), "
290 hubv, hubv, xbow_v, xbow_v, err);
299 klhwg_add_node(devfs_handle_t hwgraph_root, cnodeid_t cnode, gda_t *gdap)
304 devfs_handle_t node_vertex = NULL;
305 char path_buffer[100];
308 int board_disabled = 0;
310 nasid = COMPACT_TO_NASID_NODEID(cnode);
311 brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
312 GRPRINTF(("klhwg_add_node: Adding cnode %d, nasid %d, brd 0x%p\n",
318 /* Generate a hardware graph path for this board. */
319 board_to_path(brd, path_buffer);
321 GRPRINTF(("klhwg_add_node: adding %s to vertex 0x%p\n",
322 path_buffer, hwgraph_root));
323 rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex);
325 if (rv != GRAPH_SUCCESS)
326 PRINT_PANIC("Node vertex creation failed. "
330 hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
332 if(hub->hub_info.flags & KLINFO_ENABLE)
337 if(!board_disabled) {
338 mark_nodevertex_as_node(node_vertex,
339 cnode + board_disabled * numnodes);
341 s = dev_to_name(node_vertex, path_buffer, sizeof(path_buffer));
342 NODEPDA(cnode)->hwg_node_name =
343 kmalloc(strlen(s) + 1,
345 ASSERT_ALWAYS(NODEPDA(cnode)->hwg_node_name != NULL);
346 strcpy(NODEPDA(cnode)->hwg_node_name, s);
348 hubinfo_set(node_vertex, NODEPDA(cnode)->pdinfo);
350 /* Set up node board's slot */
351 NODEPDA(cnode)->slotdesc = brd->brd_slot;
353 /* Set up the module we're in */
354 NODEPDA(cnode)->module_id = brd->brd_module;
355 NODEPDA(cnode)->module = module_lookup(brd->brd_module);
359 klhwg_add_hub(node_vertex, hub, cnode);
361 brd = KLCF_NEXT(brd);
363 brd = find_lboard(brd, KLTYPE_SNIA);
372 klhwg_add_all_routers(devfs_handle_t hwgraph_root)
377 devfs_handle_t node_vertex;
378 char path_buffer[100];
381 for (cnode = 0; cnode < numnodes; cnode++) {
382 nasid = COMPACT_TO_NASID_NODEID(cnode);
384 GRPRINTF(("klhwg_add_all_routers: adding router on cnode %d\n",
387 brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
391 /* No routers stored in this node's memory */
396 GRPRINTF(("Router board struct is %p\n", brd));
398 /* Don't add duplicate boards. */
399 if (brd->brd_flags & DUPLICATE_BOARD)
402 GRPRINTF(("Router 0x%p module number is %d\n", brd, brd->brd_module));
403 /* Generate a hardware graph path for this board. */
404 board_to_path(brd, path_buffer);
406 GRPRINTF(("Router path is %s\n", path_buffer));
409 GRPRINTF(("klhwg_add_all_routers: adding %s to vertex 0x%p\n",
410 path_buffer, hwgraph_root));
411 rv = hwgraph_path_add(hwgraph_root, path_buffer, &node_vertex);
413 if (rv != GRAPH_SUCCESS)
414 PRINT_PANIC("Router vertex creation "
415 "failed. Path == %s",
418 GRPRINTF(("klhwg_add_all_routers: get next board from 0x%p\n",
420 /* Find the rest of the routers stored on this node. */
421 } while ( (brd = find_lboard_class(KLCF_NEXT(brd),
424 GRPRINTF(("klhwg_add_all_routers: Done.\n"));
431 klhwg_connect_one_router(devfs_handle_t hwgraph_root, lboard_t *brd,
432 cnodeid_t cnode, nasid_t nasid)
435 char path_buffer[50];
437 devfs_handle_t router_hndl;
438 devfs_handle_t dest_hndl;
443 GRPRINTF(("klhwg_connect_one_router: Connecting router on cnode %d\n",
446 /* Don't add duplicate boards. */
447 if (brd->brd_flags & DUPLICATE_BOARD) {
448 GRPRINTF(("klhwg_connect_one_router: Duplicate router 0x%p on cnode %d\n",
453 /* Generate a hardware graph path for this board. */
454 board_to_path(brd, path_buffer);
456 rc = hwgraph_traverse(hwgraph_root, path_buffer, &router_hndl);
458 if (rc != GRAPH_SUCCESS && is_specified(arg_maxnodes))
461 if (rc != GRAPH_SUCCESS)
462 printk(KERN_WARNING "Can't find router: %s", path_buffer);
464 /* We don't know what to do with multiple router components */
465 if (brd->brd_numcompts != 1) {
466 PRINT_PANIC("klhwg_connect_one_router: %d cmpts on router\n",
472 /* Convert component 0 to klrou_t ptr */
473 router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd),
476 for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
477 /* See if the port's active */
478 if (router->rou_port[port].port_nasid == INVALID_NASID) {
479 GRPRINTF(("klhwg_connect_one_router: port %d inactive.\n",
483 if (is_specified(arg_maxnodes) && NASID_TO_COMPACT_NODEID(router->rou_port[port].port_nasid)
484 == INVALID_CNODEID) {
488 dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
489 router->rou_port[port].port_nasid,
490 router->rou_port[port].port_offset);
492 /* Generate a hardware graph path for this board. */
493 board_to_path(dest_brd, dest_path);
495 rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl);
497 if (rc != GRAPH_SUCCESS) {
498 if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd))
500 PRINT_PANIC("Can't find router: %s", dest_path);
502 GRPRINTF(("klhwg_connect_one_router: Link from %s/%d to %s\n",
503 path_buffer, port, dest_path));
505 sprintf(dest_path, "%d", port);
507 rc = hwgraph_edge_add(router_hndl, dest_hndl, dest_path);
509 if (rc == GRAPH_DUP) {
510 GRPRINTF(("Skipping port %d. nasid %d %s/%s\n",
511 port, router->rou_port[port].port_nasid,
512 path_buffer, dest_path));
516 if (rc != GRAPH_SUCCESS && !is_specified(arg_maxnodes))
517 PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p error 0x%x\n",
518 path_buffer, dest_path, (void *)dest_hndl, rc);
525 klhwg_connect_routers(devfs_handle_t hwgraph_root)
531 for (cnode = 0; cnode < numnodes; cnode++) {
532 nasid = COMPACT_TO_NASID_NODEID(cnode);
534 GRPRINTF(("klhwg_connect_routers: Connecting routers on cnode %d\n",
537 brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
545 nasid = COMPACT_TO_NASID_NODEID(cnode);
547 klhwg_connect_one_router(hwgraph_root, brd,
550 /* Find the rest of the routers stored on this node. */
551 } while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) );
558 klhwg_connect_hubs(devfs_handle_t hwgraph_root)
565 devfs_handle_t hub_hndl;
566 devfs_handle_t dest_hndl;
567 char path_buffer[50];
571 for (cnode = 0; cnode < numnodes; cnode++) {
572 nasid = COMPACT_TO_NASID_NODEID(cnode);
574 GRPRINTF(("klhwg_connect_hubs: Connecting hubs on cnode %d\n",
577 brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
580 hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
583 /* See if the port's active */
584 if (hub->hub_port.port_nasid == INVALID_NASID) {
585 GRPRINTF(("klhwg_connect_hubs: port inactive.\n"));
589 if (is_specified(arg_maxnodes) && NASID_TO_COMPACT_NODEID(hub->hub_port.port_nasid) == INVALID_CNODEID)
592 /* Generate a hardware graph path for this board. */
593 board_to_path(brd, path_buffer);
595 GRPRINTF(("klhwg_connect_hubs: Hub path is %s.\n", path_buffer));
596 rc = hwgraph_traverse(hwgraph_root, path_buffer, &hub_hndl);
598 if (rc != GRAPH_SUCCESS)
599 printk(KERN_WARNING "Can't find hub: %s", path_buffer);
601 dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
602 hub->hub_port.port_nasid,
603 hub->hub_port.port_offset);
605 /* Generate a hardware graph path for this board. */
606 board_to_path(dest_brd, dest_path);
608 rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl);
610 if (rc != GRAPH_SUCCESS) {
611 if (is_specified(arg_maxnodes) && KL_CONFIG_DUPLICATE_BOARD(dest_brd))
613 PRINT_PANIC("Can't find board: %s", dest_path);
617 GRPRINTF(("klhwg_connect_hubs: Link from %s to %s.\n",
618 path_buffer, dest_path));
620 rc = hwgraph_edge_add(hub_hndl, dest_hndl, EDGE_LBL_INTERCONNECT);
622 if (rc != GRAPH_SUCCESS)
623 PRINT_PANIC("Can't create edge: %s/%s to vertex 0x%p, error 0x%x\n",
624 path_buffer, dest_path, (void *)dest_hndl, rc);
630 /* Store the pci/vme disabled board information as extended administrative
631 * hints which can later be used by the drivers using the device/driver
635 klhwg_device_disable_hints_add(void)
637 cnodeid_t cnode; /* node we are looking at */
638 nasid_t nasid; /* nasid of the node */
639 lboard_t *board; /* board we are looking at */
640 int comp_index; /* component index */
641 klinfo_t *component; /* component in the board we are
644 char device_name[MAXDEVNAME];
647 device_admin_table_init();
649 for(cnode = 0; cnode < numnodes; cnode++) {
650 nasid = COMPACT_TO_NASID_NODEID(cnode);
651 board = (lboard_t *)KL_CONFIG_INFO(nasid);
652 /* Check out all the board info stored on a node */
654 /* No need to look at duplicate boards or non-io
657 if (KL_CONFIG_DUPLICATE_BOARD(board) ||
658 KLCLASS(board->brd_type) != KLCLASS_IO) {
659 board = KLCF_NEXT(board);
662 /* Check out all the components of a board */
664 comp_index < KLCF_NUM_COMPS(board);
666 component = KLCF_COMP(board,comp_index);
667 /* If the component is enabled move on to
670 if (KLCONFIG_INFO_ENABLED(component))
672 /* NOTE : Since the prom only supports
673 * the disabling of pci devices the following
674 * piece of code makes sense.
675 * Make sure that this assumption is valid
677 /* This component is disabled. Store this
678 * hint in the extended device admin table
680 /* Get the canonical name of the pci device */
681 device_component_canonical_name_get(board,
685 device_admin_table_update(device_name,
690 printf("%s DISABLED\n",device_name);
693 /* go to the next board info stored on this
696 board = KLCF_NEXT(board);
702 klhwg_add_all_modules(devfs_handle_t hwgraph_root)
710 /* Add devices under each module */
712 for (cm = 0; cm < nummodules; cm++) {
713 /* Use module as module vertex fastinfo */
716 memset(buffer, 0, 16);
717 format_module_id(buffer, modules[cm]->id, MODULE_FORMAT_BRIEF);
718 sprintf(name, EDGE_LBL_MODULE "/%s", buffer);
720 sprintf(name, EDGE_LBL_MODULE "/%x", modules[cm]->id);
723 rc = hwgraph_path_add(hwgraph_root, name, &vhdl);
724 ASSERT(rc == GRAPH_SUCCESS);
727 hwgraph_fastinfo_set(vhdl, (arbitrary_info_t) modules[cm]);
729 /* Add system controller */
733 EDGE_LBL_MODULE "/%s/" EDGE_LBL_L1,
737 EDGE_LBL_MODULE "/%x/" EDGE_LBL_L1,
741 rc = hwgraph_path_add(hwgraph_root, name, &vhdl);
742 ASSERT_ALWAYS(rc == GRAPH_SUCCESS);
745 hwgraph_info_add_LBL(vhdl,
747 (arbitrary_info_t) (__psint_t) 1);
753 * We need to call the drivers attach routine ..
755 FIXME("klhwg_add_all_modules: Need code to call driver attach.\n");
761 klhwg_add_all_nodes(devfs_handle_t hwgraph_root)
767 gdap = (gda_t *)0xe000000000002400;
769 FIXME("klhwg_add_all_nodes: FIX GDA\n");
771 for (cnode = 0; cnode < numnodes; cnode++) {
772 ASSERT(gdap->g_nasidtable[cnode] != INVALID_NASID);
773 klhwg_add_node(hwgraph_root, cnode, gdap);
776 for (cnode = 0; cnode < numnodes; cnode++) {
777 ASSERT(gdap->g_nasidtable[cnode] != INVALID_NASID);
779 klhwg_add_xbow(cnode, gdap->g_nasidtable[cnode]);
783 * As for router hardware inventory information, we set this
787 klhwg_add_all_routers(hwgraph_root);
788 klhwg_connect_routers(hwgraph_root);
789 klhwg_connect_hubs(hwgraph_root);
791 /* Assign guardian nodes to each of the
792 * routers in the system.
796 router_guardians_set(hwgraph_root);
799 /* Go through the entire system's klconfig
800 * to figure out which pci components have been disabled
802 klhwg_device_disable_hints_add();