xp_main.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  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. * Cross Partition (XP) base.
  10. *
  11. * XP provides a base from which its users can interact
  12. * with XPC, yet not be dependent on XPC.
  13. *
  14. */
  15. #include <linux/kernel.h>
  16. #include <linux/interrupt.h>
  17. #include <linux/module.h>
  18. #include <linux/mutex.h>
  19. #include <asm/sn/intr.h>
  20. #include <asm/sn/sn_sal.h>
  21. #include "xp.h"
  22. /*
  23. * The export of xp_nofault_PIOR needs to happen here since it is defined
  24. * in drivers/misc/sgi-xp/xp_nofault.S. The target of the nofault read is
  25. * defined here.
  26. */
  27. EXPORT_SYMBOL_GPL(xp_nofault_PIOR);
  28. u64 xp_nofault_PIOR_target;
  29. EXPORT_SYMBOL_GPL(xp_nofault_PIOR_target);
  30. /*
  31. * xpc_registrations[] keeps track of xpc_connect()'s done by the kernel-level
  32. * users of XPC.
  33. */
  34. struct xpc_registration xpc_registrations[XPC_NCHANNELS];
  35. EXPORT_SYMBOL_GPL(xpc_registrations);
  36. /*
  37. * Initialize the XPC interface to indicate that XPC isn't loaded.
  38. */
  39. static enum xp_retval
  40. xpc_notloaded(void)
  41. {
  42. return xpNotLoaded;
  43. }
  44. struct xpc_interface xpc_interface = {
  45. (void (*)(int))xpc_notloaded,
  46. (void (*)(int))xpc_notloaded,
  47. (enum xp_retval(*)(partid_t, int, u32, void **))xpc_notloaded,
  48. (enum xp_retval(*)(partid_t, int, void *))xpc_notloaded,
  49. (enum xp_retval(*)(partid_t, int, void *, xpc_notify_func, void *))
  50. xpc_notloaded,
  51. (void (*)(partid_t, int, void *))xpc_notloaded,
  52. (enum xp_retval(*)(partid_t, void *))xpc_notloaded
  53. };
  54. EXPORT_SYMBOL_GPL(xpc_interface);
  55. /*
  56. * XPC calls this when it (the XPC module) has been loaded.
  57. */
  58. void
  59. xpc_set_interface(void (*connect) (int),
  60. void (*disconnect) (int),
  61. enum xp_retval (*allocate) (partid_t, int, u32, void **),
  62. enum xp_retval (*send) (partid_t, int, void *),
  63. enum xp_retval (*send_notify) (partid_t, int, void *,
  64. xpc_notify_func, void *),
  65. void (*received) (partid_t, int, void *),
  66. enum xp_retval (*partid_to_nasids) (partid_t, void *))
  67. {
  68. xpc_interface.connect = connect;
  69. xpc_interface.disconnect = disconnect;
  70. xpc_interface.allocate = allocate;
  71. xpc_interface.send = send;
  72. xpc_interface.send_notify = send_notify;
  73. xpc_interface.received = received;
  74. xpc_interface.partid_to_nasids = partid_to_nasids;
  75. }
  76. EXPORT_SYMBOL_GPL(xpc_set_interface);
  77. /*
  78. * XPC calls this when it (the XPC module) is being unloaded.
  79. */
  80. void
  81. xpc_clear_interface(void)
  82. {
  83. xpc_interface.connect = (void (*)(int))xpc_notloaded;
  84. xpc_interface.disconnect = (void (*)(int))xpc_notloaded;
  85. xpc_interface.allocate = (enum xp_retval(*)(partid_t, int, u32,
  86. void **))xpc_notloaded;
  87. xpc_interface.send = (enum xp_retval(*)(partid_t, int, void *))
  88. xpc_notloaded;
  89. xpc_interface.send_notify = (enum xp_retval(*)(partid_t, int, void *,
  90. xpc_notify_func,
  91. void *))xpc_notloaded;
  92. xpc_interface.received = (void (*)(partid_t, int, void *))
  93. xpc_notloaded;
  94. xpc_interface.partid_to_nasids = (enum xp_retval(*)(partid_t, void *))
  95. xpc_notloaded;
  96. }
  97. EXPORT_SYMBOL_GPL(xpc_clear_interface);
  98. /*
  99. * Register for automatic establishment of a channel connection whenever
  100. * a partition comes up.
  101. *
  102. * Arguments:
  103. *
  104. * ch_number - channel # to register for connection.
  105. * func - function to call for asynchronous notification of channel
  106. * state changes (i.e., connection, disconnection, error) and
  107. * the arrival of incoming messages.
  108. * key - pointer to optional user-defined value that gets passed back
  109. * to the user on any callouts made to func.
  110. * payload_size - size in bytes of the XPC message's payload area which
  111. * contains a user-defined message. The user should make
  112. * this large enough to hold their largest message.
  113. * nentries - max #of XPC message entries a message queue can contain.
  114. * The actual number, which is determined when a connection
  115. * is established and may be less then requested, will be
  116. * passed to the user via the xpConnected callout.
  117. * assigned_limit - max number of kthreads allowed to be processing
  118. * messages (per connection) at any given instant.
  119. * idle_limit - max number of kthreads allowed to be idle at any given
  120. * instant.
  121. */
  122. enum xp_retval
  123. xpc_connect(int ch_number, xpc_channel_func func, void *key, u16 payload_size,
  124. u16 nentries, u32 assigned_limit, u32 idle_limit)
  125. {
  126. struct xpc_registration *registration;
  127. DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS);
  128. DBUG_ON(payload_size == 0 || nentries == 0);
  129. DBUG_ON(func == NULL);
  130. DBUG_ON(assigned_limit == 0 || idle_limit > assigned_limit);
  131. registration = &xpc_registrations[ch_number];
  132. if (mutex_lock_interruptible(&registration->mutex) != 0)
  133. return xpInterrupted;
  134. /* if XPC_CHANNEL_REGISTERED(ch_number) */
  135. if (registration->func != NULL) {
  136. mutex_unlock(&registration->mutex);
  137. return xpAlreadyRegistered;
  138. }
  139. /* register the channel for connection */
  140. registration->msg_size = XPC_MSG_SIZE(payload_size);
  141. registration->nentries = nentries;
  142. registration->assigned_limit = assigned_limit;
  143. registration->idle_limit = idle_limit;
  144. registration->key = key;
  145. registration->func = func;
  146. mutex_unlock(&registration->mutex);
  147. xpc_interface.connect(ch_number);
  148. return xpSuccess;
  149. }
  150. EXPORT_SYMBOL_GPL(xpc_connect);
  151. /*
  152. * Remove the registration for automatic connection of the specified channel
  153. * when a partition comes up.
  154. *
  155. * Before returning this xpc_disconnect() will wait for all connections on the
  156. * specified channel have been closed/torndown. So the caller can be assured
  157. * that they will not be receiving any more callouts from XPC to their
  158. * function registered via xpc_connect().
  159. *
  160. * Arguments:
  161. *
  162. * ch_number - channel # to unregister.
  163. */
  164. void
  165. xpc_disconnect(int ch_number)
  166. {
  167. struct xpc_registration *registration;
  168. DBUG_ON(ch_number < 0 || ch_number >= XPC_NCHANNELS);
  169. registration = &xpc_registrations[ch_number];
  170. /*
  171. * We've decided not to make this a down_interruptible(), since we
  172. * figured XPC's users will just turn around and call xpc_disconnect()
  173. * again anyways, so we might as well wait, if need be.
  174. */
  175. mutex_lock(&registration->mutex);
  176. /* if !XPC_CHANNEL_REGISTERED(ch_number) */
  177. if (registration->func == NULL) {
  178. mutex_unlock(&registration->mutex);
  179. return;
  180. }
  181. /* remove the connection registration for the specified channel */
  182. registration->func = NULL;
  183. registration->key = NULL;
  184. registration->nentries = 0;
  185. registration->msg_size = 0;
  186. registration->assigned_limit = 0;
  187. registration->idle_limit = 0;
  188. xpc_interface.disconnect(ch_number);
  189. mutex_unlock(&registration->mutex);
  190. return;
  191. }
  192. EXPORT_SYMBOL_GPL(xpc_disconnect);
  193. int __init
  194. xp_init(void)
  195. {
  196. int ret, ch_number;
  197. u64 func_addr = *(u64 *)xp_nofault_PIOR;
  198. u64 err_func_addr = *(u64 *)xp_error_PIOR;
  199. if (!ia64_platform_is("sn2"))
  200. return -ENODEV;
  201. /*
  202. * Register a nofault code region which performs a cross-partition
  203. * PIO read. If the PIO read times out, the MCA handler will consume
  204. * the error and return to a kernel-provided instruction to indicate
  205. * an error. This PIO read exists because it is guaranteed to timeout
  206. * if the destination is down (AMO operations do not timeout on at
  207. * least some CPUs on Shubs <= v1.2, which unfortunately we have to
  208. * work around).
  209. */
  210. ret = sn_register_nofault_code(func_addr, err_func_addr, err_func_addr,
  211. 1, 1);
  212. if (ret != 0) {
  213. printk(KERN_ERR "XP: can't register nofault code, error=%d\n",
  214. ret);
  215. }
  216. /*
  217. * Setup the nofault PIO read target. (There is no special reason why
  218. * SH_IPI_ACCESS was selected.)
  219. */
  220. if (is_shub2())
  221. xp_nofault_PIOR_target = SH2_IPI_ACCESS0;
  222. else
  223. xp_nofault_PIOR_target = SH1_IPI_ACCESS;
  224. /* initialize the connection registration mutex */
  225. for (ch_number = 0; ch_number < XPC_NCHANNELS; ch_number++)
  226. mutex_init(&xpc_registrations[ch_number].mutex);
  227. return 0;
  228. }
  229. module_init(xp_init);
  230. void __exit
  231. xp_exit(void)
  232. {
  233. u64 func_addr = *(u64 *)xp_nofault_PIOR;
  234. u64 err_func_addr = *(u64 *)xp_error_PIOR;
  235. /* unregister the PIO read nofault code region */
  236. (void)sn_register_nofault_code(func_addr, err_func_addr,
  237. err_func_addr, 1, 0);
  238. }
  239. module_exit(xp_exit);
  240. MODULE_AUTHOR("Silicon Graphics, Inc.");
  241. MODULE_DESCRIPTION("Cross Partition (XP) base");
  242. MODULE_LICENSE("GPL");