vmwgfx_cotable.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. // SPDX-License-Identifier: GPL-2.0 OR MIT
  2. /**************************************************************************
  3. *
  4. * Copyright 2014-2023 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. /*
  28. * Treat context OTables as resources to make use of the resource
  29. * backing MOB eviction mechanism, that is used to read back the COTable
  30. * whenever the backing MOB is evicted.
  31. */
  32. #include "vmwgfx_bo.h"
  33. #include "vmwgfx_drv.h"
  34. #include "vmwgfx_mksstat.h"
  35. #include "vmwgfx_resource_priv.h"
  36. #include "vmwgfx_so.h"
  37. #include <drm/ttm/ttm_placement.h>
  38. /**
  39. * struct vmw_cotable - Context Object Table resource
  40. *
  41. * @res: struct vmw_resource we are deriving from.
  42. * @ctx: non-refcounted pointer to the owning context.
  43. * @size_read_back: Size of data read back during eviction.
  44. * @seen_entries: Seen entries in command stream for this cotable.
  45. * @type: The cotable type.
  46. * @scrubbed: Whether the cotable has been scrubbed.
  47. * @resource_list: List of resources in the cotable.
  48. */
  49. struct vmw_cotable {
  50. struct vmw_resource res;
  51. struct vmw_resource *ctx;
  52. size_t size_read_back;
  53. int seen_entries;
  54. u32 type;
  55. bool scrubbed;
  56. struct list_head resource_list;
  57. };
  58. /**
  59. * struct vmw_cotable_info - Static info about cotable types
  60. *
  61. * @min_initial_entries: Min number of initial intries at cotable allocation
  62. * for this cotable type.
  63. * @size: Size of each entry.
  64. * @unbind_func: Unbind call-back function.
  65. */
  66. struct vmw_cotable_info {
  67. u32 min_initial_entries;
  68. u32 size;
  69. void (*unbind_func)(struct vmw_private *, struct list_head *,
  70. bool);
  71. };
  72. /*
  73. * Getting the initial size right is difficult because it all depends
  74. * on what the userspace is doing. The sizes will be aligned up to
  75. * a PAGE_SIZE so we just want to make sure that for majority of apps
  76. * the initial number of entries doesn't require an immediate resize.
  77. * For all cotables except SVGACOTableDXElementLayoutEntry and
  78. * SVGACOTableDXBlendStateEntry the initial number of entries fits
  79. * within the PAGE_SIZE. For SVGACOTableDXElementLayoutEntry and
  80. * SVGACOTableDXBlendStateEntry we want to reserve two pages,
  81. * because that's what all apps will require initially.
  82. */
  83. static const struct vmw_cotable_info co_info[] = {
  84. {1, sizeof(SVGACOTableDXRTViewEntry), &vmw_view_cotable_list_destroy},
  85. {1, sizeof(SVGACOTableDXDSViewEntry), &vmw_view_cotable_list_destroy},
  86. {1, sizeof(SVGACOTableDXSRViewEntry), &vmw_view_cotable_list_destroy},
  87. {PAGE_SIZE/sizeof(SVGACOTableDXElementLayoutEntry) + 1, sizeof(SVGACOTableDXElementLayoutEntry), NULL},
  88. {PAGE_SIZE/sizeof(SVGACOTableDXBlendStateEntry) + 1, sizeof(SVGACOTableDXBlendStateEntry), NULL},
  89. {1, sizeof(SVGACOTableDXDepthStencilEntry), NULL},
  90. {1, sizeof(SVGACOTableDXRasterizerStateEntry), NULL},
  91. {1, sizeof(SVGACOTableDXSamplerEntry), NULL},
  92. {1, sizeof(SVGACOTableDXStreamOutputEntry), &vmw_dx_streamoutput_cotable_list_scrub},
  93. {1, sizeof(SVGACOTableDXQueryEntry), NULL},
  94. {1, sizeof(SVGACOTableDXShaderEntry), &vmw_dx_shader_cotable_list_scrub},
  95. {1, sizeof(SVGACOTableDXUAViewEntry), &vmw_view_cotable_list_destroy}
  96. };
  97. /*
  98. * Cotables with bindings that we remove must be scrubbed first,
  99. * otherwise, the device will swap in an invalid context when we remove
  100. * bindings before scrubbing a cotable...
  101. */
  102. const SVGACOTableType vmw_cotable_scrub_order[] = {
  103. SVGA_COTABLE_RTVIEW,
  104. SVGA_COTABLE_DSVIEW,
  105. SVGA_COTABLE_SRVIEW,
  106. SVGA_COTABLE_DXSHADER,
  107. SVGA_COTABLE_ELEMENTLAYOUT,
  108. SVGA_COTABLE_BLENDSTATE,
  109. SVGA_COTABLE_DEPTHSTENCIL,
  110. SVGA_COTABLE_RASTERIZERSTATE,
  111. SVGA_COTABLE_SAMPLER,
  112. SVGA_COTABLE_STREAMOUTPUT,
  113. SVGA_COTABLE_DXQUERY,
  114. SVGA_COTABLE_UAVIEW,
  115. };
  116. static int vmw_cotable_bind(struct vmw_resource *res,
  117. struct ttm_validate_buffer *val_buf);
  118. static int vmw_cotable_unbind(struct vmw_resource *res,
  119. bool readback,
  120. struct ttm_validate_buffer *val_buf);
  121. static int vmw_cotable_create(struct vmw_resource *res);
  122. static int vmw_cotable_destroy(struct vmw_resource *res);
  123. static const struct vmw_res_func vmw_cotable_func = {
  124. .res_type = vmw_res_cotable,
  125. .needs_guest_memory = true,
  126. .may_evict = true,
  127. .prio = 3,
  128. .dirty_prio = 3,
  129. .type_name = "context guest backed object tables",
  130. .domain = VMW_BO_DOMAIN_MOB,
  131. .busy_domain = VMW_BO_DOMAIN_MOB,
  132. .create = vmw_cotable_create,
  133. .destroy = vmw_cotable_destroy,
  134. .bind = vmw_cotable_bind,
  135. .unbind = vmw_cotable_unbind,
  136. };
  137. /**
  138. * vmw_cotable - Convert a struct vmw_resource pointer to a struct
  139. * vmw_cotable pointer
  140. *
  141. * @res: Pointer to the resource.
  142. */
  143. static struct vmw_cotable *vmw_cotable(struct vmw_resource *res)
  144. {
  145. return container_of(res, struct vmw_cotable, res);
  146. }
  147. /**
  148. * vmw_cotable_destroy - Cotable resource destroy callback
  149. *
  150. * @res: Pointer to the cotable resource.
  151. *
  152. * There is no device cotable destroy command, so this function only
  153. * makes sure that the resource id is set to invalid.
  154. */
  155. static int vmw_cotable_destroy(struct vmw_resource *res)
  156. {
  157. res->id = -1;
  158. return 0;
  159. }
  160. /**
  161. * vmw_cotable_unscrub - Undo a cotable unscrub operation
  162. *
  163. * @res: Pointer to the cotable resource
  164. *
  165. * This function issues commands to (re)bind the cotable to
  166. * its backing mob, which needs to be validated and reserved at this point.
  167. * This is identical to bind() except the function interface looks different.
  168. */
  169. static int vmw_cotable_unscrub(struct vmw_resource *res)
  170. {
  171. struct vmw_cotable *vcotbl = vmw_cotable(res);
  172. struct vmw_private *dev_priv = res->dev_priv;
  173. struct ttm_buffer_object *bo = &res->guest_memory_bo->tbo;
  174. struct {
  175. SVGA3dCmdHeader header;
  176. SVGA3dCmdDXSetCOTable body;
  177. } *cmd;
  178. WARN_ON_ONCE(bo->resource->mem_type != VMW_PL_MOB);
  179. dma_resv_assert_held(bo->base.resv);
  180. cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
  181. if (!cmd)
  182. return -ENOMEM;
  183. WARN_ON(vcotbl->ctx->id == SVGA3D_INVALID_ID);
  184. WARN_ON(bo->resource->mem_type != VMW_PL_MOB);
  185. cmd->header.id = SVGA_3D_CMD_DX_SET_COTABLE;
  186. cmd->header.size = sizeof(cmd->body);
  187. cmd->body.cid = vcotbl->ctx->id;
  188. cmd->body.type = vcotbl->type;
  189. cmd->body.mobid = bo->resource->start;
  190. cmd->body.validSizeInBytes = vcotbl->size_read_back;
  191. vmw_cmd_commit_flush(dev_priv, sizeof(*cmd));
  192. vcotbl->scrubbed = false;
  193. return 0;
  194. }
  195. /**
  196. * vmw_cotable_bind - Undo a cotable unscrub operation
  197. *
  198. * @res: Pointer to the cotable resource
  199. * @val_buf: Pointer to a struct ttm_validate_buffer prepared by the caller
  200. * for convenience / fencing.
  201. *
  202. * This function issues commands to (re)bind the cotable to
  203. * its backing mob, which needs to be validated and reserved at this point.
  204. */
  205. static int vmw_cotable_bind(struct vmw_resource *res,
  206. struct ttm_validate_buffer *val_buf)
  207. {
  208. /*
  209. * The create() callback may have changed @res->backup without
  210. * the caller noticing, and with val_buf->bo still pointing to
  211. * the old backup buffer. Although hackish, and not used currently,
  212. * take the opportunity to correct the value here so that it's not
  213. * misused in the future.
  214. */
  215. val_buf->bo = &res->guest_memory_bo->tbo;
  216. return vmw_cotable_unscrub(res);
  217. }
  218. /**
  219. * vmw_cotable_scrub - Scrub the cotable from the device.
  220. *
  221. * @res: Pointer to the cotable resource.
  222. * @readback: Whether initiate a readback of the cotable data to the backup
  223. * buffer.
  224. *
  225. * In some situations (context swapouts) it might be desirable to make the
  226. * device forget about the cotable without performing a full unbind. A full
  227. * unbind requires reserved backup buffers and it might not be possible to
  228. * reserve them due to locking order violation issues. The vmw_cotable_scrub
  229. * function implements a partial unbind() without that requirement but with the
  230. * following restrictions.
  231. * 1) Before the cotable is again used by the GPU, vmw_cotable_unscrub() must
  232. * be called.
  233. * 2) Before the cotable backing buffer is used by the CPU, or during the
  234. * resource destruction, vmw_cotable_unbind() must be called.
  235. */
  236. int vmw_cotable_scrub(struct vmw_resource *res, bool readback)
  237. {
  238. struct vmw_cotable *vcotbl = vmw_cotable(res);
  239. struct vmw_private *dev_priv = res->dev_priv;
  240. size_t submit_size;
  241. struct {
  242. SVGA3dCmdHeader header;
  243. SVGA3dCmdDXReadbackCOTable body;
  244. } *cmd0;
  245. struct {
  246. SVGA3dCmdHeader header;
  247. SVGA3dCmdDXSetCOTable body;
  248. } *cmd1;
  249. if (vcotbl->scrubbed)
  250. return 0;
  251. if (co_info[vcotbl->type].unbind_func)
  252. co_info[vcotbl->type].unbind_func(dev_priv,
  253. &vcotbl->resource_list,
  254. readback);
  255. submit_size = sizeof(*cmd1);
  256. if (readback)
  257. submit_size += sizeof(*cmd0);
  258. cmd1 = VMW_CMD_RESERVE(dev_priv, submit_size);
  259. if (!cmd1)
  260. return -ENOMEM;
  261. vcotbl->size_read_back = 0;
  262. if (readback) {
  263. cmd0 = (void *) cmd1;
  264. cmd0->header.id = SVGA_3D_CMD_DX_READBACK_COTABLE;
  265. cmd0->header.size = sizeof(cmd0->body);
  266. cmd0->body.cid = vcotbl->ctx->id;
  267. cmd0->body.type = vcotbl->type;
  268. cmd1 = (void *) &cmd0[1];
  269. vcotbl->size_read_back = res->guest_memory_size;
  270. }
  271. cmd1->header.id = SVGA_3D_CMD_DX_SET_COTABLE;
  272. cmd1->header.size = sizeof(cmd1->body);
  273. cmd1->body.cid = vcotbl->ctx->id;
  274. cmd1->body.type = vcotbl->type;
  275. cmd1->body.mobid = SVGA3D_INVALID_ID;
  276. cmd1->body.validSizeInBytes = 0;
  277. vmw_cmd_commit_flush(dev_priv, submit_size);
  278. vcotbl->scrubbed = true;
  279. /* Trigger a create() on next validate. */
  280. res->id = -1;
  281. return 0;
  282. }
  283. /**
  284. * vmw_cotable_unbind - Cotable resource unbind callback
  285. *
  286. * @res: Pointer to the cotable resource.
  287. * @readback: Whether to read back cotable data to the backup buffer.
  288. * @val_buf: Pointer to a struct ttm_validate_buffer prepared by the caller
  289. * for convenience / fencing.
  290. *
  291. * Unbinds the cotable from the device and fences the backup buffer.
  292. */
  293. static int vmw_cotable_unbind(struct vmw_resource *res,
  294. bool readback,
  295. struct ttm_validate_buffer *val_buf)
  296. {
  297. struct vmw_cotable *vcotbl = vmw_cotable(res);
  298. struct vmw_private *dev_priv = res->dev_priv;
  299. struct ttm_buffer_object *bo = val_buf->bo;
  300. struct vmw_fence_obj *fence;
  301. if (!vmw_resource_mob_attached(res))
  302. return 0;
  303. WARN_ON_ONCE(bo->resource->mem_type != VMW_PL_MOB);
  304. dma_resv_assert_held(bo->base.resv);
  305. mutex_lock(&dev_priv->binding_mutex);
  306. if (!vcotbl->scrubbed)
  307. vmw_dx_context_scrub_cotables(vcotbl->ctx, readback);
  308. mutex_unlock(&dev_priv->binding_mutex);
  309. (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
  310. vmw_bo_fence_single(bo, fence);
  311. if (likely(fence != NULL))
  312. vmw_fence_obj_unreference(&fence);
  313. return 0;
  314. }
  315. /**
  316. * vmw_cotable_readback - Read back a cotable without unbinding.
  317. *
  318. * @res: The cotable resource.
  319. *
  320. * Reads back a cotable to its backing mob without scrubbing the MOB from
  321. * the cotable. The MOB is fenced for subsequent CPU access.
  322. */
  323. static int vmw_cotable_readback(struct vmw_resource *res)
  324. {
  325. struct vmw_cotable *vcotbl = vmw_cotable(res);
  326. struct vmw_private *dev_priv = res->dev_priv;
  327. struct {
  328. SVGA3dCmdHeader header;
  329. SVGA3dCmdDXReadbackCOTable body;
  330. } *cmd;
  331. struct vmw_fence_obj *fence;
  332. if (!vcotbl->scrubbed) {
  333. cmd = VMW_CMD_RESERVE(dev_priv, sizeof(*cmd));
  334. if (!cmd)
  335. return -ENOMEM;
  336. cmd->header.id = SVGA_3D_CMD_DX_READBACK_COTABLE;
  337. cmd->header.size = sizeof(cmd->body);
  338. cmd->body.cid = vcotbl->ctx->id;
  339. cmd->body.type = vcotbl->type;
  340. vcotbl->size_read_back = res->guest_memory_size;
  341. vmw_cmd_commit(dev_priv, sizeof(*cmd));
  342. }
  343. (void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
  344. vmw_bo_fence_single(&res->guest_memory_bo->tbo, fence);
  345. vmw_fence_obj_unreference(&fence);
  346. return 0;
  347. }
  348. /**
  349. * vmw_cotable_resize - Resize a cotable.
  350. *
  351. * @res: The cotable resource.
  352. * @new_size: The new size.
  353. *
  354. * Resizes a cotable and binds the new backup buffer.
  355. * On failure the cotable is left intact.
  356. * Important! This function may not fail once the MOB switch has been
  357. * committed to hardware. That would put the device context in an
  358. * invalid state which we can't currently recover from.
  359. */
  360. static int vmw_cotable_resize(struct vmw_resource *res, size_t new_size)
  361. {
  362. struct ttm_operation_ctx ctx = { false, false };
  363. struct vmw_private *dev_priv = res->dev_priv;
  364. struct vmw_cotable *vcotbl = vmw_cotable(res);
  365. struct vmw_bo *buf, *old_buf = res->guest_memory_bo;
  366. struct ttm_buffer_object *bo, *old_bo = &res->guest_memory_bo->tbo;
  367. size_t old_size = res->guest_memory_size;
  368. size_t old_size_read_back = vcotbl->size_read_back;
  369. size_t cur_size_read_back;
  370. struct ttm_bo_kmap_obj old_map, new_map;
  371. int ret;
  372. size_t i;
  373. struct vmw_bo_params bo_params = {
  374. .domain = VMW_BO_DOMAIN_MOB,
  375. .busy_domain = VMW_BO_DOMAIN_MOB,
  376. .bo_type = ttm_bo_type_device,
  377. .size = new_size,
  378. .pin = true
  379. };
  380. MKS_STAT_TIME_DECL(MKSSTAT_KERN_COTABLE_RESIZE);
  381. MKS_STAT_TIME_PUSH(MKSSTAT_KERN_COTABLE_RESIZE);
  382. ret = vmw_cotable_readback(res);
  383. if (ret)
  384. goto out_done;
  385. cur_size_read_back = vcotbl->size_read_back;
  386. vcotbl->size_read_back = old_size_read_back;
  387. /*
  388. * While device is processing, Allocate and reserve a buffer object
  389. * for the new COTable. Initially pin the buffer object to make sure
  390. * we can use tryreserve without failure.
  391. */
  392. ret = vmw_bo_create(dev_priv, &bo_params, &buf);
  393. if (ret) {
  394. DRM_ERROR("Failed initializing new cotable MOB.\n");
  395. goto out_done;
  396. }
  397. bo = &buf->tbo;
  398. WARN_ON_ONCE(ttm_bo_reserve(bo, false, true, NULL));
  399. ret = ttm_bo_wait(old_bo, false, false);
  400. if (unlikely(ret != 0)) {
  401. DRM_ERROR("Failed waiting for cotable unbind.\n");
  402. goto out_wait;
  403. }
  404. /*
  405. * Do a page by page copy of COTables. This eliminates slow vmap()s.
  406. * This should really be a TTM utility.
  407. */
  408. for (i = 0; i < PFN_UP(old_bo->resource->size); ++i) {
  409. bool dummy;
  410. ret = ttm_bo_kmap(old_bo, i, 1, &old_map);
  411. if (unlikely(ret != 0)) {
  412. DRM_ERROR("Failed mapping old COTable on resize.\n");
  413. goto out_wait;
  414. }
  415. ret = ttm_bo_kmap(bo, i, 1, &new_map);
  416. if (unlikely(ret != 0)) {
  417. DRM_ERROR("Failed mapping new COTable on resize.\n");
  418. goto out_map_new;
  419. }
  420. memcpy(ttm_kmap_obj_virtual(&new_map, &dummy),
  421. ttm_kmap_obj_virtual(&old_map, &dummy),
  422. PAGE_SIZE);
  423. ttm_bo_kunmap(&new_map);
  424. ttm_bo_kunmap(&old_map);
  425. }
  426. /* Unpin new buffer, and switch backup buffers. */
  427. vmw_bo_placement_set(buf,
  428. VMW_BO_DOMAIN_MOB,
  429. VMW_BO_DOMAIN_MOB);
  430. ret = ttm_bo_validate(bo, &buf->placement, &ctx);
  431. if (unlikely(ret != 0)) {
  432. DRM_ERROR("Failed validating new COTable backup buffer.\n");
  433. goto out_wait;
  434. }
  435. vmw_resource_mob_detach(res);
  436. res->guest_memory_bo = buf;
  437. res->guest_memory_size = new_size;
  438. vcotbl->size_read_back = cur_size_read_back;
  439. /*
  440. * Now tell the device to switch. If this fails, then we need to
  441. * revert the full resize.
  442. */
  443. ret = vmw_cotable_unscrub(res);
  444. if (ret) {
  445. DRM_ERROR("Failed switching COTable backup buffer.\n");
  446. res->guest_memory_bo = old_buf;
  447. res->guest_memory_size = old_size;
  448. vcotbl->size_read_back = old_size_read_back;
  449. vmw_resource_mob_attach(res);
  450. goto out_wait;
  451. }
  452. vmw_resource_mob_attach(res);
  453. /* Let go of the old mob. */
  454. vmw_user_bo_unref(&old_buf);
  455. res->id = vcotbl->type;
  456. ret = dma_resv_reserve_fences(bo->base.resv, 1);
  457. if (unlikely(ret))
  458. goto out_wait;
  459. /* Release the pin acquired in vmw_bo_create */
  460. ttm_bo_unpin(bo);
  461. MKS_STAT_TIME_POP(MKSSTAT_KERN_COTABLE_RESIZE);
  462. return 0;
  463. out_map_new:
  464. ttm_bo_kunmap(&old_map);
  465. out_wait:
  466. ttm_bo_unpin(bo);
  467. ttm_bo_unreserve(bo);
  468. vmw_user_bo_unref(&buf);
  469. out_done:
  470. MKS_STAT_TIME_POP(MKSSTAT_KERN_COTABLE_RESIZE);
  471. return ret;
  472. }
  473. /**
  474. * vmw_cotable_create - Cotable resource create callback
  475. *
  476. * @res: Pointer to a cotable resource.
  477. *
  478. * There is no separate create command for cotables, so this callback, which
  479. * is called before bind() in the validation sequence is instead used for two
  480. * things.
  481. * 1) Unscrub the cotable if it is scrubbed and still attached to a backup
  482. * buffer.
  483. * 2) Resize the cotable if needed.
  484. */
  485. static int vmw_cotable_create(struct vmw_resource *res)
  486. {
  487. struct vmw_cotable *vcotbl = vmw_cotable(res);
  488. size_t new_size = res->guest_memory_size;
  489. size_t needed_size;
  490. int ret;
  491. /* Check whether we need to resize the cotable */
  492. needed_size = (vcotbl->seen_entries + 1) * co_info[vcotbl->type].size;
  493. while (needed_size > new_size)
  494. new_size *= 2;
  495. if (likely(new_size <= res->guest_memory_size)) {
  496. if (vcotbl->scrubbed && vmw_resource_mob_attached(res)) {
  497. ret = vmw_cotable_unscrub(res);
  498. if (ret)
  499. return ret;
  500. }
  501. res->id = vcotbl->type;
  502. return 0;
  503. }
  504. return vmw_cotable_resize(res, new_size);
  505. }
  506. /**
  507. * vmw_hw_cotable_destroy - Cotable hw_destroy callback
  508. *
  509. * @res: Pointer to a cotable resource.
  510. *
  511. * The final (part of resource destruction) destroy callback.
  512. */
  513. static void vmw_hw_cotable_destroy(struct vmw_resource *res)
  514. {
  515. (void) vmw_cotable_destroy(res);
  516. }
  517. /**
  518. * vmw_cotable_free - Cotable resource destructor
  519. *
  520. * @res: Pointer to a cotable resource.
  521. */
  522. static void vmw_cotable_free(struct vmw_resource *res)
  523. {
  524. kfree(res);
  525. }
  526. /**
  527. * vmw_cotable_alloc - Create a cotable resource
  528. *
  529. * @dev_priv: Pointer to a device private struct.
  530. * @ctx: Pointer to the context resource.
  531. * The cotable resource will not add a refcount.
  532. * @type: The cotable type.
  533. */
  534. struct vmw_resource *vmw_cotable_alloc(struct vmw_private *dev_priv,
  535. struct vmw_resource *ctx,
  536. u32 type)
  537. {
  538. struct vmw_cotable *vcotbl;
  539. int ret;
  540. u32 num_entries;
  541. vcotbl = kzalloc_obj(*vcotbl);
  542. if (unlikely(!vcotbl)) {
  543. ret = -ENOMEM;
  544. goto out_no_alloc;
  545. }
  546. ret = vmw_resource_init(dev_priv, &vcotbl->res, true,
  547. vmw_cotable_free, &vmw_cotable_func);
  548. if (unlikely(ret != 0))
  549. goto out_no_init;
  550. INIT_LIST_HEAD(&vcotbl->resource_list);
  551. vcotbl->res.id = type;
  552. vcotbl->res.guest_memory_size = PAGE_SIZE;
  553. num_entries = PAGE_SIZE / co_info[type].size;
  554. if (num_entries < co_info[type].min_initial_entries) {
  555. vcotbl->res.guest_memory_size = co_info[type].min_initial_entries *
  556. co_info[type].size;
  557. vcotbl->res.guest_memory_size = PFN_ALIGN(vcotbl->res.guest_memory_size);
  558. }
  559. vcotbl->scrubbed = true;
  560. vcotbl->seen_entries = -1;
  561. vcotbl->type = type;
  562. vcotbl->ctx = ctx;
  563. vcotbl->res.hw_destroy = vmw_hw_cotable_destroy;
  564. return &vcotbl->res;
  565. out_no_init:
  566. kfree(vcotbl);
  567. out_no_alloc:
  568. return ERR_PTR(ret);
  569. }
  570. /**
  571. * vmw_cotable_notify - Notify the cotable about an item creation
  572. *
  573. * @res: Pointer to a cotable resource.
  574. * @id: Item id.
  575. */
  576. int vmw_cotable_notify(struct vmw_resource *res, int id)
  577. {
  578. struct vmw_cotable *vcotbl = vmw_cotable(res);
  579. if (id < 0 || id >= SVGA_COTABLE_MAX_IDS) {
  580. DRM_ERROR("Illegal COTable id. Type is %u. Id is %d\n",
  581. (unsigned) vcotbl->type, id);
  582. return -EINVAL;
  583. }
  584. if (vcotbl->seen_entries < id) {
  585. /* Trigger a call to create() on next validate */
  586. res->id = -1;
  587. vcotbl->seen_entries = id;
  588. }
  589. return 0;
  590. }
  591. /**
  592. * vmw_cotable_add_resource - add a view to the cotable's list of active views.
  593. *
  594. * @res: pointer struct vmw_resource representing the cotable.
  595. * @head: pointer to the struct list_head member of the resource, dedicated
  596. * to the cotable active resource list.
  597. */
  598. void vmw_cotable_add_resource(struct vmw_resource *res, struct list_head *head)
  599. {
  600. struct vmw_cotable *vcotbl =
  601. container_of(res, struct vmw_cotable, res);
  602. list_add_tail(head, &vcotbl->resource_list);
  603. }