1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2022 Google, Inc. 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21bf215546Sopenharmony_ci * SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci#include "util/slab.h" 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#include "freedreno_ringbuffer_sp.h" 27bf215546Sopenharmony_ci#include "virtio_priv.h" 28bf215546Sopenharmony_ci 29bf215546Sopenharmony_cistatic int 30bf215546Sopenharmony_ciquery_param(struct fd_pipe *pipe, uint32_t param, uint64_t *value) 31bf215546Sopenharmony_ci{ 32bf215546Sopenharmony_ci struct virtio_pipe *virtio_pipe = to_virtio_pipe(pipe); 33bf215546Sopenharmony_ci struct drm_msm_param req = { 34bf215546Sopenharmony_ci .pipe = virtio_pipe->pipe, 35bf215546Sopenharmony_ci .param = param, 36bf215546Sopenharmony_ci }; 37bf215546Sopenharmony_ci int ret; 38bf215546Sopenharmony_ci 39bf215546Sopenharmony_ci ret = virtio_simple_ioctl(pipe->dev, DRM_IOCTL_MSM_GET_PARAM, &req); 40bf215546Sopenharmony_ci if (ret) 41bf215546Sopenharmony_ci return ret; 42bf215546Sopenharmony_ci 43bf215546Sopenharmony_ci *value = req.value; 44bf215546Sopenharmony_ci 45bf215546Sopenharmony_ci return 0; 46bf215546Sopenharmony_ci} 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_cistatic int 49bf215546Sopenharmony_ciquery_queue_param(struct fd_pipe *pipe, uint32_t param, uint64_t *value) 50bf215546Sopenharmony_ci{ 51bf215546Sopenharmony_ci struct msm_ccmd_submitqueue_query_req req = { 52bf215546Sopenharmony_ci .hdr = MSM_CCMD(SUBMITQUEUE_QUERY, sizeof(req)), 53bf215546Sopenharmony_ci .queue_id = to_virtio_pipe(pipe)->queue_id, 54bf215546Sopenharmony_ci .param = param, 55bf215546Sopenharmony_ci .len = sizeof(*value), 56bf215546Sopenharmony_ci }; 57bf215546Sopenharmony_ci struct msm_ccmd_submitqueue_query_rsp *rsp; 58bf215546Sopenharmony_ci unsigned rsp_len = sizeof(*rsp) + req.len; 59bf215546Sopenharmony_ci 60bf215546Sopenharmony_ci rsp = virtio_alloc_rsp(pipe->dev, &req.hdr, rsp_len); 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_ci int ret = virtio_execbuf(pipe->dev, &req.hdr, true); 63bf215546Sopenharmony_ci if (ret) 64bf215546Sopenharmony_ci goto out; 65bf215546Sopenharmony_ci 66bf215546Sopenharmony_ci memcpy(value, rsp->payload, req.len); 67bf215546Sopenharmony_ci 68bf215546Sopenharmony_ci ret = rsp->ret; 69bf215546Sopenharmony_ci 70bf215546Sopenharmony_ciout: 71bf215546Sopenharmony_ci return ret; 72bf215546Sopenharmony_ci} 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_cistatic int 75bf215546Sopenharmony_civirtio_pipe_get_param(struct fd_pipe *pipe, enum fd_param_id param, 76bf215546Sopenharmony_ci uint64_t *value) 77bf215546Sopenharmony_ci{ 78bf215546Sopenharmony_ci struct virtio_pipe *virtio_pipe = to_virtio_pipe(pipe); 79bf215546Sopenharmony_ci struct virtio_device *virtio_dev = to_virtio_device(pipe->dev); 80bf215546Sopenharmony_ci 81bf215546Sopenharmony_ci switch (param) { 82bf215546Sopenharmony_ci case FD_DEVICE_ID: // XXX probably get rid of this.. 83bf215546Sopenharmony_ci case FD_GPU_ID: 84bf215546Sopenharmony_ci *value = virtio_pipe->gpu_id; 85bf215546Sopenharmony_ci return 0; 86bf215546Sopenharmony_ci case FD_GMEM_SIZE: 87bf215546Sopenharmony_ci *value = virtio_pipe->gmem; 88bf215546Sopenharmony_ci return 0; 89bf215546Sopenharmony_ci case FD_GMEM_BASE: 90bf215546Sopenharmony_ci *value = virtio_pipe->gmem_base; 91bf215546Sopenharmony_ci return 0; 92bf215546Sopenharmony_ci case FD_CHIP_ID: 93bf215546Sopenharmony_ci *value = virtio_pipe->chip_id; 94bf215546Sopenharmony_ci return 0; 95bf215546Sopenharmony_ci case FD_MAX_FREQ: 96bf215546Sopenharmony_ci *value = virtio_dev->caps.u.msm.max_freq; 97bf215546Sopenharmony_ci return 0; 98bf215546Sopenharmony_ci case FD_TIMESTAMP: 99bf215546Sopenharmony_ci return query_param(pipe, MSM_PARAM_TIMESTAMP, value); 100bf215546Sopenharmony_ci case FD_NR_RINGS: 101bf215546Sopenharmony_ci *value = virtio_dev->caps.u.msm.priorities; 102bf215546Sopenharmony_ci return 0; 103bf215546Sopenharmony_ci case FD_CTX_FAULTS: 104bf215546Sopenharmony_ci return query_queue_param(pipe, MSM_SUBMITQUEUE_PARAM_FAULTS, value); 105bf215546Sopenharmony_ci case FD_GLOBAL_FAULTS: 106bf215546Sopenharmony_ci return query_param(pipe, MSM_PARAM_FAULTS, value); 107bf215546Sopenharmony_ci case FD_SUSPEND_COUNT: 108bf215546Sopenharmony_ci return query_param(pipe, MSM_PARAM_SUSPENDS, value); 109bf215546Sopenharmony_ci default: 110bf215546Sopenharmony_ci ERROR_MSG("invalid param id: %d", param); 111bf215546Sopenharmony_ci return -1; 112bf215546Sopenharmony_ci } 113bf215546Sopenharmony_ci} 114bf215546Sopenharmony_ci 115bf215546Sopenharmony_cistatic int 116bf215546Sopenharmony_civirtio_pipe_wait(struct fd_pipe *pipe, const struct fd_fence *fence, uint64_t timeout) 117bf215546Sopenharmony_ci{ 118bf215546Sopenharmony_ci struct msm_ccmd_wait_fence_req req = { 119bf215546Sopenharmony_ci .hdr = MSM_CCMD(WAIT_FENCE, sizeof(req)), 120bf215546Sopenharmony_ci .queue_id = to_virtio_pipe(pipe)->queue_id, 121bf215546Sopenharmony_ci .fence = fence->kfence, 122bf215546Sopenharmony_ci }; 123bf215546Sopenharmony_ci struct msm_ccmd_submitqueue_query_rsp *rsp; 124bf215546Sopenharmony_ci int64_t end_time = os_time_get_nano() + timeout; 125bf215546Sopenharmony_ci int ret; 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_ci do { 128bf215546Sopenharmony_ci rsp = virtio_alloc_rsp(pipe->dev, &req.hdr, sizeof(*rsp)); 129bf215546Sopenharmony_ci 130bf215546Sopenharmony_ci ret = virtio_execbuf(pipe->dev, &req.hdr, true); 131bf215546Sopenharmony_ci if (ret) 132bf215546Sopenharmony_ci goto out; 133bf215546Sopenharmony_ci 134bf215546Sopenharmony_ci if ((timeout != PIPE_TIMEOUT_INFINITE) && 135bf215546Sopenharmony_ci (os_time_get_nano() >= end_time)) 136bf215546Sopenharmony_ci break; 137bf215546Sopenharmony_ci 138bf215546Sopenharmony_ci ret = rsp->ret; 139bf215546Sopenharmony_ci } while (ret == -ETIMEDOUT); 140bf215546Sopenharmony_ci 141bf215546Sopenharmony_ciout: 142bf215546Sopenharmony_ci return ret; 143bf215546Sopenharmony_ci} 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_cistatic int 146bf215546Sopenharmony_ciopen_submitqueue(struct fd_pipe *pipe, uint32_t prio) 147bf215546Sopenharmony_ci{ 148bf215546Sopenharmony_ci struct virtio_pipe *virtio_pipe = to_virtio_pipe(pipe); 149bf215546Sopenharmony_ci 150bf215546Sopenharmony_ci struct drm_msm_submitqueue req = { 151bf215546Sopenharmony_ci .flags = 0, 152bf215546Sopenharmony_ci .prio = prio, 153bf215546Sopenharmony_ci }; 154bf215546Sopenharmony_ci uint64_t nr_rings = 1; 155bf215546Sopenharmony_ci int ret; 156bf215546Sopenharmony_ci 157bf215546Sopenharmony_ci virtio_pipe_get_param(pipe, FD_NR_RINGS, &nr_rings); 158bf215546Sopenharmony_ci 159bf215546Sopenharmony_ci req.prio = MIN2(req.prio, MAX2(nr_rings, 1) - 1); 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci ret = virtio_simple_ioctl(pipe->dev, DRM_IOCTL_MSM_SUBMITQUEUE_NEW, &req); 162bf215546Sopenharmony_ci if (ret) { 163bf215546Sopenharmony_ci ERROR_MSG("could not create submitqueue! %d (%s)", ret, strerror(errno)); 164bf215546Sopenharmony_ci return ret; 165bf215546Sopenharmony_ci } 166bf215546Sopenharmony_ci 167bf215546Sopenharmony_ci virtio_pipe->queue_id = req.id; 168bf215546Sopenharmony_ci virtio_pipe->ring_idx = req.prio + 1; 169bf215546Sopenharmony_ci 170bf215546Sopenharmony_ci return 0; 171bf215546Sopenharmony_ci} 172bf215546Sopenharmony_ci 173bf215546Sopenharmony_cistatic void 174bf215546Sopenharmony_ciclose_submitqueue(struct fd_pipe *pipe, uint32_t queue_id) 175bf215546Sopenharmony_ci{ 176bf215546Sopenharmony_ci virtio_simple_ioctl(pipe->dev, DRM_IOCTL_MSM_SUBMITQUEUE_CLOSE, &queue_id); 177bf215546Sopenharmony_ci} 178bf215546Sopenharmony_ci 179bf215546Sopenharmony_cistatic void 180bf215546Sopenharmony_civirtio_pipe_destroy(struct fd_pipe *pipe) 181bf215546Sopenharmony_ci{ 182bf215546Sopenharmony_ci struct virtio_pipe *virtio_pipe = to_virtio_pipe(pipe); 183bf215546Sopenharmony_ci 184bf215546Sopenharmony_ci if (util_queue_is_initialized(&virtio_pipe->retire_queue)) 185bf215546Sopenharmony_ci util_queue_destroy(&virtio_pipe->retire_queue); 186bf215546Sopenharmony_ci 187bf215546Sopenharmony_ci close_submitqueue(pipe, virtio_pipe->queue_id); 188bf215546Sopenharmony_ci fd_pipe_sp_ringpool_fini(pipe); 189bf215546Sopenharmony_ci free(virtio_pipe); 190bf215546Sopenharmony_ci} 191bf215546Sopenharmony_ci 192bf215546Sopenharmony_cistatic const struct fd_pipe_funcs funcs = { 193bf215546Sopenharmony_ci .ringbuffer_new_object = fd_ringbuffer_sp_new_object, 194bf215546Sopenharmony_ci .submit_new = virtio_submit_new, 195bf215546Sopenharmony_ci .flush = fd_pipe_sp_flush, 196bf215546Sopenharmony_ci .get_param = virtio_pipe_get_param, 197bf215546Sopenharmony_ci .wait = virtio_pipe_wait, 198bf215546Sopenharmony_ci .destroy = virtio_pipe_destroy, 199bf215546Sopenharmony_ci}; 200bf215546Sopenharmony_ci 201bf215546Sopenharmony_cistatic void 202bf215546Sopenharmony_ciinit_shmem(struct fd_device *dev) 203bf215546Sopenharmony_ci{ 204bf215546Sopenharmony_ci struct virtio_device *virtio_dev = to_virtio_device(dev); 205bf215546Sopenharmony_ci 206bf215546Sopenharmony_ci simple_mtx_lock(&virtio_dev->rsp_lock); 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci /* One would like to do this in virtio_device_new(), but we'd 209bf215546Sopenharmony_ci * have to bypass/reinvent fd_bo_new().. 210bf215546Sopenharmony_ci */ 211bf215546Sopenharmony_ci if (unlikely(!virtio_dev->shmem)) { 212bf215546Sopenharmony_ci virtio_dev->shmem_bo = fd_bo_new(dev, 0x4000, 213bf215546Sopenharmony_ci _FD_BO_VIRTIO_SHM, "shmem"); 214bf215546Sopenharmony_ci virtio_dev->shmem = fd_bo_map(virtio_dev->shmem_bo); 215bf215546Sopenharmony_ci virtio_dev->shmem_bo->bo_reuse = NO_CACHE; 216bf215546Sopenharmony_ci 217bf215546Sopenharmony_ci uint32_t offset = virtio_dev->shmem->rsp_mem_offset; 218bf215546Sopenharmony_ci virtio_dev->rsp_mem_len = fd_bo_size(virtio_dev->shmem_bo) - offset; 219bf215546Sopenharmony_ci virtio_dev->rsp_mem = &((uint8_t *)virtio_dev->shmem)[offset]; 220bf215546Sopenharmony_ci } 221bf215546Sopenharmony_ci 222bf215546Sopenharmony_ci simple_mtx_unlock(&virtio_dev->rsp_lock); 223bf215546Sopenharmony_ci} 224bf215546Sopenharmony_ci 225bf215546Sopenharmony_cistruct fd_pipe * 226bf215546Sopenharmony_civirtio_pipe_new(struct fd_device *dev, enum fd_pipe_id id, uint32_t prio) 227bf215546Sopenharmony_ci{ 228bf215546Sopenharmony_ci static const uint32_t pipe_id[] = { 229bf215546Sopenharmony_ci [FD_PIPE_3D] = MSM_PIPE_3D0, 230bf215546Sopenharmony_ci [FD_PIPE_2D] = MSM_PIPE_2D0, 231bf215546Sopenharmony_ci }; 232bf215546Sopenharmony_ci struct virtio_device *virtio_dev = to_virtio_device(dev); 233bf215546Sopenharmony_ci struct virtio_pipe *virtio_pipe = NULL; 234bf215546Sopenharmony_ci struct fd_pipe *pipe = NULL; 235bf215546Sopenharmony_ci 236bf215546Sopenharmony_ci init_shmem(dev); 237bf215546Sopenharmony_ci 238bf215546Sopenharmony_ci virtio_pipe = calloc(1, sizeof(*virtio_pipe)); 239bf215546Sopenharmony_ci if (!virtio_pipe) { 240bf215546Sopenharmony_ci ERROR_MSG("allocation failed"); 241bf215546Sopenharmony_ci goto fail; 242bf215546Sopenharmony_ci } 243bf215546Sopenharmony_ci 244bf215546Sopenharmony_ci pipe = &virtio_pipe->base; 245bf215546Sopenharmony_ci 246bf215546Sopenharmony_ci pipe->funcs = &funcs; 247bf215546Sopenharmony_ci 248bf215546Sopenharmony_ci /* initialize before get_param(): */ 249bf215546Sopenharmony_ci pipe->dev = dev; 250bf215546Sopenharmony_ci virtio_pipe->pipe = pipe_id[id]; 251bf215546Sopenharmony_ci 252bf215546Sopenharmony_ci virtio_pipe->gpu_id = virtio_dev->caps.u.msm.gpu_id; 253bf215546Sopenharmony_ci virtio_pipe->gmem = virtio_dev->caps.u.msm.gmem_size; 254bf215546Sopenharmony_ci virtio_pipe->gmem_base = virtio_dev->caps.u.msm.gmem_base; 255bf215546Sopenharmony_ci virtio_pipe->chip_id = virtio_dev->caps.u.msm.chip_id; 256bf215546Sopenharmony_ci 257bf215546Sopenharmony_ci 258bf215546Sopenharmony_ci if (!(virtio_pipe->gpu_id || virtio_pipe->chip_id)) 259bf215546Sopenharmony_ci goto fail; 260bf215546Sopenharmony_ci 261bf215546Sopenharmony_ci util_queue_init(&virtio_pipe->retire_queue, "rq", 8, 1, 262bf215546Sopenharmony_ci UTIL_QUEUE_INIT_RESIZE_IF_FULL, NULL); 263bf215546Sopenharmony_ci 264bf215546Sopenharmony_ci INFO_MSG("Pipe Info:"); 265bf215546Sopenharmony_ci INFO_MSG(" GPU-id: %d", virtio_pipe->gpu_id); 266bf215546Sopenharmony_ci INFO_MSG(" Chip-id: 0x%016"PRIx64, virtio_pipe->chip_id); 267bf215546Sopenharmony_ci INFO_MSG(" GMEM size: 0x%08x", virtio_pipe->gmem); 268bf215546Sopenharmony_ci 269bf215546Sopenharmony_ci if (open_submitqueue(pipe, prio)) 270bf215546Sopenharmony_ci goto fail; 271bf215546Sopenharmony_ci 272bf215546Sopenharmony_ci fd_pipe_sp_ringpool_init(pipe); 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ci return pipe; 275bf215546Sopenharmony_cifail: 276bf215546Sopenharmony_ci if (pipe) 277bf215546Sopenharmony_ci fd_pipe_del(pipe); 278bf215546Sopenharmony_ci return NULL; 279bf215546Sopenharmony_ci} 280