diff options
author | kib <kib@FreeBSD.org> | 2015-04-15 06:56:51 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2015-04-15 06:56:51 +0000 |
commit | 57545f1ca451f45fa9e72cfa938b983da7d593bb (patch) | |
tree | 01e14dc9ec6199e222cea6deafff42ad8e059697 /sys/x86 | |
parent | adf6ad45fa9da4466db74821b4aa048482b8430d (diff) | |
download | FreeBSD-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.c | 18 | ||||
-rw-r--r-- | sys/x86/iommu/intel_dmar.h | 2 | ||||
-rw-r--r-- | sys/x86/iommu/intel_gas.c | 33 |
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); |