162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * NVIDIA Tegra DRM GEM helper functions 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2012 Sascha Hauer, Pengutronix 662306a36Sopenharmony_ci * Copyright (C) 2013-2015 NVIDIA CORPORATION, All rights reserved. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Based on the GEM/CMA helpers 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Copyright (c) 2011 Samsung Electronics Co., Ltd. 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/dma-buf.h> 1462306a36Sopenharmony_ci#include <linux/iommu.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/vmalloc.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <drm/drm_drv.h> 1962306a36Sopenharmony_ci#include <drm/drm_prime.h> 2062306a36Sopenharmony_ci#include <drm/tegra_drm.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "drm.h" 2362306a36Sopenharmony_ci#include "gem.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ciMODULE_IMPORT_NS(DMA_BUF); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic unsigned int sg_dma_count_chunks(struct scatterlist *sgl, unsigned int nents) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci dma_addr_t next = ~(dma_addr_t)0; 3062306a36Sopenharmony_ci unsigned int count = 0, i; 3162306a36Sopenharmony_ci struct scatterlist *s; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci for_each_sg(sgl, s, nents, i) { 3462306a36Sopenharmony_ci /* sg_dma_address(s) is only valid for entries that have sg_dma_len(s) != 0. */ 3562306a36Sopenharmony_ci if (!sg_dma_len(s)) 3662306a36Sopenharmony_ci continue; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci if (sg_dma_address(s) != next) { 3962306a36Sopenharmony_ci next = sg_dma_address(s) + sg_dma_len(s); 4062306a36Sopenharmony_ci count++; 4162306a36Sopenharmony_ci } 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci return count; 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic inline unsigned int sgt_dma_count_chunks(struct sg_table *sgt) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci return sg_dma_count_chunks(sgt->sgl, sgt->nents); 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic void tegra_bo_put(struct host1x_bo *bo) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci struct tegra_bo *obj = host1x_to_tegra_bo(bo); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci drm_gem_object_put(&obj->gem); 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic struct host1x_bo_mapping *tegra_bo_pin(struct device *dev, struct host1x_bo *bo, 6062306a36Sopenharmony_ci enum dma_data_direction direction) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci struct tegra_bo *obj = host1x_to_tegra_bo(bo); 6362306a36Sopenharmony_ci struct drm_gem_object *gem = &obj->gem; 6462306a36Sopenharmony_ci struct host1x_bo_mapping *map; 6562306a36Sopenharmony_ci int err; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci map = kzalloc(sizeof(*map), GFP_KERNEL); 6862306a36Sopenharmony_ci if (!map) 6962306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci kref_init(&map->ref); 7262306a36Sopenharmony_ci map->bo = host1x_bo_get(bo); 7362306a36Sopenharmony_ci map->direction = direction; 7462306a36Sopenharmony_ci map->dev = dev; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci /* 7762306a36Sopenharmony_ci * Imported buffers need special treatment to satisfy the semantics of DMA-BUF. 7862306a36Sopenharmony_ci */ 7962306a36Sopenharmony_ci if (gem->import_attach) { 8062306a36Sopenharmony_ci struct dma_buf *buf = gem->import_attach->dmabuf; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci map->attach = dma_buf_attach(buf, dev); 8362306a36Sopenharmony_ci if (IS_ERR(map->attach)) { 8462306a36Sopenharmony_ci err = PTR_ERR(map->attach); 8562306a36Sopenharmony_ci goto free; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci map->sgt = dma_buf_map_attachment_unlocked(map->attach, direction); 8962306a36Sopenharmony_ci if (IS_ERR(map->sgt)) { 9062306a36Sopenharmony_ci dma_buf_detach(buf, map->attach); 9162306a36Sopenharmony_ci err = PTR_ERR(map->sgt); 9262306a36Sopenharmony_ci map->sgt = NULL; 9362306a36Sopenharmony_ci goto free; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci err = sgt_dma_count_chunks(map->sgt); 9762306a36Sopenharmony_ci map->size = gem->size; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci goto out; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci /* 10362306a36Sopenharmony_ci * If we don't have a mapping for this buffer yet, return an SG table 10462306a36Sopenharmony_ci * so that host1x can do the mapping for us via the DMA API. 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_ci map->sgt = kzalloc(sizeof(*map->sgt), GFP_KERNEL); 10762306a36Sopenharmony_ci if (!map->sgt) { 10862306a36Sopenharmony_ci err = -ENOMEM; 10962306a36Sopenharmony_ci goto free; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci if (obj->pages) { 11362306a36Sopenharmony_ci /* 11462306a36Sopenharmony_ci * If the buffer object was allocated from the explicit IOMMU 11562306a36Sopenharmony_ci * API code paths, construct an SG table from the pages. 11662306a36Sopenharmony_ci */ 11762306a36Sopenharmony_ci err = sg_alloc_table_from_pages(map->sgt, obj->pages, obj->num_pages, 0, gem->size, 11862306a36Sopenharmony_ci GFP_KERNEL); 11962306a36Sopenharmony_ci if (err < 0) 12062306a36Sopenharmony_ci goto free; 12162306a36Sopenharmony_ci } else { 12262306a36Sopenharmony_ci /* 12362306a36Sopenharmony_ci * If the buffer object had no pages allocated and if it was 12462306a36Sopenharmony_ci * not imported, it had to be allocated with the DMA API, so 12562306a36Sopenharmony_ci * the DMA API helper can be used. 12662306a36Sopenharmony_ci */ 12762306a36Sopenharmony_ci err = dma_get_sgtable(dev, map->sgt, obj->vaddr, obj->iova, gem->size); 12862306a36Sopenharmony_ci if (err < 0) 12962306a36Sopenharmony_ci goto free; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci err = dma_map_sgtable(dev, map->sgt, direction, 0); 13362306a36Sopenharmony_ci if (err) 13462306a36Sopenharmony_ci goto free_sgt; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ciout: 13762306a36Sopenharmony_ci /* 13862306a36Sopenharmony_ci * If we've manually mapped the buffer object through the IOMMU, make sure to return the 13962306a36Sopenharmony_ci * existing IOVA address of our mapping. 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ci if (!obj->mm) { 14262306a36Sopenharmony_ci map->phys = sg_dma_address(map->sgt->sgl); 14362306a36Sopenharmony_ci map->chunks = err; 14462306a36Sopenharmony_ci } else { 14562306a36Sopenharmony_ci map->phys = obj->iova; 14662306a36Sopenharmony_ci map->chunks = 1; 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci map->size = gem->size; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci return map; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cifree_sgt: 15462306a36Sopenharmony_ci sg_free_table(map->sgt); 15562306a36Sopenharmony_cifree: 15662306a36Sopenharmony_ci kfree(map->sgt); 15762306a36Sopenharmony_ci kfree(map); 15862306a36Sopenharmony_ci return ERR_PTR(err); 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic void tegra_bo_unpin(struct host1x_bo_mapping *map) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci if (map->attach) { 16462306a36Sopenharmony_ci dma_buf_unmap_attachment_unlocked(map->attach, map->sgt, 16562306a36Sopenharmony_ci map->direction); 16662306a36Sopenharmony_ci dma_buf_detach(map->attach->dmabuf, map->attach); 16762306a36Sopenharmony_ci } else { 16862306a36Sopenharmony_ci dma_unmap_sgtable(map->dev, map->sgt, map->direction, 0); 16962306a36Sopenharmony_ci sg_free_table(map->sgt); 17062306a36Sopenharmony_ci kfree(map->sgt); 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci host1x_bo_put(map->bo); 17462306a36Sopenharmony_ci kfree(map); 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic void *tegra_bo_mmap(struct host1x_bo *bo) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci struct tegra_bo *obj = host1x_to_tegra_bo(bo); 18062306a36Sopenharmony_ci struct iosys_map map; 18162306a36Sopenharmony_ci int ret; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (obj->vaddr) { 18462306a36Sopenharmony_ci return obj->vaddr; 18562306a36Sopenharmony_ci } else if (obj->gem.import_attach) { 18662306a36Sopenharmony_ci ret = dma_buf_vmap_unlocked(obj->gem.import_attach->dmabuf, &map); 18762306a36Sopenharmony_ci return ret ? NULL : map.vaddr; 18862306a36Sopenharmony_ci } else { 18962306a36Sopenharmony_ci return vmap(obj->pages, obj->num_pages, VM_MAP, 19062306a36Sopenharmony_ci pgprot_writecombine(PAGE_KERNEL)); 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci} 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic void tegra_bo_munmap(struct host1x_bo *bo, void *addr) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci struct tegra_bo *obj = host1x_to_tegra_bo(bo); 19762306a36Sopenharmony_ci struct iosys_map map = IOSYS_MAP_INIT_VADDR(addr); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (obj->vaddr) 20062306a36Sopenharmony_ci return; 20162306a36Sopenharmony_ci else if (obj->gem.import_attach) 20262306a36Sopenharmony_ci dma_buf_vunmap_unlocked(obj->gem.import_attach->dmabuf, &map); 20362306a36Sopenharmony_ci else 20462306a36Sopenharmony_ci vunmap(addr); 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic struct host1x_bo *tegra_bo_get(struct host1x_bo *bo) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci struct tegra_bo *obj = host1x_to_tegra_bo(bo); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci drm_gem_object_get(&obj->gem); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci return bo; 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic const struct host1x_bo_ops tegra_bo_ops = { 21762306a36Sopenharmony_ci .get = tegra_bo_get, 21862306a36Sopenharmony_ci .put = tegra_bo_put, 21962306a36Sopenharmony_ci .pin = tegra_bo_pin, 22062306a36Sopenharmony_ci .unpin = tegra_bo_unpin, 22162306a36Sopenharmony_ci .mmap = tegra_bo_mmap, 22262306a36Sopenharmony_ci .munmap = tegra_bo_munmap, 22362306a36Sopenharmony_ci}; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic int tegra_bo_iommu_map(struct tegra_drm *tegra, struct tegra_bo *bo) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci int prot = IOMMU_READ | IOMMU_WRITE; 22862306a36Sopenharmony_ci int err; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci if (bo->mm) 23162306a36Sopenharmony_ci return -EBUSY; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci bo->mm = kzalloc(sizeof(*bo->mm), GFP_KERNEL); 23462306a36Sopenharmony_ci if (!bo->mm) 23562306a36Sopenharmony_ci return -ENOMEM; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci mutex_lock(&tegra->mm_lock); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci err = drm_mm_insert_node_generic(&tegra->mm, 24062306a36Sopenharmony_ci bo->mm, bo->gem.size, PAGE_SIZE, 0, 0); 24162306a36Sopenharmony_ci if (err < 0) { 24262306a36Sopenharmony_ci dev_err(tegra->drm->dev, "out of I/O virtual memory: %d\n", 24362306a36Sopenharmony_ci err); 24462306a36Sopenharmony_ci goto unlock; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci bo->iova = bo->mm->start; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci bo->size = iommu_map_sgtable(tegra->domain, bo->iova, bo->sgt, prot); 25062306a36Sopenharmony_ci if (!bo->size) { 25162306a36Sopenharmony_ci dev_err(tegra->drm->dev, "failed to map buffer\n"); 25262306a36Sopenharmony_ci err = -ENOMEM; 25362306a36Sopenharmony_ci goto remove; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci mutex_unlock(&tegra->mm_lock); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci return 0; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ciremove: 26162306a36Sopenharmony_ci drm_mm_remove_node(bo->mm); 26262306a36Sopenharmony_ciunlock: 26362306a36Sopenharmony_ci mutex_unlock(&tegra->mm_lock); 26462306a36Sopenharmony_ci kfree(bo->mm); 26562306a36Sopenharmony_ci return err; 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_cistatic int tegra_bo_iommu_unmap(struct tegra_drm *tegra, struct tegra_bo *bo) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci if (!bo->mm) 27162306a36Sopenharmony_ci return 0; 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci mutex_lock(&tegra->mm_lock); 27462306a36Sopenharmony_ci iommu_unmap(tegra->domain, bo->iova, bo->size); 27562306a36Sopenharmony_ci drm_mm_remove_node(bo->mm); 27662306a36Sopenharmony_ci mutex_unlock(&tegra->mm_lock); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci kfree(bo->mm); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci return 0; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic const struct drm_gem_object_funcs tegra_gem_object_funcs = { 28462306a36Sopenharmony_ci .free = tegra_bo_free_object, 28562306a36Sopenharmony_ci .export = tegra_gem_prime_export, 28662306a36Sopenharmony_ci .vm_ops = &tegra_bo_vm_ops, 28762306a36Sopenharmony_ci}; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistatic struct tegra_bo *tegra_bo_alloc_object(struct drm_device *drm, 29062306a36Sopenharmony_ci size_t size) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct tegra_bo *bo; 29362306a36Sopenharmony_ci int err; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci bo = kzalloc(sizeof(*bo), GFP_KERNEL); 29662306a36Sopenharmony_ci if (!bo) 29762306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci bo->gem.funcs = &tegra_gem_object_funcs; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci host1x_bo_init(&bo->base, &tegra_bo_ops); 30262306a36Sopenharmony_ci size = round_up(size, PAGE_SIZE); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci err = drm_gem_object_init(drm, &bo->gem, size); 30562306a36Sopenharmony_ci if (err < 0) 30662306a36Sopenharmony_ci goto free; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci err = drm_gem_create_mmap_offset(&bo->gem); 30962306a36Sopenharmony_ci if (err < 0) 31062306a36Sopenharmony_ci goto release; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci return bo; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cirelease: 31562306a36Sopenharmony_ci drm_gem_object_release(&bo->gem); 31662306a36Sopenharmony_cifree: 31762306a36Sopenharmony_ci kfree(bo); 31862306a36Sopenharmony_ci return ERR_PTR(err); 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic void tegra_bo_free(struct drm_device *drm, struct tegra_bo *bo) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci if (bo->pages) { 32462306a36Sopenharmony_ci dma_unmap_sgtable(drm->dev, bo->sgt, DMA_FROM_DEVICE, 0); 32562306a36Sopenharmony_ci drm_gem_put_pages(&bo->gem, bo->pages, true, true); 32662306a36Sopenharmony_ci sg_free_table(bo->sgt); 32762306a36Sopenharmony_ci kfree(bo->sgt); 32862306a36Sopenharmony_ci } else if (bo->vaddr) { 32962306a36Sopenharmony_ci dma_free_wc(drm->dev, bo->gem.size, bo->vaddr, bo->iova); 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci int err; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci bo->pages = drm_gem_get_pages(&bo->gem); 33862306a36Sopenharmony_ci if (IS_ERR(bo->pages)) 33962306a36Sopenharmony_ci return PTR_ERR(bo->pages); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci bo->num_pages = bo->gem.size >> PAGE_SHIFT; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci bo->sgt = drm_prime_pages_to_sg(bo->gem.dev, bo->pages, bo->num_pages); 34462306a36Sopenharmony_ci if (IS_ERR(bo->sgt)) { 34562306a36Sopenharmony_ci err = PTR_ERR(bo->sgt); 34662306a36Sopenharmony_ci goto put_pages; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci err = dma_map_sgtable(drm->dev, bo->sgt, DMA_FROM_DEVICE, 0); 35062306a36Sopenharmony_ci if (err) 35162306a36Sopenharmony_ci goto free_sgt; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci return 0; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cifree_sgt: 35662306a36Sopenharmony_ci sg_free_table(bo->sgt); 35762306a36Sopenharmony_ci kfree(bo->sgt); 35862306a36Sopenharmony_ciput_pages: 35962306a36Sopenharmony_ci drm_gem_put_pages(&bo->gem, bo->pages, false, false); 36062306a36Sopenharmony_ci return err; 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic int tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci struct tegra_drm *tegra = drm->dev_private; 36662306a36Sopenharmony_ci int err; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci if (tegra->domain) { 36962306a36Sopenharmony_ci err = tegra_bo_get_pages(drm, bo); 37062306a36Sopenharmony_ci if (err < 0) 37162306a36Sopenharmony_ci return err; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci err = tegra_bo_iommu_map(tegra, bo); 37462306a36Sopenharmony_ci if (err < 0) { 37562306a36Sopenharmony_ci tegra_bo_free(drm, bo); 37662306a36Sopenharmony_ci return err; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci } else { 37962306a36Sopenharmony_ci size_t size = bo->gem.size; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci bo->vaddr = dma_alloc_wc(drm->dev, size, &bo->iova, 38262306a36Sopenharmony_ci GFP_KERNEL | __GFP_NOWARN); 38362306a36Sopenharmony_ci if (!bo->vaddr) { 38462306a36Sopenharmony_ci dev_err(drm->dev, 38562306a36Sopenharmony_ci "failed to allocate buffer of size %zu\n", 38662306a36Sopenharmony_ci size); 38762306a36Sopenharmony_ci return -ENOMEM; 38862306a36Sopenharmony_ci } 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci return 0; 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistruct tegra_bo *tegra_bo_create(struct drm_device *drm, size_t size, 39562306a36Sopenharmony_ci unsigned long flags) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci struct tegra_bo *bo; 39862306a36Sopenharmony_ci int err; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci bo = tegra_bo_alloc_object(drm, size); 40162306a36Sopenharmony_ci if (IS_ERR(bo)) 40262306a36Sopenharmony_ci return bo; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci err = tegra_bo_alloc(drm, bo); 40562306a36Sopenharmony_ci if (err < 0) 40662306a36Sopenharmony_ci goto release; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (flags & DRM_TEGRA_GEM_CREATE_TILED) 40962306a36Sopenharmony_ci bo->tiling.mode = TEGRA_BO_TILING_MODE_TILED; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci if (flags & DRM_TEGRA_GEM_CREATE_BOTTOM_UP) 41262306a36Sopenharmony_ci bo->flags |= TEGRA_BO_BOTTOM_UP; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci return bo; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cirelease: 41762306a36Sopenharmony_ci drm_gem_object_release(&bo->gem); 41862306a36Sopenharmony_ci kfree(bo); 41962306a36Sopenharmony_ci return ERR_PTR(err); 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistruct tegra_bo *tegra_bo_create_with_handle(struct drm_file *file, 42362306a36Sopenharmony_ci struct drm_device *drm, 42462306a36Sopenharmony_ci size_t size, 42562306a36Sopenharmony_ci unsigned long flags, 42662306a36Sopenharmony_ci u32 *handle) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci struct tegra_bo *bo; 42962306a36Sopenharmony_ci int err; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci bo = tegra_bo_create(drm, size, flags); 43262306a36Sopenharmony_ci if (IS_ERR(bo)) 43362306a36Sopenharmony_ci return bo; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci err = drm_gem_handle_create(file, &bo->gem, handle); 43662306a36Sopenharmony_ci if (err) { 43762306a36Sopenharmony_ci tegra_bo_free_object(&bo->gem); 43862306a36Sopenharmony_ci return ERR_PTR(err); 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci drm_gem_object_put(&bo->gem); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci return bo; 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic struct tegra_bo *tegra_bo_import(struct drm_device *drm, 44762306a36Sopenharmony_ci struct dma_buf *buf) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci struct tegra_drm *tegra = drm->dev_private; 45062306a36Sopenharmony_ci struct dma_buf_attachment *attach; 45162306a36Sopenharmony_ci struct tegra_bo *bo; 45262306a36Sopenharmony_ci int err; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci bo = tegra_bo_alloc_object(drm, buf->size); 45562306a36Sopenharmony_ci if (IS_ERR(bo)) 45662306a36Sopenharmony_ci return bo; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci attach = dma_buf_attach(buf, drm->dev); 45962306a36Sopenharmony_ci if (IS_ERR(attach)) { 46062306a36Sopenharmony_ci err = PTR_ERR(attach); 46162306a36Sopenharmony_ci goto free; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci get_dma_buf(buf); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci bo->sgt = dma_buf_map_attachment_unlocked(attach, DMA_TO_DEVICE); 46762306a36Sopenharmony_ci if (IS_ERR(bo->sgt)) { 46862306a36Sopenharmony_ci err = PTR_ERR(bo->sgt); 46962306a36Sopenharmony_ci goto detach; 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci if (tegra->domain) { 47362306a36Sopenharmony_ci err = tegra_bo_iommu_map(tegra, bo); 47462306a36Sopenharmony_ci if (err < 0) 47562306a36Sopenharmony_ci goto detach; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci bo->gem.import_attach = attach; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci return bo; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cidetach: 48362306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(bo->sgt)) 48462306a36Sopenharmony_ci dma_buf_unmap_attachment_unlocked(attach, bo->sgt, DMA_TO_DEVICE); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci dma_buf_detach(buf, attach); 48762306a36Sopenharmony_ci dma_buf_put(buf); 48862306a36Sopenharmony_cifree: 48962306a36Sopenharmony_ci drm_gem_object_release(&bo->gem); 49062306a36Sopenharmony_ci kfree(bo); 49162306a36Sopenharmony_ci return ERR_PTR(err); 49262306a36Sopenharmony_ci} 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_civoid tegra_bo_free_object(struct drm_gem_object *gem) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci struct tegra_drm *tegra = gem->dev->dev_private; 49762306a36Sopenharmony_ci struct host1x_bo_mapping *mapping, *tmp; 49862306a36Sopenharmony_ci struct tegra_bo *bo = to_tegra_bo(gem); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci /* remove all mappings of this buffer object from any caches */ 50162306a36Sopenharmony_ci list_for_each_entry_safe(mapping, tmp, &bo->base.mappings, list) { 50262306a36Sopenharmony_ci if (mapping->cache) 50362306a36Sopenharmony_ci host1x_bo_unpin(mapping); 50462306a36Sopenharmony_ci else 50562306a36Sopenharmony_ci dev_err(gem->dev->dev, "mapping %p stale for device %s\n", mapping, 50662306a36Sopenharmony_ci dev_name(mapping->dev)); 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if (tegra->domain) 51062306a36Sopenharmony_ci tegra_bo_iommu_unmap(tegra, bo); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci if (gem->import_attach) { 51362306a36Sopenharmony_ci dma_buf_unmap_attachment_unlocked(gem->import_attach, bo->sgt, 51462306a36Sopenharmony_ci DMA_TO_DEVICE); 51562306a36Sopenharmony_ci drm_prime_gem_destroy(gem, NULL); 51662306a36Sopenharmony_ci } else { 51762306a36Sopenharmony_ci tegra_bo_free(gem->dev, bo); 51862306a36Sopenharmony_ci } 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci drm_gem_object_release(gem); 52162306a36Sopenharmony_ci kfree(bo); 52262306a36Sopenharmony_ci} 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ciint tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm, 52562306a36Sopenharmony_ci struct drm_mode_create_dumb *args) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci unsigned int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); 52862306a36Sopenharmony_ci struct tegra_drm *tegra = drm->dev_private; 52962306a36Sopenharmony_ci struct tegra_bo *bo; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci args->pitch = round_up(min_pitch, tegra->pitch_align); 53262306a36Sopenharmony_ci args->size = args->pitch * args->height; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci bo = tegra_bo_create_with_handle(file, drm, args->size, 0, 53562306a36Sopenharmony_ci &args->handle); 53662306a36Sopenharmony_ci if (IS_ERR(bo)) 53762306a36Sopenharmony_ci return PTR_ERR(bo); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci return 0; 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_cistatic vm_fault_t tegra_bo_fault(struct vm_fault *vmf) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci struct vm_area_struct *vma = vmf->vma; 54562306a36Sopenharmony_ci struct drm_gem_object *gem = vma->vm_private_data; 54662306a36Sopenharmony_ci struct tegra_bo *bo = to_tegra_bo(gem); 54762306a36Sopenharmony_ci struct page *page; 54862306a36Sopenharmony_ci pgoff_t offset; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci if (!bo->pages) 55162306a36Sopenharmony_ci return VM_FAULT_SIGBUS; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT; 55462306a36Sopenharmony_ci page = bo->pages[offset]; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci return vmf_insert_page(vma, vmf->address, page); 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ciconst struct vm_operations_struct tegra_bo_vm_ops = { 56062306a36Sopenharmony_ci .fault = tegra_bo_fault, 56162306a36Sopenharmony_ci .open = drm_gem_vm_open, 56262306a36Sopenharmony_ci .close = drm_gem_vm_close, 56362306a36Sopenharmony_ci}; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ciint __tegra_gem_mmap(struct drm_gem_object *gem, struct vm_area_struct *vma) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci struct tegra_bo *bo = to_tegra_bo(gem); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (!bo->pages) { 57062306a36Sopenharmony_ci unsigned long vm_pgoff = vma->vm_pgoff; 57162306a36Sopenharmony_ci int err; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci /* 57462306a36Sopenharmony_ci * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), 57562306a36Sopenharmony_ci * and set the vm_pgoff (used as a fake buffer offset by DRM) 57662306a36Sopenharmony_ci * to 0 as we want to map the whole buffer. 57762306a36Sopenharmony_ci */ 57862306a36Sopenharmony_ci vm_flags_clear(vma, VM_PFNMAP); 57962306a36Sopenharmony_ci vma->vm_pgoff = 0; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci err = dma_mmap_wc(gem->dev->dev, vma, bo->vaddr, bo->iova, 58262306a36Sopenharmony_ci gem->size); 58362306a36Sopenharmony_ci if (err < 0) { 58462306a36Sopenharmony_ci drm_gem_vm_close(vma); 58562306a36Sopenharmony_ci return err; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci vma->vm_pgoff = vm_pgoff; 58962306a36Sopenharmony_ci } else { 59062306a36Sopenharmony_ci pgprot_t prot = vm_get_page_prot(vma->vm_flags); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci vm_flags_mod(vma, VM_MIXEDMAP, VM_PFNMAP); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci vma->vm_page_prot = pgprot_writecombine(prot); 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci return 0; 59862306a36Sopenharmony_ci} 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ciint tegra_drm_mmap(struct file *file, struct vm_area_struct *vma) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci struct drm_gem_object *gem; 60362306a36Sopenharmony_ci int err; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci err = drm_gem_mmap(file, vma); 60662306a36Sopenharmony_ci if (err < 0) 60762306a36Sopenharmony_ci return err; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci gem = vma->vm_private_data; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci return __tegra_gem_mmap(gem, vma); 61262306a36Sopenharmony_ci} 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_cistatic struct sg_table * 61562306a36Sopenharmony_citegra_gem_prime_map_dma_buf(struct dma_buf_attachment *attach, 61662306a36Sopenharmony_ci enum dma_data_direction dir) 61762306a36Sopenharmony_ci{ 61862306a36Sopenharmony_ci struct drm_gem_object *gem = attach->dmabuf->priv; 61962306a36Sopenharmony_ci struct tegra_bo *bo = to_tegra_bo(gem); 62062306a36Sopenharmony_ci struct sg_table *sgt; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); 62362306a36Sopenharmony_ci if (!sgt) 62462306a36Sopenharmony_ci return NULL; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci if (bo->pages) { 62762306a36Sopenharmony_ci if (sg_alloc_table_from_pages(sgt, bo->pages, bo->num_pages, 62862306a36Sopenharmony_ci 0, gem->size, GFP_KERNEL) < 0) 62962306a36Sopenharmony_ci goto free; 63062306a36Sopenharmony_ci } else { 63162306a36Sopenharmony_ci if (dma_get_sgtable(attach->dev, sgt, bo->vaddr, bo->iova, 63262306a36Sopenharmony_ci gem->size) < 0) 63362306a36Sopenharmony_ci goto free; 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci if (dma_map_sgtable(attach->dev, sgt, dir, 0)) 63762306a36Sopenharmony_ci goto free; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci return sgt; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cifree: 64262306a36Sopenharmony_ci sg_free_table(sgt); 64362306a36Sopenharmony_ci kfree(sgt); 64462306a36Sopenharmony_ci return NULL; 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_cistatic void tegra_gem_prime_unmap_dma_buf(struct dma_buf_attachment *attach, 64862306a36Sopenharmony_ci struct sg_table *sgt, 64962306a36Sopenharmony_ci enum dma_data_direction dir) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci struct drm_gem_object *gem = attach->dmabuf->priv; 65262306a36Sopenharmony_ci struct tegra_bo *bo = to_tegra_bo(gem); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci if (bo->pages) 65562306a36Sopenharmony_ci dma_unmap_sgtable(attach->dev, sgt, dir, 0); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci sg_free_table(sgt); 65862306a36Sopenharmony_ci kfree(sgt); 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_cistatic void tegra_gem_prime_release(struct dma_buf *buf) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci drm_gem_dmabuf_release(buf); 66462306a36Sopenharmony_ci} 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_cistatic int tegra_gem_prime_begin_cpu_access(struct dma_buf *buf, 66762306a36Sopenharmony_ci enum dma_data_direction direction) 66862306a36Sopenharmony_ci{ 66962306a36Sopenharmony_ci struct drm_gem_object *gem = buf->priv; 67062306a36Sopenharmony_ci struct tegra_bo *bo = to_tegra_bo(gem); 67162306a36Sopenharmony_ci struct drm_device *drm = gem->dev; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (bo->pages) 67462306a36Sopenharmony_ci dma_sync_sgtable_for_cpu(drm->dev, bo->sgt, DMA_FROM_DEVICE); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci return 0; 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_cistatic int tegra_gem_prime_end_cpu_access(struct dma_buf *buf, 68062306a36Sopenharmony_ci enum dma_data_direction direction) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci struct drm_gem_object *gem = buf->priv; 68362306a36Sopenharmony_ci struct tegra_bo *bo = to_tegra_bo(gem); 68462306a36Sopenharmony_ci struct drm_device *drm = gem->dev; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (bo->pages) 68762306a36Sopenharmony_ci dma_sync_sgtable_for_device(drm->dev, bo->sgt, DMA_TO_DEVICE); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci return 0; 69062306a36Sopenharmony_ci} 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_cistatic int tegra_gem_prime_mmap(struct dma_buf *buf, struct vm_area_struct *vma) 69362306a36Sopenharmony_ci{ 69462306a36Sopenharmony_ci struct drm_gem_object *gem = buf->priv; 69562306a36Sopenharmony_ci int err; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci err = drm_gem_mmap_obj(gem, gem->size, vma); 69862306a36Sopenharmony_ci if (err < 0) 69962306a36Sopenharmony_ci return err; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci return __tegra_gem_mmap(gem, vma); 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic int tegra_gem_prime_vmap(struct dma_buf *buf, struct iosys_map *map) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci struct drm_gem_object *gem = buf->priv; 70762306a36Sopenharmony_ci struct tegra_bo *bo = to_tegra_bo(gem); 70862306a36Sopenharmony_ci void *vaddr; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci vaddr = tegra_bo_mmap(&bo->base); 71162306a36Sopenharmony_ci if (IS_ERR(vaddr)) 71262306a36Sopenharmony_ci return PTR_ERR(vaddr); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci iosys_map_set_vaddr(map, vaddr); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci return 0; 71762306a36Sopenharmony_ci} 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_cistatic void tegra_gem_prime_vunmap(struct dma_buf *buf, struct iosys_map *map) 72062306a36Sopenharmony_ci{ 72162306a36Sopenharmony_ci struct drm_gem_object *gem = buf->priv; 72262306a36Sopenharmony_ci struct tegra_bo *bo = to_tegra_bo(gem); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci tegra_bo_munmap(&bo->base, map->vaddr); 72562306a36Sopenharmony_ci} 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_cistatic const struct dma_buf_ops tegra_gem_prime_dmabuf_ops = { 72862306a36Sopenharmony_ci .map_dma_buf = tegra_gem_prime_map_dma_buf, 72962306a36Sopenharmony_ci .unmap_dma_buf = tegra_gem_prime_unmap_dma_buf, 73062306a36Sopenharmony_ci .release = tegra_gem_prime_release, 73162306a36Sopenharmony_ci .begin_cpu_access = tegra_gem_prime_begin_cpu_access, 73262306a36Sopenharmony_ci .end_cpu_access = tegra_gem_prime_end_cpu_access, 73362306a36Sopenharmony_ci .mmap = tegra_gem_prime_mmap, 73462306a36Sopenharmony_ci .vmap = tegra_gem_prime_vmap, 73562306a36Sopenharmony_ci .vunmap = tegra_gem_prime_vunmap, 73662306a36Sopenharmony_ci}; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_cistruct dma_buf *tegra_gem_prime_export(struct drm_gem_object *gem, 73962306a36Sopenharmony_ci int flags) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci DEFINE_DMA_BUF_EXPORT_INFO(exp_info); 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci exp_info.exp_name = KBUILD_MODNAME; 74462306a36Sopenharmony_ci exp_info.owner = gem->dev->driver->fops->owner; 74562306a36Sopenharmony_ci exp_info.ops = &tegra_gem_prime_dmabuf_ops; 74662306a36Sopenharmony_ci exp_info.size = gem->size; 74762306a36Sopenharmony_ci exp_info.flags = flags; 74862306a36Sopenharmony_ci exp_info.priv = gem; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci return drm_gem_dmabuf_export(gem->dev, &exp_info); 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_cistruct drm_gem_object *tegra_gem_prime_import(struct drm_device *drm, 75462306a36Sopenharmony_ci struct dma_buf *buf) 75562306a36Sopenharmony_ci{ 75662306a36Sopenharmony_ci struct tegra_bo *bo; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci if (buf->ops == &tegra_gem_prime_dmabuf_ops) { 75962306a36Sopenharmony_ci struct drm_gem_object *gem = buf->priv; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (gem->dev == drm) { 76262306a36Sopenharmony_ci drm_gem_object_get(gem); 76362306a36Sopenharmony_ci return gem; 76462306a36Sopenharmony_ci } 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci bo = tegra_bo_import(drm, buf); 76862306a36Sopenharmony_ci if (IS_ERR(bo)) 76962306a36Sopenharmony_ci return ERR_CAST(bo); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci return &bo->gem; 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistruct host1x_bo *tegra_gem_lookup(struct drm_file *file, u32 handle) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci struct drm_gem_object *gem; 77762306a36Sopenharmony_ci struct tegra_bo *bo; 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci gem = drm_gem_object_lookup(file, handle); 78062306a36Sopenharmony_ci if (!gem) 78162306a36Sopenharmony_ci return NULL; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci bo = to_tegra_bo(gem); 78462306a36Sopenharmony_ci return &bo->base; 78562306a36Sopenharmony_ci} 786