From patchwork Fri May 5 08:37:54 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oza Pawandeep X-Patchwork-Id: 9713177 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 3B2AD60362 for ; Fri, 5 May 2017 08:39:00 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 35EB328627 for ; Fri, 5 May 2017 08:39:00 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2A2DB28631; Fri, 5 May 2017 08:39:00 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 9377628627 for ; Fri, 5 May 2017 08:38:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=RthR1q/2QyAioplDGSADXSzBSLAK8RGUjDnr8BL0gag=; b=BFhhMB5Us9cVnvlMa19G7On+ub uwxq3y9c9/HstlP8yJTeSC30E6LcyMhFV2aesH9qXGkzsfxTbc25bzdh6fLthixo6pJhRcLliGrCz 136jA2Uu+EncZaGDqzXBCES0fqTSDpUkZaN1Q1PUoItF6i/Tsk+ZcX0FT1S5ZlOF/qhhoj0zJQf3w hMw9q3vKL43Fcepw/uhTlAUTwL72jp+Y6qRY12c46uoMD8wnzaZcE2SdulYQ2PKff8jr9jmBOAZgG wcoTuPsKvNuV2uwMlr0av8QdSJYVBY4ExX/IiGbSX7r8gdXoMTyehk2d6THwgdqn4pmhybPRdTtDc As5R9TEg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1d6YlO-0005Gj-E1; Fri, 05 May 2017 08:38:58 +0000 Received: from mail-wm0-x229.google.com ([2a00:1450:400c:c09::229]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1d6Yl6-0004pk-HE for linux-arm-kernel@lists.infradead.org; Fri, 05 May 2017 08:38:56 +0000 Received: by mail-wm0-x229.google.com with SMTP id 142so16312116wma.1 for ; Fri, 05 May 2017 01:38:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=broadcom.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=xj+GDn5nxpbshq0AYAKDOyi2//3l6UKIibbLtWvOQpw=; b=TPDtw8ZA0QlZ8IzgBuwfFqr2RqRqYDh41cGE7nSHMLUeila151AF/9u23mUWWfVoP3 IkG6lVz2rxX9XTa5BqFNgrr72yJ9kJMGY+n/XWF2M++r92ItLDYqf2vgxyo+UX0FnmB2 6LX46J+nbSV+UgYHvA/u6TVmIbSijbOSHY1Mc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=xj+GDn5nxpbshq0AYAKDOyi2//3l6UKIibbLtWvOQpw=; b=Hl9Zm/ur5RjHCQC1zy0zUWU0Ur5iSHyn1LgtfRR7oZuBtB4hzCZrkMzk1fLaf08kNr iuKPqfHJVvFFkqqhFboRr1+4ZE/CnvjP5fk4LdxBNlmbFjB7O9AKYkqgw0A8NFfSXrwO bfy/g85yQiTBRjt5IUiRBu2Wv4UpAUpGPk2R1pOgdYEit38hUw5J6syXJSw+MNVEviJ9 WgR04LiID+FOaKJ9iEwfV0r7+aHR1v/J/DQ7cd12fvg4eFv6WFIejs0jO2HstGZQgWfH qwb5Wbbg+oG5PlyEqSlqCmQ6+ago0tNDLOKCLTPI3W0cWs+wqygBIjt7oZhS2IUwnYk8 lziw== X-Gm-Message-State: AN3rC/4whujvkQzvRx9QI2aPLXGqXg6X/86Cq2mD2M9GjcDrUN7jU1aC wqCAbAVqjix4dLun X-Received: by 10.28.55.9 with SMTP id e9mr4492686wma.44.1493973498602; Fri, 05 May 2017 01:38:18 -0700 (PDT) Received: from anjanavk-OptiPlex-7010.dhcp.avagotech.net ([192.19.237.250]) by smtp.gmail.com with ESMTPSA id b93sm5197990wrd.29.2017.05.05.01.38.12 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 05 May 2017 01:38:17 -0700 (PDT) From: Oza Pawandeep To: Joerg Roedel , Robin Murphy Subject: [PATCH v2 3/3] PCI/of fix of_dma_get_range; get PCI specific dma-ranges Date: Fri, 5 May 2017 14:07:54 +0530 Message-Id: <1493973474-13939-3-git-send-email-oza.oza@broadcom.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1493973474-13939-1-git-send-email-oza.oza@broadcom.com> References: <1493973474-13939-1-git-send-email-oza.oza@broadcom.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20170505_013841_368370_45B0B796 X-CRM114-Status: GOOD ( 19.99 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: devicetree@vger.kernel.org, Oza Pawandeep , linux-pci@vger.kernel.org, linux-kernel@vger.kernel.org, iommu@lists.linux-foundation.org, bcm-kernel-feedback-list@broadcom.com, Oza Pawandeep , linux-arm-kernel@lists.infradead.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP current device framework and OF framework integration assumes dma-ranges in a way where memory-mapped devices define their dma-ranges. (child-bus-address, parent-bus-address, length). of_dma_configure is specifically written to take care of memory mapped devices. but no implementation exists for pci to take care of pcie based memory ranges. for e.g. iproc based SOCs and other SOCs(suc as rcar) have PCI world dma-ranges. dma-ranges = <0x43000000 0x00 0x00 0x00 0x00 0x80 0x00>; this patch fixes the bug in of_dma_get_range, which with as is, parses the PCI memory ranges and return wrong size as 0. in order to get largest possible dma_mask. this patch also retuns the largest possible size based on dma-ranges, for e.g. dma-ranges = <0x43000000 0x00 0x00 0x00 0x00 0x80 0x00>; we should get dev->coherent_dma_mask=0x7fffffffff. based on which IOVA allocation space will honour PCI host bridge limitations. the implementation hooks bus specific callbacks for getting dma-ranges. Signed-off-by: Oza Pawandeep diff --git a/drivers/of/address.c b/drivers/of/address.c index 02b2903..cc0fc28 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,8 @@ struct of_bus { int na, int ns, int pna); int (*translate)(__be32 *addr, u64 offset, int na); unsigned int (*get_flags)(const __be32 *addr); + int (*get_dma_ranges)(struct device_node *np, + u64 *dma_addr, u64 *paddr, u64 *size); }; /* @@ -171,6 +174,146 @@ static int of_bus_pci_translate(__be32 *addr, u64 offset, int na) { return of_bus_default_translate(addr + 1, offset, na - 1); } + +static int of_bus_pci_get_dma_ranges(struct device_node *np, u64 *dma_addr, + u64 *paddr, u64 *size) +{ + struct device_node *node = of_node_get(np); + int ret = 0; + struct resource_entry *window; + LIST_HEAD(res); + + if (!node) + return -EINVAL; + + if (of_bus_pci_match(np)) { + *size = 0; + /* + * PCI dma-ranges is not mandatory property. + * many devices do no need to have it, since + * host bridge does not require inbound memory + * configuration or rather have design limitations. + * so we look for dma-ranges, if missing we + * just return the caller full size, and also + * no dma-ranges suggests that, host bridge allows + * whatever comes in, so we set dma_addr to 0. + */ + ret = of_pci_get_dma_ranges(np, &res); + if (!ret) { + resource_list_for_each_entry(window, &res) { + struct resource *res_dma = window->res; + + if (*size < resource_size(res_dma)) { + *dma_addr = res_dma->start - window->offset; + *paddr = res_dma->start; + *size = resource_size(res_dma); + } + } + } + pci_free_resource_list(&res); + + /* + * return the largest possible size, + * since PCI master allows everything. + */ + if (*size == 0) { + pr_debug("empty/zero size dma-ranges found for node(%s)\n", + np->full_name); + *size = DMA_BIT_MASK(sizeof(dma_addr_t) * 8) - 1; + *dma_addr = *paddr = 0; + ret = 0; + } + + pr_debug("dma_addr(%llx) cpu_addr(%llx) size(%llx)\n", + *dma_addr, *paddr, *size); + } + + of_node_put(node); + + return ret; +} + +static int get_dma_ranges(struct device_node *np, u64 *dma_addr, + u64 *paddr, u64 *size) +{ + struct device_node *node = of_node_get(np); + const __be32 *ranges = NULL; + int len, naddr, nsize, pna; + int ret = 0; + u64 dmaaddr; + + if (!node) + return -EINVAL; + + while (1) { + naddr = of_n_addr_cells(node); + nsize = of_n_size_cells(node); + node = of_get_next_parent(node); + if (!node) + break; + + ranges = of_get_property(node, "dma-ranges", &len); + + /* Ignore empty ranges, they imply no translation required */ + if (ranges && len > 0) + break; + + /* + * At least empty ranges has to be defined for parent node if + * DMA is supported + */ + if (!ranges) + break; + } + + if (!ranges) { + pr_debug("no dma-ranges found for node(%s)\n", np->full_name); + ret = -ENODEV; + goto out; + } + + len /= sizeof(u32); + + pna = of_n_addr_cells(node); + + /* dma-ranges format: + * DMA addr : naddr cells + * CPU addr : pna cells + * size : nsize cells + */ + dmaaddr = of_read_number(ranges, naddr); + *paddr = of_translate_dma_address(np, ranges); + if (*paddr == OF_BAD_ADDR) { + pr_err("translation of DMA address(%pad) to CPU address failed node(%s)\n", + dma_addr, np->full_name); + ret = -EINVAL; + goto out; + } + *dma_addr = dmaaddr; + + *size = of_read_number(ranges + naddr + pna, nsize); + + pr_debug("dma_addr(%llx) cpu_addr(%llx) size(%llx)\n", + *dma_addr, *paddr, *size); + +out: + of_node_put(node); + + return ret; +} + +static int of_bus_isa_get_dma_ranges(struct device_node *np, u64 *dma_addr, + u64 *paddr, u64 *size) +{ + return get_dma_ranges(np, dma_addr, paddr, size); +} + +static int of_bus_default_get_dma_ranges(struct device_node *np, u64 *dma_addr, + u64 *paddr, u64 *size) +{ + return get_dma_ranges(np, dma_addr, paddr, size); +} + #endif /* CONFIG_OF_ADDRESS_PCI */ #ifdef CONFIG_PCI @@ -424,6 +567,7 @@ static unsigned int of_bus_isa_get_flags(const __be32 *addr) .map = of_bus_pci_map, .translate = of_bus_pci_translate, .get_flags = of_bus_pci_get_flags, + .get_dma_ranges = of_bus_pci_get_dma_ranges, }, #endif /* CONFIG_OF_ADDRESS_PCI */ /* ISA */ @@ -435,6 +579,7 @@ static unsigned int of_bus_isa_get_flags(const __be32 *addr) .map = of_bus_isa_map, .translate = of_bus_isa_translate, .get_flags = of_bus_isa_get_flags, + .get_dma_ranges = of_bus_isa_get_dma_ranges, }, /* Default */ { @@ -445,6 +590,7 @@ static unsigned int of_bus_isa_get_flags(const __be32 *addr) .map = of_bus_default_map, .translate = of_bus_default_translate, .get_flags = of_bus_default_get_flags, + .get_dma_ranges = of_bus_default_get_dma_ranges, }, }; @@ -820,74 +966,20 @@ void __iomem *of_io_request_and_map(struct device_node *np, int index, * size : nsize cells * * It returns -ENODEV if "dma-ranges" property was not found - * for this device in DT. + * for this device in DT, except if PCI device then, dma-ranges + * can be optional property, and in that case returns size with + * entire host memory. */ int of_dma_get_range(struct device_node *np, u64 *dma_addr, u64 *paddr, u64 *size) { - struct device_node *node = of_node_get(np); - const __be32 *ranges = NULL; - int len, naddr, nsize, pna; - int ret = 0; - u64 dmaaddr; - - if (!node) - return -EINVAL; - - while (1) { - naddr = of_n_addr_cells(node); - nsize = of_n_size_cells(node); - node = of_get_next_parent(node); - if (!node) - break; - - ranges = of_get_property(node, "dma-ranges", &len); - - /* Ignore empty ranges, they imply no translation required */ - if (ranges && len > 0) - break; - - /* - * At least empty ranges has to be defined for parent node if - * DMA is supported - */ - if (!ranges) - break; - } - - if (!ranges) { - pr_debug("no dma-ranges found for node(%s)\n", np->full_name); - ret = -ENODEV; - goto out; - } - - len /= sizeof(u32); - - pna = of_n_addr_cells(node); - - /* dma-ranges format: - * DMA addr : naddr cells - * CPU addr : pna cells - * size : nsize cells - */ - dmaaddr = of_read_number(ranges, naddr); - *paddr = of_translate_dma_address(np, ranges); - if (*paddr == OF_BAD_ADDR) { - pr_err("translation of DMA address(%pad) to CPU address failed node(%s)\n", - dma_addr, np->full_name); - ret = -EINVAL; - goto out; - } - *dma_addr = dmaaddr; - - *size = of_read_number(ranges + naddr + pna, nsize); - - pr_debug("dma_addr(%llx) cpu_addr(%llx) size(%llx)\n", - *dma_addr, *paddr, *size); + struct of_bus *bus; -out: - of_node_put(node); + /* get bus specific dma-ranges. */ + bus = of_match_bus(np); + if (bus->get_dma_ranges) + return bus->get_dma_ranges(np, dma_addr, paddr, size); - return ret; + return 0; } EXPORT_SYMBOL_GPL(of_dma_get_range);