Author: kib
Date: Wed Apr 15 06:56:51 2015
New Revision: 281545
URL: https://svnweb.freebsd.org/changeset/base/281545

Log:
  MFC r281254:
  Account for the offset of the page run when allocating the
  dmar_map_entry.

Modified:
  stable/10/sys/x86/iommu/busdma_dmar.c
  stable/10/sys/x86/iommu/intel_dmar.h
  stable/10/sys/x86/iommu/intel_gas.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/x86/iommu/busdma_dmar.c
==============================================================================
--- stable/10/sys/x86/iommu/busdma_dmar.c       Wed Apr 15 05:24:39 2015        
(r281544)
+++ stable/10/sys/x86/iommu/busdma_dmar.c       Wed Apr 15 06:56:51 2015        
(r281545)
@@ -459,6 +459,7 @@ dmar_bus_dmamap_load_something1(struct b
        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 b
                }
                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 b
                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 b
                            (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 b
                    (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 b
                idx += OFF_TO_IDX(trunc_page(offset + buflen1));
                offset += buflen1;
                offset &= DMAR_PAGE_MASK;
+               buflen -= buflen1;
        }
        if (error == 0)
                *segp = seg;

Modified: stable/10/sys/x86/iommu/intel_dmar.h
==============================================================================
--- stable/10/sys/x86/iommu/intel_dmar.h        Wed Apr 15 05:24:39 2015        
(r281544)
+++ stable/10/sys/x86/iommu/intel_dmar.h        Wed Apr 15 06:56:51 2015        
(r281545)
@@ -289,7 +289,7 @@ struct dmar_map_entry *dmar_gas_alloc_en
 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,

Modified: stable/10/sys/x86/iommu/intel_gas.c
==============================================================================
--- stable/10/sys/x86/iommu/intel_gas.c Wed Apr 15 05:24:39 2015        
(r281544)
+++ stable/10/sys/x86/iommu/intel_gas.c Wed Apr 15 06:56:51 2015        
(r281545)
@@ -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
 
        /* 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_matc
                        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_matc
 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 *ct
 
 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
        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);
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to