1*e9bf5f36SDave Airlie /* 2*e9bf5f36SDave Airlie * Copyright 2011 Red Hat Inc. 3*e9bf5f36SDave Airlie * 4*e9bf5f36SDave Airlie * Permission is hereby granted, free of charge, to any person obtaining a 5*e9bf5f36SDave Airlie * copy of this software and associated documentation files (the "Software"), 6*e9bf5f36SDave Airlie * to deal in the Software without restriction, including without limitation 7*e9bf5f36SDave Airlie * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8*e9bf5f36SDave Airlie * and/or sell copies of the Software, and to permit persons to whom the 9*e9bf5f36SDave Airlie * Software is furnished to do so, subject to the following conditions: 10*e9bf5f36SDave Airlie * 11*e9bf5f36SDave Airlie * The above copyright notice and this permission notice shall be included in 12*e9bf5f36SDave Airlie * all copies or substantial portions of the Software. 13*e9bf5f36SDave Airlie * 14*e9bf5f36SDave Airlie * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15*e9bf5f36SDave Airlie * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16*e9bf5f36SDave Airlie * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17*e9bf5f36SDave Airlie * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18*e9bf5f36SDave Airlie * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19*e9bf5f36SDave Airlie * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20*e9bf5f36SDave Airlie * OTHER DEALINGS IN THE SOFTWARE. 21*e9bf5f36SDave Airlie * 22*e9bf5f36SDave Airlie * Authors: Dave Airlie 23*e9bf5f36SDave Airlie */ 2422b33e8eSDave Airlie 2522b33e8eSDave Airlie #include "drmP.h" 2622b33e8eSDave Airlie #include "drm.h" 2722b33e8eSDave Airlie 2822b33e8eSDave Airlie #include "nouveau_drv.h" 2922b33e8eSDave Airlie #include "nouveau_drm.h" 3022b33e8eSDave Airlie #include "nouveau_dma.h" 3122b33e8eSDave Airlie 3222b33e8eSDave Airlie #include <linux/dma-buf.h> 3322b33e8eSDave Airlie 3422b33e8eSDave Airlie static struct sg_table *nouveau_gem_map_dma_buf(struct dma_buf_attachment *attachment, 3522b33e8eSDave Airlie enum dma_data_direction dir) 3622b33e8eSDave Airlie { 3722b33e8eSDave Airlie struct nouveau_bo *nvbo = attachment->dmabuf->priv; 3822b33e8eSDave Airlie struct drm_device *dev = nvbo->gem->dev; 3922b33e8eSDave Airlie int npages = nvbo->bo.num_pages; 4022b33e8eSDave Airlie struct sg_table *sg; 4122b33e8eSDave Airlie int nents; 4222b33e8eSDave Airlie 4322b33e8eSDave Airlie mutex_lock(&dev->struct_mutex); 4422b33e8eSDave Airlie sg = drm_prime_pages_to_sg(nvbo->bo.ttm->pages, npages); 4522b33e8eSDave Airlie nents = dma_map_sg(attachment->dev, sg->sgl, sg->nents, dir); 4622b33e8eSDave Airlie mutex_unlock(&dev->struct_mutex); 4722b33e8eSDave Airlie return sg; 4822b33e8eSDave Airlie } 4922b33e8eSDave Airlie 5022b33e8eSDave Airlie static void nouveau_gem_unmap_dma_buf(struct dma_buf_attachment *attachment, 5122b33e8eSDave Airlie struct sg_table *sg, enum dma_data_direction dir) 5222b33e8eSDave Airlie { 5322b33e8eSDave Airlie dma_unmap_sg(attachment->dev, sg->sgl, sg->nents, dir); 5422b33e8eSDave Airlie sg_free_table(sg); 5522b33e8eSDave Airlie kfree(sg); 5622b33e8eSDave Airlie } 5722b33e8eSDave Airlie 5822b33e8eSDave Airlie static void nouveau_gem_dmabuf_release(struct dma_buf *dma_buf) 5922b33e8eSDave Airlie { 6022b33e8eSDave Airlie struct nouveau_bo *nvbo = dma_buf->priv; 6122b33e8eSDave Airlie 6222b33e8eSDave Airlie if (nvbo->gem->export_dma_buf == dma_buf) { 6322b33e8eSDave Airlie nvbo->gem->export_dma_buf = NULL; 6422b33e8eSDave Airlie drm_gem_object_unreference_unlocked(nvbo->gem); 6522b33e8eSDave Airlie } 6622b33e8eSDave Airlie } 6722b33e8eSDave Airlie 6822b33e8eSDave Airlie static void *nouveau_gem_kmap_atomic(struct dma_buf *dma_buf, unsigned long page_num) 6922b33e8eSDave Airlie { 7022b33e8eSDave Airlie return NULL; 7122b33e8eSDave Airlie } 7222b33e8eSDave Airlie 7322b33e8eSDave Airlie static void nouveau_gem_kunmap_atomic(struct dma_buf *dma_buf, unsigned long page_num, void *addr) 7422b33e8eSDave Airlie { 7522b33e8eSDave Airlie 7622b33e8eSDave Airlie } 7722b33e8eSDave Airlie static void *nouveau_gem_kmap(struct dma_buf *dma_buf, unsigned long page_num) 7822b33e8eSDave Airlie { 7922b33e8eSDave Airlie return NULL; 8022b33e8eSDave Airlie } 8122b33e8eSDave Airlie 8222b33e8eSDave Airlie static void nouveau_gem_kunmap(struct dma_buf *dma_buf, unsigned long page_num, void *addr) 8322b33e8eSDave Airlie { 8422b33e8eSDave Airlie 8522b33e8eSDave Airlie } 8622b33e8eSDave Airlie 87e1bbc4bfSDave Airlie static int nouveau_gem_prime_mmap(struct dma_buf *dma_buf, struct vm_area_struct *vma) 88e1bbc4bfSDave Airlie { 89e1bbc4bfSDave Airlie return -EINVAL; 90e1bbc4bfSDave Airlie } 91e1bbc4bfSDave Airlie 9235916aceSDave Airlie static void *nouveau_gem_prime_vmap(struct dma_buf *dma_buf) 9335916aceSDave Airlie { 9435916aceSDave Airlie struct nouveau_bo *nvbo = dma_buf->priv; 9535916aceSDave Airlie struct drm_device *dev = nvbo->gem->dev; 9635916aceSDave Airlie int ret; 9735916aceSDave Airlie 9835916aceSDave Airlie mutex_lock(&dev->struct_mutex); 9935916aceSDave Airlie if (nvbo->vmapping_count) { 10035916aceSDave Airlie nvbo->vmapping_count++; 10135916aceSDave Airlie goto out_unlock; 10235916aceSDave Airlie } 10335916aceSDave Airlie 10435916aceSDave Airlie ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.num_pages, 10535916aceSDave Airlie &nvbo->dma_buf_vmap); 10635916aceSDave Airlie if (ret) { 10735916aceSDave Airlie mutex_unlock(&dev->struct_mutex); 10835916aceSDave Airlie return ERR_PTR(ret); 10935916aceSDave Airlie } 11035916aceSDave Airlie nvbo->vmapping_count = 1; 11135916aceSDave Airlie out_unlock: 11235916aceSDave Airlie mutex_unlock(&dev->struct_mutex); 11335916aceSDave Airlie return nvbo->dma_buf_vmap.virtual; 11435916aceSDave Airlie } 11535916aceSDave Airlie 11635916aceSDave Airlie static void nouveau_gem_prime_vunmap(struct dma_buf *dma_buf, void *vaddr) 11735916aceSDave Airlie { 11835916aceSDave Airlie struct nouveau_bo *nvbo = dma_buf->priv; 11935916aceSDave Airlie struct drm_device *dev = nvbo->gem->dev; 12035916aceSDave Airlie 12135916aceSDave Airlie mutex_lock(&dev->struct_mutex); 12235916aceSDave Airlie nvbo->vmapping_count--; 12335916aceSDave Airlie if (nvbo->vmapping_count == 0) { 12435916aceSDave Airlie ttm_bo_kunmap(&nvbo->dma_buf_vmap); 12535916aceSDave Airlie } 12635916aceSDave Airlie mutex_unlock(&dev->struct_mutex); 12735916aceSDave Airlie } 12835916aceSDave Airlie 12941ceeeb2SDave Airlie static const struct dma_buf_ops nouveau_dmabuf_ops = { 13022b33e8eSDave Airlie .map_dma_buf = nouveau_gem_map_dma_buf, 13122b33e8eSDave Airlie .unmap_dma_buf = nouveau_gem_unmap_dma_buf, 13222b33e8eSDave Airlie .release = nouveau_gem_dmabuf_release, 13322b33e8eSDave Airlie .kmap = nouveau_gem_kmap, 13422b33e8eSDave Airlie .kmap_atomic = nouveau_gem_kmap_atomic, 13522b33e8eSDave Airlie .kunmap = nouveau_gem_kunmap, 13622b33e8eSDave Airlie .kunmap_atomic = nouveau_gem_kunmap_atomic, 137e1bbc4bfSDave Airlie .mmap = nouveau_gem_prime_mmap, 13835916aceSDave Airlie .vmap = nouveau_gem_prime_vmap, 13935916aceSDave Airlie .vunmap = nouveau_gem_prime_vunmap, 14022b33e8eSDave Airlie }; 14122b33e8eSDave Airlie 14222b33e8eSDave Airlie static int 14322b33e8eSDave Airlie nouveau_prime_new(struct drm_device *dev, 14422b33e8eSDave Airlie size_t size, 14522b33e8eSDave Airlie struct sg_table *sg, 14622b33e8eSDave Airlie struct nouveau_bo **pnvbo) 14722b33e8eSDave Airlie { 14822b33e8eSDave Airlie struct nouveau_bo *nvbo; 14922b33e8eSDave Airlie u32 flags = 0; 15022b33e8eSDave Airlie int ret; 15122b33e8eSDave Airlie 15222b33e8eSDave Airlie flags = TTM_PL_FLAG_TT; 15322b33e8eSDave Airlie 15422b33e8eSDave Airlie ret = nouveau_bo_new(dev, size, 0, flags, 0, 0, 15522b33e8eSDave Airlie sg, pnvbo); 15622b33e8eSDave Airlie if (ret) 15722b33e8eSDave Airlie return ret; 15822b33e8eSDave Airlie nvbo = *pnvbo; 15922b33e8eSDave Airlie 16022b33e8eSDave Airlie /* we restrict allowed domains on nv50+ to only the types 16122b33e8eSDave Airlie * that were requested at creation time. not possibly on 16222b33e8eSDave Airlie * earlier chips without busting the ABI. 16322b33e8eSDave Airlie */ 16422b33e8eSDave Airlie nvbo->valid_domains = NOUVEAU_GEM_DOMAIN_GART; 16522b33e8eSDave Airlie nvbo->gem = drm_gem_object_alloc(dev, nvbo->bo.mem.size); 16622b33e8eSDave Airlie if (!nvbo->gem) { 16722b33e8eSDave Airlie nouveau_bo_ref(NULL, pnvbo); 16822b33e8eSDave Airlie return -ENOMEM; 16922b33e8eSDave Airlie } 17022b33e8eSDave Airlie 17122b33e8eSDave Airlie nvbo->gem->driver_private = nvbo; 17222b33e8eSDave Airlie return 0; 17322b33e8eSDave Airlie } 17422b33e8eSDave Airlie 17522b33e8eSDave Airlie struct dma_buf *nouveau_gem_prime_export(struct drm_device *dev, 17622b33e8eSDave Airlie struct drm_gem_object *obj, int flags) 17722b33e8eSDave Airlie { 17822b33e8eSDave Airlie struct nouveau_bo *nvbo = nouveau_gem_object(obj); 17922b33e8eSDave Airlie int ret = 0; 18022b33e8eSDave Airlie 18122b33e8eSDave Airlie /* pin buffer into GTT */ 18222b33e8eSDave Airlie ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_TT); 18322b33e8eSDave Airlie if (ret) 18422b33e8eSDave Airlie return ERR_PTR(-EINVAL); 18522b33e8eSDave Airlie 18622b33e8eSDave Airlie return dma_buf_export(nvbo, &nouveau_dmabuf_ops, obj->size, flags); 18722b33e8eSDave Airlie } 18822b33e8eSDave Airlie 18922b33e8eSDave Airlie struct drm_gem_object *nouveau_gem_prime_import(struct drm_device *dev, 19022b33e8eSDave Airlie struct dma_buf *dma_buf) 19122b33e8eSDave Airlie { 19222b33e8eSDave Airlie struct dma_buf_attachment *attach; 19322b33e8eSDave Airlie struct sg_table *sg; 19422b33e8eSDave Airlie struct nouveau_bo *nvbo; 19522b33e8eSDave Airlie int ret; 19622b33e8eSDave Airlie 19722b33e8eSDave Airlie if (dma_buf->ops == &nouveau_dmabuf_ops) { 19822b33e8eSDave Airlie nvbo = dma_buf->priv; 19922b33e8eSDave Airlie if (nvbo->gem) { 20022b33e8eSDave Airlie if (nvbo->gem->dev == dev) { 20122b33e8eSDave Airlie drm_gem_object_reference(nvbo->gem); 20222b33e8eSDave Airlie return nvbo->gem; 20322b33e8eSDave Airlie } 20422b33e8eSDave Airlie } 20522b33e8eSDave Airlie } 20622b33e8eSDave Airlie /* need to attach */ 20722b33e8eSDave Airlie attach = dma_buf_attach(dma_buf, dev->dev); 20822b33e8eSDave Airlie if (IS_ERR(attach)) 20922b33e8eSDave Airlie return ERR_PTR(PTR_ERR(attach)); 21022b33e8eSDave Airlie 21122b33e8eSDave Airlie sg = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); 21222b33e8eSDave Airlie if (IS_ERR(sg)) { 21322b33e8eSDave Airlie ret = PTR_ERR(sg); 21422b33e8eSDave Airlie goto fail_detach; 21522b33e8eSDave Airlie } 21622b33e8eSDave Airlie 21722b33e8eSDave Airlie ret = nouveau_prime_new(dev, dma_buf->size, sg, &nvbo); 21822b33e8eSDave Airlie if (ret) 21922b33e8eSDave Airlie goto fail_unmap; 22022b33e8eSDave Airlie 22122b33e8eSDave Airlie nvbo->gem->import_attach = attach; 22222b33e8eSDave Airlie 22322b33e8eSDave Airlie return nvbo->gem; 22422b33e8eSDave Airlie 22522b33e8eSDave Airlie fail_unmap: 22622b33e8eSDave Airlie dma_buf_unmap_attachment(attach, sg, DMA_BIDIRECTIONAL); 22722b33e8eSDave Airlie fail_detach: 22822b33e8eSDave Airlie dma_buf_detach(dma_buf, attach); 22922b33e8eSDave Airlie return ERR_PTR(ret); 23022b33e8eSDave Airlie } 23122b33e8eSDave Airlie 232