sgi-xp: enable building of XPC/XPNET on x86_64
[pandora-kernel.git] / drivers / misc / sgi-xp / xp_main.c
1 /*
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
4  * for more details.
5  *
6  * Copyright (c) 2004-2008 Silicon Graphics, Inc.  All Rights Reserved.
7  */
8
9 /*
10  * Cross Partition (XP) base.
11  *
12  *      XP provides a base from which its users can interact
13  *      with XPC, yet not be dependent on XPC.
14  *
15  */
16
17 #include <linux/module.h>
18 #include <linux/device.h>
19 #include "xp.h"
20
21 /* define the XP debug device structures to be used with dev_dbg() et al */
22
23 struct device_driver xp_dbg_name = {
24         .name = "xp"
25 };
26
27 struct device xp_dbg_subname = {
28         .bus_id = {0},          /* set to "" */
29         .driver = &xp_dbg_name
30 };
31
32 struct device *xp = &xp_dbg_subname;
33
34 /* max #of partitions possible */
35 short xp_max_npartitions;
36 EXPORT_SYMBOL_GPL(xp_max_npartitions);
37
38 short xp_partition_id;
39 EXPORT_SYMBOL_GPL(xp_partition_id);
40
41 u8 xp_region_size;
42 EXPORT_SYMBOL_GPL(xp_region_size);
43
44 enum xp_retval (*xp_remote_memcpy) (void *dst, const void *src, size_t len);
45 EXPORT_SYMBOL_GPL(xp_remote_memcpy);
46
47 int (*xp_cpu_to_nasid) (int cpuid);
48 EXPORT_SYMBOL_GPL(xp_cpu_to_nasid);
49
50 /*
51  * xpc_registrations[] keeps track of xpc_connect()'s done by the kernel-level
52  * users of XPC.
53  */
54 struct xpc_registration xpc_registrations[XPC_MAX_NCHANNELS];
55 EXPORT_SYMBOL_GPL(xpc_registrations);
56
57 /*
58  * Initialize the XPC interface to indicate that XPC isn't loaded.
59  */
60 static enum xp_retval
61 xpc_notloaded(void)
62 {
63         return xpNotLoaded;
64 }
65
66 struct xpc_interface xpc_interface = {
67         (void (*)(int))xpc_notloaded,
68         (void (*)(int))xpc_notloaded,
69         (enum xp_retval(*)(short, int, u32, void *, u16))xpc_notloaded,
70         (enum xp_retval(*)(short, int, u32, void *, u16, xpc_notify_func,
71                            void *))xpc_notloaded,
72         (void (*)(short, int, void *))xpc_notloaded,
73         (enum xp_retval(*)(short, void *))xpc_notloaded
74 };
75 EXPORT_SYMBOL_GPL(xpc_interface);
76
77 /*
78  * XPC calls this when it (the XPC module) has been loaded.
79  */
80 void
81 xpc_set_interface(void (*connect) (int),
82                   void (*disconnect) (int),
83                   enum xp_retval (*send) (short, int, u32, void *, u16),
84                   enum xp_retval (*send_notify) (short, int, u32, void *, u16,
85                                                   xpc_notify_func, void *),
86                   void (*received) (short, int, void *),
87                   enum xp_retval (*partid_to_nasids) (short, void *))
88 {
89         xpc_interface.connect = connect;
90         xpc_interface.disconnect = disconnect;
91         xpc_interface.send = send;
92         xpc_interface.send_notify = send_notify;
93         xpc_interface.received = received;
94         xpc_interface.partid_to_nasids = partid_to_nasids;
95 }
96 EXPORT_SYMBOL_GPL(xpc_set_interface);
97
98 /*
99  * XPC calls this when it (the XPC module) is being unloaded.
100  */
101 void
102 xpc_clear_interface(void)
103 {
104         xpc_interface.connect = (void (*)(int))xpc_notloaded;
105         xpc_interface.disconnect = (void (*)(int))xpc_notloaded;
106         xpc_interface.send = (enum xp_retval(*)(short, int, u32, void *, u16))
107             xpc_notloaded;
108         xpc_interface.send_notify = (enum xp_retval(*)(short, int, u32, void *,
109                                                        u16, xpc_notify_func,
110                                                        void *))xpc_notloaded;
111         xpc_interface.received = (void (*)(short, int, void *))
112             xpc_notloaded;
113         xpc_interface.partid_to_nasids = (enum xp_retval(*)(short, void *))
114             xpc_notloaded;
115 }
116 EXPORT_SYMBOL_GPL(xpc_clear_interface);
117
118 /*
119  * Register for automatic establishment of a channel connection whenever
120  * a partition comes up.
121  *
122  * Arguments:
123  *
124  *      ch_number - channel # to register for connection.
125  *      func - function to call for asynchronous notification of channel
126  *             state changes (i.e., connection, disconnection, error) and
127  *             the arrival of incoming messages.
128  *      key - pointer to optional user-defined value that gets passed back
129  *            to the user on any callouts made to func.
130  *      payload_size - size in bytes of the XPC message's payload area which
131  *                     contains a user-defined message. The user should make
132  *                     this large enough to hold their largest message.
133  *      nentries - max #of XPC message entries a message queue can contain.
134  *                 The actual number, which is determined when a connection
135  *                 is established and may be less then requested, will be
136  *                 passed to the user via the xpConnected callout.
137  *      assigned_limit - max number of kthreads allowed to be processing
138  *                       messages (per connection) at any given instant.
139  *      idle_limit - max number of kthreads allowed to be idle at any given
140  *                   instant.
141  */
142 enum xp_retval
143 xpc_connect(int ch_number, xpc_channel_func func, void *key, u16 payload_size,
144             u16 nentries, u32 assigned_limit, u32 idle_limit)
145 {
146         struct xpc_registration *registration;
147
148         DBUG_ON(ch_number < 0 || ch_number >= XPC_MAX_NCHANNELS);
149         DBUG_ON(payload_size == 0 || nentries == 0);
150         DBUG_ON(func == NULL);
151         DBUG_ON(assigned_limit == 0 || idle_limit > assigned_limit);
152
153         registration = &xpc_registrations[ch_number];
154
155         if (mutex_lock_interruptible(&registration->mutex) != 0)
156                 return xpInterrupted;
157
158         /* if XPC_CHANNEL_REGISTERED(ch_number) */
159         if (registration->func != NULL) {
160                 mutex_unlock(&registration->mutex);
161                 return xpAlreadyRegistered;
162         }
163
164         /* register the channel for connection */
165         registration->msg_size = XPC_MSG_SIZE(payload_size);
166         registration->nentries = nentries;
167         registration->assigned_limit = assigned_limit;
168         registration->idle_limit = idle_limit;
169         registration->key = key;
170         registration->func = func;
171
172         mutex_unlock(&registration->mutex);
173
174         xpc_interface.connect(ch_number);
175
176         return xpSuccess;
177 }
178 EXPORT_SYMBOL_GPL(xpc_connect);
179
180 /*
181  * Remove the registration for automatic connection of the specified channel
182  * when a partition comes up.
183  *
184  * Before returning this xpc_disconnect() will wait for all connections on the
185  * specified channel have been closed/torndown. So the caller can be assured
186  * that they will not be receiving any more callouts from XPC to their
187  * function registered via xpc_connect().
188  *
189  * Arguments:
190  *
191  *      ch_number - channel # to unregister.
192  */
193 void
194 xpc_disconnect(int ch_number)
195 {
196         struct xpc_registration *registration;
197
198         DBUG_ON(ch_number < 0 || ch_number >= XPC_MAX_NCHANNELS);
199
200         registration = &xpc_registrations[ch_number];
201
202         /*
203          * We've decided not to make this a down_interruptible(), since we
204          * figured XPC's users will just turn around and call xpc_disconnect()
205          * again anyways, so we might as well wait, if need be.
206          */
207         mutex_lock(&registration->mutex);
208
209         /* if !XPC_CHANNEL_REGISTERED(ch_number) */
210         if (registration->func == NULL) {
211                 mutex_unlock(&registration->mutex);
212                 return;
213         }
214
215         /* remove the connection registration for the specified channel */
216         registration->func = NULL;
217         registration->key = NULL;
218         registration->nentries = 0;
219         registration->msg_size = 0;
220         registration->assigned_limit = 0;
221         registration->idle_limit = 0;
222
223         xpc_interface.disconnect(ch_number);
224
225         mutex_unlock(&registration->mutex);
226
227         return;
228 }
229 EXPORT_SYMBOL_GPL(xpc_disconnect);
230
231 int __init
232 xp_init(void)
233 {
234         enum xp_retval ret;
235         int ch_number;
236
237         if (is_shub())
238                 ret = xp_init_sn2();
239         else if (is_uv())
240                 ret = xp_init_uv();
241         else
242                 ret = xpUnsupported;
243
244         if (ret != xpSuccess)
245                 return -ENODEV;
246
247         /* initialize the connection registration mutex */
248         for (ch_number = 0; ch_number < XPC_MAX_NCHANNELS; ch_number++)
249                 mutex_init(&xpc_registrations[ch_number].mutex);
250
251         return 0;
252 }
253
254 module_init(xp_init);
255
256 void __exit
257 xp_exit(void)
258 {
259         if (is_shub())
260                 xp_exit_sn2();
261         else if (is_uv())
262                 xp_exit_uv();
263 }
264
265 module_exit(xp_exit);
266
267 MODULE_AUTHOR("Silicon Graphics, Inc.");
268 MODULE_DESCRIPTION("Cross Partition (XP) base");
269 MODULE_LICENSE("GPL");