1 /* 2 * Copyright 2018 Google, Inc. 3 * Copyright 2015 Intel Corporation 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 * DEALINGS IN THE SOFTWARE. 23 */ 24 25 #include "tu_private.h" 26 27 #include <errno.h> 28 #include <fcntl.h> 29 #include <stdint.h> 30 #include <sys/ioctl.h> 31 #include <xf86drm.h> 32 33 #include "drm/msm_drm.h" 34 35 static int 36 tu_drm_get_param(const struct tu_physical_device *dev, 37 uint32_t param, 38 uint64_t *value) 39 { 40 /* Technically this requires a pipe, but the kernel only supports one pipe 41 * anyway at the time of writing and most of these are clearly pipe 42 * independent. */ 43 struct drm_msm_param req = { 44 .pipe = MSM_PIPE_3D0, 45 .param = param, 46 }; 47 48 int ret = drmCommandWriteRead(dev->local_fd, DRM_MSM_GET_PARAM, &req, 49 sizeof(req)); 50 if (ret) 51 return ret; 52 53 *value = req.value; 54 55 return 0; 56 } 57 58 int 59 tu_drm_get_gpu_id(const struct tu_physical_device *dev, uint32_t *id) 60 { 61 uint64_t value; 62 int ret = tu_drm_get_param(dev, MSM_PARAM_GPU_ID, &value); 63 if (ret) 64 return ret; 65 66 *id = value; 67 return 0; 68 } 69 70 int 71 tu_drm_get_gmem_size(const struct tu_physical_device *dev, uint32_t *size) 72 { 73 uint64_t value; 74 int ret = tu_drm_get_param(dev, MSM_PARAM_GMEM_SIZE, &value); 75 if (ret) 76 return ret; 77 78 *size = value; 79 return 0; 80 } 81 82 int 83 tu_drm_submitqueue_new(const struct tu_device *dev, 84 int priority, 85 uint32_t *queue_id) 86 { 87 struct drm_msm_submitqueue req = { 88 .flags = 0, 89 .prio = priority, 90 }; 91 92 int ret = drmCommandWriteRead(dev->physical_device->local_fd, 93 DRM_MSM_SUBMITQUEUE_NEW, &req, sizeof(req)); 94 if (ret) 95 return ret; 96 97 *queue_id = req.id; 98 return 0; 99 } 100 101 void 102 tu_drm_submitqueue_close(const struct tu_device *dev, uint32_t queue_id) 103 { 104 drmCommandWrite(dev->physical_device->local_fd, DRM_MSM_SUBMITQUEUE_CLOSE, 105 &queue_id, sizeof(uint32_t)); 106 } 107 108 /** 109 * Return gem handle on success. Return 0 on failure. 110 */ 111 uint32_t 112 tu_gem_new(const struct tu_device *dev, uint64_t size, uint32_t flags) 113 { 114 struct drm_msm_gem_new req = { 115 .size = size, 116 .flags = flags, 117 }; 118 119 int ret = drmCommandWriteRead(dev->physical_device->local_fd, 120 DRM_MSM_GEM_NEW, &req, sizeof(req)); 121 if (ret) 122 return 0; 123 124 return req.handle; 125 } 126 127 uint32_t 128 tu_gem_import_dmabuf(const struct tu_device *dev, int prime_fd, uint64_t size) 129 { 130 /* lseek() to get the real size */ 131 off_t real_size = lseek(prime_fd, 0, SEEK_END); 132 lseek(prime_fd, 0, SEEK_SET); 133 if (real_size < 0 || (uint64_t) real_size < size) 134 return 0; 135 136 uint32_t gem_handle; 137 int ret = drmPrimeFDToHandle(dev->physical_device->local_fd, prime_fd, 138 &gem_handle); 139 if (ret) 140 return 0; 141 142 return gem_handle; 143 } 144 145 int 146 tu_gem_export_dmabuf(const struct tu_device *dev, uint32_t gem_handle) 147 { 148 int prime_fd; 149 int ret = drmPrimeHandleToFD(dev->physical_device->local_fd, gem_handle, 150 DRM_CLOEXEC, &prime_fd); 151 152 return ret == 0 ? prime_fd : -1; 153 } 154 155 void 156 tu_gem_close(const struct tu_device *dev, uint32_t gem_handle) 157 { 158 struct drm_gem_close req = { 159 .handle = gem_handle, 160 }; 161 162 drmIoctl(dev->physical_device->local_fd, DRM_IOCTL_GEM_CLOSE, &req); 163 } 164 165 /** Return UINT64_MAX on error. */ 166 static uint64_t 167 tu_gem_info(const struct tu_device *dev, uint32_t gem_handle, uint32_t info) 168 { 169 struct drm_msm_gem_info req = { 170 .handle = gem_handle, 171 .info = info, 172 }; 173 174 int ret = drmCommandWriteRead(dev->physical_device->local_fd, 175 DRM_MSM_GEM_INFO, &req, sizeof(req)); 176 if (ret == -1) 177 return UINT64_MAX; 178 179 return req.value; 180 } 181 182 /** Return UINT64_MAX on error. */ 183 uint64_t 184 tu_gem_info_offset(const struct tu_device *dev, uint32_t gem_handle) 185 { 186 return tu_gem_info(dev, gem_handle, MSM_INFO_GET_OFFSET); 187 } 188 189 /** Return UINT64_MAX on error. */ 190 uint64_t 191 tu_gem_info_iova(const struct tu_device *dev, uint32_t gem_handle) 192 { 193 return tu_gem_info(dev, gem_handle, MSM_INFO_GET_IOVA); 194 } 195