Re: [PATCH 1/2] dma-mapping: introduce relaxed version of dma sync

2020-08-18 Thread Cho KyongHo
On Tue, Aug 18, 2020 at 05:10:06PM +0100, Christoph Hellwig wrote:
> On Tue, Aug 18, 2020 at 11:07:57AM +0100, Will Deacon wrote:
> > > > so I'm not sure
> > > > that we should be complicating the implementation like this to try to
> > > > make it "fast".
> > > > 
> > > I agree that this patch makes the implementation of dma API a bit more
> > > but I don't think this does not impact its complication seriously.
> > 
> > It's death by a thousand cuts; this patch further fragments the architecture
> > backends and leads to arm64-specific behaviour which consequently won't get
> > well tested by anybody else. Now, it might be worth it, but there's not
> > enough information here to make that call.
> 
> So it turns out I misread the series (*cough*, crazy long lines,
> *cough*), and it does not actually expose a new API as I thought, but
> it still makes a total mess of the internal interface.  It turns out
> that on the for cpu side we already have arch_sync_dma_for_cpu_all,
> which should do all that is needed.  We could do the equivalent for
> the to device side, but only IFF there really is a major benefit for
> something that actually is mainstream and matters.
> 
Indeed, arch_sync_dma_for_cpu_all() is used where the new internal API
arch_sync_barrier_for_cpu() should be called. I just thought it is a
special hook for MIPS.
In the next version of the patch series, I should consider using
arch_sync_dma_for_cpu_all() and introducting its 'for_dev' version with
some performance data to show the benefit of the change.

Thank you for the proposal.

KyongHo
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Re: [PATCH 1/2] dma-mapping: introduce relaxed version of dma sync

2020-08-18 Thread Cho KyongHo
On Tue, Aug 18, 2020 at 11:07:57AM +0100, Will Deacon wrote:
> On Tue, Aug 18, 2020 at 06:37:39PM +0900, Cho KyongHo wrote:
> > On Tue, Aug 18, 2020 at 09:28:53AM +0100, Will Deacon wrote:
> > > On Tue, Aug 18, 2020 at 04:43:10PM +0900, Cho KyongHo wrote:
> > > > Cache maintenance operations in the most of CPU architectures needs
> > > > memory barrier after the cache maintenance for the DMAs to view the
> > > > region of the memory correctly. The problem is that memory barrier is
> > > > very expensive and dma_[un]map_sg() and dma_sync_sg_for_{device|cpu}()
> > > > involves the memory barrier per every single cache sg entry. In some
> > > > CPU micro-architecture, a single memory barrier consumes more time than
> > > > cache clean on 4KiB. It becomes more serious if the number of CPU cores
> > > > are larger.
> > > 
> > > Have you got higher-level performance data for this change? It's more 
> > > likely
> > > that the DSB is what actually forces the prior cache maintenance to
> > > complete,
> > 
> > This patch does not skip necessary DSB after cache maintenance. It just
> > remove repeated dsb per every single sg entry and call dsb just once
> > after cache maintenance on all sg entries is completed.
> 
> Yes, I realise that, but what I'm saying is that a big part of your
> justification for this change is:
> 
>   | The problem is that memory barrier is very expensive and dma_[un]map_sg()
>   | and dma_sync_sg_for_{device|cpu}() involves the memory barrier per every
>   | single cache sg entry. In some CPU micro-architecture, a single memory
>   | barrier consumes more time than cache clean on 4KiB.
> 
> and my point is that the DSB is likely completing the cache maintenance,
> so as cache maintenance instructions retire faster in the micro-architecture,
> the DSB becomes absolutely slower. In other words, it doesn't make much
> sense to me to compare the cost of the DSB with the cost of the cache
> maintenance; what matters more is the code of the high-level unmap()
> operation for the sglist.
> 
I now understand your point. But I still believe that repeated DSB in
the middle of cache maintenance wastes redundant CPU cycles. Avoiding
that redundancy causes extra complexity to implmentation of dma API. But
I think it is valuable.

> > > so it's important to look at the bigger picture, not just the
> > > apparent relative cost of these instructions.
> > > 
> > If you mean bigger picture is the performance impact of this patch to a
> > complete user scenario, we are evaluating it in some latency sensitve
> > scenario. But I wonder if a performance gain in a platform/SoC specific
> > scenario is also persuasive.
> 
> Latency is fine too, but phrasing the numbers (and we really need those)
> in terms of things like "The interrupt response time for this in-tree
> driver is improved by xxx ns (yy %) after this change" or "Throughput
> for this in-tree driver goes from xxx mb/s to yyy mb/s" would be really
> helpful.
> 

Unfortunately, we have no in-tree driver to show the performance.
Instead, we just evaluated the speed of dma_sync_sg_for_device() to see
the improvements of this patch.
For example, Cortex-A55 in our 2-cluster, big-mid-little system gains 28%
(130.9 usec. -> 94.5 usec.) during dma_sync_sg_for_device(sg, nents,
DMA_TO_DEVICE) is running with nents = 256 and length of each sg entrh is 4KiB.
Let me describe the detailed performance results in the next patch
series which will include some fixes to errata in commit messages.

> > > Also, it's a miracle that non-coherent DMA even works,
> > 
> > I am sorry, Will. I don't understand this. Can you let me know what do
> > you mena with the above sentence?
> 
> Non-coherent DMA sucks for software.

I agree. But due to the H/W cost, proposals about coherent DMA are
always challenging.

> For the most part, Linux does a nice
> job of hiding this from device drivers, and I think _that_ is the primary
> concern, rather than performance. If performance is a problem, then the
> solution is cache coherence or a shared non-cacheable buffer (rather than
> the streaming API).
We are also trying to use non-cacheable buffers for the non-coherent
DMAs. But the problem with the non-cacheable buffer is CPU access speed.
> 
> > > so I'm not sure
> > > that we should be complicating the implementation like this to try to
> > > make it "fast".
> > > 
> > I agree that this patch makes the implementation of dma API a bit more
> > but I don't think this does not impact its complication seriously.
> 
> It's death by a thousand cuts; this patch further fragments the architecture
> backends and leads to arm64-specific behaviour which consequently won't get
> well tested by anybody else. Now, it might be worth it, but there's not
> enough information here to make that call.
> Will
> 
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Re: [PATCH 1/2] dma-mapping: introduce relaxed version of dma sync

2020-08-18 Thread Cho KyongHo
On Tue, Aug 18, 2020 at 09:37:20AM +0100, Christoph Hellwig wrote:
> On Tue, Aug 18, 2020 at 09:28:53AM +0100, Will Deacon wrote:
> > On Tue, Aug 18, 2020 at 04:43:10PM +0900, Cho KyongHo wrote:
> > > Cache maintenance operations in the most of CPU architectures needs
> > > memory barrier after the cache maintenance for the DMAs to view the
> > > region of the memory correctly. The problem is that memory barrier is
> > > very expensive and dma_[un]map_sg() and dma_sync_sg_for_{device|cpu}()
> > > involves the memory barrier per every single cache sg entry. In some
> > > CPU micro-architecture, a single memory barrier consumes more time than
> > > cache clean on 4KiB. It becomes more serious if the number of CPU cores
> > > are larger.
> > 
> > Have you got higher-level performance data for this change? It's more likely
> > that the DSB is what actually forces the prior cache maintenance to
> > complete, so it's important to look at the bigger picture, not just the
> > apparent relative cost of these instructions.
> > 
> > Also, it's a miracle that non-coherent DMA even works, so I'm not sure
> > that we should be complicating the implementation like this to try to
> > make it "fast".
> 
> And without not just an important in-tree user but one that actually
> matters and can show how this is correct the whole proposal is complete
> nonstarter.
> 
The patch introduces new kernel configurations
ARCH_HAS_SYNC_DMA_FOR_CPU_RELAXED and ARCH_HAS_SYNC_DMA_FOR_CPU_RELAXED
not to affect the rest of the system. I also confirmed that the patch
does not break some other architectures including arm and x86 which do
not define the new kernel configurations.

Would you let me know some other things to confirm this patch is
correct?

Thank you.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Re: [PATCH 1/2] dma-mapping: introduce relaxed version of dma sync

2020-08-18 Thread Cho KyongHo
On Tue, Aug 18, 2020 at 09:28:53AM +0100, Will Deacon wrote:
> On Tue, Aug 18, 2020 at 04:43:10PM +0900, Cho KyongHo wrote:
> > Cache maintenance operations in the most of CPU architectures needs
> > memory barrier after the cache maintenance for the DMAs to view the
> > region of the memory correctly. The problem is that memory barrier is
> > very expensive and dma_[un]map_sg() and dma_sync_sg_for_{device|cpu}()
> > involves the memory barrier per every single cache sg entry. In some
> > CPU micro-architecture, a single memory barrier consumes more time than
> > cache clean on 4KiB. It becomes more serious if the number of CPU cores
> > are larger.
> 
> Have you got higher-level performance data for this change? It's more likely
> that the DSB is what actually forces the prior cache maintenance to
> complete,

This patch does not skip necessary DSB after cache maintenance. It just
remove repeated dsb per every single sg entry and call dsb just once
after cache maintenance on all sg entries is completed.

> so it's important to look at the bigger picture, not just the
> apparent relative cost of these instructions.
> 
If you mean bigger picture is the performance impact of this patch to a
complete user scenario, we are evaluating it in some latency sensitve
scenario. But I wonder if a performance gain in a platform/SoC specific
scenario is also persuasive.

> Also, it's a miracle that non-coherent DMA even works,

I am sorry, Will. I don't understand this. Can you let me know what do
you mena with the above sentence?

> so I'm not sure
> that we should be complicating the implementation like this to try to
> make it "fast".
> 
I agree that this patch makes the implementation of dma API a bit more
but I don't think this does not impact its complication seriously.

> Will
> 

Thank you.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

[PATCH 1/2] dma-mapping: introduce relaxed version of dma sync

2020-08-18 Thread Cho KyongHo
Cache maintenance operations in the most of CPU architectures needs
memory barrier after the cache maintenance for the DMAs to view the
region of the memory correctly. The problem is that memory barrier is
very expensive and dma_[un]map_sg() and dma_sync_sg_for_{device|cpu}()
involves the memory barrier per every single cache sg entry. In some
CPU micro-architecture, a single memory barrier consumes more time than
cache clean on 4KiB. It becomes more serious if the number of CPU cores
are larger.
This patch introduces arch_sync_dma_for_device_relaxed() and
arch_sync_dma_for_cpu_relaxed() which do not involve memory barrier.
So the users called those functions require explicitly calling
arch_sync_barrier_for_device() and arch_sync_barrier_for_cpu(),
respectively to confirm the view of memory is consistent between the
CPUs and DMAs.

Signed-off-by: Cho KyongHo 
---
 drivers/iommu/dma-iommu.c   |  6 +++--
 include/linux/dma-direct.h  | 29 +-
 include/linux/dma-noncoherent.h | 54 +
 kernel/dma/Kconfig  |  8 ++
 kernel/dma/direct.c | 25 +++
 5 files changed, 109 insertions(+), 13 deletions(-)

diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 5141d49..4f9c9cb 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -705,7 +705,8 @@ static void iommu_dma_sync_sg_for_cpu(struct device *dev,
return;
 
for_each_sg(sgl, sg, nelems, i)
-   arch_sync_dma_for_cpu(sg_phys(sg), sg->length, dir);
+   arch_sync_dma_for_cpu_relaxed(sg_phys(sg), sg->length, dir);
+   arch_sync_barrier_for_cpu(dir);
 }
 
 static void iommu_dma_sync_sg_for_device(struct device *dev,
@@ -719,7 +720,8 @@ static void iommu_dma_sync_sg_for_device(struct device *dev,
return;
 
for_each_sg(sgl, sg, nelems, i)
-   arch_sync_dma_for_device(sg_phys(sg), sg->length, dir);
+   arch_sync_dma_for_device_relaxed(sg_phys(sg), sg->length, dir);
+   arch_sync_barrier_for_device(dir);
 }
 
 static dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page,
diff --git a/include/linux/dma-direct.h b/include/linux/dma-direct.h
index 6e87225..f5b1fee 100644
--- a/include/linux/dma-direct.h
+++ b/include/linux/dma-direct.h
@@ -152,7 +152,7 @@ static inline void dma_direct_sync_single_for_cpu(struct 
device *dev,
swiotlb_tbl_sync_single(dev, paddr, size, dir, SYNC_FOR_CPU);
 }
 
-static inline dma_addr_t dma_direct_map_page(struct device *dev,
+static inline dma_addr_t __dma_direct_map_page(struct device *dev,
struct page *page, unsigned long offset, size_t size,
enum dma_data_direction dir, unsigned long attrs)
 {
@@ -172,20 +172,37 @@ static inline dma_addr_t dma_direct_map_page(struct 
device *dev,
return DMA_MAPPING_ERROR;
}
 
-   if (!dev_is_dma_coherent(dev) && !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
-   arch_sync_dma_for_device(phys, size, dir);
return dma_addr;
 }
 
-static inline void dma_direct_unmap_page(struct device *dev, dma_addr_t addr,
+static inline dma_addr_t dma_direct_map_page(struct device *dev,
+   struct page *page, unsigned long offset, size_t size,
+   enum dma_data_direction dir, unsigned long attrs)
+{
+   dma_addr_t dma_addr = __dma_direct_map_page(dev, page, offset, size, 
dir, attrs);
+
+   if (dma_addr != DMA_MAPPING_ERROR && !dev_is_dma_coherent(dev) &&
+   !(attrs & DMA_ATTR_SKIP_CPU_SYNC))
+   arch_sync_dma_for_device(page_to_phys(page) + offset, size, 
dir);
+
+   return dma_addr;
+}
+
+static inline void __dma_direct_unmap_page(struct device *dev, dma_addr_t addr,
size_t size, enum dma_data_direction dir, unsigned long attrs)
 {
phys_addr_t phys = dma_to_phys(dev, addr);
 
+   if (unlikely(is_swiotlb_buffer(phys)))
+   swiotlb_tbl_unmap_single(dev, phys, size, size, dir, attrs);
+}
+
+static inline void dma_direct_unmap_page(struct device *dev, dma_addr_t addr,
+   size_t size, enum dma_data_direction dir, unsigned long attrs)
+{
if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
dma_direct_sync_single_for_cpu(dev, addr, size, dir);
 
-   if (unlikely(is_swiotlb_buffer(phys)))
-   swiotlb_tbl_unmap_single(dev, phys, size, size, dir, attrs);
+   __dma_direct_unmap_page(dev, addr, size, dir, attrs);
 }
 #endif /* _LINUX_DMA_DIRECT_H */
diff --git a/include/linux/dma-noncoherent.h b/include/linux/dma-noncoherent.h
index ca09a4e..0a31e6c 100644
--- a/include/linux/dma-noncoherent.h
+++ b/include/linux/dma-noncoherent.h
@@ -73,23 +73,77 @@ static inline void arch_dma_cache_sync(struct device *dev, 
void *vaddr,
 #endif /* CONFIG_DMA_NONCOHERENT_CACHE_SYNC */
 
 #i

[PATCH 2/2] arm64: dma-mapping: add relaxed DMA sync

2020-08-18 Thread Cho KyongHo
__dma_[un]map_area() is the implementation of cache maintenance
operations for DMA in arm64. 'dsb sy' in the subroutine guarantees the
view of given memory area is consistent to all memory observers. So,
it is required.
However, dma_sync_sg_for_{device|cpu}() and dma_[un]map_sg() calls
__dma_[un]map_area() nents number of times and 'dsb sy' instruction is
executed the same number of times. We have observed that 'dsb sy'
consumes more time than cleaning or invalidating 4KiB area.
arch_sync_dma_for_{device|cpu}_relaxed() and
arch_sync_barrier_for_{device|cpu}() are introduced since commit
6a9356234 ("dma-mapping: introduce relaxed version of dma sync") to
reduce redundant memory barriers in sg versions of DMA sync API.
Implementing relaxed version of DMA sync API will dramatically increase
the performance of dma_sync_sg_for_{device|cpu}().

Signed-off-by: Cho KyongHo 
---
 arch/arm64/Kconfig |  4 ++--
 arch/arm64/include/asm/assembler.h | 33 -
 arch/arm64/include/asm/barrier.h   | 13 +
 arch/arm64/mm/cache.S  | 34 +++---
 arch/arm64/mm/dma-mapping.c|  4 ++--
 include/linux/dma-noncoherent.h|  1 +
 6 files changed, 61 insertions(+), 28 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 6d23283..4fc7ef4 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -31,8 +31,8 @@ config ARM64
select ARCH_HAS_SET_MEMORY
select ARCH_HAS_STRICT_KERNEL_RWX
select ARCH_HAS_STRICT_MODULE_RWX
-   select ARCH_HAS_SYNC_DMA_FOR_DEVICE
-   select ARCH_HAS_SYNC_DMA_FOR_CPU
+   select ARCH_HAS_SYNC_DMA_FOR_DEVICE_RELAXED
+   select ARCH_HAS_SYNC_DMA_FOR_CPU_RELAXED
select ARCH_HAS_SYSCALL_WRAPPER
select ARCH_HAS_TEARDOWN_DMA_OPS if IOMMU_SUPPORT
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
diff --git a/arch/arm64/include/asm/assembler.h 
b/arch/arm64/include/asm/assembler.h
index 54d1811..1f87d98 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -345,6 +345,33 @@ alternative_endif
.endm
 
 /*
+ * Macro to perform a data cache invalidation for the interval
+ * [kaddr, kaddr + size)
+ *
+ * kaddr:  starting virtual address of the region
+ * size:   size of the region
+ * Corrupts:   kaddr, size, tmp1, tmp2
+ */
+   .macro __dcache_inv_by_line kaddr, size, tmp1, tmp2
+   add \size, \size, \kaddr
+   dcache_line_size \tmp1, \tmp2
+   sub \tmp2, \tmp1, #1
+   tst \size, \tmp2// end cache line aligned?
+   bic \size, \size, \tmp2
+   b.eq9997f
+   dc  civac, \size// clean & invalidate D / U line
+9997:  tst \kaddr, \tmp2   // start cache line aligned?
+   bic \kaddr, \kaddr, \tmp2
+   b.eq9998f
+   dc  civac, \kaddr   // clean & invalidate D / U line
+   b   f
+9998:  dc  ivac, \kaddr// invalidate D / U line
+:  add \kaddr, \kaddr, \tmp1
+   cmp \kaddr, \size
+   b.lo9998b
+   .endm
+
+/*
  * Macro to perform a data cache maintenance for the interval
  * [kaddr, kaddr + size)
  *
@@ -362,7 +389,7 @@ alternative_else
 alternative_endif
.endm
 
-   .macro dcache_by_line_op op, domain, kaddr, size, tmp1, tmp2
+   .macro __dcache_by_line_op op, kaddr, size, tmp1, tmp2
dcache_line_size \tmp1, \tmp2
add \size, \kaddr, \size
sub \tmp2, \tmp1, #1
@@ -388,6 +415,10 @@ alternative_endif
add \kaddr, \kaddr, \tmp1
cmp \kaddr, \size
b.lo9998b
+   .endm
+
+   .macro dcache_by_line_op op, domain, kaddr, size, tmp1, tmp2
+   __dcache_by_line_op \op, \kaddr, \size, \tmp1, \tmp2
dsb \domain
.endm
 
diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h
index fb4c275..96bbbf6 100644
--- a/arch/arm64/include/asm/barrier.h
+++ b/arch/arm64/include/asm/barrier.h
@@ -167,6 +167,19 @@ do {   
\
 
 #include 
 
+#include 
+
+static inline void arch_sync_barrier_for_device(enum dma_data_direction dir)
+{
+   dsb(sy);
+}
+
+static inline void arch_sync_barrier_for_cpu(enum dma_data_direction dir)
+{
+   if (dir == DMA_FROM_DEVICE)
+   dsb(sy);
+}
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __ASM_BARRIER_H */
diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
index 2d881f3..7180256 100644
--- a/arch/arm64/mm/cache.S
+++ b/arch/arm64/mm/cache.S
@@ -138,34 +138,20 @@ SYM_FUNC_END(__clean_dcache_area_pou)
  * - kaddr   - kernel address
  * - size- size in question
  */
-SYM_FUNC_START_LOCAL(__dma_inv_area)
 SYM_FUNC_START_PI(__inval_dcache_area)
-   /* FALLTHROUGH */
+   __dcache_inv_by_line x0, x1, x2, x3
+   dsb 

Re: [PATCH v6 05/25] iommu: exynos: don't read version register on every tlb operation

2015-05-10 Thread Cho KyongHo
On Mon, 04 May 2015 10:16:00 +0200 Marek Szyprowski m.szyprow...@samsung.com 
wrote:

 This patch removes reading of REG_MMU_VERSION register on every tlb
 operation and caches SYSMMU version in driver's internal data.
 
 Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com
 ---
  drivers/iommu/exynos-iommu.c | 13 +
  1 file changed, 5 insertions(+), 8 deletions(-)
 
 diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
 index 3e898504a7c4..3861485f0689 100644
 --- a/drivers/iommu/exynos-iommu.c
 +++ b/drivers/iommu/exynos-iommu.c
 @@ -213,6 +213,7 @@ struct sysmmu_drvdata {
   spinlock_t lock;
   struct iommu_domain *domain;
   phys_addr_t pgtable;
 + int version;

Why don't you define its type as unsigned int or u32?

Regards,

KyongHo
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v6 06/25] iommu: exynos: remove unused functions

2015-05-10 Thread Cho KyongHo
On Mon, 04 May 2015 10:16:01 +0200 Marek Szyprowski m.szyprow...@samsung.com 
wrote:

 This patch removes two unneeded functions, which are not a part of
 generic IOMMU API and were never used by any other driver.
 
 Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com
 ---
  drivers/iommu/exynos-iommu.c | 31 ---
  1 file changed, 31 deletions(-)
 
 diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
 index 3861485f0689..98aa7e9c2507 100644
 --- a/drivers/iommu/exynos-iommu.c
 +++ b/drivers/iommu/exynos-iommu.c
 @@ -496,13 +496,6 @@ static int __exynos_sysmmu_enable(struct device *dev, 
 phys_addr_t pgtable,
   return ret;
  }
  
 -int exynos_sysmmu_enable(struct device *dev, phys_addr_t pgtable)
 -{
 - BUG_ON(!memblock_is_memory(pgtable));
 -
 - return __exynos_sysmmu_enable(dev, pgtable, NULL);
 -}
 -
  static bool exynos_sysmmu_disable(struct device *dev)
  {
   unsigned long flags;
 @@ -594,30 +587,6 @@ static void sysmmu_tlb_invalidate_entry(struct device 
 *dev, sysmmu_iova_t iova,
   spin_unlock_irqrestore(data-lock, flags);
  }
  
 -void exynos_sysmmu_tlb_invalidate(struct device *dev)
 -{
 - struct exynos_iommu_owner *owner = dev-archdata.iommu;
 - unsigned long flags;
 - struct sysmmu_drvdata *data;
 -
 - data = dev_get_drvdata(owner-sysmmu);
 -
 - spin_lock_irqsave(data-lock, flags);
 - if (is_sysmmu_active(data)) {
 - if (!IS_ERR(data-clk_master))
 - clk_enable(data-clk_master);
 - if (sysmmu_block(data-sfrbase)) {
 - __sysmmu_tlb_invalidate(data-sfrbase);
 - sysmmu_unblock(data-sfrbase);
 - }
 - if (!IS_ERR(data-clk_master))
 - clk_disable(data-clk_master);
 - } else {
 - dev_dbg(dev, disabled. Skipping TLB invalidation\n);
 - }
 - spin_unlock_irqrestore(data-lock, flags);
 -}
 -
  static int __init exynos_sysmmu_probe(struct platform_device *pdev)
  {
   int irq, ret;


Actually they are for some drivers that are not upstreamed.
But I agree removing them.

Regards,

KyongHo
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v6 08/25] iommu: exynos: refactor function parameters to simplify code

2015-05-10 Thread Cho KyongHo
On Mon, 04 May 2015 10:16:03 +0200 Marek Szyprowski m.szyprow...@samsung.com 
wrote:

 This patch simplifies the code by:
 - refactoring function parameters from struct device pointer to direct
   pointer to struct sysmmu drvdata
 - moving list_head enteries from struct exynos_iommu_owner directly to
   struct sysmmu_drvdata
 
 Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com
 ---
  drivers/iommu/exynos-iommu.c | 93 
 ++--
  1 file changed, 46 insertions(+), 47 deletions(-)
 
 diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
 index c307c400613c..0c23b69022cd 100644
 --- a/drivers/iommu/exynos-iommu.c
 +++ b/drivers/iommu/exynos-iommu.c
 @@ -186,8 +186,6 @@ static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = {
  
  /* attached to dev.archdata.iommu of the master device */
  struct exynos_iommu_owner {
 - struct list_head client; /* entry of exynos_iommu_domain.clients */
 - struct device *dev;
   struct device *sysmmu;
  };
  
 @@ -209,6 +207,7 @@ struct sysmmu_drvdata {
   int activations;
   spinlock_t lock;
   struct iommu_domain *domain;
 + struct list_head domain_node;
   phys_addr_t pgtable;
   int version;
  };
 @@ -514,12 +513,10 @@ static void __sysmmu_tlb_invalidate_flpdcache(struct 
 sysmmu_drvdata *data,
   __raw_writel(iova | 0x1, data-sfrbase + REG_MMU_FLUSH_ENTRY);
  }
  
 -static void sysmmu_tlb_invalidate_flpdcache(struct device *dev,
 +static void sysmmu_tlb_invalidate_flpdcache(struct sysmmu_drvdata *data,
   sysmmu_iova_t iova)
  {
   unsigned long flags;
 - struct exynos_iommu_owner *owner = dev-archdata.iommu;
 - struct sysmmu_drvdata *data = dev_get_drvdata(owner-sysmmu);
  
   if (!IS_ERR(data-clk_master))
   clk_enable(data-clk_master);
 @@ -533,14 +530,10 @@ static void sysmmu_tlb_invalidate_flpdcache(struct 
 device *dev,
   clk_disable(data-clk_master);
  }
  
 -static void sysmmu_tlb_invalidate_entry(struct device *dev, sysmmu_iova_t 
 iova,
 - size_t size)
 +static void sysmmu_tlb_invalidate_entry(struct sysmmu_drvdata *data,
 + sysmmu_iova_t iova, size_t size)
  {
 - struct exynos_iommu_owner *owner = dev-archdata.iommu;
   unsigned long flags;
 - struct sysmmu_drvdata *data;
 -
 - data = dev_get_drvdata(owner-sysmmu);
  
   spin_lock_irqsave(data-lock, flags);
   if (is_sysmmu_active(data)) {
 @@ -570,8 +563,8 @@ static void sysmmu_tlb_invalidate_entry(struct device 
 *dev, sysmmu_iova_t iova,
   if (!IS_ERR(data-clk_master))
   clk_disable(data-clk_master);
   } else {
 - dev_dbg(dev, disabled. Skipping TLB invalidation @ %#x\n,
 - iova);
 + dev_dbg(data-master,
 + disabled. Skipping TLB invalidation @ %#x\n, iova);
   }
   spin_unlock_irqrestore(data-lock, flags);
  }
 @@ -711,7 +704,7 @@ err_pgtable:
  static void exynos_iommu_domain_free(struct iommu_domain *domain)
  {
   struct exynos_iommu_domain *priv = to_exynos_domain(domain);
 - struct exynos_iommu_owner *owner;
 + struct sysmmu_drvdata *data;
   unsigned long flags;
   int i;
  
 @@ -719,14 +712,12 @@ static void exynos_iommu_domain_free(struct 
 iommu_domain *domain)
  
   spin_lock_irqsave(priv-lock, flags);
  
 - list_for_each_entry(owner, priv-clients, client) {
 - while (!exynos_sysmmu_disable(owner-dev))
 - ; /* until System MMU is actually disabled */
 + list_for_each_entry(data, priv-clients, domain_node) {

Use list_for_each_entry_safe() or you will get panic.

 + if (__sysmmu_disable(data))
 + data-master = NULL;
 + list_del_init(data-domain_node);
   }
  
 - while (!list_empty(priv-clients))
 - list_del_init(priv-clients.next);
 -
   spin_unlock_irqrestore(priv-lock, flags);
  
   for (i = 0; i  NUM_LV1ENTRIES; i++)
 @@ -744,20 +735,26 @@ static int exynos_iommu_attach_device(struct 
 iommu_domain *domain,
  {
   struct exynos_iommu_owner *owner = dev-archdata.iommu;
   struct exynos_iommu_domain *priv = to_exynos_domain(domain);
 + struct sysmmu_drvdata *data;
   phys_addr_t pagetable = virt_to_phys(priv-pgtable);
   unsigned long flags;
 - int ret;
 + int ret = -ENODEV;
  
 - spin_lock_irqsave(priv-lock, flags);
 + if (!has_sysmmu(dev))
 + return -ENODEV;
  
 - ret = __exynos_sysmmu_enable(dev, pagetable, domain);
 - if (ret == 0) {
 - list_add_tail(owner-client, priv-clients);
 - owner-domain = domain;
 + data = dev_get_drvdata(owner-sysmmu);
 + if (data) {

Is there a case that a probed System MMU without driver data?

 + ret = __sysmmu_enable(data, pagetable, domain);
 

Re: [PATCH v6 11/25] iommu: exynos: add support for binding more than one sysmmu to master device

2015-05-10 Thread Cho KyongHo
On Mon, 04 May 2015 10:16:06 +0200 Marek Szyprowski m.szyprow...@samsung.com 
wrote:

 This patch adds support for assigning more than one SYSMMU controller to
 the master device. This has been achieved simply by chaning the struct
 device pointer in struct exynos_iommu_owner into the list of struct
 sysmmu_drvdata of all controllers assigned to the given master device.
 
 Signed-off-by: Marek Szyprowski m.szyprow...@samsung.com
 ---
  drivers/iommu/exynos-iommu.c | 11 +--
  1 file changed, 5 insertions(+), 6 deletions(-)
 
 diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
 index f2eceb6605c5..598660c87410 100644
 --- a/drivers/iommu/exynos-iommu.c
 +++ b/drivers/iommu/exynos-iommu.c
 @@ -186,7 +186,7 @@ static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = {
  
  /* attached to dev.archdata.iommu of the master device */
  struct exynos_iommu_owner {
 - struct device *sysmmu;
 + struct list_head clients;

'clients' is the list of System MMUs that are assigned to the same iommu
domain. I don't think clients is not a good list name for exynos_iommu_owner
even though the elements are the same because they are used in different
contexts.

-- 
samsung.com pullip@samsung.com
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH] devicetree: Add generic IOMMU device tree bindings

2014-05-17 Thread Cho KyongHo
On Fri, 16 May 2014 14:23:18 +0200, Thierry Reding wrote:
 From: Thierry Reding tred...@nvidia.com
 
 This commit introduces a generic device tree binding for IOMMU devices.
 Only a very minimal subset is described here, but it is enough to cover
 the requirements of both the Exynos System MMU and Tegra SMMU as
 discussed here:
 
 https://lkml.org/lkml/2014/4/27/346
 
 More advanced functionality such as the dma-ranges property can easily
 be added in a backwards-compatible way. In the absence of a dma-ranges
 property it should be safe to default to the whole address space.
 
 Signed-off-by: Thierry Reding tred...@nvidia.com
 ---
  Documentation/devicetree/bindings/iommu/iommu.txt | 109 
 ++
  1 file changed, 109 insertions(+)
  create mode 100644 Documentation/devicetree/bindings/iommu/iommu.txt
 
 diff --git a/Documentation/devicetree/bindings/iommu/iommu.txt 
 b/Documentation/devicetree/bindings/iommu/iommu.txt
 new file mode 100644
 index ..2d67b52b656e
 --- /dev/null
 +++ b/Documentation/devicetree/bindings/iommu/iommu.txt
 @@ -0,0 +1,109 @@
 +This document describes the generic device tree binding for IOMMUs and their
 +master(s).
 +
 +
 +IOMMU device node:
 +==
 +
 +An IOMMU can provide the following services:
 +
 +* Remap address space to allow devices to access physical memory ranges that
 +  they otherwise wouldn't be capable of accessing.
 +
 +  Example: 32-bit DMA to 64-bit physical addresses
 +
 +* Implement scatter-gather at page level granularity so that the device does
 +  not have to.
 +
 +* Provide system protection against rogue DMA by forcing all accesses to go
 +  through the IOMMU and faulting when encountering accesses to unmapped
 +  address regions.
 +
 +* Provide address space isolation between multiple contexts.
 +
 +  Example: Virtualization
 +
 +Device nodes compatible with this binding represent hardware with some of the
 +above capabilities.
 +
 +IOMMUs can be single-master or multiple-master. Single-master IOMMU devices
 +typically have a fixed association to the master device, whereas multiple-
 +master IOMMU devices can translate accesses from more than one master.
 +
 +Required properties:
 +
 +- #iommu-cells: The number of cells in an IOMMU specifier. The meaning of the
 +  cells is defined by the binding for the IOMMU device.
 +
 +  Typical values include:
 +  * 0: Single-master IOMMU devices are often not configurable, therefore the
 +specifying doesn't need to encode any information and can be empty.
 +
 +  * 1: Multiple-master IOMMU devices need to know for which master they 
 should
 +enable translation. Typically the single cell in the specifier 
 corresponds
 +to the master device's ID.
 +
 +
 +IOMMU master node:
 +==
 +
 +Devices that access memory through an IOMMU are called masters. A device can
 +have multiple master interfaces (to one or more IOMMU devices).
 +
 +Required properties:
 +
 +- iommus: A list of phandle and IOMMU specifier pairs that describe the IOMMU
 +  master interfaces of the device. One entry in the list describes one master
 +  interface of the device.
 +
 +Optional properties:
 +
 +- iommu-names: A list of names identifying each entry in the iommus property.
 +
 +
 +Examples:
 +=
 +
 +Single-master IOMMU:
 +
 +
 + iommu {
 + #iommu-cells = 0;
 + };
 +
 + master {
 + iommu = /iommu;
 + };
 +

Great work, Thierry.

One simple comment.

This should be also applicable to multi-master IOMMUs that the masters
of an IOMMU is not configurable with ID or something.
I think the title needs to be changed to cover such IOMMUs which always
translate master's transactions and unable to change the configuration
of the relationship between the masters and IOMMUs by S/W.

Regards,

KyongHo

 +Multi-master IOMMU:
 +---
 +
 + iommu {
 + /* the specifier represents the ID of the master */
 + #iommu-cells = 1;
 + };
 +
 + master {
 + /* device has master ID 42 in the IOMMU */
 + iommu = /iommu 42;
 + };
 +
 +Multi-master device:
 +
 +
 + /* single-master IOMMU */
 + iommu@1 {
 + #iommu-cells = 0;
 + };
 +
 + /* multi-master IOMMU */
 + iommu@2 {
 + /* the specifier represents the ID of the master */
 + #iommu-cells = 1;
 + };
 +
 + /* device with two master interfaces */
 + master {
 + iommus = /iommu@1,/* master of the single-master IOMMU */
 +  /iommu@2 42; /* ID 42 in multi-master IOMMU */
 + };
 -- 
 1.9.2
 
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v12 11/31] documentation: iommu: add binding document of Exynos System MMU

2014-05-15 Thread Cho KyongHo
On Thu, 15 May 2014 22:37:31 +0200, Thierry Reding wrote:
 On Mon, Apr 28, 2014 at 02:05:30PM +0200, Arnd Bergmann wrote:
 [...]
  let me clarify by example:
  
  iommu@1 {
  compatible = some,simple-iommu;
  reg = 1;
  #iommu-cells = 0; /* supports only one master */
  };
  
  iommu@2 {
  compatible = some,other-iommu;
  reg = 3;
  #iommu-cells = 1; /* contains master ID */
  };
  
  iommu@3 {
  compatible = some,windowed-iommu;
  reg = 2;
  #iommu-cells = 2; /* contains dma-window */
  };
  
  device@4 {
  compatible = some,ethernet;
  iommus = /iommu@1;
  };
  
  device@5 {
  compatible = some,dmaengine;
  iommus = /iommu@2 0x4000 0x100,
   /iommu@3 0x101;
  };
  
  The device at address 4 has a one-one relationship with iommu@1, so there
  is no need for any data. device@5 has two master ports. One is connected to
  an IOMMU that has a per-device aperture, device@5 can only issue transfers
  to the 256MB area at 0x4000, and the IOMMU will have to put entries for
  this device into that address. The second master port is connected to
  iommu@3, which uses a master ID that gets passed along with each transfer,
  so that needs to be put into the IOTLBs.
 
 iommu@3 and the second port of device@5 seem to match what we need for
 Tegra (and as I understand also Exynos). Can we settle on this for now
 so that Hiroshi and Cho can go update their drivers for this binding?
 

Currently, Exynos IOMMU is the case of iommu@1.

But in the near future, it will support multiple masters with a single context
that means all masters that shares a single System MMU also views the same
address space.

For some cases, we may need iommu@3 that supports dma-window.

So, I have no other opinion.

By the way, iommu framework should allow to process the parameters
to 'iommus' property in the master nodes by iommu driver implementations
because it is depended on implementations.

  A variation would be to not use #iommu-cells at all, but provide a
  #address-cells / #size-cells pair in the IOMMU, and have a translation
  as we do for dma-ranges. This is probably most flexible.
 
 The remainder of this discussion seems to indicate that #iommu-cells and
 dma-ranges don't have to be mutually exclusive. For some IOMMUs it might
 make sense to use both.
 
 In fact perhaps we should require every IOMMU user to also specify a
 dma-ranges property, even if for some cases the range would be simply
 the complete physical address space. Perhaps in analogy to the ranges
 property an empty dma-ranges property could be taken to mean all of the
 physical address space.
 
 I'm aware that this doesn't cover any of the more exotic cases out
 there, but the fact is that we have real devices out there that ship
 with some variations of these simple IOMMUs and I don't think we're
 doing ourselves a favour by blocking support for these to be added on
 the hope of merging the perfect solution that covers all use-cases.
 Patches for Tegra have already been around for close to half a year.
 
 Thierry
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v12 18/31] iommu/exynos: allow having multiple System MMUs for a master H/W

2014-05-09 Thread Cho KyongHo
On Tue, 06 May 2014 20:05:14 +0200, Tomasz Figa wrote:
 On 27.04.2014 09:37, Shaik Ameer Basha wrote:
  From: Cho KyongHo pullip@samsung.com
 
  Some master device descriptor like fimc-is which is an abstraction
  of very complex H/W may have multiple System MMUs. For those devices,
  the design of the link between System MMU and its master H/W is needed
  to be reconsidered.
 
  A link structure, sysmmu_list_data is introduced that provides a link
  to master H/W and that has a pointer to the device descriptor of a
  System MMU. Given a device descriptor of a master H/W, it is possible
  to traverse all System MMUs that must be controlled along with the
  master H/W.
 
  Signed-off-by: Cho KyongHo pullip@samsung.com
  ---
drivers/iommu/exynos-iommu.c |  545 
  ++
1 file changed, 335 insertions(+), 210 deletions(-)
 
  diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
  index fefedec3..c2e6365 100755
  --- a/drivers/iommu/exynos-iommu.c
  +++ b/drivers/iommu/exynos-iommu.c
  @@ -117,6 +117,10 @@
#define REG_PB1_EADDR 0x058
 
#define has_sysmmu(dev)   (dev-archdata.iommu != NULL)
  +#define for_each_sysmmu_list(dev, list_data)   
  \
  +   list_for_each_entry(list_data,  \
  +   ((struct exynos_iommu_owner *)dev-archdata.iommu)-mmu_list, \
  +   entry)
 
 Sorry, NAK.
 
 Please don't add this kind of complexity and business logic to low level 
 code. We want the configuration functions to be simple, easy to read, 
 maintain and extend.
 
 The proper way to do it is to let the IOMMUs be grouped together on 
 IOMMU subsystem level, so that each IOMMU consumer driver would see just 
 one IOMMU, but then IOMMU driver callbacks would handle just particular 
 instances of the IOMMU IP blocks, without any loops, lists and other 
 crazy code...
 

It is done in IOMMU driver internally.
IOMMU consumer driver(IOMMU client device driver?) sees IOMMU domain
but IOMMU itself. How to handle IOMMUs of the client device is just
in charge of IOMMU driver according to the hardwired bus topology.

If a master and IOMMU device should be 1:1 relationship as you contend,
the master device driver should be responsible for express the bus
topology in its business logic. I think it is not good as I told earlier.

IOMMU group is different from the grouping System MMUs in Exynos IOMMU driver.
IOMMU group is invented to group several IOMMUs on different bus with different
masters to assign the same IOMMU domain.
It is useful for user level virtualization but for expressing bus topology.
Exynos IOMMU driver just groups System MMUs that have the same master device.
Even though Exynos IOMMU driver implements IOMMU group which is already
implemented by 20/31 patch, such looping is still required.

However, I will consider other elegant way of interation of multiple System 
MMUs.

Regards,

KyongHo
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v12 00/31] iommu/exynos: Fixes and Enhancements of System MMU driver with DT

2014-05-06 Thread Cho KyongHo
On Tue, 06 May 2014 20:08:47 +0200, Tomasz Figa wrote:
 On 06.05.2014 19:59, Joerg Roedel wrote:
  On Wed, Apr 30, 2014 at 04:27:10PM +0530, Shaik Ameer Basha wrote:
  This series is going on for quite a long time and most of the patches here
  doesn't depend on dt bindings. As Exynos IOMMU h/w is introducing new 
  versions
  very frequently, maintaining and reviewing all these patches again and
  again is quite a hard job.
 
  If it is acceptable, I can post one more series with the subset of
  above patches,
  which doesn't depend on dt-bindings. As all the patches which doesn't 
  depend on
  DT bindings are already tested,  I hope merging these subset of patches 
  may help
  in reducing the rework and review effort every time.
 
  Once we finalize the generic DT bindings for the IOMMU devices, the driver
  can be updated with the proposed DT bindings in mind.
 
  Sounds reasonable to me if the patch subset is self-contained. When
  Arnd is OK with that and no one else has objections I can take the
  dt-independend parts.
 
 +1.
 
 I would also suggest dropping patch 18/31, for the reasons I mentioned 
 in my reply to it.
 

Great.

We will prepare the next patch series that are independent upon DT bindings 
soon.

Thank you.

KyongHo
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v12 18/31] iommu/exynos: allow having multiple System MMUs for a master H/W

2014-05-01 Thread Cho KyongHo
On Mon, 28 Apr 2014 16:08:14 +0530, Tushar Behera wrote:
 On 04/27/2014 01:07 PM, Shaik Ameer Basha wrote:
  From: Cho KyongHo pullip@samsung.com
  
  Some master device descriptor like fimc-is which is an abstraction
  of very complex H/W may have multiple System MMUs. For those devices,
  the design of the link between System MMU and its master H/W is needed
  to be reconsidered.
  
  A link structure, sysmmu_list_data is introduced that provides a link
  to master H/W and that has a pointer to the device descriptor of a
  System MMU. Given a device descriptor of a master H/W, it is possible
  to traverse all System MMUs that must be controlled along with the
  master H/W.
  
  Signed-off-by: Cho KyongHo pullip@samsung.com
 
 Since you are posting the patches, you should also add your
 Signed-of-by.

  ---
   drivers/iommu/exynos-iommu.c |  545 
  ++
   1 file changed, 335 insertions(+), 210 deletions(-)
  
  diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
  index fefedec3..c2e6365 100755
  --- a/drivers/iommu/exynos-iommu.c
  +++ b/drivers/iommu/exynos-iommu.c
 
 [ ... ]
 
   static int sysmmu_pm_genpd_save_state(struct device *dev)
  @@ -1215,7 +1349,7 @@ static int sysmmu_pm_genpd_save_state(struct device 
  *dev)
  ret = cb(dev);
   
  if (ret == 0)
  -   sysmmu_save_state(client-sysmmu);
  +   sysmmu_save_state(dev);
   
 
 client is now unused, remove the variable.
 
  return ret;
   }
  @@ -1238,13 +1372,13 @@ static int sysmmu_pm_genpd_restore_state(struct 
  device *dev)
  if (!cb  dev-driver  dev-driver-pm)
  cb = dev-driver-pm-runtime_resume;
   
  -   sysmmu_restore_state(client-sysmmu);
  +   sysmmu_restore_state(dev);
   
  if (cb)
  ret = cb(dev);
   
  if (ret)
  -   sysmmu_save_state(client-sysmmu);
  +   sysmmu_restore_state(dev);
   
 
 client is now unused, remove the variable.
 

Ok.

Thanks.

KyongHo
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v12 30/31] ARM: dts: add System MMU nodes of exynos5250

2014-05-01 Thread Cho KyongHo
On Mon, 28 Apr 2014 16:13:19 -0700, Doug Anderson wrote:
 Vikas,
 
 
 On Sun, Apr 27, 2014 at 10:39 AM, Vikas Sajjan sajjan.li...@gmail.com wrote:
  Hi shaik,
 
  +Doug, Abhilash,
 
  On Sun, Apr 27, 2014 at 1:08 PM, Shaik Ameer Basha
  shaik.am...@samsung.com wrote:
  From: Cho KyongHo pullip@samsung.com
 
  Signed-off-by: Cho KyongHo pullip@samsung.com
  ---
   arch/arm/boot/dts/exynos5250.dtsi |  270 
  -
   1 file changed, 267 insertions(+), 3 deletions(-)
 
  diff --git a/arch/arm/boot/dts/exynos5250.dtsi 
  b/arch/arm/boot/dts/exynos5250.dtsi
  index 3742331..eebd397 100644
  --- a/arch/arm/boot/dts/exynos5250.dtsi
  +++ b/arch/arm/boot/dts/exynos5250.dtsi
  @@ -82,6 +82,16 @@
  reg = 0x10044040 0x20;
  };
 
  +   pd_isp: isp-power-domain@0x10044020 {
  +   compatible = samsung,exynos4210-pd;
  +   reg = 0x10044020 0x20;
  +   };
  +
  +   pd_disp1: disp1-power-domain@0x100440A0 {
  +   compatible = samsung,exynos4210-pd;
  +   reg = 0x100440A0 0x20;
  +   };
  +
 
  As per subject add System MMU nodes of exynos5250, it should only
  add SysMMU node.
  So, I think adding power domain nodes should go in a separate patch.
 
  Adding power domain nodes can break the system, if powering ON/OFF of
  the given power domain is NOT taken care well.
  I can see ISP is one such case. With this series I can see S2R breaks
  [1] on 5250 chromebook with current mainline kernel (same applies for
  arndale and smdk5250, but I have tested on these boards yet)
 
 Thanks for catching that!  Let's make sure not to break suspend/resume.
 
 Given that these power domains are actually used as the domains for
 some of the System MMU nodes I don't totally object to adding them in
 the same patch, but if they're breaking things then I agree that we
 could leave them out and add them in a later patch (once issues are
 sorted out).
 

Thank you, Vikas.

Let me consider adding ISP power doamin after checking
power down sequence of ISP domain.

KyongHo
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v11 20/27] iommu/exynos: allow having multiple System MMUs for a master H/W

2014-04-22 Thread Cho KyongHo
On Tue, 22 Apr 2014 18:53:51 +0530, Shaik Ameer Basha wrote:
 Hi KyongHo Cho,
 
 
 
 On Fri, Mar 14, 2014 at 10:40 AM, Cho KyongHo pullip@samsung.com wrote:
  Some master device descriptor like fimc-is which is an abstraction
  of very complex H/W may have multiple System MMUs. For those devices,
  the design of the link between System MMU and its master H/W is needed
  to be reconsidered.
 
  A link structure, sysmmu_list_data is introduced that provides a link
  to master H/W and that has a pointer to the device descriptor of a
  System MMU. Given a device descriptor of a master H/W, it is possible
  to traverse all System MMUs that must be controlled along with the
  master H/W.
 
  Signed-off-by: Cho KyongHo pullip@samsung.com
  ---
   drivers/iommu/exynos-iommu.c |  534 
  ++
   1 file changed, 333 insertions(+), 201 deletions(-)
 
  diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
  index 84ba29a..7489343 100644
  --- a/drivers/iommu/exynos-iommu.c
  +++ b/drivers/iommu/exynos-iommu.c
  @@ -128,6 +128,10 @@
   #define __master_clk_disable(data) __clk_gate_ctrl(data, clk_master, 
  dis)
 
 
 [snip]
 
  +static int __init __sysmmu_init_master(struct device *dev)
  +{
  +   int ret;
  +   int i = 0;
  +   struct device_node *node;
  +
  +   while ((node = of_parse_phandle(dev-of_node, mmu-masters, i++))) 
  {
  struct platform_device *master = 
  of_find_device_by_node(node);
  +   struct exynos_iommu_owner *owner;
  +   struct sysmmu_list_data *list_data;
 
  if (!master) {
  dev_err(dev, %s: mmu-master '%s' not found\n,
  __func__, node-name);
  -   return -EINVAL;
  +   ret = -EINVAL;
  +   goto err;
  }
 
  -   if (master-dev.archdata.iommu != NULL) {
  -   dev_err(dev, %s: '%s' is master of other MMU\n,
  -   __func__, node-name);
  -   return -EINVAL;
  +   owner = master-dev.archdata.iommu;
  +   if (!owner) {
  +   owner = devm_kzalloc(dev, sizeof(*owner), 
  GFP_KERNEL);
  +   if (!owner) {
  +   dev_err(dev,
  +   %s: Failed to allocate owner structure\n,
  +   __func__);
  +   ret = -ENOMEM;
  +   goto err;
  +   }
  +
  +   INIT_LIST_HEAD(owner-mmu_list);
  +   INIT_LIST_HEAD(owner-client);
  +   owner-dev = master-dev;
  +   spin_lock_init(owner-lock);
  +
  +   master-dev.archdata.iommu = owner;
  }
 
  +   list_data = devm_kzalloc(dev, sizeof(*list_data), 
  GFP_KERNEL);
  +   if (!list_data) {
  +   dev_err(dev,
  +   %s: Failed to allocate sysmmu_list_data\n,
  +   __func__);
  +   ret = -ENOMEM;
  +   goto err;
  +   }
  +
  +   INIT_LIST_HEAD(list_data-entry);
  +   list_data-sysmmu = dev;
  +
  /*
  -* archdata.iommu will be initialized with 
  exynos_iommu_client
  -* in sysmmu_hook_driver_register().
  +* System MMUs are attached in the order of the presence
  +* in device tree
   */
  -   master-dev.archdata.iommu = dev;
  +   list_add_tail(list_data-entry, owner-mmu_list);
  }
 
  -   data-sysmmu = dev;
  -   rwlock_init(data-lock);
  +   return 0;
  +err:
  +   while ((node = of_parse_phandle(dev-of_node, mmu-masters, i++))) 
  {
 
 Don't we need to reinitialize variable 'i' here before using?
 i = 0;
 

Oh. You are right.

Thanks.

 
 
 
  +   struct platform_device *master = 
  of_find_device_by_node(node);
  +   struct exynos_iommu_owner *owner;
  +   struct sysmmu_list_data *list_data;
 
  -   platform_set_drvdata(pdev, data);
  +   if (!master)
  +   continue;
 
  -   pm_runtime_enable(dev);
  -   data-runtime_active = !pm_runtime_enabled(dev);
  +   owner = master-dev.archdata.iommu;
  +   if (!owner)
  +   continue;
 
  -   dev_dbg(dev, Probed and initialized\n);
  -   return 0;
  +   for_each_sysmmu_list(owner-dev, list_data) {
  +   if (list_data-sysmmu == dev) {
  +   list_del(list_data-entry);
  +   kfree(list_data

Re: [PATCH v11 24/27] iommu/exynos: use exynos-iommu specific typedef

2014-03-20 Thread Cho KyongHo
On Tue, 18 Mar 2014 18:33:20 -0700, Grant Grundler wrote:
 On Thu, Mar 13, 2014 at 10:13 PM, Cho KyongHo pullip@samsung.com wrote:
  This commit introduces sysmmu_pte_t for page table entries and
  sysmmu_iova_t vor I/O virtual address that is manipulated by
  exynos-iommu driver. The purpose of the typedef is to remove
  dependencies to the driver code from the change of CPU architecture
  from 32 bit to 64 bit.
 
 hi Cho,
 I noticed this before but understood this code was only compiled for
 ILP-32 programming model. I'm assuming that is going to change in the
 not-to-distant future. Good. :)
 

Thanks.

 
  Signed-off-by: Cho KyongHo pullip@samsung.com
  ---
   drivers/iommu/exynos-iommu.c |  103 
  ++
   1 file changed, 54 insertions(+), 49 deletions(-)
 
  diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
  index e375501..6e716cc 100644
  --- a/drivers/iommu/exynos-iommu.c
  +++ b/drivers/iommu/exynos-iommu.c
  @@ -56,19 +56,19 @@
   #define lv2ent_large(pent) ((*(pent)  3) == 1)
 
   #define section_phys(sent) (*(sent)  SECT_MASK)
  -#define section_offs(iova) ((iova)  0xF)
  +#define section_offs(iova) ((sysmmu_iova_t)(iova)  0xF)
 
 The cast will mask abuses of iova. Define section_offs as a static
 function and GCC can type check iova parameter to make sure it's a
 sysmmu_iova_t.
 Thoughts?
 
 I was thinking ((iova)  (sysmmu_iova_t) 0XF) might do what you
 want but it doesn't warn on abuse that I tried. I believe GCC knows
 the upper bits are being ignored.

Thank you for advice.

I agree that type checking by compiler will be more helpful
as you mentioned.

Regards,

KyongHo
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v11 10/27] iommu/exynos: use managed device helper functions

2014-03-20 Thread Cho KyongHo
On Wed, 19 Mar 2014 13:08:42 +0100, Tomasz Figa wrote:
 On 19.03.2014 10:01, Sachin Kamat wrote:
  On 19 March 2014 14:29, Cho KyongHo pullip@samsung.com wrote:
  On Tue, 18 Mar 2014 16:14:53 +0100, Tomasz Figa wrote:
  On 18.03.2014 12:09, Cho KyongHo wrote:
  On Fri, 14 Mar 2014 20:52:43 +0530, Sachin Kamat wrote:
  Hi KyongHo,
 
  On 14 March 2014 10:35, Cho KyongHo pullip@samsung.com wrote:
  This patch uses managed device helper functions in the probe().
 
  Signed-off-by: Cho KyongHo pullip@samsung.com
  ---
  [snip]
 
  +   data-clk = devm_clk_get(dev, sysmmu);
  +   if (IS_ERR(data-clk)) {
  +   dev_info(dev, No gate clock found!\n);
  +   data-clk = NULL;
  +   }
 
  Why aren't you returning from here upon error?
 
  It is for the case of a System MMU which does not need clock gating.
 
 
  Are there really such cases?
 
 
  Yes.
  Especially in the case of initial stage of new SoC development.
 
  I have experianced some software workaround for H/W restriction
  needs prevention of clock gating for some devices.
 
  So aren't these basically some exceptions/hacks rather than the usual way
  of functioning of the device?
 
 
 This actually raises a good question, whether we really need to support 
 such early development SoC versions in mainline.
 
 Another thing is that if you need to assure that a clock is ungated, you 
 must acquire it and prepare_enable explicitly, so I don't think this 
 kind of handling is correct.
 
On early development step of a new SoC, clock related stuffs and
some device drivers like display controller are usually developed in parallel.

In that case, -ENOENT from clk_get() must not treated as an error.
[PATCH v11 20/17] iommu/exynos: allow having multiple System MMUs for a master 
H/W
patch distinguishes -ENOENT from other error values returned by devm_clk_get().

Regards,

KyongHo


___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v11 20/27] iommu/exynos: allow having multiple System MMUs for a master H/W

2014-03-20 Thread Cho KyongHo
On Wed, 19 Mar 2014 16:14:57 +0100, Tomasz Figa wrote:
 On 19.03.2014 14:20, Tomasz Figa wrote:
  On 19.03.2014 01:39, Cho KyongHo wrote:
  On Tue, 18 Mar 2014 15:26:48 +0100, Tomasz Figa wrote:
 
 
  On 18.03.2014 14:01, Cho KyongHo wrote:
  On Fri, 14 Mar 2014 17:12:03 +0100, Tomasz Figa wrote:
  Hi KyongHo,
 
  On 14.03.2014 06:10, Cho KyongHo wrote:
  Some master device descriptor like fimc-is which is an abstraction
  of very complex H/W may have multiple System MMUs. For those devices,
  the design of the link between System MMU and its master H/W is
  needed
  to be reconsidered.
 
  A link structure, sysmmu_list_data is introduced that provides a link
  to master H/W and that has a pointer to the device descriptor of a
  System MMU. Given a device descriptor of a master H/W, it is possible
  to traverse all System MMUs that must be controlled along with the
  master H/W.
 
  NAK.
 
  A device driver should handle particular hardware instances
  separately,
  without abstracting a virtual hardware instance consisting of multiple
  physical ones.
 
  If such abstraction is needed, it should be done above the
  exynos-iommu
  driver, e.g. by something like iommu-composite driver that would
  aggregate several IOMMUs. Keep in mind that such IOMMUs in a group
  could
  be different, e.g. different Exynos SysMMU versions or even completely
  different IPs handled by different drivers.
 
  Still, I don't think there is a real need for such abstraction.
  Instead,
  related drivers shall be fixed to properly handle multiple memory
  masters and their IOMMUs.
 
 
  G2D, Scalers and FIMD of Exynos5420 has 2 System MMUs while aother
  SoC like
  Exynos5250 does not.
 
  I don't understand why you are negative to this approach.
  This is the simplest than the others.
 
  Let me show you an example.
  FIMC-IS driver just controls MCU in FIMC-IS subsystem and the
  firmware of
  the MCU controls all other peripherals in the subsystem. Each
  peripherals
  have their own System MMU. Moreover, the configuration of the
  peripherals
  varies according to the SoCs.
 
  If System MMU driver accepts multiple masters, everything is done in
  DT.
  But I worry that it is not easy if System MMU driver does not support
  multiple masters.
 
  I believe I have stated enough reasons why this kind of implementation
  is bad. I'm not going to waste time repeating myself.
 
  Your concerns presented above are valid, however they are not related to
  what is wrong with this patch. I have given you two proper ways to
  handle this, none should be forced upon particular IOMMU master drivers
  - their authors should have the chance to select the method that works
  best for them.
 
 
  I don't still understand why you think this patch is wrong.
  I think this is the best way not to think for all the driver developers
  about other things than their business logic.
 
  I agree, but one of the ways I proposed (an iommu-composite layer above
  the IOMMU low level drivers) doesn't add any extra responsibility of
  driver developers.
 
  Moreover, it's this kind of business logic in low level drivers that is
  adding more responsibility, because it introduces additional complexity
  and makes the driver harder to read, maintain and extend in future.
 
 
  This does not hurt anyone and I think this is good enough.
 
 
  Well, it is barely good enough. It is a good practice to make a low
  level driver handle a single device instance and this is how Linux
  driver model is designed.
 
  Moreover, a single device tree node _must_ represent a single hardware
  block, so you can't group multiple SysMMUs into a single device tree node.
 
 
 OK, you add nodes for single SysMMUs devices which is fine, sorry. I was 
 under impression that one kernel device (struct device) corresponds to 
 multiple SysMMUs, but this was before your patches, sorry. So one issue 
 less, but it's still not good.
 

Ok. Understood why you have mentioned such.

  Furthermore, if you force grouping of SysMMUs into a single virtual one,
  you enforce using the same address space for all masters of some
  particular hardware blocks, while potentially driver developers would
  like to separate them.
 
 Probably some clarification is needed. Your other patch adds:
 
   sysmmu_fimd0w04: sysmmu@1464 {
   compatible = samsung,sysmmu-v3.3;
   reg = 0x1464 0x1000;
   interrupt-parent = combiner;
   interrupts = 3 2;
   clock-names = sysmmu, master;
   clocks = clock 422, clock 421;
   samsung,power-domain = disp_pd;
   mmu-masters = fimd;
   };
 
   sysmmu_fimd0w123: sysmmu@1468 {
   compatible = samsung,sysmmu-v3.3;
   reg = 0x1468 0x1000;
   interrupt-parent = combiner;
   interrupts = 3 0;
   clock-names = sysmmu, master;
   clocks = clock 423, clock 421;
   samsung

Re: [PATCH v11 17/27] iommu/exynos: remove calls to Runtime PM API functions

2014-03-20 Thread Cho KyongHo
On Wed, 19 Mar 2014 09:54:39 -0700, Grant Grundler wrote:
 On Wed, Mar 19, 2014 at 6:12 AM, Tomasz Figa t.f...@samsung.com wrote:
 ...
  Device driver is not only for the scholarship but also for the real use.
 
  Huh? I'm not sure what kind of comment is this.
 
 I'm guessing Cho meant: This isn't an academic exercise - I have a
 real use case that requires reference counting.

That is what I meant; Sorry for my poor English :-)

 Cho needs to be more specific about his Some driver needs enabling
 sysmmu example. Then others would understand why/when the reference
 counting is needed. Ie walk through a real driver that exists today
 that depends on reference counting.


One of my recent experience is that a display controller (FIMD) driver
of a SoC manages two different context of power management:
One is turning on and off display screen (LCD) (which is as usual as previous 
SoCs)
and the other is gating its internal clock including System MMU very
frequently to reduce power consumption.
Because System MMU driver holds its clock ungated while it is enabled,
FIMD driver explicitely disable System MMU.

Yes, well designed FIMD driver must care about balancing of
disabling and enabling System MMU between different contexts.
But the design of some complex driver may be poor in few features due to
agressive development schedule sometimes.

Please let me think about the counting.

Now I also think the system mmu driver does not need to make
an extra effort for some special cases.

Regards,

KyongHo
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v11 17/27] iommu/exynos: remove calls to Runtime PM API functions

2014-03-20 Thread Cho KyongHo
On Wed, 19 Mar 2014 19:51:21 +0100, Tomasz Figa wrote:
 On 19.03.2014 19:37, Grant Grundler wrote:
  On Wed, Mar 19, 2014 at 10:30 AM, Tomasz Figa t.f...@samsung.com wrote:
  ...
  As I said, AFAIK the trend is to get rid of ordering by initcalls and make
  sure that drivers can handle missing dependencies properly, even for
  services such as DMA, GPIO, clocks and so on, which after all are 
  provided
  by normal drivers like other.
 
  Ok - I'm not following the general kernel dev trends. initcall()
  levels are easy to understand and implement. So I would not be in a
  hurry to replace them.
 
 
 Well, initcall level is still a way to satisfy most of dependencies, 
 i.e. all client devices with higher initcall levels will probe 
 successfully. However the other case needs to be handled as well - in 
 this case the IOMMU binding code needs to defer probe of client driver 
 if respective IOMMU is not yet available.

I now understand what is deferred probing you mentioned.
However, I worry that many existing drivers are not ready
for deferred probing.

But still I wonder if System MMU driver need to be probed in the same
initcall level.

  ps. I've written IOMMU support for four different IOMMUs on three
  operating systems (See drivers/parisc for two linux examples). But I
  still feel like I at best have 80% understanding of how this one is
  organized/works. Abstract descriptions and convoluted code have been
  handicapping me (and lack of time to dig further).
 
 
  Well, this is one of my concerns with this driver. It isn't easy to read
  (and so review, maintain, extend and debug found issues).
 
  My postscript comment was more to explain why I'm not confident in my
  opinion - not a reason to reject the patch series.  I still consider
  the whole series as a step forward. But I'm not the expert here.
 
 I fully agree with you. Other than the issues mentioned in review, the 
 patches are definitely a step forward. I'd even say that all the patches 
 that have nothing to do with device tree could be merged in their 
 current form and the code refined later. It doesn't mean that patches 
 shouldn't be reviewed now and issues spotted reported, even if they 
 could be fixed later - this is for the IOMMU subsystem maintainer to decide.
 
 As for patches related to DT support, more care needs to be taken, as 
 bindings should be designed with stability in mind, so the refining 
 process should happen at review stage.
 
  Right now, with ~30 patches posted by the exynos iommu (official?)
  maintainer, no one else who has a clue will attempt to fix or clean up
  those kinds of problems.  i.e. it's useful to enable others to fix
  what are essentially unspecified design pattern issues.
 
 Agreed.

Let me wait for the way of binding System MMU and its master developed by Marek.

Regards,

KyongHo
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v11 20/27] iommu/exynos: allow having multiple System MMUs for a master H/W

2014-03-20 Thread Cho KyongHo
On Thu, 20 Mar 2014 11:54:58 +0100, Tomasz Figa wrote:
 On 20.03.2014 11:22, Cho KyongHo wrote:
  On Wed, 19 Mar 2014 16:14:57 +0100, Tomasz Figa wrote:
  On 19.03.2014 14:20, Tomasz Figa wrote:
  On 19.03.2014 01:39, Cho KyongHo wrote:
  On Tue, 18 Mar 2014 15:26:48 +0100, Tomasz Figa wrote:
 
 
  On 18.03.2014 14:01, Cho KyongHo wrote:
  On Fri, 14 Mar 2014 17:12:03 +0100, Tomasz Figa wrote:
  Hi KyongHo,
 
  On 14.03.2014 06:10, Cho KyongHo wrote:
  Some master device descriptor like fimc-is which is an abstraction
  of very complex H/W may have multiple System MMUs. For those devices,
  the design of the link between System MMU and its master H/W is
  needed
  to be reconsidered.
 
  A link structure, sysmmu_list_data is introduced that provides a link
  to master H/W and that has a pointer to the device descriptor of a
  System MMU. Given a device descriptor of a master H/W, it is possible
  to traverse all System MMUs that must be controlled along with the
  master H/W.
 
  NAK.
 
  A device driver should handle particular hardware instances
  separately,
  without abstracting a virtual hardware instance consisting of multiple
  physical ones.
 
  If such abstraction is needed, it should be done above the
  exynos-iommu
  driver, e.g. by something like iommu-composite driver that would
  aggregate several IOMMUs. Keep in mind that such IOMMUs in a group
  could
  be different, e.g. different Exynos SysMMU versions or even completely
  different IPs handled by different drivers.
 
  Still, I don't think there is a real need for such abstraction.
  Instead,
  related drivers shall be fixed to properly handle multiple memory
  masters and their IOMMUs.
 
 
  G2D, Scalers and FIMD of Exynos5420 has 2 System MMUs while aother
  SoC like
  Exynos5250 does not.
 
  I don't understand why you are negative to this approach.
  This is the simplest than the others.
 
  Let me show you an example.
  FIMC-IS driver just controls MCU in FIMC-IS subsystem and the
  firmware of
  the MCU controls all other peripherals in the subsystem. Each
  peripherals
  have their own System MMU. Moreover, the configuration of the
  peripherals
  varies according to the SoCs.
 
  If System MMU driver accepts multiple masters, everything is done in
  DT.
  But I worry that it is not easy if System MMU driver does not support
  multiple masters.
 
  I believe I have stated enough reasons why this kind of implementation
  is bad. I'm not going to waste time repeating myself.
 
  Your concerns presented above are valid, however they are not related to
  what is wrong with this patch. I have given you two proper ways to
  handle this, none should be forced upon particular IOMMU master drivers
  - their authors should have the chance to select the method that works
  best for them.
 
 
  I don't still understand why you think this patch is wrong.
  I think this is the best way not to think for all the driver developers
  about other things than their business logic.
 
  I agree, but one of the ways I proposed (an iommu-composite layer above
  the IOMMU low level drivers) doesn't add any extra responsibility of
  driver developers.
 
  Moreover, it's this kind of business logic in low level drivers that is
  adding more responsibility, because it introduces additional complexity
  and makes the driver harder to read, maintain and extend in future.
 
 
  This does not hurt anyone and I think this is good enough.
 
 
  Well, it is barely good enough. It is a good practice to make a low
  level driver handle a single device instance and this is how Linux
  driver model is designed.
 
  Moreover, a single device tree node _must_ represent a single hardware
  block, so you can't group multiple SysMMUs into a single device tree node.
 
 
  OK, you add nodes for single SysMMUs devices which is fine, sorry. I was
  under impression that one kernel device (struct device) corresponds to
  multiple SysMMUs, but this was before your patches, sorry. So one issue
  less, but it's still not good.
 
 
  Ok. Understood why you have mentioned such.
 
  Furthermore, if you force grouping of SysMMUs into a single virtual one,
  you enforce using the same address space for all masters of some
  particular hardware blocks, while potentially driver developers would
  like to separate them.
 
  Probably some clarification is needed. Your other patch adds:
 
 sysmmu_fimd0w04: sysmmu@1464 {
 compatible = samsung,sysmmu-v3.3;
 reg = 0x1464 0x1000;
 interrupt-parent = combiner;
 interrupts = 3 2;
 clock-names = sysmmu, master;
 clocks = clock 422, clock 421;
 samsung,power-domain = disp_pd;
 mmu-masters = fimd;
 };
 
 sysmmu_fimd0w123: sysmmu@1468 {
 compatible = samsung,sysmmu-v3.3;
 reg = 0x1468 0x1000;
 interrupt-parent = combiner;
 interrupts = 3 0;
 clock-names = sysmmu, master

Re: [PATCH v11 13/27] iommu/exynos: support for device tree

2014-03-19 Thread Cho KyongHo
On Tue, 18 Mar 2014 16:46:24 +0530, Sachin Kamat wrote:
 On 18 March 2014 16:44, Cho KyongHo pullip@samsung.com wrote:
  On Fri, 14 Mar 2014 20:57:42 +0530, Sachin Kamat wrote:
  Hi KyongHo,
 
  On 14 March 2014 10:39, Cho KyongHo pullip@samsung.com wrote:
  
   -static struct platform_driver exynos_sysmmu_driver = {
   -   .probe  = exynos_sysmmu_probe,
   -   .driver = {
   +#ifdef CONFIG_OF
 
  This is not needed as Exynos is DT only platform.
 
  Yes, but I hesitate to remove that.
 
 What is the reason for your hesitation? :)
 
Actually, no reason because you mentioned that Exynos is DT only platofrm.

I will remove that.

Thank you.

KyongHo
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v11 10/27] iommu/exynos: use managed device helper functions

2014-03-19 Thread Cho KyongHo
On Wed, 19 Mar 2014 08:59:09 +0900, Jingoo Han wrote:
 On Wednesday, March 19, 2014 12:12 AM, Tomasz Figa wrote:
  On 18.03.2014 11:38, Cho KyongHo wrote:
   On Fri, 14 Mar 2014 14:28:36 +0100, Tomasz Figa wrote:
   On 14.03.2014 06:05, Cho KyongHo wrote:
   This patch uses managed device helper functions in the probe().
  
   Signed-off-by: Cho KyongHo pullip@samsung.com
   ---
  drivers/iommu/exynos-iommu.c |   64 
   +-
  1 file changed, 26 insertions(+), 38 deletions(-)
  
   diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
   index 36e6b73..33b424d 100644
   --- a/drivers/iommu/exynos-iommu.c
   +++ b/drivers/iommu/exynos-iommu.c
 
 [.]
 
   res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
   if (!res) {
   -   dev_dbg(dev, Unable to find IOMEM region\n);
   -   ret = -ENOENT;
   -   goto err_init;
   +   dev_err(dev, Unable to find IOMEM region\n);
   +   return -ENOENT;
   }
  
   No need to check for error and print message, because
   devm_ioremap_resource() already checks the passed resource and handles
   error cases.
  
  
   Yes but devm_ioremap_resource() just tells that the given 'res' is not
   correct. I think the message in the driver is more informative.
  
  The common practice used in Linux kernel is to not duplicate such
  messages. It is obvious that devm_ioremap_resource() printing such
  message is related to an IOMEM resource anyway, as you can't used it
  with other types of resources.
 
 +1
 
 I agree with Tomasz Figa's opinion.
 These messages have been being removed from Linux kernel.
 Thank you.
 
Ok.

Thank you for the advice.

Kyong Ho 
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v11 10/27] iommu/exynos: use managed device helper functions

2014-03-19 Thread Cho KyongHo
On Tue, 18 Mar 2014 16:14:53 +0100, Tomasz Figa wrote:
 On 18.03.2014 12:09, Cho KyongHo wrote:
  On Fri, 14 Mar 2014 20:52:43 +0530, Sachin Kamat wrote:
  Hi KyongHo,
 
  On 14 March 2014 10:35, Cho KyongHo pullip@samsung.com wrote:
  This patch uses managed device helper functions in the probe().
 
  Signed-off-by: Cho KyongHo pullip@samsung.com
  ---
  [snip]
 
  +   data-clk = devm_clk_get(dev, sysmmu);
  +   if (IS_ERR(data-clk)) {
  +   dev_info(dev, No gate clock found!\n);
  +   data-clk = NULL;
  +   }
 
  Why aren't you returning from here upon error?
 
  It is for the case of a System MMU which does not need clock gating.
 
 
 Are there really such cases?
 

Yes.
Especially in the case of initial stage of new SoC development.

I have experianced some software workaround for H/W restriction
needs prevention of clock gating for some devices.

Regards,

KyongHo
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v11 13/27] iommu/exynos: support for device tree

2014-03-19 Thread Cho KyongHo
On Tue, 18 Mar 2014 16:25:11 +0100, Tomasz Figa wrote:
 On 18.03.2014 11:52, Cho KyongHo wrote:
  On Fri, 14 Mar 2014 14:39:33 +0100, Tomasz Figa wrote:
  @@ -557,11 +558,23 @@ static int exynos_sysmmu_probe(struct 
  platform_device *pdev)
return 0;
 }
 
  -static struct platform_driver exynos_sysmmu_driver = {
  - .probe  = exynos_sysmmu_probe,
  - .driver = {
  +#ifdef CONFIG_OF
  +static struct of_device_id sysmmu_of_match[] __initconst = {
  + { .compatible   = samsung,sysmmu-v1, },
  + { .compatible   = samsung,sysmmu-v2, },
  + { .compatible   = samsung,sysmmu-v3.1, },
  + { .compatible   = samsung,sysmmu-v3.2, },
  + { .compatible   = samsung,sysmmu-v3.3, },
 
  Do you need all these compatible strings? I mean, are there any
  implementation differences that can't be identified by reading IP
  registers, such as REG_MMU_VERSION?
 
 
  Unfortunately, there is a SoC which overrides REG_MMU_VERSION with
  a value for RTL designers and it is not related to System MMU
  versions.
 
 OK.
 
 What about having a generic compatible string for Samsung SysMMU then, 
 but an additional property that can override the version to account for 
 such brokenness? If not provided, the version would be read from 
 REG_MMU_VERSION.
 

Yes it is one of possible idea.
Let me think what better way is.

Thank you.

KyongHo
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v11 19/27] iommu/exynos: add support for power management subsystems.

2014-03-19 Thread Cho KyongHo
On Tue, 18 Mar 2014 16:33:04 +0100, Tomasz Figa wrote:
 On 18.03.2014 12:23, Cho KyongHo wrote:
  On Fri, 14 Mar 2014 17:07:53 +0100, Tomasz Figa wrote:
  Hi KyongHo,
 
  On 14.03.2014 06:10, Cho KyongHo wrote:
 
 [snip]
 
  @@ -677,11 +679,40 @@ static int __init exynos_sysmmu_probe(struct 
  platform_device *pdev)
platform_set_drvdata(pdev, data);
 
pm_runtime_enable(dev);
  + data-runtime_active = !pm_runtime_enabled(dev);
 
  Hmm, this seems to be a bit misleading. The field is named
  runtime_active, but the assignment makes it true if PM runtime is _not_
  enabled (i.e. inactive). Is this correct?
 
 
  I agree that it may lead misunderstood.
  data-runtime_active actually indicates if electric power is asserted
  to the System MMU. pm_runtime_enable() call must enable runtime pm
  for the given device. If runtime pm is not enabled although 
  pm_runtime_enable()
  is called, CONFIG_PM_RUNTIME is not configured.
 
  Actually, it is replacible with
  if (IS_ENABLED(CONFIG_PM_RUNTIME))
   data-runtime_active = true;
 
 I would keep it as !pm_runtime_enabled(dev), but rename the field to 
 something more meaningful, like data-is_powered_on.
 

That is good idea.

thanks for advice.

KyongHo.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v11 08/27] iommu/exynos: always use a single clock descriptor

2014-03-18 Thread Cho KyongHo
On Fri, 14 Mar 2014 14:07:32 +0100, Tomasz Figa wrote:
 Hi KyongHo,
 
 On 14.03.2014 06:05, Cho KyongHo wrote:
  System MMU driver is changed to control only a single instance of
  System MMU at a time. Since a single instance of System MMU has only
  a single clock descriptor for its clock gating, there is no need to
  obtain two or more clock descriptors.
 
 
 This patch does much more than just making the driver use a single clock 
 descriptor. Please update the subject and description accordingly.
 
Ok.

  Signed-off-by: Cho KyongHo pullip@samsung.com
  ---
drivers/iommu/exynos-iommu.c |  223 
  ++
1 file changed, 72 insertions(+), 151 deletions(-)
 
  diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
  index 8dc7031..a4499b2 100644
  --- a/drivers/iommu/exynos-iommu.c
  +++ b/drivers/iommu/exynos-iommu.c
  @@ -171,9 +171,8 @@ struct sysmmu_drvdata {
  struct device *sysmmu;  /* System MMU's device descriptor */
  struct device *dev; /* Owner of system MMU */
  char *dbgname;
  -   int nsfrs;
  -   void __iomem **sfrbases;
  -   struct clk *clk[2];
  +   void __iomem *sfrbase;
  +   struct clk *clk;
  int activations;
  rwlock_t lock;
  struct iommu_domain *domain;
  @@ -294,56 +293,39 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void 
  *dev_id)
{
  /* SYSMMU is in blocked when interrupt occurred. */
  struct sysmmu_drvdata *data = dev_id;
  -   struct resource *irqres;
  -   struct platform_device *pdev;
  enum exynos_sysmmu_inttype itype;
  unsigned long addr = -1;
  -
  -   int i, ret = -ENOSYS;
  +   int ret = -ENOSYS;
 
  read_lock(data-lock);
 
  WARN_ON(!is_sysmmu_active(data));
 
  -   pdev = to_platform_device(data-sysmmu);
  -   for (i = 0; i  (pdev-num_resources / 2); i++) {
  -   irqres = platform_get_resource(pdev, IORESOURCE_IRQ, i);
  -   if (irqres  ((int)irqres-start == irq))
  -   break;
  -   }
  -
  -   if (i == pdev-num_resources) {
  +   itype = (enum exynos_sysmmu_inttype)
  +   __ffs(__raw_readl(data-sfrbase + REG_INT_STATUS));
  +   if (WARN_ON(!((itype = 0)  (itype  SYSMMU_FAULT_UNKNOWN
  itype = SYSMMU_FAULT_UNKNOWN;
  -   } else {
  -   itype = (enum exynos_sysmmu_inttype)
  -   __ffs(__raw_readl(data-sfrbases[i] + REG_INT_STATUS));
  -   if (WARN_ON(!((itype = 0)  (itype  SYSMMU_FAULT_UNKNOWN
  -   itype = SYSMMU_FAULT_UNKNOWN;
  -   else
  -   addr = __raw_readl(
  -   data-sfrbases[i] + fault_reg_offset[itype]);
  -   }
  +   else
  +   addr = __raw_readl(data-sfrbase + fault_reg_offset[itype]);
 
  if (data-domain)
  -   ret = report_iommu_fault(data-domain, data-dev,
  -   addr, itype);
  +   ret = report_iommu_fault(data-domain, data-dev, addr, itype);
 
  if ((ret == -ENOSYS)  data-fault_handler) {
  unsigned long base = data-pgtable;
  if (itype != SYSMMU_FAULT_UNKNOWN)
  -   base = __raw_readl(
  -   data-sfrbases[i] + REG_PT_BASE_ADDR);
  +   base = __raw_readl(data-sfrbase + REG_PT_BASE_ADDR);
  ret = data-fault_handler(itype, base, addr);
  }
 
  if (!ret  (itype != SYSMMU_FAULT_UNKNOWN))
  -   __raw_writel(1  itype, data-sfrbases[i] + REG_INT_CLEAR);
  +   __raw_writel(1  itype, data-sfrbase + REG_INT_CLEAR);
  else
  dev_dbg(data-sysmmu, (%s) %s is not handled.\n,
  data-dbgname, sysmmu_fault_name[itype]);
 
  if (itype != SYSMMU_FAULT_UNKNOWN)
  -   sysmmu_unblock(data-sfrbases[i]);
  +   sysmmu_unblock(data-sfrbase);
 
  read_unlock(data-lock);
 
  @@ -354,20 +336,16 @@ static bool __exynos_sysmmu_disable(struct 
  sysmmu_drvdata *data)
{
  unsigned long flags;
  bool disabled = false;
  -   int i;
 
  write_lock_irqsave(data-lock, flags);
 
  if (!set_sysmmu_inactive(data))
  goto finish;
 
  -   for (i = 0; i  data-nsfrs; i++)
  -   __raw_writel(CTRL_DISABLE, data-sfrbases[i] + REG_MMU_CTRL);
  +   __raw_writel(CTRL_DISABLE, data-sfrbase + REG_MMU_CTRL);
 
  -   if (data-clk[1])
  -   clk_disable(data-clk[1]);
  -   if (data-clk[0])
  -   clk_disable(data-clk[0]);
  +   if (data-clk)
 
 I know this is already in the driver, but checking (struct clk *) for 
 NULL is incorrect. NULL is a valid pointer for dummy clocks on platforms 
 which do not provide particular clocks, to make this transparent to 
 drivers. IS_ERR() should be used to check whether a clock pointer is valid.
 
 This patch is changing all the clock code anyway, so this change could 
 be squashed into it to fix this.
 
Ok. Thank you for the information.

  +   clk_disable(data-clk);
 
  disabled

Re: [PATCH v11 10/27] iommu/exynos: use managed device helper functions

2014-03-18 Thread Cho KyongHo
On Fri, 14 Mar 2014 14:28:36 +0100, Tomasz Figa wrote:
 Hi KyongHo,
 
 On 14.03.2014 06:05, Cho KyongHo wrote:
  This patch uses managed device helper functions in the probe().
 
  Signed-off-by: Cho KyongHo pullip@samsung.com
  ---
drivers/iommu/exynos-iommu.c |   64 
  +-
1 file changed, 26 insertions(+), 38 deletions(-)
 
  diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
  index 36e6b73..33b424d 100644
  --- a/drivers/iommu/exynos-iommu.c
  +++ b/drivers/iommu/exynos-iommu.c
  @@ -499,51 +499,48 @@ void exynos_sysmmu_tlb_invalidate(struct device *dev)
 
static int exynos_sysmmu_probe(struct platform_device *pdev)
{
  -   int ret;
  +   int irq, ret;
  struct device *dev = pdev-dev;
  struct sysmmu_drvdata *data;
  struct resource *res;
 
  -   data = kzalloc(sizeof(*data), GFP_KERNEL);
  -   if (!data) {
  -   dev_dbg(dev, Not enough memory\n);
  -   ret = -ENOMEM;
  -   goto err_alloc;
  -   }
  +   data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
  +   if (!data)
  +   return -ENOMEM;
 
  res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  if (!res) {
  -   dev_dbg(dev, Unable to find IOMEM region\n);
  -   ret = -ENOENT;
  -   goto err_init;
  +   dev_err(dev, Unable to find IOMEM region\n);
  +   return -ENOENT;
  }
 
 No need to check for error and print message, because 
 devm_ioremap_resource() already checks the passed resource and handles 
 error cases.
 

Yes but devm_ioremap_resource() just tells that the given 'res' is not
correct. I think the message in the driver is more informative.

Thanks.

KyongHo
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v11 13/27] iommu/exynos: support for device tree

2014-03-18 Thread Cho KyongHo
On Fri, 14 Mar 2014 14:39:33 +0100, Tomasz Figa wrote:
 Hi KyongHo,
 
 On 14.03.2014 06:09, Cho KyongHo wrote:
  This commit adds device tree support for System MMU.
 
  Signed-off-by: Cho KyongHo pullip@samsung.com
  ---
drivers/iommu/Kconfig|5 ++---
drivers/iommu/exynos-iommu.c |   21 +
2 files changed, 19 insertions(+), 7 deletions(-)
 
  diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
  index df56e4c..22af807 100644
  --- a/drivers/iommu/Kconfig
  +++ b/drivers/iommu/Kconfig
  @@ -178,16 +178,15 @@ config TEGRA_IOMMU_SMMU
 
config EXYNOS_IOMMU
  bool Exynos IOMMU Support
  -   depends on ARCH_EXYNOS  EXYNOS_DEV_SYSMMU
  +   depends on ARCH_EXYNOS
  select IOMMU_API
  +   default n
  help
Support for the IOMMU(System MMU) of Samsung Exynos application
 
 nit: There should be a white space before the opening parenthesis.
 
Ok. :)

processor family. This enables H/W multimedia accellerators to see
 
 typo: s/accellerators/accelerators/
 

Ok.

non-linear physical memory chunks as a linear memory in their
address spaces
 
  - If unsure, say N here.
  -
config EXYNOS_IOMMU_DEBUG
  bool Debugging log for Exynos IOMMU
  depends on EXYNOS_IOMMU
  diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
  index 33b424d..34feb04 100644
  --- a/drivers/iommu/exynos-iommu.c
  +++ b/drivers/iommu/exynos-iommu.c
  @@ -26,6 +26,7 @@
#include linux/list.h
#include linux/memblock.h
#include linux/export.h
  +#include linux/of.h
 
#include asm/cacheflush.h
#include asm/pgtable.h
  @@ -497,7 +498,7 @@ void exynos_sysmmu_tlb_invalidate(struct device *dev)
  read_unlock_irqrestore(data-lock, flags);
}
 
  -static int exynos_sysmmu_probe(struct platform_device *pdev)
  +static int __init exynos_sysmmu_probe(struct platform_device *pdev)
{
  int irq, ret;
  struct device *dev = pdev-dev;
  @@ -557,11 +558,23 @@ static int exynos_sysmmu_probe(struct platform_device 
  *pdev)
  return 0;
}
 
  -static struct platform_driver exynos_sysmmu_driver = {
  -   .probe  = exynos_sysmmu_probe,
  -   .driver = {
  +#ifdef CONFIG_OF
  +static struct of_device_id sysmmu_of_match[] __initconst = {
  +   { .compatible   = samsung,sysmmu-v1, },
  +   { .compatible   = samsung,sysmmu-v2, },
  +   { .compatible   = samsung,sysmmu-v3.1, },
  +   { .compatible   = samsung,sysmmu-v3.2, },
  +   { .compatible   = samsung,sysmmu-v3.3, },
 
 Do you need all these compatible strings? I mean, are there any 
 implementation differences that can't be identified by reading IP 
 registers, such as REG_MMU_VERSION?
 

Unfortunately, there is a SoC which overrides REG_MMU_VERSION with
a value for RTL designers and it is not related to System MMU
versions.

Thank you.

KyongHo
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v11 15/27] iommu/exynos: use convenient macro to handle gate clocks

2014-03-18 Thread Cho KyongHo
On Fri, 14 Mar 2014 22:27:59 +0530, Sachin Kamat wrote:
  Hi KyongHo,
 
 On 14 March 2014 19:13, Tomasz Figa t.f...@samsung.com wrote:
  Hi KyongHo,
 
 
  On 14.03.2014 06:09, Cho KyongHo wrote:
 
  exynos-iommu driver must care about master H/W's gate clock as well as
  System MMU's gate clock. To enhance readability of the source code,
  macros to gate/ungate those clocks are defined.
 
  Signed-off-by: Cho KyongHo pullip@samsung.com
  ---
drivers/iommu/exynos-iommu.c |   34 ++
1 file changed, 22 insertions(+), 12 deletions(-)
 
  diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
  index 71e77f1..cef62d0 100644
  --- a/drivers/iommu/exynos-iommu.c
  +++ b/drivers/iommu/exynos-iommu.c
  @@ -101,6 +101,16 @@
#define REG_PB1_SADDR 0x054
#define REG_PB1_EADDR 0x058
 
  +#define __clk_gate_ctrl(data, clk, en) do {\
  +   if (data-clk)  \
  +   clk_##en##able(data-clk);  \
  +   } while (0)
  +
  +#define __sysmmu_clk_enable(data)  __clk_gate_ctrl(data, clk, en)
  +#define __sysmmu_clk_disable(data) __clk_gate_ctrl(data, clk, dis)
  +#define __master_clk_enable(data)  __clk_gate_ctrl(data, clk_master,
  en)
  +#define __master_clk_disable(data) __clk_gate_ctrl(data, clk_master,
  dis)
  +
 
 
  I'd say that such macros only obfuscate code, without any gains, as you can
  see in diffstat - this patch adds more lines than it removes.
 
  Please drop this change.
 
  I agree with Tomasz here.
 

Are you concerning about using macros or more insertions than deletions?

The deletions in this patch are only clk_enable() and clk_disable()
but they must be
if (!IS_ERR(clk)) clk_enable(clk) and if (!IS_ERR(clk)) clk_disable(clk).

I think use of macro is fancier in that case.

Thank you.

KyongHo.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v11 13/27] iommu/exynos: support for device tree

2014-03-18 Thread Cho KyongHo
On Fri, 14 Mar 2014 20:57:42 +0530, Sachin Kamat wrote:
 Hi KyongHo,
 
 On 14 March 2014 10:39, Cho KyongHo pullip@samsung.com wrote:
  This commit adds device tree support for System MMU.
 
  Signed-off-by: Cho KyongHo pullip@samsung.com
  ---
   drivers/iommu/Kconfig|5 ++---
   drivers/iommu/exynos-iommu.c |   21 +
   2 files changed, 19 insertions(+), 7 deletions(-)
 
  diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
  index df56e4c..22af807 100644
  --- a/drivers/iommu/Kconfig
  +++ b/drivers/iommu/Kconfig
  @@ -178,16 +178,15 @@ config TEGRA_IOMMU_SMMU
 
   config EXYNOS_IOMMU
  bool Exynos IOMMU Support
  -   depends on ARCH_EXYNOS  EXYNOS_DEV_SYSMMU
  +   depends on ARCH_EXYNOS
  select IOMMU_API
  +   default n
 
 This is not needed as it is the default choice.
 

OK.

  help
Support for the IOMMU(System MMU) of Samsung Exynos application
processor family. This enables H/W multimedia accellerators to see
non-linear physical memory chunks as a linear memory in their
address spaces
 
  - If unsure, say N here.
  -
   config EXYNOS_IOMMU_DEBUG
  bool Debugging log for Exynos IOMMU
  depends on EXYNOS_IOMMU
  diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
  index 33b424d..34feb04 100644
  --- a/drivers/iommu/exynos-iommu.c
  +++ b/drivers/iommu/exynos-iommu.c
  @@ -26,6 +26,7 @@
   #include linux/list.h
   #include linux/memblock.h
   #include linux/export.h
  +#include linux/of.h
 
   #include asm/cacheflush.h
   #include asm/pgtable.h
  @@ -497,7 +498,7 @@ void exynos_sysmmu_tlb_invalidate(struct device *dev)
  read_unlock_irqrestore(data-lock, flags);
   }
 
  -static int exynos_sysmmu_probe(struct platform_device *pdev)
  +static int __init exynos_sysmmu_probe(struct platform_device *pdev)
   {
  int irq, ret;
  struct device *dev = pdev-dev;
  @@ -557,11 +558,23 @@ static int exynos_sysmmu_probe(struct platform_device 
  *pdev)
  return 0;
   }
 
  -static struct platform_driver exynos_sysmmu_driver = {
  -   .probe  = exynos_sysmmu_probe,
  -   .driver = {
  +#ifdef CONFIG_OF
 
 This is not needed as Exynos is DT only platform.
 
Yes, but I hesitate to remove that.

  +static struct of_device_id sysmmu_of_match[] __initconst = {
  +   { .compatible   = samsung,sysmmu-v1, },
  +   { .compatible   = samsung,sysmmu-v2, },
  +   { .compatible   = samsung,sysmmu-v3.1, },
  +   { .compatible   = samsung,sysmmu-v3.2, },
  +   { .compatible   = samsung,sysmmu-v3.3, },
  +   { },
  +};
  +#endif
  +
  +static struct platform_driver exynos_sysmmu_driver __refdata = {
  +   .probe  = exynos_sysmmu_probe,
  +   .driver = {
  .owner  = THIS_MODULE,
  .name   = exynos-sysmmu,
  +   .of_match_table = of_match_ptr(sysmmu_of_match),
 
 of_match_ptr is not needed for the same reason as above.
 
Ditto.

Thanks.

KyongHo
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v11 19/27] iommu/exynos: add support for power management subsystems.

2014-03-18 Thread Cho KyongHo
On Fri, 14 Mar 2014 17:07:53 +0100, Tomasz Figa wrote:
 Hi KyongHo,
 
 On 14.03.2014 06:10, Cho KyongHo wrote:
  This adds support for Suspend to RAM and Runtime Power Management.
 
  Since System MMU is located in the same local power domain of its
  master H/W, System MMU must be initialized before it is working if
  its power domain was ever turned off. TLB invalidation according to
  unmapping on page tables must also be performed while power domain is
  turned on.
 
  This patch ensures that resume and runtime_resume(restore_state)
  functions in this driver is called before the calls to resume and
  runtime_resume callback functions in the drivers of master H/Ws.
  Likewise, suspend and runtime_suspend(save_state) functions in this
  driver is called after the calls to suspend and runtime_suspend in the
  drivers of master H/Ws.
 
  In order to get benefit of this support, the master H/W and its System
  MMU must resides in the same power domain in terms of Linux kernel. If
  a master H/W does not use generic I/O power domain, its driver must
  call iommu_attach_device() after its local power domain is turned on,
  iommu_detach_device before turned off.
 
  Signed-off-by: Cho KyongHo pullip@samsung.com
  ---
drivers/iommu/exynos-iommu.c |  220 
  ++
1 file changed, 201 insertions(+), 19 deletions(-)
 
  diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
  index 9037da0..84ba29a 100644
  --- a/drivers/iommu/exynos-iommu.c
  +++ b/drivers/iommu/exynos-iommu.c
  @@ -28,6 +28,7 @@
#include linux/export.h
#include linux/of.h
#include linux/of_platform.h
  +#include linux/pm_domain.h
#include linux/notifier.h
 
#include asm/cacheflush.h
  @@ -203,6 +204,7 @@ struct sysmmu_drvdata {
  int activations;
  rwlock_t lock;
  struct iommu_domain *domain;
  +   bool runtime_active;
  unsigned long pgtable;
};
 
  @@ -388,7 +390,8 @@ static bool __sysmmu_disable(struct sysmmu_drvdata 
  *data)
  data-pgtable = 0;
  data-domain = NULL;
 
  -   __sysmmu_disable_nocount(data);
  +   if (data-runtime_active)
  +   __sysmmu_disable_nocount(data);
 
  dev_dbg(data-sysmmu, Disabled\n);
  } else  {
  @@ -449,7 +452,8 @@ static int __sysmmu_enable(struct sysmmu_drvdata *data,
  data-pgtable = pgtable;
  data-domain = domain;
 
  -   __sysmmu_enable_nocount(data);
  +   if (data-runtime_active)
  +   __sysmmu_enable_nocount(data);
 
  dev_dbg(data-sysmmu, Enabled\n);
  } else {
  @@ -534,13 +538,11 @@ static void sysmmu_tlb_invalidate_entry(struct device 
  *dev, unsigned long iova,
  data = dev_get_drvdata(owner-sysmmu);
 
  read_lock_irqsave(data-lock, flags);
  -   if (is_sysmmu_active(data)) {
  -   unsigned int maj;
  +   if (is_sysmmu_active(data)  data-runtime_active) {
  unsigned int num_inv = 1;
 
  __master_clk_enable(data);
 
  -   maj = __raw_readl(data-sfrbase + REG_MMU_VERSION);
  /*
   * L2TLB invalidation required
   * 4KB page: 1 invalidation
  @@ -551,7 +553,7 @@ static void sysmmu_tlb_invalidate_entry(struct device 
  *dev, unsigned long iova,
   * 1MB page can be cached in one of all sets.
   * 64KB page can be one of 16 consecutive sets.
   */
  -   if ((maj  28) == 2) /* major version number */
  +   if (__sysmmu_version(data, NULL) == 2) /* major version number 
  */
  num_inv = min_t(unsigned int, size / PAGE_SIZE, 64);
 
  if (sysmmu_block(data-sfrbase)) {
  @@ -576,7 +578,7 @@ void exynos_sysmmu_tlb_invalidate(struct device *dev)
  data = dev_get_drvdata(owner-sysmmu);
 
  read_lock_irqsave(data-lock, flags);
  -   if (is_sysmmu_active(data)) {
  +   if (is_sysmmu_active(data)  data-runtime_active) {
  __master_clk_enable(data);
  if (sysmmu_block(data-sfrbase)) {
  __sysmmu_tlb_invalidate(data-sfrbase);
  @@ -677,11 +679,40 @@ static int __init exynos_sysmmu_probe(struct 
  platform_device *pdev)
  platform_set_drvdata(pdev, data);
 
  pm_runtime_enable(dev);
  +   data-runtime_active = !pm_runtime_enabled(dev);
 
 Hmm, this seems to be a bit misleading. The field is named 
 runtime_active, but the assignment makes it true if PM runtime is _not_ 
 enabled (i.e. inactive). Is this correct?
 

I agree that it may lead misunderstood.
data-runtime_active actually indicates if electric power is asserted
to the System MMU. pm_runtime_enable() call must enable runtime pm
for the given device. If runtime pm is not enabled although pm_runtime_enable()
is called, CONFIG_PM_RUNTIME is not configured.

Actually, it is replacible with 
if (IS_ENABLED(CONFIG_PM_RUNTIME)) 
data-runtime_active = true;

 
  dev_dbg(dev, Probed

Re: [PATCH v11 20/27] iommu/exynos: allow having multiple System MMUs for a master H/W

2014-03-18 Thread Cho KyongHo
On Fri, 14 Mar 2014 17:12:03 +0100, Tomasz Figa wrote:
 Hi KyongHo,
 
 On 14.03.2014 06:10, Cho KyongHo wrote:
  Some master device descriptor like fimc-is which is an abstraction
  of very complex H/W may have multiple System MMUs. For those devices,
  the design of the link between System MMU and its master H/W is needed
  to be reconsidered.
 
  A link structure, sysmmu_list_data is introduced that provides a link
  to master H/W and that has a pointer to the device descriptor of a
  System MMU. Given a device descriptor of a master H/W, it is possible
  to traverse all System MMUs that must be controlled along with the
  master H/W.
 
 NAK.
 
 A device driver should handle particular hardware instances separately, 
 without abstracting a virtual hardware instance consisting of multiple 
 physical ones.
 
 If such abstraction is needed, it should be done above the exynos-iommu 
 driver, e.g. by something like iommu-composite driver that would 
 aggregate several IOMMUs. Keep in mind that such IOMMUs in a group could 
 be different, e.g. different Exynos SysMMU versions or even completely 
 different IPs handled by different drivers.
 
 Still, I don't think there is a real need for such abstraction. Instead, 
 related drivers shall be fixed to properly handle multiple memory 
 masters and their IOMMUs.
 

G2D, Scalers and FIMD of Exynos5420 has 2 System MMUs while aother SoC like
Exynos5250 does not.

I don't understand why you are negative to this approach.
This is the simplest than the others.

Let me show you an example.
FIMC-IS driver just controls MCU in FIMC-IS subsystem and the firmware of
the MCU controls all other peripherals in the subsystem. Each peripherals
have their own System MMU. Moreover, the configuration of the peripherals
varies according to the SoCs.

If System MMU driver accepts multiple masters, everything is done in DT.
But I worry that it is not easy if System MMU driver does not support
multiple masters. 

Thank you.

KyongHo
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v11 20/27] iommu/exynos: allow having multiple System MMUs for a master H/W

2014-03-18 Thread Cho KyongHo
On Tue, 18 Mar 2014 15:26:48 +0100, Tomasz Figa wrote:
 
 
 On 18.03.2014 14:01, Cho KyongHo wrote:
  On Fri, 14 Mar 2014 17:12:03 +0100, Tomasz Figa wrote:
  Hi KyongHo,
 
  On 14.03.2014 06:10, Cho KyongHo wrote:
  Some master device descriptor like fimc-is which is an abstraction
  of very complex H/W may have multiple System MMUs. For those devices,
  the design of the link between System MMU and its master H/W is needed
  to be reconsidered.
 
  A link structure, sysmmu_list_data is introduced that provides a link
  to master H/W and that has a pointer to the device descriptor of a
  System MMU. Given a device descriptor of a master H/W, it is possible
  to traverse all System MMUs that must be controlled along with the
  master H/W.
 
  NAK.
 
  A device driver should handle particular hardware instances separately,
  without abstracting a virtual hardware instance consisting of multiple
  physical ones.
 
  If such abstraction is needed, it should be done above the exynos-iommu
  driver, e.g. by something like iommu-composite driver that would
  aggregate several IOMMUs. Keep in mind that such IOMMUs in a group could
  be different, e.g. different Exynos SysMMU versions or even completely
  different IPs handled by different drivers.
 
  Still, I don't think there is a real need for such abstraction. Instead,
  related drivers shall be fixed to properly handle multiple memory
  masters and their IOMMUs.
 
 
  G2D, Scalers and FIMD of Exynos5420 has 2 System MMUs while aother SoC like
  Exynos5250 does not.
 
  I don't understand why you are negative to this approach.
  This is the simplest than the others.
 
  Let me show you an example.
  FIMC-IS driver just controls MCU in FIMC-IS subsystem and the firmware of
  the MCU controls all other peripherals in the subsystem. Each peripherals
  have their own System MMU. Moreover, the configuration of the peripherals
  varies according to the SoCs.
 
  If System MMU driver accepts multiple masters, everything is done in DT.
  But I worry that it is not easy if System MMU driver does not support
  multiple masters.
 
 I believe I have stated enough reasons why this kind of implementation 
 is bad. I'm not going to waste time repeating myself.
 
 Your concerns presented above are valid, however they are not related to 
 what is wrong with this patch. I have given you two proper ways to 
 handle this, none should be forced upon particular IOMMU master drivers 
 - their authors should have the chance to select the method that works 
 best for them.
 

I don't still understand why you think this patch is wrong.
I think this is the best way not to think for all the driver developers
about other things than their business logic.

This does not hurt anyone and I think this is good enough.

If you want to provide another layer between master device and system mmu
as you mentioned, you do that. This patch does not restrict it.

Regards,

KyongHo

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v11 17/27] iommu/exynos: remove calls to Runtime PM API functions

2014-03-18 Thread Cho KyongHo
On Tue, 18 Mar 2014 16:09:50 +0100, Tomasz Figa wrote:
 On 18.03.2014 10:56, Cho KyongHo wrote:
  On Fri, 14 Mar 2014 13:59:00 +0100, Tomasz Figa wrote:
  Hi KyongHo,
 
  On 14.03.2014 06:08, Cho KyongHo wrote:
 
 [snip]
 
  -static bool __exynos_sysmmu_disable(struct sysmmu_drvdata *data)
  +static void __sysmmu_disable_nocount(struct sysmmu_drvdata *data)
 
  If you are changing the names anyway, it would be probably a good idea
  to reduce code obfuscation a bit and drop the underscores from
  beginnings of function names. Also I'd suggest keeping the exynos_ 
  prefix.
 
  Thanks for the suggestion.
  __exynos_sysmmu_disable is splitted into 2 functions: __sysmmu_disable
  and __sysmmu_disable_nocount.
  I agree with you that it is good idea to reduce code obfuscation but
  I don't think dropping beginning underscores of function names reduces
  obfuscation.
 
 
 Well, if you are ending up with a function like 
 __sysmmu_enable_nocount() below with every line starting with two 
 underscores, do you think this improves code readability?
 
 Of course this is a minor issue, but let's keep some code quality level 
 in Linux kernel.
 

Ok. understood what your are concerning about.

 
 {
  - unsigned long flags;
  - bool disabled = false;
  -
  - write_lock_irqsave(data-lock, flags);
 
 [snip]
 
 Here's the function mentioned above:
 
  +
  +static void __sysmmu_enable_nocount(struct sysmmu_drvdata *data)
  +{
  + __master_clk_enable(data);
  + __sysmmu_clk_enable(data);
  +
  + __raw_writel(CTRL_BLOCK, data-sfrbase + REG_MMU_CTRL);
  +
  + __sysmmu_init_config(data);
  +
  + __sysmmu_set_ptbase(data-sfrbase, data-pgtable);
  +
  + __raw_writel(CTRL_ENABLE, data-sfrbase + REG_MMU_CTRL);
  +
  + __master_clk_disable(data);
  +}
  +
 
 [snip]
 
 
  @@ -629,7 +700,7 @@ err_pgtable:
 static void exynos_iommu_domain_destroy(struct iommu_domain *domain)
 {
struct exynos_iommu_domain *priv = domain-priv;
  - struct sysmmu_drvdata *data;
  + struct exynos_iommu_owner *owner;
unsigned long flags;
int i;
 
  @@ -637,11 +708,14 @@ static void exynos_iommu_domain_destroy(struct 
  iommu_domain *domain)
 
spin_lock_irqsave(priv-lock, flags);
 
  - list_for_each_entry(data, priv-clients, node) {
  - while (!exynos_sysmmu_disable(data-dev))
  + list_for_each_entry(owner, priv-clients, client) {
  + while (!exynos_sysmmu_disable(owner-dev))
; /* until System MMU is actually disabled */
 
  What about using list_for_each_entry_safe() and calling list_del_init()
  here directly?
 
 
  That require another variable to be defined.
 
 Is it a problem?
 
That is not a problem.
But I think using list_for_each_entry() is not a problem likewise.

  I just wanted to avoid that because I think it is prettier.
  Moreover, list_del_init() below the empty while() clause may make
  the source code readers misunderstood..
 
 This raises another question, why the loop above is even needed. 
 exynos_sysmmu_disable() should make sure that SYSMMU is actually 
 disabled, without any need for looping like this.

Some driver needs enabling sysmmu to be counted due to its complex structure.
It can be also removed by the driver with an extra effort
but the reality is important.
Device driver is not only for the scholarship but also for the real use.

}
 
  + while (!list_empty(priv-clients))
  + list_del_init(priv-clients.next);
  +
spin_unlock_irqrestore(priv-lock, flags);
 
for (i = 0; i  NUM_LV1ENTRIES; i++)
 
 [snip]
 
  +static int sysmmu_hook_driver_register(struct notifier_block *nb,
  + unsigned long val,
  + void *p)
  +{
  + struct device *dev = p;
  +
  + switch (val) {
  + case BUS_NOTIFY_BIND_DRIVER:
  + {
  + struct exynos_iommu_owner *owner;
 
  Please move this variable to the top of the function and drop the braces
  around case blocks.
 
  I don't think it is required because this function is modified
  by the following patches.
 
 OK, if so, and similar issue is not present after further patches.
 
 
 
  +
  + /* No System MMU assigned. See exynos_sysmmu_probe(). */
  + if (dev-archdata.iommu == NULL)
  + break;
 
  This looks strange... (see below)
 
  Also this looks racy. There are no guarantees about device probing
  order, so you may end up with master devices being probed before the
  IOMMUs. Deferred probing should be used to handle this correctly.
 
  System MMU driver must be probed earlier than the drivers of master devices
  because the drivers may want to use System MMU for their initial task.
 
 As I said, there are no guarantees about platform device probe order in 
 Linux kernel. Code must be designed to check whether required 
 dependencies are met and if not, deferred probing must be used.
 

I told that System MMU driver must be probed earlier.
That's why

Re: [PATCH v11 01/27] iommu/exynos: do not include removed header

2014-03-16 Thread Cho KyongHo
On Fri, 14 Mar 2014 17:29:36 +0530, Sachin Kamat wrote:
 On 14 March 2014 17:19, Cho KyongHo pullip@samsung.com wrote:
  From: Sachin Kamat [mailto:sachin.ka...@linaro.org]
  Sent: Friday, March 14, 2014 7:00 PM
 
  On 14 March 2014 10:31, Cho KyongHo pullip@samsung.com wrote:
   Commit 25e9d28d92 (ARM: EXYNOS: remove system mmu initialization from
   exynos tree) removed arch/arm/mach-exynos/mach/sysmmu.h header without
   removing remaining use of it from exynos-iommu driver, thus causing a
   compilation error.
  
   This patch fixes the error by removing respective include line
   from exynos-iommu.c.
  
   CC: Tomasz Figa t.f...@samsung.com
   Signed-off-by: Cho KyongHo pullip@samsung.com
   ---
drivers/iommu/exynos-iommu.c |3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
  
   diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
   index 0740189..4876d35 100644
   --- a/drivers/iommu/exynos-iommu.c
   +++ b/drivers/iommu/exynos-iommu.c
   @@ -12,6 +12,7 @@
#define DEBUG
#endif
  
   +#include linux/kernel.h
 
  This change doesn't look related to the patch subject/description.
 
  Yes. But it is simply added without any side-effect.
  Do you think it should be in a separate patch?.
  Actually, the added line is a redundant.
 
 If it is redundant, then you shouldn't be adding it. If it is
 required, then please
 mention about the need in the commit description if not a separate patch.
 

Ok.

Thanks for the advice.

KyongHo
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


RE: [PATCH v11 01/27] iommu/exynos: do not include removed header

2014-03-14 Thread Cho KyongHo
 From: Sachin Kamat [mailto:sachin.ka...@linaro.org]
 Sent: Friday, March 14, 2014 7:00 PM
 
 On 14 March 2014 10:31, Cho KyongHo pullip@samsung.com wrote:
  Commit 25e9d28d92 (ARM: EXYNOS: remove system mmu initialization from
  exynos tree) removed arch/arm/mach-exynos/mach/sysmmu.h header without
  removing remaining use of it from exynos-iommu driver, thus causing a
  compilation error.
 
  This patch fixes the error by removing respective include line
  from exynos-iommu.c.
 
  CC: Tomasz Figa t.f...@samsung.com
  Signed-off-by: Cho KyongHo pullip@samsung.com
  ---
   drivers/iommu/exynos-iommu.c |3 +--
   1 file changed, 1 insertion(+), 2 deletions(-)
 
  diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
  index 0740189..4876d35 100644
  --- a/drivers/iommu/exynos-iommu.c
  +++ b/drivers/iommu/exynos-iommu.c
  @@ -12,6 +12,7 @@
   #define DEBUG
   #endif
 
  +#include linux/kernel.h
 
 This change doesn't look related to the patch subject/description.
 
Yes. But it is simply added without any side-effect.
Do you think it should be in a separate patch?.
Actually, the added line is a redundant.

Regards,

KyongHo.

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v11 01/27] iommu/exynos: do not include removed header

2014-03-13 Thread Cho KyongHo
Commit 25e9d28d92 (ARM: EXYNOS: remove system mmu initialization from
exynos tree) removed arch/arm/mach-exynos/mach/sysmmu.h header without
removing remaining use of it from exynos-iommu driver, thus causing a
compilation error.

This patch fixes the error by removing respective include line
from exynos-iommu.c.

CC: Tomasz Figa t.f...@samsung.com
Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 0740189..4876d35 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -12,6 +12,7 @@
 #define DEBUG
 #endif
 
+#include linux/kernel.h
 #include linux/io.h
 #include linux/interrupt.h
 #include linux/platform_device.h
@@ -29,8 +30,6 @@
 #include asm/cacheflush.h
 #include asm/pgtable.h
 
-#include mach/sysmmu.h
-
 /* We does not consider super section mapping (16MB) */
 #define SECT_ORDER 20
 #define LPAGE_ORDER 16
-- 
1.7.9.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v11 04/27] iommu/exynos: fix L2TLB invalidation

2014-03-13 Thread Cho KyongHo
L2TLB is 8-way set-associative TLB with 512 entries. The number of
sets is 64.
A single 4KB(small page) translation information is cached
only to a set whose index is the same with the lower 6 bits of the page
frame number.
A single 64KB(large page) translation information can be
cached to any 16 sets whose top two bits of their indices are the same
with the bit [5:4] of the page frame number.
A single 1MB(section) or larger translation information can be cached to
any set in the TLB.

It is required to invalidate entire sets that may cache the target
translation information to guarantee that the L2TLB has no stale data.

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |   31 ++-
 1 file changed, 26 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 4a74ed8..0d26aeb 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -225,9 +225,14 @@ static void __sysmmu_tlb_invalidate(void __iomem *sfrbase)
 }
 
 static void __sysmmu_tlb_invalidate_entry(void __iomem *sfrbase,
-   unsigned long iova)
+   unsigned long iova, unsigned int num_inv)
 {
-   __raw_writel((iova  SPAGE_MASK) | 1, sfrbase + REG_MMU_FLUSH_ENTRY);
+   unsigned int i;
+   for (i = 0; i  num_inv; i++) {
+   __raw_writel((iova  SPAGE_MASK) | 1,
+   sfrbase + REG_MMU_FLUSH_ENTRY);
+   iova += SPAGE_SIZE;
+   }
 }
 
 static void __sysmmu_set_ptbase(void __iomem *sfrbase,
@@ -477,7 +482,8 @@ static bool exynos_sysmmu_disable(struct device *dev)
return disabled;
 }
 
-static void sysmmu_tlb_invalidate_entry(struct device *dev, unsigned long iova)
+static void sysmmu_tlb_invalidate_entry(struct device *dev, unsigned long iova,
+   size_t size)
 {
unsigned long flags;
struct sysmmu_drvdata *data = dev_get_drvdata(dev-archdata.iommu);
@@ -487,9 +493,24 @@ static void sysmmu_tlb_invalidate_entry(struct device 
*dev, unsigned long iova)
if (is_sysmmu_active(data)) {
int i;
for (i = 0; i  data-nsfrs; i++) {
+   unsigned int maj;
+   unsigned int num_inv = 1;
+   maj = __raw_readl(data-sfrbases[i] + REG_MMU_VERSION);
+   /*
+* L2TLB invalidation required
+* 4KB page: 1 invalidation
+* 64KB page: 16 invalidation
+* 1MB page: 64 invalidation
+* because it is set-associative TLB
+* with 8-way and 64 sets.
+* 1MB page can be cached in one of all sets.
+* 64KB page can be one of 16 consecutive sets.
+*/
+   if ((maj  28) == 2) /* major version number */
+   num_inv = min_t(unsigned int, size / PAGE_SIZE, 
64);
if (sysmmu_block(data-sfrbases[i])) {
__sysmmu_tlb_invalidate_entry(
-   data-sfrbases[i], iova);
+   data-sfrbases[i], iova, num_inv);
sysmmu_unblock(data-sfrbases[i]);
}
}
@@ -999,7 +1020,7 @@ done:
 
spin_lock_irqsave(priv-lock, flags);
list_for_each_entry(data, priv-clients, node)
-   sysmmu_tlb_invalidate_entry(data-dev, iova);
+   sysmmu_tlb_invalidate_entry(data-dev, iova, size);
spin_unlock_irqrestore(priv-lock, flags);
 
return size;
-- 
1.7.9.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v11 02/27] iommu/exynos: add missing cache flush for removed page table entries

2014-03-13 Thread Cho KyongHo
This commit adds cache flush for removed small and large page entries
in exynos_iommu_unmap(). Missing cache flush of removed page table
entries can cause missing page fault interrupt when a master IP
accesses an unmapped area.

Reviewed-by: Tomasz Figa t.f...@samsung.com
Tested-by: Grant Grundler grund...@chromium.org
Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 4876d35..1c3a397 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -958,6 +958,7 @@ static size_t exynos_iommu_unmap(struct iommu_domain 
*domain,
if (lv2ent_small(ent)) {
*ent = 0;
size = SPAGE_SIZE;
+   pgtable_flush(ent, ent + 1);
priv-lv2entcnt[lv1ent_offset(iova)] += 1;
goto done;
}
@@ -966,6 +967,7 @@ static size_t exynos_iommu_unmap(struct iommu_domain 
*domain,
BUG_ON(size  LPAGE_SIZE);
 
memset(ent, 0, sizeof(*ent) * SPAGES_PER_LPAGE);
+   pgtable_flush(ent, ent + SPAGES_PER_LPAGE);
 
size = LPAGE_SIZE;
priv-lv2entcnt[lv1ent_offset(iova)] += SPAGES_PER_LPAGE;
-- 
1.7.9.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v11 03/27] iommu/exynos: change error handling when page table update is failed

2014-03-13 Thread Cho KyongHo
This patch changes not to panic on any error when updating page table.
Instead prints error messages with callstack.

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |   58 --
 1 file changed, 44 insertions(+), 14 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 1c3a397..4a74ed8 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -812,13 +812,18 @@ finish:
 static unsigned long *alloc_lv2entry(unsigned long *sent, unsigned long iova,
short *pgcounter)
 {
+   if (lv1ent_section(sent)) {
+   WARN(1, Trying mapping on %#08lx mapped with 1MiB page, iova);
+   return ERR_PTR(-EADDRINUSE);
+   }
+
if (lv1ent_fault(sent)) {
unsigned long *pent;
 
pent = kzalloc(LV2TABLE_SIZE, GFP_ATOMIC);
BUG_ON((unsigned long)pent  (LV2TABLE_SIZE - 1));
if (!pent)
-   return NULL;
+   return ERR_PTR(-ENOMEM);
 
*sent = mk_lv1ent_page(__pa(pent));
*pgcounter = NUM_LV2ENTRIES;
@@ -829,14 +834,21 @@ static unsigned long *alloc_lv2entry(unsigned long *sent, 
unsigned long iova,
return page_entry(sent, iova);
 }
 
-static int lv1set_section(unsigned long *sent, phys_addr_t paddr, short *pgcnt)
+static int lv1set_section(unsigned long *sent, unsigned long iova,
+ phys_addr_t paddr, short *pgcnt)
 {
-   if (lv1ent_section(sent))
+   if (lv1ent_section(sent)) {
+   WARN(1, Trying mapping on 1MiB@%#08lx that is mapped,
+   iova);
return -EADDRINUSE;
+   }
 
if (lv1ent_page(sent)) {
-   if (*pgcnt != NUM_LV2ENTRIES)
+   if (*pgcnt != NUM_LV2ENTRIES) {
+   WARN(1, Trying mapping on 1MiB@%#08lx that is mapped,
+   iova);
return -EADDRINUSE;
+   }
 
kfree(page_entry(sent, 0));
 
@@ -854,8 +866,10 @@ static int lv2set_page(unsigned long *pent, phys_addr_t 
paddr, size_t size,
short *pgcnt)
 {
if (size == SPAGE_SIZE) {
-   if (!lv2ent_fault(pent))
+   if (!lv2ent_fault(pent)) {
+   WARN(1, Trying mapping on 4KiB where mapping exists);
return -EADDRINUSE;
+   }
 
*pent = mk_lv2ent_spage(paddr);
pgtable_flush(pent, pent + 1);
@@ -864,7 +878,10 @@ static int lv2set_page(unsigned long *pent, phys_addr_t 
paddr, size_t size,
int i;
for (i = 0; i  SPAGES_PER_LPAGE; i++, pent++) {
if (!lv2ent_fault(pent)) {
-   memset(pent, 0, sizeof(*pent) * i);
+   WARN(1,
+   Trying mapping on 64KiB where mapping exists);
+   if (i  0)
+   memset(pent - i, 0, sizeof(*pent) * i);
return -EADDRINUSE;
}
 
@@ -892,7 +909,7 @@ static int exynos_iommu_map(struct iommu_domain *domain, 
unsigned long iova,
entry = section_entry(priv-pgtable, iova);
 
if (size == SECT_SIZE) {
-   ret = lv1set_section(entry, paddr,
+   ret = lv1set_section(entry, iova, paddr,
priv-lv2entcnt[lv1ent_offset(iova)]);
} else {
unsigned long *pent;
@@ -900,17 +917,16 @@ static int exynos_iommu_map(struct iommu_domain *domain, 
unsigned long iova,
pent = alloc_lv2entry(entry, iova,
priv-lv2entcnt[lv1ent_offset(iova)]);
 
-   if (!pent)
-   ret = -ENOMEM;
+   if (IS_ERR(pent))
+   ret = PTR_ERR(pent);
else
ret = lv2set_page(pent, paddr, size,
priv-lv2entcnt[lv1ent_offset(iova)]);
}
 
-   if (ret) {
+   if (ret)
pr_debug(%s: Failed to map iova 0x%lx/0x%x bytes\n,
__func__, iova, size);
-   }
 
spin_unlock_irqrestore(priv-pgtablelock, flags);
 
@@ -924,6 +940,7 @@ static size_t exynos_iommu_unmap(struct iommu_domain 
*domain,
struct sysmmu_drvdata *data;
unsigned long flags;
unsigned long *ent;
+   size_t err_pgsize;
 
BUG_ON(priv-pgtable == NULL);
 
@@ -932,7 +949,10 @@ static size_t exynos_iommu_unmap(struct iommu_domain 
*domain,
ent = section_entry(priv-pgtable, iova);
 
if (lv1ent_section(ent)) {
-   BUG_ON(size  SECT_SIZE

[PATCH v11 05/27] iommu/exynos: remove prefetch buffer setting

2014-03-13 Thread Cho KyongHo
Prefetch buffer is a cache of System MMU 3.x and caches a block of
page table entries to make effect of larger page with small pages.
However, how to control prefetch buffers and the specifications of
prefetch buffers different from minor versions of System MMU v3.
Prefetch buffers must be controled with care because there are some
restrictions in H/W design.

The interface and implementation to initiate prefetch buffers will
be prepared later.

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |   16 
 1 file changed, 16 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 0d26aeb..647fc46 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -244,13 +244,6 @@ static void __sysmmu_set_ptbase(void __iomem *sfrbase,
__sysmmu_tlb_invalidate(sfrbase);
 }
 
-static void __sysmmu_set_prefbuf(void __iomem *sfrbase, unsigned long base,
-   unsigned long size, int idx)
-{
-   __raw_writel(base, sfrbase + REG_PB0_SADDR + idx * 8);
-   __raw_writel(size - 1 + base,  sfrbase + REG_PB0_EADDR + idx * 8);
-}
-
 static void __set_fault_handler(struct sysmmu_drvdata *data,
sysmmu_fault_handler_t handler)
 {
@@ -424,15 +417,6 @@ static int __exynos_sysmmu_enable(struct sysmmu_drvdata 
*data,
 
for (i = 0; i  data-nsfrs; i++) {
__sysmmu_set_ptbase(data-sfrbases[i], pgtable);
-
-   if ((readl(data-sfrbases[i] + REG_MMU_VERSION)  28) == 3) {
-   /* System MMU version is 3.x */
-   __raw_writel((1  12) | (2  28),
-   data-sfrbases[i] + REG_MMU_CFG);
-   __sysmmu_set_prefbuf(data-sfrbases[i], 0, -1, 0);
-   __sysmmu_set_prefbuf(data-sfrbases[i], 0, -1, 1);
-   }
-
__raw_writel(CTRL_ENABLE, data-sfrbases[i] + REG_MMU_CTRL);
}
 
-- 
1.7.9.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v11 06/27] iommu/exynos: allocate lv2 page table from own slab

2014-03-13 Thread Cho KyongHo
Since kmalloc() does not guarantee that the allignment of 1KiB when it
allocates 1KiB, it is required to allocate lv2 page table from own
slab that guarantees alignment of 1KiB

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |   34 --
 1 file changed, 28 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 647fc46..bee1bb1 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -100,6 +100,8 @@
 #define REG_PB1_SADDR  0x054
 #define REG_PB1_EADDR  0x058
 
+static struct kmem_cache *lv2table_kmem_cache;
+
 static unsigned long *section_entry(unsigned long *pgtable, unsigned long iova)
 {
return pgtable + lv1ent_offset(iova);
@@ -726,7 +728,8 @@ static void exynos_iommu_domain_destroy(struct iommu_domain 
*domain)
 
for (i = 0; i  NUM_LV1ENTRIES; i++)
if (lv1ent_page(priv-pgtable + i))
-   kfree(__va(lv2table_base(priv-pgtable + i)));
+   kmem_cache_free(lv2table_kmem_cache,
+   __va(lv2table_base(priv-pgtable + i)));
 
free_pages((unsigned long)priv-pgtable, 2);
free_pages((unsigned long)priv-lv2entcnt, 1);
@@ -825,7 +828,7 @@ static unsigned long *alloc_lv2entry(unsigned long *sent, 
unsigned long iova,
if (lv1ent_fault(sent)) {
unsigned long *pent;
 
-   pent = kzalloc(LV2TABLE_SIZE, GFP_ATOMIC);
+   pent = kmem_cache_zalloc(lv2table_kmem_cache, GFP_ATOMIC);
BUG_ON((unsigned long)pent  (LV2TABLE_SIZE - 1));
if (!pent)
return ERR_PTR(-ENOMEM);
@@ -855,8 +858,7 @@ static int lv1set_section(unsigned long *sent, unsigned 
long iova,
return -EADDRINUSE;
}
 
-   kfree(page_entry(sent, 0));
-
+   kmem_cache_free(lv2table_kmem_cache, page_entry(sent, 0));
*pgcnt = 0;
}
 
@@ -1061,11 +1063,31 @@ static int __init exynos_iommu_init(void)
 {
int ret;
 
+   lv2table_kmem_cache = kmem_cache_create(exynos-iommu-lv2table,
+   LV2TABLE_SIZE, LV2TABLE_SIZE, 0, NULL);
+   if (!lv2table_kmem_cache) {
+   pr_err(%s: Failed to create kmem cache\n, __func__);
+   return -ENOMEM;
+   }
+
ret = platform_driver_register(exynos_sysmmu_driver);
+   if (ret) {
+   pr_err(%s: Failed to register driver\n, __func__);
+   goto err_reg_driver;
+   }
 
-   if (ret == 0)
-   bus_set_iommu(platform_bus_type, exynos_iommu_ops);
+   ret = bus_set_iommu(platform_bus_type, exynos_iommu_ops);
+   if (ret) {
+   pr_err(%s: Failed to register exynos-iommu driver.\n,
+   __func__);
+   goto err_set_iommu;
+   }
 
+   return 0;
+err_set_iommu:
+   platform_driver_unregister(exynos_sysmmu_driver);
+err_reg_driver:
+   kmem_cache_destroy(lv2table_kmem_cache);
return ret;
 }
 subsys_initcall(exynos_iommu_init);
-- 
1.7.9.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v11 07/27] iommu/exynos: always enable runtime PM

2014-03-13 Thread Cho KyongHo
Checking if the probing device has a parent device was just to discover
if the probing device is involved in a power domain when the power
domain controlled by Samsung's custom implementation.
Since generic IO power domain is applied, it is required to remove
the condition to see if the probing device has a parent device.

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index bee1bb1..8dc7031 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -632,8 +632,7 @@ static int exynos_sysmmu_probe(struct platform_device *pdev)
 
__set_fault_handler(data, default_fault_handler);
 
-   if (dev-parent)
-   pm_runtime_enable(dev);
+   pm_runtime_enable(dev);
 
dev_dbg(dev, (%s) Initialized\n, data-dbgname);
return 0;
-- 
1.7.9.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v11 09/27] iommu/exynos: remove dbgname from drvdata of a System MMU

2014-03-13 Thread Cho KyongHo
This patch removes dbgname member from sysmmu_drvdata structure.
Kernel message for debugging already has the name of a single
System MMU node.

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |   32 +---
 1 file changed, 13 insertions(+), 19 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index a4499b2..36e6b73 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -170,7 +170,6 @@ struct sysmmu_drvdata {
struct list_head node; /* entry of exynos_iommu_domain.clients */
struct device *sysmmu;  /* System MMU's device descriptor */
struct device *dev; /* Owner of system MMU */
-   char *dbgname;
void __iomem *sfrbase;
struct clk *clk;
int activations;
@@ -321,8 +320,8 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
if (!ret  (itype != SYSMMU_FAULT_UNKNOWN))
__raw_writel(1  itype, data-sfrbase + REG_INT_CLEAR);
else
-   dev_dbg(data-sysmmu, (%s) %s is not handled.\n,
-   data-dbgname, sysmmu_fault_name[itype]);
+   dev_dbg(data-sysmmu, %s is not handled.\n,
+   sysmmu_fault_name[itype]);
 
if (itype != SYSMMU_FAULT_UNKNOWN)
sysmmu_unblock(data-sfrbase);
@@ -354,10 +353,10 @@ finish:
write_unlock_irqrestore(data-lock, flags);
 
if (disabled)
-   dev_dbg(data-sysmmu, (%s) Disabled\n, data-dbgname);
+   dev_dbg(data-sysmmu, Disabled\n);
else
-   dev_dbg(data-sysmmu, (%s) %d times left to be disabled\n,
-   data-dbgname, data-activations);
+   dev_dbg(data-sysmmu, %d times left to be disabled\n,
+   data-activations);
 
return disabled;
 }
@@ -384,7 +383,7 @@ static int __exynos_sysmmu_enable(struct sysmmu_drvdata 
*data,
ret = 1;
}
 
-   dev_dbg(data-sysmmu, (%s) Already enabled\n, data-dbgname);
+   dev_dbg(data-sysmmu, Already enabled\n);
goto finish;
}
 
@@ -399,7 +398,7 @@ static int __exynos_sysmmu_enable(struct sysmmu_drvdata 
*data,
 
data-domain = domain;
 
-   dev_dbg(data-sysmmu, (%s) Enabled\n, data-dbgname);
+   dev_dbg(data-sysmmu, Enabled\n);
 finish:
write_unlock_irqrestore(data-lock, flags);
 
@@ -415,16 +414,15 @@ int exynos_sysmmu_enable(struct device *dev, unsigned 
long pgtable)
 
ret = pm_runtime_get_sync(data-sysmmu);
if (ret  0) {
-   dev_dbg(data-sysmmu, (%s) Failed to enable\n, data-dbgname);
+   dev_dbg(data-sysmmu, Failed to enable\n);
return ret;
}
 
ret = __exynos_sysmmu_enable(data, pgtable, NULL);
if (WARN_ON(ret  0)) {
pm_runtime_put(data-sysmmu);
-   dev_err(data-sysmmu,
-   (%s) Already enabled with page table %#lx\n,
-   data-dbgname, data-pgtable);
+   dev_err(data-sysmmu, Already enabled with page table %#lx\n,
+   data-pgtable);
} else {
data-dev = dev;
}
@@ -474,9 +472,7 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, 
unsigned long iova,
sysmmu_unblock(data-sfrbase);
}
} else {
-   dev_dbg(data-sysmmu,
-   (%s) Disabled. Skipping invalidating TLB.\n,
-   data-dbgname);
+   dev_dbg(data-sysmmu, Disabled. Skipping invalidating TLB.\n);
}
 
read_unlock_irqrestore(data-lock, flags);
@@ -495,9 +491,7 @@ void exynos_sysmmu_tlb_invalidate(struct device *dev)
sysmmu_unblock(data-sfrbase);
}
} else {
-   dev_dbg(data-sysmmu,
-   (%s) Disabled. Skipping invalidating TLB.\n,
-   data-dbgname);
+   dev_dbg(data-sysmmu, Disabled. Skipping invalidating TLB.\n);
}
 
read_unlock_irqrestore(data-lock, flags);
@@ -562,7 +556,7 @@ static int exynos_sysmmu_probe(struct platform_device *pdev)
 
pm_runtime_enable(dev);
 
-   dev_dbg(dev, (%s) Initialized\n, data-dbgname);
+   dev_dbg(dev, Initialized\n);
return 0;
 err_irq:
free_irq(platform_get_irq(pdev, 0), data);
-- 
1.7.9.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v11 11/27] clk: exynos: add gate clock descriptions of System MMU

2014-03-13 Thread Cho KyongHo
This adds gate clocks of all System MMUs and their master IPs
that are not apeared in clk-exynos5250.c and clk-exynos5420.c
Also fixes GATE_IP_ACP to 0x18800 and changed GATE_DA to GATE
for System MMU clocks in clk-exynos4.c

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 .../devicetree/bindings/clock/exynos5250-clock.txt |3 +++
 .../devicetree/bindings/clock/exynos5420-clock.txt |6 +-
 drivers/clk/samsung/clk-exynos5250.c   |5 +
 drivers/clk/samsung/clk-exynos5420.c   |   13 +++--
 include/dt-bindings/clock/exynos5250.h |4 
 include/dt-bindings/clock/exynos5420.h |6 +-
 6 files changed, 33 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt 
b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
index 72ce617..67e50ba 100644
--- a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
+++ b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
@@ -162,6 +162,9 @@ clock which they consume.
   g2d  345
   mdma0346
   smmu_mdma0   347
+  smmu_tv  348
+  smmu_fimd1   349
+  smmu_2d  350
 
 
[Clock Muxes]
diff --git a/Documentation/devicetree/bindings/clock/exynos5420-clock.txt 
b/Documentation/devicetree/bindings/clock/exynos5420-clock.txt
index 458f347..62dabc3 100644
--- a/Documentation/devicetree/bindings/clock/exynos5420-clock.txt
+++ b/Documentation/devicetree/bindings/clock/exynos5420-clock.txt
@@ -146,7 +146,8 @@ clock which they consume.
   hdmi 413
   aclk300_disp1420
   fimd1421
-  smmu_fimd1   422
+  smmu_fimd1m0 422
+  smmu_fimd1m1 423
   aclk166  430
   mixer431
   aclk266  440
@@ -172,12 +173,15 @@ clock which they consume.
   mdma0473
   aclk333_g2d  480
   g2d  481
+  smmu_g2d 482
   aclk333_432_gscl 490
   smmu_3aa 491
   smmu_fimcl0  492
   smmu_fimcl1  493
   smmu_fimcl3  494
   fimc_lite3   495
+  fimc_lite0   496
+  fimc_lite1   497
   aclk_g3d 500
   g3d  501
   smmu_mixer   502
diff --git a/drivers/clk/samsung/clk-exynos5250.c 
b/drivers/clk/samsung/clk-exynos5250.c
index e7ee442..6605733 100644
--- a/drivers/clk/samsung/clk-exynos5250.c
+++ b/drivers/clk/samsung/clk-exynos5250.c
@@ -615,6 +615,11 @@ static struct samsung_gate_clock exynos5250_gate_clks[] 
__initdata = {
GATE(CLK_WDT, wdt, div_aclk66, GATE_IP_PERIS, 19, 0, 0),
GATE(CLK_RTC, rtc, div_aclk66, GATE_IP_PERIS, 20, 0, 0),
GATE(CLK_TMU, tmu, div_aclk66, GATE_IP_PERIS, 21, 0, 0),
+   GATE(CLK_SMMU_TV, smmu_tv, mout_aclk200_disp1_sub,
+   GATE_IP_DISP1, 2, 0, 0),
+   GATE(CLK_SMMU_FIMD1, smmu_fimd1, mout_aclk200_disp1_sub,
+   GATE_IP_DISP1, 8, 0, 0),
+   GATE(CLK_SMMU_2D, smmu_2d, div_aclk200, GATE_IP_ACP, 7, 0, 0),
 };
 
 static struct samsung_pll_rate_table vpll_24mhz_tbl[] __initdata = {
diff --git a/drivers/clk/samsung/clk-exynos5420.c 
b/drivers/clk/samsung/clk-exynos5420.c
index 60b2681..b58e4d3 100644
--- a/drivers/clk/samsung/clk-exynos5420.c
+++ b/drivers/clk/samsung/clk-exynos5420.c
@@ -82,6 +82,7 @@
 #define GATE_BUS_PERIC10x10754
 #define GATE_BUS_PERIS00x10760
 #define GATE_BUS_PERIS10x10764
+#define GATE_IP_G2D0x08800
 #define GATE_IP_GSCL0  0x10910
 #define GATE_IP_GSCL1  0x10920
 #define GATE_IP_MFC0x1092c
@@ -707,6 +708,10 @@ static struct samsung_gate_clock exynos5420_gate_clks[] 
__initdata = {
GATE(CLK_GSCL_WB, gscl_wb, aclk300_gscl, GATE_IP_GSCL1, 13, 0, 0),
GATE(CLK_SMMU_FIMCL3, smmu_fimcl3,, aclk333_432_gscl,
GATE_IP_GSCL1, 16, 0, 0),
+   GATE(CLK_FIMC_LITE0, fimc_lite0, aclk333_432_gscl,
+   GATE_IP_GSCL0, 5, 0, 0),
+   GATE(CLK_FIMC_LITE1, fimc_lite1, aclk333_432_gscl,
+   GATE_IP_GSCL0, 6, 0, 0),
GATE(CLK_FIMC_LITE3, fimc_lite3, aclk333_432_gscl,
GATE_IP_GSCL1, 17, 0, 0),
 
@@ -715,8 +720,10 @@ static struct samsung_gate_clock exynos5420_gate_clks[] 
__initdata = {
GATE(CLK_DP1, dp1, aclk200_disp1, GATE_IP_DISP1, 4, 0, 0),
GATE(CLK_MIXER, mixer, aclk166, GATE_IP_DISP1, 5, 0, 0),
GATE(CLK_HDMI, hdmi, aclk200_disp1, GATE_IP_DISP1, 6, 0, 0),
-   GATE(CLK_SMMU_FIMD1, smmu_fimd1, aclk300_disp1, GATE_IP_DISP1, 8, 0,
-   0),
+   GATE(CLK_SMMU_FIMD1M0, smmu_fimd1m0, aclk300_disp1, GATE_IP_DISP1,
+   7, 0, 0),
+   GATE(CLK_SMMU_FIMD1M1, smmu_fimd1m1, aclk300_disp1, GATE_IP_DISP1,
+   8, 0, 0),
 
GATE(CLK_MFC, mfc, aclk333

[PATCH v11 12/27] ARM: dts: Add description of System MMU of Exynos SoCs

2014-03-13 Thread Cho KyongHo
This patch adds dts entries for the System MMU devices found on
Exynos4 and Exynos5 SoC series and the System MMU binding
documentation.

CC: Rob Herring robherri...@gmail.com
CC: Sylwester Nawrocki s.nawro...@samsung.com
Signed-off-by: Cho KyongHo pullip@samsung.com
---
 .../bindings/iommu/samsung,exynos4210-sysmmu.txt   |   86 +++
 arch/arm/boot/dts/exynos4.dtsi |  107 
 arch/arm/boot/dts/exynos4210.dtsi  |   23 +-
 arch/arm/boot/dts/exynos4x12.dtsi  |   77 +-
 arch/arm/boot/dts/exynos5250.dtsi  |  266 +++-
 arch/arm/boot/dts/exynos5420.dtsi  |  205 ++-
 6 files changed, 758 insertions(+), 6 deletions(-)
 create mode 100644 
Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.txt

diff --git 
a/Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.txt 
b/Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.txt
new file mode 100644
index 000..e4417bb
--- /dev/null
+++ b/Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.txt
@@ -0,0 +1,86 @@
+Samsung Exynos IOMMU H/W, System MMU (System Memory Management Unit)
+
+Samsung's Exynos architecture contains System MMUs that enables scattered
+physical memory chunks visible as a contiguous region to DMA-capable peripheral
+devices like MFC, FIMC, FIMD, GScaler, FIMC-IS and so forth.
+
+System MMU is an IOMMU and supports identical translation table format to
+ARMv7 translation tables with minimum set of page properties including access
+permissions, shareability and security protection. In addition, System MMU has
+another capabilities like L2 TLB or block-fetch buffers to minimize translation
+latency.
+
+System MMUs are in many to one relation with peripheral devices, i.e. single
+peripheral device might have multiple System MMUs (usually one for each bus
+master), but one System MMU can handle transactions from only one peripheral
+device. The relation between a System MMU and the peripheral device needs to be
+defined in device node of the peripheral device.
+
+MFC in all Exynos SoCs and FIMD, M2M Scalers and G2D in Exynos5420 has 2 System
+MMUs.
+* MFC has one System MMU on its left and right bus.
+* FIMD in Exynos5420 has one System MMU for window 0 and 4, the other system 
MMU
+  for window 1, 2 and 3.
+* M2M Scalers and G2D in Exynos5420 has one System MMU on the read channel and
+  the other System MMU on the write channel.
+The drivers must consider how to handle those System MMUs. One of the idea is
+to implement child devices or sub-devices which are the client devices of the
+System MMU.
+
+Required properties:
+- compatible: Should be one of:
+   samsung,sysmmu-v1
+   samsung,sysmmu-v2
+   samsung,sysmmu-v3.1
+   samsung,sysmmu-v3.2
+   samsung,sysmmu-v3.3
+
+- reg: A tuple of base address and size of System MMU registers.
+- interrupt-parent: The phandle of the interrupt controller of System MMU
+- interrupts: An interrupt specifier for interrupt signal of System MMU,
+ according to the format defined by a particular interrupt
+ controller.
+- clock-names: Should be sysmmu if the System MMU is needed to gate its 
clock.
+   Please refer to the following documents:
+  Documentation/devicetree/bindings/clock/clock-bindings.txt
+  Documentation/devicetree/bindings/clock/exynos4-clock.txt
+  Documentation/devicetree/bindings/clock/exynos5250-clock.txt
+  Documentation/devicetree/bindings/clock/exynos5420-clock.txt
+  Optional master if the clock to the System MMU is gated by
+  another gate clock other than sysmmu. The System MMU driver
+  sets master the parent of sysmmu.
+  Exynos4 SoCs, there needs no master clockj.
+  Exynos5 SoCs, some System MMUs must have master clocks.
+- clocks: Required if the System MMU is needed to gate its clock.
+ Please refer to the documents listed above.
+- samsung,power-domain: Required if the System MMU is needed to gate its power.
+ Please refer to the following document:
+ Documentation/devicetree/bindings/arm/exynos/power_domain.txt
+- mmu-masters: A phandle to device nodes representing the master for which
+   the System MMU can provide a translation. Any additional values
+  after the phandle will be ignored because a System MMU never
+  have two or more masters. #stream-id-cells specified in the
+  master's node will be also ignored.
+  If more than one phandle is specified, only the first phandle
+  will be treated.
+
+Examples:
+   gsc_0: gsc@13e0 {
+   compatible = samsung,exynos5-gsc;
+   reg = 0x13e0 0x1000;
+   interrupts = 0 85 0;
+   samsung,power-domain = pd_gsc

[PATCH v11 16/27] iommu/exynos: remove custom fault handler

2014-03-13 Thread Cho KyongHo
This commit removes custom fault handler. The device drivers that
need to register fault handler can register
with iommu_set_fault_handler().

CC: Grant Grundler grund...@chromium.org
Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |   80 +-
 1 file changed, 24 insertions(+), 56 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index cef62d0..3458349 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -136,16 +136,6 @@ enum exynos_sysmmu_inttype {
SYSMMU_FAULTS_NUM
 };
 
-/*
- * @itype: type of fault.
- * @pgtable_base: the physical address of page table base. This is 0 if @itype
- *is SYSMMU_BUSERROR.
- * @fault_addr: the device (virtual) address that the System MMU tried to
- * translated. This is 0 if @itype is SYSMMU_BUSERROR.
- */
-typedef int (*sysmmu_fault_handler_t)(enum exynos_sysmmu_inttype itype,
-   unsigned long pgtable_base, unsigned long fault_addr);
-
 static unsigned short fault_reg_offset[SYSMMU_FAULTS_NUM] = {
REG_PAGE_FAULT_ADDR,
REG_AR_FAULT_ADDR,
@@ -187,7 +177,6 @@ struct sysmmu_drvdata {
int activations;
rwlock_t lock;
struct iommu_domain *domain;
-   sysmmu_fault_handler_t fault_handler;
unsigned long pgtable;
 };
 
@@ -256,34 +245,17 @@ static void __sysmmu_set_ptbase(void __iomem *sfrbase,
__sysmmu_tlb_invalidate(sfrbase);
 }
 
-static void __set_fault_handler(struct sysmmu_drvdata *data,
-   sysmmu_fault_handler_t handler)
-{
-   unsigned long flags;
-
-   write_lock_irqsave(data-lock, flags);
-   data-fault_handler = handler;
-   write_unlock_irqrestore(data-lock, flags);
-}
-
-void exynos_sysmmu_set_fault_handler(struct device *dev,
-   sysmmu_fault_handler_t handler)
-{
-   struct sysmmu_drvdata *data = dev_get_drvdata(dev-archdata.iommu);
-
-   __set_fault_handler(data, handler);
-}
-
-static int default_fault_handler(enum exynos_sysmmu_inttype itype,
-unsigned long pgtable_base, unsigned long fault_addr)
+static void show_fault_information(const char *name,
+   enum exynos_sysmmu_inttype itype,
+   unsigned long pgtable_base, unsigned long fault_addr)
 {
unsigned long *ent;
 
if ((itype = SYSMMU_FAULTS_NUM) || (itype  SYSMMU_PAGEFAULT))
itype = SYSMMU_FAULT_UNKNOWN;
 
-   pr_err(%s occurred at 0x%lx(Page table base: 0x%lx)\n,
-   sysmmu_fault_name[itype], fault_addr, pgtable_base);
+   pr_err(%s occurred at 0x%lx by %s(Page table base: 0x%lx)\n,
+   sysmmu_fault_name[itype], fault_addr, name, pgtable_base);
 
ent = section_entry(__va(pgtable_base), fault_addr);
pr_err(\tLv1 entry: 0x%lx\n, *ent);
@@ -292,12 +264,6 @@ static int default_fault_handler(enum 
exynos_sysmmu_inttype itype,
ent = page_entry(ent, fault_addr);
pr_err(\t Lv2 entry: 0x%lx\n, *ent);
}
-
-   pr_err(Generating Kernel OOPS... because it is unrecoverable.\n);
-
-   BUG();
-
-   return 0;
 }
 
 static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
@@ -320,24 +286,28 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void 
*dev_id)
else
addr = __raw_readl(data-sfrbase + fault_reg_offset[itype]);
 
-   if (data-domain)
-   ret = report_iommu_fault(data-domain, data-dev, addr, itype);
-
-   if ((ret == -ENOSYS)  data-fault_handler) {
-   unsigned long base = data-pgtable;
-   if (itype != SYSMMU_FAULT_UNKNOWN)
-   base = __raw_readl(data-sfrbase + REG_PT_BASE_ADDR);
-   ret = data-fault_handler(itype, base, addr);
+   if (itype == SYSMMU_FAULT_UNKNOWN) {
+   pr_err(%s: Fault is not occurred by System MMU '%s'!\n,
+   __func__, dev_name(data-sysmmu));
+   pr_err(%s: Please check if IRQ is correctly configured.\n,
+   __func__);
+   BUG();
+   } else {
+   unsigned long base =
+   __raw_readl(data-sfrbase + REG_PT_BASE_ADDR);
+   show_fault_information(dev_name(data-sysmmu),
+   itype, base, addr);
+   if (data-domain)
+   ret = report_iommu_fault(data-domain,
+   data-dev, addr, itype);
}
 
-   if (!ret  (itype != SYSMMU_FAULT_UNKNOWN))
-   __raw_writel(1  itype, data-sfrbase + REG_INT_CLEAR);
-   else
-   dev_dbg(data-sysmmu, %s is not handled.\n,
-   sysmmu_fault_name[itype]);
+   /* fault is not recovered by fault handler */
+   BUG_ON(ret != 0);
 
-   if (itype

[PATCH v11 17/27] iommu/exynos: remove calls to Runtime PM API functions

2014-03-13 Thread Cho KyongHo
Runtime power management by exynos-iommu driver independently from
master H/W's runtime pm is not useful for power saving since attaching
master H/W in probing time turns on its local power endlessly.
Thus this removes runtime pm API calls.
Runtime PM support is added in the following commits to exynos-iommu
driver.

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |  369 +++---
 1 file changed, 238 insertions(+), 131 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 3458349..6834556 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -27,6 +27,8 @@
 #include linux/memblock.h
 #include linux/export.h
 #include linux/of.h
+#include linux/of_platform.h
+#include linux/notifier.h
 
 #include asm/cacheflush.h
 #include asm/pgtable.h
@@ -111,6 +113,8 @@
 #define __master_clk_enable(data)  __clk_gate_ctrl(data, clk_master, en)
 #define __master_clk_disable(data) __clk_gate_ctrl(data, clk_master, dis)
 
+#define has_sysmmu(dev)(dev-archdata.iommu != NULL)
+
 static struct kmem_cache *lv2table_kmem_cache;
 
 static unsigned long *section_entry(unsigned long *pgtable, unsigned long iova)
@@ -159,6 +163,16 @@ static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = {
UNKNOWN FAULT
 };
 
+/* attached to dev.archdata.iommu of the master device */
+struct exynos_iommu_owner {
+   struct list_head client; /* entry of exynos_iommu_domain.clients */
+   struct device *dev;
+   struct device *sysmmu;
+   struct iommu_domain *domain;
+   void *vmm_data; /* IO virtual memory manager's data */
+   spinlock_t lock;/* Lock to preserve consistency of System MMU */
+};
+
 struct exynos_iommu_domain {
struct list_head clients; /* list of sysmmu_drvdata.node */
unsigned long *pgtable; /* lv1 page table, 16KB */
@@ -168,9 +182,8 @@ struct exynos_iommu_domain {
 };
 
 struct sysmmu_drvdata {
-   struct list_head node; /* entry of exynos_iommu_domain.clients */
struct device *sysmmu;  /* System MMU's device descriptor */
-   struct device *dev; /* Owner of system MMU */
+   struct device *master;  /* Owner of system MMU */
void __iomem *sfrbase;
struct clk *clk;
struct clk *clk_master;
@@ -239,7 +252,6 @@ static void __sysmmu_tlb_invalidate_entry(void __iomem 
*sfrbase,
 static void __sysmmu_set_ptbase(void __iomem *sfrbase,
   unsigned long pgd)
 {
-   __raw_writel(0x1, sfrbase + REG_MMU_CFG); /* 16KB LV1, LRU */
__raw_writel(pgd, sfrbase + REG_PT_BASE_ADDR);
 
__sysmmu_tlb_invalidate(sfrbase);
@@ -299,7 +311,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
itype, base, addr);
if (data-domain)
ret = report_iommu_fault(data-domain,
-   data-dev, addr, itype);
+   data-master, addr, itype);
}
 
/* fault is not recovered by fault handler */
@@ -316,116 +328,148 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void 
*dev_id)
return IRQ_HANDLED;
 }
 
-static bool __exynos_sysmmu_disable(struct sysmmu_drvdata *data)
+static void __sysmmu_disable_nocount(struct sysmmu_drvdata *data)
 {
-   unsigned long flags;
-   bool disabled = false;
-
-   write_lock_irqsave(data-lock, flags);
-
-   if (!set_sysmmu_inactive(data))
-   goto finish;
-
-   __master_clk_enable(data);
+   clk_enable(data-clk_master);
 
__raw_writel(CTRL_DISABLE, data-sfrbase + REG_MMU_CTRL);
+   __raw_writel(0, data-sfrbase + REG_MMU_CFG);
 
__sysmmu_clk_disable(data);
__master_clk_disable(data);
+}
 
-   disabled = true;
-   data-pgtable = 0;
-   data-domain = NULL;
-finish:
-   write_unlock_irqrestore(data-lock, flags);
+static bool __sysmmu_disable(struct sysmmu_drvdata *data)
+{
+   bool disabled;
+   unsigned long flags;
+
+   write_lock_irqsave(data-lock, flags);
+
+   disabled = set_sysmmu_inactive(data);
+
+   if (disabled) {
+   data-pgtable = 0;
+   data-domain = NULL;
+
+   __sysmmu_disable_nocount(data);
 
-   if (disabled)
dev_dbg(data-sysmmu, Disabled\n);
-   else
-   dev_dbg(data-sysmmu, %d times left to be disabled\n,
+   } else  {
+   dev_dbg(data-sysmmu, %d times left to disable\n,
data-activations);
+   }
+
+   write_unlock_irqrestore(data-lock, flags);
 
return disabled;
 }
 
-/* __exynos_sysmmu_enable: Enables System MMU
- *
- * returns -error if an error occurred and System MMU is not enabled,
- * 0 if the System MMU has been just enabled and 1 if System MMU was already
- * enabled before.
- */
-static

[PATCH v11 18/27] iommu/exynos: turn on useful configuration options

2014-03-13 Thread Cho KyongHo
This turns on FLPD_CACHE, ACGEN and SYSSEL.

FLPD_CACHE is a cache of 1st level page table entries that contains
the address of a 2nd level page table to reduce latency of page table
walking.

ACGEN is architectural clock gating that gates clocks by System MMU
itself if it is not active. Note that ACGEN is different from clock
gating by the CPU. ACGEN just gates clocks to the internal logic of
System MMU while clock gating by the CPU gates clocks to the System
MMU.

SYSSEL selects System MMU version in some Exynos SoCs. Some Exynos
SoCs have an option to select System MMU versions exclusively because
the SoCs adopts new System MMU version experimentally.

This also always selects LRU as TLB replacement policy. Selecting TLB
replacement policy is deprecated from System MMU 3.2. TLB in System
MMU 3.3 has single TLB replacement policy, LRU. The bit of MMU_CFG
selecting TLB replacement policy is remained as reserved.

QoS value of page table walking is set to 15 (highst value). System
MMU 3.3 can inherit QoS value of page table walking from its master
H/W's transaction. This new feature is enabled by default and QoS
value written to MMU_CFG is ignored.

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |   52 +-
 1 file changed, 51 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 6834556..9037da0 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -82,6 +82,13 @@
 #define CTRL_BLOCK 0x7
 #define CTRL_DISABLE   0x0
 
+#define CFG_LRU0x1
+#define CFG_QOS(n) ((n  0xF)  7)
+#define CFG_MASK   0x0150 /* Selecting bit 0-15, 20, 22 and 24 */
+#define CFG_ACGEN  (1  24) /* System MMU 3.3 only */
+#define CFG_SYSSEL (1  22) /* System MMU 3.2 only */
+#define CFG_FLPDCACHE  (1  20) /* System MMU 3.2+ only */
+
 #define REG_MMU_CTRL   0x000
 #define REG_MMU_CFG0x004
 #define REG_MMU_STATUS 0x008
@@ -98,6 +105,12 @@
 
 #define REG_MMU_VERSION0x034
 
+#define MMU_MAJ_VER(val)   ((val)  7)
+#define MMU_MIN_VER(val)   ((val)  0x7F)
+#define MMU_RAW_VER(reg)   (((reg)  21)  ((1  11) - 1)) /* 11 bits */
+
+#define MAKE_MMU_VER(maj, min) maj)  0xF)  7) | ((min)  0x7F))
+
 #define REG_PB0_SADDR  0x04C
 #define REG_PB0_EADDR  0x050
 #define REG_PB1_SADDR  0x054
@@ -217,6 +230,29 @@ static void sysmmu_unblock(void __iomem *sfrbase)
__raw_writel(CTRL_ENABLE, sfrbase + REG_MMU_CTRL);
 }
 
+static unsigned int __raw_sysmmu_version(struct sysmmu_drvdata *data)
+{
+   return MMU_RAW_VER(__raw_readl(data-sfrbase + REG_MMU_VERSION));
+}
+
+static unsigned int __sysmmu_version(struct sysmmu_drvdata *data,
+unsigned int *minor)
+{
+   unsigned int ver = 0;
+
+   ver = __raw_sysmmu_version(data);
+   if (ver  MAKE_MMU_VER(3, 3)) {
+   dev_err(data-sysmmu, %s: version(%d.%d) is higher than 3.3\n,
+   __func__, MMU_MAJ_VER(ver), MMU_MIN_VER(ver));
+   BUG();
+   }
+
+   if (minor)
+   *minor = MMU_MIN_VER(ver);
+
+   return MMU_MAJ_VER(ver);
+}
+
 static bool sysmmu_block(void __iomem *sfrbase)
 {
int i = 120;
@@ -367,7 +403,21 @@ static bool __sysmmu_disable(struct sysmmu_drvdata *data)
 
 static void __sysmmu_init_config(struct sysmmu_drvdata *data)
 {
-   unsigned long cfg = 0;
+   unsigned long cfg = CFG_LRU | CFG_QOS(15);
+   int maj, min = 0;
+
+   maj = __sysmmu_version(data, min);
+   if (maj == 3) {
+   if (min = 2) {
+   cfg |= CFG_FLPDCACHE;
+   if (min == 3) {
+   cfg |= CFG_ACGEN;
+   cfg = ~CFG_LRU;
+   } else {
+   cfg |= CFG_SYSSEL;
+   }
+   }
+   }
 
__raw_writel(cfg, data-sfrbase + REG_MMU_CFG);
 }
-- 
1.7.9.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v11 15/27] iommu/exynos: use convenient macro to handle gate clocks

2014-03-13 Thread Cho KyongHo
exynos-iommu driver must care about master H/W's gate clock as well as
System MMU's gate clock. To enhance readability of the source code,
macros to gate/ungate those clocks are defined.

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |   34 ++
 1 file changed, 22 insertions(+), 12 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 71e77f1..cef62d0 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -101,6 +101,16 @@
 #define REG_PB1_SADDR  0x054
 #define REG_PB1_EADDR  0x058
 
+#define __clk_gate_ctrl(data, clk, en) do {\
+   if (data-clk)  \
+   clk_##en##able(data-clk);  \
+   } while (0)
+
+#define __sysmmu_clk_enable(data)  __clk_gate_ctrl(data, clk, en)
+#define __sysmmu_clk_disable(data) __clk_gate_ctrl(data, clk, dis)
+#define __master_clk_enable(data)  __clk_gate_ctrl(data, clk_master, en)
+#define __master_clk_disable(data) __clk_gate_ctrl(data, clk_master, dis)
+
 static struct kmem_cache *lv2table_kmem_cache;
 
 static unsigned long *section_entry(unsigned long *pgtable, unsigned long iova)
@@ -302,7 +312,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
 
WARN_ON(!is_sysmmu_active(data));
 
-   clk_enable(data-clk_master);
+   __master_clk_enable(data);
itype = (enum exynos_sysmmu_inttype)
__ffs(__raw_readl(data-sfrbase + REG_INT_STATUS));
if (WARN_ON(!((itype = 0)  (itype  SYSMMU_FAULT_UNKNOWN
@@ -329,7 +339,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
if (itype != SYSMMU_FAULT_UNKNOWN)
sysmmu_unblock(data-sfrbase);
 
-   clk_disable(data-clk_master);
+   __master_clk_disable(data);
 
read_unlock(data-lock);
 
@@ -346,12 +356,12 @@ static bool __exynos_sysmmu_disable(struct sysmmu_drvdata 
*data)
if (!set_sysmmu_inactive(data))
goto finish;
 
-   clk_enable(data-clk_master);
+   __master_clk_enable(data);
 
__raw_writel(CTRL_DISABLE, data-sfrbase + REG_MMU_CTRL);
 
-   clk_disable(data-clk);
-   clk_disable(data-clk_master);
+   __sysmmu_clk_disable(data);
+   __master_clk_disable(data);
 
disabled = true;
data-pgtable = 0;
@@ -396,14 +406,14 @@ static int __exynos_sysmmu_enable(struct sysmmu_drvdata 
*data,
 
data-pgtable = pgtable;
 
-   clk_enable(data-clk_master);
-   clk_enable(data-clk);
+   __master_clk_enable(data);
+   __sysmmu_clk_enable(data);
 
__sysmmu_set_ptbase(data-sfrbase, pgtable);
 
__raw_writel(CTRL_ENABLE, data-sfrbase + REG_MMU_CTRL);
 
-   clk_disable(data-clk_master);
+   __master_clk_disable(data);
 
data-domain = domain;
 
@@ -462,7 +472,7 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, 
unsigned long iova,
unsigned int maj;
unsigned int num_inv = 1;
 
-   clk_enable(data-clk_master);
+   __master_clk_enable(data);
 
maj = __raw_readl(data-sfrbase + REG_MMU_VERSION);
/*
@@ -483,7 +493,7 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, 
unsigned long iova,
num_inv);
sysmmu_unblock(data-sfrbase);
}
-   clk_disable(data-clk_master);
+   __master_clk_disable(data);
} else {
dev_dbg(data-sysmmu, Disabled. Skipping invalidating TLB.\n);
}
@@ -499,12 +509,12 @@ void exynos_sysmmu_tlb_invalidate(struct device *dev)
read_lock_irqsave(data-lock, flags);
 
if (is_sysmmu_active(data)) {
-   clk_enable(data-clk_master);
+   __master_clk_enable(data);
if (sysmmu_block(data-sfrbase)) {
__sysmmu_tlb_invalidate(data-sfrbase);
sysmmu_unblock(data-sfrbase);
}
-   clk_disable(data-clk_master);
+   __master_clk_disable(data);
} else {
dev_dbg(data-sysmmu, Disabled. Skipping invalidating TLB.\n);
}
-- 
1.7.9.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v11 13/27] iommu/exynos: support for device tree

2014-03-13 Thread Cho KyongHo
This commit adds device tree support for System MMU.

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/Kconfig|5 ++---
 drivers/iommu/exynos-iommu.c |   21 +
 2 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index df56e4c..22af807 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -178,16 +178,15 @@ config TEGRA_IOMMU_SMMU
 
 config EXYNOS_IOMMU
bool Exynos IOMMU Support
-   depends on ARCH_EXYNOS  EXYNOS_DEV_SYSMMU
+   depends on ARCH_EXYNOS
select IOMMU_API
+   default n
help
  Support for the IOMMU(System MMU) of Samsung Exynos application
  processor family. This enables H/W multimedia accellerators to see
  non-linear physical memory chunks as a linear memory in their
  address spaces
 
- If unsure, say N here.
-
 config EXYNOS_IOMMU_DEBUG
bool Debugging log for Exynos IOMMU
depends on EXYNOS_IOMMU
diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 33b424d..34feb04 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -26,6 +26,7 @@
 #include linux/list.h
 #include linux/memblock.h
 #include linux/export.h
+#include linux/of.h
 
 #include asm/cacheflush.h
 #include asm/pgtable.h
@@ -497,7 +498,7 @@ void exynos_sysmmu_tlb_invalidate(struct device *dev)
read_unlock_irqrestore(data-lock, flags);
 }
 
-static int exynos_sysmmu_probe(struct platform_device *pdev)
+static int __init exynos_sysmmu_probe(struct platform_device *pdev)
 {
int irq, ret;
struct device *dev = pdev-dev;
@@ -557,11 +558,23 @@ static int exynos_sysmmu_probe(struct platform_device 
*pdev)
return 0;
 }
 
-static struct platform_driver exynos_sysmmu_driver = {
-   .probe  = exynos_sysmmu_probe,
-   .driver = {
+#ifdef CONFIG_OF
+static struct of_device_id sysmmu_of_match[] __initconst = {
+   { .compatible   = samsung,sysmmu-v1, },
+   { .compatible   = samsung,sysmmu-v2, },
+   { .compatible   = samsung,sysmmu-v3.1, },
+   { .compatible   = samsung,sysmmu-v3.2, },
+   { .compatible   = samsung,sysmmu-v3.3, },
+   { },
+};
+#endif
+
+static struct platform_driver exynos_sysmmu_driver __refdata = {
+   .probe  = exynos_sysmmu_probe,
+   .driver = {
.owner  = THIS_MODULE,
.name   = exynos-sysmmu,
+   .of_match_table = of_match_ptr(sysmmu_of_match),
}
 };
 
-- 
1.7.9.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v11 14/27] iommu/exynos: gating clocks of master H/W

2014-03-13 Thread Cho KyongHo
This patch gates clocks of master H/W as well as clocks of System MMU
if master clocks are specified.

Some Exynos SoCs (i.e. GScalers in Exynos5250) have dependencies in
the gating clocks of master H/W and its System MMU. If a H/W is the
case, accessing control registers of System MMU is prohibited unless
both of the gating clocks of System MMU and its master H/W.

CC: Tomasz Figa t.f...@samsung.com
Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |   35 ++-
 1 file changed, 30 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 34feb04..71e77f1 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -173,6 +173,7 @@ struct sysmmu_drvdata {
struct device *dev; /* Owner of system MMU */
void __iomem *sfrbase;
struct clk *clk;
+   struct clk *clk_master;
int activations;
rwlock_t lock;
struct iommu_domain *domain;
@@ -301,6 +302,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
 
WARN_ON(!is_sysmmu_active(data));
 
+   clk_enable(data-clk_master);
itype = (enum exynos_sysmmu_inttype)
__ffs(__raw_readl(data-sfrbase + REG_INT_STATUS));
if (WARN_ON(!((itype = 0)  (itype  SYSMMU_FAULT_UNKNOWN
@@ -327,6 +329,8 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
if (itype != SYSMMU_FAULT_UNKNOWN)
sysmmu_unblock(data-sfrbase);
 
+   clk_disable(data-clk_master);
+
read_unlock(data-lock);
 
return IRQ_HANDLED;
@@ -342,10 +346,12 @@ static bool __exynos_sysmmu_disable(struct sysmmu_drvdata 
*data)
if (!set_sysmmu_inactive(data))
goto finish;
 
+   clk_enable(data-clk_master);
+
__raw_writel(CTRL_DISABLE, data-sfrbase + REG_MMU_CTRL);
 
-   if (data-clk)
-   clk_disable(data-clk);
+   clk_disable(data-clk);
+   clk_disable(data-clk_master);
 
disabled = true;
data-pgtable = 0;
@@ -388,15 +394,17 @@ static int __exynos_sysmmu_enable(struct sysmmu_drvdata 
*data,
goto finish;
}
 
-   if (data-clk)
-   clk_enable(data-clk);
-
data-pgtable = pgtable;
 
+   clk_enable(data-clk_master);
+   clk_enable(data-clk);
+
__sysmmu_set_ptbase(data-sfrbase, pgtable);
 
__raw_writel(CTRL_ENABLE, data-sfrbase + REG_MMU_CTRL);
 
+   clk_disable(data-clk_master);
+
data-domain = domain;
 
dev_dbg(data-sysmmu, Enabled\n);
@@ -453,6 +461,9 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, 
unsigned long iova,
if (is_sysmmu_active(data)) {
unsigned int maj;
unsigned int num_inv = 1;
+
+   clk_enable(data-clk_master);
+
maj = __raw_readl(data-sfrbase + REG_MMU_VERSION);
/*
 * L2TLB invalidation required
@@ -472,6 +483,7 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, 
unsigned long iova,
num_inv);
sysmmu_unblock(data-sfrbase);
}
+   clk_disable(data-clk_master);
} else {
dev_dbg(data-sysmmu, Disabled. Skipping invalidating TLB.\n);
}
@@ -487,10 +499,12 @@ void exynos_sysmmu_tlb_invalidate(struct device *dev)
read_lock_irqsave(data-lock, flags);
 
if (is_sysmmu_active(data)) {
+   clk_enable(data-clk_master);
if (sysmmu_block(data-sfrbase)) {
__sysmmu_tlb_invalidate(data-sfrbase);
sysmmu_unblock(data-sfrbase);
}
+   clk_disable(data-clk_master);
} else {
dev_dbg(data-sysmmu, Disabled. Skipping invalidating TLB.\n);
}
@@ -544,6 +558,17 @@ static int __init exynos_sysmmu_probe(struct 
platform_device *pdev)
return ret;
}
 
+   data-clk_master = devm_clk_get(dev, master);
+   if (IS_ERR(data-clk_master))
+   data-clk_master = NULL;
+
+   ret = clk_prepare(data-clk_master);
+   if (ret) {
+   clk_unprepare(data-clk);
+   dev_err(dev, Failed to prepare master's clk\n);
+   return ret;
+   }
+
data-sysmmu = dev;
rwlock_init(data-lock);
INIT_LIST_HEAD(data-node);
-- 
1.7.9.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v11 19/27] iommu/exynos: add support for power management subsystems.

2014-03-13 Thread Cho KyongHo
This adds support for Suspend to RAM and Runtime Power Management.

Since System MMU is located in the same local power domain of its
master H/W, System MMU must be initialized before it is working if
its power domain was ever turned off. TLB invalidation according to
unmapping on page tables must also be performed while power domain is
turned on.

This patch ensures that resume and runtime_resume(restore_state)
functions in this driver is called before the calls to resume and
runtime_resume callback functions in the drivers of master H/Ws.
Likewise, suspend and runtime_suspend(save_state) functions in this
driver is called after the calls to suspend and runtime_suspend in the
drivers of master H/Ws.

In order to get benefit of this support, the master H/W and its System
MMU must resides in the same power domain in terms of Linux kernel. If
a master H/W does not use generic I/O power domain, its driver must
call iommu_attach_device() after its local power domain is turned on,
iommu_detach_device before turned off.

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |  220 ++
 1 file changed, 201 insertions(+), 19 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 9037da0..84ba29a 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -28,6 +28,7 @@
 #include linux/export.h
 #include linux/of.h
 #include linux/of_platform.h
+#include linux/pm_domain.h
 #include linux/notifier.h
 
 #include asm/cacheflush.h
@@ -203,6 +204,7 @@ struct sysmmu_drvdata {
int activations;
rwlock_t lock;
struct iommu_domain *domain;
+   bool runtime_active;
unsigned long pgtable;
 };
 
@@ -388,7 +390,8 @@ static bool __sysmmu_disable(struct sysmmu_drvdata *data)
data-pgtable = 0;
data-domain = NULL;
 
-   __sysmmu_disable_nocount(data);
+   if (data-runtime_active)
+   __sysmmu_disable_nocount(data);
 
dev_dbg(data-sysmmu, Disabled\n);
} else  {
@@ -449,7 +452,8 @@ static int __sysmmu_enable(struct sysmmu_drvdata *data,
data-pgtable = pgtable;
data-domain = domain;
 
-   __sysmmu_enable_nocount(data);
+   if (data-runtime_active)
+   __sysmmu_enable_nocount(data);
 
dev_dbg(data-sysmmu, Enabled\n);
} else {
@@ -534,13 +538,11 @@ static void sysmmu_tlb_invalidate_entry(struct device 
*dev, unsigned long iova,
data = dev_get_drvdata(owner-sysmmu);
 
read_lock_irqsave(data-lock, flags);
-   if (is_sysmmu_active(data)) {
-   unsigned int maj;
+   if (is_sysmmu_active(data)  data-runtime_active) {
unsigned int num_inv = 1;
 
__master_clk_enable(data);
 
-   maj = __raw_readl(data-sfrbase + REG_MMU_VERSION);
/*
 * L2TLB invalidation required
 * 4KB page: 1 invalidation
@@ -551,7 +553,7 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, 
unsigned long iova,
 * 1MB page can be cached in one of all sets.
 * 64KB page can be one of 16 consecutive sets.
 */
-   if ((maj  28) == 2) /* major version number */
+   if (__sysmmu_version(data, NULL) == 2) /* major version number 
*/
num_inv = min_t(unsigned int, size / PAGE_SIZE, 64);
 
if (sysmmu_block(data-sfrbase)) {
@@ -576,7 +578,7 @@ void exynos_sysmmu_tlb_invalidate(struct device *dev)
data = dev_get_drvdata(owner-sysmmu);
 
read_lock_irqsave(data-lock, flags);
-   if (is_sysmmu_active(data)) {
+   if (is_sysmmu_active(data)  data-runtime_active) {
__master_clk_enable(data);
if (sysmmu_block(data-sfrbase)) {
__sysmmu_tlb_invalidate(data-sfrbase);
@@ -677,11 +679,40 @@ static int __init exynos_sysmmu_probe(struct 
platform_device *pdev)
platform_set_drvdata(pdev, data);
 
pm_runtime_enable(dev);
+   data-runtime_active = !pm_runtime_enabled(dev);
 
dev_dbg(dev, Probed and initialized\n);
return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int sysmmu_suspend(struct device *dev)
+{
+   struct sysmmu_drvdata *data = dev_get_drvdata(dev);
+   unsigned long flags;
+   read_lock_irqsave(data-lock, flags);
+   if (is_sysmmu_active(data) 
+   (!pm_runtime_enabled(dev) || data-runtime_active))
+   __sysmmu_disable_nocount(data);
+   read_unlock_irqrestore(data-lock, flags);
+   return 0;
+}
+
+static int sysmmu_resume(struct device *dev)
+{
+   struct sysmmu_drvdata *data = dev_get_drvdata(dev);
+   unsigned long flags;
+   read_lock_irqsave(data-lock, flags);
+   if (is_sysmmu_active(data

[PATCH v11 20/27] iommu/exynos: allow having multiple System MMUs for a master H/W

2014-03-13 Thread Cho KyongHo
Some master device descriptor like fimc-is which is an abstraction
of very complex H/W may have multiple System MMUs. For those devices,
the design of the link between System MMU and its master H/W is needed
to be reconsidered.

A link structure, sysmmu_list_data is introduced that provides a link
to master H/W and that has a pointer to the device descriptor of a
System MMU. Given a device descriptor of a master H/W, it is possible
to traverse all System MMUs that must be controlled along with the
master H/W.

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |  534 ++
 1 file changed, 333 insertions(+), 201 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 84ba29a..7489343 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -128,6 +128,10 @@
 #define __master_clk_disable(data) __clk_gate_ctrl(data, clk_master, dis)
 
 #define has_sysmmu(dev)(dev-archdata.iommu != NULL)
+#define for_each_sysmmu_list(dev, list_data)   \
+   list_for_each_entry(list_data,  \
+   ((struct exynos_iommu_owner *)dev-archdata.iommu)-mmu_list, \
+   entry)
 
 static struct kmem_cache *lv2table_kmem_cache;
 
@@ -181,7 +185,7 @@ static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = {
 struct exynos_iommu_owner {
struct list_head client; /* entry of exynos_iommu_domain.clients */
struct device *dev;
-   struct device *sysmmu;
+   struct list_head mmu_list;  /* list of sysmmu_list_data.entry */
struct iommu_domain *domain;
void *vmm_data; /* IO virtual memory manager's data */
spinlock_t lock;/* Lock to preserve consistency of System MMU */
@@ -195,6 +199,11 @@ struct exynos_iommu_domain {
spinlock_t pgtablelock; /* lock for modifying page table @ pgtable */
 };
 
+struct sysmmu_list_data {
+   struct list_head entry; /* entry of exynos_iommu_owner.mmu_list */
+   struct device *sysmmu;
+};
+
 struct sysmmu_drvdata {
struct device *sysmmu;  /* System MMU's device descriptor */
struct device *master;  /* Owner of system MMU */
@@ -205,6 +214,7 @@ struct sysmmu_drvdata {
rwlock_t lock;
struct iommu_domain *domain;
bool runtime_active;
+   bool suspended;
unsigned long pgtable;
 };
 
@@ -471,28 +481,39 @@ static int __sysmmu_enable(struct sysmmu_drvdata *data,
 }
 
 /* __exynos_sysmmu_enable: Enables System MMU
- *
- * returns -error if an error occurred and System MMU is not enabled,
- * 0 if the System MMU has been just enabled and 1 if System MMU was already
- * enabled before.
- */
+*
+* returns -error if an error occurred and System MMU is not enabled,
+* 0 if the System MMU has been just enabled and 1 if System MMU was already
+* enabled before.
+*/
 static int __exynos_sysmmu_enable(struct device *dev, unsigned long pgtable,
  struct iommu_domain *domain)
 {
int ret = 0;
unsigned long flags;
struct exynos_iommu_owner *owner = dev-archdata.iommu;
-   struct sysmmu_drvdata *data;
+   struct sysmmu_list_data *list;
 
BUG_ON(!has_sysmmu(dev));
 
spin_lock_irqsave(owner-lock, flags);
 
-   data = dev_get_drvdata(owner-sysmmu);
-
-   ret = __sysmmu_enable(data, pgtable, domain);
-   if (ret = 0)
+   for_each_sysmmu_list(dev, list) {
+   struct sysmmu_drvdata *data = dev_get_drvdata(list-sysmmu);
data-master = dev;
+   ret = __sysmmu_enable(data, pgtable, domain);
+   if (ret  0) {
+   struct sysmmu_list_data *iter;
+   for_each_sysmmu_list(dev, iter) {
+   if (iter-sysmmu == list-sysmmu)
+   break;
+   data = dev_get_drvdata(iter-sysmmu);
+   __sysmmu_disable(data);
+   data-master = NULL;
+   }
+   break;
+   }
+   }
 
spin_unlock_irqrestore(owner-lock, flags);
 
@@ -511,17 +532,19 @@ static bool exynos_sysmmu_disable(struct device *dev)
unsigned long flags;
bool disabled = true;
struct exynos_iommu_owner *owner = dev-archdata.iommu;
-   struct sysmmu_drvdata *data;
+   struct sysmmu_list_data *list;
 
BUG_ON(!has_sysmmu(dev));
 
spin_lock_irqsave(owner-lock, flags);
 
-   data = dev_get_drvdata(owner-sysmmu);
-
-   disabled = __sysmmu_disable(data);
-   if (disabled)
-   data-master = NULL;
+   /* Every call to __sysmmu_disable() must return same result */
+   for_each_sysmmu_list(dev, list) {
+   struct sysmmu_drvdata *data = dev_get_drvdata(list-sysmmu

[PATCH v11 21/27] iommu/exynos: change rwlock to spinlock

2014-03-13 Thread Cho KyongHo
Since acquiring read_lock is not more frequent than write_lock, it is
not beneficial to use rwlock, this commit changes rwlock to spinlock.

Reviewed-by: Grant Grundler grund...@chromium.org
Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |   39 ---
 1 file changed, 20 insertions(+), 19 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 7489343..543ea2e0 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -211,7 +211,7 @@ struct sysmmu_drvdata {
struct clk *clk;
struct clk *clk_master;
int activations;
-   rwlock_t lock;
+   spinlock_t lock;
struct iommu_domain *domain;
bool runtime_active;
bool suspended;
@@ -334,11 +334,12 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void 
*dev_id)
unsigned long addr = -1;
int ret = -ENOSYS;
 
-   read_lock(data-lock);
-
WARN_ON(!is_sysmmu_active(data));
 
+   spin_lock(data-lock);
+
__master_clk_enable(data);
+
itype = (enum exynos_sysmmu_inttype)
__ffs(__raw_readl(data-sfrbase + REG_INT_STATUS));
if (WARN_ON(!((itype = 0)  (itype  SYSMMU_FAULT_UNKNOWN
@@ -371,7 +372,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
 
__master_clk_disable(data);
 
-   read_unlock(data-lock);
+   spin_unlock(data-lock);
 
return IRQ_HANDLED;
 }
@@ -392,7 +393,7 @@ static bool __sysmmu_disable(struct sysmmu_drvdata *data)
bool disabled;
unsigned long flags;
 
-   write_lock_irqsave(data-lock, flags);
+   spin_lock_irqsave(data-lock, flags);
 
disabled = set_sysmmu_inactive(data);
 
@@ -409,7 +410,7 @@ static bool __sysmmu_disable(struct sysmmu_drvdata *data)
data-activations);
}
 
-   write_unlock_irqrestore(data-lock, flags);
+   spin_unlock_irqrestore(data-lock, flags);
 
return disabled;
 }
@@ -457,7 +458,7 @@ static int __sysmmu_enable(struct sysmmu_drvdata *data,
int ret = 0;
unsigned long flags;
 
-   write_lock_irqsave(data-lock, flags);
+   spin_lock_irqsave(data-lock, flags);
if (set_sysmmu_active(data)) {
data-pgtable = pgtable;
data-domain = domain;
@@ -475,7 +476,7 @@ static int __sysmmu_enable(struct sysmmu_drvdata *data,
if (WARN_ON(ret  0))
set_sysmmu_inactive(data); /* decrement count */
 
-   write_unlock_irqrestore(data-lock, flags);
+   spin_unlock_irqrestore(data-lock, flags);
 
return ret;
 }
@@ -562,7 +563,7 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, 
unsigned long iova,
 
for_each_sysmmu_list(dev, list) {
struct sysmmu_drvdata *data = dev_get_drvdata(list-sysmmu);
-   read_lock(data-lock);
+   spin_lock(data-lock);
if (is_sysmmu_active(data)  data-runtime_active) {
unsigned int num_inv = 1;
 
@@ -594,7 +595,7 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, 
unsigned long iova,
iova);
}
 
-   read_unlock(data-lock);
+   spin_unlock(data-lock);
}
 
spin_unlock_irqrestore(owner-lock, flags);
@@ -610,7 +611,7 @@ void exynos_sysmmu_tlb_invalidate(struct device *dev)
 
for_each_sysmmu_list(dev, list) {
struct sysmmu_drvdata *data = dev_get_drvdata(list-sysmmu);
-   read_lock(data-lock);
+   spin_lock(data-lock);
if (is_sysmmu_active(data)  data-runtime_active) {
__master_clk_enable(data);
if (sysmmu_block(data-sfrbase)) {
@@ -621,7 +622,7 @@ void exynos_sysmmu_tlb_invalidate(struct device *dev)
} else {
dev_dbg(dev, disabled. Skipping TLB invalidation\n);
}
-   read_unlock(data-lock);
+   spin_unlock(data-lock);
}
 
spin_unlock_irqrestore(owner-lock, flags);
@@ -819,7 +820,7 @@ static int __init exynos_sysmmu_probe(struct 
platform_device *pdev)
if (!ret) {
data-runtime_active = !pm_runtime_enabled(dev);
data-sysmmu = dev;
-   rwlock_init(data-lock);
+   spin_lock_init(data-lock);
 
platform_set_drvdata(pdev, data);
}
@@ -1269,12 +1270,12 @@ static int sysmmu_pm_genpd_suspend(struct device *dev)
for_each_sysmmu_list(dev, list) {
struct sysmmu_drvdata *data = dev_get_drvdata(list-sysmmu);
unsigned long flags;
-   write_lock_irqsave(data-lock, flags);
+   spin_lock_irqsave(data-lock, flags);
if (!data-suspended  is_sysmmu_active(data) 
(!pm_runtime_enabled(dev

[PATCH v11 22/27] iommu/exynos: add devices attached to the System MMU to an IOMMU group

2014-03-13 Thread Cho KyongHo
Patch written by Antonios Motakis a.mota...@virtualopensystems.com:

IOMMU groups are expected by certain users of the IOMMU API,
e.g. VFIO. Since each device is behind its own System MMU, we
can allocate a new IOMMU group for each device.

Reviewd-by: Cho KyongHo pullip@samsung.com
Signed-off-by: Antonios Motakis a.mota...@virtualopensystems.com
---
 drivers/iommu/exynos-iommu.c |   28 
 1 file changed, 28 insertions(+)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 543ea2e0..2beb197 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -1213,6 +1213,32 @@ static phys_addr_t exynos_iommu_iova_to_phys(struct 
iommu_domain *domain,
return phys;
 }
 
+static int exynos_iommu_add_device(struct device *dev)
+{
+   struct iommu_group *group;
+   int ret;
+
+   group = iommu_group_get(dev);
+
+   if (!group) {
+   group = iommu_group_alloc();
+   if (IS_ERR(group)) {
+   dev_err(dev, Failed to allocate IOMMU group\n);
+   return PTR_ERR(group);
+   }
+   }
+
+   ret = iommu_group_add_device(group, dev);
+   iommu_group_put(group);
+
+   return ret;
+}
+
+static void exynos_iommu_remove_device(struct device *dev)
+{
+   iommu_group_remove_device(dev);
+}
+
 static struct iommu_ops exynos_iommu_ops = {
.domain_init = exynos_iommu_domain_init,
.domain_destroy = exynos_iommu_domain_destroy,
@@ -1221,6 +1247,8 @@ static struct iommu_ops exynos_iommu_ops = {
.map = exynos_iommu_map,
.unmap = exynos_iommu_unmap,
.iova_to_phys = exynos_iommu_iova_to_phys,
+   .add_device = exynos_iommu_add_device,
+   .remove_device = exynos_iommu_remove_device,
.pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE,
 };
 
-- 
1.7.9.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v11 24/27] iommu/exynos: use exynos-iommu specific typedef

2014-03-13 Thread Cho KyongHo
This commit introduces sysmmu_pte_t for page table entries and
sysmmu_iova_t vor I/O virtual address that is manipulated by
exynos-iommu driver. The purpose of the typedef is to remove
dependencies to the driver code from the change of CPU architecture
from 32 bit to 64 bit.

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |  103 ++
 1 file changed, 54 insertions(+), 49 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index e375501..6e716cc 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -56,19 +56,19 @@
 #define lv2ent_large(pent) ((*(pent)  3) == 1)
 
 #define section_phys(sent) (*(sent)  SECT_MASK)
-#define section_offs(iova) ((iova)  0xF)
+#define section_offs(iova) ((sysmmu_iova_t)(iova)  0xF)
 #define lpage_phys(pent) (*(pent)  LPAGE_MASK)
-#define lpage_offs(iova) ((iova)  0x)
+#define lpage_offs(iova) ((sysmmu_iova_t)(iova)  0x)
 #define spage_phys(pent) (*(pent)  SPAGE_MASK)
-#define spage_offs(iova) ((iova)  0xFFF)
+#define spage_offs(iova) ((sysmmu_iova_t)(iova)  0xFFF)
 
-#define lv1ent_offset(iova) ((iova)  SECT_ORDER)
-#define lv2ent_offset(iova) (((iova)  0xFF000)  SPAGE_ORDER)
+#define lv1ent_offset(iova) ((sysmmu_iova_t)(iova)  SECT_ORDER)
+#define lv2ent_offset(iova) (((sysmmu_iova_t)(iova)  0xFF000)  SPAGE_ORDER)
 
 #define NUM_LV1ENTRIES 4096
-#define NUM_LV2ENTRIES 256
+#define NUM_LV2ENTRIES (SECT_SIZE / SPAGE_SIZE)
 
-#define LV2TABLE_SIZE (NUM_LV2ENTRIES * sizeof(long))
+#define LV2TABLE_SIZE (NUM_LV2ENTRIES * sizeof(sysmmu_pte_t))
 
 #define SPAGES_PER_LPAGE (LPAGE_SIZE / SPAGE_SIZE)
 
@@ -133,16 +133,19 @@
((struct exynos_iommu_owner *)dev-archdata.iommu)-mmu_list, \
entry)
 
+typedef u32 sysmmu_iova_t;
+typedef u32 sysmmu_pte_t;
+
 static struct kmem_cache *lv2table_kmem_cache;
 
-static unsigned long *section_entry(unsigned long *pgtable, unsigned long iova)
+static sysmmu_pte_t *section_entry(sysmmu_pte_t *pgtable, sysmmu_iova_t iova)
 {
return pgtable + lv1ent_offset(iova);
 }
 
-static unsigned long *page_entry(unsigned long *sent, unsigned long iova)
+static sysmmu_pte_t *page_entry(sysmmu_pte_t *sent, sysmmu_iova_t iova)
 {
-   return (unsigned long *)phys_to_virt(
+   return (sysmmu_pte_t *)phys_to_virt(
lv2table_base(sent)) + lv2ent_offset(iova);
 }
 
@@ -194,7 +197,7 @@ struct exynos_iommu_owner {
 
 struct exynos_iommu_domain {
struct list_head clients; /* list of sysmmu_drvdata.node */
-   unsigned long *pgtable; /* lv1 page table, 16KB */
+   sysmmu_pte_t *pgtable; /* lv1 page table, 16KB */
short *lv2entcnt; /* free lv2 entry counter for each section */
spinlock_t lock; /* lock for this structure */
spinlock_t pgtablelock; /* lock for modifying page table @ pgtable */
@@ -288,7 +291,7 @@ static void __sysmmu_tlb_invalidate(void __iomem *sfrbase)
 }
 
 static void __sysmmu_tlb_invalidate_entry(void __iomem *sfrbase,
-   unsigned long iova, unsigned int num_inv)
+   sysmmu_iova_t iova, unsigned int num_inv)
 {
unsigned int i;
for (i = 0; i  num_inv; i++) {
@@ -299,7 +302,7 @@ static void __sysmmu_tlb_invalidate_entry(void __iomem 
*sfrbase,
 }
 
 static void __sysmmu_set_ptbase(void __iomem *sfrbase,
-  unsigned long pgd)
+  phys_addr_t pgd)
 {
__raw_writel(pgd, sfrbase + REG_PT_BASE_ADDR);
 
@@ -308,22 +311,22 @@ static void __sysmmu_set_ptbase(void __iomem *sfrbase,
 
 static void show_fault_information(const char *name,
enum exynos_sysmmu_inttype itype,
-   phys_addr_t pgtable_base, unsigned long fault_addr)
+   phys_addr_t pgtable_base, sysmmu_iova_t fault_addr)
 {
-   unsigned long *ent;
+   sysmmu_pte_t *ent;
 
if ((itype = SYSMMU_FAULTS_NUM) || (itype  SYSMMU_PAGEFAULT))
itype = SYSMMU_FAULT_UNKNOWN;
 
-   pr_err(%s occurred at %#lx by %s(Page table base: %pa)\n,
+   pr_err(%s occurred at %#x by %s(Page table base: %pa)\n,
sysmmu_fault_name[itype], fault_addr, name, pgtable_base);
 
ent = section_entry(phys_to_virt(pgtable_base), fault_addr);
-   pr_err(\tLv1 entry: 0x%lx\n, *ent);
+   pr_err(\tLv1 entry: %#x\n, *ent);
 
if (lv1ent_page(ent)) {
ent = page_entry(ent, fault_addr);
-   pr_err(\t Lv2 entry: 0x%lx\n, *ent);
+   pr_err(\t Lv2 entry: %#x\n, *ent);
}
 }
 
@@ -332,7 +335,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
/* SYSMMU is in blocked when interrupt occurred. */
struct sysmmu_drvdata *data = dev_id;
enum exynos_sysmmu_inttype itype;
-   unsigned long addr = -1;
+   sysmmu_iova_t addr = -1;
int ret

[PATCH v11 26/27] iommu/exynos: apply workaround of caching fault page table entries

2014-03-13 Thread Cho KyongHo
This patch contains 2 workaround for the System MMU v3.x.

System MMU v3.2 and v3.3 has FLPD cache that caches first level page
table entries to reduce page table walking latency. However, the
FLPD cache is filled with a first level page table entry even though
it is not accessed by a master H/W because System MMU v3.3
speculatively prefetches page table entries that may be accessed
in the near future by the master H/W.
The prefetched FLPD cache entries are not invalidated by iommu_unmap()
because iommu_unmap() only unmaps and invalidates the page table
entries that is mapped.

Because exynos-iommu driver discards a second level page table when
it needs to be replaced with another second level page table or
a first level page table entry with 1MB mapping, It is required to
invalidate FLPD cache that may contain the first level page table
entry that points to the second level page table.

Another workaround of System MMU v3.3 is initializing the first level
page table entries with the second level page table which is filled
with all zeros. This prevents System MMU prefetches 'fault' first
level page table entry which may lead page fault on access to 16MiB
wide.

System MMU 3.x fetches consecutive page table entries by a page
table walking to maximize bus utilization and to minimize TLB miss
panelty.
Unfortunately, functional problem is raised with the fetching behavior
because it fetches 'fault' page table entries that specifies no
translation information and that a valid translation information will
be written to in the near future. The logic in the System MMU generates
page fault with the cached fault entries that is no longer coherent
with the page table which is updated.

There is another workaround that must be implemented by I/O virtual
memory manager: any two consecutive I/O virtual memory area must have
a hole between the two that is larger than or equal to 128KiB.
Also, next I/O virtual memory area must be started from the next
128KiB boundary.

0128K   256K   384K 512K
|-|---|-||
|area1|.hole...|--- area2 -

The constraint is depicted above.
The size is selected by the calculation followed:
 - System MMU can fetch consecutive 64 page table entries at once
   64 * 4KiB = 256KiB. This is the size between 128K ~ 384K of the
   above picture. This style of fetching is 'block fetch'. It fetches
   the page table entries predefined consecutive page table entries
   including the entry that is the reason of the page table walking.
 - System MMU can prefetch upto consecutive 32 page table entries.
   This is the size between 256K ~ 384K.

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |  164 +-
 1 file changed, 147 insertions(+), 17 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 3d4dabb..4888383 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -47,8 +47,12 @@
 #define LPAGE_MASK (~(LPAGE_SIZE - 1))
 #define SPAGE_MASK (~(SPAGE_SIZE - 1))
 
-#define lv1ent_fault(sent) (((*(sent)  3) == 0) || ((*(sent)  3) == 3))
-#define lv1ent_page(sent) ((*(sent)  3) == 1)
+#define lv1ent_fault(sent) ((*(sent) == ZERO_LV2LINK) || \
+  ((*(sent)  3) == 0) || ((*(sent)  3) == 3))
+#define lv1ent_zero(sent) (*(sent) == ZERO_LV2LINK)
+#define lv1ent_page_zero(sent) ((*(sent)  3) == 1)
+#define lv1ent_page(sent) ((*(sent) != ZERO_LV2LINK)  \
+ ((*(sent)  3) == 1))
 #define lv1ent_section(sent) ((*(sent)  3) == 2)
 
 #define lv2ent_fault(pent) ((*(pent)  3) == 0)
@@ -137,6 +141,8 @@ typedef u32 sysmmu_iova_t;
 typedef u32 sysmmu_pte_t;
 
 static struct kmem_cache *lv2table_kmem_cache;
+static sysmmu_pte_t *zero_lv2_table;
+#define ZERO_LV2LINK mk_lv1ent_page(virt_to_phys(zero_lv2_table))
 
 static sysmmu_pte_t *section_entry(sysmmu_pte_t *pgtable, sysmmu_iova_t iova)
 {
@@ -538,6 +544,33 @@ static bool exynos_sysmmu_disable(struct device *dev)
return disabled;
 }
 
+static void __sysmmu_tlb_invalidate_flpdcache(struct sysmmu_drvdata *data,
+ sysmmu_iova_t iova)
+{
+   if (__raw_sysmmu_version(data) == MAKE_MMU_VER(3, 3))
+   __raw_writel(iova | 0x1, data-sfrbase + REG_MMU_FLUSH_ENTRY);
+}
+
+static void sysmmu_tlb_invalidate_flpdcache(struct device *dev,
+   sysmmu_iova_t iova)
+{
+   struct sysmmu_list_data *list;
+
+   for_each_sysmmu_list(dev, list) {
+   unsigned long flags;
+   struct sysmmu_drvdata *data = dev_get_drvdata(list-sysmmu);
+
+   __master_clk_enable(data);
+
+   spin_lock_irqsave(data-lock, flags);
+   if (is_sysmmu_active(data)  data-runtime_active

[PATCH v11 25/27] iommu/exynos: use simpler function to get MMU version

2014-03-13 Thread Cho KyongHo
This commit changes the function to get MMU version simpler.

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |   30 ++
 1 file changed, 6 insertions(+), 24 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 6e716cc..3d4dabb 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -251,24 +251,6 @@ static unsigned int __raw_sysmmu_version(struct 
sysmmu_drvdata *data)
return MMU_RAW_VER(__raw_readl(data-sfrbase + REG_MMU_VERSION));
 }
 
-static unsigned int __sysmmu_version(struct sysmmu_drvdata *data,
-unsigned int *minor)
-{
-   unsigned int ver = 0;
-
-   ver = __raw_sysmmu_version(data);
-   if (ver  MAKE_MMU_VER(3, 3)) {
-   dev_err(data-sysmmu, %s: version(%d.%d) is higher than 3.3\n,
-   __func__, MMU_MAJ_VER(ver), MMU_MIN_VER(ver));
-   BUG();
-   }
-
-   if (minor)
-   *minor = MMU_MIN_VER(ver);
-
-   return MMU_MAJ_VER(ver);
-}
-
 static bool sysmmu_block(void __iomem *sfrbase)
 {
int i = 120;
@@ -422,13 +404,13 @@ static bool __sysmmu_disable(struct sysmmu_drvdata *data)
 static void __sysmmu_init_config(struct sysmmu_drvdata *data)
 {
unsigned int cfg = CFG_LRU | CFG_QOS(15);
-   int maj, min = 0;
+   unsigned int ver;
 
-   maj = __sysmmu_version(data, min);
-   if (maj == 3) {
-   if (min = 2) {
+   ver = __raw_sysmmu_version(data);
+   if (MMU_MAJ_VER(ver) == 3) {
+   if (MMU_MIN_VER(ver) = 2) {
cfg |= CFG_FLPDCACHE;
-   if (min == 3) {
+   if (MMU_MIN_VER(ver) == 3) {
cfg |= CFG_ACGEN;
cfg = ~CFG_LRU;
} else {
@@ -583,7 +565,7 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, 
sysmmu_iova_t iova,
 * 1MB page can be cached in one of all sets.
 * 64KB page can be one of 16 consecutive sets.
 */
-   if (__sysmmu_version(data, NULL) == 2)
+   if (MMU_MAJ_VER(__raw_sysmmu_version(data)) == 2)
num_inv = min_t(unsigned int,
size / PAGE_SIZE, 64);
 
-- 
1.7.9.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v11 27/27] iommu/exynos: enhanced error messages

2014-03-13 Thread Cho KyongHo
Some redundant error message is removed and some error messages
are changed to error level from debug level.

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |   23 +--
 1 file changed, 9 insertions(+), 14 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 4888383..b7f7731 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -1012,7 +1012,7 @@ static void exynos_iommu_detach_device(struct 
iommu_domain *domain,
dev_dbg(dev, %s: Detached IOMMU with pgtable %pa\n,
__func__, pgtable);
} else {
-   dev_dbg(dev, %s: No IOMMU is attached\n, __func__);
+   dev_err(dev, %s: No IOMMU is attached\n, __func__);
}
 }
 
@@ -1112,10 +1112,8 @@ static int lv2set_page(sysmmu_pte_t *pent, phys_addr_t 
paddr, size_t size,
short *pgcnt)
 {
if (size == SPAGE_SIZE) {
-   if (!lv2ent_fault(pent)) {
-   WARN(1, Trying mapping on 4KiB where mapping exists);
+   if (WARN_ON(!lv2ent_fault(pent)))
return -EADDRINUSE;
-   }
 
*pent = mk_lv2ent_spage(paddr);
pgtable_flush(pent, pent + 1);
@@ -1123,9 +1121,7 @@ static int lv2set_page(sysmmu_pte_t *pent, phys_addr_t 
paddr, size_t size,
} else { /* size == LPAGE_SIZE */
int i;
for (i = 0; i  SPAGES_PER_LPAGE; i++, pent++) {
-   if (!lv2ent_fault(pent)) {
-   WARN(1,
-   Trying mapping on 64KiB where mapping exists);
+   if (WARN_ON(!lv2ent_fault(pent))) {
if (i  0)
memset(pent - i, 0, sizeof(*pent) * i);
return -EADDRINUSE;
@@ -1198,8 +1194,8 @@ static int exynos_iommu_map(struct iommu_domain *domain, 
unsigned long l_iova,
}
 
if (ret)
-   pr_debug(%s: Failed to map iova %#x/%#zx bytes\n,
-   __func__, iova, size);
+   pr_err(%s: Failed(%d) to map %#zx bytes @ %#x\n,
+   __func__, ret, size, iova);
 
spin_unlock_irqrestore(priv-pgtablelock, flags);
 
@@ -1236,7 +1232,7 @@ static size_t exynos_iommu_unmap(struct iommu_domain 
*domain,
ent = section_entry(priv-pgtable, iova);
 
if (lv1ent_section(ent)) {
-   if (size  SECT_SIZE) {
+   if (WARN_ON(size  SECT_SIZE)) {
err_pgsize = SECT_SIZE;
goto err;
}
@@ -1271,7 +1267,7 @@ static size_t exynos_iommu_unmap(struct iommu_domain 
*domain,
}
 
/* lv1ent_large(ent) == true here */
-   if (size  LPAGE_SIZE) {
+   if (WARN_ON(size  LPAGE_SIZE)) {
err_pgsize = LPAGE_SIZE;
goto err;
}
@@ -1290,9 +1286,8 @@ done:
 err:
spin_unlock_irqrestore(priv-pgtablelock, flags);
 
-   WARN(1,
-   %s: Failed due to size(%#zx) @ %#x is smaller than page size %#zx\n,
-   __func__, size, iova, err_pgsize);
+   pr_err(%s: Failed: size(%#zx) @ %#x is smaller than page size %#zx\n,
+   __func__, size, iova, err_pgsize);
 
return 0;
 }
-- 
1.7.9.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


RE: [PATCH] iommu/exynos: Remove driver

2014-02-13 Thread Cho KyongHo
 -Original Message-
 From: Olof Johansson [mailto:o...@lixom.net]
 Sent: Friday, February 14, 2014 4:34 AM
 
 On Mon, Feb 10, 2014 at 10:21 PM, Kukjin Kim kgene@gmail.com wrote:
 
  Just adding KyongHo Cho.
 
  If he can fixup for this time, it would be best solution because he knows
  well than others, I think.
 
 It's not so much a matter of fixup for this time, it's a about
 having ownership of the driver, making sure it works (and keeps
 working if there is related development). The posted patches have not
 been followed through on and the result is a broken driver. :(
 
 I definitely appreciate his expertise, and we should make sure that he
 gets to review the code, but if someone else is able to spend time on
 reworking the driver (or rewriting a newer one) and maintaining it
 longer-term, then we should not stop them from doing so. And there is
 no reason to keep broken stale code in the kernel meanwhile.
 

Thank you for your concerning.
I also definitely agree with you that the driver must work.
I am always concerning about it but it was not easy to make some time
for the patches.

I will continue to post the next version of patches, of course.
I think it is not far from now to show it.

Regards,

Ky0ongHo

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v10 00/20] iommu/exynos: Fixes and Enhancements of System MMU driver with DT

2013-11-01 Thread Cho KyongHo
On Fri, 01 Nov 2013 12:42:24 +0100, Joerg Roedel wrote:
 On Mon, Oct 07, 2013 at 10:52:12AM +0900, Cho KyongHo wrote:
  Patch summary:
  [PATCH 01/20] iommu/exynos: do not include removed header
  [PATCH 02/20] iommu/exynos: add missing cache flush for removed page table 
  entries
  [PATCH 03/20] iommu/exynos: change error handling when page table update is 
  failed
  [PATCH 04/20] iommu/exynos: fix L2TLB invalidation
  [PATCH 05/20] iommu/exynos: allocate lv2 page table from own slab
  [PATCH 06/20] iommu/exynos: always enable runtime PM
  [PATCH 07/20] iommu/exynos: always use a single clock descriptor
  [PATCH 08/20] iommu/exynos: remove dbgname from drvdata of a System MMU
  [PATCH 09/20] iommu/exynos: use managed device helper functions
  [PATCH 10/20] clk: exynos: add gate clock descriptions of System MMU
  [PATCH 11/20] ARM: dts: Add description of System MMU of Exynos SoCs
  [PATCH 12/20] iommu/exynos: support for device tree
  [PATCH 13/20] iommu/exynos: gating clocks of master H/W
  [PATCH 14/20] iommu/exynos: remove custom fault handler
  [PATCH 15/20] iommu/exynos: remove calls to Runtime PM API functions
  [PATCH 16/20] iommu/exynos: turn on useful configuration options
  [PATCH 17/20] iommu/exynos: add support for power management subsystems.
  [PATCH 18/20] iommu/exynos: change rwlock to spinlock
  [PATCH 19/20] iommu/exynos: return 0 if iommu_attach_device() successes
  [PATCH 20/20] iommu/exynos: add devices attached to the System MMU to an 
  IOMMU group
  
  Diffstats:
   .../devicetree/bindings/clock/exynos5250-clock.txt |   28 +
   .../devicetree/bindings/clock/exynos5420-clock.txt |3 +
   .../bindings/iommu/samsung,exynos4210-sysmmu.txt   |   76 ++
   arch/arm/boot/dts/exynos4.dtsi |  105 ++
   arch/arm/boot/dts/exynos4210.dtsi  |   21 +
   arch/arm/boot/dts/exynos4x12.dtsi  |   82 ++
   arch/arm/boot/dts/exynos5250.dtsi  |  262 +
   arch/arm/boot/dts/exynos5420.dtsi  |  296 ++
   drivers/clk/samsung/clk-exynos5250.c   |   49 +-
   drivers/clk/samsung/clk-exynos5420.c   |   12 +-
   drivers/iommu/Kconfig  |5 +-
   drivers/iommu/exynos-iommu.c   | 1033 
  +---
   12 files changed, 1585 insertions(+), 387 deletions(-)
 
 What is the state of this series? It would be good to have some
 Acked-bys and/or Reviewed-bys on it.
 

I am preparing next patches to apply Alex Williamson's comment that
description of IOMMU's masters must be aligned with ARM SMMU.

It is delayed due to my jobs in the office.

I will post the next patche series in two weeks.

Thanks.

 
   Joerg
 
 
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v10 20/20] iommu/exynos: add devices attached to the System MMU to an IOMMU group

2013-10-14 Thread Cho KyongHo
On Thu, 10 Oct 2013 14:54:29 -0600, Alex Williamson wrote:
 On Mon, 2013-10-07 at 10:58 +0900, Cho KyongHo wrote:
  Patch written by Antonios Motakis a.mota...@virtualopensystems.com:
  
  IOMMU groups are expected by certain users of the IOMMU API,
  e.g. VFIO. Since each device is behind its own System MMU, we
  can allocate a new IOMMU group for each device.
  
  Reviewd-by: Cho KyongHo pullip@samsung.com
  Signed-off-by: Antonios Motakis a.mota...@virtualopensystems.com
  ---
   drivers/iommu/exynos-iommu.c |   28 
   1 files changed, 28 insertions(+), 0 deletions(-)
  
  diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
  index 5025338..24505a0 100644
  --- a/drivers/iommu/exynos-iommu.c
  +++ b/drivers/iommu/exynos-iommu.c
  @@ -1028,6 +1028,32 @@ static phys_addr_t exynos_iommu_iova_to_phys(struct 
  iommu_domain *domain,
  return phys;
   }
   
  +static int exynos_iommu_add_device(struct device *dev)
  +{
  +   struct iommu_group *group;
  +   int ret;
  +
  +   group = iommu_group_get(dev);
 
 Seems reasonable, my only nit would be whether it's really an error to
 get a group back from the above call.  If devices are always isolated
 and IOMMU groups are always singleton, it would be an error to find one
 already associated with the device.  Right?  Thanks,
 
Do you mean that calling iommu_group_add_device() with the group that is
returned by the above iommu_group_get() will return -EEXIST?

I didn't think about that.

 Alex

Thank you.

KyongHo.
 
  +
  +   if (!group) {
  +   group = iommu_group_alloc();
  +   if (IS_ERR(group)) {
  +   dev_err(dev, Failed to allocate IOMMU group\n);
  +   return PTR_ERR(group);
  +   }
  +   }
  +
  +   ret = iommu_group_add_device(group, dev);
  +   iommu_group_put(group);
  +
  +   return ret;
  +}
  +
  +static void exynos_iommu_remove_device(struct device *dev)
  +{
  +   iommu_group_remove_device(dev);
  +}
  +
   static struct iommu_ops exynos_iommu_ops = {
  .domain_init = exynos_iommu_domain_init,
  .domain_destroy = exynos_iommu_domain_destroy,
  @@ -1036,6 +1062,8 @@ static struct iommu_ops exynos_iommu_ops = {
  .map = exynos_iommu_map,
  .unmap = exynos_iommu_unmap,
  .iova_to_phys = exynos_iommu_iova_to_phys,
  +   .add_device = exynos_iommu_add_device,
  +   .remove_device = exynos_iommu_remove_device,
  .pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE,
   };
   
 
 
 
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v8 06/12] ARM: dts: Add description of System MMU of Exynos SoCs

2013-10-07 Thread Cho KyongHo
On Mon, 07 Oct 2013 08:44:54 -0500, Rob Herring wrote:
 On Fri, Jul 26, 2013 at 6:28 AM, Cho KyongHo pullip@samsung.com wrote:
  Signed-off-by: Cho KyongHo pullip@samsung.com
  ---
   .../bindings/iommu/samsung,exynos4210-sysmmu.txt   |  103 +++
   arch/arm/boot/dts/exynos4.dtsi |  122 
   arch/arm/boot/dts/exynos4210.dtsi  |   25 ++
   arch/arm/boot/dts/exynos4x12.dtsi  |   76 +
   arch/arm/boot/dts/exynos5250.dtsi  |  291 
  
   5 files changed, 617 insertions(+), 0 deletions(-)
   create mode 100644 
  Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.txt
 
  diff --git 
  a/Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.txt
  b/Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.txt
  new file mode 100644
  index 000..92f0a33
  --- /dev/null
  +++ b/Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.txt
  @@ -0,0 +1,103 @@
  +Samsung Exynos4210 IOMMU H/W, System MMU (System Memory Management Unit)
  +
  +Samsung's Exynos architecture contains System MMU that enables scattered
  +physical memory chunks visible as a contiguous region to DMA-capable 
  peripheral
  +devices like MFC, FIMC, FIMD, GScaler, FIMC-IS and so forth.
  +
  +System MMU is a sort of IOMMU and support identical translation table 
  format to
  +ARMv7 translation tables with minimum set of page properties including 
  access
  +permissions, shareability and security protection. In addition, System MMU 
  has
  +another capabilities like L2 TLB or block-fetch buffers to minimize 
  translation
  +latency.
  +
  +A System MMU is dedicated to a single master peripheral device.  Thus, it 
  is
  +important to specify the correct System MMU in the device node of its 
  master
  +device. Whereas a System MMU is dedicated to a master device, the master 
  device
  +may have more than one System MMU.
  +
  +Required properties:
  +- compatible: Should be samsung,exynos4210-sysmmu
  +- reg: A tuple of base address and size of System MMU registers.
  +- interrupt-parent: The phandle of the interrupt controller of System MMU
  +- interrupts: A tuple of numbers that indicates the interrupt source.
  +- clock-names: Should be sysmmu if the System MMU is needed to gate its 
  clock.
  +   Please refer to the following documents:
  +  Documentation/devicetree/bindings/clock/clock-bindings.txt
  +  Documentation/devicetree/bindings/clock/exynos4-clock.txt
  +  Documentation/devicetree/bindings/clock/exynos5250-clock.txt
  +  Optional master if the clock to the System MMU is gated by
  +  another gate clock other than sysmmu. The System MMU driver
  +  sets master the parent of sysmmu.
  +  Exynos4 SoCs, there needs no master clocks.
  +  Exynos5 SoCs, some System MMUs must have master clocks.
  +- clocks: Required if the System MMU is needed to gate its clock.
  + Please refer to the documents listed above.
  +- samsung,power-domain: Required if the System MMU is needed to gate its 
  power.
  + Please refer to the following document:
  + Documentation/devicetree/bindings/arm/exynos/power_domain.txt
  +
  +Required properties for the master peripheral devices:
  +- iommu: phandles to the System MMUs of the device
 
 You have not addressed my comments from the last version. We do not
 need 2 (or more) different ways to describe the connection between
 masters and iommu's. Use mmu-masters property here to describe the
 connection.
 

Sorry, I forgot to reply.
I just thought the meaning of your comment that it should be align with ARM 
System MMU.
I now understand and it should be changed to mmu-masters property
because it is now in the kernel.

Thank you.


 Rob
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v10 00/20] iommu/exynos: Fixes and Enhancements of System MMU driver with DT

2013-10-06 Thread Cho KyongHo
The current exynos-iommu(System MMU) driver does not work autonomously
since it is lack of support for power management of peripheral blocks.
For example, MFC device driver must ensure that its System MMU is disabled
before MFC block is power-down not to invalidate IOTLB in the System MMU
when I/O memory mapping is changed. Because a System MMU resides in the
same H/W block, access to control registers of System MMU while the H/W
block is turned off must be prohibited.

This set of changes solves the above problem with setting each System MMUs
as the parent of the device which owns the System MMU to receive the
information when the device is turned off or turned on.

Another big change to the driver is the support for devicetree.
The bindings for System MMU is described in
Documentation/devicetree/bindings/arm/samsung/system-mmu.txt

In addition, this patchset also includes several bug fixes and enhancements
of the current driver.

Change log:
v10:
- Rebased on the following branches
  git.linaro.org/git-ro/people/mturquette/linux.git/clk-next
  git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung.git/for-next
  git.kernel.org/pub/scm/linux/kernel/git/joro/iommu.git/next
  git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/master (3.12-rc3)
- Set parent clock to all System MMU clocks.
- Add clock and DT descriptos for Exynos5420
- Modified error handling in exynos_iommu_init()
- Split iommu/exynos: support for device tree patch into the following 6 
patches
  iommu/exynos: handle only one instance of System MMU
  iommu/exynos: always enable runtime PM
  iommu/exynos: always use a single clock descriptor
  iommu/exynos: remove dbgname from drvdata of a System MMU
  iommu/exynos: use managed driver helper functions
  iommu/exynos: support for device tree
- Remove 'interrupt-names' and 'status' properties from DT
- Change n:1 relationship between master:System MMU into 1:1 relationship.
- Removed custom fault handler and print the status of System MMU
  whenever System MMU fault is occurred.
- Post Antonios Motakis's commit together:
  iommu/exynos: add devices attached to the System MMU to an IOMMU group

v9:
- Rebased on the following branches
  git.linaro.org/git-ro/people/mturquette/linux.git/clk-next
  git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung.git/samsung-next
  git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/master (3.11-rc4)
- Split add bus notifier for registering System MMU into 5 patches
- Call clk_prepare() that was missing in v8.
- Fixed base address of sysmmu_tv in exynos4210.dtsi
- BUG_ON() instead of return -EADDRINUSE when trying mapping on an mapped area
- Moved camif_top to 317 in drivers/clk/samsung/clk-exynos5250.c
- Removed 'iommu' property from 'codec'(mfc) node
- Does not make 'master' clock to be the parent of 'sysmmu' clock.
   'master' clock is enabled before accessing control registers of System MMU
   and disabled after the access.

v8:
- Reordered patch list: moved change rwloc to spinlock to the last.
- Fixed remained bug in fix page table maintenance.
- Always return 0 from exynos_iommu_attach_device().
- Removed prefetch buffer setting when System MMU is enabled
  due to the restriction of prefetch buffers:
  A prefetch buffer must not hit from more than one DMA.
  For instance with GScalers, if a single prefetch buffer is initialized
  with 0x0 ~ 0x and a GScaler works on source buffer at 0x1000
  and target buffer @ 0x2000, the System MMU may be got deadlock.
  Clients must initialize prefetch buffers with custom function defined
  in exynos-iommu drivers whenever they need to enable prefetch buffers.
- The clock of System MMU has no relationship with the clock of its master H/W.
  The clock of master H/W is always enabled when exynos-iommu driver needs to
  access MMIO area and disabled as soon as the access finishes.
- Removed err_page variable used in exynos_iommu_unmap() in the previous patch
  fix page table maintenance.
- Split a big patch add bus notifier for registering System MMU.
   Extracted the following 2 patches: 9/12 and 10/12.
- And some additional fixes...

v7:
- Rebased on the stable 3.10
- Registered PM domains and gate clocks with DT
- Changed connection method between a System MMU and its master H/W
   'mmu-master' property in the node of System MMU
   -- 'iommu' property in the node of master H/W
- Marking device descriptor of master H/W of a System MMU with bus notifier.
- Power management (PM_RUNTIME, PM_SLEEP) of System MMUs with gpd_dev_ops
   of Generic IO Powerdomain. gpd_dev_ops are set to the master H/Ws
   before they are probed in the bus notifier.
- Removed additional debugging features like debugfs entries and
   version names.
- Removed support for advanced features of System MMU 3.2 and 3.3
   the current IOMMU API cannot handle the feature
  (A kind of L2 TLB that fetches several consequence page table entries.
   It must be initialized by the driver of master H/W whenever it 

[PATCH v10 02/20] iommu/exynos: add missing cache flush for removed page table entries

2013-10-06 Thread Cho KyongHo
This commit adds cache flush for removed small and large page entries
in exynos_iommu_unmap(). Missing cache flush of removed page table
entries can cause missing page fault interrupt when a master IP
accesses an unmapped area.

Reviewed-by: Tomasz Figa t.f...@samsung.com
Tested-by: Grant Grundler grund...@chromium.org
Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 4876d35..1c3a397 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -958,6 +958,7 @@ static size_t exynos_iommu_unmap(struct iommu_domain 
*domain,
if (lv2ent_small(ent)) {
*ent = 0;
size = SPAGE_SIZE;
+   pgtable_flush(ent, ent + 1);
priv-lv2entcnt[lv1ent_offset(iova)] += 1;
goto done;
}
@@ -966,6 +967,7 @@ static size_t exynos_iommu_unmap(struct iommu_domain 
*domain,
BUG_ON(size  LPAGE_SIZE);
 
memset(ent, 0, sizeof(*ent) * SPAGES_PER_LPAGE);
+   pgtable_flush(ent, ent + SPAGES_PER_LPAGE);
 
size = LPAGE_SIZE;
priv-lv2entcnt[lv1ent_offset(iova)] += SPAGES_PER_LPAGE;
-- 
1.7.2.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v10 01/20] iommu/exynos: do not include removed header

2013-10-06 Thread Cho KyongHo
Commit 25e9d28d92 (ARM: EXYNOS: remove system mmu initialization from
exynos tree) removed arch/arm/mach-exynos/mach/sysmmu.h header without
removing remaining use of it from exynos-iommu driver, thus causing a
compilation error.

This patch fixes the error by removing respective include line
from exynos-iommu.c.

CC: Tomasz Figa t.f...@samsung.com
Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 0740189..4876d35 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -12,6 +12,7 @@
 #define DEBUG
 #endif
 
+#include linux/kernel.h
 #include linux/io.h
 #include linux/interrupt.h
 #include linux/platform_device.h
@@ -29,8 +30,6 @@
 #include asm/cacheflush.h
 #include asm/pgtable.h
 
-#include mach/sysmmu.h
-
 /* We does not consider super section mapping (16MB) */
 #define SECT_ORDER 20
 #define LPAGE_ORDER 16
-- 
1.7.2.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v10 04/20] iommu/exynos: fix L2TLB invalidation

2013-10-06 Thread Cho KyongHo
L2TLB is 8-way set-associative TLB with 512 entries. The number of
sets is 64.
A single 4KB(small page) translation information is cached
only to a set whose index is the same with the lower 6 bits of the page
frame number.
A single 64KB(large page) translation information can be
cached to any 16 sets whose top two bits of their indices are the same
with the bit [5:4] of the page frame number.
A single 1MB(section) or larger translation information can be cached to
any set in the TLB.

It is required to invalidate entire sets that may cache the target
translation information to guarantee that the L2TLB has no stale data.

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |   27 ++-
 1 files changed, 22 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 4a74ed8..cbe1e5a 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -225,9 +225,14 @@ static void __sysmmu_tlb_invalidate(void __iomem *sfrbase)
 }
 
 static void __sysmmu_tlb_invalidate_entry(void __iomem *sfrbase,
-   unsigned long iova)
+   unsigned long iova, unsigned int num_inv)
 {
-   __raw_writel((iova  SPAGE_MASK) | 1, sfrbase + REG_MMU_FLUSH_ENTRY);
+   unsigned int i;
+   for (i = 0; i  num_inv; i++) {
+   __raw_writel((iova  SPAGE_MASK) | 1,
+   sfrbase + REG_MMU_FLUSH_ENTRY);
+   iova += SPAGE_SIZE;
+   }
 }
 
 static void __sysmmu_set_ptbase(void __iomem *sfrbase,
@@ -477,7 +482,8 @@ static bool exynos_sysmmu_disable(struct device *dev)
return disabled;
 }
 
-static void sysmmu_tlb_invalidate_entry(struct device *dev, unsigned long iova)
+static void sysmmu_tlb_invalidate_entry(struct device *dev, unsigned long iova,
+   size_t size)
 {
unsigned long flags;
struct sysmmu_drvdata *data = dev_get_drvdata(dev-archdata.iommu);
@@ -487,9 +493,20 @@ static void sysmmu_tlb_invalidate_entry(struct device 
*dev, unsigned long iova)
if (is_sysmmu_active(data)) {
int i;
for (i = 0; i  data-nsfrs; i++) {
+   unsigned int maj;
+   unsigned int num_inv = 1;
+   maj = __raw_readl(data-sfrbases[i] + REG_MMU_VERSION);
+   /*
+* L2TLB invalidation required
+* 4KB page: 1 invalidation
+* 64KB page: 16 invalidation
+* 1MB page: 64 invalidation
+*/
+   if ((maj  28) == 2) /* major version number */
+   num_inv = min_t(unsigned int, size / PAGE_SIZE, 
64);
if (sysmmu_block(data-sfrbases[i])) {
__sysmmu_tlb_invalidate_entry(
-   data-sfrbases[i], iova);
+   data-sfrbases[i], iova, num_inv);
sysmmu_unblock(data-sfrbases[i]);
}
}
@@ -999,7 +1016,7 @@ done:
 
spin_lock_irqsave(priv-lock, flags);
list_for_each_entry(data, priv-clients, node)
-   sysmmu_tlb_invalidate_entry(data-dev, iova);
+   sysmmu_tlb_invalidate_entry(data-dev, iova, size);
spin_unlock_irqrestore(priv-lock, flags);
 
return size;
-- 
1.7.2.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v10 03/20] iommu/exynos: change error handling when page table update is failed

2013-10-06 Thread Cho KyongHo
This patch changes not to panic on any error when updating page table.
Instead prints error messages with callstack.

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |   58 +++--
 1 files changed, 44 insertions(+), 14 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 1c3a397..4a74ed8 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -812,13 +812,18 @@ finish:
 static unsigned long *alloc_lv2entry(unsigned long *sent, unsigned long iova,
short *pgcounter)
 {
+   if (lv1ent_section(sent)) {
+   WARN(1, Trying mapping on %#08lx mapped with 1MiB page, iova);
+   return ERR_PTR(-EADDRINUSE);
+   }
+
if (lv1ent_fault(sent)) {
unsigned long *pent;
 
pent = kzalloc(LV2TABLE_SIZE, GFP_ATOMIC);
BUG_ON((unsigned long)pent  (LV2TABLE_SIZE - 1));
if (!pent)
-   return NULL;
+   return ERR_PTR(-ENOMEM);
 
*sent = mk_lv1ent_page(__pa(pent));
*pgcounter = NUM_LV2ENTRIES;
@@ -829,14 +834,21 @@ static unsigned long *alloc_lv2entry(unsigned long *sent, 
unsigned long iova,
return page_entry(sent, iova);
 }
 
-static int lv1set_section(unsigned long *sent, phys_addr_t paddr, short *pgcnt)
+static int lv1set_section(unsigned long *sent, unsigned long iova,
+ phys_addr_t paddr, short *pgcnt)
 {
-   if (lv1ent_section(sent))
+   if (lv1ent_section(sent)) {
+   WARN(1, Trying mapping on 1MiB@%#08lx that is mapped,
+   iova);
return -EADDRINUSE;
+   }
 
if (lv1ent_page(sent)) {
-   if (*pgcnt != NUM_LV2ENTRIES)
+   if (*pgcnt != NUM_LV2ENTRIES) {
+   WARN(1, Trying mapping on 1MiB@%#08lx that is mapped,
+   iova);
return -EADDRINUSE;
+   }
 
kfree(page_entry(sent, 0));
 
@@ -854,8 +866,10 @@ static int lv2set_page(unsigned long *pent, phys_addr_t 
paddr, size_t size,
short *pgcnt)
 {
if (size == SPAGE_SIZE) {
-   if (!lv2ent_fault(pent))
+   if (!lv2ent_fault(pent)) {
+   WARN(1, Trying mapping on 4KiB where mapping exists);
return -EADDRINUSE;
+   }
 
*pent = mk_lv2ent_spage(paddr);
pgtable_flush(pent, pent + 1);
@@ -864,7 +878,10 @@ static int lv2set_page(unsigned long *pent, phys_addr_t 
paddr, size_t size,
int i;
for (i = 0; i  SPAGES_PER_LPAGE; i++, pent++) {
if (!lv2ent_fault(pent)) {
-   memset(pent, 0, sizeof(*pent) * i);
+   WARN(1,
+   Trying mapping on 64KiB where mapping exists);
+   if (i  0)
+   memset(pent - i, 0, sizeof(*pent) * i);
return -EADDRINUSE;
}
 
@@ -892,7 +909,7 @@ static int exynos_iommu_map(struct iommu_domain *domain, 
unsigned long iova,
entry = section_entry(priv-pgtable, iova);
 
if (size == SECT_SIZE) {
-   ret = lv1set_section(entry, paddr,
+   ret = lv1set_section(entry, iova, paddr,
priv-lv2entcnt[lv1ent_offset(iova)]);
} else {
unsigned long *pent;
@@ -900,17 +917,16 @@ static int exynos_iommu_map(struct iommu_domain *domain, 
unsigned long iova,
pent = alloc_lv2entry(entry, iova,
priv-lv2entcnt[lv1ent_offset(iova)]);
 
-   if (!pent)
-   ret = -ENOMEM;
+   if (IS_ERR(pent))
+   ret = PTR_ERR(pent);
else
ret = lv2set_page(pent, paddr, size,
priv-lv2entcnt[lv1ent_offset(iova)]);
}
 
-   if (ret) {
+   if (ret)
pr_debug(%s: Failed to map iova 0x%lx/0x%x bytes\n,
__func__, iova, size);
-   }
 
spin_unlock_irqrestore(priv-pgtablelock, flags);
 
@@ -924,6 +940,7 @@ static size_t exynos_iommu_unmap(struct iommu_domain 
*domain,
struct sysmmu_drvdata *data;
unsigned long flags;
unsigned long *ent;
+   size_t err_pgsize;
 
BUG_ON(priv-pgtable == NULL);
 
@@ -932,7 +949,10 @@ static size_t exynos_iommu_unmap(struct iommu_domain 
*domain,
ent = section_entry(priv-pgtable, iova);
 
if (lv1ent_section(ent)) {
-   BUG_ON(size  SECT_SIZE

[PATCH v10 05/20] iommu/exynos: allocate lv2 page table from own slab

2013-10-06 Thread Cho KyongHo
Since kmalloc() does not guarantee that the allignment of 1KiB when it
allocates 1KiB, it is required to allocate lv2 page table from own
slab that guarantees alignment of 1KiB

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |   34 --
 1 files changed, 28 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index cbe1e5a..191cb3f 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -100,6 +100,8 @@
 #define REG_PB1_SADDR  0x054
 #define REG_PB1_EADDR  0x058
 
+static struct kmem_cache *lv2table_kmem_cache;
+
 static unsigned long *section_entry(unsigned long *pgtable, unsigned long iova)
 {
return pgtable + lv1ent_offset(iova);
@@ -738,7 +740,8 @@ static void exynos_iommu_domain_destroy(struct iommu_domain 
*domain)
 
for (i = 0; i  NUM_LV1ENTRIES; i++)
if (lv1ent_page(priv-pgtable + i))
-   kfree(__va(lv2table_base(priv-pgtable + i)));
+   kmem_cache_free(lv2table_kmem_cache,
+   __va(lv2table_base(priv-pgtable + i)));
 
free_pages((unsigned long)priv-pgtable, 2);
free_pages((unsigned long)priv-lv2entcnt, 1);
@@ -837,7 +840,7 @@ static unsigned long *alloc_lv2entry(unsigned long *sent, 
unsigned long iova,
if (lv1ent_fault(sent)) {
unsigned long *pent;
 
-   pent = kzalloc(LV2TABLE_SIZE, GFP_ATOMIC);
+   pent = kmem_cache_zalloc(lv2table_kmem_cache, GFP_ATOMIC);
BUG_ON((unsigned long)pent  (LV2TABLE_SIZE - 1));
if (!pent)
return ERR_PTR(-ENOMEM);
@@ -867,8 +870,7 @@ static int lv1set_section(unsigned long *sent, unsigned 
long iova,
return -EADDRINUSE;
}
 
-   kfree(page_entry(sent, 0));
-
+   kmem_cache_free(lv2table_kmem_cache, page_entry(sent, 0));
*pgcnt = 0;
}
 
@@ -1073,11 +1075,31 @@ static int __init exynos_iommu_init(void)
 {
int ret;
 
+   lv2table_kmem_cache = kmem_cache_create(exynos-iommu-lv2table,
+   LV2TABLE_SIZE, LV2TABLE_SIZE, 0, NULL);
+   if (!lv2table_kmem_cache) {
+   pr_err(%s: Failed to create kmem cache\n, __func__);
+   return -ENOMEM;
+   }
+
ret = platform_driver_register(exynos_sysmmu_driver);
+   if (ret) {
+   pr_err(%s: Failed to register driver\n, __func__);
+   goto err_reg_driver;
+   }
 
-   if (ret == 0)
-   bus_set_iommu(platform_bus_type, exynos_iommu_ops);
+   ret = bus_set_iommu(platform_bus_type, exynos_iommu_ops);
+   if (ret) {
+   pr_err(%s: Failed to register exynos-iommu driver.\n,
+   __func__);
+   goto err_set_iommu;
+   }
 
+   return 0;
+err_set_iommu:
+   platform_driver_unregister(exynos_sysmmu_driver);
+err_reg_driver:
+   kmem_cache_destroy(lv2table_kmem_cache);
return ret;
 }
 subsys_initcall(exynos_iommu_init);
-- 
1.7.2.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v10 07/20] iommu/exynos: always use a single clock descriptor

2013-10-06 Thread Cho KyongHo
System MMU driver is changed to control only a single instance of
System MMU at a time. Since a single instance of System MMU has only
a single clock descriptor for its clock gating, there is no need to
obtain two or more clock descriptors.

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |  222 ++
 1 files changed, 73 insertions(+), 149 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 20b032f..0092359 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -171,9 +171,8 @@ struct sysmmu_drvdata {
struct device *sysmmu;  /* System MMU's device descriptor */
struct device *dev; /* Owner of system MMU */
char *dbgname;
-   int nsfrs;
-   void __iomem **sfrbases;
-   struct clk *clk[2];
+   void __iomem *sfrbase;
+   struct clk *clk;
int activations;
rwlock_t lock;
struct iommu_domain *domain;
@@ -301,56 +300,39 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void 
*dev_id)
 {
/* SYSMMU is in blocked when interrupt occurred. */
struct sysmmu_drvdata *data = dev_id;
-   struct resource *irqres;
-   struct platform_device *pdev;
enum exynos_sysmmu_inttype itype;
unsigned long addr = -1;
-
-   int i, ret = -ENOSYS;
+   int ret = -ENOSYS;
 
read_lock(data-lock);
 
WARN_ON(!is_sysmmu_active(data));
 
-   pdev = to_platform_device(data-sysmmu);
-   for (i = 0; i  (pdev-num_resources / 2); i++) {
-   irqres = platform_get_resource(pdev, IORESOURCE_IRQ, i);
-   if (irqres  ((int)irqres-start == irq))
-   break;
-   }
-
-   if (i == pdev-num_resources) {
+   itype = (enum exynos_sysmmu_inttype)
+   __ffs(__raw_readl(data-sfrbase + REG_INT_STATUS));
+   if (WARN_ON(!((itype = 0)  (itype  SYSMMU_FAULT_UNKNOWN
itype = SYSMMU_FAULT_UNKNOWN;
-   } else {
-   itype = (enum exynos_sysmmu_inttype)
-   __ffs(__raw_readl(data-sfrbases[i] + REG_INT_STATUS));
-   if (WARN_ON(!((itype = 0)  (itype  SYSMMU_FAULT_UNKNOWN
-   itype = SYSMMU_FAULT_UNKNOWN;
-   else
-   addr = __raw_readl(
-   data-sfrbases[i] + fault_reg_offset[itype]);
-   }
+   else
+   addr = __raw_readl(data-sfrbase + fault_reg_offset[itype]);
 
if (data-domain)
-   ret = report_iommu_fault(data-domain, data-dev,
-   addr, itype);
+   ret = report_iommu_fault(data-domain, data-dev, addr, itype);
 
if ((ret == -ENOSYS)  data-fault_handler) {
unsigned long base = data-pgtable;
if (itype != SYSMMU_FAULT_UNKNOWN)
-   base = __raw_readl(
-   data-sfrbases[i] + REG_PT_BASE_ADDR);
+   base = __raw_readl(data-sfrbase + REG_PT_BASE_ADDR);
ret = data-fault_handler(itype, base, addr);
}
 
if (!ret  (itype != SYSMMU_FAULT_UNKNOWN))
-   __raw_writel(1  itype, data-sfrbases[i] + REG_INT_CLEAR);
+   __raw_writel(1  itype, data-sfrbase + REG_INT_CLEAR);
else
dev_dbg(data-sysmmu, (%s) %s is not handled.\n,
data-dbgname, sysmmu_fault_name[itype]);
 
if (itype != SYSMMU_FAULT_UNKNOWN)
-   sysmmu_unblock(data-sfrbases[i]);
+   sysmmu_unblock(data-sfrbase);
 
read_unlock(data-lock);
 
@@ -368,13 +350,10 @@ static bool __exynos_sysmmu_disable(struct sysmmu_drvdata 
*data)
if (!set_sysmmu_inactive(data))
goto finish;
 
-   for (i = 0; i  data-nsfrs; i++)
-   __raw_writel(CTRL_DISABLE, data-sfrbases[i] + REG_MMU_CTRL);
+   __raw_writel(CTRL_DISABLE, data-sfrbase + REG_MMU_CTRL);
 
-   if (data-clk[1])
-   clk_disable(data-clk[1]);
-   if (data-clk[0])
-   clk_disable(data-clk[0]);
+   if (data-clk)
+   clk_disable(data-clk);
 
disabled = true;
data-pgtable = 0;
@@ -417,27 +396,22 @@ static int __exynos_sysmmu_enable(struct sysmmu_drvdata 
*data,
goto finish;
}
 
-   if (data-clk[0])
-   clk_enable(data-clk[0]);
-   if (data-clk[1])
-   clk_enable(data-clk[1]);
+   if (data-clk)
+   clk_enable(data-clk);
 
data-pgtable = pgtable;
 
-   for (i = 0; i  data-nsfrs; i++) {
-   __sysmmu_set_ptbase(data-sfrbases[i], pgtable);
-
-   if ((readl(data-sfrbases[i] + REG_MMU_VERSION)  28) == 3) {
-   /* System MMU version is 3.x */
-   __raw_writel((1  12) | (2  28

[PATCH v10 06/20] iommu/exynos: always enable runtime PM

2013-10-06 Thread Cho KyongHo
Checking if the probing device has a parent device was just to discover
if the probing device is involved in a power domain when the power
domain controlled by Samsung's custom implementation.
Since generic IO power domain is applied, it is required to remove
the condition to see if the probing device has a parent device.

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |3 +--
 1 files changed, 1 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 191cb3f..20b032f 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -644,8 +644,7 @@ static int exynos_sysmmu_probe(struct platform_device *pdev)
 
__set_fault_handler(data, default_fault_handler);
 
-   if (dev-parent)
-   pm_runtime_enable(dev);
+   pm_runtime_enable(dev);
 
dev_dbg(dev, (%s) Initialized\n, data-dbgname);
return 0;
-- 
1.7.2.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v10 08/20] iommu/exynos: remove dbgname from drvdata of a System MMU

2013-10-06 Thread Cho KyongHo
This patch removes dbgname member from sysmmu_drvdata structure.
Kernel message for debugging already has the name of a single
System MMU node.

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |   34 +-
 1 files changed, 13 insertions(+), 21 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 0092359..735d75e 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -170,7 +170,6 @@ struct sysmmu_drvdata {
struct list_head node; /* entry of exynos_iommu_domain.clients */
struct device *sysmmu;  /* System MMU's device descriptor */
struct device *dev; /* Owner of system MMU */
-   char *dbgname;
void __iomem *sfrbase;
struct clk *clk;
int activations;
@@ -328,8 +327,8 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
if (!ret  (itype != SYSMMU_FAULT_UNKNOWN))
__raw_writel(1  itype, data-sfrbase + REG_INT_CLEAR);
else
-   dev_dbg(data-sysmmu, (%s) %s is not handled.\n,
-   data-dbgname, sysmmu_fault_name[itype]);
+   dev_dbg(data-sysmmu, %s is not handled.\n,
+   sysmmu_fault_name[itype]);
 
if (itype != SYSMMU_FAULT_UNKNOWN)
sysmmu_unblock(data-sfrbase);
@@ -362,10 +361,10 @@ finish:
write_unlock_irqrestore(data-lock, flags);
 
if (disabled)
-   dev_dbg(data-sysmmu, (%s) Disabled\n, data-dbgname);
+   dev_dbg(data-sysmmu, Disabled\n);
else
-   dev_dbg(data-sysmmu, (%s) %d times left to be disabled\n,
-   data-dbgname, data-activations);
+   dev_dbg(data-sysmmu, %d times left to be disabled\n,
+   data-activations);
 
return disabled;
 }
@@ -392,7 +391,7 @@ static int __exynos_sysmmu_enable(struct sysmmu_drvdata 
*data,
ret = 1;
}
 
-   dev_dbg(data-sysmmu, (%s) Already enabled\n, data-dbgname);
+   dev_dbg(data-sysmmu, Already enabled\n);
goto finish;
}
 
@@ -414,7 +413,7 @@ static int __exynos_sysmmu_enable(struct sysmmu_drvdata 
*data,
 
data-domain = domain;
 
-   dev_dbg(data-sysmmu, (%s) Enabled\n, data-dbgname);
+   dev_dbg(data-sysmmu, Enabled\n);
 finish:
write_unlock_irqrestore(data-lock, flags);
 
@@ -430,16 +429,15 @@ int exynos_sysmmu_enable(struct device *dev, unsigned 
long pgtable)
 
ret = pm_runtime_get_sync(data-sysmmu);
if (ret  0) {
-   dev_dbg(data-sysmmu, (%s) Failed to enable\n, data-dbgname);
+   dev_dbg(data-sysmmu, Failed to enable\n);
return ret;
}
 
ret = __exynos_sysmmu_enable(data, pgtable, NULL);
if (WARN_ON(ret  0)) {
pm_runtime_put(data-sysmmu);
-   dev_err(data-sysmmu,
-   (%s) Already enabled with page table %#lx\n,
-   data-dbgname, data-pgtable);
+   dev_err(data-sysmmu, Already enabled with page table %#lx\n,
+   data-pgtable);
} else {
data-dev = dev;
}
@@ -485,9 +483,7 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, 
unsigned long iova,
sysmmu_unblock(data-sfrbase);
}
} else {
-   dev_dbg(data-sysmmu,
-   (%s) Disabled. Skipping invalidating TLB.\n,
-   data-dbgname);
+   dev_dbg(data-sysmmu, Disabled. Skipping invalidating TLB.\n);
}
 
read_unlock_irqrestore(data-lock, flags);
@@ -506,9 +502,7 @@ void exynos_sysmmu_tlb_invalidate(struct device *dev)
sysmmu_unblock(data-sfrbase);
}
} else {
-   dev_dbg(data-sysmmu,
-   (%s) Disabled. Skipping invalidating TLB.\n,
-   data-dbgname);
+   dev_dbg(data-sysmmu, Disabled. Skipping invalidating TLB.\n);
}
 
read_unlock_irqrestore(data-lock, flags);
@@ -563,8 +557,6 @@ static int exynos_sysmmu_probe(struct platform_device *pdev)
data-clk = NULL;
dev_dbg(dev, No clock descriptor registered\n);
}
-
-   data-dbgname = platdata-dbgname;
}
 
data-sysmmu = dev;
@@ -577,7 +569,7 @@ static int exynos_sysmmu_probe(struct platform_device *pdev)
 
pm_runtime_enable(dev);
 
-   dev_dbg(dev, (%s) Initialized\n, data-dbgname);
+   dev_dbg(dev, Initialized\n);
return 0;
 err_irq:
free_irq(platform_get_irq(pdev, 0), data);
-- 
1.7.2.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https

[PATCH v10 09/20] iommu/exynos: use managed device helper functions

2013-10-06 Thread Cho KyongHo
This patch uses managed device helper functions in the probe().

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |   64 -
 1 files changed, 25 insertions(+), 39 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 735d75e..6fdb3836 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -510,53 +510,48 @@ void exynos_sysmmu_tlb_invalidate(struct device *dev)
 
 static int exynos_sysmmu_probe(struct platform_device *pdev)
 {
-   int ret;
+   int irq, ret;
struct device *dev = pdev-dev;
struct sysmmu_drvdata *data;
struct resource *res;
 
-   data = kzalloc(sizeof(*data), GFP_KERNEL);
-   if (!data) {
-   dev_dbg(dev, Not enough memory\n);
-   ret = -ENOMEM;
-   goto err_alloc;
-   }
+   data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+   if (!data)
+   return -ENOMEM;
 
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
-   dev_dbg(dev, Unable to find IOMEM region\n);
-   ret = -ENOENT;
-   goto err_res;
+   dev_err(dev, Unable to find IOMEM region\n);
+   return -ENOENT;
}
 
-   data-sfrbase = ioremap(res-start, resource_size(res));
-   if (!data-sfrbase) {
-   dev_dbg(dev, Unable to map IOMEM @ PA:%#x\n, res-start);
-   ret = -ENOENT;
-   goto err_res;
-   }
+   data-sfrbase = devm_ioremap_resource(dev, res);
+   if (IS_ERR(data-sfrbase))
+   return PTR_ERR(data-sfrbase);
 
-   ret = platform_get_irq(pdev, 0);
-   if (ret = 0) {
+   irq = platform_get_irq(pdev, 0);
+   if (irq = 0) {
dev_dbg(dev, Unable to find IRQ resource\n);
-   goto err_irq;
+   return irq;
}
 
-   ret = request_irq(ret, exynos_sysmmu_irq, 0,
+   ret = devm_request_irq(dev, irq, exynos_sysmmu_irq, 0,
dev_name(dev), data);
if (ret) {
-   dev_dbg(dev, Unabled to register interrupt handler\n);
-   goto err_irq;
+   dev_err(dev, Unabled to register handler of irq %d\n, irq);
+   return ret;
}
 
-   if (dev_get_platdata(dev)) {
-   struct sysmmu_platform_data *platdata = dev_get_platdata(dev);
+   data-clk = devm_clk_get(dev, sysmmu);
+   if (IS_ERR(data-clk)) {
+   dev_info(dev, No gate clock found!\n);
+   data-clk = NULL;
+   }
 
-   data-clk = clk_get(dev, sysmmu);
-   if (IS_ERR(data-clk)) {
-   data-clk = NULL;
-   dev_dbg(dev, No clock descriptor registered\n);
-   }
+   ret = clk_prepare(data-clk);
+   if (ret) {
+   dev_err(dev, Failed to prepare clk\n);
+   return ret;
}
 
data-sysmmu = dev;
@@ -569,17 +564,8 @@ static int exynos_sysmmu_probe(struct platform_device 
*pdev)
 
pm_runtime_enable(dev);
 
-   dev_dbg(dev, Initialized\n);
+   dev_dbg(dev, Probed and initialized\n);
return 0;
-err_irq:
-   free_irq(platform_get_irq(pdev, 0), data);
-err_res:
-   iounmap(data-sfrbase);
-err_init:
-   kfree(data);
-err_alloc:
-   dev_err(dev, Failed to initialize\n);
-   return ret;
 }
 
 static struct platform_driver exynos_sysmmu_driver = {
-- 
1.7.2.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v10 10/20] clk: exynos: add gate clock descriptions of System MMU

2013-10-06 Thread Cho KyongHo
This adds gate clocks of all System MMUs and their master IPs
that are not apeared in clk-exynos5250.c and clk-exynos5420.c
Also fixes GATE_IP_ACP to 0x18800 and changed GATE_DA to GATE
for System MMU clocks in clk-exynos4.c

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 .../devicetree/bindings/clock/exynos5250-clock.txt |   28 +++
 .../devicetree/bindings/clock/exynos5420-clock.txt |3 +
 drivers/clk/samsung/clk-exynos5250.c   |   49 ++-
 drivers/clk/samsung/clk-exynos5420.c   |   12 -
 4 files changed, 87 insertions(+), 5 deletions(-)

diff --git a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt 
b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
index 24765c1..929cfba 100644
--- a/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
+++ b/Documentation/devicetree/bindings/clock/exynos5250-clock.txt
@@ -159,6 +159,34 @@ clock which they consume.
   mixer343
   hdmi 344
   g2d  345
+  smmu_fimc_lite0  346
+  smmu_fimc_lite1  347
+  smmu_fimc_lite2  348
+  smmu_tv  349
+  smmu_fimd1   350
+  smmu_2d  351
+  fimc_isp 352
+  fimc_drc 353
+  fimc_fd  354
+  fimc_scc 355
+  fimc_scp 356
+  fimc_mcuctl  357
+  fimc_odc 358
+  fimc_dis 359
+  fimc_3dnr360
+  smmu_fimc_isp361
+  smmu_fimc_drc362
+  smmu_fimc_fd 363
+  smmu_fimc_scc364
+  smmu_fimc_scp365
+  smmu_fimc_mcuctl 366
+  smmu_fimc_odc367
+  smmu_fimc_dis0   368
+  smmu_fimc_dis1   369
+  smmu_fimc_3dnr   370
+  camif_top371
+  mdma0372
+  smmu_mdma0   373
 
 
[Clock Muxes]
diff --git a/Documentation/devicetree/bindings/clock/exynos5420-clock.txt 
b/Documentation/devicetree/bindings/clock/exynos5420-clock.txt
index 32aa34e..09dfa44 100644
--- a/Documentation/devicetree/bindings/clock/exynos5420-clock.txt
+++ b/Documentation/devicetree/bindings/clock/exynos5420-clock.txt
@@ -172,12 +172,15 @@ clock which they consume.
   mdma0473
   aclk333_g2d  480
   g2d  481
+  smmu_g2d 482
   aclk333_432_gscl 490
   smmu_3aa 491
   smmu_fimcl0  492
   smmu_fimcl1  493
   smmu_fimcl3  494
   fimc_lite3   495
+  fimc_lite0   496
+  fimc_lite1   497
   aclk_g3d 500
   g3d  501
   smmu_mixer   502
diff --git a/drivers/clk/samsung/clk-exynos5250.c 
b/drivers/clk/samsung/clk-exynos5250.c
index adf3234..c0312db 100644
--- a/drivers/clk/samsung/clk-exynos5250.c
+++ b/drivers/clk/samsung/clk-exynos5250.c
@@ -34,6 +34,7 @@
 #define VPLL_CON0  0x10140
 #define GPLL_CON0  0x10150
 #define SRC_TOP0   0x10210
+#define SRC_TOP1   0x10214
 #define SRC_TOP2   0x10218
 #define SRC_GSCL   0x10220
 #define SRC_DISP1_00x1022c
@@ -64,6 +65,8 @@
 #define DIV_PERIC3 0x10564
 #define DIV_PERIC4 0x10568
 #define DIV_PERIC5 0x1056c
+#define GATE_IP_ISP0   0x0C800
+#define GATE_IP_ISP1   0x0C800
 #define GATE_IP_GSCL   0x10920
 #define GATE_IP_MFC0x1092c
 #define GATE_IP_GEN0x10934
@@ -75,7 +78,7 @@
 #define SRC_CDREX  0x20200
 #define PLL_DIV2_SEL   0x20a24
 #define GATE_IP_DISP1  0x10928
-#define GATE_IP_ACP0x1
+#define GATE_IP_ACP0x18800
 
 /* list of PLLs to be registered */
 enum exynos5250_plls {
@@ -121,6 +124,13 @@ enum exynos5250_clks {
hsi2c3, chipid, sysreg, pmu, cmu_top, cmu_core, cmu_mem, tzpc0, tzpc1,
tzpc2, tzpc3, tzpc4, tzpc5, tzpc6, tzpc7, tzpc8, tzpc9, hdmi_cec, mct,
wdt, rtc, tmu, fimd1, mie1, dsim0, dp, mixer, hdmi, g2d,
+   smmu_fimc_lite0 = 346, smmu_fimc_lite1, smmu_fimc_lite2,
+   smmu_tv, smmu_fimd1, smmu_2d,
+   fimc_isp, fimc_drc, fimc_fd, fimc_scc, fimc_scp, fimc_mcuctl, fimc_odc,
+   fimc_dis, fimc_3dnr,
+   smmu_fimc_isp, smmu_fimc_drc, smmu_fimc_fd, smmu_fimc_scc,
+   smmu_fimc_scp, smmu_fimc_mcuctl, smmu_fimc_odc, smmu_fimc_dis0,
+   smmu_fimc_dis1, smmu_fimc_3dnr, camif_top, mdma0, smmu_mdma0,
 
/* mux clocks */
mout_hdmi = 1024,
@@ -194,6 +204,7 @@ PNAME(mout_mpll_user_p) = { fin_pll, sclk_mpll };
 PNAME(mout_bpll_user_p)= { fin_pll, sclk_bpll };
 PNAME(mout_aclk166_p)  = { sclk_cpll, sclk_mpll_user };
 PNAME(mout_aclk200_p)  = { sclk_mpll_user, sclk_bpll_user };
+PNAME(mout_aclk400_isp_p)  = { sclk_mpll_user, sclk_bpll_user };
 PNAME(mout_hdmi_p) = { div_hdmi_pixel, sclk_hdmiphy };
 PNAME(mout_usb3_p) = { sclk_mpll_user, sclk_cpll };
 PNAME

[PATCH v10 15/20] iommu/exynos: remove calls to Runtime PM API functions

2013-10-06 Thread Cho KyongHo
Runtime power management by exynos-iommu driver independently from
master H/W's runtime pm is not useful for power saving since attaching
master H/W in probing time turns on its local power endlessly.
Thus this removes runtime pm API calls.
Runtime PM support is added in the following commits to exynos-iommu
driver.

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |  337 +-
 1 files changed, 201 insertions(+), 136 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 976b88a..d9c5416 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -27,6 +27,8 @@
 #include linux/memblock.h
 #include linux/export.h
 #include linux/of.h
+#include linux/of_platform.h
+#include linux/notifier.h
 
 #include asm/cacheflush.h
 #include asm/pgtable.h
@@ -154,6 +156,12 @@ static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = {
UNKNOWN FAULT
 };
 
+struct exynos_iommu_client {
+   struct list_head node;  /* entry of exynos_iommu_domain.clients */
+   struct device *dev;
+   struct device *sysmmu;
+};
+
 struct exynos_iommu_domain {
struct list_head clients; /* list of sysmmu_drvdata.node */
unsigned long *pgtable; /* lv1 page table, 16KB */
@@ -163,9 +171,8 @@ struct exynos_iommu_domain {
 };
 
 struct sysmmu_drvdata {
-   struct list_head node; /* entry of exynos_iommu_domain.clients */
struct device *sysmmu;  /* System MMU's device descriptor */
-   struct device *dev; /* Owner of system MMU */
+   struct device *master;  /* Owner of system MMU */
void __iomem *sfrbase;
struct clk *clk;
struct clk *clk_master;
@@ -250,7 +257,6 @@ static void __sysmmu_tlb_invalidate_entry(void __iomem 
*sfrbase,
 static void __sysmmu_set_ptbase(void __iomem *sfrbase,
   unsigned long pgd)
 {
-   __raw_writel(0x1, sfrbase + REG_MMU_CFG); /* 16KB LV1, LRU */
__raw_writel(pgd, sfrbase + REG_PT_BASE_ADDR);
 
__sysmmu_tlb_invalidate(sfrbase);
@@ -310,7 +316,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
itype, base, addr);
if (data-domain)
ret = report_iommu_fault(data-domain,
-   data-dev, addr, itype);
+   data-master, addr, itype);
}
 
/* fault is not recovered by fault handler */
@@ -327,125 +333,145 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void 
*dev_id)
return IRQ_HANDLED;
 }
 
-static bool __exynos_sysmmu_disable(struct sysmmu_drvdata *data)
+static void __sysmmu_disable_nocount(struct sysmmu_drvdata *data)
 {
-   unsigned long flags;
-   bool disabled = false;
-
-   write_lock_irqsave(data-lock, flags);
-
-   if (!set_sysmmu_inactive(data))
-   goto finish;
-
clk_enable(data-clk_master);
 
__raw_writel(CTRL_DISABLE, data-sfrbase + REG_MMU_CTRL);
+   __raw_writel(0, data-sfrbase + REG_MMU_CFG);
 
+   clk_disable(data-clk);
clk_disable(data-clk_master);
+}
 
-   clk_disable(data-clk);
+static bool __sysmmu_disable(struct sysmmu_drvdata *data)
+{
+   bool disabled;
+   unsigned long flags;
 
-   disabled = true;
-   data-pgtable = 0;
-   data-domain = NULL;
-finish:
-   write_unlock_irqrestore(data-lock, flags);
+   write_lock_irqsave(data-lock, flags);
+
+   disabled = set_sysmmu_inactive(data);
+
+   if (disabled) {
+   data-pgtable = 0;
+   data-domain = NULL;
+
+   __sysmmu_disable_nocount(data);
 
-   if (disabled)
dev_dbg(data-sysmmu, Disabled\n);
-   else
-   dev_dbg(data-sysmmu, %d times left to be disabled\n,
+   } else  {
+   dev_dbg(data-sysmmu, %d times left to disable\n,
data-activations);
+   }
+
+   write_unlock_irqrestore(data-lock, flags);
 
return disabled;
 }
 
-/* __exynos_sysmmu_enable: Enables System MMU
- *
- * returns -error if an error occurred and System MMU is not enabled,
- * 0 if the System MMU has been just enabled and 1 if System MMU was already
- * enabled before.
- */
-static int __exynos_sysmmu_enable(struct sysmmu_drvdata *data,
-   unsigned long pgtable, struct iommu_domain *domain)
+static void __sysmmu_init_config(struct sysmmu_drvdata *data)
 {
-   int ret = 0;
-   unsigned long flags;
-   unsigned int min;
+   unsigned long cfg = 0;
+   int maj, min = 0;
 
-   write_lock_irqsave(data-lock, flags);
+   maj = __sysmmu_version(data, min);
+   if ((maj == 3)  (min  1))
+   cfg |= CFG_FLPDCACHE;
 
-   if (!set_sysmmu_active(data)) {
-   if (WARN_ON(pgtable != data-pgtable)) {
-   ret = -EBUSY

[PATCH v10 13/20] iommu/exynos: gating clocks of master H/W

2013-10-06 Thread Cho KyongHo
This patch gates clocks of master H/W as well as clocks of System MMU
if master clocks are specified.

Some Exynos SoCs (i.e. GScalers in Exynos5250) have dependencies in
the gating clocks of master H/W and its System MMU. If a H/W is the
case, accessing control registers of System MMU is prohibited unless
both of the gating clocks of System MMU and its master H/W.

CC: Tomasz Figa t.f...@samsung.com
Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |   75 +++--
 1 files changed, 56 insertions(+), 19 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index cf30519..75efdb81 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -80,6 +80,8 @@
 #define CTRL_BLOCK 0x7
 #define CTRL_DISABLE   0x0
 
+#define CFG_FLPDCACHE  (1  20) /* System MMU 3.2+ only */
+
 #define REG_MMU_CTRL   0x000
 #define REG_MMU_CFG0x004
 #define REG_MMU_STATUS 0x008
@@ -96,6 +98,9 @@
 
 #define REG_MMU_VERSION0x034
 
+#define MMU_MAJ_VER(reg)   (reg  28)
+#define MMU_MIN_VER(reg)   ((reg  21)  0x7F)
+
 #define REG_PB0_SADDR  0x04C
 #define REG_PB0_EADDR  0x050
 #define REG_PB1_SADDR  0x054
@@ -173,6 +178,7 @@ struct sysmmu_drvdata {
struct device *dev; /* Owner of system MMU */
void __iomem *sfrbase;
struct clk *clk;
+   struct clk *clk_master;
int activations;
rwlock_t lock;
struct iommu_domain *domain;
@@ -199,6 +205,22 @@ static bool is_sysmmu_active(struct sysmmu_drvdata *data)
return data-activations  0;
 }
 
+static unsigned int __sysmmu_version(struct sysmmu_drvdata *data,
+unsigned int *minor)
+{
+   unsigned long major;
+
+   major = readl(data-sfrbase + REG_MMU_VERSION);
+
+   if (minor)
+   *minor = MMU_MIN_VER(major);
+
+   if (MMU_MAJ_VER(major)  3)
+   return 1;
+
+   return MMU_MAJ_VER(major);
+}
+
 static void sysmmu_unblock(void __iomem *sfrbase)
 {
__raw_writel(CTRL_ENABLE, sfrbase + REG_MMU_CTRL);
@@ -245,13 +267,6 @@ static void __sysmmu_set_ptbase(void __iomem *sfrbase,
__sysmmu_tlb_invalidate(sfrbase);
 }
 
-static void __sysmmu_set_prefbuf(void __iomem *sfrbase, unsigned long base,
-   unsigned long size, int idx)
-{
-   __raw_writel(base, sfrbase + REG_PB0_SADDR + idx * 8);
-   __raw_writel(size - 1 + base,  sfrbase + REG_PB0_EADDR + idx * 8);
-}
-
 static void __set_fault_handler(struct sysmmu_drvdata *data,
sysmmu_fault_handler_t handler)
 {
@@ -308,6 +323,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
 
WARN_ON(!is_sysmmu_active(data));
 
+   clk_enable(data-clk_master);
itype = (enum exynos_sysmmu_inttype)
__ffs(__raw_readl(data-sfrbase + REG_INT_STATUS));
if (WARN_ON(!((itype = 0)  (itype  SYSMMU_FAULT_UNKNOWN
@@ -334,6 +350,8 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
if (itype != SYSMMU_FAULT_UNKNOWN)
sysmmu_unblock(data-sfrbase);
 
+   clk_disable(data-clk_master);
+
read_unlock(data-lock);
 
return IRQ_HANDLED;
@@ -349,10 +367,13 @@ static bool __exynos_sysmmu_disable(struct sysmmu_drvdata 
*data)
if (!set_sysmmu_inactive(data))
goto finish;
 
+   clk_enable(data-clk_master);
+
__raw_writel(CTRL_DISABLE, data-sfrbase + REG_MMU_CTRL);
 
-   if (data-clk)
-   clk_disable(data-clk);
+   clk_disable(data-clk_master);
+
+   clk_disable(data-clk);
 
disabled = true;
data-pgtable = 0;
@@ -380,6 +401,7 @@ static int __exynos_sysmmu_enable(struct sysmmu_drvdata 
*data,
 {
int ret = 0;
unsigned long flags;
+   unsigned int min;
 
write_lock_irqsave(data-lock, flags);
 
@@ -395,22 +417,24 @@ static int __exynos_sysmmu_enable(struct sysmmu_drvdata 
*data,
goto finish;
}
 
-   if (data-clk)
-   clk_enable(data-clk);
 
data-pgtable = pgtable;
 
+   clk_enable(data-clk);
+   clk_enable(data-clk_master);
+
__sysmmu_set_ptbase(data-sfrbase, pgtable);
 
-   if ((readl(data-sfrbase + REG_MMU_VERSION)  28) == 3) {
-   /* System MMU version is 3.x */
-   __raw_writel((1  12) | (2  28), data-sfrbase + 
REG_MMU_CFG);
-   __sysmmu_set_prefbuf(data-sfrbase, 0, -1, 0);
-   __sysmmu_set_prefbuf(data-sfrbase, 0, -1, 1);
+   if ((__sysmmu_version(data, min) == 3)  (min  1)) {
+   unsigned long cfg;
+   cfg = __raw_readl(data-sfrbase + REG_MMU_CFG);
+   __raw_writel(cfg | CFG_FLPDCACHE, data-sfrbase + REG_MMU_CFG);
}
 
__raw_writel(CTRL_ENABLE, data-sfrbase + REG_MMU_CTRL

[PATCH v10 17/20] iommu/exynos: add support for power management subsystems.

2013-10-06 Thread Cho KyongHo
This adds support for Suspend to RAM and Runtime Power Management.

Since System MMU is located in the same local power domain of its
master H/W, System MMU must be initialized before it is working if
its power domain was ever turned off. TLB invalidation according to
unmapping on page tables must also be performed while power domain is
turned on.

This patch ensures that resume and runtime_resume(restore_state)
functions in this driver is called before the calls to resume and
runtime_resume callback functions in the drivers of master H/Ws.
Likewise, suspend and runtime_suspend(save_state) functions in this
driver is called after the calls to suspend and runtime_suspend in the
drivers of master H/Ws.

In order to get benefit of this support, the master H/W and its System
MMU must resides in the same power domain in terms of Linux kernel. If
a master H/W does not use generic I/O power domain, its driver must
call iommu_attach_device() after its local power domain is turned on,
iommu_detach_device before turned off.

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |  190 +-
 1 files changed, 186 insertions(+), 4 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 03031dc..e48c2fb 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -28,6 +28,7 @@
 #include linux/export.h
 #include linux/of.h
 #include linux/of_platform.h
+#include linux/pm_domain.h
 #include linux/notifier.h
 
 #include asm/cacheflush.h
@@ -184,6 +185,7 @@ struct sysmmu_drvdata {
int activations;
rwlock_t lock;
struct iommu_domain *domain;
+   bool runtime_active;
unsigned long pgtable;
 };
 
@@ -362,7 +364,8 @@ static bool __sysmmu_disable(struct sysmmu_drvdata *data)
data-pgtable = 0;
data-domain = NULL;
 
-   __sysmmu_disable_nocount(data);
+   if (data-runtime_active)
+   __sysmmu_disable_nocount(data);
 
dev_dbg(data-sysmmu, Disabled\n);
} else  {
@@ -423,7 +426,8 @@ static int __sysmmu_enable(struct sysmmu_drvdata *data,
data-pgtable = pgtable;
data-domain = domain;
 
-   __sysmmu_enable_nocount(data);
+   if (data-runtime_active)
+   __sysmmu_enable_nocount(data);
 
dev_dbg(data-sysmmu, Enabled\n);
} else {
@@ -500,7 +504,7 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, 
unsigned long iova,
data = dev_get_drvdata(client-sysmmu);
 
read_lock_irqsave(data-lock, flags);
-   if (is_sysmmu_active(data)) {
+   if (is_sysmmu_active(data)  data-runtime_active) {
unsigned int num_inv = 1;
/*
 * L2TLB invalidation required
@@ -534,7 +538,7 @@ void exynos_sysmmu_tlb_invalidate(struct device *dev)
data = dev_get_drvdata(client-sysmmu);
 
read_lock_irqsave(data-lock, flags);
-   if (is_sysmmu_active(data)) {
+   if (is_sysmmu_active(data)  data-runtime_active) {
clk_enable(data-clk_master);
if (sysmmu_block(data-sfrbase)) {
__sysmmu_tlb_invalidate(data-sfrbase);
@@ -610,11 +614,40 @@ static int __init exynos_sysmmu_probe(struct 
platform_device *pdev)
platform_set_drvdata(pdev, data);
 
pm_runtime_enable(dev);
+   data-runtime_active = !pm_runtime_enabled(dev);
 
dev_dbg(dev, Probed and initialized\n);
return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int sysmmu_suspend(struct device *dev)
+{
+   struct sysmmu_drvdata *data = dev_get_drvdata(dev);
+   unsigned long flags;
+   read_lock_irqsave(data-lock, flags);
+   if (is_sysmmu_active(data) 
+   (!pm_runtime_enabled(dev) || data-runtime_active))
+   __sysmmu_disable_nocount(data);
+   read_unlock_irqrestore(data-lock, flags);
+   return 0;
+}
+
+static int sysmmu_resume(struct device *dev)
+{
+   struct sysmmu_drvdata *data = dev_get_drvdata(dev);
+   unsigned long flags;
+   read_lock_irqsave(data-lock, flags);
+   if (is_sysmmu_active(data) 
+   (!pm_runtime_enabled(dev) || data-runtime_active))
+   __sysmmu_enable_nocount(data);
+   read_unlock_irqrestore(data-lock, flags);
+   return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(sysmmu_pm_ops, sysmmu_suspend, sysmmu_resume);
+
 #ifdef CONFIG_OF
 static struct of_device_id sysmmu_of_match[] __initconst = {
{ .compatible   = samsung,exynos4210-sysmmu, },
@@ -627,6 +660,7 @@ static struct platform_driver exynos_sysmmu_driver 
__refdata = {
.driver = {
.owner  = THIS_MODULE,
.name   = exynos-sysmmu,
+   .pm = sysmmu_pm_ops,
.of_match_table = of_match_ptr(sysmmu_of_match

[PATCH v10 20/20] iommu/exynos: add devices attached to the System MMU to an IOMMU group

2013-10-06 Thread Cho KyongHo
Patch written by Antonios Motakis a.mota...@virtualopensystems.com:

IOMMU groups are expected by certain users of the IOMMU API,
e.g. VFIO. Since each device is behind its own System MMU, we
can allocate a new IOMMU group for each device.

Reviewd-by: Cho KyongHo pullip@samsung.com
Signed-off-by: Antonios Motakis a.mota...@virtualopensystems.com
---
 drivers/iommu/exynos-iommu.c |   28 
 1 files changed, 28 insertions(+), 0 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 5025338..24505a0 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -1028,6 +1028,32 @@ static phys_addr_t exynos_iommu_iova_to_phys(struct 
iommu_domain *domain,
return phys;
 }
 
+static int exynos_iommu_add_device(struct device *dev)
+{
+   struct iommu_group *group;
+   int ret;
+
+   group = iommu_group_get(dev);
+
+   if (!group) {
+   group = iommu_group_alloc();
+   if (IS_ERR(group)) {
+   dev_err(dev, Failed to allocate IOMMU group\n);
+   return PTR_ERR(group);
+   }
+   }
+
+   ret = iommu_group_add_device(group, dev);
+   iommu_group_put(group);
+
+   return ret;
+}
+
+static void exynos_iommu_remove_device(struct device *dev)
+{
+   iommu_group_remove_device(dev);
+}
+
 static struct iommu_ops exynos_iommu_ops = {
.domain_init = exynos_iommu_domain_init,
.domain_destroy = exynos_iommu_domain_destroy,
@@ -1036,6 +1062,8 @@ static struct iommu_ops exynos_iommu_ops = {
.map = exynos_iommu_map,
.unmap = exynos_iommu_unmap,
.iova_to_phys = exynos_iommu_iova_to_phys,
+   .add_device = exynos_iommu_add_device,
+   .remove_device = exynos_iommu_remove_device,
.pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE,
 };
 
-- 
1.7.2.5

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH v6 07/12] ARM: EXYNOS: remove system mmu initialization from exynos tree

2013-09-29 Thread Cho KyongHo
On Fri, 27 Sep 2013 14:55:51 -0400, Sean Paul wrote:
 On Tue, Dec 25, 2012 at 8:54 PM, Cho KyongHo pullip@samsung.com wrote:
  This removes System MMU initialization from arch/arm/mach-exynos/
  to move them to DT and the exynos-iommu driver except gating clock
  definitions.
 
 
 
 exynos with iommu support no longer compiles with this patch:
 
   CC  drivers/iommu/exynos-iommu.o
 /mnt/host/source/src/third_party/kernel-next/drivers/iommu/exynos-iommu.c:32:25:
 fatal error: mach/sysmmu.h: No such file or directory
 compilation terminated.
 make[3]: *** [drivers/iommu/exynos-iommu.o] Error 1
 

It is my fault.
I think you need to apply all v6 patches to compile correctly.

Since v8 patches, I checked that every patch is compiled successfully.

  iommu/exynos: do not include removed header
patch from v7 patch removes including 'mach/sysmmu.h'.

Thank you.


 Sean
 
 
  Signed-off-by: KyongHo Cho pullip@samsung.com
  ---
   arch/arm/mach-exynos/Kconfig   |   5 -
   arch/arm/mach-exynos/Makefile  |   1 -
   arch/arm/mach-exynos/clock-exynos4.c   |  41 +++--
   arch/arm/mach-exynos/clock-exynos4210.c|   9 +-
   arch/arm/mach-exynos/clock-exynos4212.c|  23 ++-
   arch/arm/mach-exynos/clock-exynos5.c   |  62 ---
   arch/arm/mach-exynos/dev-sysmmu.c  | 274 
  -
   arch/arm/mach-exynos/include/mach/sysmmu.h |  66 ---
   arch/arm/mach-exynos/mach-exynos4-dt.c |  34 
   arch/arm/mach-exynos/mach-exynos5-dt.c |  30 
   10 files changed, 137 insertions(+), 408 deletions(-)
   delete mode 100644 arch/arm/mach-exynos/dev-sysmmu.c
   delete mode 100644 arch/arm/mach-exynos/include/mach/sysmmu.h
 
  diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
  index 91d5b6f..eba6eb5 100644
  --- a/arch/arm/mach-exynos/Kconfig
  +++ b/arch/arm/mach-exynos/Kconfig
  @@ -103,11 +103,6 @@ config EXYNOS4_SETUP_FIMD0
  help
Common setup code for FIMD0.
 
  -config EXYNOS_DEV_SYSMMU
  -   bool
  -   help
  - Common setup code for SYSTEM MMU in EXYNOS platforms
  -
   config EXYNOS4_DEV_USB_OHCI
  bool
  help
  diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
  index b189881..435757e 100644
  --- a/arch/arm/mach-exynos/Makefile
  +++ b/arch/arm/mach-exynos/Makefile
  @@ -52,7 +52,6 @@ obj-$(CONFIG_ARCH_EXYNOS4)+= dev-audio.o
   obj-$(CONFIG_EXYNOS4_DEV_AHCI) += dev-ahci.o
   obj-$(CONFIG_EXYNOS_DEV_DMA)   += dma.o
   obj-$(CONFIG_EXYNOS4_DEV_USB_OHCI) += dev-ohci.o
  -obj-$(CONFIG_EXYNOS_DEV_SYSMMU)+= dev-sysmmu.o
 
   obj-$(CONFIG_ARCH_EXYNOS)  += setup-i2c0.o
   obj-$(CONFIG_EXYNOS4_SETUP_FIMC)   += setup-fimc.o
  diff --git a/arch/arm/mach-exynos/clock-exynos4.c 
  b/arch/arm/mach-exynos/clock-exynos4.c
  index bbcb3de..8a8468d 100644
  --- a/arch/arm/mach-exynos/clock-exynos4.c
  +++ b/arch/arm/mach-exynos/clock-exynos4.c
  @@ -24,7 +24,6 @@
 
   #include mach/map.h
   #include mach/regs-clock.h
  -#include mach/sysmmu.h
 
   #include common.h
   #include clock-exynos4.h
  @@ -709,53 +708,53 @@ static struct clk exynos4_init_clocks_off[] = {
  .enable = exynos4_clk_ip_peril_ctrl,
  .ctrlbit= (1  14),
  }, {
  -   .name   = SYSMMU_CLOCK_NAME,
  -   .devname= SYSMMU_CLOCK_DEVNAME(mfc_l, 0),
  +   .name   = sysmmu,
  +   .devname= exynos-sysmmu.0,
  .enable = exynos4_clk_ip_mfc_ctrl,
  .ctrlbit= (1  1),
  }, {
  -   .name   = SYSMMU_CLOCK_NAME,
  -   .devname= SYSMMU_CLOCK_DEVNAME(mfc_r, 1),
  +   .name   = sysmmu,
  +   .devname= exynos-sysmmu.1,
  .enable = exynos4_clk_ip_mfc_ctrl,
  .ctrlbit= (1  2),
  }, {
  -   .name   = SYSMMU_CLOCK_NAME,
  -   .devname= SYSMMU_CLOCK_DEVNAME(tv, 2),
  +   .name   = sysmmu,
  +   .devname= exynos-sysmmu.2,
  .enable = exynos4_clk_ip_tv_ctrl,
  .ctrlbit= (1  4),
  }, {
  -   .name   = SYSMMU_CLOCK_NAME,
  -   .devname= SYSMMU_CLOCK_DEVNAME(jpeg, 3),
  +   .name   = sysmmu,
  +   .devname= exynos-sysmmu.3,
  .enable = exynos4_clk_ip_cam_ctrl,
  .ctrlbit= (1  11),
  }, {
  -   .name   = SYSMMU_CLOCK_NAME,
  -   .devname= SYSMMU_CLOCK_DEVNAME(rot, 4),
  +   .name   = sysmmu,
  +   .devname= exynos-sysmmu.4,
  .enable

Re: [PATCH v6 07/12] ARM: EXYNOS: remove system mmu initialization from exynos tree

2013-09-29 Thread Cho KyongHo
On Sun, 29 Sep 2013 20:38:38 -0400, Sean Paul wrote:
 On Sun, Sep 29, 2013 at 8:35 PM, Cho KyongHo pullip@samsung.com wrote:
 
  On Fri, 27 Sep 2013 14:55:51 -0400, Sean Paul wrote:
   On Tue, Dec 25, 2012 at 8:54 PM, Cho KyongHo pullip@samsung.com
  wrote:
This removes System MMU initialization from arch/arm/mach-exynos/
to move them to DT and the exynos-iommu driver except gating clock
definitions.
   
  
  
   exynos with iommu support no longer compiles with this patch:
  
 CC  drivers/iommu/exynos-iommu.o
  
  /mnt/host/source/src/third_party/kernel-next/drivers/iommu/exynos-iommu.c:32:25:
   fatal error: mach/sysmmu.h: No such file or directory
   compilation terminated.
   make[3]: *** [drivers/iommu/exynos-iommu.o] Error 1
  
 
  It is my fault.
  I think you need to apply all v6 patches to compile correctly.
 
  Since v8 patches, I checked that every patch is compiled successfully.
 
 
 I'm sorry I don't think I explained properly.
 
 This patch has been merged to mainline without the rest of the series. As
 such, mainline with exynos iommu does not currently compile.
 

Ah, I remember that this is merged.
I agreed to merge this patch because iommu driver need to be completely changed.
Whenever I change exynos-iommu driver, synchronizing samsung-next and iommu-next
branches is a big challenge.
Thus I decided to remove dependencies to samsung-next branch.
But I didn't know that the rest of the new driver is not merged soon. :(
I am sorry about that.

new patch (v10) will be posted soon.

Thank you.

 Sean
 
 
 
 
iommu/exynos: do not include removed header
  patch from v7 patch removes including 'mach/sysmmu.h'.
 
  Thank you.
 
 
   Sean
  
  
Signed-off-by: KyongHo Cho pullip@samsung.com
---
 arch/arm/mach-exynos/Kconfig   |   5 -
 arch/arm/mach-exynos/Makefile  |   1 -
 arch/arm/mach-exynos/clock-exynos4.c   |  41 +++--
 arch/arm/mach-exynos/clock-exynos4210.c|   9 +-
 arch/arm/mach-exynos/clock-exynos4212.c|  23 ++-
 arch/arm/mach-exynos/clock-exynos5.c   |  62 ---
 arch/arm/mach-exynos/dev-sysmmu.c  | 274
  -
 arch/arm/mach-exynos/include/mach/sysmmu.h |  66 ---
 arch/arm/mach-exynos/mach-exynos4-dt.c |  34 
 arch/arm/mach-exynos/mach-exynos5-dt.c |  30 
 10 files changed, 137 insertions(+), 408 deletions(-)
 delete mode 100644 arch/arm/mach-exynos/dev-sysmmu.c
 delete mode 100644 arch/arm/mach-exynos/include/mach/sysmmu.h
   
diff --git a/arch/arm/mach-exynos/Kconfig
  b/arch/arm/mach-exynos/Kconfig
index 91d5b6f..eba6eb5 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -103,11 +103,6 @@ config EXYNOS4_SETUP_FIMD0
help
  Common setup code for FIMD0.
   
-config EXYNOS_DEV_SYSMMU
-   bool
-   help
- Common setup code for SYSTEM MMU in EXYNOS platforms
-
 config EXYNOS4_DEV_USB_OHCI
bool
help
diff --git a/arch/arm/mach-exynos/Makefile
  b/arch/arm/mach-exynos/Makefile
index b189881..435757e 100644
--- a/arch/arm/mach-exynos/Makefile
+++ b/arch/arm/mach-exynos/Makefile
@@ -52,7 +52,6 @@ obj-$(CONFIG_ARCH_EXYNOS4)+= dev-audio.o
 obj-$(CONFIG_EXYNOS4_DEV_AHCI) += dev-ahci.o
 obj-$(CONFIG_EXYNOS_DEV_DMA)   += dma.o
 obj-$(CONFIG_EXYNOS4_DEV_USB_OHCI) += dev-ohci.o
-obj-$(CONFIG_EXYNOS_DEV_SYSMMU)+= dev-sysmmu.o
   
 obj-$(CONFIG_ARCH_EXYNOS)  += setup-i2c0.o
 obj-$(CONFIG_EXYNOS4_SETUP_FIMC)   += setup-fimc.o
diff --git a/arch/arm/mach-exynos/clock-exynos4.c
  b/arch/arm/mach-exynos/clock-exynos4.c
index bbcb3de..8a8468d 100644
--- a/arch/arm/mach-exynos/clock-exynos4.c
+++ b/arch/arm/mach-exynos/clock-exynos4.c
@@ -24,7 +24,6 @@
   
 #include mach/map.h
 #include mach/regs-clock.h
-#include mach/sysmmu.h
   
 #include common.h
 #include clock-exynos4.h
@@ -709,53 +708,53 @@ static struct clk exynos4_init_clocks_off[] = {
.enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit= (1  14),
}, {
-   .name   = SYSMMU_CLOCK_NAME,
-   .devname= SYSMMU_CLOCK_DEVNAME(mfc_l, 0),
+   .name   = sysmmu,
+   .devname= exynos-sysmmu.0,
.enable = exynos4_clk_ip_mfc_ctrl,
.ctrlbit= (1  1),
}, {
-   .name   = SYSMMU_CLOCK_NAME,
-   .devname= SYSMMU_CLOCK_DEVNAME(mfc_r, 1),
+   .name   = sysmmu,
+   .devname= exynos-sysmmu.1,
.enable = exynos4_clk_ip_mfc_ctrl,
.ctrlbit

Re: [PATCH v9 06/16] ARM: dts: Add description of System MMU of Exynos SoCs

2013-08-09 Thread Cho KyongHo
On Fri, 09 Aug 2013 00:26:51 +0200, Tomasz Figa wrote:
 Hi KyongHo,
 
 On Thursday 08 of August 2013 18:38:35 Cho KyongHo wrote:
  Signed-off-by: Cho KyongHo pullip@samsung.com
  ---
   .../bindings/iommu/samsung,exynos4210-sysmmu.txt   |  103 +++
   arch/arm/boot/dts/exynos4.dtsi |  122 
   arch/arm/boot/dts/exynos4210.dtsi  |   25 ++
   arch/arm/boot/dts/exynos4x12.dtsi  |   82 ++
   arch/arm/boot/dts/exynos5250.dtsi  |  290
   5 files changed, 622 insertions(+), 0 deletions(-)
   create mode 100644
  Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.txt
  
  diff --git
  a/Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.txt
  b/Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.txt
  new file mode 100644
  index 000..92f0a33
  --- /dev/null
  +++
  b/Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.txt
  @@ -0,0 +1,103 @@
  +Samsung Exynos4210 IOMMU H/W, System MMU (System Memory Management
  Unit) +
  +Samsung's Exynos architecture contains System MMU that enables
  scattered +physical memory chunks visible as a contiguous region to
  DMA-capable peripheral +devices like MFC, FIMC, FIMD, GScaler, FIMC-IS
  and so forth.
  +
  +System MMU is a sort of IOMMU and support identical translation table
  format to +ARMv7 translation tables with minimum set of page properties
  including access +permissions, shareability and security protection. In
  addition, System MMU has +another capabilities like L2 TLB or
  block-fetch buffers to minimize translation +latency.
  +
  +A System MMU is dedicated to a single master peripheral device.  Thus,
  it is +important to specify the correct System MMU in the device node
  of its master +device. Whereas a System MMU is dedicated to a master
  device, the master device +may have more than one System MMU.
 
 This paragraph is still not clear. What about something among these lines:
 
Yes. It is my fault.
It is still unchanged... even though Grant sugessted clear and simple sentence.
It must be changed :)

 System MMUs are in many to one relation with peripheral devices, i.e. 
 single peripheral device might have multiple System MMUs (usually one for 
 each bus master), but one System MMU can handle only one peripheral 
 device. The relation between a System MMU and the peripheral device it 
 handles needs to be defined in device node of this peripheral device.
 

That looks good to me.
Please let me use your sentences.

  +Required properties:
  +- compatible: Should be samsung,exynos4210-sysmmu
  +- reg: A tuple of base address and size of System MMU registers.
  +- interrupt-parent: The phandle of the interrupt controller of System
  MMU +- interrupts: A tuple of numbers that indicates the interrupt
  source. 
 
 interrupts: An interrupt specifier for interrupt signal of System MMU, 
 according to format defined for particular interrupt parent.

Yes.. it is not changed.. 
 
  +- clock-names: Should be sysmmu if the System MMU is needed
  to gate its clock. +   Please refer to the following
  documents:
  +  Documentation/devicetree/bindings/clock/clock-bindings.txt
  +  Documentation/devicetree/bindings/clock/exynos4-clock.txt
  +  Documentation/devicetree/bindings/clock/exynos5250-
 clock.txt
  +  Optional master if the clock to the System MMU is gated 
 by
  +  another gate clock other than sysmmu. The System MMU 
 driver
  +  sets master the parent of sysmmu.
  +  Exynos4 SoCs, there needs no master clocks.
  +  Exynos5 SoCs, some System MMUs must have master clocks.
  +- clocks: Required if the System MMU is needed to gate its clock.
  + Please refer to the documents listed above.
  +- samsung,power-domain: Required if the System MMU is needed to gate
  its power. +  Please refer to the following document:
  + Documentation/devicetree/bindings/arm/exynos/power_domain.txt
  +
  +Required properties for the master peripheral devices:
  +- iommu: phandles to the System MMUs of the device
  +
  +Examples:
  +A System MMU is dedicated to a single master device.
  +   gsc_0:  gsc@0x13e0 {
 
 nit: duplicated space after gsc_0: and incorrect 0x prefix in node unit-
 address.
 
Ok.

  +   compatible = samsung,exynos5-gsc;
  +   reg = 0x13e0 0x1000;
  +   interrupts = 0 85 0;
  +   samsung,power-domain = pd_gsc;
  +   clocks = clock 256;
  +   clock-names = gscl;
  +   iommu = sysmmu_gsc1;
  +   };
  +
  +   sysmmu_gsc0: sysmmu@13E8 {
  +   compatible = samsung,exynos4210-sysmmu;
  +   reg = 0x13E8 0x1000;
  +   interrupt-parent = combiner;
  +   interrupt-names = sysmmu-gsc0;
 
 Hmm? interrupt-names property is not defined in your binding documentation 
 and also the value here looks wrong. This should

Re: [PATCH v9 06/16] ARM: dts: Add description of System MMU of Exynos SoCs

2013-08-09 Thread Cho KyongHo
On Fri, 09 Aug 2013 10:04:03 +0200, Tomasz Figa wrote:
 On Friday 09 of August 2013 15:15:57 Cho KyongHo wrote:
  On Fri, 09 Aug 2013 00:26:51 +0200, Tomasz Figa wrote:
   Hi KyongHo,
   
   On Thursday 08 of August 2013 18:38:35 Cho KyongHo wrote:
Signed-off-by: Cho KyongHo pullip@samsung.com
---

 .../bindings/iommu/samsung,exynos4210-sysmmu.txt   |  103 +++
 arch/arm/boot/dts/exynos4.dtsi |  122 
 arch/arm/boot/dts/exynos4210.dtsi  |   25 ++
 arch/arm/boot/dts/exynos4x12.dtsi  |   82 ++
 arch/arm/boot/dts/exynos5250.dtsi  |  290

 5 files changed, 622 insertions(+), 0
deletions(-)

 create mode 100644

Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.tx
t

diff --git
a/Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.
txt
b/Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.
txt
new file mode 100644
index 000..92f0a33
--- /dev/null
+++
b/Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.
txt
@@ -0,0 +1,103 @@
+Samsung Exynos4210 IOMMU H/W, System MMU (System Memory Management
Unit) +
+Samsung's Exynos architecture contains System MMU that enables
scattered +physical memory chunks visible as a contiguous region to
DMA-capable peripheral +devices like MFC, FIMC, FIMD, GScaler,
FIMC-IS
and so forth.
+
+System MMU is a sort of IOMMU and support identical translation
table
format to +ARMv7 translation tables with minimum set of page
properties
including access +permissions, shareability and security protection.
In
addition, System MMU has +another capabilities like L2 TLB or
block-fetch buffers to minimize translation +latency.
+
+A System MMU is dedicated to a single master peripheral device. 
Thus,
it is +important to specify the correct System MMU in the device
node
of its master +device. Whereas a System MMU is dedicated to a master
device, the master device +may have more than one System MMU.
   
   This paragraph is still not clear. What about something among these 
 lines:
  Yes. It is my fault.
  It is still unchanged... even though Grant sugessted clear and simple
  sentence. It must be changed :)
  
   System MMUs are in many to one relation with peripheral devices, i.e.
   single peripheral device might have multiple System MMUs (usually one
   for each bus master), but one System MMU can handle only one
   peripheral device. The relation between a System MMU and the
   peripheral device it handles needs to be defined in device node of
   this peripheral device.
  That looks good to me.
  Please let me use your sentences.
 
 OK.
 
+Required properties:
+- compatible: Should be samsung,exynos4210-sysmmu
+- reg: A tuple of base address and size of System MMU registers.
+- interrupt-parent: The phandle of the interrupt controller of
System
MMU +- interrupts: A tuple of numbers that indicates the interrupt
source.
   
   interrupts: An interrupt specifier for interrupt signal of System MMU,
   according to format defined for particular interrupt parent.
  
  Yes.. it is not changed..
  
+- clock-names: Should be sysmmu if the System MMU is needed
to gate its clock. +   Please refer to the following
documents:
+  
Documentation/devicetree/bindings/clock/clock-bindings.txt
+  Documentation/devicetree/bindings/clock/exynos4-clock.txt
+  Documentation/devicetree/bindings/clock/exynos5250-
   
   clock.txt
   
+  Optional master if the clock to the System MMU is gated
   
   by
   
+  another gate clock other than sysmmu. The System MMU
   
   driver
   
+  sets master the parent of sysmmu.
+  Exynos4 SoCs, there needs no master clocks.
+  Exynos5 SoCs, some System MMUs must have master clocks.
+- clocks: Required if the System MMU is needed to gate its clock.
+ Please refer to the documents listed above.
+- samsung,power-domain: Required if the System MMU is needed to
gate
its power. +  Please refer to the following document:
+ Documentation/devicetree/bindings/arm/exynos/power_domain.txt
+
+Required properties for the master peripheral devices:
+- iommu: phandles to the System MMUs of the device
+
+Examples:
+A System MMU is dedicated to a single master device.
+   gsc_0:  gsc@0x13e0 {
   
   nit: duplicated space after gsc_0: and incorrect 0x prefix in node
   unit- address.
  
  Ok.
  
+   compatible = samsung,exynos5-gsc;
+   reg = 0x13e0 0x1000;
+   interrupts = 0 85 0;
+   samsung,power-domain

RE: [PATCH v8 10/12] iommu/exynos: add bus notifier for registering System MMU

2013-08-05 Thread Cho KyongHo
 -Original Message-
 From: Bartlomiej Zolnierkiewicz [mailto:b.zolnier...@samsung.com]
 Sent: Saturday, August 03, 2013 2:32 AM
 
 Hi,
 
 On Friday, July 26, 2013 08:30:17 PM Cho KyongHo wrote:
  When a device driver is registered, all constructs to handle System MMU
  is prepared by bus notifier call.
 
 Patch description could be improved greatly by documenting what the patch
 is doing and it does a lot more than simply adding bus notifier.
 
 The patch can be also split further (at least code adding support for
 muplitple System MMUs per struct exynos_iommu_client instance could be
 separate which would make review a lot easier as the code wouldn't be
 moved around so much).
 
 Could you also tell me how (on which SoC/board and with what drivers) are
 you testing these changes? I've tried to test v7 with FIMC and MFC devices
 (on EXYNOS4210 based Universal C210 board) but as soon as I added actual
 IOMMU mappings (none of your patches in this series does it BTW) I've
 encountered problems (namely lockup related to clocks usage, probably
 related to master clock, I haven't had time to debug it further yet).
 

I am just testing if each System MMU is correctly enabled and disabled or page
tables are consistently managed. I does not run MFC nor FIMC with System MMU.

Please let me know if you found the problem.

 Best regards,
 --
 Bartlomiej Zolnierkiewicz
 Samsung RD Institute Poland
 Samsung Electronics
 
  Signed-off-by: Cho KyongHo pullip@samsung.com
  ---
   drivers/iommu/exynos-iommu.c |  708 
  -
   1 files changed, 552 insertions(+), 156 deletions(-)
 
  diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
  index f9853fe..c62c244 100644
  --- a/drivers/iommu/exynos-iommu.c
  +++ b/drivers/iommu/exynos-iommu.c
  @@ -27,6 +27,9 @@
   #include linux/memblock.h
   #include linux/export.h
   #include linux/of.h
  +#include linux/of_platform.h
  +#include linux/pm_domain.h
  +#include linux/notifier.h
 
   #include asm/cacheflush.h
   #include asm/pgtable.h
  @@ -80,7 +83,13 @@
   #define CTRL_BLOCK 0x7
   #define CTRL_DISABLE   0x0
 
  +#define CFG_LRU0x1
  +#define CFG_QOS(n) ((n  0xF)  7)
  +#define CFG_MASK   0x0150 /* Selecting bit 0-15, 20, 22 and 24 */
  +#define CFG_ACGEN  (1  24) /* System MMU 3.3 only */
  +#define CFG_SYSSEL (1  22) /* System MMU 3.2 only */
   #define CFG_FLPDCACHE  (1  20) /* System MMU 3.2+ only */
  +#define CFG_SHAREABLE  (1  12) /* System MMU 3.x only */
 
   #define REG_MMU_CTRL   0x000
   #define REG_MMU_CFG0x004
  @@ -154,6 +163,14 @@ static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = {
  UNKNOWN FAULT
   };
 
  +struct exynos_iommu_client {
  +   struct list_head node;  /* entry of exynos_iommu_domain.clients */
  +   struct device *dev;
  +   spinlock_t lock;
  +   int num_sysmmu;
  +   struct device *sysmmu[0];
  +};
  +
   struct exynos_iommu_domain {
  struct list_head clients; /* list of sysmmu_drvdata.node */
  unsigned long *pgtable; /* lv1 page table, 16KB */
  @@ -165,12 +182,14 @@ struct exynos_iommu_domain {
   struct sysmmu_drvdata {
  struct list_head node; /* entry of exynos_iommu_domain.clients */
  struct device *sysmmu;  /* System MMU's device descriptor */
  -   struct device *dev; /* Owner of system MMU */
  +   struct device *master;  /* Owner of system MMU */
  int nsfrs;
  struct clk *clk;
  +   struct clk *clk_master;
  int activations;
  rwlock_t lock;
  struct iommu_domain *domain;
  +   bool runtime_active;
  unsigned long pgtable;
  void __iomem *sfrbases[0];
   };
  @@ -245,7 +264,6 @@ static void __sysmmu_tlb_invalidate_entry(void __iomem 
  *sfrbase,
   static void __sysmmu_set_ptbase(void __iomem *sfrbase,
 unsigned long pgd)
   {
  -   __raw_writel(0x1, sfrbase + REG_MMU_CFG); /* 16KB LV1, LRU */
  __raw_writel(pgd, sfrbase + REG_PT_BASE_ADDR);
 
  __sysmmu_tlb_invalidate(sfrbase);
  @@ -273,6 +291,7 @@ void exynos_sysmmu_set_prefbuf(struct device *dev,
  if (!is_sysmmu_active(data))
  goto finish;
 
  +   clk_enable(data-clk_master);
  for (i = 0; i  data-nsfrs; i++) {
  if ((readl(data-sfrbases[i] + REG_MMU_VERSION)  28) == 3) {
  if (!sysmmu_block(data-sfrbases[i]))
  @@ -298,6 +317,7 @@ void exynos_sysmmu_set_prefbuf(struct device *dev,
  sysmmu_unblock(data-sfrbases[i]);
  }
  }
  +   clk_disable(data-clk_master);
   finish:
  read_unlock_irqrestore(data-lock, flags);
   }
  @@ -331,12 +351,13 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void 
  *dev_id)
   {
  /* SYSMMU is in blocked when interrupt occurred. */
  struct sysmmu_drvdata *data = dev_id;
  +   struct exynos_iommu_client *client = NULL;
  enum exynos_sysmmu_inttype itype;
  unsigned long addr = -1;
  -
  int i, ret = -ENOSYS

RE: [PATCH v8 10/12] iommu/exynos: add bus notifier for registering System MMU

2013-08-02 Thread Cho KyongHo
 -Original Message-
 From: Rahul Sharma [mailto:r.sh.o...@gmail.com]
 Sent: Friday, August 02, 2013 2:18 PM
 
 Hi Cho,
 
 On Fri, Jul 26, 2013 at 5:00 PM, Cho KyongHo pullip@samsung.com wrote:
  When a device driver is registered, all constructs to handle System MMU
  is prepared by bus notifier call.
 
  Signed-off-by: Cho KyongHo pullip@samsung.com
  ---
   drivers/iommu/exynos-iommu.c |  708 
  -
   1 files changed, 552 insertions(+), 156 deletions(-)
 
  diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
  index f9853fe..c62c244 100644
  --- a/drivers/iommu/exynos-iommu.c
  +++ b/drivers/iommu/exynos-iommu.c
  @@ -27,6 +27,9 @@
   #include linux/memblock.h
   #include linux/export.h
   #include linux/of.h
  +#include linux/of_platform.h
  +#include linux/pm_domain.h
  +#include linux/notifier.h
 
   #include asm/cacheflush.h
   #include asm/pgtable.h
  @@ -80,7 +83,13 @@
   #define CTRL_BLOCK 0x7
   #define CTRL_DISABLE   0x0
 
  +#define CFG_LRU0x1
  +#define CFG_QOS(n) ((n  0xF)  7)
  +#define CFG_MASK   0x0150 /* Selecting bit 0-15, 20, 22 and 24 */
  +#define CFG_ACGEN  (1  24) /* System MMU 3.3 only */
  +#define CFG_SYSSEL (1  22) /* System MMU 3.2 only */
   #define CFG_FLPDCACHE  (1  20) /* System MMU 3.2+ only */
  +#define CFG_SHAREABLE  (1  12) /* System MMU 3.x only */
 
   #define REG_MMU_CTRL   0x000
   #define REG_MMU_CFG0x004
  @@ -154,6 +163,14 @@ static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = {
  UNKNOWN FAULT
   };
 
  +struct exynos_iommu_client {
  +   struct list_head node;  /* entry of exynos_iommu_domain.clients */
  +   struct device *dev;
  +   spinlock_t lock;
  +   int num_sysmmu;
  +   struct device *sysmmu[0];
 
 Shouldn't we keep limit on the max number of iommu's to a single client ? Even
 this way, you will hit array overrun with multiple iommu's.
 

I don't think it is needed to fix the size of the array because
we know the size of the array in booting time.
sysmmu[0] is just a placeholder of array.

  +};
  +
   struct exynos_iommu_domain {
  struct list_head clients; /* list of sysmmu_drvdata.node */
  unsigned long *pgtable; /* lv1 page table, 16KB */
  @@ -165,12 +182,14 @@ struct exynos_iommu_domain {
   struct sysmmu_drvdata {
  struct list_head node; /* entry of exynos_iommu_domain.clients */
  struct device *sysmmu;  /* System MMU's device descriptor */
  -   struct device *dev; /* Owner of system MMU */
  +   struct device *master;  /* Owner of system MMU */
  int nsfrs;
  struct clk *clk;
  +   struct clk *clk_master;
  int activations;
  rwlock_t lock;
  struct iommu_domain *domain;
  +   bool runtime_active;
  unsigned long pgtable;
  void __iomem *sfrbases[0];
   };
  @@ -245,7 +264,6 @@ static void __sysmmu_tlb_invalidate_entry(void __iomem 
  *sfrbase,
   static void __sysmmu_set_ptbase(void __iomem *sfrbase,
 unsigned long pgd)
   {
  -   __raw_writel(0x1, sfrbase + REG_MMU_CFG); /* 16KB LV1, LRU */
  __raw_writel(pgd, sfrbase + REG_PT_BASE_ADDR);
 
  __sysmmu_tlb_invalidate(sfrbase);
  @@ -273,6 +291,7 @@ void exynos_sysmmu_set_prefbuf(struct device *dev,
  if (!is_sysmmu_active(data))
  goto finish;
 
  +   clk_enable(data-clk_master);
  for (i = 0; i  data-nsfrs; i++) {
  if ((readl(data-sfrbases[i] + REG_MMU_VERSION)  28) == 
  3) {
  if (!sysmmu_block(data-sfrbases[i]))
  @@ -298,6 +317,7 @@ void exynos_sysmmu_set_prefbuf(struct device *dev,
  sysmmu_unblock(data-sfrbases[i]);
  }
  }
  +   clk_disable(data-clk_master);
   finish:
  read_unlock_irqrestore(data-lock, flags);
   }
  @@ -331,12 +351,13 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void 
  *dev_id)
   {
  /* SYSMMU is in blocked when interrupt occurred. */
  struct sysmmu_drvdata *data = dev_id;
  +   struct exynos_iommu_client *client = NULL;
  enum exynos_sysmmu_inttype itype;
  unsigned long addr = -1;
  -
  int i, ret = -ENOSYS;
 
  -   read_lock(data-lock);
  +   if (data-master)
  +   client = data-master-archdata.iommu;
 
  WARN_ON(!is_sysmmu_active(data));
 
  @@ -348,6 +369,10 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void 
  *dev_id)
  break;
  }
 
  +   if (client)
  +   spin_lock(client-lock);
  +   read_lock(data-lock);
  +
  if (i == data-nsfrs) {
  itype = SYSMMU_FAULT_UNKNOWN;
  } else {
  @@ -361,7 +386,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void 
  *dev_id)
  }
 
  if (data-domain)
  -   ret

RE: [PATCH v8 06/12] ARM: dts: Add description of System MMU of Exynos SoCs

2013-08-01 Thread Cho KyongHo
 -Original Message-
 From: Rob Herring [mailto:robherri...@gmail.com]
 Sent: Saturday, July 27, 2013 10:55 PM
 On Fri, Jul 26, 2013 at 6:28 AM, Cho KyongHo pullip@samsung.com wrote:
  Signed-off-by: Cho KyongHo pullip@samsung.com
  ---
   .../bindings/iommu/samsung,exynos4210-sysmmu.txt   |  103 +++
   arch/arm/boot/dts/exynos4.dtsi |  122 
   arch/arm/boot/dts/exynos4210.dtsi  |   25 ++
   arch/arm/boot/dts/exynos4x12.dtsi  |   76 +
   arch/arm/boot/dts/exynos5250.dtsi  |  291 
  
   5 files changed, 617 insertions(+), 0 deletions(-)
   create mode 100644 
  Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.txt
 
  diff --git 
  a/Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.txt
  b/Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.txt
  new file mode 100644
  index 000..92f0a33
  --- /dev/null
  +++ b/Documentation/devicetree/bindings/iommu/samsung,exynos4210-sysmmu.txt
  @@ -0,0 +1,103 @@
  +Samsung Exynos4210 IOMMU H/W, System MMU (System Memory Management Unit)
  +
  +Samsung's Exynos architecture contains System MMU that enables scattered
  +physical memory chunks visible as a contiguous region to DMA-capable 
  peripheral
  +devices like MFC, FIMC, FIMD, GScaler, FIMC-IS and so forth.
  +
  +System MMU is a sort of IOMMU and support identical translation table 
  format to
  +ARMv7 translation tables with minimum set of page properties including 
  access
  +permissions, shareability and security protection. In addition, System MMU 
  has
  +another capabilities like L2 TLB or block-fetch buffers to minimize 
  translation
  +latency.
  +
  +A System MMU is dedicated to a single master peripheral device.  Thus, it 
  is
  +important to specify the correct System MMU in the device node of its 
  master
  +device. Whereas a System MMU is dedicated to a master device, the master 
  device
  +may have more than one System MMU.
 
 I don't follow the last sentence. Can you elaborate on the type of
 connection you are talking about.
 
Grant also addressed that.
He corrected the sentence like the following:

   Can I suggest rewriting the last two sentences to:
 The master device node must correctly specify at least one
 SystemMMU. A master  device may have more than one System MMU. 

I will change the sentence

 Also, please align with the ARM system MMU binding that Will Deacon
 has submitted particularly in terms of how master connections are
 described.
 
I didn't check it.

Should this align with ARM System MMU bindings?
System MMU in Exynos SoC is different from ARM System MMU.
It does not follows the specifications of ARM System MMU.

 Rob
 
  +
  +Required properties:
  +- compatible: Should be samsung,exynos4210-sysmmu
  +- reg: A tuple of base address and size of System MMU registers.
  +- interrupt-parent: The phandle of the interrupt controller of System MMU
  +- interrupts: A tuple of numbers that indicates the interrupt source.
  +- clock-names: Should be sysmmu if the System MMU is needed to gate its 
  clock.
  +   Please refer to the following documents:
  +  Documentation/devicetree/bindings/clock/clock-bindings.txt
  +  Documentation/devicetree/bindings/clock/exynos4-clock.txt
  +  Documentation/devicetree/bindings/clock/exynos5250-clock.txt
  +  Optional master if the clock to the System MMU is gated by
  +  another gate clock other than sysmmu. The System MMU driver
  +  sets master the parent of sysmmu.
  +  Exynos4 SoCs, there needs no master clocks.
  +  Exynos5 SoCs, some System MMUs must have master clocks.
  +- clocks: Required if the System MMU is needed to gate its clock.
  + Please refer to the documents listed above.
  +- samsung,power-domain: Required if the System MMU is needed to gate its 
  power.
  + Please refer to the following document:
  + Documentation/devicetree/bindings/arm/exynos/power_domain.txt
  +
  +Required properties for the master peripheral devices:
  +- iommu: phandles to the System MMUs of the device
  +
  +Examples:
  +A System MMU is dedicated to a single master device.
  +   gsc_0:  gsc@0x13e0 {
  +   compatible = samsung,exynos5-gsc;
  +   reg = 0x13e0 0x1000;
  +   interrupts = 0 85 0;
  +   samsung,power-domain = pd_gsc;
  +   clocks = clock 256;
  +   clock-names = gscl;
  +   iommu = sysmmu_gsc1;
  +   };
  +
  +   sysmmu_gsc0: sysmmu@13E8 {
  +   compatible = samsung,exynos4210-sysmmu;
  +   reg = 0x13E8 0x1000;
  +   interrupt-parent = combiner;
  +   interrupt-names = sysmmu-gsc0;
  +   interrupts = 2 0;
  +   clock-names = sysmmu, master

RE: [PATCH v7 9/9] iommu/exynos: add bus notifier for registering System MMU

2013-07-11 Thread Cho KyongHo
 From: Prathyush K [mailto:prathy...@chromium.org] 
 Sent: Thursday, July 11, 2013 12:03 AM
 
 I think this patch can be split further.
 There is a lot more added in this patch (suspend/resume functions etc) than 
 just adding a bus notifier.

Oh, Sorry for that ;-)

Actually, adding bus notifier is to register gpd_pm_ops to master peripheral 
devices,
it results in big change in the driver.

 
 I will review further and also, test this patchset.
 

Thank you very much.

 Regards,
 Prathyush
 
 On Fri, Jul 5, 2013 at 5:59 PM, Cho KyongHo pullip@samsung.com wrote:
 When a device driver is registered, all constructs to handle System MMU
 is prepared by bus notifier call.
 
 Signed-off-by: Cho KyongHo pullip@samsung.com
 ---
  drivers/iommu/exynos-iommu.c |  778 ++---
  1 files changed, 569 insertions(+), 209 deletions(-)
 
 diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
 index b151e51..51d43bb 100644
 --- a/drivers/iommu/exynos-iommu.c
 +++ b/drivers/iommu/exynos-iommu.c
 @@ -27,6 +27,9 @@
  #include linux/memblock.h
  #include linux/export.h
  #include linux/of.h
 +#include linux/of_platform.h
 +#include linux/pm_domain.h
 +#include linux/notifier.h
 
  #include asm/cacheflush.h
  #include asm/pgtable.h
 @@ -80,6 +83,14 @@
  #define CTRL_BLOCK 0x7
  #define CTRL_DISABLE   0x0
 
 +#define CFG_LRU0x1
 +#define CFG_QOS(n) ((n  0xF)  7)
 +#define CFG_MASK   0x0150 /* Selecting bit 0-15, 20, 22 and 24 */
 +#define CFG_ACGEN  (1  24) /* System MMU 3.3 only */
 +#define CFG_SYSSEL (1  22) /* System MMU 3.2 only */
 +#define CFG_FLPDCACHE  (1  20) /* System MMU 3.2+ only */
 +#define CFG_SHAREABLE  (1  12) /* System MMU 3.x only */
 +
  #define REG_MMU_CTRL   0x000
  #define REG_MMU_CFG0x004
  #define REG_MMU_STATUS 0x008
 @@ -96,6 +107,9 @@
 
  #define REG_MMU_VERSION0x034
 
 +#define MMU_MAJ_VER(reg)   (reg  28)
 +#define MMU_MIN_VER(reg)   ((reg  21)  0x7F)
 +
  #define REG_PB0_SADDR  0x04C
  #define REG_PB0_EADDR  0x050
  #define REG_PB1_SADDR  0x054
 @@ -126,16 +140,6 @@ enum exynos_sysmmu_inttype {
 SYSMMU_FAULTS_NUM
  };
 
 -/*
 - * @itype: type of fault.
 - * @pgtable_base: the physical address of page table base. This is 0 if 
 @itype
 - *is SYSMMU_BUSERROR.
 - * @fault_addr: the device (virtual) address that the System MMU tried to
 - * translated. This is 0 if @itype is SYSMMU_BUSERROR.
 - */
 -typedef int (*sysmmu_fault_handler_t)(enum exynos_sysmmu_inttype itype,
 -   unsigned long pgtable_base, unsigned long fault_addr);
 -
  static unsigned short fault_reg_offset[SYSMMU_FAULTS_NUM] = {
 REG_PAGE_FAULT_ADDR,
 REG_AR_FAULT_ADDR,
 @@ -159,6 +163,14 @@ static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = {
 UNKNOWN FAULT
  };
 
 +struct exynos_iommu_client {
 +   struct list_head node;  /* entry of exynos_iommu_domain.clients */
 +   struct device *dev;
 +   spinlock_t lock;
 +   int num_sysmmu;
 +   struct device *sysmmu[0];
 +};
 +
  struct exynos_iommu_domain {
 struct list_head clients; /* list of sysmmu_drvdata.node */
 unsigned long *pgtable; /* lv1 page table, 16KB */
 @@ -170,13 +182,13 @@ struct exynos_iommu_domain {
  struct sysmmu_drvdata {
 struct list_head node; /* entry of exynos_iommu_domain.clients */
 struct device *sysmmu;  /* System MMU's device descriptor */
 -   struct device *dev; /* Owner of system MMU */
 +   struct device *master;  /* Owner of system MMU */
 int nsfrs;
 struct clk *clk;
 int activations;
 spinlock_t lock;
 struct iommu_domain *domain;
 -   sysmmu_fault_handler_t fault_handler;
 +   bool runtime_active;
 unsigned long pgtable;
 void __iomem *sfrbases[0];
  };
 @@ -200,6 +212,20 @@ static bool is_sysmmu_active(struct sysmmu_drvdata *data)
 return data-activations  0;
  }
 
 +static unsigned int __sysmmu_version(struct sysmmu_drvdata *data,
 +   int idx, unsigned int *minor)
 +{
 +   unsigned int major;
 +
 +   major = readl(data-sfrbases[idx] + REG_MMU_VERSION);
 +
 +   if (minor)
 +   *minor = MMU_MIN_VER(major);
 +   major = MMU_MAJ_VER(major);
 +
 +   return major;
 +}
 +
  static void sysmmu_unblock(void __iomem *sfrbase)
  {
 __raw_writel(CTRL_ENABLE, sfrbase + REG_MMU_CTRL);
 @@ -235,7 +261,6 @@ static void __sysmmu_tlb_invalidate_entry(void __iomem 
 *sfrbase,
  static void __sysmmu_set_ptbase(void __iomem *sfrbase,
unsigned long pgd)
  {
 -   __raw_writel(0x1, sfrbase + REG_MMU_CFG); /* 16KB LV1, LRU */
 __raw_writel(pgd, sfrbase + REG_PT_BASE_ADDR);
 
 __sysmmu_tlb_invalidate(sfrbase);
 @@ -292,34 +317,17 @@ finish

[PATCH v7 9/9] iommu/exynos: add bus notifier for registering System MMU

2013-07-05 Thread Cho KyongHo
When a device driver is registered, all constructs to handle System MMU
is prepared by bus notifier call.

Signed-off-by: Cho KyongHo pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c |  778 ++---
 1 files changed, 569 insertions(+), 209 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index b151e51..51d43bb 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -27,6 +27,9 @@
 #include linux/memblock.h
 #include linux/export.h
 #include linux/of.h
+#include linux/of_platform.h
+#include linux/pm_domain.h
+#include linux/notifier.h
 
 #include asm/cacheflush.h
 #include asm/pgtable.h
@@ -80,6 +83,14 @@
 #define CTRL_BLOCK 0x7
 #define CTRL_DISABLE   0x0
 
+#define CFG_LRU0x1
+#define CFG_QOS(n) ((n  0xF)  7)
+#define CFG_MASK   0x0150 /* Selecting bit 0-15, 20, 22 and 24 */
+#define CFG_ACGEN  (1  24) /* System MMU 3.3 only */
+#define CFG_SYSSEL (1  22) /* System MMU 3.2 only */
+#define CFG_FLPDCACHE  (1  20) /* System MMU 3.2+ only */
+#define CFG_SHAREABLE  (1  12) /* System MMU 3.x only */
+
 #define REG_MMU_CTRL   0x000
 #define REG_MMU_CFG0x004
 #define REG_MMU_STATUS 0x008
@@ -96,6 +107,9 @@
 
 #define REG_MMU_VERSION0x034
 
+#define MMU_MAJ_VER(reg)   (reg  28)
+#define MMU_MIN_VER(reg)   ((reg  21)  0x7F)
+
 #define REG_PB0_SADDR  0x04C
 #define REG_PB0_EADDR  0x050
 #define REG_PB1_SADDR  0x054
@@ -126,16 +140,6 @@ enum exynos_sysmmu_inttype {
SYSMMU_FAULTS_NUM
 };
 
-/*
- * @itype: type of fault.
- * @pgtable_base: the physical address of page table base. This is 0 if @itype
- *is SYSMMU_BUSERROR.
- * @fault_addr: the device (virtual) address that the System MMU tried to
- * translated. This is 0 if @itype is SYSMMU_BUSERROR.
- */
-typedef int (*sysmmu_fault_handler_t)(enum exynos_sysmmu_inttype itype,
-   unsigned long pgtable_base, unsigned long fault_addr);
-
 static unsigned short fault_reg_offset[SYSMMU_FAULTS_NUM] = {
REG_PAGE_FAULT_ADDR,
REG_AR_FAULT_ADDR,
@@ -159,6 +163,14 @@ static char *sysmmu_fault_name[SYSMMU_FAULTS_NUM] = {
UNKNOWN FAULT
 };
 
+struct exynos_iommu_client {
+   struct list_head node;  /* entry of exynos_iommu_domain.clients */
+   struct device *dev;
+   spinlock_t lock;
+   int num_sysmmu;
+   struct device *sysmmu[0];
+};
+
 struct exynos_iommu_domain {
struct list_head clients; /* list of sysmmu_drvdata.node */
unsigned long *pgtable; /* lv1 page table, 16KB */
@@ -170,13 +182,13 @@ struct exynos_iommu_domain {
 struct sysmmu_drvdata {
struct list_head node; /* entry of exynos_iommu_domain.clients */
struct device *sysmmu;  /* System MMU's device descriptor */
-   struct device *dev; /* Owner of system MMU */
+   struct device *master;  /* Owner of system MMU */
int nsfrs;
struct clk *clk;
int activations;
spinlock_t lock;
struct iommu_domain *domain;
-   sysmmu_fault_handler_t fault_handler;
+   bool runtime_active;
unsigned long pgtable;
void __iomem *sfrbases[0];
 };
@@ -200,6 +212,20 @@ static bool is_sysmmu_active(struct sysmmu_drvdata *data)
return data-activations  0;
 }
 
+static unsigned int __sysmmu_version(struct sysmmu_drvdata *data,
+   int idx, unsigned int *minor)
+{
+   unsigned int major;
+
+   major = readl(data-sfrbases[idx] + REG_MMU_VERSION);
+
+   if (minor)
+   *minor = MMU_MIN_VER(major);
+   major = MMU_MAJ_VER(major);
+
+   return major;
+}
+
 static void sysmmu_unblock(void __iomem *sfrbase)
 {
__raw_writel(CTRL_ENABLE, sfrbase + REG_MMU_CTRL);
@@ -235,7 +261,6 @@ static void __sysmmu_tlb_invalidate_entry(void __iomem 
*sfrbase,
 static void __sysmmu_set_ptbase(void __iomem *sfrbase,
   unsigned long pgd)
 {
-   __raw_writel(0x1, sfrbase + REG_MMU_CFG); /* 16KB LV1, LRU */
__raw_writel(pgd, sfrbase + REG_PT_BASE_ADDR);
 
__sysmmu_tlb_invalidate(sfrbase);
@@ -292,34 +317,17 @@ finish:
spin_unlock_irqrestore(data-lock, flags);
 }
 
-static void __set_fault_handler(struct sysmmu_drvdata *data,
-   sysmmu_fault_handler_t handler)
-{
-   unsigned long flags;
-
-   spin_lock_irqsave(data-lock, flags);
-   data-fault_handler = handler;
-   spin_unlock_irqrestore(data-lock, flags);
-}
-
-void exynos_sysmmu_set_fault_handler(struct device *dev,
-   sysmmu_fault_handler_t handler)
-{
-   struct sysmmu_drvdata *data = dev_get_drvdata(dev-archdata.iommu);
-
-   __set_fault_handler(data, handler);
-}
-
-static int default_fault_handler(enum exynos_sysmmu_inttype itype

회신: Re: [PATCH v6 12/12] iommu/exynos: add debugfs entries for System MMU

2013-05-19 Thread Cho KyongHo
Hi.

Sorry for the late update.

I am in a very tough situation in the both of work and life :)
I will soon post the patches.

Anyway, the last patches inserts the device descriptors of System 
MMU on the top of the device descriptor of its master device to 
hook the events of Runtime PM. But I think it may not proper for 
some drivers if a master device of a System MMU must have a 
parent that is not a System MMU.

I found that hooking of Runtime PM events is possible with
gpd_dev_ops but there is a big restriction that the master device must use 
Generic IO Power Domain.

Is there any better option?

Thank you.

Cho KyongHo



 원본 메시지 
발신: Prathyush K prathy...@chromium.org 
날짜: 2013/05/18  14:26  (GMT+09:00) 
수신: Cho KyongHo pullip@samsung.com 
참조: Kukjin Kim kgene@samsung.com,Hyunwoong Kim 
khw0178@samsung.com,Prathyush prathyus...@samsung.com,Subash Patel 
supash.ramasw...@linaro.org,Linux Kernel linux-ker...@vger.kernel.org,Linux 
IOMMU iommu@lists.linux-foundation.org,Linux Samsung SOC 
linux-samsung-...@vger.kernel.org,Linux ARM Kernel 
linux-arm-ker...@lists.infradead.org,Rahul Sharma rahul.sha...@samsung.com 
제목: Re: [PATCH v6 12/12] iommu/exynos: add debugfs entries for System MMU 
 
Hi Mr. Cho,

any update on this patchset? Are you working on v7?

Regards,
Prathyush



On Wed, Dec 26, 2012 at 7:24 AM, Cho KyongHo pullip@samsung.com wrote:
This commit adds debugfs directory and nodes for inspecting internal
state of System MMU.

Signed-off-by: KyongHo Cho pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c | 204 +--
 1 file changed, 198 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 9753e0e..78c0eb7 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -26,12 +26,17 @@
 #include linux/list.h
 #include linux/memblock.h
 #include linux/export.h
+#include linux/fs.h
+#include linux/seq_file.h
+#include linux/debugfs.h
 #include linux/string.h
 #include linux/of.h
 #include linux/of_platform.h

 #include asm/cacheflush.h

+#define MODULE_NAME exynos-sysmmu
+
 /* We does not consider super section mapping (16MB) */
 #define SECT_ORDER 20
 #define LPAGE_ORDER 16
@@ -223,6 +228,7 @@ struct sysmmu_drvdata {
        struct sysmmu_prefbuf pbufs[MAX_NUM_PBUF];
        int num_pbufs;
        struct sysmmu_version ver;
+       struct dentry *debugfs_root;
        struct iommu_domain *domain;
        unsigned long pgtable;
        bool runtime_active;
@@ -1066,6 +1072,8 @@ static void __init __sysmmu_init_mmuname(struct device 
*sysmmu,
        }
 }

+static void __create_debugfs_entry(struct sysmmu_drvdata *drvdata);
+
 static int __init exynos_sysmmu_probe(struct platform_device *pdev)
 {
        int i, ret;
@@ -1134,6 +1142,8 @@ static int __init exynos_sysmmu_probe(struct 
platform_device *pdev)

                data-runtime_active = !pm_runtime_enabled(dev);

+               __create_debugfs_entry(data);
+
                platform_set_drvdata(pdev, data);

                dev-archdata.iommu = sysmmu_placeholder;
@@ -1238,7 +1248,7 @@ static struct platform_driver exynos_sysmmu_driver 
__refdata = {
        .probe          = exynos_sysmmu_probe,
        .driver         = {
                .owner          = THIS_MODULE,
-               .name           = exynos-sysmmu,
+               .name           = MODULE_NAME,
                .pm             = __pm_ops,
                .of_match_table = of_match_ptr(sysmmu_of_match),
        }
@@ -1631,6 +1641,8 @@ static struct iommu_ops exynos_iommu_ops = {
        .pgsize_bitmap = SECT_SIZE | LPAGE_SIZE | SPAGE_SIZE,
 };

+static struct dentry *sysmmu_debugfs_root; /* /sys/kernel/debug/sysmmu */
+
 static int __init exynos_iommu_init(void)
 {
        int ret;
@@ -1642,17 +1654,197 @@ static int __init exynos_iommu_init(void)
                return -ENOMEM;
        }

-       ret = platform_driver_register(exynos_sysmmu_driver);
+       ret = bus_set_iommu(platform_bus_type, exynos_iommu_ops);
+       if (ret) {
+               kmem_cache_destroy(lv2table_kmem_cache);
+               pr_err(%s: Failed to register IOMMU ops\n, __func__);
+               return -EFAULT;
+       }

-       if (ret == 0)
-               ret = bus_set_iommu(platform_bus_type, exynos_iommu_ops);
+       sysmmu_debugfs_root = debugfs_create_dir(sysmmu, NULL);
+       if (!sysmmu_debugfs_root)
+               pr_err(%s: Failed to create debugfs entry, 'sysmmu'\n,
+                                                       __func__);
+       if (IS_ERR(sysmmu_debugfs_root))
+               sysmmu_debugfs_root = NULL;

+       ret = platform_driver_register(exynos_sysmmu_driver);
        if (ret) {
-               pr_err(%s: Failed to register exynos-iommu driver.\n,
-                                                               __func__);
                kmem_cache_destroy(lv2table_kmem_cache);
+               pr_err(%s: Failed

[PATCH v6 00/12] iommu/exynos: Fixes and Enhancements of System MMU driver with DT

2012-12-25 Thread Cho KyongHo
notice: v6 patch-set is rebased on next/iommu-exynos branch of
linux-samsung.git.  This patch-set does not include 2 patches (05 and 06
patches in v5 patch-se) because they alread exist already in the branch.

The current exynos-iommu(System MMU) driver does not work autonomously
since it is lack of support for power management of peripheral blocks.
For example, MFC device driver must ensure that its System MMU is disabled
before MFC block is power-down not to invalidate IOTLB in the System MMU
when I/O memory mapping is changed. Because A System MMU is resides in the
same H/W block, access to control registers of System MMU while the H/W
block is turned off must be prohibited.

This set of changes solves the above problem with setting each System MMUs
as the parent of the device which owns the System MMU to recieve the
information when the device is turned off or turned on.

Another big change to the driver is the support for devicetree.
The bindings for System MMU is described in
Documentation/devicetree/bindings/arm/samsung/system-mmu.txt

In addition, this patchset also includes several bug fixes and enhancements
of the current driver.

Change log:
v6:
- Rebased on the branch, next/iommu-exynos of
  git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung.git

v5:
- new bugfix: patch 01
- Reordered patches
  * patch 01 ~ 05: Bugfix and enhancements of the existing driver
  * patch 06 ~ 10: Device Tree support and callbacks for power management
  * patch 11 : System MMU 3.2 and 3.3 support
  * patch 12 ~ 14: Debugging features
- Additional code compaction

v4:
- Remove Change-Id from v3 patches
- Change the order of the third and the first patch
  Thanks to Kukjin Kim.
- Fix memory leak when allocating and assigning exynos_iommu_owner to client
  device if the client device has multiple System MMUs.
  Thanks to Rahul Sharma.

v3:
- Fix prefetch buffer flag definition for System MMU 3.3 (patch 10/12)
- Fix incorrect setting for SET_RUNTIME_PM_OPS (patch 09/12)
  Thanks to Prathyush.

v2:
- Split the patch to iommu/exynos into 9 patches
- Support for System MMU 3.3
- Some code compaction

Patch summary:
[PATCH v6 01/12] iommu/exynos: add missing cache flush for removed pagetable 
entries
[PATCH v6 02/12] iommu/exynos: always use iommu fault handler
[PATCH v6 03/12] iommu/exynos: allocate lv2 page table from own slab
[PATCH v6 04/12] iommu/exynos: change rwlock to spinlock
[PATCH v6 05/12] iommu/exynos: support for device tree
[PATCH v6 06/12] iommu/exynos: set System MMU as the parent of client device
[PATCH v6 07/12] ARM: EXYNOS: remove system mmu initialization from exynos tree
[PATCH v6 08/12] iommu/exynos: add support for runtime pm and suspend/resume
[PATCH v6 09/12] iommu/exynos: add support for System MMU 3.2 and 3.3
[PATCH v6 10/12] iommu/exynos: pass version information from DT
[PATCH v6 11/12] iommu/exynos: add literal name of System MMU for debugging
[PATCH v6 12/12] iommu/exynos: add debugfs entries for System MMU

Diffstats:
 arch/arm/boot/dts/exynos5250-smdk5250.dts  |2 +-
 arch/arm/boot/dts/exynos5250.dtsi  |   27 +-
 arch/arm/mach-exynos/Kconfig   |5 -
 arch/arm/mach-exynos/Makefile  |1 -
 arch/arm/mach-exynos/clock-exynos4.c   |   41 +-
 arch/arm/mach-exynos/clock-exynos4210.c|9 +-
 arch/arm/mach-exynos/clock-exynos4212.c|   23 +-
 arch/arm/mach-exynos/clock-exynos5.c   |   87 +-
 arch/arm/mach-exynos/dev-sysmmu.c  |  274 --
 arch/arm/mach-exynos/include/mach/sysmmu.h |   66 --
 arch/arm/mach-exynos/mach-exynos4-dt.c |   34 +
 arch/arm/mach-exynos/mach-exynos5-dt.c |   30 +
 drivers/iommu/Kconfig  |2 +-
 drivers/iommu/Makefile |2 +-
 drivers/iommu/exynos-iommu.c   | 1477 +---
 15 files changed, 1284 insertions(+), 796 deletions(-)

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v6 04/12] iommu/exynos: change rwlock to spinlock

2012-12-25 Thread Cho KyongHo
Since acquiring read_lock is not more frequent than write_lock, it is
not beneficial to use rwlock, this commit changes rwlock to spinlock.

Signed-off-by: KyongHo Cho pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c | 28 ++--
 1 file changed, 14 insertions(+), 14 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 58d2a24..5847508 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -166,7 +166,7 @@ struct sysmmu_drvdata {
void __iomem **sfrbases;
struct clk *clk[2];
int activations;
-   rwlock_t lock;
+   spinlock_t lock;
struct iommu_domain *domain;
unsigned long pgtable;
 };
@@ -249,7 +249,7 @@ void exynos_sysmmu_set_prefbuf(struct device *dev,
BUG_ON((base0 + size0) = base0);
BUG_ON((size1  0)  ((base1 + size1) = base1));
 
-   read_lock_irqsave(data-lock, flags);
+   spin_lock_irqsave(data-lock, flags);
if (!is_sysmmu_active(data))
goto finish;
 
@@ -279,7 +279,7 @@ void exynos_sysmmu_set_prefbuf(struct device *dev,
}
}
 finish:
-   read_unlock_irqrestore(data-lock, flags);
+   spin_unlock_irqrestore(data-lock, flags);
 }
 
 static void __show_fault_information(unsigned long *pgtable, unsigned long 
iova,
@@ -312,7 +312,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
 
int i, ret = -ENOSYS;
 
-   read_lock(data-lock);
+   spin_lock(data-lock);
 
WARN_ON(!is_sysmmu_active(data));
 
@@ -354,7 +354,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
 
sysmmu_unblock(data-sfrbases[i]);
 
-   read_unlock(data-lock);
+   spin_unlock(data-lock);
 
return IRQ_HANDLED;
 }
@@ -365,7 +365,7 @@ static bool __exynos_sysmmu_disable(struct sysmmu_drvdata 
*data)
bool disabled = false;
int i;
 
-   write_lock_irqsave(data-lock, flags);
+   spin_lock_irqsave(data-lock, flags);
 
if (!set_sysmmu_inactive(data))
goto finish;
@@ -382,7 +382,7 @@ static bool __exynos_sysmmu_disable(struct sysmmu_drvdata 
*data)
data-pgtable = 0;
data-domain = NULL;
 finish:
-   write_unlock_irqrestore(data-lock, flags);
+   spin_unlock_irqrestore(data-lock, flags);
 
if (disabled)
dev_dbg(data-sysmmu, (%s) Disabled\n, data-dbgname);
@@ -405,7 +405,7 @@ static int __exynos_sysmmu_enable(struct sysmmu_drvdata 
*data,
int i, ret = 0;
unsigned long flags;
 
-   write_lock_irqsave(data-lock, flags);
+   spin_lock_irqsave(data-lock, flags);
 
if (!set_sysmmu_active(data)) {
if (WARN_ON(pgtable != data-pgtable)) {
@@ -444,7 +444,7 @@ static int __exynos_sysmmu_enable(struct sysmmu_drvdata 
*data,
 
dev_dbg(data-sysmmu, (%s) Enabled\n, data-dbgname);
 finish:
-   write_unlock_irqrestore(data-lock, flags);
+   spin_unlock_irqrestore(data-lock, flags);
 
return ret;
 }
@@ -491,7 +491,7 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, 
unsigned long iova)
unsigned long flags;
struct sysmmu_drvdata *data = dev_get_drvdata(dev-archdata.iommu);
 
-   read_lock_irqsave(data-lock, flags);
+   spin_lock_irqsave(data-lock, flags);
 
if (is_sysmmu_active(data)) {
int i;
@@ -508,7 +508,7 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, 
unsigned long iova)
data-dbgname);
}
 
-   read_unlock_irqrestore(data-lock, flags);
+   spin_unlock_irqrestore(data-lock, flags);
 }
 
 void exynos_sysmmu_tlb_invalidate(struct device *dev)
@@ -516,7 +516,7 @@ void exynos_sysmmu_tlb_invalidate(struct device *dev)
unsigned long flags;
struct sysmmu_drvdata *data = dev_get_drvdata(dev-archdata.iommu);
 
-   read_lock_irqsave(data-lock, flags);
+   spin_lock_irqsave(data-lock, flags);
 
if (is_sysmmu_active(data)) {
int i;
@@ -532,7 +532,7 @@ void exynos_sysmmu_tlb_invalidate(struct device *dev)
data-dbgname);
}
 
-   read_unlock_irqrestore(data-lock, flags);
+   spin_unlock_irqrestore(data-lock, flags);
 }
 
 static int exynos_sysmmu_probe(struct platform_device *pdev)
@@ -629,7 +629,7 @@ static int exynos_sysmmu_probe(struct platform_device *pdev)
}
 
data-sysmmu = dev;
-   rwlock_init(data-lock);
+   spin_lock_init(data-lock);
INIT_LIST_HEAD(data-node);
 
if (dev-parent)
-- 
1.8.0


___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v6 05/12] iommu/exynos: support for device tree

2012-12-25 Thread Cho KyongHo
This commit adds device tree support for System MMU.

Signed-off-by: KyongHo Cho pullip@samsung.com
---
 drivers/iommu/Kconfig|   2 +-
 drivers/iommu/exynos-iommu.c | 282 ++-
 2 files changed, 174 insertions(+), 110 deletions(-)

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index e39f9db..64586f1 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -168,7 +168,7 @@ config TEGRA_IOMMU_SMMU
 
 config EXYNOS_IOMMU
bool Exynos IOMMU Support
-   depends on ARCH_EXYNOS  EXYNOS_DEV_SYSMMU
+   depends on ARCH_EXYNOS
select IOMMU_API
help
  Support for the IOMMU(System MMU) of Samsung Exynos application
diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 5847508..5b35820 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -1,6 +1,6 @@
-/* linux/drivers/iommu/exynos_iommu.c
+/* linux/drivers/iommu/exynos-iommu.c
  *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd.
  * http://www.samsung.com
  *
  * This program is free software; you can redistribute it and/or modify
@@ -12,6 +12,7 @@
 #define DEBUG
 #endif
 
+#include linux/kernel.h
 #include linux/io.h
 #include linux/interrupt.h
 #include linux/platform_device.h
@@ -25,11 +26,10 @@
 #include linux/list.h
 #include linux/memblock.h
 #include linux/export.h
+#include linux/of.h
+#include linux/of_platform.h
 
 #include asm/cacheflush.h
-#include asm/pgtable.h
-
-#include mach/sysmmu.h
 
 /* We does not consider super section mapping (16MB) */
 #define SECT_ORDER 20
@@ -161,14 +161,13 @@ struct sysmmu_drvdata {
struct list_head node; /* entry of exynos_iommu_domain.clients */
struct device *sysmmu;  /* System MMU's device descriptor */
struct device *dev; /* Owner of system MMU */
-   char *dbgname;
int nsfrs;
-   void __iomem **sfrbases;
-   struct clk *clk[2];
+   struct clk *clk;
int activations;
spinlock_t lock;
struct iommu_domain *domain;
unsigned long pgtable;
+   void __iomem *sfrbases[0];
 };
 
 static bool set_sysmmu_active(struct sysmmu_drvdata *data)
@@ -373,10 +372,8 @@ static bool __exynos_sysmmu_disable(struct sysmmu_drvdata 
*data)
for (i = 0; i  data-nsfrs; i++)
__raw_writel(CTRL_DISABLE, data-sfrbases[i] + REG_MMU_CTRL);
 
-   if (data-clk[1])
-   clk_disable(data-clk[1]);
-   if (data-clk[0])
-   clk_disable(data-clk[0]);
+   if (data-clk)
+   clk_disable(data-clk);
 
disabled = true;
data-pgtable = 0;
@@ -385,10 +382,10 @@ finish:
spin_unlock_irqrestore(data-lock, flags);
 
if (disabled)
-   dev_dbg(data-sysmmu, (%s) Disabled\n, data-dbgname);
+   dev_dbg(data-sysmmu, Disabled\n);
else
-   dev_dbg(data-sysmmu, (%s) %d times left to be disabled\n,
-   data-dbgname, data-activations);
+   dev_dbg(data-sysmmu, %d times left to be disabled\n,
+   data-activations);
 
return disabled;
 }
@@ -415,14 +412,12 @@ static int __exynos_sysmmu_enable(struct sysmmu_drvdata 
*data,
ret = 1;
}
 
-   dev_dbg(data-sysmmu, (%s) Already enabled\n, data-dbgname);
+   dev_dbg(data-sysmmu, Already enabled\n);
goto finish;
}
 
-   if (data-clk[0])
-   clk_enable(data-clk[0]);
-   if (data-clk[1])
-   clk_enable(data-clk[1]);
+   if (data-clk)
+   clk_enable(data-clk);
 
data-pgtable = pgtable;
 
@@ -442,7 +437,7 @@ static int __exynos_sysmmu_enable(struct sysmmu_drvdata 
*data,
 
data-domain = domain;
 
-   dev_dbg(data-sysmmu, (%s) Enabled\n, data-dbgname);
+   dev_dbg(data-sysmmu, Enabled\n);
 finish:
spin_unlock_irqrestore(data-lock, flags);
 
@@ -458,7 +453,7 @@ int exynos_sysmmu_enable(struct device *dev, unsigned long 
pgtable)
 
ret = pm_runtime_get_sync(data-sysmmu);
if (ret  0) {
-   dev_dbg(data-sysmmu, (%s) Failed to enable\n, data-dbgname);
+   dev_dbg(data-sysmmu, Failed to enable\n);
return ret;
}
 
@@ -466,8 +461,8 @@ int exynos_sysmmu_enable(struct device *dev, unsigned long 
pgtable)
if (WARN_ON(ret  0)) {
pm_runtime_put(data-sysmmu);
dev_err(data-sysmmu,
-   (%s) Already enabled with page table %#lx\n,
-   data-dbgname, data-pgtable);
+   Already enabled with page table %#lx\n,
+   data-pgtable);
} else {
data-dev = dev;
}
@@ -504,8 +499,7 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, 
unsigned 

[PATCH v6 06/12] iommu/exynos: set System MMU as the parent of client device

2012-12-25 Thread Cho KyongHo
This commit sets System MM as the parent of the client device for
power management. If System MMU is the parent of a device, it is
guaranteed that System MMU is suspended later than the device and
resumed earlier. Runtime suspend/resume on the device is also
propagated to the System MMU.
If a device is configured to have more than one System MMU, the
advantage of power management also works and the System MMUs are
also have relationships of parent and child. In this situation,
the client device is still the descendant of its System MMUs.

Signed-off-by: KyongHo Cho pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c | 510 +--
 1 file changed, 342 insertions(+), 168 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 5b35820..a0e5ee1 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -101,6 +101,17 @@
 #define REG_PB1_SADDR  0x054
 #define REG_PB1_EADDR  0x058
 
+static void *sysmmu_placeholder; /* Inidcate if a device is System MMU */
+
+#define is_sysmmu(sysmmu) (sysmmu-archdata.iommu == sysmmu_placeholder)
+#define has_sysmmu(dev)
\
+   (dev-parent  dev-archdata.iommu  is_sysmmu(dev-parent))
+#define for_each_sysmmu(dev, sysmmu)   \
+   for (sysmmu = dev-parent; sysmmu  is_sysmmu(sysmmu); \
+   sysmmu = sysmmu-parent)
+#define for_each_sysmmu_until(dev, sysmmu, until)  \
+   for (sysmmu = dev-parent; sysmmu != until; sysmmu = sysmmu-parent)
+
 static struct kmem_cache *lv2table_kmem_cache;
 
 static unsigned long *section_entry(unsigned long *pgtable, unsigned long iova)
@@ -157,10 +168,19 @@ struct exynos_iommu_domain {
spinlock_t pgtablelock; /* lock for modifying page table @ pgtable */
 };
 
+/* exynos_iommu_owner
+ * Metadata attached to the owner of a group of System MMUs that belong
+ * to the same owner device.
+ */
+struct exynos_iommu_owner {
+   struct list_head client; /* entry of exynos_iommu_domain.clients */
+   struct device *dev;
+   spinlock_t lock;/* Lock to preserve consistency of System MMU */
+};
+
 struct sysmmu_drvdata {
-   struct list_head node; /* entry of exynos_iommu_domain.clients */
struct device *sysmmu;  /* System MMU's device descriptor */
-   struct device *dev; /* Owner of system MMU */
+   struct device *master;  /* Client device that needs System MMU */
int nsfrs;
struct clk *clk;
int activations;
@@ -241,44 +261,50 @@ void exynos_sysmmu_set_prefbuf(struct device *dev,
unsigned long base0, unsigned long size0,
unsigned long base1, unsigned long size1)
 {
-   struct sysmmu_drvdata *data = dev_get_drvdata(dev-archdata.iommu);
-   unsigned long flags;
-   int i;
+   struct device *sysmmu;
 
-   BUG_ON((base0 + size0) = base0);
-   BUG_ON((size1  0)  ((base1 + size1) = base1));
+   for_each_sysmmu(dev, sysmmu) {
+   int i;
+   unsigned long flags;
+   struct sysmmu_drvdata *data = dev_get_drvdata(sysmmu);
 
-   spin_lock_irqsave(data-lock, flags);
-   if (!is_sysmmu_active(data))
-   goto finish;
+   BUG_ON((base0 + size0) = base0);
+   BUG_ON((size1  0)  ((base1 + size1) = base1));
 
-   for (i = 0; i  data-nsfrs; i++) {
-   if ((readl(data-sfrbases[i] + REG_MMU_VERSION)  28) == 3) {
-   if (!sysmmu_block(data-sfrbases[i]))
-   continue;
+   spin_lock_irqsave(data-lock, flags);
+   if (!is_sysmmu_active(data)) {
+   spin_unlock_irqrestore(data-lock, flags);
+   continue;
+   }
 
-   if (size1 == 0) {
-   if (size0 = SZ_128K) {
-   base1 = base0;
-   size1 = size0;
-   } else {
-   size1 = size0 -
+   for (i = 0; i  data-nsfrs; i++) {
+   if ((readl(data-sfrbases[i] + REG_MMU_VERSION)  28)
+   == 3) {
+   if (!sysmmu_block(data-sfrbases[i]))
+   continue;
+
+   if (size1 == 0) {
+   if (size0 = SZ_128K) {
+   base1 = base0;
+   size1 = size0;
+   } else {
+   size1 = size0 -
ALIGN(size0 / 2, SZ_64K);

[PATCH v6 07/12] ARM: EXYNOS: remove system mmu initialization from exynos tree

2012-12-25 Thread Cho KyongHo
This removes System MMU initialization from arch/arm/mach-exynos/
to move them to DT and the exynos-iommu driver except gating clock
definitions.

Signed-off-by: KyongHo Cho pullip@samsung.com
---
 arch/arm/mach-exynos/Kconfig   |   5 -
 arch/arm/mach-exynos/Makefile  |   1 -
 arch/arm/mach-exynos/clock-exynos4.c   |  41 +++--
 arch/arm/mach-exynos/clock-exynos4210.c|   9 +-
 arch/arm/mach-exynos/clock-exynos4212.c|  23 ++-
 arch/arm/mach-exynos/clock-exynos5.c   |  62 ---
 arch/arm/mach-exynos/dev-sysmmu.c  | 274 -
 arch/arm/mach-exynos/include/mach/sysmmu.h |  66 ---
 arch/arm/mach-exynos/mach-exynos4-dt.c |  34 
 arch/arm/mach-exynos/mach-exynos5-dt.c |  30 
 10 files changed, 137 insertions(+), 408 deletions(-)
 delete mode 100644 arch/arm/mach-exynos/dev-sysmmu.c
 delete mode 100644 arch/arm/mach-exynos/include/mach/sysmmu.h

diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index 91d5b6f..eba6eb5 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -103,11 +103,6 @@ config EXYNOS4_SETUP_FIMD0
help
  Common setup code for FIMD0.
 
-config EXYNOS_DEV_SYSMMU
-   bool
-   help
- Common setup code for SYSTEM MMU in EXYNOS platforms
-
 config EXYNOS4_DEV_USB_OHCI
bool
help
diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
index b189881..435757e 100644
--- a/arch/arm/mach-exynos/Makefile
+++ b/arch/arm/mach-exynos/Makefile
@@ -52,7 +52,6 @@ obj-$(CONFIG_ARCH_EXYNOS4)+= dev-audio.o
 obj-$(CONFIG_EXYNOS4_DEV_AHCI) += dev-ahci.o
 obj-$(CONFIG_EXYNOS_DEV_DMA)   += dma.o
 obj-$(CONFIG_EXYNOS4_DEV_USB_OHCI) += dev-ohci.o
-obj-$(CONFIG_EXYNOS_DEV_SYSMMU)+= dev-sysmmu.o
 
 obj-$(CONFIG_ARCH_EXYNOS)  += setup-i2c0.o
 obj-$(CONFIG_EXYNOS4_SETUP_FIMC)   += setup-fimc.o
diff --git a/arch/arm/mach-exynos/clock-exynos4.c 
b/arch/arm/mach-exynos/clock-exynos4.c
index bbcb3de..8a8468d 100644
--- a/arch/arm/mach-exynos/clock-exynos4.c
+++ b/arch/arm/mach-exynos/clock-exynos4.c
@@ -24,7 +24,6 @@
 
 #include mach/map.h
 #include mach/regs-clock.h
-#include mach/sysmmu.h
 
 #include common.h
 #include clock-exynos4.h
@@ -709,53 +708,53 @@ static struct clk exynos4_init_clocks_off[] = {
.enable = exynos4_clk_ip_peril_ctrl,
.ctrlbit= (1  14),
}, {
-   .name   = SYSMMU_CLOCK_NAME,
-   .devname= SYSMMU_CLOCK_DEVNAME(mfc_l, 0),
+   .name   = sysmmu,
+   .devname= exynos-sysmmu.0,
.enable = exynos4_clk_ip_mfc_ctrl,
.ctrlbit= (1  1),
}, {
-   .name   = SYSMMU_CLOCK_NAME,
-   .devname= SYSMMU_CLOCK_DEVNAME(mfc_r, 1),
+   .name   = sysmmu,
+   .devname= exynos-sysmmu.1,
.enable = exynos4_clk_ip_mfc_ctrl,
.ctrlbit= (1  2),
}, {
-   .name   = SYSMMU_CLOCK_NAME,
-   .devname= SYSMMU_CLOCK_DEVNAME(tv, 2),
+   .name   = sysmmu,
+   .devname= exynos-sysmmu.2,
.enable = exynos4_clk_ip_tv_ctrl,
.ctrlbit= (1  4),
}, {
-   .name   = SYSMMU_CLOCK_NAME,
-   .devname= SYSMMU_CLOCK_DEVNAME(jpeg, 3),
+   .name   = sysmmu,
+   .devname= exynos-sysmmu.3,
.enable = exynos4_clk_ip_cam_ctrl,
.ctrlbit= (1  11),
}, {
-   .name   = SYSMMU_CLOCK_NAME,
-   .devname= SYSMMU_CLOCK_DEVNAME(rot, 4),
+   .name   = sysmmu,
+   .devname= exynos-sysmmu.4,
.enable = exynos4_clk_ip_image_ctrl,
.ctrlbit= (1  4),
}, {
-   .name   = SYSMMU_CLOCK_NAME,
-   .devname= SYSMMU_CLOCK_DEVNAME(fimc0, 5),
+   .name   = sysmmu,
+   .devname= exynos-sysmmu.5,
.enable = exynos4_clk_ip_cam_ctrl,
.ctrlbit= (1  7),
}, {
-   .name   = SYSMMU_CLOCK_NAME,
-   .devname= SYSMMU_CLOCK_DEVNAME(fimc1, 6),
+   .name   = sysmmu,
+   .devname= exynos-sysmmu.6,
.enable = exynos4_clk_ip_cam_ctrl,
.ctrlbit= (1  8),
}, {
-   .name   = SYSMMU_CLOCK_NAME,
-   .devname= SYSMMU_CLOCK_DEVNAME(fimc2, 7),
+   .name   = sysmmu,
+   .devname= 

[PATCH v6 08/12] iommu/exynos: add support for runtime pm and suspend/resume

2012-12-25 Thread Cho KyongHo
This change enables the client device drivers not to care about
the state of System MMU since the internal state of System MMU
is controlled by the runtime PM and suspend/resume callback functions.

Signed-off-by: KyongHo Cho pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c | 176 ++-
 1 file changed, 89 insertions(+), 87 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index a0e5ee1..c3c5b7b 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -187,6 +187,7 @@ struct sysmmu_drvdata {
spinlock_t lock;
struct iommu_domain *domain;
unsigned long pgtable;
+   bool runtime_active;
void __iomem *sfrbases[0];
 };
 
@@ -409,7 +410,8 @@ static bool __sysmmu_disable(struct sysmmu_drvdata *data)
data-pgtable = 0;
data-domain = NULL;
 
-   __sysmmu_disable_nocount(data);
+   if (data-runtime_active)
+   __sysmmu_disable_nocount(data);
 
dev_dbg(data-sysmmu, Disabled\n);
} else  {
@@ -422,30 +424,6 @@ static bool __sysmmu_disable(struct sysmmu_drvdata *data)
return disabled;
 }
 
-static bool __exynos_sysmmu_disable(struct device *dev)
-{
-   unsigned long flags;
-   bool disabled = true;
-   struct exynos_iommu_owner *owner = dev-archdata.iommu;
-   struct device *sysmmu;
-
-   BUG_ON(!has_sysmmu(dev));
-
-   spin_lock_irqsave(owner-lock, flags);
-
-   /* Every call to __sysmmu_disable() must return same result */
-   for_each_sysmmu(dev, sysmmu) {
-   struct sysmmu_drvdata *data = dev_get_drvdata(sysmmu);
-   disabled = __sysmmu_disable(data);
-   if (disabled)
-   data-master = NULL;
-   }
-
-   spin_unlock_irqrestore(owner-lock, flags);
-
-   return disabled;
-}
-
 static void __sysmmu_enable_nocount(struct sysmmu_drvdata *data)
 {
int i;
@@ -481,7 +459,8 @@ static int __sysmmu_enable(struct sysmmu_drvdata *data,
data-pgtable = pgtable;
data-domain = domain;
 
-   __sysmmu_enable_nocount(data);
+   if (data-runtime_active)
+   __sysmmu_enable_nocount(data);
 
dev_dbg(data-sysmmu, Enabled\n);
} else {
@@ -537,42 +516,31 @@ static int __exynos_sysmmu_enable(struct device *dev, 
unsigned long pgtable,
 
 int exynos_sysmmu_enable(struct device *dev, unsigned long pgtable)
 {
-   int ret;
-   struct device *sysmmu;
-
BUG_ON(!memblock_is_memory(pgtable));
 
-   for_each_sysmmu(dev, sysmmu) {
-   ret = pm_runtime_get_sync(sysmmu);
-   if (ret  0)
-   break;
-   }
-
-   if (ret  0) {
-   struct device *start;
-   for_each_sysmmu_until(dev, start, sysmmu)
-   pm_runtime_put(start);
-
-   return ret;
-   }
-
-   ret = __exynos_sysmmu_enable(dev, pgtable, NULL);
-   if (ret  0)
-   for_each_sysmmu(dev, sysmmu)
-   pm_runtime_put(sysmmu);
-
-   return ret;
+   return __exynos_sysmmu_enable(dev, pgtable, NULL);
 }
 
 bool exynos_sysmmu_disable(struct device *dev)
 {
-   bool disabled;
+   unsigned long flags;
+   bool disabled = true;
+   struct exynos_iommu_owner *owner = dev-archdata.iommu;
struct device *sysmmu;
 
-   disabled = __exynos_sysmmu_disable(dev);
+   BUG_ON(!has_sysmmu(dev));
+
+   spin_lock_irqsave(owner-lock, flags);
+
+   /* Every call to __sysmmu_disable() must return same result */
+   for_each_sysmmu(dev, sysmmu) {
+   struct sysmmu_drvdata *drvdata = dev_get_drvdata(sysmmu);
+   disabled = __sysmmu_disable(drvdata);
+   if (disabled)
+   drvdata-master = NULL;
+   }
 
-   for_each_sysmmu(dev, sysmmu)
-   pm_runtime_put(sysmmu);
+   spin_unlock_irqrestore(owner-lock, flags);
 
return disabled;
 }
@@ -588,7 +556,8 @@ static void sysmmu_tlb_invalidate_entry(struct device *dev, 
unsigned long iova)
data = dev_get_drvdata(sysmmu);
 
spin_lock_irqsave(data-lock, flags);
-   if (is_sysmmu_active(data)) {
+   if (is_sysmmu_active(data) 
+   data-runtime_active) {
int i;
for (i = 0; i  data-nsfrs; i++) {
if (sysmmu_block(data-sfrbases[i])) {
@@ -817,7 +786,7 @@ static int __init exynos_sysmmu_probe(struct 
platform_device *pdev)
data-sysmmu = dev;
spin_lock_init(data-lock);
 
-   pm_runtime_enable(dev);
+   data-runtime_active = !pm_runtime_enabled(dev);
 
platform_set_drvdata(pdev, data);
 
@@ -828,6 +797,64 @@ static 

[PATCH v6 10/12] iommu/exynos: pass version information from DT

2012-12-25 Thread Cho KyongHo
System MMUs in some implementation of Exynos core does not include
correct version information in the System MMU. If the version
information is not correct, exynos-iommu driver cannot take advantages
of feature of higher versions of System MMu like prefetching page
table entries prior to TLB miss.

This commit allows passing version information from DT to the driver.
If DT does not pass version information, the driver will read the
information from System MMU.

Signed-off-by: KyongHo Cho pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c | 28 
 1 file changed, 28 insertions(+)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index a558c51..70921e9 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -205,6 +205,12 @@ struct sysmmu_prefbuf {
unsigned long config;
 };
 
+struct sysmmu_version {
+   unsigned char major; /* major = 0 means that driver must use MMU_VERSION
+   register instead of this structure */
+   unsigned char minor;
+};
+
 struct sysmmu_drvdata {
struct device *sysmmu;  /* System MMU's device descriptor */
struct device *master;  /* Client device that needs System MMU */
@@ -214,6 +220,7 @@ struct sysmmu_drvdata {
spinlock_t lock;
struct sysmmu_prefbuf pbufs[MAX_NUM_PBUF];
int num_pbufs;
+   struct sysmmu_version ver;
struct iommu_domain *domain;
unsigned long pgtable;
bool runtime_active;
@@ -246,6 +253,20 @@ static unsigned int __sysmmu_version(struct sysmmu_drvdata 
*drvdata,
 
major = readl(drvdata-sfrbases[idx] + REG_MMU_VERSION);
 
+   if ((MMU_MAJ_VER(major) == 0) || (MMU_MAJ_VER(major)  3)) {
+   /* register MMU_VERSION is used for special purpose */
+   if (drvdata-ver.major == 0) {
+   /* min ver. is not important for System MMU 1 and 2 */
+   major = 1;
+   } else {
+   if (minor)
+   *minor = drvdata-ver.minor;
+   major = drvdata-ver.major;
+   }
+
+   return major;
+   }
+
if (minor)
*minor = MMU_MIN_VER(major);
 
@@ -933,8 +954,15 @@ static int __init __sysmmu_setup(struct device *sysmmu,
const char *compat;
struct platform_device *pmaster = NULL;
u32 master_inst_no = -1;
+   u32 ver[2];
int ret;
 
+   if (!of_property_read_u32_array(sysmmu-of_node, version, ver, 2)) {
+   drvdata-ver.major = (unsigned char)ver[0];
+   drvdata-ver.minor = (unsigned char)ver[1];
+   dev_dbg(sysmmu, Found version %d.%d\n, ver[0], ver[1]);
+   }
+
drvdata-pbufs[0].base = 0;
drvdata-pbufs[0].size = ~0;
drvdata-num_pbufs = 1;
-- 
1.8.0


___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v6 11/12] iommu/exynos: add literal name of System MMU for debugging

2012-12-25 Thread Cho KyongHo
This commit adds System MMU name to the driver data of each System
MMU. It is used by fault information.

Signed-off-by: KyongHo Cho pullip@samsung.com
---
 drivers/iommu/exynos-iommu.c | 72 
 1 file changed, 59 insertions(+), 13 deletions(-)

diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 70921e9..9753e0e 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -26,6 +26,7 @@
 #include linux/list.h
 #include linux/memblock.h
 #include linux/export.h
+#include linux/string.h
 #include linux/of.h
 #include linux/of_platform.h
 
@@ -180,6 +181,7 @@ struct exynos_iommu_domain {
short *lv2entcnt; /* free lv2 entry counter for each section */
spinlock_t lock; /* lock for this structure */
spinlock_t pgtablelock; /* lock for modifying page table @ pgtable */
+   const char *fault_info; /* debugging information for fault */
 };
 
 /* exynos_iommu_owner
@@ -224,6 +226,7 @@ struct sysmmu_drvdata {
struct iommu_domain *domain;
unsigned long pgtable;
bool runtime_active;
+   const char **mmuname;
void __iomem *sfrbases[0];
 };
 
@@ -601,25 +604,29 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void 
*dev_id)
 {
/* SYSMMU is in blocked when interrupt occurred. */
struct sysmmu_drvdata *data = dev_id;
-   struct resource *irqres;
-   struct platform_device *pdev;
+   struct exynos_iommu_owner *owner = NULL;
enum exynos_sysmmu_inttype itype = SYSMMU_FAULT_UNKNOWN;
unsigned long addr = -1;
-
int i, ret = -ENOSYS;
 
-   spin_lock(data-lock);
+   if (data-master)
+   owner = data-master-archdata.iommu;
+
+   if (owner)
+   spin_lock(owner-lock);
 
WARN_ON(!is_sysmmu_active(data));
 
-   pdev = to_platform_device(data-sysmmu);
-   for (i = 0; i  (pdev-num_resources / 2); i++) {
-   irqres = platform_get_resource(pdev, IORESOURCE_IRQ, i);
+   for (i = 0; i  data-nsfrs; i++) {
+   struct resource *irqres;
+   irqres = platform_get_resource(
+   to_platform_device(data-sysmmu),
+   IORESOURCE_IRQ, i);
if (irqres  ((int)irqres-start == irq))
break;
}
 
-   if (i  pdev-num_resources) {
+   if (i  data-nsfrs) {
itype = (enum exynos_sysmmu_inttype)
__ffs(__raw_readl(data-sfrbases[i] + REG_INT_STATUS));
if (WARN_ON(!((itype = 0)  (itype  SYSMMU_FAULT_UNKNOWN
@@ -629,11 +636,17 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void 
*dev_id)
data-sfrbases[i] + fault_reg_offset[itype]);
}
 
-   if (data-domain)
+   if ((itype = SYSMMU_FAULTS_NUM) || (itype  SYSMMU_PAGEFAULT))
+   itype = SYSMMU_FAULT_UNKNOWN;
+
+   if (data-domain) {
+   struct exynos_iommu_domain *priv = data-domain-priv;
+   priv-fault_info = data-mmuname[i];
ret = report_iommu_fault(data-domain,
data-master, addr, itype);
-   else
+   } else {
__show_fault_information(__va(data-pgtable), itype, addr);
+   }
 
if (ret == -ENOSYS)
pr_err(NO SYSTEM MMU FAULT HANDLER REGISTERED FOR %s\n,
@@ -651,7 +664,8 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id)
 
sysmmu_unblock(data-sfrbases[i]);
 
-   spin_unlock(data-lock);
+   if (owner)
+   spin_unlock(owner-lock);
 
return IRQ_HANDLED;
 }
@@ -1028,6 +1042,30 @@ err_dev_put:
return ret;
 }
 
+static void __init __sysmmu_init_mmuname(struct device *sysmmu,
+   struct sysmmu_drvdata *drvdata)
+{
+   int i;
+   const char *mmuname;
+
+   if (of_property_count_strings(sysmmu-of_node, mmuname) !=
+   drvdata-nsfrs)
+   return;
+
+   drvdata-mmuname = (void *)drvdata-sfrbases +
+   sizeof(drvdata-sfrbases[0]) * drvdata-nsfrs;
+
+   for (i = 0; i  drvdata-nsfrs; i++) {
+   if (of_property_read_string_index(sysmmu-of_node,
+   mmuname, i, mmuname))
+   dev_err(sysmmu, Failed read mmuname[%d]\n, i);
+   else
+   drvdata-mmuname[i] = kstrdup(mmuname, GFP_KERNEL);
+   if (!drvdata-mmuname[i])
+   drvdata-mmuname[i] = noname;
+   }
+}
+
 static int __init exynos_sysmmu_probe(struct platform_device *pdev)
 {
int i, ret;
@@ -1039,9 +1077,14 @@ static int __init exynos_sysmmu_probe(struct 
platform_device *pdev)
return -ENODEV;
}
 
+   ret = of_property_count_strings(pdev-dev.of_node, mmuname);
+

  1   2   >