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/libsync.h" 25bf215546Sopenharmony_ci 26bf215546Sopenharmony_ci#include "virtio_priv.h" 27bf215546Sopenharmony_ci 28bf215546Sopenharmony_cistatic int 29bf215546Sopenharmony_cibo_allocate(struct virtio_bo *virtio_bo) 30bf215546Sopenharmony_ci{ 31bf215546Sopenharmony_ci struct fd_bo *bo = &virtio_bo->base; 32bf215546Sopenharmony_ci if (!virtio_bo->offset) { 33bf215546Sopenharmony_ci struct drm_virtgpu_map req = { 34bf215546Sopenharmony_ci .handle = bo->handle, 35bf215546Sopenharmony_ci }; 36bf215546Sopenharmony_ci int ret; 37bf215546Sopenharmony_ci 38bf215546Sopenharmony_ci ret = drmIoctl(bo->dev->fd, DRM_IOCTL_VIRTGPU_MAP, &req); 39bf215546Sopenharmony_ci if (ret) { 40bf215546Sopenharmony_ci ERROR_MSG("alloc failed: %s", strerror(errno)); 41bf215546Sopenharmony_ci return ret; 42bf215546Sopenharmony_ci } 43bf215546Sopenharmony_ci 44bf215546Sopenharmony_ci virtio_bo->offset = req.offset; 45bf215546Sopenharmony_ci } 46bf215546Sopenharmony_ci 47bf215546Sopenharmony_ci return 0; 48bf215546Sopenharmony_ci} 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_cistatic int 51bf215546Sopenharmony_civirtio_bo_offset(struct fd_bo *bo, uint64_t *offset) 52bf215546Sopenharmony_ci{ 53bf215546Sopenharmony_ci struct virtio_bo *virtio_bo = to_virtio_bo(bo); 54bf215546Sopenharmony_ci int ret = bo_allocate(virtio_bo); 55bf215546Sopenharmony_ci if (ret) 56bf215546Sopenharmony_ci return ret; 57bf215546Sopenharmony_ci *offset = virtio_bo->offset; 58bf215546Sopenharmony_ci return 0; 59bf215546Sopenharmony_ci} 60bf215546Sopenharmony_ci 61bf215546Sopenharmony_cistatic int 62bf215546Sopenharmony_civirtio_bo_cpu_prep_guest(struct fd_bo *bo) 63bf215546Sopenharmony_ci{ 64bf215546Sopenharmony_ci struct drm_virtgpu_3d_wait args = { 65bf215546Sopenharmony_ci .handle = bo->handle, 66bf215546Sopenharmony_ci }; 67bf215546Sopenharmony_ci int ret; 68bf215546Sopenharmony_ci 69bf215546Sopenharmony_ci /* Side note, this ioctl is defined as IO_WR but should be IO_W: */ 70bf215546Sopenharmony_ci ret = drmIoctl(bo->dev->fd, DRM_IOCTL_VIRTGPU_WAIT, &args); 71bf215546Sopenharmony_ci if (ret && errno == EBUSY) 72bf215546Sopenharmony_ci return -EBUSY; 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_ci return 0; 75bf215546Sopenharmony_ci} 76bf215546Sopenharmony_ci 77bf215546Sopenharmony_cistatic int 78bf215546Sopenharmony_civirtio_bo_cpu_prep(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op) 79bf215546Sopenharmony_ci{ 80bf215546Sopenharmony_ci int ret; 81bf215546Sopenharmony_ci 82bf215546Sopenharmony_ci /* 83bf215546Sopenharmony_ci * Wait first in the guest, to avoid a blocking call in host. 84bf215546Sopenharmony_ci * If implicit sync it used, we still need to *also* wait in 85bf215546Sopenharmony_ci * host, if it is a shared buffer, because the guest doesn't 86bf215546Sopenharmony_ci * know about usage of the bo in the host (or other guests). 87bf215546Sopenharmony_ci */ 88bf215546Sopenharmony_ci 89bf215546Sopenharmony_ci ret = virtio_bo_cpu_prep_guest(bo); 90bf215546Sopenharmony_ci if (ret) 91bf215546Sopenharmony_ci goto out; 92bf215546Sopenharmony_ci 93bf215546Sopenharmony_ci /* If buffer is not shared, then it is not shared with host, 94bf215546Sopenharmony_ci * so we don't need to worry about implicit sync in host: 95bf215546Sopenharmony_ci */ 96bf215546Sopenharmony_ci if (!bo->shared) 97bf215546Sopenharmony_ci goto out; 98bf215546Sopenharmony_ci 99bf215546Sopenharmony_ci /* If buffer is shared, but we are using explicit sync, no 100bf215546Sopenharmony_ci * need to fallback to implicit sync in host: 101bf215546Sopenharmony_ci */ 102bf215546Sopenharmony_ci if (pipe && to_virtio_pipe(pipe)->no_implicit_sync) 103bf215546Sopenharmony_ci goto out; 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci struct msm_ccmd_gem_cpu_prep_req req = { 106bf215546Sopenharmony_ci .hdr = MSM_CCMD(GEM_CPU_PREP, sizeof(req)), 107bf215546Sopenharmony_ci .res_id = to_virtio_bo(bo)->res_id, 108bf215546Sopenharmony_ci .op = op, 109bf215546Sopenharmony_ci }; 110bf215546Sopenharmony_ci struct msm_ccmd_gem_cpu_prep_rsp *rsp; 111bf215546Sopenharmony_ci 112bf215546Sopenharmony_ci /* We can't do a blocking wait in the host, so we have to poll: */ 113bf215546Sopenharmony_ci do { 114bf215546Sopenharmony_ci rsp = virtio_alloc_rsp(bo->dev, &req.hdr, sizeof(*rsp)); 115bf215546Sopenharmony_ci 116bf215546Sopenharmony_ci ret = virtio_execbuf(bo->dev, &req.hdr, true); 117bf215546Sopenharmony_ci if (ret) 118bf215546Sopenharmony_ci goto out; 119bf215546Sopenharmony_ci 120bf215546Sopenharmony_ci ret = rsp->ret; 121bf215546Sopenharmony_ci } while (ret == -EBUSY); 122bf215546Sopenharmony_ci 123bf215546Sopenharmony_ciout: 124bf215546Sopenharmony_ci return ret; 125bf215546Sopenharmony_ci} 126bf215546Sopenharmony_ci 127bf215546Sopenharmony_cistatic void 128bf215546Sopenharmony_civirtio_bo_cpu_fini(struct fd_bo *bo) 129bf215546Sopenharmony_ci{ 130bf215546Sopenharmony_ci /* no-op */ 131bf215546Sopenharmony_ci} 132bf215546Sopenharmony_ci 133bf215546Sopenharmony_cistatic int 134bf215546Sopenharmony_civirtio_bo_madvise(struct fd_bo *bo, int willneed) 135bf215546Sopenharmony_ci{ 136bf215546Sopenharmony_ci /* TODO: 137bf215546Sopenharmony_ci * Currently unsupported, synchronous WILLNEED calls would introduce too 138bf215546Sopenharmony_ci * much latency.. ideally we'd keep state in the guest and only flush 139bf215546Sopenharmony_ci * down to host when host is under memory pressure. (Perhaps virtio-balloon 140bf215546Sopenharmony_ci * could signal this?) 141bf215546Sopenharmony_ci */ 142bf215546Sopenharmony_ci return willneed; 143bf215546Sopenharmony_ci} 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_cistatic uint64_t 146bf215546Sopenharmony_civirtio_bo_iova(struct fd_bo *bo) 147bf215546Sopenharmony_ci{ 148bf215546Sopenharmony_ci /* The shmem bo is allowed to have no iova, as it is only used for 149bf215546Sopenharmony_ci * guest<->host communications: 150bf215546Sopenharmony_ci */ 151bf215546Sopenharmony_ci assert(bo->iova || (to_virtio_bo(bo)->blob_id == 0)); 152bf215546Sopenharmony_ci return bo->iova; 153bf215546Sopenharmony_ci} 154bf215546Sopenharmony_ci 155bf215546Sopenharmony_cistatic void 156bf215546Sopenharmony_civirtio_bo_set_name(struct fd_bo *bo, const char *fmt, va_list ap) 157bf215546Sopenharmony_ci{ 158bf215546Sopenharmony_ci char name[32]; 159bf215546Sopenharmony_ci int sz; 160bf215546Sopenharmony_ci 161bf215546Sopenharmony_ci /* Note, we cannot set name on the host for the shmem bo, as 162bf215546Sopenharmony_ci * that isn't a real gem obj on the host side.. not having 163bf215546Sopenharmony_ci * an iova is a convenient way to detect this case: 164bf215546Sopenharmony_ci */ 165bf215546Sopenharmony_ci if (!bo->iova) 166bf215546Sopenharmony_ci return; 167bf215546Sopenharmony_ci 168bf215546Sopenharmony_ci sz = vsnprintf(name, sizeof(name), fmt, ap); 169bf215546Sopenharmony_ci sz = MIN2(sz, sizeof(name)); 170bf215546Sopenharmony_ci 171bf215546Sopenharmony_ci unsigned req_len = sizeof(struct msm_ccmd_gem_set_name_req) + align(sz, 4); 172bf215546Sopenharmony_ci 173bf215546Sopenharmony_ci uint8_t buf[req_len]; 174bf215546Sopenharmony_ci struct msm_ccmd_gem_set_name_req *req = (void *)buf; 175bf215546Sopenharmony_ci 176bf215546Sopenharmony_ci req->hdr = MSM_CCMD(GEM_SET_NAME, req_len); 177bf215546Sopenharmony_ci req->res_id = to_virtio_bo(bo)->res_id; 178bf215546Sopenharmony_ci req->len = sz; 179bf215546Sopenharmony_ci 180bf215546Sopenharmony_ci memcpy(req->payload, name, sz); 181bf215546Sopenharmony_ci 182bf215546Sopenharmony_ci virtio_execbuf(bo->dev, &req->hdr, false); 183bf215546Sopenharmony_ci} 184bf215546Sopenharmony_ci 185bf215546Sopenharmony_cistatic void 186bf215546Sopenharmony_cibo_upload(struct fd_bo *bo, unsigned off, void *src, unsigned len) 187bf215546Sopenharmony_ci{ 188bf215546Sopenharmony_ci unsigned req_len = sizeof(struct msm_ccmd_gem_upload_req) + align(len, 4); 189bf215546Sopenharmony_ci 190bf215546Sopenharmony_ci uint8_t buf[req_len]; 191bf215546Sopenharmony_ci struct msm_ccmd_gem_upload_req *req = (void *)buf; 192bf215546Sopenharmony_ci 193bf215546Sopenharmony_ci req->hdr = MSM_CCMD(GEM_UPLOAD, req_len); 194bf215546Sopenharmony_ci req->res_id = to_virtio_bo(bo)->res_id; 195bf215546Sopenharmony_ci req->pad = 0; 196bf215546Sopenharmony_ci req->off = off; 197bf215546Sopenharmony_ci req->len = len; 198bf215546Sopenharmony_ci 199bf215546Sopenharmony_ci memcpy(req->payload, src, len); 200bf215546Sopenharmony_ci 201bf215546Sopenharmony_ci virtio_execbuf(bo->dev, &req->hdr, false); 202bf215546Sopenharmony_ci} 203bf215546Sopenharmony_ci 204bf215546Sopenharmony_cistatic void 205bf215546Sopenharmony_civirtio_bo_upload(struct fd_bo *bo, void *src, unsigned len) 206bf215546Sopenharmony_ci{ 207bf215546Sopenharmony_ci unsigned off = 0; 208bf215546Sopenharmony_ci while (len > 0) { 209bf215546Sopenharmony_ci unsigned sz = MIN2(len, 0x1000); 210bf215546Sopenharmony_ci bo_upload(bo, off, src, sz); 211bf215546Sopenharmony_ci off += sz; 212bf215546Sopenharmony_ci src += sz; 213bf215546Sopenharmony_ci len -= sz; 214bf215546Sopenharmony_ci } 215bf215546Sopenharmony_ci} 216bf215546Sopenharmony_ci 217bf215546Sopenharmony_cistatic void 218bf215546Sopenharmony_ciset_iova(struct fd_bo *bo, uint64_t iova) 219bf215546Sopenharmony_ci{ 220bf215546Sopenharmony_ci struct msm_ccmd_gem_set_iova_req req = { 221bf215546Sopenharmony_ci .hdr = MSM_CCMD(GEM_SET_IOVA, sizeof(req)), 222bf215546Sopenharmony_ci .res_id = to_virtio_bo(bo)->res_id, 223bf215546Sopenharmony_ci .iova = iova, 224bf215546Sopenharmony_ci }; 225bf215546Sopenharmony_ci 226bf215546Sopenharmony_ci virtio_execbuf(bo->dev, &req.hdr, false); 227bf215546Sopenharmony_ci} 228bf215546Sopenharmony_ci 229bf215546Sopenharmony_cistatic void 230bf215546Sopenharmony_civirtio_bo_destroy(struct fd_bo *bo) 231bf215546Sopenharmony_ci{ 232bf215546Sopenharmony_ci struct virtio_bo *virtio_bo = to_virtio_bo(bo); 233bf215546Sopenharmony_ci 234bf215546Sopenharmony_ci /* Release iova by setting to zero: */ 235bf215546Sopenharmony_ci if (bo->iova) { 236bf215546Sopenharmony_ci set_iova(bo, 0); 237bf215546Sopenharmony_ci 238bf215546Sopenharmony_ci virtio_dev_free_iova(bo->dev, bo->iova, bo->size); 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_ci /* Need to flush batched ccmds to ensure the host sees the iova 241bf215546Sopenharmony_ci * release before the GEM handle is closed (ie. detach_resource() 242bf215546Sopenharmony_ci * on the host side) 243bf215546Sopenharmony_ci */ 244bf215546Sopenharmony_ci virtio_execbuf_flush(bo->dev); 245bf215546Sopenharmony_ci } 246bf215546Sopenharmony_ci 247bf215546Sopenharmony_ci free(virtio_bo); 248bf215546Sopenharmony_ci} 249bf215546Sopenharmony_ci 250bf215546Sopenharmony_cistatic const struct fd_bo_funcs funcs = { 251bf215546Sopenharmony_ci .offset = virtio_bo_offset, 252bf215546Sopenharmony_ci .cpu_prep = virtio_bo_cpu_prep, 253bf215546Sopenharmony_ci .cpu_fini = virtio_bo_cpu_fini, 254bf215546Sopenharmony_ci .madvise = virtio_bo_madvise, 255bf215546Sopenharmony_ci .iova = virtio_bo_iova, 256bf215546Sopenharmony_ci .set_name = virtio_bo_set_name, 257bf215546Sopenharmony_ci .upload = virtio_bo_upload, 258bf215546Sopenharmony_ci .destroy = virtio_bo_destroy, 259bf215546Sopenharmony_ci}; 260bf215546Sopenharmony_ci 261bf215546Sopenharmony_cistatic struct fd_bo * 262bf215546Sopenharmony_cibo_from_handle(struct fd_device *dev, uint32_t size, uint32_t handle) 263bf215546Sopenharmony_ci{ 264bf215546Sopenharmony_ci struct virtio_bo *virtio_bo; 265bf215546Sopenharmony_ci struct fd_bo *bo; 266bf215546Sopenharmony_ci 267bf215546Sopenharmony_ci virtio_bo = calloc(1, sizeof(*virtio_bo)); 268bf215546Sopenharmony_ci if (!virtio_bo) 269bf215546Sopenharmony_ci return NULL; 270bf215546Sopenharmony_ci 271bf215546Sopenharmony_ci bo = &virtio_bo->base; 272bf215546Sopenharmony_ci 273bf215546Sopenharmony_ci /* Note we need to set these because allocation_wait_execute() could 274bf215546Sopenharmony_ci * run before bo_init_commont(): 275bf215546Sopenharmony_ci */ 276bf215546Sopenharmony_ci bo->dev = dev; 277bf215546Sopenharmony_ci p_atomic_set(&bo->refcnt, 1); 278bf215546Sopenharmony_ci 279bf215546Sopenharmony_ci bo->size = size; 280bf215546Sopenharmony_ci bo->funcs = &funcs; 281bf215546Sopenharmony_ci bo->handle = handle; 282bf215546Sopenharmony_ci 283bf215546Sopenharmony_ci /* Don't assume we can mmap an imported bo: */ 284bf215546Sopenharmony_ci bo->alloc_flags = FD_BO_NOMAP; 285bf215546Sopenharmony_ci 286bf215546Sopenharmony_ci struct drm_virtgpu_resource_info args = { 287bf215546Sopenharmony_ci .bo_handle = handle, 288bf215546Sopenharmony_ci }; 289bf215546Sopenharmony_ci int ret; 290bf215546Sopenharmony_ci 291bf215546Sopenharmony_ci ret = drmCommandWriteRead(dev->fd, DRM_VIRTGPU_RESOURCE_INFO, &args, sizeof(args)); 292bf215546Sopenharmony_ci if (ret) { 293bf215546Sopenharmony_ci INFO_MSG("failed to get resource info: %s", strerror(errno)); 294bf215546Sopenharmony_ci free(virtio_bo); 295bf215546Sopenharmony_ci return NULL; 296bf215546Sopenharmony_ci } 297bf215546Sopenharmony_ci 298bf215546Sopenharmony_ci virtio_bo->res_id = args.res_handle; 299bf215546Sopenharmony_ci 300bf215546Sopenharmony_ci fd_bo_init_common(bo, dev); 301bf215546Sopenharmony_ci 302bf215546Sopenharmony_ci return bo; 303bf215546Sopenharmony_ci} 304bf215546Sopenharmony_ci 305bf215546Sopenharmony_ci/* allocate a new buffer object from existing handle */ 306bf215546Sopenharmony_cistruct fd_bo * 307bf215546Sopenharmony_civirtio_bo_from_handle(struct fd_device *dev, uint32_t size, uint32_t handle) 308bf215546Sopenharmony_ci{ 309bf215546Sopenharmony_ci struct fd_bo *bo = bo_from_handle(dev, size, handle); 310bf215546Sopenharmony_ci 311bf215546Sopenharmony_ci if (!bo) 312bf215546Sopenharmony_ci return NULL; 313bf215546Sopenharmony_ci 314bf215546Sopenharmony_ci bo->iova = virtio_dev_alloc_iova(dev, size); 315bf215546Sopenharmony_ci if (!bo->iova) 316bf215546Sopenharmony_ci goto fail; 317bf215546Sopenharmony_ci 318bf215546Sopenharmony_ci set_iova(bo, bo->iova); 319bf215546Sopenharmony_ci 320bf215546Sopenharmony_ci return bo; 321bf215546Sopenharmony_ci 322bf215546Sopenharmony_cifail: 323bf215546Sopenharmony_ci virtio_bo_destroy(bo); 324bf215546Sopenharmony_ci return NULL; 325bf215546Sopenharmony_ci} 326bf215546Sopenharmony_ci 327bf215546Sopenharmony_ci/* allocate a buffer object: */ 328bf215546Sopenharmony_cistruct fd_bo * 329bf215546Sopenharmony_civirtio_bo_new(struct fd_device *dev, uint32_t size, uint32_t flags) 330bf215546Sopenharmony_ci{ 331bf215546Sopenharmony_ci struct virtio_device *virtio_dev = to_virtio_device(dev); 332bf215546Sopenharmony_ci struct drm_virtgpu_resource_create_blob args = { 333bf215546Sopenharmony_ci .blob_mem = VIRTGPU_BLOB_MEM_HOST3D, 334bf215546Sopenharmony_ci .size = size, 335bf215546Sopenharmony_ci }; 336bf215546Sopenharmony_ci struct msm_ccmd_gem_new_req req = { 337bf215546Sopenharmony_ci .hdr = MSM_CCMD(GEM_NEW, sizeof(req)), 338bf215546Sopenharmony_ci .size = size, 339bf215546Sopenharmony_ci }; 340bf215546Sopenharmony_ci int ret; 341bf215546Sopenharmony_ci 342bf215546Sopenharmony_ci if (flags & FD_BO_SCANOUT) 343bf215546Sopenharmony_ci req.flags |= MSM_BO_SCANOUT; 344bf215546Sopenharmony_ci 345bf215546Sopenharmony_ci if (flags & FD_BO_GPUREADONLY) 346bf215546Sopenharmony_ci req.flags |= MSM_BO_GPU_READONLY; 347bf215546Sopenharmony_ci 348bf215546Sopenharmony_ci if (flags & FD_BO_CACHED_COHERENT) { 349bf215546Sopenharmony_ci req.flags |= MSM_BO_CACHED_COHERENT; 350bf215546Sopenharmony_ci } else { 351bf215546Sopenharmony_ci req.flags |= MSM_BO_WC; 352bf215546Sopenharmony_ci } 353bf215546Sopenharmony_ci 354bf215546Sopenharmony_ci if (flags & _FD_BO_VIRTIO_SHM) { 355bf215546Sopenharmony_ci args.blob_id = 0; 356bf215546Sopenharmony_ci args.blob_flags = VIRTGPU_BLOB_FLAG_USE_MAPPABLE; 357bf215546Sopenharmony_ci } else { 358bf215546Sopenharmony_ci if (flags & (FD_BO_SHARED | FD_BO_SCANOUT)) { 359bf215546Sopenharmony_ci args.blob_flags = VIRTGPU_BLOB_FLAG_USE_CROSS_DEVICE | 360bf215546Sopenharmony_ci VIRTGPU_BLOB_FLAG_USE_SHAREABLE; 361bf215546Sopenharmony_ci } 362bf215546Sopenharmony_ci 363bf215546Sopenharmony_ci if (!(flags & FD_BO_NOMAP)) { 364bf215546Sopenharmony_ci args.blob_flags |= VIRTGPU_BLOB_FLAG_USE_MAPPABLE; 365bf215546Sopenharmony_ci } 366bf215546Sopenharmony_ci 367bf215546Sopenharmony_ci args.blob_id = p_atomic_inc_return(&virtio_dev->next_blob_id); 368bf215546Sopenharmony_ci args.cmd = VOID2U64(&req); 369bf215546Sopenharmony_ci args.cmd_size = sizeof(req); 370bf215546Sopenharmony_ci 371bf215546Sopenharmony_ci /* tunneled cmds are processed separately on host side, 372bf215546Sopenharmony_ci * before the renderer->get_blob() callback.. the blob_id 373bf215546Sopenharmony_ci * is used to like the created bo to the get_blob() call 374bf215546Sopenharmony_ci */ 375bf215546Sopenharmony_ci req.blob_id = args.blob_id; 376bf215546Sopenharmony_ci req.iova = virtio_dev_alloc_iova(dev, size); 377bf215546Sopenharmony_ci if (!req.iova) { 378bf215546Sopenharmony_ci ret = -ENOMEM; 379bf215546Sopenharmony_ci goto fail; 380bf215546Sopenharmony_ci } 381bf215546Sopenharmony_ci } 382bf215546Sopenharmony_ci 383bf215546Sopenharmony_ci simple_mtx_lock(&virtio_dev->eb_lock); 384bf215546Sopenharmony_ci if (args.cmd) 385bf215546Sopenharmony_ci req.hdr.seqno = ++virtio_dev->next_seqno; 386bf215546Sopenharmony_ci ret = drmIoctl(dev->fd, DRM_IOCTL_VIRTGPU_RESOURCE_CREATE_BLOB, &args); 387bf215546Sopenharmony_ci simple_mtx_unlock(&virtio_dev->eb_lock); 388bf215546Sopenharmony_ci if (ret) 389bf215546Sopenharmony_ci goto fail; 390bf215546Sopenharmony_ci 391bf215546Sopenharmony_ci struct fd_bo *bo = bo_from_handle(dev, size, args.bo_handle); 392bf215546Sopenharmony_ci struct virtio_bo *virtio_bo = to_virtio_bo(bo); 393bf215546Sopenharmony_ci 394bf215546Sopenharmony_ci virtio_bo->blob_id = args.blob_id; 395bf215546Sopenharmony_ci bo->iova = req.iova; 396bf215546Sopenharmony_ci 397bf215546Sopenharmony_ci return bo; 398bf215546Sopenharmony_ci 399bf215546Sopenharmony_cifail: 400bf215546Sopenharmony_ci if (req.iova) { 401bf215546Sopenharmony_ci virtio_dev_free_iova(dev, req.iova, size); 402bf215546Sopenharmony_ci } 403bf215546Sopenharmony_ci return NULL; 404bf215546Sopenharmony_ci} 405