From patchwork Mon Nov 26 13:19:13 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Terje Bergstrom X-Patchwork-Id: 1802961 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by patchwork2.kernel.org (Postfix) with ESMTP id 2DCDFDF2EB for ; Mon, 26 Nov 2012 16:15:02 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id D9651E61C7 for ; Mon, 26 Nov 2012 08:15:01 -0800 (PST) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from hqemgate04.nvidia.com (hqemgate04.nvidia.com [216.228.121.35]) by gabe.freedesktop.org (Postfix) with ESMTP id AAA92E5C37 for ; Mon, 26 Nov 2012 05:16:21 -0800 (PST) Received: from hqnvupgp08.nvidia.com (Not Verified[216.228.121.13]) by hqemgate04.nvidia.com id ; Mon, 26 Nov 2012 05:15:52 -0800 Received: from hqemhub01.nvidia.com ([172.17.108.22]) by hqnvupgp08.nvidia.com (PGP Universal service); Mon, 26 Nov 2012 05:16:16 -0800 X-PGP-Universal: processed; by hqnvupgp08.nvidia.com on Mon, 26 Nov 2012 05:16:16 -0800 Received: from deemhub02.nvidia.com (10.21.69.138) by hqemhub01.nvidia.com (172.20.150.30) with Microsoft SMTP Server (TLS) id 8.3.279.1; Mon, 26 Nov 2012 05:16:16 -0800 Received: from tbergstrom-desktop.Nvidia.com (10.21.65.27) by deemhub02.nvidia.com (10.21.69.138) with Microsoft SMTP Server id 8.3.279.1; Mon, 26 Nov 2012 14:16:13 +0100 From: Terje Bergstrom To: , , Subject: [RFC v2 7/8] gpu: drm: tegra: Prime support Date: Mon, 26 Nov 2012 15:19:13 +0200 Message-ID: <1353935954-13763-8-git-send-email-tbergstrom@nvidia.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1353935954-13763-1-git-send-email-tbergstrom@nvidia.com> References: <1353935954-13763-1-git-send-email-tbergstrom@nvidia.com> X-NVConfidentiality: public MIME-Version: 1.0 X-Mailman-Approved-At: Mon, 26 Nov 2012 06:29:37 -0800 Cc: linux-kernel@vger.kernel.org, Arto Merilainen X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org Errors-To: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org From: Arto Merilainen This patch introduces support for exporting allocated memory as dmabuf objects. Exported buffers are used for delivering data to nvhost driver. Signed-off-by: Arto Merilainen Signed-off-by: Terje Bergstrom --- drivers/gpu/drm/tegra/Makefile | 2 +- drivers/gpu/drm/tegra/dmabuf.c | 150 ++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/tegra/drm.c | 9 ++- drivers/gpu/drm/tegra/drm.h | 6 ++ 4 files changed, 165 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/tegra/dmabuf.c diff --git a/drivers/gpu/drm/tegra/Makefile b/drivers/gpu/drm/tegra/Makefile index 57a334d..53ea383 100644 --- a/drivers/gpu/drm/tegra/Makefile +++ b/drivers/gpu/drm/tegra/Makefile @@ -3,6 +3,6 @@ ccflags-$(CONFIG_DRM_TEGRA_DEBUG) += -DDEBUG tegra-drm-y := drm.o fb.o dc.o tegra-drm-y += output.o rgb.o hdmi.o tvo.o dsi.o -tegra-drm-y += plane.o +tegra-drm-y += plane.o dmabuf.o obj-$(CONFIG_DRM_TEGRA) += tegra-drm.o diff --git a/drivers/gpu/drm/tegra/dmabuf.c b/drivers/gpu/drm/tegra/dmabuf.c new file mode 100644 index 0000000..e81db12 --- /dev/null +++ b/drivers/gpu/drm/tegra/dmabuf.c @@ -0,0 +1,150 @@ +/* + * drivers/gpu/drm/tegra/dmabuf.c + * + * dmabuf exporter for cma allocations + * + * Copyright (c) 2012, NVIDIA Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static struct sg_table *tegra_dmabuf_map(struct dma_buf_attachment *attach, + enum dma_data_direction dir) +{ + struct drm_gem_cma_object *obj = attach->dmabuf->priv; + struct page **pages; + int npages = obj->base.size / PAGE_SIZE; + struct sg_table *sgt; + struct scatterlist *sg; + int i, page_num = 0; + + /* create a list of used pages */ + pages = kzalloc(sizeof(*pages) * npages, GFP_KERNEL); + if (!pages) + goto err_alloc_pages; + for (i = 0; i < npages; i++) + pages[i] = virt_to_page(obj->vaddr + i * PAGE_SIZE); + + /* generate sgt using the page list */ + sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); + if (!sgt) + goto err_alloc_sgt; + if (sg_alloc_table_from_pages(sgt, pages, npages, 0, obj->base.size, + GFP_KERNEL)) + goto err_generate_sgt; + for_each_sg(sgt->sgl, sg, sgt->nents, i) { + sg->dma_address = page_to_phys(pages[page_num]); + page_num += sg->length >> PAGE_SHIFT; + } + + /* only the sgt is interesting */ + kfree(pages); + + return sgt; + +err_generate_sgt: + kfree(sgt); +err_alloc_sgt: + kfree(pages); +err_alloc_pages: + return NULL; +} + +static void tegra_dmabuf_unmap(struct dma_buf_attachment *attach, + struct sg_table *sgt, + enum dma_data_direction dir) +{ + sg_free_table(sgt); + kfree(sgt); +} + +static void tegra_dmabuf_release(struct dma_buf *dmabuf) +{ + struct drm_gem_cma_object *obj = dmabuf->priv; + + if (obj->base.export_dma_buf == dmabuf) { + obj->base.export_dma_buf = NULL; + drm_gem_object_unreference_unlocked(&obj->base); + } +} + +static void *tegra_dmabuf_kmap_atomic(struct dma_buf *dmabuf, + unsigned long page_num) +{ + struct drm_gem_cma_object *obj = dmabuf->priv; + return obj->vaddr + PAGE_SIZE * page_num; +} + +static void *tegra_dmabuf_kmap(struct dma_buf *dmabuf, unsigned long page_num) +{ + return tegra_dmabuf_kmap_atomic(dmabuf, page_num); +} + +static int tegra_dmabuf_mmap(struct dma_buf *dmabuf, + struct vm_area_struct *vma) +{ + struct drm_gem_cma_object *obj = dmabuf->priv; + DEFINE_DMA_ATTRS(attrs); + + vma->vm_private_data = obj; + + return dma_mmap_attrs(obj->base.dev->dev->parent, vma, obj->vaddr, + obj->paddr, obj->base.size, &attrs); +} + +static void *tegra_dmabuf_vmap(struct dma_buf *dmabuf) +{ + struct drm_gem_cma_object *obj = dmabuf->priv; + return obj->vaddr; +} + +static struct dma_buf_ops tegra_dmabuf_ops = { + .map_dma_buf = tegra_dmabuf_map, + .unmap_dma_buf = tegra_dmabuf_unmap, + .release = tegra_dmabuf_release, + .kmap_atomic = tegra_dmabuf_kmap_atomic, + .kmap = tegra_dmabuf_kmap, + .mmap = tegra_dmabuf_mmap, + .vmap = tegra_dmabuf_vmap, +}; + +struct dma_buf *tegra_dmabuf_export(struct drm_device *drm_dev, + struct drm_gem_object *obj, int flags) +{ + return dma_buf_export(obj, &tegra_dmabuf_ops, obj->size, O_RDWR); +} + +struct drm_gem_object *tegra_dmabuf_import(struct drm_device *drm_dev, + struct dma_buf *dmabuf) +{ + return NULL; +} diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index cba2d1d..f78a31b 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -251,7 +251,8 @@ static const struct file_operations tegra_drm_fops = { }; struct drm_driver tegra_drm_driver = { - .driver_features = DRIVER_BUS_PLATFORM | DRIVER_MODESET | DRIVER_GEM, + .driver_features = DRIVER_BUS_PLATFORM | DRIVER_MODESET | DRIVER_GEM | + DRIVER_PRIME, .load = tegra_drm_load, .unload = tegra_drm_unload, .open = tegra_drm_open, @@ -267,6 +268,12 @@ struct drm_driver tegra_drm_driver = { .num_ioctls = ARRAY_SIZE(tegra_drm_ioctls), .fops = &tegra_drm_fops, + .prime_handle_to_fd = drm_gem_prime_handle_to_fd, + .prime_fd_to_handle = drm_gem_prime_fd_to_handle, + + .gem_prime_export = tegra_dmabuf_export, + .gem_prime_import = tegra_dmabuf_import, + .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE, diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index b2f9f10..1267a38 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -227,4 +227,10 @@ extern struct platform_driver tegra_dsi_driver; extern struct platform_driver tegra_dc_driver; extern struct drm_driver tegra_drm_driver; +/* from dmabuf.c */ +struct dma_buf *tegra_dmabuf_export(struct drm_device *drm_dev, + struct drm_gem_object *obj, int flags); +struct drm_gem_object *tegra_dmabuf_import(struct drm_device *drm_dev, + struct dma_buf *dmabuf); + #endif /* TEGRA_DRM_H */