1fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz/**************************************************************************
2fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz *
3fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * Copyright © 2009 VMware, Inc., Palo Alto, CA., USA
4fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * All Rights Reserved.
5fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz *
6fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * Permission is hereby granted, free of charge, to any person obtaining a
7fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * copy of this software and associated documentation files (the
8fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * "Software"), to deal in the Software without restriction, including
9fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * without limitation the rights to use, copy, modify, merge, publish,
10fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * distribute, sub license, and/or sell copies of the Software, and to
11fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * permit persons to whom the Software is furnished to do so, subject to
12fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * the following conditions:
13fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz *
14fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * The above copyright notice and this permission notice (including the
15fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * next paragraph) shall be included in all copies or substantial portions
16fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * of the Software.
17fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz *
18fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
22fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * USE OR OTHER DEALINGS IN THE SOFTWARE.
25fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz *
26fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz **************************************************************************/
27fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
28fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz#include "vmwgfx_drv.h"
29fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz#include "vmwgfx_drm.h"
30fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz#include "ttm/ttm_object.h"
31fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz#include "ttm/ttm_placement.h"
32fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz#include "drmP.h"
33fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
34fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstruct vmw_user_context {
35fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct ttm_base_object base;
36fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_resource res;
37fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz};
38fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
39fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstruct vmw_user_surface {
40fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct ttm_base_object base;
41fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_surface srf;
42414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	uint32_t size;
43fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz};
44fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
45fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstruct vmw_user_dma_buffer {
46fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct ttm_base_object base;
47fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_dma_buffer dma;
48fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz};
49fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
50fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstruct vmw_bo_user_rep {
51fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	uint32_t handle;
52fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	uint64_t map_handle;
53fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz};
54fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
55fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstruct vmw_stream {
56fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_resource res;
57fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	uint32_t stream_id;
58fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz};
59fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
60fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstruct vmw_user_stream {
61fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct ttm_base_object base;
62fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_stream stream;
63fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz};
64fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
655bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromstruct vmw_surface_offset {
665bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	uint32_t face;
675bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	uint32_t mip;
685bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	uint32_t bo_offset;
695bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom};
705bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
71414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom
72414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstromstatic uint64_t vmw_user_context_size;
73414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstromstatic uint64_t vmw_user_surface_size;
74414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstromstatic uint64_t vmw_user_stream_size;
75414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom
76fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstatic inline struct vmw_dma_buffer *
77fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzvmw_dma_buffer(struct ttm_buffer_object *bo)
78fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
79fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return container_of(bo, struct vmw_dma_buffer, base);
80fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
81fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
82fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstatic inline struct vmw_user_dma_buffer *
83fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzvmw_user_dma_buffer(struct ttm_buffer_object *bo)
84fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
85fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
86fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return container_of(vmw_bo, struct vmw_user_dma_buffer, dma);
87fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
88fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
89fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstruct vmw_resource *vmw_resource_reference(struct vmw_resource *res)
90fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
91fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	kref_get(&res->kref);
92fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return res;
93fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
94fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
955bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
965bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom/**
975bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * vmw_resource_release_id - release a resource id to the id manager.
985bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
995bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * @res: Pointer to the resource.
1005bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
1015bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * Release the resource id to the resource id manager and set it to -1
1025bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom */
1035bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromstatic void vmw_resource_release_id(struct vmw_resource *res)
1045bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom{
1055bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	struct vmw_private *dev_priv = res->dev_priv;
1065bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
1075bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	write_lock(&dev_priv->resource_lock);
1085bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (res->id != -1)
1095bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		idr_remove(res->idr, res->id);
1105bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	res->id = -1;
1115bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	write_unlock(&dev_priv->resource_lock);
1125bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom}
1135bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
114fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstatic void vmw_resource_release(struct kref *kref)
115fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
116fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_resource *res =
117fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	    container_of(kref, struct vmw_resource, kref);
118fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_private *dev_priv = res->dev_priv;
1195bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	int id = res->id;
1205bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	struct idr *idr = res->idr;
121fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1225bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	res->avail = false;
1235bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (res->remove_from_lists != NULL)
1245bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		res->remove_from_lists(res);
125fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	write_unlock(&dev_priv->resource_lock);
126fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
127fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (likely(res->hw_destroy != NULL))
128fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		res->hw_destroy(res);
129fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
130fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (res->res_free != NULL)
131fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		res->res_free(res);
132fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	else
133fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		kfree(res);
134fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
135fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	write_lock(&dev_priv->resource_lock);
1365bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
1375bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (id != -1)
1385bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		idr_remove(idr, id);
139fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
140fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
141fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzvoid vmw_resource_unreference(struct vmw_resource **p_res)
142fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
143fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_resource *res = *p_res;
144fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_private *dev_priv = res->dev_priv;
145fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
146fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	*p_res = NULL;
147fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	write_lock(&dev_priv->resource_lock);
148fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	kref_put(&res->kref, vmw_resource_release);
149fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	write_unlock(&dev_priv->resource_lock);
150fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
151fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1525bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
1535bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom/**
1545bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * vmw_resource_alloc_id - release a resource id to the id manager.
1555bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
1565bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * @dev_priv: Pointer to the device private structure.
1575bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * @res: Pointer to the resource.
1585bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
1595bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * Allocate the lowest free resource from the resource manager, and set
1605bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * @res->id to that id. Returns 0 on success and -ENOMEM on failure.
1615bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom */
1625bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromstatic int vmw_resource_alloc_id(struct vmw_private *dev_priv,
1635bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom				 struct vmw_resource *res)
1645bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom{
1655bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	int ret;
1665bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
1675bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	BUG_ON(res->id != -1);
1685bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
1695bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	do {
1705bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		if (unlikely(idr_pre_get(res->idr, GFP_KERNEL) == 0))
1715bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			return -ENOMEM;
1725bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
1735bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		write_lock(&dev_priv->resource_lock);
1745bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		ret = idr_get_new_above(res->idr, res, 1, &res->id);
1755bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		write_unlock(&dev_priv->resource_lock);
1765bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
1775bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	} while (ret == -EAGAIN);
1785bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
1795bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	return ret;
1805bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom}
1815bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
1825bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
183fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstatic int vmw_resource_init(struct vmw_private *dev_priv,
184fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			     struct vmw_resource *res,
185fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			     struct idr *idr,
186fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			     enum ttm_object_type obj_type,
1875bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			     bool delay_id,
1885bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			     void (*res_free) (struct vmw_resource *res),
1895bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			     void (*remove_from_lists)
1905bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			     (struct vmw_resource *res))
191fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
192fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	kref_init(&res->kref);
193fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	res->hw_destroy = NULL;
194fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	res->res_free = res_free;
1955bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	res->remove_from_lists = remove_from_lists;
196fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	res->res_type = obj_type;
197fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	res->idr = idr;
198fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	res->avail = false;
199fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	res->dev_priv = dev_priv;
200e2fa3a76839ada0d788549607263a036aa654243Thomas Hellstrom	INIT_LIST_HEAD(&res->query_head);
201f18c8840bef4195e6f35298b7746563f10d2d502Thomas Hellstrom	INIT_LIST_HEAD(&res->validate_head);
2025bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	res->id = -1;
2035bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (delay_id)
2045bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		return 0;
2055bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	else
2065bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		return vmw_resource_alloc_id(dev_priv, res);
207fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
208fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
209fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz/**
210fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * vmw_resource_activate
211fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz *
212fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * @res:        Pointer to the newly created resource
213fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * @hw_destroy: Destroy function. NULL if none.
214fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz *
215fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * Activate a resource after the hardware has been made aware of it.
216fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * Set tye destroy function to @destroy. Typically this frees the
217fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * resource and destroys the hardware resources associated with it.
218fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * Activate basically means that the function vmw_resource_lookup will
219fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * find it.
220fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz */
221fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
222fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstatic void vmw_resource_activate(struct vmw_resource *res,
223fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz				  void (*hw_destroy) (struct vmw_resource *))
224fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
225fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_private *dev_priv = res->dev_priv;
226fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
227fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	write_lock(&dev_priv->resource_lock);
228fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	res->avail = true;
229fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	res->hw_destroy = hw_destroy;
230fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	write_unlock(&dev_priv->resource_lock);
231fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
232fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
233fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstruct vmw_resource *vmw_resource_lookup(struct vmw_private *dev_priv,
234fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz					 struct idr *idr, int id)
235fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
236fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_resource *res;
237fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
238fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	read_lock(&dev_priv->resource_lock);
239fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	res = idr_find(idr, id);
240fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (res && res->avail)
241fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		kref_get(&res->kref);
242fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	else
243fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		res = NULL;
244fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	read_unlock(&dev_priv->resource_lock);
245fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
246fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(res == NULL))
247fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return NULL;
248fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
249fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return res;
250fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
251fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
252fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz/**
253fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * Context management:
254fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz */
255fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
256fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstatic void vmw_hw_context_destroy(struct vmw_resource *res)
257fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
258fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
259fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_private *dev_priv = res->dev_priv;
260fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct {
261fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		SVGA3dCmdHeader header;
262fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		SVGA3dCmdDestroyContext body;
263e2fa3a76839ada0d788549607263a036aa654243Thomas Hellstrom	} *cmd;
264e2fa3a76839ada0d788549607263a036aa654243Thomas Hellstrom
265e2fa3a76839ada0d788549607263a036aa654243Thomas Hellstrom
266e2fa3a76839ada0d788549607263a036aa654243Thomas Hellstrom	vmw_execbuf_release_pinned_bo(dev_priv, true, res->id);
267fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
268e2fa3a76839ada0d788549607263a036aa654243Thomas Hellstrom	cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
269fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(cmd == NULL)) {
270fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		DRM_ERROR("Failed reserving FIFO space for surface "
271fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			  "destruction.\n");
272fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return;
273fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
274fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
275fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	cmd->header.id = cpu_to_le32(SVGA_3D_CMD_CONTEXT_DESTROY);
276fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	cmd->header.size = cpu_to_le32(sizeof(cmd->body));
277fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	cmd->body.cid = cpu_to_le32(res->id);
278fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
279fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	vmw_fifo_commit(dev_priv, sizeof(*cmd));
28005730b32a78dab4bed8fb7ccc64c53d9fcf31e9dThomas Hellstrom	vmw_3d_resource_dec(dev_priv, false);
281fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
282fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
283fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstatic int vmw_context_init(struct vmw_private *dev_priv,
284fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			    struct vmw_resource *res,
285fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			    void (*res_free) (struct vmw_resource *res))
286fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
287fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	int ret;
288fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
289fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct {
290fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		SVGA3dCmdHeader header;
291fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		SVGA3dCmdDefineContext body;
292fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	} *cmd;
293fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
294fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ret = vmw_resource_init(dev_priv, res, &dev_priv->context_idr,
2955bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom				VMW_RES_CONTEXT, false, res_free, NULL);
296fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
297fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(ret != 0)) {
2985bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		DRM_ERROR("Failed to allocate a resource id.\n");
2995bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		goto out_early;
3005bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	}
3015bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
3025bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (unlikely(res->id >= SVGA3D_MAX_CONTEXT_IDS)) {
3035bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		DRM_ERROR("Out of hw context ids.\n");
3045bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		vmw_resource_unreference(&res);
3055bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		return -ENOMEM;
306fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
307fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
308fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
309fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(cmd == NULL)) {
310fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		DRM_ERROR("Fifo reserve failed.\n");
311fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		vmw_resource_unreference(&res);
312fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return -ENOMEM;
313fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
314fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
315fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	cmd->header.id = cpu_to_le32(SVGA_3D_CMD_CONTEXT_DEFINE);
316fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	cmd->header.size = cpu_to_le32(sizeof(cmd->body));
317fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	cmd->body.cid = cpu_to_le32(res->id);
318fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
319fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	vmw_fifo_commit(dev_priv, sizeof(*cmd));
32005730b32a78dab4bed8fb7ccc64c53d9fcf31e9dThomas Hellstrom	(void) vmw_3d_resource_inc(dev_priv, false);
321fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	vmw_resource_activate(res, vmw_hw_context_destroy);
322fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return 0;
3235bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
3245bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromout_early:
3255bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (res_free == NULL)
3265bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		kfree(res);
3275bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	else
3285bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		res_free(res);
3295bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	return ret;
330fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
331fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
332fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstruct vmw_resource *vmw_context_alloc(struct vmw_private *dev_priv)
333fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
334fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
335fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	int ret;
336fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
337fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(res == NULL))
338fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return NULL;
339fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
340fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ret = vmw_context_init(dev_priv, res, NULL);
341fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return (ret == 0) ? res : NULL;
342fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
343fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
344fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz/**
345fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * User-space context management:
346fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz */
347fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
348fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstatic void vmw_user_context_free(struct vmw_resource *res)
349fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
350fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_user_context *ctx =
351fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	    container_of(res, struct vmw_user_context, res);
352414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	struct vmw_private *dev_priv = res->dev_priv;
353fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
354fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	kfree(ctx);
355414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	ttm_mem_global_free(vmw_mem_glob(dev_priv),
356414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom			    vmw_user_context_size);
357fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
358fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
359fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz/**
360fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * This function is called when user space has no more references on the
361fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * base object. It releases the base-object's reference on the resource object.
362fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz */
363fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
364fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstatic void vmw_user_context_base_release(struct ttm_base_object **p_base)
365fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
366fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct ttm_base_object *base = *p_base;
367fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_user_context *ctx =
368fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	    container_of(base, struct vmw_user_context, base);
369fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_resource *res = &ctx->res;
370fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
371fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	*p_base = NULL;
372fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	vmw_resource_unreference(&res);
373fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
374fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
375fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzint vmw_context_destroy_ioctl(struct drm_device *dev, void *data,
376fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			      struct drm_file *file_priv)
377fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
378fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_private *dev_priv = vmw_priv(dev);
379fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_resource *res;
380fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_user_context *ctx;
381fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data;
382fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
383fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	int ret = 0;
384fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
385fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	res = vmw_resource_lookup(dev_priv, &dev_priv->context_idr, arg->cid);
386fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(res == NULL))
387fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return -EINVAL;
388fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
389fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (res->res_free != &vmw_user_context_free) {
390fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		ret = -EINVAL;
391fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		goto out;
392fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
393fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
394fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ctx = container_of(res, struct vmw_user_context, res);
395fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (ctx->base.tfile != tfile && !ctx->base.shareable) {
396fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		ret = -EPERM;
397fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		goto out;
398fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
399fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
400fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ttm_ref_object_base_unref(tfile, ctx->base.hash.key, TTM_REF_USAGE);
401fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzout:
402fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	vmw_resource_unreference(&res);
403fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return ret;
404fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
405fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
406fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzint vmw_context_define_ioctl(struct drm_device *dev, void *data,
407fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			     struct drm_file *file_priv)
408fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
409fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_private *dev_priv = vmw_priv(dev);
410414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	struct vmw_user_context *ctx;
411fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_resource *res;
412fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_resource *tmp;
413fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data;
414fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
415414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	struct vmw_master *vmaster = vmw_master(file_priv->master);
416fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	int ret;
417fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
418414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom
419414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	/*
420414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	 * Approximate idr memory usage with 128 bytes. It will be limited
421414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	 * by maximum number_of contexts anyway.
422414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	 */
423414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom
424414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	if (unlikely(vmw_user_context_size == 0))
425414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		vmw_user_context_size = ttm_round_pot(sizeof(*ctx)) + 128;
426414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom
427414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	ret = ttm_read_lock(&vmaster->lock, true);
428414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	if (unlikely(ret != 0))
429414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		return ret;
430414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom
431414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
432414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom				   vmw_user_context_size,
433414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom				   false, true);
434414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	if (unlikely(ret != 0)) {
435414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		if (ret != -ERESTARTSYS)
436414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom			DRM_ERROR("Out of graphics memory for context"
437414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom				  " creation.\n");
438414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		goto out_unlock;
439414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	}
440414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom
441414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
442414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	if (unlikely(ctx == NULL)) {
443414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		ttm_mem_global_free(vmw_mem_glob(dev_priv),
444414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom				    vmw_user_context_size);
445414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		ret = -ENOMEM;
446414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		goto out_unlock;
447414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	}
448fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
449fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	res = &ctx->res;
450fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ctx->base.shareable = false;
451fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ctx->base.tfile = NULL;
452fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
453414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	/*
454414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	 * From here on, the destructor takes over resource freeing.
455414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	 */
456414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom
457fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ret = vmw_context_init(dev_priv, res, vmw_user_context_free);
458fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(ret != 0))
459414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		goto out_unlock;
460fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
461fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	tmp = vmw_resource_reference(&ctx->res);
462fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ret = ttm_base_object_init(tfile, &ctx->base, false, VMW_RES_CONTEXT,
463fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz				   &vmw_user_context_base_release, NULL);
464fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
465fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(ret != 0)) {
466fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		vmw_resource_unreference(&tmp);
467fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		goto out_err;
468fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
469fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
470fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	arg->cid = res->id;
471fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzout_err:
472fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	vmw_resource_unreference(&res);
473414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstromout_unlock:
474414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	ttm_read_unlock(&vmaster->lock);
475fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return ret;
476fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
477fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
478fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
479fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzint vmw_context_check(struct vmw_private *dev_priv,
480fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		      struct ttm_object_file *tfile,
481be38ab6ea7b0de0542a0ff78690d63bb22f66a4dThomas Hellstrom		      int id,
482be38ab6ea7b0de0542a0ff78690d63bb22f66a4dThomas Hellstrom		      struct vmw_resource **p_res)
483fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
484fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_resource *res;
485fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	int ret = 0;
486fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
487fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	read_lock(&dev_priv->resource_lock);
488fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	res = idr_find(&dev_priv->context_idr, id);
489fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (res && res->avail) {
490fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		struct vmw_user_context *ctx =
491fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			container_of(res, struct vmw_user_context, res);
492fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		if (ctx->base.tfile != tfile && !ctx->base.shareable)
493fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			ret = -EPERM;
494be38ab6ea7b0de0542a0ff78690d63bb22f66a4dThomas Hellstrom		if (p_res)
495be38ab6ea7b0de0542a0ff78690d63bb22f66a4dThomas Hellstrom			*p_res = vmw_resource_reference(res);
496fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	} else
497fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		ret = -EINVAL;
498fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	read_unlock(&dev_priv->resource_lock);
499fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
500fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return ret;
501fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
502fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
5035bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromstruct vmw_bpp {
5045bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	uint8_t bpp;
5055bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	uint8_t s_bpp;
5065bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom};
5075bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
5085bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom/*
5095bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * Size table for the supported SVGA3D surface formats. It consists of
5105bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * two values. The bpp value and the s_bpp value which is short for
5115bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * "stride bits per pixel" The values are given in such a way that the
5125bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * minimum stride for the image is calculated using
5135bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
5145bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * min_stride = w*s_bpp
5155bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
5165bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * and the total memory requirement for the image is
5175bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
5185bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * h*min_stride*bpp/s_bpp
5195bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
5205bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom */
5215bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromstatic const struct vmw_bpp vmw_sf_bpp[] = {
5225bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_FORMAT_INVALID] = {0, 0},
5235bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_X8R8G8B8] = {32, 32},
5245bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_A8R8G8B8] = {32, 32},
5255bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_R5G6B5] = {16, 16},
5265bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_X1R5G5B5] = {16, 16},
5275bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_A1R5G5B5] = {16, 16},
5285bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_A4R4G4B4] = {16, 16},
5295bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_Z_D32] = {32, 32},
5305bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_Z_D16] = {16, 16},
5315bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_Z_D24S8] = {32, 32},
5325bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_Z_D15S1] = {16, 16},
5335bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_LUMINANCE8] = {8, 8},
5345bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_LUMINANCE4_ALPHA4] = {8, 8},
5355bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_LUMINANCE16] = {16, 16},
5365bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_LUMINANCE8_ALPHA8] = {16, 16},
5375bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_DXT1] = {4, 16},
5385bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_DXT2] = {8, 32},
5395bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_DXT3] = {8, 32},
5405bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_DXT4] = {8, 32},
5415bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_DXT5] = {8, 32},
5425bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_BUMPU8V8] = {16, 16},
5435bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_BUMPL6V5U5] = {16, 16},
5445bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_BUMPX8L8V8U8] = {32, 32},
5455bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_ARGB_S10E5] = {16, 16},
5465bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_ARGB_S23E8] = {32, 32},
5475bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_A2R10G10B10] = {32, 32},
5485bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_V8U8] = {16, 16},
5495bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_Q8W8V8U8] = {32, 32},
5505bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_CxV8U8] = {16, 16},
5515bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_X8L8V8U8] = {32, 32},
5525bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_A2W10V10U10] = {32, 32},
5535bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_ALPHA8] = {8, 8},
5545bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_R_S10E5] = {16, 16},
5555bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_R_S23E8] = {32, 32},
5565bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_RG_S10E5] = {16, 16},
5575bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_RG_S23E8] = {32, 32},
5585bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_BUFFER] = {8, 8},
5595bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_Z_D24X8] = {32, 32},
5605bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_V16U16] = {32, 32},
5615bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_G16R16] = {32, 32},
5625bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_A16B16G16R16] = {64,  64},
5635bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_UYVY] = {12, 12},
5645bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_YUY2] = {12, 12},
5655bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_NV12] = {12, 8},
5665bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_AYUV] = {32, 32},
5675bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_BC4_UNORM] = {4,  16},
5685bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_BC5_UNORM] = {8,  32},
5695bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_Z_DF16] = {16,  16},
5705bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_Z_DF24] = {24,  24},
5715bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	[SVGA3D_Z_D24S8_INT] = {32,  32}
5725bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom};
5735bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
574fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
575fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz/**
576fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * Surface management.
577fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz */
578fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
5795bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromstruct vmw_surface_dma {
5805bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	SVGA3dCmdHeader header;
5815bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	SVGA3dCmdSurfaceDMA body;
5825bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	SVGA3dCopyBox cb;
5835bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	SVGA3dCmdSurfaceDMASuffix suffix;
5845bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom};
5855bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
5865bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromstruct vmw_surface_define {
5875bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	SVGA3dCmdHeader header;
5885bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	SVGA3dCmdDefineSurface body;
5895bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom};
5905bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
5915bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromstruct vmw_surface_destroy {
5925bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	SVGA3dCmdHeader header;
5935bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	SVGA3dCmdDestroySurface body;
5945bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom};
5955bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
5965bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
5975bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom/**
5985bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * vmw_surface_dma_size - Compute fifo size for a dma command.
5995bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
6005bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * @srf: Pointer to a struct vmw_surface
6015bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
6025bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * Computes the required size for a surface dma command for backup or
6035bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * restoration of the surface represented by @srf.
6045bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom */
6055bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromstatic inline uint32_t vmw_surface_dma_size(const struct vmw_surface *srf)
6065bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom{
6075bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	return srf->num_sizes * sizeof(struct vmw_surface_dma);
6085bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom}
6095bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
6105bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
6115bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom/**
6125bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * vmw_surface_define_size - Compute fifo size for a surface define command.
6135bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
6145bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * @srf: Pointer to a struct vmw_surface
6155bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
6165bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * Computes the required size for a surface define command for the definition
6175bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * of the surface represented by @srf.
6185bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom */
6195bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromstatic inline uint32_t vmw_surface_define_size(const struct vmw_surface *srf)
6205bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom{
6215bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	return sizeof(struct vmw_surface_define) + srf->num_sizes *
6225bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		sizeof(SVGA3dSize);
6235bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom}
6245bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
6255bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
6265bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom/**
6275bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * vmw_surface_destroy_size - Compute fifo size for a surface destroy command.
6285bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
6295bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * Computes the required size for a surface destroy command for the destruction
6305bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * of a hw surface.
6315bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom */
6325bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromstatic inline uint32_t vmw_surface_destroy_size(void)
6335bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom{
6345bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	return sizeof(struct vmw_surface_destroy);
6355bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom}
6365bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
6375bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom/**
6385bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * vmw_surface_destroy_encode - Encode a surface_destroy command.
6395bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
6405bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * @id: The surface id
6415bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * @cmd_space: Pointer to memory area in which the commands should be encoded.
6425bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom */
6435bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromstatic void vmw_surface_destroy_encode(uint32_t id,
6445bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom				       void *cmd_space)
6455bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom{
6465bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	struct vmw_surface_destroy *cmd = (struct vmw_surface_destroy *)
6475bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		cmd_space;
6485bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
6495bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	cmd->header.id = SVGA_3D_CMD_SURFACE_DESTROY;
6505bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	cmd->header.size = sizeof(cmd->body);
6515bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	cmd->body.sid = id;
6525bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom}
6535bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
6545bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom/**
6555bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * vmw_surface_define_encode - Encode a surface_define command.
6565bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
6575bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * @srf: Pointer to a struct vmw_surface object.
6585bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * @cmd_space: Pointer to memory area in which the commands should be encoded.
6595bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom */
6605bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromstatic void vmw_surface_define_encode(const struct vmw_surface *srf,
6615bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom				      void *cmd_space)
6625bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom{
6635bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	struct vmw_surface_define *cmd = (struct vmw_surface_define *)
6645bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		cmd_space;
6655bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	struct drm_vmw_size *src_size;
6665bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	SVGA3dSize *cmd_size;
6675bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	uint32_t cmd_len;
6685bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	int i;
6695bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
6705bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	cmd_len = sizeof(cmd->body) + srf->num_sizes * sizeof(SVGA3dSize);
6715bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
6725bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	cmd->header.id = SVGA_3D_CMD_SURFACE_DEFINE;
6735bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	cmd->header.size = cmd_len;
6745bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	cmd->body.sid = srf->res.id;
6755bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	cmd->body.surfaceFlags = srf->flags;
6765bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	cmd->body.format = cpu_to_le32(srf->format);
6775bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i)
6785bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		cmd->body.face[i].numMipLevels = srf->mip_levels[i];
6795bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
6805bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	cmd += 1;
6815bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	cmd_size = (SVGA3dSize *) cmd;
6825bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	src_size = srf->sizes;
6835bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
6845bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	for (i = 0; i < srf->num_sizes; ++i, cmd_size++, src_size++) {
6855bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		cmd_size->width = src_size->width;
6865bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		cmd_size->height = src_size->height;
6875bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		cmd_size->depth = src_size->depth;
6885bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	}
6895bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom}
6905bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
6915bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
6925bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom/**
6935bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * vmw_surface_dma_encode - Encode a surface_dma command.
6945bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
6955bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * @srf: Pointer to a struct vmw_surface object.
6965bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * @cmd_space: Pointer to memory area in which the commands should be encoded.
6975bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * @ptr: Pointer to an SVGAGuestPtr indicating where the surface contents
6985bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * should be placed or read from.
6995bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * @to_surface: Boolean whether to DMA to the surface or from the surface.
7005bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom */
7015bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromstatic void vmw_surface_dma_encode(struct vmw_surface *srf,
7025bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom				   void *cmd_space,
7035bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom				   const SVGAGuestPtr *ptr,
7045bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom				   bool to_surface)
7055bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom{
7065bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	uint32_t i;
7075bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	uint32_t bpp = vmw_sf_bpp[srf->format].bpp;
7085bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	uint32_t stride_bpp = vmw_sf_bpp[srf->format].s_bpp;
7095bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	struct vmw_surface_dma *cmd = (struct vmw_surface_dma *)cmd_space;
7105bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
7115bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	for (i = 0; i < srf->num_sizes; ++i) {
7125bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		SVGA3dCmdHeader *header = &cmd->header;
7135bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		SVGA3dCmdSurfaceDMA *body = &cmd->body;
7145bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		SVGA3dCopyBox *cb = &cmd->cb;
7155bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		SVGA3dCmdSurfaceDMASuffix *suffix = &cmd->suffix;
7165bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		const struct vmw_surface_offset *cur_offset = &srf->offsets[i];
7175bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		const struct drm_vmw_size *cur_size = &srf->sizes[i];
7185bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
7195bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		header->id = SVGA_3D_CMD_SURFACE_DMA;
7205bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		header->size = sizeof(*body) + sizeof(*cb) + sizeof(*suffix);
7215bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
7225bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		body->guest.ptr = *ptr;
7235bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		body->guest.ptr.offset += cur_offset->bo_offset;
7245bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		body->guest.pitch = (cur_size->width * stride_bpp + 7) >> 3;
7255bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		body->host.sid = srf->res.id;
7265bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		body->host.face = cur_offset->face;
7275bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		body->host.mipmap = cur_offset->mip;
7285bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		body->transfer = ((to_surface) ?  SVGA3D_WRITE_HOST_VRAM :
7295bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom				  SVGA3D_READ_HOST_VRAM);
7305bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		cb->x = 0;
7315bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		cb->y = 0;
7325bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		cb->z = 0;
7335bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		cb->srcx = 0;
7345bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		cb->srcy = 0;
7355bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		cb->srcz = 0;
7365bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		cb->w = cur_size->width;
7375bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		cb->h = cur_size->height;
7385bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		cb->d = cur_size->depth;
7395bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
7405bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		suffix->suffixSize = sizeof(*suffix);
7415bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		suffix->maximumOffset = body->guest.pitch*cur_size->height*
7425bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			cur_size->depth*bpp / stride_bpp;
7435bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		suffix->flags.discard = 0;
7445bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		suffix->flags.unsynchronized = 0;
7455bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		suffix->flags.reserved = 0;
7465bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		++cmd;
7475bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	}
7485bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom};
7495bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
7505bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
751fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstatic void vmw_hw_surface_destroy(struct vmw_resource *res)
752fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
753fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
754fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_private *dev_priv = res->dev_priv;
7555bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	struct vmw_surface *srf;
7565bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	void *cmd;
757fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
7585bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (res->id != -1) {
759fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
7605bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		cmd = vmw_fifo_reserve(dev_priv, vmw_surface_destroy_size());
7615bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		if (unlikely(cmd == NULL)) {
7625bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			DRM_ERROR("Failed reserving FIFO space for surface "
7635bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom				  "destruction.\n");
7645bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			return;
7655bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		}
766fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
7675bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		vmw_surface_destroy_encode(res->id, cmd);
7685bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		vmw_fifo_commit(dev_priv, vmw_surface_destroy_size());
7695bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
7705bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		/*
7715bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		 * used_memory_size_atomic, or separate lock
7725bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		 * to avoid taking dev_priv::cmdbuf_mutex in
7735bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		 * the destroy path.
7745bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		 */
7755bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
7765bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		mutex_lock(&dev_priv->cmdbuf_mutex);
7775bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		srf = container_of(res, struct vmw_surface, res);
7785bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		dev_priv->used_memory_size -= srf->backup_size;
7795bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		mutex_unlock(&dev_priv->cmdbuf_mutex);
7805bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
7815bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	}
78205730b32a78dab4bed8fb7ccc64c53d9fcf31e9dThomas Hellstrom	vmw_3d_resource_dec(dev_priv, false);
783fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
784fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
785fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzvoid vmw_surface_res_free(struct vmw_resource *res)
786fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
787fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_surface *srf = container_of(res, struct vmw_surface, res);
788fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
7895bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (srf->backup)
7905bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		ttm_bo_unref(&srf->backup);
7915bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	kfree(srf->offsets);
792fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	kfree(srf->sizes);
793fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	kfree(srf->snooper.image);
794fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	kfree(srf);
795fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
796fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
7975bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
7985bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom/**
7995bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * vmw_surface_do_validate - make a surface available to the device.
8005bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
8015bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * @dev_priv: Pointer to a device private struct.
8025bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * @srf: Pointer to a struct vmw_surface.
8035bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
8045bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * If the surface doesn't have a hw id, allocate one, and optionally
8055bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * DMA the backed up surface contents to the device.
8065bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
8075bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * Returns -EBUSY if there wasn't sufficient device resources to
8085bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * complete the validation. Retry after freeing up resources.
8095bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
8105bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * May return other errors if the kernel is out of guest resources.
8115bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom */
8125bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromint vmw_surface_do_validate(struct vmw_private *dev_priv,
8135bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			    struct vmw_surface *srf)
814fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
815fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_resource *res = &srf->res;
8165bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	struct list_head val_list;
8175bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	struct ttm_validate_buffer val_buf;
8185bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	uint32_t submit_size;
8195bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	uint8_t *cmd;
8205bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	int ret;
821fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
8225bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (likely(res->id != -1))
8235bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		return 0;
8245bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
8255bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (unlikely(dev_priv->used_memory_size + srf->backup_size >=
8265bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		     dev_priv->memory_size))
8275bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		return -EBUSY;
8285bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
8295bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	/*
8305bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 * Reserve- and validate the backup DMA bo.
8315bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 */
8325bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
8335bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (srf->backup) {
8345bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		INIT_LIST_HEAD(&val_list);
8355bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		val_buf.bo = ttm_bo_reference(srf->backup);
8365bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		val_buf.new_sync_obj_arg = (void *)((unsigned long)
8375bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom						    DRM_VMW_FENCE_FLAG_EXEC);
8385bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		list_add_tail(&val_buf.head, &val_list);
8395bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		ret = ttm_eu_reserve_buffers(&val_list);
8405bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		if (unlikely(ret != 0))
8415bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			goto out_no_reserve;
8425bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
8435bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		ret = ttm_bo_validate(srf->backup, &vmw_srf_placement,
8445bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom				      true, false, false);
8455bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		if (unlikely(ret != 0))
8465bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			goto out_no_validate;
8475bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	}
8485bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
8495bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	/*
8505bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 * Alloc id for the resource.
8515bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 */
852fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
8535bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	ret = vmw_resource_alloc_id(dev_priv, res);
854fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(ret != 0)) {
8555bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		DRM_ERROR("Failed to allocate a surface id.\n");
8565bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		goto out_no_id;
8575bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	}
8585bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (unlikely(res->id >= SVGA3D_MAX_SURFACE_IDS)) {
8595bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		ret = -EBUSY;
8605bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		goto out_no_fifo;
861fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
862fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
8635bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
8645bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	/*
8655bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 * Encode surface define- and dma commands.
8665bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 */
8675bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
8685bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	submit_size = vmw_surface_define_size(srf);
8695bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (srf->backup)
8705bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		submit_size += vmw_surface_dma_size(srf);
871fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
872fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	cmd = vmw_fifo_reserve(dev_priv, submit_size);
873fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(cmd == NULL)) {
8745bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		DRM_ERROR("Failed reserving FIFO space for surface "
8755bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			  "validation.\n");
8765bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		ret = -ENOMEM;
8775bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		goto out_no_fifo;
878fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
879fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
8805bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	vmw_surface_define_encode(srf, cmd);
8815bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (srf->backup) {
8825bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		SVGAGuestPtr ptr;
8835bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
8845bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		cmd += vmw_surface_define_size(srf);
8855bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		vmw_bo_get_guest_ptr(srf->backup, &ptr);
8865bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		vmw_surface_dma_encode(srf, cmd, &ptr, true);
887fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
888fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
8895bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	vmw_fifo_commit(dev_priv, submit_size);
890fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
8915bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	/*
8925bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 * Create a fence object and fence the backup buffer.
8935bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 */
8945bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
8955bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (srf->backup) {
8965bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		struct vmw_fence_obj *fence;
8975bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
8985bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		(void) vmw_execbuf_fence_commands(NULL, dev_priv,
8995bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom						  &fence, NULL);
9005bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		ttm_eu_fence_buffer_objects(&val_list, fence);
9015bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		if (likely(fence != NULL))
9025bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			vmw_fence_obj_unreference(&fence);
9035bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		ttm_bo_unref(&val_buf.bo);
9045bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		ttm_bo_unref(&srf->backup);
905fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
906fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
9075bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	/*
9085bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 * Surface memory usage accounting.
9095bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 */
9105bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
9115bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	dev_priv->used_memory_size += srf->backup_size;
9125bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
9135bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	return 0;
9145bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
9155bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromout_no_fifo:
9165bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	vmw_resource_release_id(res);
9175bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromout_no_id:
9185bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromout_no_validate:
9195bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (srf->backup)
9205bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		ttm_eu_backoff_reservation(&val_list);
9215bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromout_no_reserve:
9225bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (srf->backup)
9235bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		ttm_bo_unref(&val_buf.bo);
9245bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	return ret;
9255bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom}
9265bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
9275bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom/**
9285bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * vmw_surface_evict - Evict a hw surface.
9295bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
9305bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * @dev_priv: Pointer to a device private struct.
9315bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * @srf: Pointer to a struct vmw_surface
9325bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
9335bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * DMA the contents of a hw surface to a backup guest buffer object,
9345bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * and destroy the hw surface, releasing its id.
9355bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom */
9365bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromint vmw_surface_evict(struct vmw_private *dev_priv,
9375bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		      struct vmw_surface *srf)
9385bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom{
9395bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	struct vmw_resource *res = &srf->res;
9405bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	struct list_head val_list;
9415bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	struct ttm_validate_buffer val_buf;
9425bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	uint32_t submit_size;
9435bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	uint8_t *cmd;
9445bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	int ret;
9455bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	struct vmw_fence_obj *fence;
9465bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	SVGAGuestPtr ptr;
9475bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
9485bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	BUG_ON(res->id == -1);
9495bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
9505bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	/*
9515bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 * Create a surface backup buffer object.
9525bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 */
9535bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
9545bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (!srf->backup) {
9555bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		ret = ttm_bo_create(&dev_priv->bdev, srf->backup_size,
9565bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom				    ttm_bo_type_device,
9575bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom				    &vmw_srf_placement, 0, 0, true,
9585bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom				    NULL, &srf->backup);
9595bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		if (unlikely(ret != 0))
9605bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			return ret;
9615bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	}
9625bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
9635bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	/*
9645bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 * Reserve- and validate the backup DMA bo.
9655bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 */
9665bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
9675bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	INIT_LIST_HEAD(&val_list);
9685bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	val_buf.bo = ttm_bo_reference(srf->backup);
9695bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	val_buf.new_sync_obj_arg = (void *)(unsigned long)
9705bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		DRM_VMW_FENCE_FLAG_EXEC;
9715bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	list_add_tail(&val_buf.head, &val_list);
9725bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	ret = ttm_eu_reserve_buffers(&val_list);
9735bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (unlikely(ret != 0))
9745bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		goto out_no_reserve;
9755bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
9765bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	ret = ttm_bo_validate(srf->backup, &vmw_srf_placement,
9775bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			      true, false, false);
9785bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (unlikely(ret != 0))
9795bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		goto out_no_validate;
9805bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
9815bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
9825bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	/*
9835bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 * Encode the dma- and surface destroy commands.
9845bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 */
9855bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
9865bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	submit_size = vmw_surface_dma_size(srf) + vmw_surface_destroy_size();
9875bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	cmd = vmw_fifo_reserve(dev_priv, submit_size);
9885bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (unlikely(cmd == NULL)) {
9895bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		DRM_ERROR("Failed reserving FIFO space for surface "
9905bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			  "eviction.\n");
9915bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		ret = -ENOMEM;
9925bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		goto out_no_fifo;
9935bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	}
9945bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
9955bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	vmw_bo_get_guest_ptr(srf->backup, &ptr);
9965bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	vmw_surface_dma_encode(srf, cmd, &ptr, false);
9975bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	cmd += vmw_surface_dma_size(srf);
9985bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	vmw_surface_destroy_encode(res->id, cmd);
999fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	vmw_fifo_commit(dev_priv, submit_size);
10005bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
10015bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	/*
10025bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 * Surface memory usage accounting.
10035bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 */
10045bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
10055bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	dev_priv->used_memory_size -= srf->backup_size;
10065bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
10075bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	/*
10085bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 * Create a fence object and fence the DMA buffer.
10095bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 */
10105bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
10115bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	(void) vmw_execbuf_fence_commands(NULL, dev_priv,
10125bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom					  &fence, NULL);
10135bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	ttm_eu_fence_buffer_objects(&val_list, fence);
10145bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (likely(fence != NULL))
10155bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		vmw_fence_obj_unreference(&fence);
10165bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	ttm_bo_unref(&val_buf.bo);
10175bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
10185bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	/*
10195bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 * Release the surface ID.
10205bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 */
10215bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
10225bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	vmw_resource_release_id(res);
10235bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
10245bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	return 0;
10255bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
10265bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromout_no_fifo:
10275bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromout_no_validate:
10285bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (srf->backup)
10295bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		ttm_eu_backoff_reservation(&val_list);
10305bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromout_no_reserve:
10315bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	ttm_bo_unref(&val_buf.bo);
10325bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	ttm_bo_unref(&srf->backup);
10335bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	return ret;
10345bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom}
10355bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
10365bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
10375bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom/**
10385bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * vmw_surface_validate - make a surface available to the device, evicting
10395bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * other surfaces if needed.
10405bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
10415bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * @dev_priv: Pointer to a device private struct.
10425bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * @srf: Pointer to a struct vmw_surface.
10435bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
10445bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * Try to validate a surface and if it fails due to limited device resources,
10455bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * repeatedly try to evict other surfaces until the request can be
10465bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * acommodated.
10475bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
10485bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * May return errors if out of resources.
10495bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom */
10505bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromint vmw_surface_validate(struct vmw_private *dev_priv,
10515bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			 struct vmw_surface *srf)
10525bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom{
10535bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	int ret;
10545bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	struct vmw_surface *evict_srf;
10555bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
10565bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	do {
10575bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		write_lock(&dev_priv->resource_lock);
10585bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		list_del_init(&srf->lru_head);
10595bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		write_unlock(&dev_priv->resource_lock);
10605bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
10615bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		ret = vmw_surface_do_validate(dev_priv, srf);
10625bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		if (likely(ret != -EBUSY))
10635bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			break;
10645bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
10655bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		write_lock(&dev_priv->resource_lock);
10665bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		if (list_empty(&dev_priv->surface_lru)) {
10675bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			DRM_ERROR("Out of device memory for surfaces.\n");
10685bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			ret = -EBUSY;
10695bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			write_unlock(&dev_priv->resource_lock);
10705bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			break;
10715bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		}
10725bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
10735bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		evict_srf = vmw_surface_reference
10745bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			(list_first_entry(&dev_priv->surface_lru,
10755bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom					  struct vmw_surface,
10765bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom					  lru_head));
10775bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		list_del_init(&evict_srf->lru_head);
10785bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
10795bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		write_unlock(&dev_priv->resource_lock);
10805bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		(void) vmw_surface_evict(dev_priv, evict_srf);
10815bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
10825bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		vmw_surface_unreference(&evict_srf);
10835bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
10845bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	} while (1);
10855bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
10865bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (unlikely(ret != 0 && srf->res.id != -1)) {
10875bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		write_lock(&dev_priv->resource_lock);
10885bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		list_add_tail(&srf->lru_head, &dev_priv->surface_lru);
10895bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		write_unlock(&dev_priv->resource_lock);
10905bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	}
10915bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
10925bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	return ret;
10935bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom}
10945bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
10955bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
10965bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom/**
10975bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * vmw_surface_remove_from_lists - Remove surface resources from lookup lists
10985bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
10995bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * @res: Pointer to a struct vmw_resource embedded in a struct vmw_surface
11005bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
11015bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * As part of the resource destruction, remove the surface from any
11025bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * lookup lists.
11035bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom */
11045bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromstatic void vmw_surface_remove_from_lists(struct vmw_resource *res)
11055bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom{
11065bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	struct vmw_surface *srf = container_of(res, struct vmw_surface, res);
11075bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
11085bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	list_del_init(&srf->lru_head);
11095bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom}
11105bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
11115bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromint vmw_surface_init(struct vmw_private *dev_priv,
11125bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		     struct vmw_surface *srf,
11135bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		     void (*res_free) (struct vmw_resource *res))
11145bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom{
11155bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	int ret;
11165bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	struct vmw_resource *res = &srf->res;
11175bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
11185bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	BUG_ON(res_free == NULL);
11195bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	INIT_LIST_HEAD(&srf->lru_head);
11205bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	ret = vmw_resource_init(dev_priv, res, &dev_priv->surface_idr,
11215bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom				VMW_RES_SURFACE, true, res_free,
11225bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom				vmw_surface_remove_from_lists);
11235bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
11245bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (unlikely(ret != 0))
11255bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		res_free(res);
11265bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
11275bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	/*
11285bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 * The surface won't be visible to hardware until a
11295bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 * surface validate.
11305bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	 */
11315bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
113205730b32a78dab4bed8fb7ccc64c53d9fcf31e9dThomas Hellstrom	(void) vmw_3d_resource_inc(dev_priv, false);
1133fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	vmw_resource_activate(res, vmw_hw_surface_destroy);
11345bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	return ret;
1135fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1136fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1137fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstatic void vmw_user_surface_free(struct vmw_resource *res)
1138fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
1139fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_surface *srf = container_of(res, struct vmw_surface, res);
1140fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_user_surface *user_srf =
1141fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	    container_of(srf, struct vmw_user_surface, srf);
1142414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	struct vmw_private *dev_priv = srf->res.dev_priv;
1143414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	uint32_t size = user_srf->size;
1144fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
11455bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (srf->backup)
11465bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		ttm_bo_unref(&srf->backup);
11475bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	kfree(srf->offsets);
1148fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	kfree(srf->sizes);
1149fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	kfree(srf->snooper.image);
1150fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	kfree(user_srf);
1151414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	ttm_mem_global_free(vmw_mem_glob(dev_priv), size);
1152fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1153fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
11545bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom/**
11555bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * vmw_resource_unreserve - unreserve resources previously reserved for
11565bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * command submission.
11575bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
11585bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * @list_head: list of resources to unreserve.
11595bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom *
11605bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * Currently only surfaces are considered, and unreserving a surface
11615bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * means putting it back on the device's surface lru list,
11625bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * so that it can be evicted if necessary.
11635bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * This function traverses the resource list and
11645bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * checks whether resources are surfaces, and in that case puts them back
11655bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom * on the device's surface LRU list.
11665bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom */
11675bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromvoid vmw_resource_unreserve(struct list_head *list)
11685bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom{
11695bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	struct vmw_resource *res;
11705bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	struct vmw_surface *srf;
11715bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	rwlock_t *lock = NULL;
11725bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
11735bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	list_for_each_entry(res, list, validate_head) {
11745bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
11755bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		if (res->res_free != &vmw_surface_res_free &&
11765bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		    res->res_free != &vmw_user_surface_free)
11775bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			continue;
11785bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
11795bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		if (unlikely(lock == NULL)) {
11805bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			lock = &res->dev_priv->resource_lock;
11815bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			write_lock(lock);
11825bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		}
11835bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
11845bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		srf = container_of(res, struct vmw_surface, res);
11855bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		list_del_init(&srf->lru_head);
11865bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		list_add_tail(&srf->lru_head, &res->dev_priv->surface_lru);
11875bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	}
11885bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
11895bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (lock != NULL)
11905bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		write_unlock(lock);
11915bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom}
11925bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
1193551a6697d08f92a311d6adbf8d03af2bc7f9e2eeJakob Bornecrantz/**
1194551a6697d08f92a311d6adbf8d03af2bc7f9e2eeJakob Bornecrantz * Helper function that looks either a surface or dmabuf.
1195551a6697d08f92a311d6adbf8d03af2bc7f9e2eeJakob Bornecrantz *
1196551a6697d08f92a311d6adbf8d03af2bc7f9e2eeJakob Bornecrantz * The pointer this pointed at by out_surf and out_buf needs to be null.
1197551a6697d08f92a311d6adbf8d03af2bc7f9e2eeJakob Bornecrantz */
1198551a6697d08f92a311d6adbf8d03af2bc7f9e2eeJakob Bornecrantzint vmw_user_lookup_handle(struct vmw_private *dev_priv,
1199551a6697d08f92a311d6adbf8d03af2bc7f9e2eeJakob Bornecrantz			   struct ttm_object_file *tfile,
1200551a6697d08f92a311d6adbf8d03af2bc7f9e2eeJakob Bornecrantz			   uint32_t handle,
1201551a6697d08f92a311d6adbf8d03af2bc7f9e2eeJakob Bornecrantz			   struct vmw_surface **out_surf,
1202551a6697d08f92a311d6adbf8d03af2bc7f9e2eeJakob Bornecrantz			   struct vmw_dma_buffer **out_buf)
1203551a6697d08f92a311d6adbf8d03af2bc7f9e2eeJakob Bornecrantz{
1204551a6697d08f92a311d6adbf8d03af2bc7f9e2eeJakob Bornecrantz	int ret;
1205551a6697d08f92a311d6adbf8d03af2bc7f9e2eeJakob Bornecrantz
1206551a6697d08f92a311d6adbf8d03af2bc7f9e2eeJakob Bornecrantz	BUG_ON(*out_surf || *out_buf);
1207551a6697d08f92a311d6adbf8d03af2bc7f9e2eeJakob Bornecrantz
1208551a6697d08f92a311d6adbf8d03af2bc7f9e2eeJakob Bornecrantz	ret = vmw_user_surface_lookup_handle(dev_priv, tfile, handle, out_surf);
1209551a6697d08f92a311d6adbf8d03af2bc7f9e2eeJakob Bornecrantz	if (!ret)
1210551a6697d08f92a311d6adbf8d03af2bc7f9e2eeJakob Bornecrantz		return 0;
1211551a6697d08f92a311d6adbf8d03af2bc7f9e2eeJakob Bornecrantz
1212551a6697d08f92a311d6adbf8d03af2bc7f9e2eeJakob Bornecrantz	ret = vmw_user_dmabuf_lookup(tfile, handle, out_buf);
1213551a6697d08f92a311d6adbf8d03af2bc7f9e2eeJakob Bornecrantz	return ret;
1214551a6697d08f92a311d6adbf8d03af2bc7f9e2eeJakob Bornecrantz}
1215551a6697d08f92a311d6adbf8d03af2bc7f9e2eeJakob Bornecrantz
12165bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
12177a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstromint vmw_user_surface_lookup_handle(struct vmw_private *dev_priv,
12187a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom				   struct ttm_object_file *tfile,
12197a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom				   uint32_t handle, struct vmw_surface **out)
1220fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
1221fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_resource *res;
1222fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_surface *srf;
1223fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_user_surface *user_srf;
12247a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	struct ttm_base_object *base;
12257a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	int ret = -EINVAL;
1226fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
12277a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	base = ttm_base_object_lookup(tfile, handle);
12287a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	if (unlikely(base == NULL))
1229fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return -EINVAL;
1230fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
12317a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	if (unlikely(base->object_type != VMW_RES_SURFACE))
12327a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom		goto out_bad_resource;
12337a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom
12347a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	user_srf = container_of(base, struct vmw_user_surface, base);
12357a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	srf = &user_srf->srf;
12367a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	res = &srf->res;
12377a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom
12387a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	read_lock(&dev_priv->resource_lock);
12397a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom
12407a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	if (!res->avail || res->res_free != &vmw_user_surface_free) {
12417a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom		read_unlock(&dev_priv->resource_lock);
12427a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom		goto out_bad_resource;
12437a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	}
1244fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
12457a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	kref_get(&res->kref);
12467a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	read_unlock(&dev_priv->resource_lock);
1247fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1248fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	*out = srf;
12497a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	ret = 0;
12507a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom
12517a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstromout_bad_resource:
12527a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	ttm_base_object_unref(&base);
12537a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom
12547a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	return ret;
1255fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1256fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1257fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstatic void vmw_user_surface_base_release(struct ttm_base_object **p_base)
1258fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
1259fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct ttm_base_object *base = *p_base;
1260fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_user_surface *user_srf =
1261fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	    container_of(base, struct vmw_user_surface, base);
1262fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_resource *res = &user_srf->srf.res;
1263fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1264fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	*p_base = NULL;
1265fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	vmw_resource_unreference(&res);
1266fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1267fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1268fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzint vmw_surface_destroy_ioctl(struct drm_device *dev, void *data,
1269fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			      struct drm_file *file_priv)
1270fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
1271fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct drm_vmw_surface_arg *arg = (struct drm_vmw_surface_arg *)data;
1272fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
1273fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
12747a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	return ttm_ref_object_base_unref(tfile, arg->sid, TTM_REF_USAGE);
1275fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1276fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1277fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzint vmw_surface_define_ioctl(struct drm_device *dev, void *data,
1278fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			     struct drm_file *file_priv)
1279fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
1280fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_private *dev_priv = vmw_priv(dev);
12810c5d37033b3a16fdf6442730cee82dd3e8465fb1Dan Carpenter	struct vmw_user_surface *user_srf;
1282fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_surface *srf;
1283fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_resource *res;
1284fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_resource *tmp;
1285fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	union drm_vmw_surface_create_arg *arg =
1286fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	    (union drm_vmw_surface_create_arg *)data;
1287fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct drm_vmw_surface_create_req *req = &arg->req;
1288fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct drm_vmw_surface_arg *rep = &arg->rep;
1289fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
1290fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct drm_vmw_size __user *user_sizes;
1291fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	int ret;
12925bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	int i, j;
12935bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	uint32_t cur_bo_offset;
12945bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	struct drm_vmw_size *cur_size;
12955bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	struct vmw_surface_offset *cur_offset;
12965bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	uint32_t stride_bpp;
12975bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	uint32_t bpp;
1298414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	uint32_t num_sizes;
1299414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	uint32_t size;
1300414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	struct vmw_master *vmaster = vmw_master(file_priv->master);
1301fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1302414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	if (unlikely(vmw_user_surface_size == 0))
1303414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) +
1304414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom			128;
1305414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom
1306414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	num_sizes = 0;
1307414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i)
1308414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		num_sizes += req->mip_levels[i];
1309414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom
1310414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	if (num_sizes > DRM_VMW_MAX_SURFACE_FACES *
1311414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	    DRM_VMW_MAX_MIP_LEVELS)
1312414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		return -EINVAL;
1313414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom
1314414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	size = vmw_user_surface_size + 128 +
1315414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		ttm_round_pot(num_sizes * sizeof(struct drm_vmw_size)) +
1316414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		ttm_round_pot(num_sizes * sizeof(struct vmw_surface_offset));
1317414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom
1318414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom
1319414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	ret = ttm_read_lock(&vmaster->lock, true);
1320414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	if (unlikely(ret != 0))
1321414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		return ret;
1322414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom
1323414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
1324414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom				   size, false, true);
1325414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	if (unlikely(ret != 0)) {
1326414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		if (ret != -ERESTARTSYS)
1327414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom			DRM_ERROR("Out of graphics memory for surface"
1328414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom				  " creation.\n");
1329414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		goto out_unlock;
1330414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	}
1331414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom
1332414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	user_srf = kmalloc(sizeof(*user_srf), GFP_KERNEL);
1333414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	if (unlikely(user_srf == NULL)) {
1334414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		ret = -ENOMEM;
1335414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		goto out_no_user_srf;
1336414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	}
1337fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1338fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	srf = &user_srf->srf;
1339fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	res = &srf->res;
1340fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1341fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	srf->flags = req->flags;
1342fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	srf->format = req->format;
1343a87897edbae2d60db7bcb6bb0a75e82013d68305Jakob Bornecrantz	srf->scanout = req->scanout;
13445bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	srf->backup = NULL;
13455bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
1346fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	memcpy(srf->mip_levels, req->mip_levels, sizeof(srf->mip_levels));
1347414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	srf->num_sizes = num_sizes;
1348414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	user_srf->size = size;
1349fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1350fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	srf->sizes = kmalloc(srf->num_sizes * sizeof(*srf->sizes), GFP_KERNEL);
1351fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(srf->sizes == NULL)) {
1352fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		ret = -ENOMEM;
1353414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		goto out_no_sizes;
1354fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
13555bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	srf->offsets = kmalloc(srf->num_sizes * sizeof(*srf->offsets),
13565bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			       GFP_KERNEL);
13575bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	if (unlikely(srf->sizes == NULL)) {
13585bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		ret = -ENOMEM;
13595bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		goto out_no_offsets;
13605bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	}
1361fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1362fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	user_sizes = (struct drm_vmw_size __user *)(unsigned long)
1363fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	    req->size_addr;
1364fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1365fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ret = copy_from_user(srf->sizes, user_sizes,
1366fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			     srf->num_sizes * sizeof(*srf->sizes));
13679b8eb4d14767209c83087063352cd04266ecdfd1Dan Carpenter	if (unlikely(ret != 0)) {
13689b8eb4d14767209c83087063352cd04266ecdfd1Dan Carpenter		ret = -EFAULT;
1369414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		goto out_no_copy;
13709b8eb4d14767209c83087063352cd04266ecdfd1Dan Carpenter	}
1371fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
13725bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	cur_bo_offset = 0;
13735bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	cur_offset = srf->offsets;
13745bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	cur_size = srf->sizes;
13755bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
13765bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	bpp = vmw_sf_bpp[srf->format].bpp;
13775bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	stride_bpp = vmw_sf_bpp[srf->format].s_bpp;
13785bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
13795bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	for (i = 0; i < DRM_VMW_MAX_SURFACE_FACES; ++i) {
13805bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		for (j = 0; j < srf->mip_levels[i]; ++j) {
13815bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			uint32_t stride =
13825bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom				(cur_size->width * stride_bpp + 7) >> 3;
13835bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
13845bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			cur_offset->face = i;
13855bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			cur_offset->mip = j;
13865bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			cur_offset->bo_offset = cur_bo_offset;
13875bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			cur_bo_offset += stride * cur_size->height *
13885bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom				cur_size->depth * bpp / stride_bpp;
13895bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			++cur_offset;
13905bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom			++cur_size;
13915bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom		}
13925bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	}
13935bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	srf->backup_size = cur_bo_offset;
13945bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom
13955ffdb658f605cbc420944e7c7eeec9fbb8a73772Jakob Bornecrantz	if (srf->scanout &&
139650ec3b7c35fda131e92abc6f9d93a230b7e009ebThomas Hellstrom	    srf->num_sizes == 1 &&
139750ec3b7c35fda131e92abc6f9d93a230b7e009ebThomas Hellstrom	    srf->sizes[0].width == 64 &&
139850ec3b7c35fda131e92abc6f9d93a230b7e009ebThomas Hellstrom	    srf->sizes[0].height == 64 &&
139950ec3b7c35fda131e92abc6f9d93a230b7e009ebThomas Hellstrom	    srf->format == SVGA3D_A8R8G8B8) {
140050ec3b7c35fda131e92abc6f9d93a230b7e009ebThomas Hellstrom
1401f35119d6681300ba6d76da53cb1ebc2eed62e77aRakib Mullick		/* allocate image area and clear it */
1402f35119d6681300ba6d76da53cb1ebc2eed62e77aRakib Mullick		srf->snooper.image = kzalloc(64 * 64 * 4, GFP_KERNEL);
1403f35119d6681300ba6d76da53cb1ebc2eed62e77aRakib Mullick		if (!srf->snooper.image) {
140450ec3b7c35fda131e92abc6f9d93a230b7e009ebThomas Hellstrom			DRM_ERROR("Failed to allocate cursor_image\n");
140550ec3b7c35fda131e92abc6f9d93a230b7e009ebThomas Hellstrom			ret = -ENOMEM;
1406414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom			goto out_no_copy;
140750ec3b7c35fda131e92abc6f9d93a230b7e009ebThomas Hellstrom		}
140850ec3b7c35fda131e92abc6f9d93a230b7e009ebThomas Hellstrom	} else {
140950ec3b7c35fda131e92abc6f9d93a230b7e009ebThomas Hellstrom		srf->snooper.image = NULL;
141050ec3b7c35fda131e92abc6f9d93a230b7e009ebThomas Hellstrom	}
141150ec3b7c35fda131e92abc6f9d93a230b7e009ebThomas Hellstrom	srf->snooper.crtc = NULL;
141250ec3b7c35fda131e92abc6f9d93a230b7e009ebThomas Hellstrom
1413fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	user_srf->base.shareable = false;
1414fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	user_srf->base.tfile = NULL;
1415fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1416fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	/**
1417fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	 * From this point, the generic resource management functions
1418fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	 * destroy the object on failure.
1419fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	 */
1420fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1421fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ret = vmw_surface_init(dev_priv, srf, vmw_user_surface_free);
1422fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(ret != 0))
1423414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		goto out_unlock;
1424fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1425fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	tmp = vmw_resource_reference(&srf->res);
1426fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ret = ttm_base_object_init(tfile, &user_srf->base,
1427fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz				   req->shareable, VMW_RES_SURFACE,
1428fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz				   &vmw_user_surface_base_release, NULL);
1429fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1430fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(ret != 0)) {
1431fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		vmw_resource_unreference(&tmp);
1432fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		vmw_resource_unreference(&res);
1433414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		goto out_unlock;
1434fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
1435fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
14367a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	rep->sid = user_srf->base.hash.key;
14377a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	if (rep->sid == SVGA3D_INVALID_ID)
14387a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom		DRM_ERROR("Created bad Surface ID.\n");
14397a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom
1440fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	vmw_resource_unreference(&res);
1441414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom
1442414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	ttm_read_unlock(&vmaster->lock);
1443fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return 0;
1444414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstromout_no_copy:
14455bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom	kfree(srf->offsets);
14465bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstromout_no_offsets:
1447fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	kfree(srf->sizes);
1448414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstromout_no_sizes:
1449fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	kfree(user_srf);
1450414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstromout_no_user_srf:
1451414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	ttm_mem_global_free(vmw_mem_glob(dev_priv), size);
1452414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstromout_unlock:
1453414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	ttm_read_unlock(&vmaster->lock);
1454fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return ret;
1455fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1456fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1457fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzint vmw_surface_reference_ioctl(struct drm_device *dev, void *data,
1458fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz				struct drm_file *file_priv)
1459fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
1460fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	union drm_vmw_surface_reference_arg *arg =
1461fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	    (union drm_vmw_surface_reference_arg *)data;
1462fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct drm_vmw_surface_arg *req = &arg->req;
1463fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct drm_vmw_surface_create_req *rep = &arg->rep;
1464fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
1465fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_surface *srf;
1466fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_user_surface *user_srf;
1467fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct drm_vmw_size __user *user_sizes;
14687a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	struct ttm_base_object *base;
14697a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	int ret = -EINVAL;
1470fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
14717a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	base = ttm_base_object_lookup(tfile, req->sid);
14727a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	if (unlikely(base == NULL)) {
14737a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom		DRM_ERROR("Could not find surface to reference.\n");
1474fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return -EINVAL;
1475fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
1476fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
14777a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	if (unlikely(base->object_type != VMW_RES_SURFACE))
14787a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom		goto out_bad_resource;
14797a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom
14807a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	user_srf = container_of(base, struct vmw_user_surface, base);
14817a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	srf = &user_srf->srf;
1482fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1483fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ret = ttm_ref_object_add(tfile, &user_srf->base, TTM_REF_USAGE, NULL);
1484fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(ret != 0)) {
1485fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		DRM_ERROR("Could not add a reference to a surface.\n");
14867a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom		goto out_no_reference;
1487fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
1488fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1489fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	rep->flags = srf->flags;
1490fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	rep->format = srf->format;
1491fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	memcpy(rep->mip_levels, srf->mip_levels, sizeof(srf->mip_levels));
1492fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	user_sizes = (struct drm_vmw_size __user *)(unsigned long)
1493fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	    rep->size_addr;
1494fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1495fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (user_sizes)
1496fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		ret = copy_to_user(user_sizes, srf->sizes,
1497fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz				   srf->num_sizes * sizeof(*srf->sizes));
14989b8eb4d14767209c83087063352cd04266ecdfd1Dan Carpenter	if (unlikely(ret != 0)) {
1499fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		DRM_ERROR("copy_to_user failed %p %u\n",
1500fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			  user_sizes, srf->num_sizes);
15019b8eb4d14767209c83087063352cd04266ecdfd1Dan Carpenter		ret = -EFAULT;
15029b8eb4d14767209c83087063352cd04266ecdfd1Dan Carpenter	}
15037a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstromout_bad_resource:
15047a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstromout_no_reference:
15057a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	ttm_base_object_unref(&base);
15067a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom
1507fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return ret;
1508fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1509fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1510fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzint vmw_surface_check(struct vmw_private *dev_priv,
1511fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		      struct ttm_object_file *tfile,
15127a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom		      uint32_t handle, int *id)
1513fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
15147a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	struct ttm_base_object *base;
15157a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	struct vmw_user_surface *user_srf;
1516fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
15177a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	int ret = -EPERM;
1518fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
15197a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	base = ttm_base_object_lookup(tfile, handle);
15207a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	if (unlikely(base == NULL))
15217a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom		return -EINVAL;
15227a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom
15237a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	if (unlikely(base->object_type != VMW_RES_SURFACE))
15247a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom		goto out_bad_surface;
15257a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom
15267a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	user_srf = container_of(base, struct vmw_user_surface, base);
15277a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	*id = user_srf->srf.res.id;
15287a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	ret = 0;
15297a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom
15307a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstromout_bad_surface:
15317a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	/**
15327a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	 * FIXME: May deadlock here when called from the
15337a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	 * command parsing code.
15347a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	 */
1535fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
15367a73ba7469cbea631050094fd14f73acebb97cf9Thomas Hellstrom	ttm_base_object_unref(&base);
1537fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return ret;
1538fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1539fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1540fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz/**
1541fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * Buffer management.
1542fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz */
1543effe1105bef07f42366c20eac41b80ff9fcf675eThomas Hellstromvoid vmw_dmabuf_bo_free(struct ttm_buffer_object *bo)
1544effe1105bef07f42366c20eac41b80ff9fcf675eThomas Hellstrom{
1545effe1105bef07f42366c20eac41b80ff9fcf675eThomas Hellstrom	struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
1546effe1105bef07f42366c20eac41b80ff9fcf675eThomas Hellstrom
1547fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	kfree(vmw_bo);
1548fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1549fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1550fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzint vmw_dmabuf_init(struct vmw_private *dev_priv,
1551fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		    struct vmw_dma_buffer *vmw_bo,
1552fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		    size_t size, struct ttm_placement *placement,
1553fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		    bool interruptible,
1554fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		    void (*bo_free) (struct ttm_buffer_object *bo))
1555fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
1556fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct ttm_bo_device *bdev = &dev_priv->bdev;
1557fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	size_t acc_size;
1558fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	int ret;
1559fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1560fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	BUG_ON(!bo_free);
1561fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
156257de4ba959b290f0b8cf36ecd5e7f1b29d4b8a12Jerome Glisse	acc_size = ttm_bo_acc_size(bdev, size, sizeof(struct vmw_dma_buffer));
1563fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	memset(vmw_bo, 0, sizeof(*vmw_bo));
1564fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1565fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	INIT_LIST_HEAD(&vmw_bo->validate_list);
1566fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1567fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ret = ttm_bo_init(bdev, &vmw_bo->base, size,
1568fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			  ttm_bo_type_device, placement,
1569fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			  0, 0, interruptible,
1570fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			  NULL, acc_size, bo_free);
1571fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return ret;
1572fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1573fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1574fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstatic void vmw_user_dmabuf_destroy(struct ttm_buffer_object *bo)
1575fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
1576fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_user_dma_buffer *vmw_user_bo = vmw_user_dma_buffer(bo);
1577fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1578fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	kfree(vmw_user_bo);
1579fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1580fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1581fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstatic void vmw_user_dmabuf_release(struct ttm_base_object **p_base)
1582fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
1583fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_user_dma_buffer *vmw_user_bo;
1584fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct ttm_base_object *base = *p_base;
1585fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct ttm_buffer_object *bo;
1586fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1587fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	*p_base = NULL;
1588fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1589fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(base == NULL))
1590fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return;
1591fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1592fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	vmw_user_bo = container_of(base, struct vmw_user_dma_buffer, base);
1593fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	bo = &vmw_user_bo->dma.base;
1594fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ttm_bo_unref(&bo);
1595fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1596fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1597fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzint vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data,
1598fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			   struct drm_file *file_priv)
1599fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
1600fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_private *dev_priv = vmw_priv(dev);
1601fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	union drm_vmw_alloc_dmabuf_arg *arg =
1602fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	    (union drm_vmw_alloc_dmabuf_arg *)data;
1603fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct drm_vmw_alloc_dmabuf_req *req = &arg->req;
1604fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct drm_vmw_dmabuf_rep *rep = &arg->rep;
1605fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_user_dma_buffer *vmw_user_bo;
1606fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct ttm_buffer_object *tmp;
1607fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_master *vmaster = vmw_master(file_priv->master);
1608fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	int ret;
1609fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1610fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	vmw_user_bo = kzalloc(sizeof(*vmw_user_bo), GFP_KERNEL);
1611fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(vmw_user_bo == NULL))
1612fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return -ENOMEM;
1613fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1614fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ret = ttm_read_lock(&vmaster->lock, true);
1615fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(ret != 0)) {
1616fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		kfree(vmw_user_bo);
1617fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return ret;
1618fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
1619fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1620fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ret = vmw_dmabuf_init(dev_priv, &vmw_user_bo->dma, req->size,
16218ba5152a3acd5914cade42a1c8c9dc58ad8d1a89Thomas Hellstrom			      &vmw_vram_sys_placement, true,
1622fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			      &vmw_user_dmabuf_destroy);
1623fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(ret != 0))
16242f5993cca67f9c80dcd390feef13695ca072b8a5Thomas Hellstrom		goto out_no_dmabuf;
1625fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1626fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	tmp = ttm_bo_reference(&vmw_user_bo->dma.base);
1627fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ret = ttm_base_object_init(vmw_fpriv(file_priv)->tfile,
1628fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz				   &vmw_user_bo->base,
1629fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz				   false,
1630fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz				   ttm_buffer_type,
1631fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz				   &vmw_user_dmabuf_release, NULL);
16322f5993cca67f9c80dcd390feef13695ca072b8a5Thomas Hellstrom	if (unlikely(ret != 0))
16332f5993cca67f9c80dcd390feef13695ca072b8a5Thomas Hellstrom		goto out_no_base_object;
16342f5993cca67f9c80dcd390feef13695ca072b8a5Thomas Hellstrom	else {
1635fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		rep->handle = vmw_user_bo->base.hash.key;
1636fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		rep->map_handle = vmw_user_bo->dma.base.addr_space_offset;
1637fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		rep->cur_gmr_id = vmw_user_bo->base.hash.key;
1638fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		rep->cur_gmr_offset = 0;
1639fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
1640fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
16412f5993cca67f9c80dcd390feef13695ca072b8a5Thomas Hellstromout_no_base_object:
16422f5993cca67f9c80dcd390feef13695ca072b8a5Thomas Hellstrom	ttm_bo_unref(&tmp);
16432f5993cca67f9c80dcd390feef13695ca072b8a5Thomas Hellstromout_no_dmabuf:
1644fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ttm_read_unlock(&vmaster->lock);
1645fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
16462f5993cca67f9c80dcd390feef13695ca072b8a5Thomas Hellstrom	return ret;
1647fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1648fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1649fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzint vmw_dmabuf_unref_ioctl(struct drm_device *dev, void *data,
1650fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			   struct drm_file *file_priv)
1651fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
1652fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct drm_vmw_unref_dmabuf_arg *arg =
1653fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	    (struct drm_vmw_unref_dmabuf_arg *)data;
1654fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1655fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile,
1656fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz					 arg->handle,
1657fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz					 TTM_REF_USAGE);
1658fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1659fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1660fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzuint32_t vmw_dmabuf_validate_node(struct ttm_buffer_object *bo,
1661fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz				  uint32_t cur_validate_node)
1662fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
1663fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
1664fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1665fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (likely(vmw_bo->on_validate_list))
1666fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return vmw_bo->cur_validate_node;
1667fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1668fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	vmw_bo->cur_validate_node = cur_validate_node;
1669fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	vmw_bo->on_validate_list = true;
1670fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1671fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return cur_validate_node;
1672fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1673fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1674fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzvoid vmw_dmabuf_validate_clear(struct ttm_buffer_object *bo)
1675fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
1676fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_dma_buffer *vmw_bo = vmw_dma_buffer(bo);
1677fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1678fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	vmw_bo->on_validate_list = false;
1679fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1680fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1681fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzint vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
1682fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			   uint32_t handle, struct vmw_dma_buffer **out)
1683fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
1684fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_user_dma_buffer *vmw_user_bo;
1685fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct ttm_base_object *base;
1686fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1687fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	base = ttm_base_object_lookup(tfile, handle);
1688fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(base == NULL)) {
1689fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		printk(KERN_ERR "Invalid buffer object handle 0x%08lx.\n",
1690fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		       (unsigned long)handle);
1691fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return -ESRCH;
1692fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
1693fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1694fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(base->object_type != ttm_buffer_type)) {
1695fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		ttm_base_object_unref(&base);
1696fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		printk(KERN_ERR "Invalid buffer object handle 0x%08lx.\n",
1697fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		       (unsigned long)handle);
1698fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return -EINVAL;
1699fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
1700fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1701fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	vmw_user_bo = container_of(base, struct vmw_user_dma_buffer, base);
1702fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	(void)ttm_bo_reference(&vmw_user_bo->dma.base);
1703fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ttm_base_object_unref(&base);
1704fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	*out = &vmw_user_bo->dma;
1705fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1706fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return 0;
1707fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1708fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1709fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz/*
171065155b3708137fabee865dc4da822763c0c41208Uwe Kleine-König * Stream management
1711fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz */
1712fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1713fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstatic void vmw_stream_destroy(struct vmw_resource *res)
1714fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
1715fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_private *dev_priv = res->dev_priv;
1716fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_stream *stream;
1717fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	int ret;
1718fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1719fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	DRM_INFO("%s: unref\n", __func__);
1720fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	stream = container_of(res, struct vmw_stream, res);
1721fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1722fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ret = vmw_overlay_unref(dev_priv, stream->stream_id);
1723fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	WARN_ON(ret != 0);
1724fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1725fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1726fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstatic int vmw_stream_init(struct vmw_private *dev_priv,
1727fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			   struct vmw_stream *stream,
1728fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			   void (*res_free) (struct vmw_resource *res))
1729fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
1730fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_resource *res = &stream->res;
1731fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	int ret;
1732fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1733fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ret = vmw_resource_init(dev_priv, res, &dev_priv->stream_idr,
17345bb39e818169783ee17ddbbefbd7bd16a4383fecThomas Hellstrom				VMW_RES_STREAM, false, res_free, NULL);
1735fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1736fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(ret != 0)) {
1737fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		if (res_free == NULL)
1738fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			kfree(stream);
1739fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		else
1740fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			res_free(&stream->res);
1741fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return ret;
1742fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
1743fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1744fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ret = vmw_overlay_claim(dev_priv, &stream->stream_id);
1745fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (ret) {
1746fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		vmw_resource_unreference(&res);
1747fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return ret;
1748fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
1749fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1750fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	DRM_INFO("%s: claimed\n", __func__);
1751fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1752fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	vmw_resource_activate(&stream->res, vmw_stream_destroy);
1753fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return 0;
1754fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1755fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1756fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz/**
1757fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * User-space context management:
1758fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz */
1759fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1760fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstatic void vmw_user_stream_free(struct vmw_resource *res)
1761fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
1762fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_user_stream *stream =
1763fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	    container_of(res, struct vmw_user_stream, stream.res);
1764414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	struct vmw_private *dev_priv = res->dev_priv;
1765fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1766fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	kfree(stream);
1767414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	ttm_mem_global_free(vmw_mem_glob(dev_priv),
1768414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom			    vmw_user_stream_size);
1769fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1770fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1771fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz/**
1772fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * This function is called when user space has no more references on the
1773fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz * base object. It releases the base-object's reference on the resource object.
1774fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz */
1775fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1776fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzstatic void vmw_user_stream_base_release(struct ttm_base_object **p_base)
1777fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
1778fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct ttm_base_object *base = *p_base;
1779fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_user_stream *stream =
1780fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	    container_of(base, struct vmw_user_stream, base);
1781fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_resource *res = &stream->stream.res;
1782fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1783fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	*p_base = NULL;
1784fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	vmw_resource_unreference(&res);
1785fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1786fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1787fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzint vmw_stream_unref_ioctl(struct drm_device *dev, void *data,
1788fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			   struct drm_file *file_priv)
1789fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
1790fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_private *dev_priv = vmw_priv(dev);
1791fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_resource *res;
1792fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_user_stream *stream;
1793fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct drm_vmw_stream_arg *arg = (struct drm_vmw_stream_arg *)data;
1794fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
1795fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	int ret = 0;
1796fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1797fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	res = vmw_resource_lookup(dev_priv, &dev_priv->stream_idr, arg->stream_id);
1798fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(res == NULL))
1799fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return -EINVAL;
1800fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1801fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (res->res_free != &vmw_user_stream_free) {
1802fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		ret = -EINVAL;
1803fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		goto out;
1804fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
1805fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1806fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	stream = container_of(res, struct vmw_user_stream, stream.res);
1807fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (stream->base.tfile != tfile) {
1808fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		ret = -EINVAL;
1809fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		goto out;
1810fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
1811fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1812fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ttm_ref_object_base_unref(tfile, stream->base.hash.key, TTM_REF_USAGE);
1813fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzout:
1814fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	vmw_resource_unreference(&res);
1815fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return ret;
1816fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1817fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1818fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzint vmw_stream_claim_ioctl(struct drm_device *dev, void *data,
1819fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			   struct drm_file *file_priv)
1820fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
1821fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_private *dev_priv = vmw_priv(dev);
1822414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	struct vmw_user_stream *stream;
1823fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_resource *res;
1824fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_resource *tmp;
1825fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct drm_vmw_stream_arg *arg = (struct drm_vmw_stream_arg *)data;
1826fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
1827414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	struct vmw_master *vmaster = vmw_master(file_priv->master);
1828fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	int ret;
1829fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1830414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	/*
1831414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	 * Approximate idr memory usage with 128 bytes. It will be limited
1832414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	 * by maximum number_of streams anyway?
1833414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	 */
1834414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom
1835414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	if (unlikely(vmw_user_stream_size == 0))
1836414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		vmw_user_stream_size = ttm_round_pot(sizeof(*stream)) + 128;
1837414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom
1838414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	ret = ttm_read_lock(&vmaster->lock, true);
1839414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	if (unlikely(ret != 0))
1840414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		return ret;
1841414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom
1842414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
1843414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom				   vmw_user_stream_size,
1844414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom				   false, true);
1845414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	if (unlikely(ret != 0)) {
1846414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		if (ret != -ERESTARTSYS)
1847414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom			DRM_ERROR("Out of graphics memory for stream"
1848414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom				  " creation.\n");
1849414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		goto out_unlock;
1850414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	}
1851414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom
1852414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom
1853414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	stream = kmalloc(sizeof(*stream), GFP_KERNEL);
1854414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	if (unlikely(stream == NULL)) {
1855414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		ttm_mem_global_free(vmw_mem_glob(dev_priv),
1856414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom				    vmw_user_stream_size);
1857414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		ret = -ENOMEM;
1858414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		goto out_unlock;
1859414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	}
1860fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1861fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	res = &stream->stream.res;
1862fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	stream->base.shareable = false;
1863fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	stream->base.tfile = NULL;
1864fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1865414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	/*
1866414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	 * From here on, the destructor takes over resource freeing.
1867414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	 */
1868414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom
1869fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ret = vmw_stream_init(dev_priv, &stream->stream, vmw_user_stream_free);
1870fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(ret != 0))
1871414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom		goto out_unlock;
1872fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1873fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	tmp = vmw_resource_reference(res);
1874fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	ret = ttm_base_object_init(tfile, &stream->base, false, VMW_RES_STREAM,
1875fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz				   &vmw_user_stream_base_release, NULL);
1876fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1877fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(ret != 0)) {
1878fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		vmw_resource_unreference(&tmp);
1879fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		goto out_err;
1880fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
1881fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1882fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	arg->stream_id = res->id;
1883fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzout_err:
1884fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	vmw_resource_unreference(&res);
1885414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstromout_unlock:
1886414ee50b3a111983056b1a828fac08f9e8fbc7e9Thomas Hellstrom	ttm_read_unlock(&vmaster->lock);
1887fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return ret;
1888fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1889fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1890fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzint vmw_user_stream_lookup(struct vmw_private *dev_priv,
1891fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			   struct ttm_object_file *tfile,
1892fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz			   uint32_t *inout_id, struct vmw_resource **out)
1893fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz{
1894fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_user_stream *stream;
1895fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	struct vmw_resource *res;
1896fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	int ret;
1897fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1898fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	res = vmw_resource_lookup(dev_priv, &dev_priv->stream_idr, *inout_id);
1899fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (unlikely(res == NULL))
1900fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		return -EINVAL;
1901fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1902fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (res->res_free != &vmw_user_stream_free) {
1903fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		ret = -EINVAL;
1904fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		goto err_ref;
1905fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
1906fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1907fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	stream = container_of(res, struct vmw_user_stream, stream.res);
1908fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	if (stream->base.tfile != tfile) {
1909fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		ret = -EPERM;
1910fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz		goto err_ref;
1911fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	}
1912fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz
1913fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	*inout_id = stream->stream.stream_id;
1914fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	*out = res;
1915fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return 0;
1916fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantzerr_ref:
1917fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	vmw_resource_unreference(&res);
1918fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz	return ret;
1919fb1d9738ca053ea8afa5e86af6463155f983b01cJakob Bornecrantz}
1920