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