memcpy(bo_map(bo), src, len);
}
+bool
+fd_bo_prefer_upload(struct fd_bo *bo, unsigned len)
+{
+ if (bo->funcs->prefer_upload)
+ return bo->funcs->prefer_upload(bo, len);
+
+ return false;
+}
+
/* a bit odd to take the pipe as an arg, but it's a, umm, quirk of kgsl.. */
int
fd_bo_cpu_prep(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op)
uint32_t fd_bo_size(struct fd_bo *bo);
void *fd_bo_map(struct fd_bo *bo);
void fd_bo_upload(struct fd_bo *bo, void *src, unsigned len);
+bool fd_bo_prefer_upload(struct fd_bo *bo, unsigned len);
int fd_bo_cpu_prep(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op);
void fd_bo_cpu_fini(struct fd_bo *bo);
bool fd_bo_is_cached(struct fd_bo *bo);
* implemented, it must be possible to mmap all buffers
*/
void (*upload)(struct fd_bo *bo, void *src, unsigned len);
+
+ /**
+ * Optional, if upload is supported, should upload be preferred?
+ */
+ bool (*prefer_upload)(struct fd_bo *bo, unsigned len);
};
struct fd_bo_fence {
}
}
+/**
+ * For recently allocated buffers, an immediate mmap would stall waiting
+ * for the host to handle the allocation and map to the guest, which
+ * could take a few ms. So for small transfers to recently allocated
+ * buffers, we'd prefer to use the upload path instead.
+ */
+static bool
+virtio_bo_prefer_upload(struct fd_bo *bo, unsigned len)
+{
+ struct virtio_bo *virtio_bo = to_virtio_bo(bo);
+
+ if (len > 0x4000)
+ return false;
+
+ int64_t age_ns = os_time_get_nano() - virtio_bo->alloc_time_ns;
+ if (age_ns > 5000000)
+ return false;
+
+ return true;
+}
+
static void
set_iova(struct fd_bo *bo, uint64_t iova)
{
.iova = virtio_bo_iova,
.set_name = virtio_bo_set_name,
.upload = virtio_bo_upload,
+ .prefer_upload = virtio_bo_prefer_upload,
.destroy = virtio_bo_destroy,
};
if (!virtio_bo)
return NULL;
+ virtio_bo->alloc_time_ns = os_time_get_nano();
+
bo = &virtio_bo->base;
/* Note we need to set these because allocation_wait_execute() could
struct virtio_bo {
struct fd_bo base;
+ uint64_t alloc_time_ns;
uint64_t offset;
uint32_t res_id;
uint32_t blob_id;