Skip to content

Commit f51d7bb

Browse files
rmurphy-armjoergroedel
authored andcommitted
iommu/dma: Stop getting dma_32bit_pfn wrong
iommu_dma_init_domain() was originally written under the misconception that dma_32bit_pfn represented some sort of size limit for IOVA domains. Since the truth is almost the exact opposite of that, rework the logic and comments to reflect its real purpose of optimising lookups when allocating from a subset of the available 64-bit space. Signed-off-by: Robin Murphy <[email protected]> Signed-off-by: Joerg Roedel <[email protected]>
1 parent ce273db commit f51d7bb

File tree

1 file changed

+18
-5
lines changed

1 file changed

+18
-5
lines changed

drivers/iommu/dma-iommu.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,
203203
struct iommu_dma_cookie *cookie = domain->iova_cookie;
204204
struct iova_domain *iovad = &cookie->iovad;
205205
unsigned long order, base_pfn, end_pfn;
206+
bool pci = dev && dev_is_pci(dev);
206207

207208
if (!cookie || cookie->type != IOMMU_DMA_IOVA_COOKIE)
208209
return -EINVAL;
@@ -225,19 +226,31 @@ int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,
225226
end_pfn = min_t(unsigned long, end_pfn,
226227
domain->geometry.aperture_end >> order);
227228
}
229+
/*
230+
* PCI devices may have larger DMA masks, but still prefer allocating
231+
* within a 32-bit mask to avoid DAC addressing. Such limitations don't
232+
* apply to the typical platform device, so for those we may as well
233+
* leave the cache limit at the top of their range to save an rb_last()
234+
* traversal on every allocation.
235+
*/
236+
if (pci)
237+
end_pfn &= DMA_BIT_MASK(32) >> order;
228238

229-
/* All we can safely do with an existing domain is enlarge it */
239+
/* start_pfn is always nonzero for an already-initialised domain */
230240
if (iovad->start_pfn) {
231241
if (1UL << order != iovad->granule ||
232-
base_pfn != iovad->start_pfn ||
233-
end_pfn < iovad->dma_32bit_pfn) {
242+
base_pfn != iovad->start_pfn) {
234243
pr_warn("Incompatible range for DMA domain\n");
235244
return -EFAULT;
236245
}
237-
iovad->dma_32bit_pfn = end_pfn;
246+
/*
247+
* If we have devices with different DMA masks, move the free
248+
* area cache limit down for the benefit of the smaller one.
249+
*/
250+
iovad->dma_32bit_pfn = min(end_pfn, iovad->dma_32bit_pfn);
238251
} else {
239252
init_iova_domain(iovad, 1UL << order, base_pfn, end_pfn);
240-
if (dev && dev_is_pci(dev))
253+
if (pci)
241254
iova_reserve_pci_windows(to_pci_dev(dev), iovad);
242255
}
243256
return 0;

0 commit comments

Comments
 (0)