1/* 2 * Copyright (C) 2012-2018 Rob Clark <robclark@freedesktop.org> 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 FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 * 23 * Authors: 24 * Rob Clark <robclark@freedesktop.org> 25 */ 26 27#include "util/slab.h" 28 29#include "msm_priv.h" 30 31static int 32query_param(struct fd_pipe *pipe, uint32_t param, uint64_t *value) 33{ 34 struct msm_pipe *msm_pipe = to_msm_pipe(pipe); 35 struct drm_msm_param req = { 36 .pipe = msm_pipe->pipe, 37 .param = param, 38 }; 39 int ret; 40 41 ret = 42 drmCommandWriteRead(pipe->dev->fd, DRM_MSM_GET_PARAM, &req, sizeof(req)); 43 if (ret) 44 return ret; 45 46 *value = req.value; 47 48 return 0; 49} 50 51static int 52query_queue_param(struct fd_pipe *pipe, uint32_t param, uint64_t *value) 53{ 54 struct msm_pipe *msm_pipe = to_msm_pipe(pipe); 55 struct drm_msm_submitqueue_query req = { 56 .data = VOID2U64(value), 57 .id = msm_pipe->queue_id, 58 .param = param, 59 .len = sizeof(*value), 60 }; 61 int ret; 62 63 ret = drmCommandWriteRead(pipe->dev->fd, DRM_MSM_SUBMITQUEUE_QUERY, &req, 64 sizeof(req)); 65 if (ret) 66 return ret; 67 68 return 0; 69} 70 71static int 72msm_pipe_get_param(struct fd_pipe *pipe, enum fd_param_id param, 73 uint64_t *value) 74{ 75 struct msm_pipe *msm_pipe = to_msm_pipe(pipe); 76 switch (param) { 77 case FD_DEVICE_ID: // XXX probably get rid of this.. 78 case FD_GPU_ID: 79 *value = msm_pipe->gpu_id; 80 return 0; 81 case FD_GMEM_SIZE: 82 *value = msm_pipe->gmem; 83 return 0; 84 case FD_GMEM_BASE: 85 *value = msm_pipe->gmem_base; 86 return 0; 87 case FD_CHIP_ID: 88 *value = msm_pipe->chip_id; 89 return 0; 90 case FD_MAX_FREQ: 91 return query_param(pipe, MSM_PARAM_MAX_FREQ, value); 92 case FD_TIMESTAMP: 93 return query_param(pipe, MSM_PARAM_TIMESTAMP, value); 94 case FD_NR_RINGS: 95 return query_param(pipe, MSM_PARAM_NR_RINGS, value); 96 case FD_PP_PGTABLE: 97 return query_param(pipe, MSM_PARAM_PP_PGTABLE, value); 98 case FD_CTX_FAULTS: 99 return query_queue_param(pipe, MSM_SUBMITQUEUE_PARAM_FAULTS, value); 100 case FD_GLOBAL_FAULTS: 101 return query_param(pipe, MSM_PARAM_FAULTS, value); 102 case FD_SUSPEND_COUNT: 103 return query_param(pipe, MSM_PARAM_SUSPENDS, value); 104 default: 105 ERROR_MSG("invalid param id: %d", param); 106 return -1; 107 } 108} 109 110static int 111msm_pipe_wait(struct fd_pipe *pipe, const struct fd_fence *fence, uint64_t timeout) 112{ 113 struct fd_device *dev = pipe->dev; 114 struct drm_msm_wait_fence req = { 115 .fence = fence->kfence, 116 .queueid = to_msm_pipe(pipe)->queue_id, 117 }; 118 int ret; 119 120 get_abs_timeout(&req.timeout, timeout); 121 122 ret = drmCommandWrite(dev->fd, DRM_MSM_WAIT_FENCE, &req, sizeof(req)); 123 if (ret && (ret != -ETIMEDOUT)) { 124 ERROR_MSG("wait-fence failed! %d (%s)", ret, strerror(errno)); 125 } 126 127 return ret; 128} 129 130static int 131open_submitqueue(struct fd_pipe *pipe, uint32_t prio) 132{ 133 struct drm_msm_submitqueue req = { 134 .flags = 0, 135 .prio = prio, 136 }; 137 uint64_t nr_rings = 1; 138 int ret; 139 140 if (fd_device_version(pipe->dev) < FD_VERSION_SUBMIT_QUEUES) { 141 to_msm_pipe(pipe)->queue_id = 0; 142 return 0; 143 } 144 145 msm_pipe_get_param(pipe, FD_NR_RINGS, &nr_rings); 146 147 req.prio = MIN2(req.prio, MAX2(nr_rings, 1) - 1); 148 149 ret = drmCommandWriteRead(pipe->dev->fd, DRM_MSM_SUBMITQUEUE_NEW, &req, 150 sizeof(req)); 151 if (ret) { 152 ERROR_MSG("could not create submitqueue! %d (%s)", ret, strerror(errno)); 153 return ret; 154 } 155 156 to_msm_pipe(pipe)->queue_id = req.id; 157 return 0; 158} 159 160static void 161close_submitqueue(struct fd_pipe *pipe, uint32_t queue_id) 162{ 163 if (fd_device_version(pipe->dev) < FD_VERSION_SUBMIT_QUEUES) 164 return; 165 166 drmCommandWrite(pipe->dev->fd, DRM_MSM_SUBMITQUEUE_CLOSE, &queue_id, 167 sizeof(queue_id)); 168} 169 170static void 171msm_pipe_destroy(struct fd_pipe *pipe) 172{ 173 struct msm_pipe *msm_pipe = to_msm_pipe(pipe); 174 175 if (msm_pipe->suballoc_bo) 176 fd_bo_del_locked(msm_pipe->suballoc_bo); 177 178 close_submitqueue(pipe, msm_pipe->queue_id); 179 msm_pipe_sp_ringpool_init(msm_pipe); 180 free(msm_pipe); 181} 182 183static const struct fd_pipe_funcs sp_funcs = { 184 .ringbuffer_new_object = msm_ringbuffer_sp_new_object, 185 .submit_new = msm_submit_sp_new, 186 .flush = msm_pipe_sp_flush, 187 .get_param = msm_pipe_get_param, 188 .wait = msm_pipe_wait, 189 .destroy = msm_pipe_destroy, 190}; 191 192static const struct fd_pipe_funcs legacy_funcs = { 193 .ringbuffer_new_object = msm_ringbuffer_new_object, 194 .submit_new = msm_submit_new, 195 .get_param = msm_pipe_get_param, 196 .wait = msm_pipe_wait, 197 .destroy = msm_pipe_destroy, 198}; 199 200static uint64_t 201get_param(struct fd_pipe *pipe, uint32_t param) 202{ 203 uint64_t value; 204 int ret = query_param(pipe, param, &value); 205 if (ret) { 206 ERROR_MSG("get-param failed! %d (%s)", ret, strerror(errno)); 207 return 0; 208 } 209 return value; 210} 211 212struct fd_pipe * 213msm_pipe_new(struct fd_device *dev, enum fd_pipe_id id, uint32_t prio) 214{ 215 static const uint32_t pipe_id[] = { 216 [FD_PIPE_3D] = MSM_PIPE_3D0, 217 [FD_PIPE_2D] = MSM_PIPE_2D0, 218 }; 219 struct msm_pipe *msm_pipe = NULL; 220 struct fd_pipe *pipe = NULL; 221 222 msm_pipe = calloc(1, sizeof(*msm_pipe)); 223 if (!msm_pipe) { 224 ERROR_MSG("allocation failed"); 225 goto fail; 226 } 227 228 pipe = &msm_pipe->base; 229 230 if (fd_device_version(dev) >= FD_VERSION_SOFTPIN) { 231 pipe->funcs = &sp_funcs; 232 } else { 233 pipe->funcs = &legacy_funcs; 234 } 235 236 /* initialize before get_param(): */ 237 pipe->dev = dev; 238 msm_pipe->pipe = pipe_id[id]; 239 240 /* these params should be supported since the first version of drm/msm: */ 241 msm_pipe->gpu_id = get_param(pipe, MSM_PARAM_GPU_ID); 242 msm_pipe->gmem = get_param(pipe, MSM_PARAM_GMEM_SIZE); 243 msm_pipe->chip_id = get_param(pipe, MSM_PARAM_CHIP_ID); 244 245 if (fd_device_version(pipe->dev) >= FD_VERSION_GMEM_BASE) 246 msm_pipe->gmem_base = get_param(pipe, MSM_PARAM_GMEM_BASE); 247 248 if (!(msm_pipe->gpu_id || msm_pipe->chip_id)) 249 goto fail; 250 251 INFO_MSG("Pipe Info:"); 252 INFO_MSG(" GPU-id: %d", msm_pipe->gpu_id); 253 INFO_MSG(" Chip-id: 0x%016"PRIx64, msm_pipe->chip_id); 254 INFO_MSG(" GMEM size: 0x%08x", msm_pipe->gmem); 255 256 if (open_submitqueue(pipe, prio)) 257 goto fail; 258 259 msm_pipe_sp_ringpool_init(msm_pipe); 260 261 return pipe; 262fail: 263 if (pipe) 264 fd_pipe_del(pipe); 265 return NULL; 266} 267