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