/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c

https://gitlab.com/sunny256/linux · C · 292 lines · 161 code · 39 blank · 92 comment · 17 complexity · 5d3939a5dfc0855cd5252d25f03d4cf9 MD5 · raw file

  1. /*
  2. * Copyright 2016 Advanced Micro Devices, Inc.
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  17. * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18. * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19. * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20. * OTHER DEALINGS IN THE SOFTWARE.
  21. *
  22. * Authors: Christian König
  23. */
  24. #include <drm/drmP.h>
  25. #include "amdgpu.h"
  26. struct amdgpu_vram_mgr {
  27. struct drm_mm mm;
  28. spinlock_t lock;
  29. atomic64_t usage;
  30. atomic64_t vis_usage;
  31. };
  32. /**
  33. * amdgpu_vram_mgr_init - init VRAM manager and DRM MM
  34. *
  35. * @man: TTM memory type manager
  36. * @p_size: maximum size of VRAM
  37. *
  38. * Allocate and initialize the VRAM manager.
  39. */
  40. static int amdgpu_vram_mgr_init(struct ttm_mem_type_manager *man,
  41. unsigned long p_size)
  42. {
  43. struct amdgpu_vram_mgr *mgr;
  44. mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
  45. if (!mgr)
  46. return -ENOMEM;
  47. drm_mm_init(&mgr->mm, 0, p_size);
  48. spin_lock_init(&mgr->lock);
  49. man->priv = mgr;
  50. return 0;
  51. }
  52. /**
  53. * amdgpu_vram_mgr_fini - free and destroy VRAM manager
  54. *
  55. * @man: TTM memory type manager
  56. *
  57. * Destroy and free the VRAM manager, returns -EBUSY if ranges are still
  58. * allocated inside it.
  59. */
  60. static int amdgpu_vram_mgr_fini(struct ttm_mem_type_manager *man)
  61. {
  62. struct amdgpu_vram_mgr *mgr = man->priv;
  63. spin_lock(&mgr->lock);
  64. drm_mm_takedown(&mgr->mm);
  65. spin_unlock(&mgr->lock);
  66. kfree(mgr);
  67. man->priv = NULL;
  68. return 0;
  69. }
  70. /**
  71. * amdgpu_vram_mgr_vis_size - Calculate visible node size
  72. *
  73. * @adev: amdgpu device structure
  74. * @node: MM node structure
  75. *
  76. * Calculate how many bytes of the MM node are inside visible VRAM
  77. */
  78. static u64 amdgpu_vram_mgr_vis_size(struct amdgpu_device *adev,
  79. struct drm_mm_node *node)
  80. {
  81. uint64_t start = node->start << PAGE_SHIFT;
  82. uint64_t end = (node->size + node->start) << PAGE_SHIFT;
  83. if (start >= adev->mc.visible_vram_size)
  84. return 0;
  85. return (end > adev->mc.visible_vram_size ?
  86. adev->mc.visible_vram_size : end) - start;
  87. }
  88. /**
  89. * amdgpu_vram_mgr_new - allocate new ranges
  90. *
  91. * @man: TTM memory type manager
  92. * @tbo: TTM BO we need this range for
  93. * @place: placement flags and restrictions
  94. * @mem: the resulting mem object
  95. *
  96. * Allocate VRAM for the given BO.
  97. */
  98. static int amdgpu_vram_mgr_new(struct ttm_mem_type_manager *man,
  99. struct ttm_buffer_object *tbo,
  100. const struct ttm_place *place,
  101. struct ttm_mem_reg *mem)
  102. {
  103. struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
  104. struct amdgpu_vram_mgr *mgr = man->priv;
  105. struct drm_mm *mm = &mgr->mm;
  106. struct drm_mm_node *nodes;
  107. enum drm_mm_insert_mode mode;
  108. unsigned long lpfn, num_nodes, pages_per_node, pages_left;
  109. uint64_t usage = 0, vis_usage = 0;
  110. unsigned i;
  111. int r;
  112. lpfn = place->lpfn;
  113. if (!lpfn)
  114. lpfn = man->size;
  115. if (place->flags & TTM_PL_FLAG_CONTIGUOUS ||
  116. amdgpu_vram_page_split == -1) {
  117. pages_per_node = ~0ul;
  118. num_nodes = 1;
  119. } else {
  120. pages_per_node = max((uint32_t)amdgpu_vram_page_split,
  121. mem->page_alignment);
  122. num_nodes = DIV_ROUND_UP(mem->num_pages, pages_per_node);
  123. }
  124. nodes = kcalloc(num_nodes, sizeof(*nodes), GFP_KERNEL);
  125. if (!nodes)
  126. return -ENOMEM;
  127. mode = DRM_MM_INSERT_BEST;
  128. if (place->flags & TTM_PL_FLAG_TOPDOWN)
  129. mode = DRM_MM_INSERT_HIGH;
  130. mem->start = 0;
  131. pages_left = mem->num_pages;
  132. spin_lock(&mgr->lock);
  133. for (i = 0; i < num_nodes; ++i) {
  134. unsigned long pages = min(pages_left, pages_per_node);
  135. uint32_t alignment = mem->page_alignment;
  136. unsigned long start;
  137. if (pages == pages_per_node)
  138. alignment = pages_per_node;
  139. r = drm_mm_insert_node_in_range(mm, &nodes[i],
  140. pages, alignment, 0,
  141. place->fpfn, lpfn,
  142. mode);
  143. if (unlikely(r))
  144. goto error;
  145. usage += nodes[i].size << PAGE_SHIFT;
  146. vis_usage += amdgpu_vram_mgr_vis_size(adev, &nodes[i]);
  147. /* Calculate a virtual BO start address to easily check if
  148. * everything is CPU accessible.
  149. */
  150. start = nodes[i].start + nodes[i].size;
  151. if (start > mem->num_pages)
  152. start -= mem->num_pages;
  153. else
  154. start = 0;
  155. mem->start = max(mem->start, start);
  156. pages_left -= pages;
  157. }
  158. spin_unlock(&mgr->lock);
  159. atomic64_add(usage, &mgr->usage);
  160. atomic64_add(vis_usage, &mgr->vis_usage);
  161. mem->mm_node = nodes;
  162. return 0;
  163. error:
  164. while (i--)
  165. drm_mm_remove_node(&nodes[i]);
  166. spin_unlock(&mgr->lock);
  167. kfree(nodes);
  168. return r == -ENOSPC ? 0 : r;
  169. }
  170. /**
  171. * amdgpu_vram_mgr_del - free ranges
  172. *
  173. * @man: TTM memory type manager
  174. * @tbo: TTM BO we need this range for
  175. * @place: placement flags and restrictions
  176. * @mem: TTM memory object
  177. *
  178. * Free the allocated VRAM again.
  179. */
  180. static void amdgpu_vram_mgr_del(struct ttm_mem_type_manager *man,
  181. struct ttm_mem_reg *mem)
  182. {
  183. struct amdgpu_device *adev = amdgpu_ttm_adev(man->bdev);
  184. struct amdgpu_vram_mgr *mgr = man->priv;
  185. struct drm_mm_node *nodes = mem->mm_node;
  186. uint64_t usage = 0, vis_usage = 0;
  187. unsigned pages = mem->num_pages;
  188. if (!mem->mm_node)
  189. return;
  190. spin_lock(&mgr->lock);
  191. while (pages) {
  192. pages -= nodes->size;
  193. drm_mm_remove_node(nodes);
  194. usage += nodes->size << PAGE_SHIFT;
  195. vis_usage += amdgpu_vram_mgr_vis_size(adev, nodes);
  196. ++nodes;
  197. }
  198. spin_unlock(&mgr->lock);
  199. atomic64_sub(usage, &mgr->usage);
  200. atomic64_sub(vis_usage, &mgr->vis_usage);
  201. kfree(mem->mm_node);
  202. mem->mm_node = NULL;
  203. }
  204. /**
  205. * amdgpu_vram_mgr_usage - how many bytes are used in this domain
  206. *
  207. * @man: TTM memory type manager
  208. *
  209. * Returns how many bytes are used in this domain.
  210. */
  211. uint64_t amdgpu_vram_mgr_usage(struct ttm_mem_type_manager *man)
  212. {
  213. struct amdgpu_vram_mgr *mgr = man->priv;
  214. return atomic64_read(&mgr->usage);
  215. }
  216. /**
  217. * amdgpu_vram_mgr_vis_usage - how many bytes are used in the visible part
  218. *
  219. * @man: TTM memory type manager
  220. *
  221. * Returns how many bytes are used in the visible part of VRAM
  222. */
  223. uint64_t amdgpu_vram_mgr_vis_usage(struct ttm_mem_type_manager *man)
  224. {
  225. struct amdgpu_vram_mgr *mgr = man->priv;
  226. return atomic64_read(&mgr->vis_usage);
  227. }
  228. /**
  229. * amdgpu_vram_mgr_debug - dump VRAM table
  230. *
  231. * @man: TTM memory type manager
  232. * @printer: DRM printer to use
  233. *
  234. * Dump the table content using printk.
  235. */
  236. static void amdgpu_vram_mgr_debug(struct ttm_mem_type_manager *man,
  237. struct drm_printer *printer)
  238. {
  239. struct amdgpu_vram_mgr *mgr = man->priv;
  240. spin_lock(&mgr->lock);
  241. drm_mm_print(&mgr->mm, printer);
  242. spin_unlock(&mgr->lock);
  243. drm_printf(printer, "man size:%llu pages, ram usage:%lluMB, vis usage:%lluMB\n",
  244. man->size, amdgpu_vram_mgr_usage(man) >> 20,
  245. amdgpu_vram_mgr_vis_usage(man) >> 20);
  246. }
  247. const struct ttm_mem_type_manager_func amdgpu_vram_mgr_func = {
  248. .init = amdgpu_vram_mgr_init,
  249. .takedown = amdgpu_vram_mgr_fini,
  250. .get_node = amdgpu_vram_mgr_new,
  251. .put_node = amdgpu_vram_mgr_del,
  252. .debug = amdgpu_vram_mgr_debug
  253. };