Skip to content

Commit 2a2b8ea

Browse files
pippy360willdeacon
authored andcommitted
iommu: Handle freelists when using deferred flushing in iommu drivers
Allow the iommu_unmap_fast to return newly freed page table pages and pass the freelist to queue_iova in the dma-iommu ops path. This is useful for iommu drivers (in this case the intel iommu driver) which need to wait for the ioTLB to be flushed before newly free/unmapped page table pages can be freed. This way we can still batch ioTLB free operations and handle the freelists. Signed-off-by: Tom Murphy <[email protected]> Signed-off-by: Lu Baolu <[email protected]> Tested-by: Logan Gunthorpe <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 66930e7 commit 2a2b8ea

File tree

3 files changed

+58
-27
lines changed

3 files changed

+58
-27
lines changed

drivers/iommu/dma-iommu.c

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,18 @@ struct iommu_dma_cookie {
4949
struct iommu_domain *fq_domain;
5050
};
5151

52+
static void iommu_dma_entry_dtor(unsigned long data)
53+
{
54+
struct page *freelist = (struct page *)data;
55+
56+
while (freelist) {
57+
unsigned long p = (unsigned long)page_address(freelist);
58+
59+
freelist = freelist->freelist;
60+
free_page(p);
61+
}
62+
}
63+
5264
static inline size_t cookie_msi_granule(struct iommu_dma_cookie *cookie)
5365
{
5466
if (cookie->type == IOMMU_DMA_IOVA_COOKIE)
@@ -343,7 +355,7 @@ static int iommu_dma_init_domain(struct iommu_domain *domain, dma_addr_t base,
343355
if (!cookie->fq_domain && !iommu_domain_get_attr(domain,
344356
DOMAIN_ATTR_DMA_USE_FLUSH_QUEUE, &attr) && attr) {
345357
if (init_iova_flush_queue(iovad, iommu_dma_flush_iotlb_all,
346-
NULL))
358+
iommu_dma_entry_dtor))
347359
pr_warn("iova flush queue initialization failed\n");
348360
else
349361
cookie->fq_domain = domain;
@@ -440,7 +452,7 @@ static dma_addr_t iommu_dma_alloc_iova(struct iommu_domain *domain,
440452
}
441453

442454
static void iommu_dma_free_iova(struct iommu_dma_cookie *cookie,
443-
dma_addr_t iova, size_t size)
455+
dma_addr_t iova, size_t size, struct page *freelist)
444456
{
445457
struct iova_domain *iovad = &cookie->iovad;
446458

@@ -449,7 +461,8 @@ static void iommu_dma_free_iova(struct iommu_dma_cookie *cookie,
449461
cookie->msi_iova -= size;
450462
else if (cookie->fq_domain) /* non-strict mode */
451463
queue_iova(iovad, iova_pfn(iovad, iova),
452-
size >> iova_shift(iovad), 0);
464+
size >> iova_shift(iovad),
465+
(unsigned long)freelist);
453466
else
454467
free_iova_fast(iovad, iova_pfn(iovad, iova),
455468
size >> iova_shift(iovad));
@@ -474,7 +487,7 @@ static void __iommu_dma_unmap(struct device *dev, dma_addr_t dma_addr,
474487

475488
if (!cookie->fq_domain)
476489
iommu_iotlb_sync(domain, &iotlb_gather);
477-
iommu_dma_free_iova(cookie, dma_addr, size);
490+
iommu_dma_free_iova(cookie, dma_addr, size, iotlb_gather.freelist);
478491
}
479492

480493
static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys,
@@ -496,7 +509,7 @@ static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys,
496509
return DMA_MAPPING_ERROR;
497510

498511
if (iommu_map_atomic(domain, iova, phys - iova_off, size, prot)) {
499-
iommu_dma_free_iova(cookie, iova, size);
512+
iommu_dma_free_iova(cookie, iova, size, NULL);
500513
return DMA_MAPPING_ERROR;
501514
}
502515
return iova + iova_off;
@@ -649,7 +662,7 @@ static void *iommu_dma_alloc_remap(struct device *dev, size_t size,
649662
out_free_sg:
650663
sg_free_table(&sgt);
651664
out_free_iova:
652-
iommu_dma_free_iova(cookie, iova, size);
665+
iommu_dma_free_iova(cookie, iova, size, NULL);
653666
out_free_pages:
654667
__iommu_dma_free_pages(pages, count);
655668
return NULL;
@@ -900,7 +913,7 @@ static int iommu_dma_map_sg(struct device *dev, struct scatterlist *sg,
900913
return __finalise_sg(dev, sg, nents, iova);
901914

902915
out_free_iova:
903-
iommu_dma_free_iova(cookie, iova, iova_len);
916+
iommu_dma_free_iova(cookie, iova, iova_len, NULL);
904917
out_restore_sg:
905918
__invalidate_sg(sg, nents);
906919
return 0;
@@ -1228,7 +1241,7 @@ static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev,
12281241
return msi_page;
12291242

12301243
out_free_iova:
1231-
iommu_dma_free_iova(cookie, iova, size);
1244+
iommu_dma_free_iova(cookie, iova, size, NULL);
12321245
out_free_page:
12331246
kfree(msi_page);
12341247
return NULL;

drivers/iommu/intel/iommu.c

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,17 +1243,17 @@ static struct page *dma_pte_clear_level(struct dmar_domain *domain, int level,
12431243
pages can only be freed after the IOTLB flush has been done. */
12441244
static struct page *domain_unmap(struct dmar_domain *domain,
12451245
unsigned long start_pfn,
1246-
unsigned long last_pfn)
1246+
unsigned long last_pfn,
1247+
struct page *freelist)
12471248
{
1248-
struct page *freelist;
1249-
12501249
BUG_ON(!domain_pfn_supported(domain, start_pfn));
12511250
BUG_ON(!domain_pfn_supported(domain, last_pfn));
12521251
BUG_ON(start_pfn > last_pfn);
12531252

12541253
/* we don't need lock here; nobody else touches the iova range */
12551254
freelist = dma_pte_clear_level(domain, agaw_to_level(domain->agaw),
1256-
domain->pgd, 0, start_pfn, last_pfn, NULL);
1255+
domain->pgd, 0, start_pfn, last_pfn,
1256+
freelist);
12571257

12581258
/* free pgd */
12591259
if (start_pfn == 0 && last_pfn == DOMAIN_MAX_PFN(domain->gaw)) {
@@ -2011,7 +2011,8 @@ static void domain_exit(struct dmar_domain *domain)
20112011
if (domain->pgd) {
20122012
struct page *freelist;
20132013

2014-
freelist = domain_unmap(domain, 0, DOMAIN_MAX_PFN(domain->gaw));
2014+
freelist = domain_unmap(domain, 0,
2015+
DOMAIN_MAX_PFN(domain->gaw), NULL);
20152016
dma_free_pagelist(freelist);
20162017
}
20172018

@@ -3570,7 +3571,7 @@ static void intel_unmap(struct device *dev, dma_addr_t dev_addr, size_t size)
35703571
if (dev_is_pci(dev))
35713572
pdev = to_pci_dev(dev);
35723573

3573-
freelist = domain_unmap(domain, start_pfn, last_pfn);
3574+
freelist = domain_unmap(domain, start_pfn, last_pfn, NULL);
35743575
if (intel_iommu_strict || (pdev && pdev->untrusted) ||
35753576
!has_iova_flush_queue(&domain->iovad)) {
35763577
iommu_flush_iotlb_psi(iommu, domain, start_pfn,
@@ -4636,7 +4637,8 @@ static int intel_iommu_memory_notifier(struct notifier_block *nb,
46364637
struct page *freelist;
46374638

46384639
freelist = domain_unmap(si_domain,
4639-
start_vpfn, last_vpfn);
4640+
start_vpfn, last_vpfn,
4641+
NULL);
46404642

46414643
rcu_read_lock();
46424644
for_each_active_iommu(iommu, drhd)
@@ -5608,10 +5610,8 @@ static size_t intel_iommu_unmap(struct iommu_domain *domain,
56085610
struct iommu_iotlb_gather *gather)
56095611
{
56105612
struct dmar_domain *dmar_domain = to_dmar_domain(domain);
5611-
struct page *freelist = NULL;
56125613
unsigned long start_pfn, last_pfn;
5613-
unsigned int npages;
5614-
int iommu_id, level = 0;
5614+
int level = 0;
56155615

56165616
/* Cope with horrid API which requires us to unmap more than the
56175617
size argument if it happens to be a large-page mapping. */
@@ -5623,22 +5623,38 @@ static size_t intel_iommu_unmap(struct iommu_domain *domain,
56235623
start_pfn = iova >> VTD_PAGE_SHIFT;
56245624
last_pfn = (iova + size - 1) >> VTD_PAGE_SHIFT;
56255625

5626-
freelist = domain_unmap(dmar_domain, start_pfn, last_pfn);
5627-
5628-
npages = last_pfn - start_pfn + 1;
5629-
5630-
for_each_domain_iommu(iommu_id, dmar_domain)
5631-
iommu_flush_iotlb_psi(g_iommus[iommu_id], dmar_domain,
5632-
start_pfn, npages, !freelist, 0);
5633-
5634-
dma_free_pagelist(freelist);
5626+
gather->freelist = domain_unmap(dmar_domain, start_pfn,
5627+
last_pfn, gather->freelist);
56355628

56365629
if (dmar_domain->max_addr == iova + size)
56375630
dmar_domain->max_addr = iova;
56385631

5632+
iommu_iotlb_gather_add_page(domain, gather, iova, size);
5633+
56395634
return size;
56405635
}
56415636

5637+
static void intel_iommu_tlb_sync(struct iommu_domain *domain,
5638+
struct iommu_iotlb_gather *gather)
5639+
{
5640+
struct dmar_domain *dmar_domain = to_dmar_domain(domain);
5641+
unsigned long iova_pfn = IOVA_PFN(gather->start);
5642+
size_t size = gather->end - gather->start;
5643+
unsigned long start_pfn, last_pfn;
5644+
unsigned long nrpages;
5645+
int iommu_id;
5646+
5647+
nrpages = aligned_nrpages(gather->start, size);
5648+
start_pfn = mm_to_dma_pfn(iova_pfn);
5649+
last_pfn = start_pfn + nrpages - 1;
5650+
5651+
for_each_domain_iommu(iommu_id, dmar_domain)
5652+
iommu_flush_iotlb_psi(g_iommus[iommu_id], dmar_domain,
5653+
start_pfn, nrpages, !gather->freelist, 0);
5654+
5655+
dma_free_pagelist(gather->freelist);
5656+
}
5657+
56425658
static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
56435659
dma_addr_t iova)
56445660
{
@@ -6098,6 +6114,7 @@ const struct iommu_ops intel_iommu_ops = {
60986114
.aux_get_pasid = intel_iommu_aux_get_pasid,
60996115
.map = intel_iommu_map,
61006116
.unmap = intel_iommu_unmap,
6117+
.iotlb_sync = intel_iommu_tlb_sync,
61016118
.iova_to_phys = intel_iommu_iova_to_phys,
61026119
.probe_device = intel_iommu_probe_device,
61036120
.probe_finalize = intel_iommu_probe_finalize,

include/linux/iommu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ struct iommu_iotlb_gather {
180180
unsigned long start;
181181
unsigned long end;
182182
size_t pgsize;
183+
struct page *freelist;
183184
};
184185

185186
/**

0 commit comments

Comments
 (0)