Re: [PATCH] iommu/rockchip: silence attaching and detaching of devices

2015-05-29 Thread Joerg Roedel
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

2015-05-29 Thread Yingjoe Chen

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

2015-05-29 Thread Joerg Roedel
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

2015-05-29 Thread Joerg Roedel
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

2015-05-29 Thread Joerg Roedel
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

2015-05-29 Thread Joerg Roedel
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

2015-05-29 Thread Robin Murphy

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

2015-05-29 Thread Joerg Roedel
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

2015-05-29 Thread Joerg Roedel
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

2015-05-29 Thread Rob Herring
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

2015-05-29 Thread wdavis
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

2015-05-29 Thread wdavis
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

2015-05-29 Thread wdavis
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

2015-05-29 Thread wdavis
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

2015-05-29 Thread wdavis
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

2015-05-29 Thread Robin Murphy

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)

2015-05-29 Thread kbuild test robot
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

2015-05-29 Thread Chalamarla, Tirumalesh

 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

2015-05-29 Thread Rob Herring
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