Page MenuHomeFreeBSD

D36624.diff
No OneTemporary

D36624.diff

diff --git a/sys/dev/iommu/iommu.h b/sys/dev/iommu/iommu.h
--- a/sys/dev/iommu/iommu.h
+++ b/sys/dev/iommu/iommu.h
@@ -109,6 +109,7 @@
struct iommu_map_entries_tailq unload_entries; /* (d) Entries to
unload */
struct iommu_gas_entries_tree rb_root; /* (d) */
+ struct iommu_map_entry *start_gap; /* (d) */
iommu_gaddr_t end; /* (c) Highest address + 1 in
the guest AS */
struct iommu_map_entry *first_place, *last_place; /* (d) */
diff --git a/sys/dev/iommu/iommu_gas.c b/sys/dev/iommu/iommu_gas.c
--- a/sys/dev/iommu/iommu_gas.c
+++ b/sys/dev/iommu/iommu_gas.c
@@ -209,7 +209,18 @@
static void
iommu_gas_rb_remove(struct iommu_domain *domain, struct iommu_map_entry *entry)
{
-
+ struct iommu_map_entry *nbr;
+
+ /* Removing entry may open a new free gap before domain->start_gap. */
+ if (entry->end <= domain->start_gap->end) {
+ if (RB_RIGHT(entry, rb_entry) != NULL)
+ nbr = iommu_gas_entries_tree_RB_NEXT(entry);
+ else if (RB_LEFT(entry, rb_entry) != NULL)
+ nbr = RB_LEFT(entry, rb_entry);
+ else
+ nbr = RB_PARENT(entry, rb_entry);
+ domain->start_gap = nbr;
+ }
RB_REMOVE(iommu_gas_entries_tree, &domain->rb_root, entry);
}
@@ -253,6 +264,7 @@
begin->flags = IOMMU_MAP_ENTRY_PLACE | IOMMU_MAP_ENTRY_UNMAPPED;
RB_INSERT_PREV(iommu_gas_entries_tree, &domain->rb_root, end, begin);
+ domain->start_gap = end;
domain->first_place = begin;
domain->last_place = end;
domain->flags |= IOMMU_DOMAIN_GAS_INITED;
@@ -296,7 +308,6 @@
}
struct iommu_gas_match_args {
- struct iommu_domain *domain;
iommu_gaddr_t size;
int offset;
const struct bus_dma_tag_common *common;
@@ -395,16 +406,44 @@
return (curr);
}
+/*
+ * Address-ordered first-fit search of 'domain' for free space satisfying the
+ * conditions of 'a'. The space allocated is at least one page big, and is
+ * bounded by guard pages to left and right. The allocated space for 'domain'
+ * is described by an rb-tree of map entries at domain->rb_root, and
+ * domain->start_gap points a map entry less than or adjacent to the first
+ * free-space of size at least 3 pages.
+ */
static int
-iommu_gas_find_space(struct iommu_gas_match_args *a)
+iommu_gas_find_space(struct iommu_domain *domain,
+ struct iommu_gas_match_args *a)
{
- struct iommu_domain *domain;
struct iommu_map_entry *curr, *first;
iommu_gaddr_t addr, min_free;
- IOMMU_DOMAIN_ASSERT_LOCKED(a->domain);
+ IOMMU_DOMAIN_ASSERT_LOCKED(domain);
KASSERT(a->entry->flags == 0,
- ("dirty entry %p %p", a->domain, a->entry));
+ ("dirty entry %p %p", domain, a->entry));
+
+ /*
+ * start_gap may point to an entry adjacent to gaps too small for any
+ * new allocation. In that case, advance start_gap to the first free
+ * space big enough for a minimum allocation plus two guard pages.
+ */
+ min_free = 3 * IOMMU_PAGE_SIZE;
+ first = domain->start_gap;
+ while (first != NULL && first->free_down < min_free)
+ first = RB_PARENT(first, rb_entry);
+ for (curr = first; curr != NULL;
+ curr = iommu_gas_next(curr, min_free)) {
+ if ((first = RB_LEFT(curr, rb_entry)) != NULL &&
+ first->last + min_free <= curr->start)
+ break;
+ if ((first = RB_RIGHT(curr, rb_entry)) != NULL &&
+ curr->end + min_free <= first->first)
+ break;
+ }
+ domain->start_gap = curr;
/*
* If the subtree doesn't have free space for the requested allocation
@@ -413,20 +452,13 @@
min_free = 2 * IOMMU_PAGE_SIZE +
roundup2(a->size + a->offset, IOMMU_PAGE_SIZE);
- /*
- * Find the first entry in the lower region that could abut a big-enough
- * range.
- */
- domain = a->domain;
- curr = RB_ROOT(&domain->rb_root);
- first = NULL;
- while (curr != NULL && curr->free_down >= min_free) {
- first = curr;
- curr = RB_LEFT(curr, rb_entry);
- }
+ /* Climb to find a node in the subtree of big-enough ranges. */
+ first = curr;
+ while (first != NULL && first->free_down < min_free)
+ first = RB_PARENT(first, rb_entry);
/*
- * Walk the big-enough ranges until one satisfies alignment
+ * Walk the big-enough ranges tree until one satisfies alignment
* requirements, or violates lowaddr address requirement.
*/
addr = a->common->lowaddr + 1;
@@ -746,7 +778,6 @@
KASSERT((flags & ~(IOMMU_MF_CANWAIT | IOMMU_MF_CANSPLIT)) == 0,
("invalid flags 0x%x", flags));
- a.domain = domain;
a.size = size;
a.offset = offset;
a.common = common;
@@ -757,7 +788,7 @@
return (ENOMEM);
a.entry = entry;
IOMMU_DOMAIN_LOCK(domain);
- error = iommu_gas_find_space(&a);
+ error = iommu_gas_find_space(domain, &a);
if (error == ENOMEM) {
IOMMU_DOMAIN_UNLOCK(domain);
iommu_gas_free_entry(entry);

File Metadata

Mime Type
text/plain
Expires
Wed, Jan 8, 2:16 PM (1 h, 10 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15718547
Default Alt Text
D36624.diff (4 KB)

Event Timeline