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_streamoutput.c (10876B)


      1// SPDX-License-Identifier: GPL-2.0 OR MIT
      2/**************************************************************************
      3 *
      4 * Copyright © 2018-2019 VMware, Inc., Palo Alto, CA., USA
      5 * All Rights Reserved.
      6 *
      7 * Permission is hereby granted, free of charge, to any person obtaining a
      8 * copy of this software and associated documentation files (the
      9 * "Software"), to deal in the Software without restriction, including
     10 * without limitation the rights to use, copy, modify, merge, publish,
     11 * distribute, sub license, and/or sell copies of the Software, and to
     12 * permit persons to whom the Software is furnished to do so, subject to
     13 * the following conditions:
     14 *
     15 * The above copyright notice and this permission notice (including the
     16 * next paragraph) shall be included in all copies or substantial portions
     17 * of the Software.
     18 *
     19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     21 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
     22 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
     23 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     24 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
     25 * USE OR OTHER DEALINGS IN THE SOFTWARE.
     26 *
     27 **************************************************************************/
     28
     29#include <drm/ttm/ttm_placement.h>
     30
     31#include "vmwgfx_drv.h"
     32#include "vmwgfx_resource_priv.h"
     33#include "vmwgfx_binding.h"
     34
     35/**
     36 * struct vmw_dx_streamoutput - Streamoutput resource metadata.
     37 * @res: Base resource struct.
     38 * @ctx: Non-refcounted context to which @res belong.
     39 * @cotable: Refcounted cotable holding this Streamoutput.
     40 * @cotable_head: List head for cotable-so_res list.
     41 * @id: User-space provided identifier.
     42 * @size: User-space provided mob size.
     43 * @committed: Whether streamoutput is actually created or pending creation.
     44 */
     45struct vmw_dx_streamoutput {
     46	struct vmw_resource res;
     47	struct vmw_resource *ctx;
     48	struct vmw_resource *cotable;
     49	struct list_head cotable_head;
     50	u32 id;
     51	u32 size;
     52	bool committed;
     53};
     54
     55static int vmw_dx_streamoutput_create(struct vmw_resource *res);
     56static int vmw_dx_streamoutput_bind(struct vmw_resource *res,
     57				    struct ttm_validate_buffer *val_buf);
     58static int vmw_dx_streamoutput_unbind(struct vmw_resource *res, bool readback,
     59				      struct ttm_validate_buffer *val_buf);
     60static void vmw_dx_streamoutput_commit_notify(struct vmw_resource *res,
     61					      enum vmw_cmdbuf_res_state state);
     62
     63static const struct vmw_res_func vmw_dx_streamoutput_func = {
     64	.res_type = vmw_res_streamoutput,
     65	.needs_backup = true,
     66	.may_evict = false,
     67	.type_name = "DX streamoutput",
     68	.backup_placement = &vmw_mob_placement,
     69	.create = vmw_dx_streamoutput_create,
     70	.destroy = NULL, /* Command buffer managed resource. */
     71	.bind = vmw_dx_streamoutput_bind,
     72	.unbind = vmw_dx_streamoutput_unbind,
     73	.commit_notify = vmw_dx_streamoutput_commit_notify,
     74};
     75
     76static inline struct vmw_dx_streamoutput *
     77vmw_res_to_dx_streamoutput(struct vmw_resource *res)
     78{
     79	return container_of(res, struct vmw_dx_streamoutput, res);
     80}
     81
     82/**
     83 * vmw_dx_streamoutput_unscrub - Reattach the MOB to streamoutput.
     84 * @res: The streamoutput resource.
     85 *
     86 * Return: 0 on success, negative error code on failure.
     87 */
     88static int vmw_dx_streamoutput_unscrub(struct vmw_resource *res)
     89{
     90	struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
     91	struct vmw_private *dev_priv = res->dev_priv;
     92	struct {
     93		SVGA3dCmdHeader header;
     94		SVGA3dCmdDXBindStreamOutput body;
     95	} *cmd;
     96
     97	if (!list_empty(&so->cotable_head) || !so->committed )
     98		return 0;
     99
    100	cmd = VMW_CMD_CTX_RESERVE(dev_priv, sizeof(*cmd), so->ctx->id);
    101	if (!cmd)
    102		return -ENOMEM;
    103
    104	cmd->header.id = SVGA_3D_CMD_DX_BIND_STREAMOUTPUT;
    105	cmd->header.size = sizeof(cmd->body);
    106	cmd->body.soid = so->id;
    107	cmd->body.mobid = res->backup->base.resource->start;
    108	cmd->body.offsetInBytes = res->backup_offset;
    109	cmd->body.sizeInBytes = so->size;
    110	vmw_cmd_commit(dev_priv, sizeof(*cmd));
    111
    112	vmw_cotable_add_resource(so->cotable, &so->cotable_head);
    113
    114	return 0;
    115}
    116
    117static int vmw_dx_streamoutput_create(struct vmw_resource *res)
    118{
    119	struct vmw_private *dev_priv = res->dev_priv;
    120	struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
    121	int ret = 0;
    122
    123	WARN_ON_ONCE(!so->committed);
    124
    125	if (vmw_resource_mob_attached(res)) {
    126		mutex_lock(&dev_priv->binding_mutex);
    127		ret = vmw_dx_streamoutput_unscrub(res);
    128		mutex_unlock(&dev_priv->binding_mutex);
    129	}
    130
    131	res->id = so->id;
    132
    133	return ret;
    134}
    135
    136static int vmw_dx_streamoutput_bind(struct vmw_resource *res,
    137				    struct ttm_validate_buffer *val_buf)
    138{
    139	struct vmw_private *dev_priv = res->dev_priv;
    140	struct ttm_buffer_object *bo = val_buf->bo;
    141	int ret;
    142
    143	if (WARN_ON(bo->resource->mem_type != VMW_PL_MOB))
    144		return -EINVAL;
    145
    146	mutex_lock(&dev_priv->binding_mutex);
    147	ret = vmw_dx_streamoutput_unscrub(res);
    148	mutex_unlock(&dev_priv->binding_mutex);
    149
    150	return ret;
    151}
    152
    153/**
    154 * vmw_dx_streamoutput_scrub - Unbind the MOB from streamoutput.
    155 * @res: The streamoutput resource.
    156 *
    157 * Return: 0 on success, negative error code on failure.
    158 */
    159static int vmw_dx_streamoutput_scrub(struct vmw_resource *res)
    160{
    161	struct vmw_private *dev_priv = res->dev_priv;
    162	struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
    163	struct {
    164		SVGA3dCmdHeader header;
    165		SVGA3dCmdDXBindStreamOutput body;
    166	} *cmd;
    167
    168	if (list_empty(&so->cotable_head))
    169		return 0;
    170
    171	WARN_ON_ONCE(!so->committed);
    172
    173	cmd = VMW_CMD_CTX_RESERVE(dev_priv, sizeof(*cmd), so->ctx->id);
    174	if (!cmd)
    175		return -ENOMEM;
    176
    177	cmd->header.id = SVGA_3D_CMD_DX_BIND_STREAMOUTPUT;
    178	cmd->header.size = sizeof(cmd->body);
    179	cmd->body.soid = res->id;
    180	cmd->body.mobid = SVGA3D_INVALID_ID;
    181	cmd->body.offsetInBytes = 0;
    182	cmd->body.sizeInBytes = so->size;
    183	vmw_cmd_commit(dev_priv, sizeof(*cmd));
    184
    185	res->id = -1;
    186	list_del_init(&so->cotable_head);
    187
    188	return 0;
    189}
    190
    191static int vmw_dx_streamoutput_unbind(struct vmw_resource *res, bool readback,
    192				      struct ttm_validate_buffer *val_buf)
    193{
    194	struct vmw_private *dev_priv = res->dev_priv;
    195	struct vmw_fence_obj *fence;
    196	int ret;
    197
    198	if (WARN_ON(res->backup->base.resource->mem_type != VMW_PL_MOB))
    199		return -EINVAL;
    200
    201	mutex_lock(&dev_priv->binding_mutex);
    202	ret = vmw_dx_streamoutput_scrub(res);
    203	mutex_unlock(&dev_priv->binding_mutex);
    204
    205	if (ret)
    206		return ret;
    207
    208	(void) vmw_execbuf_fence_commands(NULL, dev_priv, &fence, NULL);
    209	vmw_bo_fence_single(val_buf->bo, fence);
    210
    211	if (fence != NULL)
    212		vmw_fence_obj_unreference(&fence);
    213
    214	return 0;
    215}
    216
    217static void vmw_dx_streamoutput_commit_notify(struct vmw_resource *res,
    218					   enum vmw_cmdbuf_res_state state)
    219{
    220	struct vmw_private *dev_priv = res->dev_priv;
    221	struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
    222
    223	if (state == VMW_CMDBUF_RES_ADD) {
    224		mutex_lock(&dev_priv->binding_mutex);
    225		vmw_cotable_add_resource(so->cotable, &so->cotable_head);
    226		so->committed = true;
    227		res->id = so->id;
    228		mutex_unlock(&dev_priv->binding_mutex);
    229	} else {
    230		mutex_lock(&dev_priv->binding_mutex);
    231		list_del_init(&so->cotable_head);
    232		so->committed = false;
    233		res->id = -1;
    234		mutex_unlock(&dev_priv->binding_mutex);
    235	}
    236}
    237
    238/**
    239 * vmw_dx_streamoutput_lookup - Do a streamoutput resource lookup by user key.
    240 * @man: Command buffer managed resource manager for current context.
    241 * @user_key: User-space identifier for lookup.
    242 *
    243 * Return: Valid refcounted vmw_resource on success, error pointer on failure.
    244 */
    245struct vmw_resource *
    246vmw_dx_streamoutput_lookup(struct vmw_cmdbuf_res_manager *man,
    247			   u32 user_key)
    248{
    249	return vmw_cmdbuf_res_lookup(man, vmw_cmdbuf_res_streamoutput,
    250				     user_key);
    251}
    252
    253static void vmw_dx_streamoutput_res_free(struct vmw_resource *res)
    254{
    255	struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
    256
    257	vmw_resource_unreference(&so->cotable);
    258	kfree(so);
    259}
    260
    261static void vmw_dx_streamoutput_hw_destroy(struct vmw_resource *res)
    262{
    263	/* Destroyed by user-space cmd buf or as part of context takedown. */
    264	res->id = -1;
    265}
    266
    267/**
    268 * vmw_dx_streamoutput_add - Add a streamoutput as a cmd buf managed resource.
    269 * @man: Command buffer managed resource manager for current context.
    270 * @ctx: Pointer to context resource.
    271 * @user_key: The identifier for this streamoutput.
    272 * @list: The list of staged command buffer managed resources.
    273 *
    274 * Return: 0 on success, negative error code on failure.
    275 */
    276int vmw_dx_streamoutput_add(struct vmw_cmdbuf_res_manager *man,
    277			    struct vmw_resource *ctx, u32 user_key,
    278			    struct list_head *list)
    279{
    280	struct vmw_dx_streamoutput *so;
    281	struct vmw_resource *res;
    282	struct vmw_private *dev_priv = ctx->dev_priv;
    283	int ret;
    284
    285	so = kmalloc(sizeof(*so), GFP_KERNEL);
    286	if (!so) {
    287		return -ENOMEM;
    288	}
    289
    290	res = &so->res;
    291	so->ctx = ctx;
    292	so->cotable = vmw_resource_reference
    293		(vmw_context_cotable(ctx, SVGA_COTABLE_STREAMOUTPUT));
    294	so->id = user_key;
    295	so->committed = false;
    296	INIT_LIST_HEAD(&so->cotable_head);
    297	ret = vmw_resource_init(dev_priv, res, true,
    298				vmw_dx_streamoutput_res_free,
    299				&vmw_dx_streamoutput_func);
    300	if (ret)
    301		goto out_resource_init;
    302
    303	ret = vmw_cmdbuf_res_add(man, vmw_cmdbuf_res_streamoutput, user_key,
    304				 res, list);
    305	if (ret)
    306		goto out_resource_init;
    307
    308	res->id = so->id;
    309	res->hw_destroy = vmw_dx_streamoutput_hw_destroy;
    310
    311out_resource_init:
    312	vmw_resource_unreference(&res);
    313
    314	return ret;
    315}
    316
    317/**
    318 * vmw_dx_streamoutput_set_size - Sets streamoutput mob size in res struct.
    319 * @res: The streamoutput res for which need to set size.
    320 * @size: The size provided by user-space to set.
    321 */
    322void vmw_dx_streamoutput_set_size(struct vmw_resource *res, u32 size)
    323{
    324	struct vmw_dx_streamoutput *so = vmw_res_to_dx_streamoutput(res);
    325
    326	so->size = size;
    327}
    328
    329/**
    330 * vmw_dx_streamoutput_remove - Stage streamoutput for removal.
    331 * @man: Command buffer managed resource manager for current context.
    332 * @user_key: The identifier for this streamoutput.
    333 * @list: The list of staged command buffer managed resources.
    334 *
    335 * Return: 0 on success, negative error code on failure.
    336 */
    337int vmw_dx_streamoutput_remove(struct vmw_cmdbuf_res_manager *man,
    338			       u32 user_key,
    339			       struct list_head *list)
    340{
    341	struct vmw_resource *r;
    342
    343	return vmw_cmdbuf_res_remove(man, vmw_cmdbuf_res_streamoutput,
    344				     (u32)user_key, list, &r);
    345}
    346
    347/**
    348 * vmw_dx_streamoutput_cotable_list_scrub - cotable unbind_func callback.
    349 * @dev_priv: Device private.
    350 * @list: The list of cotable resources.
    351 * @readback: Whether the call was part of a readback unbind.
    352 */
    353void vmw_dx_streamoutput_cotable_list_scrub(struct vmw_private *dev_priv,
    354					    struct list_head *list,
    355					    bool readback)
    356{
    357	struct vmw_dx_streamoutput *entry, *next;
    358
    359	lockdep_assert_held_once(&dev_priv->binding_mutex);
    360
    361	list_for_each_entry_safe(entry, next, list, cotable_head) {
    362		WARN_ON(vmw_dx_streamoutput_scrub(&entry->res));
    363		if (!readback)
    364			entry->committed =false;
    365	}
    366}