File: /usr/src/linux/arch/ia64/sn/io/xswitch.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 #include <linux/types.h>
12 #include <linux/slab.h>
13 #include <asm/sn/sgi.h>
14 #include <asm/sn/iobus.h>
15 #include <asm/sn/iograph.h>
16 #include <asm/sn/invent.h>
17 #include <asm/sn/hcl.h>
18 #include <asm/sn/labelcl.h>
19 #include <asm/sn/xtalk/xtalk.h>
20 #include <asm/sn/xtalk/xswitch.h>
21 #include <asm/sn/xtalk/xwidget.h>
22 #include <asm/sn/xtalk/xtalk_private.h>
23
24 #define NEW(ptr) (ptr = kmalloc(sizeof (*(ptr)), GFP_KERNEL))
25 #define DEL(ptr) (kfree(ptr))
26
27 int xswitch_devflag = D_MP;
28
29 /*
30 * This file provides generic support for Crosstalk
31 * Switches, in a way that insulates crosstalk providers
32 * from specifics about the switch chips being used.
33 */
34
35 #include <asm/sn/xtalk/xbow.h>
36 #define DEV_FUNC(dev,func) xbow_##func
37
38 #if !defined(DEV_FUNC)
39 /*
40 * There is more than one possible provider
41 * for this platform. We need to examine the
42 * master vertex of the current vertex for
43 * a provider function structure, and indirect
44 * through the appropriately named member.
45 */
46 #define DEV_FUNC(dev,func) xwidget_to_provider_fns(dev)->func
47
48 static xswitch_provider_t *
49 xwidget_to_provider_fns(devfs_handle_t xconn)
50 {
51 devfs_handle_t busv;
52 xswitch_info_t xswitch_info;
53 xswitch_provider_t provider_fns;
54
55 busv = hwgraph_connectpt_get(xconn_vhdl);
56 ASSERT(busv != GRAPH_VERTEX_NONE);
57
58 xswitch_info = xswitch_info_get(busv);
59 ASSERT(xswitch_info != NULL);
60
61 provider_fns = xswitch_info->xswitch_fns;
62 ASSERT(provider_fns != NULL);
63
64 return provider_fns;
65 }
66 #endif
67
68 #define XSWITCH_CENSUS_BIT(port) (1<<(port))
69 #define XSWITCH_CENSUS_PORT_MIN (0x0)
70 #define XSWITCH_CENSUS_PORT_MAX (0xF)
71 #define XSWITCH_CENSUS_PORTS (0x10)
72 #define XSWITCH_WIDGET_PRESENT(infop,port) ((infop)->census & XSWITCH_CENSUS_BIT(port))
73
74 static char xswitch_info_fingerprint[] = "xswitch_info";
75
76 struct xswitch_info_s {
77 char *fingerprint;
78 unsigned census;
79 devfs_handle_t vhdl[XSWITCH_CENSUS_PORTS];
80 devfs_handle_t master_vhdl[XSWITCH_CENSUS_PORTS];
81 xswitch_provider_t *xswitch_fns;
82 };
83
84 xswitch_info_t
85 xswitch_info_get(devfs_handle_t xwidget)
86 {
87 xswitch_info_t xswitch_info;
88
89 xswitch_info = (xswitch_info_t)
90 hwgraph_fastinfo_get(xwidget);
91 #ifdef LATER
92 if ((xswitch_info != NULL) &&
93 (xswitch_info->fingerprint != xswitch_info_fingerprint))
94 #ifdef SUPPORT_PRINTING_V_FORMAT
95 PRINT_PANIC("%v xswitch_info_get bad fingerprint", xwidget);
96 #else
97 PRINT_PANIC("%x xswitch_info_get bad fingerprint", xwidget);
98 #endif
99 #endif /* LATER */
100
101 return (xswitch_info);
102 }
103
104 void
105 xswitch_info_vhdl_set(xswitch_info_t xswitch_info,
106 xwidgetnum_t port,
107 devfs_handle_t xwidget)
108 {
109 #if XSWITCH_CENSUS_PORT_MIN
110 if (port < XSWITCH_CENSUS_PORT_MIN)
111 return;
112 #endif
113 if (port > XSWITCH_CENSUS_PORT_MAX)
114 return;
115
116 xswitch_info->vhdl[port - XSWITCH_CENSUS_PORT_MIN] = xwidget;
117 }
118
119 devfs_handle_t
120 xswitch_info_vhdl_get(xswitch_info_t xswitch_info,
121 xwidgetnum_t port)
122 {
123 #ifdef LATER
124 if (xswitch_info == NULL)
125 PRINT_PANIC("xswitch_info_vhdl_get: null xswitch_info");
126 #endif
127
128 #if XSWITCH_CENSUS_PORT_MIN
129 if (port < XSWITCH_CENSUS_PORT_MIN)
130 return GRAPH_VERTEX_NONE;
131 #endif
132 if (port > XSWITCH_CENSUS_PORT_MAX)
133 return GRAPH_VERTEX_NONE;
134
135 return xswitch_info->vhdl[port - XSWITCH_CENSUS_PORT_MIN];
136 }
137
138 /*
139 * Some systems may allow for multiple switch masters. On such systems,
140 * we assign a master for each port on the switch. These interfaces
141 * establish and retrieve that assignment.
142 */
143 void
144 xswitch_info_master_assignment_set(xswitch_info_t xswitch_info,
145 xwidgetnum_t port,
146 devfs_handle_t master_vhdl)
147 {
148 #if XSWITCH_CENSUS_PORT_MIN
149 if (port < XSWITCH_CENSUS_PORT_MIN)
150 return;
151 #endif
152 if (port > XSWITCH_CENSUS_PORT_MAX)
153 return;
154
155 xswitch_info->master_vhdl[port - XSWITCH_CENSUS_PORT_MIN] = master_vhdl;
156 }
157
158 devfs_handle_t
159 xswitch_info_master_assignment_get(xswitch_info_t xswitch_info,
160 xwidgetnum_t port)
161 {
162 #if XSWITCH_CENSUS_PORT_MIN
163 if (port < XSWITCH_CENSUS_PORT_MIN)
164 return GRAPH_VERTEX_NONE;
165 #endif
166 if (port > XSWITCH_CENSUS_PORT_MAX)
167 return GRAPH_VERTEX_NONE;
168
169 return xswitch_info->master_vhdl[port - XSWITCH_CENSUS_PORT_MIN];
170 }
171
172 void
173 xswitch_info_set(devfs_handle_t xwidget, xswitch_info_t xswitch_info)
174 {
175 xswitch_info->fingerprint = xswitch_info_fingerprint;
176 hwgraph_fastinfo_set(xwidget, (arbitrary_info_t) xswitch_info);
177 }
178
179 xswitch_info_t
180 xswitch_info_new(devfs_handle_t xwidget)
181 {
182 xswitch_info_t xswitch_info;
183
184 xswitch_info = xswitch_info_get(xwidget);
185 if (xswitch_info == NULL) {
186 int port;
187
188 NEW(xswitch_info);
189 xswitch_info->census = 0;
190 for (port = XSWITCH_CENSUS_PORT_MIN;
191 port <= XSWITCH_CENSUS_PORT_MAX;
192 port++) {
193 xswitch_info_vhdl_set(xswitch_info, port,
194 GRAPH_VERTEX_NONE);
195
196 xswitch_info_master_assignment_set(xswitch_info,
197 port,
198 GRAPH_VERTEX_NONE);
199 }
200 xswitch_info_set(xwidget, xswitch_info);
201 }
202 return xswitch_info;
203 }
204
205 void
206 xswitch_provider_register(devfs_handle_t busv,
207 xswitch_provider_t * xswitch_fns)
208 {
209 xswitch_info_t xswitch_info = xswitch_info_get(busv);
210
211 ASSERT(xswitch_info);
212 xswitch_info->xswitch_fns = xswitch_fns;
213 }
214
215 void
216 xswitch_info_link_is_ok(xswitch_info_t xswitch_info, xwidgetnum_t port)
217 {
218 xswitch_info->census |= XSWITCH_CENSUS_BIT(port);
219 }
220
221 int
222 xswitch_info_link_ok(xswitch_info_t xswitch_info, xwidgetnum_t port)
223 {
224 #if XSWITCH_CENSUS_PORT_MIN
225 if (port < XSWITCH_CENSUS_PORT_MIN)
226 return 0;
227 #endif
228
229 if (port > XSWITCH_CENSUS_PORT_MAX)
230 return 0;
231
232 return (xswitch_info->census & XSWITCH_CENSUS_BIT(port));
233 }
234
235 int
236 xswitch_reset_link(devfs_handle_t xconn_vhdl)
237 {
238 return DEV_FUNC(xconn_vhdl, reset_link)
239 (xconn_vhdl);
240 }
241
242 /* Given a vertex handle to the xswitch get its logical
243 * id.
244 */
245 int
246 xswitch_id_get(devfs_handle_t xconn_vhdl)
247 {
248 arbitrary_info_t xbow_num;
249 graph_error_t rv;
250
251 rv = hwgraph_info_get_LBL(xconn_vhdl,INFO_LBL_XSWITCH_ID,&xbow_num);
252 ASSERT(rv == GRAPH_SUCCESS);
253 return(xbow_num);
254 }
255
256 /* Given a vertex handle to the xswitch set its logical
257 * id.
258 */
259 void
260 xswitch_id_set(devfs_handle_t xconn_vhdl,int xbow_num)
261 {
262 graph_error_t rv;
263
264 rv = hwgraph_info_add_LBL(xconn_vhdl,INFO_LBL_XSWITCH_ID,
265 (arbitrary_info_t)xbow_num);
266 ASSERT(rv == GRAPH_SUCCESS);
267 }
268