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-2003 Silicon Graphics, Inc. All rights reserved.
8  */
9 
10 #include <linux/types.h>
11 #include <linux/kernel.h>
12 #include <asm/sn/sgi.h>
13 #include <asm/io.h>
14 #include <asm/sn/io.h>
15 #include <asm/sn/iograph.h>
16 #include <asm/sn/hwgfs.h>
17 #include <asm/sn/invent.h>
18 #include <asm/sn/hcl.h>
19 #include <asm/sn/labelcl.h>
20 #include <asm/sn/invent.h>
21 #include <asm/sn/hcl_util.h>
22 #include <asm/sn/nodepda.h>
23 
24 static vertex_hdl_t hwgraph_all_cnodes = GRAPH_VERTEX_NONE;
25 static vertex_hdl_t hwgraph_all_cpuids = GRAPH_VERTEX_NONE;
26 extern vertex_hdl_t hwgraph_root;
27 extern int maxcpus;
28 
29 
30 
31 /*
32 ** Return the "master" for a given vertex.  A master vertex is a
33 ** controller or adapter or other piece of hardware that the given
34 ** vertex passes through on the way to the rest of the system.
35 */
36 vertex_hdl_t
device_master_get(vertex_hdl_t vhdl)37 device_master_get(vertex_hdl_t vhdl)
38 {
39 	graph_error_t rc;
40 	vertex_hdl_t master;
41 
42 	rc = hwgraph_edge_get(vhdl, EDGE_LBL_MASTER, &master);
43 	if (rc == GRAPH_SUCCESS)
44 		return(master);
45 	else
46 		return(GRAPH_VERTEX_NONE);
47 }
48 
49 /*
50 ** Set the master for a given vertex.
51 ** Returns 0 on success, non-0 indicates failure
52 */
53 int
device_master_set(vertex_hdl_t vhdl,vertex_hdl_t master)54 device_master_set(vertex_hdl_t vhdl, vertex_hdl_t master)
55 {
56 	graph_error_t rc;
57 
58 	rc = hwgraph_edge_add(vhdl, master, EDGE_LBL_MASTER);
59 	return(rc != GRAPH_SUCCESS);
60 }
61 
62 
63 /*
64 ** Return the compact node id of the node that ultimately "owns" the specified
65 ** vertex.  In order to do this, we walk back through masters and connect points
66 ** until we reach a vertex that represents a node.
67 */
68 cnodeid_t
master_node_get(vertex_hdl_t vhdl)69 master_node_get(vertex_hdl_t vhdl)
70 {
71 	cnodeid_t cnodeid;
72 	vertex_hdl_t master;
73 
74 	for (;;) {
75 		cnodeid = nodevertex_to_cnodeid(vhdl);
76 		if (cnodeid != CNODEID_NONE)
77 			return(cnodeid);
78 
79 		master = device_master_get(vhdl);
80 
81 		/* Check for exceptional cases */
82 		if (master == vhdl) {
83 			/* Since we got a reference to the "master" thru
84 			 * device_master_get() we should decrement
85 			 * its reference count by 1
86 			 */
87 			return(CNODEID_NONE);
88 		}
89 
90 		if (master == GRAPH_VERTEX_NONE) {
91 			master = hwgraph_connectpt_get(vhdl);
92 			if ((master == GRAPH_VERTEX_NONE) ||
93 			    (master == vhdl)) {
94 				return(CNODEID_NONE);
95 			}
96 		}
97 
98 		vhdl = master;
99 	}
100 }
101 
102 void
mark_cpuvertex_as_cpu(vertex_hdl_t vhdl,cpuid_t cpuid)103 mark_cpuvertex_as_cpu(vertex_hdl_t vhdl, cpuid_t cpuid)
104 {
105 	if (cpuid == CPU_NONE)
106 		return;
107 
108 	(void)labelcl_info_add_LBL(vhdl, INFO_LBL_CPUID, INFO_DESC_EXPORT,
109 			(arbitrary_info_t)cpuid);
110 	{
111 		char cpuid_buffer[10];
112 
113 		if (hwgraph_all_cpuids == GRAPH_VERTEX_NONE) {
114 			(void)hwgraph_path_add( hwgraph_root,
115 						EDGE_LBL_CPUNUM,
116 						&hwgraph_all_cpuids);
117 		}
118 
119 		sprintf(cpuid_buffer, "%ld", cpuid);
120 		(void)hwgraph_edge_add( hwgraph_all_cpuids,
121 							vhdl,
122 							cpuid_buffer);
123 	}
124 }
125 
126 /*
127 ** If the specified device represents a node, return its
128 ** compact node ID; otherwise, return CNODEID_NONE.
129 */
130 cnodeid_t
nodevertex_to_cnodeid(vertex_hdl_t vhdl)131 nodevertex_to_cnodeid(vertex_hdl_t vhdl)
132 {
133 	int rv = 0;
134 	arbitrary_info_t cnodeid = CNODEID_NONE;
135 
136 	rv = labelcl_info_get_LBL(vhdl, INFO_LBL_CNODEID, NULL, &cnodeid);
137 
138 	return((cnodeid_t)cnodeid);
139 }
140 
141 void
mark_nodevertex_as_node(vertex_hdl_t vhdl,cnodeid_t cnodeid)142 mark_nodevertex_as_node(vertex_hdl_t vhdl, cnodeid_t cnodeid)
143 {
144 	if (cnodeid == CNODEID_NONE)
145 		return;
146 
147 	cnodeid_to_vertex(cnodeid) = vhdl;
148 	labelcl_info_add_LBL(vhdl, INFO_LBL_CNODEID, INFO_DESC_EXPORT,
149 		(arbitrary_info_t)cnodeid);
150 
151 	{
152 		char cnodeid_buffer[10];
153 
154 		if (hwgraph_all_cnodes == GRAPH_VERTEX_NONE) {
155 			(void)hwgraph_path_add( hwgraph_root,
156 						EDGE_LBL_NODENUM,
157 						&hwgraph_all_cnodes);
158 		}
159 
160 		sprintf(cnodeid_buffer, "%d", cnodeid);
161 		(void)hwgraph_edge_add( hwgraph_all_cnodes,
162 					vhdl,
163 					cnodeid_buffer);
164 		HWGRAPH_DEBUG((__FILE__, __FUNCTION__, __LINE__, hwgraph_all_cnodes, NULL, "Creating path vhdl1\n"));
165 	}
166 }
167 
168 /*
169 ** If the specified device represents a CPU, return its cpuid;
170 ** otherwise, return CPU_NONE.
171 */
172 cpuid_t
cpuvertex_to_cpuid(vertex_hdl_t vhdl)173 cpuvertex_to_cpuid(vertex_hdl_t vhdl)
174 {
175 	arbitrary_info_t cpuid = CPU_NONE;
176 
177 	(void)labelcl_info_get_LBL(vhdl, INFO_LBL_CPUID, NULL, &cpuid);
178 
179 	return((cpuid_t)cpuid);
180 }
181 
182 
183 /*
184 ** dev_to_name converts a vertex_hdl_t into a canonical name.  If the vertex_hdl_t
185 ** represents a vertex in the hardware graph, it is converted in the
186 ** normal way for vertices.  If the vertex_hdl_t is an old vertex_hdl_t (one which
187 ** does not represent a hwgraph vertex), we synthesize a name based
188 ** on major/minor number.
189 **
190 ** Usually returns a pointer to the original buffer, filled in as
191 ** appropriate.  If the buffer is too small to hold the entire name,
192 ** or if anything goes wrong while determining the name, dev_to_name
193 ** returns "UnknownDevice".
194 */
195 char *
dev_to_name(vertex_hdl_t dev,char * buf,uint buflen)196 dev_to_name(vertex_hdl_t dev, char *buf, uint buflen)
197 {
198         return(vertex_to_name(dev, buf, buflen));
199 }
200 
201 
202