summaryrefslogtreecommitdiffstats
path: root/sys/x86
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2015-04-15 06:56:51 +0000
committerkib <kib@FreeBSD.org>2015-04-15 06:56:51 +0000
commit57545f1ca451f45fa9e72cfa938b983da7d593bb (patch)
tree01e14dc9ec6199e222cea6deafff42ad8e059697 /sys/x86
parentadf6ad45fa9da4466db74821b4aa048482b8430d (diff)
downloadFreeBSD-src-57545f1ca451f45fa9e72cfa938b983da7d593bb.zip
FreeBSD-src-57545f1ca451f45fa9e72cfa938b983da7d593bb.tar.gz
MFC r281254:
Account for the offset of the page run when allocating the dmar_map_entry.
Diffstat (limited to 'sys/x86')
-rw-r--r--sys/x86/iommu/busdma_dmar.c18
-rw-r--r--sys/x86/iommu/intel_dmar.h2
-rw-r--r--sys/x86/iommu/intel_gas.c33
3 files changed, 32 insertions, 21 deletions
diff --git a/sys/x86/iommu/busdma_dmar.c b/sys/x86/iommu/busdma_dmar.c
index d3ba834..b81556c 100644
--- a/sys/x86/iommu/busdma_dmar.c
+++ b/sys/x86/iommu/busdma_dmar.c
@@ -459,6 +459,7 @@ dmar_bus_dmamap_load_something1(struct bus_dma_tag_dmar *tag,
bus_size_t buflen1;
int error, idx, gas_flags, seg;
+ KASSERT(offset < DMAR_PAGE_SIZE, ("offset %d", offset));
if (segs == NULL)
segs = tag->segments;
ctx = tag->ctx;
@@ -473,7 +474,6 @@ dmar_bus_dmamap_load_something1(struct bus_dma_tag_dmar *tag,
}
buflen1 = buflen > tag->common.maxsegsz ?
tag->common.maxsegsz : buflen;
- buflen -= buflen1;
size = round_page(offset + buflen1);
/*
@@ -484,7 +484,7 @@ dmar_bus_dmamap_load_something1(struct bus_dma_tag_dmar *tag,
if (seg + 1 < tag->common.nsegments)
gas_flags |= DMAR_GM_CANSPLIT;
- error = dmar_gas_map(ctx, &tag->common, size,
+ error = dmar_gas_map(ctx, &tag->common, size, offset,
DMAR_MAP_ENTRY_READ | DMAR_MAP_ENTRY_WRITE,
gas_flags, ma + idx, &entry);
if (error != 0)
@@ -503,6 +503,10 @@ dmar_bus_dmamap_load_something1(struct bus_dma_tag_dmar *tag,
(uintmax_t)size, (uintmax_t)entry->start,
(uintmax_t)entry->end));
}
+ if (offset + buflen1 > size)
+ buflen1 = size - offset;
+ if (buflen1 > tag->common.maxsegsz)
+ buflen1 = tag->common.maxsegsz;
KASSERT(((entry->start + offset) & (tag->common.alignment - 1))
== 0,
@@ -516,15 +520,16 @@ dmar_bus_dmamap_load_something1(struct bus_dma_tag_dmar *tag,
(uintmax_t)entry->start, (uintmax_t)entry->end,
(uintmax_t)tag->common.lowaddr,
(uintmax_t)tag->common.highaddr));
- KASSERT(dmar_test_boundary(entry->start, entry->end -
- entry->start, tag->common.boundary),
+ KASSERT(dmar_test_boundary(entry->start + offset, buflen1,
+ tag->common.boundary),
("boundary failed: ctx %p start 0x%jx end 0x%jx "
"boundary 0x%jx", ctx, (uintmax_t)entry->start,
(uintmax_t)entry->end, (uintmax_t)tag->common.boundary));
KASSERT(buflen1 <= tag->common.maxsegsz,
("segment too large: ctx %p start 0x%jx end 0x%jx "
- "maxsegsz 0x%jx", ctx, (uintmax_t)entry->start,
- (uintmax_t)entry->end, (uintmax_t)tag->common.maxsegsz));
+ "buflen1 0x%jx maxsegsz 0x%jx", ctx,
+ (uintmax_t)entry->start, (uintmax_t)entry->end,
+ (uintmax_t)buflen1, (uintmax_t)tag->common.maxsegsz));
DMAR_CTX_LOCK(ctx);
TAILQ_INSERT_TAIL(&map->map_entries, entry, dmamap_link);
@@ -538,6 +543,7 @@ dmar_bus_dmamap_load_something1(struct bus_dma_tag_dmar *tag,
idx += OFF_TO_IDX(trunc_page(offset + buflen1));
offset += buflen1;
offset &= DMAR_PAGE_MASK;
+ buflen -= buflen1;
}
if (error == 0)
*segp = seg;
diff --git a/sys/x86/iommu/intel_dmar.h b/sys/x86/iommu/intel_dmar.h
index 0f5c6c9..974fa32 100644
--- a/sys/x86/iommu/intel_dmar.h
+++ b/sys/x86/iommu/intel_dmar.h
@@ -289,7 +289,7 @@ struct dmar_map_entry *dmar_gas_alloc_entry(struct dmar_ctx *ctx, u_int flags);
void dmar_gas_free_entry(struct dmar_ctx *ctx, struct dmar_map_entry *entry);
void dmar_gas_free_space(struct dmar_ctx *ctx, struct dmar_map_entry *entry);
int dmar_gas_map(struct dmar_ctx *ctx, const struct bus_dma_tag_common *common,
- dmar_gaddr_t size, u_int eflags, u_int flags, vm_page_t *ma,
+ dmar_gaddr_t size, int offset, u_int eflags, u_int flags, vm_page_t *ma,
struct dmar_map_entry **res);
void dmar_gas_free_region(struct dmar_ctx *ctx, struct dmar_map_entry *entry);
int dmar_gas_map_region(struct dmar_ctx *ctx, struct dmar_map_entry *entry,
diff --git a/sys/x86/iommu/intel_gas.c b/sys/x86/iommu/intel_gas.c
index 0957df3..ad7b146 100644
--- a/sys/x86/iommu/intel_gas.c
+++ b/sys/x86/iommu/intel_gas.c
@@ -293,6 +293,7 @@ dmar_gas_fini_ctx(struct dmar_ctx *ctx)
struct dmar_gas_match_args {
struct dmar_ctx *ctx;
dmar_gaddr_t size;
+ int offset;
const struct bus_dma_tag_common *common;
u_int gas_flags;
struct dmar_map_entry *entry;
@@ -309,25 +310,28 @@ dmar_gas_match_one(struct dmar_gas_match_args *a, struct dmar_map_entry *prev,
/* DMAR_PAGE_SIZE to create gap after new entry. */
if (a->entry->start < prev->end + DMAR_PAGE_SIZE ||
- a->entry->start + a->size + DMAR_PAGE_SIZE > prev->end +
- prev->free_after)
+ a->entry->start + a->size + a->offset + DMAR_PAGE_SIZE >
+ prev->end + prev->free_after)
return (false);
/* No boundary crossing. */
- if (dmar_test_boundary(a->entry->start, a->size, a->common->boundary))
+ if (dmar_test_boundary(a->entry->start + a->offset, a->size,
+ a->common->boundary))
return (true);
/*
- * The start to start + size region crosses the boundary.
- * Check if there is enough space after the next boundary
- * after the prev->end.
+ * The start + offset to start + offset + size region crosses
+ * the boundary. Check if there is enough space after the
+ * next boundary after the prev->end.
*/
- bs = (a->entry->start + a->common->boundary) & ~(a->common->boundary
- - 1);
+ bs = (a->entry->start + a->offset + a->common->boundary) &
+ ~(a->common->boundary - 1);
start = roundup2(bs, a->common->alignment);
/* DMAR_PAGE_SIZE to create gap after new entry. */
- if (start + a->size + DMAR_PAGE_SIZE <= prev->end + prev->free_after &&
- start + a->size <= end && dmar_test_boundary(start, a->size,
+ if (start + a->offset + a->size + DMAR_PAGE_SIZE <=
+ prev->end + prev->free_after &&
+ start + a->offset + a->size <= end &&
+ dmar_test_boundary(start + a->offset, a->size,
a->common->boundary)) {
a->entry->start = start;
return (true);
@@ -409,7 +413,7 @@ dmar_gas_lowermatch(struct dmar_gas_match_args *a, struct dmar_map_entry *prev)
return (0);
}
}
- if (prev->free_down < a->size + DMAR_PAGE_SIZE)
+ if (prev->free_down < a->size + a->offset + DMAR_PAGE_SIZE)
return (ENOMEM);
l = RB_LEFT(prev, rb_entry);
if (l != NULL) {
@@ -465,7 +469,7 @@ dmar_gas_uppermatch(struct dmar_gas_match_args *a)
static int
dmar_gas_find_space(struct dmar_ctx *ctx,
const struct bus_dma_tag_common *common, dmar_gaddr_t size,
- u_int flags, struct dmar_map_entry *entry)
+ int offset, u_int flags, struct dmar_map_entry *entry)
{
struct dmar_gas_match_args a;
int error;
@@ -476,6 +480,7 @@ dmar_gas_find_space(struct dmar_ctx *ctx,
a.ctx = ctx;
a.size = size;
+ a.offset = offset;
a.common = common;
a.gas_flags = flags;
a.entry = entry;
@@ -617,7 +622,7 @@ dmar_gas_free_region(struct dmar_ctx *ctx, struct dmar_map_entry *entry)
int
dmar_gas_map(struct dmar_ctx *ctx, const struct bus_dma_tag_common *common,
- dmar_gaddr_t size, u_int eflags, u_int flags, vm_page_t *ma,
+ dmar_gaddr_t size, int offset, u_int eflags, u_int flags, vm_page_t *ma,
struct dmar_map_entry **res)
{
struct dmar_map_entry *entry;
@@ -631,7 +636,7 @@ dmar_gas_map(struct dmar_ctx *ctx, const struct bus_dma_tag_common *common,
if (entry == NULL)
return (ENOMEM);
DMAR_CTX_LOCK(ctx);
- error = dmar_gas_find_space(ctx, common, size, flags, entry);
+ error = dmar_gas_find_space(ctx, common, size, offset, flags, entry);
if (error == ENOMEM) {
DMAR_CTX_UNLOCK(ctx);
dmar_gas_free_entry(ctx, entry);
OpenPOWER on IntegriCloud