v3d_bo.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /* Copyright (C) 2015-2018 Broadcom */
  3. /**
  4. * DOC: V3D GEM BO management support
  5. *
  6. * Compared to VC4 (V3D 2.x), V3D 3.3 introduces an MMU between the
  7. * GPU and the bus, allowing us to use shmem objects for our storage
  8. * instead of CMA.
  9. *
  10. * Physically contiguous objects may still be imported to V3D, but the
  11. * driver doesn't allocate physically contiguous objects on its own.
  12. * Display engines requiring physically contiguous allocations should
  13. * look into Mesa's "renderonly" support (as used by the Mesa pl111
  14. * driver) for an example of how to integrate with V3D.
  15. *
  16. * Long term, we should support evicting pages from the MMU when under
  17. * memory pressure (thus the v3d_bo_get_pages() refcounting), but
  18. * that's not a high priority since our systems tend to not have swap.
  19. */
  20. #include <linux/dma-buf.h>
  21. #include <linux/pfn_t.h>
  22. #include "v3d_drv.h"
  23. #include "uapi/drm/v3d_drm.h"
  24. /* Pins the shmem pages, fills in the .pages and .sgt fields of the BO, and maps
  25. * it for DMA.
  26. */
  27. static int
  28. v3d_bo_get_pages(struct v3d_bo *bo)
  29. {
  30. struct drm_gem_object *obj = &bo->base;
  31. struct drm_device *dev = obj->dev;
  32. int npages = obj->size >> PAGE_SHIFT;
  33. int ret = 0;
  34. mutex_lock(&bo->lock);
  35. if (bo->pages_refcount++ != 0)
  36. goto unlock;
  37. if (!obj->import_attach) {
  38. bo->pages = drm_gem_get_pages(obj);
  39. if (IS_ERR(bo->pages)) {
  40. ret = PTR_ERR(bo->pages);
  41. goto unlock;
  42. }
  43. bo->sgt = drm_prime_pages_to_sg(bo->pages, npages);
  44. if (IS_ERR(bo->sgt)) {
  45. ret = PTR_ERR(bo->sgt);
  46. goto put_pages;
  47. }
  48. /* Map the pages for use by the GPU. */
  49. dma_map_sg(dev->dev, bo->sgt->sgl,
  50. bo->sgt->nents, DMA_BIDIRECTIONAL);
  51. } else {
  52. bo->pages = kcalloc(npages, sizeof(*bo->pages), GFP_KERNEL);
  53. if (!bo->pages)
  54. goto put_pages;
  55. drm_prime_sg_to_page_addr_arrays(bo->sgt, bo->pages,
  56. NULL, npages);
  57. /* Note that dma-bufs come in mapped. */
  58. }
  59. mutex_unlock(&bo->lock);
  60. return 0;
  61. put_pages:
  62. drm_gem_put_pages(obj, bo->pages, true, true);
  63. bo->pages = NULL;
  64. unlock:
  65. bo->pages_refcount--;
  66. mutex_unlock(&bo->lock);
  67. return ret;
  68. }
  69. static void
  70. v3d_bo_put_pages(struct v3d_bo *bo)
  71. {
  72. struct drm_gem_object *obj = &bo->base;
  73. mutex_lock(&bo->lock);
  74. if (--bo->pages_refcount == 0) {
  75. if (!obj->import_attach) {
  76. dma_unmap_sg(obj->dev->dev, bo->sgt->sgl,
  77. bo->sgt->nents, DMA_BIDIRECTIONAL);
  78. sg_free_table(bo->sgt);
  79. kfree(bo->sgt);
  80. drm_gem_put_pages(obj, bo->pages, true, true);
  81. } else {
  82. kfree(bo->pages);
  83. }
  84. }
  85. mutex_unlock(&bo->lock);
  86. }
  87. static struct v3d_bo *v3d_bo_create_struct(struct drm_device *dev,
  88. size_t unaligned_size)
  89. {
  90. struct v3d_dev *v3d = to_v3d_dev(dev);
  91. struct drm_gem_object *obj;
  92. struct v3d_bo *bo;
  93. size_t size = roundup(unaligned_size, PAGE_SIZE);
  94. int ret;
  95. if (size == 0)
  96. return ERR_PTR(-EINVAL);
  97. bo = kzalloc(sizeof(*bo), GFP_KERNEL);
  98. if (!bo)
  99. return ERR_PTR(-ENOMEM);
  100. obj = &bo->base;
  101. INIT_LIST_HEAD(&bo->vmas);
  102. INIT_LIST_HEAD(&bo->unref_head);
  103. mutex_init(&bo->lock);
  104. ret = drm_gem_object_init(dev, obj, size);
  105. if (ret)
  106. goto free_bo;
  107. spin_lock(&v3d->mm_lock);
  108. ret = drm_mm_insert_node_generic(&v3d->mm, &bo->node,
  109. obj->size >> PAGE_SHIFT,
  110. GMP_GRANULARITY >> PAGE_SHIFT, 0, 0);
  111. spin_unlock(&v3d->mm_lock);
  112. if (ret)
  113. goto free_obj;
  114. return bo;
  115. free_obj:
  116. drm_gem_object_release(obj);
  117. free_bo:
  118. kfree(bo);
  119. return ERR_PTR(ret);
  120. }
  121. struct v3d_bo *v3d_bo_create(struct drm_device *dev, struct drm_file *file_priv,
  122. size_t unaligned_size)
  123. {
  124. struct v3d_dev *v3d = to_v3d_dev(dev);
  125. struct drm_gem_object *obj;
  126. struct v3d_bo *bo;
  127. int ret;
  128. bo = v3d_bo_create_struct(dev, unaligned_size);
  129. if (IS_ERR(bo))
  130. return bo;
  131. obj = &bo->base;
  132. bo->resv = &bo->_resv;
  133. reservation_object_init(bo->resv);
  134. ret = v3d_bo_get_pages(bo);
  135. if (ret)
  136. goto free_mm;
  137. v3d_mmu_insert_ptes(bo);
  138. mutex_lock(&v3d->bo_lock);
  139. v3d->bo_stats.num_allocated++;
  140. v3d->bo_stats.pages_allocated += obj->size >> PAGE_SHIFT;
  141. mutex_unlock(&v3d->bo_lock);
  142. return bo;
  143. free_mm:
  144. spin_lock(&v3d->mm_lock);
  145. drm_mm_remove_node(&bo->node);
  146. spin_unlock(&v3d->mm_lock);
  147. drm_gem_object_release(obj);
  148. kfree(bo);
  149. return ERR_PTR(ret);
  150. }
  151. /* Called DRM core on the last userspace/kernel unreference of the
  152. * BO.
  153. */
  154. void v3d_free_object(struct drm_gem_object *obj)
  155. {
  156. struct v3d_dev *v3d = to_v3d_dev(obj->dev);
  157. struct v3d_bo *bo = to_v3d_bo(obj);
  158. mutex_lock(&v3d->bo_lock);
  159. v3d->bo_stats.num_allocated--;
  160. v3d->bo_stats.pages_allocated -= obj->size >> PAGE_SHIFT;
  161. mutex_unlock(&v3d->bo_lock);
  162. reservation_object_fini(&bo->_resv);
  163. v3d_bo_put_pages(bo);
  164. if (obj->import_attach)
  165. drm_prime_gem_destroy(obj, bo->sgt);
  166. v3d_mmu_remove_ptes(bo);
  167. spin_lock(&v3d->mm_lock);
  168. drm_mm_remove_node(&bo->node);
  169. spin_unlock(&v3d->mm_lock);
  170. mutex_destroy(&bo->lock);
  171. drm_gem_object_release(obj);
  172. kfree(bo);
  173. }
  174. struct reservation_object *v3d_prime_res_obj(struct drm_gem_object *obj)
  175. {
  176. struct v3d_bo *bo = to_v3d_bo(obj);
  177. return bo->resv;
  178. }
  179. static void
  180. v3d_set_mmap_vma_flags(struct vm_area_struct *vma)
  181. {
  182. vma->vm_flags &= ~VM_PFNMAP;
  183. vma->vm_flags |= VM_MIXEDMAP;
  184. vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
  185. }
  186. int v3d_gem_fault(struct vm_fault *vmf)
  187. {
  188. struct vm_area_struct *vma = vmf->vma;
  189. struct drm_gem_object *obj = vma->vm_private_data;
  190. struct v3d_bo *bo = to_v3d_bo(obj);
  191. unsigned long pfn;
  192. pgoff_t pgoff;
  193. int ret;
  194. /* We don't use vmf->pgoff since that has the fake offset: */
  195. pgoff = (vmf->address - vma->vm_start) >> PAGE_SHIFT;
  196. pfn = page_to_pfn(bo->pages[pgoff]);
  197. ret = vm_insert_mixed(vma, vmf->address, __pfn_to_pfn_t(pfn, PFN_DEV));
  198. switch (ret) {
  199. case -EAGAIN:
  200. case 0:
  201. case -ERESTARTSYS:
  202. case -EINTR:
  203. case -EBUSY:
  204. /*
  205. * EBUSY is ok: this just means that another thread
  206. * already did the job.
  207. */
  208. return VM_FAULT_NOPAGE;
  209. case -ENOMEM:
  210. return VM_FAULT_OOM;
  211. default:
  212. return VM_FAULT_SIGBUS;
  213. }
  214. }
  215. int v3d_mmap(struct file *filp, struct vm_area_struct *vma)
  216. {
  217. int ret;
  218. ret = drm_gem_mmap(filp, vma);
  219. if (ret)
  220. return ret;
  221. v3d_set_mmap_vma_flags(vma);
  222. return ret;
  223. }
  224. int v3d_prime_mmap(struct drm_gem_object *obj, struct vm_area_struct *vma)
  225. {
  226. int ret;
  227. ret = drm_gem_mmap_obj(obj, obj->size, vma);
  228. if (ret < 0)
  229. return ret;
  230. v3d_set_mmap_vma_flags(vma);
  231. return 0;
  232. }
  233. struct sg_table *
  234. v3d_prime_get_sg_table(struct drm_gem_object *obj)
  235. {
  236. struct v3d_bo *bo = to_v3d_bo(obj);
  237. int npages = obj->size >> PAGE_SHIFT;
  238. return drm_prime_pages_to_sg(bo->pages, npages);
  239. }
  240. struct drm_gem_object *
  241. v3d_prime_import_sg_table(struct drm_device *dev,
  242. struct dma_buf_attachment *attach,
  243. struct sg_table *sgt)
  244. {
  245. struct drm_gem_object *obj;
  246. struct v3d_bo *bo;
  247. bo = v3d_bo_create_struct(dev, attach->dmabuf->size);
  248. if (IS_ERR(bo))
  249. return ERR_CAST(bo);
  250. obj = &bo->base;
  251. bo->resv = attach->dmabuf->resv;
  252. bo->sgt = sgt;
  253. v3d_bo_get_pages(bo);
  254. v3d_mmu_insert_ptes(bo);
  255. return obj;
  256. }
  257. int v3d_create_bo_ioctl(struct drm_device *dev, void *data,
  258. struct drm_file *file_priv)
  259. {
  260. struct drm_v3d_create_bo *args = data;
  261. struct v3d_bo *bo = NULL;
  262. int ret;
  263. if (args->flags != 0) {
  264. DRM_INFO("unknown create_bo flags: %d\n", args->flags);
  265. return -EINVAL;
  266. }
  267. bo = v3d_bo_create(dev, file_priv, PAGE_ALIGN(args->size));
  268. if (IS_ERR(bo))
  269. return PTR_ERR(bo);
  270. args->offset = bo->node.start << PAGE_SHIFT;
  271. ret = drm_gem_handle_create(file_priv, &bo->base, &args->handle);
  272. drm_gem_object_put_unlocked(&bo->base);
  273. return ret;
  274. }
  275. int v3d_mmap_bo_ioctl(struct drm_device *dev, void *data,
  276. struct drm_file *file_priv)
  277. {
  278. struct drm_v3d_mmap_bo *args = data;
  279. struct drm_gem_object *gem_obj;
  280. int ret;
  281. if (args->flags != 0) {
  282. DRM_INFO("unknown mmap_bo flags: %d\n", args->flags);
  283. return -EINVAL;
  284. }
  285. gem_obj = drm_gem_object_lookup(file_priv, args->handle);
  286. if (!gem_obj) {
  287. DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle);
  288. return -ENOENT;
  289. }
  290. ret = drm_gem_create_mmap_offset(gem_obj);
  291. if (ret == 0)
  292. args->offset = drm_vma_node_offset_addr(&gem_obj->vma_node);
  293. drm_gem_object_put_unlocked(gem_obj);
  294. return ret;
  295. }
  296. int v3d_get_bo_offset_ioctl(struct drm_device *dev, void *data,
  297. struct drm_file *file_priv)
  298. {
  299. struct drm_v3d_get_bo_offset *args = data;
  300. struct drm_gem_object *gem_obj;
  301. struct v3d_bo *bo;
  302. gem_obj = drm_gem_object_lookup(file_priv, args->handle);
  303. if (!gem_obj) {
  304. DRM_DEBUG("Failed to look up GEM BO %d\n", args->handle);
  305. return -ENOENT;
  306. }
  307. bo = to_v3d_bo(gem_obj);
  308. args->offset = bo->node.start << PAGE_SHIFT;
  309. drm_gem_object_put_unlocked(gem_obj);
  310. return 0;
  311. }