aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/libvfio-user.h1
-rw-r--r--lib/dma.c8
-rw-r--r--lib/dma.h23
-rw-r--r--test/unit-tests.c26
4 files changed, 44 insertions, 14 deletions
diff --git a/include/libvfio-user.h b/include/libvfio-user.h
index 89e1c85..a39b5f4 100644
--- a/include/libvfio-user.h
+++ b/include/libvfio-user.h
@@ -67,6 +67,7 @@ typedef struct {
int region; /* TODO replace region and length with struct iovec */
int length;
uint64_t offset;
+ bool mappable;
} dma_sg_t;
typedef struct vfu_ctx vfu_ctx_t;
diff --git a/lib/dma.c b/lib/dma.c
index 0bb623c..69b3fe5 100644
--- a/lib/dma.c
+++ b/lib/dma.c
@@ -375,13 +375,7 @@ _dma_addr_sg_split(const dma_controller_t *dma,
size_t region_len = MIN(region_end - dma_addr, len);
if (cnt < max_sg) {
- sg[cnt].dma_addr = region->dma_addr;
- sg[cnt].region = idx;
- sg[cnt].offset = dma_addr - region->dma_addr;
- sg[cnt].length = region_len;
- if (_dma_should_mark_dirty(dma, prot)) {
- _dma_mark_dirty(dma, region, sg);
- }
+ dma_init_sg(dma, sg, dma_addr, region_len, prot, idx);
}
cnt++;
diff --git a/lib/dma.h b/lib/dma.h
index aeed9bb..7bab3da 100644
--- a/lib/dma.h
+++ b/lib/dma.h
@@ -181,6 +181,21 @@ _dma_mark_dirty(const dma_controller_t *dma, const dma_memory_region_t *region,
}
}
+static inline void
+dma_init_sg(const dma_controller_t *dma, dma_sg_t *sg, dma_addr_t dma_addr,
+ uint32_t len, int prot, int region_index)
+{
+ const dma_memory_region_t *const region = &dma->regions[region_index];
+ sg->dma_addr = region->dma_addr;
+ sg->region = region_index;
+ sg->offset = dma_addr - region->dma_addr;
+ sg->length = len;
+ if (_dma_should_mark_dirty(dma, prot)) {
+ _dma_mark_dirty(dma, region, sg);
+ }
+ sg->mappable = region->virt_addr != NULL;
+}
+
/* Takes a linear dma address span and returns a sg list suitable for DMA.
* A single linear dma address span may need to be split into multiple
* scatter gather regions due to limitations of how memory can be mapped.
@@ -207,13 +222,7 @@ dma_addr_to_sg(const dma_controller_t *dma,
if (likely(max_sg > 0 && len > 0 &&
dma_addr >= region->dma_addr && dma_addr + len <= region_end &&
region_hint < dma->nregions)) {
- sg->dma_addr = region->dma_addr;
- sg->region = region_hint;
- sg->offset = dma_addr - region->dma_addr;
- sg->length = len;
- if (_dma_should_mark_dirty(dma, prot)) {
- _dma_mark_dirty(dma, region, sg);
- }
+ dma_init_sg(dma, sg, dma_addr, len, prot, region_hint);
return 1;
}
// Slow path: search through regions.
diff --git a/test/unit-tests.c b/test/unit-tests.c
index 6355843..9063038 100644
--- a/test/unit-tests.c
+++ b/test/unit-tests.c
@@ -681,6 +681,31 @@ test_dma_map_sg(void **state __attribute__((unused)))
}
static void
+test_dma_addr_to_sg(void **state __attribute__((unused)))
+{
+ dma_controller_t *dma = alloca(sizeof(dma_controller_t) + sizeof(dma_memory_region_t));
+ dma_sg_t sg;
+ dma_memory_region_t *r;
+
+ dma->nregions = 1;
+ r = &dma->regions[0];
+ r->dma_addr = 0x1000;
+ r->size = 0x4000;
+ r->virt_addr = (void*)0xdeadbeef;
+
+ /* fast path, region hint hit */
+ assert_int_equal(1,
+ dma_addr_to_sg(dma, 0x2000, 0x400, &sg, 1, PROT_NONE));
+ assert_int_equal(r->dma_addr, sg.dma_addr);
+ assert_int_equal(0, sg.region);
+ assert_int_equal(0x2000 - r->dma_addr, sg.offset);
+ assert_int_equal(0x400, sg.length);
+ assert_true(sg.mappable);
+
+ /* TODO test more scenarios */
+}
+
+static void
test_vfu_setup_device_dma_cb(void **state __attribute__((unused)))
{
vfu_ctx_t vfu_ctx = { 0 };
@@ -722,6 +747,7 @@ int main(void)
cmocka_unit_test_setup(test_setup_sparse_region, setup),
cmocka_unit_test_setup(test_dma_map_return_value, setup),
cmocka_unit_test_setup(test_dma_map_sg, setup),
+ cmocka_unit_test_setup(test_dma_addr_to_sg, setup),
cmocka_unit_test_setup(test_vfu_setup_device_dma_cb, setup)
};