[PATCH v3 12/12] intel-ipu3: imgu top level pci device

2017-07-18 Thread Yong Zhi
This patch adds support for the Intel IPU v3 as found
on Skylake and Kaby Lake SoCs. The driver has a dependency
on the firmware binary to function properly.

Signed-off-by: Yong Zhi 
Signed-off-by: Tomasz Figa 
---
 drivers/media/pci/intel/ipu3/Kconfig  |  14 +
 drivers/media/pci/intel/ipu3/Makefile |   7 +
 drivers/media/pci/intel/ipu3/ipu3.c   | 844 ++
 drivers/media/pci/intel/ipu3/ipu3.h   | 188 
 4 files changed, 1053 insertions(+)
 create mode 100644 drivers/media/pci/intel/ipu3/ipu3.c
 create mode 100644 drivers/media/pci/intel/ipu3/ipu3.h

diff --git a/drivers/media/pci/intel/ipu3/Kconfig 
b/drivers/media/pci/intel/ipu3/Kconfig
index d503806..5d15ecc 100644
--- a/drivers/media/pci/intel/ipu3/Kconfig
+++ b/drivers/media/pci/intel/ipu3/Kconfig
@@ -32,3 +32,17 @@ config INTEL_IPU3_DMAMAP
select IOMMU_IOVA
---help---
  This is IPU3 IOMMU domain specific DMA driver.
+
+config VIDEO_IPU3_IMGU
+   tristate "Intel ipu3-imgu driver"
+   depends on PCI && VIDEO_V4L2 && IOMMU_SUPPORT
+   depends on MEDIA_CONTROLLER && VIDEO_V4L2_SUBDEV_API
+   select INTEL_IPU3_MMU
+   select INTEL_IPU3_DMAMAP
+   ---help---
+ This is the video4linux2 driver for Intel IPU3 image processing unit,
+ found in Intel Skylake and Kaby Lake SoCs and used for processing
+ images and video.
+
+ Say Y or M here if you have a Skylake/Kaby Lake SoC with a MIPI
+ camera.   The module will be called ipu3-imgu.
diff --git a/drivers/media/pci/intel/ipu3/Makefile 
b/drivers/media/pci/intel/ipu3/Makefile
index 6517732..4448d60 100644
--- a/drivers/media/pci/intel/ipu3/Makefile
+++ b/drivers/media/pci/intel/ipu3/Makefile
@@ -14,3 +14,10 @@
 obj-$(CONFIG_VIDEO_IPU3_CIO2) += ipu3-cio2.o
 obj-$(CONFIG_INTEL_IPU3_MMU) += ipu3-mmu.o
 obj-$(CONFIG_INTEL_IPU3_DMAMAP) += ipu3-dmamap.o
+
+ipu3-imgu-objs += \
+   ipu3-tables.o ipu3-css-pool.o \
+   ipu3-css-fw.o ipu3-css-params.o \
+   ipu3-css.o ipu3-v4l2.o ipu3.o
+
+obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3-imgu.o
diff --git a/drivers/media/pci/intel/ipu3/ipu3.c 
b/drivers/media/pci/intel/ipu3/ipu3.c
new file mode 100644
index 000..a77a10d
--- /dev/null
+++ b/drivers/media/pci/intel/ipu3/ipu3.c
@@ -0,0 +1,844 @@
+/*
+ * Copyright (c) 2017 Intel Corporation.
+ * Copyright (C) 2017 Google, Inc.
+ *
+ * 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.
+ *
+ * Based on Intel IPU4 driver.
+ *
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "ipu3.h"
+#include "ipu3-dmamap.h"
+#include "ipu3-mmu.h"
+
+#define IMGU_NAME  "ipu3-imgu"
+#define IMGU_DMA_NAME  "ipu3-imgu-dma"
+#define IMGU_DMA_BUS_NAME  "ipu3-imgu-bus"
+#define IMGU_PCI_ID0x1919
+#define IMGU_PCI_BAR   0
+#define IMGU_DMA_MASK  DMA_BIT_MASK(32)
+#define IMGU_MAX_QUEUE_DEPTH   (2 + 2)
+
+static struct imgu_node_mapping const imgu_node_map[IMGU_NODE_NUM] = {
+   [IMGU_NODE_IN] = {IPU3_CSS_QUEUE_IN, "input"},
+   [IMGU_NODE_PARAMS] = {IPU3_CSS_QUEUE_PARAMS, "parameters"},
+   [IMGU_NODE_OUT] = {IPU3_CSS_QUEUE_OUT, "output"},
+   [IMGU_NODE_VF] = {IPU3_CSS_QUEUE_VF, "viewfinder"},
+   [IMGU_NODE_PV] = {IPU3_CSS_QUEUE_VF, "postview"},
+   [IMGU_NODE_STAT_3A] = {IPU3_CSS_QUEUE_STAT_3A, "3a stat"},
+   [IMGU_NODE_STAT_DVS] = {IPU3_CSS_QUEUE_STAT_DVS, "dvs stat"},
+   [IMGU_NODE_STAT_LACE] = {IPU3_CSS_QUEUE_STAT_LACE, "lace stat"},
+};
+
+int imgu_node_to_queue(int node)
+{
+   return imgu_node_map[node].css_queue;
+}
+
+int imgu_map_node(struct imgu_device *imgu, int css_queue)
+{
+   unsigned int i;
+
+   if (css_queue == IPU3_CSS_QUEUE_VF)
+   return imgu->mem2mem2.nodes[IMGU_NODE_VF].enabled ?
+   IMGU_NODE_VF : IMGU_NODE_PV;
+
+   for (i = 0; i < IMGU_NODE_NUM; i++)
+   if (imgu_node_map[i].css_queue == css_queue)
+   return i;
+
+   return -EINVAL;
+}
+/ Dummy buffers /
+
+void imgu_dummybufs_cleanup(struct imgu_device *imgu)
+{
+   unsigned int i;
+
+   for (i = 0; i < IPU3_CSS_QUEUES; i++) {
+   if (imgu->queues[i].dummybuf_vaddr)
+   dma_free_coherent(>dma_dev,
+   imgu->queues[i].dummybuf_size,
+   imgu->queues[i].dummybuf_vaddr,
+   

[PATCH v3 02/12] intel-ipu3: mmu: implement driver

2017-07-18 Thread Yong Zhi
From: Tomasz Figa 

This driver translates Intel IPU3 internal virtual
address to physical address.

Signed-off-by: Tomasz Figa 
Signed-off-by: Yong Zhi 
---
 drivers/media/pci/intel/ipu3/Kconfig|   9 +
 drivers/media/pci/intel/ipu3/Makefile   |  15 +
 drivers/media/pci/intel/ipu3/ipu3-mmu.c | 639 
 drivers/media/pci/intel/ipu3/ipu3-mmu.h |  27 ++
 4 files changed, 690 insertions(+)
 create mode 100644 drivers/media/pci/intel/ipu3/ipu3-mmu.c
 create mode 100644 drivers/media/pci/intel/ipu3/ipu3-mmu.h

diff --git a/drivers/media/pci/intel/ipu3/Kconfig 
b/drivers/media/pci/intel/ipu3/Kconfig
index 2a895d6..7bcdfa5 100644
--- a/drivers/media/pci/intel/ipu3/Kconfig
+++ b/drivers/media/pci/intel/ipu3/Kconfig
@@ -15,3 +15,12 @@ config VIDEO_IPU3_CIO2
Say Y or M here if you have a Skylake/Kaby Lake SoC with MIPI CSI-2
connected camera.
The module will be called ipu3-cio2.
+
+config INTEL_IPU3_MMU
+   tristate
+   default n
+   select IOMMU_API
+   select IOMMU_IOVA
+   ---help---
+ For IPU3, this option enables its MMU driver to translate its internal
+ virtual address to 39 bits wide physical address for 64GBytes space 
access.
diff --git a/drivers/media/pci/intel/ipu3/Makefile 
b/drivers/media/pci/intel/ipu3/Makefile
index 20186e3..91cac9c 100644
--- a/drivers/media/pci/intel/ipu3/Makefile
+++ b/drivers/media/pci/intel/ipu3/Makefile
@@ -1 +1,16 @@
+#
+#  Copyright (c) 2017, Intel Corporation.
+#
+#  This program is free software; you can redistribute it and/or modify it
+#  under the terms and conditions of the GNU General Public License,
+#  version 2, as published by the Free Software Foundation.
+#
+#  This program is distributed in the hope 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.
+#
+
 obj-$(CONFIG_VIDEO_IPU3_CIO2) += ipu3-cio2.o
+obj-$(CONFIG_INTEL_IPU3_MMU) += ipu3-mmu.o
+
diff --git a/drivers/media/pci/intel/ipu3/ipu3-mmu.c 
b/drivers/media/pci/intel/ipu3/ipu3-mmu.c
new file mode 100644
index 000..093b821
--- /dev/null
+++ b/drivers/media/pci/intel/ipu3/ipu3-mmu.c
@@ -0,0 +1,639 @@
+/*
+ * Copyright (c) 2017 Intel Corporation.
+ * Copyright (C) 2017 Google, Inc.
+ *
+ * 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 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#include "ipu3-mmu.h"
+
+#define IPU3_PAGE_SHIFT12
+#define IPU3_PAGE_SIZE (1UL << IPU3_PAGE_SHIFT)
+
+#define IPU3_PT_BITS   10
+#define IPU3_PT_PTES   (1UL << IPU3_PT_BITS)
+
+#define IPU3_ADDR2PTE(addr)((addr) >> IPU3_PAGE_SHIFT)
+#define IPU3_PTE2ADDR(pte) ((phys_addr_t)(pte) << IPU3_PAGE_SHIFT)
+
+#define IPU3_L2PT_SHIFTIPU3_PT_BITS
+#define IPU3_L2PT_MASK ((1UL << IPU3_L2PT_SHIFT) - 1)
+
+#define IPU3_L1PT_SHIFTIPU3_PT_BITS
+#define IPU3_L1PT_MASK ((1UL << IPU3_L1PT_SHIFT) - 1)
+
+#define IPU3_MMU_ADDRESS_BITS  (IPU3_PAGE_SHIFT + \
+IPU3_L2PT_SHIFT + \
+IPU3_L1PT_SHIFT)
+
+#define IMGU_REG_BASE  0x4000
+#define REG_TLB_INVALIDATE (IMGU_REG_BASE + 0x300)
+#define TLB_INVALIDATE 1
+#define REG_L1_PHYS(IMGU_REG_BASE + 0x304) /* 27-bit pfn */
+#define REG_GP_HALT(IMGU_REG_BASE + 0x5dc)
+#define REG_GP_HALTED  (IMGU_REG_BASE + 0x5e0)
+
+struct ipu3_mmu_domain {
+   struct iommu_domain domain;
+
+   struct ipu3_mmu *mmu;
+   spinlock_t lock;
+
+   void *dummy_page;
+   u32 dummy_page_pteval;
+
+   u32 *dummy_l2pt;
+   u32 dummy_l2pt_pteval;
+
+   u32 **l2pts;
+};
+
+struct ipu3_mmu {
+   struct device *dev;
+   struct bus_type *bus;
+   void __iomem *base;
+   struct iommu_group *group;
+   struct iommu_ops ops;
+   struct ipu3_mmu_domain *domain;
+
+   u32 *l1pt;
+};
+
+static inline struct ipu3_mmu *to_ipu3_mmu(struct device *dev)
+{
+   const struct iommu_ops *iommu_ops = dev->bus->iommu_ops;
+
+   return container_of(iommu_ops, struct ipu3_mmu, ops);
+}
+
+static inline struct ipu3_mmu_domain *
+to_ipu3_mmu_domain(struct iommu_domain *domain)
+{
+   return container_of(domain, struct ipu3_mmu_domain, domain);
+}
+
+/**
+ * ipu3_mmu_tlb_invalidate - invalidate translation look-aside buffer
+ * 

[PATCH v3 03/12] intel-ipu3: Add DMA API implementation

2017-07-18 Thread Yong Zhi
From: Tomasz Figa 

This patch adds support for the IPU3 DMA mapping API.

Signed-off-by: Tomasz Figa 
Signed-off-by: Yong Zhi 
---
 drivers/media/pci/intel/ipu3/Kconfig   |   8 +
 drivers/media/pci/intel/ipu3/Makefile  |   2 +-
 drivers/media/pci/intel/ipu3/ipu3-dmamap.c | 302 +
 drivers/media/pci/intel/ipu3/ipu3-dmamap.h |  22 +++
 4 files changed, 333 insertions(+), 1 deletion(-)
 create mode 100644 drivers/media/pci/intel/ipu3/ipu3-dmamap.c
 create mode 100644 drivers/media/pci/intel/ipu3/ipu3-dmamap.h

diff --git a/drivers/media/pci/intel/ipu3/Kconfig 
b/drivers/media/pci/intel/ipu3/Kconfig
index 7bcdfa5..d503806 100644
--- a/drivers/media/pci/intel/ipu3/Kconfig
+++ b/drivers/media/pci/intel/ipu3/Kconfig
@@ -24,3 +24,11 @@ config INTEL_IPU3_MMU
---help---
  For IPU3, this option enables its MMU driver to translate its internal
  virtual address to 39 bits wide physical address for 64GBytes space 
access.
+
+config INTEL_IPU3_DMAMAP
+   tristate
+   default n
+   select IOMMU_DMA
+   select IOMMU_IOVA
+   ---help---
+ This is IPU3 IOMMU domain specific DMA driver.
diff --git a/drivers/media/pci/intel/ipu3/Makefile 
b/drivers/media/pci/intel/ipu3/Makefile
index 91cac9c..6517732 100644
--- a/drivers/media/pci/intel/ipu3/Makefile
+++ b/drivers/media/pci/intel/ipu3/Makefile
@@ -13,4 +13,4 @@
 
 obj-$(CONFIG_VIDEO_IPU3_CIO2) += ipu3-cio2.o
 obj-$(CONFIG_INTEL_IPU3_MMU) += ipu3-mmu.o
-
+obj-$(CONFIG_INTEL_IPU3_DMAMAP) += ipu3-dmamap.o
diff --git a/drivers/media/pci/intel/ipu3/ipu3-dmamap.c 
b/drivers/media/pci/intel/ipu3/ipu3-dmamap.c
new file mode 100644
index 000..86a0e15
--- /dev/null
+++ b/drivers/media/pci/intel/ipu3/ipu3-dmamap.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (c) 2017 Intel Corporation.
+ * Copyright (C) 2017 Google, Inc.
+ *
+ * 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 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "ipu3-mmu.h"
+
+/*
+ * Based on arch/arm64/mm/dma-mapping.c, with simplifications possible due
+ * to driver-specific character of this file.
+ */
+
+static pgprot_t __get_dma_pgprot(unsigned long attrs, pgprot_t prot)
+{
+   if (DMA_ATTR_NON_CONSISTENT & attrs)
+   return prot;
+   return pgprot_writecombine(prot);
+}
+
+static void flush_page(struct device *dev, const void *virt, phys_addr_t phys)
+{
+   /*
+* FIXME: Yes, casting to override the const specifier is ugly.
+* However, for some reason, this callback is intended to flush cache
+* for a page pointed to by a const pointer, even though the cach
+* flush operation by definition does not keep the affected memory
+* constant...
+*/
+   clflush_cache_range((void *)virt, PAGE_SIZE);
+}
+
+static void *ipu3_dmamap_alloc(struct device *dev, size_t size,
+  dma_addr_t *handle, gfp_t gfp,
+  unsigned long attrs)
+{
+   int ioprot = dma_info_to_prot(DMA_BIDIRECTIONAL, false, attrs);
+   size_t iosize = size;
+   struct page **pages;
+   pgprot_t prot;
+   void *addr;
+
+   if (WARN(!dev, "cannot create IOMMU mapping for unknown device\n"))
+   return NULL;
+
+   if (WARN(!gfpflags_allow_blocking(gfp),
+"atomic allocations not supported\n") ||
+   WARN((DMA_ATTR_FORCE_CONTIGUOUS & attrs),
+"contiguous allocations not supported\n"))
+   return NULL;
+
+   size = PAGE_ALIGN(size);
+
+   dev_dbg(dev, "%s: allocating %zu\n", __func__, size);
+
+   /*
+* Some drivers rely on this, and we probably don't want the
+* possibility of stale kernel data being read by devices anyway.
+*/
+   gfp |= __GFP_ZERO;
+
+   /*
+* On x86, __GFP_DMA or __GFP_DMA32 might be added implicitly, based
+* on device DMA mask. However the mask does not apply to the IOMMU,
+* which is expected to be able to map any physical page.
+*/
+   gfp &= ~(__GFP_DMA | __GFP_DMA32);
+
+   pages = iommu_dma_alloc(dev, iosize, gfp, attrs, ioprot,
+   handle, flush_page);
+   if (!pages)
+   return NULL;
+
+   prot = __get_dma_pgprot(attrs, PAGE_KERNEL);
+   addr = dma_common_pages_remap(pages, size, VM_USERMAP, prot,
+ __builtin_return_address(0));
+   if (!addr)
+   

[PATCH v3 00/12] Intel IPU3 ImgU patchset

2017-07-18 Thread Yong Zhi
This patchset adds support for the Intel IPU3 (Image Processing Unit)
ImgU, which is essentially a modern memory-to-memory ISP. It implements
raw Bayer to YUV image format conversion as well as a large number of
other pixel processing algorithms for improving the image quality.

Meta data formats are defined for image statistics (3A, i.e. automatic
white balance, exposure and focus, histogram and local area contrast
enhancement) as well as for the pixel processing algorithm parameters.
The documentation for these formats is currently not included in the
patchset but will be added in a future version of this set.

The algorithm parameters need to be considered specific to a given frame
and typically a large number of these parameters change on frame to frame
basis. Additionally, the parameters are highly structured (and not a flat
space of independent configuration primitives). They also reflect the
data structures used by the firmware and the hardware. On top of that,
the algorithms require highly specialized user space to make meaningful
use of them. For these reasons it has been chosen video buffers to pass
the parameters to the device.

On individual patches:

The heart of ImgU is the CSS, or Camera Subsystem, which contains the
image processors and HW accelerators.

The 3A statistics and other firmware parameter computation related
functions are implemented in patch 8.

All h/w programming related code can be found in patch 9.

To access DDR via ImgU's own memory space, IPU3 is also equipped with
its own MMU unit, the driver is implemented in patch 2.

Patch 3 uses above driver for DMA mapping operation.

Tomasz Figa thoroughly reworked both mmu and dmamap driver submitted in v2;
as a result, current code has dependency on "[RFC PATCH 0/5] Fixes for loadable 
modules
implementing DMA/IOMMU APIs" series being discussed on the following thread:



Patch 5-10 are basically IPU3 CSS specific implementations:

6 and 7 provide some utility functions and manage IPU3 fw download and
install.

The firmware which is called ipu3-fw.bin can be downloaded from here:

git://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git

Patch 9 and 10 are of the same file, the latter implements interface
functions for access fw & hw capabilities defined in patch 8.

Patch 12 uses Kconfig and Makefile created by IPU3 cio2 patch series:



Here is the device topology:

localhost ~ # media-ctl -d /dev/media0 -p
Media controller API version 0.1.0

Media device information

driver  ipu3-imgu
model   ipu3-imgu
serial  
bus info:00:05.0
hw revision 0x0
driver version  4.12.0

Device topology
- entity 1: ipu3-imgu:0 (8 pads, 8 links)
type V4L2 subdev subtype Unknown flags 0
device node name /dev/v4l-subdev0
pad0:Sink
stream:0[fmt:UYVY2X8/352x288]
link: 
<- "input":0 [ENABLED,IMMUTABLE]
pad1:Sink
stream:0[fmt:UYVY2X8/352x288]
link: 
<- "parameters":0 []
pad2:Source
stream:0[fmt:UYVY2X8/352x288]
link: 
-> "output":0 []
pad3:Source
stream:0[fmt:UYVY2X8/352x288]
link: 
-> "viewfinder":0 []
pad4:Source
stream:0[fmt:UYVY2X8/352x288]
link: 
-> "postview":0 []
pad5:Source
stream:0[fmt:UYVY2X8/352x288]
link: 
-> "3a stat":0 []
pad6:Source
stream:0[fmt:UYVY2X8/352x288]
link: 
-> "dvs stat":0 []
pad7:Source
stream:0[fmt:UYVY2X8/352x288]
link: 
-> "lace stat":0 []

- entity 2: input (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video0
pad0:Source
link: 
-> "ipu3-imgu:0":0 [ENABLED,IMMUTABLE]

- entity 3: parameters (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video1
pad0:Source
link: 
-> "ipu3-imgu:0":1 []

- entity 4: output (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video2
pad0:Sink
link: 
<- "ipu3-imgu:0":2 []

- entity 5: viewfinder (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video3
pad0:Sink
link: 
<- "ipu3-imgu:0":3 []

- entity 6: postview (1 pad, 1 link)
type Node subtype V4L flags 0
device node name /dev/video4
pad0:Sink
link: 
<- "ipu3-imgu:0":4 []

- entity 7: 3a stat (1 pad, 1 

Re: [PATCH 1/2] iommu/arm-smmu: Track context bank state

2017-07-18 Thread Sricharan R
Hi Robin,

On 7/18/2017 6:14 PM, Robin Murphy wrote:
> Echoing what we do for Stream Map Entries, maintain a software shadow
> state for context bank configuration. With this in place, we are mere
> moments away from blissfully easy suspend/resume support.
> 
> Signed-off-by: Robin Murphy 
> ---
> 
> Since the runtime PM discussion has come back again, I figured it was
> probably about time to finish off my plan for system PM. Lightly tested
> on Juno (MMU-401) with hibernation.
> 
> Robin.
> 
>  drivers/iommu/arm-smmu.c | 159 
> +--
>  1 file changed, 97 insertions(+), 62 deletions(-)
> 
> diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
> index bc89b4d6c043..86897b7b81d8 100644
> --- a/drivers/iommu/arm-smmu.c
> +++ b/drivers/iommu/arm-smmu.c
> @@ -338,6 +338,13 @@ struct arm_smmu_smr {
>   boolvalid;
>  };
>  
> +struct arm_smmu_cb {
> + u64 ttbr[2];
> + u32 tcr[2];
> + u32 mair[2];
> + struct arm_smmu_cfg *cfg;
> +};
> +

 When i was trying this sometime back [1], was
 saving and using the pgtbl->cfg and domain->cfg for
 restoring the context. But this looks correct to make
 a actual shadow once and use it later all the time.
 Will also try some testing today.

 Reviewed-by: sricha...@codeaurora.org

[1] https://patchwork.kernel.org/patch/9389717/

Regards,
 Sricharan


>  struct arm_smmu_master_cfg {
>   struct arm_smmu_device  *smmu;
>   s16 smendx[];
> @@ -380,6 +387,7 @@ struct arm_smmu_device {
>   u32 num_context_banks;
>   u32 num_s2_context_banks;
>   DECLARE_BITMAP(context_map, ARM_SMMU_MAX_CBS);
> + struct arm_smmu_cb  *cbs;
>   atomic_tirptndx;
>  
>   u32 num_mapping_groups;
> @@ -768,17 +776,69 @@ static irqreturn_t arm_smmu_global_fault(int irq, void 
> *dev)
>  static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain,
>  struct io_pgtable_cfg *pgtbl_cfg)
>  {
> - u32 reg, reg2;
> - u64 reg64;
> - bool stage1;
>   struct arm_smmu_cfg *cfg = _domain->cfg;
> - struct arm_smmu_device *smmu = smmu_domain->smmu;
> + struct arm_smmu_cb *cb = _domain->smmu->cbs[cfg->cbndx];
> + bool stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS;
> +
> + cb->cfg = cfg;
> +
> + /* TTBCR */
> + if (stage1) {
> + if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) {
> + cb->tcr[0] = pgtbl_cfg->arm_v7s_cfg.tcr;
> + } else {
> + cb->tcr[0] = pgtbl_cfg->arm_lpae_s1_cfg.tcr;
> + cb->tcr[1] = pgtbl_cfg->arm_lpae_s1_cfg.tcr >> 32;
> + cb->tcr[1] |= TTBCR2_SEP_UPSTREAM;
> + if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH64)
> + cb->tcr[1] |= TTBCR2_AS;
> + }
> + } else {
> + cb->tcr[0] = pgtbl_cfg->arm_lpae_s2_cfg.vtcr;
> + }
> +
> + /* TTBRs */
> + if (stage1) {
> + if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) {
> + cb->ttbr[0] = pgtbl_cfg->arm_v7s_cfg.ttbr[0];
> + cb->ttbr[1] = pgtbl_cfg->arm_v7s_cfg.ttbr[1];
> + } else {
> + cb->ttbr[0] = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[0];
> + cb->ttbr[1] = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[1];
> + }
> + } else {
> + cb->ttbr[0] = pgtbl_cfg->arm_lpae_s2_cfg.vttbr;
> + }
> +
> + /* MAIRs (stage-1 only) */
> + if (stage1) {
> + if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) {
> + cb->mair[0] = pgtbl_cfg->arm_v7s_cfg.prrr;
> + cb->mair[1] = pgtbl_cfg->arm_v7s_cfg.nmrr;
> + } else {
> + cb->mair[0] = pgtbl_cfg->arm_lpae_s1_cfg.mair[0];
> + cb->mair[1] = pgtbl_cfg->arm_lpae_s1_cfg.mair[1];
> + }
> + }
> +}
> +
> +static void arm_smmu_write_context_bank(struct arm_smmu_device *smmu, int 
> idx)
> +{
> + u32 reg;
> + bool stage1;
> + struct arm_smmu_cb *cb = >cbs[idx];
> + struct arm_smmu_cfg *cfg = cb->cfg;
> + struct arm_smmu_cfg default_cfg = {0};
>   void __iomem *cb_base, *gr1_base;
>  
> + if (!cfg)
> + cfg = _cfg;
> +
>   gr1_base = ARM_SMMU_GR1(smmu);
>   stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS;
> - cb_base = ARM_SMMU_CB(smmu, cfg->cbndx);
> + cb_base = ARM_SMMU_CB(smmu, idx);
>  
> + /* CBA2R */
>   if (smmu->version > ARM_SMMU_V1) {
>   if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH64)
>   reg = CBA2R_RW64_64BIT;
> @@ -788,7 +848,7 @@ static void 

[PATCH] iommu: Convert to using %pOF instead of full_name

2017-07-18 Thread Rob Herring
Now that we have a custom printf format specifier, convert users of
full_name to use %pOF instead. This is preparation to remove storing
of the full path string for each node.

Signed-off-by: Rob Herring 
Cc: Joerg Roedel 
Cc: Heiko Stuebner 
Cc: iommu@lists.linux-foundation.org
Cc: linux-arm-ker...@lists.infradead.org
Cc: linux-rockc...@lists.infradead.org
---
 drivers/iommu/fsl_pamu.c| 20 
 drivers/iommu/fsl_pamu_domain.c | 10 --
 drivers/iommu/of_iommu.c|  3 +--
 drivers/iommu/rockchip-iommu.c  | 10 +-
 4 files changed, 18 insertions(+), 25 deletions(-)

diff --git a/drivers/iommu/fsl_pamu.c b/drivers/iommu/fsl_pamu.c
index a34355fca37a..919ad9045ac4 100644
--- a/drivers/iommu/fsl_pamu.c
+++ b/drivers/iommu/fsl_pamu.c
@@ -530,8 +530,8 @@ u32 get_stash_id(u32 stash_dest_hint, u32 vcpu)
if (node) {
prop = of_get_property(node, "cache-stash-id", NULL);
if (!prop) {
-   pr_debug("missing cache-stash-id at %s\n",
-node->full_name);
+   pr_debug("missing cache-stash-id at %pOF\n",
+node);
of_node_put(node);
return ~(u32)0;
}
@@ -557,8 +557,8 @@ u32 get_stash_id(u32 stash_dest_hint, u32 vcpu)
if (stash_dest_hint == cache_level) {
prop = of_get_property(node, "cache-stash-id", NULL);
if (!prop) {
-   pr_debug("missing cache-stash-id at %s\n",
-node->full_name);
+   pr_debug("missing cache-stash-id at %pOF\n",
+node);
of_node_put(node);
return ~(u32)0;
}
@@ -568,8 +568,7 @@ u32 get_stash_id(u32 stash_dest_hint, u32 vcpu)

prop = of_get_property(node, "next-level-cache", NULL);
if (!prop) {
-   pr_debug("can't find next-level-cache at %s\n",
-node->full_name);
+   pr_debug("can't find next-level-cache at %pOF\n", node);
of_node_put(node);
return ~(u32)0;  /* can't traverse any further */
}
@@ -1063,8 +1062,7 @@ static int fsl_pamu_probe(struct platform_device *pdev)

guts_node = of_find_matching_node(NULL, guts_device_ids);
if (!guts_node) {
-   dev_err(dev, "could not find GUTS node %s\n",
-   dev->of_node->full_name);
+   dev_err(dev, "could not find GUTS node %pOF\n", dev->of_node);
ret = -ENODEV;
goto error;
}
@@ -1246,8 +1244,7 @@ static __init int fsl_pamu_init(void)

pdev = platform_device_alloc("fsl-of-pamu", 0);
if (!pdev) {
-   pr_err("could not allocate device %s\n",
-  np->full_name);
+   pr_err("could not allocate device %pOF\n", np);
ret = -ENOMEM;
goto error_device_alloc;
}
@@ -1259,8 +1256,7 @@ static __init int fsl_pamu_init(void)

ret = platform_device_add(pdev);
if (ret) {
-   pr_err("could not add device %s (err=%i)\n",
-  np->full_name, ret);
+   pr_err("could not add device %pOF (err=%i)\n", np, ret);
goto error_device_add;
}

diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c
index da0e1e30ef37..01c73479345d 100644
--- a/drivers/iommu/fsl_pamu_domain.c
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -619,8 +619,8 @@ static int handle_attach_device(struct fsl_dma_domain 
*dma_domain,
for (i = 0; i < num; i++) {
/* Ensure that LIODN value is valid */
if (liodn[i] >= PAACE_NUMBER_ENTRIES) {
-   pr_debug("Invalid liodn %d, attach device failed for 
%s\n",
-liodn[i], dev->of_node->full_name);
+   pr_debug("Invalid liodn %d, attach device failed for 
%pOF\n",
+liodn[i], dev->of_node);
ret = -EINVAL;
break;
}
@@ -684,8 +684,7 @@ static int fsl_pamu_attach_device(struct iommu_domain 
*domain,
liodn_cnt = len / sizeof(u32);
ret = handle_attach_device(dma_domain, dev, liodn, liodn_cnt);
} else {
-   pr_debug("missing fsl,liodn property at %s\n",
-dev->of_node->full_name);
+   pr_debug("missing fsl,liodn property at %pOF\n", dev->of_node);
ret = -EINVAL;
}


[PATCH 2/4] iommu/iova: Optimise the padding calculation

2017-07-18 Thread Robin Murphy
From: Zhen Lei 

The mask for calculating the padding size doesn't change, so there's no
need to recalculate it every loop iteration. Furthermore, Once we've
done that, it becomes clear that we don't actually need to calculate a
padding size at all - by flipping the arithmetic around, we can just
combine the upper limit, size, and mask directly to check against the
lower limit.

For an arm64 build, this alone knocks 16% off the size of the entire
alloc_iova() function!

Signed-off-by: Zhen Lei 
[rm: simplified more of the arithmetic, rewrote commit message]
Signed-off-by: Robin Murphy 
---
 drivers/iommu/iova.c | 40 ++--
 1 file changed, 14 insertions(+), 26 deletions(-)

diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c
index 8f7552dc4e04..d094d1ca8f23 100644
--- a/drivers/iommu/iova.c
+++ b/drivers/iommu/iova.c
@@ -129,16 +129,6 @@ iova_insert_rbtree(struct rb_root *root, struct iova *iova,
rb_insert_color(>node, root);
 }
 
-/*
- * Computes the padding size required, to make the start address
- * naturally aligned on the power-of-two order of its size
- */
-static unsigned int
-iova_get_pad_size(unsigned int size, unsigned int limit_pfn)
-{
-   return (limit_pfn - size) & (__roundup_pow_of_two(size) - 1);
-}
-
 static int __alloc_and_insert_iova_range(struct iova_domain *iovad,
unsigned long size, unsigned long limit_pfn,
struct iova *new, bool size_aligned)
@@ -146,7 +136,10 @@ static int __alloc_and_insert_iova_range(struct 
iova_domain *iovad,
struct rb_node *prev, *curr = NULL;
unsigned long flags;
unsigned long saved_pfn;
-   unsigned int pad_size = 0;
+   unsigned long align_mask = ~0UL;
+
+   if (size_aligned)
+   align_mask <<= __fls(size);
 
/* Walk the tree backwards */
spin_lock_irqsave(>iova_rbtree_lock, flags);
@@ -156,31 +149,26 @@ static int __alloc_and_insert_iova_range(struct 
iova_domain *iovad,
while (curr) {
struct iova *curr_iova = rb_entry(curr, struct iova, node);
 
-   if (limit_pfn <= curr_iova->pfn_lo) {
+   if (limit_pfn <= curr_iova->pfn_lo)
goto move_left;
-   } else if (limit_pfn > curr_iova->pfn_hi) {
-   if (size_aligned)
-   pad_size = iova_get_pad_size(size, limit_pfn);
-   if ((curr_iova->pfn_hi + size + pad_size) < limit_pfn)
-   break;  /* found a free slot */
-   }
+
+   if (((limit_pfn - size) & align_mask) > curr_iova->pfn_hi)
+   break;  /* found a free slot */
+
limit_pfn = curr_iova->pfn_lo;
 move_left:
prev = curr;
curr = rb_prev(curr);
}
 
-   if (!curr) {
-   if (size_aligned)
-   pad_size = iova_get_pad_size(size, limit_pfn);
-   if ((iovad->start_pfn + size + pad_size) > limit_pfn) {
-   spin_unlock_irqrestore(>iova_rbtree_lock, flags);
-   return -ENOMEM;
-   }
+   if (limit_pfn < size ||
+   (!curr && ((limit_pfn - size) & align_mask) < iovad->start_pfn)) {
+   spin_unlock_irqrestore(>iova_rbtree_lock, flags);
+   return -ENOMEM;
}
 
/* pfn_lo will point to size aligned address if size_aligned is set */
-   new->pfn_lo = limit_pfn - (size + pad_size);
+   new->pfn_lo = (limit_pfn - size) & align_mask;
new->pfn_hi = new->pfn_lo + size - 1;
 
/* If we have 'prev', it's a valid place to start the insertion. */
-- 
2.12.2.dirty

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


[PATCH 3/4] iommu/iova: Extend rbtree node caching

2017-07-18 Thread Robin Murphy
The cached node mechanism provides a significant performance benefit for
allocations using a 32-bit DMA mask, but in the case of non-PCI devices
or where the 32-bit space is full, the loss of this benefit can be
significant - on large systems there can be many thousands of entries in
the tree, such that traversing to the end then walking all the way down
to find free space every time becomes increasingly awful.

Maintain a similar cached node for the whole IOVA space as a superset of
the 32-bit space so that performance can remain much more consistent.

Inspired by work by Zhen Lei .

Signed-off-by: Robin Murphy 
---
 drivers/iommu/iova.c | 59 +---
 include/linux/iova.h |  3 ++-
 2 files changed, 30 insertions(+), 32 deletions(-)

diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c
index d094d1ca8f23..f5809a2ee6c2 100644
--- a/drivers/iommu/iova.c
+++ b/drivers/iommu/iova.c
@@ -46,6 +46,7 @@ init_iova_domain(struct iova_domain *iovad, unsigned long 
granule,
 
spin_lock_init(>iova_rbtree_lock);
iovad->rbroot = RB_ROOT;
+   iovad->cached_node = NULL;
iovad->cached32_node = NULL;
iovad->granule = granule;
iovad->start_pfn = start_pfn;
@@ -57,48 +58,46 @@ EXPORT_SYMBOL_GPL(init_iova_domain);
 static struct rb_node *
 __get_cached_rbnode(struct iova_domain *iovad, unsigned long *limit_pfn)
 {
-   if ((*limit_pfn > iovad->dma_32bit_pfn) ||
-   (iovad->cached32_node == NULL))
+   struct rb_node *cached_node = NULL;
+   struct iova *curr_iova;
+
+   if (*limit_pfn <= iovad->dma_32bit_pfn)
+   cached_node = iovad->cached32_node;
+   if (!cached_node)
+   cached_node = iovad->cached_node;
+   if (!cached_node)
return rb_last(>rbroot);
-   else {
-   struct rb_node *prev_node = rb_prev(iovad->cached32_node);
-   struct iova *curr_iova =
-   rb_entry(iovad->cached32_node, struct iova, node);
-   *limit_pfn = curr_iova->pfn_lo;
-   return prev_node;
-   }
+
+   curr_iova = rb_entry(cached_node, struct iova, node);
+   *limit_pfn = curr_iova->pfn_lo;
+
+   return rb_prev(cached_node);
 }
 
 static void
-__cached_rbnode_insert_update(struct iova_domain *iovad,
-   unsigned long limit_pfn, struct iova *new)
+__cached_rbnode_insert_update(struct iova_domain *iovad, struct iova *new)
 {
-   if (limit_pfn != iovad->dma_32bit_pfn)
-   return;
-   iovad->cached32_node = >node;
+   if (new->pfn_lo > iovad->dma_32bit_pfn)
+   iovad->cached_node = >node;
+   else
+   iovad->cached32_node = >node;
 }
 
 static void
 __cached_rbnode_delete_update(struct iova_domain *iovad, struct iova *free)
 {
struct iova *cached_iova;
-   struct rb_node *curr;
+   struct rb_node **curr = NULL;
 
-   if (!iovad->cached32_node)
-   return;
-   curr = iovad->cached32_node;
-   cached_iova = rb_entry(curr, struct iova, node);
+   if (free->pfn_hi < iovad->dma_32bit_pfn)
+   curr = >cached32_node;
+   if (!curr)
+   curr = >cached_node;
 
-   if (free->pfn_lo >= cached_iova->pfn_lo) {
-   struct rb_node *node = rb_next(>node);
-   struct iova *iova = rb_entry(node, struct iova, node);
+   cached_iova = rb_entry(*curr, struct iova, node);
 
-   /* only cache if it's below 32bit pfn */
-   if (node && iova->pfn_lo < iovad->dma_32bit_pfn)
-   iovad->cached32_node = node;
-   else
-   iovad->cached32_node = NULL;
-   }
+   if (free->pfn_lo >= cached_iova->pfn_lo)
+   *curr = rb_next(>node);
 }
 
 /* Insert the iova into domain rbtree by holding writer lock */
@@ -135,7 +134,6 @@ static int __alloc_and_insert_iova_range(struct iova_domain 
*iovad,
 {
struct rb_node *prev, *curr = NULL;
unsigned long flags;
-   unsigned long saved_pfn;
unsigned long align_mask = ~0UL;
 
if (size_aligned)
@@ -143,7 +141,6 @@ static int __alloc_and_insert_iova_range(struct iova_domain 
*iovad,
 
/* Walk the tree backwards */
spin_lock_irqsave(>iova_rbtree_lock, flags);
-   saved_pfn = limit_pfn;
curr = __get_cached_rbnode(iovad, _pfn);
prev = curr;
while (curr) {
@@ -173,7 +170,7 @@ static int __alloc_and_insert_iova_range(struct iova_domain 
*iovad,
 
/* If we have 'prev', it's a valid place to start the insertion. */
iova_insert_rbtree(>rbroot, new, prev);
-   __cached_rbnode_insert_update(iovad, saved_pfn, new);
+   __cached_rbnode_insert_update(iovad, new);
 
spin_unlock_irqrestore(>iova_rbtree_lock, flags);
 
diff --git a/include/linux/iova.h b/include/linux/iova.h
index e0a892ae45c0..0bb8df43b393 

[PATCH 4/4] iommu/iova: Make dma_32bit_pfn implicit

2017-07-18 Thread Robin Murphy
From: Zhen Lei 

Now that the cached node optimisation can apply to all allocations, the
couple of users which were playing tricks with dma_32bit_pfn in order to
benefit from it can stop doing so. Conversely, there is also no need for
all the other users to explicitly calculate a 'real' 32-bit PFN, when
init_iova_domain() can happily do that itself from the page granularity.

CC: Thierry Reding 
CC: Jonathan Hunter 
CC: David Airlie 
CC: Sudeep Dutt 
CC: Ashutosh Dixit 
Signed-off-by: Zhen Lei 
[rm: use iova_pfn(), rewrote commit message]
Signed-off-by: Robin Murphy 
---
 drivers/gpu/drm/tegra/drm.c  |  3 +--
 drivers/gpu/host1x/dev.c |  3 +--
 drivers/iommu/amd_iommu.c|  7 ++-
 drivers/iommu/dma-iommu.c| 18 +-
 drivers/iommu/intel-iommu.c  | 11 +++
 drivers/iommu/iova.c |  4 ++--
 drivers/misc/mic/scif/scif_rma.c |  3 +--
 include/linux/iova.h |  5 ++---
 8 files changed, 13 insertions(+), 41 deletions(-)

diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 518f4b69ea53..81e9ae1ee90b 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -150,8 +150,7 @@ static int tegra_drm_load(struct drm_device *drm, unsigned 
long flags)
 
order = __ffs(tegra->domain->pgsize_bitmap);
init_iova_domain(>carveout.domain, 1UL << order,
-carveout_start >> order,
-carveout_end >> order);
+carveout_start >> order);
 
tegra->carveout.shift = iova_shift(>carveout.domain);
tegra->carveout.limit = carveout_end >> tegra->carveout.shift;
diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c
index 2c58a390123a..57c8eed0ed71 100644
--- a/drivers/gpu/host1x/dev.c
+++ b/drivers/gpu/host1x/dev.c
@@ -193,8 +193,7 @@ static int host1x_probe(struct platform_device *pdev)
 
order = __ffs(host->domain->pgsize_bitmap);
init_iova_domain(>iova, 1UL << order,
-geometry->aperture_start >> order,
-geometry->aperture_end >> order);
+geometry->aperture_start >> order);
host->iova_end = geometry->aperture_end;
}
 
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 688e77576e5a..a12e3e12014a 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -63,7 +63,6 @@
 /* IO virtual address start page frame number */
 #define IOVA_START_PFN (1)
 #define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT)
-#define DMA_32BIT_PFN  IOVA_PFN(DMA_BIT_MASK(32))
 
 /* Reserved IOVA ranges */
 #define MSI_RANGE_START(0xfee0)
@@ -2010,8 +2009,7 @@ static struct dma_ops_domain *dma_ops_domain_alloc(void)
if (!dma_dom->domain.pt_root)
goto free_dma_dom;
 
-   init_iova_domain(_dom->iovad, PAGE_SIZE,
-IOVA_START_PFN, DMA_32BIT_PFN);
+   init_iova_domain(_dom->iovad, PAGE_SIZE, IOVA_START_PFN);
 
/* Initialize reserved ranges */
copy_reserved_iova(_iova_ranges, _dom->iovad);
@@ -2912,8 +2910,7 @@ static int init_reserved_iova_ranges(void)
struct pci_dev *pdev = NULL;
struct iova *val;
 
-   init_iova_domain(_iova_ranges, PAGE_SIZE,
-IOVA_START_PFN, DMA_32BIT_PFN);
+   init_iova_domain(_iova_ranges, PAGE_SIZE, IOVA_START_PFN);
 
lockdep_set_class(_iova_ranges.iova_rbtree_lock,
  _rbtree_key);
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 9d1cebe7f6cb..191be9c80a8a 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -292,18 +292,7 @@ int iommu_dma_init_domain(struct iommu_domain *domain, 
dma_addr_t base,
/* ...then finally give it a kicking to make sure it fits */
base_pfn = max_t(unsigned long, base_pfn,
domain->geometry.aperture_start >> order);
-   end_pfn = min_t(unsigned long, end_pfn,
-   domain->geometry.aperture_end >> order);
}
-   /*
-* PCI devices may have larger DMA masks, but still prefer allocating
-* within a 32-bit mask to avoid DAC addressing. Such limitations don't
-* apply to the typical platform device, so for those we may as well
-* leave the cache limit at the top of their range to save an rb_last()
-* traversal on every allocation.
-*/
-   if (dev && dev_is_pci(dev))
-   end_pfn &= DMA_BIT_MASK(32) >> order;
 
/* start_pfn is always nonzero for an 

[PATCH 1/4] iommu/iova: Optimise rbtree searching

2017-07-18 Thread Robin Murphy
From: Zhen Lei 

Checking the IOVA bounds separately before deciding which direction to
continue the search (if necessary) results in redundantly comparing both
pfns twice each. GCC can already determine that the final comparison op
is redundant and optimise it down to 3 in total, but we can go one
further with a little tweak of the ordering (which makes the intent of
the code that much cleaner as a bonus).

Signed-off-by: Zhen Lei 
[rm: rewrote commit message to clarify]
Signed-off-by: Robin Murphy 
---
 drivers/iommu/iova.c | 9 +++--
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c
index 246f14c83944..8f7552dc4e04 100644
--- a/drivers/iommu/iova.c
+++ b/drivers/iommu/iova.c
@@ -289,15 +289,12 @@ private_find_iova(struct iova_domain *iovad, unsigned 
long pfn)
while (node) {
struct iova *iova = rb_entry(node, struct iova, node);
 
-   /* If pfn falls within iova's range, return iova */
-   if ((pfn >= iova->pfn_lo) && (pfn <= iova->pfn_hi)) {
-   return iova;
-   }
-
if (pfn < iova->pfn_lo)
node = node->rb_left;
-   else if (pfn > iova->pfn_lo)
+   else if (pfn > iova->pfn_hi)
node = node->rb_right;
+   else
+   return iova;/* pfn falls within iova's range */
}
 
return NULL;
-- 
2.12.2.dirty

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


[PATCH 0/4] Optimise 64-bit IOVA allocations

2017-07-18 Thread Robin Murphy
Hi all,

In the wake of the ARM SMMU optimisation efforts, it seems that certain
workloads (e.g. storage I/O with large scatterlists) probably remain quite
heavily influenced by IOVA allocation performance. Separately, Ard also
reported massive performance drops for a graphical desktop on AMD Seattle
when enabling SMMUs via IORT, which we traced to dma_32bit_pfn in the DMA
ops domain getting initialised differently for ACPI vs. DT, and exposing
the overhead of the rbtree slow path. Whilst we could go around trying to
close up all the little gaps that lead to hitting the slowest case, it
seems a much better idea to simply make said slowest case a lot less slow.

I had a go at rebasing Leizhen's last IOVA series[1], but ended up finding
the changes rather too hard to follow, so I've taken the liberty here of
picking the whole thing up and reimplementing the main part in a rather
less invasive manner.

Robin.

[1] https://www.mail-archive.com/iommu@lists.linux-foundation.org/msg17753.html

Robin Murphy (1):
  iommu/iova: Extend rbtree node caching

Zhen Lei (3):
  iommu/iova: Optimise rbtree searching
  iommu/iova: Optimise the padding calculation
  iommu/iova: Make dma_32bit_pfn implicit

 drivers/gpu/drm/tegra/drm.c  |   3 +-
 drivers/gpu/host1x/dev.c |   3 +-
 drivers/iommu/amd_iommu.c|   7 +--
 drivers/iommu/dma-iommu.c|  18 +--
 drivers/iommu/intel-iommu.c  |  11 ++--
 drivers/iommu/iova.c | 112 ---
 drivers/misc/mic/scif/scif_rma.c |   3 +-
 include/linux/iova.h |   8 +--
 8 files changed, 60 insertions(+), 105 deletions(-)

-- 
2.12.2.dirty

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


Re: [Qemu-devel] [RFC PATCH 7/8] VFIO: Add new IOCTL for IOMMU TLB invalidate propagation

2017-07-18 Thread Jean-Philippe Brucker
On 18/07/17 15:29, Alex Williamson wrote:
> On Tue, 18 Jul 2017 10:38:40 +0100
> Jean-Philippe Brucker  wrote:
> 
>> On 17/07/17 23:45, Alex Williamson wrote:
>> [..]
>
> How does a user learn which model(s) are supported by the interface?
> How do they learn which ops are supported?  Perhaps a good use for one of 
> those
> flag bits in the outer data structure is "probe".

 My initial plan to user fills it, if the underlying HW doesn't support the
 model, it refuses to service it. User should get a failure and stop to use
 it. But your suggestion to have a probe or kinds of query makes sense.
 How about we add one more operation for such purpose? Besides the
 supported model query, I'd like to add more. E.g the HW IOMMU 
 capabilities.  
>>>
>>> We also have VFIO_IOMMU_GET_INFO where the structure can be extended
>>> for missing capabilities.  Depending on the capability you want to
>>> describe, this might be a better, existing interface for it.  
>>
>> It might become hairy when physical IOMMUs start supporting multiple
>> formats, or when we want to describe multiple page table formats in
>> addition to PASID tables. I was wondering if sysfs iommu_group would be
>> better suited for this kind of hardware description with variable-length
>> properties, but a new ioctl-based probing mechanism would work as well.
> 
> Would different groups have different properties?  Perhaps it's related
> to the iommu hardware unit supporting the device, which could host one
> or more groups.  Each device already has a link to its iommu where we
> could add info (/sys/class/iommu/).

Yes, /sys/class/iommu might be better than iommu_group for PASID and page
table formats.

>> Other things that we'll want to describe are fault reporting capability
>> and PASID range, which would fit better in vfio_device_info.
> 
> Why?  The per device PASID info is in a PCI capability, so wouldn't
> this be iommu info?  Isn't the fault reporting also via the iommu?

Ah yes, I missed that. If userspace can read the PASID and PRI
capabilities it should be enough.

Inspecting individual device capability might help userspace decide how to
combine multiple devices in a container. For example, if it puts
PASID-capable and non-PASID-capable device in the same container, the
container probably wouldn't support PASID (but would still support MAP/UNMAP).

I'm not sure how it will work for platform devices though, some integrated
devices on ARM will support features resembling PASID and PRI. I suspect
these will need ACPI/DT description anyway, that userspace would access
via sysfs.

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


Re: [Qemu-devel] [RFC PATCH 7/8] VFIO: Add new IOCTL for IOMMU TLB invalidate propagation

2017-07-18 Thread Alex Williamson
On Tue, 18 Jul 2017 10:38:40 +0100
Jean-Philippe Brucker  wrote:

> On 17/07/17 23:45, Alex Williamson wrote:
> [..]
> >>>
> >>> How does a user learn which model(s) are supported by the interface?
> >>> How do they learn which ops are supported?  Perhaps a good use for one of 
> >>> those
> >>> flag bits in the outer data structure is "probe".
> >>
> >> My initial plan to user fills it, if the underlying HW doesn't support the
> >> model, it refuses to service it. User should get a failure and stop to use
> >> it. But your suggestion to have a probe or kinds of query makes sense.
> >> How about we add one more operation for such purpose? Besides the
> >> supported model query, I'd like to add more. E.g the HW IOMMU 
> >> capabilities.  
> > 
> > We also have VFIO_IOMMU_GET_INFO where the structure can be extended
> > for missing capabilities.  Depending on the capability you want to
> > describe, this might be a better, existing interface for it.  
> 
> It might become hairy when physical IOMMUs start supporting multiple
> formats, or when we want to describe multiple page table formats in
> addition to PASID tables. I was wondering if sysfs iommu_group would be
> better suited for this kind of hardware description with variable-length
> properties, but a new ioctl-based probing mechanism would work as well.

Would different groups have different properties?  Perhaps it's related
to the iommu hardware unit supporting the device, which could host one
or more groups.  Each device already has a link to its iommu where we
could add info (/sys/class/iommu/).
 
> Other things that we'll want to describe are fault reporting capability
> and PASID range, which would fit better in vfio_device_info.

Why?  The per device PASID info is in a PCI capability, so wouldn't
this be iommu info?  Isn't the fault reporting also via the iommu?
Thanks,

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


Re: [PATCH v10 00/38] x86: Secure Memory Encryption (AMD)

2017-07-18 Thread Tom Lendacky

On 7/18/2017 7:03 AM, Thomas Gleixner wrote:

On Mon, 17 Jul 2017, Tom Lendacky wrote:

This patch series provides support for AMD's new Secure Memory Encryption (SME)
feature.

SME can be used to mark individual pages of memory as encrypted through the
page tables. A page of memory that is marked encrypted will be automatically
decrypted when read from DRAM and will be automatically encrypted when
written to DRAM. Details on SME can found in the links below.

The SME feature is identified through a CPUID function and enabled through
the SYSCFG MSR. Once enabled, page table entries will determine how the
memory is accessed. If a page table entry has the memory encryption mask set,
then that memory will be accessed as encrypted memory. The memory encryption
mask (as well as other related information) is determined from settings
returned through the same CPUID function that identifies the presence of the
feature.

The approach that this patch series takes is to encrypt everything possible
starting early in the boot where the kernel is encrypted. Using the page
table macros the encryption mask can be incorporated into all page table
entries and page allocations. By updating the protection map, userspace
allocations are also marked encrypted. Certain data must be accounted for
as having been placed in memory before SME was enabled (EFI, initrd, etc.)
and accessed accordingly.

This patch series is a pre-cursor to another AMD processor feature called
Secure Encrypted Virtualization (SEV). The support for SEV will build upon
the SME support and will be submitted later. Details on SEV can be found
in the links below.


Well done series. Thanks to all people involved, especially Tom and Boris!
It was a pleasure to review that.

Reviewed-by: Thomas Gleixner 


A big thanks from me to everyone that helped review this.  I truly
appreciate all the time that everyone put into this - especially Boris,
who helped guide this series from the start.

Thanks,
Tom




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


[PATCH 1/2] iommu/arm-smmu: Track context bank state

2017-07-18 Thread Robin Murphy
Echoing what we do for Stream Map Entries, maintain a software shadow
state for context bank configuration. With this in place, we are mere
moments away from blissfully easy suspend/resume support.

Signed-off-by: Robin Murphy 
---

Since the runtime PM discussion has come back again, I figured it was
probably about time to finish off my plan for system PM. Lightly tested
on Juno (MMU-401) with hibernation.

Robin.

 drivers/iommu/arm-smmu.c | 159 +--
 1 file changed, 97 insertions(+), 62 deletions(-)

diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index bc89b4d6c043..86897b7b81d8 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -338,6 +338,13 @@ struct arm_smmu_smr {
boolvalid;
 };
 
+struct arm_smmu_cb {
+   u64 ttbr[2];
+   u32 tcr[2];
+   u32 mair[2];
+   struct arm_smmu_cfg *cfg;
+};
+
 struct arm_smmu_master_cfg {
struct arm_smmu_device  *smmu;
s16 smendx[];
@@ -380,6 +387,7 @@ struct arm_smmu_device {
u32 num_context_banks;
u32 num_s2_context_banks;
DECLARE_BITMAP(context_map, ARM_SMMU_MAX_CBS);
+   struct arm_smmu_cb  *cbs;
atomic_tirptndx;
 
u32 num_mapping_groups;
@@ -768,17 +776,69 @@ static irqreturn_t arm_smmu_global_fault(int irq, void 
*dev)
 static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain,
   struct io_pgtable_cfg *pgtbl_cfg)
 {
-   u32 reg, reg2;
-   u64 reg64;
-   bool stage1;
struct arm_smmu_cfg *cfg = _domain->cfg;
-   struct arm_smmu_device *smmu = smmu_domain->smmu;
+   struct arm_smmu_cb *cb = _domain->smmu->cbs[cfg->cbndx];
+   bool stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS;
+
+   cb->cfg = cfg;
+
+   /* TTBCR */
+   if (stage1) {
+   if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) {
+   cb->tcr[0] = pgtbl_cfg->arm_v7s_cfg.tcr;
+   } else {
+   cb->tcr[0] = pgtbl_cfg->arm_lpae_s1_cfg.tcr;
+   cb->tcr[1] = pgtbl_cfg->arm_lpae_s1_cfg.tcr >> 32;
+   cb->tcr[1] |= TTBCR2_SEP_UPSTREAM;
+   if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH64)
+   cb->tcr[1] |= TTBCR2_AS;
+   }
+   } else {
+   cb->tcr[0] = pgtbl_cfg->arm_lpae_s2_cfg.vtcr;
+   }
+
+   /* TTBRs */
+   if (stage1) {
+   if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) {
+   cb->ttbr[0] = pgtbl_cfg->arm_v7s_cfg.ttbr[0];
+   cb->ttbr[1] = pgtbl_cfg->arm_v7s_cfg.ttbr[1];
+   } else {
+   cb->ttbr[0] = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[0];
+   cb->ttbr[1] = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[1];
+   }
+   } else {
+   cb->ttbr[0] = pgtbl_cfg->arm_lpae_s2_cfg.vttbr;
+   }
+
+   /* MAIRs (stage-1 only) */
+   if (stage1) {
+   if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH32_S) {
+   cb->mair[0] = pgtbl_cfg->arm_v7s_cfg.prrr;
+   cb->mair[1] = pgtbl_cfg->arm_v7s_cfg.nmrr;
+   } else {
+   cb->mair[0] = pgtbl_cfg->arm_lpae_s1_cfg.mair[0];
+   cb->mair[1] = pgtbl_cfg->arm_lpae_s1_cfg.mair[1];
+   }
+   }
+}
+
+static void arm_smmu_write_context_bank(struct arm_smmu_device *smmu, int idx)
+{
+   u32 reg;
+   bool stage1;
+   struct arm_smmu_cb *cb = >cbs[idx];
+   struct arm_smmu_cfg *cfg = cb->cfg;
+   struct arm_smmu_cfg default_cfg = {0};
void __iomem *cb_base, *gr1_base;
 
+   if (!cfg)
+   cfg = _cfg;
+
gr1_base = ARM_SMMU_GR1(smmu);
stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS;
-   cb_base = ARM_SMMU_CB(smmu, cfg->cbndx);
+   cb_base = ARM_SMMU_CB(smmu, idx);
 
+   /* CBA2R */
if (smmu->version > ARM_SMMU_V1) {
if (cfg->fmt == ARM_SMMU_CTX_FMT_AARCH64)
reg = CBA2R_RW64_64BIT;
@@ -788,7 +848,7 @@ static void arm_smmu_init_context_bank(struct 
arm_smmu_domain *smmu_domain,
if (smmu->features & ARM_SMMU_FEAT_VMID16)
reg |= cfg->vmid << CBA2R_VMID_SHIFT;
 
-   writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBA2R(cfg->cbndx));
+   writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBA2R(idx));
}
 
/* CBAR */
@@ -807,72 +867,43 @@ static void arm_smmu_init_context_bank(struct 
arm_smmu_domain *smmu_domain,
/* 8-bit VMIDs live in CBAR */

[PATCH 2/2] iommu/arm-smmu: Add system PM support

2017-07-18 Thread Robin Murphy
With all our hardware state tracked in such a way that we can naturally
restore it as part of the necessary reset, resuming is trivial, and
there's nothing to do on suspend at all.

Signed-off-by: Robin Murphy 
---
 drivers/iommu/arm-smmu.c | 12 
 1 file changed, 12 insertions(+)

diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 86897b7b81d8..0f5f06e9abfa 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -2356,10 +2356,22 @@ static int arm_smmu_device_remove(struct 
platform_device *pdev)
return 0;
 }
 
+static int __maybe_unused arm_smmu_pm_resume(struct device *dev)
+{
+   struct arm_smmu_device *smmu = dev_get_drvdata(dev);
+
+   arm_smmu_device_reset(smmu);
+   return 0;
+}
+
+
+static SIMPLE_DEV_PM_OPS(arm_smmu_pm_ops, NULL, arm_smmu_pm_resume);
+
 static struct platform_driver arm_smmu_driver = {
.driver = {
.name   = "arm-smmu",
.of_match_table = of_match_ptr(arm_smmu_of_match),
+   .pm = _smmu_pm_ops,
},
.probe  = arm_smmu_device_probe,
.remove = arm_smmu_device_remove,
-- 
2.12.2.dirty

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


Re: [PATCH v10 00/38] x86: Secure Memory Encryption (AMD)

2017-07-18 Thread Thomas Gleixner
On Mon, 17 Jul 2017, Tom Lendacky wrote:
> This patch series provides support for AMD's new Secure Memory Encryption 
> (SME)
> feature.
> 
> SME can be used to mark individual pages of memory as encrypted through the
> page tables. A page of memory that is marked encrypted will be automatically
> decrypted when read from DRAM and will be automatically encrypted when
> written to DRAM. Details on SME can found in the links below.
> 
> The SME feature is identified through a CPUID function and enabled through
> the SYSCFG MSR. Once enabled, page table entries will determine how the
> memory is accessed. If a page table entry has the memory encryption mask set,
> then that memory will be accessed as encrypted memory. The memory encryption
> mask (as well as other related information) is determined from settings
> returned through the same CPUID function that identifies the presence of the
> feature.
> 
> The approach that this patch series takes is to encrypt everything possible
> starting early in the boot where the kernel is encrypted. Using the page
> table macros the encryption mask can be incorporated into all page table
> entries and page allocations. By updating the protection map, userspace
> allocations are also marked encrypted. Certain data must be accounted for
> as having been placed in memory before SME was enabled (EFI, initrd, etc.)
> and accessed accordingly.
> 
> This patch series is a pre-cursor to another AMD processor feature called
> Secure Encrypted Virtualization (SEV). The support for SEV will build upon
> the SME support and will be submitted later. Details on SEV can be found
> in the links below.

Well done series. Thanks to all people involved, especially Tom and Boris!
It was a pleasure to review that.

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


[tip:x86/mm] iommu/amd: Allow the AMD IOMMU to work with memory encryption

2017-07-18 Thread tip-bot for Tom Lendacky
Commit-ID:  2543a786aa25258451f3418b87a038c7ddaa2e85
Gitweb: http://git.kernel.org/tip/2543a786aa25258451f3418b87a038c7ddaa2e85
Author: Tom Lendacky 
AuthorDate: Mon, 17 Jul 2017 16:10:24 -0500
Committer:  Ingo Molnar 
CommitDate: Tue, 18 Jul 2017 11:38:03 +0200

iommu/amd: Allow the AMD IOMMU to work with memory encryption

The IOMMU is programmed with physical addresses for the various tables
and buffers that are used to communicate between the device and the
driver. When the driver allocates this memory it is encrypted. In order
for the IOMMU to access the memory as encrypted the encryption mask needs
to be included in these physical addresses during configuration.

The PTE entries created by the IOMMU should also include the encryption
mask so that when the device behind the IOMMU performs a DMA, the DMA
will be performed to encrypted memory.

Signed-off-by: Tom Lendacky 
Reviewed-by: Thomas Gleixner 
Reviewed-by: Borislav Petkov 
Acked-by: Joerg Roedel 
Cc: 
Cc: Alexander Potapenko 
Cc: Andrey Ryabinin 
Cc: Andy Lutomirski 
Cc: Arnd Bergmann 
Cc: Borislav Petkov 
Cc: Brijesh Singh 
Cc: Dave Young 
Cc: Dmitry Vyukov 
Cc: Jonathan Corbet 
Cc: Konrad Rzeszutek Wilk 
Cc: Larry Woodman 
Cc: Linus Torvalds 
Cc: Matt Fleming 
Cc: Michael S. Tsirkin 
Cc: Paolo Bonzini 
Cc: Peter Zijlstra 
Cc: Radim Krčmář 
Cc: Rik van Riel 
Cc: Toshimitsu Kani 
Cc: kasan-...@googlegroups.com
Cc: k...@vger.kernel.org
Cc: linux-a...@vger.kernel.org
Cc: linux-...@vger.kernel.org
Cc: linux-...@vger.kernel.org
Cc: linux...@kvack.org
Link: 
http://lkml.kernel.org/r/3053631ea25ba8b1601c351cb7c541c496f6d9bc.1500319216.git.thomas.lenda...@amd.com
Signed-off-by: Ingo Molnar 
---
 drivers/iommu/amd_iommu.c   | 30 --
 drivers/iommu/amd_iommu_init.c  | 34 --
 drivers/iommu/amd_iommu_proto.h | 10 ++
 drivers/iommu/amd_iommu_types.h |  2 +-
 4 files changed, 55 insertions(+), 21 deletions(-)

diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 688e775..abc6ca6 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -575,7 +575,7 @@ static void dump_dte_entry(u16 devid)
 
 static void dump_command(unsigned long phys_addr)
 {
-   struct iommu_cmd *cmd = phys_to_virt(phys_addr);
+   struct iommu_cmd *cmd = iommu_phys_to_virt(phys_addr);
int i;
 
for (i = 0; i < 4; ++i)
@@ -919,11 +919,13 @@ static void copy_cmd_to_buffer(struct amd_iommu *iommu,
 
 static void build_completion_wait(struct iommu_cmd *cmd, u64 address)
 {
+   u64 paddr = iommu_virt_to_phys((void *)address);
+
WARN_ON(address & 0x7ULL);
 
memset(cmd, 0, sizeof(*cmd));
-   cmd->data[0] = lower_32_bits(__pa(address)) | CMD_COMPL_WAIT_STORE_MASK;
-   cmd->data[1] = upper_32_bits(__pa(address));
+   cmd->data[0] = lower_32_bits(paddr) | CMD_COMPL_WAIT_STORE_MASK;
+   cmd->data[1] = upper_32_bits(paddr);
cmd->data[2] = 1;
CMD_SET_TYPE(cmd, CMD_COMPL_WAIT);
 }
@@ -1383,7 +1385,7 @@ static bool increase_address_space(struct 
protection_domain *domain,
return false;
 
*pte = PM_LEVEL_PDE(domain->mode,
-   virt_to_phys(domain->pt_root));
+   iommu_virt_to_phys(domain->pt_root));
domain->pt_root  = pte;
domain->mode+= 1;
domain->updated  = true;
@@ -1420,7 +1422,7 @@ static u64 *alloc_pte(struct protection_domain *domain,
if (!page)
return NULL;
 
-   __npte = PM_LEVEL_PDE(level, virt_to_phys(page));
+   __npte = PM_LEVEL_PDE(level, iommu_virt_to_phys(page));
 
/* pte could have been changed somewhere. */
if (cmpxchg64(pte, __pte, __npte) != __pte) {
@@ -1536,10 +1538,10 @@ static int iommu_map_page(struct protection_domain *dom,
return -EBUSY;
 
if (count > 1) {
-   __pte = PAGE_SIZE_PTE(phys_addr, page_size);
+   __pte = PAGE_SIZE_PTE(__sme_set(phys_addr), page_size);
__pte |= PM_LEVEL_ENC(7) | IOMMU_PTE_P | IOMMU_PTE_FC;
} else
-   __pte = phys_addr | IOMMU_PTE_P | IOMMU_PTE_FC;
+   __pte = __sme_set(phys_addr) | IOMMU_PTE_P | IOMMU_PTE_FC;
 
if (prot & 

[PATCH 4/4] ARM64: dts: rockchip: rk3399 add iommu nodes

2017-07-18 Thread Simon Xue
From: Simon 

Add VPU/VDEC/IEP/VOPL/VOPB/ISP0/ISP1 iommu nodes

Signed-off-by: Simon 
---
 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 63 
 1 file changed, 63 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi 
b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 69c56f7..95cabe1 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -1151,6 +1151,33 @@
status = "disabled";
};
 
+   vpu_mmu: iommu@ff650800 {
+   compatible = "rockchip,iommu";
+   reg = <0x0 0xff650800 0x0 0x40>;
+   interrupts = ;
+   interrupt-names = "vpu_mmu";
+   #iommu-cells = <0>;
+   status = "disabled";
+   };
+
+   vdec_mmu: iommu@ff660480 {
+   compatible = "rockchip,iommu";
+   reg = <0x0 0xff660480 0x0 0x40>, <0x0 0xff6604c0 0x0 0x40>;
+   interrupts = ;
+   interrupt-names = "vdec_mmu";
+   #iommu-cells = <0>;
+   status = "disabled";
+   };
+
+   iep_mmu: iommu@ff670800 {
+   compatible = "rockchip,iommu";
+   reg = <0x0 0xff670800 0x0 0x40>;
+   interrupts = ;
+   interrupt-names = "iep_mmu";
+   #iommu-cells = <0>;
+   status = "disabled";
+   };
+
efuse0: efuse@ff69 {
compatible = "rockchip,rk3399-efuse";
reg = <0x0 0xff69 0x0 0x80>;
@@ -1360,6 +1387,15 @@
};
};
 
+   vopl_mmu: iommu@ff8f3f00 {
+   compatible = "rockchip,iommu";
+   reg = <0x0 0xff8f3f00 0x0 0x100>;
+   interrupts = ;
+   interrupt-names = "vopl_mmu";
+   #iommu-cells = <0>;
+   status = "disabled";
+   };
+
watchdog@ff848000 {
compatible = "snps,dw-wdt";
reg = <0x0 0xff848000 0x0 0x100>;
@@ -1426,6 +1462,33 @@
status = "disabled";
};
 
+   vopb_mmu: iommu@ff903f00 {
+   compatible = "rockchip,iommu";
+   reg = <0x0 0xff903f00 0x0 0x100>;
+   interrupts = ;
+   interrupt-names = "vopb_mmu";
+   #iommu-cells = <0>;
+   status = "disabled";
+   };
+
+   isp0_mmu: iommu@ff914000 {
+   compatible = "rockchip,iommu";
+   reg = <0x0 0xff914000 0x0 0x100>, <0x0 0xff915000 0x0 0x100>;
+   interrupts = ;
+   interrupt-names = "isp0_mmu";
+   #iommu-cells = <0>;
+   status = "disabled";
+   };
+
+   isp1_mmu: iommu@ff924000 {
+   compatible = "rockchip,iommu";
+   reg = <0x0 0xff924000 0x0 0x100>, <0x0 0xff925000 0x0 0x100>;
+   interrupts = ;
+   interrupt-names = "isp1_mmu";
+   #iommu-cells = <0>;
+   status = "disabled";
+   };
+
pinctrl: pinctrl {
compatible = "rockchip,rk3399-pinctrl";
rockchip,grf = <>;
-- 
1.9.1


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


[PATCH 3/4] ARM64: dts: rockchip: rk3368 add iommu nodes

2017-07-18 Thread Simon Xue
From: Simon 

Add IEP/ISP/VOP/HEVC/VPU iommu nodes

Signed-off-by: Simon 
---
 arch/arm64/boot/dts/rockchip/rk3368.dtsi | 48 
 1 file changed, 48 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi 
b/arch/arm64/boot/dts/rockchip/rk3368.dtsi
index 6d5dc05..ed9a56c 100644
--- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi
@@ -724,6 +724,54 @@
status = "disabled";
};
 
+   iep_mmu: iommu@ff900800 {
+   compatible = "rockchip,iommu";
+   reg = <0x0 0xff900800 0x0 0x100>;
+   interrupts = ;
+   interrupt-names = "iep_mmu";
+   #iommu-cells = <0>;
+   status = "disabled";
+   };
+
+   isp_mmu: iommu@ff914000 {
+   compatible = "rockchip,iommu";
+   reg = <0x0 0xff914000 0x0 0x100>,
+ <0x0 0xff915000 0x0 0x100>;
+   interrupts = ;
+   interrupt-names = "isp_mmu";
+   #iommu-cells = <0>;
+   status = "disabled";
+   };
+
+   vop_mmu: iommu@ff930300 {
+   compatible = "rockchip,iommu";
+   reg = <0x0 0xff930300 0x0 0x100>;
+   interrupts = ;
+   interrupt-names = "vop_mmu";
+   #iommu-cells = <0>;
+   status = "disabled";
+   };
+
+   hevc_mmu: iommu@ff9a0440 {
+   compatible = "rockchip,iommu";
+   reg = <0x0 0xff9a0440 0x0 0x40>,
+ <0x0 0xff9a0480 0x0 0x40>;
+   interrupts = ;
+   interrupt-names = "hevc_mmu";
+   #iommu-cells = <0>;
+   status = "disabled";
+   };
+
+   vpu_mmu: iommu@ff9a0800 {
+   compatible = "rockchip,iommu";
+   reg = <0x0 0xff9a0800 0x0 0x100>;
+   interrupts = ,
+;
+   interrupt-names = "vepu_mmu", "vdpu_mmu";
+   #iommu-cells = <0>;
+   status = "disabled";
+   };
+
gic: interrupt-controller@ffb71000 {
compatible = "arm,gic-400";
interrupt-controller;
-- 
1.9.1


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


[PATCH 1/4] ARM64: dts: rockchip: rk3328 add iommu nodes

2017-07-18 Thread Simon Xue
From: Simon 

Add H265e/VEPU/VPU/VDEC/VOP iommu nodes

Signed-off-by: Simon 
---
 arch/arm64/boot/dts/rockchip/rk3328.dtsi | 45 
 1 file changed, 45 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3328.dtsi 
b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
index 0be96ce..bdd7711 100644
--- a/arch/arm64/boot/dts/rockchip/rk3328.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3328.dtsi
@@ -320,6 +320,51 @@
status = "disabled";
};
 
+   h265e_mmu: iommu@ff330200 {
+   compatible = "rockchip,iommu";
+   reg = <0x0 0xff330200 0 0x100>;
+   interrupts = ;
+   interrupt-names = "h265e_mmu";
+   #iommu-cells = <0>;
+   status = "disabled";
+   };
+
+   vepu_mmu: iommu@ff340800 {
+   compatible = "rockchip,iommu";
+   reg = <0x0 0xff340800 0x0 0x40>;
+   interrupts = ;
+   interrupt-names = "vepu_mmu";
+   #iommu-cells = <0>;
+   status = "disabled";
+   };
+
+   vpu_mmu: iommu@ff350800 {
+   compatible = "rockchip,iommu";
+   reg = <0x0 0xff350800 0x0 0x40>;
+   interrupts = ;
+   interrupt-names = "vpu_mmu";
+   #iommu-cells = <0>;
+   status = "disabled";
+   };
+
+   rkvdec_mmu: iommu@ff360480 {
+   compatible = "rockchip,iommu";
+   reg = <0x0 0xff360480 0x0 0x40>, <0x0 0xff3604c0 0x0 0x40>;
+   interrupts = ;
+   interrupt-names = "rkvdec_mmu";
+   #iommu-cells = <0>;
+   status = "disabled";
+   };
+
+   vop_mmu: iommu@ff373f00 {
+   compatible = "rockchip,iommu";
+   reg = <0x0 0xff373f00 0x0 0x100>;
+   interrupts = ;
+   interrupt-names = "vop_mmu";
+   #iommu-cells = <0>;
+   status = "disabled";
+   };
+
cru: clock-controller@ff44 {
compatible = "rockchip,rk3328-cru", "rockchip,cru", "syscon";
reg = <0x0 0xff44 0x0 0x1000>;
-- 
1.9.1


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


[PATCH 2/4] ARM: dts: rockchip: rk322x add iommu nodes

2017-07-18 Thread Simon Xue
From: Simon 

Add VPU/VDEC/VOP/IEP iommu nodes

Signed-off-by: Simon 
---
 arch/arm/boot/dts/rk322x.dtsi | 36 
 1 file changed, 36 insertions(+)

diff --git a/arch/arm/boot/dts/rk322x.dtsi b/arch/arm/boot/dts/rk322x.dtsi
index f3e4ffd..36f7c4b 100644
--- a/arch/arm/boot/dts/rk322x.dtsi
+++ b/arch/arm/boot/dts/rk322x.dtsi
@@ -500,6 +500,42 @@
status = "disabled";
};
 
+   vpu_mmu: iommu@20020800 {
+   compatible = "rockchip,iommu";
+   reg = <0x20020800 0x100>;
+   interrupts = ;
+   interrupt-names = "vpu_mmu";
+   iommu-cells = <0>;
+   status = "disabled";
+   };
+
+   vdec_mmu: iommu@20030480 {
+   compatible = "rockchip,iommu";
+   reg = <0x20030480 0x40>, <0x200304c0 0x40>;
+   interrupts = ;
+   interrupt-names = "vdec_mmu";
+   iommu-cells = <0>;
+   status = "disabled";
+   };
+
+   vop_mmu: iommu@20053f00 {
+   compatible = "rockchip,iommu";
+   reg = <0x20053f00 0x100>;
+   interrupts = ;
+   interrupt-names = "vop_mmu";
+   iommu-cells = <0>;
+   status = "disabled";
+   };
+
+   iep_mmu: iommu@20070800 {
+   compatible = "rockchip,iommu";
+   reg = <0x20070800 0x100>;
+   interrupts = ;
+   interrupt-names = "iep_mmu";
+   iommu-cells = <0>;
+   status = "disabled";
+   };
+
emmc: dwmmc@3002 {
compatible = "rockchip,rk3288-dw-mshc";
reg = <0x3002 0x4000>;
-- 
1.9.1


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


Re: [Qemu-devel] [RFC PATCH 7/8] VFIO: Add new IOCTL for IOMMU TLB invalidate propagation

2017-07-18 Thread Jean-Philippe Brucker
On 17/07/17 23:45, Alex Williamson wrote:
[..]
>>>
>>> How does a user learn which model(s) are supported by the interface?
>>> How do they learn which ops are supported?  Perhaps a good use for one of 
>>> those
>>> flag bits in the outer data structure is "probe".  
>>
>> My initial plan to user fills it, if the underlying HW doesn't support the
>> model, it refuses to service it. User should get a failure and stop to use
>> it. But your suggestion to have a probe or kinds of query makes sense.
>> How about we add one more operation for such purpose? Besides the
>> supported model query, I'd like to add more. E.g the HW IOMMU capabilities.
> 
> We also have VFIO_IOMMU_GET_INFO where the structure can be extended
> for missing capabilities.  Depending on the capability you want to
> describe, this might be a better, existing interface for it.

It might become hairy when physical IOMMUs start supporting multiple
formats, or when we want to describe multiple page table formats in
addition to PASID tables. I was wondering if sysfs iommu_group would be
better suited for this kind of hardware description with variable-length
properties, but a new ioctl-based probing mechanism would work as well.

Other things that we'll want to describe are fault reporting capability
and PASID range, which would fit better in vfio_device_info.

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


Re: [PATCH 1/5] iommu/arm-smmu-v3: put off the execution of TLBI* to reduce lock confliction

2017-07-18 Thread Jonathan Cameron
On Mon, 17 Jul 2017 13:28:47 -0400
Nate Watterson  wrote:

> Hi Jonathan,
> 
> On 7/17/2017 10:23 AM, Jonathan Cameron wrote:
> > On Mon, 17 Jul 2017 14:06:42 +0100
> > John Garry  wrote:
> >   
> >> +
> >>
> >> On 29/06/2017 03:08, Leizhen (ThunderTown) wrote:  
> >>>
> >>>
> >>> On 2017/6/28 17:32, Will Deacon wrote:  
>  Hi Zhen Lei,
> 
>  Nate (CC'd), Robin and I have been working on something very similar to
>  this series, but this patch is different to what we had planned. More 
>  below.
> 
>  On Mon, Jun 26, 2017 at 09:38:46PM +0800, Zhen Lei wrote:  
> > Because all TLBI commands should be followed by a SYNC command, to make
> > sure that it has been completely finished. So we can just add the TLBI
> > commands into the queue, and put off the execution until meet SYNC or
> > other commands. To prevent the followed SYNC command waiting for a long
> > time because of too many commands have been delayed, restrict the max
> > delayed number.
> >
> > According to my test, I got the same performance data as I replaced 
> > writel
> > with writel_relaxed in queue_inc_prod.
> >
> > Signed-off-by: Zhen Lei 
> > ---
> >   drivers/iommu/arm-smmu-v3.c | 42 
> > +-
> >   1 file changed, 37 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
> > index 291da5f..4481123 100644
> > --- a/drivers/iommu/arm-smmu-v3.c
> > +++ b/drivers/iommu/arm-smmu-v3.c
> > @@ -337,6 +337,7 @@
> >   /* Command queue */
> >   #define CMDQ_ENT_DWORDS   2
> >   #define CMDQ_MAX_SZ_SHIFT 8
> > +#define CMDQ_MAX_DELAYED   32
> >
> >   #define CMDQ_ERR_SHIFT24
> >   #define CMDQ_ERR_MASK 0x7f
> > @@ -472,6 +473,7 @@ struct arm_smmu_cmdq_ent {
> > };
> > } cfgi;
> >
> > +   #define CMDQ_OP_TLBI_NH_ALL 0x10
> > #define CMDQ_OP_TLBI_NH_ASID0x11
> > #define CMDQ_OP_TLBI_NH_VA  0x12
> > #define CMDQ_OP_TLBI_EL2_ALL0x20
> > @@ -499,6 +501,7 @@ struct arm_smmu_cmdq_ent {
> >
> >   struct arm_smmu_queue {
> > int irq; /* Wired interrupt */
> > +   u32 nr_delay;
> >
> > __le64  *base;
> > dma_addr_t  base_dma;
> > @@ -722,11 +725,16 @@ static int queue_sync_prod(struct arm_smmu_queue 
> > *q)
> > return ret;
> >   }
> >
> > -static void queue_inc_prod(struct arm_smmu_queue *q)
> > +static void queue_inc_swprod(struct arm_smmu_queue *q)
> >   {
> > -   u32 prod = (Q_WRP(q, q->prod) | Q_IDX(q, q->prod)) + 1;
> > +   u32 prod = q->prod + 1;
> >
> > q->prod = Q_OVF(q, q->prod) | Q_WRP(q, prod) | Q_IDX(q, prod);
> > +}
> > +
> > +static void queue_inc_prod(struct arm_smmu_queue *q)
> > +{
> > +   queue_inc_swprod(q);
> > writel(q->prod, q->prod_reg);
> >   }
> >
> > @@ -761,13 +769,24 @@ static void queue_write(__le64 *dst, u64 *src, 
> > size_t n_dwords)
> > *dst++ = cpu_to_le64(*src++);
> >   }
> >
> > -static int queue_insert_raw(struct arm_smmu_queue *q, u64 *ent)
> > +static int queue_insert_raw(struct arm_smmu_queue *q, u64 *ent, int 
> > optimize)
> >   {
> > if (queue_full(q))
> > return -ENOSPC;
> >
> > queue_write(Q_ENT(q, q->prod), ent, q->ent_dwords);
> > -   queue_inc_prod(q);
> > +
> > +   /*
> > +* We don't want too many commands to be delayed, this may lead 
> > the
> > +* followed sync command to wait for a long time.
> > +*/
> > +   if (optimize && (++q->nr_delay < CMDQ_MAX_DELAYED)) {
> > +   queue_inc_swprod(q);
> > +   } else {
> > +   queue_inc_prod(q);
> > +   q->nr_delay = 0;
> > +   }
> > +  
> 
>  So here, you're effectively putting invalidation commands into the 
>  command
>  queue without updating PROD. Do you actually see a performance advantage
>  from doing so? Another side of the argument would be that we should be  
> >>> Yes, my sas ssd performance test showed that it can improve about 
> >>> 100-150K/s(the same to I directly replace
> >>> writel with writel_relaxed). And the average execution time of 
> >>> iommu_unmap(which called by iommu_dma_unmap_sg)
> >>> dropped from 10us to 5us.
> >>> 
>  moving PROD as soon as we can, so that the SMMU can