Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver

2015-03-09 Thread Yong Wu
Dear Mitchel,
 Thanks very much for your review.

On Fri, 2015-03-06 at 09:15 -0800, Mitchel Humpherys wrote:
 On Fri, Mar 06 2015 at 02:48:17 AM, yong...@mediatek.com wrote:
  From: Yong Wu yong...@mediatek.com
 
  This patch adds support for mediatek m4u (MultiMedia Memory Management 
  Unit).
  Currently this only supports m4u gen 2 with 2 levels of page table on 
  mt8173.
 
 [...]
 
  +static int mtk_iommu_invalidate_tlb(const struct mtk_iommu_info *piommu,
  +   int isinvall, unsigned int iova_start,
  +   unsigned int iova_end)
  +{
  +   void __iomem *m4u_base = piommu-m4u_base;
  +   u32 val;
  +   u64 start, end;
  +
  +   start = sched_clock();
  +
  +   if (!isinvall) {
  +   iova_start = round_down(iova_start, SZ_4K);
  +   iova_end = round_up(iova_end, SZ_4K);
  +   }
  +
  +   val = F_MMU_INV_EN_L2 | F_MMU_INV_EN_L1;
  +
  +   writel(val, m4u_base + REG_INVLID_SEL);
  +
  +   if (isinvall) {
  +   writel(F_MMU_INV_ALL, m4u_base + REG_MMU_INVLD);
  +   } else {
  +   writel(iova_start, m4u_base + REG_MMU_INVLD_SA);
  +   writel(iova_end, m4u_base + REG_MMU_INVLD_EA);
  +   writel(F_MMU_INV_RANGE, m4u_base + REG_MMU_INVLD);
  +
  +   while (!readl(m4u_base + REG_MMU_CPE_DONE)) {
  +   end = sched_clock();
  +   if (end - start = 1ULL) {
  +   dev_warn(piommu-dev, invalid don't done\n);
  +   writel(F_MMU_INV_ALL, m4u_base + REG_MMU_INVLD);
  +   }
  +   };
 
 Superfluous `;'.  Also, maybe you should be using readl_poll_timeout?
   Thanks.
   For the readl_poll_timeout, My base is 3.19-rc7 and robin's patch.
it don't have this interface.  I will try to add it in the next version.
 
  +   writel(0, m4u_base + REG_MMU_CPE_DONE);
  +   }
  +
  +   return 0;
  +}
 
 
 
 -Mitch
 


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


Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver

2015-03-09 Thread Tomasz Figa
Hi,

You can find part 2 of my comments inline.

On Fri, Mar 6, 2015 at 7:48 PM,  yong...@mediatek.com wrote:

[snip]

 +static irqreturn_t mtk_iommu_isr(int irq, void *dev_id)
 +{
 +   struct iommu_domain *domain = dev_id;
 +   struct mtk_iommu_domain *mtkdomain = domain-priv;
 +   struct mtk_iommu_info *piommu = mtkdomain-piommuinfo;
 +
 +   if (irq == piommu-irq)
 +   report_iommu_fault(domain, piommu-dev, 0, 0);

In addition to my previous comment about how this gets called from
this handler, you need to keep in mind that the function called by
report_iommu_fault() might actually be a different function than
mtk_iommu_fault_handler(), because upper layers can provide their own
handlers. This means that you need to perform any operations on
hardware from this handler and only use the iommu fault handler as a
way to tell an upper layer about the fault (including notifying the
user through kernel log if there is no special handler installed and
the generic fallback is used).

 +   else
 +   dev_err(piommu-dev, irq number:%d\n, irq);
 +
 +   return IRQ_HANDLED;
 +}

[snip]

 +static int mtk_iommu_fault_handler(struct iommu_domain *imudomain,
 +  struct device *dev, unsigned long iova,
 +  int m4uindex, void *pimu)
 +{
 +   void __iomem *m4u_base;
 +   u32 int_state, regval;
 +   int m4u_slave_id = 0;
 +   unsigned int layer, write, m4u_port;
 +   unsigned int fault_mva, fault_pa;
 +   struct mtk_iommu_info *piommu = pimu;
 +   struct mtk_iommu_domain *mtkdomain = imudomain-priv;
 +
 +   m4u_base = piommu-m4u_base;
 +   int_state = readl(m4u_base + REG_MMU_MAIN_FAULT_ST);
 +
 +   /* read error info from registers */
 +   fault_mva = readl(m4u_base + REG_MMU_FAULT_VA(m4u_slave_id));
 +   layer = !!(fault_mva  F_MMU_FAULT_VA_LAYER_BIT);
 +   write = !!(fault_mva  F_MMU_FAULT_VA_WRITE_BIT);
 +   fault_mva = F_MMU_FAULT_VA_MSK;
 +   fault_pa = readl(m4u_base + REG_MMU_INVLD_PA(m4u_slave_id));
 +   regval = readl(m4u_base + REG_MMU_INT_ID(m4u_slave_id));
 +   regval = F_MMU0_INT_ID_TF_MSK;
 +   m4u_port = mtk_iommu_get_port_by_tfid(piommu, regval);
 +
 +   if (int_state  F_INT_TRANSLATION_FAULT(m4u_slave_id)) {
 +   struct m4u_pte_info_t pte;
 +   unsigned long flags;
 +
 +   spin_lock_irqsave(mtkdomain-pgtlock, flags);
 +   m4u_get_pte_info(mtkdomain, fault_mva, pte);
 +   spin_unlock_irqrestore(mtkdomain-pgtlock, flags);
 +
 +   if (pte.size == MMU_SMALL_PAGE_SIZE ||
 +   pte.size == MMU_LARGE_PAGE_SIZE) {
 +   dev_err_ratelimited(
 +   dev,
 +   fault:port=%s iova=0x%x pa=0x%x layer=%d %s;
 +   
 pgd(0x%x)-pte(0x%x)-pa(%pad)sz(0x%x)Valid(%d)\n,
 +   mtk_iommu_get_port_name(piommu, m4u_port),
 +   fault_mva, fault_pa, layer,
 +   write ? write : read,
 +   imu_pgd_val(*pte.pgd), imu_pte_val(*pte.pte),
 +   pte.pa, pte.size, pte.valid);
 +   } else {
 +   dev_err_ratelimited(
 +   dev,
 +   fault:port=%s iova=0x%x pa=0x%x layer=%d %s;
 +   pgd(0x%x)-pa(%pad)sz(0x%x)Valid(%d)\n,
 +   mtk_iommu_get_port_name(piommu, m4u_port),
 +   fault_mva, fault_pa, layer,
 +   write ? write : read,
 +   imu_pgd_val(*pte.pgd),
 +   pte.pa, pte.size, pte.valid);
 +   }
 +   }
 +
 +   if (int_state  F_INT_MAIN_MULTI_HIT_FAULT(m4u_slave_id))
 +   dev_err_ratelimited(dev, multi-hit!port=%s iova=0x%x\n,
 +   mtk_iommu_get_port_name(piommu, m4u_port),
 +   fault_mva);
 +
 +   if (int_state  F_INT_INVALID_PA_FAULT(m4u_slave_id)) {
 +   if (!(int_state  F_INT_TRANSLATION_FAULT(m4u_slave_id)))
 +   dev_err_ratelimited(dev, invalid pa!port=%s 
 iova=0x%x\n,
 +   mtk_iommu_get_port_name(piommu,
 +   m4u_port),
 +   fault_mva);
 +   }
 +   if (int_state  F_INT_ENTRY_REPLACEMENT_FAULT(m4u_slave_id))
 +   dev_err_ratelimited(dev, replace-fault!port=%s iova=0x%x\n,
 +   mtk_iommu_get_port_name(piommu, m4u_port),
 +   fault_mva);
 +
 +   if (int_state  F_INT_TLB_MISS_FAULT(m4u_slave_id))
 +   

Re: [PATCH 4/5] dt-bindings: iommu: Add binding for mediatek IOMMU

2015-03-09 Thread Yong Wu
Dear Mark,

 Thanks very much for your review.
 I will fix them in the next verion.

On Fri, 2015-03-06 at 11:21 +, Mark Rutland wrote:
 On Fri, Mar 06, 2015 at 10:48:19AM +, yong...@mediatek.com wrote:
  From: Yong Wu yong...@mediatek.com
  
  This patch add mediatek iommu dts binding document.
  
  Signed-off-by: Yong Wu yong...@mediatek.com
  ---
   .../devicetree/bindings/iommu/mediatek,iommu.txt   | 41 
  ++
   1 file changed, 41 insertions(+)
   create mode 100644 
  Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
  
  diff --git a/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt 
  b/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
  new file mode 100644
  index 000..db01c92
  --- /dev/null
  +++ b/Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
  @@ -0,0 +1,41 @@
  +/**/
  +/*Mediatek IOMMU Hardware block diagram   */
  +/**/
  +  EMI (External Memory Interface)
  +   |
  +  m4u (Multimedia Memory Management Unit)
  +   |
  +  smi (Smart Multimedia Interface)
  +   |
  ++---+---
  +|   |
  +|   |
  +vdec larb   disp larb  ... SoCs have different local 
  arbiter(larb).
  +|   |
  +|   |
  +   ++++-+-+
  +   |||| | |...
  +   |||| | |...
  +   |||| | |...
  +  MC   PP   VLD  OVL0 RDMA0 WDMA0  ... There are different ports in each 
  larb.
  +
  +Required properties:
  +- compatible : must be mediatek,mt8173-iommu
 
 s/iommu/m4u/ -- the name should match what the hardware is called.
 
  +- reg : m4u register base
 
 ... and size
 
  +- interrupts : must contain the interrupts from each internal translation 
  unit
 
 How many internal translation units are there?
 
 How should the interrupts be ordered?
 
 How do these relate to the larbs?
   There is only one internal translation units in MT8173.(2 units in
MT8135)
   Because this patch is only for mt8173, so I will change it like this:

interrupts : the interrupt of the m4u.
is it ok?
 
  +- clocks : must contain one entry for each clock-name
  +- clock-name: m4u clock
 
 This does not match the example.
 
 s/clock-name/clock-names/
 
 Please format this like a list, with names quoted, e.g.
 
 - clock-names: must contain:
   * m4u - The functional clock for the m4u
 
  +- larb : must contain the larbes of current platform
 
 s/larbes/local arbiters/
 
 How should these be ordered? Surely there's a relationship with
 registers/interrupts/etc in this unit?
 
  +- iommu-cells : must be 1. Specifies the client PortID as defined in
  +dt-binding/iommu/mt**-iommu-port.h
 
 Give the absolute filename.
 
 The include file should be added in this patch (it's part of the
 binding). The whole patch should be moved earlier in the series.
 
 Thanks,
 Mark.
 
  +
  +Example:
  +   iommu: mmsys_iommu@10205000 {
  +   compatible = mediatek,mt8173-iommu;
  +   reg = 0 0x10205000 0 0x1000;
  +   interrupts = GIC_SPI 139 IRQ_TYPE_LEVEL_LOW;
  +   clocks = infrasys INFRA_M4U;
  +   clock-names = infra_m4u;
  +   larb = larb0 larb1 larb2 larb3 larb4 larb5;
  +   #iommu-cells = 1;
  +   };
  \ No newline at end of file
  -- 
  1.8.1.1.dirty
  
  


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


Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver

2015-03-09 Thread Tomasz Figa
On Mon, Mar 9, 2015 at 11:46 PM, Yingjoe Chen yingjoe.c...@mediatek.com wrote:
 On Mon, 2015-03-09 at 20:11 +0900, Tomasz Figa wrote:
 ...
  +/*
  + * pimudev is a global var for dma_alloc_coherent.
  + * It is not accepatable, we will delete it if domain_alloc is enabled
  + */
  +static struct device *pimudev;

 This is indeed not acceptable. Could you replace dma_alloc_coherent()
 with something that doesn't require device pointer, e.g.
 alloc_pages()? (Although that would require you to handle cache
 maintenance in the driver, due to cached memory allocated.) I need to
 think about a better solution for this.

 Hi,

 For 2nd level page table, we use cached memory now. Currently we are
 using __dma_flush_range to flush the cache, which is also unacceptable.

 For proper cache management, we'll need to use dma_map_single or
 dma_sync_*, which still need a deivce*.

Looking at how already mainlined drivers do this, they either use
dmac_flush_range()
(https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/iommu/msm_iommu.c?id=refs/tags/v4.0-rc3#n80)
or directly __cpuc_flush_dcache_area() and outer_flush_range()
(https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/iommu/rockchip-iommu.c?id=refs/tags/v4.0-rc3#n93).

Joerg, what's your opinion on this?

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


Re: [PATCH 2/5] iommu/mediatek: Add mt8173 IOMMU driver

2015-03-09 Thread Yingjoe Chen
On Tue, 2015-03-10 at 02:00 +0900, Tomasz Figa wrote:
 On Mon, Mar 9, 2015 at 11:46 PM, Yingjoe Chen yingjoe.c...@mediatek.com 
 wrote:
  On Mon, 2015-03-09 at 20:11 +0900, Tomasz Figa wrote:
  ...
   +/*
   + * pimudev is a global var for dma_alloc_coherent.
   + * It is not accepatable, we will delete it if domain_alloc is enabled
   + */
   +static struct device *pimudev;
 
  This is indeed not acceptable. Could you replace dma_alloc_coherent()
  with something that doesn't require device pointer, e.g.
  alloc_pages()? (Although that would require you to handle cache
  maintenance in the driver, due to cached memory allocated.) I need to
  think about a better solution for this.
 
  Hi,
 
  For 2nd level page table, we use cached memory now. Currently we are
  using __dma_flush_range to flush the cache, which is also unacceptable.
 
  For proper cache management, we'll need to use dma_map_single or
  dma_sync_*, which still need a deivce*.
 
 Looking at how already mainlined drivers do this, they either use
 dmac_flush_range()
 (https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/iommu/msm_iommu.c?id=refs/tags/v4.0-rc3#n80)
 or directly __cpuc_flush_dcache_area() and outer_flush_range()
 (https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/drivers/iommu/rockchip-iommu.c?id=refs/tags/v4.0-rc3#n93).

Hi,

These only exist in arch/arm, not arm64. I think we should avoid using
API start with __ in drivers. This driver might be used in both
arm/arm64, I think the only option for us is DMA APIs.

Actually, I'm thinking that we should change to use coherent memory for
2nd level page table as well and totally skip the cache flush. It seems
dma_pool_create is suitable to replace kmem_cache we are using right
now. However it still need a device*, which we have to fix anyway.

Joe.C


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


Re: [PATCH 1/5] soc: mediatek: Add SMI driver

2015-03-09 Thread Daniel Kurtz
Hi Yong,

On Fri, Mar 6, 2015 at 6:37 PM,  yong...@mediatek.com wrote:
 From: Yong Wu yong...@mediatek.com

 This patch add SMI(Smart Multimedia Interface) driver. This driver
 is responsible to enable/disable iommu and control the clocks of each
 local arbiter.

High-level:
Is there more to the smi (or smi-larb) driver, or is it always just a
1:1 wrapper for a particular m4u consumer?
In other words, instead of a separate driver, is it possible to move
this functionality into the m4u driver and/or the m4u consumers
directly?


 Signed-off-by: Yong Wu yong...@mediatek.com
 ---
  drivers/soc/mediatek/Kconfig  |   7 ++
  drivers/soc/mediatek/Makefile |   1 +
  drivers/soc/mediatek/mt8173-smi.c | 143 
 ++
  include/linux/mtk-smi.h   |  40 +++
  4 files changed, 191 insertions(+)
  create mode 100644 drivers/soc/mediatek/mt8173-smi.c
  create mode 100644 include/linux/mtk-smi.h

 diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig
 index 729f93e..27fb26c 100644
 --- a/drivers/soc/mediatek/Kconfig
 +++ b/drivers/soc/mediatek/Kconfig
 @@ -20,3 +20,10 @@ config MT8173_PMIC_WRAP
   PMIC wrapper is a proprietary hardware in MT8173 to make
   communication protocols to access PMIC device.
   This driver implement access protocols for MT8173.
 +
 +config MTK_SMI
 +bool
 +   help
 + Smi help enable/disable iommu in mt8173 and control the
 + clock of each local arbiter.
 + It should be true while MTK_IOMMU enable.
 diff --git a/drivers/soc/mediatek/Makefile b/drivers/soc/mediatek/Makefile
 index 9b5709b..cdfe95c 100644
 --- a/drivers/soc/mediatek/Makefile
 +++ b/drivers/soc/mediatek/Makefile
 @@ -1,2 +1,3 @@
  obj-$(CONFIG_MT8135_PMIC_WRAP) += mt8135-pmic-wrap.o
  obj-$(CONFIG_MT8173_PMIC_WRAP) += mt8173-pmic-wrap.o
 +obj-$(CONFIG_MTK_SMI)   += mt8173-smi.o
 diff --git a/drivers/soc/mediatek/mt8173-smi.c 
 b/drivers/soc/mediatek/mt8173-smi.c
 new file mode 100644
 index 000..4e3fab9
 --- /dev/null
 +++ b/drivers/soc/mediatek/mt8173-smi.c
 @@ -0,0 +1,143 @@
 +/*
 + * Copyright (c) 2014-2015 MediaTek Inc.
 + * Author: Yong Wu yong...@mediatek.com
 + *
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License version 2 as
 + * published by the Free Software Foundation.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + */
 +#include linux/io.h
 +#include linux/interrupt.h
 +#include linux/platform_device.h
 +#include linux/clk.h
 +#include linux/err.h
 +#include linux/mm.h
 +
 +#define SMI_LARB_MMU_EN (0xf00)
 +#define F_SMI_MMU_EN(port)  (1  (port))
 +
 +struct mtk_smi_larb {
 +   void __iomem *larb_base;
 +   struct clk *larb_clk[3];/* each larb has 3 clk at most */
 +};
 +
 +static const char * const mtk_smi_clk_name[] = {
 +   larb_sub0, larb_sub1, larb_sub2
 +};

The order and meaning of these clocks do not seem particularly important.
It seems a bit awkward to use these arbitrary names just so we can use
devm_clk_get() to get a variably sized array of clocks from .dts.
Can we eliminate the clock-names property, and just use a single
.dts proprety that lists an array of clocks?
Then you would also get an explicit clock count, and can remove the
NULL checking when iterating.
An example of a clock list without names is:

Clock list in .dts:
  https://lkml.org/lkml/2014/11/17/115
Filling in the clocks from .dts:
  https://lkml.org/lkml/2014/11/17/114

Unfortunately, those patches never made it out of list discussion into
a maintainer tree.

 +
 +static const struct of_device_id mtk_smi_of_ids[] = {
 +   { .compatible = mediatek,mt8173-smi-larb,
 +   },
 +   {}
 +};

I find it a bit redundant to call the struct mtk_smi_larb, and then
to prepend larb_ to all of the fields.
In fact this whole driver is a bit confusing because it isn't clear if
this is an smi driver (of which only larb control has been
implemented) or is this an smi_larb driver (and potentially there
are other smi drivers).

Perhaps we can just call this an smi_larb driver, rename this file
to mt8173-smi-larb.c, and then doing something like:

struct mtk_smi_larb {
  void __iomem *base;
  struct clk *clk[3];/* each smi_larb has at most 3 clocks */
};

static const struct of_device_id mtk_smi_larb_of_ids[] = {
   { .compatible = mediatek,mt8173-smi-larb },
   {}
};


 +
 +int mtk_smi_larb_get(struct platform_device *plarbdev)

Is there any reason to use struct platform_device here instead of
just struct device?

 +{
 +   struct mtk_smi_larb *larbpriv = dev_get_drvdata(plarbdev-dev);
 +   int i, ret = 0;
 +
 +   for (i = 0; i