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
6 * Copyright (C) 1992 - 1997, 2000-2003 Silicon Graphics, Inc. All rights reserved.
11 * This file specifies the interface between the kernel and the PROM's
12 * configuration data structures.
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>
25 /* #define KLGRAPH_DEBUG 1 */
27 #define GRPRINTF(x) printk x
32 void mark_cpuvertex_as_cpu(vertex_hdl_t vhdl, cpuid_t cpuid);
37 klhwg_add_hub(vertex_hdl_t node_vertex, klhub_t *hub, cnodeid_t cnode)
42 extern struct file_operations shub_mon_fops;
44 hwgraph_path_add(node_vertex, EDGE_LBL_HUB, &myhubv);
46 HWGRAPH_DEBUG(__FILE__, __FUNCTION__,__LINE__, myhubv, NULL, "Created path for hub vertex for Shub node.\n");
48 rc = device_master_set(myhubv, node_vertex);
50 printk("klhwg_add_hub: Unable to create hub vertex.\n");
53 hub_mon = hwgraph_register(myhubv, EDGE_LBL_PERFMON,
55 S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
56 &shub_mon_fops, (void *)(long)cnode);
61 klhwg_add_disabled_cpu(vertex_hdl_t node_vertex, cnodeid_t cnode, klcpu_t *cpu, slotid_t slot)
68 nasid = COMPACT_TO_NASID_NODEID(cnode);
69 cpu_id = nasid_slice_to_cpuid(nasid, cpu->cpu_info.physid);
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);
74 HWGRAPH_DEBUG(__FILE__, __FUNCTION__,__LINE__, my_cpu, NULL, "Created path for disabled cpu slice.\n");
76 mark_cpuvertex_as_cpu(my_cpu, cpu_id);
77 device_master_set(my_cpu, node_vertex);
84 klhwg_add_cpu(vertex_hdl_t node_vertex, cnodeid_t cnode, klcpu_t *cpu)
86 vertex_hdl_t my_cpu, cpu_dir;
91 nasid = COMPACT_TO_NASID_NODEID(cnode);
92 cpu_id = nasid_slice_to_cpuid(nasid, cpu->cpu_info.physid);
94 snprintf(name, 120, "%s/%d/%c",
97 'a' + cpu->cpu_info.physid);
99 (void) hwgraph_path_add(node_vertex, name, &my_cpu);
101 HWGRAPH_DEBUG(__FILE__, __FUNCTION__,__LINE__, my_cpu, NULL, "Created path for active cpu slice.\n");
103 mark_cpuvertex_as_cpu(my_cpu, cpu_id);
104 device_master_set(my_cpu, node_vertex);
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);
116 klhwg_add_xbow(cnodeid_t cnode, nasid_t nasid)
123 vertex_hdl_t xbow_v, hubv;
127 if (!(brd = find_lboard_nasid((lboard_t *)KL_CONFIG_INFO(nasid),
128 nasid, KLTYPE_IOBRICK_XBOW)))
131 if (KL_CONFIG_DUPLICATE_BOARD(brd))
134 if ((xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW))
138 for (widgetnum = HUB_WIDGET_ID_MIN; widgetnum <= HUB_WIDGET_ID_MAX; widgetnum++) {
139 if (!XBOW_PORT_TYPE_HUB(xbow_p, widgetnum))
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);
148 hub_cnode = NASID_TO_COMPACT_NODEID(hub_nasid);
150 if (hub_cnode == INVALID_CNODEID) {
154 hubv = cnodeid_to_vertex(hub_cnode);
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!");
162 printk("klhwg_add_xbow: Failed to add "
163 "edge: vertex 0x%p to vertex 0x%p,"
165 (void *)hubv, (void *)xbow_v, err);
169 HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, xbow_v, NULL, "Created path for xtalk.\n");
171 xswitch_vertex_init(xbow_v);
173 NODEPDA(hub_cnode)->xbow_vhdl = xbow_v;
176 * XXX - This won't work is we ever hook up two hubs
177 * by crosstown through a crossbow.
179 if (hub_nasid != nasid) {
180 NODEPDA(hub_cnode)->xbow_peer = nasid;
181 NODEPDA(NASID_TO_COMPACT_NODEID(nasid))->xbow_peer =
190 klhwg_add_node(vertex_hdl_t hwgraph_root, cnodeid_t cnode)
195 vertex_hdl_t node_vertex = NULL;
196 char path_buffer[100];
199 int board_disabled = 0;
201 vertex_hdl_t cpu_dir;
203 nasid = COMPACT_TO_NASID_NODEID(cnode);
204 brd = find_lboard_any((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
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);
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);
218 if(hub->hub_info.flags & KLINFO_ENABLE)
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__);
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);
241 * If there's at least 1 CPU, add a "cpu" directory to represent
242 * the collection of all CPUs attached to this node.
244 cpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU);
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");
253 HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, cpu_dir, NULL, "Created cpu directiry on SHUB node.\n");
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);
263 klhwg_add_disabled_cpu(node_vertex, cnode, cpu, brd->brd_slot);
266 find_component(brd, (klinfo_t *)cpu, KLSTRUCT_CPU);
273 klhwg_add_all_routers(vertex_hdl_t hwgraph_root)
278 vertex_hdl_t node_vertex;
279 char path_buffer[100];
282 for (cnode = 0; cnode < numnodes; cnode++) {
283 nasid = COMPACT_TO_NASID_NODEID(cnode);
284 brd = find_lboard_class_any((lboard_t *)KL_CONFIG_INFO(nasid),
288 /* No routers stored in this node's memory */
294 /* Don't add duplicate boards. */
295 if (brd->brd_flags & DUPLICATE_BOARD)
298 /* Generate a hardware graph path for this board. */
299 board_to_path(brd, path_buffer);
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);
308 HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, node_vertex, NULL, "Created router path.\n");
310 /* Find the rest of the routers stored on this node. */
311 } while ( (brd = find_lboard_class_any(KLCF_NEXT_ANY(brd),
319 klhwg_connect_one_router(vertex_hdl_t hwgraph_root, lboard_t *brd,
320 cnodeid_t cnode, nasid_t nasid)
323 char path_buffer[50];
325 vertex_hdl_t router_hndl;
326 vertex_hdl_t dest_hndl;
331 /* Don't add duplicate boards. */
332 if (brd->brd_flags & DUPLICATE_BOARD) {
336 /* Generate a hardware graph path for this board. */
337 board_to_path(brd, path_buffer);
339 rc = hwgraph_traverse(hwgraph_root, path_buffer, &router_hndl);
341 if (rc != GRAPH_SUCCESS)
344 if (rc != GRAPH_SUCCESS)
345 printk(KERN_WARNING "Can't find router: %s", path_buffer);
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",
355 /* Convert component 0 to klrou_t ptr */
356 router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd),
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",
366 if (NASID_TO_COMPACT_NODEID(router->rou_port[port].port_nasid)
367 == INVALID_CNODEID) {
371 dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
372 router->rou_port[port].port_nasid,
373 router->rou_port[port].port_offset);
375 /* Generate a hardware graph path for this board. */
376 board_to_path(dest_brd, dest_path);
378 rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl);
380 if (rc != GRAPH_SUCCESS) {
381 if (KL_CONFIG_DUPLICATE_BOARD(dest_brd))
383 printk("Can't find router: %s", dest_path);
387 sprintf(dest_path, "%d", port);
389 rc = hwgraph_edge_add(router_hndl, dest_hndl, dest_path);
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));
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);
403 HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, router_hndl, dest_hndl, "Created edge %s from vhdl1 to vhdl2.\n", dest_path);
410 klhwg_connect_routers(vertex_hdl_t hwgraph_root)
416 for (cnode = 0; cnode < numnodes; cnode++) {
417 nasid = COMPACT_TO_NASID_NODEID(cnode);
418 brd = find_lboard_class_any((lboard_t *)KL_CONFIG_INFO(nasid),
426 nasid = COMPACT_TO_NASID_NODEID(cnode);
428 klhwg_connect_one_router(hwgraph_root, brd,
431 /* Find the rest of the routers stored on this node. */
432 } while ( (brd = find_lboard_class_any(KLCF_NEXT_ANY(brd), KLTYPE_ROUTER)) );
439 klhwg_connect_hubs(vertex_hdl_t hwgraph_root)
446 vertex_hdl_t hub_hndl;
447 vertex_hdl_t dest_hndl;
448 char path_buffer[50];
453 for (cnode = 0; cnode < numionodes; cnode++) {
454 nasid = COMPACT_TO_NASID_NODEID(cnode);
456 brd = find_lboard_any((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_SNIA);
458 hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
461 for (port = 1; port <= MAX_NI_PORTS; port++) {
462 if (hub->hub_port[port].port_nasid == INVALID_NASID) {
463 continue; /* Port not active */
466 if (NASID_TO_COMPACT_NODEID(hub->hub_port[port].port_nasid) == INVALID_CNODEID)
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);
473 if (rc != GRAPH_SUCCESS)
474 printk(KERN_WARNING "Can't find hub: %s", path_buffer);
476 dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
477 hub->hub_port[port].port_nasid,
478 hub->hub_port[port].port_offset);
480 /* Generate a hardware graph path for this board. */
481 board_to_path(dest_brd, dest_path);
483 rc = hwgraph_traverse(hwgraph_root, dest_path, &dest_hndl);
485 if (rc != GRAPH_SUCCESS) {
486 if (KL_CONFIG_DUPLICATE_BOARD(dest_brd))
488 printk("Can't find board: %s", dest_path);
493 rc = hwgraph_path_add(hub_hndl, EDGE_LBL_INTERCONNECT, &hub_hndl);
495 HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, hub_hndl, NULL, "Created link path.\n");
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);
502 HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, hub_hndl, dest_hndl, "Created edge %s from vhdl1 to vhdl2.\n", buf);
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);
515 klhwg_add_all_modules(vertex_hdl_t hwgraph_root)
520 vertex_hdl_t module_vhdl;
524 /* Add devices under each module */
526 for (cm = 0; cm < nummodules; cm++) {
527 /* Use module as module vertex fastinfo */
529 memset(buffer, 0, 16);
530 format_module_id(buffer, modules[cm]->id, MODULE_FORMAT_BRIEF);
531 sprintf(name, EDGE_LBL_MODULE "/%s", buffer);
533 rc = hwgraph_path_add(hwgraph_root, name, &module_vhdl);
534 ASSERT(rc == GRAPH_SUCCESS);
536 HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, module_vhdl, NULL, "Created module path.\n");
538 hwgraph_fastinfo_set(module_vhdl, (arbitrary_info_t) modules[cm]);
540 /* Add system controller */
542 EDGE_LBL_MODULE "/%s/" EDGE_LBL_L1,
545 rc = hwgraph_path_add(hwgraph_root, name, &vhdl);
546 ASSERT_ALWAYS(rc == GRAPH_SUCCESS);
548 HWGRAPH_DEBUG(__FILE__, __FUNCTION__, __LINE__, vhdl, NULL, "Created L1 path.\n");
550 hwgraph_info_add_LBL(vhdl, INFO_LBL_ELSC,
551 (arbitrary_info_t)1);
557 klhwg_add_all_nodes(vertex_hdl_t hwgraph_root)
561 for (cnode = 0; cnode < numionodes; cnode++) {
562 klhwg_add_node(hwgraph_root, cnode);
565 for (cnode = 0; cnode < numionodes; cnode++) {
566 klhwg_add_xbow(cnode, cnodeid_to_nasid(cnode));
570 * As for router hardware inventory information, we set this
574 klhwg_add_all_routers(hwgraph_root);
575 klhwg_connect_routers(hwgraph_root);
576 klhwg_connect_hubs(hwgraph_root);