From patchwork Mon Mar 12 10:17:11 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benjamin Gaignard X-Patchwork-Id: 7227 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 270D123E14 for ; Mon, 12 Mar 2012 10:07:08 +0000 (UTC) Received: from mail-iy0-f180.google.com (mail-iy0-f180.google.com [209.85.210.180]) by fiordland.canonical.com (Postfix) with ESMTP id CA1B7A18409 for ; Mon, 12 Mar 2012 10:07:07 +0000 (UTC) Received: by iage36 with SMTP id e36so8578276iag.11 for ; Mon, 12 Mar 2012 03:07:07 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf:from:to:cc :subject:date:message-id:x-mailer:in-reply-to:references :mime-version:content-type:x-gm-message-state; bh=AkNpkSWLPSuheBw50iW7uphFsoXRvQSdPmGJXENcVTg=; b=IG2uz6qHDyzG3jYj8BZZwID9pB6kTOfWAltwGxvi2FFw32uYVxoCWln8cP24GwgQYi N4vYwsdv90zra5k/OHADz+I7FiGrHcEMFsWZRBhUoa/+cI7HQvhpYWbvEeebgXx/xG2Y 7mDIm8o3BRYYfdJRMP47cpbid+MO324o42NoggevAwLrRNztNGzHL6eIWzhzTfgIQalg wDhNUe763njLfzm/NBin9fBMYC0PFFYb2Wi6rm0LH0Kq9mHrg9YWgqZkYa3TD3KHaRDj hRWgu0H9vUpeBCgtCv4UTBWIwyOixyka26OfgiMlJQtiLAmCiVJ6ewjEDxYh4cXzGzWe eEOQ== Received: by 10.50.222.233 with SMTP id qp9mr7035188igc.58.1331546827299; Mon, 12 Mar 2012 03:07:07 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.231.53.18 with SMTP id k18csp36625ibg; Mon, 12 Mar 2012 03:07:04 -0700 (PDT) Received: by 10.14.100.208 with SMTP id z56mr1720007eef.79.1331546824143; Mon, 12 Mar 2012 03:07:04 -0700 (PDT) Received: from eu1sys200aog120.obsmtp.com (eu1sys200aog120.obsmtp.com. [207.126.144.149]) by mx.google.com with SMTP id d12si5839554eei.214.2012.03.12.03.07.02 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 12 Mar 2012 03:07:04 -0700 (PDT) Received-SPF: neutral (google.com: 207.126.144.149 is neither permitted nor denied by best guess record for domain of benjamin.gaignard@stericsson.com) client-ip=207.126.144.149; Authentication-Results: mx.google.com; spf=neutral (google.com: 207.126.144.149 is neither permitted nor denied by best guess record for domain of benjamin.gaignard@stericsson.com) smtp.mail=benjamin.gaignard@stericsson.com Received: from beta.dmz-us.st.com ([167.4.1.35]) (using TLSv1) by eu1sys200aob120.postini.com ([207.126.147.11]) with SMTP ID DSNKT13Kxbc5/9fmjwLWeJkLER1FA4KZ934u@postini.com; Mon, 12 Mar 2012 10:07:03 UTC Received: from zeta.dmz-us.st.com (ns4.st.com [167.4.16.71]) by beta.dmz-us.st.com (STMicroelectronics) with ESMTP id 5E284B0; Mon, 12 Mar 2012 10:06:41 +0000 (GMT) Received: from relay2.stm.gmessaging.net (unknown [10.230.100.18]) by zeta.dmz-us.st.com (STMicroelectronics) with ESMTP id 9D075269; Mon, 12 Mar 2012 08:30:03 +0000 (GMT) Received: from exdcvycastm022.EQ1STM.local (alteon-source-exch [10.230.100.61]) (using TLSv1 with cipher RC4-MD5 (128/128 bits)) (Client CN "exdcvycastm022", Issuer "exdcvycastm022" (not verified)) by relay2.stm.gmessaging.net (Postfix) with ESMTPS id 0259AA80A7; Mon, 12 Mar 2012 11:06:49 +0100 (CET) Received: from localhost.localdomain (10.230.100.153) by smtp.stericsson.com (10.230.100.30) with Microsoft SMTP Server (TLS) id 8.3.83.0; Mon, 12 Mar 2012 11:06:52 +0100 From: To: Cc: , , benjamin gaignard Subject: [PATCH 3/3] add CMA heap Date: Mon, 12 Mar 2012 11:17:11 +0100 Message-ID: <1331547431-3737-4-git-send-email-benjamin.gaignard@stericsson.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1331547431-3737-1-git-send-email-benjamin.gaignard@stericsson.com> References: <1331547431-3737-1-git-send-email-benjamin.gaignard@stericsson.com> MIME-Version: 1.0 X-Gm-Message-State: ALoCoQmAF2W4qcu0dyafMp09ky5izhIotCLO4cCuDElJVOh2e3OTsHO5C/b5HOUKm6ezNjCHiwW8 From: benjamin gaignard New heap, allocation is done with dma_alloc_coherent API. device coherent_dma_mask is set to DMA_BIT_MASK(32) Heap type isn't checked but we can think that ION_HEAP_TYPE_SYSTEM_CONTIG is the correct choice Signed-off-by: Benjamin Gaignard --- drivers/gpu/ion/Kconfig | 5 + drivers/gpu/ion/Makefile | 1 + drivers/gpu/ion/cma/Makefile | 1 + drivers/gpu/ion/cma/ion_cma_heap.c | 217 ++++++++++++++++++++++++++++++++++++ 4 files changed, 224 insertions(+), 0 deletions(-) create mode 100644 drivers/gpu/ion/cma/Makefile create mode 100644 drivers/gpu/ion/cma/ion_cma_heap.c diff --git a/drivers/gpu/ion/Kconfig b/drivers/gpu/ion/Kconfig index 5b48b4e..231dbb1 100644 --- a/drivers/gpu/ion/Kconfig +++ b/drivers/gpu/ion/Kconfig @@ -10,3 +10,8 @@ config ION_TEGRA help Choose this option if you wish to use ion on an nVidia Tegra. +config ION_CMA + tristate "Ion CMA heap" + depends on ION && CMA + help + Choose this option to enable ION CMA heap. diff --git a/drivers/gpu/ion/Makefile b/drivers/gpu/ion/Makefile index 73fe3fa..05f174a 100644 --- a/drivers/gpu/ion/Makefile +++ b/drivers/gpu/ion/Makefile @@ -1,2 +1,3 @@ obj-$(CONFIG_ION) += ion.o ion_heap.o ion_system_heap.o ion_carveout_heap.o obj-$(CONFIG_ION_TEGRA) += tegra/ +obj-$(CONFIG_ION_CMA) += cma/ diff --git a/drivers/gpu/ion/cma/Makefile b/drivers/gpu/ion/cma/Makefile new file mode 100644 index 0000000..673508d --- /dev/null +++ b/drivers/gpu/ion/cma/Makefile @@ -0,0 +1 @@ +obj-y += ion_cma_heap.o diff --git a/drivers/gpu/ion/cma/ion_cma_heap.c b/drivers/gpu/ion/cma/ion_cma_heap.c new file mode 100644 index 0000000..1714316 --- /dev/null +++ b/drivers/gpu/ion/cma/ion_cma_heap.c @@ -0,0 +1,217 @@ +/* + * drivers/gpu/ion/ion_cma_heap.c + * + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* for ion_heap_ops structure */ +#include "../ion_priv.h" + +#define ION_CMA_ALLOCATE_FAILED -1 + +static u64 dma_mask = DMA_BIT_MASK(32); + +struct ion_heap **heaps; +struct ion_device *ion_cma_device; + +struct ion_cma_buffer_info { + void *cpu_addr; + dma_addr_t handle; +}; + +/* ION CMA heap operations functions */ +static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer, + unsigned long len, unsigned long align, + unsigned long flags) +{ + struct ion_device *idev = heap->dev; + struct device *dev = idev->dev.parent; + struct ion_cma_buffer_info *info; + + dev_dbg(dev, "Request buffer allocation len %ld\n", len); + + info = kzalloc(sizeof(struct ion_cma_buffer_info), GFP_KERNEL); + if (!info) { + dev_err(dev, "Can't allocate buffer info\n"); + return ION_CMA_ALLOCATE_FAILED; + } + + info->cpu_addr = dma_alloc_coherent(dev, len, &(info->handle), 0); + + if (!info->cpu_addr) { + dev_err(dev, "Fail to allocate buffer\n"); + kfree(info); + return ION_CMA_ALLOCATE_FAILED; + } + + /* keep this for memory release */ + buffer->priv_virt = info; + dev_dbg(dev, "Allocate buffer %p\n", buffer); + return 0; +} + +static void ion_cma_free(struct ion_buffer *buffer) +{ + struct ion_device *idev = buffer->dev; + struct device *dev = idev->dev.parent; + struct ion_cma_buffer_info *info = buffer->priv_virt; + + dev_dbg(dev, "Release buffer %p\n", buffer); + dma_free_coherent(dev, buffer->size, info->cpu_addr, info->handle); + kfree(info); +} + +/* return physical address in addr */ +static int ion_cma_phys(struct ion_heap *heap, struct ion_buffer *buffer, + ion_phys_addr_t *addr, size_t *len) +{ + struct ion_device *idev = buffer->dev; + struct device *dev = idev->dev.parent; + struct ion_cma_buffer_info *info = buffer->priv_virt; + + dev_dbg(dev, "Return buffer %p physical address 0x%x\n", buffer, + virt_to_phys(info->cpu_addr)); + + *addr = virt_to_phys(info->cpu_addr); + *len = buffer->size; + + return 0; +} + +static int ion_cma_mmap(struct ion_heap *mapper, struct ion_buffer *buffer, + struct vm_area_struct *vma) +{ + struct ion_device *idev = buffer->dev; + struct device *dev = idev->dev.parent; + struct ion_cma_buffer_info *info = buffer->priv_virt; + + return dma_mmap_coherent(dev, vma, info->cpu_addr, info->handle, + buffer->size); +} + +static struct ion_heap_ops ion_cma_ops = { + .allocate = ion_cma_allocate, + .free = ion_cma_free, + .phys = ion_cma_phys, + .map_user = ion_cma_mmap, +}; + +struct ion_heap *ion_cma_heap_create(struct ion_platform_heap *data) +{ + struct ion_heap *heap; + + heap = ion_heap_create(data); + + if (heap) + heap->ops = &ion_cma_ops; + + return heap; +} + +/* ION CMA heap platform driver functions */ +int ion_cma_probe(struct platform_device *pdev) +{ + struct ion_platform_data *pdata = pdev->dev.platform_data; + int num_heaps = pdata->nr; + int i, err; + + heaps = kzalloc(sizeof(struct ion_heap *) * num_heaps, GFP_KERNEL); + + dev_info(&pdev->dev, "Create ION CMA device %p\n", &pdev->dev); + ion_cma_device = ion_device_create(NULL); + if (IS_ERR_OR_NULL(ion_cma_device)) { + kfree(heaps); + dev_err(&pdev->dev, "Can't create ION CMA device\n"); + return PTR_ERR(ion_cma_device); + } + + ion_cma_device->dev.parent = &pdev->dev; + + /* set dma mask for this device */ + pdev->dev.dma_mask = &dma_mask; + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + + /* create all the heaps specified in board configuration file */ + for (i = 0; i < num_heaps; i++) { + struct ion_platform_heap *heap_data = &pdata->heaps[i]; + + heaps[i] = ion_cma_heap_create(heap_data); + if (IS_ERR_OR_NULL(heaps[i])) { + dev_err(&pdev->dev, "Can't create heap %s\n", + heap_data->name); + err = PTR_ERR(heaps[i]); + goto err; + } + ion_device_add_heap(ion_cma_device, heaps[i]); + dev_dbg(&pdev->dev, "Add heap %s\n", heap_data->name); + } + + platform_set_drvdata(pdev, ion_cma_device); + return 0; + +err: + for (i = 0; i < num_heaps; i++) + if (heaps[i]) + ion_heap_destroy(heaps[i]); + + kfree(heaps); + return err; +} + +int ion_cma_remove(struct platform_device *pdev) +{ + struct ion_device *idev = platform_get_drvdata(pdev); + struct ion_platform_data *pdata = pdev->dev.platform_data; + int i, num_heaps; + + num_heaps = pdata->nr; + + /* remove ION device */ + ion_device_destroy(idev); + + /* remove all heaps create by the driver */ + for (i = 0; i < num_heaps; i++) + if (heaps[i]) + ion_heap_destroy(heaps[i]); + + return 0; +} + +static struct platform_driver ion_cma_driver = { + .probe = ion_cma_probe, + .remove = ion_cma_remove, + .driver = { + .name = "ion-cma" + } +}; + +static int __init ion_cma_init(void) +{ + return platform_driver_register(&ion_cma_driver); +} + +static void __exit ion_cma_exit(void) +{ + platform_driver_unregister(&ion_cma_driver); +} + +module_init(ion_cma_init); +module_exit(ion_cma_exit);