Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dc92d4ac authored by Lingfeng Yang's avatar Lingfeng Yang Committed by Alistair Delva
Browse files

CHROMIUM: drm/virtgpu: implement DRM_VIRTGPU_RESOURCE_CREATE_V2

Pass 'args_size' bytes to the host, where it can be decoded.
Allocate 'size' bytes from the pool specified by 'guest_memory_type'.

BUG=chromium:924405
TEST=compile

Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/1629915


Reviewed-by: default avatarRobert Tarasov <tutankhamen@chromium.org>
Commit-Queue: Gurchetan Singh <gurchetansingh@chromium.org>
Tested-by: default avatarGurchetan Singh <gurchetansingh@chromium.org>
[rebase54(groeck):
	Add missing include file
	Renamed reservation_object_add_excl_fence -> dma_resv_add_excl_fence
]
Signed-off-by: default avatarGuenter Roeck <groeck@chromium.org>
Bug: 153580313
Signed-off-by: default avatarLingfeng Yang <lfy@google.com>
Change-Id: I7901019384017cae2f7b341c60ff91bb774abe94
parent 73738bea
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -365,6 +365,17 @@ virtio_gpu_cmd_resource_create_3d(struct virtio_gpu_device *vgdev,
				  struct virtio_gpu_object *bo,
				  struct virtio_gpu_object_params *params,
				  struct virtio_gpu_fence *fence);
void
virtio_gpu_cmd_resource_create_v2(struct virtio_gpu_device *vgdev,
			     uint32_t resource_id, uint32_t guest_memory_type,
			     uint32_t caching_type, uint64_t size,
			     uint64_t pci_addr, uint32_t nents,
			     uint32_t args_size, void *data, uint32_t data_size,
			     struct virtio_gpu_fence *fence);
void
virtio_gpu_cmd_resource_v2_unref(struct virtio_gpu_device *vgdev,
			    uint32_t resource_id,
			    struct virtio_gpu_fence *fence);
void virtio_gpu_ctrl_ack(struct virtqueue *vq);
void virtio_gpu_cursor_ack(struct virtqueue *vq);
void virtio_gpu_fence_ack(struct virtqueue *vq);
+114 −1
Original line number Diff line number Diff line
@@ -25,10 +25,13 @@
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#include <linux/dma-mapping.h>
#include <linux/file.h>
#include <linux/sync_file.h>

#include <drm/drmP.h>
#include <drm/virtgpu_drm.h>
#include <drm/ttm/ttm_execbuf_util.h>
#include <linux/sync_file.h>

#include "virtgpu_drv.h"

@@ -575,7 +578,117 @@ static int virtio_gpu_get_caps_ioctl(struct drm_device *dev,
static int virtio_gpu_resource_create_v2_ioctl(struct drm_device *dev,
				void *data, struct drm_file *file)
{
	void *buf;
	int ret, si, nents;
	uint32_t handle = 0;
	uint64_t pci_addr = 0;
	struct scatterlist *sg;
	size_t total_size, offset;
	struct virtio_gpu_object *obj;
	struct virtio_gpu_fence *fence;
	struct virtio_gpu_mem_entry *ents;
	struct drm_virtgpu_resource_create_v2 *rc_v2 = data;
	struct virtio_gpu_object_params params = { 0 };
	struct virtio_gpu_device *vgdev = dev->dev_private;
	bool use_dma_api = !virtio_has_iommu_quirk(vgdev->vdev);
	void __user *args = u64_to_user_ptr(rc_v2->args);

	total_size = offset = 0;
	params.size = rc_v2->size;
	params.guest_memory_type = rc_v2->guest_memory_type;
	params.resource_v2 = true;
	params.caching_type = rc_v2->caching_type;

	obj = virtio_gpu_alloc_object(dev, &params, NULL);
	if (IS_ERR(obj))
		return PTR_ERR(obj);

	if (!obj->pages) {
                int ret;
                ret = virtio_gpu_object_get_sg_table(vgdev, obj);
                if (ret)
			goto err_free_obj;
        }

	if (rc_v2->guest_memory_type == VIRTGPU_MEMORY_HOST_COHERENT) {
		nents = 0;
	} else if (use_dma_api) {
                obj->mapped = dma_map_sg(vgdev->vdev->dev.parent,
                                         obj->pages->sgl, obj->pages->nents,
                                         DMA_TO_DEVICE);
                nents = obj->mapped;
        } else {
                nents = obj->pages->nents;
        }

	total_size = nents * sizeof(struct virtio_gpu_mem_entry) +
		     rc_v2->args_size;

	buf = kzalloc(total_size, GFP_KERNEL);
	if (!buf) {
		ret = -ENOMEM;
		goto err_free_obj;
	}

	ents = buf;
	if (rc_v2->guest_memory_type == VIRTGPU_MEMORY_HOST_COHERENT) {
		pci_addr = vgdev->caddr + obj->tbo.offset;
	} else {
		for_each_sg(obj->pages->sgl, sg, nents, si) {
			ents[si].addr = cpu_to_le64(use_dma_api
						    ? sg_dma_address(sg)
						    : sg_phys(sg));
			ents[si].length = cpu_to_le32(sg->length);
			ents[si].padding = 0;
			offset += sizeof(struct virtio_gpu_mem_entry);
		}
	}

	if (rc_v2->args_size) {
		if (copy_from_user(buf + offset, args,
				   rc_v2->args_size)) {
			ret = -EFAULT;
			goto err_free_buf;
		}
	}

	fence = virtio_gpu_fence_alloc(vgdev);
	if (!fence) {
		ret = -ENOMEM;
		goto err_free_buf;
	}

	ret = drm_gem_handle_create(file, &obj->gem_base, &handle);
	if (ret)
		goto err_fence_put;

	virtio_gpu_cmd_resource_create_v2(vgdev, obj->hw_res_handle,
				          rc_v2->guest_memory_type,
				          rc_v2->caching_type, rc_v2->size,
					  pci_addr, nents, rc_v2->args_size,
					  buf, total_size, fence);

	/*
	 * No need to call virtio_gpu_object_reserve since the buffer is not
	 * being used for ttm validation and no other processes can access
	 * the reservation object at this point.
	 */
	reservation_object_add_excl_fence(obj->tbo.resv, &fence->f);

	dma_fence_put(&fence->f);
	drm_gem_object_put_unlocked(&obj->gem_base);

	rc_v2->resource_id = obj->hw_res_handle;
	rc_v2->gem_handle = handle;
	return 0;

err_fence_put:
	dma_fence_put(&fence->f);
err_free_buf:
	kfree(buf);
err_free_obj:
	drm_gem_object_release(&obj->gem_base);
	return ret;
}

static int virtio_gpu_allocation_metadata_request_ioctl(struct drm_device *dev,
+7 −0
Original line number Diff line number Diff line
@@ -274,6 +274,13 @@ static int virtio_gpu_ttm_vram_bind(struct ttm_tt *ttm,

static int virtio_gpu_ttm_vram_unbind(struct ttm_tt *ttm)
{
	struct virtio_gpu_ttm_tt *gtt =
		container_of(ttm, struct virtio_gpu_ttm_tt, ttm.ttm);
	struct virtio_gpu_device *vgdev =
		virtio_gpu_get_vgdev(gtt->obj->tbo.bdev);
	struct virtio_gpu_object *obj = gtt->obj;

	virtio_gpu_cmd_resource_v2_unref(vgdev, obj->hw_res_handle, NULL);
	return 0;
}

+48 −0
Original line number Diff line number Diff line
@@ -532,6 +532,54 @@ virtio_gpu_cmd_resource_attach_backing(struct virtio_gpu_device *vgdev,
	virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence);
}

void
virtio_gpu_cmd_resource_create_v2(struct virtio_gpu_device *vgdev,
				  uint32_t resource_id,
				  uint32_t guest_memory_type,
				  uint32_t caching_type, uint64_t size,
				  uint64_t pci_addr, uint32_t nents,
				  uint32_t args_size, void *data,
				  uint32_t data_size,
				  struct virtio_gpu_fence *fence)
{
	struct virtio_gpu_resource_create_v2 *cmd_p;
	struct virtio_gpu_vbuffer *vbuf;

	cmd_p = virtio_gpu_alloc_cmd(vgdev, &vbuf, sizeof(*cmd_p));
	memset(cmd_p, 0, sizeof(*cmd_p));

	cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_CREATE_V2);
	cmd_p->resource_id = cpu_to_le32(resource_id);
	cmd_p->guest_memory_type = cpu_to_le32(guest_memory_type);
	cmd_p->caching_type = cpu_to_le32(caching_type);
	cmd_p->size = cpu_to_le64(size);
	cmd_p->pci_addr = cpu_to_le64(pci_addr);
	cmd_p->args_size = cpu_to_le32(args_size);
	cmd_p->nr_entries = cpu_to_le32(nents);

	vbuf->data_buf = data;
	vbuf->data_size = data_size;

	virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence);
}

void
virtio_gpu_cmd_resource_v2_unref(struct virtio_gpu_device *vgdev,
			         uint32_t resource_id,
			         struct virtio_gpu_fence *fence)
{
	struct virtio_gpu_resource_v2_unref *cmd_p;
	struct virtio_gpu_vbuffer *vbuf;

	cmd_p = virtio_gpu_alloc_cmd(vgdev, &vbuf, sizeof(*cmd_p));
	memset(cmd_p, 0, sizeof(*cmd_p));

	cmd_p->hdr.type = cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_CREATE_V2_UNREF);
	cmd_p->resource_id = cpu_to_le32(resource_id);

	virtio_gpu_queue_fenced_ctrl_buffer(vgdev, vbuf, &cmd_p->hdr, fence);
}

static void virtio_gpu_cmd_get_display_info_cb(struct virtio_gpu_device *vgdev,
					       struct virtio_gpu_vbuffer *vbuf)
{