Skip to contentSkip to conversation

Add MSM SMMUv1 support

PATCH New Olav Haugan 8 participants 30 messages Jun 30, 2014 – Jul 15, 2014 1 message not in the archive

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

cover Add MSM SMMUv1 support

These patches add support for Qualcomm MSM SMMUv1 hardware. The first patch renames the files for the existing MSM IOMMU driver to align with the SMMU hardware revision (v1 is ARM SMMUv1 spec). The second patch adds back map_range/unmap_range APIs. These APIs allows SMMU driver implementations to optimize mappings of scatter-gather list of physically contiguous chunks of memory. The third patch adds common macros to allow device drivers to poll memory mapped registers. The fourth and fifth patch is the actual MSM SMMUv1 driver which supports the following:

- ARM V7S and V7L page table format independent of ARM CPU page table format
- 4K/64K/1M/16M mappings (V7S)
- 4K/64K/2M/32M/1G mappings (V7L)
- ATOS used for unit testing of driver
- Sharing of page tables among SMMUs
- Verbose context bank fault reporting
- Verbose global fault reporting
- Support for clocks and GDSC
- map/unmap range
- Domain specific enabling of coherent Hardware Table Walk (HTW)

The last patch adds a new IOMMU domain attribute allowing us to set whether hardware table walks should go to cache or not.

Matt Wagantall (1):
iopoll: Introduce memory-mapped IO polling macros

Olav Haugan (6):
iommu: msm: Rename iommu driver files
iommu-api: Add map_range/unmap_range functions
iommu: msm: Add MSM IOMMUv1 driver
iommu: msm: Add support for V7L page table format
defconfig: msm: Enable Qualcomm SMMUv1 driver
iommu-api: Add domain attribute to enable coherent HTW

 .../devicetree/bindings/iommu/msm,iommu_v1.txt     |   60 +
 arch/arm/configs/qcom_defconfig                    |    3 +-
 drivers/iommu/Kconfig                              |   57 +-
 drivers/iommu/Makefile                             |    8 +-
 drivers/iommu/iommu.c                              |   24 +
 drivers/iommu/{msm_iommu.c => msm_iommu-v0.c}      |    2 +-
 drivers/iommu/msm_iommu-v1.c                       | 1529 +++++++++++++
 drivers/iommu/msm_iommu.c                          |  771 +------
 .../iommu/{msm_iommu_dev.c => msm_iommu_dev-v0.c}  |    2 +-
 drivers/iommu/msm_iommu_dev-v1.c                   |  345 +++
 .../{msm_iommu_hw-8xxx.h => msm_iommu_hw-v0.h}     |    0
 drivers/iommu/msm_iommu_hw-v1.h                    | 2322 ++++++++++++++++++++
 drivers/iommu/msm_iommu_pagetable.c                |  600 +++++
 drivers/iommu/msm_iommu_pagetable.h                |   33 +
 drivers/iommu/msm_iommu_pagetable_lpae.c           |  717 ++++++
 drivers/iommu/msm_iommu_priv.h                     |   65 +
 include/linux/iommu.h                              |   25 +
 include/linux/iopoll.h                             |  114 +
 include/linux/qcom_iommu.h                         |  221 ++
 19 files changed, 6236 insertions(+), 662 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iommu/msm,iommu_v1.txt
 copy drivers/iommu/{msm_iommu.c => msm_iommu-v0.c} (99%)
 create mode 100644 drivers/iommu/msm_iommu-v1.c
 rename drivers/iommu/{msm_iommu_dev.c => msm_iommu_dev-v0.c} (99%)
 create mode 100644 drivers/iommu/msm_iommu_dev-v1.c
 rename drivers/iommu/{msm_iommu_hw-8xxx.h => msm_iommu_hw-v0.h} (100%)
 create mode 100644 drivers/iommu/msm_iommu_hw-v1.h
 create mode 100644 drivers/iommu/msm_iommu_pagetable.c
 create mode 100644 drivers/iommu/msm_iommu_pagetable.h
 create mode 100644 drivers/iommu/msm_iommu_pagetable_lpae.c
 create mode 100644 drivers/iommu/msm_iommu_priv.h
 create mode 100644 include/linux/iopoll.h
 create mode 100644 include/linux/qcom_iommu.h

--
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

#1 lore raw

PATCH 1/7 iommu: msm: Rename iommu driver files

Rename the MSM IOMMU driver for MSM8960 SoC to "-v0" version to align with hardware version number for next generation MSM IOMMU (v1).

---
 arch/arm/configs/qcom_defconfig                          |  2 +-
 drivers/iommu/Kconfig                                    | 11 +++++++++--
 drivers/iommu/Makefile                                   |  2 +-
 drivers/iommu/{msm_iommu.c => msm_iommu-v0.c}            |  2 +-
 drivers/iommu/{msm_iommu_dev.c => msm_iommu_dev-v0.c}    |  2 +-
 drivers/iommu/{msm_iommu_hw-8xxx.h => msm_iommu_hw-v0.h} |  0
 6 files changed, 13 insertions(+), 6 deletions(-)
 rename drivers/iommu/{msm_iommu.c => msm_iommu-v0.c} (99%)
 rename drivers/iommu/{msm_iommu_dev.c => msm_iommu_dev-v0.c} (99%)
 rename drivers/iommu/{msm_iommu_hw-8xxx.h => msm_iommu_hw-v0.h} (100%)
arch/arm/configs/qcom_defconfig +1 -1
index 42ebd72..0414889 100644
@@ -136,7 +136,7 @@ CONFIG_COMMON_CLK_QCOM=y
 CONFIG_MSM_GCC_8660=y
 CONFIG_MSM_MMCC_8960=y
 CONFIG_MSM_MMCC_8974=y
-CONFIG_MSM_IOMMU=y
+CONFIG_MSM_IOMMU_V0=y
 CONFIG_GENERIC_PHY=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
drivers/iommu/Kconfig +9 -2
index d260605..705a257 100644
@@ -28,12 +28,19 @@ config FSL_PAMU
 	  transaction types.
 
 # MSM IOMMU support
+
+# MSM_IOMMU always gets selected by whoever wants it.
 config MSM_IOMMU
-	bool "MSM IOMMU Support"
+	bool
+
+# MSM IOMMUv0 support
+config MSM_IOMMU_V0
+	bool "MSM IOMMUv0 Support"
 	depends on ARCH_MSM8X60 || ARCH_MSM8960
 	select IOMMU_API
+	select MSM_IOMMU
 	help
-	  Support for the IOMMUs found on certain Qualcomm SOCs.
+	  Support for the IOMMUs (v0) found on certain Qualcomm SOCs.
 	  These IOMMUs allow virtualization of the address space used by most
 	  cores within the multimedia subsystem.
 
drivers/iommu/Makefile +1 -1
index 8893bad..894ced9 100644
@@ -1,7 +1,7 @@
 obj-$(CONFIG_IOMMU_API) += iommu.o
 obj-$(CONFIG_IOMMU_API) += iommu-traces.o
 obj-$(CONFIG_OF_IOMMU)	+= of_iommu.o
-obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o
+obj-$(CONFIG_MSM_IOMMU_V0) += msm_iommu-v0.o msm_iommu_dev-v0.o
 obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
 obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o
 obj-$(CONFIG_ARM_SMMU) += arm-smmu.o
drivers/iommu/msm_iommu-v0.c renamed from drivers/iommu/msm_iommu.c +1 -1
similarity index 99%
rename from drivers/iommu/msm_iommu.c
rename to drivers/iommu/msm_iommu-v0.c
index f5ff657..17731061 100644
@@ -31,7 +31,7 @@
 #include <asm/cacheflush.h>
 #include <asm/sizes.h>
 
-#include "msm_iommu_hw-8xxx.h"
+#include "msm_iommu_hw-v0.h"
 #include "msm_iommu.h"
 
 #define MRC(reg, processor, op1, crn, crm, op2)				\
drivers/iommu/msm_iommu_dev-v0.c renamed from drivers/iommu/msm_iommu_dev.c +1 -1
similarity index 99%
rename from drivers/iommu/msm_iommu_dev.c
rename to drivers/iommu/msm_iommu_dev-v0.c
index 61def7cb..2f86e46 100644
@@ -27,7 +27,7 @@
 #include <linux/err.h>
 #include <linux/slab.h>
 
-#include "msm_iommu_hw-8xxx.h"
+#include "msm_iommu_hw-v0.h"
 #include "msm_iommu.h"
 
 struct iommu_ctx_iter_data {
drivers/iommu/msm_iommu_hw-v0.h renamed from drivers/iommu/msm_iommu_hw-8xxx.h +0 -0
similarity index 100%
rename from drivers/iommu/msm_iommu_hw-8xxx.h
rename to drivers/iommu/msm_iommu_hw-v0.h
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#2 lore raw

PATCH 2/7 iommu-api: Add map_range/unmap_range functions

In reply to Olav Haugan

Mapping and unmapping are more often than not in the critical path. map_range and unmap_range allows SMMU driver implementations to optimize the process of mapping and unmapping buffers into the SMMU page tables. Instead of mapping one physical address, do TLB operation (expensive), mapping, do TLB operation, mapping, do TLB operation the driver can map a scatter-gatherlist of physically contiguous pages into one virtual address space and then at the end do one TLB operation.

Additionally, the mapping operation would be faster in general since clients does not have to keep calling map API over and over again for each physically contiguous chunk of memory that needs to be mapped to a virtually contiguous region.

---
 drivers/iommu/iommu.c | 24 ++++++++++++++++++++++++
 include/linux/iommu.h | 24 ++++++++++++++++++++++++
 2 files changed, 48 insertions(+)
drivers/iommu/iommu.c +24 -0
index e5555fc..f2a6b80 100644
@@ -898,6 +898,30 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
 EXPORT_SYMBOL_GPL(iommu_unmap);
 
 
+int iommu_map_range(struct iommu_domain *domain, unsigned int iova,
+		    struct scatterlist *sg, unsigned int len, int prot)
+{
+	if (unlikely(domain->ops->map_range == NULL))
+		return -ENODEV;
+
+	BUG_ON(iova & (~PAGE_MASK));
+
+	return domain->ops->map_range(domain, iova, sg, len, prot);
+}
+EXPORT_SYMBOL_GPL(iommu_map_range);
+
+int iommu_unmap_range(struct iommu_domain *domain, unsigned int iova,
+		      unsigned int len)
+{
+	if (unlikely(domain->ops->unmap_range == NULL))
+		return -ENODEV;
+
+	BUG_ON(iova & (~PAGE_MASK));
+
+	return domain->ops->unmap_range(domain, iova, len);
+}
+EXPORT_SYMBOL_GPL(iommu_unmap_range);
+
 int iommu_domain_window_enable(struct iommu_domain *domain, u32 wnd_nr,
 			       phys_addr_t paddr, u64 size, int prot)
 {
include/linux/iommu.h +24 -0
index b96a5b2..63dca6d 100644
@@ -22,6 +22,7 @@
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/types.h>
+#include <linux/scatterlist.h>
 #include <trace/events/iommu.h>
 
 #define IOMMU_READ	(1 << 0)
@@ -93,6 +94,8 @@ enum iommu_attr {
  * @detach_dev: detach device from an iommu domain
  * @map: map a physically contiguous memory region to an iommu domain
  * @unmap: unmap a physically contiguous memory region from an iommu domain
+ * @map_range: map a scatter-gather list of physically contiguous memory chunks to an iommu domain
+ * @unmap_range: unmap a scatter-gather list of physically contiguous memory chunks from an iommu domain
  * @iova_to_phys: translate iova to physical address
  * @domain_has_cap: domain capabilities query
  * @add_device: add device to iommu grouping
@@ -110,6 +113,10 @@ struct iommu_ops {
 		   phys_addr_t paddr, size_t size, int prot);
 	size_t (*unmap)(struct iommu_domain *domain, unsigned long iova,
 		     size_t size);
+	int (*map_range)(struct iommu_domain *domain, unsigned int iova,
+		    struct scatterlist *sg, unsigned int len, int prot);
+	int (*unmap_range)(struct iommu_domain *domain, unsigned int iova,
+		      unsigned int len);
 	phys_addr_t (*iova_to_phys)(struct iommu_domain *domain, dma_addr_t iova);
 	int (*domain_has_cap)(struct iommu_domain *domain,
 			      unsigned long cap);
@@ -153,6 +160,10 @@ extern int iommu_map(struct iommu_domain *domain, unsigned long iova,
 		     phys_addr_t paddr, size_t size, int prot);
 extern size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova,
 		       size_t size);
+extern int iommu_map_range(struct iommu_domain *domain, unsigned int iova,
+		    struct scatterlist *sg, unsigned int len, int prot);
+extern int iommu_unmap_range(struct iommu_domain *domain, unsigned int iova,
+		      unsigned int len);
 extern phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova);
 extern int iommu_domain_has_cap(struct iommu_domain *domain,
 				unsigned long cap);
@@ -280,6 +291,19 @@ static inline int iommu_unmap(struct iommu_domain *domain, unsigned long iova,
 	return -ENODEV;
 }
 
+static inline int iommu_map_range(struct iommu_domain *domain,
+				  unsigned int iova, struct scatterlist *sg,
+				  unsigned int len, int prot)
+{
+	return -ENODEV;
+}
+
+static inline int iommu_unmap_range(struct iommu_domain *domain,
+				    unsigned int iova, unsigned int len)
+{
+	return -ENODEV;
+}
+
 static inline int iommu_domain_window_enable(struct iommu_domain *domain,
 					     u32 wnd_nr, phys_addr_t paddr,
 					     u64 size, int prot)
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#3 lore raw

PATCH 2/7 iommu-api: Add map_range/unmap_range functions

On Mon, Jun 30, 2014 at 09:51:51AM -0700, Olav Haugan wrote:
[...]

drivers/iommu/iommu.c size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) · line 905

Quoted 5 lines
drivers/iommu/iommu.c +5 -0
+int iommu_map_range(struct iommu_domain *domain, unsigned int iova,
+		    struct scatterlist *sg, unsigned int len, int prot)
+{
+	if (unlikely(domain->ops->map_range == NULL))
+		return -ENODEV;

Should we perhaps make this mandatory? For drivers that don't provide it we could implement a generic helper that wraps iommu_{map,unmap}().

Quoted 8 lines
drivers/iommu/iommu.c +8 -0
+
+	BUG_ON(iova & (~PAGE_MASK));
+
+	return domain->ops->map_range(domain, iova, sg, len, prot);
+}
+EXPORT_SYMBOL_GPL(iommu_map_range);
+
+int iommu_unmap_range(struct iommu_domain *domain, unsigned int iova,

drivers/iommu/iommu.c size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) · line 923

Quoted 10 lines
drivers/iommu/iommu.c +10 -0
+		      unsigned int len)
+{
+	if (unlikely(domain->ops->unmap_range == NULL))
+		return -ENODEV;
+
+	BUG_ON(iova & (~PAGE_MASK));
+
+	return domain->ops->unmap_range(domain, iova, len);
+}
+EXPORT_SYMBOL_GPL(iommu_unmap_range);

Could these be renamed iommu_{map,unmap}_sg() instead to make it more obvious what exactly they map? And perhaps this could take an sg_table instead, which already provides a count and is a very common structure used in drivers (and the DMA mapping API).

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140630/40852b16/attachment-0001.sig>

#4 lore raw

PATCH 2/7 iommu-api: Add map_range/unmap_range functions

In reply to Olav Haugan

Hi Olav,

Quoted 8 lines · Olav Haugan

Mapping and unmapping are more often than not in the critical path. map_range and unmap_range allows SMMU driver implementations to optimize the process of mapping and unmapping buffers into the SMMU page tables. Instead of mapping one physical address, do TLB operation (expensive), mapping, do TLB operation, mapping, do TLB operation the driver can map a scatter-gatherlist of physically contiguous pages into one virtual address space and then at the end do one TLB operation.

Quoted 4 lines

Additionally, the mapping operation would be faster in general since clients does not have to keep calling map API over and over again for each physically contiguous chunk of memory that needs to be mapped to a virtually contiguous region.

I like the idea of this, although it does mean that drivers implementing the range mapping functions need more featureful page-table manipulation code than currently required.

For example, iommu_map uses iommu_pgsize to guarantee that mappings are created in blocks of the largest support page size. This can be used to simplify iterating in the SMMU driver (although the ARM SMMU driver doesn't yet make use of this, I think Varun would add this when he adds support for sections).

Given that we're really trying to kill the TLBI here, why not implement something like iommu_unmap_nosync (unmap without DSB; TLBI) and iommu_sync (DSB; TLBI) instead? If we guarantee that ranges must be unmapped before being remapped, then there shouldn't be a TLBI on the map path anyway.

Will

#5 lore raw

PATCH 2/7 iommu-api: Add map_range/unmap_range functions

Quoted 34 lines

-----Original Message-----
From: iommu-bounces at lists.linux-foundation.org [mailto:iommu- bounces at lists.linux-foundation.org] On Behalf Of Will Deacon
Sent: Tuesday, July 01, 2014 3:04 PM
To: Olav Haugan
Cc: linux-arm-msm at vger.kernel.org; iommu at lists.linux-foundation.org; thierry.reding at gmail.com; vgandhi at codeaurora.org; linux-arm- kernel at lists.infradead.org
Subject: Re: [RFC/PATCH 2/7] iommu-api: Add map_range/unmap_range functions

Hi Olav,

Quoted 3 lines · Olav Haugan

Mapping and unmapping are more often than not in the critical path. map_range and unmap_range allows SMMU driver implementations to optimize the process of mapping and unmapping buffers into the SMMU

page tables.

Quoted 9 lines

Instead of mapping one physical address, do TLB operation (expensive), mapping, do TLB operation, mapping, do TLB operation the driver can map a scatter-gatherlist of physically contiguous pages into one virtual address space and then at the end do one TLB operation.

Additionally, the mapping operation would be faster in general since clients does not have to keep calling map API over and over again for each physically contiguous chunk of memory that needs to be mapped to a virtually contiguous region.

I like the idea of this, although it does mean that drivers implementing the range mapping functions need more featureful page-table manipulation code than currently required.

Quoted 5 lines

For example, iommu_map uses iommu_pgsize to guarantee that mappings are created in blocks of the largest support page size. This can be used to simplify iterating in the SMMU driver (although the ARM SMMU driver doesn't yet make use of this, I think Varun would add this when he adds support for sections).

Yes, this would be supported.

-Varun

#6 lore raw

PATCH 2/7 iommu-api: Add map_range/unmap_range functions

In reply to Olav Haugan

Hi Olav,

Quoted 28 lines · Olav Haugan

Mapping and unmapping are more often than not in the critical path. map_range and unmap_range allows SMMU driver implementations to optimize the process of mapping and unmapping buffers into the SMMU page tables. Instead of mapping one physical address, do TLB operation (expensive), mapping, do TLB operation, mapping, do TLB operation the driver can map a scatter-gatherlist of physically contiguous pages into one virtual address space and then at the end do one TLB operation.

Additionally, the mapping operation would be faster in general since clients does not have to keep calling map API over and over again for each physically contiguous chunk of memory that needs to be mapped to a virtually contiguous region.

---
 drivers/iommu/iommu.c | 24 ++++++++++++++++++++++++
 include/linux/iommu.h | 24 ++++++++++++++++++++++++
 2 files changed, 48 insertions(+)
drivers/iommu/iommu.c +1 -0
index e5555fc..f2a6b80 100644
@@ -898,6 +898,30 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
 EXPORT_SYMBOL_GPL(iommu_unmap);
 
 
+int iommu_map_range(struct iommu_domain *domain, unsigned int iova,

drivers/iommu/iommu.c size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) · line 911

Quoted 10 lines
drivers/iommu/iommu.c +10 -0
+		    struct scatterlist *sg, unsigned int len, int prot)
+{
+	if (unlikely(domain->ops->map_range == NULL))
+		return -ENODEV;
+
+	BUG_ON(iova & (~PAGE_MASK));
+
+	return domain->ops->map_range(domain, iova, sg, len, prot);
+}
+EXPORT_SYMBOL_GPL(iommu_map_range);

We have the similar one internally, which is named, "iommu_map_sg()", called from DMA API.

drivers/iommu/iommu.c size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) · line 923

Quoted 11 lines
drivers/iommu/iommu.c +11 -0
+int iommu_unmap_range(struct iommu_domain *domain, unsigned int iova,
+		      unsigned int len)
+{
+	if (unlikely(domain->ops->unmap_range == NULL))
+		return -ENODEV;
+
+	BUG_ON(iova & (~PAGE_MASK));
+
+	return domain->ops->unmap_range(domain, iova, len);
+}
+EXPORT_SYMBOL_GPL(iommu_unmap_range);

Can the existing iommu_unmap() do the same?

#7 lore raw

PATCH 2/7 iommu-api: Add map_range/unmap_range functions

Hi Hiroshi,

Quoted 31 lines · Hiroshi Doyu

Hi Olav,

Quoted 27 lines · Olav Haugan

Mapping and unmapping are more often than not in the critical path. map_range and unmap_range allows SMMU driver implementations to optimize the process of mapping and unmapping buffers into the SMMU page tables. Instead of mapping one physical address, do TLB operation (expensive), mapping, do TLB operation, mapping, do TLB operation the driver can map a scatter-gatherlist of physically contiguous pages into one virtual address space and then at the end do one TLB operation.

Additionally, the mapping operation would be faster in general since clients does not have to keep calling map API over and over again for each physically contiguous chunk of memory that needs to be mapped to a virtually contiguous region.

---
 drivers/iommu/iommu.c | 24 ++++++++++++++++++++++++
 include/linux/iommu.h | 24 ++++++++++++++++++++++++
 2 files changed, 48 insertions(+)
drivers/iommu/iommu.c +0 -0
index e5555fc..f2a6b80 100644
@@ -898,6 +898,30 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
 EXPORT_SYMBOL_GPL(iommu_unmap);
 
 
Quoted 14 lines

drivers/iommu/iommu.c size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) · line 911

Quoted 11 lines
drivers/iommu/iommu.c +11 -0
+int iommu_map_range(struct iommu_domain *domain, unsigned int iova,
+		    struct scatterlist *sg, unsigned int len, int prot)
+{
+	if (unlikely(domain->ops->map_range == NULL))
+		return -ENODEV;
+
+	BUG_ON(iova & (~PAGE_MASK));
+
+	return domain->ops->map_range(domain, iova, sg, len, prot);
+}
+EXPORT_SYMBOL_GPL(iommu_map_range);

We have the similar one internally, which is named, "iommu_map_sg()", called from DMA API.

Great, so this new API will be useful to more people!

Quoted 5 lines
Quoted 5 lines
drivers/iommu/iommu.c +5 -0
+int iommu_unmap_range(struct iommu_domain *domain, unsigned int iova,
+		      unsigned int len)
+{
+	if (unlikely(domain->ops->unmap_range == NULL))
+		return -ENODEV;
Quoted 8 lines

drivers/iommu/iommu.c size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) · line 923

Quoted 6 lines
drivers/iommu/iommu.c +6 -0
+
+	BUG_ON(iova & (~PAGE_MASK));
+
+	return domain->ops->unmap_range(domain, iova, len);
+}
+EXPORT_SYMBOL_GPL(iommu_unmap_range);

Can the existing iommu_unmap() do the same?

I believe iommu_unmap() behaves a bit differently because it will keep on calling domain->ops->unmap() until everything is unmapped instead of letting the iommu implementation take care of unmapping everything in one call.

I am abandoning the patch series since our driver was not accepted. However, if there are no objections I will resubmit this patch (PATCH 2/7) as an independent patch to add this new map_range API.

Thanks,

Olav Haugan

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#8 lore raw

PATCH 2/7 iommu-api: Add map_range/unmap_range functions

Quoted 65 lines · Olav Haugan

Hi Hiroshi,

Quoted 31 lines · Hiroshi Doyu

Hi Olav,

Quoted 27 lines · Olav Haugan

Mapping and unmapping are more often than not in the critical path. map_range and unmap_range allows SMMU driver implementations to optimize the process of mapping and unmapping buffers into the SMMU page tables. Instead of mapping one physical address, do TLB operation (expensive), mapping, do TLB operation, mapping, do TLB operation the driver can map a scatter-gatherlist of physically contiguous pages into one virtual address space and then at the end do one TLB operation.

Additionally, the mapping operation would be faster in general since clients does not have to keep calling map API over and over again for each physically contiguous chunk of memory that needs to be mapped to a virtually contiguous region.

---
 drivers/iommu/iommu.c | 24 ++++++++++++++++++++++++
 include/linux/iommu.h | 24 ++++++++++++++++++++++++
 2 files changed, 48 insertions(+)
drivers/iommu/iommu.c +0 -0
index e5555fc..f2a6b80 100644
@@ -898,6 +898,30 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
 EXPORT_SYMBOL_GPL(iommu_unmap);
 
 
Quoted 14 lines

drivers/iommu/iommu.c size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) · line 911

Quoted 11 lines
drivers/iommu/iommu.c +11 -0
+int iommu_map_range(struct iommu_domain *domain, unsigned int iova,
+                struct scatterlist *sg, unsigned int len, int prot)
+{
+    if (unlikely(domain->ops->map_range == NULL))
+            return -ENODEV;
+
+    BUG_ON(iova & (~PAGE_MASK));
+
+    return domain->ops->map_range(domain, iova, sg, len, prot);
+}
+EXPORT_SYMBOL_GPL(iommu_map_range);

We have the similar one internally, which is named, "iommu_map_sg()", called from DMA API.

Great, so this new API will be useful to more people!

Quoted 5 lines
Quoted 5 lines
drivers/iommu/iommu.c +5 -0
+int iommu_unmap_range(struct iommu_domain *domain, unsigned int iova,
+                  unsigned int len)
+{
+    if (unlikely(domain->ops->unmap_range == NULL))
+            return -ENODEV;
Quoted 8 lines

drivers/iommu/iommu.c size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) · line 923

Quoted 6 lines
drivers/iommu/iommu.c +6 -0
+
+    BUG_ON(iova & (~PAGE_MASK));
+
+    return domain->ops->unmap_range(domain, iova, len);
+}
+EXPORT_SYMBOL_GPL(iommu_unmap_range);

Can the existing iommu_unmap() do the same?

Quoted 8 lines

I believe iommu_unmap() behaves a bit differently because it will keep on calling domain->ops->unmap() until everything is unmapped instead of letting the iommu implementation take care of unmapping everything in one call.

I am abandoning the patch series since our driver was not accepted. However, if there are no objections I will resubmit this patch (PATCH 2/7) as an independent patch to add this new map_range API.

+1 for map_range().. I've seen for gpu workloads, at least, it is the
downstream map_range() API is quite beneficial. It was worth at
least a few fps in xonotic.

And, possibly getting off the subject a bit, but I was wondering about the possibility of going one step further and batching up mapping and/or unmapping multiple buffers (ranges) at once. I have a pretty convenient sync point in drm/msm to flush out multiple mappings before kicking gpu.

BR,
-R

Quoted 11 lines

Thanks,

Olav Haugan

--
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

#9 lore raw

PATCH 2/7 iommu-api: Add map_range/unmap_range functions

Quoted 79 lines · Rob Clark
Quoted 65 lines · Olav Haugan

Hi Hiroshi,

Quoted 31 lines · Hiroshi Doyu

Hi Olav,

Quoted 27 lines · Olav Haugan

Mapping and unmapping are more often than not in the critical path. map_range and unmap_range allows SMMU driver implementations to optimize the process of mapping and unmapping buffers into the SMMU page tables. Instead of mapping one physical address, do TLB operation (expensive), mapping, do TLB operation, mapping, do TLB operation the driver can map a scatter-gatherlist of physically contiguous pages into one virtual address space and then at the end do one TLB operation.

Additionally, the mapping operation would be faster in general since clients does not have to keep calling map API over and over again for each physically contiguous chunk of memory that needs to be mapped to a virtually contiguous region.

---
 drivers/iommu/iommu.c | 24 ++++++++++++++++++++++++
 include/linux/iommu.h | 24 ++++++++++++++++++++++++
 2 files changed, 48 insertions(+)
drivers/iommu/iommu.c +0 -0
index e5555fc..f2a6b80 100644
@@ -898,6 +898,30 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
 EXPORT_SYMBOL_GPL(iommu_unmap);
 
 
Quoted 14 lines

drivers/iommu/iommu.c size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) · line 911

Quoted 11 lines
drivers/iommu/iommu.c +11 -0
+int iommu_map_range(struct iommu_domain *domain, unsigned int iova,
+                struct scatterlist *sg, unsigned int len, int prot)
+{
+    if (unlikely(domain->ops->map_range == NULL))
+            return -ENODEV;
+
+    BUG_ON(iova & (~PAGE_MASK));
+
+    return domain->ops->map_range(domain, iova, sg, len, prot);
+}
+EXPORT_SYMBOL_GPL(iommu_map_range);

We have the similar one internally, which is named, "iommu_map_sg()", called from DMA API.

Great, so this new API will be useful to more people!

Quoted 5 lines
Quoted 5 lines
drivers/iommu/iommu.c +5 -0
+int iommu_unmap_range(struct iommu_domain *domain, unsigned int iova,
+                  unsigned int len)
+{
+    if (unlikely(domain->ops->unmap_range == NULL))
+            return -ENODEV;
Quoted 8 lines

drivers/iommu/iommu.c size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) · line 923

Quoted 6 lines
drivers/iommu/iommu.c +6 -0
+
+    BUG_ON(iova & (~PAGE_MASK));
+
+    return domain->ops->unmap_range(domain, iova, len);
+}
+EXPORT_SYMBOL_GPL(iommu_unmap_range);

Can the existing iommu_unmap() do the same?

Quoted 8 lines

I believe iommu_unmap() behaves a bit differently because it will keep on calling domain->ops->unmap() until everything is unmapped instead of letting the iommu implementation take care of unmapping everything in one call.

I am abandoning the patch series since our driver was not accepted. However, if there are no objections I will resubmit this patch (PATCH 2/7) as an independent patch to add this new map_range API.

+1 for map_range().. I've seen for gpu workloads, at least, it is the
downstream map_range() API is quite beneficial. It was worth at
least a few fps in xonotic.

Quoted 5 lines

And, possibly getting off the subject a bit, but I was wondering about the possibility of going one step further and batching up mapping and/or unmapping multiple buffers (ranges) at once. I have a pretty convenient sync point in drm/msm to flush out multiple mappings before kicking gpu.

I think you should be able to do that with this API already - at least the mapping part since we are passing in a sg list (this could be a chained sglist).

Thanks,

Olav

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#10 lore raw

PATCH 2/7 iommu-api: Add map_range/unmap_range functions

Quoted 86 lines · Olav Haugan
Quoted 79 lines · Rob Clark
Quoted 65 lines · Olav Haugan

Hi Hiroshi,

Quoted 31 lines · Hiroshi Doyu

Hi Olav,

Quoted 27 lines · Olav Haugan

Mapping and unmapping are more often than not in the critical path. map_range and unmap_range allows SMMU driver implementations to optimize the process of mapping and unmapping buffers into the SMMU page tables. Instead of mapping one physical address, do TLB operation (expensive), mapping, do TLB operation, mapping, do TLB operation the driver can map a scatter-gatherlist of physically contiguous pages into one virtual address space and then at the end do one TLB operation.

Additionally, the mapping operation would be faster in general since clients does not have to keep calling map API over and over again for each physically contiguous chunk of memory that needs to be mapped to a virtually contiguous region.

---
 drivers/iommu/iommu.c | 24 ++++++++++++++++++++++++
 include/linux/iommu.h | 24 ++++++++++++++++++++++++
 2 files changed, 48 insertions(+)
drivers/iommu/iommu.c +0 -0
index e5555fc..f2a6b80 100644
@@ -898,6 +898,30 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
 EXPORT_SYMBOL_GPL(iommu_unmap);
 
 
Quoted 14 lines

drivers/iommu/iommu.c size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) · line 911

Quoted 11 lines
drivers/iommu/iommu.c +11 -0
+int iommu_map_range(struct iommu_domain *domain, unsigned int iova,
+                struct scatterlist *sg, unsigned int len, int prot)
+{
+    if (unlikely(domain->ops->map_range == NULL))
+            return -ENODEV;
+
+    BUG_ON(iova & (~PAGE_MASK));
+
+    return domain->ops->map_range(domain, iova, sg, len, prot);
+}
+EXPORT_SYMBOL_GPL(iommu_map_range);

We have the similar one internally, which is named, "iommu_map_sg()", called from DMA API.

Great, so this new API will be useful to more people!

Quoted 5 lines
Quoted 5 lines
drivers/iommu/iommu.c +5 -0
+int iommu_unmap_range(struct iommu_domain *domain, unsigned int iova,
+                  unsigned int len)
+{
+    if (unlikely(domain->ops->unmap_range == NULL))
+            return -ENODEV;
Quoted 8 lines

drivers/iommu/iommu.c size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) · line 923

Quoted 6 lines
drivers/iommu/iommu.c +6 -0
+
+    BUG_ON(iova & (~PAGE_MASK));
+
+    return domain->ops->unmap_range(domain, iova, len);
+}
+EXPORT_SYMBOL_GPL(iommu_unmap_range);

Can the existing iommu_unmap() do the same?

Quoted 8 lines

I believe iommu_unmap() behaves a bit differently because it will keep on calling domain->ops->unmap() until everything is unmapped instead of letting the iommu implementation take care of unmapping everything in one call.

I am abandoning the patch series since our driver was not accepted. However, if there are no objections I will resubmit this patch (PATCH 2/7) as an independent patch to add this new map_range API.

+1 for map_range().. I've seen for gpu workloads, at least, it is the
downstream map_range() API is quite beneficial. It was worth at
least a few fps in xonotic.

Quoted 5 lines

And, possibly getting off the subject a bit, but I was wondering about the possibility of going one step further and batching up mapping and/or unmapping multiple buffers (ranges) at once. I have a pretty convenient sync point in drm/msm to flush out multiple mappings before kicking gpu.

Quoted 3 lines

I think you should be able to do that with this API already - at least the mapping part since we are passing in a sg list (this could be a chained sglist).

What I mean by batching up is mapping and unmapping multiple sglists each at different iova's with minmal cpu cache and iommu tlb flushes..

Ideally we'd let the IOMMU driver be clever and build out all 2nd level tables before inserting into first level tables (to minimize cpu cache flushing).. also, there is probably a reasonable chance that we'd be mapping a new buffer into existing location, so there might be some potential to reuse existing 2nd level tables (and save a tiny bit of free/alloc). I've not thought too much about how that would look in code.. might be kinda, umm, fun..

But at an API level, we should be able to do a bunch of map/unmap_range's with one flush.

Maybe it could look like a sequence of iommu_{map,unmap}_range() followed by iommu_flush()?

BR,
-R

Quoted 7 lines

Thanks,

Olav

--
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

#11 lore raw

PATCH 2/7 iommu-api: Add map_range/unmap_range functions

Quoted 102 lines · Rob Clark
Quoted 86 lines · Olav Haugan
Quoted 79 lines · Rob Clark
Quoted 65 lines · Olav Haugan

Hi Hiroshi,

Quoted 31 lines · Hiroshi Doyu

Hi Olav,

Quoted 27 lines · Olav Haugan

Mapping and unmapping are more often than not in the critical path. map_range and unmap_range allows SMMU driver implementations to optimize the process of mapping and unmapping buffers into the SMMU page tables. Instead of mapping one physical address, do TLB operation (expensive), mapping, do TLB operation, mapping, do TLB operation the driver can map a scatter-gatherlist of physically contiguous pages into one virtual address space and then at the end do one TLB operation.

Additionally, the mapping operation would be faster in general since clients does not have to keep calling map API over and over again for each physically contiguous chunk of memory that needs to be mapped to a virtually contiguous region.

---
 drivers/iommu/iommu.c | 24 ++++++++++++++++++++++++
 include/linux/iommu.h | 24 ++++++++++++++++++++++++
 2 files changed, 48 insertions(+)
drivers/iommu/iommu.c +0 -0
index e5555fc..f2a6b80 100644
@@ -898,6 +898,30 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
 EXPORT_SYMBOL_GPL(iommu_unmap);
 
 
Quoted 14 lines

drivers/iommu/iommu.c size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) · line 911

Quoted 11 lines
drivers/iommu/iommu.c +11 -0
+int iommu_map_range(struct iommu_domain *domain, unsigned int iova,
+                struct scatterlist *sg, unsigned int len, int prot)
+{
+    if (unlikely(domain->ops->map_range == NULL))
+            return -ENODEV;
+
+    BUG_ON(iova & (~PAGE_MASK));
+
+    return domain->ops->map_range(domain, iova, sg, len, prot);
+}
+EXPORT_SYMBOL_GPL(iommu_map_range);

We have the similar one internally, which is named, "iommu_map_sg()", called from DMA API.

Great, so this new API will be useful to more people!

Quoted 5 lines
Quoted 5 lines
drivers/iommu/iommu.c +5 -0
+int iommu_unmap_range(struct iommu_domain *domain, unsigned int iova,
+                  unsigned int len)
+{
+    if (unlikely(domain->ops->unmap_range == NULL))
+            return -ENODEV;
Quoted 8 lines

drivers/iommu/iommu.c size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) · line 923

Quoted 6 lines
drivers/iommu/iommu.c +6 -0
+
+    BUG_ON(iova & (~PAGE_MASK));
+
+    return domain->ops->unmap_range(domain, iova, len);
+}
+EXPORT_SYMBOL_GPL(iommu_unmap_range);

Can the existing iommu_unmap() do the same?

Quoted 8 lines

I believe iommu_unmap() behaves a bit differently because it will keep on calling domain->ops->unmap() until everything is unmapped instead of letting the iommu implementation take care of unmapping everything in one call.

I am abandoning the patch series since our driver was not accepted. However, if there are no objections I will resubmit this patch (PATCH 2/7) as an independent patch to add this new map_range API.

+1 for map_range().. I've seen for gpu workloads, at least, it is the
downstream map_range() API is quite beneficial. It was worth at
least a few fps in xonotic.

Quoted 5 lines

And, possibly getting off the subject a bit, but I was wondering about the possibility of going one step further and batching up mapping and/or unmapping multiple buffers (ranges) at once. I have a pretty convenient sync point in drm/msm to flush out multiple mappings before kicking gpu.

Quoted 3 lines

I think you should be able to do that with this API already - at least the mapping part since we are passing in a sg list (this could be a chained sglist).

What I mean by batching up is mapping and unmapping multiple sglists each at different iova's with minmal cpu cache and iommu tlb flushes..

Ideally we'd let the IOMMU driver be clever and build out all 2nd level tables before inserting into first level tables (to minimize cpu cache flushing).. also, there is probably a reasonable chance that we'd be mapping a new buffer into existing location, so there might be some potential to reuse existing 2nd level tables (and save a tiny bit of free/alloc). I've not thought too much about how that would look in code.. might be kinda, umm, fun..

Quoted 5 lines

But at an API level, we should be able to do a bunch of map/unmap_range's with one flush.

Maybe it could look like a sequence of iommu_{map,unmap}_range() followed by iommu_flush()?

Doesn't that mean that the IOMMU driver would have to keep track of all mappings until it sees an iommu_flush()? That sounds like it could be a lot of work and complicated code.

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140710/5d9ecb22/attachment-0001.sig>

#12 lore raw

PATCH 2/7 iommu-api: Add map_range/unmap_range functions

Quoted 106 lines · Thierry Reding
Quoted 105 lines · Rob Clark
Quoted 86 lines · Olav Haugan
Quoted 79 lines · Rob Clark
Quoted 65 lines · Olav Haugan

Hi Hiroshi,

Quoted 31 lines · Hiroshi Doyu

Hi Olav,

Quoted 27 lines · Olav Haugan

Mapping and unmapping are more often than not in the critical path. map_range and unmap_range allows SMMU driver implementations to optimize the process of mapping and unmapping buffers into the SMMU page tables. Instead of mapping one physical address, do TLB operation (expensive), mapping, do TLB operation, mapping, do TLB operation the driver can map a scatter-gatherlist of physically contiguous pages into one virtual address space and then at the end do one TLB operation.

Additionally, the mapping operation would be faster in general since clients does not have to keep calling map API over and over again for each physically contiguous chunk of memory that needs to be mapped to a virtually contiguous region.

---
 drivers/iommu/iommu.c | 24 ++++++++++++++++++++++++
 include/linux/iommu.h | 24 ++++++++++++++++++++++++
 2 files changed, 48 insertions(+)
drivers/iommu/iommu.c +0 -0
index e5555fc..f2a6b80 100644
@@ -898,6 +898,30 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
 EXPORT_SYMBOL_GPL(iommu_unmap);
 
 
Quoted 14 lines

drivers/iommu/iommu.c size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) · line 911

Quoted 11 lines
drivers/iommu/iommu.c +11 -0
+int iommu_map_range(struct iommu_domain *domain, unsigned int iova,
+                struct scatterlist *sg, unsigned int len, int prot)
+{
+    if (unlikely(domain->ops->map_range == NULL))
+            return -ENODEV;
+
+    BUG_ON(iova & (~PAGE_MASK));
+
+    return domain->ops->map_range(domain, iova, sg, len, prot);
+}
+EXPORT_SYMBOL_GPL(iommu_map_range);

We have the similar one internally, which is named, "iommu_map_sg()", called from DMA API.

Great, so this new API will be useful to more people!

Quoted 5 lines
Quoted 5 lines
drivers/iommu/iommu.c +5 -0
+int iommu_unmap_range(struct iommu_domain *domain, unsigned int iova,
+                  unsigned int len)
+{
+    if (unlikely(domain->ops->unmap_range == NULL))
+            return -ENODEV;
Quoted 8 lines

drivers/iommu/iommu.c size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) · line 922

Quoted 6 lines
drivers/iommu/iommu.c +6 -0
+
+    BUG_ON(iova & (~PAGE_MASK));
+
+    return domain->ops->unmap_range(domain, iova, len);
+}
+EXPORT_SYMBOL_GPL(iommu_unmap_range);

Can the existing iommu_unmap() do the same?

Quoted 8 lines

I believe iommu_unmap() behaves a bit differently because it will keep on calling domain->ops->unmap() until everything is unmapped instead of letting the iommu implementation take care of unmapping everything in one call.

I am abandoning the patch series since our driver was not accepted. However, if there are no objections I will resubmit this patch (PATCH 2/7) as an independent patch to add this new map_range API.

+1 for map_range().. I've seen for gpu workloads, at least, it is the
downstream map_range() API is quite beneficial. It was worth at
least a few fps in xonotic.

Quoted 5 lines

And, possibly getting off the subject a bit, but I was wondering about the possibility of going one step further and batching up mapping and/or unmapping multiple buffers (ranges) at once. I have a pretty convenient sync point in drm/msm to flush out multiple mappings before kicking gpu.

Quoted 3 lines

I think you should be able to do that with this API already - at least the mapping part since we are passing in a sg list (this could be a chained sglist).

What I mean by batching up is mapping and unmapping multiple sglists each at different iova's with minmal cpu cache and iommu tlb flushes..

Ideally we'd let the IOMMU driver be clever and build out all 2nd level tables before inserting into first level tables (to minimize cpu cache flushing).. also, there is probably a reasonable chance that we'd be mapping a new buffer into existing location, so there might be some potential to reuse existing 2nd level tables (and save a tiny bit of free/alloc). I've not thought too much about how that would look in code.. might be kinda, umm, fun..

But at an API level, we should be able to do a bunch of map/unmap_range's with one flush.

Quoted 6 lines
Quoted 2 lines

Maybe it could look like a sequence of iommu_{map,unmap}_range() followed by iommu_flush()?

Doesn't that mean that the IOMMU driver would have to keep track of all mappings until it sees an iommu_flush()? That sounds like it could be a lot of work and complicated code.

Well, depends on how elaborate you want to get. If you don't want to be too fancy, it may just be a matter of not doing TLB flush until iommu_flush(). If you want to get fancy and minimize cpu flushes too, then iommu driver would have to do some more tracking to build up a transaction internally. I'm not really sure how you avoid that.

I'm not quite sure how frequent it would be that separate buffers touch the same 2nd level table, so it might be sufficient to treat it like N map_range and unmap_range's followed by one TLB flush. I would, I think, need to implement a prototype or at least instrument the iommu driver somehow to generate some statistics.

I've nearly got qcom-iommu-v0 working here on top of upstream + small set of patches.. but once that is a bit more complete, experimenting with some of this will be on my TODO list to see what amount of crazy/complicated brings worthwhile performance benefits.

BR,
-R

Quoted 1 line

Thierry

#13 lore raw

PATCH 2/7 iommu-api: Add map_range/unmap_range functions

In reply to Rob Clark
Quoted 102 lines · Rob Clark
Quoted 86 lines · Olav Haugan
Quoted 79 lines · Rob Clark
Quoted 65 lines · Olav Haugan

Hi Hiroshi,

Quoted 31 lines · Hiroshi Doyu

Hi Olav,

Quoted 27 lines · Olav Haugan

Mapping and unmapping are more often than not in the critical path. map_range and unmap_range allows SMMU driver implementations to optimize the process of mapping and unmapping buffers into the SMMU page tables. Instead of mapping one physical address, do TLB operation (expensive), mapping, do TLB operation, mapping, do TLB operation the driver can map a scatter-gatherlist of physically contiguous pages into one virtual address space and then at the end do one TLB operation.

Additionally, the mapping operation would be faster in general since clients does not have to keep calling map API over and over again for each physically contiguous chunk of memory that needs to be mapped to a virtually contiguous region.

---
 drivers/iommu/iommu.c | 24 ++++++++++++++++++++++++
 include/linux/iommu.h | 24 ++++++++++++++++++++++++
 2 files changed, 48 insertions(+)
drivers/iommu/iommu.c +0 -0
index e5555fc..f2a6b80 100644
@@ -898,6 +898,30 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
 EXPORT_SYMBOL_GPL(iommu_unmap);
 
 
Quoted 14 lines

drivers/iommu/iommu.c size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) · line 911

Quoted 11 lines
drivers/iommu/iommu.c +11 -0
+int iommu_map_range(struct iommu_domain *domain, unsigned int iova,
+                struct scatterlist *sg, unsigned int len, int prot)
+{
+    if (unlikely(domain->ops->map_range == NULL))
+            return -ENODEV;
+
+    BUG_ON(iova & (~PAGE_MASK));
+
+    return domain->ops->map_range(domain, iova, sg, len, prot);
+}
+EXPORT_SYMBOL_GPL(iommu_map_range);

We have the similar one internally, which is named, "iommu_map_sg()", called from DMA API.

Great, so this new API will be useful to more people!

Quoted 5 lines
Quoted 5 lines
drivers/iommu/iommu.c +5 -0
+int iommu_unmap_range(struct iommu_domain *domain, unsigned int iova,
+                  unsigned int len)
+{
+    if (unlikely(domain->ops->unmap_range == NULL))
+            return -ENODEV;
Quoted 8 lines

drivers/iommu/iommu.c size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) · line 923

Quoted 6 lines
drivers/iommu/iommu.c +6 -0
+
+    BUG_ON(iova & (~PAGE_MASK));
+
+    return domain->ops->unmap_range(domain, iova, len);
+}
+EXPORT_SYMBOL_GPL(iommu_unmap_range);

Can the existing iommu_unmap() do the same?

Quoted 8 lines

I believe iommu_unmap() behaves a bit differently because it will keep on calling domain->ops->unmap() until everything is unmapped instead of letting the iommu implementation take care of unmapping everything in one call.

I am abandoning the patch series since our driver was not accepted. However, if there are no objections I will resubmit this patch (PATCH 2/7) as an independent patch to add this new map_range API.

+1 for map_range().. I've seen for gpu workloads, at least, it is the
downstream map_range() API is quite beneficial. It was worth at
least a few fps in xonotic.

Quoted 5 lines

And, possibly getting off the subject a bit, but I was wondering about the possibility of going one step further and batching up mapping and/or unmapping multiple buffers (ranges) at once. I have a pretty convenient sync point in drm/msm to flush out multiple mappings before kicking gpu.

Quoted 3 lines

I think you should be able to do that with this API already - at least the mapping part since we are passing in a sg list (this could be a chained sglist).

What I mean by batching up is mapping and unmapping multiple sglists each at different iova's with minmal cpu cache and iommu tlb flushes..

Ideally we'd let the IOMMU driver be clever and build out all 2nd level tables before inserting into first level tables (to minimize cpu cache flushing).. also, there is probably a reasonable chance that we'd be mapping a new buffer into existing location, so there might be some potential to reuse existing 2nd level tables (and save a tiny bit of free/alloc). I've not thought too much about how that would look in code.. might be kinda, umm, fun..

Quoted 6 lines

But at an API level, we should be able to do a bunch of map/unmap_range's with one flush.

Maybe it could look like a sequence of iommu_{map,unmap}_range() followed by iommu_flush()?

So we could add another argument ("options") in the range api that allows you to indicate whether you want to invalidate TLB or not.

Thanks,

Olav

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#14 lore raw

PATCH 2/7 iommu-api: Add map_range/unmap_range functions

Quoted 106 lines · Olav Haugan
Quoted 105 lines · Rob Clark
Quoted 86 lines · Olav Haugan
Quoted 79 lines · Rob Clark
Quoted 65 lines · Olav Haugan

Hi Hiroshi,

Quoted 31 lines · Hiroshi Doyu

Hi Olav,

Quoted 27 lines · Olav Haugan

Mapping and unmapping are more often than not in the critical path. map_range and unmap_range allows SMMU driver implementations to optimize the process of mapping and unmapping buffers into the SMMU page tables. Instead of mapping one physical address, do TLB operation (expensive), mapping, do TLB operation, mapping, do TLB operation the driver can map a scatter-gatherlist of physically contiguous pages into one virtual address space and then at the end do one TLB operation.

Additionally, the mapping operation would be faster in general since clients does not have to keep calling map API over and over again for each physically contiguous chunk of memory that needs to be mapped to a virtually contiguous region.

---
 drivers/iommu/iommu.c | 24 ++++++++++++++++++++++++
 include/linux/iommu.h | 24 ++++++++++++++++++++++++
 2 files changed, 48 insertions(+)
drivers/iommu/iommu.c +0 -0
index e5555fc..f2a6b80 100644
@@ -898,6 +898,30 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
 EXPORT_SYMBOL_GPL(iommu_unmap);
 
 
Quoted 14 lines

drivers/iommu/iommu.c size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) · line 911

Quoted 11 lines
drivers/iommu/iommu.c +11 -0
+int iommu_map_range(struct iommu_domain *domain, unsigned int iova,
+                struct scatterlist *sg, unsigned int len, int prot)
+{
+    if (unlikely(domain->ops->map_range == NULL))
+            return -ENODEV;
+
+    BUG_ON(iova & (~PAGE_MASK));
+
+    return domain->ops->map_range(domain, iova, sg, len, prot);
+}
+EXPORT_SYMBOL_GPL(iommu_map_range);

We have the similar one internally, which is named, "iommu_map_sg()", called from DMA API.

Great, so this new API will be useful to more people!

Quoted 5 lines
Quoted 5 lines
drivers/iommu/iommu.c +5 -0
+int iommu_unmap_range(struct iommu_domain *domain, unsigned int iova,
+                  unsigned int len)
+{
+    if (unlikely(domain->ops->unmap_range == NULL))
+            return -ENODEV;
Quoted 8 lines

drivers/iommu/iommu.c size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) · line 922

Quoted 6 lines
drivers/iommu/iommu.c +6 -0
+
+    BUG_ON(iova & (~PAGE_MASK));
+
+    return domain->ops->unmap_range(domain, iova, len);
+}
+EXPORT_SYMBOL_GPL(iommu_unmap_range);

Can the existing iommu_unmap() do the same?

Quoted 8 lines

I believe iommu_unmap() behaves a bit differently because it will keep on calling domain->ops->unmap() until everything is unmapped instead of letting the iommu implementation take care of unmapping everything in one call.

I am abandoning the patch series since our driver was not accepted. However, if there are no objections I will resubmit this patch (PATCH 2/7) as an independent patch to add this new map_range API.

+1 for map_range().. I've seen for gpu workloads, at least, it is the
downstream map_range() API is quite beneficial. It was worth at
least a few fps in xonotic.

Quoted 5 lines

And, possibly getting off the subject a bit, but I was wondering about the possibility of going one step further and batching up mapping and/or unmapping multiple buffers (ranges) at once. I have a pretty convenient sync point in drm/msm to flush out multiple mappings before kicking gpu.

Quoted 3 lines

I think you should be able to do that with this API already - at least the mapping part since we are passing in a sg list (this could be a chained sglist).

What I mean by batching up is mapping and unmapping multiple sglists each at different iova's with minmal cpu cache and iommu tlb flushes..

Ideally we'd let the IOMMU driver be clever and build out all 2nd level tables before inserting into first level tables (to minimize cpu cache flushing).. also, there is probably a reasonable chance that we'd be mapping a new buffer into existing location, so there might be some potential to reuse existing 2nd level tables (and save a tiny bit of free/alloc). I've not thought too much about how that would look in code.. might be kinda, umm, fun..

But at an API level, we should be able to do a bunch of map/unmap_range's with one flush.

Quoted 6 lines
Quoted 3 lines

Maybe it could look like a sequence of iommu_{map,unmap}_range() followed by iommu_flush()?

So we could add another argument ("options") in the range api that allows you to indicate whether you want to invalidate TLB or not.

sounds reasonable.. I'm pretty sure we want explict-flush to be an opt-in behaviour.

BR,
-R

Quoted 7 lines

Thanks,

Olav

--
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation

maintainer
#15 lore raw

PATCH 2/7 iommu-api: Add map_range/unmap_range functions

In reply to Olav Haugan
Quoted 13 lines · Olav Haugan
drivers/iommu/iommu.c +13 -0
+int iommu_map_range(struct iommu_domain *domain, unsigned int iova,
+		    struct scatterlist *sg, unsigned int len, int prot)
+{
+	if (unlikely(domain->ops->map_range == NULL))
+		return -ENODEV;
+
+	BUG_ON(iova & (~PAGE_MASK));
+
+	return domain->ops->map_range(domain, iova, sg, len, prot);
+}
+EXPORT_SYMBOL_GPL(iommu_map_range);
+
+int iommu_unmap_range(struct iommu_domain *domain, unsigned int iova,

drivers/iommu/iommu.c size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) · line 923

Quoted 10 lines
drivers/iommu/iommu.c +10 -0
+		      unsigned int len)
+{
+	if (unlikely(domain->ops->unmap_range == NULL))
+		return -ENODEV;
+
+	BUG_ON(iova & (~PAGE_MASK));
+
+	return domain->ops->unmap_range(domain, iova, len);
+}
+EXPORT_SYMBOL_GPL(iommu_unmap_range);

Before introducing these new API functions there should be a fall-back for IOMMU drivers that do (not yet) implement the map_range and unmap_range call-backs.

The last thing we want is this kind of functional partitioning between different IOMMU drivers.

Joerg

#16 lore raw

PATCH 2/7 iommu-api: Add map_range/unmap_range functions

Quoted 29 lines · Joerg Roedel
Quoted 13 lines · Olav Haugan
drivers/iommu/iommu.c +13 -0
+int iommu_map_range(struct iommu_domain *domain, unsigned int iova,
+		    struct scatterlist *sg, unsigned int len, int prot)
+{
+	if (unlikely(domain->ops->map_range == NULL))
+		return -ENODEV;
+
+	BUG_ON(iova & (~PAGE_MASK));
+
+	return domain->ops->map_range(domain, iova, sg, len, prot);
+}
+EXPORT_SYMBOL_GPL(iommu_map_range);
+
+int iommu_unmap_range(struct iommu_domain *domain, unsigned int iova,

drivers/iommu/iommu.c size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size) · line 923

Quoted 10 lines
drivers/iommu/iommu.c +10 -0
+		      unsigned int len)
+{
+	if (unlikely(domain->ops->unmap_range == NULL))
+		return -ENODEV;
+
+	BUG_ON(iova & (~PAGE_MASK));
+
+	return domain->ops->unmap_range(domain, iova, len);
+}
+EXPORT_SYMBOL_GPL(iommu_unmap_range);

Before introducing these new API functions there should be a fall-back for IOMMU drivers that do (not yet) implement the map_range and unmap_range call-backs.

Quoted 2 lines

The last thing we want is this kind of functional partitioning between different IOMMU drivers.

Yes, I can definitely add a fallback instead of returning -ENODEV.

Thanks,

Olav

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#17 lore raw

PATCH 3/7 iopoll: Introduce memory-mapped IO polling macros

In reply to Olav Haugan

From: Matt Wagantall <[email protected]>

It is sometimes necessary to poll a memory-mapped register until its value satisfies some condition. Introduce a family of convenience macros that do this. Tight-loop and sleeping versions are provided with and without timeouts.

---
 include/linux/iopoll.h | 114 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 114 insertions(+)
 create mode 100644 include/linux/iopoll.h
include/linux/iopoll.h new file +114 -0
new file mode 100644
index 0000000..d085e03
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2012-2014 The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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.
+ *
+ */
+
+#ifndef _LINUX_IOPOLL_H
+#define _LINUX_IOPOLL_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/hrtimer.h>
+#include <linux/delay.h>
+#include <asm-generic/errno.h>
+#include <asm/io.h>
+
+/**
+ * readl_poll_timeout - Periodically poll an address until a condition is met or a timeout occurs
+ * @addr: Address to poll
+ * @val: Variable to read the value into
+ * @cond: Break condition (usually involving @val)
+ * @sleep_us: Maximum time to sleep between reads in uS (0 tight-loops)
+ * @timeout_us: Timeout in uS, 0 means never timeout
+ *
+ * Returns 0 on success and -ETIMEDOUT upon a timeout. In either
+ * case, the last read value at @addr is stored in @val. Must not
+ * be called from atomic context if sleep_us or timeout_us are used.
+ */
+#define readl_poll_timeout(addr, val, cond, sleep_us, timeout_us) \
+({ \
+	ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \
+	might_sleep_if(timeout_us); \
+	for (;;) { \
+		(val) = readl(addr); \
+		if (cond) \
+			break; \
+		if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) { \
+			(val) = readl(addr); \
+			break; \
+		} \
+		if (sleep_us) \
+			usleep_range(DIV_ROUND_UP(sleep_us, 4), sleep_us); \
+	} \
+	(cond) ? 0 : -ETIMEDOUT; \
+})
+
+/**
+ * readl_poll_timeout_noirq - Periodically poll an address until a condition is met or a timeout occurs
+ * @addr: Address to poll
+ * @val: Variable to read the value into
+ * @cond: Break condition (usually involving @val)
+ * @max_reads: Maximum number of reads before giving up
+ * @time_between_us: Time to udelay() between successive reads
+ *
+ * Returns 0 on success and -ETIMEDOUT upon a timeout.
+ */
+#define readl_poll_timeout_noirq(addr, val, cond, max_reads, time_between_us) \
+({ \
+	int count; \
+	for (count = (max_reads); count > 0; count--) { \
+		(val) = readl(addr); \
+		if (cond) \
+			break; \
+		udelay(time_between_us); \
+	} \
+	(cond) ? 0 : -ETIMEDOUT; \
+})
+
+/**
+ * readl_poll - Periodically poll an address until a condition is met
+ * @addr: Address to poll
+ * @val: Variable to read the value into
+ * @cond: Break condition (usually involving @val)
+ * @sleep_us: Maximum time to sleep between reads in uS (0 tight-loops)
+ *
+ * Must not be called from atomic context if sleep_us is used.
+ */
+#define readl_poll(addr, val, cond, sleep_us) \
+	readl_poll_timeout(addr, val, cond, sleep_us, 0)
+
+/**
+ * readl_tight_poll_timeout - Tight-loop on an address until a condition is met or a timeout occurs
+ * @addr: Address to poll
+ * @val: Variable to read the value into
+ * @cond: Break condition (usually involving @val)
+ * @timeout_us: Timeout in uS, 0 means never timeout
+ *
+ * Returns 0 on success and -ETIMEDOUT upon a timeout. In either
+ * case, the last read value at @addr is stored in @val. Must not
+ * be called from atomic context if timeout_us is used.
+ */
+#define readl_tight_poll_timeout(addr, val, cond, timeout_us) \
+	readl_poll_timeout(addr, val, cond, 0, timeout_us)
+
+/**
+ * readl_tight_poll - Tight-loop on an address until a condition is met
+ * @addr: Address to poll
+ * @val: Variable to read the value into
+ * @cond: Break condition (usually involving @val)
+ *
+ * May be called from atomic context.
+ */
+#define readl_tight_poll(addr, val, cond) \
+	readl_poll_timeout(addr, val, cond, 0, 0)
+
+#endif /* _LINUX_IOPOLL_H */
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#18 lore raw

PATCH 3/7 iopoll: Introduce memory-mapped IO polling macros

On Mon, Jun 30, 2014 at 09:51:52AM -0700, Olav Haugan wrote:
[...]

Quoted 1 line
include/linux/iopoll.h +0 -0

[...]

Quoted 6 lines

+/**
+ * readl_poll_timeout - Periodically poll an address until a condition is met or a timeout occurs
+ * @addr: Address to poll
+ * @val: Variable to read the value into
+ * @cond: Break condition (usually involving @val)
+ * @sleep_us: Maximum time to sleep between reads in uS (0 tight-loops)

s/uS/us/ here and elsewhere. S is the symbol for Siemens.

Quoted 13 lines

+ * @timeout_us: Timeout in uS, 0 means never timeout
+ *
+ * Returns 0 on success and -ETIMEDOUT upon a timeout. In either
+ * case, the last read value at @addr is stored in @val. Must not
+ * be called from atomic context if sleep_us or timeout_us are used.
+ */

include/linux/iopoll.h +7 -0
+#define readl_poll_timeout(addr, val, cond, sleep_us, timeout_us) \
+({ \
+	ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \
+	might_sleep_if(timeout_us); \
+	for (;;) { \
+		(val) = readl(addr); \
+		if (cond) \

include/linux/iopoll.h line 53

Quoted 10 lines
include/linux/iopoll.h +10 -0
+			break; \
+		if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) { \
+			(val) = readl(addr); \
+			break; \
+		} \
+		if (sleep_us) \
+			usleep_range(DIV_ROUND_UP(sleep_us, 4), sleep_us); \
+	} \
+	(cond) ? 0 : -ETIMEDOUT; \
+})

Why can't these be functions?

Thierry
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20140630/67f196b9/attachment.sig>

#19 lore raw

PATCH 3/7 iopoll: Introduce memory-mapped IO polling macros

In reply to Olav Haugan

Hi Matt,

Quoted 6 lines · Olav Haugan

From: Matt Wagantall <[email protected]>

It is sometimes necessary to poll a memory-mapped register until its value satisfies some condition. Introduce a family of convenience macros that do this. Tight-loop and sleeping versions are provided with and without timeouts.

We could certainly use something like this in the SMMU and GICv3 drivers, so I agree that it makes sense for this to be in generic code.

Quoted 7 lines

+/**
+ * readl_poll_timeout - Periodically poll an address until a condition is met or a timeout occurs
+ * @addr: Address to poll
+ * @val: Variable to read the value into
+ * @cond: Break condition (usually involving @val)
+ * @sleep_us: Maximum time to sleep between reads in uS (0 tight-loops)
+ * @timeout_us: Timeout in uS, 0 means never timeout

I think 0 should actually mean `use the default timeout', which could be something daft like 1s. Removing the timeout is asking for kernel lock-ups. We could also have a version without the timeout parameter at all, which acts like a timeout of 0.

Quoted 19 lines

+ *
+ * Returns 0 on success and -ETIMEDOUT upon a timeout. In either
+ * case, the last read value at @addr is stored in @val. Must not
+ * be called from atomic context if sleep_us or timeout_us are used.
+ */

include/linux/iopoll.h new file +14 -0
+#define readl_poll_timeout(addr, val, cond, sleep_us, timeout_us) \
+({ \
+	ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \
+	might_sleep_if(timeout_us); \
+	for (;;) { \
+		(val) = readl(addr); \
+		if (cond) \
+			break; \
+		if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) { \
+			(val) = readl(addr); \
+			break; \
+		} \
+		if (sleep_us) \
+			usleep_range(DIV_ROUND_UP(sleep_us, 4), sleep_us); \

include/linux/iopoll.h line 60

Quoted 10 lines
include/linux/iopoll.h new file +10 -0
+	} \
+	(cond) ? 0 : -ETIMEDOUT; \
+})
+
+/**
+ * readl_poll_timeout_noirq - Periodically poll an address until a condition is met or a timeout occurs
+ * @addr: Address to poll
+ * @val: Variable to read the value into
+ * @cond: Break condition (usually involving @val)
+ * @max_reads: Maximum number of reads before giving up

I don't think max_reads is a useful tunable.

Quoted 5 lines

+ * @time_between_us: Time to udelay() between successive reads
+ *
+ * Returns 0 on success and -ETIMEDOUT upon a timeout.
+ */
+#define readl_poll_timeout_noirq(addr, val, cond, max_reads, time_between_us) \

Maybe readl_poll_[timeout_]atomic is a better name?

Quoted 12 lines
include/linux/iopoll.h new file +12 -0
+({ \
+	int count; \
+	for (count = (max_reads); count > 0; count--) { \
+		(val) = readl(addr); \
+		if (cond) \
+			break; \
+		udelay(time_between_us); \
+	} \
+	(cond) ? 0 : -ETIMEDOUT; \
+})
+
+/**

include/linux/iopoll.h line 87

Quoted 10 lines
include/linux/iopoll.h new file +10 -0
+ * readl_poll - Periodically poll an address until a condition is met
+ * @addr: Address to poll
+ * @val: Variable to read the value into
+ * @cond: Break condition (usually involving @val)
+ * @sleep_us: Maximum time to sleep between reads in uS (0 tight-loops)
+ *
+ * Must not be called from atomic context if sleep_us is used.
+ */
+#define readl_poll(addr, val, cond, sleep_us) \
+	readl_poll_timeout(addr, val, cond, sleep_us, 0)

Good idea ;)

Quoted 14 lines
include/linux/iopoll.h new file +14 -0
+/**
+ * readl_tight_poll_timeout - Tight-loop on an address until a condition is met or a timeout occurs
+ * @addr: Address to poll
+ * @val: Variable to read the value into
+ * @cond: Break condition (usually involving @val)
+ * @timeout_us: Timeout in uS, 0 means never timeout
+ *
+ * Returns 0 on success and -ETIMEDOUT upon a timeout. In either
+ * case, the last read value at @addr is stored in @val. Must not
+ * be called from atomic context if timeout_us is used.
+ */
+#define readl_tight_poll_timeout(addr, val, cond, timeout_us) \
+	readl_poll_timeout(addr, val, cond, 0, timeout_us)
+

include/linux/iopoll.h line 112

Quoted 10 lines
include/linux/iopoll.h new file +10 -0
+/**
+ * readl_tight_poll - Tight-loop on an address until a condition is met
+ * @addr: Address to poll
+ * @val: Variable to read the value into
+ * @cond: Break condition (usually involving @val)
+ *
+ * May be called from atomic context.
+ */
+#define readl_tight_poll(addr, val, cond) \
+	readl_poll_timeout(addr, val, cond, 0, 0)

This would be readl_poll_timeout_atomic if you went with my suggestion (i.e. readl_poll_timeout would have an unconditional might_sleep).

What do you reckon?

Will

A message that is not in the archive (sent off-list or not yet received): 1404147116-4598-1-git-send-email-ohaugan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org

#21 lore raw

PATCH 4/7 iommu: msm: Add MSM IOMMUv1 driver

MSM IOMMUv1 driver supports Qualcomm SoC MSM8974 and MSM8084.

The IOMMU driver supports the following features:

- ARM V7S page table format independent of ARM CPU page table format
- 4K/64K/1M/16M mappings (V7S)
- ATOS used for unit testing of driver
- Sharing of page tables among SMMUs
- Verbose context bank fault reporting
- Verbose global fault reporting
- Support for clocks and GDSC
- map/unmap range
- Domain specific enabling of coherent Hardware Table Walk (HTW)

---
 .../devicetree/bindings/iommu/msm,iommu_v1.txt     |   56 +
 drivers/iommu/Kconfig                              |   36 +
 drivers/iommu/Makefile                             |    2 +
 drivers/iommu/msm_iommu-v1.c                       | 1448 +++++++++++++
 drivers/iommu/msm_iommu.c                          |  149 ++
 drivers/iommu/msm_iommu_dev-v1.c                   |  340 +++
 drivers/iommu/msm_iommu_hw-v1.h                    | 2236 ++++++++++++++++++++
 drivers/iommu/msm_iommu_pagetable.c                |  600 ++++++
 drivers/iommu/msm_iommu_pagetable.h                |   33 +
 drivers/iommu/msm_iommu_priv.h                     |   55 +
 include/linux/qcom_iommu.h                         |  221 ++
 11 files changed, 5176 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iommu/msm,iommu_v1.txt
 create mode 100644 drivers/iommu/msm_iommu-v1.c
 create mode 100644 drivers/iommu/msm_iommu.c
 create mode 100644 drivers/iommu/msm_iommu_dev-v1.c
 create mode 100644 drivers/iommu/msm_iommu_hw-v1.h
 create mode 100644 drivers/iommu/msm_iommu_pagetable.c
 create mode 100644 drivers/iommu/msm_iommu_pagetable.h
 create mode 100644 drivers/iommu/msm_iommu_priv.h
 create mode 100644 include/linux/qcom_iommu.h
Documentation/devicetree/bindings/iommu/msm,iommu_v1.txt new file +56 -0
new file mode 100644
index 0000000..412ed44
@@ -0,0 +1,56 @@
+* Qualcomm MSM IOMMU v1
+
+Required properties:
+- compatible :
+	- "qcom,msm-smmu-v1"
+- reg : - offset and length of the register set for the device.
+	- Optional offset and length for clock halt register that
+	  needs to be turned on for access to this IOMMU.
+- reg-names: "iommu_base", "clk_halt_reg_base" (optional)
+- #global-interrupts : The number of global interrupts exposed by the
+                       device.
+- interrupts    : Interrupt list, with the first #global-irqs entries
+                  corresponding to the global interrupts and any
+                  following entries corresponding to context interrupts,
+                  specified in order of their indexing by the SMMU.
+
+Optional properties:
+- label: Symbolic name for this IOMMU instance used for debugging purposes.
+  For example when a page fault occurs on the jpeg iommu the text
+  "jpeg_iommu" will be printed letting people know which IOMMU is complaining.
+- qcom,vdd-supply: Regulator needed to access IOMMU
+- qcom,alt-vdd-supply : Alternative regulator needed to access IOMMU
+  configuration registers.
+- qcom,iommu-bfb-regs : An array of unsigned 32-bit integers corresponding to
+  Burst Fetch Buffers (BFB) register addresses that need to be configured
+  for performance tuning purposes. BFB holds cached values of TLB/PTE entries
+  in the SMMU. BFB registers controls the configuration of the TLB/PTE fetching
+  mechanism in the SMMU. In general these values comes from performance
+  modelling team.
+  If this property is present, the qcom,iommu-bfb-data must also be
+  present. Register addresses are specified as an offset from the base of the
+  IOMMU hardware block. This property may be omitted if no BFB register
+  configuration needs to be done for a particular IOMMU hardware instance. The
+  registers specified by this property shall fall within the IOMMU
+  implementation-defined register region.
+- qcom,iommu-bfb-data : An array of unsigned 32-bit integers representing the
+  values to be programmed into the corresponding registers given by the
+  qcom,iommu-bfb-regs property. If this property is present, the
+  qcom,iommu-bfb-regs property shall also be present, and the lengths of both
+  properties shall be the same.
+
+Example:
+
+	qcom,iommu@fda64000 {
+		compatible = "qcom,msm-smmu-v1";
+		reg = <0xfda64000 0x10000>;
+		reg-names = "iommu_base";
+		vdd-supply = <&gdsc_iommu>;
+		qcom,iommu-bfb-regs = <0x204c 0x2050>;
+		qcom,iommu-bfb-data = <0xffff 0xffce>;
+		label = "iommu_0";
+		#global-interrupts = <2>;
+		interrupts = <0 229 0>,
+			     <0 231 0>,
+			     <0 70 0>;
+	};
drivers/iommu/Kconfig +36 -0
index 705a257..e972127 100644
@@ -50,6 +50,42 @@ config IOMMU_PGTABLES_L2
 	def_bool y
 	depends on MSM_IOMMU && MMU && SMP && CPU_DCACHE_DISABLE=n
 
+# MSM IOMMUv1 support
+config MSM_IOMMU_V1
+	bool "MSM IOMMUv1 Support"
+	depends on ARCH_MSM8974 || ARCH_MSM8226 || ARCH_APQ8084 || ARCH_MSM8994
+	select IOMMU_API
+	select MSM_IOMMU
+	help
+	  Support for the IOMMUs (v1) found on certain Qualcomm SOCs.
+	  These IOMMUs allow virtualization of the address space used by most
+	  cores within the multimedia subsystem.
+
+	  If unsure, say N here.
+
+config MSM_IOMMU_VBIF_CHECK
+	bool "Enable support for VBIF check when IOMMU gets stuck"
+	depends on MSM_IOMMU
+	help
+	  Utilize the Virtual Bus Interface (VBIF) to get more debug
+	  information. Enables an extra check in the IOMMU driver that logs
+	  debugging information when TLB sync or iommu halt issue occurs.
+	  This helps in debugging such issues.
+
+	  If unsure, say N here.
+
+config IOMMU_FORCE_4K_MAPPINGS
+	bool "Turns off mapping optimization and map only 4K pages"
+	depends on MSM_IOMMU
+        help
+         Say Y here if you want the IOMMU driver to map buffers with
+         4KB mapping only. With this, we don't get performance gains
+         by optimizing mapping. This is a debug feature and should be
+         used only when we want to profile the performance in the
+         worst case scenario.
+
+         If unsure, say N here.
+
 # AMD IOMMU support
 config AMD_IOMMU
 	bool "AMD IOMMU support"
drivers/iommu/Makefile +2 -0
index 894ced9..1f98fcc 100644
@@ -2,6 +2,8 @@ obj-$(CONFIG_IOMMU_API) += iommu.o
 obj-$(CONFIG_IOMMU_API) += iommu-traces.o
 obj-$(CONFIG_OF_IOMMU)	+= of_iommu.o
 obj-$(CONFIG_MSM_IOMMU_V0) += msm_iommu-v0.o msm_iommu_dev-v0.o
+obj-$(CONFIG_MSM_IOMMU_V1) += msm_iommu-v1.o msm_iommu_dev-v1.o msm_iommu.o
+obj-$(CONFIG_MSM_IOMMU_V1) += msm_iommu_pagetable.o
 obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
 obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o
 obj-$(CONFIG_ARM_SMMU) += arm-smmu.o
drivers/iommu/msm_iommu-v1.c new file +1448 -0

1,448 lines not on this page · raw message

drivers/iommu/msm_iommu.c new file +149 -0

149 lines not on this page · raw message

drivers/iommu/msm_iommu_dev-v1.c new file +340 -0

340 lines not on this page · raw message

drivers/iommu/msm_iommu_hw-v1.h new file +2236 -0

957 lines not on this page · raw message

drivers/iommu/msm_iommu_pagetable.c new file +600 -0

600 lines not on this page · raw message

drivers/iommu/msm_iommu_pagetable.h new file +33 -0
new file mode 100644
index 0000000..12a8d27

Lines of this file are not shown. View the raw message.

drivers/iommu/msm_iommu_priv.h new file +55 -0

55 lines not on this page · raw message

include/linux/qcom_iommu.h new file +221 -0

221 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation

Part of the diff is not shown here. View the raw message.

#22 lore raw

PATCH 4/7 iommu: msm: Add MSM IOMMUv1 driver

Hi Olav,

Quoted 16 lines · Olav Haugan

MSM IOMMUv1 driver supports Qualcomm SoC MSM8974 and MSM8084.

The IOMMU driver supports the following features:

- ARM V7S page table format independent of ARM CPU page table format
- 4K/64K/1M/16M mappings (V7S)
- ATOS used for unit testing of driver
- Sharing of page tables among SMMUs
- Verbose context bank fault reporting
- Verbose global fault reporting
- Support for clocks and GDSC
- map/unmap range
- Domain specific enabling of coherent Hardware Table Walk (HTW)

Quoted 13 lines
---
 .../devicetree/bindings/iommu/msm,iommu_v1.txt     |   56 +
 drivers/iommu/Kconfig                              |   36 +
 drivers/iommu/Makefile                             |    2 +
 drivers/iommu/msm_iommu-v1.c                       | 1448 +++++++++++++
 drivers/iommu/msm_iommu.c                          |  149 ++
 drivers/iommu/msm_iommu_dev-v1.c                   |  340 +++
 drivers/iommu/msm_iommu_hw-v1.h                    | 2236 ++++++++++++++++++++
 drivers/iommu/msm_iommu_pagetable.c                |  600 ++++++
 drivers/iommu/msm_iommu_pagetable.h                |   33 +
 drivers/iommu/msm_iommu_priv.h                     |   55 +
 include/linux/qcom_iommu.h                         |  221 ++
 11 files changed, 5176 insertions(+)

This patch is *huge*! It may get bounced from some lists (I think the linux-arm-kernel lists has a ~100k limit), so it might be worth trying to do this incrementally.

That said, a quick glance at your code indicates that this IOMMU is compliant with the ARM SMMU architecture, and we already have a driver for that. Please can you rework this series to build on top of the code in mainline already, rather than simply duplicating it? We need fewer IOMMU drivers, not more!

It's also worth talking to Varun Sethi, as he was already looking at implementing block mappings in the existing driver.

Thanks,

Will

#23 lore raw

PATCH 4/7 iommu: msm: Add MSM IOMMUv1 driver

Quoted 33 lines · Will Deacon

Hi Olav,

Quoted 16 lines · Olav Haugan

MSM IOMMUv1 driver supports Qualcomm SoC MSM8974 and MSM8084.

The IOMMU driver supports the following features:

- ARM V7S page table format independent of ARM CPU page table format
- 4K/64K/1M/16M mappings (V7S)
- ATOS used for unit testing of driver
- Sharing of page tables among SMMUs
- Verbose context bank fault reporting
- Verbose global fault reporting
- Support for clocks and GDSC
- map/unmap range
- Domain specific enabling of coherent Hardware Table Walk (HTW)

Quoted 13 lines
---
 .../devicetree/bindings/iommu/msm,iommu_v1.txt     |   56 +
 drivers/iommu/Kconfig                              |   36 +
 drivers/iommu/Makefile                             |    2 +
 drivers/iommu/msm_iommu-v1.c                       | 1448 +++++++++++++
 drivers/iommu/msm_iommu.c                          |  149 ++
 drivers/iommu/msm_iommu_dev-v1.c                   |  340 +++
 drivers/iommu/msm_iommu_hw-v1.h                    | 2236 ++++++++++++++++++++
 drivers/iommu/msm_iommu_pagetable.c                |  600 ++++++
 drivers/iommu/msm_iommu_pagetable.h                |   33 +
 drivers/iommu/msm_iommu_priv.h                     |   55 +
 include/linux/qcom_iommu.h                         |  221 ++
 11 files changed, 5176 insertions(+)
Quoted 3 lines

This patch is *huge*! It may get bounced from some lists (I think the linux-arm-kernel lists has a ~100k limit), so it might be worth trying to do this incrementally.

Yes, I noticed. Sorry about that.

Quoted 5 lines

That said, a quick glance at your code indicates that this IOMMU is compliant with the ARM SMMU architecture, and we already have a driver for that. Please can you rework this series to build on top of the code in mainline already, rather than simply duplicating it? We need fewer IOMMU drivers, not more!

Ok, I will rework.

Thanks,

Olav Haugan

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#24 lore raw

PATCH 5/7 iommu: msm: Add support for V7L page table format

In reply to Olav Haugan

Add support for VMSA long descriptor page table format (V7L) supporting the following features:

- ARM V7L page table format independent of ARM CPU page table format
- 4K/64K/2M/32M/1G mappings (V7L)

---
 .../devicetree/bindings/iommu/msm,iommu_v1.txt     |   4 +
 drivers/iommu/Kconfig                              |  10 +
 drivers/iommu/Makefile                             |   4 +
 drivers/iommu/msm_iommu-v1.c                       |  65 ++
 drivers/iommu/msm_iommu.c                          |  47 ++
 drivers/iommu/msm_iommu_dev-v1.c                   |   5 +
 drivers/iommu/msm_iommu_hw-v1.h                    |  86 +++
 drivers/iommu/msm_iommu_pagetable_lpae.c           | 717 +++++++++++++++++++++
 drivers/iommu/msm_iommu_priv.h                     |  12 +-
 9 files changed, 949 insertions(+), 1 deletion(-)
 create mode 100644 drivers/iommu/msm_iommu_pagetable_lpae.c
Documentation/devicetree/bindings/iommu/msm,iommu_v1.txt +4 -0
index 412ed44..c0a8f6c 100644
@@ -38,6 +38,10 @@ Optional properties:
   qcom,iommu-bfb-regs property. If this property is present, the
   qcom,iommu-bfb-regs property shall also be present, and the lengths of both
   properties shall be the same.
+- qcom,iommu-lpae-bfb-regs : See description for qcom,iommu-bfb-regs. This is
+  the same property except this is for IOMMU with LPAE enabled.
+- qcom,iommu-lpae-bfb-data : See description for qcom,iommu-bfb-data. This is
+  the same property except this is for IOMMU with LPAE enabled.
 
 Example:
 
drivers/iommu/Kconfig +10 -0
index e972127..9053908 100644
@@ -63,6 +63,16 @@ config MSM_IOMMU_V1
 
 	  If unsure, say N here.
 
+config MSM_IOMMU_LPAE
+	bool "Enable support for LPAE in IOMMU"
+	depends on MSM_IOMMU
+	help
+	  Enables Large Physical Address Extension (LPAE) for IOMMU. This allows
+	  clients of IOMMU to access physical addresses that are greater than
+	  32 bits.
+
+	  If unsure, say N here.
+
 config MSM_IOMMU_VBIF_CHECK
 	bool "Enable support for VBIF check when IOMMU gets stuck"
 	depends on MSM_IOMMU
drivers/iommu/Makefile +4 -0
index 1f98fcc..debb251 100644
@@ -3,7 +3,11 @@ obj-$(CONFIG_IOMMU_API) += iommu-traces.o
 obj-$(CONFIG_OF_IOMMU)	+= of_iommu.o
 obj-$(CONFIG_MSM_IOMMU_V0) += msm_iommu-v0.o msm_iommu_dev-v0.o
 obj-$(CONFIG_MSM_IOMMU_V1) += msm_iommu-v1.o msm_iommu_dev-v1.o msm_iommu.o
+ifdef CONFIG_MSM_IOMMU_LPAE
+obj-$(CONFIG_MSM_IOMMU_V1) += msm_iommu_pagetable_lpae.o
+else
 obj-$(CONFIG_MSM_IOMMU_V1) += msm_iommu_pagetable.o
+endif
 obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
 obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o
 obj-$(CONFIG_ARM_SMMU) += arm-smmu.o
drivers/iommu/msm_iommu-v1.c +65 -0

119 lines not on this page · raw message

drivers/iommu/msm_iommu.c +47 -0

66 lines not on this page · raw message

drivers/iommu/msm_iommu_dev-v1.c +5 -0
index c1fa732..30f6b07 100644
@@ -28,8 +28,13 @@
 
 #include "msm_iommu_hw-v1.h"
 
+#ifdef CONFIG_MSM_IOMMU_LPAE
+static const char *BFB_REG_NODE_NAME = "qcom,iommu-lpae-bfb-regs";
+static const char *BFB_DATA_NODE_NAME = "qcom,iommu-lpae-bfb-data";
+#else
 static const char *BFB_REG_NODE_NAME = "qcom,iommu-bfb-regs";
 static const char *BFB_DATA_NODE_NAME = "qcom,iommu-bfb-data";
+#endif
 
 static int msm_iommu_parse_bfb_settings(struct platform_device *pdev,
 				    struct msm_iommu_drvdata *drvdata)
drivers/iommu/msm_iommu_hw-v1.h +86 -0

139 lines not on this page · raw message

drivers/iommu/msm_iommu_pagetable_lpae.c new file +717 -0

717 lines not on this page · raw message

drivers/iommu/msm_iommu_priv.h +11 -1
index 031e6b4..1064d89 100644
@@ -31,13 +31,23 @@
  * clients trying to unmap an address that is being used.
  * fl_table_shadow will use the lower 9 bits for the use count and the upper
  * bits for the second level page table address.
+ * sl_table_shadow uses the same concept as fl_table_shadow but for LPAE 2nd
+ * level page tables.
  */
+#ifdef CONFIG_MSM_IOMMU_LPAE
+struct msm_iommu_pt {
+	u64 *fl_table;
+	u64 **sl_table_shadow;
+	int redirect;
+	u64 *unaligned_fl_table;
+};
+#else
 struct msm_iommu_pt {
 	u32 *fl_table;
 	int redirect;
 	u32 *fl_table_shadow;
 };
-
+#endif
 /**
  * struct msm_iommu_priv - Container for page table attributes and other
  * private iommu domain information.
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#25 lore raw

PATCH 6/7 defconfig: msm: Enable Qualcomm SMMUv1 driver

In reply to Olav Haugan

Enable the Qualcomm SMMUv1 driver allowing bus masters to operate on physically discontigous memory.

---
 arch/arm/configs/qcom_defconfig | 1 +
 1 file changed, 1 insertion(+)
arch/arm/configs/qcom_defconfig +1 -0
index 0414889..12838bb 100644
@@ -137,6 +137,7 @@ CONFIG_MSM_GCC_8660=y
 CONFIG_MSM_MMCC_8960=y
 CONFIG_MSM_MMCC_8974=y
 CONFIG_MSM_IOMMU_V0=y
+CONFIG_MSM_IOMMU_V1=y
 CONFIG_GENERIC_PHY=y
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#26 lore raw

PATCH 7/7 iommu-api: Add domain attribute to enable coherent HTW

In reply to Olav Haugan

Add a new iommu domain attribute that can be used to enable cache coherent hardware table walks (HTW) by the SMMU. HTW might be supported by the SMMU HW but depending on the use case and the usage of the SMMU in the SoC it might not be always beneficial to always turn on coherent HTW for all domains/iommu's.

---
 drivers/iommu/msm_iommu-v1.c | 16 ++++++++++++++++
 include/linux/iommu.h        |  1 +
 2 files changed, 17 insertions(+)
drivers/iommu/msm_iommu-v1.c +16 -0
index 2c574ef..e163ffc 100644
@@ -1456,8 +1456,16 @@ static int msm_domain_get_attr(struct iommu_domain *domain,
 			       enum iommu_attr attr, void *data)
 {
 	s32 ret = 0;
+	struct msm_iommu_priv *priv = domain->priv;
 
 	switch (attr) {
+	case DOMAIN_ATTR_COHERENT_HTW:
+	{
+		s32 *int_ptr = (s32 *) data;
+
+		*int_ptr = priv->pt.redirect;
+		break;
+	}
 	default:
 		pr_err("Unsupported attribute type\n");
 		ret = -EINVAL;
@@ -1471,8 +1479,16 @@ static int msm_domain_set_attr(struct iommu_domain *domain,
 			       enum iommu_attr attr, void *data)
 {
 	s32 ret = 0;
+	struct msm_iommu_priv *priv = domain->priv;
 
 	switch (attr) {
+	case DOMAIN_ATTR_COHERENT_HTW:
+	{
+		s32 *int_ptr = (s32 *) data;
+
+		priv->pt.redirect = *int_ptr;
+		break;
+	}
 	default:
 		pr_err("Unsupported attribute type\n");
 		ret = -EINVAL;
include/linux/iommu.h +1 -0
index 63dca6d..6d9596d 100644
@@ -81,6 +81,7 @@ enum iommu_attr {
 	DOMAIN_ATTR_FSL_PAMU_STASH,
 	DOMAIN_ATTR_FSL_PAMU_ENABLE,
 	DOMAIN_ATTR_FSL_PAMUV1,
+	DOMAIN_ATTR_COHERENT_HTW,
 	DOMAIN_ATTR_MAX,
 };
 
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#27 lore raw

PATCH 7/7 iommu-api: Add domain attribute to enable coherent HTW

Quoted 13 lines

-----Original Message-----
From: iommu-bounces at lists.linux-foundation.org [mailto:iommu- bounces at lists.linux-foundation.org] On Behalf Of Olav Haugan
Sent: Monday, June 30, 2014 10:22 PM
To: linux-arm-kernel at lists.infradead.org; iommu at lists.linux- foundation.org
Cc: linux-arm-msm at vger.kernel.org; will.deacon at arm.com; thierry.reding at gmail.com; vgandhi at codeaurora.org
Subject: [RFC/PATCH 7/7] iommu-api: Add domain attribute to enable coherent HTW

Quoted 6 lines

Add a new iommu domain attribute that can be used to enable cache coherent hardware table walks (HTW) by the SMMU. HTW might be supported by the SMMU HW but depending on the use case and the usage of the SMMU in the SoC it might not be always beneficial to always turn on coherent HTW for all domains/iommu's.

[Sethi Varun-B16395] Why won't you want to use the coherent table walk feature?

Quoted 49 lines
---
 drivers/iommu/msm_iommu-v1.c | 16 ++++++++++++++++
 include/linux/iommu.h        |  1 +
 2 files changed, 17 insertions(+)
drivers/iommu/msm_iommu-v1.c +16 -0
index 2c574ef..e163ffc 100644
@@ -1456,8 +1456,16 @@ static int msm_domain_get_attr(struct iommu_domain
 *domain,
 			       enum iommu_attr attr, void *data)  {
 	s32 ret = 0;
+	struct msm_iommu_priv *priv = domain->priv;
 
 	switch (attr) {
+	case DOMAIN_ATTR_COHERENT_HTW:
+	{
+		s32 *int_ptr = (s32 *) data;
+
+		*int_ptr = priv->pt.redirect;
+		break;
+	}
 	default:
 		pr_err("Unsupported attribute type\n");
 		ret = -EINVAL;
@@ -1471,8 +1479,16 @@ static int msm_domain_set_attr(struct iommu_domain
 *domain,
 			       enum iommu_attr attr, void *data)  {
 	s32 ret = 0;
+	struct msm_iommu_priv *priv = domain->priv;
 
 	switch (attr) {
+	case DOMAIN_ATTR_COHERENT_HTW:
+	{
+		s32 *int_ptr = (s32 *) data;
+
+		priv->pt.redirect = *int_ptr;
+		break;
+	}
 	default:
 		pr_err("Unsupported attribute type\n");
 		ret = -EINVAL;
include/linux/iommu.h index renamed from include/linux/iommu.h +0 -0

63dca6d..6d9596d 100644

include/linux/iommu.h enum iommu_attr { · line 84

Quoted 4 lines
include/linux/iommu.h +1 -0
@@ -81,6 +81,7 @@ enum iommu_attr {
 	DOMAIN_ATTR_FSL_PAMU_STASH,
 	DOMAIN_ATTR_FSL_PAMU_ENABLE,
 	DOMAIN_ATTR_FSL_PAMUV1,
+	DOMAIN_ATTR_COHERENT_HTW,

[Sethi Varun-B16395] Would it make sense to represent this as DOMAIN_ATTR_SMMU_COHERENT_HTW? I believe this is specific to SMMU.

-Varun

#28 lore raw

PATCH 7/7 iommu-api: Add domain attribute to enable coherent HTW

Quoted 13 lines · Varun Sethi
Quoted 13 lines

-----Original Message-----
From: iommu-bounces at lists.linux-foundation.org [mailto:iommu- bounces at lists.linux-foundation.org] On Behalf Of Olav Haugan
Sent: Monday, June 30, 2014 10:22 PM
To: linux-arm-kernel at lists.infradead.org; iommu at lists.linux- foundation.org
Cc: linux-arm-msm at vger.kernel.org; will.deacon at arm.com; thierry.reding at gmail.com; vgandhi at codeaurora.org
Subject: [RFC/PATCH 7/7] iommu-api: Add domain attribute to enable coherent HTW

Quoted 7 lines
Quoted 6 lines

Add a new iommu domain attribute that can be used to enable cache coherent hardware table walks (HTW) by the SMMU. HTW might be supported by the SMMU HW but depending on the use case and the usage of the SMMU in the SoC it might not be always beneficial to always turn on coherent HTW for all domains/iommu's.

[Sethi Varun-B16395] Why won't you want to use the coherent table walk feature?

Very good question. We have found that turning on IOMMU coherent HTW is not always beneficial to performance (performance either the same or slightly worse in some cases). Even if the perf. is the same we would like to avoid using precious L2 cache for no benefit to the IOMMU. Although our HW supports this feature we don't always want to turn this on for a specific use case/domain (bus master).

Quoted 46 lines
Quoted 46 lines
---
 drivers/iommu/msm_iommu-v1.c | 16 ++++++++++++++++
 include/linux/iommu.h        |  1 +
 2 files changed, 17 insertions(+)
drivers/iommu/msm_iommu-v1.c +16 -0
index 2c574ef..e163ffc 100644
@@ -1456,8 +1456,16 @@ static int msm_domain_get_attr(struct iommu_domain
 *domain,
 			       enum iommu_attr attr, void *data)  {
 	s32 ret = 0;
+	struct msm_iommu_priv *priv = domain->priv;
 
 	switch (attr) {
+	case DOMAIN_ATTR_COHERENT_HTW:
+	{
+		s32 *int_ptr = (s32 *) data;
+
+		*int_ptr = priv->pt.redirect;
+		break;
+	}
 	default:
 		pr_err("Unsupported attribute type\n");
 		ret = -EINVAL;
@@ -1471,8 +1479,16 @@ static int msm_domain_set_attr(struct iommu_domain
 *domain,
 			       enum iommu_attr attr, void *data)  {
 	s32 ret = 0;
+	struct msm_iommu_priv *priv = domain->priv;
 
 	switch (attr) {
+	case DOMAIN_ATTR_COHERENT_HTW:
+	{
+		s32 *int_ptr = (s32 *) data;
+
+		priv->pt.redirect = *int_ptr;
+		break;
+	}
 	default:
 		pr_err("Unsupported attribute type\n");
 		ret = -EINVAL;
include/linux/iommu.h index renamed from include/linux/iommu.h +0 -0

63dca6d..6d9596d 100644

Quoted 8 lines

include/linux/iommu.h enum iommu_attr { · line 84

Quoted 7 lines
include/linux/iommu.h +1 -0
@@ -81,6 +81,7 @@ enum iommu_attr {
 	DOMAIN_ATTR_FSL_PAMU_STASH,
 	DOMAIN_ATTR_FSL_PAMU_ENABLE,
 	DOMAIN_ATTR_FSL_PAMUV1,
+	DOMAIN_ATTR_COHERENT_HTW,

[Sethi Varun-B16395] Would it make sense to represent this as DOMAIN_ATTR_SMMU_COHERENT_HTW? I believe this is specific to SMMU.

Yes, it does.

Thanks,

Olav Haugan

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#29 lore raw

PATCH 7/7 iommu-api: Add domain attribute to enable coherent HTW

Quoted 20 lines · Olav Haugan
Quoted 19 lines · Varun Sethi
Quoted 19 lines

-----Original Message-----
From: iommu-bounces at lists.linux-foundation.org [mailto:iommu- bounces at lists.linux-foundation.org] On Behalf Of Olav Haugan
Sent: Monday, June 30, 2014 10:22 PM
To: linux-arm-kernel at lists.infradead.org; iommu at lists.linux- foundation.org
Cc: linux-arm-msm at vger.kernel.org; will.deacon at arm.com; thierry.reding at gmail.com; vgandhi at codeaurora.org
Subject: [RFC/PATCH 7/7] iommu-api: Add domain attribute to enable coherent HTW

Add a new iommu domain attribute that can be used to enable cache coherent hardware table walks (HTW) by the SMMU. HTW might be supported by the SMMU HW but depending on the use case and the usage of the SMMU in the SoC it might not be always beneficial to always turn on coherent HTW for all domains/iommu's.

Quoted 8 lines
Quoted 1 line

[Sethi Varun-B16395] Why won't you want to use the coherent table walk feature?

Very good question. We have found that turning on IOMMU coherent HTW is not always beneficial to performance (performance either the same or slightly worse in some cases). Even if the perf. is the same we would like to avoid using precious L2 cache for no benefit to the IOMMU. Although our HW supports this feature we don't always want to turn this on for a specific use case/domain (bus master).

Could we at least invert the feature flag, please? i.e. you set an attribute to *disable* coherent walks? I'd also be interested to see some performance numbers, as the added cacheflushing overhead from non-coherent walks is going to be non-trivial.

Will

#30 lore raw

PATCH 7/7 iommu-api: Add domain attribute to enable coherent HTW

Quoted 30 lines · Will Deacon
Quoted 20 lines · Olav Haugan
Quoted 19 lines · Varun Sethi
Quoted 19 lines

-----Original Message-----
From: iommu-bounces at lists.linux-foundation.org [mailto:iommu- bounces at lists.linux-foundation.org] On Behalf Of Olav Haugan
Sent: Monday, June 30, 2014 10:22 PM
To: linux-arm-kernel at lists.infradead.org; iommu at lists.linux- foundation.org
Cc: linux-arm-msm at vger.kernel.org; will.deacon at arm.com; thierry.reding at gmail.com; vgandhi at codeaurora.org
Subject: [RFC/PATCH 7/7] iommu-api: Add domain attribute to enable coherent HTW

Add a new iommu domain attribute that can be used to enable cache coherent hardware table walks (HTW) by the SMMU. HTW might be supported by the SMMU HW but depending on the use case and the usage of the SMMU in the SoC it might not be always beneficial to always turn on coherent HTW for all domains/iommu's.

Quoted 8 lines
Quoted 1 line

[Sethi Varun-B16395] Why won't you want to use the coherent table walk feature?

Very good question. We have found that turning on IOMMU coherent HTW is not always beneficial to performance (performance either the same or slightly worse in some cases). Even if the perf. is the same we would like to avoid using precious L2 cache for no benefit to the IOMMU. Although our HW supports this feature we don't always want to turn this on for a specific use case/domain (bus master).

Quoted 5 lines

Could we at least invert the feature flag, please? i.e. you set an attribute to *disable* coherent walks? I'd also be interested to see some performance numbers, as the added cacheflushing overhead from non-coherent walks is going to be non-trivial.

Yes, agree that we can do the inverse. On one SoC I saw about 5% degradation in performance with coherent table walk enabled for a specific bus master. However, we have seen improved performance also with other SMMUs/bus masters. It just depends on the SMMU/bus master and how it is being used. Hence the need to be able to disable this on a per-domain basis.

Thanks,

Olav Haugan

Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation