1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <dirent.h> 4 #include <errno.h> 5 #include <fcntl.h> 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <stdint.h> 9 #include <string.h> 10 #include <unistd.h> 11 #include <sys/ioctl.h> 12 #include <sys/mman.h> 13 #include <sys/types.h> 14 15 #include <linux/dma-buf.h> 16 #include <drm/drm.h> 17 18 #include "../../../../include/uapi/linux/dma-heap.h" 19 20 #define DEVPATH "/dev/dma_heap" 21 22 static int check_vgem(int fd) 23 { 24 drm_version_t version = { 0 }; 25 char name[5]; 26 int ret; 27 28 version.name_len = 4; 29 version.name = name; 30 31 ret = ioctl(fd, DRM_IOCTL_VERSION, &version); 32 if (ret) 33 return 0; 34 35 return !strcmp(name, "vgem"); 36 } 37 38 static int open_vgem(void) 39 { 40 int i, fd; 41 const char *drmstr = "/dev/dri/card"; 42 43 fd = -1; 44 for (i = 0; i < 16; i++) { 45 char name[80]; 46 47 snprintf(name, 80, "%s%u", drmstr, i); 48 49 fd = open(name, O_RDWR); 50 if (fd < 0) 51 continue; 52 53 if (!check_vgem(fd)) { 54 close(fd); 55 fd = -1; 56 continue; 57 } else { 58 break; 59 } 60 } 61 return fd; 62 } 63 64 static int import_vgem_fd(int vgem_fd, int dma_buf_fd, uint32_t *handle) 65 { 66 struct drm_prime_handle import_handle = { 67 .fd = dma_buf_fd, 68 .flags = 0, 69 .handle = 0, 70 }; 71 int ret; 72 73 ret = ioctl(vgem_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &import_handle); 74 if (ret == 0) 75 *handle = import_handle.handle; 76 return ret; 77 } 78 79 static void close_handle(int vgem_fd, uint32_t handle) 80 { 81 struct drm_gem_close close = { 82 .handle = handle, 83 }; 84 85 ioctl(vgem_fd, DRM_IOCTL_GEM_CLOSE, &close); 86 } 87 88 static int dmabuf_heap_open(char *name) 89 { 90 int ret, fd; 91 char buf[256]; 92 93 ret = snprintf(buf, 256, "%s/%s", DEVPATH, name); 94 if (ret < 0) { 95 printf("snprintf failed!\n"); 96 return ret; 97 } 98 99 fd = open(buf, O_RDWR); 100 if (fd < 0) 101 printf("open %s failed!\n", buf); 102 return fd; 103 } 104 105 static int dmabuf_heap_alloc(int fd, size_t len, unsigned int flags, 106 int *dmabuf_fd) 107 { 108 struct dma_heap_allocation_data data = { 109 .len = len, 110 .fd_flags = O_RDWR | O_CLOEXEC, 111 .heap_flags = flags, 112 }; 113 int ret; 114 115 if (!dmabuf_fd) 116 return -EINVAL; 117 118 ret = ioctl(fd, DMA_HEAP_IOC_ALLOC, &data); 119 if (ret < 0) 120 return ret; 121 *dmabuf_fd = (int)data.fd; 122 return ret; 123 } 124 125 static void dmabuf_sync(int fd, int start_stop) 126 { 127 struct dma_buf_sync sync = { 128 .flags = start_stop | DMA_BUF_SYNC_RW, 129 }; 130 int ret; 131 132 ret = ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync); 133 if (ret) 134 printf("sync failed %d\n", errno); 135 } 136 137 #define ONE_MEG (1024 * 1024) 138 139 static int do_test(char *heap_name) 140 { 141 int heap_fd = -1, dmabuf_fd = -1, importer_fd = -1; 142 uint32_t handle = 0; 143 void *p = NULL; 144 int ret; 145 146 printf("Testing heap: %s\n", heap_name); 147 148 heap_fd = dmabuf_heap_open(heap_name); 149 if (heap_fd < 0) 150 return; 151 152 printf("Allocating 1 MEG\n"); 153 ret = dmabuf_heap_alloc(heap_fd, ONE_MEG, 0, &dmabuf_fd); 154 if (ret) { 155 printf("Allocation Failed!\n"); 156 ret = -1; 157 goto out; 158 } 159 /* mmap and write a simple pattern */ 160 p = mmap(NULL, 161 ONE_MEG, 162 PROT_READ | PROT_WRITE, 163 MAP_SHARED, 164 dmabuf_fd, 165 0); 166 if (p == MAP_FAILED) { 167 printf("mmap() failed: %m\n"); 168 ret = -1; 169 goto out; 170 } 171 printf("mmap passed\n"); 172 173 dmabuf_sync(dmabuf_fd, DMA_BUF_SYNC_START); 174 memset(p, 1, ONE_MEG / 2); 175 memset((char *)p + ONE_MEG / 2, 0, ONE_MEG / 2); 176 dmabuf_sync(dmabuf_fd, DMA_BUF_SYNC_END); 177 178 importer_fd = open_vgem(); 179 if (importer_fd < 0) { 180 ret = importer_fd; 181 printf("Failed to open vgem\n"); 182 goto out; 183 } 184 185 ret = import_vgem_fd(importer_fd, dmabuf_fd, &handle); 186 if (ret < 0) { 187 printf("Failed to import buffer\n"); 188 goto out; 189 } 190 printf("import passed\n"); 191 192 dmabuf_sync(dmabuf_fd, DMA_BUF_SYNC_START); 193 memset(p, 0xff, ONE_MEG); 194 dmabuf_sync(dmabuf_fd, DMA_BUF_SYNC_END); 195 printf("syncs passed\n"); 196 197 close_handle(importer_fd, handle); 198 ret = 0; 199 200 out: 201 if (p) 202 munmap(p, ONE_MEG); 203 if (importer_fd >= 0) 204 close(importer_fd); 205 if (dmabuf_fd >= 0) 206 close(dmabuf_fd); 207 if (heap_fd >= 0) 208 close(heap_fd); 209 210 return ret; 211 } 212 213 int main(void) 214 { 215 DIR *d; 216 struct dirent *dir; 217 int ret = -1; 218 219 d = opendir(DEVPATH); 220 if (!d) { 221 printf("No %s directory?\n", DEVPATH); 222 return -1; 223 } 224 225 while ((dir = readdir(d)) != NULL) { 226 if (!strncmp(dir->d_name, ".", 2)) 227 continue; 228 if (!strncmp(dir->d_name, "..", 3)) 229 continue; 230 231 ret = do_test(dir->d_name); 232 if (ret) 233 break; 234 } 235 closedir(d); 236 237 return ret; 238 } 239