mmu_context_hash64.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. /*
  2. * MMU context allocation for 64-bit kernels.
  3. *
  4. * Copyright (C) 2004 Anton Blanchard, IBM Corp. <anton@samba.org>
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version
  9. * 2 of the License, or (at your option) any later version.
  10. *
  11. */
  12. #include <linux/sched.h>
  13. #include <linux/kernel.h>
  14. #include <linux/errno.h>
  15. #include <linux/string.h>
  16. #include <linux/types.h>
  17. #include <linux/mm.h>
  18. #include <linux/spinlock.h>
  19. #include <linux/idr.h>
  20. #include <linux/module.h>
  21. #include <linux/gfp.h>
  22. #include <linux/slab.h>
  23. #include <asm/mmu_context.h>
  24. #ifdef CONFIG_PPC_ICSWX
  25. /*
  26. * The processor and its L2 cache cause the icswx instruction to
  27. * generate a COP_REQ transaction on PowerBus. The transaction has
  28. * no address, and the processor does not perform an MMU access
  29. * to authenticate the transaction. The command portion of the
  30. * PowerBus COP_REQ transaction includes the LPAR_ID (LPID) and
  31. * the coprocessor Process ID (PID), which the coprocessor compares
  32. * to the authorized LPID and PID held in the coprocessor, to determine
  33. * if the process is authorized to generate the transaction.
  34. * The data of the COP_REQ transaction is 128-byte or less and is
  35. * placed in cacheable memory on a 128-byte cache line boundary.
  36. *
  37. * The task to use a coprocessor should use use_cop() to allocate
  38. * a coprocessor PID before executing icswx instruction. use_cop()
  39. * also enables the coprocessor context switching. Drop_cop() is
  40. * used to free the coprocessor PID.
  41. *
  42. * Example:
  43. * Host Fabric Interface (HFI) is a PowerPC network coprocessor.
  44. * Each HFI have multiple windows. Each HFI window serves as a
  45. * network device sending to and receiving from HFI network.
  46. * HFI immediate send function uses icswx instruction. The immediate
  47. * send function allows small (single cache-line) packets be sent
  48. * without using the regular HFI send FIFO and doorbell, which are
  49. * much slower than immediate send.
  50. *
  51. * For each task intending to use HFI immediate send, the HFI driver
  52. * calls use_cop() to obtain a coprocessor PID for the task.
  53. * The HFI driver then allocate a free HFI window and save the
  54. * coprocessor PID to the HFI window to allow the task to use the
  55. * HFI window.
  56. *
  57. * The HFI driver repeatedly creates immediate send packets and
  58. * issues icswx instruction to send data through the HFI window.
  59. * The HFI compares the coprocessor PID in the CPU PID register
  60. * to the PID held in the HFI window to determine if the transaction
  61. * is allowed.
  62. *
  63. * When the task to release the HFI window, the HFI driver calls
  64. * drop_cop() to release the coprocessor PID.
  65. */
  66. #define COP_PID_NONE 0
  67. #define COP_PID_MIN (COP_PID_NONE + 1)
  68. #define COP_PID_MAX (0xFFFF)
  69. static DEFINE_SPINLOCK(mmu_context_acop_lock);
  70. static DEFINE_IDA(cop_ida);
  71. void switch_cop(struct mm_struct *next)
  72. {
  73. mtspr(SPRN_PID, next->context.cop_pid);
  74. mtspr(SPRN_ACOP, next->context.acop);
  75. }
  76. static int new_cop_pid(struct ida *ida, int min_id, int max_id,
  77. spinlock_t *lock)
  78. {
  79. int index;
  80. int err;
  81. again:
  82. if (!ida_pre_get(ida, GFP_KERNEL))
  83. return -ENOMEM;
  84. spin_lock(lock);
  85. err = ida_get_new_above(ida, min_id, &index);
  86. spin_unlock(lock);
  87. if (err == -EAGAIN)
  88. goto again;
  89. else if (err)
  90. return err;
  91. if (index > max_id) {
  92. spin_lock(lock);
  93. ida_remove(ida, index);
  94. spin_unlock(lock);
  95. return -ENOMEM;
  96. }
  97. return index;
  98. }
  99. static void sync_cop(void *arg)
  100. {
  101. struct mm_struct *mm = arg;
  102. if (mm == current->active_mm)
  103. switch_cop(current->active_mm);
  104. }
  105. /**
  106. * Start using a coprocessor.
  107. * @acop: mask of coprocessor to be used.
  108. * @mm: The mm the coprocessor to associate with. Most likely current mm.
  109. *
  110. * Return a positive PID if successful. Negative errno otherwise.
  111. * The returned PID will be fed to the coprocessor to determine if an
  112. * icswx transaction is authenticated.
  113. */
  114. int use_cop(unsigned long acop, struct mm_struct *mm)
  115. {
  116. int ret;
  117. if (!cpu_has_feature(CPU_FTR_ICSWX))
  118. return -ENODEV;
  119. if (!mm || !acop)
  120. return -EINVAL;
  121. /* We need to make sure mm_users doesn't change */
  122. down_read(&mm->mmap_sem);
  123. spin_lock(mm->context.cop_lockp);
  124. if (mm->context.cop_pid == COP_PID_NONE) {
  125. ret = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX,
  126. &mmu_context_acop_lock);
  127. if (ret < 0)
  128. goto out;
  129. mm->context.cop_pid = ret;
  130. }
  131. mm->context.acop |= acop;
  132. sync_cop(mm);
  133. /*
  134. * If this is a threaded process then there might be other threads
  135. * running. We need to send an IPI to force them to pick up any
  136. * change in PID and ACOP.
  137. */
  138. if (atomic_read(&mm->mm_users) > 1)
  139. smp_call_function(sync_cop, mm, 1);
  140. ret = mm->context.cop_pid;
  141. out:
  142. spin_unlock(mm->context.cop_lockp);
  143. up_read(&mm->mmap_sem);
  144. return ret;
  145. }
  146. EXPORT_SYMBOL_GPL(use_cop);
  147. /**
  148. * Stop using a coprocessor.
  149. * @acop: mask of coprocessor to be stopped.
  150. * @mm: The mm the coprocessor associated with.
  151. */
  152. void drop_cop(unsigned long acop, struct mm_struct *mm)
  153. {
  154. int free_pid = COP_PID_NONE;
  155. if (!cpu_has_feature(CPU_FTR_ICSWX))
  156. return;
  157. if (WARN_ON_ONCE(!mm))
  158. return;
  159. /* We need to make sure mm_users doesn't change */
  160. down_read(&mm->mmap_sem);
  161. spin_lock(mm->context.cop_lockp);
  162. mm->context.acop &= ~acop;
  163. if ((!mm->context.acop) && (mm->context.cop_pid != COP_PID_NONE)) {
  164. free_pid = mm->context.cop_pid;
  165. mm->context.cop_pid = COP_PID_NONE;
  166. }
  167. sync_cop(mm);
  168. /*
  169. * If this is a threaded process then there might be other threads
  170. * running. We need to send an IPI to force them to pick up any
  171. * change in PID and ACOP.
  172. */
  173. if (atomic_read(&mm->mm_users) > 1)
  174. smp_call_function(sync_cop, mm, 1);
  175. if (free_pid != COP_PID_NONE) {
  176. spin_lock(&mmu_context_acop_lock);
  177. ida_remove(&cop_ida, free_pid);
  178. spin_unlock(&mmu_context_acop_lock);
  179. }
  180. spin_unlock(mm->context.cop_lockp);
  181. up_read(&mm->mmap_sem);
  182. }
  183. EXPORT_SYMBOL_GPL(drop_cop);
  184. #endif /* CONFIG_PPC_ICSWX */
  185. static DEFINE_SPINLOCK(mmu_context_lock);
  186. static DEFINE_IDA(mmu_context_ida);
  187. /*
  188. * The proto-VSID space has 2^35 - 1 segments available for user mappings.
  189. * Each segment contains 2^28 bytes. Each context maps 2^44 bytes,
  190. * so we can support 2^19-1 contexts (19 == 35 + 28 - 44).
  191. */
  192. #define MAX_CONTEXT ((1UL << 19) - 1)
  193. int __init_new_context(void)
  194. {
  195. int index;
  196. int err;
  197. again:
  198. if (!ida_pre_get(&mmu_context_ida, GFP_KERNEL))
  199. return -ENOMEM;
  200. spin_lock(&mmu_context_lock);
  201. err = ida_get_new_above(&mmu_context_ida, 1, &index);
  202. spin_unlock(&mmu_context_lock);
  203. if (err == -EAGAIN)
  204. goto again;
  205. else if (err)
  206. return err;
  207. if (index > MAX_CONTEXT) {
  208. spin_lock(&mmu_context_lock);
  209. ida_remove(&mmu_context_ida, index);
  210. spin_unlock(&mmu_context_lock);
  211. return -ENOMEM;
  212. }
  213. return index;
  214. }
  215. EXPORT_SYMBOL_GPL(__init_new_context);
  216. int init_new_context(struct task_struct *tsk, struct mm_struct *mm)
  217. {
  218. int index;
  219. index = __init_new_context();
  220. if (index < 0)
  221. return index;
  222. /* The old code would re-promote on fork, we don't do that
  223. * when using slices as it could cause problem promoting slices
  224. * that have been forced down to 4K
  225. */
  226. if (slice_mm_new_context(mm))
  227. slice_set_user_psize(mm, mmu_virtual_psize);
  228. subpage_prot_init_new_context(mm);
  229. mm->context.id = index;
  230. #ifdef CONFIG_PPC_ICSWX
  231. mm->context.cop_lockp = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
  232. if (!mm->context.cop_lockp) {
  233. __destroy_context(index);
  234. subpage_prot_free(mm);
  235. mm->context.id = MMU_NO_CONTEXT;
  236. return -ENOMEM;
  237. }
  238. spin_lock_init(mm->context.cop_lockp);
  239. #endif /* CONFIG_PPC_ICSWX */
  240. return 0;
  241. }
  242. void __destroy_context(int context_id)
  243. {
  244. spin_lock(&mmu_context_lock);
  245. ida_remove(&mmu_context_ida, context_id);
  246. spin_unlock(&mmu_context_lock);
  247. }
  248. EXPORT_SYMBOL_GPL(__destroy_context);
  249. void destroy_context(struct mm_struct *mm)
  250. {
  251. #ifdef CONFIG_PPC_ICSWX
  252. drop_cop(mm->context.acop, mm);
  253. kfree(mm->context.cop_lockp);
  254. mm->context.cop_lockp = NULL;
  255. #endif /* CONFIG_PPC_ICSWX */
  256. __destroy_context(mm->context.id);
  257. subpage_prot_free(mm);
  258. mm->context.id = MMU_NO_CONTEXT;
  259. }