IOMMU: have iommu_{,un}map() split requests into largest possible chunks

Introduce a helper function to determine the largest possible mapping
that allows covering a request (or the next part of it that is left to
be processed).

In order to not add yet more recurring dfn_add() / mfn_add() to the two
callers of the new helper, also introduce local variables holding the
values presently operated on.

Note that strictly speaking iommu_unmap() doen't need to consult
mapping_order(), as unmapping doesn't require superpage support. This,
however, prevents freeing of deep hierarchies of page tables in vendor
code (once suitably enabled), which otherwise would require dealing with
preemption needs.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
This commit is contained in:
Jan Beulich committed 2022-05-20 12:23:31 +02:00
1 parent e0de7c2ee6
commit ba3fcb5f52
1 file changed
+47 -12
+47 -12
View File
@@ -283,12 +283,38 @@ void iommu_domain_destroy(struct domain *d)
arch_iommu_domain_destroy(d);
}
int iommu_map(struct domain *d, dfn_t dfn, mfn_t mfn,
static unsigned int mapping_order(const struct domain_iommu *hd,
dfn_t dfn, mfn_t mfn, unsigned long nr)
{
unsigned long res = dfn_x(dfn) | mfn_x(mfn);
unsigned long sizes = hd->platform_ops->page_sizes;
unsigned int bit = find_first_set_bit(sizes), order = 0;
ASSERT(bit == PAGE_SHIFT);
while ( (sizes = (sizes >> bit) & ~1) )
{
unsigned long mask;
bit = find_first_set_bit(sizes);
mask = (1UL << bit) - 1;
if ( nr <= mask || (res & mask) )
break;
order += bit;
nr >>= bit;
res >>= bit;
}
return order;
}
int iommu_map(struct domain *d, dfn_t dfn0, mfn_t mfn0,
unsigned long page_count, unsigned int flags,
unsigned int *flush_flags)
{
const struct domain_iommu *hd = dom_iommu(d);
unsigned long i;
unsigned int order;
int rc = 0;
if ( !is_iommu_enabled(d) )
@@ -296,10 +322,15 @@ int iommu_map(struct domain *d, dfn_t dfn, mfn_t mfn,
ASSERT(!IOMMUF_order(flags));
for ( i = 0; i < page_count; i++ )
for ( i = 0; i < page_count; i += 1UL << order )
{
rc = iommu_call(hd->platform_ops, map_page, d, dfn_add(dfn, i),
mfn_add(mfn, i), flags, flush_flags);
dfn_t dfn = dfn_add(dfn0, i);
mfn_t mfn = mfn_add(mfn0, i);
order = mapping_order(hd, dfn, mfn, page_count - i);
rc = iommu_call(hd->platform_ops, map_page, d, dfn, mfn,
flags | IOMMUF_order(order), flush_flags);
if ( likely(!rc) )
continue;
@@ -307,11 +338,10 @@ int iommu_map(struct domain *d, dfn_t dfn, mfn_t mfn,
if ( !d->is_shutting_down && printk_ratelimit() )
printk(XENLOG_ERR
"d%d: IOMMU mapping dfn %"PRI_dfn" to mfn %"PRI_mfn" failed: %d\n",
d->domain_id, dfn_x(dfn_add(dfn, i)),
mfn_x(mfn_add(mfn, i)), rc);
d->domain_id, dfn_x(dfn), mfn_x(mfn), rc);
/* while statement to satisfy __must_check */
while ( iommu_unmap(d, dfn, i, flush_flags) )
while ( iommu_unmap(d, dfn0, i, flush_flags) )
break;
if ( !is_hardware_domain(d) )
@@ -343,20 +373,25 @@ int iommu_legacy_map(struct domain *d, dfn_t dfn, mfn_t mfn,
return rc;
}
int iommu_unmap(struct domain *d, dfn_t dfn, unsigned long page_count,
int iommu_unmap(struct domain *d, dfn_t dfn0, unsigned long page_count,
unsigned int *flush_flags)
{
const struct domain_iommu *hd = dom_iommu(d);
unsigned long i;
unsigned int order;
int rc = 0;
if ( !is_iommu_enabled(d) )
return 0;
for ( i = 0; i < page_count; i++ )
for ( i = 0; i < page_count; i += 1UL << order )
{
int err = iommu_call(hd->platform_ops, unmap_page, d, dfn_add(dfn, i),
0, flush_flags);
dfn_t dfn = dfn_add(dfn0, i);
int err;
order = mapping_order(hd, dfn, _mfn(0), page_count - i);
err = iommu_call(hd->platform_ops, unmap_page, d, dfn,
order, flush_flags);
if ( likely(!err) )
continue;
@@ -364,7 +399,7 @@ int iommu_unmap(struct domain *d, dfn_t dfn, unsigned long page_count,
if ( !d->is_shutting_down && printk_ratelimit() )
printk(XENLOG_ERR
"d%d: IOMMU unmapping dfn %"PRI_dfn" failed: %d\n",
d->domain_id, dfn_x(dfn_add(dfn, i)), err);
d->domain_id, dfn_x(dfn), err);
if ( !rc )
rc = err;
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.