vmwgfx_cmdbuf_res.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. // SPDX-License-Identifier: GPL-2.0 OR MIT
  2. /**************************************************************************
  3. *
  4. * Copyright 2014-2022 VMware, Inc., Palo Alto, CA., USA
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a
  7. * copy of this software and associated documentation files (the
  8. * "Software"), to deal in the Software without restriction, including
  9. * without limitation the rights to use, copy, modify, merge, publish,
  10. * distribute, sub license, and/or sell copies of the Software, and to
  11. * permit persons to whom the Software is furnished to do so, subject to
  12. * the following conditions:
  13. *
  14. * The above copyright notice and this permission notice (including the
  15. * next paragraph) shall be included in all copies or substantial portions
  16. * of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
  21. * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
  22. * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  23. * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  24. * USE OR OTHER DEALINGS IN THE SOFTWARE.
  25. *
  26. **************************************************************************/
  27. #include "vmwgfx_drv.h"
  28. #include "vmwgfx_resource_priv.h"
  29. #include <linux/hashtable.h>
  30. #define VMW_CMDBUF_RES_MAN_HT_ORDER 12
  31. /**
  32. * struct vmw_cmdbuf_res - Command buffer managed resource entry.
  33. *
  34. * @res: Refcounted pointer to a struct vmw_resource.
  35. * @hash: Hash entry for the manager hash table.
  36. * @head: List head used either by the staging list or the manager list
  37. * of committed resources.
  38. * @state: Staging state of this resource entry.
  39. * @man: Pointer to a resource manager for this entry.
  40. */
  41. struct vmw_cmdbuf_res {
  42. struct vmw_resource *res;
  43. struct vmwgfx_hash_item hash;
  44. struct list_head head;
  45. enum vmw_cmdbuf_res_state state;
  46. struct vmw_cmdbuf_res_manager *man;
  47. };
  48. /**
  49. * struct vmw_cmdbuf_res_manager - Command buffer resource manager.
  50. *
  51. * @resources: Hash table containing staged and committed command buffer
  52. * resources
  53. * @list: List of committed command buffer resources.
  54. * @dev_priv: Pointer to a device private structure.
  55. *
  56. * @resources and @list are protected by the cmdbuf mutex for now.
  57. */
  58. struct vmw_cmdbuf_res_manager {
  59. DECLARE_HASHTABLE(resources, VMW_CMDBUF_RES_MAN_HT_ORDER);
  60. struct list_head list;
  61. struct vmw_private *dev_priv;
  62. };
  63. /**
  64. * vmw_cmdbuf_res_lookup - Look up a command buffer resource
  65. *
  66. * @man: Pointer to the command buffer resource manager
  67. * @res_type: The resource type, that combined with the user key
  68. * identifies the resource.
  69. * @user_key: The user key.
  70. *
  71. * Returns a valid refcounted struct vmw_resource pointer on success,
  72. * an error pointer on failure.
  73. */
  74. struct vmw_resource *
  75. vmw_cmdbuf_res_lookup(struct vmw_cmdbuf_res_manager *man,
  76. enum vmw_cmdbuf_res_type res_type,
  77. u32 user_key)
  78. {
  79. struct vmwgfx_hash_item *hash;
  80. unsigned long key = user_key | (res_type << 24);
  81. hash_for_each_possible_rcu(man->resources, hash, head, key) {
  82. if (hash->key == key)
  83. return hlist_entry(hash, struct vmw_cmdbuf_res, hash)->res;
  84. }
  85. return ERR_PTR(-EINVAL);
  86. }
  87. /**
  88. * vmw_cmdbuf_res_free - Free a command buffer resource.
  89. *
  90. * @man: Pointer to the command buffer resource manager
  91. * @entry: Pointer to a struct vmw_cmdbuf_res.
  92. *
  93. * Frees a struct vmw_cmdbuf_res entry and drops its reference to the
  94. * struct vmw_resource.
  95. */
  96. static void vmw_cmdbuf_res_free(struct vmw_cmdbuf_res_manager *man,
  97. struct vmw_cmdbuf_res *entry)
  98. {
  99. list_del(&entry->head);
  100. hash_del_rcu(&entry->hash.head);
  101. vmw_resource_unreference(&entry->res);
  102. kfree(entry);
  103. }
  104. /**
  105. * vmw_cmdbuf_res_commit - Commit a list of command buffer resource actions
  106. *
  107. * @list: Caller's list of command buffer resource actions.
  108. *
  109. * This function commits a list of command buffer resource
  110. * additions or removals.
  111. * It is typically called when the execbuf ioctl call triggering these
  112. * actions has committed the fifo contents to the device.
  113. */
  114. void vmw_cmdbuf_res_commit(struct list_head *list)
  115. {
  116. struct vmw_cmdbuf_res *entry, *next;
  117. list_for_each_entry_safe(entry, next, list, head) {
  118. list_del(&entry->head);
  119. if (entry->res->func->commit_notify)
  120. entry->res->func->commit_notify(entry->res,
  121. entry->state);
  122. switch (entry->state) {
  123. case VMW_CMDBUF_RES_ADD:
  124. entry->state = VMW_CMDBUF_RES_COMMITTED;
  125. list_add_tail(&entry->head, &entry->man->list);
  126. break;
  127. case VMW_CMDBUF_RES_DEL:
  128. vmw_resource_unreference(&entry->res);
  129. kfree(entry);
  130. break;
  131. default:
  132. BUG();
  133. break;
  134. }
  135. }
  136. }
  137. /**
  138. * vmw_cmdbuf_res_revert - Revert a list of command buffer resource actions
  139. *
  140. * @list: Caller's list of command buffer resource action
  141. *
  142. * This function reverts a list of command buffer resource
  143. * additions or removals.
  144. * It is typically called when the execbuf ioctl call triggering these
  145. * actions failed for some reason, and the command stream was never
  146. * submitted.
  147. */
  148. void vmw_cmdbuf_res_revert(struct list_head *list)
  149. {
  150. struct vmw_cmdbuf_res *entry, *next;
  151. list_for_each_entry_safe(entry, next, list, head) {
  152. switch (entry->state) {
  153. case VMW_CMDBUF_RES_ADD:
  154. vmw_cmdbuf_res_free(entry->man, entry);
  155. break;
  156. case VMW_CMDBUF_RES_DEL:
  157. hash_add_rcu(entry->man->resources, &entry->hash.head,
  158. entry->hash.key);
  159. list_move_tail(&entry->head, &entry->man->list);
  160. entry->state = VMW_CMDBUF_RES_COMMITTED;
  161. break;
  162. default:
  163. BUG();
  164. break;
  165. }
  166. }
  167. }
  168. /**
  169. * vmw_cmdbuf_res_add - Stage a command buffer managed resource for addition.
  170. *
  171. * @man: Pointer to the command buffer resource manager.
  172. * @res_type: The resource type.
  173. * @user_key: The user-space id of the resource.
  174. * @res: Valid (refcount != 0) pointer to a struct vmw_resource.
  175. * @list: The staging list.
  176. *
  177. * This function allocates a struct vmw_cmdbuf_res entry and adds the
  178. * resource to the hash table of the manager identified by @man. The
  179. * entry is then put on the staging list identified by @list.
  180. */
  181. int vmw_cmdbuf_res_add(struct vmw_cmdbuf_res_manager *man,
  182. enum vmw_cmdbuf_res_type res_type,
  183. u32 user_key,
  184. struct vmw_resource *res,
  185. struct list_head *list)
  186. {
  187. struct vmw_cmdbuf_res *cres;
  188. cres = kzalloc(sizeof(*cres), GFP_KERNEL);
  189. if (unlikely(!cres))
  190. return -ENOMEM;
  191. cres->hash.key = user_key | (res_type << 24);
  192. hash_add_rcu(man->resources, &cres->hash.head, cres->hash.key);
  193. cres->state = VMW_CMDBUF_RES_ADD;
  194. cres->res = vmw_resource_reference(res);
  195. cres->man = man;
  196. list_add_tail(&cres->head, list);
  197. return 0;
  198. }
  199. /**
  200. * vmw_cmdbuf_res_remove - Stage a command buffer managed resource for removal.
  201. *
  202. * @man: Pointer to the command buffer resource manager.
  203. * @res_type: The resource type.
  204. * @user_key: The user-space id of the resource.
  205. * @list: The staging list.
  206. * @res_p: If the resource is in an already committed state, points to the
  207. * struct vmw_resource on successful return. The pointer will be
  208. * non ref-counted.
  209. *
  210. * This function looks up the struct vmw_cmdbuf_res entry from the manager
  211. * hash table and, if it exists, removes it. Depending on its current staging
  212. * state it then either removes the entry from the staging list or adds it
  213. * to it with a staging state of removal.
  214. */
  215. int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man,
  216. enum vmw_cmdbuf_res_type res_type,
  217. u32 user_key,
  218. struct list_head *list,
  219. struct vmw_resource **res_p)
  220. {
  221. struct vmw_cmdbuf_res *entry = NULL;
  222. struct vmwgfx_hash_item *hash;
  223. unsigned long key = user_key | (res_type << 24);
  224. hash_for_each_possible_rcu(man->resources, hash, head, key) {
  225. if (hash->key == key) {
  226. entry = hlist_entry(hash, struct vmw_cmdbuf_res, hash);
  227. break;
  228. }
  229. }
  230. if (unlikely(!entry))
  231. return -EINVAL;
  232. switch (entry->state) {
  233. case VMW_CMDBUF_RES_ADD:
  234. vmw_cmdbuf_res_free(man, entry);
  235. *res_p = NULL;
  236. break;
  237. case VMW_CMDBUF_RES_COMMITTED:
  238. hash_del_rcu(&entry->hash.head);
  239. list_del(&entry->head);
  240. entry->state = VMW_CMDBUF_RES_DEL;
  241. list_add_tail(&entry->head, list);
  242. *res_p = entry->res;
  243. break;
  244. default:
  245. BUG();
  246. break;
  247. }
  248. return 0;
  249. }
  250. /**
  251. * vmw_cmdbuf_res_man_create - Allocate a command buffer managed resource
  252. * manager.
  253. *
  254. * @dev_priv: Pointer to a struct vmw_private
  255. *
  256. * Allocates and initializes a command buffer managed resource manager. Returns
  257. * an error pointer on failure.
  258. */
  259. struct vmw_cmdbuf_res_manager *
  260. vmw_cmdbuf_res_man_create(struct vmw_private *dev_priv)
  261. {
  262. struct vmw_cmdbuf_res_manager *man;
  263. man = kzalloc(sizeof(*man), GFP_KERNEL);
  264. if (!man)
  265. return ERR_PTR(-ENOMEM);
  266. man->dev_priv = dev_priv;
  267. INIT_LIST_HEAD(&man->list);
  268. hash_init(man->resources);
  269. return man;
  270. }
  271. /**
  272. * vmw_cmdbuf_res_man_destroy - Destroy a command buffer managed resource
  273. * manager.
  274. *
  275. * @man: Pointer to the manager to destroy.
  276. *
  277. * This function destroys a command buffer managed resource manager and
  278. * unreferences / frees all command buffer managed resources and -entries
  279. * associated with it.
  280. */
  281. void vmw_cmdbuf_res_man_destroy(struct vmw_cmdbuf_res_manager *man)
  282. {
  283. struct vmw_cmdbuf_res *entry, *next;
  284. list_for_each_entry_safe(entry, next, &man->list, head)
  285. vmw_cmdbuf_res_free(man, entry);
  286. kfree(man);
  287. }