cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vmwgfx_cmdbuf_res.c (9611B)


      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 vmwgfx_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 vmwgfx_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 * @res_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 vmwgfx_hash_item *hash;
     85	int ret;
     86	unsigned long key = user_key | (res_type << 24);
     87
     88	ret = vmwgfx_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(vmwgfx_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 * @list: Caller's list of command buffer resource action
    152 *
    153 * This function reverts a list of command buffer resource
    154 * additions or removals.
    155 * It is typically called when the execbuf ioctl call triggering these
    156 * actions failed for some reason, and the command stream was never
    157 * submitted.
    158 */
    159void vmw_cmdbuf_res_revert(struct list_head *list)
    160{
    161	struct vmw_cmdbuf_res *entry, *next;
    162	int ret;
    163
    164	list_for_each_entry_safe(entry, next, list, head) {
    165		switch (entry->state) {
    166		case VMW_CMDBUF_RES_ADD:
    167			vmw_cmdbuf_res_free(entry->man, entry);
    168			break;
    169		case VMW_CMDBUF_RES_DEL:
    170			ret = vmwgfx_ht_insert_item(&entry->man->resources, &entry->hash);
    171			BUG_ON(ret);
    172			list_move_tail(&entry->head, &entry->man->list);
    173			entry->state = VMW_CMDBUF_RES_COMMITTED;
    174			break;
    175		default:
    176			BUG();
    177			break;
    178		}
    179	}
    180}
    181
    182/**
    183 * vmw_cmdbuf_res_add - Stage a command buffer managed resource for addition.
    184 *
    185 * @man: Pointer to the command buffer resource manager.
    186 * @res_type: The resource type.
    187 * @user_key: The user-space id of the resource.
    188 * @res: Valid (refcount != 0) pointer to a struct vmw_resource.
    189 * @list: The staging list.
    190 *
    191 * This function allocates a struct vmw_cmdbuf_res entry and adds the
    192 * resource to the hash table of the manager identified by @man. The
    193 * entry is then put on the staging list identified by @list.
    194 */
    195int vmw_cmdbuf_res_add(struct vmw_cmdbuf_res_manager *man,
    196		       enum vmw_cmdbuf_res_type res_type,
    197		       u32 user_key,
    198		       struct vmw_resource *res,
    199		       struct list_head *list)
    200{
    201	struct vmw_cmdbuf_res *cres;
    202	int ret;
    203
    204	cres = kzalloc(sizeof(*cres), GFP_KERNEL);
    205	if (unlikely(!cres))
    206		return -ENOMEM;
    207
    208	cres->hash.key = user_key | (res_type << 24);
    209	ret = vmwgfx_ht_insert_item(&man->resources, &cres->hash);
    210	if (unlikely(ret != 0)) {
    211		kfree(cres);
    212		goto out_invalid_key;
    213	}
    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 vmwgfx_hash_item *hash;
    248	int ret;
    249
    250	ret = vmwgfx_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) vmwgfx_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 = vmwgfx_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	vmwgfx_ht_remove(&man->resources);
    324	kfree(man);
    325}
    326