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