linux/drivers/gpu/drm/vmwgfx/vmwgfx_cmdbuf_res.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0 OR MIT
   2/**************************************************************************
   3 *
   4 * Copyright 2014-2015 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#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 drm_hash_entry(hash, struct vmw_cmdbuf_res, hash)->res;
  93}
  94
  95/**
  96 * vmw_cmdbuf_res_free - Free a command buffer resource.
  97 *
  98 * @man: Pointer to the command buffer resource manager
  99 * @entry: Pointer to a struct vmw_cmdbuf_res.
 100 *
 101 * Frees a struct vmw_cmdbuf_res entry and drops its reference to the
 102 * struct vmw_resource.
 103 */
 104static void vmw_cmdbuf_res_free(struct vmw_cmdbuf_res_manager *man,
 105                                struct vmw_cmdbuf_res *entry)
 106{
 107        list_del(&entry->head);
 108        WARN_ON(drm_ht_remove_item(&man->resources, &entry->hash));
 109        vmw_resource_unreference(&entry->res);
 110        kfree(entry);
 111}
 112
 113/**
 114 * vmw_cmdbuf_res_commit - Commit a list of command buffer resource actions
 115 *
 116 * @list: Caller's list of command buffer resource actions.
 117 *
 118 * This function commits a list of command buffer resource
 119 * additions or removals.
 120 * It is typically called when the execbuf ioctl call triggering these
 121 * actions has commited the fifo contents to the device.
 122 */
 123void vmw_cmdbuf_res_commit(struct list_head *list)
 124{
 125        struct vmw_cmdbuf_res *entry, *next;
 126
 127        list_for_each_entry_safe(entry, next, list, head) {
 128                list_del(&entry->head);
 129                if (entry->res->func->commit_notify)
 130                        entry->res->func->commit_notify(entry->res,
 131                                                        entry->state);
 132                switch (entry->state) {
 133                case VMW_CMDBUF_RES_ADD:
 134                        entry->state = VMW_CMDBUF_RES_COMMITTED;
 135                        list_add_tail(&entry->head, &entry->man->list);
 136                        break;
 137                case VMW_CMDBUF_RES_DEL:
 138                        vmw_resource_unreference(&entry->res);
 139                        kfree(entry);
 140                        break;
 141                default:
 142                        BUG();
 143                        break;
 144                }
 145        }
 146}
 147
 148/**
 149 * vmw_cmdbuf_res_revert - Revert a list of command buffer resource actions
 150 *
 151 * @man: Pointer to the command buffer resource manager
 152 * @list: Caller's list of command buffer resource action
 153 *
 154 * This function reverts a list of command buffer resource
 155 * additions or removals.
 156 * It is typically called when the execbuf ioctl call triggering these
 157 * actions failed for some reason, and the command stream was never
 158 * submitted.
 159 */
 160void vmw_cmdbuf_res_revert(struct list_head *list)
 161{
 162        struct vmw_cmdbuf_res *entry, *next;
 163        int ret;
 164
 165        list_for_each_entry_safe(entry, next, list, head) {
 166                switch (entry->state) {
 167                case VMW_CMDBUF_RES_ADD:
 168                        vmw_cmdbuf_res_free(entry->man, entry);
 169                        break;
 170                case VMW_CMDBUF_RES_DEL:
 171                        ret = drm_ht_insert_item(&entry->man->resources,
 172                                                 &entry->hash);
 173                        list_del(&entry->head);
 174                        list_add_tail(&entry->head, &entry->man->list);
 175                        entry->state = VMW_CMDBUF_RES_COMMITTED;
 176                        break;
 177                default:
 178                        BUG();
 179                        break;
 180                }
 181        }
 182}
 183
 184/**
 185 * vmw_cmdbuf_res_add - Stage a command buffer managed resource for addition.
 186 *
 187 * @man: Pointer to the command buffer resource manager.
 188 * @res_type: The resource type.
 189 * @user_key: The user-space id of the resource.
 190 * @res: Valid (refcount != 0) pointer to a struct vmw_resource.
 191 * @list: The staging list.
 192 *
 193 * This function allocates a struct vmw_cmdbuf_res entry and adds the
 194 * resource to the hash table of the manager identified by @man. The
 195 * entry is then put on the staging list identified by @list.
 196 */
 197int vmw_cmdbuf_res_add(struct vmw_cmdbuf_res_manager *man,
 198                       enum vmw_cmdbuf_res_type res_type,
 199                       u32 user_key,
 200                       struct vmw_resource *res,
 201                       struct list_head *list)
 202{
 203        struct vmw_cmdbuf_res *cres;
 204        int ret;
 205
 206        cres = kzalloc(sizeof(*cres), GFP_KERNEL);
 207        if (unlikely(!cres))
 208                return -ENOMEM;
 209
 210        cres->hash.key = user_key | (res_type << 24);
 211        ret = drm_ht_insert_item(&man->resources, &cres->hash);
 212        if (unlikely(ret != 0)) {
 213                kfree(cres);
 214                goto out_invalid_key;
 215        }
 216
 217        cres->state = VMW_CMDBUF_RES_ADD;
 218        cres->res = vmw_resource_reference(res);
 219        cres->man = man;
 220        list_add_tail(&cres->head, list);
 221
 222out_invalid_key:
 223        return ret;
 224}
 225
 226/**
 227 * vmw_cmdbuf_res_remove - Stage a command buffer managed resource for removal.
 228 *
 229 * @man: Pointer to the command buffer resource manager.
 230 * @res_type: The resource type.
 231 * @user_key: The user-space id of the resource.
 232 * @list: The staging list.
 233 * @res_p: If the resource is in an already committed state, points to the
 234 * struct vmw_resource on successful return. The pointer will be
 235 * non ref-counted.
 236 *
 237 * This function looks up the struct vmw_cmdbuf_res entry from the manager
 238 * hash table and, if it exists, removes it. Depending on its current staging
 239 * state it then either removes the entry from the staging list or adds it
 240 * to it with a staging state of removal.
 241 */
 242int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man,
 243                          enum vmw_cmdbuf_res_type res_type,
 244                          u32 user_key,
 245                          struct list_head *list,
 246                          struct vmw_resource **res_p)
 247{
 248        struct vmw_cmdbuf_res *entry;
 249        struct drm_hash_item *hash;
 250        int ret;
 251
 252        ret = drm_ht_find_item(&man->resources, user_key | (res_type << 24),
 253                               &hash);
 254        if (likely(ret != 0))
 255                return -EINVAL;
 256
 257        entry = drm_hash_entry(hash, struct vmw_cmdbuf_res, hash);
 258
 259        switch (entry->state) {
 260        case VMW_CMDBUF_RES_ADD:
 261                vmw_cmdbuf_res_free(man, entry);
 262                *res_p = NULL;
 263                break;
 264        case VMW_CMDBUF_RES_COMMITTED:
 265                (void) drm_ht_remove_item(&man->resources, &entry->hash);
 266                list_del(&entry->head);
 267                entry->state = VMW_CMDBUF_RES_DEL;
 268                list_add_tail(&entry->head, list);
 269                *res_p = entry->res;
 270                break;
 271        default:
 272                BUG();
 273                break;
 274        }
 275
 276        return 0;
 277}
 278
 279/**
 280 * vmw_cmdbuf_res_man_create - Allocate a command buffer managed resource
 281 * manager.
 282 *
 283 * @dev_priv: Pointer to a struct vmw_private
 284 *
 285 * Allocates and initializes a command buffer managed resource manager. Returns
 286 * an error pointer on failure.
 287 */
 288struct vmw_cmdbuf_res_manager *
 289vmw_cmdbuf_res_man_create(struct vmw_private *dev_priv)
 290{
 291        struct vmw_cmdbuf_res_manager *man;
 292        int ret;
 293
 294        man = kzalloc(sizeof(*man), GFP_KERNEL);
 295        if (!man)
 296                return ERR_PTR(-ENOMEM);
 297
 298        man->dev_priv = dev_priv;
 299        INIT_LIST_HEAD(&man->list);
 300        ret = drm_ht_create(&man->resources, VMW_CMDBUF_RES_MAN_HT_ORDER);
 301        if (ret == 0)
 302                return man;
 303
 304        kfree(man);
 305        return ERR_PTR(ret);
 306}
 307
 308/**
 309 * vmw_cmdbuf_res_man_destroy - Destroy a command buffer managed resource
 310 * manager.
 311 *
 312 * @man: Pointer to the  manager to destroy.
 313 *
 314 * This function destroys a command buffer managed resource manager and
 315 * unreferences / frees all command buffer managed resources and -entries
 316 * associated with it.
 317 */
 318void vmw_cmdbuf_res_man_destroy(struct vmw_cmdbuf_res_manager *man)
 319{
 320        struct vmw_cmdbuf_res *entry, *next;
 321
 322        list_for_each_entry_safe(entry, next, &man->list, head)
 323                vmw_cmdbuf_res_free(man, entry);
 324
 325        drm_ht_remove(&man->resources);
 326        kfree(man);
 327}
 328
 329/**
 330 *
 331 * vmw_cmdbuf_res_man_size - Return the size of a command buffer managed
 332 * resource manager
 333 *
 334 * Returns the approximate allocation size of a command buffer managed
 335 * resource manager.
 336 */
 337size_t vmw_cmdbuf_res_man_size(void)
 338{
 339        static size_t res_man_size;
 340
 341        if (unlikely(res_man_size == 0))
 342                res_man_size =
 343                        ttm_round_pot(sizeof(struct vmw_cmdbuf_res_manager)) +
 344                        ttm_round_pot(sizeof(struct hlist_head) <<
 345                                      VMW_CMDBUF_RES_MAN_HT_ORDER);
 346
 347        return res_man_size;
 348}
 349