950-0174-drm-vc4-Add-the-DRM_IOCTL_VC4_GEM_MADVISE-ioctl.patch 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870
  1. From 4264bba50d050577580cc6309524e3d92959fff2 Mon Sep 17 00:00:00 2001
  2. From: Boris Brezillon <[email protected]>
  3. Date: Thu, 19 Oct 2017 14:57:48 +0200
  4. Subject: [PATCH 174/454] drm/vc4: Add the DRM_IOCTL_VC4_GEM_MADVISE ioctl
  5. This ioctl will allow us to purge inactive userspace buffers when the
  6. system is running out of contiguous memory.
  7. For now, the purge logic is rather dumb in that it does not try to
  8. release only the amount of BO needed to meet the last CMA alloc request
  9. but instead purges all objects placed in the purgeable pool as soon as
  10. we experience a CMA allocation failure.
  11. Note that the in-kernel BO cache is always purged before the purgeable
  12. cache because those objects are known to be unused while objects marked
  13. as purgeable by a userspace application/library might have to be
  14. restored when they are marked back as unpurgeable, which can be
  15. expensive.
  16. Signed-off-by: Boris Brezillon <[email protected]>
  17. Signed-off-by: Eric Anholt <[email protected]>
  18. Reviewed-by: Eric Anholt <[email protected]>
  19. Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
  20. (cherry picked from commit b9f19259b84dc648f207a46f3581d15eeaedf4b6)
  21. ---
  22. drivers/gpu/drm/vc4/vc4_bo.c | 287 +++++++++++++++++++++++++++++++-
  23. drivers/gpu/drm/vc4/vc4_drv.c | 10 +-
  24. drivers/gpu/drm/vc4/vc4_drv.h | 30 ++++
  25. drivers/gpu/drm/vc4/vc4_gem.c | 156 ++++++++++++++++-
  26. drivers/gpu/drm/vc4/vc4_plane.c | 20 +++
  27. include/uapi/drm/vc4_drm.h | 19 +++
  28. 6 files changed, 507 insertions(+), 15 deletions(-)
  29. --- a/drivers/gpu/drm/vc4/vc4_bo.c
  30. +++ b/drivers/gpu/drm/vc4/vc4_bo.c
  31. @@ -53,6 +53,17 @@ static void vc4_bo_stats_dump(struct vc4
  32. vc4->bo_labels[i].size_allocated / 1024,
  33. vc4->bo_labels[i].num_allocated);
  34. }
  35. +
  36. + mutex_lock(&vc4->purgeable.lock);
  37. + if (vc4->purgeable.num)
  38. + DRM_INFO("%30s: %6zdkb BOs (%d)\n", "userspace BO cache",
  39. + vc4->purgeable.size / 1024, vc4->purgeable.num);
  40. +
  41. + if (vc4->purgeable.purged_num)
  42. + DRM_INFO("%30s: %6zdkb BOs (%d)\n", "total purged BO",
  43. + vc4->purgeable.purged_size / 1024,
  44. + vc4->purgeable.purged_num);
  45. + mutex_unlock(&vc4->purgeable.lock);
  46. }
  47. #ifdef CONFIG_DEBUG_FS
  48. @@ -75,6 +86,17 @@ int vc4_bo_stats_debugfs(struct seq_file
  49. }
  50. mutex_unlock(&vc4->bo_lock);
  51. + mutex_lock(&vc4->purgeable.lock);
  52. + if (vc4->purgeable.num)
  53. + seq_printf(m, "%30s: %6dkb BOs (%d)\n", "userspace BO cache",
  54. + vc4->purgeable.size / 1024, vc4->purgeable.num);
  55. +
  56. + if (vc4->purgeable.purged_num)
  57. + seq_printf(m, "%30s: %6dkb BOs (%d)\n", "total purged BO",
  58. + vc4->purgeable.purged_size / 1024,
  59. + vc4->purgeable.purged_num);
  60. + mutex_unlock(&vc4->purgeable.lock);
  61. +
  62. return 0;
  63. }
  64. #endif
  65. @@ -248,6 +270,109 @@ static void vc4_bo_cache_purge(struct dr
  66. mutex_unlock(&vc4->bo_lock);
  67. }
  68. +void vc4_bo_add_to_purgeable_pool(struct vc4_bo *bo)
  69. +{
  70. + struct vc4_dev *vc4 = to_vc4_dev(bo->base.base.dev);
  71. +
  72. + mutex_lock(&vc4->purgeable.lock);
  73. + list_add_tail(&bo->size_head, &vc4->purgeable.list);
  74. + vc4->purgeable.num++;
  75. + vc4->purgeable.size += bo->base.base.size;
  76. + mutex_unlock(&vc4->purgeable.lock);
  77. +}
  78. +
  79. +static void vc4_bo_remove_from_purgeable_pool_locked(struct vc4_bo *bo)
  80. +{
  81. + struct vc4_dev *vc4 = to_vc4_dev(bo->base.base.dev);
  82. +
  83. + /* list_del_init() is used here because the caller might release
  84. + * the purgeable lock in order to acquire the madv one and update the
  85. + * madv status.
  86. + * During this short period of time a user might decide to mark
  87. + * the BO as unpurgeable, and if bo->madv is set to
  88. + * VC4_MADV_DONTNEED it will try to remove the BO from the
  89. + * purgeable list which will fail if the ->next/prev fields
  90. + * are set to LIST_POISON1/LIST_POISON2 (which is what
  91. + * list_del() does).
  92. + * Re-initializing the list element guarantees that list_del()
  93. + * will work correctly even if it's a NOP.
  94. + */
  95. + list_del_init(&bo->size_head);
  96. + vc4->purgeable.num--;
  97. + vc4->purgeable.size -= bo->base.base.size;
  98. +}
  99. +
  100. +void vc4_bo_remove_from_purgeable_pool(struct vc4_bo *bo)
  101. +{
  102. + struct vc4_dev *vc4 = to_vc4_dev(bo->base.base.dev);
  103. +
  104. + mutex_lock(&vc4->purgeable.lock);
  105. + vc4_bo_remove_from_purgeable_pool_locked(bo);
  106. + mutex_unlock(&vc4->purgeable.lock);
  107. +}
  108. +
  109. +static void vc4_bo_purge(struct drm_gem_object *obj)
  110. +{
  111. + struct vc4_bo *bo = to_vc4_bo(obj);
  112. + struct drm_device *dev = obj->dev;
  113. +
  114. + WARN_ON(!mutex_is_locked(&bo->madv_lock));
  115. + WARN_ON(bo->madv != VC4_MADV_DONTNEED);
  116. +
  117. + drm_vma_node_unmap(&obj->vma_node, dev->anon_inode->i_mapping);
  118. +
  119. + dma_free_wc(dev->dev, obj->size, bo->base.vaddr, bo->base.paddr);
  120. + bo->base.vaddr = NULL;
  121. + bo->madv = __VC4_MADV_PURGED;
  122. +}
  123. +
  124. +static void vc4_bo_userspace_cache_purge(struct drm_device *dev)
  125. +{
  126. + struct vc4_dev *vc4 = to_vc4_dev(dev);
  127. +
  128. + mutex_lock(&vc4->purgeable.lock);
  129. + while (!list_empty(&vc4->purgeable.list)) {
  130. + struct vc4_bo *bo = list_first_entry(&vc4->purgeable.list,
  131. + struct vc4_bo, size_head);
  132. + struct drm_gem_object *obj = &bo->base.base;
  133. + size_t purged_size = 0;
  134. +
  135. + vc4_bo_remove_from_purgeable_pool_locked(bo);
  136. +
  137. + /* Release the purgeable lock while we're purging the BO so
  138. + * that other people can continue inserting things in the
  139. + * purgeable pool without having to wait for all BOs to be
  140. + * purged.
  141. + */
  142. + mutex_unlock(&vc4->purgeable.lock);
  143. + mutex_lock(&bo->madv_lock);
  144. +
  145. + /* Since we released the purgeable pool lock before acquiring
  146. + * the BO madv one, the user may have marked the BO as WILLNEED
  147. + * and re-used it in the meantime.
  148. + * Before purging the BO we need to make sure
  149. + * - it is still marked as DONTNEED
  150. + * - it has not been re-inserted in the purgeable list
  151. + * - it is not used by HW blocks
  152. + * If one of these conditions is not met, just skip the entry.
  153. + */
  154. + if (bo->madv == VC4_MADV_DONTNEED &&
  155. + list_empty(&bo->size_head) &&
  156. + !refcount_read(&bo->usecnt)) {
  157. + purged_size = bo->base.base.size;
  158. + vc4_bo_purge(obj);
  159. + }
  160. + mutex_unlock(&bo->madv_lock);
  161. + mutex_lock(&vc4->purgeable.lock);
  162. +
  163. + if (purged_size) {
  164. + vc4->purgeable.purged_size += purged_size;
  165. + vc4->purgeable.purged_num++;
  166. + }
  167. + }
  168. + mutex_unlock(&vc4->purgeable.lock);
  169. +}
  170. +
  171. static struct vc4_bo *vc4_bo_get_from_cache(struct drm_device *dev,
  172. uint32_t size,
  173. enum vc4_kernel_bo_type type)
  174. @@ -294,6 +419,9 @@ struct drm_gem_object *vc4_create_object
  175. if (!bo)
  176. return ERR_PTR(-ENOMEM);
  177. + bo->madv = VC4_MADV_WILLNEED;
  178. + refcount_set(&bo->usecnt, 0);
  179. + mutex_init(&bo->madv_lock);
  180. mutex_lock(&vc4->bo_lock);
  181. bo->label = VC4_BO_TYPE_KERNEL;
  182. vc4->bo_labels[VC4_BO_TYPE_KERNEL].num_allocated++;
  183. @@ -331,16 +459,38 @@ struct vc4_bo *vc4_bo_create(struct drm_
  184. * CMA allocations we've got laying around and try again.
  185. */
  186. vc4_bo_cache_purge(dev);
  187. + cma_obj = drm_gem_cma_create(dev, size);
  188. + }
  189. + if (IS_ERR(cma_obj)) {
  190. + /*
  191. + * Still not enough CMA memory, purge the userspace BO
  192. + * cache and retry.
  193. + * This is sub-optimal since we purge the whole userspace
  194. + * BO cache which forces user that want to re-use the BO to
  195. + * restore its initial content.
  196. + * Ideally, we should purge entries one by one and retry
  197. + * after each to see if CMA allocation succeeds. Or even
  198. + * better, try to find an entry with at least the same
  199. + * size.
  200. + */
  201. + vc4_bo_userspace_cache_purge(dev);
  202. cma_obj = drm_gem_cma_create(dev, size);
  203. - if (IS_ERR(cma_obj)) {
  204. - DRM_ERROR("Failed to allocate from CMA:\n");
  205. - vc4_bo_stats_dump(vc4);
  206. - return ERR_PTR(-ENOMEM);
  207. - }
  208. + }
  209. +
  210. + if (IS_ERR(cma_obj)) {
  211. + DRM_ERROR("Failed to allocate from CMA:\n");
  212. + vc4_bo_stats_dump(vc4);
  213. + return ERR_PTR(-ENOMEM);
  214. }
  215. bo = to_vc4_bo(&cma_obj->base);
  216. + /* By default, BOs do not support the MADV ioctl. This will be enabled
  217. + * only on BOs that are exposed to userspace (V3D, V3D_SHADER and DUMB
  218. + * BOs).
  219. + */
  220. + bo->madv = __VC4_MADV_NOTSUPP;
  221. +
  222. mutex_lock(&vc4->bo_lock);
  223. vc4_bo_set_label(&cma_obj->base, type);
  224. mutex_unlock(&vc4->bo_lock);
  225. @@ -366,6 +516,8 @@ int vc4_dumb_create(struct drm_file *fil
  226. if (IS_ERR(bo))
  227. return PTR_ERR(bo);
  228. + bo->madv = VC4_MADV_WILLNEED;
  229. +
  230. ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle);
  231. drm_gem_object_put_unlocked(&bo->base.base);
  232. @@ -404,6 +556,12 @@ void vc4_free_object(struct drm_gem_obje
  233. struct vc4_bo *bo = to_vc4_bo(gem_bo);
  234. struct list_head *cache_list;
  235. + /* Remove the BO from the purgeable list. */
  236. + mutex_lock(&bo->madv_lock);
  237. + if (bo->madv == VC4_MADV_DONTNEED && !refcount_read(&bo->usecnt))
  238. + vc4_bo_remove_from_purgeable_pool(bo);
  239. + mutex_unlock(&bo->madv_lock);
  240. +
  241. mutex_lock(&vc4->bo_lock);
  242. /* If the object references someone else's memory, we can't cache it.
  243. */
  244. @@ -419,7 +577,8 @@ void vc4_free_object(struct drm_gem_obje
  245. }
  246. /* If this object was partially constructed but CMA allocation
  247. - * had failed, just free it.
  248. + * had failed, just free it. Can also happen when the BO has been
  249. + * purged.
  250. */
  251. if (!bo->base.vaddr) {
  252. vc4_bo_destroy(bo);
  253. @@ -439,6 +598,10 @@ void vc4_free_object(struct drm_gem_obje
  254. bo->validated_shader = NULL;
  255. }
  256. + /* Reset madv and usecnt before adding the BO to the cache. */
  257. + bo->madv = __VC4_MADV_NOTSUPP;
  258. + refcount_set(&bo->usecnt, 0);
  259. +
  260. bo->t_format = false;
  261. bo->free_time = jiffies;
  262. list_add(&bo->size_head, cache_list);
  263. @@ -463,6 +626,56 @@ static void vc4_bo_cache_time_work(struc
  264. mutex_unlock(&vc4->bo_lock);
  265. }
  266. +int vc4_bo_inc_usecnt(struct vc4_bo *bo)
  267. +{
  268. + int ret;
  269. +
  270. + /* Fast path: if the BO is already retained by someone, no need to
  271. + * check the madv status.
  272. + */
  273. + if (refcount_inc_not_zero(&bo->usecnt))
  274. + return 0;
  275. +
  276. + mutex_lock(&bo->madv_lock);
  277. + switch (bo->madv) {
  278. + case VC4_MADV_WILLNEED:
  279. + refcount_inc(&bo->usecnt);
  280. + ret = 0;
  281. + break;
  282. + case VC4_MADV_DONTNEED:
  283. + /* We shouldn't use a BO marked as purgeable if at least
  284. + * someone else retained its content by incrementing usecnt.
  285. + * Luckily the BO hasn't been purged yet, but something wrong
  286. + * is happening here. Just throw an error instead of
  287. + * authorizing this use case.
  288. + */
  289. + case __VC4_MADV_PURGED:
  290. + /* We can't use a purged BO. */
  291. + default:
  292. + /* Invalid madv value. */
  293. + ret = -EINVAL;
  294. + break;
  295. + }
  296. + mutex_unlock(&bo->madv_lock);
  297. +
  298. + return ret;
  299. +}
  300. +
  301. +void vc4_bo_dec_usecnt(struct vc4_bo *bo)
  302. +{
  303. + /* Fast path: if the BO is still retained by someone, no need to test
  304. + * the madv value.
  305. + */
  306. + if (refcount_dec_not_one(&bo->usecnt))
  307. + return;
  308. +
  309. + mutex_lock(&bo->madv_lock);
  310. + if (refcount_dec_and_test(&bo->usecnt) &&
  311. + bo->madv == VC4_MADV_DONTNEED)
  312. + vc4_bo_add_to_purgeable_pool(bo);
  313. + mutex_unlock(&bo->madv_lock);
  314. +}
  315. +
  316. static void vc4_bo_cache_time_timer(unsigned long data)
  317. {
  318. struct drm_device *dev = (struct drm_device *)data;
  319. @@ -482,18 +695,52 @@ struct dma_buf *
  320. vc4_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags)
  321. {
  322. struct vc4_bo *bo = to_vc4_bo(obj);
  323. + struct dma_buf *dmabuf;
  324. + int ret;
  325. if (bo->validated_shader) {
  326. DRM_DEBUG("Attempting to export shader BO\n");
  327. return ERR_PTR(-EINVAL);
  328. }
  329. - return drm_gem_prime_export(dev, obj, flags);
  330. + /* Note: as soon as the BO is exported it becomes unpurgeable, because
  331. + * noone ever decrements the usecnt even if the reference held by the
  332. + * exported BO is released. This shouldn't be a problem since we don't
  333. + * expect exported BOs to be marked as purgeable.
  334. + */
  335. + ret = vc4_bo_inc_usecnt(bo);
  336. + if (ret) {
  337. + DRM_ERROR("Failed to increment BO usecnt\n");
  338. + return ERR_PTR(ret);
  339. + }
  340. +
  341. + dmabuf = drm_gem_prime_export(dev, obj, flags);
  342. + if (IS_ERR(dmabuf))
  343. + vc4_bo_dec_usecnt(bo);
  344. +
  345. + return dmabuf;
  346. +}
  347. +
  348. +int vc4_fault(struct vm_fault *vmf)
  349. +{
  350. + struct vm_area_struct *vma = vmf->vma;
  351. + struct drm_gem_object *obj = vma->vm_private_data;
  352. + struct vc4_bo *bo = to_vc4_bo(obj);
  353. +
  354. + /* The only reason we would end up here is when user-space accesses
  355. + * BO's memory after it's been purged.
  356. + */
  357. + mutex_lock(&bo->madv_lock);
  358. + WARN_ON(bo->madv != __VC4_MADV_PURGED);
  359. + mutex_unlock(&bo->madv_lock);
  360. +
  361. + return VM_FAULT_SIGBUS;
  362. }
  363. int vc4_mmap(struct file *filp, struct vm_area_struct *vma)
  364. {
  365. struct drm_gem_object *gem_obj;
  366. + unsigned long vm_pgoff;
  367. struct vc4_bo *bo;
  368. int ret;
  369. @@ -509,16 +756,36 @@ int vc4_mmap(struct file *filp, struct v
  370. return -EINVAL;
  371. }
  372. + if (bo->madv != VC4_MADV_WILLNEED) {
  373. + DRM_DEBUG("mmaping of %s BO not allowed\n",
  374. + bo->madv == VC4_MADV_DONTNEED ?
  375. + "purgeable" : "purged");
  376. + return -EINVAL;
  377. + }
  378. +
  379. /*
  380. * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the
  381. * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map
  382. * the whole buffer.
  383. */
  384. vma->vm_flags &= ~VM_PFNMAP;
  385. - vma->vm_pgoff = 0;
  386. + /* This ->vm_pgoff dance is needed to make all parties happy:
  387. + * - dma_mmap_wc() uses ->vm_pgoff as an offset within the allocated
  388. + * mem-region, hence the need to set it to zero (the value set by
  389. + * the DRM core is a virtual offset encoding the GEM object-id)
  390. + * - the mmap() core logic needs ->vm_pgoff to be restored to its
  391. + * initial value before returning from this function because it
  392. + * encodes the offset of this GEM in the dev->anon_inode pseudo-file
  393. + * and this information will be used when we invalidate userspace
  394. + * mappings with drm_vma_node_unmap() (called from vc4_gem_purge()).
  395. + */
  396. + vm_pgoff = vma->vm_pgoff;
  397. + vma->vm_pgoff = 0;
  398. ret = dma_mmap_wc(bo->base.base.dev->dev, vma, bo->base.vaddr,
  399. bo->base.paddr, vma->vm_end - vma->vm_start);
  400. + vma->vm_pgoff = vm_pgoff;
  401. +
  402. if (ret)
  403. drm_gem_vm_close(vma);
  404. @@ -582,6 +849,8 @@ int vc4_create_bo_ioctl(struct drm_devic
  405. if (IS_ERR(bo))
  406. return PTR_ERR(bo);
  407. + bo->madv = VC4_MADV_WILLNEED;
  408. +
  409. ret = drm_gem_handle_create(file_priv, &bo->base.base, &args->handle);
  410. drm_gem_object_put_unlocked(&bo->base.base);
  411. @@ -635,6 +904,8 @@ vc4_create_shader_bo_ioctl(struct drm_de
  412. if (IS_ERR(bo))
  413. return PTR_ERR(bo);
  414. + bo->madv = VC4_MADV_WILLNEED;
  415. +
  416. if (copy_from_user(bo->base.vaddr,
  417. (void __user *)(uintptr_t)args->data,
  418. args->size)) {
  419. --- a/drivers/gpu/drm/vc4/vc4_drv.c
  420. +++ b/drivers/gpu/drm/vc4/vc4_drv.c
  421. @@ -100,6 +100,7 @@ static int vc4_get_param_ioctl(struct dr
  422. case DRM_VC4_PARAM_SUPPORTS_ETC1:
  423. case DRM_VC4_PARAM_SUPPORTS_THREADED_FS:
  424. case DRM_VC4_PARAM_SUPPORTS_FIXED_RCL_ORDER:
  425. + case DRM_VC4_PARAM_SUPPORTS_MADVISE:
  426. args->value = true;
  427. break;
  428. default:
  429. @@ -117,6 +118,12 @@ static void vc4_lastclose(struct drm_dev
  430. drm_fbdev_cma_restore_mode(vc4->fbdev);
  431. }
  432. +static const struct vm_operations_struct vc4_vm_ops = {
  433. + .fault = vc4_fault,
  434. + .open = drm_gem_vm_open,
  435. + .close = drm_gem_vm_close,
  436. +};
  437. +
  438. static const struct file_operations vc4_drm_fops = {
  439. .owner = THIS_MODULE,
  440. .open = drm_open,
  441. @@ -142,6 +149,7 @@ static const struct drm_ioctl_desc vc4_d
  442. DRM_IOCTL_DEF_DRV(VC4_SET_TILING, vc4_set_tiling_ioctl, DRM_RENDER_ALLOW),
  443. DRM_IOCTL_DEF_DRV(VC4_GET_TILING, vc4_get_tiling_ioctl, DRM_RENDER_ALLOW),
  444. DRM_IOCTL_DEF_DRV(VC4_LABEL_BO, vc4_label_bo_ioctl, DRM_RENDER_ALLOW),
  445. + DRM_IOCTL_DEF_DRV(VC4_GEM_MADVISE, vc4_gem_madvise_ioctl, DRM_RENDER_ALLOW),
  446. };
  447. static struct drm_driver vc4_drm_driver = {
  448. @@ -166,7 +174,7 @@ static struct drm_driver vc4_drm_driver
  449. .gem_create_object = vc4_create_object,
  450. .gem_free_object_unlocked = vc4_free_object,
  451. - .gem_vm_ops = &drm_gem_cma_vm_ops,
  452. + .gem_vm_ops = &vc4_vm_ops,
  453. .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
  454. .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
  455. --- a/drivers/gpu/drm/vc4/vc4_drv.h
  456. +++ b/drivers/gpu/drm/vc4/vc4_drv.h
  457. @@ -77,6 +77,19 @@ struct vc4_dev {
  458. /* Protects bo_cache and bo_labels. */
  459. struct mutex bo_lock;
  460. + /* Purgeable BO pool. All BOs in this pool can have their memory
  461. + * reclaimed if the driver is unable to allocate new BOs. We also
  462. + * keep stats related to the purge mechanism here.
  463. + */
  464. + struct {
  465. + struct list_head list;
  466. + unsigned int num;
  467. + size_t size;
  468. + unsigned int purged_num;
  469. + size_t purged_size;
  470. + struct mutex lock;
  471. + } purgeable;
  472. +
  473. uint64_t dma_fence_context;
  474. /* Sequence number for the last job queued in bin_job_list.
  475. @@ -195,6 +208,16 @@ struct vc4_bo {
  476. * for user-allocated labels.
  477. */
  478. int label;
  479. +
  480. + /* Count the number of active users. This is needed to determine
  481. + * whether we can move the BO to the purgeable list or not (when the BO
  482. + * is used by the GPU or the display engine we can't purge it).
  483. + */
  484. + refcount_t usecnt;
  485. +
  486. + /* Store purgeable/purged state here */
  487. + u32 madv;
  488. + struct mutex madv_lock;
  489. };
  490. static inline struct vc4_bo *
  491. @@ -506,6 +529,7 @@ int vc4_get_hang_state_ioctl(struct drm_
  492. struct drm_file *file_priv);
  493. int vc4_label_bo_ioctl(struct drm_device *dev, void *data,
  494. struct drm_file *file_priv);
  495. +int vc4_fault(struct vm_fault *vmf);
  496. int vc4_mmap(struct file *filp, struct vm_area_struct *vma);
  497. struct reservation_object *vc4_prime_res_obj(struct drm_gem_object *obj);
  498. int vc4_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma);
  499. @@ -516,6 +540,10 @@ void *vc4_prime_vmap(struct drm_gem_obje
  500. int vc4_bo_cache_init(struct drm_device *dev);
  501. void vc4_bo_cache_destroy(struct drm_device *dev);
  502. int vc4_bo_stats_debugfs(struct seq_file *m, void *arg);
  503. +int vc4_bo_inc_usecnt(struct vc4_bo *bo);
  504. +void vc4_bo_dec_usecnt(struct vc4_bo *bo);
  505. +void vc4_bo_add_to_purgeable_pool(struct vc4_bo *bo);
  506. +void vc4_bo_remove_from_purgeable_pool(struct vc4_bo *bo);
  507. /* vc4_crtc.c */
  508. extern struct platform_driver vc4_crtc_driver;
  509. @@ -564,6 +592,8 @@ void vc4_job_handle_completed(struct vc4
  510. int vc4_queue_seqno_cb(struct drm_device *dev,
  511. struct vc4_seqno_cb *cb, uint64_t seqno,
  512. void (*func)(struct vc4_seqno_cb *cb));
  513. +int vc4_gem_madvise_ioctl(struct drm_device *dev, void *data,
  514. + struct drm_file *file_priv);
  515. /* vc4_hdmi.c */
  516. extern struct platform_driver vc4_hdmi_driver;
  517. --- a/drivers/gpu/drm/vc4/vc4_gem.c
  518. +++ b/drivers/gpu/drm/vc4/vc4_gem.c
  519. @@ -188,11 +188,22 @@ vc4_save_hang_state(struct drm_device *d
  520. continue;
  521. for (j = 0; j < exec[i]->bo_count; j++) {
  522. + bo = to_vc4_bo(&exec[i]->bo[j]->base);
  523. +
  524. + /* Retain BOs just in case they were marked purgeable.
  525. + * This prevents the BO from being purged before
  526. + * someone had a chance to dump the hang state.
  527. + */
  528. + WARN_ON(!refcount_read(&bo->usecnt));
  529. + refcount_inc(&bo->usecnt);
  530. drm_gem_object_get(&exec[i]->bo[j]->base);
  531. kernel_state->bo[k++] = &exec[i]->bo[j]->base;
  532. }
  533. list_for_each_entry(bo, &exec[i]->unref_list, unref_head) {
  534. + /* No need to retain BOs coming from the ->unref_list
  535. + * because they are naturally unpurgeable.
  536. + */
  537. drm_gem_object_get(&bo->base.base);
  538. kernel_state->bo[k++] = &bo->base.base;
  539. }
  540. @@ -233,6 +244,26 @@ vc4_save_hang_state(struct drm_device *d
  541. state->fdbgs = V3D_READ(V3D_FDBGS);
  542. state->errstat = V3D_READ(V3D_ERRSTAT);
  543. + /* We need to turn purgeable BOs into unpurgeable ones so that
  544. + * userspace has a chance to dump the hang state before the kernel
  545. + * decides to purge those BOs.
  546. + * Note that BO consistency at dump time cannot be guaranteed. For
  547. + * example, if the owner of these BOs decides to re-use them or mark
  548. + * them purgeable again there's nothing we can do to prevent it.
  549. + */
  550. + for (i = 0; i < kernel_state->user_state.bo_count; i++) {
  551. + struct vc4_bo *bo = to_vc4_bo(kernel_state->bo[i]);
  552. +
  553. + if (bo->madv == __VC4_MADV_NOTSUPP)
  554. + continue;
  555. +
  556. + mutex_lock(&bo->madv_lock);
  557. + if (!WARN_ON(bo->madv == __VC4_MADV_PURGED))
  558. + bo->madv = VC4_MADV_WILLNEED;
  559. + refcount_dec(&bo->usecnt);
  560. + mutex_unlock(&bo->madv_lock);
  561. + }
  562. +
  563. spin_lock_irqsave(&vc4->job_lock, irqflags);
  564. if (vc4->hang_state) {
  565. spin_unlock_irqrestore(&vc4->job_lock, irqflags);
  566. @@ -639,9 +670,6 @@ vc4_queue_submit(struct drm_device *dev,
  567. * The command validator needs to reference BOs by their index within
  568. * the submitted job's BO list. This does the validation of the job's
  569. * BO list and reference counting for the lifetime of the job.
  570. - *
  571. - * Note that this function doesn't need to unreference the BOs on
  572. - * failure, because that will happen at vc4_complete_exec() time.
  573. */
  574. static int
  575. vc4_cl_lookup_bos(struct drm_device *dev,
  576. @@ -693,16 +721,47 @@ vc4_cl_lookup_bos(struct drm_device *dev
  577. DRM_DEBUG("Failed to look up GEM BO %d: %d\n",
  578. i, handles[i]);
  579. ret = -EINVAL;
  580. - spin_unlock(&file_priv->table_lock);
  581. - goto fail;
  582. + break;
  583. }
  584. +
  585. drm_gem_object_get(bo);
  586. exec->bo[i] = (struct drm_gem_cma_object *)bo;
  587. }
  588. spin_unlock(&file_priv->table_lock);
  589. + if (ret)
  590. + goto fail_put_bo;
  591. +
  592. + for (i = 0; i < exec->bo_count; i++) {
  593. + ret = vc4_bo_inc_usecnt(to_vc4_bo(&exec->bo[i]->base));
  594. + if (ret)
  595. + goto fail_dec_usecnt;
  596. + }
  597. +
  598. + kvfree(handles);
  599. + return 0;
  600. +
  601. +fail_dec_usecnt:
  602. + /* Decrease usecnt on acquired objects.
  603. + * We cannot rely on vc4_complete_exec() to release resources here,
  604. + * because vc4_complete_exec() has no information about which BO has
  605. + * had its ->usecnt incremented.
  606. + * To make things easier we just free everything explicitly and set
  607. + * exec->bo to NULL so that vc4_complete_exec() skips the 'BO release'
  608. + * step.
  609. + */
  610. + for (i-- ; i >= 0; i--)
  611. + vc4_bo_dec_usecnt(to_vc4_bo(&exec->bo[i]->base));
  612. +
  613. +fail_put_bo:
  614. + /* Release any reference to acquired objects. */
  615. + for (i = 0; i < exec->bo_count && exec->bo[i]; i++)
  616. + drm_gem_object_put_unlocked(&exec->bo[i]->base);
  617. +
  618. fail:
  619. kvfree(handles);
  620. + kvfree(exec->bo);
  621. + exec->bo = NULL;
  622. return ret;
  623. }
  624. @@ -835,8 +894,12 @@ vc4_complete_exec(struct drm_device *dev
  625. }
  626. if (exec->bo) {
  627. - for (i = 0; i < exec->bo_count; i++)
  628. + for (i = 0; i < exec->bo_count; i++) {
  629. + struct vc4_bo *bo = to_vc4_bo(&exec->bo[i]->base);
  630. +
  631. + vc4_bo_dec_usecnt(bo);
  632. drm_gem_object_put_unlocked(&exec->bo[i]->base);
  633. + }
  634. kvfree(exec->bo);
  635. }
  636. @@ -1100,6 +1163,9 @@ vc4_gem_init(struct drm_device *dev)
  637. INIT_WORK(&vc4->job_done_work, vc4_job_done_work);
  638. mutex_init(&vc4->power_lock);
  639. +
  640. + INIT_LIST_HEAD(&vc4->purgeable.list);
  641. + mutex_init(&vc4->purgeable.lock);
  642. }
  643. void
  644. @@ -1123,3 +1189,81 @@ vc4_gem_destroy(struct drm_device *dev)
  645. if (vc4->hang_state)
  646. vc4_free_hang_state(dev, vc4->hang_state);
  647. }
  648. +
  649. +int vc4_gem_madvise_ioctl(struct drm_device *dev, void *data,
  650. + struct drm_file *file_priv)
  651. +{
  652. + struct drm_vc4_gem_madvise *args = data;
  653. + struct drm_gem_object *gem_obj;
  654. + struct vc4_bo *bo;
  655. + int ret;
  656. +
  657. + switch (args->madv) {
  658. + case VC4_MADV_DONTNEED:
  659. + case VC4_MADV_WILLNEED:
  660. + break;
  661. + default:
  662. + return -EINVAL;
  663. + }
  664. +
  665. + if (args->pad != 0)
  666. + return -EINVAL;
  667. +
  668. + gem_obj = drm_gem_object_lookup(file_priv, args->handle);
  669. + if (!gem_obj) {
  670. + DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle);
  671. + return -ENOENT;
  672. + }
  673. +
  674. + bo = to_vc4_bo(gem_obj);
  675. +
  676. + /* Only BOs exposed to userspace can be purged. */
  677. + if (bo->madv == __VC4_MADV_NOTSUPP) {
  678. + DRM_DEBUG("madvise not supported on this BO\n");
  679. + ret = -EINVAL;
  680. + goto out_put_gem;
  681. + }
  682. +
  683. + /* Not sure it's safe to purge imported BOs. Let's just assume it's
  684. + * not until proven otherwise.
  685. + */
  686. + if (gem_obj->import_attach) {
  687. + DRM_DEBUG("madvise not supported on imported BOs\n");
  688. + ret = -EINVAL;
  689. + goto out_put_gem;
  690. + }
  691. +
  692. + mutex_lock(&bo->madv_lock);
  693. +
  694. + if (args->madv == VC4_MADV_DONTNEED && bo->madv == VC4_MADV_WILLNEED &&
  695. + !refcount_read(&bo->usecnt)) {
  696. + /* If the BO is about to be marked as purgeable, is not used
  697. + * and is not already purgeable or purged, add it to the
  698. + * purgeable list.
  699. + */
  700. + vc4_bo_add_to_purgeable_pool(bo);
  701. + } else if (args->madv == VC4_MADV_WILLNEED &&
  702. + bo->madv == VC4_MADV_DONTNEED &&
  703. + !refcount_read(&bo->usecnt)) {
  704. + /* The BO has not been purged yet, just remove it from
  705. + * the purgeable list.
  706. + */
  707. + vc4_bo_remove_from_purgeable_pool(bo);
  708. + }
  709. +
  710. + /* Save the purged state. */
  711. + args->retained = bo->madv != __VC4_MADV_PURGED;
  712. +
  713. + /* Update internal madv state only if the bo was not purged. */
  714. + if (bo->madv != __VC4_MADV_PURGED)
  715. + bo->madv = args->madv;
  716. +
  717. + mutex_unlock(&bo->madv_lock);
  718. +
  719. + ret = 0;
  720. +
  721. +out_put_gem:
  722. + drm_gem_object_put_unlocked(gem_obj);
  723. +
  724. + return ret;
  725. +}
  726. --- a/drivers/gpu/drm/vc4/vc4_plane.c
  727. +++ b/drivers/gpu/drm/vc4/vc4_plane.c
  728. @@ -23,6 +23,7 @@
  729. #include <drm/drm_fb_cma_helper.h>
  730. #include <drm/drm_plane_helper.h>
  731. +#include "uapi/drm/vc4_drm.h"
  732. #include "vc4_drv.h"
  733. #include "vc4_regs.h"
  734. @@ -779,21 +780,40 @@ static int vc4_prepare_fb(struct drm_pla
  735. {
  736. struct vc4_bo *bo;
  737. struct dma_fence *fence;
  738. + int ret;
  739. if ((plane->state->fb == state->fb) || !state->fb)
  740. return 0;
  741. bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base);
  742. +
  743. + ret = vc4_bo_inc_usecnt(bo);
  744. + if (ret)
  745. + return ret;
  746. +
  747. fence = reservation_object_get_excl_rcu(bo->resv);
  748. drm_atomic_set_fence_for_plane(state, fence);
  749. return 0;
  750. }
  751. +static void vc4_cleanup_fb(struct drm_plane *plane,
  752. + struct drm_plane_state *state)
  753. +{
  754. + struct vc4_bo *bo;
  755. +
  756. + if (plane->state->fb == state->fb || !state->fb)
  757. + return;
  758. +
  759. + bo = to_vc4_bo(&drm_fb_cma_get_gem_obj(state->fb, 0)->base);
  760. + vc4_bo_dec_usecnt(bo);
  761. +}
  762. +
  763. static const struct drm_plane_helper_funcs vc4_plane_helper_funcs = {
  764. .atomic_check = vc4_plane_atomic_check,
  765. .atomic_update = vc4_plane_atomic_update,
  766. .prepare_fb = vc4_prepare_fb,
  767. + .cleanup_fb = vc4_cleanup_fb,
  768. };
  769. static void vc4_plane_destroy(struct drm_plane *plane)
  770. --- a/include/uapi/drm/vc4_drm.h
  771. +++ b/include/uapi/drm/vc4_drm.h
  772. @@ -41,6 +41,7 @@ extern "C" {
  773. #define DRM_VC4_SET_TILING 0x08
  774. #define DRM_VC4_GET_TILING 0x09
  775. #define DRM_VC4_LABEL_BO 0x0a
  776. +#define DRM_VC4_GEM_MADVISE 0x0b
  777. #define DRM_IOCTL_VC4_SUBMIT_CL DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_SUBMIT_CL, struct drm_vc4_submit_cl)
  778. #define DRM_IOCTL_VC4_WAIT_SEQNO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_WAIT_SEQNO, struct drm_vc4_wait_seqno)
  779. @@ -53,6 +54,7 @@ extern "C" {
  780. #define DRM_IOCTL_VC4_SET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_SET_TILING, struct drm_vc4_set_tiling)
  781. #define DRM_IOCTL_VC4_GET_TILING DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GET_TILING, struct drm_vc4_get_tiling)
  782. #define DRM_IOCTL_VC4_LABEL_BO DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_LABEL_BO, struct drm_vc4_label_bo)
  783. +#define DRM_IOCTL_VC4_GEM_MADVISE DRM_IOWR(DRM_COMMAND_BASE + DRM_VC4_GEM_MADVISE, struct drm_vc4_gem_madvise)
  784. struct drm_vc4_submit_rcl_surface {
  785. __u32 hindex; /* Handle index, or ~0 if not present. */
  786. @@ -305,6 +307,7 @@ struct drm_vc4_get_hang_state {
  787. #define DRM_VC4_PARAM_SUPPORTS_ETC1 4
  788. #define DRM_VC4_PARAM_SUPPORTS_THREADED_FS 5
  789. #define DRM_VC4_PARAM_SUPPORTS_FIXED_RCL_ORDER 6
  790. +#define DRM_VC4_PARAM_SUPPORTS_MADVISE 7
  791. struct drm_vc4_get_param {
  792. __u32 param;
  793. @@ -333,6 +336,22 @@ struct drm_vc4_label_bo {
  794. __u64 name;
  795. };
  796. +/*
  797. + * States prefixed with '__' are internal states and cannot be passed to the
  798. + * DRM_IOCTL_VC4_GEM_MADVISE ioctl.
  799. + */
  800. +#define VC4_MADV_WILLNEED 0
  801. +#define VC4_MADV_DONTNEED 1
  802. +#define __VC4_MADV_PURGED 2
  803. +#define __VC4_MADV_NOTSUPP 3
  804. +
  805. +struct drm_vc4_gem_madvise {
  806. + __u32 handle;
  807. + __u32 madv;
  808. + __u32 retained;
  809. + __u32 pad;
  810. +};
  811. +
  812. #if defined(__cplusplus)
  813. }
  814. #endif