panthor_gem.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. // SPDX-License-Identifier: GPL-2.0 or MIT
  2. /* Copyright 2019 Linaro, Ltd, Rob Herring <robh@kernel.org> */
  3. /* Copyright 2023 Collabora ltd. */
  4. /* Copyright 2025 Amazon.com, Inc. or its affiliates */
  5. #include <linux/cleanup.h>
  6. #include <linux/dma-buf.h>
  7. #include <linux/dma-mapping.h>
  8. #include <linux/err.h>
  9. #include <linux/slab.h>
  10. #include <drm/drm_print.h>
  11. #include <drm/panthor_drm.h>
  12. #include "panthor_device.h"
  13. #include "panthor_drv.h"
  14. #include "panthor_fw.h"
  15. #include "panthor_gem.h"
  16. #include "panthor_mmu.h"
  17. void panthor_gem_init(struct panthor_device *ptdev)
  18. {
  19. int err;
  20. if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) &&
  21. !panthor_transparent_hugepage)
  22. return;
  23. err = drm_gem_huge_mnt_create(&ptdev->base, "within_size");
  24. if (drm_gem_get_huge_mnt(&ptdev->base))
  25. drm_info(&ptdev->base, "Using Transparent Hugepage\n");
  26. else if (err)
  27. drm_warn(&ptdev->base, "Can't use Transparent Hugepage (%d)\n",
  28. err);
  29. }
  30. #ifdef CONFIG_DEBUG_FS
  31. static void panthor_gem_debugfs_bo_init(struct panthor_gem_object *bo)
  32. {
  33. INIT_LIST_HEAD(&bo->debugfs.node);
  34. }
  35. static void panthor_gem_debugfs_bo_add(struct panthor_gem_object *bo)
  36. {
  37. struct panthor_device *ptdev = container_of(bo->base.base.dev,
  38. struct panthor_device, base);
  39. bo->debugfs.creator.tgid = current->tgid;
  40. get_task_comm(bo->debugfs.creator.process_name, current->group_leader);
  41. mutex_lock(&ptdev->gems.lock);
  42. list_add_tail(&bo->debugfs.node, &ptdev->gems.node);
  43. mutex_unlock(&ptdev->gems.lock);
  44. }
  45. static void panthor_gem_debugfs_bo_rm(struct panthor_gem_object *bo)
  46. {
  47. struct panthor_device *ptdev = container_of(bo->base.base.dev,
  48. struct panthor_device, base);
  49. if (list_empty(&bo->debugfs.node))
  50. return;
  51. mutex_lock(&ptdev->gems.lock);
  52. list_del_init(&bo->debugfs.node);
  53. mutex_unlock(&ptdev->gems.lock);
  54. }
  55. static void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u32 usage_flags)
  56. {
  57. bo->debugfs.flags = usage_flags;
  58. panthor_gem_debugfs_bo_add(bo);
  59. }
  60. #else
  61. static void panthor_gem_debugfs_bo_rm(struct panthor_gem_object *bo) {}
  62. static void panthor_gem_debugfs_set_usage_flags(struct panthor_gem_object *bo, u32 usage_flags) {}
  63. static void panthor_gem_debugfs_bo_init(struct panthor_gem_object *bo) {}
  64. #endif
  65. static bool
  66. should_map_wc(struct panthor_gem_object *bo, struct panthor_vm *exclusive_vm)
  67. {
  68. struct panthor_device *ptdev = container_of(bo->base.base.dev, struct panthor_device, base);
  69. /* We can't do uncached mappings if the device is coherent,
  70. * because the zeroing done by the shmem layer at page allocation
  71. * time happens on a cached mapping which isn't CPU-flushed (at least
  72. * not on Arm64 where the flush is deferred to PTE setup time, and
  73. * only done conditionally based on the mapping permissions). We can't
  74. * rely on dma_map_sgtable()/dma_sync_sgtable_for_xxx() either to flush
  75. * those, because they are NOPed if dma_dev_coherent() returns true.
  76. *
  77. * FIXME: Note that this problem is going to pop up again when we
  78. * decide to support mapping buffers with the NO_MMAP flag as
  79. * non-shareable (AKA buffers accessed only by the GPU), because we
  80. * need the same CPU flush to happen after page allocation, otherwise
  81. * there's a risk of data leak or late corruption caused by a dirty
  82. * cacheline being evicted. At this point we'll need a way to force
  83. * CPU cache maintenance regardless of whether the device is coherent
  84. * or not.
  85. */
  86. if (ptdev->coherent)
  87. return false;
  88. /* Cached mappings are explicitly requested, so no write-combine. */
  89. if (bo->flags & DRM_PANTHOR_BO_WB_MMAP)
  90. return false;
  91. /* The default is write-combine. */
  92. return true;
  93. }
  94. static void panthor_gem_free_object(struct drm_gem_object *obj)
  95. {
  96. struct panthor_gem_object *bo = to_panthor_bo(obj);
  97. struct drm_gem_object *vm_root_gem = bo->exclusive_vm_root_gem;
  98. panthor_gem_debugfs_bo_rm(bo);
  99. /*
  100. * Label might have been allocated with kstrdup_const(),
  101. * we need to take that into account when freeing the memory
  102. */
  103. kfree_const(bo->label.str);
  104. mutex_destroy(&bo->label.lock);
  105. drm_gem_free_mmap_offset(&bo->base.base);
  106. drm_gem_shmem_free(&bo->base);
  107. drm_gem_object_put(vm_root_gem);
  108. }
  109. /**
  110. * panthor_kernel_bo_destroy() - Destroy a kernel buffer object
  111. * @bo: Kernel buffer object to destroy. If NULL or an ERR_PTR(), the destruction
  112. * is skipped.
  113. */
  114. void panthor_kernel_bo_destroy(struct panthor_kernel_bo *bo)
  115. {
  116. struct panthor_vm *vm;
  117. if (IS_ERR_OR_NULL(bo))
  118. return;
  119. vm = bo->vm;
  120. panthor_kernel_bo_vunmap(bo);
  121. drm_WARN_ON(bo->obj->dev,
  122. to_panthor_bo(bo->obj)->exclusive_vm_root_gem != panthor_vm_root_gem(vm));
  123. panthor_vm_unmap_range(vm, bo->va_node.start, bo->va_node.size);
  124. panthor_vm_free_va(vm, &bo->va_node);
  125. drm_gem_object_put(bo->obj);
  126. panthor_vm_put(vm);
  127. kfree(bo);
  128. }
  129. /**
  130. * panthor_kernel_bo_create() - Create and map a GEM object to a VM
  131. * @ptdev: Device.
  132. * @vm: VM to map the GEM to. If NULL, the kernel object is not GPU mapped.
  133. * @size: Size of the buffer object.
  134. * @bo_flags: Combination of drm_panthor_bo_flags flags.
  135. * @vm_map_flags: Combination of drm_panthor_vm_bind_op_flags (only those
  136. * that are related to map operations).
  137. * @gpu_va: GPU address assigned when mapping to the VM.
  138. * If gpu_va == PANTHOR_VM_KERNEL_AUTO_VA, the virtual address will be
  139. * automatically allocated.
  140. * @name: Descriptive label of the BO's contents
  141. *
  142. * Return: A valid pointer in case of success, an ERR_PTR() otherwise.
  143. */
  144. struct panthor_kernel_bo *
  145. panthor_kernel_bo_create(struct panthor_device *ptdev, struct panthor_vm *vm,
  146. size_t size, u32 bo_flags, u32 vm_map_flags,
  147. u64 gpu_va, const char *name)
  148. {
  149. struct drm_gem_shmem_object *obj;
  150. struct panthor_kernel_bo *kbo;
  151. struct panthor_gem_object *bo;
  152. u32 debug_flags = PANTHOR_DEBUGFS_GEM_USAGE_FLAG_KERNEL;
  153. int ret;
  154. if (drm_WARN_ON(&ptdev->base, !vm))
  155. return ERR_PTR(-EINVAL);
  156. kbo = kzalloc_obj(*kbo);
  157. if (!kbo)
  158. return ERR_PTR(-ENOMEM);
  159. obj = drm_gem_shmem_create(&ptdev->base, size);
  160. if (IS_ERR(obj)) {
  161. ret = PTR_ERR(obj);
  162. goto err_free_bo;
  163. }
  164. bo = to_panthor_bo(&obj->base);
  165. kbo->obj = &obj->base;
  166. bo->flags = bo_flags;
  167. bo->base.map_wc = should_map_wc(bo, vm);
  168. bo->exclusive_vm_root_gem = panthor_vm_root_gem(vm);
  169. drm_gem_object_get(bo->exclusive_vm_root_gem);
  170. bo->base.base.resv = bo->exclusive_vm_root_gem->resv;
  171. if (vm == panthor_fw_vm(ptdev))
  172. debug_flags |= PANTHOR_DEBUGFS_GEM_USAGE_FLAG_FW_MAPPED;
  173. panthor_gem_kernel_bo_set_label(kbo, name);
  174. panthor_gem_debugfs_set_usage_flags(to_panthor_bo(kbo->obj), debug_flags);
  175. /* The system and GPU MMU page size might differ, which becomes a
  176. * problem for FW sections that need to be mapped at explicit address
  177. * since our PAGE_SIZE alignment might cover a VA range that's
  178. * expected to be used for another section.
  179. * Make sure we never map more than we need.
  180. */
  181. size = ALIGN(size, panthor_vm_page_size(vm));
  182. ret = panthor_vm_alloc_va(vm, gpu_va, size, &kbo->va_node);
  183. if (ret)
  184. goto err_put_obj;
  185. ret = panthor_vm_map_bo_range(vm, bo, 0, size, kbo->va_node.start, vm_map_flags);
  186. if (ret)
  187. goto err_free_va;
  188. kbo->vm = panthor_vm_get(vm);
  189. return kbo;
  190. err_free_va:
  191. panthor_vm_free_va(vm, &kbo->va_node);
  192. err_put_obj:
  193. drm_gem_object_put(&obj->base);
  194. err_free_bo:
  195. kfree(kbo);
  196. return ERR_PTR(ret);
  197. }
  198. static struct sg_table *
  199. panthor_gem_prime_map_dma_buf(struct dma_buf_attachment *attach,
  200. enum dma_data_direction dir)
  201. {
  202. struct sg_table *sgt = drm_gem_map_dma_buf(attach, dir);
  203. if (!IS_ERR(sgt))
  204. attach->priv = sgt;
  205. return sgt;
  206. }
  207. static void
  208. panthor_gem_prime_unmap_dma_buf(struct dma_buf_attachment *attach,
  209. struct sg_table *sgt,
  210. enum dma_data_direction dir)
  211. {
  212. attach->priv = NULL;
  213. drm_gem_unmap_dma_buf(attach, sgt, dir);
  214. }
  215. static int
  216. panthor_gem_prime_begin_cpu_access(struct dma_buf *dma_buf,
  217. enum dma_data_direction dir)
  218. {
  219. struct drm_gem_object *obj = dma_buf->priv;
  220. struct drm_device *dev = obj->dev;
  221. struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
  222. struct dma_buf_attachment *attach;
  223. dma_resv_lock(obj->resv, NULL);
  224. if (shmem->sgt)
  225. dma_sync_sgtable_for_cpu(dev->dev, shmem->sgt, dir);
  226. if (shmem->vaddr)
  227. invalidate_kernel_vmap_range(shmem->vaddr, shmem->base.size);
  228. list_for_each_entry(attach, &dma_buf->attachments, node) {
  229. struct sg_table *sgt = attach->priv;
  230. if (sgt)
  231. dma_sync_sgtable_for_cpu(attach->dev, sgt, dir);
  232. }
  233. dma_resv_unlock(obj->resv);
  234. return 0;
  235. }
  236. static int
  237. panthor_gem_prime_end_cpu_access(struct dma_buf *dma_buf,
  238. enum dma_data_direction dir)
  239. {
  240. struct drm_gem_object *obj = dma_buf->priv;
  241. struct drm_device *dev = obj->dev;
  242. struct drm_gem_shmem_object *shmem = to_drm_gem_shmem_obj(obj);
  243. struct dma_buf_attachment *attach;
  244. dma_resv_lock(obj->resv, NULL);
  245. list_for_each_entry(attach, &dma_buf->attachments, node) {
  246. struct sg_table *sgt = attach->priv;
  247. if (sgt)
  248. dma_sync_sgtable_for_device(attach->dev, sgt, dir);
  249. }
  250. if (shmem->vaddr)
  251. flush_kernel_vmap_range(shmem->vaddr, shmem->base.size);
  252. if (shmem->sgt)
  253. dma_sync_sgtable_for_device(dev->dev, shmem->sgt, dir);
  254. dma_resv_unlock(obj->resv);
  255. return 0;
  256. }
  257. static const struct dma_buf_ops panthor_dma_buf_ops = {
  258. .attach = drm_gem_map_attach,
  259. .detach = drm_gem_map_detach,
  260. .map_dma_buf = panthor_gem_prime_map_dma_buf,
  261. .unmap_dma_buf = panthor_gem_prime_unmap_dma_buf,
  262. .release = drm_gem_dmabuf_release,
  263. .mmap = drm_gem_dmabuf_mmap,
  264. .vmap = drm_gem_dmabuf_vmap,
  265. .vunmap = drm_gem_dmabuf_vunmap,
  266. .begin_cpu_access = panthor_gem_prime_begin_cpu_access,
  267. .end_cpu_access = panthor_gem_prime_end_cpu_access,
  268. };
  269. static struct dma_buf *
  270. panthor_gem_prime_export(struct drm_gem_object *obj, int flags)
  271. {
  272. struct drm_device *dev = obj->dev;
  273. struct dma_buf_export_info exp_info = {
  274. .exp_name = KBUILD_MODNAME,
  275. .owner = THIS_MODULE,
  276. .ops = &panthor_dma_buf_ops,
  277. .size = obj->size,
  278. .flags = flags,
  279. .priv = obj,
  280. .resv = obj->resv,
  281. };
  282. /* We can't export GEMs that have an exclusive VM. */
  283. if (to_panthor_bo(obj)->exclusive_vm_root_gem)
  284. return ERR_PTR(-EINVAL);
  285. return drm_gem_dmabuf_export(dev, &exp_info);
  286. }
  287. struct drm_gem_object *
  288. panthor_gem_prime_import(struct drm_device *dev,
  289. struct dma_buf *dma_buf)
  290. {
  291. struct drm_gem_object *obj = dma_buf->priv;
  292. if (dma_buf->ops == &panthor_dma_buf_ops && obj->dev == dev) {
  293. /* Importing dmabuf exported from our own gem increases
  294. * refcount on gem itself instead of f_count of dmabuf.
  295. */
  296. drm_gem_object_get(obj);
  297. return obj;
  298. }
  299. return drm_gem_prime_import(dev, dma_buf);
  300. }
  301. static enum drm_gem_object_status panthor_gem_status(struct drm_gem_object *obj)
  302. {
  303. struct panthor_gem_object *bo = to_panthor_bo(obj);
  304. enum drm_gem_object_status res = 0;
  305. if (drm_gem_is_imported(&bo->base.base) || bo->base.pages)
  306. res |= DRM_GEM_OBJECT_RESIDENT;
  307. return res;
  308. }
  309. static const struct drm_gem_object_funcs panthor_gem_funcs = {
  310. .free = panthor_gem_free_object,
  311. .print_info = drm_gem_shmem_object_print_info,
  312. .pin = drm_gem_shmem_object_pin,
  313. .unpin = drm_gem_shmem_object_unpin,
  314. .get_sg_table = drm_gem_shmem_object_get_sg_table,
  315. .vmap = drm_gem_shmem_object_vmap,
  316. .vunmap = drm_gem_shmem_object_vunmap,
  317. .mmap = drm_gem_shmem_object_mmap,
  318. .status = panthor_gem_status,
  319. .export = panthor_gem_prime_export,
  320. .vm_ops = &drm_gem_shmem_vm_ops,
  321. };
  322. /**
  323. * panthor_gem_create_object - Implementation of driver->gem_create_object.
  324. * @ddev: DRM device
  325. * @size: Size in bytes of the memory the object will reference
  326. *
  327. * This lets the GEM helpers allocate object structs for us, and keep
  328. * our BO stats correct.
  329. */
  330. struct drm_gem_object *panthor_gem_create_object(struct drm_device *ddev, size_t size)
  331. {
  332. struct panthor_gem_object *obj;
  333. obj = kzalloc_obj(*obj);
  334. if (!obj)
  335. return ERR_PTR(-ENOMEM);
  336. obj->base.base.funcs = &panthor_gem_funcs;
  337. mutex_init(&obj->label.lock);
  338. panthor_gem_debugfs_bo_init(obj);
  339. return &obj->base.base;
  340. }
  341. /**
  342. * panthor_gem_create_with_handle() - Create a GEM object and attach it to a handle.
  343. * @file: DRM file.
  344. * @ddev: DRM device.
  345. * @exclusive_vm: Exclusive VM. Not NULL if the GEM object can't be shared.
  346. * @size: Size of the GEM object to allocate.
  347. * @flags: Combination of drm_panthor_bo_flags flags.
  348. * @handle: Pointer holding the handle pointing to the new GEM object.
  349. *
  350. * Return: Zero on success
  351. */
  352. int
  353. panthor_gem_create_with_handle(struct drm_file *file,
  354. struct drm_device *ddev,
  355. struct panthor_vm *exclusive_vm,
  356. u64 *size, u32 flags, u32 *handle)
  357. {
  358. int ret;
  359. struct drm_gem_shmem_object *shmem;
  360. struct panthor_gem_object *bo;
  361. shmem = drm_gem_shmem_create(ddev, *size);
  362. if (IS_ERR(shmem))
  363. return PTR_ERR(shmem);
  364. bo = to_panthor_bo(&shmem->base);
  365. bo->flags = flags;
  366. bo->base.map_wc = should_map_wc(bo, exclusive_vm);
  367. if (exclusive_vm) {
  368. bo->exclusive_vm_root_gem = panthor_vm_root_gem(exclusive_vm);
  369. drm_gem_object_get(bo->exclusive_vm_root_gem);
  370. bo->base.base.resv = bo->exclusive_vm_root_gem->resv;
  371. }
  372. panthor_gem_debugfs_set_usage_flags(bo, 0);
  373. /* If this is a write-combine mapping, we query the sgt to force a CPU
  374. * cache flush (dma_map_sgtable() is called when the sgt is created).
  375. * This ensures the zero-ing is visible to any uncached mapping created
  376. * by vmap/mmap.
  377. * FIXME: Ideally this should be done when pages are allocated, not at
  378. * BO creation time.
  379. */
  380. if (shmem->map_wc) {
  381. struct sg_table *sgt;
  382. sgt = drm_gem_shmem_get_pages_sgt(shmem);
  383. if (IS_ERR(sgt)) {
  384. ret = PTR_ERR(sgt);
  385. goto out_put_gem;
  386. }
  387. }
  388. /*
  389. * Allocate an id of idr table where the obj is registered
  390. * and handle has the id what user can see.
  391. */
  392. ret = drm_gem_handle_create(file, &shmem->base, handle);
  393. if (!ret)
  394. *size = bo->base.base.size;
  395. out_put_gem:
  396. /* drop reference from allocate - handle holds it now. */
  397. drm_gem_object_put(&shmem->base);
  398. return ret;
  399. }
  400. void
  401. panthor_gem_bo_set_label(struct drm_gem_object *obj, const char *label)
  402. {
  403. struct panthor_gem_object *bo = to_panthor_bo(obj);
  404. const char *old_label;
  405. scoped_guard(mutex, &bo->label.lock) {
  406. old_label = bo->label.str;
  407. bo->label.str = label;
  408. }
  409. kfree_const(old_label);
  410. }
  411. void
  412. panthor_gem_kernel_bo_set_label(struct panthor_kernel_bo *bo, const char *label)
  413. {
  414. const char *str;
  415. /* We should never attempt labelling a UM-exposed GEM object */
  416. if (drm_WARN_ON(bo->obj->dev, bo->obj->handle_count > 0))
  417. return;
  418. if (!label)
  419. return;
  420. str = kstrdup_const(label, GFP_KERNEL);
  421. if (!str) {
  422. /* Failing to allocate memory for a label isn't a fatal condition */
  423. drm_warn(bo->obj->dev, "Not enough memory to allocate BO label");
  424. return;
  425. }
  426. panthor_gem_bo_set_label(bo->obj, str);
  427. }
  428. int
  429. panthor_gem_sync(struct drm_gem_object *obj, u32 type,
  430. u64 offset, u64 size)
  431. {
  432. struct panthor_gem_object *bo = to_panthor_bo(obj);
  433. struct drm_gem_shmem_object *shmem = &bo->base;
  434. const struct drm_device *dev = shmem->base.dev;
  435. struct sg_table *sgt;
  436. struct scatterlist *sgl;
  437. unsigned int count;
  438. /* Make sure the range is in bounds. */
  439. if (offset + size < offset || offset + size > shmem->base.size)
  440. return -EINVAL;
  441. /* Disallow CPU-cache maintenance on imported buffers. */
  442. if (drm_gem_is_imported(&shmem->base))
  443. return -EINVAL;
  444. switch (type) {
  445. case DRM_PANTHOR_BO_SYNC_CPU_CACHE_FLUSH:
  446. case DRM_PANTHOR_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE:
  447. break;
  448. default:
  449. return -EINVAL;
  450. }
  451. /* Don't bother if it's WC-mapped */
  452. if (shmem->map_wc)
  453. return 0;
  454. /* Nothing to do if the size is zero. */
  455. if (size == 0)
  456. return 0;
  457. sgt = drm_gem_shmem_get_pages_sgt(shmem);
  458. if (IS_ERR(sgt))
  459. return PTR_ERR(sgt);
  460. for_each_sgtable_dma_sg(sgt, sgl, count) {
  461. if (size == 0)
  462. break;
  463. dma_addr_t paddr = sg_dma_address(sgl);
  464. size_t len = sg_dma_len(sgl);
  465. if (len <= offset) {
  466. offset -= len;
  467. continue;
  468. }
  469. paddr += offset;
  470. len -= offset;
  471. len = min_t(size_t, len, size);
  472. size -= len;
  473. offset = 0;
  474. /* It's unclear whether dma_sync_xxx() is the right API to do CPU
  475. * cache maintenance given an IOMMU can register their own
  476. * implementation doing more than just CPU cache flushes/invalidation,
  477. * and what we really care about here is CPU caches only, but that's
  478. * the best we have that is both arch-agnostic and does at least the
  479. * CPU cache maintenance on a <page,offset,size> tuple.
  480. *
  481. * Also, I wish we could do a single
  482. *
  483. * dma_sync_single_for_device(BIDIR)
  484. *
  485. * and get a flush+invalidate, but that's not how it's implemented
  486. * in practice (at least on arm64), so we have to make it
  487. *
  488. * dma_sync_single_for_device(TO_DEVICE)
  489. * dma_sync_single_for_cpu(FROM_DEVICE)
  490. *
  491. * for the flush+invalidate case.
  492. */
  493. dma_sync_single_for_device(dev->dev, paddr, len, DMA_TO_DEVICE);
  494. if (type == DRM_PANTHOR_BO_SYNC_CPU_CACHE_FLUSH_AND_INVALIDATE)
  495. dma_sync_single_for_cpu(dev->dev, paddr, len, DMA_FROM_DEVICE);
  496. }
  497. return 0;
  498. }
  499. #ifdef CONFIG_DEBUG_FS
  500. struct gem_size_totals {
  501. size_t size;
  502. size_t resident;
  503. size_t reclaimable;
  504. };
  505. static void panthor_gem_debugfs_print_flag_names(struct seq_file *m)
  506. {
  507. int len;
  508. int i;
  509. static const char * const gem_state_flags_names[] = {
  510. [PANTHOR_DEBUGFS_GEM_STATE_IMPORTED_BIT] = "imported",
  511. [PANTHOR_DEBUGFS_GEM_STATE_EXPORTED_BIT] = "exported",
  512. };
  513. static const char * const gem_usage_flags_names[] = {
  514. [PANTHOR_DEBUGFS_GEM_USAGE_KERNEL_BIT] = "kernel",
  515. [PANTHOR_DEBUGFS_GEM_USAGE_FW_MAPPED_BIT] = "fw-mapped",
  516. };
  517. seq_puts(m, "GEM state flags: ");
  518. for (i = 0, len = ARRAY_SIZE(gem_state_flags_names); i < len; i++) {
  519. if (!gem_state_flags_names[i])
  520. continue;
  521. seq_printf(m, "%s (0x%x)%s", gem_state_flags_names[i],
  522. (u32)BIT(i), (i < len - 1) ? ", " : "\n");
  523. }
  524. seq_puts(m, "GEM usage flags: ");
  525. for (i = 0, len = ARRAY_SIZE(gem_usage_flags_names); i < len; i++) {
  526. if (!gem_usage_flags_names[i])
  527. continue;
  528. seq_printf(m, "%s (0x%x)%s", gem_usage_flags_names[i],
  529. (u32)BIT(i), (i < len - 1) ? ", " : "\n\n");
  530. }
  531. }
  532. static void panthor_gem_debugfs_bo_print(struct panthor_gem_object *bo,
  533. struct seq_file *m,
  534. struct gem_size_totals *totals)
  535. {
  536. unsigned int refcount = kref_read(&bo->base.base.refcount);
  537. char creator_info[32] = {};
  538. size_t resident_size;
  539. u32 gem_usage_flags = bo->debugfs.flags;
  540. u32 gem_state_flags = 0;
  541. /* Skip BOs being destroyed. */
  542. if (!refcount)
  543. return;
  544. resident_size = bo->base.pages ? bo->base.base.size : 0;
  545. snprintf(creator_info, sizeof(creator_info),
  546. "%s/%d", bo->debugfs.creator.process_name, bo->debugfs.creator.tgid);
  547. seq_printf(m, "%-32s%-16d%-16d%-16zd%-16zd0x%-16lx",
  548. creator_info,
  549. bo->base.base.name,
  550. refcount,
  551. bo->base.base.size,
  552. resident_size,
  553. drm_vma_node_start(&bo->base.base.vma_node));
  554. if (bo->base.base.import_attach)
  555. gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_IMPORTED;
  556. if (bo->base.base.dma_buf)
  557. gem_state_flags |= PANTHOR_DEBUGFS_GEM_STATE_FLAG_EXPORTED;
  558. seq_printf(m, "0x%-8x 0x%-10x", gem_state_flags, gem_usage_flags);
  559. scoped_guard(mutex, &bo->label.lock) {
  560. seq_printf(m, "%s\n", bo->label.str ? : "");
  561. }
  562. totals->size += bo->base.base.size;
  563. totals->resident += resident_size;
  564. if (bo->base.madv > 0)
  565. totals->reclaimable += resident_size;
  566. }
  567. void panthor_gem_debugfs_print_bos(struct panthor_device *ptdev,
  568. struct seq_file *m)
  569. {
  570. struct gem_size_totals totals = {0};
  571. struct panthor_gem_object *bo;
  572. panthor_gem_debugfs_print_flag_names(m);
  573. seq_puts(m, "created-by global-name refcount size resident-size file-offset state usage label\n");
  574. seq_puts(m, "----------------------------------------------------------------------------------------------------------------------------------------------\n");
  575. scoped_guard(mutex, &ptdev->gems.lock) {
  576. list_for_each_entry(bo, &ptdev->gems.node, debugfs.node) {
  577. panthor_gem_debugfs_bo_print(bo, m, &totals);
  578. }
  579. }
  580. seq_puts(m, "==============================================================================================================================================\n");
  581. seq_printf(m, "Total size: %zd, Total resident: %zd, Total reclaimable: %zd\n",
  582. totals.size, totals.resident, totals.reclaimable);
  583. }
  584. #endif