From patchwork Mon Jul 14 08:28:06 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Szyprowski X-Patchwork-Id: 4543381 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id E33CC9F37F for ; Mon, 14 Jul 2014 08:31:26 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id D7D2D20158 for ; Mon, 14 Jul 2014 08:31:25 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id C90B72012B for ; Mon, 14 Jul 2014 08:31:23 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1X6bd6-000647-IU; Mon, 14 Jul 2014 08:29:00 +0000 Received: from mailout3.w1.samsung.com ([210.118.77.13]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1X6bco-0005vS-UB for linux-arm-kernel@lists.infradead.org; Mon, 14 Jul 2014 08:28:44 +0000 Received: from eucpsbgm2.samsung.com (unknown [203.254.199.245]) by mailout3.w1.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0N8P00E1Z0V46710@mailout3.w1.samsung.com> for linux-arm-kernel@lists.infradead.org; Mon, 14 Jul 2014 09:28:16 +0100 (BST) X-AuditID: cbfec7f5-b7f626d000004b39-4e-53c394a164c2 Received: from eusync3.samsung.com ( [203.254.199.213]) by eucpsbgm2.samsung.com (EUCPMTA) with SMTP id B5.FD.19257.1A493C35; Mon, 14 Jul 2014 09:28:17 +0100 (BST) Received: from amdc1339.digital.local ([106.116.147.30]) by eusync3.samsung.com (Oracle Communications Messaging Server 7u4-23.01 (7.0.4.23.0) 64bit (built Aug 10 2011)) with ESMTPA id <0N8P00JJ10UYW070@eusync3.samsung.com>; Mon, 14 Jul 2014 09:28:17 +0100 (BST) From: Marek Szyprowski To: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org Subject: [PATCH v2 RESEND 3/4] drivers: dma-coherent: add initialization from device tree Date: Mon, 14 Jul 2014 10:28:06 +0200 Message-id: <1405326487-15346-4-git-send-email-m.szyprowski@samsung.com> X-Mailer: git-send-email 1.9.2 In-reply-to: <1405326487-15346-1-git-send-email-m.szyprowski@samsung.com> References: <1405326487-15346-1-git-send-email-m.szyprowski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrPLMWRmVeSWpSXmKPExsVy+t/xq7oLpxwONnjZxmUxZ/0aNovHr+ex WPyddIzd4v2yHkaL+UfOsVoc+LOD0WJldzObxc517xgtzja9YbfY3jmD3eLLlYdMFpseX2O1 uLxrDpvF2iN32S02vDzIZLHgeAurxZ/pchZrjixmt/i7fROLxfoZr1ksFs6/z27x8uMJFgcx jzXz1jB6/P41idHjcl8vk8fOWXfZPbreXmHyuHNtD5vHiRm/WTweHNrM4rF5Sb3H7X+PmT3W /XnF5NH/18Bj7q4+Ro++LasYPT5vkgvgj+KySUnNySxLLdK3S+DKeDNrNmPBJtuKvnXL2BsY Fxh1MXJySAiYSKxYNpcNwhaTuHBvPZDNxSEksJRR4vPj7+wgCSGBPiaJd3/8QGw2AUOJrrdd YA0iAm4S/9YdAmtgFnjNKrHi0WcWkISwQLTEt1PrgWwODhYBVYnF6+JAwrwCHhIvu6+wQyyT k/j/cgUTiM0p4Ckx4/N7qF0eEu8v97JOYORdwMiwilE0tTS5oDgpPddIrzgxt7g0L10vOT93 EyMkkr7uYFx6zOoQowAHoxIPbwH/4WAh1sSy4srcQ4wSHMxKIrzhbkAh3pTEyqrUovz4otKc 1OJDjEwcnFINjId3Os1Orb96r4ZhxzOtHcV1u+YJv/7gp8YwJW09p5cDt4TwXtE3T6Orliu9 /yFY1PhU3zhGWUhlqlYTa9et2i9fqy3Wsl3yiI6YP/2JQY3zq/U7nx9LyC65xv0he4mOqcGq qnqWJdcl5K4fFd4vb9T/0eLwv6qZr4Kdbqbs5D+yueIGxy2BICWW4oxEQy3mouJEAK0To2SC AgAA X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140714_012843_153980_113DA160 X-CRM114-Status: GOOD ( 20.58 ) X-Spam-Score: -5.0 (-----) Cc: Jon Medhurst , devicetree@vger.kernel.org, Laura Abbott , Andrew Morton , Arnd Bergmann , Josh Cartwright , Catalin Marinas , Tomasz Figa , Will Deacon , Michal Nazarewicz , linaro-mm-sig@lists.linaro.org, Marc , Nishanth Peethambaran , Paul Mackerras , "Aneesh Kumar K.V." , Grant Likely , Joonsoo Kim , Sascha Hauer , Marek Szyprowski X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Initialization procedure of dma coherent pool has been split into two parts, so memory pool can now be initialized without assigning to particular struct device. Then initialized region can be assigned to more than one struct device. To protect from concurent allocations from different devices, a spinlock has been added to dma_coherent_mem structure. The last part of this patch adds support for handling 'shared-dma-pool' reserved-memory device tree nodes. Signed-off-by: Marek Szyprowski --- drivers/base/dma-coherent.c | 137 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 118 insertions(+), 19 deletions(-) diff --git a/drivers/base/dma-coherent.c b/drivers/base/dma-coherent.c index 7d6e84a51424..7185a4f247e1 100644 --- a/drivers/base/dma-coherent.c +++ b/drivers/base/dma-coherent.c @@ -14,11 +14,14 @@ struct dma_coherent_mem { int size; int flags; unsigned long *bitmap; + spinlock_t spinlock; }; -int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, - dma_addr_t device_addr, size_t size, int flags) +static int dma_init_coherent_memory(phys_addr_t phys_addr, dma_addr_t device_addr, + size_t size, int flags, + struct dma_coherent_mem **mem) { + struct dma_coherent_mem *dma_mem = NULL; void __iomem *mem_base = NULL; int pages = size >> PAGE_SHIFT; int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long); @@ -27,27 +30,26 @@ int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, goto out; if (!size) goto out; - if (dev->dma_mem) - goto out; - - /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ mem_base = ioremap(phys_addr, size); if (!mem_base) goto out; - dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); - if (!dev->dma_mem) + dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL); + if (!dma_mem) goto out; - dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL); - if (!dev->dma_mem->bitmap) + dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL); + if (!dma_mem->bitmap) goto free1_out; - dev->dma_mem->virt_base = mem_base; - dev->dma_mem->device_base = device_addr; - dev->dma_mem->pfn_base = PFN_DOWN(phys_addr); - dev->dma_mem->size = pages; - dev->dma_mem->flags = flags; + dma_mem->virt_base = mem_base; + dma_mem->device_base = device_addr; + dma_mem->pfn_base = PFN_DOWN(phys_addr); + dma_mem->size = pages; + dma_mem->flags = flags; + spin_lock_init(&dma_mem->spinlock); + + *mem = dma_mem; if (flags & DMA_MEMORY_MAP) return DMA_MEMORY_MAP; @@ -55,12 +57,51 @@ int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, return DMA_MEMORY_IO; free1_out: - kfree(dev->dma_mem); + kfree(dma_mem); out: if (mem_base) iounmap(mem_base); return 0; } + +static void dma_release_coherent_memory(struct dma_coherent_mem *mem) +{ + if (!mem) + return; + iounmap(mem->virt_base); + kfree(mem->bitmap); + kfree(mem); +} + +static int dma_assign_coherent_memory(struct device *dev, + struct dma_coherent_mem *mem) +{ + if (dev->dma_mem) + return -EBUSY; + + dev->dma_mem = mem; + /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */ + + return 0; +} + +int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, + dma_addr_t device_addr, size_t size, int flags) +{ + struct dma_coherent_mem *mem; + int ret; + + ret = dma_init_coherent_memory(phys_addr, device_addr, size, flags, + &mem); + if (ret == 0) + return 0; + + if (dma_assign_coherent_memory(dev, mem) == 0) + return ret; + + dma_release_coherent_memory(mem); + return 0; +} EXPORT_SYMBOL(dma_declare_coherent_memory); void dma_release_declared_memory(struct device *dev) @@ -69,10 +110,8 @@ void dma_release_declared_memory(struct device *dev) if (!mem) return; + dma_release_coherent_memory(mem); dev->dma_mem = NULL; - iounmap(mem->virt_base); - kfree(mem->bitmap); - kfree(mem); } EXPORT_SYMBOL(dma_release_declared_memory); @@ -80,6 +119,7 @@ void *dma_mark_declared_memory_occupied(struct device *dev, dma_addr_t device_addr, size_t size) { struct dma_coherent_mem *mem = dev->dma_mem; + unsigned long flags; int pos, err; size += device_addr & ~PAGE_MASK; @@ -87,8 +127,11 @@ void *dma_mark_declared_memory_occupied(struct device *dev, if (!mem) return ERR_PTR(-EINVAL); + spin_lock_irqsave(&mem->spinlock, flags); pos = (device_addr - mem->device_base) >> PAGE_SHIFT; err = bitmap_allocate_region(mem->bitmap, pos, get_order(size)); + spin_unlock_irqrestore(&mem->spinlock, flags); + if (err != 0) return ERR_PTR(err); return mem->virt_base + (pos << PAGE_SHIFT); @@ -115,6 +158,7 @@ int dma_alloc_from_coherent(struct device *dev, ssize_t size, { struct dma_coherent_mem *mem; int order = get_order(size); + unsigned long flags; int pageno; if (!dev) @@ -124,6 +168,7 @@ int dma_alloc_from_coherent(struct device *dev, ssize_t size, return 0; *ret = NULL; + spin_lock_irqsave(&mem->spinlock, flags); if (unlikely(size > (mem->size << PAGE_SHIFT))) goto err; @@ -138,10 +183,12 @@ int dma_alloc_from_coherent(struct device *dev, ssize_t size, *dma_handle = mem->device_base + (pageno << PAGE_SHIFT); *ret = mem->virt_base + (pageno << PAGE_SHIFT); memset(*ret, 0, size); + spin_unlock_irqrestore(&mem->spinlock, flags); return 1; err: + spin_unlock_irqrestore(&mem->spinlock, flags); /* * In the case where the allocation can not be satisfied from the * per-device area, try to fall back to generic memory if the @@ -171,8 +218,11 @@ int dma_release_from_coherent(struct device *dev, int order, void *vaddr) if (mem && vaddr >= mem->virt_base && vaddr < (mem->virt_base + (mem->size << PAGE_SHIFT))) { int page = (vaddr - mem->virt_base) >> PAGE_SHIFT; + unsigned long flags; + spin_lock_irqsave(&mem->spinlock, flags); bitmap_release_region(mem->bitmap, page, order); + spin_unlock_irqrestore(&mem->spinlock, flags); return 1; } return 0; @@ -218,3 +268,52 @@ int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma, return 0; } EXPORT_SYMBOL(dma_mmap_from_coherent); + +/* + * Support for reserved memory regions defined in device tree + */ +#ifdef CONFIG_OF_RESERVED_MEM +#include +#include +#include + +static void rmem_dma_device_init(struct reserved_mem *rmem, struct device *dev) +{ + struct dma_coherent_mem *mem = rmem->priv; + if (!mem && + dma_init_coherent_memory(rmem->base, rmem->base, rmem->size, + DMA_MEMORY_MAP | DMA_MEMORY_EXCLUSIVE, + &mem) != DMA_MEMORY_MAP) { + pr_info("Reserved memory: failed to init DMA memory pool at %pa, size %ld MiB\n", + &rmem->base, (unsigned long)rmem->size / SZ_1M); + return; + } + rmem->priv = mem; + dma_assign_coherent_memory(dev, mem); +} + +static void rmem_dma_device_release(struct reserved_mem *rmem, + struct device *dev) +{ + dev->dma_mem = NULL; +} + +static const struct reserved_mem_ops rmem_dma_ops = { + .device_init = rmem_dma_device_init, + .device_release = rmem_dma_device_release, +}; + +static int __init rmem_dma_setup(struct reserved_mem *rmem) +{ + unsigned long node = rmem->fdt_node; + + if (of_get_flat_dt_prop(node, "reusable", NULL)) + return -EINVAL; + + rmem->ops = &rmem_dma_ops; + pr_info("Reserved memory: created DMA memory pool at %pa, size %ld MiB\n", + &rmem->base, (unsigned long)rmem->size / SZ_1M); + return 0; +} +RESERVEDMEM_OF_DECLARE(dma, "shared-dma-pool", rmem_dma_setup); +#endif