aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Callanan <spyffe@google.com>2019-11-27 16:39:24 -0800
committerandroid-build-merger <android-build-merger@google.com>2019-11-27 16:39:24 -0800
commitbe62c784dbba55ebf057b7498325648e86462ff2 (patch)
tree850a6f81ff1d27569736452389a2e9a4fb1b9093
parent0d5e3ba4977cd6b99c7a309c53cc14adce490ed8 (diff)
parent839bbf47aa8e19169e17fcbb6a79c68fffa3d820 (diff)
downloadplatform_external_igt-gpu-tools-be62c784dbba55ebf057b7498325648e86462ff2.tar.gz
platform_external_igt-gpu-tools-be62c784dbba55ebf057b7498325648e86462ff2.tar.bz2
platform_external_igt-gpu-tools-be62c784dbba55ebf057b7498325648e86462ff2.zip
igt-gpu-tools: add tests for ion/gem interaction am: 2db11e1cbb am: 7553c470d4
am: 839bbf47aa Change-Id: I1ce28d05c7a0501b95f4e7b1f167566a3835fc89
-rw-r--r--Android.bp13
-rw-r--r--lib/gem.c119
-rw-r--r--lib/gem.h85
-rw-r--r--lib/gem_msm.c68
-rw-r--r--lib/gem_msm.h8
-rw-r--r--lib/ion.c180
-rw-r--r--lib/ion.h108
-rw-r--r--tests/ion_fb.c223
8 files changed, 802 insertions, 2 deletions
diff --git a/Android.bp b/Android.bp
index 77b8b0ee..e970a854 100644
--- a/Android.bp
+++ b/Android.bp
@@ -10,7 +10,7 @@ cc_defaults {
"-DHAVE_LIBGEN_H",
"-DHAVE_MEMFD_CREATE",
],
- static_libs: ["libelf", "libkmod"],
+ static_libs: ["libelf", "libkmod", "libion", "liblog"],
shared_libs: ["libdrm"],
}
@@ -19,6 +19,8 @@ cc_library_static {
defaults: ["igt-gpu-tools-defaults"],
srcs: [
"lib/drmtest.c",
+ "lib/gem.c",
+ "lib/gem_msm.c",
"lib/igt_aux.c",
"lib/igt_core.c",
"lib/igt_debugfs.c",
@@ -29,11 +31,13 @@ cc_library_static {
"lib/igt_kms.c",
"lib/igt_stats.c",
"lib/igt_sysfs.c",
+ "lib/ion.c",
"lib/ioctl_wrappers.c",
"lib/i915/gem_mman.c",
- "lib/uwildmat/uwildmat.c"
+ "lib/uwildmat/uwildmat.c",
],
export_include_dirs: [
+ "include",
"lib",
"lib/stubs/drm",
"prebuilt-intermediates",
@@ -58,3 +62,8 @@ cc_test {
srcs: ["tests/kms_flip.c"],
}
+cc_test {
+ name: "ion_fb",
+ defaults: ["igt-gpu-tools-test-defaults"],
+ srcs: ["tests/ion_fb.c"],
+}
diff --git a/lib/gem.c b/lib/gem.c
new file mode 100644
index 00000000..1f401929
--- /dev/null
+++ b/lib/gem.c
@@ -0,0 +1,119 @@
+#include "gem.h"
+
+#include "gem_msm.h"
+
+struct gem_driver_lookup
+{
+ const char name[16];
+ struct gem_driver *driver;
+};
+
+static struct gem_driver_lookup drivers[] = {
+ {
+ .name = "msm_drm",
+ .driver = &gem_msm_driver
+ }
+};
+
+static inline size_t num_drivers()
+{
+ return ARRAY_SIZE(drivers);
+}
+
+struct gem_driver *gem_get_driver(int drm_fd)
+{
+ char name[16] = {0};
+ drm_version_t version = {};
+
+ version.name_len = sizeof(name);
+ version.name = name;
+
+ if (drmIoctl(drm_fd, DRM_IOCTL_VERSION, &version))
+ {
+ return NULL;
+ }
+
+ for (struct gem_driver_lookup *di = drivers;
+ di - drivers < num_drivers();
+ ++di)
+ {
+ if (!strncmp(name, di->name, sizeof(name)))
+ {
+ return di->driver;
+ }
+ }
+
+ return NULL;
+}
+
+int gem_size(int drm_fd, size_t *size, uint32_t gem_handle)
+{
+ struct drm_gem_flink drm_gem_flink_arg = {
+ .handle = gem_handle,
+ .name = 0
+ };
+
+ if (drmIoctl(drm_fd,
+ DRM_IOCTL_GEM_FLINK,
+ &drm_gem_flink_arg))
+ {
+ return -1;
+ }
+
+ struct drm_gem_open drm_gem_open_arg = {
+ .name = drm_gem_flink_arg.name,
+ .handle = 0,
+ .size = 0
+ };
+
+ if (drmIoctl(drm_fd,
+ DRM_IOCTL_GEM_OPEN,
+ &drm_gem_open_arg))
+ {
+ return -1;
+ }
+
+ *size = drm_gem_open_arg.size;
+
+ if (drm_gem_open_arg.handle != gem_handle)
+ {
+ gem_release_handle(drm_fd, drm_gem_open_arg.handle);
+ }
+
+ return 0;
+}
+
+void gem_release_handle(int drm_fd, uint32_t gem_handle)
+{
+ struct drm_gem_close drm_gem_close_arg = {
+ .handle = gem_handle,
+ .pad = 0
+ };
+
+ drmIoctl(drm_fd, DRM_IOCTL_GEM_CLOSE, &drm_gem_close_arg);
+}
+
+int drm_fb_for_gem_handle(int drm_fd, uint32_t *fb_id, uint32_t gem_handle,
+ const struct fb_configuration *fb_config)
+{
+ struct drm_mode_fb_cmd2 drm_mode_addfb2_arg = {
+ .fb_id = 0,
+ .width = fb_config->width,
+ .height = fb_config->height,
+ .pixel_format = fb_config->pixel_format,
+ .flags = DRM_MODE_FB_MODIFIERS,
+ .handles = { gem_handle, 0, 0, 0 },
+ .pitches = { fb_config->width * fb_config->pixel_size, 0, 0, 0 },
+ .offsets = { 0, 0, 0, 0 },
+ .modifier = { 0 }
+ };
+
+ if (drmIoctl(drm_fd, DRM_IOCTL_MODE_ADDFB2, &drm_mode_addfb2_arg))
+ {
+ return -1;
+ }
+
+ *fb_id = drm_mode_addfb2_arg.fb_id;
+
+ return 0;
+}
diff --git a/lib/gem.h b/lib/gem.h
new file mode 100644
index 00000000..790d9adb
--- /dev/null
+++ b/lib/gem.h
@@ -0,0 +1,85 @@
+#ifndef GEM_H
+#define GEM_H
+
+#include "igt.h"
+
+struct gem_driver
+{
+ /**
+ * mmap:
+ * @ptr: (out) pointer to the buffer in the user process's memory
+ * @drm_fd: open DRM device fd
+ * @gem_handle: GEM handle
+ * @size: exact size of the GEM buffer
+ *
+ * Maps the buffer backing the GEM handle for reading and writing.
+ *
+ * Returns: 0 on success, -1 otherwise
+ **/
+ int (*mmap)(void **ptr, int drm_fd, uint32_t gem_handle, size_t size);
+
+ /**
+ * munmap:
+ * @drm_fd: open DRM device fd
+ * @gem_handle: GEM handle
+ * @ptr: pointer (see ptr argument to mmap)
+ * @size: exact size of the mapped area
+ *
+ * Unmaps a region previously mapped with mmap.
+ *
+ * Returns: 0 on success: -1 otherwise
+ **/
+ int (*munmap)(int drm_fd, uint32_t gem_handle, void *ptr, size_t size);
+};
+
+/**
+ * gem_get_driver:
+ * @drm_fd: open DRM device fd
+ *
+ * Gets the driver-specific GEM APIs for a particular device.
+ *
+ * Returns: a struct with function pointers on success; NULL otherwise
+ **/
+struct gem_driver *gem_get_driver(int drm_fd);
+
+/**
+ * gem_size:
+ * @drm_fd: open DRM device fd
+ * @size: (out) size of the buffer
+ * @gem_handle: GEM handle
+ * Returns: size of the buffer backing the GEM handle.
+ **/
+int gem_size(int drm_fd, size_t *size, uint32_t gem_handle);
+
+/**
+ * gem_release_handle
+ * @drm_fd: open DRM device fd
+ * @gem_handle: GEM handle
+ *
+ * Releases a GEM handle.
+ **/
+void gem_release_handle(int drm_fd, uint32_t gem_handle);
+
+struct fb_configuration
+{
+ uint32_t width;
+ uint32_t height;
+ uint32_t pixel_format;
+ uint32_t pixel_size;
+};
+
+/**
+ * drm_fb_for_gem_handle
+ * @drm_fd: open DRM device fd
+ * @fb_id: (out) id of the DRM KMS fb
+ * @gem_handle: GEM handle
+ * @fb_config: metadata for the fb
+ *
+ * Converts a GEM buffer into a DRM KMS fb
+ *
+ * Returns: 0 if the buffer could be converted; -1 otherwise
+ **/
+int drm_fb_for_gem_handle(int drm_fd, uint32_t *fb_id, uint32_t gem_handle,
+ const struct fb_configuration *fb_config);
+
+#endif
diff --git a/lib/gem_msm.c b/lib/gem_msm.c
new file mode 100644
index 00000000..2160f443
--- /dev/null
+++ b/lib/gem_msm.c
@@ -0,0 +1,68 @@
+#include "gem_msm.h"
+#include "drm-uapi/msm_drm.h"
+
+#include "drm.h"
+
+static int gem_msm_mmap(void **ptr, int drm_fd, uint32_t gem_handle, size_t size)
+{
+ struct drm_msm_gem_cpu_prep gem_prep = {
+ .handle = gem_handle,
+ .op = MSM_PREP_READ,
+ .timeout = { .tv_sec = 1, .tv_nsec = 0 }
+ };
+
+ if (drmIoctl(drm_fd, DRM_IOCTL_MSM_GEM_CPU_PREP, &gem_prep))
+ {
+ return -1;
+ }
+
+ struct drm_msm_gem_info gem_info = {
+ .handle = gem_handle,
+ .flags = 0,
+ .offset = 0
+ };
+
+ if (drmIoctl(drm_fd, DRM_IOCTL_MSM_GEM_INFO, &gem_info))
+ {
+ return -1;
+ }
+
+ void *const k_addr = 0;
+ const int k_prot = PROT_READ | PROT_WRITE;
+ const int k_flags = MAP_SHARED;
+
+ void *ret = mmap(k_addr, size, k_prot, k_flags, drm_fd, gem_info.offset);
+
+ if (ret == MAP_FAILED)
+ {
+ return -1;
+ }
+
+ *ptr = ret;
+
+ return 0;
+}
+
+static int gem_msm_munmap(int drm_fd, uint32_t gem_handle, void *ptr, size_t size)
+{
+ if (munmap(ptr, size))
+ {
+ return -1;
+ }
+
+ struct drm_msm_gem_cpu_fini gem_fini = {
+ .handle = gem_handle
+ };
+
+ if (drmIoctl(drm_fd, DRM_IOCTL_MSM_GEM_CPU_FINI, &gem_fini))
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+struct gem_driver gem_msm_driver = {
+ .mmap = gem_msm_mmap,
+ .munmap = gem_msm_munmap
+};
diff --git a/lib/gem_msm.h b/lib/gem_msm.h
new file mode 100644
index 00000000..4b9724bc
--- /dev/null
+++ b/lib/gem_msm.h
@@ -0,0 +1,8 @@
+#ifndef GEM_MSM_H
+#define GEM_MSM_H
+
+#include "gem.h"
+
+extern struct gem_driver gem_msm_driver;
+
+#endif
diff --git a/lib/ion.c b/lib/ion.c
new file mode 100644
index 00000000..59f7b3b8
--- /dev/null
+++ b/lib/ion.c
@@ -0,0 +1,180 @@
+#include <ion/ion.h>
+#include <linux/ion_4.12.h>
+
+#include "ion.h"
+
+int ion_get_heap_id(int ion_fd, uint32_t heap_type)
+{
+ int heap_count = 0;
+ int ret = -1;
+
+ if (ion_query_heap_cnt(ion_fd, &heap_count))
+ {
+ return -1;
+ }
+
+ struct ion_heap_data *heap_data =
+ malloc(heap_count * sizeof(struct ion_heap_data));
+
+ if (ion_query_get_heaps(ion_fd, heap_count, heap_data))
+ {
+ free(heap_data);
+ return -1;
+ }
+
+ for (struct ion_heap_data *hi = heap_data;
+ (hi - heap_data) < heap_count;
+ ++hi)
+ {
+ if (hi->type == heap_type)
+ {
+ ret = hi->heap_id;
+ break;
+ }
+ }
+
+ free(heap_data);
+
+ return ret;
+}
+
+static const int kBitsInAnInt = (sizeof(int) * 8);
+
+int ion_alloc_one_fd(int ion_fd, size_t size, int heap_id, int *ion_buffer_fd)
+{
+ if (heap_id < 0 || heap_id >= kBitsInAnInt)
+ {
+ return -1;
+ }
+
+ const int align = 0;
+ const int heap_mask = 1 << heap_id;
+ const int flags = 0;
+
+ return ion_alloc_fd(ion_fd, size, align, heap_mask, flags, ion_buffer_fd);
+}
+
+int ion_mmap(void **ptr, int ion_buffer_fd, size_t size)
+{
+ void *const k_addr = 0;
+ const int k_prot = PROT_READ | PROT_WRITE;
+ const int k_flags = MAP_SHARED;
+
+ void *ret = mmap(k_addr, size, k_prot, k_flags, ion_buffer_fd, 0);
+
+ if (ret == MAP_FAILED)
+ {
+ return -1;
+ }
+
+ *ptr = ret;
+ return 0;
+}
+
+int ion_munmap(void *ptr, size_t size)
+{
+ if (munmap(ptr, size))
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+int drm_check_prime_caps(int drm_fd)
+{
+ struct drm_get_cap drm_get_cap_arg = {
+ .capability = DRM_CAP_PRIME,
+ .value = 0
+ };
+
+ if (drmIoctl(drm_fd, DRM_IOCTL_GET_CAP, &drm_get_cap_arg))
+ {
+ return -1;
+ }
+
+ if (!(drm_get_cap_arg.value & DRM_PRIME_CAP_IMPORT) ||
+ !(drm_get_cap_arg.value & DRM_PRIME_CAP_EXPORT))
+ {
+ return -1;
+ }
+
+ return 0;
+}
+
+int gem_handle_for_ion_buffer(int drm_fd, uint32_t *gem_handle, int ion_buffer_fd)
+{
+ struct drm_prime_handle drm_prime_fd_to_handle_arg = {
+ .handle = 0,
+ .flags = 0,
+ .fd = ion_buffer_fd
+ };
+
+ if (drmIoctl(drm_fd,
+ DRM_IOCTL_PRIME_FD_TO_HANDLE,
+ &drm_prime_fd_to_handle_arg))
+ {
+ return -1;
+ }
+
+ *gem_handle = drm_prime_fd_to_handle_arg.handle;
+
+ return 0;
+}
+
+int ion_fd_for_gem_handle(int drm_fd, int *ion_fd, uint32_t gem_handle)
+{
+ struct drm_prime_handle drm_prime_handle_to_fd_arg = {
+ .handle = gem_handle,
+ .flags = 0,
+ .fd = 0
+ };
+
+ if (drmIoctl(drm_fd,
+ DRM_IOCTL_PRIME_HANDLE_TO_FD,
+ &drm_prime_handle_to_fd_arg))
+ {
+ return -1;
+ }
+
+ *ion_fd = drm_prime_handle_to_fd_arg.fd;
+
+ return 0;
+}
+
+int drm_fb_for_ion_buffer(int drm_fd, uint32_t *fb_id, int ion_buffer_fd,
+ const struct fb_configuration *fb_config)
+{
+ uint32_t gem_handle = 0;
+
+ if (gem_handle_for_ion_buffer(drm_fd, &gem_handle, ion_buffer_fd))
+ {
+ return -1;
+ }
+
+ int ret = drm_fb_for_gem_handle(drm_fd, fb_id, gem_handle, fb_config);
+
+ gem_release_handle(drm_fd, gem_handle);
+ return ret;
+}
+
+void drm_release_fb(int drm_fd, uint32_t fb_id)
+{
+ (void)drmIoctl(drm_fd, DRM_IOCTL_MODE_RMFB, &fb_id);
+}
+
+int ion_clone_fd_via_gem(int drm_fd, int *cloned_fd, int ion_buffer_fd)
+{
+ uint32_t gem_handle = 0;
+ if (gem_handle_for_ion_buffer(drm_fd, &gem_handle, ion_buffer_fd))
+ {
+ return -1;
+ }
+
+ int ret = ion_fd_for_gem_handle(drm_fd, cloned_fd, gem_handle);
+ gem_release_handle(drm_fd, gem_handle);
+
+ return ret;
+}
+
+
diff --git a/lib/ion.h b/lib/ion.h
new file mode 100644
index 00000000..c598b968
--- /dev/null
+++ b/lib/ion.h
@@ -0,0 +1,108 @@
+#ifndef ION_GEM_H
+#define ION_GEM_H
+
+#include "igt.h"
+#include "gem.h"
+
+/**
+ * ion_get_heap_id:
+ * @ion_fd: open ion device fd
+ * @heap_type: ION_HEAP_TYPE_* constant
+ * Returns: the index of the first heap with type matching heap_type, or -1 on
+ * failure
+ **/
+int ion_get_heap_id(int ion_fd, uint32_t heap_type);
+
+/**
+ * ion_alloc_one_fd
+ * @ion_fd: open ion device fd
+ * @size: size of the desired ion buffer
+ * @heap_id: index of the heap to allocate from
+ * @ion_buffer_fd: (out) ion buffer fd
+ * Returns: 0 on success; not 0 otherwise
+ **/
+int ion_alloc_one_fd(int ion_fd, size_t size, int heap_id, int *ion_buffer_fd);
+
+/**
+ * ion_mmap
+ * @ptr: (out) pointer to the buffer in the user process's memory
+ * @ion_buffer_fd: ion buffer fd
+ * @size: size of the desired mapping
+ * Returns: 0 on success; not 0 otherwise
+ **/
+int ion_mmap(void **ptr, int ion_buffer_fd, size_t size);
+
+/**
+ * ion_munmap
+ * @ptr: pointer to the buffer in the user process's memory
+ * @size: exact size of the mapping
+ * Returns: 0 on success; not 0 otherwise
+ **/
+int ion_munmap(void *ptr, size_t size);
+
+/**
+ * drm_check_prime_caps
+ * drm_fd: open DRM device fd
+ * Returns: 0 if the device supports Prime import/export; -1 otherwise
+ **/
+int drm_check_prime_caps(int drm_fd);
+
+/**
+ * gem_handle_for_ion_buffer
+ * drm_fd: open DRM device fd
+ * gem_handle: (out) GEM handle
+ * ion_fd: ion buffer fd
+ *
+ * Imports an ion buffer into GEM
+ *
+ * Returns: 0 if the ion buffer could be imported; -1 otherwise
+ **/
+int gem_handle_for_ion_buffer(int drm_fd, uint32_t *gem_handle, int ion_buffer_fd);
+
+/**
+ * ion_fd_for_gem_handle
+ * drm_fd: open DRM device fd
+ * ion_fd: ion buffer fd
+ *
+ * Exports a GEM buffer into ion
+ *
+ * Returns: 0 if the buffer could be exported; -1 otherwise
+ **/
+int ion_fd_for_gem_handle(int drm_fd, int *ion_bufferfd, uint32_t gem_handle);
+
+/**
+ * drm_fb_for_ion_buffer
+ * drm_fd: open DRM device fd
+ * fb_id: (out) id of the DRM KMS fb
+ * ion_fd: ion buffer fd
+ * fb_config: metadata for the fb
+ *
+ * Converts an ion buffer into a DRM KMS fb
+ *
+ * Returns: 0 if the buffer could be exported; -1 otherwise
+ **/
+int drm_fb_for_ion_buffer(int drm_fd, uint32_t *fb_id, int ion_buffer_fd,
+ const struct fb_configuration *fb_config);
+
+/**
+ * drm_release_fb
+ * drm_fd: open DRM device fd
+ * fb_id: id of the DRM KMS fb
+ *
+ * Releases the DRM KMS fb
+ **/
+void drm_release_fb(int drm_fd, uint32_t fb_id);
+
+/**
+ * ion_clone_fd_via_gem
+ * drm_fd: open DRM device fd
+ * cloned_fd: (out) cloned buffer fd
+ * ion_fd: ion buffer fd
+ *
+ * Uses GEM to clone an ion fd by importing and re-exporting it.
+ *
+ * Returns: 0 if the buffer could be cloned; -1 otherwise
+ **/
+int ion_clone_fd_via_gem(int drm_fd, int *cloned_fd, int ion_buffer_fd);
+
+#endif
diff --git a/tests/ion_fb.c b/tests/ion_fb.c
new file mode 100644
index 00000000..b8b86161
--- /dev/null
+++ b/tests/ion_fb.c
@@ -0,0 +1,223 @@
+#include "drm.h"
+#include "gem.h"
+#include "igt.h"
+#include "ion.h"
+
+#include <ion/ion.h>
+
+size_t size_for_fb(const struct fb_configuration *config)
+{
+ return config->width * config->height * config->pixel_size;
+}
+
+/**
+ * test_make_fb
+ *
+ * Tests that an ion buffer can be ingested into DRM to the point
+ * where it can be used for a framebuffer
+ **/
+
+static void make_fb_with_buffer(int drm_fd, int ion_fd,
+ const struct fb_configuration *config,
+ int ion_buffer_fd)
+{
+ uint32_t fb_id = 0;
+
+ igt_assert_eq(0, drm_check_prime_caps(drm_fd));
+ igt_assert_eq(0, drm_fb_for_ion_buffer(
+ drm_fd, &fb_id, ion_buffer_fd, config));
+ drm_release_fb(drm_fd, fb_id);
+}
+
+static void make_fb_with_fds(int drm_fd, int ion_fd,
+ const struct fb_configuration *config)
+{
+ int ion_buffer_fd;
+
+ const int heap_id = ion_get_heap_id(ion_fd, ION_HEAP_TYPE_SYSTEM);
+ igt_assert(heap_id != -1);
+
+ igt_assert(!ion_alloc_one_fd(
+ ion_fd,
+ size_for_fb(config),
+ heap_id,
+ &ion_buffer_fd));
+
+ make_fb_with_buffer(drm_fd, ion_fd, config, ion_buffer_fd);
+
+ close(ion_buffer_fd);
+}
+
+static void test_make_fb(const struct fb_configuration *config)
+{
+ const int drm_fd = drm_open_driver(DRIVER_ANY);
+ igt_assert(drm_fd >= 0);
+
+ const int ion_fd = ion_open();
+ igt_assert(ion_fd >= 0);
+
+ make_fb_with_fds(drm_fd, ion_fd, config);
+
+ ion_close(ion_fd);
+ close(drm_fd);
+}
+
+/**
+ * test_clone
+ *
+ * Tests that an ion buffer can be 'cloned' by making a GEM buffer out of
+ * it and then reversing the process
+ **/
+
+static void clone_with_fds(int drm_fd, int ion_fd,
+ const struct fb_configuration *config)
+{
+ int ion_buffer_fd;
+
+ const int heap_id = ion_get_heap_id(ion_fd, ION_HEAP_TYPE_SYSTEM);
+ igt_assert(heap_id != -1);
+
+ igt_assert(!ion_alloc_one_fd(
+ ion_fd,
+ size_for_fb(config),
+ heap_id,
+ &ion_buffer_fd));
+
+ int clone_fd = 0;
+
+ igt_assert(!ion_clone_fd_via_gem(drm_fd, &clone_fd, ion_buffer_fd));
+
+ igt_assert(clone_fd >= 0);
+ igt_assert(clone_fd != ion_buffer_fd);
+
+ close(clone_fd);
+ close(ion_buffer_fd);
+}
+
+static void test_clone(const struct fb_configuration *config)
+{
+ const int drm_fd = drm_open_driver(DRIVER_ANY);
+ igt_assert(drm_fd >= 0);
+
+ const int ion_fd = ion_open();
+ igt_assert(ion_fd >= 0);
+
+ clone_with_fds(drm_fd, ion_fd, config);
+
+ ion_close(ion_fd);
+ close(drm_fd);
+}
+
+/**
+ * test_mmap
+ *
+ * Tests that the GEM version of an ion buffer contains the same data that
+ * the original ion buffer did
+ **/
+
+static void mmap_with_buffer(int drm_fd, int ion_fd,
+ uint8_t *buffer, size_t size)
+{
+ int ion_buffer_fd;
+
+ const int heap_id = ion_get_heap_id(ion_fd, ION_HEAP_TYPE_SYSTEM);
+ igt_assert(heap_id != -1);
+
+ const struct gem_driver *gem = gem_get_driver(drm_fd);
+ igt_assert(gem != NULL);
+
+ igt_assert(!ion_alloc_one_fd(
+ ion_fd,
+ size,
+ heap_id,
+ &ion_buffer_fd));
+
+ void *ion_ptr = NULL;
+
+ igt_assert(!ion_mmap(&ion_ptr, ion_buffer_fd, size));
+
+ memcpy(buffer, ion_ptr, size);
+
+ igt_assert(!ion_munmap(ion_ptr, size));
+
+ uint32_t gem_handle = 0;
+
+ igt_assert(!gem_handle_for_ion_buffer(
+ drm_fd,
+ &gem_handle,
+ ion_buffer_fd));
+
+ close(ion_buffer_fd);
+
+ size_t gem_buf_size = 0;
+
+ igt_assert(!gem_size(drm_fd, &gem_buf_size, gem_handle));
+ igt_assert_eq(gem_buf_size, size);
+
+ void *gem_ptr = NULL;
+ igt_assert(!gem->mmap(
+ &gem_ptr,
+ drm_fd,
+ gem_handle,
+ size));
+
+ igt_assert(!memcmp(buffer, gem_ptr, size));
+
+ igt_assert(!gem->munmap(
+ drm_fd,
+ gem_handle,
+ gem_ptr,
+ size));
+
+ gem_release_handle(drm_fd, gem_handle);
+}
+
+static void mmap_with_fds(int drm_fd, int ion_fd,
+ const struct fb_configuration *config)
+{
+ uint8_t *buffer = malloc(size_for_fb(config));
+ igt_assert(buffer);
+
+ mmap_with_buffer(drm_fd, ion_fd, buffer, size_for_fb(config));
+
+ free(buffer);
+}
+
+static void test_mmap(const struct fb_configuration *config)
+{
+ const int drm_fd = drm_open_driver(DRIVER_ANY);
+ igt_assert(drm_fd >= 0);
+
+ const int ion_fd = ion_open();
+ igt_assert(ion_fd >= 0);
+
+ mmap_with_fds(drm_fd, ion_fd, config);
+
+ ion_close(ion_fd);
+ close(drm_fd);
+}
+
+igt_main
+{
+ const struct fb_configuration config = {
+ .width = 1024,
+ .height = 1024,
+ .pixel_format = DRM_FORMAT_ABGR8888,
+ .pixel_size = 4
+ };
+
+ igt_subtest("make-fb")
+ {
+ test_make_fb(&config);
+ }
+
+ igt_subtest("clone")
+ {
+ test_clone(&config);
+ }
+
+ igt_subtest("mmap")
+ {
+ test_mmap(&config);
+ }
+}