1b8e80941Smrg/* 2b8e80941Smrg * Copyright (C) 2012-2018 Rob Clark <robclark@freedesktop.org> 3b8e80941Smrg * 4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5b8e80941Smrg * copy of this software and associated documentation files (the "Software"), 6b8e80941Smrg * to deal in the Software without restriction, including without limitation 7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the 9b8e80941Smrg * Software is furnished to do so, subject to the following conditions: 10b8e80941Smrg * 11b8e80941Smrg * The above copyright notice and this permission notice (including the next 12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the 13b8e80941Smrg * Software. 14b8e80941Smrg * 15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20b8e80941Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21b8e80941Smrg * SOFTWARE. 22b8e80941Smrg * 23b8e80941Smrg * Authors: 24b8e80941Smrg * Rob Clark <robclark@freedesktop.org> 25b8e80941Smrg */ 26b8e80941Smrg 27b8e80941Smrg#include "util/slab.h" 28b8e80941Smrg 29b8e80941Smrg#include "msm_priv.h" 30b8e80941Smrg 31b8e80941Smrgstatic int query_param(struct fd_pipe *pipe, uint32_t param, 32b8e80941Smrg uint64_t *value) 33b8e80941Smrg{ 34b8e80941Smrg struct msm_pipe *msm_pipe = to_msm_pipe(pipe); 35b8e80941Smrg struct drm_msm_param req = { 36b8e80941Smrg .pipe = msm_pipe->pipe, 37b8e80941Smrg .param = param, 38b8e80941Smrg }; 39b8e80941Smrg int ret; 40b8e80941Smrg 41b8e80941Smrg ret = drmCommandWriteRead(pipe->dev->fd, DRM_MSM_GET_PARAM, 42b8e80941Smrg &req, sizeof(req)); 43b8e80941Smrg if (ret) 44b8e80941Smrg return ret; 45b8e80941Smrg 46b8e80941Smrg *value = req.value; 47b8e80941Smrg 48b8e80941Smrg return 0; 49b8e80941Smrg} 50b8e80941Smrg 51b8e80941Smrgstatic int query_queue_param(struct fd_pipe *pipe, uint32_t param, 52b8e80941Smrg uint64_t *value) 53b8e80941Smrg{ 54b8e80941Smrg struct msm_pipe *msm_pipe = to_msm_pipe(pipe); 55b8e80941Smrg struct drm_msm_submitqueue_query req = { 56b8e80941Smrg .data = VOID2U64(value), 57b8e80941Smrg .id = msm_pipe->queue_id, 58b8e80941Smrg .param = param, 59b8e80941Smrg .len = sizeof(*value), 60b8e80941Smrg }; 61b8e80941Smrg int ret; 62b8e80941Smrg 63b8e80941Smrg ret = drmCommandWriteRead(pipe->dev->fd, DRM_MSM_SUBMITQUEUE_QUERY, 64b8e80941Smrg &req, sizeof(req)); 65b8e80941Smrg if (ret) 66b8e80941Smrg return ret; 67b8e80941Smrg 68b8e80941Smrg return 0; 69b8e80941Smrg} 70b8e80941Smrg 71b8e80941Smrgstatic int msm_pipe_get_param(struct fd_pipe *pipe, 72b8e80941Smrg enum fd_param_id param, uint64_t *value) 73b8e80941Smrg{ 74b8e80941Smrg struct msm_pipe *msm_pipe = to_msm_pipe(pipe); 75b8e80941Smrg switch(param) { 76b8e80941Smrg case FD_DEVICE_ID: // XXX probably get rid of this.. 77b8e80941Smrg case FD_GPU_ID: 78b8e80941Smrg *value = msm_pipe->gpu_id; 79b8e80941Smrg return 0; 80b8e80941Smrg case FD_GMEM_SIZE: 81b8e80941Smrg *value = msm_pipe->gmem; 82b8e80941Smrg return 0; 83b8e80941Smrg case FD_GMEM_BASE: 84b8e80941Smrg *value = msm_pipe->gmem_base; 85b8e80941Smrg return 0; 86b8e80941Smrg case FD_CHIP_ID: 87b8e80941Smrg *value = msm_pipe->chip_id; 88b8e80941Smrg return 0; 89b8e80941Smrg case FD_MAX_FREQ: 90b8e80941Smrg return query_param(pipe, MSM_PARAM_MAX_FREQ, value); 91b8e80941Smrg case FD_TIMESTAMP: 92b8e80941Smrg return query_param(pipe, MSM_PARAM_TIMESTAMP, value); 93b8e80941Smrg case FD_NR_RINGS: 94b8e80941Smrg return query_param(pipe, MSM_PARAM_NR_RINGS, value); 95b8e80941Smrg case FD_PP_PGTABLE: 96b8e80941Smrg return query_param(pipe, MSM_PARAM_PP_PGTABLE, value); 97b8e80941Smrg case FD_CTX_FAULTS: 98b8e80941Smrg return query_queue_param(pipe, MSM_SUBMITQUEUE_PARAM_FAULTS, value); 99b8e80941Smrg case FD_GLOBAL_FAULTS: 100b8e80941Smrg return query_param(pipe, MSM_PARAM_FAULTS, value); 101b8e80941Smrg default: 102b8e80941Smrg ERROR_MSG("invalid param id: %d", param); 103b8e80941Smrg return -1; 104b8e80941Smrg } 105b8e80941Smrg} 106b8e80941Smrg 107b8e80941Smrgstatic int msm_pipe_wait(struct fd_pipe *pipe, uint32_t timestamp, 108b8e80941Smrg uint64_t timeout) 109b8e80941Smrg{ 110b8e80941Smrg struct fd_device *dev = pipe->dev; 111b8e80941Smrg struct drm_msm_wait_fence req = { 112b8e80941Smrg .fence = timestamp, 113b8e80941Smrg .queueid = to_msm_pipe(pipe)->queue_id, 114b8e80941Smrg }; 115b8e80941Smrg int ret; 116b8e80941Smrg 117b8e80941Smrg get_abs_timeout(&req.timeout, timeout); 118b8e80941Smrg 119b8e80941Smrg ret = drmCommandWrite(dev->fd, DRM_MSM_WAIT_FENCE, &req, sizeof(req)); 120b8e80941Smrg if (ret) { 121b8e80941Smrg ERROR_MSG("wait-fence failed! %d (%s)", ret, strerror(errno)); 122b8e80941Smrg return ret; 123b8e80941Smrg } 124b8e80941Smrg 125b8e80941Smrg return 0; 126b8e80941Smrg} 127b8e80941Smrg 128b8e80941Smrgstatic int open_submitqueue(struct fd_pipe *pipe, uint32_t prio) 129b8e80941Smrg{ 130b8e80941Smrg struct drm_msm_submitqueue req = { 131b8e80941Smrg .flags = 0, 132b8e80941Smrg .prio = prio, 133b8e80941Smrg }; 134b8e80941Smrg uint64_t nr_rings = 1; 135b8e80941Smrg int ret; 136b8e80941Smrg 137b8e80941Smrg if (fd_device_version(pipe->dev) < FD_VERSION_SUBMIT_QUEUES) { 138b8e80941Smrg to_msm_pipe(pipe)->queue_id = 0; 139b8e80941Smrg return 0; 140b8e80941Smrg } 141b8e80941Smrg 142b8e80941Smrg msm_pipe_get_param(pipe, FD_NR_RINGS, &nr_rings); 143b8e80941Smrg 144b8e80941Smrg req.prio = MIN2(req.prio, MAX2(nr_rings, 1) - 1); 145b8e80941Smrg 146b8e80941Smrg ret = drmCommandWriteRead(pipe->dev->fd, DRM_MSM_SUBMITQUEUE_NEW, 147b8e80941Smrg &req, sizeof(req)); 148b8e80941Smrg if (ret) { 149b8e80941Smrg ERROR_MSG("could not create submitqueue! %d (%s)", ret, strerror(errno)); 150b8e80941Smrg return ret; 151b8e80941Smrg } 152b8e80941Smrg 153b8e80941Smrg to_msm_pipe(pipe)->queue_id = req.id; 154b8e80941Smrg return 0; 155b8e80941Smrg} 156b8e80941Smrg 157b8e80941Smrgstatic void close_submitqueue(struct fd_pipe *pipe, uint32_t queue_id) 158b8e80941Smrg{ 159b8e80941Smrg if (fd_device_version(pipe->dev) < FD_VERSION_SUBMIT_QUEUES) 160b8e80941Smrg return; 161b8e80941Smrg 162b8e80941Smrg drmCommandWrite(pipe->dev->fd, DRM_MSM_SUBMITQUEUE_CLOSE, 163b8e80941Smrg &queue_id, sizeof(queue_id)); 164b8e80941Smrg} 165b8e80941Smrg 166b8e80941Smrgstatic void msm_pipe_destroy(struct fd_pipe *pipe) 167b8e80941Smrg{ 168b8e80941Smrg struct msm_pipe *msm_pipe = to_msm_pipe(pipe); 169b8e80941Smrg close_submitqueue(pipe, msm_pipe->queue_id); 170b8e80941Smrg free(msm_pipe); 171b8e80941Smrg} 172b8e80941Smrg 173b8e80941Smrgstatic const struct fd_pipe_funcs sp_funcs = { 174b8e80941Smrg .ringbuffer_new_object = msm_ringbuffer_sp_new_object, 175b8e80941Smrg .submit_new = msm_submit_sp_new, 176b8e80941Smrg .get_param = msm_pipe_get_param, 177b8e80941Smrg .wait = msm_pipe_wait, 178b8e80941Smrg .destroy = msm_pipe_destroy, 179b8e80941Smrg}; 180b8e80941Smrg 181b8e80941Smrgstatic const struct fd_pipe_funcs legacy_funcs = { 182b8e80941Smrg .ringbuffer_new_object = msm_ringbuffer_new_object, 183b8e80941Smrg .submit_new = msm_submit_new, 184b8e80941Smrg .get_param = msm_pipe_get_param, 185b8e80941Smrg .wait = msm_pipe_wait, 186b8e80941Smrg .destroy = msm_pipe_destroy, 187b8e80941Smrg}; 188b8e80941Smrg 189b8e80941Smrgstatic uint64_t get_param(struct fd_pipe *pipe, uint32_t param) 190b8e80941Smrg{ 191b8e80941Smrg uint64_t value; 192b8e80941Smrg int ret = query_param(pipe, param, &value); 193b8e80941Smrg if (ret) { 194b8e80941Smrg ERROR_MSG("get-param failed! %d (%s)", ret, strerror(errno)); 195b8e80941Smrg return 0; 196b8e80941Smrg } 197b8e80941Smrg return value; 198b8e80941Smrg} 199b8e80941Smrg 200b8e80941Smrgstruct fd_pipe * msm_pipe_new(struct fd_device *dev, 201b8e80941Smrg enum fd_pipe_id id, uint32_t prio) 202b8e80941Smrg{ 203b8e80941Smrg static const uint32_t pipe_id[] = { 204b8e80941Smrg [FD_PIPE_3D] = MSM_PIPE_3D0, 205b8e80941Smrg [FD_PIPE_2D] = MSM_PIPE_2D0, 206b8e80941Smrg }; 207b8e80941Smrg struct msm_pipe *msm_pipe = NULL; 208b8e80941Smrg struct fd_pipe *pipe = NULL; 209b8e80941Smrg 210b8e80941Smrg msm_pipe = calloc(1, sizeof(*msm_pipe)); 211b8e80941Smrg if (!msm_pipe) { 212b8e80941Smrg ERROR_MSG("allocation failed"); 213b8e80941Smrg goto fail; 214b8e80941Smrg } 215b8e80941Smrg 216b8e80941Smrg pipe = &msm_pipe->base; 217b8e80941Smrg 218b8e80941Smrg if (fd_device_version(dev) >= FD_VERSION_SOFTPIN) { 219b8e80941Smrg pipe->funcs = &sp_funcs; 220b8e80941Smrg } else { 221b8e80941Smrg pipe->funcs = &legacy_funcs; 222b8e80941Smrg } 223b8e80941Smrg 224b8e80941Smrg /* initialize before get_param(): */ 225b8e80941Smrg pipe->dev = dev; 226b8e80941Smrg msm_pipe->pipe = pipe_id[id]; 227b8e80941Smrg 228b8e80941Smrg /* these params should be supported since the first version of drm/msm: */ 229b8e80941Smrg msm_pipe->gpu_id = get_param(pipe, MSM_PARAM_GPU_ID); 230b8e80941Smrg msm_pipe->gmem = get_param(pipe, MSM_PARAM_GMEM_SIZE); 231b8e80941Smrg msm_pipe->chip_id = get_param(pipe, MSM_PARAM_CHIP_ID); 232b8e80941Smrg 233b8e80941Smrg if (fd_device_version(pipe->dev) >= FD_VERSION_GMEM_BASE) 234b8e80941Smrg msm_pipe->gmem_base = get_param(pipe, MSM_PARAM_GMEM_BASE); 235b8e80941Smrg 236b8e80941Smrg if (! msm_pipe->gpu_id) 237b8e80941Smrg goto fail; 238b8e80941Smrg 239b8e80941Smrg INFO_MSG("Pipe Info:"); 240b8e80941Smrg INFO_MSG(" GPU-id: %d", msm_pipe->gpu_id); 241b8e80941Smrg INFO_MSG(" Chip-id: 0x%08x", msm_pipe->chip_id); 242b8e80941Smrg INFO_MSG(" GMEM size: 0x%08x", msm_pipe->gmem); 243b8e80941Smrg 244b8e80941Smrg if (open_submitqueue(pipe, prio)) 245b8e80941Smrg goto fail; 246b8e80941Smrg 247b8e80941Smrg return pipe; 248b8e80941Smrgfail: 249b8e80941Smrg if (pipe) 250b8e80941Smrg fd_pipe_del(pipe); 251b8e80941Smrg return NULL; 252b8e80941Smrg} 253