Skip to contentSkip to conversation

Add iommu map_sg/unmap_sg API

PATCH Superseded Olav Haugan 7 participants 29 messages Aug 11, 2014 – Oct 17, 2014

Subsystems (7)

v5 of 6 Superseded Latest is v6 →

lore
Share & tools
lore
#0 lore raw

v5 cover Add iommu map_sg/unmap_sg API

Patch for adding map_sg/unmap_sg to the generic IOMMU API.

v4 -> v5:
* Simplified logic in map_sg on error
* Moved fallback to separate function for both map an unmap and pointed all drivers to these fallbacks.

v3 -> v4:
* Removed BUG_ON in both map_sg and unmap_sg
* Removed PAGE_ALIGN of length of mapping

v2 -> v3:
* Updated commit text
* Simplifed fallback code and fixed variable types in map_sg function.
* Renamed and changed arguments to map and unmap functions

v1 -> v2:
* Added support for "option" argument to unmap call. This can be used by IOMMU driver implentations to allow clients to signal to the driver not to do TLB invalidate for example.
* Added fallback in case iommu_{map,unmap}_range is called for an IOMMU driver that does not have these implemented.
* Rebased on top of Joerg's tree.
* Split out patch from the rest of the patches.

Olav Haugan (1):
iommu-api: Add map_sg/unmap_sg functions

 drivers/iommu/amd_iommu.c      |  2 ++
 drivers/iommu/arm-smmu.c       |  2 ++
 drivers/iommu/exynos-iommu.c   |  2 ++
 drivers/iommu/intel-iommu.c    |  2 ++
 drivers/iommu/iommu.c          | 33 +++++++++++++++++++++++++++++++
 drivers/iommu/ipmmu-vmsa.c     |  2 ++
 drivers/iommu/msm_iommu.c      |  2 ++
 drivers/iommu/omap-iommu.c     |  2 ++
 drivers/iommu/shmobile-iommu.c |  2 ++
 drivers/iommu/tegra-smmu.c     |  2 ++
 include/linux/iommu.h          | 44 ++++++++++++++++++++++++++++++++++++++++++
 11 files changed, 95 insertions(+)
Signature · 2 lines
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
#1 lore raw

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

Mapping and unmapping are more often than not in the critical path. map_sg and unmap_sg allows IOMMU driver implementations to optimize the process of mapping and unmapping buffers into the IOMMU page tables.

Instead of mapping a buffer one page at a time and requiring potentially expensive TLB operations for each page, this function allows the driver to map all pages in one go and defer TLB maintenance until after all pages have been mapped.

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/amd_iommu.c      |  2 ++
 drivers/iommu/arm-smmu.c       |  2 ++
 drivers/iommu/exynos-iommu.c   |  2 ++
 drivers/iommu/intel-iommu.c    |  2 ++
 drivers/iommu/iommu.c          | 33 +++++++++++++++++++++++++++++++
 drivers/iommu/ipmmu-vmsa.c     |  2 ++
 drivers/iommu/msm_iommu.c      |  2 ++
 drivers/iommu/omap-iommu.c     |  2 ++
 drivers/iommu/shmobile-iommu.c |  2 ++
 drivers/iommu/tegra-smmu.c     |  2 ++
 include/linux/iommu.h          | 44 ++++++++++++++++++++++++++++++++++++++++++
 11 files changed, 95 insertions(+)
drivers/iommu/amd_iommu.c +2 -0
index 1840531..3604f3c 100644
@@ -3402,6 +3402,8 @@ static const struct iommu_ops amd_iommu_ops = {
 	.detach_dev = amd_iommu_detach_device,
 	.map = amd_iommu_map,
 	.unmap = amd_iommu_unmap,
+	.map_sg = default_iommu_map_sg,
+	.unmap_sg = default_iommu_unmap_sg,
 	.iova_to_phys = amd_iommu_iova_to_phys,
 	.domain_has_cap = amd_iommu_domain_has_cap,
 	.pgsize_bitmap	= AMD_IOMMU_PGSIZES,
drivers/iommu/arm-smmu.c +2 -0
index ca18d6d..231e006 100644
@@ -1604,6 +1604,8 @@ static const struct iommu_ops arm_smmu_ops = {
 	.detach_dev	= arm_smmu_detach_dev,
 	.map		= arm_smmu_map,
 	.unmap		= arm_smmu_unmap,
+	.map_sg		= default_iommu_map_sg,
+	.unmap_sg	= default_iommu_unmap_sg,
 	.iova_to_phys	= arm_smmu_iova_to_phys,
 	.domain_has_cap	= arm_smmu_domain_has_cap,
 	.add_device	= arm_smmu_add_device,
drivers/iommu/exynos-iommu.c +2 -0
index d037e87..8876508 100644
@@ -1177,6 +1177,8 @@ static const struct iommu_ops exynos_iommu_ops = {
 	.detach_dev = exynos_iommu_detach_device,
 	.map = exynos_iommu_map,
 	.unmap = exynos_iommu_unmap,
+	.map_sg = default_iommu_map_sg,
+	.unmap_sg = default_iommu_unmap_sg,
 	.iova_to_phys = exynos_iommu_iova_to_phys,
 	.add_device = exynos_iommu_add_device,
 	.remove_device = exynos_iommu_remove_device,
drivers/iommu/intel-iommu.c +2 -0
index d1f5caa..4fc61ff 100644
@@ -4462,6 +4462,8 @@ static const struct iommu_ops intel_iommu_ops = {
 	.detach_dev	= intel_iommu_detach_device,
 	.map		= intel_iommu_map,
 	.unmap		= intel_iommu_unmap,
+	.map_sg		= default_iommu_map_sg,
+	.unmap_sg	= default_iommu_unmap_sg,
 	.iova_to_phys	= intel_iommu_iova_to_phys,
 	.domain_has_cap = intel_iommu_domain_has_cap,
 	.add_device	= intel_iommu_add_device,
drivers/iommu/iommu.c +33 -0
index 1698360..24cf727 100644
@@ -1088,6 +1088,39 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
 }
 EXPORT_SYMBOL_GPL(iommu_unmap);
 
+int default_iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
+			 struct scatterlist *sg, unsigned int nents,
+			 int prot, unsigned long flags)
+{
+	int ret = 0;
+	unsigned long offset = 0;
+	unsigned int i;
+	struct scatterlist *s;
+
+	for_each_sg(sg, s, nents, i) {
+		phys_addr_t phys = page_to_phys(sg_page(s));
+		size_t page_len = s->offset + s->length;
+
+		ret = iommu_map(domain, iova + offset, phys, page_len,
+				prot);
+		if (ret) {
+			/* undo mappings already done */
+			iommu_unmap(domain, iova, offset);
+			break;
+		}
+		offset += page_len;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(default_iommu_map_sg);
+
+int default_iommu_unmap_sg(struct iommu_domain *domain, unsigned long iova,
+			       size_t size, unsigned long flags)
+{
+	return iommu_unmap(domain, iova, size);
+}
+EXPORT_SYMBOL_GPL(default_iommu_unmap_sg);
 
 int iommu_domain_window_enable(struct iommu_domain *domain, u32 wnd_nr,
 			       phys_addr_t paddr, u64 size, int prot)
drivers/iommu/ipmmu-vmsa.c +2 -0
index 7dab5cb..1dc6f94 100644
@@ -1127,6 +1127,8 @@ static const struct iommu_ops ipmmu_ops = {
 	.detach_dev = ipmmu_detach_device,
 	.map = ipmmu_map,
 	.unmap = ipmmu_unmap,
+	.map_sg = default_iommu_map_sg,
+	.unmap_sg = default_iommu_unmap_sg,
 	.iova_to_phys = ipmmu_iova_to_phys,
 	.add_device = ipmmu_add_device,
 	.remove_device = ipmmu_remove_device,
drivers/iommu/msm_iommu.c +2 -0
index 49f41d6..2b3c8d3 100644
@@ -681,6 +681,8 @@ static const struct iommu_ops msm_iommu_ops = {
 	.detach_dev = msm_iommu_detach_dev,
 	.map = msm_iommu_map,
 	.unmap = msm_iommu_unmap,
+	.map_sg = default_iommu_map_sg,
+	.unmap_sg = default_iommu_unmap_sg,
 	.iova_to_phys = msm_iommu_iova_to_phys,
 	.domain_has_cap = msm_iommu_domain_has_cap,
 	.pgsize_bitmap = MSM_IOMMU_PGSIZES,
drivers/iommu/omap-iommu.c +2 -0
index e202b0c..7d4c920 100644
@@ -1285,6 +1285,8 @@ static const struct iommu_ops omap_iommu_ops = {
 	.detach_dev	= omap_iommu_detach_dev,
 	.map		= omap_iommu_map,
 	.unmap		= omap_iommu_unmap,
+	.map_sg		= default_iommu_map_sg,
+	.unmap_sg	= default_iommu_unmap_sg,
 	.iova_to_phys	= omap_iommu_iova_to_phys,
 	.add_device	= omap_iommu_add_device,
 	.remove_device	= omap_iommu_remove_device,
drivers/iommu/shmobile-iommu.c +2 -0
index 1333e6fb..3510f70 100644
@@ -361,6 +361,8 @@ static const struct iommu_ops shmobile_iommu_ops = {
 	.detach_dev = shmobile_iommu_detach_device,
 	.map = shmobile_iommu_map,
 	.unmap = shmobile_iommu_unmap,
+	.map_sg = default_iommu_map_sg,
+	.unmap_sg = default_iommu_unmap_sg,
 	.iova_to_phys = shmobile_iommu_iova_to_phys,
 	.add_device = shmobile_iommu_add_device,
 	.pgsize_bitmap = SZ_1M | SZ_64K | SZ_4K,
drivers/iommu/tegra-smmu.c +2 -0
index 792da5e..ebd847b 100644
@@ -954,6 +954,8 @@ static const struct iommu_ops smmu_iommu_ops = {
 	.detach_dev	= smmu_iommu_detach_dev,
 	.map		= smmu_iommu_map,
 	.unmap		= smmu_iommu_unmap,
+	.map_sg		= default_iommu_map_sg,
+	.unmap_sg	= default_iommu_unmap_sg,
 	.iova_to_phys	= smmu_iommu_iova_to_phys,
 	.domain_has_cap	= smmu_iommu_domain_has_cap,
 	.pgsize_bitmap	= SMMU_IOMMU_PGSIZES,
include/linux/iommu.h +44 -0

80 lines not on this page · raw message

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

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

Quoted 9 lines · Olav Haugan

Mapping and unmapping are more often than not in the critical path. map_sg and unmap_sg allows IOMMU driver implementations to optimize the process of mapping and unmapping buffers into the IOMMU page tables.

Instead of mapping a buffer one page at a time and requiring potentially expensive TLB operations for each page, this function allows the driver to map all pages in one go and defer TLB maintenance until after all pages have been mapped.

Quoted 6 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.

Thank you for changing it this way.

.. snip..

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

Quoted 9 lines
drivers/iommu/iommu.c +9 -0
+	for_each_sg(sg, s, nents, i) {
+		phys_addr_t phys = page_to_phys(sg_page(s));
+		size_t page_len = s->offset + s->length;
+
+		ret = iommu_map(domain, iova + offset, phys, page_len,
+				prot);
+		if (ret) {
+			/* undo mappings already done */
+			iommu_unmap(domain, iova, offset);

Don't we want then to unmap all of the scatter list instead of just the last one?

Quoted 7 lines
drivers/iommu/iommu.c +7 -0
+			break;
+		}
+		offset += page_len;
+	}
+
+	return ret;
+}
#3 lore raw

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

Quoted 15 lines · Konrad Rzeszutek Wilk

On Mon, Aug 11, 2014 at 03:45:50PM -0700, Olav Haugan wrote:
.. snip..

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

Quoted 9 lines
drivers/iommu/iommu.c +9 -0
+	for_each_sg(sg, s, nents, i) {
+		phys_addr_t phys = page_to_phys(sg_page(s));
+		size_t page_len = s->offset + s->length;
+
+		ret = iommu_map(domain, iova + offset, phys, page_len,
+				prot);
+		if (ret) {
+			/* undo mappings already done */
+			iommu_unmap(domain, iova, offset);

Don't we want then to unmap all of the scatter list instead of just the last one?

It reverts all the mapping that was already done up until the error occurred. "offset" contains the amount we have mapped so far.

Thanks,

Olav

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

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

In reply to Olav Haugan

Hi Olav,

Quoted 12 lines · Olav Haugan
include/linux/iommu.h +4 -0
@@ -93,6 +94,10 @@ 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_sg: map a scatter-gather list of physically contiguous memory chunks
+ * to an iommu domain
+ * @unmap_sg: 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

include/linux/iommu.h struct iommu_ops { · line 122

Quoted 8 lines
include/linux/iommu.h +5 -0
@@ -110,6 +115,11 @@ 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_sg)(struct iommu_domain *domain, unsigned long iova,
+                       struct scatterlist *sg, unsigned int nents, int prot,
+                       unsigned long flags);
+       int (*unmap_sg)(struct iommu_domain *domain, unsigned long iova,
+                       size_t size, unsigned long flags);

Do you have any exmaple/explanation for the above "flags"?

Is this going to be used for iommu global/standard attribute or SoC spcific one?

#5 lore raw

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

Quoted 27 lines · Hiroshi Doyu

Hi Olav,

Quoted 12 lines · Olav Haugan
include/linux/iommu.h +4 -0
@@ -93,6 +94,10 @@ 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_sg: map a scatter-gather list of physically contiguous memory chunks
+ * to an iommu domain
+ * @unmap_sg: 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

include/linux/iommu.h struct iommu_ops { · line 122

Quoted 8 lines
include/linux/iommu.h +5 -0
@@ -110,6 +115,11 @@ 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_sg)(struct iommu_domain *domain, unsigned long iova,
+                       struct scatterlist *sg, unsigned int nents, int prot,
+                       unsigned long flags);
+       int (*unmap_sg)(struct iommu_domain *domain, unsigned long iova,
+                       size_t size, unsigned long flags);

Do you have any exmaple/explanation for the above "flags"?

Quoted 2 lines

Is this going to be used for iommu global/standard attribute or SoC spcific one?

iirc, one plan for 'flags' was some sort of DONT_FLUSH_TLB flag for drivers which wanted to map/unmap N buffers with a single flush at the end. There might have been some other usages envisioned.

BR,
-R

#6 lore raw

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

Quoted 28 lines · Rob Clark
Quoted 27 lines · Hiroshi Doyu

Hi Olav,

Quoted 12 lines · Olav Haugan
include/linux/iommu.h +4 -0
@@ -93,6 +94,10 @@ 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_sg: map a scatter-gather list of physically contiguous memory chunks
+ * to an iommu domain
+ * @unmap_sg: 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

include/linux/iommu.h struct iommu_ops { · line 122

Quoted 8 lines
include/linux/iommu.h +5 -0
@@ -110,6 +115,11 @@ 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_sg)(struct iommu_domain *domain, unsigned long iova,
+                       struct scatterlist *sg, unsigned int nents, int prot,
+                       unsigned long flags);
+       int (*unmap_sg)(struct iommu_domain *domain, unsigned long iova,
+                       size_t size, unsigned long flags);

Do you have any exmaple/explanation for the above "flags"?

Quoted 7 lines
Quoted 2 lines

Is this going to be used for iommu global/standard attribute or SoC spcific one?

iirc, one plan for 'flags' was some sort of DONT_FLUSH_TLB flag for drivers which wanted to map/unmap N buffers with a single flush at the end. There might have been some other usages envisioned.

Yes, that was the original intent of the flags for now. I am sure we can find other uses for this in the future.

Thanks,

Olav

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

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

Quoted 7 lines · Olav Haugan
Quoted 3 lines · Rob Clark

iirc, one plan for 'flags' was some sort of DONT_FLUSH_TLB flag for drivers which wanted to map/unmap N buffers with a single flush at the end. There might have been some other usages envisioned.

Yes, that was the original intent of the flags for now. I am sure we can find other uses for this in the future.

Do you have anything else in mind already besides the DONT_FLUSH_TLB flag?

How is the IOTLB supposed to be flushed when this flag is used?

Joerg

#8 lore raw

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

Quoted 6 lines · On Mon, Aug 18, 2014 at 10:07 AM, joro at 8bytes.org <[email protected]> wrote:
Quoted 5 lines · Olav Haugan
Quoted 3 lines · Rob Clark

iirc, one plan for 'flags' was some sort of DONT_FLUSH_TLB flag for drivers which wanted to map/unmap N buffers with a single flush at the end. There might have been some other usages envisioned.

Quoted 8 lines
Quoted 2 lines

Yes, that was the original intent of the flags for now. I am sure we can find other uses for this in the future.

Do you have anything else in mind already besides the DONT_FLUSH_TLB flag?

How is the IOTLB supposed to be flushed when this flag is used?

well, I was thinking one of two ways:

1) add new flush() vfunc.. this, I think, would be most convenient for drivers using this feature
2) or driver simply doesn't set DONT_FLUSH_TLB flag on the last {map,unmap}.. that would be slightly more awkward to use, but would avoid adding a new vfunc

BR,
-R

Quoted 2 lines

Joerg

#9 lore raw

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

Quoted 7 lines · Rob Clark
Quoted 6 lines · On Mon, Aug 18, 2014 at 10:07 AM, joro at 8bytes.org <[email protected]> wrote:
Quoted 5 lines · Olav Haugan
Quoted 3 lines · Rob Clark

iirc, one plan for 'flags' was some sort of DONT_FLUSH_TLB flag for drivers which wanted to map/unmap N buffers with a single flush at the end. There might have been some other usages envisioned.

Quoted 5 lines
Quoted 5 lines
Quoted 2 lines

Yes, that was the original intent of the flags for now. I am sure we can find other uses for this in the future.

Do you have anything else in mind already besides the DONT_FLUSH_TLB flag?

No, I do not have other uses right now. But could imagine use cases like "force <insert minimum mapping size here> mapping" flag etc.

Quoted 11 lines
Quoted 2 lines

How is the IOTLB supposed to be flushed when this flag is used?

well, I was thinking one of two ways:

1) add new flush() vfunc.. this, I think, would be most convenient for drivers using this feature
2) or driver simply doesn't set DONT_FLUSH_TLB flag on the last {map,unmap}.. that would be slightly more awkward to use, but would avoid adding a new vfunc

I agree and would support adding a public flush() API. It is cleaner. However, it does allow clients to chose which method to use. Either an extra call to flush() or just do not pass DONT_FLUSH_TLB flag on the last invocation of map/unmap.

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 v5 1/1 iommu-api: Add map_sg/unmap_sg functions

Quoted 4 lines · Olav Haugan

On 8/18/2014 11:32 AM, Rob Clark wrote:

No, I do not have other uses right now. But could imagine use cases like "force <insert minimum mapping size here> mapping" flag etc.

I think it is worth discussing to add a flush() function to the IOMMU-API. I sent a patch-set myself a few years ago introducing an iommu_commit() function with the same semantics, but this is out-of-scope for this patch-set.

Also adding a flag parameter to iommu_map_sg would introduce an asymentrie in the API to the iommu_map() function. So please leave it out for this patch-set, when we really need a flag parameter someday we can introduce it for iommu_map() and iommu_map_sg() together.

Joerg

#11 lore raw

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

Quoted 11 lines · On 8/18/2014 2:26 PM, joro at 8bytes.org wrote:
Quoted 4 lines · Olav Haugan

On 8/18/2014 11:32 AM, Rob Clark wrote:

No, I do not have other uses right now. But could imagine use cases like "force <insert minimum mapping size here> mapping" flag etc.

I think it is worth discussing to add a flush() function to the IOMMU-API. I sent a patch-set myself a few years ago introducing an iommu_commit() function with the same semantics, but this is out-of-scope for this patch-set.

Quoted 5 lines

Also adding a flag parameter to iommu_map_sg would introduce an asymentrie in the API to the iommu_map() function. So please leave it out for this patch-set, when we really need a flag parameter someday we can introduce it for iommu_map() and iommu_map_sg() together.

Sure, I can remove it. I was trying to make iommu_map_sg/iommu_unmap_sg symmetric :-)

Anything else before I push v6?

Thanks,

Olav

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

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

In reply to Olav Haugan

Hi Olav,

Thank you for the patch.

Quoted 28 lines · On Monday 11 August 2014 15:45:50 Olav Haugan wrote:

Mapping and unmapping are more often than not in the critical path. map_sg and unmap_sg allows IOMMU driver implementations to optimize the process of mapping and unmapping buffers into the IOMMU page tables.

Instead of mapping a buffer one page at a time and requiring potentially expensive TLB operations for each page, this function allows the driver to map all pages in one go and defer TLB maintenance until after all pages have been mapped.

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/amd_iommu.c      |  2 ++
 drivers/iommu/arm-smmu.c       |  2 ++
 drivers/iommu/exynos-iommu.c   |  2 ++
 drivers/iommu/intel-iommu.c    |  2 ++
 drivers/iommu/iommu.c          | 33 +++++++++++++++++++++++++++++++
 drivers/iommu/ipmmu-vmsa.c     |  2 ++
 drivers/iommu/msm_iommu.c      |  2 ++
 drivers/iommu/omap-iommu.c     |  2 ++
 drivers/iommu/shmobile-iommu.c |  2 ++
 drivers/iommu/tegra-smmu.c     |  2 ++
 include/linux/iommu.h          | 44 +++++++++++++++++++++++++++++++++++++++
 11 files changed, 95 insertions(+)

[snip]

Quoted 6 lines
drivers/iommu/iommu.c +0 -0
index 1698360..24cf727 100644
@@ -1088,6 +1088,39 @@ size_t iommu_unmap(struct iommu_domain *domain,
 unsigned long iova, size_t size)

[snip]

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

Quoted 2 lines
drivers/iommu/iommu.c +2 -0
+int default_iommu_unmap_sg(struct iommu_domain *domain, unsigned long iova,
+			       size_t size, unsigned long flags)

I would have called this iommu_default_unmap_sg (and same comment for default_iommu_map_sg) to keep the iommu_ prefix, but that's up to you.

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

Quoted 4 lines
drivers/iommu/iommu.c +4 -0
+{
+	return iommu_unmap(domain, iova, size);
+}
+EXPORT_SYMBOL_GPL(default_iommu_unmap_sg);

Do you expect drivers to need to override this ? What are the use cases for non-default implementation of unmap_sg different than this ?

[snip]

Quoted 4 lines
include/linux/iommu.h +0 -0
index 20f9a52..ee106ce 100644

[snip]

include/linux/iommu.h static inline int report_iommu_fault(struct · line 264

Quoted 10 lines
include/linux/iommu.h +5 -0
@@ -240,6 +256,20 @@ static inline int report_iommu_fault(struct
 iommu_domain *domain, return ret;
 }
 
+static inline int iommu_map_sg(struct iommu_domain *domain, unsigned long
 iova,
+			       struct scatterlist *sg, unsigned int nents,
+			       int prot, unsigned long flags)
+{
+	return domain->ops->map_sg(domain, iova, sg, nents, prot, flags);

Instead of having to modify all IOMMU drivers to set the map_sg operation to default_iommu_map_sg, how about calling it automatically as a fallback when map_sg is NULL ? Something like

	if (domain->ops->map_sg)
		return domain->ops->map_sg(domain, iova, sg, nents, prot, flags);

	return default_iommu_map_sg(domain, iova, sg, nents, prot, flags);
Quoted 9 lines
include/linux/iommu.h +9 -0
+}
+
+static inline int iommu_unmap_sg(struct iommu_domain *domain,
+				 unsigned long iova, size_t size,
+				 unsigned long flags)
+{
+	return domain->ops->unmap_sg(domain, iova, size, flags);
+}
+
Signature · 3 lines
Regards,

Laurent Pinchart
#13 lore raw

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

Hi Laurent,

Quoted 51 lines · Laurent Pinchart

Hi Olav,

Thank you for the patch.

Quoted 28 lines · On Monday 11 August 2014 15:45:50 Olav Haugan wrote:

Mapping and unmapping are more often than not in the critical path. map_sg and unmap_sg allows IOMMU driver implementations to optimize the process of mapping and unmapping buffers into the IOMMU page tables.

Instead of mapping a buffer one page at a time and requiring potentially expensive TLB operations for each page, this function allows the driver to map all pages in one go and defer TLB maintenance until after all pages have been mapped.

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/amd_iommu.c      |  2 ++
 drivers/iommu/arm-smmu.c       |  2 ++
 drivers/iommu/exynos-iommu.c   |  2 ++
 drivers/iommu/intel-iommu.c    |  2 ++
 drivers/iommu/iommu.c          | 33 +++++++++++++++++++++++++++++++
 drivers/iommu/ipmmu-vmsa.c     |  2 ++
 drivers/iommu/msm_iommu.c      |  2 ++
 drivers/iommu/omap-iommu.c     |  2 ++
 drivers/iommu/shmobile-iommu.c |  2 ++
 drivers/iommu/tegra-smmu.c     |  2 ++
 include/linux/iommu.h          | 44 +++++++++++++++++++++++++++++++++++++++
 11 files changed, 95 insertions(+)

[snip]

Quoted 6 lines
drivers/iommu/iommu.c +0 -0
index 1698360..24cf727 100644
@@ -1088,6 +1088,39 @@ size_t iommu_unmap(struct iommu_domain *domain,
 unsigned long iova, size_t size)

[snip]

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

Quoted 2 lines
drivers/iommu/iommu.c +2 -0
+int default_iommu_unmap_sg(struct iommu_domain *domain, unsigned long iova,
+			       size_t size, unsigned long flags)

I would have called this iommu_default_unmap_sg (and same comment for default_iommu_map_sg) to keep the iommu_ prefix, but that's up to you.

Quoted 7 lines

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

Quoted 4 lines
drivers/iommu/iommu.c +4 -0
+{
+	return iommu_unmap(domain, iova, size);
+}
+EXPORT_SYMBOL_GPL(default_iommu_unmap_sg);

Do you expect drivers to need to override this ? What are the use cases for non-default implementation of unmap_sg different than this ?

Good question. Yes, maybe some drivers does not need or want to override this but a use case is to provide a more optimized version of the map_sg/unmap_sg functions. For example a very simple way to optimize this would be to have an implementation that unmaps everything and then does a TLB invalidate instead of doing a TLB invalidate after every single unmap (which happens with the default implementation if your driver does TLB invalidate after unmapping).

Quoted 24 lines

[snip]

Quoted 4 lines
include/linux/iommu.h +0 -0
index 20f9a52..ee106ce 100644

[snip]

include/linux/iommu.h static inline int report_iommu_fault(struct · line 264

Quoted 10 lines
include/linux/iommu.h +5 -0
@@ -240,6 +256,20 @@ static inline int report_iommu_fault(struct
 iommu_domain *domain, return ret;
 }
 
+static inline int iommu_map_sg(struct iommu_domain *domain, unsigned long
 iova,
+			       struct scatterlist *sg, unsigned int nents,
+			       int prot, unsigned long flags)
+{
+	return domain->ops->map_sg(domain, iova, sg, nents, prot, flags);

Instead of having to modify all IOMMU drivers to set the map_sg operation to default_iommu_map_sg, how about calling it automatically as a fallback when map_sg is NULL ? Something like

Quoted 4 lines
	if (domain->ops->map_sg)
		return domain->ops->map_sg(domain, iova, sg, nents, prot, flags);

	return default_iommu_map_sg(domain, iova, sg, nents, prot, flags);

This was my original proposal but after some discussion on the list we ended up with what we have now.

Quoted 11 lines

include/linux/iommu.h static inline int report_iommu_fault(struct iommu_domain *domain, · line 272

Quoted 10 lines
include/linux/iommu.h +9 -0
+}
+
+static inline int iommu_unmap_sg(struct iommu_domain *domain,
+				 unsigned long iova, size_t size,
+				 unsigned long flags)
+{
+	return domain->ops->unmap_sg(domain, iova, size, flags);
+}
+

Thanks,

Olav

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

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

In reply to Olav Haugan
Quoted 5 lines · Olav Haugan
drivers/iommu/iommu.c +5 -0
+int default_iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
+			 struct scatterlist *sg, unsigned int nents,
+			 int prot, unsigned long flags)
+{
+	int ret = 0;

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

Quoted 10 lines
drivers/iommu/iommu.c +10 -0
+	unsigned long offset = 0;
+	unsigned int i;
+	struct scatterlist *s;
+
+	for_each_sg(sg, s, nents, i) {
+		phys_addr_t phys = page_to_phys(sg_page(s));
+		size_t page_len = s->offset + s->length;
+
+		ret = iommu_map(domain, iova + offset, phys, page_len,
+				prot);

This isn't going to work, iova + offset, phys and page_len need to be aligned to the minimum page-size the given IOMMU implementation supports. See the iommu_map implementation for details.

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

Quoted 2 lines
drivers/iommu/iommu.c +2 -0
+int default_iommu_unmap_sg(struct iommu_domain *domain, unsigned long iova,
+			       size_t size, unsigned long flags)

Another asymmentry here, why don't you just pass a scatterlist and nents like in the map_sg function? if you implement it like this it is just a duplication of iommu_unmap().

include/linux/iommu.h static inline int report_iommu_fault(struct iommu_domain *domain, · line 271

Quoted 13 lines
include/linux/iommu.h +13 -0
+static inline int iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
+			       struct scatterlist *sg, unsigned int nents,
+			       int prot, unsigned long flags)
+{
+	return domain->ops->map_sg(domain, iova, sg, nents, prot, flags);
+}
+
+static inline int iommu_unmap_sg(struct iommu_domain *domain,
+				 unsigned long iova, size_t size,
+				 unsigned long flags)
+{
+	return domain->ops->unmap_sg(domain, iova, size, flags);
+}

These function pointers need to be checked for != NULL before calling them.

Joerg

#15 lore raw

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

Quoted 12 lines · Joerg Roedel
Quoted 11 lines · Olav Haugan
drivers/iommu/iommu.c +11 -0
+int default_iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
+			 struct scatterlist *sg, unsigned int nents,
+			 int prot, unsigned long flags)
+{
+	int ret = 0;
+	unsigned long offset = 0;
+	unsigned int i;
+	struct scatterlist *s;
+
+	for_each_sg(sg, s, nents, i) {
+		phys_addr_t phys = page_to_phys(sg_page(s));
Quoted 8 lines

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

Quoted 4 lines
drivers/iommu/iommu.c +4 -0
+		size_t page_len = s->offset + s->length;
+
+		ret = iommu_map(domain, iova + offset, phys, page_len,
+				prot);

This isn't going to work, iova + offset, phys and page_len need to be aligned to the minimum page-size the given IOMMU implementation supports. See the iommu_map implementation for details.

If the alignment is not correct then iommu_map() will return error. Not sure what other option we have here (and why make it different behavior than iommu_map which just return error when it is not aligned properly). I don't think we want to force any kind of alignment automatically. I would rather have the API tell me I am doing something wrong than having the function aligning the values and possibly undermap or overmap.

Quoted 6 lines

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

Quoted 2 lines
drivers/iommu/iommu.c +2 -0
+int default_iommu_unmap_sg(struct iommu_domain *domain, unsigned long iova,
+			       size_t size, unsigned long flags)

Another asymmentry here, why don't you just pass a scatterlist and nents like in the map_sg function? if you implement it like this it is just a duplication of iommu_unmap().

Yes, I am aware of that. However, several people prefer this than passing in scatterlist. It is not very convenient to pass a scatterlist in some use cases. Someone mentioned a use case where they would have to create a dummy sg list and populate it with the iova just to do an unmap. I believe we would have to do this also. There is no use for sglist when unmapping. However, would like to keep separate API from iommu_unmap() to keep the API function names symmetric (map_sg/unmap_sg).

Quoted 8 lines
Quoted 8 lines
include/linux/iommu.h +8 -0
+static inline int iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
+			       struct scatterlist *sg, unsigned int nents,
+			       int prot, unsigned long flags)
+{
+	return domain->ops->map_sg(domain, iova, sg, nents, prot, flags);
+}
+
+static inline int iommu_unmap_sg(struct iommu_domain *domain,
Quoted 8 lines

include/linux/iommu.h static inline int report_iommu_fault(struct iommu_domain *domain, · line 271

Quoted 5 lines
include/linux/iommu.h +5 -0
+				 unsigned long iova, size_t size,
+				 unsigned long flags)
+{
+	return domain->ops->unmap_sg(domain, iova, size, flags);
+}

These function pointers need to be checked for != NULL before calling them.

I thought that was why we added the default fallback and set all the drivers to point to these fallback functions. Several people wanted this so that we don't have to have NULL-check in these functions (and have the functions be simple inline functions).

Thanks,

Olav

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

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

Quoted 6 lines · Olav Haugan

If the alignment is not correct then iommu_map() will return error. Not sure what other option we have here (and why make it different behavior than iommu_map which just return error when it is not aligned properly). I don't think we want to force any kind of alignment automatically. I would rather have the API tell me I am doing something wrong than having the function aligning the values and possibly undermap or overmap.

But sg->offset is an offset into the page (at least it is used that way in the DMA-API and since you do 'page_len = s->offset + s->length' you use it the same way).
So when you pass iova + offset the result will no longer be page-aligned. You should force sg->offset == 0 and sg->length to be page-aligned instead. This makes more sense because the IOMMU-API works on (io)-page granularity and not on arbitrary phys-addr ranges like the DMA-API.

Quoted 7 lines

Yes, I am aware of that. However, several people prefer this than passing in scatterlist. It is not very convenient to pass a scatterlist in some use cases. Someone mentioned a use case where they would have to create a dummy sg list and populate it with the iova just to do an unmap. I believe we would have to do this also. There is no use for sglist when unmapping. However, would like to keep separate API from iommu_unmap() to keep the API function names symmetric (map_sg/unmap_sg).

Keeping it symetric is not more complicated, the caller just needs to keep the sg-list used for mapping around. I prefer the unmap_sg call to work in sg-lists too.

Quoted 4 lines

I thought that was why we added the default fallback and set all the drivers to point to these fallback functions. Several people wanted this so that we don't have to have NULL-check in these functions (and have the functions be simple inline functions).

Okay, since you add these call-backs to all drivers I think I can live with not doing a pointer check here.

Joerg

#17 lore raw

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

Quoted 25 lines · On Tuesday 19 August 2014 13:59:54 Joerg Roedel wrote:
Quoted 6 lines · Olav Haugan

If the alignment is not correct then iommu_map() will return error. Not sure what other option we have here (and why make it different behavior than iommu_map which just return error when it is not aligned properly). I don't think we want to force any kind of alignment automatically. I would rather have the API tell me I am doing something wrong than having the function aligning the values and possibly undermap or overmap.

But sg->offset is an offset into the page (at least it is used that way in the DMA-API and since you do 'page_len = s->offset + s->length' you use it the same way).
So when you pass iova + offset the result will no longer be page-aligned. You should force sg->offset == 0 and sg->length to be page-aligned instead. This makes more sense because the IOMMU-API works on (io)-page granularity and not on arbitrary phys-addr ranges like the DMA-API.

Quoted 7 lines

Yes, I am aware of that. However, several people prefer this than passing in scatterlist. It is not very convenient to pass a scatterlist in some use cases. Someone mentioned a use case where they would have to create a dummy sg list and populate it with the iova just to do an unmap. I believe we would have to do this also. There is no use for sglist when unmapping. However, would like to keep separate API from iommu_unmap() to keep the API function names symmetric (map_sg/unmap_sg).

Quoted 3 lines

Keeping it symetric is not more complicated, the caller just needs to keep the sg-list used for mapping around. I prefer the unmap_sg call to work in sg-lists too.

Do we have a use case where the unmap_sg() implementation would be different than a plain iommu_unmap() call ? If not I'd rather remove unmap_sg() completely.

Quoted 7 lines
Quoted 4 lines

I thought that was why we added the default fallback and set all the drivers to point to these fallback functions. Several people wanted this so that we don't have to have NULL-check in these functions (and have the functions be simple inline functions).

Okay, since you add these call-backs to all drivers I think I can live with not doing a pointer check here.

I suggested doing a

if (ops is not NULL)

	return ops();
else
	return default_ops();

to avoid modifying all drivers. I'm not sure why that wasn't received with much enthusiasm.

Signature · 3 lines
Regards,

Laurent Pinchart
#18 lore raw

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

Quoted 44 lines · Laurent Pinchart
Quoted 25 lines · On Tuesday 19 August 2014 13:59:54 Joerg Roedel wrote:
Quoted 6 lines · Olav Haugan

If the alignment is not correct then iommu_map() will return error. Not sure what other option we have here (and why make it different behavior than iommu_map which just return error when it is not aligned properly). I don't think we want to force any kind of alignment automatically. I would rather have the API tell me I am doing something wrong than having the function aligning the values and possibly undermap or overmap.

But sg->offset is an offset into the page (at least it is used that way in the DMA-API and since you do 'page_len = s->offset + s->length' you use it the same way).
So when you pass iova + offset the result will no longer be page-aligned. You should force sg->offset == 0 and sg->length to be page-aligned instead. This makes more sense because the IOMMU-API works on (io)-page granularity and not on arbitrary phys-addr ranges like the DMA-API.

Quoted 7 lines

Yes, I am aware of that. However, several people prefer this than passing in scatterlist. It is not very convenient to pass a scatterlist in some use cases. Someone mentioned a use case where they would have to create a dummy sg list and populate it with the iova just to do an unmap. I believe we would have to do this also. There is no use for sglist when unmapping. However, would like to keep separate API from iommu_unmap() to keep the API function names symmetric (map_sg/unmap_sg).

Quoted 3 lines

Keeping it symetric is not more complicated, the caller just needs to keep the sg-list used for mapping around. I prefer the unmap_sg call to work in sg-lists too.

Do we have a use case where the unmap_sg() implementation would be different than a plain iommu_unmap() call ? If not I'd rather remove unmap_sg() completely.

Quoted 7 lines
Quoted 4 lines

I thought that was why we added the default fallback and set all the drivers to point to these fallback functions. Several people wanted this so that we don't have to have NULL-check in these functions (and have the functions be simple inline functions).

Okay, since you add these call-backs to all drivers I think I can live with not doing a pointer check here.

I suggested doing a

Quoted 8 lines

if (ops is not NULL)

	return ops();
else
	return default_ops();

to avoid modifying all drivers. I'm not sure why that wasn't received with much enthusiasm.

Both Thierry R. and Konrad W. argued for modifying the drivers instead so I implemented what the majority wanted. :-)

Olav

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

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

Quoted 52 lines · On Tuesday 19 August 2014 11:40:24 Olav Haugan wrote:
Quoted 51 lines · Laurent Pinchart
Quoted 26 lines · On Tuesday 19 August 2014 13:59:54 Joerg Roedel wrote:
Quoted 6 lines · Olav Haugan

If the alignment is not correct then iommu_map() will return error. Not sure what other option we have here (and why make it different behavior than iommu_map which just return error when it is not aligned properly). I don't think we want to force any kind of alignment automatically. I would rather have the API tell me I am doing something wrong than having the function aligning the values and possibly undermap or overmap.

But sg->offset is an offset into the page (at least it is used that way in the DMA-API and since you do 'page_len = s->offset + s->length' you use it the same way).
So when you pass iova + offset the result will no longer be page-aligned. You should force sg->offset == 0 and sg->length to be page-aligned instead. This makes more sense because the IOMMU-API works on (io)-page granularity and not on arbitrary phys-addr ranges like the DMA-API.

Quoted 8 lines

Yes, I am aware of that. However, several people prefer this than passing in scatterlist. It is not very convenient to pass a scatterlist in some use cases. Someone mentioned a use case where they would have to create a dummy sg list and populate it with the iova just to do an unmap. I believe we would have to do this also. There is no use for sglist when unmapping. However, would like to keep separate API from iommu_unmap() to keep the API function names symmetric (map_sg/unmap_sg).

Quoted 3 lines

Keeping it symetric is not more complicated, the caller just needs to keep the sg-list used for mapping around. I prefer the unmap_sg call to work in sg-lists too.

Do we have a use case where the unmap_sg() implementation would be different than a plain iommu_unmap() call ? If not I'd rather remove unmap_sg() completely.

Quoted 7 lines
Quoted 4 lines

I thought that was why we added the default fallback and set all the drivers to point to these fallback functions. Several people wanted this so that we don't have to have NULL-check in these functions (and have the functions be simple inline functions).

Okay, since you add these call-backs to all drivers I think I can live with not doing a pointer check here.

I suggested doing a

if (ops is not NULL)

	return ops();

else

Quoted 7 lines
Quoted 4 lines
	return default_ops();

to avoid modifying all drivers. I'm not sure why that wasn't received with much enthusiasm.

Both Thierry R. and Konrad W. argued for modifying the drivers instead so I implemented what the majority wanted. :-)

I'm not blaming you :-) I was just wondering what their rationale was.

Signature · 3 lines
Regards,

Laurent Pinchart
#20 lore raw

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

Quoted 55 lines · Laurent Pinchart
Quoted 54 lines · On Tuesday 19 August 2014 11:40:24 Olav Haugan wrote:
Quoted 53 lines · Laurent Pinchart
Quoted 26 lines · On Tuesday 19 August 2014 13:59:54 Joerg Roedel wrote:
Quoted 6 lines · Olav Haugan

If the alignment is not correct then iommu_map() will return error. Not sure what other option we have here (and why make it different behavior than iommu_map which just return error when it is not aligned properly). I don't think we want to force any kind of alignment automatically. I would rather have the API tell me I am doing something wrong than having the function aligning the values and possibly undermap or overmap.

But sg->offset is an offset into the page (at least it is used that way in the DMA-API and since you do 'page_len = s->offset + s->length' you use it the same way).
So when you pass iova + offset the result will no longer be page-aligned. You should force sg->offset == 0 and sg->length to be page-aligned instead. This makes more sense because the IOMMU-API works on (io)-page granularity and not on arbitrary phys-addr ranges like the DMA-API.

Quoted 8 lines

Yes, I am aware of that. However, several people prefer this than passing in scatterlist. It is not very convenient to pass a scatterlist in some use cases. Someone mentioned a use case where they would have to create a dummy sg list and populate it with the iova just to do an unmap. I believe we would have to do this also. There is no use for sglist when unmapping. However, would like to keep separate API from iommu_unmap() to keep the API function names symmetric (map_sg/unmap_sg).

Quoted 3 lines

Keeping it symetric is not more complicated, the caller just needs to keep the sg-list used for mapping around. I prefer the unmap_sg call to work in sg-lists too.

Do we have a use case where the unmap_sg() implementation would be different than a plain iommu_unmap() call ? If not I'd rather remove unmap_sg() completely.

Quoted 7 lines
Quoted 4 lines

I thought that was why we added the default fallback and set all the drivers to point to these fallback functions. Several people wanted this so that we don't have to have NULL-check in these functions (and have the functions be simple inline functions).

Okay, since you add these call-backs to all drivers I think I can live with not doing a pointer check here.

I suggested doing a

if (ops is not NULL)

	return ops();

else

	return default_ops();
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

to avoid modifying all drivers. I'm not sure why that wasn't received with much enthusiasm.

Both Thierry R. and Konrad W. argued for modifying the drivers instead so I implemented what the majority wanted. :-)

I'm not blaming you :-) I was just wondering what their rationale was.

In my opinion it's much more direct that way. It means that if a driver doesn't implement it, it won't fall back to some default implementation instead. Providing an explicit helper like this makes it obvious that the driver is using a default implementation rather than making things work "magically". It's easier to see in the driver that there's the potential to optimize.

It also has the side-effect of keeping the core code cleaner in my opinion, since the core iommu_map_sg() and iommu_unmap_sg() functions can now blindly call into drivers directly rather than performing the various checks to see if they implement the required functionality.

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/20140820/192e9789/attachment.sig>

#21 lore raw

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

In reply to Laurent Pinchart
Quoted 55 lines · Laurent Pinchart
Quoted 54 lines · On Tuesday 19 August 2014 11:40:24 Olav Haugan wrote:
Quoted 53 lines · Laurent Pinchart
Quoted 26 lines · On Tuesday 19 August 2014 13:59:54 Joerg Roedel wrote:
Quoted 6 lines · Olav Haugan

If the alignment is not correct then iommu_map() will return error. Not sure what other option we have here (and why make it different behavior than iommu_map which just return error when it is not aligned properly). I don't think we want to force any kind of alignment automatically. I would rather have the API tell me I am doing something wrong than having the function aligning the values and possibly undermap or overmap.

But sg->offset is an offset into the page (at least it is used that way in the DMA-API and since you do 'page_len = s->offset + s->length' you use it the same way).
So when you pass iova + offset the result will no longer be page-aligned. You should force sg->offset == 0 and sg->length to be page-aligned instead. This makes more sense because the IOMMU-API works on (io)-page granularity and not on arbitrary phys-addr ranges like the DMA-API.

Quoted 8 lines

Yes, I am aware of that. However, several people prefer this than passing in scatterlist. It is not very convenient to pass a scatterlist in some use cases. Someone mentioned a use case where they would have to create a dummy sg list and populate it with the iova just to do an unmap. I believe we would have to do this also. There is no use for sglist when unmapping. However, would like to keep separate API from iommu_unmap() to keep the API function names symmetric (map_sg/unmap_sg).

Quoted 3 lines

Keeping it symetric is not more complicated, the caller just needs to keep the sg-list used for mapping around. I prefer the unmap_sg call to work in sg-lists too.

Do we have a use case where the unmap_sg() implementation would be different than a plain iommu_unmap() call ? If not I'd rather remove unmap_sg() completely.

Quoted 7 lines
Quoted 4 lines

I thought that was why we added the default fallback and set all the drivers to point to these fallback functions. Several people wanted this so that we don't have to have NULL-check in these functions (and have the functions be simple inline functions).

Okay, since you add these call-backs to all drivers I think I can live with not doing a pointer check here.

I suggested doing a

if (ops is not NULL)

	return ops();

else

	return default_ops();
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

to avoid modifying all drivers. I'm not sure why that wasn't received with much enthusiasm.

Both Thierry R. and Konrad W. argued for modifying the drivers instead so I implemented what the majority wanted. :-)

I'm not blaming you :-) I was just wondering what their rationale was.

a). To be inline with the usage of this API.

For this particular case the other functions (but maybe I missed some) follow the idea that they implement the ops->func for every operation and they don't have an fallback.

b) Follow what x86 maintainers prefer (based on other API calls, such as x86_init or any other platform overrides).

c). When there are new IOMMUs it has to take in-to account all of the
function ops. If they fail to implement all of them the kernel crashes instead of working (but maybe working incorrectly).

d). Lastly, we also want the bloat of kernel. If the compiler decides
to roll in the fallback implementation for 'iommu_map_sg' in - it will needlessly expand the kernel wherever we use 'iommu_map_sg' call with a fallback implementation (which might not be called 99% of time).

Having the little inline static just do 'func_ops->func' will stop the compiler from optimizing too much and convert this just to a simple function.

#22 lore raw

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

Hi Konrad,

Quoted 4 lines · On Wednesday 20 August 2014 09:02:50 Konrad Rzeszutek Wilk wrote:
Quoted 3 lines · Laurent Pinchart
Quoted 2 lines · On Tuesday 19 August 2014 11:40:24 Olav Haugan wrote:
Quoted 1 line · Laurent Pinchart

On Tuesday 19 August 2014 13:59:54 Joerg Roedel wrote:

[snip]

Quoted 16 lines
Quoted 16 lines
Quoted 15 lines
Quoted 5 lines
Quoted 2 lines

Okay, since you add these call-backs to all drivers I think I can live with not doing a pointer check here.

I suggested doing a

Quoted 7 lines

if (ops is not NULL)

	return ops();
else
	return default_ops();

to avoid modifying all drivers. I'm not sure why that wasn't received with much enthusiasm.

Both Thierry R. and Konrad W. argued for modifying the drivers instead so I implemented what the majority wanted. :-)

Quoted 7 lines
Quoted 1 line

I'm not blaming you :-) I was just wondering what their rationale was.

a). To be inline with the usage of this API.

For this particular case the other functions (but maybe I missed some) follow the idea that they implement the ops->func for every operation and they don't have an fallback.

That's because the other functions are mandatory, while this particular one is just an optimization and can be implemented generically.

Quoted 6 lines

b) Follow what x86 maintainers prefer (based on other API calls, such as x86_init or any other platform overrides).

c). When there are new IOMMUs it has to take in-to account all of the
function ops. If they fail to implement all of them the kernel crashes instead of working (but maybe working incorrectly).

I don't think that applies in this case, the generic implementation should work in all cases.

Quoted 8 lines

d). Lastly, we also want the bloat of kernel. If the compiler decides
to roll in the fallback implementation for 'iommu_map_sg' in - it will needlessly expand the kernel wherever we use 'iommu_map_sg' call with a fallback implementation (which might not be called 99% of time).

Having the little inline static just do 'func_ops->func' will stop the compiler from optimizing too much and convert this just to a simple function.

That's an argument I can buy.

Signature · 3 lines
Regards,

Laurent Pinchart
#23 lore raw

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

In reply to Joerg Roedel
Quoted 8 lines · Joerg Roedel
Quoted 6 lines · Olav Haugan

If the alignment is not correct then iommu_map() will return error. Not sure what other option we have here (and why make it different behavior than iommu_map which just return error when it is not aligned properly). I don't think we want to force any kind of alignment automatically. I would rather have the API tell me I am doing something wrong than having the function aligning the values and possibly undermap or overmap.

Quoted 8 lines

But sg->offset is an offset into the page (at least it is used that way in the DMA-API and since you do 'page_len = s->offset + s->length' you use it the same way).
So when you pass iova + offset the result will no longer be page-aligned. You should force sg->offset == 0 and sg->length to be page-aligned instead. This makes more sense because the IOMMU-API works on (io)-page granularity and not on arbitrary phys-addr ranges like the DMA-API.

Ok, but I don't think we want to force a specific alignment here (as I discussed earlier with Will D.). So I would just do something like

	iommu_map(domain, iova + offset, phys, s->length, prot);
	offset += s->length;
Quoted 11 lines
Quoted 7 lines

Yes, I am aware of that. However, several people prefer this than passing in scatterlist. It is not very convenient to pass a scatterlist in some use cases. Someone mentioned a use case where they would have to create a dummy sg list and populate it with the iova just to do an unmap. I believe we would have to do this also. There is no use for sglist when unmapping. However, would like to keep separate API from iommu_unmap() to keep the API function names symmetric (map_sg/unmap_sg).

Keeping it symetric is not more complicated, the caller just needs to keep the sg-list used for mapping around. I prefer the unmap_sg call to work in sg-lists too.

So are you looking for something like this then:

int iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
struct scatterlist *sg, unsigned int nents, int prot, unsigned long flags)

int iommu_unmap_sg(struct iommu_domain *domain, unsigned long iova,
struct scatterlist *sg, unsigned int nents, unsigned long flags)

This makes unmapping code more complicated (and slow) though. For example the way I would implement the fallback would be to iterate through the sglist first to calculate the total length to unmap and then call iommu_unmap().

I know we talked about removing the flag argument in the map call. However, the TLB_NO_INV usage is actually needed for both map and unmap. We have HW that requires TLB invalidate on MAP and TLB inv. is also required if you implement your mapping function to support replacing an existing mapping...

Rob, did you have an issue with this API before or was it just an issue with not having the iova in the unmap call?

Quoted 9 lines
Quoted 4 lines

I thought that was why we added the default fallback and set all the drivers to point to these fallback functions. Several people wanted this so that we don't have to have NULL-check in these functions (and have the functions be simple inline functions).

Okay, since you add these call-backs to all drivers I think I can live with not doing a pointer check here.

Quoted 8 lines

Joerg

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel at lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

Olav

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

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

In reply to Olav Haugan

include/linux/iommu.h static inline int report_iommu_fault(struct iommu_domain *domain, · line 271

Quoted 13 lines · Olav Haugan
include/linux/iommu.h +13 -0
+static inline int iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
+			       struct scatterlist *sg, unsigned int nents,
+			       int prot, unsigned long flags)
+{
+	return domain->ops->map_sg(domain, iova, sg, nents, prot, flags);
+}
+
+static inline int iommu_unmap_sg(struct iommu_domain *domain,
+				 unsigned long iova, size_t size,
+				 unsigned long flags)
+{
+	return domain->ops->unmap_sg(domain, iova, size, flags);
+}

I have thought a little bit more about this interface and think that it would be better to just return a size_t from iommu_map_sg(). The function returns the amount of address space mapped by it, 0 in the worst case.

This makes it easy to unmap the region just with iommu_unmap(domain, iova, size) in the end and removing the need for a new iommu_unmap_sg() function. Also the error-path of the map_sg call-backs becomes easier as the function then just returns the amount of address-space already mapped before the error happened.

So the prototype would be:

size_t iommu_map_sg(struct iommu_domain *domain,
unsigned long iova, struct scatterlist *sg, unsigned int nents, int prot);

(as I said before, the flags parameter should not be added by this
patch-set).

Joerg

#25 lore raw

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

Quoted 28 lines · Joerg Roedel

include/linux/iommu.h static inline int report_iommu_fault(struct iommu_domain *domain, · line 271

Quoted 13 lines · Olav Haugan
include/linux/iommu.h +13 -0
+static inline int iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
+			       struct scatterlist *sg, unsigned int nents,
+			       int prot, unsigned long flags)
+{
+	return domain->ops->map_sg(domain, iova, sg, nents, prot, flags);
+}
+
+static inline int iommu_unmap_sg(struct iommu_domain *domain,
+				 unsigned long iova, size_t size,
+				 unsigned long flags)
+{
+	return domain->ops->unmap_sg(domain, iova, size, flags);
+}

I have thought a little bit more about this interface and think that it would be better to just return a size_t from iommu_map_sg(). The function returns the amount of address space mapped by it, 0 in the worst case.

This makes it easy to unmap the region just with iommu_unmap(domain, iova, size) in the end and removing the need for a new iommu_unmap_sg() function. Also the error-path of the map_sg call-backs becomes easier as the function then just returns the amount of address-space already mapped before the error happened.

So the prototype would be:

Quoted 9 lines

size_t iommu_map_sg(struct iommu_domain *domain,
unsigned long iova, struct scatterlist *sg, unsigned int nents, int prot);

(as I said before, the flags parameter should not be added by this
patch-set).

Ok, sounds good. I'll post v6 soon.

.Olav

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

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

Quoted 35 lines · Olav Haugan
Quoted 34 lines · Joerg Roedel

include/linux/iommu.h static inline int report_iommu_fault(struct iommu_domain *domain, · line 271

Quoted 13 lines · Olav Haugan
include/linux/iommu.h +13 -0
+static inline int iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
+			       struct scatterlist *sg, unsigned int nents,
+			       int prot, unsigned long flags)
+{
+	return domain->ops->map_sg(domain, iova, sg, nents, prot, flags);
+}
+
+static inline int iommu_unmap_sg(struct iommu_domain *domain,
+				 unsigned long iova, size_t size,
+				 unsigned long flags)
+{
+	return domain->ops->unmap_sg(domain, iova, size, flags);
+}

I have thought a little bit more about this interface and think that it would be better to just return a size_t from iommu_map_sg(). The function returns the amount of address space mapped by it, 0 in the worst case.

This makes it easy to unmap the region just with iommu_unmap(domain, iova, size) in the end and removing the need for a new iommu_unmap_sg() function. Also the error-path of the map_sg call-backs becomes easier as the function then just returns the amount of address-space already mapped before the error happened.

So the prototype would be:

size_t iommu_map_sg(struct iommu_domain *domain,
unsigned long iova, struct scatterlist *sg, unsigned int nents, int prot);

Quoted 5 lines
Quoted 3 lines

(as I said before, the flags parameter should not be added by this
patch-set).

Ok, sounds good. I'll post v6 soon.

Perhaps make the return value ssize_t so that we can propagate errors?

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/20141015/7248bdde/attachment-0001.sig>

#27 lore raw

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

Quoted 36 lines · Thierry Reding
Quoted 35 lines · Olav Haugan
Quoted 34 lines · Joerg Roedel

include/linux/iommu.h static inline int report_iommu_fault(struct iommu_domain *domain, · line 271

Quoted 13 lines · Olav Haugan
include/linux/iommu.h +13 -0
+static inline int iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
+			       struct scatterlist *sg, unsigned int nents,
+			       int prot, unsigned long flags)
+{
+	return domain->ops->map_sg(domain, iova, sg, nents, prot, flags);
+}
+
+static inline int iommu_unmap_sg(struct iommu_domain *domain,
+				 unsigned long iova, size_t size,
+				 unsigned long flags)
+{
+	return domain->ops->unmap_sg(domain, iova, size, flags);
+}

I have thought a little bit more about this interface and think that it would be better to just return a size_t from iommu_map_sg(). The function returns the amount of address space mapped by it, 0 in the worst case.

This makes it easy to unmap the region just with iommu_unmap(domain, iova, size) in the end and removing the need for a new iommu_unmap_sg() function. Also the error-path of the map_sg call-backs becomes easier as the function then just returns the amount of address-space already mapped before the error happened.

So the prototype would be:

size_t iommu_map_sg(struct iommu_domain *domain,
unsigned long iova, struct scatterlist *sg, unsigned int nents, int prot);

Quoted 8 lines
Quoted 5 lines
Quoted 3 lines

(as I said before, the flags parameter should not be added by this
patch-set).

Ok, sounds good. I'll post v6 soon.

Perhaps make the return value ssize_t so that we can propagate errors?

I am fine with that. Joerg?

Thanks,

.Olav

Signature · 3 lines
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora 
Forum, a Linux Foundation Collaborative Project
maintainer
#28 lore raw

PATCH v5 1/1 iommu-api: Add map_sg/unmap_sg functions

Quoted 5 lines · Olav Haugan
Quoted 2 lines · Thierry Reding

Perhaps make the return value ssize_t so that we can propagate errors?

I am fine with that. Joerg?

I am not so sure this is a good idea. On error the function should return the size that is already mapped, so that the caller can check that against the expected size and just call iommu_unmap with the returned size when return value does not match expected size.

The benefit of ssize_t is that we can return more detailed error information when the function did not map anything yet. But this complicates the error handling for the caller and implementers might get it wrong and return an error-value even when some space was already mapped, so that the caller can not unmap the addresses.

So taking this into mind, I prefer it to be size_t for now. We can always change it later if it turns out to be wrong.

Regards,

Joerg