qxl_object.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. /*
  2. * Copyright 2013 Red Hat 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: Dave Airlie
  23. * Alon Levy
  24. */
  25. #include <linux/iosys-map.h>
  26. #include <linux/io-mapping.h>
  27. #include "qxl_drv.h"
  28. #include "qxl_object.h"
  29. static void qxl_ttm_bo_destroy(struct ttm_buffer_object *tbo)
  30. {
  31. struct qxl_bo *bo;
  32. struct qxl_device *qdev;
  33. bo = to_qxl_bo(tbo);
  34. qdev = to_qxl(bo->tbo.base.dev);
  35. qxl_surface_evict(qdev, bo, false);
  36. WARN_ON_ONCE(bo->map_count > 0);
  37. mutex_lock(&qdev->gem.mutex);
  38. list_del_init(&bo->list);
  39. mutex_unlock(&qdev->gem.mutex);
  40. drm_gem_object_release(&bo->tbo.base);
  41. kfree(bo);
  42. }
  43. bool qxl_ttm_bo_is_qxl_bo(struct ttm_buffer_object *bo)
  44. {
  45. if (bo->destroy == &qxl_ttm_bo_destroy)
  46. return true;
  47. return false;
  48. }
  49. void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain)
  50. {
  51. u32 c = 0;
  52. u32 pflag = 0;
  53. unsigned int i;
  54. if (qbo->tbo.base.size <= PAGE_SIZE)
  55. pflag |= TTM_PL_FLAG_TOPDOWN;
  56. qbo->placement.placement = qbo->placements;
  57. if (domain == QXL_GEM_DOMAIN_VRAM) {
  58. qbo->placements[c].mem_type = TTM_PL_VRAM;
  59. qbo->placements[c++].flags = pflag;
  60. }
  61. if (domain == QXL_GEM_DOMAIN_SURFACE) {
  62. qbo->placements[c].mem_type = TTM_PL_PRIV;
  63. qbo->placements[c++].flags = pflag;
  64. qbo->placements[c].mem_type = TTM_PL_VRAM;
  65. qbo->placements[c++].flags = pflag;
  66. }
  67. if (domain == QXL_GEM_DOMAIN_CPU) {
  68. qbo->placements[c].mem_type = TTM_PL_SYSTEM;
  69. qbo->placements[c++].flags = pflag;
  70. }
  71. if (!c) {
  72. qbo->placements[c].mem_type = TTM_PL_SYSTEM;
  73. qbo->placements[c++].flags = 0;
  74. }
  75. qbo->placement.num_placement = c;
  76. for (i = 0; i < c; ++i) {
  77. qbo->placements[i].fpfn = 0;
  78. qbo->placements[i].lpfn = 0;
  79. }
  80. }
  81. static const struct drm_gem_object_funcs qxl_object_funcs = {
  82. .free = qxl_gem_object_free,
  83. .open = qxl_gem_object_open,
  84. .close = qxl_gem_object_close,
  85. .pin = qxl_gem_prime_pin,
  86. .unpin = qxl_gem_prime_unpin,
  87. .get_sg_table = qxl_gem_prime_get_sg_table,
  88. .vmap = qxl_gem_prime_vmap,
  89. .vunmap = qxl_gem_prime_vunmap,
  90. .mmap = drm_gem_ttm_mmap,
  91. .print_info = drm_gem_ttm_print_info,
  92. };
  93. int qxl_bo_create(struct qxl_device *qdev, unsigned long size,
  94. bool kernel, bool pinned, u32 domain, u32 priority,
  95. struct qxl_surface *surf,
  96. struct qxl_bo **bo_ptr)
  97. {
  98. struct ttm_operation_ctx ctx = { !kernel, false };
  99. struct qxl_bo *bo;
  100. enum ttm_bo_type type;
  101. int r;
  102. if (kernel)
  103. type = ttm_bo_type_kernel;
  104. else
  105. type = ttm_bo_type_device;
  106. *bo_ptr = NULL;
  107. bo = kzalloc_obj(struct qxl_bo);
  108. if (bo == NULL)
  109. return -ENOMEM;
  110. size = roundup(size, PAGE_SIZE);
  111. r = drm_gem_object_init(&qdev->ddev, &bo->tbo.base, size);
  112. if (unlikely(r)) {
  113. kfree(bo);
  114. return r;
  115. }
  116. bo->tbo.base.funcs = &qxl_object_funcs;
  117. bo->type = domain;
  118. bo->surface_id = 0;
  119. INIT_LIST_HEAD(&bo->list);
  120. if (surf)
  121. bo->surf = *surf;
  122. qxl_ttm_placement_from_domain(bo, domain);
  123. bo->tbo.priority = priority;
  124. r = ttm_bo_init_reserved(&qdev->mman.bdev, &bo->tbo, type,
  125. &bo->placement, 0, &ctx, NULL, NULL,
  126. &qxl_ttm_bo_destroy);
  127. if (unlikely(r != 0)) {
  128. if (r != -ERESTARTSYS)
  129. dev_err(qdev->ddev.dev,
  130. "object_init failed for (%lu, 0x%08X)\n",
  131. size, domain);
  132. return r;
  133. }
  134. if (pinned)
  135. ttm_bo_pin(&bo->tbo);
  136. ttm_bo_unreserve(&bo->tbo);
  137. *bo_ptr = bo;
  138. return 0;
  139. }
  140. int qxl_bo_vmap_locked(struct qxl_bo *bo, struct iosys_map *map)
  141. {
  142. int r;
  143. dma_resv_assert_held(bo->tbo.base.resv);
  144. if (bo->kptr) {
  145. bo->map_count++;
  146. goto out;
  147. }
  148. r = ttm_bo_vmap(&bo->tbo, &bo->map);
  149. if (r) {
  150. qxl_bo_unpin_locked(bo);
  151. return r;
  152. }
  153. bo->map_count = 1;
  154. /* TODO: Remove kptr in favor of map everywhere. */
  155. if (bo->map.is_iomem)
  156. bo->kptr = (void *)bo->map.vaddr_iomem;
  157. else
  158. bo->kptr = bo->map.vaddr;
  159. out:
  160. *map = bo->map;
  161. return 0;
  162. }
  163. int qxl_bo_pin_and_vmap(struct qxl_bo *bo, struct iosys_map *map)
  164. {
  165. int r;
  166. r = qxl_bo_reserve(bo);
  167. if (r)
  168. return r;
  169. r = qxl_bo_pin_locked(bo);
  170. if (r) {
  171. qxl_bo_unreserve(bo);
  172. return r;
  173. }
  174. r = qxl_bo_vmap_locked(bo, map);
  175. if (r)
  176. qxl_bo_unpin_locked(bo);
  177. qxl_bo_unreserve(bo);
  178. return r;
  179. }
  180. void *qxl_bo_kmap_atomic_page(struct qxl_device *qdev,
  181. struct qxl_bo *bo, int page_offset)
  182. {
  183. unsigned long offset;
  184. void *rptr;
  185. int ret;
  186. struct io_mapping *map;
  187. struct iosys_map bo_map;
  188. if (bo->tbo.resource->mem_type == TTM_PL_VRAM)
  189. map = qdev->vram_mapping;
  190. else if (bo->tbo.resource->mem_type == TTM_PL_PRIV)
  191. map = qdev->surface_mapping;
  192. else
  193. goto fallback;
  194. offset = bo->tbo.resource->start << PAGE_SHIFT;
  195. return io_mapping_map_atomic_wc(map, offset + page_offset);
  196. fallback:
  197. if (bo->kptr) {
  198. rptr = bo->kptr + (page_offset * PAGE_SIZE);
  199. return rptr;
  200. }
  201. ret = qxl_bo_vmap_locked(bo, &bo_map);
  202. if (ret)
  203. return NULL;
  204. rptr = bo_map.vaddr; /* TODO: Use mapping abstraction properly */
  205. rptr += page_offset * PAGE_SIZE;
  206. return rptr;
  207. }
  208. void qxl_bo_vunmap_locked(struct qxl_bo *bo)
  209. {
  210. dma_resv_assert_held(bo->tbo.base.resv);
  211. if (bo->kptr == NULL)
  212. return;
  213. bo->map_count--;
  214. if (bo->map_count > 0)
  215. return;
  216. bo->kptr = NULL;
  217. ttm_bo_vunmap(&bo->tbo, &bo->map);
  218. }
  219. int qxl_bo_vunmap_and_unpin(struct qxl_bo *bo)
  220. {
  221. int r;
  222. r = qxl_bo_reserve(bo);
  223. if (r)
  224. return r;
  225. qxl_bo_vunmap_locked(bo);
  226. qxl_bo_unpin_locked(bo);
  227. qxl_bo_unreserve(bo);
  228. return 0;
  229. }
  230. void qxl_bo_kunmap_atomic_page(struct qxl_device *qdev,
  231. struct qxl_bo *bo, void *pmap)
  232. {
  233. if ((bo->tbo.resource->mem_type != TTM_PL_VRAM) &&
  234. (bo->tbo.resource->mem_type != TTM_PL_PRIV))
  235. goto fallback;
  236. io_mapping_unmap_atomic(pmap);
  237. return;
  238. fallback:
  239. qxl_bo_vunmap_locked(bo);
  240. }
  241. void qxl_bo_unref(struct qxl_bo **bo)
  242. {
  243. if ((*bo) == NULL)
  244. return;
  245. drm_gem_object_put(&(*bo)->tbo.base);
  246. *bo = NULL;
  247. }
  248. struct qxl_bo *qxl_bo_ref(struct qxl_bo *bo)
  249. {
  250. drm_gem_object_get(&bo->tbo.base);
  251. return bo;
  252. }
  253. int qxl_bo_pin_locked(struct qxl_bo *bo)
  254. {
  255. struct ttm_operation_ctx ctx = { false, false };
  256. struct drm_device *ddev = bo->tbo.base.dev;
  257. int r;
  258. dma_resv_assert_held(bo->tbo.base.resv);
  259. if (bo->tbo.pin_count) {
  260. ttm_bo_pin(&bo->tbo);
  261. return 0;
  262. }
  263. qxl_ttm_placement_from_domain(bo, bo->type);
  264. r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);
  265. if (likely(r == 0))
  266. ttm_bo_pin(&bo->tbo);
  267. if (unlikely(r != 0))
  268. dev_err(ddev->dev, "%p pin failed\n", bo);
  269. return r;
  270. }
  271. void qxl_bo_unpin_locked(struct qxl_bo *bo)
  272. {
  273. dma_resv_assert_held(bo->tbo.base.resv);
  274. ttm_bo_unpin(&bo->tbo);
  275. }
  276. /*
  277. * Reserve the BO before pinning the object. If the BO was reserved
  278. * beforehand, use the internal version directly qxl_bo_pin_locked.
  279. *
  280. */
  281. int qxl_bo_pin(struct qxl_bo *bo)
  282. {
  283. int r;
  284. r = qxl_bo_reserve(bo);
  285. if (r)
  286. return r;
  287. r = qxl_bo_pin_locked(bo);
  288. qxl_bo_unreserve(bo);
  289. return r;
  290. }
  291. /*
  292. * Reserve the BO before pinning the object. If the BO was reserved
  293. * beforehand, use the internal version directly qxl_bo_unpin_locked.
  294. *
  295. */
  296. int qxl_bo_unpin(struct qxl_bo *bo)
  297. {
  298. int r;
  299. r = qxl_bo_reserve(bo);
  300. if (r)
  301. return r;
  302. qxl_bo_unpin_locked(bo);
  303. qxl_bo_unreserve(bo);
  304. return 0;
  305. }
  306. void qxl_bo_force_delete(struct qxl_device *qdev)
  307. {
  308. struct qxl_bo *bo, *n;
  309. if (list_empty(&qdev->gem.objects))
  310. return;
  311. dev_err(qdev->ddev.dev, "Userspace still has active objects !\n");
  312. list_for_each_entry_safe(bo, n, &qdev->gem.objects, list) {
  313. dev_err(qdev->ddev.dev, "%p %p %lu %lu force free\n",
  314. &bo->tbo.base, bo, (unsigned long)bo->tbo.base.size,
  315. *((unsigned long *)&bo->tbo.base.refcount));
  316. mutex_lock(&qdev->gem.mutex);
  317. list_del_init(&bo->list);
  318. mutex_unlock(&qdev->gem.mutex);
  319. /* this should unref the ttm bo */
  320. drm_gem_object_put(&bo->tbo.base);
  321. }
  322. }
  323. int qxl_bo_init(struct qxl_device *qdev)
  324. {
  325. return qxl_ttm_init(qdev);
  326. }
  327. void qxl_bo_fini(struct qxl_device *qdev)
  328. {
  329. qxl_ttm_fini(qdev);
  330. }
  331. int qxl_bo_check_id(struct qxl_device *qdev, struct qxl_bo *bo)
  332. {
  333. int ret;
  334. if (bo->type == QXL_GEM_DOMAIN_SURFACE && bo->surface_id == 0) {
  335. /* allocate a surface id for this surface now */
  336. ret = qxl_surface_id_alloc(qdev, bo);
  337. if (ret)
  338. return ret;
  339. ret = qxl_hw_surface_alloc(qdev, bo);
  340. if (ret)
  341. return ret;
  342. }
  343. return 0;
  344. }
  345. int qxl_surf_evict(struct qxl_device *qdev)
  346. {
  347. struct ttm_resource_manager *man;
  348. man = ttm_manager_type(&qdev->mman.bdev, TTM_PL_PRIV);
  349. return ttm_resource_manager_evict_all(&qdev->mman.bdev, man);
  350. }
  351. int qxl_vram_evict(struct qxl_device *qdev)
  352. {
  353. struct ttm_resource_manager *man;
  354. man = ttm_manager_type(&qdev->mman.bdev, TTM_PL_VRAM);
  355. return ttm_resource_manager_evict_all(&qdev->mman.bdev, man);
  356. }