linux/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c
<<
>>
Prefs
   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 */
  43struct 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 */
  61struct 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 */
  79struct vmw_resource *
  80vmw_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 */
 105static 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 */
 124void 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 */
 161void 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 */
 198int 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
 221out_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 */
 241int 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 */
 287struct vmw_cmdbuf_res_manager *
 288vmw_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 */
 317void 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 */
 335size_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