17e102996Smaya/* 27e102996Smaya * Copyright (C) 2012-2018 Rob Clark <robclark@freedesktop.org> 37e102996Smaya * 47e102996Smaya * Permission is hereby granted, free of charge, to any person obtaining a 57e102996Smaya * copy of this software and associated documentation files (the "Software"), 67e102996Smaya * to deal in the Software without restriction, including without limitation 77e102996Smaya * the rights to use, copy, modify, merge, publish, distribute, sublicense, 87e102996Smaya * and/or sell copies of the Software, and to permit persons to whom the 97e102996Smaya * Software is furnished to do so, subject to the following conditions: 107e102996Smaya * 117e102996Smaya * The above copyright notice and this permission notice (including the next 127e102996Smaya * paragraph) shall be included in all copies or substantial portions of the 137e102996Smaya * Software. 147e102996Smaya * 157e102996Smaya * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 167e102996Smaya * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 177e102996Smaya * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 187e102996Smaya * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 197e102996Smaya * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 207e102996Smaya * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 217e102996Smaya * SOFTWARE. 227e102996Smaya * 237e102996Smaya * Authors: 247e102996Smaya * Rob Clark <robclark@freedesktop.org> 257e102996Smaya */ 267e102996Smaya 277e102996Smaya#include "util/slab.h" 287e102996Smaya 297e102996Smaya#include "msm_priv.h" 307e102996Smaya 317ec681f3Smrgstatic int 327ec681f3Smrgquery_param(struct fd_pipe *pipe, uint32_t param, uint64_t *value) 337e102996Smaya{ 347ec681f3Smrg struct msm_pipe *msm_pipe = to_msm_pipe(pipe); 357ec681f3Smrg struct drm_msm_param req = { 367ec681f3Smrg .pipe = msm_pipe->pipe, 377ec681f3Smrg .param = param, 387ec681f3Smrg }; 397ec681f3Smrg int ret; 407e102996Smaya 417ec681f3Smrg ret = 427ec681f3Smrg drmCommandWriteRead(pipe->dev->fd, DRM_MSM_GET_PARAM, &req, sizeof(req)); 437ec681f3Smrg if (ret) 447ec681f3Smrg return ret; 457e102996Smaya 467ec681f3Smrg *value = req.value; 477e102996Smaya 487ec681f3Smrg return 0; 497e102996Smaya} 507e102996Smaya 517ec681f3Smrgstatic int 527ec681f3Smrgquery_queue_param(struct fd_pipe *pipe, uint32_t param, uint64_t *value) 537e102996Smaya{ 547ec681f3Smrg struct msm_pipe *msm_pipe = to_msm_pipe(pipe); 557ec681f3Smrg struct drm_msm_submitqueue_query req = { 567ec681f3Smrg .data = VOID2U64(value), 577ec681f3Smrg .id = msm_pipe->queue_id, 587ec681f3Smrg .param = param, 597ec681f3Smrg .len = sizeof(*value), 607ec681f3Smrg }; 617ec681f3Smrg int ret; 627ec681f3Smrg 637ec681f3Smrg ret = drmCommandWriteRead(pipe->dev->fd, DRM_MSM_SUBMITQUEUE_QUERY, &req, 647ec681f3Smrg sizeof(req)); 657ec681f3Smrg if (ret) 667ec681f3Smrg return ret; 677ec681f3Smrg 687ec681f3Smrg return 0; 697e102996Smaya} 707e102996Smaya 717ec681f3Smrgstatic int 727ec681f3Smrgmsm_pipe_get_param(struct fd_pipe *pipe, enum fd_param_id param, 737ec681f3Smrg uint64_t *value) 747e102996Smaya{ 757ec681f3Smrg struct msm_pipe *msm_pipe = to_msm_pipe(pipe); 767ec681f3Smrg switch (param) { 777ec681f3Smrg case FD_DEVICE_ID: // XXX probably get rid of this.. 787ec681f3Smrg case FD_GPU_ID: 797ec681f3Smrg *value = msm_pipe->gpu_id; 807ec681f3Smrg return 0; 817ec681f3Smrg case FD_GMEM_SIZE: 827ec681f3Smrg *value = msm_pipe->gmem; 837ec681f3Smrg return 0; 847ec681f3Smrg case FD_GMEM_BASE: 857ec681f3Smrg *value = msm_pipe->gmem_base; 867ec681f3Smrg return 0; 877ec681f3Smrg case FD_CHIP_ID: 887ec681f3Smrg *value = msm_pipe->chip_id; 897ec681f3Smrg return 0; 907ec681f3Smrg case FD_MAX_FREQ: 917ec681f3Smrg return query_param(pipe, MSM_PARAM_MAX_FREQ, value); 927ec681f3Smrg case FD_TIMESTAMP: 937ec681f3Smrg return query_param(pipe, MSM_PARAM_TIMESTAMP, value); 947ec681f3Smrg case FD_NR_RINGS: 957ec681f3Smrg return query_param(pipe, MSM_PARAM_NR_RINGS, value); 967ec681f3Smrg case FD_PP_PGTABLE: 977ec681f3Smrg return query_param(pipe, MSM_PARAM_PP_PGTABLE, value); 987ec681f3Smrg case FD_CTX_FAULTS: 997ec681f3Smrg return query_queue_param(pipe, MSM_SUBMITQUEUE_PARAM_FAULTS, value); 1007ec681f3Smrg case FD_GLOBAL_FAULTS: 1017ec681f3Smrg return query_param(pipe, MSM_PARAM_FAULTS, value); 1027ec681f3Smrg case FD_SUSPEND_COUNT: 1037ec681f3Smrg return query_param(pipe, MSM_PARAM_SUSPENDS, value); 1047ec681f3Smrg default: 1057ec681f3Smrg ERROR_MSG("invalid param id: %d", param); 1067ec681f3Smrg return -1; 1077ec681f3Smrg } 1087e102996Smaya} 1097e102996Smaya 1107ec681f3Smrgstatic int 1117ec681f3Smrgmsm_pipe_wait(struct fd_pipe *pipe, const struct fd_fence *fence, uint64_t timeout) 1127e102996Smaya{ 1137ec681f3Smrg struct fd_device *dev = pipe->dev; 1147ec681f3Smrg struct drm_msm_wait_fence req = { 1157ec681f3Smrg .fence = fence->kfence, 1167ec681f3Smrg .queueid = to_msm_pipe(pipe)->queue_id, 1177ec681f3Smrg }; 1187ec681f3Smrg int ret; 1197ec681f3Smrg 1207ec681f3Smrg get_abs_timeout(&req.timeout, timeout); 1217ec681f3Smrg 1227ec681f3Smrg ret = drmCommandWrite(dev->fd, DRM_MSM_WAIT_FENCE, &req, sizeof(req)); 1237ec681f3Smrg if (ret && (ret != -ETIMEDOUT)) { 1247ec681f3Smrg ERROR_MSG("wait-fence failed! %d (%s)", ret, strerror(errno)); 1257ec681f3Smrg } 1267ec681f3Smrg 1277ec681f3Smrg return ret; 1287e102996Smaya} 1297e102996Smaya 1307ec681f3Smrgstatic int 1317ec681f3Smrgopen_submitqueue(struct fd_pipe *pipe, uint32_t prio) 1327e102996Smaya{ 1337ec681f3Smrg struct drm_msm_submitqueue req = { 1347ec681f3Smrg .flags = 0, 1357ec681f3Smrg .prio = prio, 1367ec681f3Smrg }; 1377ec681f3Smrg uint64_t nr_rings = 1; 1387ec681f3Smrg int ret; 1397ec681f3Smrg 1407ec681f3Smrg if (fd_device_version(pipe->dev) < FD_VERSION_SUBMIT_QUEUES) { 1417ec681f3Smrg to_msm_pipe(pipe)->queue_id = 0; 1427ec681f3Smrg return 0; 1437ec681f3Smrg } 1447ec681f3Smrg 1457ec681f3Smrg msm_pipe_get_param(pipe, FD_NR_RINGS, &nr_rings); 1467ec681f3Smrg 1477ec681f3Smrg req.prio = MIN2(req.prio, MAX2(nr_rings, 1) - 1); 1487ec681f3Smrg 1497ec681f3Smrg ret = drmCommandWriteRead(pipe->dev->fd, DRM_MSM_SUBMITQUEUE_NEW, &req, 1507ec681f3Smrg sizeof(req)); 1517ec681f3Smrg if (ret) { 1527ec681f3Smrg ERROR_MSG("could not create submitqueue! %d (%s)", ret, strerror(errno)); 1537ec681f3Smrg return ret; 1547ec681f3Smrg } 1557ec681f3Smrg 1567ec681f3Smrg to_msm_pipe(pipe)->queue_id = req.id; 1577ec681f3Smrg return 0; 1587e102996Smaya} 1597e102996Smaya 1607ec681f3Smrgstatic void 1617ec681f3Smrgclose_submitqueue(struct fd_pipe *pipe, uint32_t queue_id) 1627e102996Smaya{ 1637ec681f3Smrg if (fd_device_version(pipe->dev) < FD_VERSION_SUBMIT_QUEUES) 1647ec681f3Smrg return; 1657e102996Smaya 1667ec681f3Smrg drmCommandWrite(pipe->dev->fd, DRM_MSM_SUBMITQUEUE_CLOSE, &queue_id, 1677ec681f3Smrg sizeof(queue_id)); 1687e102996Smaya} 1697e102996Smaya 1707ec681f3Smrgstatic void 1717ec681f3Smrgmsm_pipe_destroy(struct fd_pipe *pipe) 1727e102996Smaya{ 1737ec681f3Smrg struct msm_pipe *msm_pipe = to_msm_pipe(pipe); 1747ec681f3Smrg 1757ec681f3Smrg if (msm_pipe->suballoc_bo) 1767ec681f3Smrg fd_bo_del_locked(msm_pipe->suballoc_bo); 1777ec681f3Smrg 1787ec681f3Smrg close_submitqueue(pipe, msm_pipe->queue_id); 1797ec681f3Smrg msm_pipe_sp_ringpool_init(msm_pipe); 1807ec681f3Smrg free(msm_pipe); 1817e102996Smaya} 1827e102996Smaya 1837e102996Smayastatic const struct fd_pipe_funcs sp_funcs = { 1847ec681f3Smrg .ringbuffer_new_object = msm_ringbuffer_sp_new_object, 1857ec681f3Smrg .submit_new = msm_submit_sp_new, 1867ec681f3Smrg .flush = msm_pipe_sp_flush, 1877ec681f3Smrg .get_param = msm_pipe_get_param, 1887ec681f3Smrg .wait = msm_pipe_wait, 1897ec681f3Smrg .destroy = msm_pipe_destroy, 1907e102996Smaya}; 1917e102996Smaya 1927e102996Smayastatic const struct fd_pipe_funcs legacy_funcs = { 1937ec681f3Smrg .ringbuffer_new_object = msm_ringbuffer_new_object, 1947ec681f3Smrg .submit_new = msm_submit_new, 1957ec681f3Smrg .get_param = msm_pipe_get_param, 1967ec681f3Smrg .wait = msm_pipe_wait, 1977ec681f3Smrg .destroy = msm_pipe_destroy, 1987e102996Smaya}; 1997e102996Smaya 2007ec681f3Smrgstatic uint64_t 2017ec681f3Smrgget_param(struct fd_pipe *pipe, uint32_t param) 2027e102996Smaya{ 2037ec681f3Smrg uint64_t value; 2047ec681f3Smrg int ret = query_param(pipe, param, &value); 2057ec681f3Smrg if (ret) { 2067ec681f3Smrg ERROR_MSG("get-param failed! %d (%s)", ret, strerror(errno)); 2077ec681f3Smrg return 0; 2087ec681f3Smrg } 2097ec681f3Smrg return value; 2107e102996Smaya} 2117e102996Smaya 2127ec681f3Smrgstruct fd_pipe * 2137ec681f3Smrgmsm_pipe_new(struct fd_device *dev, enum fd_pipe_id id, uint32_t prio) 2147e102996Smaya{ 2157ec681f3Smrg static const uint32_t pipe_id[] = { 2167ec681f3Smrg [FD_PIPE_3D] = MSM_PIPE_3D0, 2177ec681f3Smrg [FD_PIPE_2D] = MSM_PIPE_2D0, 2187ec681f3Smrg }; 2197ec681f3Smrg struct msm_pipe *msm_pipe = NULL; 2207ec681f3Smrg struct fd_pipe *pipe = NULL; 2217ec681f3Smrg 2227ec681f3Smrg msm_pipe = calloc(1, sizeof(*msm_pipe)); 2237ec681f3Smrg if (!msm_pipe) { 2247ec681f3Smrg ERROR_MSG("allocation failed"); 2257ec681f3Smrg goto fail; 2267ec681f3Smrg } 2277ec681f3Smrg 2287ec681f3Smrg pipe = &msm_pipe->base; 2297ec681f3Smrg 2307ec681f3Smrg if (fd_device_version(dev) >= FD_VERSION_SOFTPIN) { 2317ec681f3Smrg pipe->funcs = &sp_funcs; 2327ec681f3Smrg } else { 2337ec681f3Smrg pipe->funcs = &legacy_funcs; 2347ec681f3Smrg } 2357ec681f3Smrg 2367ec681f3Smrg /* initialize before get_param(): */ 2377ec681f3Smrg pipe->dev = dev; 2387ec681f3Smrg msm_pipe->pipe = pipe_id[id]; 2397ec681f3Smrg 2407ec681f3Smrg /* these params should be supported since the first version of drm/msm: */ 2417ec681f3Smrg msm_pipe->gpu_id = get_param(pipe, MSM_PARAM_GPU_ID); 2427ec681f3Smrg msm_pipe->gmem = get_param(pipe, MSM_PARAM_GMEM_SIZE); 2437ec681f3Smrg msm_pipe->chip_id = get_param(pipe, MSM_PARAM_CHIP_ID); 2447ec681f3Smrg 2457ec681f3Smrg if (fd_device_version(pipe->dev) >= FD_VERSION_GMEM_BASE) 2467ec681f3Smrg msm_pipe->gmem_base = get_param(pipe, MSM_PARAM_GMEM_BASE); 2477ec681f3Smrg 2487ec681f3Smrg if (!(msm_pipe->gpu_id || msm_pipe->chip_id)) 2497ec681f3Smrg goto fail; 2507ec681f3Smrg 2517ec681f3Smrg INFO_MSG("Pipe Info:"); 2527ec681f3Smrg INFO_MSG(" GPU-id: %d", msm_pipe->gpu_id); 2537ec681f3Smrg INFO_MSG(" Chip-id: 0x%016"PRIx64, msm_pipe->chip_id); 2547ec681f3Smrg INFO_MSG(" GMEM size: 0x%08x", msm_pipe->gmem); 2557ec681f3Smrg 2567ec681f3Smrg if (open_submitqueue(pipe, prio)) 2577ec681f3Smrg goto fail; 2587ec681f3Smrg 2597ec681f3Smrg msm_pipe_sp_ringpool_init(msm_pipe); 2607ec681f3Smrg 2617ec681f3Smrg return pipe; 2627e102996Smayafail: 2637ec681f3Smrg if (pipe) 2647ec681f3Smrg fd_pipe_del(pipe); 2657ec681f3Smrg return NULL; 2667e102996Smaya} 267