1 /* 2 * Copyright 2011 Red Hat 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 * 23 * Authors: 24 * Jerome Glisse <j.glisse (at) gmail.com> 25 */ 26 #define _FILE_OFFSET_BITS 64 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <sys/mman.h> 31 #include <errno.h> 32 #include "xf86drm.h" 33 #include "radeon_drm.h" 34 #include "rbo.h" 35 36 struct rbo *rbo(int fd, unsigned handle, unsigned size, 37 unsigned alignment, void *ptr) 38 { 39 struct rbo *bo; 40 int r; 41 42 bo = calloc(1, sizeof(*bo)); 43 if (bo == NULL) { 44 return NULL; 45 } 46 list_inithead(&bo->list); 47 bo->fd = fd; 48 bo->size = size; 49 bo->handle = handle; 50 bo->refcount = 1; 51 bo->alignment = alignment; 52 53 if (handle) { 54 struct drm_gem_open open_arg; 55 56 memset(&open_arg, 0, sizeof(open_arg)); 57 open_arg.name = handle; 58 r = drmIoctl(fd, DRM_IOCTL_GEM_OPEN, &open_arg); 59 if (r != 0) { 60 free(bo); 61 return NULL; 62 } 63 bo->handle = open_arg.handle; 64 } else { 65 struct drm_radeon_gem_create args; 66 67 args.size = size; 68 args.alignment = alignment; 69 args.initial_domain = RADEON_GEM_DOMAIN_CPU; 70 args.flags = 0; 71 args.handle = 0; 72 r = drmCommandWriteRead(fd, DRM_RADEON_GEM_CREATE, 73 &args, sizeof(args)); 74 bo->handle = args.handle; 75 if (r) { 76 fprintf(stderr, "Failed to allocate :\n"); 77 fprintf(stderr, " size : %d bytes\n", size); 78 fprintf(stderr, " alignment : %d bytes\n", alignment); 79 free(bo); 80 return NULL; 81 } 82 } 83 if (ptr) { 84 if (rbo_map(bo)) { 85 fprintf(stderr, "%s failed to copy data into bo\n", __func__); 86 return rbo_decref(bo); 87 } 88 memcpy(bo->data, ptr, size); 89 rbo_unmap(bo); 90 } 91 return bo; 92 } 93 94 int rbo_map(struct rbo *bo) 95 { 96 struct drm_radeon_gem_mmap args; 97 void *ptr; 98 int r; 99 100 if (bo->mapcount++ != 0) { 101 return 0; 102 } 103 /* Zero out args to make valgrind happy */ 104 memset(&args, 0, sizeof(args)); 105 args.handle = bo->handle; 106 args.offset = 0; 107 args.size = (uint64_t)bo->size; 108 r = drmCommandWriteRead(bo->fd, DRM_RADEON_GEM_MMAP, 109 &args, sizeof(args)); 110 if (r) { 111 fprintf(stderr, "error mapping %p 0x%08X (error = %d)\n", 112 bo, bo->handle, r); 113 return r; 114 } 115 ptr = mmap(0, args.size, PROT_READ|PROT_WRITE, MAP_SHARED, bo->fd, args.addr_ptr); 116 if (ptr == MAP_FAILED) { 117 fprintf(stderr, "%s failed to map bo\n", __func__); 118 return -errno; 119 } 120 bo->data = ptr; 121 return 0; 122 } 123 124 void rbo_unmap(struct rbo *bo) 125 { 126 if (--bo->mapcount > 0) { 127 return; 128 } 129 munmap(bo->data, bo->size); 130 bo->data = NULL; 131 } 132 133 struct rbo *rbo_incref(struct rbo *bo) 134 { 135 bo->refcount++; 136 return bo; 137 } 138 139 struct rbo *rbo_decref(struct rbo *bo) 140 { 141 struct drm_gem_close args; 142 143 if (bo == NULL) 144 return NULL; 145 if (--bo->refcount > 0) { 146 return NULL; 147 } 148 149 munmap(bo->data, bo->size); 150 memset(&args, 0, sizeof(args)); 151 args.handle = bo->handle; 152 drmIoctl(bo->fd, DRM_IOCTL_GEM_CLOSE, &args); 153 memset(bo, 0, sizeof(struct rbo)); 154 free(bo); 155 return NULL; 156 } 157 158 int rbo_wait(struct rbo *bo) 159 { 160 struct drm_radeon_gem_wait_idle args; 161 int ret; 162 163 /* Zero out args to make valgrind happy */ 164 memset(&args, 0, sizeof(args)); 165 args.handle = bo->handle; 166 do { 167 ret = drmCommandWriteRead(bo->fd, DRM_RADEON_GEM_WAIT_IDLE, 168 &args, sizeof(args)); 169 } while (ret == -EBUSY); 170 return ret; 171 } 172