Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

kselftests: Add dma-heap test

Add very trivial allocation and import test for dma-heaps,
utilizing the vgem driver as a test importer.

A good chunk of this code taken from:
tools/testing/selftests/android/ion/ionmap_test.c
Originally by Laura Abbott <labbott@redhat.com>

Cc: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Cc: Sumit Semwal <sumit.semwal@linaro.org>
Cc: Liam Mark <lmark@codeaurora.org>
Cc: Pratik Patel <pratikp@codeaurora.org>
Cc: Brian Starkey <Brian.Starkey@arm.com>
Cc: Vincent Donnefort <Vincent.Donnefort@arm.com>
Cc: Sudipto Paul <Sudipto.Paul@arm.com>
Cc: Andrew F. Davis <afd@ti.com>
Cc: Christoph Hellwig <hch@infradead.org>
Cc: Chenbo Feng <fengc@google.com>
Cc: Alistair Strachan <astrachan@google.com>
Cc: Hridya Valsaraju <hridya@google.com>
Cc: Sandeep Patil <sspatil@google.com>
Cc: Hillf Danton <hdanton@sina.com>
Cc: Dave Airlie <airlied@gmail.com>
Cc: dri-devel@lists.freedesktop.org
Reviewed-by: Benjamin Gaignard <benjamin.gaignard@linaro.org>
Reviewed-by: Brian Starkey <brian.starkey@arm.com>
Acked-by: Sandeep Patil <sspatil@android.com>
Acked-by: Laura Abbott <labbott@redhat.com>
Tested-by: Ayan Kumar Halder <ayan.halder@arm.com>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20191203172641.66642-6-john.stultz@linaro.org

authored by

John Stultz and committed by
Sumit Semwal
a8779927 b61614ec

+402
+6
tools/testing/selftests/dmabuf-heaps/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + CFLAGS += -static -O3 -Wl,-no-as-needed -Wall -I../../../../usr/include 3 + 4 + TEST_GEN_PROGS = dmabuf-heap 5 + 6 + include ../lib.mk
+396
tools/testing/selftests/dmabuf-heaps/dmabuf-heap.c
··· 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_fdflags(int fd, size_t len, unsigned int fd_flags, 106 + unsigned int heap_flags, int *dmabuf_fd) 107 + { 108 + struct dma_heap_allocation_data data = { 109 + .len = len, 110 + .fd = 0, 111 + .fd_flags = fd_flags, 112 + .heap_flags = heap_flags, 113 + }; 114 + int ret; 115 + 116 + if (!dmabuf_fd) 117 + return -EINVAL; 118 + 119 + ret = ioctl(fd, DMA_HEAP_IOC_ALLOC, &data); 120 + if (ret < 0) 121 + return ret; 122 + *dmabuf_fd = (int)data.fd; 123 + return ret; 124 + } 125 + 126 + static int dmabuf_heap_alloc(int fd, size_t len, unsigned int flags, 127 + int *dmabuf_fd) 128 + { 129 + return dmabuf_heap_alloc_fdflags(fd, len, O_RDWR | O_CLOEXEC, flags, 130 + dmabuf_fd); 131 + } 132 + 133 + static void dmabuf_sync(int fd, int start_stop) 134 + { 135 + struct dma_buf_sync sync = { 136 + .flags = start_stop | DMA_BUF_SYNC_RW, 137 + }; 138 + int ret; 139 + 140 + ret = ioctl(fd, DMA_BUF_IOCTL_SYNC, &sync); 141 + if (ret) 142 + printf("sync failed %d\n", errno); 143 + } 144 + 145 + #define ONE_MEG (1024 * 1024) 146 + 147 + static int test_alloc_and_import(char *heap_name) 148 + { 149 + int heap_fd = -1, dmabuf_fd = -1, importer_fd = -1; 150 + uint32_t handle = 0; 151 + void *p = NULL; 152 + int ret; 153 + 154 + printf("Testing heap: %s\n", heap_name); 155 + 156 + heap_fd = dmabuf_heap_open(heap_name); 157 + if (heap_fd < 0) 158 + return -1; 159 + 160 + printf("Allocating 1 MEG\n"); 161 + ret = dmabuf_heap_alloc(heap_fd, ONE_MEG, 0, &dmabuf_fd); 162 + if (ret) { 163 + printf("Allocation Failed!\n"); 164 + ret = -1; 165 + goto out; 166 + } 167 + /* mmap and write a simple pattern */ 168 + p = mmap(NULL, 169 + ONE_MEG, 170 + PROT_READ | PROT_WRITE, 171 + MAP_SHARED, 172 + dmabuf_fd, 173 + 0); 174 + if (p == MAP_FAILED) { 175 + printf("mmap() failed: %m\n"); 176 + ret = -1; 177 + goto out; 178 + } 179 + printf("mmap passed\n"); 180 + 181 + dmabuf_sync(dmabuf_fd, DMA_BUF_SYNC_START); 182 + memset(p, 1, ONE_MEG / 2); 183 + memset((char *)p + ONE_MEG / 2, 0, ONE_MEG / 2); 184 + dmabuf_sync(dmabuf_fd, DMA_BUF_SYNC_END); 185 + 186 + importer_fd = open_vgem(); 187 + if (importer_fd < 0) { 188 + ret = importer_fd; 189 + printf("Failed to open vgem\n"); 190 + goto out; 191 + } 192 + 193 + ret = import_vgem_fd(importer_fd, dmabuf_fd, &handle); 194 + if (ret < 0) { 195 + printf("Failed to import buffer\n"); 196 + goto out; 197 + } 198 + printf("import passed\n"); 199 + 200 + dmabuf_sync(dmabuf_fd, DMA_BUF_SYNC_START); 201 + memset(p, 0xff, ONE_MEG); 202 + dmabuf_sync(dmabuf_fd, DMA_BUF_SYNC_END); 203 + printf("syncs passed\n"); 204 + 205 + close_handle(importer_fd, handle); 206 + ret = 0; 207 + 208 + out: 209 + if (p) 210 + munmap(p, ONE_MEG); 211 + if (importer_fd >= 0) 212 + close(importer_fd); 213 + if (dmabuf_fd >= 0) 214 + close(dmabuf_fd); 215 + if (heap_fd >= 0) 216 + close(heap_fd); 217 + 218 + return ret; 219 + } 220 + 221 + /* Test the ioctl version compatibility w/ a smaller structure then expected */ 222 + static int dmabuf_heap_alloc_older(int fd, size_t len, unsigned int flags, 223 + int *dmabuf_fd) 224 + { 225 + int ret; 226 + unsigned int older_alloc_ioctl; 227 + struct dma_heap_allocation_data_smaller { 228 + __u64 len; 229 + __u32 fd; 230 + __u32 fd_flags; 231 + } data = { 232 + .len = len, 233 + .fd = 0, 234 + .fd_flags = O_RDWR | O_CLOEXEC, 235 + }; 236 + 237 + older_alloc_ioctl = _IOWR(DMA_HEAP_IOC_MAGIC, 0x0, 238 + struct dma_heap_allocation_data_smaller); 239 + if (!dmabuf_fd) 240 + return -EINVAL; 241 + 242 + ret = ioctl(fd, older_alloc_ioctl, &data); 243 + if (ret < 0) 244 + return ret; 245 + *dmabuf_fd = (int)data.fd; 246 + return ret; 247 + } 248 + 249 + /* Test the ioctl version compatibility w/ a larger structure then expected */ 250 + static int dmabuf_heap_alloc_newer(int fd, size_t len, unsigned int flags, 251 + int *dmabuf_fd) 252 + { 253 + int ret; 254 + unsigned int newer_alloc_ioctl; 255 + struct dma_heap_allocation_data_bigger { 256 + __u64 len; 257 + __u32 fd; 258 + __u32 fd_flags; 259 + __u64 heap_flags; 260 + __u64 garbage1; 261 + __u64 garbage2; 262 + __u64 garbage3; 263 + } data = { 264 + .len = len, 265 + .fd = 0, 266 + .fd_flags = O_RDWR | O_CLOEXEC, 267 + .heap_flags = flags, 268 + .garbage1 = 0xffffffff, 269 + .garbage2 = 0x88888888, 270 + .garbage3 = 0x11111111, 271 + }; 272 + 273 + newer_alloc_ioctl = _IOWR(DMA_HEAP_IOC_MAGIC, 0x0, 274 + struct dma_heap_allocation_data_bigger); 275 + if (!dmabuf_fd) 276 + return -EINVAL; 277 + 278 + ret = ioctl(fd, newer_alloc_ioctl, &data); 279 + if (ret < 0) 280 + return ret; 281 + 282 + *dmabuf_fd = (int)data.fd; 283 + return ret; 284 + } 285 + 286 + static int test_alloc_compat(char *heap_name) 287 + { 288 + int heap_fd = -1, dmabuf_fd = -1; 289 + int ret; 290 + 291 + heap_fd = dmabuf_heap_open(heap_name); 292 + if (heap_fd < 0) 293 + return -1; 294 + 295 + printf("Testing (theoretical)older alloc compat\n"); 296 + ret = dmabuf_heap_alloc_older(heap_fd, ONE_MEG, 0, &dmabuf_fd); 297 + if (ret) { 298 + printf("Older compat allocation failed!\n"); 299 + ret = -1; 300 + goto out; 301 + } 302 + close(dmabuf_fd); 303 + 304 + printf("Testing (theoretical)newer alloc compat\n"); 305 + ret = dmabuf_heap_alloc_newer(heap_fd, ONE_MEG, 0, &dmabuf_fd); 306 + if (ret) { 307 + printf("Newer compat allocation failed!\n"); 308 + ret = -1; 309 + goto out; 310 + } 311 + printf("Ioctl compatibility tests passed\n"); 312 + out: 313 + if (dmabuf_fd >= 0) 314 + close(dmabuf_fd); 315 + if (heap_fd >= 0) 316 + close(heap_fd); 317 + 318 + return ret; 319 + } 320 + 321 + static int test_alloc_errors(char *heap_name) 322 + { 323 + int heap_fd = -1, dmabuf_fd = -1; 324 + int ret; 325 + 326 + heap_fd = dmabuf_heap_open(heap_name); 327 + if (heap_fd < 0) 328 + return -1; 329 + 330 + printf("Testing expected error cases\n"); 331 + ret = dmabuf_heap_alloc(0, ONE_MEG, 0x111111, &dmabuf_fd); 332 + if (!ret) { 333 + printf("Did not see expected error (invalid fd)!\n"); 334 + ret = -1; 335 + goto out; 336 + } 337 + 338 + ret = dmabuf_heap_alloc(heap_fd, ONE_MEG, 0x111111, &dmabuf_fd); 339 + if (!ret) { 340 + printf("Did not see expected error (invalid heap flags)!\n"); 341 + ret = -1; 342 + goto out; 343 + } 344 + 345 + ret = dmabuf_heap_alloc_fdflags(heap_fd, ONE_MEG, 346 + ~(O_RDWR | O_CLOEXEC), 0, &dmabuf_fd); 347 + if (!ret) { 348 + printf("Did not see expected error (invalid fd flags)!\n"); 349 + ret = -1; 350 + goto out; 351 + } 352 + 353 + printf("Expected error checking passed\n"); 354 + out: 355 + if (dmabuf_fd >= 0) 356 + close(dmabuf_fd); 357 + if (heap_fd >= 0) 358 + close(heap_fd); 359 + 360 + return ret; 361 + } 362 + 363 + int main(void) 364 + { 365 + DIR *d; 366 + struct dirent *dir; 367 + int ret = -1; 368 + 369 + d = opendir(DEVPATH); 370 + if (!d) { 371 + printf("No %s directory?\n", DEVPATH); 372 + return -1; 373 + } 374 + 375 + while ((dir = readdir(d)) != NULL) { 376 + if (!strncmp(dir->d_name, ".", 2)) 377 + continue; 378 + if (!strncmp(dir->d_name, "..", 3)) 379 + continue; 380 + 381 + ret = test_alloc_and_import(dir->d_name); 382 + if (ret) 383 + break; 384 + 385 + ret = test_alloc_compat(dir->d_name); 386 + if (ret) 387 + break; 388 + 389 + ret = test_alloc_errors(dir->d_name); 390 + if (ret) 391 + break; 392 + } 393 + closedir(d); 394 + 395 + return ret; 396 + }