From patchwork Mon May 4 08:15:56 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Szyprowski X-Patchwork-Id: 6323981 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 47EC8BEEE1 for ; Mon, 4 May 2015 08:20:20 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 1DEC3202A1 for ; Mon, 4 May 2015 08:20:19 +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 E5B63202AE for ; Mon, 4 May 2015 08:20:17 +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 1YpBZi-0003M1-Ai; Mon, 04 May 2015 08:18:02 +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 1YpBZ8-0002xb-37 for linux-arm-kernel@lists.infradead.org; Mon, 04 May 2015 08:17:27 +0000 Received: from eucpsbgm1.samsung.com (unknown [203.254.199.244]) by mailout3.w1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTP id <0NNT008YXGCDY150@mailout3.w1.samsung.com> for linux-arm-kernel@lists.infradead.org; Mon, 04 May 2015 09:17:01 +0100 (BST) X-AuditID: cbfec7f4-f79c56d0000012ee-33-55472afd5269 Received: from eusync1.samsung.com ( [203.254.199.211]) by eucpsbgm1.samsung.com (EUCPMTA) with SMTP id 8D.B6.04846.DFA27455; Mon, 4 May 2015 09:17:01 +0100 (BST) Received: from amdc1339.digital.local ([106.116.147.30]) by eusync1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0NNT008X3GC52F50@eusync1.samsung.com>; Mon, 04 May 2015 09:17:01 +0100 (BST) From: Marek Szyprowski To: iommu@lists.linux-foundation.org, linux-samsung-soc@vger.kernel.org, linux-arm-kernel@lists.infradead.org Subject: [PATCH v6 01/25] arm: dma-mapping: add support for creating reserved mappings in iova space Date: Mon, 04 May 2015 10:15:56 +0200 Message-id: <1430727380-10912-2-git-send-email-m.szyprowski@samsung.com> X-Mailer: git-send-email 1.9.2 In-reply-to: <1430727380-10912-1-git-send-email-m.szyprowski@samsung.com> References: <1430727380-10912-1-git-send-email-m.szyprowski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFupmkeLIzCtJLcpLzFFi42I5/e/4Zd2/Wu6hBs1LJC3+TjrGbjFx5WRm i0n3J7BYLNhvbXHt9ww2i87ZG9gtXty7yGLR//g1s8XZpjfsFp0Tl7BbfLnykMli0+NrrBYz zu9jslh75C67xanrn9ks/vUeZLT4v2cHu8WRh7vZLWZMfslmsWrXH0aL27/5LF5+PMHiIObx 5OA8Jo8189Ywevz+NYnR4+/sVmaPnbPusnvM7pjJ6rF5hZbHplWdbB6bl9R73P73mNlj8o3l jB5XTjSxevQ2v2Pz6NuyitHj8ya5AP4oLpuU1JzMstQifbsEroyF6/vYCy5ZV/zb8Y25gfGu QRcjB4eEgInE4gv6XYycQKaYxIV769m6GLk4hASWMkpMbPrHCOE0MUms7NvGClLFJmAo0fW2 iw3EFhHIl3ix9y8LiM0s8J5VYsq3QBBbWCBNovnZTzaQBSwCqhJzJoIt4BXwkFj8cxkjxDI5 if8vVzCB2JwCnhLv2reDjRcCqjnTupl1AiPvAkaGVYyiqaXJBcVJ6bmGesWJucWleel6yfm5 mxghUfRlB+PiY1aHGAU4GJV4eBfIuocKsSaWFVfmHmKU4GBWEuF98tEtVIg3JbGyKrUoP76o NCe1+BCjNAeLkjjv3F3vQ4QE0hNLUrNTUwtSi2CyTBycUg2MoWrhD6xa37RfK93ELLnx3deF 6ccP61XmHlmazSXMfft33FPvayemRynmh0/V2Dox9e08qZeTa+tiLVer+cc48wTP+rDFRSSH MThA5LmTsIC5ZVz6lZX3pBWkjr/v8V15L7dCPcx7N6eP7pF3l53db6wyT5vyxC7ApMVpaqze 8w/d6tse3TRUYinOSDTUYi4qTgQAejmXip4CAAA= X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150504_011726_333312_6ACC0313 X-CRM114-Status: GOOD ( 22.00 ) X-Spam-Score: -5.0 (-----) Cc: Rob Herring , Thierry Reding , Shaik Ameer Basha , Joonyoung Shim , Arnd Bergmann , Inki Dae , Seung-Woo Kim , Joerg Roedel , Will Deacon , Tomasz Figa , linaro-mm-sig@lists.linaro.org, Kyungmin Park , Kukjin Kim , Laurent Pinchart , Olof Johansson , Javier Martinez Canillas , Cho KyongHo , David Wodhouse , 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=-4.2 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, T_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 Some devices (like frame buffers) are enabled by bootloader and configured to perform DMA operations automatically (like displaying boot logo or splash screen). Such devices operate and perform DMA operation usually until the proper driver for them is loaded and probed. However before that happens, system usually loads IOMMU drivers and configures dma parameters for each device. When such initial configuration is created and enabled, it usually contains empty translation rules betweem IO address space and physical memory, because no buffers nor memory regions have been requested by the respective driver. This patch adds support for "iommu-reserved-mapping", which can be used to provide definitions for mappings that need to be created on system boot to let such devices (enabled by bootloader) to operate properly until respective driver is probed. Signed-off-by: Marek Szyprowski --- Documentation/devicetree/bindings/iommu/iommu.txt | 44 +++++++++ arch/arm/mm/dma-mapping.c | 112 ++++++++++++++++++++++ 2 files changed, 156 insertions(+) diff --git a/Documentation/devicetree/bindings/iommu/iommu.txt b/Documentation/devicetree/bindings/iommu/iommu.txt index 5a8b4624defc..fd54e6b597f0 100644 --- a/Documentation/devicetree/bindings/iommu/iommu.txt +++ b/Documentation/devicetree/bindings/iommu/iommu.txt @@ -86,6 +86,35 @@ have a means to turn off translation. But it is invalid in such cases to disable the IOMMU's device tree node in the first place because it would prevent any driver from properly setting up the translations. +Optional properties: +-------------------- +- iommu-reserved-mapping: A list of entries describing additional + reserved mapping, that will be inserted to the default IO address space + created for given master device. Each entry consist of IO address, + physical memory address and size of the region. + +Some devices (like frame buffers) are enabled by bootloader and configured +to perform DMA operations automatically (like displaying boot logo or splash +screen). Such devices operate and perform DMA operation usually until the +proper driver for them is loaded and probed. However before that happens, +system usually loads IOMMU drivers and configures dma parameters for each +device. When such initial configuration is created and enabled, it usually +contains empty translation rules betweem IO address space and physical +memory, because no buffers nor memory regions have been requested by the +respective driver. + +To avoid IOMMU page fault, one can provide "iommu-reserved-mapping" +property, which defines all memory regions which must be mapped to IO +address space to boot properly when device has been enabled by the +bootloader. More than one region can be defined for given master device. +Each region is defined by the following triplet: first entry is IO +address (encoded in "address" cells), second is base physical memory +address for this regions (also encoded in "address" cells) and the last +is size of the region (encoded in "size" cells). To ensure that that +given master device will not trigger page fault after enabling IOMMU, +one should define identity mapping between physical memory and IO +address space for the range of addresses accessed by the device. + Notes: ====== @@ -113,6 +142,21 @@ Single-master IOMMU: iommus = <&{/iommu}>; }; + +Single-master IOMMU, which has been left enabled by bootloader: +--------------------------------------------------------------- + + iommu { + #iommu-cells = <0>; + }; + + master { + iommus = <&{/iommu}>; + /* bootloader configures framebuffer at 0x40000000 (32MiB) + iommu-reserved-mapping = <0x40000000 0x40000000 0x2000000>; + }; + + Multiple-master IOMMU with fixed associations: ---------------------------------------------- diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index 7e7583ddd607..3b4a94695b68 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -1019,6 +1019,50 @@ fs_initcall(dma_debug_do_init); static int extend_iommu_mapping(struct dma_iommu_mapping *mapping); +static inline int __reserve_iova(struct dma_iommu_mapping *mapping, + dma_addr_t iova, size_t size) +{ + unsigned long count, start; + unsigned long flags; + int i, sbitmap, ebitmap; + + if (iova < mapping->base) + return -EINVAL; + + start = (iova - mapping->base) >> PAGE_SHIFT; + count = PAGE_ALIGN(size) >> PAGE_SHIFT; + + sbitmap = start / mapping->bits; + ebitmap = (start + count) / mapping->bits; + start = start % mapping->bits; + + if (ebitmap > mapping->extensions) + return -EINVAL; + + spin_lock_irqsave(&mapping->lock, flags); + + for (i = mapping->nr_bitmaps; i <= ebitmap; i++) { + if (extend_iommu_mapping(mapping)) { + spin_unlock_irqrestore(&mapping->lock, flags); + return -ENOMEM; + } + } + + for (i = sbitmap; count && i < mapping->nr_bitmaps; i++) { + int bits = count; + + if (bits + start > mapping->bits) + bits = mapping->bits - start; + bitmap_set(mapping->bitmaps[i], start, bits); + start = 0; + count -= bits; + } + + spin_unlock_irqrestore(&mapping->lock, flags); + + return 0; +} + static inline dma_addr_t __alloc_iova(struct dma_iommu_mapping *mapping, size_t size) { @@ -2048,6 +2092,66 @@ void arm_iommu_detach_device(struct device *dev) } EXPORT_SYMBOL_GPL(arm_iommu_detach_device); +static int arm_iommu_add_reserved(struct device *dev, + struct dma_iommu_mapping *domain, phys_addr_t phys, + dma_addr_t dma, size_t size) +{ + int ret; + + ret = __reserve_iova(domain, dma, size); + if (ret) { + dev_err(dev, "failed to reserve mapping\n"); + return -EINVAL; + } + + ret = iommu_map(domain->domain, dma, phys, size, IOMMU_READ); + if (ret != 0) { + dev_err(dev, "create IOMMU mapping\n"); + return ret; + } + + dev_info(dev, "created reserved DMA mapping (%pa -> %pad, %zu bytes)\n", + &phys, &dma, size); + + return 0; +} + +static int arm_iommu_init_reserved(struct device *dev, + struct dma_iommu_mapping *domain) +{ + const char *name = "iommu-reserved-mapping"; + const __be32 *prop = NULL; + int len, naddr, nsize; + struct device_node *node = dev->of_node; + phys_addr_t phys; + dma_addr_t dma; + size_t size; + + if (!node) + return 0; + + naddr = of_n_addr_cells(node); + nsize = of_n_size_cells(node); + + prop = of_get_property(node, name, &len); + if (!prop) + return 0; + + len /= sizeof(u32); + + if (len < 2 * naddr + nsize) { + dev_err(dev, "invalid length (%d cells) of %s property\n", + len, name); + return -EINVAL; + } + + phys = of_read_number(prop, naddr); + dma = of_read_number(prop + naddr, naddr); + size = of_read_number(prop + 2*naddr, nsize); + + return arm_iommu_add_reserved(dev, domain, phys, dma, size); +} + static struct dma_map_ops *arm_get_iommu_dma_map_ops(bool coherent) { return coherent ? &iommu_coherent_ops : &iommu_ops; @@ -2068,6 +2172,14 @@ static bool arm_setup_iommu_dma_ops(struct device *dev, u64 dma_base, u64 size, return false; } + if (arm_iommu_init_reserved(dev, mapping) != 0) { + pr_warn("Failed to initialize reserved mapping for device %s\n", + dev_name(dev)); + __arm_iommu_detach_device(dev); + arm_iommu_release_mapping(mapping); + return false; + } + if (__arm_iommu_attach_device(dev, mapping)) { pr_warn("Failed to attached device %s to IOMMU_mapping\n", dev_name(dev));