Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright © 2014-2015 VMware, Inc., Palo Alto, CA., USA
  4.  * All Rights Reserved.
  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. #include "vmwgfx_drv.h"
  29. #include "vmwgfx_resource_priv.h"
  30.  
  31. #define VMW_CMDBUF_RES_MAN_HT_ORDER 12
  32.  
  33. /**
  34.  * struct vmw_cmdbuf_res - Command buffer managed resource entry.
  35.  *
  36.  * @res: Refcounted pointer to a struct vmw_resource.
  37.  * @hash: Hash entry for the manager hash table.
  38.  * @head: List head used either by the staging list or the manager list
  39.  * of commited resources.
  40.  * @state: Staging state of this resource entry.
  41.  * @man: Pointer to a resource manager for this entry.
  42.  */
  43. struct vmw_cmdbuf_res {
  44.         struct vmw_resource *res;
  45.         struct drm_hash_item hash;
  46.         struct list_head head;
  47.         enum vmw_cmdbuf_res_state state;
  48.         struct vmw_cmdbuf_res_manager *man;
  49. };
  50.  
  51. /**
  52.  * struct vmw_cmdbuf_res_manager - Command buffer resource manager.
  53.  *
  54.  * @resources: Hash table containing staged and commited command buffer
  55.  * resources
  56.  * @list: List of commited command buffer resources.
  57.  * @dev_priv: Pointer to a device private structure.
  58.  *
  59.  * @resources and @list are protected by the cmdbuf mutex for now.
  60.  */
  61. struct vmw_cmdbuf_res_manager {
  62.         struct drm_open_hash resources;
  63.         struct list_head list;
  64.         struct vmw_private *dev_priv;
  65. };
  66.  
  67.  
  68. /**
  69.  * vmw_cmdbuf_res_lookup - Look up a command buffer resource
  70.  *
  71.  * @man: Pointer to the command buffer resource manager
  72.  * @resource_type: The resource type, that combined with the user key
  73.  * identifies the resource.
  74.  * @user_key: The user key.
  75.  *
  76.  * Returns a valid refcounted struct vmw_resource pointer on success,
  77.  * an error pointer on failure.
  78.  */
  79. struct vmw_resource *
  80. vmw_cmdbuf_res_lookup(struct vmw_cmdbuf_res_manager *man,
  81.                       enum vmw_cmdbuf_res_type res_type,
  82.                       u32 user_key)
  83. {
  84.         struct drm_hash_item *hash;
  85.         int ret;
  86.         unsigned long key = user_key | (res_type << 24);
  87.  
  88.         ret = drm_ht_find_item(&man->resources, key, &hash);
  89.         if (unlikely(ret != 0))
  90.                 return ERR_PTR(ret);
  91.  
  92.         return vmw_resource_reference
  93.                 (drm_hash_entry(hash, struct vmw_cmdbuf_res, hash)->res);
  94. }
  95.  
  96. /**
  97.  * vmw_cmdbuf_res_free - Free a command buffer resource.
  98.  *
  99.  * @man: Pointer to the command buffer resource manager
  100.  * @entry: Pointer to a struct vmw_cmdbuf_res.
  101.  *
  102.  * Frees a struct vmw_cmdbuf_res entry and drops its reference to the
  103.  * struct vmw_resource.
  104.  */
  105. static void vmw_cmdbuf_res_free(struct vmw_cmdbuf_res_manager *man,
  106.                                 struct vmw_cmdbuf_res *entry)
  107. {
  108.         list_del(&entry->head);
  109.         WARN_ON(drm_ht_remove_item(&man->resources, &entry->hash));
  110.         vmw_resource_unreference(&entry->res);
  111.         kfree(entry);
  112. }
  113.  
  114. /**
  115.  * vmw_cmdbuf_res_commit - Commit a list of command buffer resource actions
  116.  *
  117.  * @list: Caller's list of command buffer resource actions.
  118.  *
  119.  * This function commits a list of command buffer resource
  120.  * additions or removals.
  121.  * It is typically called when the execbuf ioctl call triggering these
  122.  * actions has commited the fifo contents to the device.
  123.  */
  124. void vmw_cmdbuf_res_commit(struct list_head *list)
  125. {
  126.         struct vmw_cmdbuf_res *entry, *next;
  127.  
  128.         list_for_each_entry_safe(entry, next, list, head) {
  129.                 list_del(&entry->head);
  130.                 if (entry->res->func->commit_notify)
  131.                         entry->res->func->commit_notify(entry->res,
  132.                                                         entry->state);
  133.                 switch (entry->state) {
  134.                 case VMW_CMDBUF_RES_ADD:
  135.                         entry->state = VMW_CMDBUF_RES_COMMITTED;
  136.                         list_add_tail(&entry->head, &entry->man->list);
  137.                         break;
  138.                 case VMW_CMDBUF_RES_DEL:
  139.                         vmw_resource_unreference(&entry->res);
  140.                         kfree(entry);
  141.                         break;
  142.                 default:
  143.                         BUG();
  144.                         break;
  145.                 }
  146.         }
  147. }
  148.  
  149. /**
  150.  * vmw_cmdbuf_res_revert - Revert a list of command buffer resource actions
  151.  *
  152.  * @man: Pointer to the command buffer resource manager
  153.  * @list: Caller's list of command buffer resource action
  154.  *
  155.  * This function reverts a list of command buffer resource
  156.  * additions or removals.
  157.  * It is typically called when the execbuf ioctl call triggering these
  158.  * actions failed for some reason, and the command stream was never
  159.  * submitted.
  160.  */
  161. void vmw_cmdbuf_res_revert(struct list_head *list)
  162. {
  163.         struct vmw_cmdbuf_res *entry, *next;
  164.         int ret;
  165.  
  166.         list_for_each_entry_safe(entry, next, list, head) {
  167.                 switch (entry->state) {
  168.                 case VMW_CMDBUF_RES_ADD:
  169.                         vmw_cmdbuf_res_free(entry->man, entry);
  170.                         break;
  171.                 case VMW_CMDBUF_RES_DEL:
  172.                         ret = drm_ht_insert_item(&entry->man->resources,
  173.                                                  &entry->hash);
  174.                         list_del(&entry->head);
  175.                         list_add_tail(&entry->head, &entry->man->list);
  176.                         entry->state = VMW_CMDBUF_RES_COMMITTED;
  177.                         break;
  178.                 default:
  179.                         BUG();
  180.                         break;
  181.                 }
  182.         }
  183. }
  184.  
  185. /**
  186.  * vmw_cmdbuf_res_add - Stage a command buffer managed resource for addition.
  187.  *
  188.  * @man: Pointer to the command buffer resource manager.
  189.  * @res_type: The resource type.
  190.  * @user_key: The user-space id of the resource.
  191.  * @res: Valid (refcount != 0) pointer to a struct vmw_resource.
  192.  * @list: The staging list.
  193.  *
  194.  * This function allocates a struct vmw_cmdbuf_res entry and adds the
  195.  * resource to the hash table of the manager identified by @man. The
  196.  * entry is then put on the staging list identified by @list.
  197.  */
  198. int vmw_cmdbuf_res_add(struct vmw_cmdbuf_res_manager *man,
  199.                        enum vmw_cmdbuf_res_type res_type,
  200.                        u32 user_key,
  201.                        struct vmw_resource *res,
  202.                        struct list_head *list)
  203. {
  204.         struct vmw_cmdbuf_res *cres;
  205.         int ret;
  206.  
  207.         cres = kzalloc(sizeof(*cres), GFP_KERNEL);
  208.         if (unlikely(cres == NULL))
  209.                 return -ENOMEM;
  210.  
  211.         cres->hash.key = user_key | (res_type << 24);
  212.         ret = drm_ht_insert_item(&man->resources, &cres->hash);
  213.         if (unlikely(ret != 0))
  214.                 goto out_invalid_key;
  215.  
  216.         cres->state = VMW_CMDBUF_RES_ADD;
  217.         cres->res = vmw_resource_reference(res);
  218.         cres->man = man;
  219.         list_add_tail(&cres->head, list);
  220.  
  221. out_invalid_key:
  222.         return ret;
  223. }
  224.  
  225. /**
  226.  * vmw_cmdbuf_res_remove - Stage a command buffer managed resource for removal.
  227.  *
  228.  * @man: Pointer to the command buffer resource manager.
  229.  * @res_type: The resource type.
  230.  * @user_key: The user-space id of the resource.
  231.  * @list: The staging list.
  232.  * @res_p: If the resource is in an already committed state, points to the
  233.  * struct vmw_resource on successful return. The pointer will be
  234.  * non ref-counted.
  235.  *
  236.  * This function looks up the struct vmw_cmdbuf_res entry from the manager
  237.  * hash table and, if it exists, removes it. Depending on its current staging
  238.  * state it then either removes the entry from the staging list or adds it
  239.  * to it with a staging state of removal.
  240.  */
  241. int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man,
  242.                           enum vmw_cmdbuf_res_type res_type,
  243.                           u32 user_key,
  244.                           struct list_head *list,
  245.                           struct vmw_resource **res_p)
  246. {
  247.         struct vmw_cmdbuf_res *entry;
  248.         struct drm_hash_item *hash;
  249.         int ret;
  250.  
  251.         ret = drm_ht_find_item(&man->resources, user_key | (res_type << 24),
  252.                                &hash);
  253.         if (likely(ret != 0))
  254.                 return -EINVAL;
  255.  
  256.         entry = drm_hash_entry(hash, struct vmw_cmdbuf_res, hash);
  257.  
  258.         switch (entry->state) {
  259.         case VMW_CMDBUF_RES_ADD:
  260.                 vmw_cmdbuf_res_free(man, entry);
  261.                 *res_p = NULL;
  262.                 break;
  263.         case VMW_CMDBUF_RES_COMMITTED:
  264.                 (void) drm_ht_remove_item(&man->resources, &entry->hash);
  265.                 list_del(&entry->head);
  266.                 entry->state = VMW_CMDBUF_RES_DEL;
  267.                 list_add_tail(&entry->head, list);
  268.                 *res_p = entry->res;
  269.                 break;
  270.         default:
  271.                 BUG();
  272.                 break;
  273.         }
  274.  
  275.         return 0;
  276. }
  277.  
  278. /**
  279.  * vmw_cmdbuf_res_man_create - Allocate a command buffer managed resource
  280.  * manager.
  281.  *
  282.  * @dev_priv: Pointer to a struct vmw_private
  283.  *
  284.  * Allocates and initializes a command buffer managed resource manager. Returns
  285.  * an error pointer on failure.
  286.  */
  287. struct vmw_cmdbuf_res_manager *
  288. vmw_cmdbuf_res_man_create(struct vmw_private *dev_priv)
  289. {
  290.         struct vmw_cmdbuf_res_manager *man;
  291.         int ret;
  292.  
  293.         man = kzalloc(sizeof(*man), GFP_KERNEL);
  294.         if (man == NULL)
  295.                 return ERR_PTR(-ENOMEM);
  296.  
  297.         man->dev_priv = dev_priv;
  298.         INIT_LIST_HEAD(&man->list);
  299.         ret = drm_ht_create(&man->resources, VMW_CMDBUF_RES_MAN_HT_ORDER);
  300.         if (ret == 0)
  301.                 return man;
  302.  
  303.         kfree(man);
  304.         return ERR_PTR(ret);
  305. }
  306.  
  307. /**
  308.  * vmw_cmdbuf_res_man_destroy - Destroy a command buffer managed resource
  309.  * manager.
  310.  *
  311.  * @man: Pointer to the  manager to destroy.
  312.  *
  313.  * This function destroys a command buffer managed resource manager and
  314.  * unreferences / frees all command buffer managed resources and -entries
  315.  * associated with it.
  316.  */
  317. void vmw_cmdbuf_res_man_destroy(struct vmw_cmdbuf_res_manager *man)
  318. {
  319.         struct vmw_cmdbuf_res *entry, *next;
  320.  
  321.         list_for_each_entry_safe(entry, next, &man->list, head)
  322.                 vmw_cmdbuf_res_free(man, entry);
  323.  
  324.         kfree(man);
  325. }
  326.  
  327. /**
  328.  *
  329.  * vmw_cmdbuf_res_man_size - Return the size of a command buffer managed
  330.  * resource manager
  331.  *
  332.  * Returns the approximate allocation size of a command buffer managed
  333.  * resource manager.
  334.  */
  335. size_t vmw_cmdbuf_res_man_size(void)
  336. {
  337.         static size_t res_man_size;
  338.  
  339.         if (unlikely(res_man_size == 0))
  340.                 res_man_size =
  341.                         ttm_round_pot(sizeof(struct vmw_cmdbuf_res_manager)) +
  342.                         ttm_round_pot(sizeof(struct hlist_head) <<
  343.                                       VMW_CMDBUF_RES_MAN_HT_ORDER);
  344.  
  345.         return res_man_size;
  346. }
  347.