From patchwork Thu Sep 13 13:52:47 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Federico Vaga X-Patchwork-Id: 14347 Received: from mail.tu-berlin.de ([130.149.7.33]) by www.linuxtv.org with esmtp (Exim 4.72) (envelope-from ) id 1TC9on-00009q-RE for patchwork@linuxtv.org; Thu, 13 Sep 2012 15:50:57 +0200 X-tubIT-Incoming-IP: 209.132.180.67 Received: from vger.kernel.org ([209.132.180.67]) by mail.tu-berlin.de (exim-4.75/mailfrontend-2) with esmtp for id 1TC9on-0002JJ-GI; Thu, 13 Sep 2012 15:50:57 +0200 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754773Ab2IMNuK (ORCPT ); Thu, 13 Sep 2012 09:50:10 -0400 Received: from mail-ee0-f46.google.com ([74.125.83.46]:42751 "EHLO mail-ee0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753518Ab2IMNuI (ORCPT ); Thu, 13 Sep 2012 09:50:08 -0400 Received: by mail-ee0-f46.google.com with SMTP id c1so1953878eek.19 for ; Thu, 13 Sep 2012 06:50:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references; bh=2MrVRFD/UenHT8Isi7JdiM4e5xTgdtZVnXa3UfuTR90=; b=p9/gAIYM+cP09rfbX8lPagKT1Kp/20OvWbcZavHjo9EG6V56ScPIS9yk7JLURZcSDG Mp8KrhD8kRa7pJMWq6xzgzZTNx73Hl0fqyFSlKp8xL6Np0Ybf2/hjmbvOI/xLDKK4G2s Wh07xVR1OzRctytXZAtX/aw4Tk6vUfIubZPylCAePtzQ0O3m4i39PCBYiWEqPIJvVHZO r5dwZ1OKIyZ9waGYcnmyNZdc1/pv0DFnovT51EY8ZbIx5RPpSULQ7Ia+7K9x37QYZOly eMJz9wLHYPUoH3ALOCRsk087v04p8WMt5nOKlXdCMnkNoikow+otTsjramU6vL9FzyHq j/qQ== Received: by 10.14.202.66 with SMTP id c42mr2771397eeo.35.1347544207481; Thu, 13 Sep 2012 06:50:07 -0700 (PDT) Received: from harkonnen.fastwebnet.it (2-225-41-194.ip174.fastwebnet.it. [2.225.41.194]) by mx.google.com with ESMTPS id h2sm65371158eeo.3.2012.09.13.06.50.05 (version=SSLv3 cipher=OTHER); Thu, 13 Sep 2012 06:50:06 -0700 (PDT) From: Federico Vaga To: Mauro Carvalho Chehab , Pawel Osciak , Marek Szyprowski , Hans Verkuil Cc: Giancarlo Asnaghi , linux-media@vger.kernel.org, linux-kernel@vger.kernel.org, Jonathan Corbet , Federico Vaga Subject: [PATCH 3/4] videobuf2-dma-streaming: new videobuf2 memory allocator Date: Thu, 13 Sep 2012 15:52:47 +0200 Message-Id: <1347544368-30583-3-git-send-email-federico.vaga@gmail.com> X-Mailer: git-send-email 1.7.11.4 In-Reply-To: <1347544368-30583-1-git-send-email-federico.vaga@gmail.com> References: <1347544368-30583-1-git-send-email-federico.vaga@gmail.com> Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-PMX-Version: 5.6.1.2065439, Antispam-Engine: 2.7.2.376379, Antispam-Data: 2012.9.13.133923 X-PMX-Spam: Gauge=IIIIIIIII, Probability=9%, Report=' FORGED_FROM_GMAIL 0.1, MULTIPLE_RCPTS 0.1, HTML_00_01 0.05, HTML_00_10 0.05, DKIM_SIGNATURE 0, URI_ENDS_IN_HTML 0, __ANY_URI 0, __CP_URI_IN_BODY 0, __FRAUD_BODY_WEBMAIL 0, __FRAUD_WEBMAIL 0, __FRAUD_WEBMAIL_FROM 0, __FROM_GMAIL 0, __HAS_FROM 0, __HAS_MSGID 0, __HAS_X_MAILER 0, __HAS_X_MAILING_LIST 0, __MIME_TEXT_ONLY 0, __MULTIPLE_RCPTS_CC_X2 0, __PHISH_SPEAR_STRUCTURE_1 0, __SANE_MSGID 0, __SUBJ_ALPHA_END 0, __TO_MALFORMED_2 0, __URI_NO_WWW 0, __URI_NS ' Signed-off-by: Federico Vaga --- drivers/media/v4l2-core/Kconfig | 5 + drivers/media/v4l2-core/Makefile | 1 + drivers/media/v4l2-core/videobuf2-dma-streaming.c | 205 ++++++++++++++++++++++ include/media/videobuf2-dma-streaming.h | 24 +++ 4 file modificati, 235 inserzioni(+) create mode 100644 drivers/media/v4l2-core/videobuf2-dma-streaming.c create mode 100644 include/media/videobuf2-dma-streaming.h diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index 0c54e19..60548a7 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -79,3 +79,8 @@ config VIDEOBUF2_DMA_SG #depends on HAS_DMA select VIDEOBUF2_CORE select VIDEOBUF2_MEMOPS + +config VIDEOBUF2_DMA_STREAMING + select VIDEOBUF2_CORE + select VIDEOBUF2_MEMOPS + tristate diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile index c2d61d4..0b2756f 100644 --- a/drivers/media/v4l2-core/Makefile +++ b/drivers/media/v4l2-core/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_VIDEOBUF2_MEMOPS) += videobuf2-memops.o obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o obj-$(CONFIG_VIDEOBUF2_DMA_SG) += videobuf2-dma-sg.o +obj-$(CONFIG_VIDEOBUF2_DMA_STREAMING) += videobuf2-dma-streaming.o ccflags-y += -I$(srctree)/drivers/media/dvb-core ccflags-y += -I$(srctree)/drivers/media/dvb-frontends diff --git a/drivers/media/v4l2-core/videobuf2-dma-streaming.c b/drivers/media/v4l2-core/videobuf2-dma-streaming.c new file mode 100644 index 0000000..23475a6 --- /dev/null +++ b/drivers/media/v4l2-core/videobuf2-dma-streaming.c @@ -0,0 +1,205 @@ +/* + * videobuf2-dma-streaming.c - DMA streaming memory allocator for videobuf2 + * + * Copyright (C) 2012 Federico Vaga + * * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include + +#include +#include +#include + +struct vb2_streaming_conf { + struct device *dev; +}; +struct vb2_streaming_buf { + struct vb2_streaming_conf *conf; + void *vaddr; + + dma_addr_t dma_handle; + + unsigned long size; + struct vm_area_struct *vma; + + atomic_t refcount; + struct vb2_vmarea_handler handler; +}; + +static void vb2_dma_streaming_put(void *buf_priv) +{ + struct vb2_streaming_buf *buf = buf_priv; + + if (atomic_dec_and_test(&buf->refcount)) { + dma_unmap_single(buf->conf->dev, buf->dma_handle, buf->size, + DMA_FROM_DEVICE); + free_pages_exact(buf->vaddr, buf->size); + kfree(buf); + } + +} + +static void *vb2_dma_streaming_alloc(void *alloc_ctx, unsigned long size) +{ + struct vb2_streaming_conf *conf = alloc_ctx; + struct vb2_streaming_buf *buf; + int err; + + buf = kzalloc(sizeof *buf, GFP_KERNEL); + if (!buf) + return ERR_PTR(-ENOMEM); + buf->vaddr = alloc_pages_exact(size, GFP_KERNEL | GFP_DMA); + if (!buf->vaddr) { + err = -ENOMEM; + goto out; + } + buf->dma_handle = dma_map_single(conf->dev, buf->vaddr, size, + DMA_FROM_DEVICE); + err = dma_mapping_error(conf->dev, buf->dma_handle); + if (err) { + dev_err(conf->dev, "dma_map_single failed\n"); + + free_pages_exact(buf->vaddr, size); + buf->vaddr = NULL; + goto out_pages; + } + buf->conf = conf; + buf->size = size; + buf->handler.refcount = &buf->refcount; + buf->handler.put = vb2_dma_streaming_put; + buf->handler.arg = buf; + + atomic_inc(&buf->refcount); + return buf; + +out_pages: + free_pages_exact(buf->vaddr, buf->size); +out: + kfree(buf); + return ERR_PTR(err); +} + +static void *vb2_dma_streaming_cookie(void *buf_priv) +{ + struct vb2_streaming_buf *buf = buf_priv; + + return (void *)buf->dma_handle; +} + +static void *vb2_dma_streaming_vaddr(void *buf_priv) +{ + struct vb2_streaming_buf *buf = buf_priv; + + if (!buf) + return NULL; + return buf->vaddr; +} + +static unsigned int vb2_dma_streaming_num_users(void *buf_priv) +{ + struct vb2_streaming_buf *buf = buf_priv; + + return atomic_read(&buf->refcount); +} + +static int vb2_dma_streaming_mmap(void *buf_priv, struct vm_area_struct *vma) +{ + struct vb2_streaming_buf *buf = buf_priv; + unsigned long pos, start = vma->vm_start; + unsigned long size; + struct page *page; + int err; + + /* Try to remap memory */ + size = vma->vm_end - vma->vm_start; + size = (size < buf->size) ? size : buf->size; + pos = (unsigned long)buf->vaddr; + + while (size > 0) { + page = virt_to_page((void *)pos); + if (!page) { + dev_err(buf->conf->dev, "mmap: virt_to_page failed\n"); + return -ENOMEM; + } + err = vm_insert_page(vma, start, page); + if (err) { + dev_err(buf->conf->dev, "mmap: insert failed %d\n", err); + return -ENOMEM; + } + start += PAGE_SIZE; + pos += PAGE_SIZE; + + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + + + vma->vm_ops = &vb2_common_vm_ops; + vma->vm_flags |= VM_DONTEXPAND; + vma->vm_private_data = &buf->handler; + + vma->vm_ops->open(vma); + + return 0; +} + +static void vb2_dma_streaming_prepare(void *buf_priv) +{ + struct vb2_streaming_buf *buf = buf_priv; + + dma_sync_single_for_device(buf->conf->dev, buf->dma_handle, + buf->size, DMA_FROM_DEVICE); +} + +static void vb2_dma_streaming_finish(void *buf_priv) +{ + struct vb2_streaming_buf *buf = buf_priv; + + dma_sync_single_for_cpu(buf->conf->dev, buf->dma_handle, + buf->size, DMA_FROM_DEVICE); +} + +const struct vb2_mem_ops vb2_dma_streaming_memops = { + .alloc = vb2_dma_streaming_alloc, + .put = vb2_dma_streaming_put, + .cookie = vb2_dma_streaming_cookie, + .vaddr = vb2_dma_streaming_vaddr, + .mmap = vb2_dma_streaming_mmap, + .num_users = vb2_dma_streaming_num_users, + .prepare = vb2_dma_streaming_prepare, + .finish = vb2_dma_streaming_finish, +}; +EXPORT_SYMBOL_GPL(vb2_dma_streaming_memops); + +void *vb2_dma_streaming_init_ctx(struct device *dev) +{ + struct vb2_streaming_conf *conf; + + conf = kmalloc(sizeof *conf, GFP_KERNEL); + if (!conf) + return ERR_PTR(-ENOMEM); + + conf->dev = dev; + + return conf; +} +EXPORT_SYMBOL_GPL(vb2_dma_streaming_init_ctx); + +void vb2_dma_streaming_cleanup_ctx(void *alloc_ctx) +{ + kfree(alloc_ctx); +} +EXPORT_SYMBOL_GPL(vb2_dma_streaming_cleanup_ctx); + +MODULE_DESCRIPTION("DMA-streaming memory allocator for videobuf2"); +MODULE_AUTHOR("Federico Vaga "); +MODULE_LICENSE("GPL v2"); diff --git a/include/media/videobuf2-dma-streaming.h b/include/media/videobuf2-dma-streaming.h new file mode 100644 index 0000000..89cbd06 --- /dev/null +++ b/include/media/videobuf2-dma-streaming.h @@ -0,0 +1,24 @@ +/* + * videobuf2-dma-streaming.h - DMA steaming memory allocator for videobuf2 + * + * Copyright (C) 2012 Federico Vaga + * + * Author: Federico Vaga + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + */ + +#ifndef _MEDIA_VIDEOBUF2_DMA_STREAMING_H +#define _MEDIA_VIDEOBUF2_DMA_STREAMING_H + +#include +#include + +void *vb2_dma_streaming_init_ctx(struct device *dev); +void vb2_dma_streaming_cleanup_ctx(void *alloc_ctx); + +extern const struct vb2_mem_ops vb2_dma_streaming_memops; + +#endif