Re: [PATCH] iommu/rockchip: silence attaching and detaching of devices
On Thu, May 21, 2015 at 09:57:29AM +0200, Heiko Stuebner wrote: Currently the driver emits a log line every time a device attaches or detaches - which happens at every unblank/blank of the drm for example. The message itself also has no real value to the average user and is merely useful when debugging a problem, so make it a dev_dbg instead. Signed-off-by: Heiko Stuebner he...@sntech.de --- drivers/iommu/rockchip-iommu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) Applied, thanks. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 2/4] iommu: Implement common IOMMU ops for DMA mapping
Hi Robin, More info, hope this make it clearer. We are calling dma_map_sg_attrs with the following 2 sg. With IOMMU, we are expecting it got merged into 1 contiguous va range, but instead we get 2 va range. sg0 dma_address 0xfeeddc00 size 0x400, offset 0xc00 sg1 dma_address 0xfeede000 size 0x1000, offset 0x0 Joe.C On Fri, 2015-05-29 at 13:26 +0800, Yong Wu wrote: Hi Robin, Thanks. While we test venc in v4l2, we get a problem: When we enter the funtion[0], it will be break unexpectedly in the funcion[1] while the offset of sg table is not zero. It is ok if the offset is zero. Then I add more log in dma-iommu.c, please help check below. All we tested it based on dma v2. and have not tested it on v3 yet. The code of iommu-map-sg seems the same. if it's fixed in v3, I'm very sorry. The map_sg in mtk-iommu use default_iommu_map_sg. Any question please tell me, Thanks very much. [0]http://lxr.free-electrons.com/source/drivers/media/v4l2-core/videobuf2-dma-contig.c#L564 [1]http://lxr.free-electrons.com/source/drivers/media/v4l2-core/videobuf2-dma-contig.c#L70 On Wed, 2015-05-27 at 15:09 +0100, Robin Murphy wrote: Taking inspiration from the existing arch/arm code, break out some generic functions to interface the DMA-API to the IOMMU-API. This will do the bulk of the heavy lifting for IOMMU-backed dma-mapping. Signed-off-by: Robin Murphy robin.mur...@arm.com --- drivers/iommu/Kconfig | 7 + drivers/iommu/Makefile| 1 + drivers/iommu/dma-iommu.c | 560 ++ include/linux/dma-iommu.h | 94 4 files changed, 662 insertions(+) create mode 100644 drivers/iommu/dma-iommu.c create mode 100644 include/linux/dma-iommu.h [snip] +static int __finalise_sg(struct device *dev, struct scatterlist *sg, int nents, + dma_addr_t dma_addr) +{ + struct scatterlist *s, *seg = sg; + unsigned long seg_mask = dma_get_seg_boundary(dev); + unsigned int max_len = dma_get_max_seg_size(dev); + unsigned int seg_len = 0, seg_dma = 0; + int i, count = 1; + + for_each_sg(sg, s, nents, i) { + /* Un-swizzling the fields here, hence the naming mismatch */ + unsigned int s_offset = sg_dma_address(s); + unsigned int s_length = sg_dma_len(s); + unsigned int s_dma_len = s-length; + + s-offset = s_offset; + s-length = s_length; + sg_dma_address(s) = DMA_ERROR_CODE; + sg_dma_len(s) = 0; + + if (seg_len (seg_dma + seg_len == dma_addr + s_offset) + (seg_len + s_dma_len = max_len) + ((seg_dma seg_mask) = seg_mask - (seg_len + s_length)) + ) { + sg_dma_len(seg) += s_dma_len; + } else { + if (seg_len) { + seg = sg_next(seg); + count++; + } + sg_dma_len(seg) = s_dma_len; + sg_dma_address(seg) = dma_addr + s_offset; Here the value of sg_dma_address have added s_offset, but sg_dma_len(seg) still is s_dma_len. In the first loop, s_dma_len is from s-length which is alignd by s_length = iova_align(iovad, s_length + s_offset); in the interface iommu_dma_map_sg. + + seg_len = s_offset; + seg_dma = dma_addr + s_offset; + } + seg_len += s_length; + dma_addr += s_dma_len; + } + return count; +} + +static void __invalidate_sg(struct scatterlist *sg, int nents) +{ + struct scatterlist *s; + int i; + + for_each_sg(sg, s, nents, i) { + if (sg_dma_address(s) != DMA_ERROR_CODE) + s-offset = sg_dma_address(s); + if (sg_dma_len(s)) + s-length = sg_dma_len(s); + sg_dma_address(s) = DMA_ERROR_CODE; + sg_dma_len(s) = 0; + } +} + +int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg, + int nents, int prot, bool coherent) +{ + struct iommu_dma_domain *dom = arch_get_dma_domain(dev); + struct iova_domain *iovad = dom-iovad; + struct iova *iova; + struct scatterlist *s; + dma_addr_t dma_addr; + size_t iova_len = 0; + int i; + + /* +* Work out how much IOVA space we need, and align the segments to +* IOVA granules for the IOMMU driver to handle. With some clever +* trickery we can modify the list in a reversible manner. +*/ + for_each_sg(sg, s, nents, i) { + size_t s_offset = iova_offset(iovad, s-offset); + size_t s_length = s-length; + + sg_dma_address(s) = s-offset; + sg_dma_len(s) = s_length; + s-offset -= s_offset; + s_length = iova_align(iovad, s_length + s_offset); + s-length =
Re: [PATCH v7 03/25] iommu: Init iommu-groups support earlier, in core_initcall
On Sat, May 23, 2015 at 07:23:34PM +0300, Laurent Pinchart wrote: On Tuesday 19 May 2015 15:20:23 Marek Szyprowski wrote: -arch_initcall(iommu_init); +core_initcall(iommu_init); I'll let Joerg comment on this, but this initcall ordering dance always makes me feel that something isn't quite right. Have you had a chance to look at the patch series I posted about a week ago to implement IOMMU probe deferral support ? Yeah, this is hacky, but I can live with it until your probe deferal patch-set is merged. Joerg ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH v2 2/7] DMA-API: Introduce dma_(un)map_resource
On Mon, May 18, 2015 at 01:24:59PM -0500, wda...@nvidia.com wrote: +static inline dma_addr_t dma_map_resource_attrs(struct device *dev, + struct resource *res, + size_t offset, size_t size, + enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + const struct dma_map_ops *ops = get_dma_ops(dev); + dma_addr_t addr = 0; + + BUG_ON(!valid_dma_direction(dir)); + if (ops-map_resource) + addr = ops-map_resource(dev, res, offset, size, dir, atops-map_resourcetrs); + debug_dma_map_resource(dev, res, offset, size, dir, addr); + + return addr; +} Please just do a BUG_ON(ops-map_resource == NULL) instead of checking the pointer and returning 0 if it is NULL. The 0 could be a valid dma_addr in some implementations, drivers are supposed to check the returned addr with dma_mapping_error only (and no '== 0' checks). Joerg ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 0/4] arm64: IOMMU-backed DMA mapping
Hi Robin, Thanks for your work. We are really moving forward to a common DMA-API implementation for all iommu drivers. On Wed, May 27, 2015 at 03:09:14PM +0100, Robin Murphy wrote: In the meantime, Laurent's proposal for probe deferral[2] offers hope that the bus notifier dance may only need to be short-lived, and I'm hoping to spend some more time on DT-based IOMMU group handling for platform devices, which should hopefully tie in with default domains to make the add_device callback mostly redundant. Yes, this would be great. I think it makes a lot of sense to make use of the default domain feature. Can you have a look at how well this integrates with my current patches for default domains and provide some feedback? Thanks, Joerg ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 2/3] iommu/arm-smmu: Add initial driver support for ARM SMMUv3 devices
Hi Will, On Wed, May 20, 2015 at 06:09:26PM +0100, Will Deacon wrote: On Tue, May 19, 2015 at 04:24:35PM +0100, Joerg Roedel wrote: + /* Page sizes */ + if (reg IDR5_GRAN64K) + pgsize_bitmap |= SZ_64K | SZ_512M; + if (reg IDR5_GRAN16K) + pgsize_bitmap |= SZ_16K | SZ_32M; + if (reg IDR5_GRAN4K) + pgsize_bitmap |= SZ_4K | SZ_2M | SZ_1G; + + arm_smmu_ops.pgsize_bitmap = pgsize_bitmap; So this could effictivly lead to a zero pgsize_bitmap when there are SMMUs in the system with support for different page sizes, no? Indeed, if there is no common page size then we end up not being able to support any. I tried to resolve this by moving the bitmap out of the iommu_ops and into the iommu_domain, but you weren't fond of that idea ;) Well, what you could do (and what I think the core should do at some point) is to build the resulting page-size bitmap by taking the biggest minimum page-size from all iommus and OR the page-size bigger than that together. For a system with 3 SMMUs supporting all of the above pgsize_bitmaps the resulting bitmap would look like this: SZ_64K | SZ_32M | SZ_2M | SZ_512M | SZ_1G; With the biggest minimum page-size all of the bigger page-sizes can be emulated. But that is not necessary for this patch-set, just a suggestion for future work. Joerg ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 2/3] iommu/arm-smmu: Add initial driver support for ARM SMMUv3 devices
Hi Joerg, On 29/05/15 07:43, Joerg Roedel wrote: Hi Will, On Wed, May 20, 2015 at 06:09:26PM +0100, Will Deacon wrote: On Tue, May 19, 2015 at 04:24:35PM +0100, Joerg Roedel wrote: + /* Page sizes */ + if (reg IDR5_GRAN64K) + pgsize_bitmap |= SZ_64K | SZ_512M; + if (reg IDR5_GRAN16K) + pgsize_bitmap |= SZ_16K | SZ_32M; + if (reg IDR5_GRAN4K) + pgsize_bitmap |= SZ_4K | SZ_2M | SZ_1G; + + arm_smmu_ops.pgsize_bitmap = pgsize_bitmap; So this could effictivly lead to a zero pgsize_bitmap when there are SMMUs in the system with support for different page sizes, no? Indeed, if there is no common page size then we end up not being able to support any. I tried to resolve this by moving the bitmap out of the iommu_ops and into the iommu_domain, but you weren't fond of that idea ;) Well, what you could do (and what I think the core should do at some point) is to build the resulting page-size bitmap by taking the biggest minimum page-size from all iommus and OR the page-size bigger than that together. For a system with 3 SMMUs supporting all of the above pgsize_bitmaps the resulting bitmap would look like this: SZ_64K | SZ_32M | SZ_2M | SZ_512M | SZ_1G; With the biggest minimum page-size all of the bigger page-sizes can be emulated. But that is not necessary for this patch-set, just a suggestion for future work. The trouble with this is, what about the CPU page size? Say you have some multimedia subsystem with its own integrated SMMU and for that they've only implemented the 16K granule scheme because it works best for the video hardware (and the GPU driver is making direct IOMMU API calls to remap carved-out RAM rather than using DMA-mapping). Now, the SMMU on the compute side of the SoC serving the general peripherals will be rendered useless by bumping the system-wide minimum page size up to 16K, because it then can't map that scatterlist of discontiguous 4K pages that the USB controller needs... I think this really represents another push to get away from (or at least around) the page-at-a-time paradigm - if the IOMMU API itself wasn't too fussed about page sizes and could let drivers handle the full map/unmap requests however they see fit, I think we could bypass a lot of these issues. We've already got the Intel IOMMU driver doing horrible hacks with the pgsize_bitmap to cheat the system, I'm sure we don't want to add any more of that. How about something like the below diff as a first step? Robin. ---8--- From: Robin Murphy robin.mur...@arm.com Date: Fri, 29 May 2015 12:05:58 +0100 Subject: [PATCH] iommu: Allow drivers to support arbitrary map/unmap requests In certain situations, the page-at-a-time operation of the IOMMU API becomes problematic. For instance, IOMMUs which can support different page sizes per domain confound the use of a single pgsize_bitmap, and more generally it can be horribly inefficient for large operations (such as tearing down VFIO domains). To resolve this, allow drivers to expose their own low-level map/unmap handlers, in the manner of iommu_map_sg, which may bypass this restriction as necessary. The existing callbacks are renamed to better reflect their page-oriented nature. Signed-off-by: Robin Murphy robin.mur...@arm.com --- drivers/iommu/amd_iommu.c | 4 ++-- drivers/iommu/arm-smmu.c | 4 ++-- drivers/iommu/exynos-iommu.c | 4 ++-- drivers/iommu/intel-iommu.c| 4 ++-- drivers/iommu/iommu.c | 14 ++ drivers/iommu/ipmmu-vmsa.c | 4 ++-- drivers/iommu/msm_iommu.c | 4 ++-- drivers/iommu/omap-iommu.c | 4 ++-- drivers/iommu/rockchip-iommu.c | 4 ++-- drivers/iommu/shmobile-iommu.c | 4 ++-- drivers/iommu/tegra-gart.c | 4 ++-- drivers/iommu/tegra-smmu.c | 4 ++-- include/linux/iommu.h | 8 +++- 13 files changed, 39 insertions(+), 27 deletions(-) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index e43d489..13e94ae 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -3418,8 +3418,8 @@ static const struct iommu_ops amd_iommu_ops = { .domain_free = amd_iommu_domain_free, .attach_dev = amd_iommu_attach_device, .detach_dev = amd_iommu_detach_device, - .map = amd_iommu_map, - .unmap = amd_iommu_unmap, + .map_page = amd_iommu_map, + .unmap_page = amd_iommu_unmap, .map_sg = default_iommu_map_sg, .iova_to_phys = amd_iommu_iova_to_phys, .pgsize_bitmap = AMD_IOMMU_PGSIZES, diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 66a803b..427ae40 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1447,8 +1447,8 @@ static struct iommu_ops arm_smmu_ops = { .domain_free= arm_smmu_domain_free, .attach_dev = arm_smmu_attach_dev, .detach_dev = arm_smmu_detach_dev, - .map
Re: [PATCH v2 0/3] iommu/arm=smmu: Add driver for ARM SMMUv3 devices
On Wed, May 27, 2015 at 05:25:57PM +0100, Will Deacon wrote: Will Deacon (3): Documentation: dt-bindings: Add device-tree binding for ARM SMMUv3 IOMMU iommu/arm-smmu: Add initial driver support for ARM SMMUv3 devices drivers/vfio: Allow type-1 IOMMU instantiation on top of an ARM SMMUv3 .../devicetree/bindings/iommu/arm,smmu-v3.txt | 37 + MAINTAINERS|3 +- drivers/iommu/Kconfig | 13 + drivers/iommu/Makefile |1 + drivers/iommu/arm-smmu-v3.c| 2670 drivers/vfio/Kconfig |2 +- 6 files changed, 2724 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/iommu/arm,smmu-v3.txt create mode 100644 drivers/iommu/arm-smmu-v3.c Applied, thanks. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 2/2] iommu/arm-smmu: Make force_stage module param read-only in sysfs
On Wed, May 27, 2015 at 05:09:35PM +0100, Will Deacon wrote: Changing force_stage dynamically isn't supported by the driver and it also doesn't make a whole lot of sense to change it once the SMMU is up and running. This patch makes the sysfs entry for the parameter read-only. Signed-off-by: Will Deacon will.dea...@arm.com --- drivers/iommu/arm-smmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) Applied both patches, thanks. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [RFC/PATCH 4/9] of: dma: Make of_dma_deconfigure() public
On Thu, May 14, 2015 at 6:00 PM, Laurent Pinchart laurent.pinchart+rene...@ideasonboard.com wrote: As part of moving DMA initializing to probe time the of_dma_deconfigure() function will need to be called from different source files. Make it public and move it to drivers/of/device.c where the of_dma_configure() function is. Signed-off-by: Laurent Pinchart laurent.pinchart+rene...@ideasonboard.com One minor fix below, but otherwise: Acked-by: Rob Herring r...@kernel.org --- drivers/of/device.c | 12 drivers/of/platform.c | 5 - include/linux/of_device.h | 3 +++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/drivers/of/device.c b/drivers/of/device.c index 530aa1ed3e1b..f1b84f464fe1 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -135,6 +135,18 @@ void of_dma_configure(struct device *dev, struct device_node *np) } EXPORT_SYMBOL_GPL(of_dma_configure); +/** + * of_dma_deconfigure - Clean up DMA configuration + * @dev: Device for which to clean up DMA configuration + * + * Clean up all configuration performed by of_dma_configure_ops() and free all + * resources that have been allocated. + */ +void of_dma_deconfigure(struct device *dev) +{ + arch_teardown_dma_ops(dev); +} You need an EXPORT_SYMBOL_GPL ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v3 1/7] dma-debug: add checking for map/unmap_resource
From: Will Davis wda...@nvidia.com Add debug callbacks for the new dma_map_resource and dma_unmap_resource functions. Signed-off-by: Will Davis wda...@nvidia.com Reviewed-by: Terence Ripperda trippe...@nvidia.com Reviewed-by: John Hubbard jhubb...@nvidia.com --- include/linux/dma-debug.h | 20 lib/dma-debug.c | 47 +++ 2 files changed, 67 insertions(+) diff --git a/include/linux/dma-debug.h b/include/linux/dma-debug.h index fe8cb61..19f328c 100644 --- a/include/linux/dma-debug.h +++ b/include/linux/dma-debug.h @@ -44,6 +44,13 @@ extern void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr); extern void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, size_t size, int direction, bool map_single); +extern void debug_dma_map_resource(struct device *dev, struct resource *res, + size_t offset, size_t size, int direction, + dma_addr_t dma_addr); + +extern void debug_dma_unmap_resource(struct device *dev, dma_addr_t addr, +size_t size, int direction); + extern void debug_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, int mapped_ents, int direction); @@ -120,6 +127,19 @@ static inline void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, { } +static inline void debug_dma_map_resource(struct device *dev, + struct resource *res, size_t offset, + size_t size, int direction, + dma_addr_t dma_addr) +{ +} + +static inline void debug_dma_unmap_resource(struct device *dev, + dma_addr_t addr, size_t size, + int direction) +{ +} + static inline void debug_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, int mapped_ents, int direction) { diff --git a/lib/dma-debug.c b/lib/dma-debug.c index ae4b65e..a6d8fa7 100644 --- a/lib/dma-debug.c +++ b/lib/dma-debug.c @@ -43,6 +43,7 @@ enum { dma_debug_page, dma_debug_sg, dma_debug_coherent, + dma_debug_resource, }; enum map_err_types { @@ -1348,6 +1349,52 @@ void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, } EXPORT_SYMBOL(debug_dma_unmap_page); +void debug_dma_map_resource(struct device *dev, struct resource *resource, + size_t offset, size_t size, int direction, + dma_addr_t dma_addr) +{ + struct dma_debug_entry *entry; + + if (unlikely(dma_debug_disabled())) + return; + + if (dma_mapping_error(dev, dma_addr)) + return; + + entry = dma_entry_alloc(); + if (!entry) + return; + + entry-dev = dev; + entry-type = dma_debug_resource; + entry-pfn = resource-start PAGE_SHIFT; + entry-offset= offset, + entry-dev_addr = dma_addr; + entry-size = size; + entry-direction = direction; + + add_dma_entry(entry); +} +EXPORT_SYMBOL(debug_dma_map_resource); + +void debug_dma_unmap_resource(struct device *dev, dma_addr_t addr, + size_t size, int direction) +{ + struct dma_debug_entry ref = { + .type = dma_debug_resource, + .dev= dev, + .dev_addr = addr, + .size = size, + .direction = direction, + }; + + if (unlikely(dma_debug_disabled())) + return; + + check_unmap(ref); +} +EXPORT_SYMBOL(debug_dma_unmap_resource); + void debug_dma_map_sg(struct device *dev, struct scatterlist *sg, int nents, int mapped_ents, int direction) { -- 2.4.0 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v3 6/7] iommu/vt-d: implement (un)map_resource
From: Will Davis wda...@nvidia.com Implement 'map_resource' for the Intel IOMMU driver. Simply translate the resource to a physical address and route it to the same handlers used by the 'map_page' API. This allows a device to map another's resource, to enable peer-to-peer transactions. Signed-off-by: Will Davis wda...@nvidia.com Reviewed-by: Terence Ripperda trippe...@nvidia.com Reviewed-by: John Hubbard jhubb...@nvidia.com --- drivers/iommu/intel-iommu.c | 18 ++ 1 file changed, 18 insertions(+) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index 68d43be..0f49eff 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -3095,6 +3095,15 @@ static dma_addr_t intel_map_page(struct device *dev, struct page *page, dir, *dev-dma_mask); } +static dma_addr_t intel_map_resource(struct device *dev, struct resource *res, +unsigned long offset, size_t size, +enum dma_data_direction dir, +struct dma_attrs *attrs) +{ + return __intel_map_single(dev, res-start + offset, size, + dir, *dev-dma_mask); +} + static void flush_unmaps(void) { int i, j; @@ -3226,6 +3235,13 @@ static void intel_unmap_page(struct device *dev, dma_addr_t dev_addr, intel_unmap(dev, dev_addr); } +static void intel_unmap_resource(struct device *dev, dma_addr_t dev_addr, +size_t size, enum dma_data_direction dir, +struct dma_attrs *attrs) +{ + intel_unmap(dev, dev_addr); +} + static void *intel_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flags, struct dma_attrs *attrs) @@ -3382,6 +3398,8 @@ struct dma_map_ops intel_dma_ops = { .unmap_sg = intel_unmap_sg, .map_page = intel_map_page, .unmap_page = intel_unmap_page, + .map_resource = intel_map_resource, + .unmap_resource = intel_unmap_resource, .mapping_error = intel_mapping_error, }; -- 2.4.0 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[PATCH v3 5/7] iommu/amd: Implement (un)map_resource
From: Will Davis wda...@nvidia.com Implement 'map_resource' for the AMD IOMMU driver. Generalize the existing map_page implementation to operate on a physical address, and make both map_page and map_resource wrappers around that helper (and similiarly, for unmap_page and unmap_resource). This allows a device to map another's resource, to enable peer-to-peer transactions. Signed-off-by: Will Davis wda...@nvidia.com Reviewed-by: Terence Ripperda trippe...@nvidia.com Reviewed-by: John Hubbard jhubb...@nvidia.com --- drivers/iommu/amd_iommu.c | 76 +++ 1 file changed, 63 insertions(+), 13 deletions(-) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index e43d489..ca2dac6 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -503,6 +503,8 @@ DECLARE_STATS_COUNTER(cnt_map_single); DECLARE_STATS_COUNTER(cnt_unmap_single); DECLARE_STATS_COUNTER(cnt_map_sg); DECLARE_STATS_COUNTER(cnt_unmap_sg); +DECLARE_STATS_COUNTER(cnt_map_resource); +DECLARE_STATS_COUNTER(cnt_unmap_resource); DECLARE_STATS_COUNTER(cnt_alloc_coherent); DECLARE_STATS_COUNTER(cnt_free_coherent); DECLARE_STATS_COUNTER(cross_page); @@ -541,6 +543,8 @@ static void amd_iommu_stats_init(void) amd_iommu_stats_add(cnt_unmap_single); amd_iommu_stats_add(cnt_map_sg); amd_iommu_stats_add(cnt_unmap_sg); + amd_iommu_stats_add(cnt_map_resource); + amd_iommu_stats_add(cnt_unmap_resource); amd_iommu_stats_add(cnt_alloc_coherent); amd_iommu_stats_add(cnt_free_coherent); amd_iommu_stats_add(cross_page); @@ -2752,20 +2756,16 @@ static void __unmap_single(struct dma_ops_domain *dma_dom, } /* - * The exported map_single function for dma_ops. + * Wrapper function that contains code common to mapping a physical address + * range from a page or a resource. */ -static dma_addr_t map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction dir, - struct dma_attrs *attrs) +static dma_addr_t __map_phys(struct device *dev, phys_addr_t paddr, +size_t size, enum dma_data_direction dir) { unsigned long flags; struct protection_domain *domain; dma_addr_t addr; u64 dma_mask; - phys_addr_t paddr = page_to_phys(page) + offset; - - INC_STATS_COUNTER(cnt_map_single); domain = get_domain(dev); if (PTR_ERR(domain) == -EINVAL) @@ -2791,16 +2791,15 @@ out: } /* - * The exported unmap_single function for dma_ops. + * Wrapper function that contains code common to unmapping a physical address + * range from a page or a resource. */ -static void unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, - enum dma_data_direction dir, struct dma_attrs *attrs) +static void __unmap_phys(struct device *dev, dma_addr_t dma_addr, size_t size, +enum dma_data_direction dir) { unsigned long flags; struct protection_domain *domain; - INC_STATS_COUNTER(cnt_unmap_single); - domain = get_domain(dev); if (IS_ERR(domain)) return; @@ -2815,6 +2814,55 @@ static void unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, } /* + * The exported map_single function for dma_ops. + */ +static dma_addr_t map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + INC_STATS_COUNTER(cnt_map_single); + + return __map_phys(dev, page_to_phys(page) + offset, size, dir); +} + +/* + * The exported unmap_single function for dma_ops. + */ +static void unmap_page(struct device *dev, dma_addr_t dma_addr, size_t size, + enum dma_data_direction dir, struct dma_attrs *attrs) +{ + INC_STATS_COUNTER(cnt_unmap_single); + + __unmap_phys(dev, dma_addr, size, dir); +} + +/* + * The exported map_resource function for dma_ops. + */ +static dma_addr_t map_resource(struct device *dev, struct resource *res, + unsigned long offset, size_t size, + enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + INC_STATS_COUNTER(cnt_map_resource); + + return __map_phys(dev, res-start + offset, size, dir); +} + +/* + * The exported unmap_resource function for dma_ops. + */ +static void unmap_resource(struct device *dev, dma_addr_t dma_addr, + size_t size, enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + INC_STATS_COUNTER(cnt_unmap_resource); + + __unmap_phys(dev, dma_addr, size, dir); +} + +/* * The exported map_sg function for dma_ops (handles scatter-gather * lists). */
[PATCH v3 2/7] DMA-API: Introduce dma_(un)map_resource
From: Will Davis wda...@nvidia.com Add functions to DMA-map and -unmap a resource for a given device. This will allow devices to DMA-map a peer device's resource (for example, another device's BAR region on PCI) to enable peer-to-peer transactions. Signed-off-by: Will Davis wda...@nvidia.com --- include/asm-generic/dma-mapping-broken.h | 9 + include/asm-generic/dma-mapping-common.h | 34 include/linux/dma-mapping.h | 7 +++ 3 files changed, 50 insertions(+) diff --git a/include/asm-generic/dma-mapping-broken.h b/include/asm-generic/dma-mapping-broken.h index 6c32af9..d171f01 100644 --- a/include/asm-generic/dma-mapping-broken.h +++ b/include/asm-generic/dma-mapping-broken.h @@ -59,6 +59,15 @@ extern void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size, enum dma_data_direction direction); +extern dma_addr_t +dma_map_resource(struct device *dev, struct resource *res, +unsigned long offset, size_t size, +enum dma_data_direction direction); + +extern void +dma_unmap_resource(struct device *dev, dma_addr_t dma_address, size_t size, + enum dma_data_direction direction); + extern void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size, enum dma_data_direction direction); diff --git a/include/asm-generic/dma-mapping-common.h b/include/asm-generic/dma-mapping-common.h index 940d5ec..9e6c201 100644 --- a/include/asm-generic/dma-mapping-common.h +++ b/include/asm-generic/dma-mapping-common.h @@ -73,6 +73,36 @@ static inline void dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg ops-unmap_sg(dev, sg, nents, dir, attrs); } +static inline dma_addr_t dma_map_resource_attrs(struct device *dev, + struct resource *res, + size_t offset, size_t size, + enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + struct dma_map_ops *ops = get_dma_ops(dev); + dma_addr_t addr; + + BUG_ON(!valid_dma_direction(dir)); + BUG_ON(ops-map_resource == NULL); + addr = ops-map_resource(dev, res, offset, size, dir, attrs); + debug_dma_map_resource(dev, res, offset, size, dir, addr); + + return addr; +} + +static inline void dma_unmap_resource_attrs(struct device *dev, dma_addr_t addr, + size_t size, + enum dma_data_direction dir, + struct dma_attrs *attrs) +{ + struct dma_map_ops *ops = get_dma_ops(dev); + + BUG_ON(!valid_dma_direction(dir)); + if (ops-unmap_resource) + ops-unmap_resource(dev, addr, size, dir, attrs); + debug_dma_unmap_resource(dev, addr, size, dir); +} + static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, size_t offset, size_t size, enum dma_data_direction dir) @@ -180,6 +210,10 @@ dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, #define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, NULL) #define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, NULL) #define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, NULL) +#define dma_map_resource(d, e, o, s, r) \ + dma_map_resource_attrs(d, e, o, s, r, NULL) +#define dma_unmap_resource(d, a, s, r) \ + dma_unmap_resource_attrs(d, a, s, r, NULL) extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, void *cpu_addr, dma_addr_t dma_addr, size_t size); diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h index ac07ff0..05b0b51 100644 --- a/include/linux/dma-mapping.h +++ b/include/linux/dma-mapping.h @@ -34,6 +34,13 @@ struct dma_map_ops { void (*unmap_page)(struct device *dev, dma_addr_t dma_handle, size_t size, enum dma_data_direction dir, struct dma_attrs *attrs); + dma_addr_t (*map_resource)(struct device *dev, struct resource *res, + unsigned long offset, size_t size, + enum dma_data_direction dir, + struct dma_attrs *attrs); + void (*unmap_resource)(struct device *dev, dma_addr_t dma_handle, + size_t size, enum dma_data_direction dir, + struct dma_attrs *attrs); /* * map_sg returns 0 on error and a value 0 on success. * It should never return a value 0. -- 2.4.0 ___ iommu mailing list iommu@lists.linux-foundation.org
[PATCH v3 0/7] IOMMU/DMA map_resource support for peer-to-peer
From: Will Davis wda...@nvidia.com Hi, This is the third version of a patchset to add the DMA APIs necessary to map and unmap a struct resource to and from a PCI device's IOVA domain. This allows a PCI device to access a peer device's BAR resource when a hardware IOMMU is enabled. Thanks, Will Changelog: v3: - changed dma_map_resource() to BUG() if the map_resource DMA op is not provided, instead of returning 0 - updated documentation to remove requirement to check for 0 return value as an error - remove const keyword from struct dma_map_ops in new DMA APIs for consistency with other APIs v2: http://www.spinics.net/lists/linux-pci/msg41192.html - added documentation for the new DMA APIs - fixed physical-to-bus address conversion in the nommu implementation v1: http://www.spinics.net/lists/linux-pci/msg40747.html Will Davis (7): dma-debug: add checking for map/unmap_resource DMA-API: Introduce dma_(un)map_resource dma-mapping: pci: add pci_(un)map_resource DMA-API: Add dma_(un)map_resource() documentation iommu/amd: Implement (un)map_resource iommu/vt-d: implement (un)map_resource x86: add pci-nommu implementation of map_resource Documentation/DMA-API-HOWTO.txt | 36 ++- Documentation/DMA-API.txt| 31 ++--- arch/x86/kernel/pci-nommu.c | 32 ++ drivers/iommu/amd_iommu.c| 76 ++-- drivers/iommu/intel-iommu.c | 18 include/asm-generic/dma-mapping-broken.h | 9 include/asm-generic/dma-mapping-common.h | 34 ++ include/asm-generic/pci-dma-compat.h | 14 ++ include/linux/dma-debug.h| 20 + include/linux/dma-mapping.h | 7 +++ lib/dma-debug.c | 47 11 files changed, 304 insertions(+), 20 deletions(-) -- 2.4.0 ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: [PATCH 2/4] iommu: Implement common IOMMU ops for DMA mapping
On 29/05/15 06:26, Yong Wu wrote: Hi Robin, Thanks. While we test venc in v4l2, we get a problem: Thanks as always for testing! When we enter the funtion[0], it will be break unexpectedly in the funcion[1] while the offset of sg table is not zero. It is ok if the offset is zero. Then I add more log in dma-iommu.c, please help check below. Bah, non-zero offset was about the only scatterlist case I wasn't able to get out of the EHCI driver... All we tested it based on dma v2. and have not tested it on v3 yet. The code of iommu-map-sg seems the same. if it's fixed in v3, I'm very sorry. The map_sg in mtk-iommu use default_iommu_map_sg. Any question please tell me, Thanks very much. [0]http://lxr.free-electrons.com/source/drivers/media/v4l2-core/videobuf2-dma-contig.c#L564 [1]http://lxr.free-electrons.com/source/drivers/media/v4l2-core/videobuf2-dma-contig.c#L70 On Wed, 2015-05-27 at 15:09 +0100, Robin Murphy wrote: Taking inspiration from the existing arch/arm code, break out some generic functions to interface the DMA-API to the IOMMU-API. This will do the bulk of the heavy lifting for IOMMU-backed dma-mapping. Signed-off-by: Robin Murphy robin.mur...@arm.com --- drivers/iommu/Kconfig | 7 + drivers/iommu/Makefile| 1 + drivers/iommu/dma-iommu.c | 560 ++ include/linux/dma-iommu.h | 94 4 files changed, 662 insertions(+) create mode 100644 drivers/iommu/dma-iommu.c create mode 100644 include/linux/dma-iommu.h [snip] +static int __finalise_sg(struct device *dev, struct scatterlist *sg, int nents, + dma_addr_t dma_addr) +{ + struct scatterlist *s, *seg = sg; + unsigned long seg_mask = dma_get_seg_boundary(dev); + unsigned int max_len = dma_get_max_seg_size(dev); + unsigned int seg_len = 0, seg_dma = 0; + int i, count = 1; + + for_each_sg(sg, s, nents, i) { + /* Un-swizzling the fields here, hence the naming mismatch */ + unsigned int s_offset = sg_dma_address(s); + unsigned int s_length = sg_dma_len(s); + unsigned int s_dma_len = s-length; + + s-offset = s_offset; + s-length = s_length; + sg_dma_address(s) = DMA_ERROR_CODE; + sg_dma_len(s) = 0; + + if (seg_len (seg_dma + seg_len == dma_addr + s_offset) + (seg_len + s_dma_len = max_len) + ((seg_dma seg_mask) = seg_mask - (seg_len + s_length)) + ) { + sg_dma_len(seg) += s_dma_len; + } else { + if (seg_len) { + seg = sg_next(seg); + count++; + } + sg_dma_len(seg) = s_dma_len; Does changing this to sg_dma_len(seg) = s_dma_len - s_offset; make things behave as expected? Since the new unmap code no longer relies on adding up the individual segments to equal the IOVA size I don't _think_ that'll break anything here. Robin. ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
[iommu:x86/vt-d 4/10] drivers/iommu/intel-iommu.c:4875:17: sparse: incorrect type in argument 2 (different address spaces)
tree: git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git x86/vt-d head: 6c37b5ba0e4df96647677fac5d87d9fd561c3ef8 commit: ebe05c7397dc63d99fb3ec69a37b4440952089bc [4/10] iommu/vt-d: Functions to copy data from old mem reproduce: # apt-get install sparse git checkout ebe05c7397dc63d99fb3ec69a37b4440952089bc make ARCH=x86_64 allmodconfig make C=1 CF=-D__CHECK_ENDIAN__ sparse warnings: (new ones prefixed by ) drivers/iommu/intel-iommu.c:1158:13: sparse: symbol 'domain_unmap' was not declared. Should it be static? drivers/iommu/intel-iommu.c:1184:6: sparse: symbol 'dma_free_pagelist' was not declared. Should it be static? drivers/iommu/intel-iommu.c:4875:17: sparse: incorrect type in argument 2 (different address spaces) drivers/iommu/intel-iommu.c:4875:17:expected void const *from drivers/iommu/intel-iommu.c:4875:17:got void [noderef] asn:2*[assigned] virt_mem drivers/iommu/intel-iommu.c:4912:17: sparse: incorrect type in argument 1 (different address spaces) drivers/iommu/intel-iommu.c:4912:17:expected void *to drivers/iommu/intel-iommu.c:4912:17:got void [noderef] asn:2*[assigned] virt_mem drivers/iommu/intel-iommu.c:4829:30: warning: 'device_to_existing_context_entry' defined but not used [-Wunused-function] static struct context_entry *device_to_existing_context_entry( ^ vim +4875 drivers/iommu/intel-iommu.c 4869 4870 virt_mem = ioremap_cache((unsigned long)from, size); 4871 if (!virt_mem) { 4872 kfree(mapped); 4873 return -ENOMEM; 4874 } 4875 memcpy(to, virt_mem, size); 4876 4877 mutex_lock(__iommu_mem_list_lock); 4878 mapped-mem = virt_mem; 4879 list_add_tail(mapped-list, __iommu_remapped_mem); 4880 mutex_unlock(__iommu_mem_list_lock); 4881 } 4882 return size; 4883 } 4884 4885 /* 4886 * Copy memory from a virtually-addressed area into a physically-addressed area 4887 */ 4888 int __iommu_save_to_oldmem(unsigned long to, void *from, unsigned long size) 4889 { 4890 unsigned long pfn; /* Page Frame Number */ 4891 size_t csize = (size_t)size;/* Num(bytes to copy) */ 4892 unsigned long offset; /* Lower 12 bits of to */ 4893 void __iomem *virt_mem; 4894 struct iommu_remapped_entry *mapped; 4895 4896 pfn = to VTD_PAGE_SHIFT; 4897 offset = to (~VTD_PAGE_MASK); 4898 4899 if (page_is_ram(pfn)) { 4900 memcpy(pfn_to_kaddr(pfn) + offset, from, csize); 4901 } else{ 4902 mapped = kzalloc(sizeof(struct iommu_remapped_entry), 4903 GFP_KERNEL); 4904 if (!mapped) 4905 return -ENOMEM; 4906 4907 virt_mem = ioremap_cache((unsigned long)to, size); 4908 if (!virt_mem) { 4909 kfree(mapped); 4910 return -ENOMEM; 4911 } 4912 memcpy(virt_mem, from, size); 4913 mutex_lock(__iommu_mem_list_lock); 4914 mapped-mem = virt_mem; 4915 list_add_tail(mapped-list, __iommu_remapped_mem); --- 0-DAY kernel test infrastructureOpen Source Technology Center http://lists.01.org/mailman/listinfo/kbuild Intel Corporation ___ iommu mailing list iommu@lists.linux-foundation.org https://lists.linuxfoundation.org/mailman/listinfo/iommu
Re: Master-aware devices and sideband ID data
On May 27, 2015, at 10:39 AM, Mark Rutland mark.rutl...@arm.com wrote: On Tue, May 26, 2015 at 11:20:59PM +0100, Chalamarla, Tirumalesh wrote: This is some thing we also like to see in ITS and SMMU drivers. On Mar 24, 2015, at 8:50 AM, Mark Rutland mark.rutl...@arm.com wrote: Hi all, For some devices, identification of particular masters is critical to their operation (e.g. IOMMUs, MSI controllers). The identity of masters is determined from sideband signals on the bus, and it may or may not be possible to probe and/or configure this information. Worse still, these information may be rewritten by intermediate buses, so the information for a given master may differ at different points in the bus hierarchy. We currently describe this master information for devices attached to IOMMUs, with a master ID being encoded in the iommu-cells. However this only covers the ID between the master and its IOMMU(s), and we don't currently have a mechanism to describe the master IDs as they are seen by devices beyond the IOMMU(s), or in the absence of any IOMMU(s). The following are example of master IDs: * PCIe Requester IDs (RIDs) (bus:device.function AKA BDF) * SMMU Stream IDs (SIDs) * GICv3 ITS Device IDs (DIDs) In the case of a system with PCIe, SMMU and GICv3, the master IDs are rewritten in a chain of RID=SID=DID, as in the following diagram: +-+ | PCIe master | +-+ || || Requester ID (RID) || Probeable from RC. \/ +---+ | PCIe Root Complex | +---+ || || SMMU Stream ID (SID) || Derived from RID, static non-probeable mapping. \/ +--+ | SMMU (IOMMU) | +--+ || || ITS Device ID (DID) || Derived from SID, static non-probeable mapping. \/ ++ | GICv3 ITS (MSI controller) | ++ In simpler cases, you might have a simpler set of master ID translations, e.g. just a DID: +-+ | Platform device | +-+ || || ITS Device ID (DID) || Hard-wired on the bus. \/ ++ | GICv3 ITS (MSI controller) | ++ Ignoring current bindings for the moment, I can see how we can describe this with a generic master id-binding, with master-id-map along the lines of interrupt-map, with a tuple format like: child-id-base child-id-length parent parent-id-base For the PCIe example, this would look something like the following (with properties omitted for brevity): PCI: pci@af00 { ... /* Requester ID of PCIe endpoints, implicit at runtime */ master-id-cells = 1; /* RIDS idmapped to SIDS @ SMMU */ master-id-map = 0 0x1 SMMU 0; } SMMU: iommu@bf00 { ... /* SID, derived from RID */ master-id-cells = 1; /* * For some reason the high bit of the ID was negated. */ master-id-map = 0x 0x8000 ITS 0x0 0x8000, 0x8000 0x8000 ITS 0x0 0x; }; ITS: its@cf00 { ... /* DID, derived from SID */ master-id-cells = 2; /* * Master traffic not propagated beyond this point, so no * master-id-ranges */ }; I think it is nice to have max IDs supported by masters. so that drivers can check and enforce. The set of IDs that we expect to transform (i.e. those masters use) would be implicit in the first master-id-map from a master. In the PCI example above, no master is expected to generate an ID outside of the range 0-0x1 inclusive (and that's all the SMMU would see). For devices which are not hotpluggable, the nodes for those devices would describe the specific set of IDs they use. Generally, between a master and a slave there might not be one contiguous set of valid IDs as these may be rewritten along the way (as happens at the SMMU between the PCI root complex and the ITS in the example above). Which drivers do you think need this information? What exactly are they trying to check and enforce? I think, i miss understood by the names, so it is not base it is some thing like x = f(x) = y (and f(x) is bitwise | ) ok now i see it. For the simpler case, this would look something like: DEV: device@af00 { master-id-cells = 1; master-ids = 0xf, 0xb; master-id-map = 0 0xf ITS 0 0; }; ITS: its@cf00 { ... /* DID */ master-id-cells = 2; }; Is this is not depending heavily on discover order, how do drivers know which device to get which ID. is it implicitly assumed in discovery order? I'm not sure I follow the question. Could you elaborate? what happens to hot pluggable devices. It would be necessary to be able to discover the ID assigned to the device by the hotpluggable bus. For example, this could depend on which slot the device is plugged into. If you can't discover the ID
Re: [RFC/PATCH 5/9] of: dma: Split of_configure_dma() into mask and ops configuration
On Thu, May 14, 2015 at 6:00 PM, Laurent Pinchart laurent.pinchart+rene...@ideasonboard.com wrote: The of_configure_dma() function configures both the DMA masks and ops. Moving DMA ops configuration to probe time would thus also delay configuration of the DMA masks, which might not be safe. To avoid issues split the configuration in two to allow keeping masks configuration at device add time and move ops configuration to device probe time. Why is it not safe? The probe is deferred before drivers' probe happens. Rob Signed-off-by: Laurent Pinchart laurent.pinchart+rene...@ideasonboard.com --- drivers/of/device.c | 48 ++- drivers/of/of_pci.c | 3 ++- drivers/of/platform.c | 6 -- include/linux/of_device.h | 11 +-- 4 files changed, 50 insertions(+), 18 deletions(-) diff --git a/drivers/of/device.c b/drivers/of/device.c index f1b84f464fe1..3cb3f78a6d13 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c @@ -70,7 +70,7 @@ int of_device_add(struct platform_device *ofdev) } /** - * of_dma_configure - Setup DMA configuration + * of_dma_configure - Setup DMA masks and offset * @dev: Device to apply DMA configuration * @np:Pointer to OF node having DMA configuration * @@ -81,13 +81,11 @@ int of_device_add(struct platform_device *ofdev) * can use a platform bus notifier and handle BUS_NOTIFY_ADD_DEVICE events * to fix up DMA configuration. */ -void of_dma_configure(struct device *dev, struct device_node *np) +void of_dma_configure_masks(struct device *dev, struct device_node *np) { - u64 dma_addr, paddr, size; - int ret; - bool coherent; + u64 dma_addr, paddr, size, range_mask; unsigned long offset; - struct iommu_ops *iommu; + int ret; /* * Set default coherent_dma_mask to 32 bit. Drivers are expected to @@ -105,9 +103,10 @@ void of_dma_configure(struct device *dev, struct device_node *np) ret = of_dma_get_range(np, dma_addr, paddr, size); if (ret 0) { - dma_addr = offset = 0; - size = dev-coherent_dma_mask + 1; + range_mask = dev-coherent_dma_mask + 1; + offset = 0; } else { + range_mask = DMA_BIT_MASK(ilog2(dma_addr + size)); offset = PFN_DOWN(paddr - dma_addr); dev_dbg(dev, dma_pfn_offset(%#08lx)\n, offset); } @@ -118,10 +117,31 @@ void of_dma_configure(struct device *dev, struct device_node *np) * Limit coherent and dma mask based on size and default mask * set by the driver. */ - dev-coherent_dma_mask = min(dev-coherent_dma_mask, -DMA_BIT_MASK(ilog2(dma_addr + size))); - *dev-dma_mask = min((*dev-dma_mask), -DMA_BIT_MASK(ilog2(dma_addr + size))); + dev-coherent_dma_mask = min(dev-coherent_dma_mask, range_mask); + *dev-dma_mask = min((*dev-dma_mask), range_mask); +} +EXPORT_SYMBOL_GPL(of_dma_configure_masks); + +/** + * of_dma_configure_ops - Setup DMA operations + * @dev: Device to apply DMA configuration + * @np:Pointer to OF node having DMA configuration + * + * Try to get devices's DMA configuration from DT and update it + * accordingly. + */ +int of_dma_configure_ops(struct device *dev, struct device_node *np) +{ + u64 dma_addr, paddr, size; + struct iommu_ops *iommu; + bool coherent; + int ret; + + ret = of_dma_get_range(np, dma_addr, paddr, size); + if (ret 0) { + dma_addr = 0; + size = dev-coherent_dma_mask + 1; + } coherent = of_dma_is_coherent(np); dev_dbg(dev, device is%sdma coherent\n, @@ -132,8 +152,10 @@ void of_dma_configure(struct device *dev, struct device_node *np) iommu ? : not ); arch_setup_dma_ops(dev, dma_addr, size, iommu, coherent); + + return 0; } -EXPORT_SYMBOL_GPL(of_dma_configure); +EXPORT_SYMBOL_GPL(of_dma_configure_ops); /** * of_dma_deconfigure - Clean up DMA configuration diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c index 5751dc5b6494..c65803da2067 100644 --- a/drivers/of/of_pci.c +++ b/drivers/of/of_pci.c @@ -132,7 +132,8 @@ void of_pci_dma_configure(struct pci_dev *pci_dev) if (!bridge-parent) return; - of_dma_configure(dev, bridge-parent-of_node); + of_dma_configure_masks(dev, bridge-parent-of_node); + of_dma_configure_ops(dev, bridge-parent-of_node); pci_put_host_bridge_device(bridge); } EXPORT_SYMBOL_GPL(of_pci_dma_configure); diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 7a660c79ff84..9a29f09b7723 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -177,7 +177,8 @@ static struct