brintos

brintos / linux-shallow public Read only

0
0
Text · 9.3 KiB · 66635c5 Raw
419 lines · c
1/*2 * Copyright 2013 Red Hat Inc.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice shall be included in12 * all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR20 * OTHER DEALINGS IN THE SOFTWARE.21 *22 * Authors: Dave Airlie23 *          Alon Levy24 */25 26#include <linux/iosys-map.h>27#include <linux/io-mapping.h>28 29#include "qxl_drv.h"30#include "qxl_object.h"31 32static void qxl_ttm_bo_destroy(struct ttm_buffer_object *tbo)33{34	struct qxl_bo *bo;35	struct qxl_device *qdev;36 37	bo = to_qxl_bo(tbo);38	qdev = to_qxl(bo->tbo.base.dev);39 40	qxl_surface_evict(qdev, bo, false);41	WARN_ON_ONCE(bo->map_count > 0);42	mutex_lock(&qdev->gem.mutex);43	list_del_init(&bo->list);44	mutex_unlock(&qdev->gem.mutex);45	drm_gem_object_release(&bo->tbo.base);46	kfree(bo);47}48 49bool qxl_ttm_bo_is_qxl_bo(struct ttm_buffer_object *bo)50{51	if (bo->destroy == &qxl_ttm_bo_destroy)52		return true;53	return false;54}55 56void qxl_ttm_placement_from_domain(struct qxl_bo *qbo, u32 domain)57{58	u32 c = 0;59	u32 pflag = 0;60	unsigned int i;61 62	if (qbo->tbo.base.size <= PAGE_SIZE)63		pflag |= TTM_PL_FLAG_TOPDOWN;64 65	qbo->placement.placement = qbo->placements;66	if (domain == QXL_GEM_DOMAIN_VRAM) {67		qbo->placements[c].mem_type = TTM_PL_VRAM;68		qbo->placements[c++].flags = pflag;69	}70	if (domain == QXL_GEM_DOMAIN_SURFACE) {71		qbo->placements[c].mem_type = TTM_PL_PRIV;72		qbo->placements[c++].flags = pflag;73		qbo->placements[c].mem_type = TTM_PL_VRAM;74		qbo->placements[c++].flags = pflag;75	}76	if (domain == QXL_GEM_DOMAIN_CPU) {77		qbo->placements[c].mem_type = TTM_PL_SYSTEM;78		qbo->placements[c++].flags = pflag;79	}80	if (!c) {81		qbo->placements[c].mem_type = TTM_PL_SYSTEM;82		qbo->placements[c++].flags = 0;83	}84	qbo->placement.num_placement = c;85	for (i = 0; i < c; ++i) {86		qbo->placements[i].fpfn = 0;87		qbo->placements[i].lpfn = 0;88	}89}90 91static const struct drm_gem_object_funcs qxl_object_funcs = {92	.free = qxl_gem_object_free,93	.open = qxl_gem_object_open,94	.close = qxl_gem_object_close,95	.pin = qxl_gem_prime_pin,96	.unpin = qxl_gem_prime_unpin,97	.get_sg_table = qxl_gem_prime_get_sg_table,98	.vmap = qxl_gem_prime_vmap,99	.vunmap = qxl_gem_prime_vunmap,100	.mmap = drm_gem_ttm_mmap,101	.print_info = drm_gem_ttm_print_info,102};103 104int qxl_bo_create(struct qxl_device *qdev, unsigned long size,105		  bool kernel, bool pinned, u32 domain, u32 priority,106		  struct qxl_surface *surf,107		  struct qxl_bo **bo_ptr)108{109	struct ttm_operation_ctx ctx = { !kernel, false };110	struct qxl_bo *bo;111	enum ttm_bo_type type;112	int r;113 114	if (kernel)115		type = ttm_bo_type_kernel;116	else117		type = ttm_bo_type_device;118	*bo_ptr = NULL;119	bo = kzalloc(sizeof(struct qxl_bo), GFP_KERNEL);120	if (bo == NULL)121		return -ENOMEM;122	size = roundup(size, PAGE_SIZE);123	r = drm_gem_object_init(&qdev->ddev, &bo->tbo.base, size);124	if (unlikely(r)) {125		kfree(bo);126		return r;127	}128	bo->tbo.base.funcs = &qxl_object_funcs;129	bo->type = domain;130	bo->surface_id = 0;131	INIT_LIST_HEAD(&bo->list);132 133	if (surf)134		bo->surf = *surf;135 136	qxl_ttm_placement_from_domain(bo, domain);137 138	bo->tbo.priority = priority;139	r = ttm_bo_init_reserved(&qdev->mman.bdev, &bo->tbo, type,140				 &bo->placement, 0, &ctx, NULL, NULL,141				 &qxl_ttm_bo_destroy);142	if (unlikely(r != 0)) {143		if (r != -ERESTARTSYS)144			dev_err(qdev->ddev.dev,145				"object_init failed for (%lu, 0x%08X)\n",146				size, domain);147		return r;148	}149	if (pinned)150		ttm_bo_pin(&bo->tbo);151	ttm_bo_unreserve(&bo->tbo);152	*bo_ptr = bo;153	return 0;154}155 156int qxl_bo_vmap_locked(struct qxl_bo *bo, struct iosys_map *map)157{158	int r;159 160	dma_resv_assert_held(bo->tbo.base.resv);161 162	if (bo->kptr) {163		bo->map_count++;164		goto out;165	}166 167	r = ttm_bo_vmap(&bo->tbo, &bo->map);168	if (r) {169		qxl_bo_unpin_locked(bo);170		return r;171	}172	bo->map_count = 1;173 174	/* TODO: Remove kptr in favor of map everywhere. */175	if (bo->map.is_iomem)176		bo->kptr = (void *)bo->map.vaddr_iomem;177	else178		bo->kptr = bo->map.vaddr;179 180out:181	*map = bo->map;182	return 0;183}184 185int qxl_bo_pin_and_vmap(struct qxl_bo *bo, struct iosys_map *map)186{187	int r;188 189	r = qxl_bo_reserve(bo);190	if (r)191		return r;192 193	r = qxl_bo_pin_locked(bo);194	if (r) {195		qxl_bo_unreserve(bo);196		return r;197	}198 199	r = qxl_bo_vmap_locked(bo, map);200	if (r)201		qxl_bo_unpin_locked(bo);202	qxl_bo_unreserve(bo);203	return r;204}205 206void *qxl_bo_kmap_atomic_page(struct qxl_device *qdev,207			      struct qxl_bo *bo, int page_offset)208{209	unsigned long offset;210	void *rptr;211	int ret;212	struct io_mapping *map;213	struct iosys_map bo_map;214 215	if (bo->tbo.resource->mem_type == TTM_PL_VRAM)216		map = qdev->vram_mapping;217	else if (bo->tbo.resource->mem_type == TTM_PL_PRIV)218		map = qdev->surface_mapping;219	else220		goto fallback;221 222	offset = bo->tbo.resource->start << PAGE_SHIFT;223	return io_mapping_map_atomic_wc(map, offset + page_offset);224fallback:225	if (bo->kptr) {226		rptr = bo->kptr + (page_offset * PAGE_SIZE);227		return rptr;228	}229 230	ret = qxl_bo_vmap_locked(bo, &bo_map);231	if (ret)232		return NULL;233	rptr = bo_map.vaddr; /* TODO: Use mapping abstraction properly */234 235	rptr += page_offset * PAGE_SIZE;236	return rptr;237}238 239void qxl_bo_vunmap_locked(struct qxl_bo *bo)240{241	dma_resv_assert_held(bo->tbo.base.resv);242 243	if (bo->kptr == NULL)244		return;245	bo->map_count--;246	if (bo->map_count > 0)247		return;248	bo->kptr = NULL;249	ttm_bo_vunmap(&bo->tbo, &bo->map);250}251 252int qxl_bo_vunmap_and_unpin(struct qxl_bo *bo)253{254	int r;255 256	r = qxl_bo_reserve(bo);257	if (r)258		return r;259 260	qxl_bo_vunmap_locked(bo);261	qxl_bo_unpin_locked(bo);262	qxl_bo_unreserve(bo);263	return 0;264}265 266void qxl_bo_kunmap_atomic_page(struct qxl_device *qdev,267			       struct qxl_bo *bo, void *pmap)268{269	if ((bo->tbo.resource->mem_type != TTM_PL_VRAM) &&270	    (bo->tbo.resource->mem_type != TTM_PL_PRIV))271		goto fallback;272 273	io_mapping_unmap_atomic(pmap);274	return;275 fallback:276	qxl_bo_vunmap_locked(bo);277}278 279void qxl_bo_unref(struct qxl_bo **bo)280{281	if ((*bo) == NULL)282		return;283 284	drm_gem_object_put(&(*bo)->tbo.base);285	*bo = NULL;286}287 288struct qxl_bo *qxl_bo_ref(struct qxl_bo *bo)289{290	drm_gem_object_get(&bo->tbo.base);291	return bo;292}293 294int qxl_bo_pin_locked(struct qxl_bo *bo)295{296	struct ttm_operation_ctx ctx = { false, false };297	struct drm_device *ddev = bo->tbo.base.dev;298	int r;299 300	dma_resv_assert_held(bo->tbo.base.resv);301 302	if (bo->tbo.pin_count) {303		ttm_bo_pin(&bo->tbo);304		return 0;305	}306	qxl_ttm_placement_from_domain(bo, bo->type);307	r = ttm_bo_validate(&bo->tbo, &bo->placement, &ctx);308	if (likely(r == 0))309		ttm_bo_pin(&bo->tbo);310	if (unlikely(r != 0))311		dev_err(ddev->dev, "%p pin failed\n", bo);312	return r;313}314 315void qxl_bo_unpin_locked(struct qxl_bo *bo)316{317	dma_resv_assert_held(bo->tbo.base.resv);318 319	ttm_bo_unpin(&bo->tbo);320}321 322/*323 * Reserve the BO before pinning the object.  If the BO was reserved324 * beforehand, use the internal version directly qxl_bo_pin_locked.325 *326 */327int qxl_bo_pin(struct qxl_bo *bo)328{329	int r;330 331	r = qxl_bo_reserve(bo);332	if (r)333		return r;334 335	r = qxl_bo_pin_locked(bo);336	qxl_bo_unreserve(bo);337	return r;338}339 340/*341 * Reserve the BO before pinning the object.  If the BO was reserved342 * beforehand, use the internal version directly qxl_bo_unpin_locked.343 *344 */345int qxl_bo_unpin(struct qxl_bo *bo)346{347	int r;348 349	r = qxl_bo_reserve(bo);350	if (r)351		return r;352 353	qxl_bo_unpin_locked(bo);354	qxl_bo_unreserve(bo);355	return 0;356}357 358void qxl_bo_force_delete(struct qxl_device *qdev)359{360	struct qxl_bo *bo, *n;361 362	if (list_empty(&qdev->gem.objects))363		return;364	dev_err(qdev->ddev.dev, "Userspace still has active objects !\n");365	list_for_each_entry_safe(bo, n, &qdev->gem.objects, list) {366		dev_err(qdev->ddev.dev, "%p %p %lu %lu force free\n",367			&bo->tbo.base, bo, (unsigned long)bo->tbo.base.size,368			*((unsigned long *)&bo->tbo.base.refcount));369		mutex_lock(&qdev->gem.mutex);370		list_del_init(&bo->list);371		mutex_unlock(&qdev->gem.mutex);372		/* this should unref the ttm bo */373		drm_gem_object_put(&bo->tbo.base);374	}375}376 377int qxl_bo_init(struct qxl_device *qdev)378{379	return qxl_ttm_init(qdev);380}381 382void qxl_bo_fini(struct qxl_device *qdev)383{384	qxl_ttm_fini(qdev);385}386 387int qxl_bo_check_id(struct qxl_device *qdev, struct qxl_bo *bo)388{389	int ret;390 391	if (bo->type == QXL_GEM_DOMAIN_SURFACE && bo->surface_id == 0) {392		/* allocate a surface id for this surface now */393		ret = qxl_surface_id_alloc(qdev, bo);394		if (ret)395			return ret;396 397		ret = qxl_hw_surface_alloc(qdev, bo);398		if (ret)399			return ret;400	}401	return 0;402}403 404int qxl_surf_evict(struct qxl_device *qdev)405{406	struct ttm_resource_manager *man;407 408	man = ttm_manager_type(&qdev->mman.bdev, TTM_PL_PRIV);409	return ttm_resource_manager_evict_all(&qdev->mman.bdev, man);410}411 412int qxl_vram_evict(struct qxl_device *qdev)413{414	struct ttm_resource_manager *man;415 416	man = ttm_manager_type(&qdev->mman.bdev, TTM_PL_VRAM);417	return ttm_resource_manager_evict_all(&qdev->mman.bdev, man);418}419