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                goto out_invalid_key;
 214
 215        cres->state = VMW_CMDBUF_RES_ADD;
 216        cres->res = vmw_resource_reference(res);
 217        cres->man = man;
 218        list_add_tail(&cres->head, list);
 219
 220out_invalid_key:
 221        return ret;
 222}
 223
 224/**
 225 * vmw_cmdbuf_res_remove - Stage a command buffer managed resource for removal.
 226 *
 227 * @man: Pointer to the command buffer resource manager.
 228 * @res_type: The resource type.
 229 * @user_key: The user-space id of the resource.
 230 * @list: The staging list.
 231 * @res_p: If the resource is in an already committed state, points to the
 232 * struct vmw_resource on successful return. The pointer will be
 233 * non ref-counted.
 234 *
 235 * This function looks up the struct vmw_cmdbuf_res entry from the manager
 236 * hash table and, if it exists, removes it. Depending on its current staging
 237 * state it then either removes the entry from the staging list or adds it
 238 * to it with a staging state of removal.
 239 */
 240int vmw_cmdbuf_res_remove(struct vmw_cmdbuf_res_manager *man,
 241                          enum vmw_cmdbuf_res_type res_type,
 242                          u32 user_key,
 243                          struct list_head *list,
 244                          struct vmw_resource **res_p)
 245{
 246        struct vmw_cmdbuf_res *entry;
 247        struct drm_hash_item *hash;
 248        int ret;
 249
 250        ret = drm_ht_find_item(&man->resources, user_key | (res_type << 24),
 251                               &hash);
 252        if (likely(ret != 0))
 253                return -EINVAL;
 254
 255        entry = drm_hash_entry(hash, struct vmw_cmdbuf_res, hash);
 256
 257        switch (entry->state) {
 258        case VMW_CMDBUF_RES_ADD:
 259                vmw_cmdbuf_res_free(man, entry);
 260                *res_p = NULL;
 261                break;
 262        case VMW_CMDBUF_RES_COMMITTED:
 263                (void) drm_ht_remove_item(&man->resources, &entry->hash);
 264                list_del(&entry->head);
 265                entry->state = VMW_CMDBUF_RES_DEL;
 266                list_add_tail(&entry->head, list);
 267                *res_p = entry->res;
 268                break;
 269        default:
 270                BUG();
 271                break;
 272        }
 273
 274        return 0;
 275}
 276
 277/**
 278 * vmw_cmdbuf_res_man_create - Allocate a command buffer managed resource
 279 * manager.
 280 *
 281 * @dev_priv: Pointer to a struct vmw_private
 282 *
 283 * Allocates and initializes a command buffer managed resource manager. Returns
 284 * an error pointer on failure.
 285 */
 286struct vmw_cmdbuf_res_manager *
 287vmw_cmdbuf_res_man_create(struct vmw_private *dev_priv)
 288{
 289        struct vmw_cmdbuf_res_manager *man;
 290        int ret;
 291
 292        man = kzalloc(sizeof(*man), GFP_KERNEL);
 293        if (!man)
 294                return ERR_PTR(-ENOMEM);
 295
 296        man->dev_priv = dev_priv;
 297        INIT_LIST_HEAD(&man->list);
 298        ret = drm_ht_create(&man->resources, VMW_CMDBUF_RES_MAN_HT_ORDER);
 299        if (ret == 0)
 300                return man;
 301
 302        kfree(man);
 303        return ERR_PTR(ret);
 304}
 305
 306/**
 307 * vmw_cmdbuf_res_man_destroy - Destroy a command buffer managed resource
 308 * manager.
 309 *
 310 * @man: Pointer to the  manager to destroy.
 311 *
 312 * This function destroys a command buffer managed resource manager and
 313 * unreferences / frees all command buffer managed resources and -entries
 314 * associated with it.
 315 */
 316void vmw_cmdbuf_res_man_destroy(struct vmw_cmdbuf_res_manager *man)
 317{
 318        struct vmw_cmdbuf_res *entry, *next;
 319
 320        list_for_each_entry_safe(entry, next, &man->list, head)
 321                vmw_cmdbuf_res_free(man, entry);
 322
 323        drm_ht_remove(&man->resources);
 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