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 35static int 36tu_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 58int 59tu_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 70int 71tu_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 82int 83tu_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 101void 102tu_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 */ 111uint32_t 112tu_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 127uint32_t 128tu_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 145int 146tu_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 155void 156tu_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. */ 166static uint64_t 167tu_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. */ 183uint64_t 184tu_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. */ 190uint64_t 191tu_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