summaryrefslogtreecommitdiffstats
path: root/arch/ia64/sn/io/hcl_util.c
blob: d11f49cdde8d29419c7afef8756be02dc2268b68 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/* $Id$
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 * Copyright (C) 1992 - 1997, 2000 Silicon Graphics, Inc.
 * Copyright (C) 2000 by Colin Ngam
 */

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/devfs_fs.h>
#include <linux/devfs_fs_kernel.h>
#include <asm/sn/sgi.h>
#include <asm/io.h>
#include <asm/sn/iograph.h>
#include <asm/sn/invent.h>
#include <asm/sn/hcl.h>
#include <asm/sn/labelcl.h>
#include <asm/sn/hcl_util.h>
#include <asm/sn/nodepda.h>

static devfs_handle_t hwgraph_all_cnodes = GRAPH_VERTEX_NONE;
extern devfs_handle_t hwgraph_root;


/*
** Return the "master" for a given vertex.  A master vertex is a
** controller or adapter or other piece of hardware that the given
** vertex passes through on the way to the rest of the system.
*/
devfs_handle_t
device_master_get(devfs_handle_t vhdl)
{
	graph_error_t rc;
	devfs_handle_t master;

	rc = hwgraph_edge_get(vhdl, EDGE_LBL_MASTER, &master);
	if (rc == GRAPH_SUCCESS)
		return(master);
	else
		return(GRAPH_VERTEX_NONE);
}

/*
** Set the master for a given vertex.
** Returns 0 on success, non-0 indicates failure
*/
int
device_master_set(devfs_handle_t vhdl, devfs_handle_t master)
{
	graph_error_t rc;

	rc = hwgraph_edge_add(vhdl, master, EDGE_LBL_MASTER);
	return(rc != GRAPH_SUCCESS);
}


/*
** Return the compact node id of the node that ultimately "owns" the specified
** vertex.  In order to do this, we walk back through masters and connect points
** until we reach a vertex that represents a node.
*/
cnodeid_t
master_node_get(devfs_handle_t vhdl)
{
	cnodeid_t cnodeid;
	devfs_handle_t master;

	for (;;) {
		cnodeid = nodevertex_to_cnodeid(vhdl);
		if (cnodeid != CNODEID_NONE)
			return(cnodeid);

		master = device_master_get(vhdl);

		/* Check for exceptional cases */
		if (master == vhdl) {
			/* Since we got a reference to the "master" thru
			 * device_master_get() we should decrement
			 * its reference count by 1
			 */
			return(CNODEID_NONE);
		}

		if (master == GRAPH_VERTEX_NONE) {
			master = hwgraph_connectpt_get(vhdl);
			if ((master == GRAPH_VERTEX_NONE) ||
			    (master == vhdl)) {
				return(CNODEID_NONE);
			}
		}

		vhdl = master;
	}
}

/*
** If the specified device represents a node, return its
** compact node ID; otherwise, return CNODEID_NONE.
*/
cnodeid_t
nodevertex_to_cnodeid(devfs_handle_t vhdl)
{
	int rv = 0;
	arbitrary_info_t cnodeid = CNODEID_NONE;

	rv = labelcl_info_get_LBL(vhdl, INFO_LBL_CNODEID, NULL, &cnodeid);

	return((cnodeid_t)cnodeid);
}

void
mark_nodevertex_as_node(devfs_handle_t vhdl, cnodeid_t cnodeid)
{
	if (cnodeid == CNODEID_NONE)
		return;

	cnodeid_to_vertex(cnodeid) = vhdl;
	labelcl_info_add_LBL(vhdl, INFO_LBL_CNODEID, INFO_DESC_EXPORT, 
		(arbitrary_info_t)cnodeid);

	{
		char cnodeid_buffer[10];

		if (hwgraph_all_cnodes == GRAPH_VERTEX_NONE) {
			(void)hwgraph_path_add( hwgraph_root,
						EDGE_LBL_NODENUM,
						&hwgraph_all_cnodes);
		}

		sprintf(cnodeid_buffer, "%d", cnodeid);
		(void)hwgraph_edge_add( hwgraph_all_cnodes,
					vhdl,
					cnodeid_buffer);
	}
}


/*
** dev_to_name converts a devfs_handle_t into a canonical name.  If the devfs_handle_t
** represents a vertex in the hardware graph, it is converted in the
** normal way for vertices.  If the devfs_handle_t is an old devfs_handle_t (one which
** does not represent a hwgraph vertex), we synthesize a name based
** on major/minor number.
**
** Usually returns a pointer to the original buffer, filled in as
** appropriate.  If the buffer is too small to hold the entire name,
** or if anything goes wrong while determining the name, dev_to_name
** returns "UnknownDevice".
*/
char *
dev_to_name(devfs_handle_t dev, char *buf, uint buflen)
{
        return(vertex_to_name(dev, buf, buflen));
}