iommu: Avoid DMA ops domain refcount contention
Subsystems (3)
Robin Murphy
maintainercover iommu: Avoid DMA ops domain refcount contention
John raised the issue[1] that we have some unnecessary refcount contention in the DMA ops path which shows scalability problems now that we have more real high-performance hardware using iommu-dma. The x86 IOMMU drivers are sidestepping this by stashing domain references in archdata, but since that's not very nice for architecture-agnostic code, I think it's time to look at a generic API-level solution.
These are a couple of quick patches based on the idea I had back when first implementing this lot, but didn't have any way to justify at the time. The third patch can be ignored for the sake of API discussion, but is included for completeness.
Robin.
[1] https://lists.linuxfoundation.org/pipermail/iommu/2018-August/029303.html
Robin Murphy (3):
iommu: Add fast hook for getting DMA domains iommu/dma: Use fast DMA domain lookup arm64/dma-mapping: Mildly optimise non-coherent IOMMU ops
arch/arm64/mm/dma-mapping.c | 10 +++++----- drivers/iommu/dma-iommu.c | 23 ++++++++++++----------- drivers/iommu/iommu.c | 9 +++++++++ include/linux/iommu.h | 1 + 4 files changed, 27 insertions(+), 16 deletions(-)
Signature · 1 line
2.17.1.dirty
Robin Murphy
maintainerPATCH 1/3 iommu: Add fast hook for getting DMA domains
While iommu_get_domain_for_dev() is the robust way for arbitrary IOMMU API callers to retrieve the domain pointer, for DMA ops domains it doesn't scale well for large systems and multi-queue devices, since the momentary refcount adjustment will lead to exclusive cacheline contention when multiple CPUs are operating in parallel on different mappings for the same device.
In the case of DMA ops domains, however, this refcounting is actually unnecessary, since they already imply that the group exists and is managed by platform code and IOMMU internals (by virtue of iommu_group_get_for_dev()) such that a reference will already be held for the lifetime of the device. Thus we can avoid the bottleneck by providing a fast lookup specifically for the DMA code to retrieve the default domain it already knows it has set up - a simple read-only dereference plays much nicer with cache-coherency protocols.
--- drivers/iommu/iommu.c | 9 +++++++++ include/linux/iommu.h | 1 + 2 files changed, 10 insertions(+)
drivers/iommu/iommu.c +9 -0
@@ -1379,6 +1379,15 @@ struct iommu_domain *iommu_get_domain_for_dev(struct device *dev) }EXPORT_SYMBOL_GPL (iommu_get_domain_for_dev); +/* +* For IOMMU_DOMAIN_DMA implementations which already provide their own +* guarantees that the group and its default domain are valid and correct. +*/ +struct iommu_domain *iommu_get_dma_domain (struct device *dev) +{ +return dev->iommu_group->default_domain; +} +/* * IOMMU groups are really the natrual working unit of the IOMMU, but * the IOMMU API works on domains and devices. Bridge that gap by
include/linux/iommu.h +1 -0
@@ -297,6 +297,7 @@ extern int iommu_attach_device(struct iommu_domain *domain,extern void iommu_detach_device (struct iommu_domain *domain,struct device *dev);extern struct iommu_domain *iommu_get_domain_for_dev (struct device *dev); +extern struct iommu_domain *iommu_get_dma_domain (struct device *dev);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,
Signature · 1 line
2.17.1.dirty
Robin Murphy
maintainerPATCH 2/3 iommu/dma: Use fast DMA domain lookup
In reply to Robin MurphyMost parts of iommu-dma already assume they are operating on a default domain set up by iommu_dma_init_domain(), and can be converted straight over to avoid the refcounting bottleneck. MSI page mappings may be in an unmanaged domain with an explicit MSI-only cookie, so retain the non-specific lookup, but that's OK since they're far from a contended fast path either way.
--- drivers/iommu/dma-iommu.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-)
drivers/iommu/dma-iommu.c +12 -11
@@ -510,7 +510,7 @@ static struct page **__iommu_dma_alloc_pages(unsigned int count,void iommu_dma_free (struct device *dev,struct page **pages,size_t size,dma_addr_t *handle) { -__iommu_dma_unmap (iommu_get_domain_for_dev (dev), *handle, size); +__iommu_dma_unmap (iommu_get_dma_domain (dev), *handle, size);__iommu_dma_free_pages (pages,PAGE_ALIGN (size) >>PAGE_SHIFT ); *handle =IOMMU_MAPPING_ERROR ; }
@@ -537,7 +537,7 @@ struct page **iommu_dma_alloc(struct device *dev, size_t size, gfp_t gfp, unsigned long attrs, int prot, dma_addr_t *handle, void (*flush_page)(struct device *, const void *, phys_addr_t)) { - struct iommu_domain *domain = iommu_get_domain_for_dev(dev); + struct iommu_domain *domain = iommu_get_dma_domain(dev);struct iommu_dma_cookie *cookie = domain->iova_cookie;struct iova_domain *iovad = &cookie->iovad;struct page **pages;
@@ -625,9 +625,8 @@ int iommu_dma_mmap(struct page **pages, size_t size, struct vm_area_struct *vma) }static dma_addr_t __iommu_dma_map (struct device *dev,phys_addr_t phys, -size_t size,int prot) +size_t size,int prot,struct iommu_domain *domain) { -struct iommu_domain *domain =iommu_get_domain_for_dev (dev);struct iommu_dma_cookie *cookie = domain->iova_cookie;size_t iova_off =0 ;dma_addr_t iova;
@@ -651,13 +650,14 @@ static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys,dma_addr_t iommu_dma_map_page (struct device *dev,struct page *page,unsigned long offset,size_t size,int prot) { -return __iommu_dma_map (dev,page_to_phys (page) + offset, size, prot); +return __iommu_dma_map (dev,page_to_phys (page) + offset, size, prot, +iommu_get_dma_domain (dev)); }void iommu_dma_unmap_page (struct device *dev,dma_addr_t handle,size_t size,enum dma_data_direction dir,unsigned long attrs) { -__iommu_dma_unmap (iommu_get_domain_for_dev (dev), handle, size); +__iommu_dma_unmap (iommu_get_dma_domain (dev), handle, size); }/*
@@ -745,7 +745,7 @@ static void __invalidate_sg(struct scatterlist *sg, int nents)int iommu_dma_map_sg (struct device *dev,struct scatterlist *sg,int nents,int prot) { -struct iommu_domain *domain =iommu_get_domain_for_dev (dev); +struct iommu_domain *domain =iommu_get_dma_domain (dev);struct iommu_dma_cookie *cookie = domain->iova_cookie;struct iova_domain *iovad = &cookie->iovad;struct scatterlist *s, *prev =NULL ;
@@ -830,20 +830,21 @@ void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, sg = tmp; } end =sg_dma_address (sg) +sg_dma_len (sg); -__iommu_dma_unmap (iommu_get_domain_for_dev (dev), start, end - start); +__iommu_dma_unmap (iommu_get_dma_domain (dev), start, end - start); }dma_addr_t iommu_dma_map_resource (struct device *dev,phys_addr_t phys,size_t size,enum dma_data_direction dir,unsigned long attrs) {return __iommu_dma_map (dev, phys, size, -dma_info_to_prot (dir, false, attrs) |IOMMU_MMIO ); +dma_info_to_prot (dir, false, attrs) |IOMMU_MMIO , +iommu_get_dma_domain (dev)); }void iommu_dma_unmap_resource (struct device *dev,dma_addr_t handle,size_t size,enum dma_data_direction dir,unsigned long attrs) { -__iommu_dma_unmap (iommu_get_domain_for_dev (dev), handle, size); +__iommu_dma_unmap (iommu_get_dma_domain (dev), handle, size); }int iommu_dma_mapping_error (struct device *dev,dma_addr_t dma_addr)
@@ -869,7 +870,7 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev,if (!msi_page)return NULL ; - iova =__iommu_dma_map (dev, msi_addr, size, prot); + iova =__iommu_dma_map (dev, msi_addr, size, prot, domain);if (iommu_dma_mapping_error (dev, iova)) goto out_free_page;
Signature · 1 line
2.17.1.dirty
Robin Murphy
maintainerPATCH 3/3 arm64/dma-mapping: Mildly optimise non-coherent IOMMU ops
In reply to Robin MurphyWhilst the symmetry of deferring to the existing sync callback in __iommu_map_page() is nice, taking a round-trip through iommu_iova_to_phys() is a pretty heavyweight way to get an address we can trivially compute from the page we already have. Tweaking it to just perform the cache maintenance directly when appropriate doesn't really make the code any more complicated, and the runtime efficiency gain can only be a benefit.
Furthermore, the sync operations themselves know they can only be invoked on a managed DMA ops domain, so can use the fast specific domain lookup to avoid excessive manipulation of the group refcount (particularly in the scatterlist cases).
--- arch/arm64/mm/dma-mapping.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
arch/arm64/mm/dma-mapping.c +5 -5
@@ -712,7 +712,7 @@ static void __iommu_sync_single_for_cpu(struct device *dev,if (is_device_dma_coherent (dev))return ; - phys =iommu_iova_to_phys (iommu_get_domain_for_dev (dev), dev_addr); + phys =iommu_iova_to_phys (iommu_get_dma_domain (dev), dev_addr);__dma_unmap_area (phys_to_virt (phys), size, dir); }
@@ -725,7 +725,7 @@ static void __iommu_sync_single_for_device(struct device *dev,if (is_device_dma_coherent (dev))return ; - phys =iommu_iova_to_phys (iommu_get_domain_for_dev (dev), dev_addr); + phys =iommu_iova_to_phys (iommu_get_dma_domain (dev), dev_addr);__dma_map_area (phys_to_virt (phys), size, dir); }
@@ -738,9 +738,9 @@ static dma_addr_t __iommu_map_page(struct device *dev, struct page *page,int prot =dma_info_to_prot (dir, coherent, attrs);dma_addr_t dev_addr =iommu_dma_map_page (dev, page, offset, size, prot); -if (!iommu_dma_mapping_error (dev, dev_addr) && - (attrs &DMA_ATTR_SKIP_CPU_SYNC ) ==0 ) -__iommu_sync_single_for_device (dev, dev_addr, size, dir); +if (!coherent && !(attrs &DMA_ATTR_SKIP_CPU_SYNC ) && + !iommu_dma_mapping_error (dev, dev_addr)) +__dma_map_area (page_address (page), size, dir);return dev_addr; }
Signature · 1 line
2.17.1.dirty
cover iommu: Avoid DMA ops domain refcount contention
In reply to Robin MurphyQuoted 22 lines · Robin Murphy
John raised the issue[1] that we have some unnecessary refcount contention in the DMA ops path which shows scalability problems now that we have more real high-performance hardware using iommu-dma. The x86 IOMMU drivers are sidestepping this by stashing domain references in archdata, but since that's not very nice for architecture-agnostic code, I think it's time to look at a generic API-level solution.
These are a couple of quick patches based on the idea I had back when first implementing this lot, but didn't have any way to justify at the time. The third patch can be ignored for the sake of API discussion, but is included for completeness.
Robin.
[1] https://lists.linuxfoundation.org/pipermail/iommu/2018-August/029303.html
Robin Murphy (3):
iommu: Add fast hook for getting DMA domains iommu/dma: Use fast DMA domain lookup arm64/dma-mapping: Mildly optimise non-coherent IOMMU ops
Quoted 6 lines
arch/arm64/mm/dma-mapping.c | 10 +++++----- drivers/iommu/dma-iommu.c | 23 ++++++++++++----------- drivers/iommu/iommu.c | 9 +++++++++ include/linux/iommu.h | 1 + 4 files changed, 27 insertions(+), 16 deletions(-)
Thanks Robin. So we'll test this now. I anticipate a decent improvement across the board since we are now simply dereferencing the device's iommu group directly.
Cheers,
John
cover iommu: Avoid DMA ops domain refcount contention
In reply to Robin MurphyI plan to make the arm iommu dma ops generic and move them to drivers/iommu for the 4.20 merge window. Because of that it would be great to create a stable branch or even pull this in through the dma-mapping tree entirely.
cover iommu: Avoid DMA ops domain refcount contention
Quoted 4 lines · Christoph Hellwig
I plan to make the arm iommu dma ops generic and move them to
drivers/iommufor the 4.20 merge window. Because of that it would be great to create a stable branch or even pull this in through the dma-mapping tree entirely.
In which case, for the arm64 bits:
Will
PATCH 1/3 iommu: Add fast hook for getting DMA domains
In reply to Robin MurphyQuoted 47 lines · Robin Murphy
While
iommu_get_domain_for_dev()is the robust way for arbitrary IOMMU API callers to retrieve the domain pointer, for DMA ops domains it doesn't scale well for large systems and multi-queue devices, since the momentary refcount adjustment will lead to exclusive cacheline contention when multiple CPUs are operating in parallel on different mappings for the same device.In the case of DMA ops domains, however, this refcounting is actually unnecessary, since they already imply that the group exists and is managed by platform code and IOMMU internals (by virtue of
iommu_group_get_for_dev()) such that a reference will already be held for the lifetime of the device. Thus we can avoid the bottleneck by providing a fast lookup specifically for the DMA code to retrieve the default domain it already knows it has set up - a simple read-only dereference plays much nicer with cache-coherency protocols.Signed-off-by Robin Murphy <[email protected]>--- drivers/iommu/iommu.c | 9 +++++++++ include/linux/iommu.h | 1 + 2 files changed, 10 insertions(+)drivers/iommu/iommu.c +9
-0@@ -1379,6 +1379,15 @@ struct iommu_domain *iommu_get_domain_for_dev(struct device *dev) }EXPORT_SYMBOL_GPL (iommu_get_domain_for_dev); +/* +* For IOMMU_DOMAIN_DMA implementations which already provide their own +* guarantees that the group and its default domain are valid and correct. +*/ +struct iommu_domain *iommu_get_dma_domain (struct device *dev) +{ +return dev->iommu_group->default_domain; +} +/* * IOMMU groups are really the natrual working unit of the IOMMU, but * the IOMMU API works on domains and devices. Bridge that gap by include/linux/iommu.h +0
-0
include/linux/iommu.h extern int iommu_attach_device(struct iommu_domain *domain, · line 300
Quoted 4 lines
include/linux/iommu.h +1
-0@@ -297,6 +297,7 @@ extern int iommu_attach_device(struct iommu_domain *domain,extern void iommu_detach_device (struct iommu_domain *domain,struct device *dev);extern struct iommu_domain *iommu_get_domain_for_dev (struct device *dev); +extern struct iommu_domain *iommu_get_dma_domain (struct device *dev);
Hi Robin,
I was wondering whether it's standard to provide a stubbed version of this function for !CONFIG_IOMMU_API?
Cheers,
John
Quoted 4 lines
include/linux/iommu.h +0
-0extern 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,
Robin Murphy
maintainerPATCH 1/3 iommu: Add fast hook for getting DMA domains
Quoted 59 lines · John Garry
Quoted 52 lines · Robin Murphy
While
iommu_get_domain_for_dev()is the robust way for arbitrary IOMMU API callers to retrieve the domain pointer, for DMA ops domains it doesn't scale well for large systems and multi-queue devices, since the momentary refcount adjustment will lead to exclusive cacheline contention when multiple CPUs are operating in parallel on different mappings for the same device.In the case of DMA ops domains, however, this refcounting is actually unnecessary, since they already imply that the group exists and is managed by platform code and IOMMU internals (by virtue of
iommu_group_get_for_dev()) such that a reference will already be held for the lifetime of the device. Thus we can avoid the bottleneck by providing a fast lookup specifically for the DMA code to retrieve the default domain it already knows it has set up - a simple read-only dereference plays much nicer with cache-coherency protocols.Signed-off-by Robin Murphy <[email protected]>---
?drivers/iommu/iommu.c | 9 +++++++++
?include/linux/iommu.h | 1 +
?2 files changed, 10 insertions(+)drivers/iommu/iommu.c +3
-0@@ -1379,6 +1379,15 @@ struct iommu_domain *iommu_get_domain_for_dev(struct device *dev) ?} ?EXPORT_SYMBOL_GPL(iommu_get_domain_for_dev); +/* +* For IOMMU_DOMAIN_DMA implementations which already provide their own +* guarantees that the group and its default domain are valid and correct.
+ */drivers/iommu/iommu.c +5
-0+struct iommu_domain *iommu_get_dma_domain (struct device *dev) +{ +??? return dev->iommu_group->default_domain; +} +?/*
? * IOMMU groups are really the natrual working unit of the IOMMU, but ? * the IOMMU API works on domains and devices.? Bridge that gap byinclude/linux/iommu.h +0
-0@@ -297,6 +297,7 @@ extern int iommu_attach_device(struct iommu_domain *domain, ?extern void iommu_detach_device(struct iommu_domain *domain, ???????????????? struct device *dev);Quoted 3 lines
?extern struct
iommu_domain*iommu_get_domain_for_dev(struct device *dev);
+extern structiommu_domain*iommu_get_dma_domain(struct device *dev);Hi Robin,
Quoted 2 lines
I was wondering whether it's standard to provide a stubbed version of this function for !CONFIG_IOMMU_API?
Nope, that's deliberate - this is one of those hooks where any legitimate caller will already be dependent on IOMMU_API itself.
Robin.
Quoted 11 lines
Cheers,
JohnQuoted 5 lines
?extern int iommu_map(struct
iommu_domain*domain, unsigned long iova, ?????????????phys_addr_tpaddr,size_tsize, int prot); ?externsize_tiommu_unmap(structiommu_domain*domain, unsigned long iova,
Robin Murphy
maintainercover iommu: Avoid DMA ops domain refcount contention
In reply to Christoph HellwigQuoted 2 lines · Christoph Hellwig
I plan to make the arm iommu dma ops generic and move them to
drivers/iommufor the 4.20 merge window.
You mean 32-bit arm? The only place that code should move to is /dev/null ;) - the plan has always been to convert it to use groups and default domains so it can just plug iommu-dma in. The tricky bit is either weaning the users of the private arm_iommu_*() API onto generic IOMMU API usage, or at least implementing transitional wrappers in a way that doesn't break anything.
Quoted 3 lines
Because of that it would
be great to create a stable branch or even pull this in through the dma-mapping tree entirely.
FWIW I might still need to tweak the first patch depending on how we choose to resolve the interaction between DMA ops and unmanaged domains[1] - if we want to add fallback paths to iommu-dma instead of swizzling device ops then the assumptions for this hook change and it will need to reference group->domain rather than group->default_domain.
Robin.
[1]
https://www.mail-archive.com/dri-devel at lists.freedesktop.org/msg230275.html
cover iommu: Avoid DMA ops domain refcount contention
Quoted 5 lines · Robin Murphy
Quoted 2 lines · Christoph Hellwig
I plan to make the arm iommu dma ops generic and move them to
drivers/iommufor the 4.20 merge window.You mean 32-bit arm?
Sorry, I meant the arm64 wrappers for dma-iommu of course.
Quoted 5 lines
The only place that code should move to is
/dev/null;)
- the plan has always been to convert it to use groups and default domains so it can just plug iommu-dma in. The tricky bit is either weaning the users of the private arm_iommu_*() API onto generic IOMMU API usage, or at least implementing transitional wrappers in a way that doesn't break anything.
Agreed on the arm32 iommu code.
cover iommu: Avoid DMA ops domain refcount contention
In reply to Robin MurphyQuoted 7 lines · Robin Murphy
John raised the issue[1] that we have some unnecessary refcount contention in the DMA ops path which shows scalability problems now that we have more real high-performance hardware using iommu-dma. The x86 IOMMU drivers are sidestepping this by stashing domain references in archdata, but since that's not very nice for architecture-agnostic code, I think it's time to look at a generic API-level solution.
Quoted 7 lines
These are a couple of quick patches based on the idea I had back when first implementing this lot, but didn't have any way to justify at the time. The third patch can be ignored for the sake of API discussion, but is included for completeness.
Robin.
Some results:
PCIe NIC iperf test (128 processes, small packets):
Without patchset:
289232.00 rxpck/s
With patchset:
367283 rxpck/s
JFYI, with Leizhen's non-strict mode patchset + Robin's patchset:
1215539 rxpck/s
Leizhen can share non-strict mode results in his own patchset however.
We did also try the storage controller fio test with a lot of SAS SSD disks (24 disks, 24 fio processes) for Robin's patchset only, but did not see a significant change.
Thanks to Dongdong + chenxiang for testing.
Let me know if you require more info.
Thanks again,
John
Quoted 14 lines
[1] https://lists.linuxfoundation.org/pipermail/iommu/2018-August/029303.html
Robin Murphy (3):
iommu: Add fast hook for getting DMA domains iommu/dma: Use fast DMA domain lookup arm64/dma-mapping: Mildly optimise non-coherent IOMMU opsarch/arm64/mm/dma-mapping.c | 10 +++++----- drivers/iommu/dma-iommu.c | 23 ++++++++++++----------- drivers/iommu/iommu.c | 9 +++++++++ include/linux/iommu.h | 1 + 4 files changed, 27 insertions(+), 16 deletions(-)
PATCH 1/3 iommu: Add fast hook for getting DMA domains
In reply to Robin MurphyHi Robin,
Quoted 28 lines · Robin Murphy
While
iommu_get_domain_for_dev()is the robust way for arbitrary IOMMU API callers to retrieve the domain pointer, for DMA ops domains it doesn't scale well for large systems and multi-queue devices, since the momentary refcount adjustment will lead to exclusive cacheline contention when multiple CPUs are operating in parallel on different mappings for the same device.In the case of DMA ops domains, however, this refcounting is actually unnecessary, since they already imply that the group exists and is managed by platform code and IOMMU internals (by virtue of
iommu_group_get_for_dev()) such that a reference will already be held for the lifetime of the device. Thus we can avoid the bottleneck by providing a fast lookup specifically for the DMA code to retrieve the default domain it already knows it has set up - a simple read-only dereference plays much nicer with cache-coherency protocols.Signed-off-by Robin Murphy <[email protected]>--- drivers/iommu/iommu.c | 9 +++++++++ include/linux/iommu.h | 1 + 2 files changed, 10 insertions(+)drivers/iommu/iommu.c +0
-0@@ -1379,6 +1379,15 @@ struct iommu_domain *iommu_get_domain_for_dev(struct device *dev) }
drivers/iommu/iommu.c struct iommu_domain *iommu_get_domain_for_dev(struct device *dev) · line 1389
Quoted 10 lines
drivers/iommu/iommu.c +8
-0EXPORT_SYMBOL_GPL (iommu_get_domain_for_dev); +/* +* For IOMMU_DOMAIN_DMA implementations which already provide their own +* guarantees that the group and its default domain are valid and correct. +*/ +struct iommu_domain *iommu_get_dma_domain (struct device *dev) +{ +return dev->iommu_group->default_domain; +}
After some preliminary tests I'm seeing a ~10% performance improvement on one of our chips (nxp ls1046a) which is pretty nice. :-) Any chance of making the function inline?
If not, shouldn't an EXPORT_SYMBOL_GPL be added?
---
Thanks & Best Regards, Laurentiu
Robin Murphy
maintainerPATCH 3/3 arm64/dma-mapping: Mildly optimise non-coherent IOMMU ops
In reply to Robin MurphyQuoted 41 lines · Robin Murphy
Whilst the symmetry of deferring to the existing sync callback in
__iommu_map_page()is nice, taking a round-trip throughiommu_iova_to_phys()is a pretty heavyweight way to get an address we can trivially compute from the page we already have. Tweaking it to just perform the cache maintenance directly when appropriate doesn't really make the code any more complicated, and the runtime efficiency gain can only be a benefit.Furthermore, the sync operations themselves know they can only be invoked on a managed DMA ops domain, so can use the fast specific domain lookup to avoid excessive manipulation of the group refcount (particularly in the scatterlist cases).
Signed-off-by Robin Murphy <[email protected]>--- arch/arm64/mm/dma-mapping.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)arch/arm64/mm/dma-mapping.c +2
-2@@ -712,7 +712,7 @@ static void __iommu_sync_single_for_cpu(struct device *dev,if (is_device_dma_coherent (dev))return ; - phys =iommu_iova_to_phys (iommu_get_domain_for_dev (dev), dev_addr); + phys =iommu_iova_to_phys (iommu_get_dma_domain (dev), dev_addr);__dma_unmap_area (phys_to_virt (phys), size, dir); }@@ -725,7 +725,7 @@ static void __iommu_sync_single_for_device(struct device *dev,if (is_device_dma_coherent (dev))return ; - phys =iommu_iova_to_phys (iommu_get_domain_for_dev (dev), dev_addr); + phys =iommu_iova_to_phys (iommu_get_dma_domain (dev), dev_addr);__dma_map_area (phys_to_virt (phys), size, dir); }
arch/arm64/mm/dma-mapping.c static dma_addr_t __iommu_map_page(struct device *dev, struct page *page, · line 743
Quoted 9 lines
arch/arm64/mm/dma-mapping.c +3
-3@@ -738,9 +738,9 @@ static dma_addr_t __iommu_map_page(struct device *dev, struct page *page,int prot =dma_info_to_prot (dir, coherent, attrs);dma_addr_t dev_addr =iommu_dma_map_page (dev, page, offset, size, prot); -if (!iommu_dma_mapping_error (dev, dev_addr) && - (attrs &DMA_ATTR_SKIP_CPU_SYNC ) ==0 ) -__iommu_sync_single_for_device (dev, dev_addr, size, dir); +if (!coherent && !(attrs &DMA_ATTR_SKIP_CPU_SYNC ) && + !iommu_dma_mapping_error (dev, dev_addr)) +__dma_map_area (page_address (page), size, dir);
+ offset
Sigh...
And there I was assuming that if I'd bothered to write up a proper commit message for the 15-month-old change I was cherry-picking, I must have actually tested it at the time.
Robin.
Quoted 4 lines
arch/arm64/mm/dma-mapping.c +0
-0return dev_addr; }