Skip to content

Commit 99fb8af

Browse files
jgunthorpejoergroedel
authored andcommitted
iommupt: Directly call iommupt's unmap_range()
The common algorithm in iommupt does not require the iommu_pgsize() calculations, it can directly unmap any arbitrary range. Add a new function pointer to directly call an iommupt unmap_range op and make __iommu_unmap() call it directly. Gives about a 5% gain on single page unmappings. The function pointer is run through pt_iommu_ops instead of iommu_domain_ops to discourage using it outside iommupt. All drivers with their own page tables should continue to use the simplified map/unmap_pages() style interfaces. Reviewed-by: Samiullah Khawaja <skhawaja@google.com> Reviewed-by: Kevin Tian <kevin.tian@intel.com> Signed-off-by: Jason Gunthorpe <jgg@nvidia.com> Reviewed-by: Lu Baolu <baolu.lu@linux.intel.com> Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
1 parent fa8fb60 commit 99fb8af

4 files changed

Lines changed: 57 additions & 37 deletions

File tree

drivers/iommu/generic_pt/iommu_pt.h

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,34 +1031,12 @@ static __maybe_unused int __unmap_range(struct pt_range *range, void *arg,
10311031
return ret;
10321032
}
10331033

1034-
/**
1035-
* unmap_pages() - Make a range of IOVA empty/not present
1036-
* @domain: Domain to manipulate
1037-
* @iova: IO virtual address to start
1038-
* @pgsize: Length of each page
1039-
* @pgcount: Length of the range in pgsize units starting from @iova
1040-
* @iotlb_gather: Gather struct that must be flushed on return
1041-
*
1042-
* unmap_pages() will remove a translation created by map_pages(). It cannot
1043-
* subdivide a mapping created by map_pages(), so it should be called with IOVA
1044-
* ranges that match those passed to map_pages(). The IOVA range can aggregate
1045-
* contiguous map_pages() calls so long as no individual range is split.
1046-
*
1047-
* Context: The caller must hold a write range lock that includes
1048-
* the whole range.
1049-
*
1050-
* Returns: Number of bytes of VA unmapped. iova + res will be the point
1051-
* unmapping stopped.
1052-
*/
1053-
size_t DOMAIN_NS(unmap_pages)(struct iommu_domain *domain, unsigned long iova,
1054-
size_t pgsize, size_t pgcount,
1034+
static size_t NS(unmap_range)(struct pt_iommu *iommu_table, dma_addr_t iova,
1035+
dma_addr_t len,
10551036
struct iommu_iotlb_gather *iotlb_gather)
10561037
{
1057-
struct pt_iommu *iommu_table =
1058-
container_of(domain, struct pt_iommu, domain);
10591038
struct pt_unmap_args unmap = { .free_list = IOMMU_PAGES_LIST_INIT(
10601039
unmap.free_list) };
1061-
pt_vaddr_t len = pgsize * pgcount;
10621040
struct pt_range range;
10631041
int ret;
10641042

@@ -1073,7 +1051,6 @@ size_t DOMAIN_NS(unmap_pages)(struct iommu_domain *domain, unsigned long iova,
10731051

10741052
return unmap.unmapped;
10751053
}
1076-
EXPORT_SYMBOL_NS_GPL(DOMAIN_NS(unmap_pages), "GENERIC_PT_IOMMU");
10771054

10781055
static void NS(get_info)(struct pt_iommu *iommu_table,
10791056
struct pt_iommu_info *info)
@@ -1121,6 +1098,7 @@ static void NS(deinit)(struct pt_iommu *iommu_table)
11211098
}
11221099

11231100
static const struct pt_iommu_ops NS(ops) = {
1101+
.unmap_range = NS(unmap_range),
11241102
#if IS_ENABLED(CONFIG_IOMMUFD_DRIVER) && defined(pt_entry_is_write_dirty) && \
11251103
IS_ENABLED(CONFIG_IOMMUFD_TEST) && defined(pt_entry_make_write_dirty)
11261104
.set_dirty = NS(set_dirty),
@@ -1183,6 +1161,7 @@ static int pt_iommu_init_domain(struct pt_iommu *iommu_table,
11831161

11841162
domain->type = __IOMMU_DOMAIN_PAGING;
11851163
domain->pgsize_bitmap = info.pgsize_bitmap;
1164+
domain->is_iommupt = true;
11861165

11871166
if (pt_feature(common, PT_FEAT_DYNAMIC_TOP))
11881167
range = _pt_top_range(common,

drivers/iommu/iommu.c

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <linux/sched/mm.h>
3535
#include <linux/msi.h>
3636
#include <uapi/linux/iommufd.h>
37+
#include <linux/generic_pt/iommu.h>
3738

3839
#include "dma-iommu.h"
3940
#include "iommu-priv.h"
@@ -2666,13 +2667,12 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova,
26662667
}
26672668
EXPORT_SYMBOL_GPL(iommu_map);
26682669

2669-
static size_t __iommu_unmap(struct iommu_domain *domain,
2670-
unsigned long iova, size_t size,
2671-
struct iommu_iotlb_gather *iotlb_gather)
2670+
static size_t
2671+
__iommu_unmap_domain_pgtbl(struct iommu_domain *domain, unsigned long iova,
2672+
size_t size, struct iommu_iotlb_gather *iotlb_gather)
26722673
{
26732674
const struct iommu_domain_ops *ops = domain->ops;
26742675
size_t unmapped_page, unmapped = 0;
2675-
unsigned long orig_iova = iova;
26762676
unsigned int min_pagesz;
26772677

26782678
if (unlikely(!(domain->type & __IOMMU_DOMAIN_PAGING)))
@@ -2718,8 +2718,23 @@ static size_t __iommu_unmap(struct iommu_domain *domain,
27182718
unmapped += unmapped_page;
27192719
}
27202720

2721-
trace_unmap(orig_iova, size, unmapped);
2722-
iommu_debug_unmap_end(domain, orig_iova, size, unmapped);
2721+
return unmapped;
2722+
}
2723+
2724+
static size_t __iommu_unmap(struct iommu_domain *domain, unsigned long iova,
2725+
size_t size,
2726+
struct iommu_iotlb_gather *iotlb_gather)
2727+
{
2728+
struct pt_iommu *pt = iommupt_from_domain(domain);
2729+
size_t unmapped;
2730+
2731+
if (pt)
2732+
unmapped = pt->ops->unmap_range(pt, iova, size, iotlb_gather);
2733+
else
2734+
unmapped = __iommu_unmap_domain_pgtbl(domain, iova, size,
2735+
iotlb_gather);
2736+
trace_unmap(iova, size, unmapped);
2737+
iommu_debug_unmap_end(domain, iova, size, unmapped);
27232738
return unmapped;
27242739
}
27252740

include/linux/generic_pt/iommu.h

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ struct pt_iommu {
6666
struct device *iommu_device;
6767
};
6868

69+
static inline struct pt_iommu *iommupt_from_domain(struct iommu_domain *domain)
70+
{
71+
if (!IS_ENABLED(CONFIG_IOMMU_PT) || !domain->is_iommupt)
72+
return NULL;
73+
return container_of(domain, struct pt_iommu, domain);
74+
}
75+
6976
/**
7077
* struct pt_iommu_info - Details about the IOMMU page table
7178
*
@@ -80,6 +87,29 @@ struct pt_iommu_info {
8087
};
8188

8289
struct pt_iommu_ops {
90+
/**
91+
* @unmap_range: Make a range of IOVA empty/not present
92+
* @iommu_table: Table to manipulate
93+
* @iova: IO virtual address to start
94+
* @len: Length of the range starting from @iova
95+
* @iotlb_gather: Gather struct that must be flushed on return
96+
*
97+
* unmap_range() will remove a translation created by map_range(). It
98+
* cannot subdivide a mapping created by map_range(), so it should be
99+
* called with IOVA ranges that match those passed to map_pages. The
100+
* IOVA range can aggregate contiguous map_range() calls so long as no
101+
* individual range is split.
102+
*
103+
* Context: The caller must hold a write range lock that includes
104+
* the whole range.
105+
*
106+
* Returns: Number of bytes of VA unmapped. iova + res will be the
107+
* point unmapping stopped.
108+
*/
109+
size_t (*unmap_range)(struct pt_iommu *iommu_table, dma_addr_t iova,
110+
dma_addr_t len,
111+
struct iommu_iotlb_gather *iotlb_gather);
112+
83113
/**
84114
* @set_dirty: Make the iova write dirty
85115
* @iommu_table: Table to manipulate
@@ -198,10 +228,6 @@ struct pt_iommu_cfg {
198228
unsigned long iova, phys_addr_t paddr, \
199229
size_t pgsize, size_t pgcount, \
200230
int prot, gfp_t gfp, size_t *mapped); \
201-
size_t pt_iommu_##fmt##_unmap_pages( \
202-
struct iommu_domain *domain, unsigned long iova, \
203-
size_t pgsize, size_t pgcount, \
204-
struct iommu_iotlb_gather *iotlb_gather); \
205231
int pt_iommu_##fmt##_read_and_clear_dirty( \
206232
struct iommu_domain *domain, unsigned long iova, size_t size, \
207233
unsigned long flags, struct iommu_dirty_bitmap *dirty); \
@@ -223,8 +249,7 @@ struct pt_iommu_cfg {
223249
*/
224250
#define IOMMU_PT_DOMAIN_OPS(fmt) \
225251
.iova_to_phys = &pt_iommu_##fmt##_iova_to_phys, \
226-
.map_pages = &pt_iommu_##fmt##_map_pages, \
227-
.unmap_pages = &pt_iommu_##fmt##_unmap_pages
252+
.map_pages = &pt_iommu_##fmt##_map_pages
228253
#define IOMMU_PT_DIRTY_OPS(fmt) \
229254
.read_and_clear_dirty = &pt_iommu_##fmt##_read_and_clear_dirty
230255

include/linux/iommu.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ enum iommu_domain_cookie_type {
223223
struct iommu_domain {
224224
unsigned type;
225225
enum iommu_domain_cookie_type cookie_type;
226+
bool is_iommupt;
226227
const struct iommu_domain_ops *ops;
227228
const struct iommu_dirty_ops *dirty_ops;
228229
const struct iommu_ops *owner; /* Whose domain_alloc we came from */

0 commit comments

Comments
 (0)