grutlbpurge.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * SN Platform GRU Driver
  4. *
  5. * MMUOPS callbacks + TLB flushing
  6. *
  7. * This file handles emu notifier callbacks from the core kernel. The callbacks
  8. * are used to update the TLB in the GRU as a result of changes in the
  9. * state of a process address space. This file also handles TLB invalidates
  10. * from the GRU driver.
  11. *
  12. * Copyright (c) 2008 Silicon Graphics, Inc. All Rights Reserved.
  13. */
  14. #include <linux/kernel.h>
  15. #include <linux/list.h>
  16. #include <linux/spinlock.h>
  17. #include <linux/mm.h>
  18. #include <linux/slab.h>
  19. #include <linux/device.h>
  20. #include <linux/hugetlb.h>
  21. #include <linux/delay.h>
  22. #include <linux/timex.h>
  23. #include <linux/srcu.h>
  24. #include <asm/processor.h>
  25. #include "gru.h"
  26. #include "grutables.h"
  27. #include <asm/uv/uv_hub.h>
  28. #define gru_random() get_cycles()
  29. /* ---------------------------------- TLB Invalidation functions --------
  30. * get_tgh_handle
  31. *
  32. * Find a TGH to use for issuing a TLB invalidate. For GRUs that are on the
  33. * local blade, use a fixed TGH that is a function of the blade-local cpu
  34. * number. Normally, this TGH is private to the cpu & no contention occurs for
  35. * the TGH. For offblade GRUs, select a random TGH in the range above the
  36. * private TGHs. A spinlock is required to access this TGH & the lock must be
  37. * released when the invalidate is completes. This sucks, but it is the best we
  38. * can do.
  39. *
  40. * Note that the spinlock is IN the TGH handle so locking does not involve
  41. * additional cache lines.
  42. *
  43. */
  44. static inline int get_off_blade_tgh(struct gru_state *gru)
  45. {
  46. int n;
  47. n = GRU_NUM_TGH - gru->gs_tgh_first_remote;
  48. n = gru_random() % n;
  49. n += gru->gs_tgh_first_remote;
  50. return n;
  51. }
  52. static inline int get_on_blade_tgh(struct gru_state *gru)
  53. {
  54. return uv_blade_processor_id() >> gru->gs_tgh_local_shift;
  55. }
  56. static struct gru_tlb_global_handle *get_lock_tgh_handle(struct gru_state
  57. *gru)
  58. {
  59. struct gru_tlb_global_handle *tgh;
  60. int n;
  61. if (uv_numa_blade_id() == gru->gs_blade_id)
  62. n = get_on_blade_tgh(gru);
  63. else
  64. n = get_off_blade_tgh(gru);
  65. tgh = get_tgh_by_index(gru, n);
  66. lock_tgh_handle(tgh);
  67. return tgh;
  68. }
  69. static void get_unlock_tgh_handle(struct gru_tlb_global_handle *tgh)
  70. {
  71. unlock_tgh_handle(tgh);
  72. }
  73. /*
  74. * gru_flush_tlb_range
  75. *
  76. * General purpose TLB invalidation function. This function scans every GRU in
  77. * the ENTIRE system (partition) looking for GRUs where the specified MM has
  78. * been accessed by the GRU. For each GRU found, the TLB must be invalidated OR
  79. * the ASID invalidated. Invalidating an ASID causes a new ASID to be assigned
  80. * on the next fault. This effectively flushes the ENTIRE TLB for the MM at the
  81. * cost of (possibly) a large number of future TLBmisses.
  82. *
  83. * The current algorithm is optimized based on the following (somewhat true)
  84. * assumptions:
  85. * - GRU contexts are not loaded into a GRU unless a reference is made to
  86. * the data segment or control block (this is true, not an assumption).
  87. * If a DS/CB is referenced, the user will also issue instructions that
  88. * cause TLBmisses. It is not necessary to optimize for the case where
  89. * contexts are loaded but no instructions cause TLB misses. (I know
  90. * this will happen but I'm not optimizing for it).
  91. * - GRU instructions to invalidate TLB entries are SLOOOOWWW - normally
  92. * a few usec but in unusual cases, it could be longer. Avoid if
  93. * possible.
  94. * - intrablade process migration between cpus is not frequent but is
  95. * common.
  96. * - a GRU context is not typically migrated to a different GRU on the
  97. * blade because of intrablade migration
  98. * - interblade migration is rare. Processes migrate their GRU context to
  99. * the new blade.
  100. * - if interblade migration occurs, migration back to the original blade
  101. * is very very rare (ie., no optimization for this case)
  102. * - most GRU instruction operate on a subset of the user REGIONS. Code
  103. * & shared library regions are not likely targets of GRU instructions.
  104. *
  105. * To help improve the efficiency of TLB invalidation, the GMS data
  106. * structure is maintained for EACH address space (MM struct). The GMS is
  107. * also the structure that contains the pointer to the mmu callout
  108. * functions. This structure is linked to the mm_struct for the address space
  109. * using the mmu "register" function. The mmu interfaces are used to
  110. * provide the callbacks for TLB invalidation. The GMS contains:
  111. *
  112. * - asid[maxgrus] array. ASIDs are assigned to a GRU when a context is
  113. * loaded into the GRU.
  114. * - asidmap[maxgrus]. bitmap to make it easier to find non-zero asids in
  115. * the above array
  116. * - ctxbitmap[maxgrus]. Indicates the contexts that are currently active
  117. * in the GRU for the address space. This bitmap must be passed to the
  118. * GRU to do an invalidate.
  119. *
  120. * The current algorithm for invalidating TLBs is:
  121. * - scan the asidmap for GRUs where the context has been loaded, ie,
  122. * asid is non-zero.
  123. * - for each gru found:
  124. * - if the ctxtmap is non-zero, there are active contexts in the
  125. * GRU. TLB invalidate instructions must be issued to the GRU.
  126. * - if the ctxtmap is zero, no context is active. Set the ASID to
  127. * zero to force a full TLB invalidation. This is fast but will
  128. * cause a lot of TLB misses if the context is reloaded onto the
  129. * GRU
  130. *
  131. */
  132. void gru_flush_tlb_range(struct gru_mm_struct *gms, unsigned long start,
  133. unsigned long len)
  134. {
  135. struct gru_state *gru;
  136. struct gru_mm_tracker *asids;
  137. struct gru_tlb_global_handle *tgh;
  138. unsigned long num;
  139. int grupagesize, pagesize, pageshift, gid, asid;
  140. /* ZZZ TODO - handle huge pages */
  141. pageshift = PAGE_SHIFT;
  142. pagesize = (1UL << pageshift);
  143. grupagesize = GRU_PAGESIZE(pageshift);
  144. num = min(((len + pagesize - 1) >> pageshift), GRUMAXINVAL);
  145. STAT(flush_tlb);
  146. gru_dbg(grudev, "gms %p, start 0x%lx, len 0x%lx, asidmap 0x%lx\n", gms,
  147. start, len, gms->ms_asidmap[0]);
  148. spin_lock(&gms->ms_asid_lock);
  149. for_each_gru_in_bitmap(gid, gms->ms_asidmap) {
  150. STAT(flush_tlb_gru);
  151. gru = GID_TO_GRU(gid);
  152. asids = gms->ms_asids + gid;
  153. asid = asids->mt_asid;
  154. if (asids->mt_ctxbitmap && asid) {
  155. STAT(flush_tlb_gru_tgh);
  156. asid = GRUASID(asid, start);
  157. gru_dbg(grudev,
  158. " FLUSH gruid %d, asid 0x%x, vaddr 0x%lx, vamask 0x%x, num %ld, cbmap 0x%x\n",
  159. gid, asid, start, grupagesize, num, asids->mt_ctxbitmap);
  160. tgh = get_lock_tgh_handle(gru);
  161. tgh_invalidate(tgh, start, ~0, asid, grupagesize, 0,
  162. num - 1, asids->mt_ctxbitmap);
  163. get_unlock_tgh_handle(tgh);
  164. } else {
  165. STAT(flush_tlb_gru_zero_asid);
  166. asids->mt_asid = 0;
  167. __clear_bit(gru->gs_gid, gms->ms_asidmap);
  168. gru_dbg(grudev,
  169. " CLEARASID gruid %d, asid 0x%x, cbtmap 0x%x, asidmap 0x%lx\n",
  170. gid, asid, asids->mt_ctxbitmap,
  171. gms->ms_asidmap[0]);
  172. }
  173. }
  174. spin_unlock(&gms->ms_asid_lock);
  175. }
  176. /*
  177. * Flush the entire TLB on a chiplet.
  178. */
  179. void gru_flush_all_tlb(struct gru_state *gru)
  180. {
  181. struct gru_tlb_global_handle *tgh;
  182. gru_dbg(grudev, "gid %d\n", gru->gs_gid);
  183. tgh = get_lock_tgh_handle(gru);
  184. tgh_invalidate(tgh, 0, ~0, 0, 1, 1, GRUMAXINVAL - 1, 0xffff);
  185. get_unlock_tgh_handle(tgh);
  186. }
  187. /*
  188. * MMUOPS notifier callout functions
  189. */
  190. static int gru_invalidate_range_start(struct mmu_notifier *mn,
  191. const struct mmu_notifier_range *range)
  192. {
  193. struct gru_mm_struct *gms = container_of(mn, struct gru_mm_struct,
  194. ms_notifier);
  195. STAT(mmu_invalidate_range);
  196. atomic_inc(&gms->ms_range_active);
  197. gru_dbg(grudev, "gms %p, start 0x%lx, end 0x%lx, act %d\n", gms,
  198. range->start, range->end, atomic_read(&gms->ms_range_active));
  199. gru_flush_tlb_range(gms, range->start, range->end - range->start);
  200. return 0;
  201. }
  202. static void gru_invalidate_range_end(struct mmu_notifier *mn,
  203. const struct mmu_notifier_range *range)
  204. {
  205. struct gru_mm_struct *gms = container_of(mn, struct gru_mm_struct,
  206. ms_notifier);
  207. /* ..._and_test() provides needed barrier */
  208. (void)atomic_dec_and_test(&gms->ms_range_active);
  209. wake_up_all(&gms->ms_wait_queue);
  210. gru_dbg(grudev, "gms %p, start 0x%lx, end 0x%lx\n",
  211. gms, range->start, range->end);
  212. }
  213. static struct mmu_notifier *gru_alloc_notifier(struct mm_struct *mm)
  214. {
  215. struct gru_mm_struct *gms;
  216. gms = kzalloc(sizeof(*gms), GFP_KERNEL);
  217. if (!gms)
  218. return ERR_PTR(-ENOMEM);
  219. STAT(gms_alloc);
  220. spin_lock_init(&gms->ms_asid_lock);
  221. init_waitqueue_head(&gms->ms_wait_queue);
  222. return &gms->ms_notifier;
  223. }
  224. static void gru_free_notifier(struct mmu_notifier *mn)
  225. {
  226. kfree(container_of(mn, struct gru_mm_struct, ms_notifier));
  227. STAT(gms_free);
  228. }
  229. static const struct mmu_notifier_ops gru_mmuops = {
  230. .invalidate_range_start = gru_invalidate_range_start,
  231. .invalidate_range_end = gru_invalidate_range_end,
  232. .alloc_notifier = gru_alloc_notifier,
  233. .free_notifier = gru_free_notifier,
  234. };
  235. struct gru_mm_struct *gru_register_mmu_notifier(void)
  236. {
  237. struct mmu_notifier *mn;
  238. mn = mmu_notifier_get_locked(&gru_mmuops, current->mm);
  239. if (IS_ERR(mn))
  240. return ERR_CAST(mn);
  241. return container_of(mn, struct gru_mm_struct, ms_notifier);
  242. }
  243. void gru_drop_mmu_notifier(struct gru_mm_struct *gms)
  244. {
  245. mmu_notifier_put(&gms->ms_notifier);
  246. }
  247. /*
  248. * Setup TGH parameters. There are:
  249. * - 24 TGH handles per GRU chiplet
  250. * - a portion (MAX_LOCAL_TGH) of the handles are reserved for
  251. * use by blade-local cpus
  252. * - the rest are used by off-blade cpus. This usage is
  253. * less frequent than blade-local usage.
  254. *
  255. * For now, use 16 handles for local flushes, 8 for remote flushes. If the blade
  256. * has less tan or equal to 16 cpus, each cpu has a unique handle that it can
  257. * use.
  258. */
  259. #define MAX_LOCAL_TGH 16
  260. void gru_tgh_flush_init(struct gru_state *gru)
  261. {
  262. int cpus, shift = 0, n;
  263. cpus = uv_blade_nr_possible_cpus(gru->gs_blade_id);
  264. /* n = cpus rounded up to next power of 2 */
  265. if (cpus) {
  266. n = 1 << fls(cpus - 1);
  267. /*
  268. * shift count for converting local cpu# to TGH index
  269. * 0 if cpus <= MAX_LOCAL_TGH,
  270. * 1 if cpus <= 2*MAX_LOCAL_TGH,
  271. * etc
  272. */
  273. shift = max(0, fls(n - 1) - fls(MAX_LOCAL_TGH - 1));
  274. }
  275. gru->gs_tgh_local_shift = shift;
  276. /* first starting TGH index to use for remote purges */
  277. gru->gs_tgh_first_remote = (cpus + (1 << shift) - 1) >> shift;
  278. }