vmwgfx_streamoutput.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. // SPDX-License-Identifier: GPL-2.0 OR MIT
  2. /**************************************************************************
  3. *
  4. * Copyright © 2018-2023 VMware, Inc., Palo Alto, CA., USA
  5. * All Rights Reserved.
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a
  8. * copy of this software and associated documentation files (the
  9. * "Software"), to deal in the Software without restriction, including
  10. * without limitation the rights to use, copy, modify, merge, publish,
  11. * distribute, sub license, and/or sell copies of the Software, and to
  12. * permit persons to whom the Software is furnished to do so, subject to
  13. * the following conditions:
  14. *
  15. * The above copyright notice and this permission notice (including the
  16. * next paragraph) shall be included in all copies or substantial portions
  17. * of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21. * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  22. * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
  23. * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  24. * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  25. * USE OR OTHER DEALINGS IN THE SOFTWARE.
  26. *
  27. **************************************************************************/
  28. #include "vmwgfx_binding.h"
  29. #include "vmwgfx_bo.h"
  30. #include "vmwgfx_drv.h"
  31. #include "vmwgfx_resource_priv.h"
  32. #include <drm/ttm/ttm_placement.h>
  33. /**
  34. * struct vmw_dx_streamoutput - Streamoutput resource metadata.
  35. * @res: Base resource struct.
  36. * @ctx: Non-refcounted context to which @res belong.
  37. * @cotable: Refcounted cotable holding this Streamoutput.
  38. * @cotable_head: List head for cotable-so_res list.
  39. * @id: User-space provided identifier.
  40. * @size: User-space provided mob size.
  41. * @committed: Whether streamoutput is actually created or pending creation.
  42. */
  43. struct vmw_dx_streamoutput {
  44. struct vmw_resource res;
  45. struct vmw_resource *ctx;
  46. struct vmw_resource *cotable;
  47. struct list_head cotable_head;
  48. u32 id;
  49. u32 size;
  50. bool committed;
  51. };
  52. static int vmw_dx_streamoutput_create(struct vmw_resource *res);
  53. static int vmw_dx_streamoutput_bind(struct vmw_resource *res,
  54. struct ttm_validate_buffer *val_buf);
  55. static int vmw_dx_streamoutput_unbind(struct vmw_resource *res, bool readback,
  56. struct ttm_validate_buffer *val_buf);
  57. static void vmw_dx_streamoutput_commit_notify(struct vmw_resource *res,
  58. enum vmw_cmdbuf_res_state state);
  59. static const struct vmw_res_func vmw_dx_streamoutput_func = {
  60. .res_type = vmw_res_streamoutput,
  61. .needs_guest_memory = true,
  62. .may_evict = false,
  63. .type_name = "DX streamoutput",
  64. .domain = VMW_BO_DOMAIN_MOB,
  65. .busy_domain = VMW_BO_DOMAIN_MOB,
  66. .create = vmw_dx_streamoutput_create,
  67. .destroy = NULL, /* Command buffer managed resource. */
  68. .bind = vmw_dx_streamoutput_bind,
  69. .unbind = vmw_dx_streamoutput_unbind,
  70. .commit_notify = vmw_dx_streamoutput_commit_notify,
  71. };
  72. static inline struct vmw_dx_streamoutput *
  73. vmw_res_to_dx_streamoutput(struct vmw_resource *res)
  74. {
  75. return container_of(res, struct vmw_dx_streamoutput, res);
  76. }
  77. /**
  78. * vmw_dx_streamoutput_unscrub - Reattach the MOB to streamoutput.
  79. * @res: The streamoutput resource.
  80. *
  81. * Return: 0 on success, negative error code on failure.
  82. */
  83. static int vmw_dx_streamoutput_unscrub(struct vmw_resource *res)
  84. {
  85. struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
  86. struct vmw_private *dev_priv = res->dev_priv;
  87. struct {
  88. SVGA3dCmdHeader header;
  89. SVGA3dCmdDXBindStreamOutput body;
  90. } *cmd;
  91. if (!list_empty(&so->cotable_head) || !so->committed )
  92. return 0;
  93. cmd = VMW_CMD_CTX_RESERVE(dev_priv, sizeof(*cmd), so->ctx->id);
  94. if (!cmd)
  95. return -ENOMEM;
  96. cmd->header.id = SVGA_3D_CMD_DX_BIND_STREAMOUTPUT;
  97. cmd->header.size = sizeof(cmd->body);
  98. cmd->body.soid = so->id;
  99. cmd->body.mobid = res->guest_memory_bo->tbo.resource->start;
  100. cmd->body.offsetInBytes = res->guest_memory_offset;
  101. cmd->body.sizeInBytes = so->size;
  102. vmw_cmd_commit(dev_priv, sizeof(*cmd));
  103. vmw_cotable_add_resource(so->cotable, &so->cotable_head);
  104. return 0;
  105. }
  106. static int vmw_dx_streamoutput_create(struct vmw_resource *res)
  107. {
  108. struct vmw_private *dev_priv = res->dev_priv;
  109. struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
  110. int ret = 0;
  111. WARN_ON_ONCE(!so->committed);
  112. if (vmw_resource_mob_attached(res)) {
  113. mutex_lock(&dev_priv->binding_mutex);
  114. ret = vmw_dx_streamoutput_unscrub(res);
  115. mutex_unlock(&dev_priv->binding_mutex);
  116. }
  117. res->id = so->id;
  118. return ret;
  119. }
  120. static int vmw_dx_streamoutput_bind(struct vmw_resource *res,
  121. struct ttm_validate_buffer *val_buf)
  122. {
  123. struct vmw_private *dev_priv = res->dev_priv;
  124. struct ttm_buffer_object *bo = val_buf->bo;
  125. int ret;
  126. if (WARN_ON(bo->resource->mem_type != VMW_PL_MOB))
  127. return -EINVAL;
  128. mutex_lock(&dev_priv->binding_mutex);
  129. ret = vmw_dx_streamoutput_unscrub(res);
  130. mutex_unlock(&dev_priv->binding_mutex);
  131. return ret;
  132. }
  133. /**
  134. * vmw_dx_streamoutput_scrub - Unbind the MOB from streamoutput.
  135. * @res: The streamoutput resource.
  136. *
  137. * Return: 0 on success, negative error code on failure.
  138. */
  139. static int vmw_dx_streamoutput_scrub(struct vmw_resource *res)
  140. {
  141. struct vmw_private *dev_priv = res->dev_priv;
  142. struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
  143. struct {
  144. SVGA3dCmdHeader header;
  145. SVGA3dCmdDXBindStreamOutput body;
  146. } *cmd;
  147. if (list_empty(&so->cotable_head))
  148. return 0;
  149. WARN_ON_ONCE(!so->committed);
  150. cmd = VMW_CMD_CTX_RESERVE(dev_priv, sizeof(*cmd), so->ctx->id);
  151. if (!cmd)
  152. return -ENOMEM;
  153. cmd->header.id = SVGA_3D_CMD_DX_BIND_STREAMOUTPUT;
  154. cmd->header.size = sizeof(cmd->body);
  155. cmd->body.soid = res->id;
  156. cmd->body.mobid = SVGA3D_INVALID_ID;
  157. cmd->body.offsetInBytes = 0;
  158. cmd->body.sizeInBytes = so->size;
  159. vmw_cmd_commit(dev_priv, sizeof(*cmd));
  160. res->id = -1;
  161. list_del_init(&so->cotable_head);
  162. return 0;
  163. }
  164. static int vmw_dx_streamoutput_unbind(struct vmw_resource *res, bool readback,
  165. struct ttm_validate_buffer *val_buf)
  166. {
  167. struct vmw_private *dev_priv = res->dev_priv;
  168. struct vmw_fence_obj *fence;
  169. int ret;
  170. if (WARN_ON(res->guest_memory_bo->tbo.resource->mem_type != VMW_PL_MOB))
  171. return -EINVAL;
  172. mutex_lock(&dev_priv->binding_mutex);
  173. ret = vmw_dx_streamoutput_scrub(res);
  174. mutex_unlock(&dev_priv->binding_mutex);
  175. if (ret)
  176. return ret;
  177. (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
  178. vmw_bo_fence_single(val_buf->bo, fence);
  179. if (fence != NULL)
  180. vmw_fence_obj_unreference(&fence);
  181. return 0;
  182. }
  183. static void vmw_dx_streamoutput_commit_notify(struct vmw_resource *res,
  184. enum vmw_cmdbuf_res_state state)
  185. {
  186. struct vmw_private *dev_priv = res->dev_priv;
  187. struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
  188. if (state == VMW_CMDBUF_RES_ADD) {
  189. mutex_lock(&dev_priv->binding_mutex);
  190. vmw_cotable_add_resource(so->cotable, &so->cotable_head);
  191. so->committed = true;
  192. res->id = so->id;
  193. mutex_unlock(&dev_priv->binding_mutex);
  194. } else {
  195. mutex_lock(&dev_priv->binding_mutex);
  196. list_del_init(&so->cotable_head);
  197. so->committed = false;
  198. res->id = -1;
  199. mutex_unlock(&dev_priv->binding_mutex);
  200. }
  201. }
  202. /**
  203. * vmw_dx_streamoutput_lookup - Do a streamoutput resource lookup by user key.
  204. * @man: Command buffer managed resource manager for current context.
  205. * @user_key: User-space identifier for lookup.
  206. *
  207. * Return: Valid refcounted vmw_resource on success, error pointer on failure.
  208. */
  209. struct vmw_resource *
  210. vmw_dx_streamoutput_lookup(struct vmw_cmdbuf_res_manager *man,
  211. u32 user_key)
  212. {
  213. return vmw_cmdbuf_res_lookup(man, vmw_cmdbuf_res_streamoutput,
  214. user_key);
  215. }
  216. static void vmw_dx_streamoutput_res_free(struct vmw_resource *res)
  217. {
  218. struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
  219. vmw_resource_unreference(&so->cotable);
  220. kfree(so);
  221. }
  222. static void vmw_dx_streamoutput_hw_destroy(struct vmw_resource *res)
  223. {
  224. /* Destroyed by user-space cmd buf or as part of context takedown. */
  225. res->id = -1;
  226. }
  227. /**
  228. * vmw_dx_streamoutput_add - Add a streamoutput as a cmd buf managed resource.
  229. * @man: Command buffer managed resource manager for current context.
  230. * @ctx: Pointer to context resource.
  231. * @user_key: The identifier for this streamoutput.
  232. * @list: The list of staged command buffer managed resources.
  233. *
  234. * Return: 0 on success, negative error code on failure.
  235. */
  236. int vmw_dx_streamoutput_add(struct vmw_cmdbuf_res_manager *man,
  237. struct vmw_resource *ctx, u32 user_key,
  238. struct list_head *list)
  239. {
  240. struct vmw_dx_streamoutput *so;
  241. struct vmw_resource *res;
  242. struct vmw_private *dev_priv = ctx->dev_priv;
  243. int ret;
  244. so = kmalloc(sizeof(*so), GFP_KERNEL);
  245. if (!so) {
  246. return -ENOMEM;
  247. }
  248. res = &so->res;
  249. so->ctx = ctx;
  250. so->cotable = vmw_resource_reference
  251. (vmw_context_cotable(ctx, SVGA_COTABLE_STREAMOUTPUT));
  252. so->id = user_key;
  253. so->committed = false;
  254. INIT_LIST_HEAD(&so->cotable_head);
  255. ret = vmw_resource_init(dev_priv, res, true,
  256. vmw_dx_streamoutput_res_free,
  257. &vmw_dx_streamoutput_func);
  258. if (ret)
  259. goto out_resource_init;
  260. ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_streamoutput, user_key,
  261. res, list);
  262. if (ret)
  263. goto out_resource_init;
  264. res->id = so->id;
  265. res->hw_destroy = vmw_dx_streamoutput_hw_destroy;
  266. out_resource_init:
  267. vmw_resource_unreference(&res);
  268. return ret;
  269. }
  270. /**
  271. * vmw_dx_streamoutput_set_size - Sets streamoutput mob size in res struct.
  272. * @res: The streamoutput res for which need to set size.
  273. * @size: The size provided by user-space to set.
  274. */
  275. void vmw_dx_streamoutput_set_size(struct vmw_resource *res, u32 size)
  276. {
  277. struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
  278. so->size = size;
  279. }
  280. /**
  281. * vmw_dx_streamoutput_remove - Stage streamoutput for removal.
  282. * @man: Command buffer managed resource manager for current context.
  283. * @user_key: The identifier for this streamoutput.
  284. * @list: The list of staged command buffer managed resources.
  285. *
  286. * Return: 0 on success, negative error code on failure.
  287. */
  288. int vmw_dx_streamoutput_remove(struct vmw_cmdbuf_res_manager *man,
  289. u32 user_key,
  290. struct list_head *list)
  291. {
  292. struct vmw_resource *r;
  293. return vmw_cmdbuf_res_remove(man, vmw_cmdbuf_res_streamoutput,
  294. (u32)user_key, list, &r);
  295. }
  296. /**
  297. * vmw_dx_streamoutput_cotable_list_scrub - cotable unbind_func callback.
  298. * @dev_priv: Device private.
  299. * @list: The list of cotable resources.
  300. * @readback: Whether the call was part of a readback unbind.
  301. */
  302. void vmw_dx_streamoutput_cotable_list_scrub(struct vmw_private *dev_priv,
  303. struct list_head *list,
  304. bool readback)
  305. {
  306. struct vmw_dx_streamoutput *entry, *next;
  307. lockdep_assert_held_once(&dev_priv->binding_mutex);
  308. list_for_each_entry_safe(entry, next, list, cotable_head) {
  309. WARN_ON(vmw_dx_streamoutput_scrub(&entry->res));
  310. if (!readback)
  311. entry->committed =false;
  312. }
  313. }