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