aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-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
6 files changed, 568 insertions, 0 deletions
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